From 5419c5032984533632365375fd8857fc0c952f75 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Fri, 13 Nov 2026 00:33:32 +0000 Subject: [PATCH 1/6] [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,KAAM,gBACN,KAAM,QACN,KAAM,kBACN,KAAM,cACN,KAAM,SACN,KAAM,OACN,KAAM,YACN,KAAM,QACN,KAAM,QACN,KAAM,QACN,KAAM,UACN,KAAM,mBACN,KAAM,WACN,KAAM,YACN,KAAM,SACN,KAAM,eACN,KAAM,eACN,KAAM,WACN,KAAM,eACN,KAAM,aACN,KAAM,kBACN,KAAM,sBACN,KAAM,oBACN,KAAM,aACN,KAAM,wBACN,KAAM,sBACN,KAAM,SACN,KAAM,WACN,KAAM,eACN,KAAM,eACN,KAAM,WACN,KAAM,iBACN,KAAM,gBACN,KAAM,YACN,KAAM,eACN,KAAM,YACN,KAAM,YACN,KAAM,gBACN,KAAM,oBACN,KAAM,QACN,KAAM,iBACN,KAAM,YACN,KAAM,UACN,KAAM,SACN,KAAM,WACN,KAAM,mBACN,KAAM,UACN,KAAM,oBACN,KAAM,cACN,KAAM,uBACN,KAAM,UACN,KAAM,cACN,KAAM,QACN,KAAM,SACN,KAAM,UACN,MAAO,OACP,MAAO,cACP,MAAO,kBACP,MAAO,sBACP,MAAO,yBACP,MAAO,SACX,EACA,oBAAqB,CACjB,EAAG,QACH,GAAI,aACJ,GAAI,4BACJ,GAAI,6BACJ,GAAI,UACJ,GAAI,oBACJ,GAAI,iBACJ,GAAI,gBACJ,GAAI,yBACJ,GAAI,aACJ,GAAI,UACJ,GAAI,cACJ,GAAI,gBACJ,GAAI,WACJ,GAAI,kBACJ,GAAI,oBACJ,GAAI,MACJ,GAAI,aACJ,GAAI,YACJ,IAAK,eACL,IAAK,aACL,IAAK,qBACL,IAAK,eACL,IAAK,aACL,IAAK,uBACT,EACA,kBAAmB,CACf,EAAG,MACH,EAAG,UACH,EAAG,cACH,EAAG,gBACH,EAAG,YACH,EAAG,cACH,GAAI,MACJ,GAAI,YACR,EACA,gBAAiB,CACb,EAAG,gBACH,EAAG,aACH,EAAG,aACH,EAAG,qBACH,EAAG,aACH,EAAG,eACH,EAAG,UACH,EAAG,cACP,EACA,YAAa,CACT,EAAG,SACH,EAAG,UACH,EAAG,QACH,EAAG,SACP,EACA,qBAAsB,CAClB,EAAG,EACH,EAAG,WACH,EAAG,SACH,EAAG,oBACH,EAAG,YACH,GAAI,WACJ,GAAI,MACJ,IAAK,QACL,IAAK,aACL,IAAK,WACL,KAAM,UACN,KAAM,QACN,KAAM,QACN,KAAM,aACN,MAAO,WACX,EACA,eAAgB,CACZ,EAAG,EACH,EAAG,MACH,EAAG,OACH,EAAG,KACH,EAAG,MACH,EAAG,WACH,EAAG,WACH,EAAG,SACP,EACA,QAAS,CACL,EAAG,SACH,EAAG,WACP,EACA,oBAAqB,CACjB,EAAG,EACH,EAAG,YACH,EAAG,QACH,EAAG,OACH,EAAG,WACH,GAAI,WACJ,GAAI,aACJ,GAAI,QACJ,IAAK,UACL,IAAK,WACL,IAAK,aACL,KAAM,SACV,EACA,OAAQ,CACJ,EAAG,EACH,MAAO,aACX,EACA,WAAY,CACR,EAAG,EACH,IAAK,YACT,EACA,cAAe,CACX,EAAG,EACH,IAAM,cACV,EACA,UAAW,CACP,EAAG,WACH,EAAG,wBACH,EAAG,uBACH,EAAG,0BACH,EAAG,4BACP,EACA,cAAe,CACX,EAAG,YACH,GAAI,YACJ,GAAI,iBACJ,IAAK,iBACL,IAAK,eACL,MAAO,cACX,EACA,YAAa,CACT,EAAG,YACH,EAAG,aACH,EAAG,eACH,EAAG,YACH,EAAG,QACH,EAAG,QACH,EAAG,IACP,EACA,cAAe,CACX,EAAG,UACH,EAAG,UACH,EAAG,UACH,EAAG,aACH,EAAG,oBACH,EAAG,WACH,EAAG,UACH,EAAG,YACH,IAAK,KACT,EACA,iBAAkB,CACd,EAAG,UACH,EAAG,YACH,EAAG,SACH,EAAG,QACH,EAAG,QACH,EAAG,OACH,EAAG,iBACH,EAAG,OACH,EAAG,WACH,EAAG,WACH,GAAI,YACJ,GAAI,aACJ,GAAI,eACJ,GAAI,gBACJ,GAAI,gBACJ,GAAI,aACJ,GAAI,iBACJ,GAAI,eACJ,GAAI,aACJ,IAAK,KACT,EACA,eAAgB,CACZ,EAAG,MACH,EAAG,SACH,EAAG,MACP,EACA,KAAM,CACF,EAAG,QACH,EAAG,MACP,EACA,mBAAoB,CAChB,EAAG,EACH,IAAK,OACL,IAAK,OACT,EACA,uBAAwB,CACpB,EAAG,EACH,MAAO,OACP,MAAO,OACX,EACA,YAAa,CACT,EAAG,OACH,EAAG,QACP,EACA,YAAa,CACT,EAAG,SACH,EAAG,SACH,EAAG,UACH,EAAG,YACH,EAAG,WACH,EAAG,SACH,EAAG,UACP,EACA,0BAA2B,CACvB,EAAG,EACH,EAAG,YACH,EAAG,eACH,EAAG,MACH,EAAG,kBACH,GAAI,kBACJ,GAAI,mBACJ,GAAI,aACJ,IAAK,qBACL,IAAK,iBACL,IAAK,yBACL,KAAM,mBACN,KAAM,mBACN,KAAM,sCACN,KAAM,0BACN,MAAO,uBACP,MAAO,wBACP,MAAO,gCACP,OAAQ,6BACR,OAAQ,iCACR,OAAQ,iCACR,QAAS,2BACT,QAAS,eACT,QAAS,sBACT,QAAS,qBACT,SAAU,gBACV,SAAU,oBACV,SAAU,UACV,UAAW,gBACX,UAAW,qBACX,UAAW,wBACX,WAAY,uBACZ,WAAY,eAChB,EACA,eAAgB,CACZ,EAAG,UACH,EAAG,kBACH,EAAG,gBACP,EACA,eAAgB,CACZ,EAAG,QACH,EAAG,gBACH,EAAG,gBACH,EAAG,OACH,EAAG,OACH,EAAG,QACH,EAAG,gBACH,EAAG,aACH,EAAG,MACH,GAAI,OACJ,GAAI,OACJ,GAAI,oBACJ,GAAI,0BACJ,GAAI,wBACJ,GAAI,aACJ,GAAI,aACJ,GAAI,aACJ,GAAI,aACJ,GAAI,kBACJ,GAAI,kBACJ,GAAI,QACR,EACA,iBAAkB,CACd,EAAG,UACH,EAAG,UACH,EAAG,QACH,EAAG,WACH,EAAG,WACP,EACA,oBAAqB,CACjB,EAAG,cACH,EAAG,UACH,EAAG,UACH,EAAG,YACH,EAAG,eACH,EAAG,UACH,EAAG,mBACH,EAAG,uBACH,EAAG,aACH,EAAG,sBACH,GAAI,mBACJ,GAAI,kBACJ,GAAI,YACJ,GAAI,cACJ,GAAI,iBACJ,GAAI,wBACJ,GAAI,WACJ,GAAI,YACJ,GAAI,gBACJ,GAAI,cACJ,GAAI,eACJ,GAAI,aACJ,GAAI,YACJ,GAAI,eACJ,GAAI,uBACJ,GAAI,eACJ,GAAI,aACJ,GAAI,YACJ,GAAI,mBACJ,GAAI,2BACJ,GAAI,cACJ,GAAI,mBACJ,GAAI,iBACJ,GAAI,QACJ,GAAI,WACJ,GAAI,wBACJ,GAAI,eACJ,GAAI,aACJ,GAAI,iBACJ,GAAI,mBACJ,GAAI,QACJ,GAAI,cACJ,GAAI,WACJ,GAAI,cACJ,GAAI,gBACJ,GAAI,kBACJ,GAAI,iBACJ,GAAI,OACJ,GAAI,UACJ,GAAI,yBACJ,GAAI,qBACJ,GAAI,UACJ,GAAI,OACJ,GAAI,iBACJ,GAAI,iBACJ,GAAI,SACJ,GAAI,cACJ,GAAI,YACJ,GAAI,iBACJ,GAAI,OACJ,GAAI,6BACJ,GAAI,iBACJ,GAAI,cACJ,GAAI,oBACJ,GAAI,wBACJ,GAAI,mBACJ,GAAI,UACJ,GAAI,eACJ,GAAI,YACJ,GAAI,cACJ,GAAI,eACJ,GAAI,cACJ,GAAI,SACJ,GAAI,QACJ,GAAI,eACJ,GAAI,QACJ,GAAI,WACJ,GAAI,YACJ,GAAI,OACJ,GAAI,cACJ,GAAI,aACJ,GAAI,iBACJ,GAAI,YACJ,GAAI,eACJ,GAAI,iBACR,EACA,YAAa,CACT,EAAG,WACH,EAAG,QACH,EAAG,QACH,EAAG,WACH,EAAG,WACH,EAAG,OACP,EACA,cAAe,CACX,EAAG,WACH,EAAG,YACH,EAAG,YACH,EAAG,iBACH,EAAG,YACH,EAAG,aACH,EAAG,YACH,EAAG,aACH,EAAG,aACH,EAAG,kBACH,GAAI,aACJ,GAAI,cACJ,GAAI,aACJ,GAAI,kBACJ,GAAI,kBACJ,GAAI,mBACJ,GAAI,mBACJ,GAAI,cACJ,GAAI,eACJ,GAAI,aACJ,GAAI,gBACJ,GAAI,cACJ,GAAI,WACJ,GAAI,gBACJ,GAAI,aACJ,GAAI,cACJ,GAAI,uBACJ,GAAI,yBACJ,GAAI,YACJ,GAAI,iBACJ,GAAI,cACJ,GAAI,eACJ,GAAI,wBACJ,GAAI,0BACJ,GAAI,OACJ,GAAI,SACJ,GAAI,iBACJ,GAAI,cACJ,GAAI,aACJ,GAAI,aACR,EACA,mBAAoB,CAChB,EAAG,MACH,EAAG,MACP,EACA,yBAA0B,CACtB,EAAG,UACH,EAAG,gBACH,EAAG,cACH,EAAG,QACH,EAAG,aACH,EAAG,MACH,EAAG,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": "AAWA,IAAMA,GAAM,KAENC,GAAuB,QACvBC,GAAiBF,GAAM,KACvBG,GAAiBH,GAAM,KACvBI,GAAiBJ,GAAM,QACvBK,GAAiBL,GAAM,OACvBM,GAAiBN,GAAM,QACvBO,GAAiBP,GAAM,OACvBQ,GAAiBR,GAAM,OACvBS,GAAiBT,GAAM,MACvBU,GAAiBV,GAAM,SACvBW,GAAiBX,GAAM,WACvBY,GAAiBZ,GAAM,WACvBa,GAAiBb,GAAM,YACvBc,GAAiBd,GAAM,SACvBe,GAAiBf,GAAM,OACvBgB,GAAiBhB,GAAM,SACvBiB,GAAiBjB,GAAM,SACvBkB,GAAiBlB,GAAM,SACvBmB,GAAiBnB,GAAM,QACvBoB,GAAiBpB,GAAM,QAEvBqB,GAAc,QACdC,GAAc,SACdC,GAAc,MACdC,GAAc,SACdC,GAAc,OACdC,GAAc,QACdC,GAAc,OACdC,GAAcD,GAAW,IAEzBE,GAAc,YACdC,GAAc,YACdC,GAAc,UACdC,GAAc,aACdC,GAAc,aACdC,GAAc,WACdC,GAAc,SACdC,GAAc,SAEdC,GAAc,SACdC,GAAc,aAEdC,GAAc,KAEdC,GAAS,OAAO,OAAU,IAE1BC,GAAMD,GAAS,SAAY,KAC3BE,GAAMF,GAAS,OAAY,KAC3BG,GAAMH,GAAS,UAAY,KAE7BI,GAIAC,GAEJ,SAASC,IAAa,CACrB,IAAIC,EAAW,iBAGXH,IAAWG,IACdH,GAAUG,EAEVF,IAASG,GAAIX,GAAQQ,GAAOC,EAAU,EACtCD,GAAQ,WAAW,oBAAoBD,GAAU,IAAK,8BAA8BA,GAAU,IAAK,OAAO,EAC1GK,GAAGZ,GAAQQ,GAAOC,EAAU,EAE5BJ,GAAI,cAAc,IAAI,YAAYJ,EAAU,CAAC,EAE/C,CAEA,SAASY,GAASC,EAAIC,EAAG,CACxB,GAAIA,GAAK,KAAM,CACd,IAAIC,EAAKF,EAAG,UACZ,CAACE,EAAG,SAASD,CAAC,GAAKC,EAAG,IAAID,CAAC,CAC5B,CACD,CAEA,SAASE,GAASH,EAAIC,EAAG,CACxB,IAAIC,EAAKF,EAAG,UACZE,EAAG,SAASD,CAAC,GAAKC,EAAG,OAAOD,CAAC,CAC9B,CAEA,SAASG,GAAWJ,EAAIK,EAAMC,EAAO,CACpCN,EAAG,MAAMK,CAAI,EAAIC,EAAQ,IAC1B,CAEA,SAASC,GAASC,EAAKC,EAAKC,EAAMC,EAAO,CACxC,IAAIX,EAAKV,GAAI,cAAckB,CAAG,EAE9B,OAAIC,GAAO,MACVV,GAASC,EAAIS,CAAG,EAGhBC,GAAK,aAAaV,EAAIW,CAAK,EAErBX,CACR,CAEA,SAASY,GAASH,EAAKC,EAAM,CAC5B,OAAOH,GAAS,MAAOE,EAAKC,CAAI,CACjC,CAEA,IAAMG,GAAa,IAAI,QAEvB,SAASC,GAAQd,EAAIe,EAAMC,EAAMC,EAAMC,EAAM,CAC5C,IAAIC,EAAQ,aAAeJ,EAAO,MAAQC,EAAO,MAC7CI,EAAWP,GAAW,IAAIb,CAAE,EAE5BmB,GAASC,IACZpB,EAAG,MAAM,UAAYmB,EACrBN,GAAW,IAAIb,EAAImB,CAAK,EAEpBJ,EAAO,GAAKC,EAAO,GAAKD,EAAOE,GAAQD,EAAOE,EACjDnB,GAASC,EAAI1C,EAAG,EAEhB6C,GAASH,EAAI1C,EAAG,EAEnB,CAEA,IAAM+D,GAAa,IAAI,QAEvB,SAASC,GAAQtB,EAAIuB,EAAYC,EAAa,CAC7C,IAAIC,EAAWF,EAAaC,EACxBE,EAAWL,GAAW,IAAIrB,CAAE,EAE5ByB,GAAYC,IACfL,GAAW,IAAIrB,EAAIyB,CAAQ,EAC3BzB,EAAG,MAAM,WAAauB,EACtBvB,EAAG,MAAM,YAAcwB,EAEzB,CAEA,IAAMG,GAAY,IAAI,QAEtB,SAASC,GAAO5B,EAAI6B,EAAQC,EAAQC,EAAU,CAC7C,IAAIC,EAAUH,EAAS,GAAKC,EACxBG,EAAUN,GAAU,IAAI3B,CAAE,EAE1BgC,GAAWC,IACdN,GAAU,IAAI3B,EAAIgC,CAAO,EACzBhC,EAAG,MAAM,OAAS8B,EAAS,KAC3B9B,EAAG,MAAM,MAAQ6B,EAAS,KAC1B7B,EAAG,MAAM,WAAa+B,EAAW,CAACF,EAAO,EAAI,KAAO,EACpD7B,EAAG,MAAM,UAAY+B,EAAW,CAACD,EAAO,EAAI,KAAO,EAErD,CAEA,IAAMI,GAAS,CAAC,QAAS,EAAI,EACvBC,GAAU,CAAC,GAAGD,GAAQ,QAAS,EAAI,EAEzC,SAASpC,GAAGsC,EAAIpC,EAAIqC,EAAIC,EAAM,CAC7BtC,EAAG,iBAAiBoC,EAAIC,EAAIC,EAAOH,GAAUD,EAAM,CACpD,CAEA,SAASrC,GAAIuC,EAAIpC,EAAIqC,EAAIC,EAAM,CAC9BtC,EAAG,oBAAoBoC,EAAIC,EAAIH,EAAM,CACtC,CAEA7C,IAAUM,GAAW,EAGrB,SAAS4C,GAAWC,EAAKC,EAAKC,EAAIC,EAAI,CACrC,IAAIC,EACJF,EAAKA,GAAM,EACXC,EAAKA,GAAMF,EAAI,OAAS,EACxB,IAAII,EAAUF,GAAM,WAEpB,KAAOA,EAAKD,EAAK,GAChBE,EAAMC,EAAWH,EAAKC,GAAO,EAAIG,IAAOJ,EAAKC,GAAM,CAAC,EAEhDF,EAAIG,CAAG,EAAIJ,EACdE,EAAKE,EAELD,EAAKC,EAGP,OAAIJ,EAAMC,EAAIC,CAAE,GAAKD,EAAIE,CAAE,EAAIH,EACvBE,EAEDC,CACR,CAEA,SAASI,GAAaC,EAAW,CAsB/B,MArBe,CAACC,EAAMC,EAAKC,IAAQ,CACnC,IAAIC,EAAK,GACLC,EAAK,GAET,QAASC,EAAIJ,EAAKI,GAAKH,EAAKG,IAC3B,GAAIN,EAAUC,EAAKK,CAAC,CAAC,EAAG,CACvBF,EAAKE,EACL,KACD,CAGD,QAASA,EAAIH,EAAKG,GAAKJ,EAAKI,IAC3B,GAAIN,EAAUC,EAAKK,CAAC,CAAC,EAAG,CACvBD,EAAKC,EACL,KACD,CAGD,MAAO,CAACF,EAAIC,CAAE,CACd,CAGF,CAEA,IAAME,GAAaC,GAAKA,GAAK,KACvBC,GAAaD,GAAKA,GAAK,MAAQA,EAAI,EAEnCE,GAAcX,GAAaQ,EAAU,EACrCI,GAAeZ,GAAaU,EAAU,EAE5C,SAASG,GAAUX,EAAMC,EAAKC,EAAKU,EAAS,EAAGC,EAAM,GAAO,CAG3D,IAAIC,EAAcD,EAAMH,GAAeD,GACnCV,EAAYc,EAAML,GAAaF,GAEnC,CAACL,EAAKC,CAAG,EAAIY,EAAYd,EAAMC,EAAKC,CAAG,EAEvC,IAAIa,EAAOf,EAAKC,CAAG,EACfe,EAAOhB,EAAKC,CAAG,EAEnB,GAAIA,EAAM,GACT,GAAIW,GAAU,EACbG,EAAOf,EAAKC,CAAG,EACfe,EAAOhB,EAAKE,CAAG,UAEPU,GAAU,GAClBG,EAAOf,EAAKE,CAAG,EACfc,EAAOhB,EAAKC,CAAG,MAGf,SAASI,EAAIJ,EAAKI,GAAKH,EAAKG,IAAK,CAChC,IAAIE,EAAIP,EAAKK,CAAC,EAEVN,EAAUQ,CAAC,IACVA,EAAIQ,EACPA,EAAOR,EACCA,EAAIS,IACZA,EAAOT,GAEV,CAIF,MAAO,CAACQ,GAAQE,GAAKD,GAAQ,CAACC,EAAG,CAClC,CAEA,SAASC,GAASC,EAAKC,EAAKC,EAAMC,EAAU,CAC3C,IAAIC,EAAUC,GAAKL,CAAG,EAClBM,EAAUD,GAAKJ,CAAG,EAElBD,GAAOC,IACNG,GAAW,IACdJ,GAAOE,EACPD,GAAOC,IAGPF,GAAOE,EACPD,GAAOC,IAIT,IAAIK,EAAQL,GAAQ,GAAKM,GAAQC,GAE7BC,EAAaN,GAAW,EAAI1B,GAAQiC,GACpCC,EAAaN,GAAW,EAAIK,GAAOjC,GAEnCmC,EAASH,EAAWH,EAAMO,GAAId,CAAG,CAAC,CAAC,EACnCe,EAASH,EAAWL,EAAMO,GAAIb,CAAG,CAAC,CAAC,EAEnCe,EAAUC,GAAIf,EAAMW,CAAM,EAC1BK,EAAUD,GAAIf,EAAMa,CAAM,EAG9B,OAAIb,GAAQ,KACPW,EAAS,IACZG,EAAUG,GAASH,EAAS,CAACH,CAAM,GAChCE,EAAS,IACZG,EAAUC,GAASD,EAAS,CAACH,CAAM,IAGjCZ,GAAYD,GAAQ,GACvBF,EAAMgB,EAAUZ,EAChBH,EAAMiB,EAAUZ,IAGhBN,EAAMoB,GAAYpB,EAAKgB,CAAO,EAC9Bf,EAAMoB,GAAYpB,EAAKiB,CAAO,GAGxB,CAAClB,EAAKC,CAAG,CACjB,CAEA,SAASqB,GAAWtB,EAAKC,EAAKC,EAAMC,EAAU,CAC7C,IAAIoB,EAASxB,GAASC,EAAKC,EAAKC,EAAMC,CAAQ,EAE9C,OAAIH,GAAO,IACVuB,EAAO,CAAC,EAAI,GAETtB,GAAO,IACVsB,EAAO,CAAC,EAAI,GAENA,CACR,CAEA,IAAMC,GAAW,GAEXC,GAAgB,CACrB,KAAM,EACN,IAAKD,EACN,EAEME,GAAe,CACpB,IAAM,EACN,KAAM,KACN,KAAM,CACP,EAEMC,GAAW,CAChB,IAAKD,GACL,IAAKA,EACN,EAIA,SAASE,GAAShC,EAAMC,EAAMgC,EAAMC,EAAO,CAC1C,OAAIC,GAAMF,CAAI,EACNG,GAAUpC,EAAMC,EAAMgC,CAAI,GAElCH,GAAa,IAAOG,EACpBH,GAAa,KAAOI,EAAQ,EAAI,KAChCJ,GAAa,KAAOI,EAAQ,EAAI,EAEzBE,GAAUpC,EAAMC,EAAM8B,EAAQ,EACtC,CAGA,SAASM,GAAOC,EAAIC,EAAI,CACvB,OAAOD,GAAaC,CACrB,CAIA,SAASC,GAAQvD,EAAMwD,EAAMC,EAAM,CAIlC,IAHAD,EAAOJ,GAAOI,EAAM,CAAC,EACrBC,EAAOL,GAAOK,EAAMzD,EAAK,OAAS,CAAC,EAE5BwD,GAAQC,GAAM,CACpB,GAAIzD,EAAKwD,CAAI,GAAK,KACjB,MAAO,GACRA,GACD,CAEA,MAAO,EACR,CAEA,SAASL,GAAUpC,EAAMC,EAAM0C,EAAK,CACnC,IAAIC,EAAOD,EAAI,IACXE,EAAOF,EAAI,IAEXG,EAAST,GAAOO,EAAK,IAAK,CAAC,EAC3BG,EAASV,GAAOQ,EAAK,IAAK,CAAC,EAE3BG,EAAUX,GAAOO,EAAK,KAAM,CAAC1C,EAAG,EAChC+C,EAAUZ,GAAOQ,EAAK,KAAO3C,EAAG,EAEhCgD,EAAUb,GAAOO,EAAK,KAAO1C,EAAG,EAChCiD,EAAUd,GAAOQ,EAAK,KAAM,CAAC3C,EAAG,EAEhCkD,EAAcf,GAAOO,EAAK,KAAM,CAAC,EACjCS,EAAchB,GAAOQ,EAAK,KAAM,CAAC,EAEjCS,EAAQrD,EAAOD,EACfuD,EAAW3C,GAAM0C,CAAK,EAEtBE,EAAYnD,GAAIa,GAAIlB,CAAI,EAAGkB,GAAIjB,CAAI,CAAC,EACpCwD,EAAY7C,GAAM4C,CAAS,EAE3BE,EAAiBxC,GAAIuC,EAAYF,CAAQ,GASzCD,EAAQ,OAASI,EAAiB,MACrCJ,EAAQ,GAIJtD,GAAQ,GAAKC,GAAQ,KACxBqD,EAAQ,MAEJF,GAAe,GAAKF,GAAWhD,KAClC4C,EAAS,GAENO,GAAe,GAAKF,GAAW,CAACjD,KACnC6C,EAAS,KAIZ,IAAIY,EAAeL,GAASE,GAAa,IACrCI,EAAehD,GAAM+C,CAAY,EACjCrD,EAAee,GAAI,GAAIvC,GAAM8E,CAAG,CAAC,EAEjCC,EAAWF,GAAgBL,GAAS,EAAKtD,GAAQ,EAAI,GAAK,EAAK8C,GAC/DgB,EAAWvC,GAASC,GAAYxB,EAAO6D,EAASvD,EAAK,EAAE,EAAG,EAAE,EAC5DyD,EAAW/D,GAAQkD,IAAYE,GAAe,GAAKA,GAAe,GAAKU,GAAWZ,GAAWE,GAAe,GAAKU,GAAWZ,GAAWA,EAAUhD,GACjJ8D,EAAW3D,GAAI2C,EAASc,EAAUC,GAAY/D,GAAQ+D,EAAWA,EAAW3D,GAAI2D,EAAUD,CAAO,CAAC,EAElGG,EAAWN,GAAgBL,GAAS,EAAKrD,GAAQ,EAAI,GAAK,EAAK8C,GAC/DmB,EAAW3C,GAASE,GAAYxB,EAAOgE,EAAS3D,EAAK,EAAE,EAAG,EAAE,EAC5D6D,EAAWlE,GAAQkD,IAAYE,GAAe,GAAKA,GAAe,GAAKa,GAAWf,GAAWE,GAAe,GAAKa,GAAWf,GAAWA,EAAU,CAACjD,GAClJkE,EAAWhE,GAAI6C,EAASiB,EAAUC,GAAYlE,GAAQkE,EAAWA,EAAW9D,GAAI8D,EAAUD,CAAO,CAAC,EAEtG,OAAIF,GAAUI,GAAUJ,GAAU,IACjCI,EAAS,KAEH,CAACJ,EAAQI,CAAM,CACvB,CAGA,IAAMC,GAAe,IAAI,KAAK,aAAahJ,GAASG,GAAI,SAAW,OAAO,EACpE8I,GAASC,GAAOF,GAAa,OAAOE,CAAG,EAEvCC,GAAI,KAEJC,GAAKD,GAAE,GACPtD,GAAMsD,GAAE,IACR1F,GAAQ0F,GAAE,MACVE,GAAQF,GAAE,MACVzD,GAAOyD,GAAE,KACTpE,GAAMoE,GAAE,IACRnE,GAAMmE,GAAE,IACRnD,GAAMmD,GAAE,IACR/D,GAAO+D,GAAE,KACT5D,GAAQ4D,GAAE,MACV3D,GAAO2D,GAAE,KAETG,GAAQ,CAACnF,EAAGoF,EAAY,IAAMJ,GAAE,KAAKhF,CAAC,EAAIoF,EAC1CC,GAAQ,CAACrF,EAAGoF,EAAY,IAAMJ,GAAE,MAAMhF,EAAIoF,CAAS,EAEnD1E,GAAM,IAEZ,SAAS4E,GAAaC,EAAG,CACxB,OAAQnE,IAAOmE,EAAKA,GAAK,KAAQA,GAAK,GAAG,EAAI,GAAK,CACnD,CAEA,SAASC,GAAMxG,EAAKwB,EAAMC,EAAM,CAC/B,OAAOG,GAAIC,GAAI7B,EAAKwB,CAAI,EAAGC,CAAI,CAChC,CAEA,SAASgF,GAAKzF,EAAG,CAChB,OAAO,OAAOA,GAAK,UACpB,CAEA,SAAS0F,EAAS1F,EAAG,CACpB,OAAOyF,GAAKzF,CAAC,EAAIA,EAAI,IAAMA,CAC5B,CAEA,IAAM2F,GAAO,IAAM,CAAC,EAIdC,GAAUC,GAAMA,EAEhBC,GAAU,CAACD,EAAIE,IAAOA,EAEtBC,GAAUC,GAAK,KAEfC,GAAUD,GAAK,GAEfE,GAAQ,CAACC,EAAGC,IAAMD,GAAKC,EAEvBC,GAAS,0BAGTC,GAAWxB,GAAO,CACvB,GAAIyB,GAAMzB,CAAG,GAAK0B,GAAS,IAAI1B,CAAG,EACjC,OAAOA,EAER,IAAM2B,EAAM,GAAG3B,CAAG,GAEZ4B,EAAQD,EAAI,MAAMJ,EAAM,EAE9B,GAAIK,GAAS,KACZ,OAAO5B,EAER,IAAI6B,EAAMD,EAAM,CAAC,EAAE,OAAS,EAG5B,GAAID,EAAI,QAAQ,IAAI,GAAK,GAAI,CAC5B,GAAI,CAAC1H,EAAK6H,CAAG,EAAIH,EAAI,MAAM,GAAG,EAC9B,MAAO,CAAC,GAAGH,GAASvH,CAAG,CAAC,IAAI6H,CAAG,EAChC,CAEA,OAAO9E,GAASgD,EAAK6B,CAAG,CACzB,EAEA,SAASE,GAAU9H,EAAK+H,EAAM,CAC7B,OAAOR,GAASxE,GAASwE,GAASvH,EAAI+H,CAAI,CAAC,EAAEA,CAAI,CAClD,CAEA,SAAS9E,GAAYjD,EAAK+H,EAAM,CAC/B,OAAOR,GAAShF,GAAKgF,GAASvH,EAAI+H,CAAI,CAAC,EAAEA,CAAI,CAC9C,CAEA,SAAS/E,GAAYhD,EAAK+H,EAAM,CAC/B,OAAOR,GAASjH,GAAMiH,GAASvH,EAAI+H,CAAI,CAAC,EAAEA,CAAI,CAC/C,CAIA,SAAShF,GAASgD,EAAKiC,EAAM,EAAG,CAC/B,GAAIR,GAAMzB,CAAG,EACZ,OAAOA,EAIR,IAAIkC,EAAI,IAAMD,EACV,EAAKjC,EAAMkC,GAAM,EAAI,OAAO,SAChC,OAAO/B,GAAM,CAAC,EAAI+B,CACnB,CAEA,IAAMR,GAAW,IAAI,IAErB,SAASS,GAASlI,EAAK,CACtB,QAAS,GAAGA,GAAK,MAAM,GAAG,EAAE,CAAC,GAAK,IAAI,MACvC,CAEA,SAASmI,GAASrG,EAAMW,EAAQE,EAAQyF,EAAO,CAC9C,IAAIC,EAAQ,CAAC,EAETC,EAAUF,EAAM,IAAIF,EAAQ,EAEhC,QAASL,EAAMpF,EAAQoF,EAAMlF,EAAQkF,IAAO,CAC3C,IAAIU,EAAO7F,GAAImF,CAAG,EACdzC,EAAMrC,GAASF,GAAIf,EAAM+F,CAAG,EAAGU,CAAI,EAEvC,QAASzH,EAAI,EAAGA,EAAIsH,EAAM,OAAQtH,IAAK,CACtC,IAAI0H,EAAQ1G,GAAQ,GAAK,CAAC,GAAGsG,EAAMtH,CAAC,CAAC,IAAI+G,CAAG,GAAKO,EAAMtH,CAAC,EAAIsE,EACxD4C,GAAOH,GAAO,EAAI,EAAIU,IAASV,GAAOS,EAAQxH,CAAC,EAAI,EAAIwH,EAAQxH,CAAC,GAChEiH,EAAOjG,GAAQ,GAAK0G,EAAQzF,GAASyF,EAAOR,CAAG,EACnDK,EAAM,KAAKN,CAAI,EACfN,GAAS,IAAIM,EAAMC,CAAG,CACvB,CACD,CAEA,OAAOK,CACR,CAIA,IAAMI,GAAY,CAAC,EACbC,GAAY,CAAC,EAEbC,GAAgB,CAAC,KAAM,IAAI,EAE3BC,GAAQ,MAAM,QACdpB,GAAQ,OAAO,UACfqB,GAAU7H,GAAKA,IAAM,OAE3B,SAAS8H,GAAM9H,EAAG,CACjB,OAAO,OAAOA,GAAK,QACpB,CAEA,SAAS2C,GAAM3C,EAAG,CACjB,IAAI+H,EAAK,GAET,GAAI/H,GAAK,KAAM,CACd,IAAIvD,EAAIuD,EAAE,YACV+H,EAAKtL,GAAK,MAAQA,GAAK,MACxB,CAEA,OAAOsL,CACR,CAEA,SAASC,GAAUhI,EAAG,CACrB,OAAOA,GAAK,MAAQ,OAAOA,GAAK,QACjC,CAEA,IAAMiI,GAAa,OAAO,eAAe,UAAU,EAE7CC,GAAY,YAElB,SAASC,GAAKC,EAAGC,EAAS1F,GAAO,CAChC,IAAI2F,EAEJ,GAAIV,GAAMQ,CAAC,EAAG,CACb,IAAIrD,EAAMqD,EAAE,KAAKpI,GAAKA,GAAK,IAAI,EAE/B,GAAI4H,GAAM7C,CAAG,GAAKsD,EAAOtD,CAAG,EAAG,CAC9BuD,EAAM,MAAMF,EAAE,MAAM,EACpB,QAAStI,EAAI,EAAGA,EAAIsI,EAAE,OAAQtI,IAC7BwI,EAAIxI,CAAC,EAAIqI,GAAKC,EAAEtI,CAAC,EAAGuI,CAAM,CAC5B,MAECC,EAAMF,EAAE,MAAM,CAChB,SACSA,aAAaH,GACrBK,EAAMF,EAAE,MAAM,UACNC,EAAOD,CAAC,EAAG,CACnBE,EAAM,CAAC,EACP,QAASC,KAAKH,EACTG,GAAKL,KACRI,EAAIC,CAAC,EAAIJ,GAAKC,EAAEG,CAAC,EAAGF,CAAM,EAE7B,MAECC,EAAMF,EAEP,OAAOE,CACR,CAEA,SAASE,GAAOtL,EAAM,CACrB,IAAIuL,EAAO,UAEX,QAAS3I,EAAI,EAAGA,EAAI2I,EAAK,OAAQ3I,IAAK,CACrC,IAAI4I,EAAMD,EAAK3I,CAAC,EAEhB,QAAS6I,KAAOD,EACXC,GAAOT,KACNvF,GAAMzF,EAAKyL,CAAG,CAAC,EAClBH,GAAOtL,EAAKyL,CAAG,EAAGR,GAAKO,EAAIC,CAAG,CAAC,CAAC,EAEhCzL,EAAKyL,CAAG,EAAIR,GAAKO,EAAIC,CAAG,CAAC,EAG7B,CAEA,OAAOzL,CACR,CAGA,IAAM0L,GAAc,EACdC,GAAc,EACdC,GAAc,EAGpB,SAASC,GAAWC,EAAOC,EAAUC,EAAY,CAChD,QAASpJ,EAAI,EAAGqJ,EAAIC,EAAc,GAAItJ,EAAImJ,EAAS,OAAQnJ,IAAK,CAC/D,IAAIuJ,EAAUJ,EAASnJ,CAAC,EAExB,GAAIuJ,EAAUD,EAAa,CAE1B,IADAD,EAAKE,EAAU,EACRF,GAAM,GAAKH,EAAMG,CAAE,GAAK,MAC9BH,EAAMG,GAAI,EAAI,KAGf,IADAA,EAAKE,EAAU,EACRF,EAAKD,GAAcF,EAAMG,CAAE,GAAK,MACtCH,EAAMI,EAAcD,GAAI,EAAI,IAC9B,CACD,CACD,CAIA,SAASG,GAAKC,EAAQC,EAAW,CAChC,GAAIC,GAAeF,CAAM,EAAG,CAG3B,IAAIG,EAAQH,EAAO,CAAC,EAAE,MAAM,EAE5B,QAASzJ,EAAI,EAAGA,EAAIyJ,EAAO,OAAQzJ,IAClC4J,EAAM,KAAK,GAAGH,EAAOzJ,CAAC,EAAE,MAAM,CAAC,CAAC,EAEjC,OAAK6J,GAAMD,EAAM,CAAC,CAAC,IAClBA,EAAQE,GAASF,CAAK,GAEhBA,CACR,CAEA,IAAIG,EAAQ,IAAI,IAEhB,QAASC,EAAK,EAAGA,EAAKP,EAAO,OAAQO,IAAM,CAE1C,IAAIC,EADIR,EAAOO,CAAE,EACN,CAAC,EACRlD,EAAMmD,EAAG,OAEb,QAASjK,EAAI,EAAGA,EAAI8G,EAAK9G,IACxB+J,EAAM,IAAIE,EAAGjK,CAAC,CAAC,CACjB,CAEA,IAAIL,EAAO,CAAC,MAAM,KAAKoK,CAAK,EAAE,KAAK,CAACzD,EAAGC,IAAMD,EAAIC,CAAC,CAAC,EAE/C6C,EAAazJ,EAAK,CAAC,EAAE,OAErBuK,EAAQ,IAAI,IAEhB,QAASlK,EAAI,EAAGA,EAAIoJ,EAAYpJ,IAC/BkK,EAAM,IAAIvK,EAAK,CAAC,EAAEK,CAAC,EAAGA,CAAC,EAExB,QAASgK,EAAK,EAAGA,EAAKP,EAAO,OAAQO,IAAM,CAC1C,IAAIG,EAAIV,EAAOO,CAAE,EACbC,EAAKE,EAAE,CAAC,EAEZ,QAASC,EAAK,EAAGA,EAAKD,EAAE,OAAQC,IAAM,CACrC,IAAIC,EAAKF,EAAEC,CAAE,EAETlB,EAAQ,MAAME,CAAU,EAAE,KAAK,MAAS,EAExCkB,EAAWZ,EAAYA,EAAUM,CAAE,EAAEI,CAAE,EAAIrB,GAE3CI,EAAW,CAAC,EAEhB,QAASnJ,EAAI,EAAGA,EAAIqK,EAAG,OAAQrK,IAAK,CACnC,IAAIuK,EAAOF,EAAGrK,CAAC,EACXwK,EAAaN,EAAM,IAAID,EAAGjK,CAAC,CAAC,EAE5BuK,IAAS,KACRD,GAAYxB,KACfI,EAAMsB,CAAU,EAAID,EAEhBD,GAAYtB,IACfG,EAAS,KAAKqB,CAAU,GAI1BtB,EAAMsB,CAAU,EAAID,CACtB,CAEAtB,GAAWC,EAAOC,EAAUC,CAAU,EAEtCzJ,EAAK,KAAKuJ,CAAK,CAChB,CACD,CAEA,OAAOvJ,CACR,CAEA,IAAM8K,GAAY,OAAO,eAAkB,IAAcC,GAAM,QAAQ,QAAQ,EAAE,KAAKA,CAAE,EAAI,eAG5F,SAASZ,GAASF,EAAO,CACxB,IAAIe,EAAOf,EAAM,CAAC,EACdgB,EAAOD,EAAK,OAEZE,EAAO,MAAMD,CAAI,EACrB,QAAS5K,EAAI,EAAGA,EAAI6K,EAAK,OAAQ7K,IAChC6K,EAAK7K,CAAC,EAAIA,EAEX6K,EAAK,KAAK,CAAC/K,EAAIC,IAAO4K,EAAK7K,CAAE,EAAI6K,EAAK5K,CAAE,CAAC,EAEzC,IAAI+K,EAAS,CAAC,EACd,QAAS9K,EAAI,EAAGA,EAAI4J,EAAM,OAAQ5J,IAAK,CACtC,IAAI+K,EAAMnB,EAAM5J,CAAC,EACbgL,EAAO,MAAMJ,CAAI,EAErB,QAASK,EAAI,EAAGA,EAAIL,EAAMK,IACzBD,EAAKC,CAAC,EAAIF,EAAIF,EAAKI,CAAC,CAAC,EAEtBH,EAAO,KAAKE,CAAI,CACjB,CAEA,OAAOF,CACR,CAGA,SAASnB,GAAeF,EAAQ,CAC/B,IAAIyB,EAAQzB,EAAO,CAAC,EAAE,CAAC,EACnB0B,EAAOD,EAAM,OAEjB,QAASlL,EAAI,EAAGA,EAAIyJ,EAAO,OAAQzJ,IAAK,CACvC,IAAIoL,EAAQ3B,EAAOzJ,CAAC,EAAE,CAAC,EAEvB,GAAIoL,EAAM,QAAUD,EACnB,MAAO,GAER,GAAIC,GAASF,GACZ,QAASD,EAAI,EAAGA,EAAIE,EAAMF,IACzB,GAAIG,EAAMH,CAAC,GAAKC,EAAMD,CAAC,EACtB,MAAO,GAGX,CAEA,MAAO,EACR,CAEA,SAASpB,GAAMwB,EAAMC,EAAU,IAAK,CACnC,IAAMxE,EAAMuE,EAAK,OAGjB,GAAIvE,GAAO,EACV,MAAO,GAGR,IAAIyE,EAAW,EACXC,EAAU1E,EAAM,EAEpB,KAAOyE,GAAYC,GAAWH,EAAKE,CAAQ,GAAK,MAC/CA,IAED,KAAOC,GAAWD,GAAYF,EAAKG,CAAO,GAAK,MAC9CA,IAGD,GAAIA,GAAWD,EACd,MAAO,GAER,IAAME,EAAS1K,GAAI,EAAGvB,IAAOgM,EAAUD,EAAW,GAAKD,CAAO,CAAC,EAE/D,QAASI,EAAUL,EAAKE,CAAQ,EAAGvL,EAAIuL,EAAWE,EAAQzL,GAAKwL,EAASxL,GAAKyL,EAAQ,CACpF,IAAMvL,EAAImL,EAAKrL,CAAC,EAEhB,GAAIE,GAAK,KAAM,CACd,GAAIA,GAAKwL,EACR,MAAO,GAERA,EAAUxL,CACX,CACD,CAEA,MAAO,EACR,CAEA,IAAMyL,GAAS,CACd,UACA,WACA,QACA,QACA,MACA,OACA,OACA,SACA,YACA,UACA,WACA,UACD,EAEMC,GAAO,CACZ,SACA,SACA,UACA,YACA,WACA,SACA,UACD,EAEA,SAASC,GAAOjF,EAAK,CACpB,OAAOA,EAAI,MAAM,EAAG,CAAC,CACtB,CAEA,IAAMkF,GAAQF,GAAK,IAAIC,EAAM,EAEvBE,GAAUJ,GAAO,IAAIE,EAAM,EAE3BG,GAAW,CAChB,KAAML,GACN,IAAMI,GACN,KAAMH,GACN,IAAME,EACP,EAEA,SAASG,GAASC,EAAK,CACtB,OAAQA,EAAM,GAAK,IAAM,IAAMA,CAChC,CAEA,SAASC,GAASD,EAAK,CACtB,OAAQA,EAAM,GAAK,KAAOA,EAAM,IAAM,IAAM,IAAMA,CACnD,CAcA,IAAME,GAAO,CAEZ,KAAMC,GAAKA,EAAE,YAAY,EAEzB,GAAKA,IAAMA,EAAE,YAAY,EAAE,IAAI,MAAM,CAAC,EAEtC,KAAM,CAACA,EAAGC,IAAUA,EAAM,KAAKD,EAAE,SAAS,CAAC,EAE3C,IAAK,CAACA,EAAGC,IAAUA,EAAM,IAAID,EAAE,SAAS,CAAC,EAEzC,GAAKA,GAAKJ,GAASI,EAAE,SAAS,EAAE,CAAC,EAEjC,EAAIA,GAAKA,EAAE,SAAS,EAAE,EAEtB,GAAKA,GAAKJ,GAASI,EAAE,QAAQ,CAAC,EAE9B,EAAIA,GAAKA,EAAE,QAAQ,EAEnB,KAAM,CAACA,EAAGC,IAAUA,EAAM,KAAKD,EAAE,OAAO,CAAC,EAEzC,IAAK,CAACA,EAAGC,IAAUA,EAAM,IAAID,EAAE,OAAO,CAAC,EAEvC,GAAKA,GAAKJ,GAASI,EAAE,SAAS,CAAC,EAE/B,EAAIA,GAAKA,EAAE,SAAS,EAEpB,EAAIA,GAAK,CAAC,IAAIE,EAAIF,EAAE,SAAS,EAAG,OAAOE,GAAK,EAAI,GAAKA,EAAI,GAAKA,EAAI,GAAKA,CAAE,EAEzE,GAAKF,GAAKA,EAAE,SAAS,GAAK,GAAK,KAAO,KAEtC,GAAKA,GAAKA,EAAE,SAAS,GAAK,GAAK,KAAO,KAEtC,EAAIA,GAAKA,EAAE,SAAS,GAAK,GAAK,IAAM,IAEpC,GAAKA,GAAKJ,GAASI,EAAE,WAAW,CAAC,EAEjC,EAAIA,GAAKA,EAAE,WAAW,EAEtB,GAAKA,GAAKJ,GAASI,EAAE,WAAW,CAAC,EAEjC,EAAIA,GAAKA,EAAE,WAAW,EAEtB,IAAKA,GAAKF,GAASE,EAAE,gBAAgB,CAAC,CACvC,EAEA,SAASG,GAAQC,EAAKH,EAAO,CAC5BA,EAAQA,GAASN,GACjB,IAAIU,EAAQ,CAAC,EAETC,EAAI,uBAAwBC,EAEhC,KAAOA,EAAID,EAAE,KAAKF,CAAG,GACpBC,EAAM,KAAKE,EAAE,CAAC,EAAE,CAAC,GAAK,IAAMR,GAAKQ,EAAE,CAAC,CAAC,EAAIA,EAAE,CAAC,CAAC,EAE9C,OAAOP,GAAK,CACX,IAAI7D,EAAM,GAEV,QAASxI,EAAI,EAAGA,EAAI0M,EAAM,OAAQ1M,IACjCwI,GAAO,OAAOkE,EAAM1M,CAAC,GAAK,SAAW0M,EAAM1M,CAAC,EAAI0M,EAAM1M,CAAC,EAAEqM,EAAGC,CAAK,EAElE,OAAO9D,CACR,CACD,CAEA,IAAMqE,GAAU,IAAI,KAAK,eAAe,EAAE,gBAAgB,EAAE,SAG5D,SAASC,GAAOC,EAAMC,EAAI,CACzB,IAAIC,EAGJ,OAAID,GAAM,OAASA,GAAM,UACxBC,EAAQ,IAAI,KAAK,CAACF,EAAOA,EAAK,kBAAkB,EAAI,GAAG,EAC/CC,GAAMH,GACdI,EAAQF,GAERE,EAAQ,IAAI,KAAKF,EAAK,eAAe,QAAS,CAAC,SAAUC,CAAE,CAAC,CAAC,EAC7DC,EAAM,gBAAgBF,EAAK,gBAAgB,CAAC,GAGtCE,CACR,CAMA,IAAMC,GAAYhN,GAAKA,EAAI,GAAK,EAE1BiN,GAAW,CAAC,EAAE,EAAE,IAAI,CAAC,EAGrBC,GAAW/F,GAAS,GAAI,IAAK,EAAG8F,EAAQ,EAGxCE,GAAWhG,GAAS,GAAI,EAAG,GAAI8F,EAAQ,EAGvCG,GAAaD,GAAS,OAAOH,EAAS,EAEtCK,GAAWH,GAAS,OAAOC,EAAQ,EAEnCG,GAAK;AAAA,EAELC,GAAU,SACVC,GAAUF,GAAKC,GACfE,GAAU,UACVC,GAAUJ,GAAKG,GACfE,GAAUD,GAAO,QAEjBE,GAAU,OACVC,GAAU,WACVC,GAAUD,GAAMD,GAChBG,GAAUT,GAAKQ,GACfE,GAAU,QAEV/H,GAAI,KAEV,SAASgI,GAAcC,EAAI,CAC1B,IAAIC,EAAKD,EAAK,IACbxB,EAAKyB,EAAK,GACV9B,EAAKK,EAAK,GACVP,EAAKE,EAAK,GACV+B,EAAKjC,EAAK,GACVkC,EAAKlC,EAAK,IAKPmC,GAFcJ,GAAM,EAAI/G,GAAS,GAAI,EAAG,EAAG8F,EAAQ,EAAE,OAAOD,EAAS,EAAI7F,GAAS,GAAI,GAAI,EAAG8F,EAAQ,GAE7E,OAAO,CAElCkB,EACAA,EAAI,EACJA,EAAI,GACJA,EAAI,GACJA,EAAI,GAEJzB,EACAA,EAAI,EACJA,EAAI,GACJA,EAAI,GACJA,EAAI,GAEJL,EACAA,EAAI,EACJA,EAAI,EACJA,EAAI,EACJA,EAAI,EACJA,EAAI,EACJA,EAAI,GAEJF,EACAA,EAAI,EACJA,EAAI,EACJA,EAAI,EACJA,EAAI,EACJA,EAAI,EACJA,EAAI,EACJA,EAAI,EACJA,EAAI,EACJA,EAAI,GACJA,EAAI,GAEJiC,EACAA,EAAK,EACLA,EAAK,EACLA,EAAK,EACLA,EAAK,EAELC,EACAA,EAAI,EACJA,EAAI,EACJA,EAAI,GACJA,EAAI,GACJA,EAAI,GACJA,EAAI,GACL,CAAC,EAMKE,EAAkB,CAEvB,CAACF,EAAad,GAAiBtH,GAAwBA,GAAQA,GAAsBA,GAAQA,GAAUA,GAAS,CAAC,EACjH,CAACkG,EAAI,GAAS,QAAiBqB,GAAwBvH,GAAQA,GAAsBA,GAAQA,GAAUA,GAAS,CAAC,EACjH,CAACkG,EAAasB,GAAiBD,GAAwBvH,GAAQA,GAAsBA,GAAQA,GAAUA,GAAS,CAAC,EACjH,CAACoG,EAAa,MAAQuB,GAASD,GAAwB1H,GAAQyH,GAAsBzH,GAAQA,GAAUA,GAAS,CAAC,EACjH,CAACyG,EAAaoB,GAAiBH,GAAwB1H,GAAQyH,GAAsBzH,GAAQA,GAAUA,GAAS,CAAC,EACjH,CAACkI,EAAaH,GAAiBL,GAAS,IAAMG,GAAS7H,GAAQyH,GAAO,IAAMI,GAAS7H,GAAQ8H,GAAU9H,GAAS,CAAC,EACjH,CAACiI,EAAaF,GAAK,SAAYL,GAAS,IAAMG,GAAS7H,GAAQyH,GAAO,IAAMI,GAAS7H,GAAQ8H,GAAU9H,GAAS,CAAC,CAClH,EAMA,SAASuI,EAAe5B,EAAQ,CAC/B,MAAO,CAAC6B,EAAMC,EAASC,EAAUC,EAAUC,EAAWC,IAAe,CACpE,IAAIC,EAAS,CAAC,EACVC,EAAOH,GAAaR,EACpBY,EAAOJ,GAAaT,GAAMS,EAAYR,EAGtCa,EAAUtC,EAAO+B,CAAQ,EACzBQ,EAAYpN,GAASmN,EAAUhB,EAAI,CAAC,EAGpCkB,EAASC,GAAOH,EAAQ,YAAY,EAAGF,EAAO,EAAIE,EAAQ,SAAS,EAAGD,GAAQD,EAAO,EAAIE,EAAQ,QAAQ,CAAC,EAC1GI,EAAWvN,GAASqN,EAASlB,EAAI,CAAC,EAEtC,GAAIe,GAAQD,EAAM,CACjB,IAAIO,EAASN,EAAOJ,EAAYT,EAAK,EACjCoB,EAASR,EAAOH,EAAYR,EAAK,EAEjCoB,EAAQN,GAAaG,EAAWH,EAAYpN,GAASsN,GAAOD,EAAO,YAAY,EAAII,EAAQJ,EAAO,SAAS,EAAIG,EAAQ,CAAC,EAAIrB,EAAI,CAAC,EACjIwB,EAAY,IAAI,KAAKxK,GAAMuK,EAAQvB,CAAE,CAAC,EACtCyB,EAAWD,EAAU,YAAY,EACjCE,EAAYF,EAAU,SAAS,EAEnC,QAAS5P,EAAI,EAAG2P,GAASb,EAAU9O,IAAK,CACvC,IAAI+P,GAAOR,GAAOM,EAAWH,EAAS1P,EAAG8P,EAAYL,EAASzP,EAAG,CAAC,EAC9DgQ,EAAOD,GAAOjD,EAAO7K,GAAS8N,GAAO3B,EAAI,CAAC,CAAC,EAE/CuB,EAAQ1N,IAAU,CAAC8N,GAAOC,GAAQ5B,EAAI,CAAC,EAEnCuB,GAASb,GACZG,EAAO,KAAKU,CAAK,CACnB,CACD,KACK,CACJ,IAAIM,EAAQlB,GAAa1C,EAAIA,EAAI0C,EAC7BmB,EAAW1Q,GAAMqP,CAAQ,EAAIrP,GAAM6P,CAAS,EAC5CM,EAAQH,EAAWU,EAAW/N,GAAYkN,EAAYG,EAAUS,CAAK,EACzEhB,EAAO,KAAKU,CAAK,EAEjB,IAAIQ,EAAQrD,EAAO6C,CAAK,EAEpBS,EAAWD,EAAM,SAAS,EAAKA,EAAM,WAAW,EAAIvD,EAAMuD,EAAM,WAAW,EAAI5D,EAC/E8D,EAAYtB,EAAYxC,EAExB+D,EAAW3B,EAAK,KAAKC,CAAO,EAAE,OAC9B2B,GAAWvB,EAAasB,EAE5B,KACCX,EAAQ1N,GAAS0N,EAAQZ,EAAWX,GAAM,EAAI,EAAI,CAAC,EAE/C,EAAAuB,EAAQb,IAGZ,GAAIuB,EAAY,EAAG,CAClB,IAAIG,EAAehR,GAAMyC,GAASmO,EAAWC,EAAW,CAAC,CAAC,EAAI,GAI1DI,GAHY3D,EAAO6C,CAAK,EACD,SAAS,EAERa,EAExBC,GAAW,IACdA,GAAW,IAEZd,GAASc,GAAWlE,EAEpB6D,GAAYA,EAAWC,GAAa,GAGpC,IAAIK,GAAYzB,EAAOA,EAAO,OAAS,CAAC,EAC1BhN,IAAU0N,EAAQe,IAAa3B,EAAW,CAAC,EAE3CwB,IAAY,IACzBtB,EAAO,KAAKU,CAAK,CACnB,MAECV,EAAO,KAAKU,CAAK,CAEpB,CAEA,OAAOV,CACR,CACD,CAEA,MAAO,CACNT,EACAC,EACAC,CACD,CACD,CAEA,GAAM,CAAEiC,GAAaC,GAAmBC,EAAiB,EAAI1C,GAAc,CAAC,EACtE,CAAE2C,GAAaC,GAAmBC,EAAiB,EAAI7C,GAAc,IAAI,EAG/E9G,GAAS,EAAG,IAAK,GAAI,CAAC,CAAC,CAAC,EAaxB,SAAS4J,GAAeC,EAAU1E,EAAS,CAC1C,OAAO0E,EAAS,IAAI7C,GAAKA,EAAE,IAAI,CAACnO,EAAGF,IAClCA,GAAK,GAAKA,GAAK,GAAKE,GAAK,KAAOA,EAAIsM,EAAQxM,GAAK,GAAKqO,EAAE,CAAC,GAAK,EAAInO,EAAImO,EAAE,CAAC,EAAInO,CAAC,CAC/E,CAAC,CACF,CAIA,SAASiR,GAAarE,EAAQsE,EAAQ,CACrC,MAAO,CAACzC,EAAMM,EAAQL,EAASI,EAAYD,IAAc,CACxD,IAAIV,EAAI+C,EAAO,KAAK/C,GAAKU,GAAaV,EAAE,CAAC,CAAC,GAAK+C,EAAOA,EAAO,OAAS,CAAC,EAGnEC,EACAC,EACAC,EACAnB,EACAoB,EACAC,EAEJ,OAAOxC,EAAO,IAAIU,GAAS,CAC1B,IAAI5C,EAAOD,EAAO6C,CAAK,EAEnB+B,EAAU3E,EAAK,YAAY,EAC3B4E,EAAU5E,EAAK,SAAS,EACxB6E,EAAU7E,EAAK,QAAQ,EACvB8E,EAAU9E,EAAK,SAAS,EACxB+E,EAAU/E,EAAK,WAAW,EAC1BgF,EAAUhF,EAAK,WAAW,EAE1BiF,EACHN,GAAWL,GAAYhD,EAAE,CAAC,GAC1BsD,GAAWL,GAAYjD,EAAE,CAAC,GAC1BuD,GAAWL,GAAYlD,EAAE,CAAC,GAC1BwD,GAAWzB,GAAY/B,EAAE,CAAC,GAC1ByD,GAAWN,GAAYnD,EAAE,CAAC,GAC1B0D,GAAWN,GAAYpD,EAAE,CAAC,GACHA,EAAE,CAAC,EAG3B,OAAAgD,EAAWK,EACXJ,EAAWK,EACXJ,EAAWK,EACXxB,EAAWyB,EACXL,EAAWM,EACXL,EAAWM,EAEJC,EAAMjF,CAAI,CAClB,CAAC,CACF,CACD,CAGA,SAASkF,GAAYnF,EAAQoF,EAAS,CACrC,IAAIF,EAAQxF,GAAQ0F,CAAO,EAC3B,MAAO,CAACvD,EAAMM,EAAQL,EAASI,EAAYD,IAAcE,EAAO,IAAIU,GAASqC,EAAMlF,EAAO6C,CAAK,CAAC,CAAC,CAClG,CAEA,SAASJ,GAAOhB,EAAG3B,EAAGP,EAAG,CACxB,OAAO,IAAI,KAAKkC,EAAG3B,EAAGP,CAAC,CACxB,CAEA,SAAS8F,GAAgBjB,EAAU1E,EAAS,CAC3C,OAAOA,EAAQ0E,CAAQ,CACxB,CACA,IAAMkB,GAAmB,gCAEzB,SAASC,GAAcvF,EAAQkF,EAAO,CACrC,MAAO,CAACrD,EAAM1J,EAAKqN,EAAWC,IAAYA,GAAW,KAAOzW,GAAckW,EAAMlF,EAAO7H,CAAG,CAAC,CAC5F,CAEA,SAASuN,GAAa7D,EAAM2D,EAAW,CACtC,IAAIjE,EAAIM,EAAK,OAAO2D,CAAS,EAC7B,OAAOjE,EAAE,MAAQA,EAAE,OAAOM,EAAM2D,CAAS,EAAIjE,EAAE,OAAO,MAAQA,EAAE,OAAO,OAAOM,EAAM2D,CAAS,EAAI,IAClG,CAEA,SAASG,GAAW9D,EAAM2D,EAAW,CACpC,OAAO3D,EAAK,OAAO2D,CAAS,EAAE,KAAK3D,EAAM2D,CAAS,CACnD,CAEA,IAAMI,GAAa,CAClB,KAAM,GACN,KAAM,GACN,QAAS,GACT,MAAO7M,GACP,QAAS,CACR,KAAM,GACN,MAAO,EACP,OAAQ2M,GACR,KAAMC,GACN,KAAM,OACP,EACA,IAAK,KACL,KAAM,KACN,OAAQ,CAAC,CACV,EAEA,SAASE,GAAgBhE,EAAMvE,EAAI,CAClC,IAAI,EAAIuE,EAAK,OAAO,OAEhBiE,EAAKtV,GAAS,EAEduV,EAAO,EAAE,KAAKlE,EAAMvE,CAAE,EAC1BtN,GAAW8V,EAAIhY,GAAOiY,CAAI,EAC1B/V,GAAW8V,EAAI/X,GAAQgY,CAAI,EAE3B,IAAIC,EAAMD,EAAO,GACjB/V,GAAW8V,EAAI,aAAcE,CAAG,EAChChW,GAAW8V,EAAI,YAAaE,CAAG,EAE/B,IAAIC,EAAQ,EAAE,MAAMpE,EAAMvE,EAAIyI,CAAI,EAClC,OAAAE,GAASjW,GAAW8V,EAAI,cAAeG,CAAK,EAErCH,CACR,CAEA,SAASI,GAAgBrE,EAAMvE,EAAI,CAClC,IAAI6I,EAAKtE,EAAK,OAAOvE,CAAE,EAAE,OACzB,OAAO6I,EAAG,OAASA,EAAG,OACvB,CAEA,SAASC,GAAkBvE,EAAMvE,EAAI,CACpC,IAAI6I,EAAKtE,EAAK,OAAOvE,CAAE,EAAE,OACzB,OAAO6I,EAAG,SAAWA,EAAG,KACzB,CAEA,SAASE,GAAgBxE,EAAMvE,EAAI,CAElC,OADSuE,EAAK,OAAOvE,CAAE,EAAE,OACf,IACX,CAEA,IAAMgJ,GAAY,CAAC,EAAE,CAAC,EAEtB,SAASC,GAAW1E,EAAM2E,EAAYC,EAAW,CAChD,OAAAH,GAAU,CAAC,EAAIE,EACfF,GAAU,CAAC,EAAIG,EACRH,EACR,CAEA,SAASI,GAAS7E,EAAMvR,EAAMqW,EAAQC,EAAW,GAAM,CACtD,OAAOC,GAAK,CACXA,EAAE,QAAU,IAAM,CAACD,GAAYC,EAAE,QAAUvW,IAASqW,EAAOE,CAAC,CAC7D,CACD,CAEA,SAASC,GAASjF,EAAMvR,EAAMqW,EAAQC,EAAW,GAAM,CACtD,OAAOC,GAAK,EACV,CAACD,GAAYC,EAAE,QAAUvW,IAASqW,EAAOE,CAAC,CAC5C,CACD,CAEA,IAAME,GAAa,CAClB,KAAM,GACN,EAAG,GACH,EAAG,GACH,KAAM,GACN,KAAMR,GACN,OAAQ,CACP,IAAQ,GACR,KAAQV,GACR,KAAQQ,GACR,MAAQ,EACR,OAAQD,GACR,KAAQF,EACT,EAEA,KAAM,CACL,UAAaQ,GACb,QAAaA,GACb,MAAaA,GACb,SAAaA,GAEb,UAAaI,GACb,WAAaA,GACb,WAAaA,EACd,EAEA,KAAM,CACL,SAAU,GACV,EAAG,GACH,EAAG,GACH,KAAM,EACN,IAAK,KACL,MAAO,CAACjF,EAAMgF,IAAM,CAEnBA,EAAE,gBAAgB,EAClBA,EAAE,yBAAyB,CAC5B,EACA,GAAI,GACJ,GAAI,EACL,EAEA,MAAO,CACN,KAAM,CAAChF,EAAM2D,EAAWC,EAASuB,EAAQC,IAAWD,EAASC,EAC7D,KAAM,GACN,KAAM,CACP,EAEA,MAAO,CACN,KAAM,CAAC,MAAM,EACb,KAAM,KACN,KAAM,CACP,EAEA,KAAM,IACN,IAAK,IACL,IAAK,KACL,QAAS,KACT,KAAM,KAEN,MAAO,IACR,EAEMC,GAAY,CACjB,KAAM,GACN,OAAQ,mBACR,MAAO,CAER,EAEMC,GAAOvL,GAAO,CAAC,EAAGsL,GAAW,CAClC,OAAQhO,EACT,CAAC,EAEKkO,GAAQxL,GAAO,CAAC,EAAGuL,GAAM,CAC9B,KAAM,EACP,CAAC,EAEKE,GAASzL,GAAO,CAAC,EAAGsL,GAAW,CACpC,KAAM,EACP,CAAC,EAEKI,GAAY,oLACZC,GAAY,QAAUD,GACtBE,GAAU,IAEVC,GAAY,CACjB,KAAM,GACN,MAAO,IACP,OAAQrZ,GACR,MAAO,GACP,IAAK,EACL,QAAS,EACT,KAAM,GACN,SAAU,EACV,UAAW,GACX,UAAAmZ,GACA,KAAM,EAKN,KAAAJ,GACA,MAAAC,GACA,OAAAC,GACA,KAAAC,GACA,QAAAE,GACA,OAAQ,CACT,EAEME,GAAiB,QACjBC,GAAkB,OAElBC,GAAc,CACnB,KAAM,GACN,MAAO,IACP,KAAM,GACN,OAAQ,EAKR,IAAK9T,GACL,IAAK,CAACA,GACN,KAAM,CAAC,CACR,EAEA,SAAS+T,GAAYhG,EAAMM,EAAQL,EAASI,EAAYD,EAAW,CAClE,OAAOE,EAAO,IAAI/O,GAAKA,GAAK,KAAO,GAAK8E,GAAO9E,CAAC,CAAC,CAClD,CAEA,SAAS0U,GAAcjG,EAAMC,EAASC,EAAUC,EAAUC,EAAWC,EAAY6F,EAAU,CAC1F,IAAI5F,EAAS,CAAC,EAEV6F,EAASnO,GAAS,IAAIoI,CAAS,GAAK,EAExCF,EAAWgG,EAAWhG,EAAW5M,GAASE,GAAY0M,EAAUE,CAAS,EAAG+F,CAAM,EAElF,QAAS7P,EAAM4J,EAAU5J,GAAO6J,EAAU7J,EAAMhD,GAASgD,EAAM8J,EAAW+F,CAAM,EAC/E7F,EAAO,KAAK,OAAO,GAAGhK,EAAK,EAAE,EAAI,EAAIA,CAAG,EAEzC,OAAOgK,CACR,CAGA,SAAS8F,GAAcpG,EAAMC,EAASC,EAAUC,EAAUC,EAAWC,EAAY6F,EAAU,CAC1F,IAAM5F,EAAS,CAAC,EAEV+F,EAAUrG,EAAK,OAAOA,EAAK,KAAKC,CAAO,EAAE,KAAK,EAAE,IAEhDvN,EAAQ2T,GAAW,GAAK1T,GAAQC,GAEhCwF,EAAMvH,GAAM6B,EAAMwN,CAAQ,CAAC,EAEjCE,EAAYhN,GAAIiT,EAASjO,CAAG,EAIxBiO,GAAW,KACdjG,EAAYxB,GAAStO,GAAW8P,EAAWxB,EAAQ,CAAC,GAErD,IAAIoC,EAAQd,EACRoG,EAAclG,EAAYiG,EAE1BA,GAAW,KACdC,EAAc1H,GAAStO,GAAWgW,EAAa1H,EAAQ,CAAC,GAEzD,GACC0B,EAAO,KAAKU,CAAK,EACjBA,EAAQA,EAAQZ,EAEZiG,GAAW,IAAM,CAACrO,GAAS,IAAIgJ,CAAK,IACvCA,EAAQ1N,GAAS0N,EAAOhJ,GAAS,IAAIoI,CAAS,CAAC,GAE5CY,GAASsF,IACZlG,EAAYY,EACZsF,EAAclG,EAAYiG,EAEtBA,GAAW,KACdC,EAAc1H,GAAStO,GAAWgW,EAAa1H,EAAQ,CAAC,UAElDoC,GAASb,GAElB,OAAOG,CACR,CAEA,SAASiG,GAAgBvG,EAAMC,EAASC,EAAUC,EAAUC,EAAWC,EAAY6F,EAAU,CAG5F,IAAIvP,EAFKqJ,EAAK,OAAOA,EAAK,KAAKC,CAAO,EAAE,KAAK,EAE1B,MAEfuG,EAAYrG,EAAWxJ,EAAYyP,GAAcpG,EAAMC,EAAS7N,GAAIuE,EAAWuJ,CAAQ,EAAGC,EAAUC,CAAS,EAAI,CAACzJ,CAAS,EAC3H8P,EAAOtG,GAAY,GAAKD,GAAY,EAAI,CAAC,CAAC,EAAI,CAAC,EAGnD,OAFgBA,EAAW,CAACvJ,EAAYyP,GAAcpG,EAAMC,EAAS7N,GAAIuE,EAAW,CAACwJ,CAAQ,EAAG,CAACD,EAAUE,CAAS,EAAG,CAACzJ,CAAS,GAEhH,QAAQ,EAAE,IAAIpF,GAAK,CAACA,CAAC,EAAE,OAAOkV,EAAMD,CAAS,CAC/D,CAEA,IAAME,GAAW,IACXC,GAAW,UACXC,GAAW,QACXC,GAAW,IAEXC,GAAQ,CAACxG,EAAQyG,EAAOC,EAAIC,IAAY3G,EAAO,IAAI,CAAC/O,EAAGF,IAAQ0V,GAAS,GAAKxV,GAAK,GAAMF,EAAI4V,GAAW,GAAKD,EAAG,KAAKzV,EAAE,cAAc,EAAEA,EAAI,EAAI,EAAI,CAAC,CAAC,EAAKA,EAAI,IAAI,EAEvK,SAAS2V,GAAkBlH,EAAMM,EAAQL,EAASI,EAAYD,EAAW,CACxE,IAAI+G,EAAOnH,EAAK,KAAKC,CAAO,EACxBmH,EAAWD,EAAK,MAChBE,EAAKrH,EAAK,OAAOoH,CAAQ,EAKzBE,EAAWtH,EAAK,SAEhB2B,EAAWwF,EAAK,OAEhBI,EAAMD,EAAS,GAAIF,CAAQ,EAE3BJ,EACHM,EAAS,EAAGF,CAAQ,EAAIG,GAAO5F,EAAW+E,GAC1CY,EAAS,EAAGF,CAAQ,EAAIG,GAAO5F,EAAWgF,GAC1CW,EAAS,EAAGF,CAAQ,EAAIG,GAAO5F,EAAWiF,GAC1CC,GAGD,GAAIG,GAAMH,GAAM,CACf,IAAIW,EAAWvU,GAAIqU,EAAS,EAAGF,CAAQ,EAAIG,CAAG,EAE9C,GAAIC,EAAW7F,EACd,OAAOmF,GAAMxG,EAAO,MAAM,EAAE,QAAQ,EAAG+G,EAAG,MAAOL,EAAIlU,GAAK6O,EAAW6F,CAAQ,CAAC,EAAE,QAAQ,CAC1F,CAEA,OAAOV,GAAMxG,EAAQ+G,EAAG,MAAOL,EAAI,CAAC,CACrC,CAEA,SAASS,GAAiBzH,EAAMM,EAAQL,EAASI,EAAYD,EAAW,CACvE,IAAI+G,EAAOnH,EAAK,KAAKC,CAAO,EACxBmH,EAAWD,EAAK,MAChBxF,EAAWwF,EAAK,OAChBG,EAAWtH,EAAK,SAEhBwH,EAAWvU,GAAIqU,EAAS,EAAGF,CAAQ,EAAIE,EAAS,EAAGF,CAAQ,CAAC,EAEhE,OAAII,EAAW7F,EACPmF,GAAMxG,EAAO,MAAM,EAAE,QAAQ,EAAG,EAAGoG,GAAQ5T,GAAK6O,EAAW6F,CAAQ,CAAC,EAAE,QAAQ,EAE/ElH,CACR,CAEA,SAASoH,GAAa1H,EAAM1J,EAAKqN,EAAWC,EAAS,CACpD,OAAOA,GAAW,KAAOzW,GAAcmJ,GAAO,KAAO,GAAKD,GAAOC,CAAG,CACrE,CAEA,IAAMqR,GAAY,CACjB,KAAM,GACN,MAAO,IACP,OAAQpb,GACR,MAAO,GACP,IAAK,EACL,QAAS,EACT,KAAM,GACN,SAAU,EACV,UAAW,GACX,UAAAmZ,GACA,KAAM,EAKN,KAAAJ,GACA,MAAAC,GACA,OAAAC,GACA,KAAAC,GACA,QAAAE,GACA,OAAQ,CACT,EAGA,SAASiC,GAAMxD,EAAOpQ,EAAM,CAC3B,IAAI6T,EAAM,GAAKzD,GAAS,GAAK,EAC7B,OAAO9Q,GAASuU,EAAM7T,EAAM,CAAC,CAC9B,CAEA,SAAS8T,GAAiB9H,EAAMvE,EAAI,CACnC,GAAI,CAAE,MAAAsM,EAAO,KAAA7L,CAAK,EAAI8D,EAAK,OAAO,CAAC,EAC/BgI,EAAQhI,EAAK,MAAM,CAAC,EACpBiI,EAAKjI,EAAK,SAASgI,EAAM9L,EAAK,CAAC,CAAC,EAAG6L,EAAO,EAAI,EAC9CG,EAAKlI,EAAK,SAASgI,EAAM9L,EAAK,CAAC,CAAC,EAAG6L,EAAO,EAAI,EAC9CI,EAAMlV,GAAIiV,EAAKD,CAAE,EAEjBvI,EAAIM,EAAK,OAAOvE,CAAE,EAElB2M,EAASD,GAAOzI,EAAE,OAAO,MAAQlS,IACrC,OAAO0O,EAAK,CAAC,EAAIA,EAAK,CAAC,GAAKkM,CAC7B,CAEA,IAAMC,GAAQ,CACb,MAAO,KACP,KAAM,GACN,OAAQ,EAGR,IAAKpW,GACL,IAAK,CAACA,EACP,EAEMqW,GAAO,CAACtI,EAAM2D,EAAWnP,EAAMC,EAAM8T,IAAaA,EAElDC,GAAe,CACpB,KAAM,GACN,KAAM,GACN,OAAQ,EACR,KAAAF,GACA,MAAO,EACP,OAAQ,CACPvO,GAAO,CAAC,EAAGsO,GAAO,CAAC,MAAO,GAAG,CAAC,EAC9BtO,GAAO,CAAC,EAAGsO,GAAO,CAAC,MAAO,GAAG,CAAC,CAC/B,CACD,EAEMI,GAAc,CACnB,MAAO,IACP,KAAM,GACN,OAAQ,EACR,KAAM,GACN,SAAU,GACV,KAAAH,GACA,MAAO,EACP,OAAQ,CACP,KAAMR,GACN,OAAQ,IAMT,EAGA,OAAQ,KAGR,IAAK7V,GACL,IAAK,CAACA,GACN,KAAM,CAAC,EAEP,KAAM,KACN,KAAM,IACP,EAEA,SAASyW,GAAW1I,EAAM1J,EAAK4J,EAAUC,EAAUiH,EAAU,CAS5D,OAAOlH,EAAW,EACnB,CAEA,IAAMyI,GAAa,CAClB,KAAM,GACN,KAAM,GACN,MAAO,EACP,IAAK,GACL,MAAO,EACP,IAAK,KACL,IAAK,KACL,IAAK,EACL,IAAK,CACN,EAEMC,GAAa7O,GAAO,CAAC,EAAG4O,GAAY,CACzC,KAAM,GACN,IAAK,CACN,CAAC,EAEKE,GAAQ,CAAC,EAEf,SAASC,GAAM5O,EAAK6O,EAAM,CACzB,IAAIrJ,EAAImJ,GAAM3O,CAAG,EAEjB,OAAKwF,IACJA,EAAI,CACH,IAAAxF,EACA,MAAO,CAAC,EACR,IAAI8O,EAAM,CACTtJ,EAAE,MAAM,KAAKsJ,CAAI,CAClB,EACA,MAAMA,EAAM,CACXtJ,EAAE,MAAQA,EAAE,MAAM,OAAO1R,GAAKA,GAAKgb,CAAI,CACxC,EACA,IAAIC,EAAMjJ,EAAMlJ,EAAG8I,EAAGsJ,EAAGtL,EAAGvM,EAAG,CAC9B,QAASiL,EAAI,EAAGA,EAAIoD,EAAE,MAAM,OAAQpD,IACnCoD,EAAE,MAAMpD,CAAC,GAAK0D,GAAQN,EAAE,MAAMpD,CAAC,EAAE,IAAI2M,EAAMjJ,EAAMlJ,EAAG8I,EAAGsJ,EAAGtL,EAAGvM,CAAC,CAChE,CACD,EAEI6I,GAAO,OACV2O,GAAM3O,CAAG,EAAIwF,IAGRA,CACR,CAEA,IAAMyJ,GAAmB,EACnBC,GAAmB,EAEzB,SAASC,GAAOC,EAAG3F,EAAWvT,EAAI,CACjC,IAAMmZ,EAAOD,EAAE,KACTE,EAASF,EAAE,OAAO3F,CAAS,EAC3B3S,EAAOuY,GAAQ,EAAID,EAAE,MAAM3F,CAAS,EAAI2F,EAAE,MAC1CG,EAASH,EAAE,OACXI,EAASJ,EAAE,KAEbK,EAAK3Y,EAAK,CAAC,EACd4Y,EAAKL,GAAQ,EAAIvY,EAAK,CAAC,EAAIA,EAAK2S,CAAS,EACzCkG,EAAKN,GAAQ,EAAIE,EAAOD,EAAO,OAAO,CAAC,EAAE,KAAK,EAAIC,EAAOH,EAAE,OAAO,CAAC,EAAE,KAAK,EAC1EQ,EAAKP,GAAQ,EAAIE,EAAOD,EAAO,OAAO,CAAC,EAAE,KAAK,EAAIC,EAAOD,EAAO,KAAK,EACrEO,EAAIL,EAAK,KACTlO,EAAIkO,EAAK,IACTR,EAAIQ,EAAK,MACT9L,EAAI8L,EAAK,OACTM,EAAIV,EAAE,UACNW,EAAIX,EAAE,UAEP,OAAQO,EAAG,KAAO,EACfzZ,EACDoZ,EACAG,EACAC,EACAC,EACAC,EACAE,EACAC,EACAF,EACAvO,EACA0N,EACAtL,EACAsM,GACAC,GACAC,GACAC,GACAC,EACD,EACEla,EACDoZ,EACAG,EACAC,EACAC,EACAC,EACAG,EACAD,EACAxO,EACAuO,EACAnM,EACAsL,EACAqB,GACAC,GACAC,GACAC,GACAC,EACD,CAEF,CAEA,SAASC,GAAiB5K,EAAM2D,EAAW,CAC1C,IAAIkH,EAAU,EAGVC,EAAW,EAEXC,EAAQ3W,GAAO4L,EAAK,MAAO/G,EAAS,EAExC,QAAS5H,EAAI,EAAGA,EAAI0Z,EAAM,OAAQ1Z,IAAK,CACtC,IAAIuG,EAAImT,EAAM1Z,CAAC,EAGXuG,EAAE,OAAO,CAAC,GAAK+L,EAClBkH,EAAUjT,EAAE,IAEJA,EAAE,OAAO,CAAC,GAAK+L,IACnB/L,EAAE,KAAO,EACZkT,GAAY,EAEZA,GAAY,EAEf,CAEA,MAAO,CACND,EAECC,GAAY,EAAI,GAChBA,GAAY,EAAK,EACjBA,GAAY,EAAK,EACA,CAEnB,CACD,CAEA,SAASE,GAAahL,EAAM2D,EAAWsH,EAASC,EAASC,EAAa,CACrE,IAAI5B,EAAOvJ,EAAK,KACZwJ,EAASxJ,EAAK,OAAO2D,CAAS,EAC9ByD,EAAWmC,GAAQ,EAAIC,EAAO,OAAO,CAAC,EAAE,MAAQA,EAAO,MACvDzB,EAAQ/H,EAAK,OAAOoH,CAAQ,EAEhC,OACC+D,GAAe,GAAKpD,EAAM,IAC1BoD,GAAgB,EAAIpD,EAAM,IAC1BA,EAAM,OAAU,EACfA,EAAM,KAAO,EAAIA,EAAM,IACvBA,EAAM,IACH,CAEN,CAKA,SAASqD,GAAapL,EAAM2D,EAAWnP,EAAMC,EAAM4W,EAAYC,EAAS,CACvE,OAAOjC,GAAOrJ,EAAM2D,EAAW,CAAC6F,EAAQ+B,EAAOC,EAAOC,EAAQC,EAAQC,EAAWC,EAAWC,EAAMC,EAAMC,EAAMC,IAAS,CACtH,IAAIC,EAAUzC,EAAO,QAEf0C,EAAMT,EAAO,KAAOA,EAAO,KAAO,EAAI,EAAI,IAC1CU,EAASV,EAAO,KAAO,EAAItB,GAAUK,GAEvC4B,EAAOC,EAEPH,GAAO,GACVE,EAAQ5X,EACR6X,EAAQ5X,IAGR2X,EAAQ3X,EACR4X,EAAQ7X,GAIT,IAAI8X,EAAKL,EAAQN,EAAUJ,EAAMa,CAAK,EAAGX,EAAQM,EAAMF,CAAI,CAAC,EACxDU,EAAKN,EAAQL,EAAUJ,EAAMY,CAAK,EAAGV,EAAQM,EAAMF,CAAI,CAAC,EAExDU,EAAKP,EAAQN,EAAUJ,EAAMc,CAAK,EAAGZ,EAAQM,EAAMF,CAAI,CAAC,EAExDY,EAASR,EAAQL,EAAUN,GAAW,EAAII,EAAO,IAAMA,EAAO,IAAKA,EAAQM,EAAMF,CAAI,CAAC,EAEtFY,EAAO,IAAI,OAAOrB,CAAU,EAEhC,OAAAc,EAAOO,EAAMF,EAAIC,CAAM,EACvBN,EAAOO,EAAMJ,EAAIG,CAAM,EACvBN,EAAOO,EAAMJ,EAAIC,CAAE,EAEZG,CACR,CAAC,CACF,CAEA,SAASC,GAASrE,EAAMsE,EAAKC,EAASC,EAASC,EAASC,EAAS,CAChE,IAAIN,EAAO,KAGX,GAAIpE,EAAK,OAAS,EAAG,CACpBoE,EAAO,IAAI,OAEX,IAAMO,EAAOL,GAAO,EAAIxC,GAAQK,GAE5ByC,EAAaL,EAEjB,QAASxb,EAAI,EAAGA,EAAIiX,EAAK,OAAQjX,IAAK,CACrC,IAAI8b,EAAI7E,EAAKjX,CAAC,EAEd,GAAI8b,EAAE,CAAC,EAAIA,EAAE,CAAC,EAAG,CAChB,IAAIjE,EAAIiE,EAAE,CAAC,EAAID,EAEfhE,EAAI,GAAK+D,EAAKP,EAAMQ,EAAYJ,EAAS5D,EAAG4D,EAAUE,CAAO,EAE7DE,EAAaC,EAAE,CAAC,CACjB,CACD,CAEA,IAAIjE,EAAI2D,EAAUE,EAAUG,EAGxBE,EAAiB,GAErBlE,EAAI,GAAK+D,EAAKP,EAAMQ,EAAYJ,EAAUM,EAAiB,EAAGlE,EAAG4D,EAAUE,EAAUI,CAAc,CACpG,CAEA,OAAOV,CACR,CAEA,SAASW,GAAO/E,EAAMgF,EAAOC,EAAK,CACjC,IAAIC,EAAUlF,EAAKA,EAAK,OAAS,CAAC,EAE9BkF,GAAWA,EAAQ,CAAC,GAAKF,EAC5BE,EAAQ,CAAC,EAAID,EAEbjF,EAAK,KAAK,CAACgF,EAAOC,CAAG,CAAC,CACxB,CAEA,SAASE,GAASnS,EAAII,EAAIlH,EAAMC,EAAMyX,EAAKwB,EAAWC,EAAO,CAC5D,IAAIrF,EAAO,CAAC,EACRnQ,EAAMmD,EAAG,OAEb,QAASjK,EAAI6a,GAAO,EAAI1X,EAAOC,EAAMpD,GAAKmD,GAAQnD,GAAKoD,EAAMpD,GAAK6a,EAGjE,GAFWxQ,EAAGrK,CAAC,IAEF,KAAM,CAClB,IAAIuc,EAAKvc,EAAGwc,EAAKxc,EAEjB,GAAI6a,GAAO,EACV,KAAO,EAAE7a,GAAKoD,GAAQiH,EAAGrK,CAAC,IAAM,MAC/Bwc,EAAKxc,MAGN,MAAO,EAAEA,GAAKmD,GAAQkH,EAAGrK,CAAC,IAAM,MAC/Bwc,EAAKxc,EAGP,IAAIyc,EAAOJ,EAAUpS,EAAGsS,CAAE,CAAC,EACvBG,EAAOF,GAAMD,EAAKE,EAAOJ,EAAUpS,EAAGuS,CAAE,CAAC,EAIzCG,EAAOJ,EAAK1B,EAKf4B,EAJWH,GAAS,GAAKK,GAAQ,GAAKA,EAAO7V,EAAMuV,EAAUpS,EAAG0S,CAAI,CAAC,EAAIF,EAM1E,IAAIG,EAAOJ,EAAK3B,EAKf6B,EAJWJ,GAAS,GAAKM,GAAQ,GAAKA,EAAO9V,EAAMuV,EAAUpS,EAAG2S,CAAI,CAAC,EAAIF,EAMtEA,GAAQD,GACXxF,EAAK,KAAK,CAACwF,EAAMC,CAAI,CAAC,CACxB,CAGD,OAAOzF,CACR,CAEA,SAAS4F,GAAWC,EAAS,CAC5B,OAAOA,GAAW,EAAIhX,GAAUgX,GAAW,EAAI1X,GAAQlF,GAAK8G,GAAU9G,EAAG4c,CAAO,CACjF,CAeA,SAASlB,GAAKL,EAAK,CAClB,IAAIwB,EAASxB,GAAO,EACnB1C,GACAK,GAEG8D,EAAQzB,GAAO,EAClB,CAACpU,EAAGgU,EAAI8B,EAAIC,EAAIC,EAAIC,IAAM,CAAEjW,EAAE,MAAMgU,EAAI8B,EAAIC,EAAIC,EAAIC,CAAC,CAAG,EACxD,CAACjW,EAAG8V,EAAI9B,EAAIgC,EAAID,EAAIE,IAAM,CAAEjW,EAAE,MAAMgU,EAAI8B,EAAIC,EAAIC,EAAIC,CAAC,CAAG,EAErDxB,EAAOL,GAAO,EACjB,CAACpU,EAAG1B,EAAG8I,EAAGsJ,EAAGtL,IAAM,CAAEpF,EAAE,KAAK1B,EAAG8I,EAAGsJ,EAAGtL,CAAC,CAAG,EACzC,CAACpF,EAAGoH,EAAG9I,EAAG,EAAGoS,IAAM,CAAE1Q,EAAE,KAAK1B,EAAG8I,EAAGsJ,EAAG,CAAC,CAAG,EAG1C,MAAO,CAAC1Q,EAAG1B,EAAG8I,EAAGsJ,EAAGtL,EAAG8Q,EAAS,EAAGC,EAAU,IAAM,CAC9CD,GAAU,GAAKC,GAAW,EAC7B1B,EAAKzU,EAAG1B,EAAG8I,EAAGsJ,EAAGtL,CAAC,GAElB8Q,EAAUvc,GAAIuc,EAASxF,EAAI,EAAGtL,EAAI,CAAC,EACnC+Q,EAAUxc,GAAIwc,EAASzF,EAAI,EAAGtL,EAAI,CAAC,EAGnCwQ,EAAO5V,EAAG1B,EAAI4X,EAAQ9O,CAAC,EACvByO,EAAM7V,EAAG1B,EAAIoS,EAAGtJ,EAAG9I,EAAIoS,EAAGtJ,EAAIhC,EAAG8Q,CAAM,EACvCL,EAAM7V,EAAG1B,EAAIoS,EAAGtJ,EAAIhC,EAAG9G,EAAG8I,EAAIhC,EAAG+Q,CAAO,EACxCN,EAAM7V,EAAG1B,EAAG8I,EAAIhC,EAAG9G,EAAG8I,EAAG+O,CAAO,EAChCN,EAAM7V,EAAG1B,EAAG8I,EAAG9I,EAAIoS,EAAGtJ,EAAG8O,CAAM,EAC/BlW,EAAE,UAAU,EAEd,CACD,CAGA,IAAM0R,GAAU,CAAC1R,EAAG1B,EAAG8I,IAAM,CAAEpH,EAAE,OAAO1B,EAAG8I,CAAC,CAAG,EACzC2K,GAAU,CAAC/R,EAAGoH,EAAG9I,IAAM,CAAE0B,EAAE,OAAO1B,EAAG8I,CAAC,CAAG,EACzCuK,GAAU,CAAC3R,EAAG1B,EAAG8I,IAAM,CAAEpH,EAAE,OAAO1B,EAAG8I,CAAC,CAAG,EACzC4K,GAAU,CAAChS,EAAGoH,EAAG9I,IAAM,CAAE0B,EAAE,OAAO1B,EAAG8I,CAAC,CAAG,EACzCwK,GAAQ6C,GAAK,CAAC,EACdxC,GAAQwC,GAAK,CAAC,EACd5C,GAAO,CAAC7R,EAAG1B,EAAG8I,EAAG6O,EAAGG,EAAYC,IAAa,CAAErW,EAAE,IAAI1B,EAAG8I,EAAG6O,EAAGG,EAAYC,CAAQ,CAAG,EACrFnE,GAAO,CAAClS,EAAGoH,EAAG9I,EAAG2X,EAAGG,EAAYC,IAAa,CAAErW,EAAE,IAAI1B,EAAG8I,EAAG6O,EAAGG,EAAYC,CAAQ,CAAG,EACrFvE,GAAiB,CAAC9R,EAAGsW,EAAMC,EAAMC,EAAMC,EAAMC,EAAKC,IAAQ,CAAE3W,EAAE,cAAcsW,EAAMC,EAAMC,EAAMC,EAAMC,EAAKC,CAAG,CAAG,EAC/GxE,GAAiB,CAACnS,EAAGuW,EAAMD,EAAMG,EAAMD,EAAMG,EAAKD,IAAQ,CAAE1W,EAAE,cAAcsW,EAAMC,EAAMC,EAAMC,EAAMC,EAAKC,CAAG,CAAG,EAGrH,SAASC,GAAOrG,EAAM,CACrB,MAAO,CAACO,EAAG3F,EAAWnP,EAAMC,EAAM4a,IAG1BhG,GAAOC,EAAG3F,EAAW,CAAC6F,EAAQ+B,EAAOC,EAAOC,EAAQC,EAAQC,EAAWC,EAAWC,EAAMC,EAAMC,EAAMC,IAAS,CACnH,GAAI,CAAE,QAAAC,EAAS,OAAAmD,CAAO,EAAI5F,EAEtB4E,EAAQkB,EAER7D,EAAO,KAAO,GACjB2C,EAASlE,GACToF,EAAMjF,KAGN+D,EAAS7D,GACT+E,EAAM5E,IAGP,IAAMtG,EAAQ9Q,GAAS8b,EAAO,MAAQ5hB,GAAS,CAAC,EAE5C+hB,GAAOH,EAAO,KAAOA,EAAO,OAAS,EAAI5hB,GACzCqa,EAAMvU,GAASic,EAAM,EAAG,CAAC,EAEzBC,EAAO,IAAI,OACX9C,EAAO,IAAI,OAEX,CAAE,KAAM+C,EAAK,IAAKC,EAAK,MAAOC,EAAK,OAAQC,CAAI,EAAItG,EAAE,KAEzDc,GAAMsC,EACL+C,EAAM5H,EACN6H,EAAM7H,EACN8H,EAAM9H,EAAM,EACZ+H,EAAM/H,EAAM,CACb,EAEA,IAAMgI,EAAYC,GAAM,CACvB,GAAItE,EAAMsE,CAAE,GAAK,KAAM,CACtB,IAAIhZ,GAAImV,EAAQN,EAAUJ,EAAMuE,CAAE,EAAGrE,EAAQM,EAAMF,CAAI,CAAC,EACpDjM,EAAIqM,EAAQL,EAAUJ,EAAMsE,CAAE,EAAGpE,EAAQM,EAAMF,CAAI,CAAC,EAExDsC,EAAOoB,EAAM1Y,GAAIyY,EAAK3P,CAAC,EACvB0P,EAAIE,EAAM1Y,GAAG8I,EAAG2P,EAAK,EAAG/Y,GAAK,CAAC,CAC/B,CACD,EAEA,GAAI6Y,EACHA,EAAS,QAAQQ,CAAS,MAE1B,SAASC,EAAKtb,EAAMsb,GAAMrb,EAAMqb,IAC/BD,EAAUC,CAAE,EAGd,MAAO,CACN,OAAQ1L,EAAQ,EAAIoL,EAAO,KAC3B,KAAAA,EACA,KAAA9C,EACA,MAAOvD,GAAiBC,EACzB,CACD,CAAC,CAEH,CAEA,SAAS2G,GAAS5D,EAAQ,CACzB,MAAO,CAAC6D,EAAQC,EAAMC,EAAMC,EAAMC,EAAKC,IAAS,CAC3CH,GAAQC,IACPC,GAAOF,GAAQG,GAAQH,GAC1B/D,EAAO6D,EAAQC,EAAMC,CAAI,EACtBE,GAAOD,GAAQE,GAAQF,GAC1BhE,EAAO6D,EAAQC,EAAME,CAAI,EAE1BhE,EAAO6D,EAAQC,EAAMI,CAAI,EAE3B,CACD,CAEA,IAAMC,GAAWP,GAAS5F,EAAO,EAC3BoG,GAAWR,GAASvF,EAAO,EAEjC,SAASgG,GAAOzH,EAAM,CACrB,IAAM0H,EAAYrc,GAAO2U,GAAM,UAAW,CAAC,EAE3C,MAAO,CAACO,EAAG3F,EAAWnP,EAAMC,IACpB4U,GAAOC,EAAG3F,EAAW,CAAC6F,EAAQ+B,EAAOC,EAAOC,EAAQC,EAAQC,EAAWC,EAAWC,EAAMC,EAAMC,EAAMC,IAAS,CACnH,CAACxX,EAAMC,CAAI,EAAIhD,GAAY+Z,EAAOhX,EAAMC,CAAI,EAE5C,IAAIwX,EAAUzC,EAAO,QAEjBkE,EAAYpX,GAAO2V,EAAQN,EAAUrV,EAAKmV,EAAQM,EAAMF,CAAI,CAAC,EAC7D6E,EAAYpa,GAAO2V,EAAQL,EAAUtV,EAAKoV,EAAQM,EAAMF,CAAI,CAAC,EAE7DK,EAAQwE,EAERlF,EAAO,KAAO,GACjBU,EAAShC,GACTwG,EAAUL,KAGVnE,EAAS3B,GACTmG,EAAUJ,IAGX,IAAMrE,EAAMT,EAAO,KAAOA,EAAO,KAAO,EAAI,EAAI,IAE1CmF,EAAS,CAAC,OAAQ,IAAI,OAAU,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,MAAOzH,EAAc,EACrG6G,EAASY,EAAO,OAElBC,EAAS,GAKb,GAFiBpc,EAAOD,GAAQuX,EAAO,EAEzB,CACb,IAAI+E,EAAYC,GAAOzH,EAAE,SAASyH,EAAKtF,EAAO,IAAK,EAAI,EAEnDyE,EAAO,KACVC,EAAO,KACPC,GAAKC,EAAMW,GAERf,GAAOvC,EAAUnC,EAAMW,GAAO,EAAI1X,EAAOC,CAAI,CAAC,EAE9Cwc,GAASvD,EAAUnC,EAAM/W,CAAI,CAAC,EAC9B0c,GAASxD,EAAUnC,EAAM9W,CAAI,CAAC,EAG9B0c,EAAcL,EAAU5E,GAAO,EAAI+E,GAAS,EAAIC,GAAS,CAAC,EAE9D,QAAS7f,EAAI6a,GAAO,EAAI1X,EAAOC,EAAMpD,GAAKmD,GAAQnD,GAAKoD,EAAMpD,GAAK6a,EAAK,CACtE,IAAIkF,GAAO7F,EAAMla,CAAC,EAEdyF,IADYoV,GAAO,EAAKkF,GAAOD,EAAgBC,GAAOD,GACtClB,GAAQvC,EAAU0D,EAAI,EAEtCxV,GAAO4P,EAAMna,CAAC,EAEdyF,IAAKmZ,GACJrU,IAAQ,MACXyU,EAAOzU,GAEHsU,GAAQ,MACX/D,EAAO6D,EAAQlZ,GAAG4Z,EAAUL,CAAI,CAAC,EACjCD,GAAMF,EAAOC,EAAOE,GAEhBA,EAAOH,EACVA,EAAOG,EACCA,EAAOF,IACfA,EAAOE,IAILzU,KAAS,OACZiV,EAAS,KAIPX,GAAQ,MACXS,EAAQX,EAAQC,GAAMS,EAAUR,CAAI,EAAGQ,EAAUP,CAAI,EAAGO,EAAUN,EAAG,EAAGM,EAAUL,CAAI,CAAC,EAEpFzU,IAAQ,MACXyU,EAAOzU,GACPuQ,EAAO6D,EAAQlZ,GAAG4Z,EAAUL,CAAI,CAAC,EACjCH,EAAOC,EAAOC,GAAMC,IAGpBH,EAAOC,EAAO,KAEVvU,KAAS,OACZiV,EAAS,KAGXZ,GAAOnZ,GACPqa,EAAcL,EAAUb,GAAO/D,CAAG,EAEpC,CAEIgE,GAAQ,MAAQA,GAAQC,GAAQa,IAAYf,IAC/CU,EAAQX,EAAQC,GAAMS,EAAUR,CAAI,EAAGQ,EAAUP,CAAI,EAAGO,EAAUN,EAAG,EAAGM,EAAUL,CAAI,CAAC,CACzF,KAEC,SAAShf,EAAI6a,GAAO,EAAI1X,EAAOC,EAAMpD,GAAKmD,GAAQnD,GAAKoD,EAAMpD,GAAK6a,EAAK,CACtE,IAAItQ,EAAO4P,EAAMna,CAAC,EAEduK,IAAS,KACZiV,EAAS,GACDjV,GAAQ,MAChBuQ,EAAO6D,EAAQtC,EAAUnC,EAAMla,CAAC,CAAC,EAAGqf,EAAU9U,CAAI,CAAC,CACrD,CAGD,GAAI,CAAEuP,EAAakG,CAAY,EAAIzG,GAAiBtB,EAAG3F,CAAS,EAEhE,GAAI6F,EAAO,MAAQ,MAAQ2B,GAAe,EAAG,CAC5C,IAAIqE,EAAOoB,EAAO,KAAO,IAAI,OAAOZ,CAAM,EAEtCsB,EAAY9H,EAAO,OAAOF,EAAG3F,EAAW6F,EAAO,IAAKA,EAAO,IAAK2B,CAAW,EAC3EoG,EAAUb,EAAUY,CAAS,EAE7BE,GAAM9D,EAAUnC,EAAM/W,CAAI,CAAC,EAC3B+Y,EAAMG,EAAUnC,EAAM9W,CAAI,CAAC,EAE3ByX,GAAO,KACV,CAACqB,EAAKiE,EAAG,EAAI,CAACA,GAAKjE,CAAG,GAEvBpB,EAAOqD,EAAMjC,EAAKgE,CAAO,EACzBpF,EAAOqD,EAAMgC,GAAKD,CAAO,CAC1B,CAEA,GAAI,CAAC/H,EAAO,SAAU,CAErB,IAAIlB,EAAO,CAAC,EAEZuI,GAAUvI,EAAK,KAAK,GAAGmF,GAASlC,EAAOC,EAAOhX,EAAMC,EAAMyX,EAAKwB,EAAW+C,CAAS,CAAC,EAMpFG,EAAO,KAAOtI,EAAOkB,EAAO,KAAKF,EAAG3F,EAAWnP,EAAMC,EAAM6T,CAAI,EAE/DsI,EAAO,KAAOjE,GAASrE,EAAMmD,EAAO,IAAKI,EAAMC,EAAMC,EAAMC,CAAI,CAChE,CAEA,OAAIqF,GAAe,IAClBT,EAAO,KAAOS,GAAe,EAAI,CAChCjG,GAAa9B,EAAG3F,EAAWnP,EAAMC,EAAMub,EAAQ,EAAE,EACjD5E,GAAa9B,EAAG3F,EAAWnP,EAAMC,EAAMub,EAAS,CAAC,CAClD,EAAI5E,GAAa9B,EAAG3F,EAAWnP,EAAMC,EAAMub,EAAQqB,CAAW,GAGxDT,CACR,CAAC,CAEH,CAGA,SAASa,GAAQ1I,EAAM,CACtB,IAAM4E,EAAQvZ,GAAO2U,EAAK,MAAO,CAAC,EAE5B2I,EAAUtd,GAAO2U,EAAK,QAAS,EAAK,EACpC0H,EAAYrc,GAAO2U,EAAK,UAAW,CAAC,EACpC4I,EAASvd,GAAO2U,EAAK,OAAQ,EAAK,EAExC,MAAO,CAACO,EAAG3F,EAAWnP,EAAMC,IACpB4U,GAAOC,EAAG3F,EAAW,CAAC6F,EAAQ+B,EAAOC,EAAOC,EAAQC,EAAQC,EAAWC,EAAWC,EAAMC,EAAMC,EAAMC,IAAS,CACnH,CAACxX,EAAMC,CAAI,EAAIhD,GAAY+Z,EAAOhX,EAAMC,CAAI,EAE5C,IAAIwX,EAAUzC,EAAO,QAEjB,CAAE,KAAAoI,EAAM,MAAAxN,CAAM,EAAIkF,EAAE,KAEpBoE,EAAYpX,IAAO2V,EAAQN,EAAUrV,GAAKmV,EAAQM,EAAMF,CAAI,CAAC,EAC7D6E,EAAYpa,IAAO2V,EAAQL,EAAUtV,GAAKoV,EAAQM,EAAMF,CAAI,CAAC,EAE7DK,EAASV,EAAO,KAAO,EAAItB,GAAUK,GAEnCoG,EAAS,CAAC,OAAQ,IAAI,OAAU,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,MAAOzH,EAAc,EACrG6G,EAASY,EAAO,OAEhB1E,EAAMT,EAAO,KAAOA,EAAO,KAAO,EAAI,EAAI,IAE5CoG,EAAYnB,EAAUlF,EAAMU,GAAO,EAAI1X,EAAOC,CAAI,CAAC,EACnDqd,EAAYpE,EAAUnC,EAAMW,GAAO,EAAI1X,EAAOC,CAAI,CAAC,EACnDsd,EAAWD,EAEXE,GAAeF,EAEfH,GAAUhE,GAAS,KACtBqE,GAAeJ,EACfzF,EAAO6D,EAAQgC,GAAcH,CAAQ,GAGtC1F,EAAO6D,EAAQ8B,EAAWD,CAAQ,EAElC,QAASxgB,GAAI6a,GAAO,EAAI1X,EAAOC,EAAMpD,IAAKmD,GAAQnD,IAAKoD,EAAMpD,IAAK6a,EAAK,CACtE,IAAI+F,GAAQzG,EAAMna,EAAC,EAEnB,GAAI4gB,IAAS,KACZ,SAED,IAAIzF,EAAKkB,EAAUnC,EAAMla,EAAC,CAAC,EACvBid,EAAKoC,EAAUuB,EAAK,EAEpBtE,GAAS,EACZxB,EAAO6D,EAAQxD,EAAIqF,CAAQ,EAE3B1F,EAAO6D,EAAQ+B,EAAUzD,CAAE,EAE5BnC,EAAO6D,EAAQxD,EAAI8B,CAAE,EAErBuD,EAAWvD,EACXyD,EAAWvF,CACZ,CAEA,IAAI0F,EAAcH,EAEdJ,GAAUhE,GAAS,IACtBuE,EAAcN,EAAOxN,EACrB+H,EAAO6D,EAAQkC,EAAaL,CAAQ,GAGrC,GAAI,CAAE1G,GAAakG,EAAY,EAAIzG,GAAiBtB,EAAG3F,CAAS,EAEhE,GAAI6F,EAAO,MAAQ,MAAQ2B,IAAe,EAAG,CAC5C,IAAIqE,GAAOoB,EAAO,KAAO,IAAI,OAAOZ,CAAM,EAEtCmC,GAAS3I,EAAO,OAAOF,EAAG3F,EAAW6F,EAAO,IAAKA,EAAO,IAAK2B,EAAW,EACxEoG,EAAUb,EAAUyB,EAAM,EAE9BhG,EAAOqD,GAAM0C,EAAaX,CAAO,EACjCpF,EAAOqD,GAAMwC,GAAcT,CAAO,CACnC,CAEA,GAAI,CAAC/H,EAAO,SAAU,CAErB,IAAIlB,GAAO,CAAC,EAEZA,GAAK,KAAK,GAAGmF,GAASlC,EAAOC,EAAOhX,EAAMC,EAAMyX,EAAKwB,EAAW+C,CAAS,CAAC,EAO1E,IAAI2B,GAAc5I,EAAO,MAAQhc,GAAW,EACxC6kB,EAAgBX,GAAW/D,GAAU,EAAMyE,GAAa,CAACA,GACzDE,EAAgBZ,GAAW/D,GAAS,GAAM,CAACyE,GAAcA,GAE7D9J,GAAK,QAAQ6E,IAAK,CACjBA,GAAE,CAAC,GAAKkF,EACRlF,GAAE,CAAC,GAAKmF,CACT,CAAC,EAED1B,EAAO,KAAOtI,GAAOkB,EAAO,KAAKF,EAAG3F,EAAWnP,EAAMC,EAAM6T,EAAI,EAE/DsI,EAAO,KAAOjE,GAASrE,GAAMmD,EAAO,IAAKI,EAAMC,EAAMC,EAAMC,CAAI,CAChE,CAEA,OAAIqF,IAAe,IAClBT,EAAO,KAAOS,IAAe,EAAI,CAChCjG,GAAa9B,EAAG3F,EAAWnP,EAAMC,EAAMub,EAAQ,EAAE,EACjD5E,GAAa9B,EAAG3F,EAAWnP,EAAMC,EAAMub,EAAS,CAAC,CAClD,EAAI5E,GAAa9B,EAAG3F,EAAWnP,EAAMC,EAAMub,EAAQqB,EAAW,GAGxDT,CACR,CAAC,CAEH,CAEA,SAAS2B,GAAahH,EAAOC,EAAOG,EAAWF,EAAQM,EAAMF,EAAM2G,EAASvgB,GAAK,CAChF,GAAIsZ,EAAM,OAAS,EAAG,CAErB,IAAIkH,EAAU,KAId,QAASphB,EAAI,EAAGqhB,EAAW,IAAUrhB,EAAIka,EAAM,OAAQla,IACtD,GAAIma,EAAMna,CAAC,IAAM,OAAW,CAC3B,GAAIohB,GAAW,KAAM,CACpB,IAAIpd,EAAQpC,GAAIsY,EAAMla,CAAC,EAAIka,EAAMkH,CAAO,CAAC,EAErCpd,EAAQqd,IACXA,EAAWrd,EACXmd,EAASvf,GAAI0Y,EAAUJ,EAAMla,CAAC,EAAGoa,EAAQM,EAAMF,CAAI,EAAIF,EAAUJ,EAAMkH,CAAO,EAAGhH,EAAQM,EAAMF,CAAI,CAAC,EAEtG,CAEA4G,EAAUphB,CACX,CAEF,CAEA,OAAOmhB,CACR,CAEA,SAASG,GAAK5J,EAAM,CACnBA,EAAOA,GAAQ/P,GACf,IAAMkL,EAAO9P,GAAO2U,EAAK,KAAM,CAAC,GAAK9W,GAAK,CAAC,CAAC,EACtC0b,EAAQ5E,EAAK,OAAS,EACtB6J,EAAa7J,EAAK,KAAO,EAE3B8J,EAAK9J,EAAK,OAEd8J,EAECA,GAAM,KAAO,CAAC,EAAG,CAAC,EAClB,OAAOA,GAAM,SAAW,CAACA,EAAI,CAAC,EAAIA,EAEnC,IAAMC,EAAW7b,EAAS4b,CAAE,EAEtBE,EAAY,EAAI7O,EAAK,CAAC,EACtB8O,EAAa5e,GAAO8P,EAAK,CAAC,EAAGjS,EAAG,EAChCghB,EAAa7e,GAAO8P,EAAK,CAAC,EAAG,CAAC,EAE9BgP,EAAO9e,GAAO2U,EAAK,KAAM/P,EAAS,EAClCma,EAAQ/e,GAAO2U,EAAK,KAAMvR,GAAK,CAAC,CAAC,EAEjC,CAAE,KAAM4b,EAAW,OAAQC,CAAY,EAAIH,EAEjD,MAAO,CAAC5J,EAAG3F,EAAWnP,EAAMC,IACpB4U,GAAOC,EAAG3F,EAAW,CAAC6F,EAAQ+B,EAAOC,EAAOC,EAAQC,EAAQC,EAAWC,EAAWC,EAAMC,EAAMC,EAAMC,IAAS,CACnH,IAAIC,EAAUzC,EAAO,QACjB8J,EAAS3F,EAET4F,EAAWX,EAAYplB,GACvBgmB,EAAWR,EAAYxlB,GACvBimB,GAAWR,EAAYzlB,GAEvBkmB,EAAWC,GAEXlI,EAAO,KAAO,EACjB,CAACiI,EAAWC,EAAU,EAAIb,EAASxJ,EAAG3F,CAAS,EAE/C,CAACgQ,GAAYD,CAAS,EAAIZ,EAASxJ,EAAG3F,CAAS,EAEhD,IAAMiQ,GAAQnI,EAAO,KAAOA,EAAO,KAAO,EAAI,EAAI,IAG9CwB,GAAOxB,EAAO,KAAO,EAAIrB,GAAQK,GAEjCoJ,GAAOpI,EAAO,KAAO,EAAI0H,EAAQ,CAAC7J,EAAG3F,GAAWtS,GAAGqe,GAAKD,GAAKG,GAAKD,KAAQ,CAC7EwD,EAAM7J,EAAG3F,GAAWtS,GAAGoe,GAAKC,GAAKC,GAAKC,EAAG,CAC1C,EAGIkE,EAAO1f,GAAOkV,EAAE,MAAOrQ,EAAS,EAAE,KAAKrB,GAAKA,EAAE,OAAO,CAAC,GAAK+L,CAAS,EAEpEkH,EAAUiJ,GAAQ,KAAOA,EAAK,IAAM,EACpC3B,GAAS3I,EAAO,OAAOF,EAAG3F,EAAW6F,EAAO,IAAKA,EAAO,IAAKqB,CAAO,EACpE0G,GAAUtF,EAAQL,EAAUuG,GAAQzG,EAAQM,EAAMF,CAAI,CAAC,EAGvDiI,GAAQC,GAAQC,GAASzB,GAASzG,EAElCmI,GAAcjI,EAAQzC,EAAO,MAAQhc,EAAO,EAE5C2mB,GAAY,GAEZC,GAAa,KACbC,GAAY,KACZC,GAAe,KACfC,GAAc,KAEdnB,GAAa,OAASc,IAAe,GAAKb,GAAe,QAC5Dc,GAAY,GAEZC,GAAahB,EAAU,OAAO9J,EAAG3F,EAAWnP,EAAMC,CAAI,EACtD4f,GAAY,IAAI,IACf,IAAI,IAAID,EAAU,EAAG,QAAQI,GAAS,CAClCA,GAAS,MACZH,GAAU,IAAIG,EAAO,IAAI,MAAQ,CACnC,CAAC,EAEGN,GAAc,IACjBI,GAAejB,EAAY,OAAO/J,EAAG3F,EAAWnP,EAAMC,CAAI,EAC1D8f,GAAc,IAAI,IACjB,IAAI,IAAID,EAAY,EAAG,QAAQE,GAAS,CACpCA,GAAS,MACZD,GAAY,IAAIC,EAAO,IAAI,MAAQ,CACrC,CAAC,IAIH,GAAI,CAAE,GAAAlI,GAAI,KAAApI,EAAK,EAAIgP,EAEnB,GAAI5G,IAAM,MAAQpI,IAAQ,KAAM,CAC/BoP,EAAS,EACT/H,EAAQe,GAAG,OAAOhD,EAAG3F,EAAWnP,EAAMC,CAAI,EAEtC6X,GAAG,MAAQ,IACdf,EAAQA,EAAM,IAAIkJ,IAAOnL,EAAE,SAASuC,EAAO4I,GAAM1I,EAAMN,EAAO,IAAK,EAAI,CAAC,GAGzE,IAAIiJ,EAAQxQ,GAAK,OAAOoF,EAAG3F,EAAWnP,EAAMC,CAAI,EAE5CyP,GAAK,MAAQ,EAChB8P,GAASU,EAAM,CAAC,EAAI3I,EAEpBiI,GAASrI,EAAU+I,EAAM,CAAC,EAAGjJ,EAAQM,EAAMF,CAAI,EAAIF,EAAU,EAAGF,EAAQM,EAAMF,CAAI,EAEnF2G,GAASD,GAAahH,EAAOC,EAAOG,EAAWF,EAAQM,EAAMF,EAAM2G,EAAM,EAGzEyB,GADazB,GAASwB,GACHT,CACpB,MAECf,GAASD,GAAahH,EAAOC,EAAOG,EAAWF,EAAQM,EAAMF,EAAM2G,EAAM,EAIzEyB,GAFazB,GAASO,EAEHQ,EACnBS,GAASxB,GAASyB,GAGfA,GAAU,IACbA,GAAU,GAEPC,IAAeF,GAAS,IAC3BE,GAAc,GAGXD,GAAU,IACbhI,EAAU9U,IAEX,IAAIwd,GAAcV,GAAU,EAExBW,GAAYpC,GAASyB,IAAWU,GAAcT,GAAc,GAEhEF,GAAS/H,EAAQlV,GAAM6d,GAAWnB,GAAUD,CAAQ,CAAC,EAErDO,IAAUT,GAAU,EAAIU,GAAS,EAAIV,GAAUM,GAAQ,EAAII,IAAUV,EAASM,KAAUN,GAAU,EAAIC,EAAW,EAAI,IAAMoB,GAAcT,GAAc,EAAI,IAG3J,IAAMtD,GAAS,CAAC,OAAQ,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,MAAO,CAAC,EAEhFZ,GAASmE,GAAY,KAAO,IAAI,OAElCU,GAAS,KAEb,GAAIf,GAAQ,KACXe,GAASvL,EAAE,KAAKwK,EAAK,OAAO,CAAC,CAAC,MAC1B,CACJ,GAAI,CAAE,GAAAvH,EAAI,GAAA+B,EAAG,EAAI4E,EAEb3G,GAAM,MAAQ+B,IAAM,OACvB9C,EAAQ8C,GAAG,OAAOhF,EAAG3F,EAAWnP,EAAMC,CAAI,EAC1CogB,GAAStI,EAAG,OAAOjD,EAAG3F,EAAWnP,EAAMC,CAAI,EAE7C,CAEA,IAAIqgB,GAASpB,EAAYM,GACrBe,EAAUpB,GAAaK,GAE3B,QAAS3iB,EAAIuiB,IAAS,EAAIpf,EAAOC,EAAMpD,GAAKmD,GAAQnD,GAAKoD,EAAMpD,GAAKuiB,GAAO,CAC1E,IAAIhY,GAAO4P,EAAMna,CAAC,EAElB,GAAIuK,IAAQ,KACX,SAED,GAAIiZ,IAAU,KAAM,CACnB,IAAIG,GAAQH,GAAOxjB,CAAC,GAAK,EAEzB,GAAIuK,GAAOoZ,IAAS,EACnB,SAEDzD,GAAU3F,EAAUoJ,GAAOtJ,EAAQM,EAAMF,CAAI,CAC9C,CAEA,IAAIsF,GAAO3F,EAAO,OAAS,GAAKyH,GAAQ,KAAO3H,EAAMla,CAAC,EAAIA,EAGtDvC,GAAO6c,EAAUyF,GAAM3F,EAAQM,EAAMF,CAAI,EACzC9c,GAAO6c,EAAUxX,GAAOwH,GAAMuW,EAAM,EAAGzG,EAAQM,EAAMF,CAAI,EAEzD2D,GAAMxD,EAAQnd,GAAOilB,EAAM,EAC3BkB,GAAMhJ,EAAQ7Z,GAAIrD,GAAMwiB,EAAO,CAAC,EAChC7B,GAAMzD,EAAQ9Z,GAAIpD,GAAMwiB,EAAO,CAAC,EAEhC2D,GAASD,GAAMvF,GAEnB,GAAI9T,IAAQ,KAAM,CACjB,IAAIuZ,GAAKvZ,GAAO,EAAImZ,EAAUD,GAC1BM,GAAKxZ,GAAO,EAAIkZ,GAASC,EAEzBZ,IACCD,GAAc,GAAKI,GAAajjB,CAAC,GAAK,MACzC4b,GAAKsH,GAAY,IAAID,GAAajjB,CAAC,CAAC,EAAGoe,GAAKC,GAAM7e,GAAMqjB,GAAc,CAAC,EAAGF,GAAQ5hB,GAAI,EAAG8iB,GAAShB,EAAW,EAAGiB,GAAIC,EAAE,EAEnHhB,GAAW/iB,CAAC,GAAK,MACpB4b,GAAKoH,GAAU,IAAID,GAAW/iB,CAAC,CAAC,EAAGoe,GAAKC,GAAM7e,GAAMqjB,GAAc,CAAC,EAAGF,GAAQ5hB,GAAI,EAAG8iB,GAAShB,EAAW,EAAGiB,GAAIC,EAAE,GAGnHnI,GAAK+C,GAAQP,GAAKC,GAAM7e,GAAMqjB,GAAc,CAAC,EAAGF,GAAQ5hB,GAAI,EAAG8iB,GAAShB,EAAW,EAAGiB,GAAIC,EAAE,EAE7FvB,GAAKvK,EAAG3F,EAAWtS,EAClBoe,GAASyE,GAAc,EACvBxE,GACAsE,GAASE,GACTgB,EACD,CACD,CACD,CAEA,OAAIhB,GAAc,EACjBtD,GAAO,OAASuD,GAAYI,GAAcvE,GACjCmE,KACTvD,GAAO,MAAQpH,EAAO,OAAS,EAAIA,EAAO,MAAQA,EAAO,SAAWA,EAAO,MAC3EoH,GAAO,MAAQ,GAGhBA,GAAO,KAAOuD,GAAYE,GAAYrE,GAE/BY,EACR,CAAC,CAEH,CAEA,SAASyE,GAAaC,EAAQvM,EAAM,CACnC,IAAM0H,EAAYrc,GAAO2U,GAAM,UAAW,CAAC,EAE3C,MAAO,CAACO,EAAG3F,EAAWnP,EAAMC,IACpB4U,GAAOC,EAAG3F,EAAW,CAAC6F,EAAQ+B,EAAOC,EAAOC,EAAQC,EAAQC,EAAWC,EAAWC,EAAMC,EAAMC,EAAMC,IAAS,CACnH,CAACxX,EAAMC,CAAI,EAAIhD,GAAY+Z,EAAOhX,EAAMC,CAAI,EAE5C,IAAIwX,EAAUzC,EAAO,QAEjBkE,EAAYpX,GAAO2V,EAAQN,EAAUrV,EAAKmV,EAAQM,EAAMF,CAAI,CAAC,EAC7D6E,EAAYpa,GAAO2V,EAAQL,EAAUtV,EAAKoV,EAAQM,EAAMF,CAAI,CAAC,EAE7DsC,EAAQmH,EAAepJ,EAEvBV,EAAO,KAAO,GACjB2C,EAASlE,GACTiC,EAAShC,GACToL,EAAgBjL,KAGhB8D,EAAS7D,GACT4B,EAAS3B,GACT+K,EAAgB5K,IAGjB,IAAMuB,EAAMT,EAAO,KAAOA,EAAO,KAAO,EAAI,EAAI,IAE5CqG,EAAYpE,EAAUnC,EAAMW,GAAO,EAAI1X,EAAOC,CAAI,CAAC,EACnDsd,EAAWD,EAEX0D,EAAU,CAAC,EACXC,EAAU,CAAC,EAEf,QAASpkB,EAAI6a,GAAO,EAAI1X,EAAOC,EAAMpD,GAAKmD,GAAQnD,GAAKoD,EAAMpD,GAAK6a,EAGjE,GAFWV,EAAMna,CAAC,GAEN,KAAM,CACjB,IAAI+f,GAAO7F,EAAMla,CAAC,EACdvC,GAAO4e,EAAU0D,EAAI,EAEzBoE,EAAQ,KAAKzD,EAAWjjB,EAAI,EAC5B2mB,EAAQ,KAAK/E,EAAUlF,EAAMna,CAAC,CAAC,CAAC,CACjC,CAGD,IAAMuf,EAAS,CAAC,OAAQ0E,EAAOE,EAASC,EAASrH,EAAQjC,EAAQoJ,EAAetJ,CAAO,EAAG,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,MAAO9C,EAAc,EACzJ6G,EAASY,EAAO,OAElB,CAAEzF,EAAakG,EAAY,EAAIzG,GAAiBtB,EAAG3F,CAAS,EAEhE,GAAI6F,EAAO,MAAQ,MAAQ2B,GAAe,EAAG,CAC5C,IAAIqE,EAAOoB,EAAO,KAAO,IAAI,OAAOZ,CAAM,EAEtCmC,GAAS3I,EAAO,OAAOF,EAAG3F,EAAW6F,EAAO,IAAKA,EAAO,IAAK2B,CAAW,EACxEoG,GAAUb,EAAUyB,EAAM,EAE9BhG,EAAOqD,EAAMuC,EAAUR,EAAO,EAC9BpF,EAAOqD,EAAMsC,EAAWP,EAAO,CAChC,CAEA,GAAI,CAAC/H,EAAO,SAAU,CAErB,IAAIlB,EAAO,CAAC,EAEZA,EAAK,KAAK,GAAGmF,GAASlC,EAAOC,EAAOhX,EAAMC,EAAMyX,EAAKwB,EAAW+C,CAAS,CAAC,EAM1EG,EAAO,KAAOtI,EAAOkB,EAAO,KAAKF,EAAG3F,EAAWnP,EAAMC,EAAM6T,CAAI,EAE/DsI,EAAO,KAAOjE,GAASrE,EAAMmD,EAAO,IAAKI,EAAMC,EAAMC,EAAMC,CAAI,CAChE,CAEA,OAAIqF,IAAe,IAClBT,EAAO,KAAOS,IAAe,EAAI,CAChCjG,GAAa9B,EAAG3F,EAAWnP,EAAMC,EAAMub,EAAQ,EAAE,EACjD5E,GAAa9B,EAAG3F,EAAWnP,EAAMC,EAAMub,EAAS,CAAC,CAClD,EAAI5E,GAAa9B,EAAG3F,EAAWnP,EAAMC,EAAMub,EAAQqB,EAAW,GAGxDT,CAaR,CAAC,CAEH,CAEA,SAAS8E,GAAc3M,EAAM,CAC5B,OAAOsM,GAAaM,GAAgB5M,CAAI,CACzC,CAIA,SAAS4M,GAAera,EAAII,EAAI0S,EAAQjC,EAAQoJ,EAAetJ,EAAS,CACvE,IAAM2J,EAAIta,EAAG,OAEb,GAAIsa,EAAI,EACP,OAAO,KAER,IAAMC,EAAO,IAAI,OAIjB,GAFAzH,EAAOyH,EAAMva,EAAG,CAAC,EAAGI,EAAG,CAAC,CAAC,EAErBka,GAAK,EACRzJ,EAAO0J,EAAMva,EAAG,CAAC,EAAGI,EAAG,CAAC,CAAC,MACrB,CACJ,IAAI+D,EAAM,MAAMmW,CAAC,EAChBE,EAAM,MAAMF,EAAI,CAAC,EACjBG,EAAM,MAAMH,EAAI,CAAC,EACjBI,EAAM,MAAMJ,EAAI,CAAC,EAGlB,QAASvkB,EAAI,EAAGA,EAAIukB,EAAI,EAAGvkB,IAC1B0kB,EAAI1kB,CAAC,EAAIqK,EAAGrK,EAAI,CAAC,EAAIqK,EAAGrK,CAAC,EACzB2kB,EAAI3kB,CAAC,EAAIiK,EAAGjK,EAAI,CAAC,EAAIiK,EAAGjK,CAAC,EACzBykB,EAAGzkB,CAAC,EAAK0kB,EAAI1kB,CAAC,EAAI2kB,EAAI3kB,CAAC,EAKxBoO,EAAG,CAAC,EAAIqW,EAAG,CAAC,EAEZ,QAASzkB,EAAI,EAAGA,EAAIukB,EAAI,EAAGvkB,IACtBykB,EAAGzkB,CAAC,IAAM,GAAKykB,EAAGzkB,EAAI,CAAC,IAAM,GAAMykB,EAAGzkB,EAAI,CAAC,EAAI,GAAQykB,EAAGzkB,CAAC,EAAI,EAClEoO,EAAGpO,CAAC,EAAI,GAERoO,EAAGpO,CAAC,EAAI,GAAK2kB,EAAI3kB,EAAI,CAAC,EAAI2kB,EAAI3kB,CAAC,KAC7B,EAAI2kB,EAAI3kB,CAAC,EAAI2kB,EAAI3kB,EAAI,CAAC,GAAKykB,EAAGzkB,EAAI,CAAC,GACnC2kB,EAAI3kB,CAAC,EAAI,EAAI2kB,EAAI3kB,EAAI,CAAC,GAAKykB,EAAGzkB,CAAC,GAG5B,SAASoO,EAAGpO,CAAC,CAAC,IAClBoO,EAAGpO,CAAC,EAAI,IAIXoO,EAAGmW,EAAI,CAAC,EAAIE,EAAGF,EAAI,CAAC,EAEpB,QAASvkB,EAAI,EAAGA,EAAIukB,EAAI,EAAGvkB,IAC1BkkB,EACCM,EACAva,EAAGjK,CAAC,EAAI2kB,EAAI3kB,CAAC,EAAI,EACjBqK,EAAGrK,CAAC,EAAIoO,EAAGpO,CAAC,EAAI2kB,EAAI3kB,CAAC,EAAI,EACzBiK,EAAGjK,EAAI,CAAC,EAAI2kB,EAAI3kB,CAAC,EAAI,EACrBqK,EAAGrK,EAAI,CAAC,EAAIoO,EAAGpO,EAAI,CAAC,EAAI2kB,EAAI3kB,CAAC,EAAI,EACjCiK,EAAGjK,EAAI,CAAC,EACRqK,EAAGrK,EAAI,CAAC,CACT,CAEF,CAEA,OAAOwkB,CACR,CAEA,IAAMI,GAAc,IAAI,IAExB,SAASC,IAAkB,CAC1B,QAAS5M,KAAK2M,GACb3M,EAAE,SAAS,EAAI,CACjB,CAEIlc,KACHS,GAAGd,GAAQO,GAAK4oB,EAAe,EAC/BroB,GAAGb,GAAQM,GAAK4oB,GAAiB,EAAI,EACrCroB,GAAGX,GAAYI,GAAK,IAAM,CAAE6oB,GAAM,QAAU3oB,EAAS,CAAC,GAGvD,IAAM4oB,GAAa5F,GAAO,EACpB6F,GAAajH,GAAO,EAE1B,SAASkH,GAAY5Y,EAAG6Y,EAAIC,EAAIC,EAAO,CAEtC,OADSA,EAAQ,CAAC/Y,EAAE,CAAC,EAAGA,EAAE,CAAC,CAAC,EAAE,OAAOA,EAAE,MAAM,CAAC,CAAC,EAAI,CAACA,EAAE,CAAC,CAAC,EAAE,OAAOA,EAAE,MAAM,CAAC,CAAC,GACjE,IAAI,CAAC/D,EAAGtI,IAAMqlB,GAAW/c,EAAGtI,EAAGklB,EAAIC,CAAE,CAAC,CACjD,CAEA,SAASG,GAAajZ,EAAGkZ,EAAK,CAC7B,OAAOlZ,EAAE,IAAI,CAAC,EAAGrM,IAAMA,GAAK,EAAI,CAAC,EAAI0I,GAAO,CAAC,EAAG6c,EAAK,CAAC,CAAC,CACxD,CAEA,SAASF,GAAW/c,EAAG,EAAG4c,EAAIC,EAAI,CACjC,OAAOzc,GAAO,CAAC,EAAI,GAAK,EAAIwc,EAAKC,EAAK7c,CAAC,CACxC,CAEA,SAASkd,GAAS7W,EAAMiL,EAASC,EAAS,CACzC,OAAOD,GAAW,KAAO/R,GAAgB,CAAC+R,EAASC,CAAO,CAC3D,CAEA,IAAM4L,GAAYD,GAIlB,SAASE,GAAS/W,EAAMiL,EAASC,EAAS,CACzC,OAAOD,GAAW,KAAO/R,GAAgBnF,GAASkX,EAASC,EAASvX,GAAU,EAAI,CACnF,CAEA,SAASqjB,GAAShX,EAAMiL,EAASC,EAASnD,EAAO,CAChD,OAAOkD,GAAW,KAAO/R,GAAgBhH,GAAS+Y,EAASC,EAASlL,EAAK,OAAO+H,CAAK,EAAE,IAAK,EAAK,CAClG,CAEA,IAAMkP,GAAWD,GAEjB,SAASE,GAAWlX,EAAMiL,EAASC,EAASnD,EAAO,CAClD,OAAOkD,GAAW,KAAO/R,GAAgBzF,GAAWwX,EAASC,EAASlL,EAAK,OAAO+H,CAAK,EAAE,IAAK,EAAK,CACpG,CAEA,IAAMoP,GAAaD,GAGnB,SAASE,GAASC,EAAQC,EAAQ1e,EAAOuP,EAAKxG,EAAU,CACvD,IAAI4V,EAAYnlB,GAAIyE,GAAawgB,CAAM,EAAGxgB,GAAaygB,CAAM,CAAC,EAE1DjiB,EAAQiiB,EAASD,EAEjBG,EAAUlnB,GAAYqR,EAAWwG,EAAO9S,EAAOuD,CAAK,EAExD,EAAG,CACF,IAAIwH,EAAYxH,EAAM4e,CAAO,EACzBnX,EAAa8H,EAAM/H,EAAY/K,EAEnC,GAAIgL,GAAcsB,GAAY4V,GAAanX,EAAY,EAAIpI,GAAS,IAAIoI,CAAS,EAAI,IAAM,GAC1F,MAAO,CAACA,EAAWC,CAAU,CAC/B,OAAS,EAAEmX,EAAU5e,EAAM,QAE3B,MAAO,CAAC,EAAG,CAAC,CACb,CAEA,SAAS6e,GAAYhS,EAAM,CAC1B,IAAIiS,EAAUC,EACd,OAAAlS,EAAOA,EAAK,QAAQ,UAAW,CAACxH,EAAGiK,KAAQwP,EAAWjhB,IAAOkhB,EAAc,CAACzP,GAAM1a,EAAO,GAAK,IAAI,EAC3F,CAACiY,EAAMiS,EAAUC,CAAW,CACpC,CAEA,SAASC,GAAazQ,EAAM,CACvBA,EAAK,MACR,CAACA,EAAK,KAAMA,EAAK,SAAS,EAAE,QAAQ0Q,GAAK,CACxC,IAAI3T,EAAO5Q,GAASukB,EAAE,CAAC,EAAIrqB,GAAS,CAAC,EACrCqqB,EAAE,CAAC,EAAIA,EAAE,CAAC,EAAE,QAAQ,YAAa3T,EAAO,IAAI,EAC5C2T,EAAE,CAAC,EAAI3T,CACR,CAAC,CAEH,CAEA,SAASiS,GAAMpN,EAAM/X,EAAM8mB,EAAM,CAChC,IAAM9X,EAAO,CACZ,KAAM5L,GAAO2U,EAAK,KAAM,CAAC,CAC1B,EAEMQ,EAAOvJ,EAAK,KAElB,SAAS+X,EAAQzhB,EAAKyR,EAAOI,EAAKva,EAAK,CACtC,IAAI6mB,EAAM1M,EAAM,SAASzR,CAAG,EAC5B,OAAO1I,EAAMua,GAAOJ,EAAM,KAAO,GAAM,EAAI0M,EAAOA,EACnD,CAEA,SAASuD,EAAQ1hB,EAAKyR,EAAOI,EAAKva,EAAK,CACtC,IAAI6mB,EAAM1M,EAAM,SAASzR,CAAG,EAC5B,OAAO1I,EAAMua,GAAOJ,EAAM,KAAO,GAAK0M,EAAO,EAAIA,EAClD,CAEA,SAASwD,EAAO3hB,EAAKyR,EAAOI,EAAKva,EAAK,CACrC,OAAOma,EAAM,KAAO,EAAIgQ,EAAQzhB,EAAKyR,EAAOI,EAAKva,CAAG,EAAIoqB,EAAQ1hB,EAAKyR,EAAOI,EAAKva,CAAG,CACrF,CAEAoS,EAAK,UAAY+X,EACjB/X,EAAK,UAAYgY,EAEjB,IAAIE,EAAQ,GACZlY,EAAK,OAAS,EAEd,IAAMmY,EAAOnY,EAAK,KAAOrR,GAAS9D,EAAK,EAOvC,GALIke,EAAK,IAAM,OACdoP,EAAK,GAAKpP,EAAK,IAEhBjb,GAASqqB,EAAMpP,EAAK,KAAK,EAErBA,EAAK,MAAO,CACf,IAAIqP,EAAQzpB,GAAS3D,GAAOmtB,CAAI,EAChCC,EAAM,YAAcrP,EAAK,KAC1B,CAEA,IAAMsP,EAAM/pB,GAAS,QAAQ,EACvBgqB,EAAMtY,EAAK,IAAMqY,EAAI,WAAW,IAAI,EAEpCE,EAAO5pB,GAAS1D,GAAMktB,CAAI,EAEhCtqB,GAAG,QAAS0qB,EAAMvT,GAAK,CAClBA,EAAE,SAAWwT,IACF7T,IAAc8T,IAAc7T,IAAa8T,KAC5CC,GAAK,MAAM3Y,EAAMgF,CAAC,CAE/B,EAAG,EAAI,EAEP,IAAM4T,EAAQ5Y,EAAK,MAAQrR,GAASzD,GAAOqtB,CAAI,EAC/CA,EAAK,YAAYF,CAAG,EACpB,IAAMG,EAAOxY,EAAK,KAAOrR,GAASxD,GAAMotB,CAAI,EAE5CxP,EAAOrP,GAAKqP,CAAI,EAEhB,IAAMoF,EAAU,CAAC/Z,GAAO2U,EAAK,QAAS,CAAC,EAEjCkD,EAAUiC,GAAWC,CAAO,GAEjCpF,EAAK,SAAW,CAAC,GAAG,QAAQvQ,GAAK,CAC7BA,EAAE,OACLuQ,EAAOvQ,EAAE,KAAKwH,EAAM+I,CAAI,GAAKA,EAC/B,CAAC,EAED,IAAMtJ,EAAKsJ,EAAK,IAAM,KAEhBS,EAAUxJ,EAAK,OAASuJ,GAAQ,EACrC+M,GAAYvN,EAAK,QAAU,CAAC,EAAGhD,GAAa0C,GAAa,EAAK,EAC9DkO,GAAa5N,EAAK,QAAU,CAAC,IAAI,EAAGP,EAAY,EAC3CqQ,EAAU7Y,EAAK,KAASsW,GAAYvN,EAAK,MAAU,CAAC,EAAGnD,GAAa+B,GAAc,EAAI,EACtF8B,EAAUzJ,EAAK,OAAS,CAAC,EACzB+K,EAAU/K,EAAK,MAAS+I,EAAK,OAAS,CAAC,EAE7CgC,EAAM,QAAQnT,GAAK,CAClBA,EAAE,KAAOX,EAASW,EAAE,MAAQ,IAAI,EAChCA,EAAE,IAAMxD,GAAOwD,EAAE,IAAK,EAAE,CACzB,CAAC,EAED,IAAMkhB,EAAYvP,GAAQ,EAAIC,EAAO,CAAC,EAAE,OAAO,CAAC,EAAE,MAAQA,EAAO,CAAC,EAAE,MAE9DuP,EAAe,CACpB,KAAMC,GACN,OAAQC,EACT,EAEMC,GAAanQ,EAAK,WAAa,CAAC,OAAQ,QAAQ,GAAG,IAAI7O,GAAO6e,EAAa7e,CAAG,CAAC,EAErF,SAASif,EAAa9R,EAAI,CACzB,IAAM+R,EACL/R,EAAG,OAAS,EAAM/Q,GAAO3D,GAAM2D,EAAM,EAAIA,EAAM+Q,EAAG,MAAMrH,EAAM1J,EAAK+Q,EAAG,IAAKA,EAAG,IAAKA,EAAG,GAAG,CAAC,EAC1FA,EAAG,OAAS,EAAM/Q,GAAOM,GAAMN,EAAK+Q,EAAG,KAAK,EAC5CA,EAAG,OAAS,IAAM/Q,GAAO+Q,EAAG,IAAI/Q,CAAG,EACnCA,GAAOA,EAGR,OAAOA,GAAO,CACb,IAAI+iB,EAAOD,EAAO9iB,CAAG,EACjB,CAAE,KAAAvE,EAAM,KAAAC,CAAK,EAAIqV,EACjBhS,EAAQrD,EAAOD,EACnB,OAAQsnB,EAAOtnB,GAAQsD,CACxB,CACD,CAEA,SAASikB,EAAUlS,EAAU,CAC5B,IAAIC,EAAKoC,EAAOrC,CAAQ,EAExB,GAAIC,GAAM,KAAM,CACf,IAAIkS,GAAaxQ,EAAK,QAAU/P,IAAWoO,CAAQ,GAAKpO,GAExD,GAAIugB,EAAU,MAAQ,KAAM,CAE3BD,EAAUC,EAAU,IAAI,EAExB,IAAIlS,EAAKtN,GAAO,CAAC,EAAG0P,EAAO8P,EAAU,IAAI,EAAGA,EAAW,CAAC,IAAKnS,CAAQ,CAAC,EACtEC,EAAG,SAAW8R,EAAa9R,CAAE,EAC7BoC,EAAOrC,CAAQ,EAAIC,CACpB,KACK,CACJA,EAAKoC,EAAOrC,CAAQ,EAAIrN,GAAO,CAAC,EAAIqN,GAAY0R,EAAYnQ,GAAaC,GAAa2Q,CAAS,EAE/FlS,EAAG,IAAMD,EAET,IAAIoS,EAASnS,EAAG,KAEZoS,EAAKpS,EAAG,MAERqS,EAAavgB,GAAMsgB,CAAE,EAEzB,IAAIrS,GAAY0R,GAAcvP,GAAQ,GAAK,CAACiQ,KAEvCE,IAAeD,EAAG,CAAC,GAAK,MAAQA,EAAG,CAAC,GAAK,QAC5CA,EAAK,CACJ,IAAKA,EAAG,CAAC,GAAK,KAAO7lB,GAAgB,CACpC,KAAM,EACN,KAAM6lB,EAAG,CAAC,EACV,KAAMA,EAAG,CAAC,CACX,EACA,IAAKA,EAAG,CAAC,GAAK,KAAO7lB,GAAgB,CACpC,KAAM,EACN,KAAM6lB,EAAG,CAAC,EACV,KAAMA,EAAG,CAAC,CACX,CACD,EACAC,EAAa,IAGV,CAACA,GAAcxlB,GAAMulB,CAAE,GAAG,CAC7B,IAAI/kB,EAAM+kB,EAEVA,EAAK,CAACzZ,EAAMiL,EAASC,IAAYD,GAAW,KAAO/R,GAAgBnF,GAASkX,EAASC,EAASxW,CAAG,CAClG,CAGD2S,EAAG,MAAQpQ,EAASwiB,IAAOD,EAAS1C,GAAY1P,GAAY0R,EAC1DzR,EAAG,OAAS,EAAI4P,GAAW5P,EAAG,OAAS,EAAI8P,GAAaN,GACxDxP,EAAG,OAAS,EAAI2P,GAAW3P,EAAG,OAAS,EAAI6P,GAAaH,GACzD,EAED1P,EAAG,KAAOpQ,EAASyiB,EAAa,GAAQrS,EAAG,IAAI,EAE/CA,EAAG,MAAQpQ,EAASoQ,EAAG,OAASqB,EAAU,EAG1CrB,EAAG,KAAOA,EAAG,KAAO,KAEpBA,EAAG,SAAW8R,EAAa9R,CAAE,CAC9B,CACD,CACD,CAEAiS,EAAU,GAAG,EACbA,EAAU,GAAG,EAGT/P,GAAQ,GACXC,EAAO,QAAQ9J,GAAK,CACnB4Z,EAAU5Z,EAAE,KAAK,CAClB,CAAC,EAGFmZ,EAAK,QAAQlhB,GAAK,CACjB2hB,EAAU3hB,EAAE,KAAK,CAClB,CAAC,EAED,QAASmC,KAAKiP,EAAK,OAClBuQ,EAAUxf,CAAC,EAEZ,IAAM2R,EAAShC,EAAOqP,CAAS,EAEzBa,EAAclO,EAAO,MAEvBE,EAAWC,EAEXH,EAAO,KAAO,GACjB3d,GAASqqB,EAAMrtB,EAAM,EACrB6gB,EAAYoM,EACZnM,EAAYoM,IAgBZlqB,GAASqqB,EAAMptB,EAAM,EACrB4gB,EAAYqM,EACZpM,EAAYmM,GAgBb,IAAM6B,EAAa,CAAC,EAGpB,QAAS9f,KAAK2P,EAAQ,CACrB,IAAIpC,EAAKoC,EAAO3P,CAAC,GAEbuN,EAAG,KAAO,MAAQA,EAAG,KAAO,QAC/BuS,EAAW9f,CAAC,EAAI,CAAC,IAAKuN,EAAG,IAAK,IAAKA,EAAG,GAAG,EACzCA,EAAG,IAAMA,EAAG,IAAM,KAEpB,CAGA,IAAMwS,GAAY9Q,EAAK,SAAW+Q,GAAM,IAAI,KAAKrjB,GAAMqjB,EAAKra,CAAE,CAAC,GACzDsa,EAAYhR,EAAK,SAAWlL,GAE5Bmc,GAAmBva,GAAM,EAAIyC,GAAiB2X,EAAO,EAAIxX,GAAgBwX,EAAO,EAChFI,GAAkBzX,GAAaqX,GAASvX,GAAgB7C,GAAM,EAAIwC,GAAoBG,GAAmB2X,CAAQ,CAAC,EAClHG,GAAkBxW,GAAcmW,GAASrW,GAAgBC,GAAkBsW,CAAQ,CAAC,EAEpFI,GAAa,CAAC,EAEdC,EAAcpa,EAAK,OAASjG,GAAO,CAAC,EAAGgK,GAAYgF,EAAK,MAAM,EAC9DsR,EAA6Bra,EAAK,OAASjG,GAAO,CAAC,EAAGmL,GAAY,CAAC,KAAM,CAAC,EAAGqE,GAAQ,CAAC,CAAC,EAAGR,EAAK,MAAM,EACrGuR,GAAaF,EAAO,KACpBG,GAA4BF,EAAO,KACnCG,GAAaJ,EAAO,QAGzBA,EAAO,KAAOD,GAEdK,GAAQ,MAASvjB,EAASujB,GAAQ,KAAK,EACvCA,GAAQ,KAASvjB,EAASujB,GAAQ,IAAI,EACtCA,GAAQ,OAASvjB,EAASujB,GAAQ,MAAM,EACxCA,GAAQ,KAASvjB,EAASujB,GAAQ,IAAI,EAGvC,IAAIC,GACAC,GACAC,GACAC,GAAa,CAAC,EACdC,GAAc,CAAC,EACfC,GACAC,GAAiB,GACjBC,GAAqB,CAAC,EAE1B,GAAIZ,EAAO,KAAM,CAChB,IAAMa,EAAezR,EAAO,CAAC,EAAIA,EAAO,CAAC,EAAE,OAAS,KACpDuR,GAAiBE,GAAgB,KACjCH,GAAaC,GAAiBE,EAAajb,EAAM,EAAG,CAAC,EAAI,CAAC,EAAG,CAAC,EAE9D,QAASlG,KAAKghB,GACbE,GAAmBlhB,CAAC,EAAI3M,EAC1B,CAEA,GAAImtB,GAOH,GANAG,GAAcnsB,GAAS,QAAS5C,GAAQysB,CAAI,EAC5CwC,GAAarsB,GAAS,QAAS,KAAMmsB,EAAW,EAGhDL,EAAO,MAAMpa,EAAMya,EAAW,EAE1BM,GAAgB,CACnBL,GAAapsB,GAAS,QAAS,KAAMmsB,GAAaE,EAAU,EAE5D,IAAI3e,EAAO1N,GAAS,KAAM,KAAMosB,EAAU,EAC1CpsB,GAAS,KAAM,KAAM0N,CAAI,EAEzB,QAAS9B,MAAO4gB,GACfxsB,GAAS,KAAMvC,GAAciQ,CAAI,EAAE,YAAc9B,EACnD,MAECpM,GAAS2sB,GAAa7uB,EAAa,EACnCwuB,EAAO,MAAQtsB,GAAS2sB,GAAa9uB,EAAW,EAIlD,IAAMuvB,GAAO,CAAC,KAAM,EAAI,EAClBC,GAAO,CAAC,KAAM,EAAK,EAEzB,SAASC,GAAc1b,EAAGrO,EAAG,CAC5B,GAAIA,GAAK,IAAM0pB,IAAkB,CAACX,EAAO,MAAQ7Q,GAAQ,GACxD,OAAOrQ,GAER,IAAImiB,EAAQ,CAAC,EAETjf,EAAM9N,GAAS,KAAMzC,GAAe8uB,GAAYA,GAAW,WAAWtpB,CAAC,CAAC,EAE5EvD,GAASsO,EAAKsD,EAAE,KAAK,EAEhBA,EAAE,MACN5R,GAASsO,EAAK/Q,EAAG,EAElB,IAAIiwB,EAAQhtB,GAAS,KAAM,KAAM8N,CAAG,EAEpC,GAAIoe,GAAQ,KAAM,CACjB,IAAIe,EAAQ5sB,GAAS7C,GAAewvB,CAAK,EAEzC,GAAIjqB,EAAI,EAAG,CACV,IAAI+S,EAASoW,GAAQ,MAAMxa,EAAM3O,CAAC,EAE9B+S,IACHmX,EAAM,MAAM,OAASnX,EAAQ,MAAQoW,GAAQ,KAAKxa,EAAM3O,CAAC,EAAI,IAAMmpB,GAAQ,OAAOxa,EAAM3O,CAAC,GAE1FkqB,EAAM,MAAM,WAAaf,GAAQ,KAAKxa,EAAM3O,CAAC,CAC9C,CACD,CAEA,IAAImqB,EAAO7sB,GAAS5C,GAAcuvB,CAAK,EAEnC5b,EAAE,iBAAiB,YACtB8b,EAAK,YAAY9b,EAAE,KAAK,EAExB8b,EAAK,YAAc9b,EAAE,MAElBrO,EAAI,IACFmpB,GAAQ,OACZgB,EAAK,MAAM,MAAQ9b,EAAE,MAAQ,EAAI8a,GAAQ,OAAOxa,EAAM3O,CAAC,EAAImpB,GAAQ,KAAKxa,EAAM3O,CAAC,GAEhFoqB,GAAQ,QAASH,EAAOtW,GAAK,CAC5B,GAAIqV,EAAO,MACV,OAEDqB,GAAe1W,CAAC,EAEhB,IAAIrB,EAAY6F,EAAO,QAAQ9J,CAAC,EAEhC,IAAKsF,EAAE,SAAWA,EAAE,UAAYoV,EAAO,QAAS,CAE/C,IAAIuB,EAAUnS,EAAO,KAAK,CAAC9J,EAAGrO,IAAMA,EAAI,GAAKA,GAAKsS,GAAajE,EAAE,IAAI,EAErE8J,EAAO,QAAQ,CAAC9J,EAAGrO,IAAM,CACxBA,EAAI,GAAKuqB,GAAUvqB,EAAGsqB,EAAWtqB,GAAKsS,EAAYuX,GAAMC,GAAQD,GAAK,GAAMW,GAAS,SAAS,CAC9F,CAAC,CACF,MAECD,GAAUjY,EAAW,CAAC,KAAM,CAACjE,EAAE,IAAI,EAAG,GAAMmc,GAAS,SAAS,CAChE,EAAG,EAAK,EAEJC,IACHL,GAAQ7uB,GAAY0uB,EAAOtW,GAAK,CAC3BqV,EAAO,QAGXqB,GAAe1W,CAAC,EAEhB4W,GAAUpS,EAAO,QAAQ9J,CAAC,EAAGqc,GAAY,GAAMF,GAAS,SAAS,EAClE,EAAG,EAAK,GAIV,QAAS3hB,KAAO4gB,GAAY,CAC3B,IAAIvpB,EAAIjD,GAAS,KAAMtC,GAAcoQ,CAAG,EACxC7K,EAAE,YAAc,KAChB8pB,EAAM,KAAK9pB,CAAC,CACb,CAEA,MAAO,CAAC6K,EAAKif,CAAK,CACnB,CAEA,IAAMW,GAAiB,IAAI,IAE3B,SAASP,GAAQtrB,EAAI1B,EAAMsN,EAAIgJ,EAAW,GAAM,CAC/C,IAAMkX,EAAgBD,GAAe,IAAIvtB,CAAI,GAAK,CAAC,EAC7CytB,EAAW7B,EAAO,KAAKlqB,CAAE,EAAE6P,EAAMvR,EAAMsN,EAAIgJ,CAAQ,EAErDmX,IACHruB,GAAGsC,EAAI1B,EAAMwtB,EAAc9rB,CAAE,EAAI+rB,CAAQ,EACzCF,GAAe,IAAIvtB,EAAMwtB,CAAa,EAExC,CAEA,SAASE,GAAShsB,EAAI1B,EAAMsN,EAAI,CAC/B,IAAMkgB,EAAgBD,GAAe,IAAIvtB,CAAI,GAAK,CAAC,EAEnD,QAASqL,KAAKmiB,GACT9rB,GAAM,MAAQ2J,GAAK3J,KACtBvC,GAAIkM,EAAGrL,EAAMwtB,EAAcniB,CAAC,CAAC,EAC7B,OAAOmiB,EAAcniB,CAAC,GAIpB3J,GAAM,MACT6rB,GAAe,OAAOvtB,CAAI,CAC5B,CAEA,IAAI2tB,GAAa,EACbC,GAAa,EAEbC,EAAa,EACbC,EAAa,EAGbC,GAAa,EACbC,GAAa,EAGbC,GAAcF,GACdG,GAAcF,GACdG,GAAcN,EACdO,GAAcN,EAGd1P,GAAU,EACVC,GAAU,EACVC,GAAU,EACVC,GAAU,EAEdhN,EAAK,KAAO,CAAC,EAEb,IAAI8c,GAAkB,GAClBC,GAAgB,GAChBC,GAAqB,GACrBC,GAAkB,GAClBC,GAAkB,GAClBC,GAAkB,GAEtB,SAASC,GAAShZ,EAAOiZ,EAAQC,EAAO,EACnCA,GAAUlZ,GAASpE,EAAK,OAASqd,GAAUrd,EAAK,SACnDud,GAASnZ,EAAOiZ,CAAM,EAEvBG,GAAa,EAAK,EAElBR,GAAqB,GACrBD,GAAgB,GAEhBU,GAAO,CACR,CAEA,SAASF,GAASnZ,EAAOiZ,EAAQ,CAGhCrd,EAAK,MAASoc,GAAaE,EAAalY,EACxCpE,EAAK,OAASqc,GAAaE,EAAac,EACxCb,GAAcC,GAAa,EAE3BiB,GAAa,EACbC,GAAc,EAEd,IAAIC,EAAK5d,EAAK,KAEd6M,GAAU+Q,EAAG,KAASvlB,GAAUmkB,GAAahvB,GAAS,EAAG,EACzDsf,GAAU8Q,EAAG,IAASvlB,GAAUokB,GAAajvB,GAAS,EAAG,EACzDuf,GAAU6Q,EAAG,MAASvlB,GAAUikB,EAAa9uB,GAAS,EAAG,EACzDwf,GAAU4Q,EAAG,OAASvlB,GAAUkkB,EAAa/uB,GAAS,EAAG,CAG1D,CAGA,IAAMqwB,GAAc,EAEpB,SAASC,IAAe,CACvB,IAAIC,EAAY,GAEZC,EAAW,EAEf,KAAO,CAACD,GAAW,CAClBC,IAEA,IAAIC,EAAgBC,GAASF,CAAQ,EACjCG,EAAmBC,GAAYJ,CAAQ,EAE3CD,EAAYC,GAAYH,IAAgBI,GAAiBE,EAEpDJ,IACJR,GAASvd,EAAK,MAAOA,EAAK,MAAM,EAChC+c,GAAgB,GAElB,CACD,CAEA,SAASsB,GAAQ,CAAC,MAAAja,EAAO,OAAAiZ,CAAM,EAAG,CACjCD,GAAShZ,EAAOiZ,CAAM,CACvB,CAEArd,EAAK,QAAUqe,GAGf,SAASX,IAAe,CAEvB,IAAIY,EAAa,GACbC,EAAa,GACbC,EAAa,GACbC,EAAa,GAEjB5F,EAAK,QAAQ,CAAC1R,EAAM9V,IAAM,CACzB,GAAI8V,EAAK,MAAQA,EAAK,MAAO,CAC5B,GAAI,CAAC,KAAAuX,EAAM,MAAAC,CAAK,EAAIxX,EAChByX,EAAOF,EAAO,EACdG,EAAY1X,EAAK,OAAS,KAAOA,EAAK,UAAY,EAElD2X,EAAWH,EAAQE,EAEnBC,EAAW,IACVF,GACHtC,GAAcwC,EAEVJ,GAAQ,GACXlC,IAAcsC,EACdL,EAAa,IAGbD,EAAa,KAGdjC,GAAcuC,EAEVJ,GAAQ,GACXjC,IAAcqC,EACdR,EAAa,IAGbC,EAAa,IAGjB,CACD,CAAC,EAEDQ,GAAc,CAAC,EAAIT,EACnBS,GAAc,CAAC,EAAIP,EACnBO,GAAc,CAAC,EAAIR,EACnBQ,GAAc,CAAC,EAAIN,EAGnBnC,GAAc0C,GAAS,CAAC,EAAIA,GAAS,CAAC,EACtCxC,IAAcwC,GAAS,CAAC,EAGxBzC,GAAcyC,GAAS,CAAC,EAAIA,GAAS,CAAC,EACtCvC,IAAcuC,GAAS,CAAC,CACzB,CAEA,SAASrB,IAAgB,CAExB,IAAIsB,EAAOzC,GAAaF,EACpB4C,EAAOzC,GAAaF,EAEpB4C,EAAO3C,GACP4C,EAAO3C,GAEX,SAAS4C,EAAWX,EAAMxa,EAAM,CAC/B,OAAQwa,EAAM,CACb,IAAK,GAAG,OAAAO,GAAQ/a,EAAa+a,EAAO/a,EACpC,IAAK,GAAG,OAAAgb,GAAQhb,EAAagb,EAAOhb,EACpC,IAAK,GAAG,OAAAib,GAAQjb,EAAaib,EAAOjb,EACpC,IAAK,GAAG,OAAAkb,GAAQlb,EAAakb,EAAOlb,CACrC,CACD,CAEA2U,EAAK,QAAQ,CAAC1R,EAAM9V,IAAM,CACzB,GAAI8V,EAAK,MAAQA,EAAK,MAAO,CAC5B,IAAIuX,EAAOvX,EAAK,KAEhBA,EAAK,KAAOkY,EAAWX,EAAMvX,EAAK,KAAK,EAEnCA,EAAK,OAAS,OACjBA,EAAK,MAAQkY,EAAWX,EAAMvX,EAAK,SAAS,EAC9C,CACD,CAAC,CACF,CAEA,GAAIkT,EAAO,SAAW,KAAM,CAC3B,IAAIiF,EAAMjF,EAAO,MAEbkF,EAAOD,EAAI,KAAO,IAAI,IAAIA,EAAI,MAAQ,CAAC,CAAC,EAC5CC,EAAK,IAAI,MAAM,EACf,IAAIC,EAAOF,EAAI,KAAOroB,EAASqoB,EAAI,IAAI,EACnCG,EAAOH,EAAI,OAAJA,EAAI,KAAS,GAGxBjF,EAAO,QAAU,CAACra,EAAM2D,EAAW+b,EAAWC,IAAc,CAC3D,GAAIhc,GAAa,EAChB,OAAO+b,EAER,IAAIE,EAAOF,EAEPG,EAAQL,EAAKxf,EAAM2D,EAAW+b,EAAWC,CAAS,GAAK1tB,GACvD6tB,EAAWD,GAAS,GAAKA,EAAQ5tB,GACjC8Z,EAAON,EAAO,KAAO,EAAI6Q,EAAaC,EACtCwD,EAAY1F,EAAO,KAEnB2F,GAAUhvB,EAAK,CAAC,EAChBivB,GAAUjvB,EAAK2S,CAAS,EAE5B,GAAI4b,EAAK,IAAIU,GAAQP,CAAS,CAAC,EAAG,CACjCE,EAAO,KAEP,IAAIM,EAAa,KAChBC,EAAa,KACb7jB,EAED,GAAImjB,GAAQ,GAAKA,GAAQ,GAExB,IADAnjB,EAAIojB,EACGQ,GAAc,MAAQ5jB,KAAM,GAC7BijB,EAAK,IAAIU,GAAQ3jB,CAAC,CAAC,IACvB4jB,EAAa5jB,GAIhB,GAAImjB,GAAQ,GAAKA,GAAQ,EAExB,IADAnjB,EAAIojB,EACGS,GAAc,MAAQ7jB,IAAM2jB,GAAQ,QACrCV,EAAK,IAAIU,GAAQ3jB,CAAC,CAAC,IACvB6jB,EAAa7jB,GAIhB,GAAI4jB,GAAc,MAAQC,GAAc,KACvC,GAAIL,EAAU,CACb,IAAIM,GAASF,GAAc,KAAO,KAAYvU,EAAUqU,GAAQE,CAAU,EAAGzU,EAAQM,EAAM,CAAC,EACxFsU,GAASF,GAAc,KAAQ,IAAWxU,EAAUqU,GAAQG,CAAU,EAAG1U,EAAQM,EAAM,CAAC,EAExFuU,GAAWP,EAAYK,GACvBG,GAAWF,GAASN,EAEpBO,IAAYC,GACXD,IAAYT,IACfD,EAAOM,GAEJK,IAAYV,IACfD,EAAOO,EAEV,MAECP,EACCO,GAAc,KAAOD,EACrBA,GAAc,KAAOC,EACrBT,EAAYQ,GAAcC,EAAaT,EAAYQ,EAAaC,CAGpE,MACSL,GACG7sB,GAAI8sB,EAAYpU,EAAUqU,GAAQN,CAAS,EAAGjU,EAAQM,EAAM,CAAC,CAAC,EAE9D8T,IACVD,EAAO,MAGT,OAAOA,CACR,CACD,CAEA,IAAMlE,GAAiB1W,GAAK,CAAEqV,EAAO,MAAQrV,CAAG,EAEhDqV,EAAO,KAAOF,GAEdE,EAAO,MAAQ,GAEf,IAAIjL,GAASiL,EAAO,OAEpBjL,GAAO,KAASnY,EAASmY,GAAO,IAAI,EACpCA,GAAO,KAASnY,EAASmY,GAAO,IAAI,EACpCA,GAAO,OAASnY,EAASmY,GAAO,MAAM,EACtCA,GAAO,MAASnY,EAASmY,GAAO,KAAK,EACrCA,GAAO,KAASnY,EAASmY,GAAO,IAAI,EAEpC,IAAMoR,GAAQxgB,EAAK,MAAQjG,GAAO,CAAC,EAAGgP,EAAK,OAAS,CAAC,MAAO,EAAG,EAAGsR,EAAO,KAAK,EAExEyB,GAAc0E,GAAM,MAAQ,EAC5BC,GAAc3E,IAAe1M,GAAO,IAGtCsR,GAAY,CAAC,EAEbC,GAAe,CAAC,EAChBC,GAAe,CAAC,EAEpB,SAASC,GAAanhB,EAAGjE,EAAI,CAC5B,IAAIwI,EAAKmL,GAAO,KAAKpP,EAAMvE,CAAE,EAE7B,GAAIwI,aAAc,YACjB,OAAAnW,GAASmW,EAAIxY,EAAS,EACtBqC,GAASmW,EAAIvE,EAAE,KAAK,EACpB7Q,GAAQoV,EAAI,IAAK,IAAKqY,EAAYC,CAAU,EAC5C/D,EAAK,aAAavU,EAAIyc,GAAUjlB,CAAE,CAAC,EAE5BwI,CAET,CAEA,SAAS6c,GAAWphB,EAAGrO,EAAG,CACzB,GAAIkY,GAAQ,GAAKlY,EAAI,EAAG,CACvB,IAAImoB,EAASjQ,GAAQ,GAAKE,EAAO/J,EAAE,KAAK,EAAE,KAEtCqhB,EAAKrhB,EAAE,MACXA,EAAE,MAAQ8Z,EAAUngB,GAAM0nB,CAAE,EAAIrd,GAAcmW,GAASrW,GAAgBud,EAAIhH,CAAQ,CAAC,EAAIgH,GAAM7G,GAAkB6G,GAAMrZ,GACtHhI,EAAE,MAAQA,EAAE,QAAU8Z,EAAS1T,GAAkBD,GAClD,CAEA,GAAI4a,IAAepvB,EAAI,EAAG,CACzBqO,EAAE,MAASA,EAAE,OAAS,KAAO,EAAIA,EAAE,MACnCA,EAAE,MAASA,EAAE,OAAS0W,IAAc7e,GACpCmI,EAAE,OAASzI,EAASyI,EAAE,QAAUsL,EAAY,EAC5CtL,EAAE,QAAU,CAACtL,GAAOsL,EAAE,QAASyO,CAAO,EACtCzO,EAAE,QAAUwO,GAAWxO,EAAE,OAAO,EAEhCA,EAAE,OAASzI,EAASyI,EAAE,QAAU,IAAI,EACpCA,EAAE,KAASzI,EAASyI,EAAE,MAAQ,IAAI,EAClCA,EAAE,QAAUA,EAAE,MAAQA,EAAE,OAASA,EAAE,OAAS,KAE5C,IAAIshB,EAASpZ,GAAMxV,GAAI,EAAGsN,EAAE,KAAK,EAAG,CAAC,EACjC0P,EAAS1P,EAAE,OAAS3F,GAAO,CAAC,EAAG,CAClC,KAAMinB,EACN,MAAO5uB,GAAI,EAAG4uB,EAAS,EAAE,EACzB,OAAQthB,EAAE,OACV,MAAOshB,EAAS,EAChB,MAAO3K,GACP,QAAS,KACT,MAAO,IACR,EAAG3W,EAAE,MAAM,EACX0P,EAAO,KAASnY,EAASmY,EAAO,IAAI,EACpCA,EAAO,OAASnY,EAASmY,EAAO,MAAM,EACtCA,EAAO,KAASnY,EAASmY,EAAO,IAAI,EACpCA,EAAO,OAASnY,EAASmY,EAAO,MAAM,EACtCA,EAAO,MAASnY,EAASmY,EAAO,KAAK,EACrCA,EAAO,QAAU1P,EAAE,OACpB,CAEA,GAAI4a,GAAY,CACf,IAAI2G,EAAW7F,GAAc1b,EAAGrO,CAAC,EACjCupB,GAAW,OAAOvpB,EAAG,EAAG4vB,EAAS,CAAC,CAAC,EACnCpG,GAAY,OAAOxpB,EAAG,EAAG4vB,EAAS,CAAC,CAAC,EACpC7G,EAAO,OAAO,KAAK,IAAI,CACxB,CAEA,GAAIG,GAAY,CACfJ,GAAW,OAAO9oB,EAAG,EAAG,IAAI,EAE5B,IAAI4S,EAAK,KAELwc,GACCpvB,GAAK,IACR4S,EAAK4c,GAAanhB,EAAGrO,CAAC,GAEfA,EAAI,IACZ4S,EAAK4c,GAAanhB,EAAGrO,CAAC,GAEvBqvB,GAAU,OAAOrvB,EAAG,EAAG4S,CAAE,EACzB0c,GAAa,OAAOtvB,EAAG,EAAG,CAAC,EAC3BuvB,GAAa,OAAOvvB,EAAG,EAAG,CAAC,CAC5B,CAEA6vB,GAAK,YAAa7vB,CAAC,CACpB,CAEA,SAAS8vB,GAAUpY,EAAMtN,EAAI,CAC5BA,EAAKA,GAAa+N,EAAO,OAEzBT,EAAOQ,GAAQ,EAAImN,GAAW3N,EAAMtN,EAAIsK,GAAa0C,EAAW,EAAIiO,GAAW3N,EAAMtN,EAAI,CAAC,EAAG+M,EAAY,EAEzGgB,EAAO,OAAO/N,EAAI,EAAGsN,CAAI,EACzB+X,GAAWtX,EAAO/N,CAAE,EAAGA,CAAE,CAC1B,CAEAuE,EAAK,UAAYmhB,GAEjB,SAASC,GAAU/vB,EAAG,CAGrB,GAFAmY,EAAO,OAAOnY,EAAG,CAAC,EAEdipB,GAAY,CACfF,EAAO,OAAO,OAAO/oB,EAAG,CAAC,EAEzBwpB,GAAY,OAAOxpB,EAAG,CAAC,EACvB,IAAIgwB,EAAKzG,GAAW,OAAOvpB,EAAG,CAAC,EAAE,CAAC,EAClC8qB,GAAS,KAAMkF,EAAG,UAAU,EAC5BA,EAAG,OAAO,CACX,CAEI9G,KACHJ,GAAW,OAAO9oB,EAAG,CAAC,EACtBqvB,GAAU,OAAOrvB,EAAG,CAAC,EAAE,CAAC,EAAE,OAAO,EACjCsvB,GAAa,OAAOtvB,EAAG,CAAC,EACxBuvB,GAAa,OAAOvvB,EAAG,CAAC,GAKzB6vB,GAAK,YAAa7vB,CAAC,CACpB,CAEA2O,EAAK,UAAYohB,GAEjB,IAAMrC,GAAgB,CAAC,GAAO,GAAO,GAAO,EAAK,EAEjD,SAASuC,GAASna,EAAM9V,EAAG,CAG1B,GAFA8V,EAAK,MAAQA,EAAK,KAEdA,EAAK,KAAM,CACd,IAAIyX,EAAOzX,EAAK,KAAO,EAEnBE,EAAKoC,EAAOtC,EAAK,KAAK,EAGtBE,GAAM,OACTF,EAAK,MAAQyX,EAAOpV,EAAO,CAAC,EAAE,MAAQsP,EACtCzR,EAAKoC,EAAOtC,EAAK,KAAK,GAIvB,IAAIqS,EAASnS,EAAG,KAEhBF,EAAK,KAASlQ,EAASkQ,EAAK,IAAI,EAChCA,EAAK,MAASlQ,EAASkQ,EAAK,KAAK,EACjCA,EAAK,OAASlQ,EAASkQ,EAAK,MAAM,EAE9BhO,GAAMgO,EAAK,KAAK,GACnBA,EAAK,MAAM,QAAQ7O,GAAQ,CAC1B,CAACN,GAAS,IAAIM,CAAI,GAAKN,GAAS,IAAIM,EAAMG,GAASH,CAAI,CAAC,CACzD,CAAC,EAGF6O,EAAK,MAASlQ,EAASkQ,EAAK,QAAqBE,EAAG,OAAS,EAAI1I,GAAc6a,EAAU/Z,GAAM,EAAIuC,GAAcG,GAAcvD,GAAU,EACzIuI,EAAK,OAASlQ,EAASkQ,EAAK,SAAWqS,GAAUnS,EAAG,OAAS,EAAI2S,GAAkB3S,EAAG,OAAS,EAAIjB,GAAgBiB,EAAG,OAAS,EAAId,GAAkBN,GAAc,EAEnKkB,EAAK,OAAgBlQ,EAASkQ,EAAK,MAAM,EACzCA,EAAK,KAAK,OAAWlQ,EAASkQ,EAAK,KAAK,MAAM,EAC9CA,EAAK,MAAM,OAAUlQ,EAASkQ,EAAK,MAAM,MAAM,EAC/CA,EAAK,OAAO,OAASlQ,EAASkQ,EAAK,OAAO,MAAM,EAEhD,IAAIoa,EAAKpa,EAAK,OAEdA,EAAK,OAEJhO,GAAMooB,CAAE,GAAK,CAACpoB,GAAMooB,EAAG,CAAC,CAAC,EAAItqB,EAASsqB,CAAE,EAExC/H,EAECrgB,GAAMooB,CAAE,EACP/e,GAAaqX,GAASvX,GAAeif,EAAIxH,CAAQ,CAAC,EAEnD1gB,GAAMkoB,CAAE,EACPje,GAAYuW,GAAS0H,CAAE,EACxBA,GAAMtH,GACHsH,GAAMvb,GAGXmB,EAAK,OAASlQ,EAASkQ,EAAK,SAAqBE,EAAG,OAAS,GAAKA,EAAG,KAAO,GAAKH,GAAoBG,EAAG,OAAS,GAAKA,EAAG,KAAO,EAAII,GAAmBpQ,GAAQ,EAE/J8P,EAAK,KAAYsQ,GAAYtQ,EAAK,IAAI,EACtCA,EAAK,UAAYsQ,GAAYtQ,EAAK,SAAS,EAE3CA,EAAK,MAAUA,EAAK,KAAKnH,EAAM,KAAM3O,EAAG,CAAC,EAEzC8V,EAAK,OACLA,EAAK,QACLA,EAAK,OACLA,EAAK,OACLA,EAAK,QACLA,EAAK,QAAU,KAEXA,EAAK,MAAQ,IAChB4X,GAAc1tB,CAAC,EAAI,GACnB8V,EAAK,IAAMxY,GAASvD,GAAMmtB,CAAI,EAKhC,CACD,CAEA,SAASiJ,GAAYxhB,EAAM0e,EAAMK,EAAef,EAAU,CACzD,GAAI,CAACM,EAAYE,EAAYD,EAAYE,CAAU,EAAIM,EAEnDnS,EAAM8R,EAAO,EACbxa,EAAO,EAEX,OAAI0I,GAAO,IAAM6R,GAAcD,KAC9Bta,EAAQwa,GAAQ,GAAK,CAACJ,GAAcI,GAAQ,GAAK,CAACH,EAAa9nB,GAAMmP,GAAU,KAAO,CAAC,EAAI,GACxFgH,GAAO,IAAM0R,GAAcC,KAC9Bra,EAAQwa,GAAQ,GAAK,CAACF,GAAcE,GAAQ,GAAK,CAACD,EAAahoB,GAAMkR,GAAU,KAAO,CAAC,EAAI,GAErFzD,CACR,CAEA,IAAMud,GAAUzhB,EAAK,SAAW+I,EAAK,SAAW,CAACyY,GAAYA,GAAYA,GAAYA,EAAW,GAAG,IAAIhpB,GAAKvB,EAAS7C,GAAOoE,EAAGgpB,EAAW,CAAC,CAAC,EACtIxC,GAAWhf,EAAK,SAAWyhB,GAAQ,IAAI,CAACjpB,EAAGnH,IAAMmH,EAAEwH,EAAM3O,EAAG0tB,GAAe,CAAC,CAAC,EAE/E2C,GAGAvwB,GAAK,KACLC,GAAK,KACH8K,GAAOqN,GAAQ,EAAIC,EAAO,CAAC,EAAE,KAAO,KAEtCmY,GAAQ,KAERC,GAAgB,GAEpB,SAASC,GAAQC,EAAOC,EAAc,CAKrC,GAJA/wB,EAAO8wB,GAAgB,CAAC,EAExB9hB,EAAK,KAAOA,EAAK,MAAQhP,EAErBuY,GAAQ,EAAG,CACdmY,GAAU,EACV,QAASrwB,EAAI,EAAGA,EAAImY,EAAO,OAAQnY,IAClCqwB,IAAW1wB,EAAKK,CAAC,EAAE,CAAC,EAAE,MACxB,KACK,CACAL,EAAK,QAAU,IAClBgP,EAAK,KAAOA,EAAK,MAAQhP,EAAO,CAAC,CAAC,CAAC,GAEpC2wB,GAAQ3wB,EAAK,CAAC,EACd0wB,GAAUC,GAAM,OAEhB,IAAIK,EAAYhxB,EAEhB,GAAI2oB,GAAe,EAAG,CACrBqI,EAAYhxB,EAAK,MAAM,EAEvB,IAAIixB,EAASD,EAAU,CAAC,EAAI,MAAMN,EAAO,EACzC,QAASrwB,EAAI,EAAGA,EAAIqwB,GAASrwB,IAC5B4wB,EAAO5wB,CAAC,EAAIA,CACd,CAEA2O,EAAK,MAAQhP,EAAOgxB,CACrB,CAwBA,GAtBAxE,GAAa,EAAI,EAEjB0D,GAAK,SAAS,EAIVvH,GAAe,IAClBqD,GAAqB,IAelB+E,IAAiB,GAAO,CAC3B,IAAIG,EAAMzW,EAENyW,EAAI,KAAKliB,EAAM4hB,EAAa,EAC/BO,GAAW,EAEXC,GAAUtJ,EAAWoJ,EAAI,IAAKA,EAAI,GAAG,EAEtCjF,GAAkBA,IAAmB5C,EAAO,MAAQ,EACpD8C,GAAkB,GAClBM,GAAO,CACR,CACD,CAEAzd,EAAK,QAAU6hB,GAEf,SAASM,IAAa,CACrBP,GAAgB,GAEhB,IAAI7vB,EAAMC,EAENuX,GAAQ,IACPmY,GAAU,GACbvwB,GAAK+K,GAAK,CAAC,EAAI,EACf9K,GAAK8K,GAAK,CAAC,EAAIwlB,GAAU,EAEzB3vB,EAAOf,EAAK,CAAC,EAAEG,EAAE,EACjBa,EAAOhB,EAAK,CAAC,EAAEI,EAAE,EAEbuoB,GAAe,GAClB5nB,EAAOZ,GACPa,EAAOZ,IAECW,GAAQC,IACZ2nB,GAAe,EAClB,CAAC5nB,EAAMC,CAAI,EAAIE,GAASH,EAAMA,EAAM0Z,EAAO,IAAK,EAAK,EAC7CkO,GAAe,EACvB,CAAC5nB,EAAMC,CAAI,EAAIyB,GAAW1B,EAAMA,EAAM0Z,EAAO,IAAK,EAAK,EAC/CA,EAAO,KACfzZ,EAAOD,EAAO0E,GAAM,MAAQgJ,CAAE,EAE9B,CAAC1N,EAAMC,CAAI,EAAI+B,GAAShC,EAAMC,EAAM2B,GAAU,EAAI,KAIpDxC,GAAK+K,GAAK,CAAC,EAAInK,EAAO,KACtBX,GAAK8K,GAAK,CAAC,EAAIlK,EAAO,OAIxBowB,GAAUtJ,EAAW/mB,EAAMC,CAAI,CAChC,CAEA,IAAIqwB,GAAWC,GAASC,GAAUC,GAASC,GAASC,GAAQC,GAASC,GAAUC,GAC3EC,GAEJ,SAASC,GAAY/S,EAAQ5L,EAAO4e,EAAMC,EAAKzT,EAAM3U,EAAM,CAC1DmV,MAAWxjB,IACXw2B,MAAW/pB,IACXgqB,MAAW,QACXzT,MAAWhjB,IACXqO,MAAW,SAEPmV,GAAUqS,KACb/J,EAAI,YAAc+J,GAAYrS,GAC3BR,GAAQ8S,KACXhK,EAAI,UAAYgK,GAAU9S,GACvBpL,GAASme,KACZjK,EAAI,UAAYiK,GAAWne,GACxBvJ,GAAQ4nB,KACXnK,EAAI,SAAWmK,GAAU5nB,GACtBooB,GAAOP,KACVpK,EAAI,QAAUoK,GAASO,GACpBD,GAAQR,IACXlK,EAAI,YAAYkK,GAAUQ,CAAI,CAChC,CAEA,SAASE,GAAazd,EAAM+J,EAAM7B,EAAOwV,EAAU,CAC9C3T,GAAQ8S,KACXhK,EAAI,UAAYgK,GAAU9S,GACvB/J,GAAQkd,KACXrK,EAAI,KAAOqK,GAAUld,GAClBkI,GAASiV,KACZtK,EAAI,UAAYsK,GAAWjV,GACxBwV,GAAYN,KACfvK,EAAI,aAAeuK,GAAcM,EACnC,CAEA,SAASC,GAASC,EAAKC,EAAKjb,EAAOrX,EAAMY,EAAS,EAAG,CACpD,GAAIZ,EAAK,OAAS,GAAKqyB,EAAI,KAAKrjB,EAAM4hB,EAAa,IAAM0B,GAAO,MAAQA,EAAI,KAAO,MAAO,CACzF,IAAIryB,EAAMmD,GAAOjD,GAAI,CAAC,EAClBD,EAAMkD,GAAOhD,GAAIJ,EAAK,OAAS,CAAC,EAGhC0C,EAAS2U,EAAM,KAAO,KAAO1W,GAAUX,EAAMC,EAAKC,EAAKU,EAAQyxB,EAAI,OAAS,CAAC,EAAI,CAAChb,EAAM,IAAKA,EAAM,GAAG,EAG1Ggb,EAAI,IAAMlxB,GAAIkxB,EAAI,IAAKhb,EAAM,IAAM3U,EAAO,CAAC,CAAC,EAC5C2vB,EAAI,IAAMjxB,GAAIixB,EAAI,IAAKhb,EAAM,IAAM3U,EAAO,CAAC,CAAC,CAC7C,CACD,CAEA,IAAM6vB,GAAY,CAAC,IAAK,KAAM,IAAK,IAAI,EAEvC,SAASC,IAAY,CAIpB,QAAS1pB,KAAK2P,EAAQ,CACrB,IAAIpC,EAAKoC,EAAO3P,CAAC,EAEb8f,EAAW9f,CAAC,GAAK,OAGnBuN,EAAG,KAAO,MAEVuS,EAAWd,CAAS,GAAK,MAAQzR,EAAG,KAAKrH,EAAM4hB,EAAa,KAG7DhI,EAAW9f,CAAC,EAAIypB,GAElB,CAGA,QAASzpB,KAAK2P,EAAQ,CACrB,IAAIpC,EAAKoC,EAAO3P,CAAC,EAEb8f,EAAW9f,CAAC,GAAK,MAAQuN,EAAG,MAAQ,MAAQuS,EAAWvS,EAAG,IAAI,GAAK,OACtEuS,EAAW9f,CAAC,EAAIypB,GAClB,CAGI3J,EAAWd,CAAS,GAAK,MAC5B0E,GAAa,EAAI,EAElB,IAAIiG,EAAY,CAAC,EAEjB,QAAS3pB,KAAK8f,EAAY,CACzB,IAAI0J,EAAM1J,EAAW9f,CAAC,EAEtB,GAAIwpB,GAAO,KAAM,CAChB,IAAID,EAAMI,EAAU3pB,CAAC,EAAIJ,GAAK+P,EAAO3P,CAAC,EAAGP,EAAS,EAElD,GAAI+pB,EAAI,KAAO,KACdvpB,GAAOspB,EAAKC,CAAG,UACPxpB,GAAKgf,GAAavP,GAAQ,EAClC,GAAImY,IAAW,GAAK2B,EAAI,MAAQ,KAAM,CACrC,IAAI3vB,EAAS2vB,EAAI,MAAMrjB,EAAM,KAAM,KAAMlG,CAAC,EAC1CupB,EAAI,IAAM3vB,EAAO,CAAC,EAClB2vB,EAAI,IAAM3vB,EAAO,CAAC,CACnB,MAEC2vB,EAAI,IAAMpxB,GACVoxB,EAAI,IAAM,CAACpxB,EAGd,CACD,CAEA,GAAIyvB,GAAU,EAAG,CAEhBlY,EAAO,QAAQ,CAAC9J,EAAGrO,IAAM,CACxB,GAAIkY,GAAQ,EAAG,CACd,IAAIzP,EAAI4F,EAAE,MACN4jB,EAAM1J,EAAW9f,CAAC,EAEtB,GAAIwpB,GAAO,KACV,OAED,IAAID,EAAMI,EAAU3pB,CAAC,EAErB,GAAIzI,GAAK,EAAG,CACX,IAAIqC,EAAS2vB,EAAI,MAAMrjB,EAAMqjB,EAAI,IAAKA,EAAI,IAAKvpB,CAAC,EAEhDupB,EAAI,IAAM3vB,EAAO,CAAC,EAClB2vB,EAAI,IAAM3vB,EAAO,CAAC,EAElBvC,GAAKb,GAAW+yB,EAAI,IAAKryB,EAAK,CAAC,CAAC,EAChCI,GAAKd,GAAW+yB,EAAI,IAAKryB,EAAK,CAAC,CAAC,EAG5BI,GAAKD,GAAK,IAETH,EAAK,CAAC,EAAEG,EAAE,EAAIkyB,EAAI,KACrBlyB,KACGH,EAAK,CAAC,EAAEI,EAAE,EAAIiyB,EAAI,KACrBjyB,MAGFsO,EAAE,IAAMiiB,GAAMxwB,EAAE,EAChBuO,EAAE,IAAMiiB,GAAMvwB,EAAE,CACjB,MACSsO,EAAE,MAAQA,EAAE,MACpB0jB,GAASC,EAAKC,EAAK5jB,EAAG1O,EAAKK,CAAC,EAAGqO,EAAE,MAAM,EAExCA,EAAE,KAAK,CAAC,EAAIvO,GACZuO,EAAE,KAAK,CAAC,EAAItO,EACb,SAEKC,EAAI,GACHqO,EAAE,MAAQA,EAAE,KAAM,CAErB,GAAI,CAAEgkB,EAAQC,CAAO,EAAIjkB,EAAE,OACvBoZ,EAAY4K,EAAO,MACnBE,EAAYD,EAAO,MACnB,CAAE3b,EAAO6b,CAAM,EAAI7yB,EAAKK,CAAC,EAEzByyB,EAAOL,EAAU3K,CAAS,EAC1BiL,EAAON,EAAUG,CAAS,EAG9BE,GAAQ,MAAQV,GAASU,EAAMlK,EAAWd,CAAS,EAAG4K,EAAQ1b,EAAO0b,EAAO,MAAM,EAClFK,GAAQ,MAAQX,GAASW,EAAMnK,EAAWgK,CAAS,EAAGD,EAAQE,EAAOF,EAAO,MAAM,EAGlFjkB,EAAE,IAAMikB,EAAO,IACfjkB,EAAE,IAAMikB,EAAO,GAChB,CAGH,CAAC,EAGD,QAAS7pB,KAAK2pB,EAAW,CACxB,IAAIJ,EAAMI,EAAU3pB,CAAC,EACjBwpB,EAAM1J,EAAW9f,CAAC,EAEtB,GAAIupB,EAAI,MAAQ,OAASC,GAAO,MAAQA,EAAI,KAAO,MAAO,CACzD,IAAI5vB,EAAS2vB,EAAI,MAChBrjB,EACAqjB,EAAI,KAAQpxB,GAAM,KAAOoxB,EAAI,IAC7BA,EAAI,KAAO,CAACpxB,GAAM,KAAOoxB,EAAI,IAC7BvpB,CACD,EACAupB,EAAI,IAAM3vB,EAAO,CAAC,EAClB2vB,EAAI,IAAM3vB,EAAO,CAAC,CACnB,CACD,CACD,CAGA,QAASoG,KAAK2pB,EAAW,CACxB,IAAIJ,EAAMI,EAAU3pB,CAAC,EAErB,GAAIupB,EAAI,MAAQ,KAAM,CACrB,IAAIhxB,EAAOoxB,EAAUJ,EAAI,IAAI,EAE7B,GAAIhxB,EAAK,KAAO,KACfgxB,EAAI,IAAMA,EAAI,IAAM,SAChB,CACJ,IAAI3vB,EAAS2vB,EAAI,MAAMrjB,EAAM3N,EAAK,IAAKA,EAAK,IAAKyH,CAAC,EAClDupB,EAAI,IAAM3vB,EAAO,CAAC,EAClB2vB,EAAI,IAAM3vB,EAAO,CAAC,CACnB,CACD,CACD,CAEA,IAAIswB,EAAU,CAAC,EACXC,EAAa,GAEjB,QAASnqB,KAAK2pB,EAAW,CACxB,IAAIJ,EAAMI,EAAU3pB,CAAC,EACjBuN,EAAKoC,EAAO3P,CAAC,EAEjB,GAAIuN,EAAG,KAAOgc,EAAI,KAAOhc,EAAG,KAAOgc,EAAI,IAAK,CAC3Chc,EAAG,IAAMgc,EAAI,IACbhc,EAAG,IAAMgc,EAAI,IAEb,IAAItc,EAAQM,EAAG,MAEfA,EAAG,KAAON,GAAS,EAAIpU,GAAM0U,EAAG,GAAG,EAAIN,GAAS,EAAInQ,GAAMyQ,EAAG,IAAKA,EAAG,KAAK,EAAIN,GAAS,IAAMM,EAAG,IAAIA,EAAG,GAAG,EAAIA,EAAG,IACjHA,EAAG,KAAON,GAAS,EAAIpU,GAAM0U,EAAG,GAAG,EAAIN,GAAS,EAAInQ,GAAMyQ,EAAG,IAAKA,EAAG,KAAK,EAAIN,GAAS,IAAMM,EAAG,IAAIA,EAAG,GAAG,EAAIA,EAAG,IAEjH2c,EAAQlqB,CAAC,EAAImqB,EAAa,EAC3B,CACD,CAEA,GAAIA,EAAY,CAEfza,EAAO,QAAQ,CAAC9J,EAAGrO,IAAM,CACpBkY,GAAQ,EACPlY,EAAI,GAAK2yB,EAAQ,IACpBtkB,EAAE,OAAS,MAGRskB,EAAQtkB,EAAE,KAAK,IAClBA,EAAE,OAAS,KAEd,CAAC,EAED,QAAS5F,KAAKkqB,EACbhH,GAAqB,GACrBkE,GAAK,WAAYpnB,CAAC,EAGfygB,IAAcF,EAAO,MAAQ,IAChC4C,GAAkBE,GAAkB,GACtC,CAEA,QAASrjB,KAAK8f,EACbA,EAAW9f,CAAC,EAAI,IAClB,CAGA,SAASoqB,GAAaC,EAAO,CAC5B,IAAIlzB,EAAM8F,GAAM5F,GAAK,EAAG,EAAGuwB,GAAU,CAAC,EAClCxwB,EAAM6F,GAAM3F,GAAK,EAAG,EAAGswB,GAAU,CAAC,EAEtC,KAAOyC,EAAMlzB,CAAG,GAAK,MAAQA,EAAM,GAClCA,IAED,KAAOkzB,EAAMjzB,CAAG,GAAK,MAAQA,EAAMwwB,GAAU,GAC5CxwB,IAED,MAAO,CAACD,EAAKC,CAAG,CACjB,CAEA,SAAS+nB,IAAa,CACrB,GAAIyI,GAAU,EAAG,CAChB,IAAI0C,EAAc5a,EAAO,KAAK9J,GAAKA,EAAE,MAAM,GAAKojB,IAAYtC,GAAM,MAE9D4D,IACH9L,EAAI,YAAcwK,GAAWtC,GAAM,OAEpChX,EAAO,QAAQ,CAAC9J,EAAGrO,IAAM,CACxB,GAAIA,EAAI,GAAKqO,EAAE,OACd2kB,GAAgBhzB,EAAG,EAAK,EACxBgzB,GAAgBhzB,EAAG,EAAI,EAEnBqO,EAAE,QAAU,MAAM,CACrB,IAAI4kB,EAAYxB,GAEZA,IAAYpjB,EAAE,QACjB4Y,EAAI,YAAcwK,GAAWpjB,EAAE,OAEhC,IAAI6kB,EAAQhb,GAAQ,EAAI,CAAC,EAAGvY,EAAKK,CAAC,EAAE,CAAC,EAAE,OAAS,CAAC,EAAI6yB,GAAalzB,EAAKK,CAAC,CAAC,EACzEqO,EAAE,OAASA,EAAE,MAAMM,EAAM3O,EAAGkzB,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EAE1CzB,IAAYwB,IACfhM,EAAI,YAAcwK,GAAWwB,EAC/B,CAEF,CAAC,EAED9a,EAAO,QAAQ,CAAC9J,EAAGrO,IAAM,CACxB,GAAIA,EAAI,GAAKqO,EAAE,KAAM,CACpB,IAAI4kB,EAAYxB,GAEZA,IAAYpjB,EAAE,QACjB4Y,EAAI,YAAcwK,GAAWpjB,EAAE,OAEhCA,EAAE,QAAU,MAAQ8kB,GAASnzB,EAAG,EAAK,EAErC,CACC,IAAIozB,EAAQ/kB,EAAE,QAAU,KAAOA,EAAE,OAAO,KAAO,KAE3CglB,EAAOhlB,EAAE,OAAO,KAAKM,EAAM3O,EAAGF,GAAIC,GAAIqzB,CAAK,EAC3CvoB,EAAOwD,EAAE,OAAO,OAAOM,EAAM3O,EAAGqzB,EAAMD,CAAK,GAE3CC,GAAQxoB,KACXwD,EAAE,OAAO,OAASA,EAAE,OAAO,MAAMM,EAAM3O,EAAGF,GAAIC,GAAI8K,CAAI,EACtDsoB,GAASnzB,EAAG,EAAI,EAElB,CAEIyxB,IAAYwB,IACfhM,EAAI,YAAcwK,GAAWwB,GAE9BpD,GAAK,aAAc7vB,CAAC,CACrB,CACD,CAAC,EAEG+yB,IACH9L,EAAI,YAAcwK,GAAW,EAC/B,CACD,CAEA,SAASuB,GAAgB5oB,EAAIkpB,EAAS,CACrC,IAAIjlB,EAAIilB,EAAUnb,EAAO/N,CAAE,EAAE,OAAS+N,EAAO/N,CAAE,EAE/CiE,EAAE,QAAUA,EAAE,OAAOM,EAAMvE,CAAE,EAC7BiE,EAAE,MAAUA,EAAE,KAAKM,EAAMvE,CAAE,CAC5B,CAEA,SAAS+oB,GAAS/oB,EAAIkpB,EAAS,CAC9B,IAAIjlB,EAAIilB,EAAUnb,EAAO/N,CAAE,EAAE,OAAS+N,EAAO/N,CAAE,EAE3C,CACH,OAAAuU,EACA,KAAAR,EACA,KAAMoV,EACN,MAAAC,EAEA,QAASC,EAAcplB,EAAE,QACzB,MAASqlB,EAAcrlB,EAAE,MACzB,OAAS0E,EAAc1E,EAAE,KAC1B,EAAIA,EAAE,OAEN0E,EAAQ9Q,GAAS8Q,EAAQ5W,GAAS,CAAC,EAEnC,IAAIw3B,EAAa,KACbC,EAAU7gB,EAAQ,EAAK,EAEvBugB,GAAWI,GAAa,OAC3BA,EAAY3gB,EAAQ,EAAI,OAAS0gB,GAElC,IAAII,EAAWxlB,EAAE,SAAW,GAAKulB,EAAS,EAI1C,GAFAC,GAAY5M,EAAI,UAAU2M,EAAQA,CAAM,EAEpC,CAACN,EAAS,CACb,IAAIlV,GAAM5C,GAAUzI,EAAQ,EAC3BsL,GAAM5C,GAAU1I,EAAQ,EACxBuL,EAAM5C,GAAU3I,EAChBwL,EAAM5C,GAAU5I,EAEjB4gB,EAAa,IAAI,OACjBA,EAAW,KAAKvV,GAAKC,GAAKC,EAAKC,CAAG,CACnC,CAGI+U,EACHQ,GAAWL,EAAa1gB,EAAO1E,EAAE,KAAMA,EAAE,IAAKqlB,EAAW/U,EAAQR,EAAMqV,EAAOD,CAAQ,EAEtFQ,GAAW3pB,EAAIqpB,EAAa1gB,EAAO1E,EAAE,KAAMA,EAAE,IAAKqlB,EAAW/U,EAAQR,EAAMqV,EAAOG,EAAYJ,CAAQ,EAEvGM,GAAY5M,EAAI,UAAU,CAAC2M,EAAQ,CAACA,CAAM,CAC3C,CAEA,SAASG,GAAW3pB,EAAIqpB,EAAaO,EAAWC,EAAUC,EAASR,EAAW1Z,EAAYma,EAAUX,EAAOG,EAAYJ,EAAU,CAChI,IAAIa,EAAgB,GAIpBZ,GAAS,GAAK9Z,EAAM,QAAQ,CAACnT,EAAG8tB,KAAO,CAEtC,GAAI9tB,EAAE,OAAO,CAAC,GAAK6D,EAAI,CACtB,IAAIkqB,GAAYnc,EAAO5R,EAAE,OAAO,CAAC,CAAC,EAC9BguB,EAAY50B,EAAK4G,EAAE,OAAO,CAAC,CAAC,EAE5BiuB,GAAYF,GAAU,QAAU3sB,IAAW,KAE3CG,GAAM0sB,CAAQ,IACjBA,EAAWjuB,EAAE,KAAO,EAAIiuB,EAAS,CAAC,EAAIA,EAAS,CAAC,GAEjD,IAAIC,EAEAC,GAAa,KAGbJ,GAAU,MAAQE,GAAYtxB,GAAQqxB,EAAWz0B,GAAIC,EAAE,GAC1D20B,GAAanuB,EAAE,KAAKoI,EAAM0lB,EAAE,GAAKX,EACjCe,EAAYH,GAAU,OAAO,MAG7BE,EAAW,KAEZV,GAAWL,EAAaO,EAAWC,EAAUC,EAASQ,GAAY1a,EAAYma,EAAUX,EAAOG,EAAYJ,EAAUkB,EAAWD,CAAQ,EAExIJ,EAAgB,EACjB,CACD,CAAC,EAEIA,GACJN,GAAWL,EAAaO,EAAWC,EAAUC,EAASR,EAAW1Z,EAAYma,EAAUX,EAAOG,EAAYJ,CAAQ,CACpH,CAEA,IAAMoB,GAAmB7c,GAAiBC,GAE1C,SAAS+b,GAAWL,EAAaO,EAAWC,EAAUC,EAASR,EAAW1Z,EAAYma,EAAUX,EAAOG,EAAYJ,EAAUkB,EAAWD,EAAU,CACjJ9C,GAAY+B,EAAaO,EAAWC,EAAUC,EAASR,CAAS,GAE5DC,GAAcJ,GAAYiB,KAC7BvN,EAAI,KAAK,EACT0M,GAAc1M,EAAI,KAAK0M,CAAU,EACjCJ,GAAYtM,EAAI,KAAKsM,CAAQ,GAG1BiB,GACEhB,EAAQmB,KAAqBA,IACjC1N,EAAI,KAAKuN,CAAQ,EACjBC,GAAaxN,EAAI,KAAKwN,CAAS,EAC/BG,GAAOlB,EAAWS,CAAQ,EAC1BU,GAASpB,EAAazZ,EAAYga,CAAS,GAEnCR,EAAQzb,IAChB6c,GAAOlB,EAAWS,CAAQ,EAC1BlN,EAAI,KAAKuN,CAAQ,EACjBK,GAASpB,EAAazZ,EAAYga,CAAS,GAEnCR,EAAQ1b,KAChBmP,EAAI,KAAK,EACTA,EAAI,KAAKuN,CAAQ,EACjBC,GAAaxN,EAAI,KAAKwN,CAAS,EAC/BG,GAAOlB,EAAWS,CAAQ,EAC1BlN,EAAI,QAAQ,EACZ4N,GAASpB,EAAazZ,EAAYga,CAAS,IAI5CY,GAAOlB,EAAWS,CAAQ,EAC1BU,GAASpB,EAAazZ,EAAYga,CAAS,IAGxCL,GAAcJ,GAAYiB,IAC7BvN,EAAI,QAAQ,CACd,CAEA,SAAS4N,GAASpB,EAAazZ,EAAYga,EAAW,CACjDA,EAAY,IACXha,aAAsB,IACzBA,EAAW,QAAQ,CAACA,EAAYyZ,IAAgB,CAC/CxM,EAAI,YAAc+J,GAAYyC,EAC9BxM,EAAI,OAAOjN,CAAU,CACtB,CAAC,EAGDA,GAAc,MAAQyZ,GAAexM,EAAI,OAAOjN,CAAU,EAE7D,CAEA,SAAS4a,GAAOlB,EAAWS,EAAU,CAChCA,aAAoB,IACvBA,EAAS,QAAQ,CAACA,EAAUT,IAAc,CACzCzM,EAAI,UAAYgK,GAAUyC,EAC1BzM,EAAI,KAAKkN,CAAQ,CAClB,CAAC,EAGDA,GAAY,MAAQT,GAAazM,EAAI,KAAKkN,CAAQ,CACpD,CAEA,SAASW,GAAalmB,EAAS9N,EAAKC,EAAKg0B,EAAS,CACjD,IAAIjf,EAAO0R,EAAK5Y,CAAO,EAEnBomB,EAEJ,GAAID,GAAW,EACdC,EAAY,CAAC,EAAG,CAAC,MACb,CACJ,IAAI1kB,EAAWwF,EAAK,OAASA,EAAK,MAAMnH,EAAMC,EAAS9N,EAAKC,EAAKg0B,CAAO,EACpExtB,EAAWuO,EAAK,OAASA,EAAK,MAAMnH,EAAMC,EAAS9N,EAAKC,EAAKg0B,EAASzkB,CAAQ,EAClF0kB,EAAejP,GAASjlB,EAAKC,EAAKwG,EAAOwtB,EAASzkB,CAAQ,CAC3D,CAEA,OAAQwF,EAAK,OAASkf,CACvB,CAEA,SAASC,GAAejlB,EAAMklB,EAAO3Z,EAAK8R,EAAM8H,EAAMruB,EAAKiM,EAAO4L,EAAQgT,EAAMC,EAAK,CACpF,IAAIgC,EAAU7gB,EAAQ,EAAK,EAE3B+J,GAAW,GAAKmK,EAAI,UAAU2M,EAAQA,CAAM,EAE5ClC,GAAY/S,EAAQ5L,EAAO4e,EAAMC,EAAKjT,CAAM,EAE5CsI,EAAI,UAAU,EAEd,IAAIhM,EAAIC,EAAIC,GAAI8B,GAAImY,EAAOD,GAAQ9H,GAAQ,GAAKA,GAAQ,EAAI,CAACvmB,EAAMA,GAE/DyU,GAAO,GACVL,EAAKia,EACLlY,GAAKmY,IAGLna,EAAKka,EACLha,GAAKia,GAGN,QAASp1B,EAAI,EAAGA,EAAIgQ,EAAK,OAAQhQ,IAC5Bk1B,EAAMl1B,CAAC,GAAK,OACXub,GAAO,EACVN,EAAKE,GAAKnL,EAAKhQ,CAAC,EAEhBkb,EAAK+B,GAAKjN,EAAKhQ,CAAC,EAEjBinB,EAAI,OAAOhM,EAAIC,CAAE,EACjB+L,EAAI,OAAO9L,GAAI8B,EAAE,GAInBgK,EAAI,OAAO,EAEXnK,GAAW,GAAKmK,EAAI,UAAU,CAAC2M,EAAQ,CAACA,CAAM,CAC/C,CAEA,SAAS/G,GAASF,EAAU,CAG3B,IAAID,EAAY,GAEhB,OAAAlF,EAAK,QAAQ,CAAC1R,EAAM9V,IAAM,CACzB,GAAI,CAAC8V,EAAK,KACT,OAED,IAAIY,EAAQ0B,EAAOtC,EAAK,KAAK,EAE7B,GAAIY,EAAM,KAAO,KAAM,CAClBZ,EAAK,QACR4W,EAAY,GACZ5W,EAAK,MAAQ,GACbqW,GAAa,EAAK,GAEnB,MACD,MAEMrW,EAAK,QACT4W,EAAY,GACZ5W,EAAK,MAAQ,GACbqW,GAAa,EAAK,GAIpB,IAAIkB,EAAOvX,EAAK,KACZyF,EAAM8R,EAAO,EAEb,CAAC,IAAAvsB,EAAK,IAAAC,CAAG,EAAI2V,EAEb,CAAChP,EAAO2tB,CAAM,EAAIP,GAAa90B,EAAGc,EAAKC,EAAKwa,GAAO,EAAI0P,EAAaC,CAAU,EAElF,GAAImK,GAAU,EACb,OAGD,IAAIxgB,EAAW6B,EAAM,OAAS,EAE1B4e,EAAUxf,EAAK,QAAUA,EAAK,OAAOnH,EAAM3O,EAAGc,EAAKC,EAAK2G,EAAO2tB,EAAQxgB,CAAQ,EAI/E5F,GAASyH,EAAM,OAAS,EAAI4e,EAAQ,IAAIt1B,GAAKswB,GAAMtwB,CAAC,CAAC,EAAIs1B,EACzDruB,GAASyP,EAAM,OAAS,EAAI4Z,GAAMgF,EAAQ,CAAC,CAAC,EAAIhF,GAAMgF,EAAQ,CAAC,CAAC,EAAI5tB,EAEpE6tB,EAASzf,EAAK,QAAUA,EAAK,OAAOnH,EAAMmH,EAAK,OAAOnH,EAAMM,GAAQjP,EAAGq1B,EAAQpuB,EAAI,EAAGjH,EAAGq1B,EAAQpuB,EAAI,EAGzG6O,EAAK,QAAUuX,GAAQ,EAAIvX,EAAK,OAAOnH,EAAM4mB,EAAQv1B,EAAGq1B,CAAM,EAAI,EAElE,IAAI12B,EAAUmX,EAAK,MAEnBA,EAAK,MAAQrU,GAAKqU,EAAK,KAAKnH,EAAM4mB,EAAQv1B,EAAG2sB,CAAQ,CAAC,EAElDhuB,GAAW,MAAQmX,EAAK,OAASnX,IACpC+tB,EAAY,GACd,CAAC,EAEMA,CACR,CAEA,SAASK,GAAYJ,EAAU,CAC9B,IAAID,EAAY,GAEhB,OAAA0D,GAAQ,QAAQ,CAACjpB,EAAGnH,IAAM,CACzB,IAAIw1B,EAAKruB,EAAEwH,EAAM3O,EAAG0tB,GAAef,CAAQ,EAEvC6I,GAAM7H,GAAS3tB,CAAC,IACnB0sB,EAAY,IAEbiB,GAAS3tB,CAAC,EAAIw1B,CACf,CAAC,EAEM9I,CACR,CAEA,SAAS/E,IAAe,CACvB,QAAS3nB,EAAI,EAAGA,EAAIwnB,EAAK,OAAQxnB,IAAK,CACrC,IAAI8V,EAAO0R,EAAKxnB,CAAC,EAEjB,GAAI,CAAC8V,EAAK,MAAQ,CAACA,EAAK,MACvB,SAED,IAAIuX,EAAOvX,EAAK,KACZyF,EAAM8R,EAAO,EAEb5nB,EAAG8I,EAEHmlB,EAAY5d,EAAK,OAAOnH,EAAM3O,CAAC,EAE/By1B,EAAWpI,GAAQ,GAAKA,GAAQ,EAAI,GAAK,EAEzC,CAAC3lB,EAAO2tB,CAAM,EAAIvf,EAAK,OAG3B,GAAIA,EAAK,OAAS,KAAM,CACvB,IAAI4f,GAAW5f,EAAK,SAAW2f,EAC3BE,GAAWvwB,IAAO0Q,EAAK,MAAQ4f,IAAYv5B,EAAO,EAEtD01B,GAAa/b,EAAK,UAAU,CAAC,EAAG4d,EAAW,SAAUrG,GAAQ,EAAIvyB,GAAMC,EAAM,EAE7EksB,EAAI,KAAK,EAEL1L,GAAO,GACV9V,EAAI8I,EAAI,EAER0Y,EAAI,UACH0O,GACAvwB,GAAMqW,GAAUE,GAAU,CAAC,CAC5B,EACAsL,EAAI,QAAQoG,GAAQ,EAAI,CAACloB,GAAKA,IAAM,CAAC,IAIrCM,EAAIL,GAAMoW,GAAUE,GAAU,CAAC,EAC/BnN,EAAIonB,IAGL,IAAIC,GAASjwB,GAAKmQ,EAAK,KAAK,EAAIA,EAAK,MAAMnH,EAAM3O,EAAG0H,EAAO2tB,CAAM,EAAIvf,EAAK,MAE1EmR,EAAI,SAAS2O,GAAQnwB,EAAG8I,CAAC,EAEzB0Y,EAAI,QAAQ,CACb,CAEA,GAAIoO,GAAU,EACb,SAED,IAAI3e,EAAQ0B,EAAOtC,EAAK,KAAK,EAEzB+f,EAAUta,GAAO,EAAIG,GAAUC,GAC/Bma,EAAUva,GAAO,EAAIC,GAAUC,GAE/B6Z,GAAUxf,EAAK,QAIf7G,GAASyH,EAAM,OAAS,EAAI4e,GAAQ,IAAIt1B,IAAKswB,GAAMtwB,EAAC,CAAC,EAAIs1B,GACzDruB,EAASyP,EAAM,OAAS,EAAI4Z,GAAMgF,GAAQ,CAAC,CAAC,EAAIhF,GAAMgF,GAAQ,CAAC,CAAC,EAAI5tB,EAEpEwM,EAAQ4B,EAAK,MACb3B,EAAS2B,EAAK,OACdigB,GAAY7hB,EAAM,KAAOA,EAAM,KAAO,EACtC8hB,GAAW5wB,GAAM2wB,GAAY55B,EAAO,EACpC85B,GAAU7wB,IAAO0Q,EAAK,SAAW,EAAIA,EAAK,MAAQigB,GAAYjgB,EAAK,IAAMA,EAAK,KAAO3Z,EAAO,EAG5F+5B,GAAQpgB,EAAK,QAAU,CAAC3Q,GAAG,IAE3BgxB,GAAWvb,EAAQ9E,EAAK,KAAO3Z,EAAO,EACtCu5B,IAAYM,GAAWC,IAAWR,EAClCW,GAAWD,GAAUT,GACrBnnB,EAAWgN,GAAO,EAAI6a,GAAW,EACjC3wB,EAAW8V,GAAO,EAAI6a,GAAW,EAErC,IAAIhiB,GAAe0B,EAAK,KAAK,CAAC,EAC1BugB,GAAevgB,EAAK,OAAS,EAAI9a,GAClB8a,EAAK,OAAS,EAAI7a,GAClBi7B,GAAQ,EAAIl7B,GACZk7B,GAAQ,EAAIj7B,GACZsgB,GAAO,EAAI,SAAW8R,GAAQ,EAAIpyB,GAAQD,GACzDs7B,GAAeJ,IACA3a,GAAO,EAAI,SAAW8R,GAAQ,EAAIvyB,GAAQC,GAE7D82B,GAAazd,GAAMsf,EAAW2C,GAAWC,EAAY,EAErD,IAAIC,GAAazgB,EAAK,KAAK,CAAC,EAAIA,EAAK,QAEjC0gB,GAAUlB,GAAQ,IAAIrwB,IAAO2V,EAAQgM,EAAO3hB,GAAKyR,EAAOmf,EAASC,CAAO,CAAC,CAAC,EAE1EW,GAAU3gB,EAAK,QAEnB,QAAS9V,GAAI,EAAGA,GAAIy2B,GAAQ,OAAQz2B,KAAK,CACxC,IAAIiF,GAAMwxB,GAAQz2B,EAAC,EAEnB,GAAIiF,IAAO,KAAM,CACZsW,GAAO,EACV9V,EAAI+wB,GAAQx2B,EAAC,EAEbuO,EAAIioB,GAAQx2B,EAAC,EAEdiF,GAAM,GAAKA,GAEX,IAAIyxB,GAASzxB,GAAI,QAAQ;AAAA,CAAI,GAAK,GAAK,CAACA,EAAG,EAAIA,GAAI,MAAM,MAAM,EAE/D,QAASgG,GAAI,EAAGA,GAAIyrB,GAAO,OAAQzrB,KAAK,CACvC,IAAIkf,GAAOuM,GAAOzrB,EAAC,EAEfirB,IACHjP,EAAI,KAAK,EACTA,EAAI,UAAUxhB,EAAG8I,EAAItD,GAAIsrB,EAAU,EACnCtP,EAAI,OAAOiP,EAAK,EAChBjP,EAAI,SAASkD,GAAM,EAAG,CAAC,EACvBlD,EAAI,QAAQ,GAGZA,EAAI,SAASkD,GAAM1kB,EAAG8I,EAAItD,GAAIsrB,EAAU,CAC1C,CACD,CACD,CAGIriB,EAAM,MACT+gB,GACCuB,GACAtiB,EAAM,OAAOvF,EAAMM,GAAQjP,EAAGq1B,EAAQpuB,CAAI,EAC1CsU,EACA8R,EACA8I,GACAH,GACA/zB,GAASiS,EAAM,MAAQ/X,GAAS,CAAC,EACjC+X,EAAM,OAAOvF,EAAM3O,CAAC,EACpBkU,EAAM,KACNA,EAAM,GACP,EAID,IAAID,GAAO6B,EAAK,KAEZ7B,GAAK,MACRghB,GACCuB,GACAviB,GAAK,OAAOtF,EAAMM,GAAQjP,EAAGq1B,EAAQpuB,CAAI,EACzCsU,EACAA,GAAO,EAAI,EAAI,EACfA,GAAO,EAAIE,GAAUD,GACrBD,GAAO,EAAII,GAAUD,GACrBzZ,GAASgS,GAAK,MAAQ9X,GAAS,CAAC,EAChC8X,GAAK,OAAOtF,EAAM3O,CAAC,EACnBiU,GAAK,KACLA,GAAK,GACN,EAGGE,EAAO,MACV8gB,GACC,CAACkB,EAAO,EACR,CAAC,CAAC,EACF5a,GAAO,EAAI,EAAI,EACfA,GAAO,EAAI,EAAI,EACfA,GAAO,EAAIE,GAAUD,GACrBD,GAAO,EAAII,GAAUD,GACrBzZ,GAASkS,EAAO,MAAQhY,GAAS,CAAC,EAClCgY,EAAO,OAAOxF,EAAM3O,CAAC,EACrBmU,EAAO,KACPA,EAAO,GACR,CAEF,CAEA0b,GAAK,UAAU,CAChB,CAEA,SAAS1D,GAAa9pB,EAAQ,CAG7B8V,EAAO,QAAQ,CAAC9J,EAAGrO,IAAM,CACpBA,EAAI,IACPqO,EAAE,OAAS,KAEPhM,IACC6V,GAAQ,GACX7J,EAAE,IAAM,KACRA,EAAE,IAAM,MAGRA,EAAE,OAAO,QAAQ,GAAK,CACrB,EAAE,IAAM,KACR,EAAE,IAAM,IACT,CAAC,GAIL,CAAC,CACF,CAEA,IAAIsoB,GAAe,GACfC,GAAa,GACbC,GAAa,CAAC,EAElB,SAASC,IAAa,CACrBF,GAAa,GAEb,QAAS52B,EAAI,EAAGA,EAAI62B,GAAW,OAAQ72B,IACtC6vB,GAAK,GAAGgH,GAAW72B,CAAC,CAAC,EAEtB62B,GAAW,OAAS,CACrB,CAEA,SAASzK,IAAS,CACZuK,KACJlsB,GAAUssB,EAAO,EACjBJ,GAAe,GAEjB,CAGA,SAASK,GAAMtsB,EAAIusB,EAAc,GAAO,CACvCN,GAAe,GACfC,GAAaK,EAEbvsB,EAAGiE,CAAI,EACPooB,GAAQ,EAEJE,GAAeJ,GAAW,OAAS,GACtC,eAAeC,EAAU,CAC3B,CAEAnoB,EAAK,MAAQqoB,GAEb,SAASD,IAAU,CAalB,GAVItL,KACH0G,GAAU,EACV1G,GAAkB,IAGfE,KACHc,GAAa,EACbd,GAAqB,IAGlBD,GAAe,CA2ClB,GA1CA5uB,GAAWyqB,EAAOvsB,GAAQmwB,EAAU,EACpCruB,GAAWyqB,EAAOzsB,GAAQswB,EAAU,EACpCtuB,GAAWyqB,EAAO3sB,GAAQqwB,CAAU,EACpCnuB,GAAWyqB,EAAO1sB,GAAQqwB,CAAU,EAEpCpuB,GAAWqqB,EAAMnsB,GAASmwB,EAAU,EACpCruB,GAAWqqB,EAAMrsB,GAASswB,EAAU,EACpCtuB,GAAWqqB,EAAMvsB,GAASqwB,CAAU,EACpCnuB,GAAWqqB,EAAMtsB,GAASqwB,CAAU,EAEpCpuB,GAAWoqB,EAAMtsB,GAASmwB,EAAU,EACpCjuB,GAAWoqB,EAAMrsB,GAASmwB,EAAU,EAIpChE,EAAI,MAAS5hB,GAAM2lB,GAAa5uB,EAAO,EACvC6qB,EAAI,OAAS5hB,GAAM4lB,GAAa7uB,EAAO,EAEvCqrB,EAAK,QAAQ,CAAC,CAAE,IAAA0P,EAAK,MAAAC,EAAO,MAAA7J,EAAO,KAAA8J,EAAM,KAAA/J,CAAK,IAAM,CACnD,GAAI6J,GAAO,KACV,GAAIC,EAAO,CACV,IAAIE,EAAahK,IAAS,GAAKA,IAAS,EAAIC,EAAQ,EAChDC,EAAOF,EAAO,GAAK,EAEvBvwB,GAAWo6B,EAAK3J,EAAO,OAAW,MAAU6J,EAAOC,CAAS,EAC5Dv6B,GAAWo6B,EAAK3J,EAAO,QAAW,SAAUD,CAAK,EACjDxwB,GAAWo6B,EAAK3J,EAAO,MAAW,OAAUA,EAAOnC,GAAaD,EAAU,EAC1EruB,GAAWo6B,EAAK3J,EAAO,SAAW,QAAUA,EAAOrC,EAAaD,CAAU,EAE1EpuB,GAASq6B,EAAKl9B,EAAG,CAClB,MAECyC,GAASy6B,EAAKl9B,EAAG,CAEpB,CAAC,EAGDg3B,GAAYC,GAAUC,GAAWE,GAAUC,GAASC,GAAUC,GAAWC,GAAcL,GAAU,KACjGM,GAAW,EAEX6F,GAAS,EAAI,EAGZnM,IAAcE,IACdD,IAAcE,IACdL,GAAcM,IACdL,GAAcM,GACb,CACDW,GAAa,EAAK,EAElB,IAAIoL,EAAStM,EAAaM,GACtBiM,EAAStM,EAAaM,GAE1B,GAAItC,IAAc,CAAC0C,IAAmB5C,EAAO,MAAQ,EAAG,CACvDA,EAAO,MAAQuO,EACfvO,EAAO,KAAQwO,EAEfC,IAAWj6B,GAAQi6B,GAASryB,GAAM4jB,EAAO,IAAI,EAAG,EAAGiC,EAAYC,CAAU,EACzEwM,IAAWl6B,GAAQk6B,GAAS,EAAGtyB,GAAM4jB,EAAO,GAAG,EAAGiC,EAAYC,CAAU,EAExE,QAASlrB,EAAI,EAAGA,EAAIqvB,GAAU,OAAQrvB,IAAK,CAC1C,IAAI4S,EAAKyc,GAAUrvB,CAAC,EAEhB4S,GAAM,OACT0c,GAAatvB,CAAC,GAAKu3B,EACnBhI,GAAavvB,CAAC,GAAKw3B,EACnBh6B,GAAQoV,EAAInR,GAAK6tB,GAAatvB,CAAC,CAAC,EAAGyB,GAAK8tB,GAAavvB,CAAC,CAAC,EAAGirB,EAAYC,CAAU,EAElF,CACD,CAEA,GAAIyM,GAAO,MAAQ,CAAC9L,IAAmB8L,GAAO,MAAQ,GAAKA,GAAO,MAAQ,EAAG,CAC5EA,GAAO,MAAUJ,EACjBI,GAAO,OAAUJ,EACjBI,GAAO,KAAUH,EACjBG,GAAO,QAAUH,EAEjB,QAASI,KAAQC,GAChB/6B,GAAWg7B,GAAWF,EAAMD,GAAOC,CAAI,CAAC,CAC1C,CAEAvM,GAAcF,GACdG,GAAcF,GACdG,GAAcN,EACdO,GAAcN,CACf,CAEA2E,GAAK,SAAS,EAEdnE,GAAgB,EACjB,CAEIX,GAAa,GAAKC,GAAa,IAClC/D,EAAI,UAAU,EAAG,EAAGD,EAAI,MAAOA,EAAI,MAAM,EACzC6I,GAAK,WAAW,EAChBhI,EAAU,QAAQnd,GAAMA,EAAG,CAAC,EAC5BmlB,GAAK,MAAM,GAGR8H,GAAO,MAAQ9L,KAClBkM,GAAUJ,EAAM,EAChB9L,GAAkB,IAGf3C,IAAc0C,KACjBoM,GAAa,KAAM,GAAM,EAAK,EAC9BpM,GAAkB,IAGf7C,EAAO,MAAQA,EAAO,MAAQ+C,KACjCmM,GAAU,EACVnM,GAAkB,IAGdjF,IACJA,EAAQ,GACRlY,EAAK,OAAS,EAEdkhB,GAAK,OAAO,GAGbU,GAAgB,GAEhBoG,GAAe,EAChB,CAEAhoB,EAAK,OAAS,CAACupB,EAAcC,IAAe,CAC3CxM,GAAqBwM,GAAc,GAE/BD,IAAiB,GACpBnH,GAAUtJ,EAAWrN,EAAO,IAAKA,EAAO,GAAG,EAE3CgS,GAAO,CACT,EAKA,SAASgM,GAASvvB,EAAK6O,EAAM,CAC5B,IAAI1B,EAAKoC,EAAOvP,CAAG,EAEnB,GAAImN,EAAG,MAAQ,KAAM,CACpB,GAAIqa,IAAW,EAAG,CACjB,IAAIhuB,EAAS2T,EAAG,MAAMrH,EAAM+I,EAAK,IAAKA,EAAK,IAAK7O,CAAG,EACnD6O,EAAK,IAAMrV,EAAO,CAAC,EACnBqV,EAAK,IAAMrV,EAAO,CAAC,CACpB,CAEA,GAAIqV,EAAK,IAAMA,EAAK,IAAK,CACxB,IAAIhX,EAAOgX,EAAK,IAChBA,EAAK,IAAMA,EAAK,IAChBA,EAAK,IAAMhX,CACZ,CAEA,GAAI2vB,GAAU,GAAK3Y,EAAK,KAAO,MAAQA,EAAK,KAAO,MAAQA,EAAK,IAAMA,EAAK,IAAM,MAChF,OAEG7O,GAAO4e,GACNzR,EAAG,OAAS,GAAKqa,GAAU,IAC9B3Y,EAAK,IAAMzY,GAAWyY,EAAK,IAAK/X,EAAK,CAAC,CAAC,EACvC+X,EAAK,IAAMzY,GAAWyY,EAAK,IAAK/X,EAAK,CAAC,CAAC,EAEnC+X,EAAK,KAAOA,EAAK,KACpBA,EAAK,OAMR6Q,EAAW1f,CAAG,EAAI6O,EAElB+T,GAAkB,GAClBW,GAAO,CACR,CACD,CAEAzd,EAAK,SAAWypB,GAIhB,IAAIC,GACAC,GACAb,GACAC,GAGAa,GACAC,GAGApR,GACAC,GAGAoR,GACAC,GAGAplB,GACAC,GAEAolB,GAAW,GAETrR,GAAO0B,EAAO,KAEhB4P,GAAQtR,GAAK,EACbuR,GAAQvR,GAAK,EAEb4B,KACCF,EAAO,IACVqP,GAAU/6B,GAASpD,GAAUitB,CAAI,GAC9B6B,EAAO,IACVsP,GAAUh7B,GAASnD,GAAUgtB,CAAI,GAE9B/M,EAAO,KAAO,GACjBqd,GAAUY,GACVX,GAAUY,KAGVb,GAAUa,GACVZ,GAAUW,IAGX/kB,GAAa0V,EAAO,KACpBzV,GAAYyV,EAAO,KAGpB,IAAM2O,GAAShpB,EAAK,OAASjG,GAAO,CACnC,KAAQ,GACR,KAAQ,GACR,KAAQ,EACR,MAAQ,EACR,IAAQ,EACR,OAAQ,CACT,EAAGgP,EAAK,MAAM,EAERogB,GAAYH,GAAO,KAAOr6B,GAASrD,GAAQ09B,GAAO,KAAOxQ,EAAOI,CAAK,EAAI,KAE/E,SAASwQ,GAAUrgB,EAAMohB,EAAO,CAC/B,GAAInB,GAAO,KAAM,CAChB,QAASC,KAAQlgB,EAChBigB,GAAOC,CAAI,EAAIlgB,EAAKkgB,CAAI,EAEpBA,KAAQC,IACX/6B,GAAWg7B,GAAWF,EAAMlgB,EAAKkgB,CAAI,CAAC,EAGxCkB,IAAU,IAASjJ,GAAK,WAAW,CACpC,CACD,CAEAlhB,EAAK,UAAYopB,GAEjB,SAASgB,GAAU/4B,EAAG,CAGrB,GAFQmY,EAAOnY,CAAC,EAEV,KACLipB,IAAcpsB,GAAS0sB,GAAWvpB,CAAC,EAAGhG,EAAG,UAEzCivB,IAAcxsB,GAAS8sB,GAAWvpB,CAAC,EAAGhG,EAAG,EAErCkvB,GAAY,CACf,IAAItW,EAAKwc,GAAcC,GAAU,CAAC,EAAIA,GAAUrvB,CAAC,EACjD4S,GAAM,MAAQpV,GAAQoV,EAAI,IAAK,IAAKqY,EAAYC,CAAU,CAC3D,CAEF,CAEA,SAAS6F,GAAUloB,EAAK/H,EAAKC,EAAK,CACjCq3B,GAASvvB,EAAK,CAAC,IAAA/H,EAAK,IAAAC,CAAG,CAAC,CACzB,CAEA,SAASwpB,GAAUvqB,EAAG0X,EAAMohB,EAAOE,EAAM,CAGpCthB,EAAK,OAAS,MACjBuhB,GAASj5B,CAAC,EAEP0X,EAAK,MAAQ,MAChBS,EAAO,QAAQ,CAAC9J,EAAGjE,IAAO,CACrBA,EAAK,IAAMpK,GAAKoK,GAAMpK,GAAK,QAC9BqO,EAAE,KAAOqJ,EAAK,KACdqhB,GAAU3uB,CAAE,EAER8N,GAAQ,GACX6Y,GAAU1iB,EAAE,OAAO,CAAC,EAAE,MAAO,KAAM,IAAI,EACvC0iB,GAAU1iB,EAAE,OAAO,CAAC,EAAE,MAAO,KAAM,IAAI,GAGvC0iB,GAAU1iB,EAAE,MAAO,KAAM,IAAI,EAE9B+d,GAAO,EAET,CAAC,EAGF0M,IAAU,IAASjJ,GAAK,YAAa7vB,EAAG0X,CAAI,EAE5CshB,GAAQE,GAAQ,YAAavqB,EAAM3O,EAAG0X,CAAI,CAC3C,CAEA/I,EAAK,UAAY4b,GAEjB,SAAS4O,GAAQ9E,EAAI3c,EAAM,CAC1BhP,GAAOgR,EAAM2a,CAAE,EAAG3c,CAAI,CACvB,CAEA,SAAS0hB,GAAQ1hB,EAAM2c,EAAI,CAC1B3c,EAAK,KAAO9R,EAAS8R,EAAK,MAAQ,IAAI,EACtCA,EAAK,IAAM3U,GAAO2U,EAAK,IAAK,EAAE,EAC9B2c,EAAKA,GAAa3a,EAAM,OACxBA,EAAM,OAAO2a,EAAI,EAAG3c,CAAI,CACzB,CAEA,SAAS2hB,GAAQhF,EAAI,CAChBA,GAAM,KACT3a,EAAM,OAAS,EAEfA,EAAM,OAAO2a,EAAI,CAAC,CACpB,CAEA1lB,EAAK,QAAUyqB,GACfzqB,EAAK,QAAUwqB,GACfxqB,EAAK,QAAU0qB,GAEf,SAASC,GAASt5B,EAAGhD,EAAO,CAC3Bmb,EAAOnY,CAAC,EAAE,MAAQhD,EAEdksB,IAAcmG,GAAUrvB,CAAC,GAAK,OACjCqvB,GAAUrvB,CAAC,EAAE,MAAM,QAAUhD,GAE1BisB,IAAcM,GAAWvpB,CAAC,IAC7BupB,GAAWvpB,CAAC,EAAE,MAAM,QAAUhD,EAChC,CAGA,IAAIu8B,GACAC,GACAC,GACE/O,GAAc,CAAC,MAAO,EAAI,EAEhC,SAASuO,GAASj5B,EAAG,CACpB,GAAIA,GAAKy5B,GAAe,CAGvB,IAAIC,EAAa15B,GAAK,KAElB25B,EAAYxK,GAAM,OAAS,EAE/BhX,EAAO,QAAQ,CAAC9J,EAAGurB,IAAO,CACzB,GAAI1hB,GAAQ,GAAK0hB,EAAK,EAAG,CACxB,IAAIC,EAAYH,GAAcE,GAAM,GAAKA,GAAM55B,EAC/CqO,EAAE,OAASqrB,EAAa,KAAOG,EAC/BF,GAAaL,GAASM,EAAIC,EAAY,EAAI1K,GAAM,KAAK,CACtD,CACD,CAAC,EAEDsK,GAAgBz5B,EAChB25B,GAAavN,GAAO,CACrB,CACD,CAEInD,IAAcwB,IACjBL,GAAQ5uB,GAAY4tB,GAAazV,GAAK,CACjCqV,EAAO,QAGXqB,GAAe1W,CAAC,EAEZ8lB,IAAiB,MACpBlP,GAAU,KAAMG,GAAY,GAAMF,GAAS,SAAS,EACtD,CAAC,EAGF,SAASsP,GAASpa,EAAKhJ,EAAOsQ,EAAK,CAClC,IAAIhR,EAAKoC,EAAO1B,CAAK,EAEjBsQ,IACHtH,EAAMA,EAAMvjB,IAAW6Z,EAAG,KAAO,EAAIoV,GAAaD,KAEnD,IAAIrU,EAAMmU,EAENjV,EAAG,KAAO,IACbc,EAAMoU,EACNxL,EAAM5I,EAAM4I,GAGT1J,EAAG,KAAO,KACb0J,EAAM5I,EAAM4I,GAEb,IAAIhf,EAAOsV,EAAG,KACbrV,EAAOqV,EAAG,KACVoN,EAAM1D,EAAM5I,EAET4Y,EAAKhvB,GAAQC,EAAOD,GAAQ0iB,EAE5B1N,EAAQM,EAAG,MAEf,OACCN,GAAS,EAAI3T,GAAI,GAAI2tB,CAAE,EACvBha,GAAS,EAAIrQ,GAAKqqB,EAAI1Z,EAAG,KAAK,EAC9BN,GAAS,IAAMM,EAAG,IAAI0Z,CAAE,EACxBA,CAEF,CAEA,SAASqK,GAAmBra,EAAKsH,EAAK,CACrC,IAAI9mB,EAAI45B,GAASpa,EAAK+H,EAAWT,CAAG,EACpC,OAAO/nB,GAAWiB,EAAGP,EAAK,CAAC,EAAGG,GAAIC,EAAE,CACrC,CAEA4O,EAAK,SAAW1J,GAAOhG,GAAWgG,EAAKtF,EAAK,CAAC,CAAC,EAC9CgP,EAAK,SAAWorB,GAChBprB,EAAK,SAAWmrB,GAChBnrB,EAAK,SAAW,CAAC1J,EAAKyR,EAAOsQ,IAC5B5O,EAAO1B,CAAK,EAAE,KAAO,EACrBgQ,EAAQzhB,EAAKmT,EAAO1B,CAAK,EACxBsQ,EAAMtL,GAAUuP,EAChBjE,EAAMxL,GAAU,CACjB,EACAmL,EAAQ1hB,EAAKmT,EAAO1B,CAAK,EACxBsQ,EAAMrL,GAAUuP,EAChBlE,EAAMvL,GAAU,CACjB,EAGD9M,EAAK,UAAY,CAAC+I,EAAMohB,EAAOE,IAAS,CACvC1lB,GAAaoE,EAAK,KAClBnE,GAAYmE,EAAK,IAEjBsgB,GAAa,KAAMc,EAAOE,CAAI,CAC/B,EAEA,SAASgB,GAAQz9B,EAAKua,EAAK,CAC1Bha,GAAWg7B,GAAW98B,GAAO28B,GAAO,KAAOp7B,CAAG,EAC9CO,GAAWg7B,GAAWl9B,GAAO+8B,GAAO,MAAQ7gB,CAAG,CAChD,CAEA,SAASmjB,GAAQ19B,EAAKua,EAAK,CAC1Bha,GAAWg7B,GAAWh9B,GAAQ68B,GAAO,IAAMp7B,CAAG,EAC9CO,GAAWg7B,GAAWj9B,GAAQ88B,GAAO,OAAS7gB,CAAG,CAClD,CAEA,IAAIojB,GAAU9f,EAAO,KAAO,EAAI4f,GAAUC,GACtCE,GAAU/f,EAAO,KAAO,EAAI4f,GAAUC,GAE1C,SAASG,IAAa,CACrB,GAAInR,IAAcF,EAAO,KACxB,QAAS/oB,EAAIkY,GAAQ,EAAI,EAAI,EAAGlY,EAAImY,EAAO,OAAQnY,IAAK,CACvD,GAAIA,GAAK,GAAK0pB,GACb,SAED,IAAIre,EAAO0d,EAAO,OAAO/oB,CAAC,EAEtBiL,EAAI,EAER,QAASxC,KAAK4C,EACbme,GAAYxpB,CAAC,EAAEiL,GAAG,EAAE,WAAW,UAAYI,EAAK5C,CAAC,CACnD,CAEF,CAEA,SAASwvB,GAAUvgB,EAAMohB,EAAO,CAa/B,GAZIphB,GAAQ,OACPA,EAAK,KACRA,EAAK,KAAK,QAAQ,CAAC2iB,EAAMC,IAAS,CACjCxR,GAAWwR,CAAI,EAAID,CACpB,CAAC,EAEQtyB,GAAQ2P,EAAK,GAAG,GACzBoR,GAAW,KAAKpR,EAAK,GAAG,EAEzBqR,EAAO,IAAMD,GAAW,CAAC,GAGtBG,IAAcF,EAAO,KAAM,CAC9B,QAASuR,EAAO,EAAGA,EAAOniB,EAAO,OAAQmiB,KACpCA,EAAO,GAAKpiB,GAAQ,GAAK,CAACwR,KAC7B6Q,GAAgBD,EAAMxR,GAAWwR,CAAI,CAAC,EAGxCF,GAAW,CACZ,CAEAtO,GAAkB,GAElBgN,IAAU,IAASjJ,GAAK,WAAW,CACpC,CAEAlhB,EAAK,UAAYspB,GAEjB,SAASsC,GAAgBD,EAAME,EAAK,CACnC,IAAInsB,EAAI8J,EAAOmiB,CAAI,EACf1xB,EAAM0xB,GAAQ,GAAKhS,GAAe,EAAIgI,GAAQ3wB,EAAK26B,CAAI,EACvDr1B,EAEAykB,GACHzkB,EAAMoJ,EAAE,OAAOM,EAAM2rB,EAAME,CAAG,GAAK7Q,IAEnC1kB,EAAMoJ,EAAE,MAAMM,EAAM6rB,GAAO,KAAO,KAAO5xB,EAAI4xB,CAAG,EAAGF,EAAME,CAAG,EAC5Dv1B,EAAMA,GAAO,KAAO0kB,GAAqB,CAAC,EAAG1kB,CAAG,GAGjD8jB,EAAO,OAAOuR,CAAI,EAAIr1B,CACvB,CAEA,SAAS+yB,GAAapvB,EAAKkwB,EAAOE,EAAM,CAGvCP,GAAgBnlB,GAChBolB,GAAenlB,GAEf,CAACD,GAAYC,EAAS,EAAIyV,EAAO,KAAKra,EAAM2E,GAAYC,EAAS,EAEjEyV,EAAO,KAAO1V,GACd0V,EAAO,IAAMzV,GAET2V,KACHuO,IAAWj6B,GAAQi6B,GAASryB,GAAMkO,EAAU,EAAG,EAAG2X,EAAYC,CAAU,EACxEwM,IAAWl6B,GAAQk6B,GAAS,EAAGtyB,GAAMmO,EAAS,EAAG0X,EAAYC,CAAU,GAGxE,IAAIsP,EAIAC,EAAgB36B,GAAKC,GAEzBw5B,GAAc34B,GACd44B,GAAgB,KAGhB,IAAI9e,EAAON,EAAO,KAAO,EAAI6Q,EAAaC,EACtCvQ,EAAOP,EAAO,KAAO,EAAI6Q,EAAaC,EAG1C,GAAI5X,GAAa,GAAK+c,IAAW,GAAKoK,EAAe,CACpDD,EAAMxR,EAAO,IAAM,KAEnB,QAAShpB,EAAI,EAAGA,EAAImY,EAAO,OAAQnY,IAAK,CACvC,IAAI4S,EAAKyc,GAAUrvB,CAAC,EACpB4S,GAAM,MAAQpV,GAAQoV,EAAI,IAAK,IAAKqY,EAAYC,CAAU,CAC3D,CAEIT,IACHF,GAAU,KAAMG,GAAY,GAAM9hB,GAAO,MAAQ4hB,GAAS,SAAS,EAEhEzB,EAAO,OACVD,GAAW,KAAK0R,CAAG,EACnB1O,GAAkB,GAEpB,KACK,CAGJ,IAAI4O,EAAWpM,EAAW7wB,EAEtBya,GAAQ,IACXwiB,EAAYtgB,EAAO,KAAO,EAAI9G,GAAaC,GAC3C+a,EAAYwL,GAASY,EAAWjT,CAAS,EACzC+S,EAAMxR,EAAO,IAAM/pB,GAAWqvB,EAAW3uB,EAAK,CAAC,EAAGG,GAAIC,EAAE,EACxDtC,EAAO6c,EAAU3a,EAAK,CAAC,EAAE66B,CAAG,EAAGpgB,EAAQM,EAAM,CAAC,GAI/C,IAAIigB,EAAS,IACTC,EAAS,IACTC,EAAS,EACTC,GAAS,EACTC,GAAY,GACZC,EAAU,GACVC,EAAY,GAEhB,QAASj7B,EAAIkY,GAAQ,EAAI,EAAI,EAAGlY,EAAImY,EAAO,OAAQnY,IAAK,CACvD,IAAIqO,GAAI8J,EAAOnY,CAAC,EAEZoD,GAAQ0lB,GAAW9oB,CAAC,EACpB4gB,GAAQxd,IAAQ,KAAO,KAAQ8U,GAAQ,EAAIvY,EAAKK,CAAC,EAAEoD,EAAI,EAAIzD,EAAKK,CAAC,EAAE,CAAC,EAAEoD,EAAI,EAE1EmrB,GAAQvF,EAAO,QAAQra,EAAM3O,EAAGw6B,EAAKlM,CAAS,EAC9C4M,GAAQ3M,IAAQ,KAAO,KAAQrW,GAAQ,EAAIvY,EAAKK,CAAC,EAAEuuB,EAAI,EAAI5uB,EAAKK,CAAC,EAAE,CAAC,EAAEuuB,EAAI,EAM9E,GAJAzC,GAAkBA,IAAmBoP,IAASta,IAAS2N,IAAQnrB,GAE/D0lB,GAAW9oB,CAAC,EAAIuuB,GAEZvuB,EAAI,GAAKqO,GAAE,KAAM,CACpB,IAAI8sB,GAAQ5M,IAAQ,KAAO,IAAMA,IAAQiM,EAAM/8B,EAAO6c,EAAUpC,GAAQ,EAAIvY,EAAK,CAAC,EAAE4uB,EAAI,EAAI5uB,EAAKK,CAAC,EAAE,CAAC,EAAEuuB,EAAI,EAAGnU,EAAQM,EAAM,CAAC,EAGzHhd,GAAOw9B,IAAS,KAAO,IAAM3gB,EAAU2gB,GAAOhjB,GAAQ,EAAIE,EAAO/J,GAAE,KAAK,EAAI+J,EAAO/J,GAAE,OAAO,CAAC,EAAE,KAAK,EAAGsM,EAAM,CAAC,EAElH,GAAI8P,IAAeyQ,IAAS,KAAM,CACjC,IAAIE,GAAYhhB,EAAO,KAAO,EAAI9G,GAAaC,GAC3C8nB,GAAOz5B,GAAIutB,GAAM,KAAKxgB,EAAM3O,EAAGuuB,GAAM7wB,GAAM09B,EAAS,CAAC,EAEzD,GAAIC,GAAO9B,GAAa,CACvB,IAAInL,GAAOe,GAAM,KAEjB,GAAIf,IAAQ,EAAG,CACd,IAAIkN,GAAYxB,GAASsB,GAAW/sB,GAAE,KAAK,EAEvCktB,GAAiBL,IAAa,EAAI,EAAI,GACtCM,GAAiBF,IAAa,EAAI,EAAI,GAItCE,IAAiBD,KACpBC,IAAiB,EACfpN,IAAQ,EAAI8M,IAASI,GAAYJ,IAASI,GAC1ClN,IAAQ,EAAI8M,IAASI,GAAYJ,IAASI,MAE5C/B,GAAc8B,GACd7B,GAAgBx5B,EAElB,MAECu5B,GAAc8B,GACd7B,GAAgBx5B,CAElB,CACD,CAEA,GAAI8rB,IAAmBsD,GAAa,CACnC,IAAIqM,GAAMC,GAENthB,EAAO,KAAO,GACjBqhB,GAAON,GACPO,GAAOh+B,KAGP+9B,GAAO/9B,GACPg+B,GAAOP,IAGR,IAAIQ,GAAOC,GAAOC,GAAOC,GACxBC,GAAUC,GACVv9B,GAAW,GACXw9B,GAAUle,GAAO,KAElB,GAAIke,IAAW,KAAM,CACpBx9B,GAAW,GAEX,IAAI4Z,GAAO4jB,GAAQttB,EAAM3O,CAAC,EAE1B67B,GAAQxjB,GAAK,KACbyjB,GAAQzjB,GAAK,IACbsjB,GAAQtjB,GAAK,MACbujB,GAAQvjB,GAAK,MACd,MAECwjB,GAAQJ,GACRK,GAAQJ,GACRC,GAAQC,GAAQ7d,GAAO,KAAKpP,EAAM3O,CAAC,EAMpC,GAHAg8B,GAASje,GAAO,KAAKpP,EAAM3O,CAAC,EAC5B+7B,GAAWhe,GAAO,OAAOpP,EAAM3O,CAAC,EAE5BovB,GACCpvB,GAAKw5B,IAAiBD,IAAepK,GAAM,OAC9CwL,EAASkB,GACTjB,EAASkB,GACTjB,EAASc,GACTb,GAASc,GACTb,GAAYt8B,GACZu8B,EAAUgB,GACVf,EAAYc,QAGT,CACJ,IAAInpB,GAAKyc,GAAUrvB,CAAC,EAEhB4S,IAAM,OACT0c,GAAatvB,CAAC,EAAI67B,GAClBtM,GAAavvB,CAAC,EAAI87B,GAElBx9B,GAAOsU,GAAI+oB,GAAOC,GAAOn9B,EAAQ,EACjCT,GAAQ4U,GAAIopB,GAAQD,EAAQ,EAC5Bv+B,GAAQoV,GAAInR,GAAKo6B,EAAK,EAAGp6B,GAAKq6B,EAAK,EAAG7Q,EAAYC,CAAU,EAE9D,CACD,CACD,CACD,CAIA,GAAIkE,GAAa,CAGhB,IAAIjoB,EAAIgoB,GAAM,KAEV+M,GAAezC,IAAiB,KAAOF,IAAepyB,EAAKoyB,GAAcpyB,GAAKqyB,IAAiBC,GAEnG,GAAI3N,IAAmBoQ,GAAc,CACpC,IAAItpB,GAAKyc,GAAU,CAAC,EAEhBzc,IAAM,OACT0c,GAAa,CAAC,EAAIqL,EAClBpL,GAAa,CAAC,EAAIqL,EAElBt8B,GAAOsU,GAAIioB,EAAQC,GAAQC,EAAS,EACpC/8B,GAAQ4U,GAAIooB,EAASC,CAAS,EAC9Bz9B,GAAQoV,GAAInR,GAAKk5B,CAAM,EAAGl5B,GAAKm5B,CAAM,EAAG3P,EAAYC,CAAU,EAEhE,CACD,CACD,CAGA,GAAIyM,GAAO,MAAQgB,GAClB,GAAI/vB,GAAO,KAAM,CAChB,GAAI,CAACuzB,EAAMC,CAAI,EAAI5R,GAAS,OACxB,CAAC6R,EAAYC,CAAU,EAAI9R,GAAS,MACpC,CAAC+R,EAASC,CAAO,EAAI5zB,EAAI,OAAO,KAAK,OAGrC6zB,GAAQ7zB,EAAI,OAAO,KAIvB,GAHAgwB,GAAQ6D,GAAM,GACd5D,GAAQ4D,GAAM,GAEV7D,IAASC,GAAO,CACnB,GAAI,CAAE,KAAAtY,GAAM,IAAAlC,EAAK,MAAAtL,EAAO,OAAAiZ,CAAO,EAAIpjB,EAAI,OAEnC8zB,GAAO9zB,EAAI,OAAO2zB,CAAO,EAAE,IAC3BI,GAAY/zB,EAAI,SAEhBg0B,GAAMC,GAAM7mB,GAAI1P,GAAGC,GAEnBu2B,GAAYX,GAAQ,MAAQE,EAAWF,EAAMI,CAAO,EACpDQ,GAAYX,GAAQ,MAAQE,EAAWF,EAAMI,CAAO,EAEpDM,IAAalE,IACZ8D,IAAQ,GACXE,GAAOrc,GACPsc,GAAO9pB,IAGP6pB,GAAOve,EACPwe,GAAO7Q,GAGRhW,GAAKoC,EAAO+jB,CAAI,EAEhB71B,GAAIgU,EAAUqiB,GAAUC,GAAML,CAAO,EAAUvmB,GAAI0E,EAAM,CAAC,EAC1DnU,GAAI+T,EAAUqiB,GAAUC,GAAOC,GAAMN,CAAO,EAAGvmB,GAAI0E,EAAM,CAAC,EAE1Dwf,GAAQp5B,GAAIwF,GAAEC,EAAC,EAAG3E,GAAI2E,GAAED,EAAC,CAAC,GAG1B4zB,GAAQ,EAAGxf,CAAI,EAEZqiB,IAAalE,IACZ6D,IAAQ,GACXE,GAAOrc,GACPsc,GAAO9pB,IAGP6pB,GAAOve,EACPwe,GAAO7Q,GAGRhW,GAAKoC,EAAOgkB,CAAI,EAEhB91B,GAAIiU,EAAUoiB,GAAUC,GAAMJ,CAAO,EAAUxmB,GAAI2E,EAAM,CAAC,EAC1DpU,GAAIgU,EAAUoiB,GAAUC,GAAOC,GAAML,CAAO,EAAGxmB,GAAI2E,EAAM,CAAC,EAE1Dwf,GAAQr5B,GAAIwF,GAAEC,EAAC,EAAG3E,GAAI2E,GAAED,EAAC,CAAC,GAG1B6zB,GAAQ,EAAGxf,CAAI,CACjB,MAECqiB,GAAW,CACb,KACK,CACJ,IAAIC,EAAQr7B,GAAI62B,GAAgBF,EAAa,EACzC2E,EAAQt7B,GAAI82B,GAAeF,EAAY,EAE3C,GAAIpe,EAAO,KAAO,EAAG,CACpB,IAAI+iB,EAASF,EACbA,EAAQC,EACRA,EAAQC,CACT,CAEAvE,GAAQtR,GAAK,GAAK2V,GAAS3V,GAAK,KAChCuR,GAAQvR,GAAK,GAAK4V,GAAS5V,GAAK,KAEhC,IAAI8V,EAAM9V,GAAK,IAEX8V,GAAO,KAENxE,IAASC,KACZD,GAAQqE,GAASG,EACjBvE,GAAQqE,GAASE,EAGb,CAACxE,IAAS,CAACC,KACVqE,EAAQD,EACXpE,GAAQ,GAERD,GAAQ,KAIHtR,GAAK,GAAKA,GAAK,IAAMsR,IAASC,MAEtCD,GAAQC,GAAQ,IAEjB,IAAIjiB,EAAIC,EAEJ+hB,KACCxe,EAAO,KAAO,GACjBxD,EAAKwQ,GACLvQ,EAAKvD,KAGLsD,EAAKyQ,GACLxQ,EAAKtD,IAGN2mB,GAAQp5B,GAAI8V,EAAIC,CAAE,EAAGjV,GAAIiV,EAAKD,CAAE,CAAC,EAE5BiiB,IACJsB,GAAQ,EAAGxf,CAAI,GAGbke,KACCze,EAAO,KAAO,GACjBxD,EAAKwQ,GACLvQ,EAAKvD,KAGLsD,EAAKyQ,GACLxQ,EAAKtD,IAGN4mB,GAAQr5B,GAAI8V,EAAIC,CAAE,EAAGjV,GAAIiV,EAAKD,CAAE,CAAC,EAE5BgiB,IACJsB,GAAQ,EAAGxf,CAAI,GAIb,CAACke,IAAS,CAACC,KACdqB,GAAQ,EAAG,CAAC,EACZC,GAAQ,EAAG,CAAC,EAEd,CAMD,GAHA7S,GAAK,GAAKsR,GACVtR,GAAK,GAAKuR,GAENjwB,GAAO,KAAM,CAChB,GAAIowB,EAAM,CACT,GAAIqE,IAAW,KAAM,CACpB,GAAI,CAACC,EAAUC,CAAQ,EAAI/S,GAAS,OAEpCA,GAAS,OAAO,CAAC,EAAI8S,GAAY,KAAOxD,GAAS1f,EAAO,KAAO,EAAI9G,GAAaC,GAAW+pB,CAAQ,EAAI,KACvG9S,GAAS,OAAO,CAAC,EAAI+S,GAAY,KAAOzD,GAAS1f,EAAO,KAAO,EAAI9G,GAAaC,GAAWgqB,CAAQ,EAAI,IACxG,CAEArE,GAAQ99B,GAAWuT,EAAM2E,GAAYC,GAAW0X,EAAYC,EAAYsP,CAAG,CAC5E,CAEA,GAAI/P,GAAa,CAChB,IAAI+S,EAAYxE,GAAQxO,GAAS,UAC7BrjB,EAAIgoB,GAAM,KAEVsK,IAAiB,KAChBF,IAAepyB,GAClBojB,GAAUiP,GAAe9O,GAAY,GAAM8S,CAAS,EAGjDjE,GAAcpyB,EACjBojB,GAAU,KAAMG,GAAY,GAAM8S,CAAS,EACnChE,IAAiBC,IACzBlP,GAAUiP,GAAe9O,GAAY,GAAM8S,CAAS,CAEvD,CACD,CAEI1R,KACH/C,EAAO,IAAMyR,EACbvC,GAAU,GAGXa,IAAU,IAASjJ,GAAK,WAAW,CACpC,CAEA,IAAIjU,GAAO,KAEX,OAAO,eAAejN,EAAM,OAAQ,CACnC,KAAM,CACL,OAAIiN,IAAQ,MACX0b,GAAS,EAAK,EAER1b,EACR,CACD,CAAC,EAED,SAAS0b,GAASmG,EAAQ,GAAO,CAC5BA,EACH7hB,GAAO,MAEPA,GAAOuL,EAAK,sBAAsB,EAClC0I,GAAK,WAAYjU,EAAI,EAEvB,CAEA,SAAS8hB,GAAU/pB,EAAG/K,EAAK+0B,EAAIC,EAAIC,EAAIC,EAAIC,EAAI,CAC1C/U,EAAO,OAQP2P,IAAYhlB,GAAK,MAAQA,EAAE,WAAa,GAAKA,EAAE,WAAa,IAGhEqqB,GAAWrqB,EAAG/K,EAAK+0B,EAAIC,EAAIC,EAAIC,EAAIC,EAAI,GAAOpqB,GAAK,IAAI,EAEnDA,GAAK,KACRqkB,GAAa,KAAM,GAAM,EAAI,EAE7BA,GAAapvB,EAAK,GAAM,EAAK,EAC/B,CAEA,SAASo1B,GAAWrqB,EAAG/K,EAAK+0B,EAAIC,EAAIC,EAAIC,EAAIC,EAAIE,EAASC,EAAM,CAM9D,GALItiB,IAAQ,MACX0b,GAAS,EAAK,EAEfjN,GAAe1W,CAAC,EAEZA,GAAK,KACRgqB,EAAKhqB,EAAE,QAAUiI,GAAK,KACtBgiB,EAAKjqB,EAAE,QAAUiI,GAAK,QAElB,CACJ,GAAI+hB,EAAK,GAAKC,EAAK,EAAG,CACrBtqB,GAAa,IACbC,GAAY,IACZ,MACD,CAEA,GAAI,CAAC4oB,EAAMC,CAAI,EAAI5R,GAAS,OAExB2T,EAAcv1B,EAAI,OAAO,KACzB,CAACw1B,EAASC,EAAO,EAAIF,EAAY,OACjC,CAAC5B,GAASC,CAAO,EAAI2B,EAAY,OACjC,CAAC9B,EAAYC,CAAU,EAAI9R,GAAS,MAEpC8T,GAAS11B,EAAI,KAAK,CAAC,EAAE,KAAO,GAAK,EAEjC8R,GAAON,EAAO,KAAO,EAAI6Q,EAAaC,EACzCvQ,GAAOP,EAAO,KAAO,EAAI6Q,EAAaC,EACtCqT,GAAQD,GAASR,EAAKD,EACtBW,GAAQF,GAAST,EAAKC,EACtBW,GAAQH,GAASV,EAAKD,EACtBe,GAAQJ,GAASX,EAAKC,EAYvB,GAVIrB,IAAW,KACdoB,EAAKtB,EAAWF,EAAMI,EAAO,EAAI3V,EAAOwX,EAAShmB,EAAO+jB,CAAI,EAAGzhB,GAAM,CAAC,EAAI,IAE1EijB,EAAKjjB,IAAQ+jB,GAAMF,IAEhB/B,GAAW,KACdoB,EAAKtB,EAAWF,EAAMI,CAAO,EAAI5V,EAAOyX,GAASjmB,EAAOgkB,CAAI,EAAGzhB,GAAM,CAAC,EAAI,IAE1EijB,EAAKjjB,IAAQ+jB,GAAMF,IAEhBpkB,EAAO,KAAO,EAAG,CACpB,IAAIukB,GAAMhB,EACVA,EAAKC,EACLA,EAAKe,EACN,CACD,CAEIT,IAASt1B,GAAO,MAAQA,EAAI,OAAO,MAAM,MAAQxN,OAChDuiC,GAAM,GAAKA,GAAM1S,EAAa,KACjC0S,EAAK32B,GAAU22B,EAAI1S,CAAU,IAE1B2S,GAAM,GAAKA,GAAM1S,EAAa,KACjC0S,EAAK52B,GAAU42B,EAAI1S,CAAU,IAG3B+S,GACH1F,GAAgBoF,EAChBnF,GAAeoF,EAEf,CAACxW,GAAYC,EAAS,EAAI2B,EAAO,KAAKra,EAAMgvB,EAAIC,CAAE,IAGlDtqB,GAAaqqB,EACbpqB,GAAYqqB,EAEd,CAEA,IAAM/F,GAAa,CAClB,MAAO,EACP,OAAQ,EACR,KAAM,EACN,IAAK,CACN,EAEA,SAASmF,IAAa,CACrBjF,GAAUF,GAAY,EAAK,CAC5B,CAEA,IAAI+G,GACAC,GACAC,GACAC,GAEJ,SAASC,GAAUrrB,EAAG/K,EAAK+0B,EAAIC,EAAIC,EAAIC,EAAIC,EAAI,CAC9CpF,GAAW,GACXC,GAAQC,GAAQvR,GAAK,GAAKA,GAAK,GAAK,GAEpC0W,GAAWrqB,EAAG/K,EAAK+0B,EAAIC,EAAIC,EAAIC,EAAIC,EAAI,GAAM,EAAK,EAE9CpqB,GAAK,OACRyW,GAAQ9uB,GAASU,GAAKijC,GAAS,EAAK,EACpC/F,GAAQ79B,GAAWsT,EAAMyY,GAAYC,GAAW4D,EAAYC,EAAY,IAAI,GAG7E,GAAI,CAAE,KAAA3K,EAAM,IAAAlC,EAAK,MAAAtL,EAAO,OAAAiZ,CAAO,EAAI2L,GAEnCiH,GAAmBre,EACnBse,GAAmBxgB,EACnBygB,GAAmB/rB,EACnBgsB,GAAmB/S,CAGpB,CAEA,SAASiT,GAAQtrB,EAAG/K,EAAK+0B,EAAIC,EAAIC,EAAIC,EAAIC,EAAI,CAC5CpF,GAAWrR,GAAK,GAAKA,GAAK,GAAK,GAE/B0W,GAAWrqB,EAAG/K,EAAK+0B,EAAIC,EAAIC,EAAIC,EAAIC,EAAI,GAAO,EAAI,EAElD,GAAI,CAAE,KAAAxd,EAAM,IAAAlC,EAAK,MAAAtL,EAAO,OAAAiZ,CAAO,EAAI2L,GAE/BuH,EAAYnsB,EAAQ,GAAKiZ,EAAS,EAClCmT,EACHP,IAAoBre,GACpBse,IAAoBxgB,GACpBygB,IAAoB/rB,GACpBgsB,IAAoB/S,EAKrB,GAFAkT,GAAaC,GAAapH,GAAUJ,EAAM,EAEtCrQ,GAAK,UAAY4X,GAAaC,EAAW,CAM5C,IAAI3kB,GAAO+F,EACV7F,GAAO3H,EACP0H,EAAO4D,EACP1D,EAAOqR,EAgBR,GAdI5R,EAAO,KAAO,IACjBI,GAAO6D,EACP3D,GAAOsR,EACPvR,EAAO8F,EACP5F,EAAO5H,GAGJ6lB,IACH7H,GAAUtJ,EACTqS,GAAStf,GAAMiN,CAAS,EACxBqS,GAAStf,GAAOE,GAAM+M,CAAS,CAChC,EAGGoR,GACH,QAASpwB,KAAK2P,EAAQ,CACrB,IAAIpC,GAAKoC,EAAO3P,CAAC,EAEbA,GAAKgf,GAAazR,GAAG,MAAQ,MAAQA,GAAG,KAAOpV,IAClDmwB,GAAUtoB,EACTqxB,GAASrf,EAAOE,EAAMlS,CAAC,EACvBqxB,GAASrf,EAAMhS,CAAC,CACjB,CAEF,CAGDu0B,GAAW,CACZ,MACShU,EAAO,OACfA,EAAO,MAAQ,CAACA,EAAO,MACvBgP,GAAapvB,EAAK,GAAM+K,GAAK,IAAI,GAG9BA,GAAK,OACRmX,GAASxvB,GAASU,EAAG,EACrBk9B,GAAQ59B,GAASqT,EAAM2E,GAAYC,GAAW0X,EAAYC,EAAY,IAAI,EAE5E,CAEA,SAASkU,GAAWzrB,EAAG/K,EAAK+0B,EAAIC,EAAIC,EAAIC,EAAIC,EAAI,CAC/C,GAAI/U,EAAO,MACV,OAEDqB,GAAe1W,CAAC,EAEhB,IAAI0rB,EAAY1G,GAEhB,GAAIA,GAAU,CAEb,IAAI2G,EAAQ,GACRC,EAAQ,GACRC,EAAW,GAEXC,EAAOC,EAEPtlB,EAAO,KAAO,GACjBqlB,EAAQ7G,GACR8G,EAAQ7G,KAGR4G,EAAQ5G,GACR6G,EAAQ9G,IAGL6G,GAASC,IAEZJ,EAAQhsB,IAAcksB,GAAYlsB,IAAc2X,EAAauU,EAC7DD,EAAQhsB,IAAcisB,GAAYjsB,IAAc2X,EAAasU,GAG1DC,GAASH,IACZhsB,GAAaA,GAAa8T,GAAa,EAAI6D,GAExCyU,GAASH,IACZhsB,GAAYA,GAAY8T,GAAY,EAAI6D,GAEzC8M,GAAa,KAAM,GAAM,EAAI,EAE7BW,GAAW,EACZ,CAEArlB,GAAa,IACbC,GAAY,IAEZuV,GAAW,KAAK,IAAI,EAGpBkP,GAAa,KAAM,GAAM,EAAI,EAEzBqH,IACH1G,GAAW0G,EACb,CAEA,SAASM,GAAShsB,EAAG/K,EAAK+0B,EAAIC,EAAIC,EAAIC,EAAIC,EAAI,CACzC/U,EAAO,QAGXqB,GAAe1W,CAAC,EAEhBmd,GAAW,EAEXkM,GAAW,EAEPrpB,GAAK,MACRulB,GAAQz9B,GAAUkT,EAAM2E,GAAYC,GAAW0X,EAAYC,EAAY,IAAI,EAC7E,CAEA,SAAS0U,IAAc,CACtBpY,EAAK,QAAQjB,EAAY,EACzBwF,GAASpd,EAAK,MAAOA,EAAK,OAAQ,EAAI,CACvC,CAEAnS,GAAGX,GAAYI,GAAK2jC,EAAW,EAG/B,IAAMC,GAAS,CAAC,EAEhBA,GAAO,UAAYb,GACnBa,GAAO,UAAYnC,GACnBmC,GAAO,QAAUZ,GACjBY,GAAO,SAAWF,GAClBE,GAAO,UAAe,CAAClsB,EAAG/K,EAAK4xB,EAAK9iB,IAAS,CAC5C,IAAIooB,EAAmBtV,GAAS,MAAM,CAAC,EACvCgQ,EAAMsF,EAAiBnxB,EAAM/F,EAAK4xB,CAAG,EACrCA,GAAO,IAAMjQ,GAAUiQ,EAAK9iB,EAAM,GAAM,EAAK,CAC9C,EAEIwR,KACHkB,GAAQ/uB,GAAY8rB,EAAM6X,EAAS,EACnC5U,GAAQhvB,GAAY+rB,EAAMuW,EAAS,EACnCtT,GAAQ7uB,GAAY4rB,EAAMxT,GAAK,CAC9B0W,GAAe1W,CAAC,EAChB2jB,GAAS,EAAK,CACf,CAAC,EACDlN,GAAQ5uB,GAAY2rB,EAAMiY,EAAU,EAEpChV,GAAQ3uB,GAAU0rB,EAAMwY,EAAQ,EAEhC/a,GAAY,IAAIjW,CAAI,EAEpBA,EAAK,SAAW2oB,IAIjB,IAAMyI,GAAQpxB,EAAK,MAAQ+I,EAAK,OAAS,CAAC,EAE1C,SAASmY,GAAKmQ,EAAQC,EAAIC,EAAI,CACzBtJ,GACHC,GAAW,KAAK,CAACmJ,EAAQC,EAAIC,CAAE,CAAC,EAE5BF,KAAUD,IACbA,GAAMC,CAAM,EAAE,QAAQt1B,GAAM,CAC3BA,EAAG,KAAK,KAAMiE,EAAMsxB,EAAIC,CAAE,CAC3B,CAAC,CAGJ,EAECxoB,EAAK,SAAW,CAAC,GAAG,QAAQvQ,GAAK,CACjC,QAAS64B,KAAU74B,EAAE,MACpB44B,GAAMC,CAAM,GAAKD,GAAMC,CAAM,GAAK,CAAC,GAAG,OAAO74B,EAAE,MAAM64B,CAAM,CAAC,CAC9D,CAAC,EAED,IAAMF,GAAmB,CAACnxB,EAAM/F,EAAKu3B,IAAiBA,EAEhD3V,GAAW9hB,GAAO,CACvB,IAAK,KACL,UAAW,GACX,QAAS,CACR,IAAKtC,GACL,IAAKA,EACN,EACA,OAAQ,CAACqhB,EAAWtP,EAAO,CAAC,EAAIA,EAAO,CAAC,EAAE,MAAQ,IAAI,EACtD,MAAO,CAAC9R,GAAOA,GAAOy5B,EAAgB,EACtC,OAAQ,CAAC,KAAM,IAAI,CACpB,EAAG9W,EAAO,IAAI,EAEVwB,GAAS,MAAM,QAAU,GAC5BA,GAAS,MAAM,KAAKsV,EAAgB,EAErC9W,EAAO,KAAOwB,GAEd,IAAM6S,GAAU7S,GAAS,IAEnB4V,GAAO3oB,GAAM4lB,EAAO,EAE1B,SAASnE,GAAQthB,EAAMhP,EAAKnD,EAAG8I,EAAGsJ,EAAGtL,EAAGvM,EAAG,CACtCwqB,GAAS,QAAQ,IAAI5S,EAAMhP,EAAKnD,EAAG8I,EAAGsJ,EAAGtL,EAAGvM,CAAC,GAChDogC,GAAK,IAAIxoB,EAAMhP,EAAKnD,EAAG8I,EAAGsJ,EAAGtL,EAAGvM,CAAC,CACnC,CAEAogC,GAAK,IAAIzxB,CAAI,EAEb,SAAS0xB,GAAIzoB,EAAMhP,EAAKnD,EAAG8I,EAAGsJ,EAAGtL,EAAGvM,EAAG,CAClCwqB,GAAS,QAAQ,IAAI5S,EAAMhP,EAAKnD,EAAG8I,EAAGsJ,EAAGtL,EAAGvM,CAAC,GAChD6/B,GAAOjoB,CAAI,EAAE,KAAMhP,EAAKnD,EAAG8I,EAAGsJ,EAAGtL,EAAGvM,CAAC,CACvC,CAEA2O,EAAK,IAAM0xB,GAEX,SAASC,IAAU,CAClBF,GAAK,MAAMzxB,CAAI,EACfiW,GAAY,OAAOjW,CAAI,EACvBgc,GAAe,MAAM,EACrBpuB,GAAIV,GAAYI,GAAK2jC,EAAW,EAChC9Y,EAAK,OAAO,EACZsC,IAAa,OAAO,EACpByG,GAAK,SAAS,CACf,CAEAlhB,EAAK,QAAU2xB,GAEf,SAASC,IAAQ,CAChB1Q,GAAK,OAAQnY,EAAM/X,CAAI,EAEvB6wB,GAAQ7wB,GAAQ+X,EAAK,KAAM,EAAK,EAE5B6Q,EAAWd,CAAS,EACvB2Q,GAAS3Q,EAAWc,EAAWd,CAAS,CAAC,EAEzCqJ,GAAW,EAEZjF,GAAkB8L,GAAO,OAASA,GAAO,MAAQ,GAAKA,GAAO,OAAS,GACtE/L,GAAkBE,GAAkB,GAEpCC,GAASrU,EAAK,MAAOA,EAAK,MAAM,CACjC,CAEA,OAAAS,EAAO,QAAQsX,EAAU,EAEzBjI,EAAK,QAAQyI,EAAQ,EAEjBxJ,EACCA,aAAgB,aACnBA,EAAK,YAAYK,CAAI,EACrByZ,GAAM,GAGN9Z,EAAK9X,EAAM4xB,EAAK,EAGjBA,GAAM,EAEA5xB,CACR,CAEAmW,GAAM,OAASpc,GACfoc,GAAM,OAAS9f,GACf8f,GAAM,SAAWpiB,GACjBoiB,GAAM,SAAWjkB,GACjBikB,GAAM,WAAa1iB,GACnB0iB,GAAM,OAAW9M,GACjB8M,GAAM,QAAU3oB,GAGf2oB,GAAM,KAAOtb,GAIbsb,GAAM,QAAUtY,GAChBsY,GAAM,OAAUhY,GAGjBgY,GAAM,KAAOrN,GAEb,CACCqN,GAAM,OAAS9I,GACf8I,GAAM,SAAWxJ,GAEjB,IAAIklB,EAAQ1b,GAAM,MAAQ,CACzB,OAAA/G,EACD,EAECyiB,EAAM,OAAUrhB,GAChBqhB,EAAM,QAAUpgB,GAChBogB,EAAM,KAAUlf,GAChBkf,EAAM,OAAUnc,EAClB", + "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 z2iCU?zkSLW4CjpI&BG<=EquqBh?j8@S&pbisG(xfLrKnQN|p)t7vd49@3KQjIAW!Y zkbinP=q`FPy7OuOw9DoT+s_sZ5N}T(^DFQm^)l&p6y5)OdLO5-Bb%%NLw4W$E?G^f zx)+LYL$|MNgS81B3!9V)req^wP#k60jP+bFi9cAx1zdtfYbMil<~0a839fA46hYf{ zNxX*N&S4}7XvBf3pJmjfe2cKu!!pK@jok`SyJcot^b>~i@Q1$+Oyn|$CEFOsNUkJL zzDG1?Gkcnoh~r5xeVU4gitqLu0;5VFbt+0y>2xw@*m@D?;q&#)xZzSZI< z%6<^OC|-L$LlXVypPVAh2)$%`ZS9k63r5la&(rVc`|IST0KALj0F#nLQk^Oy*XeDF zYy^C8z^eKyK(u#=bnAbFP^2c51VT+Hp_Nc0q?3@gDFk`|frJ)H3y9Ezfv%|7!SXZM3-!Y2#NJsTEFfo-|JC`vuazv4{oL||uy*7P z(2gL`vJ)3!eOl#J5NJ6-?FWFh!0X4e|8JqL|Eg-qo|y%vAff}#fRgBfcxBHV5Jr^$ zz3ift_QSFXuV!8(V=ThT8yPf9jBf4M}r= z_z_L5&#USlk~}gcyyP5sH%A|klN`|p06qd*2w9d!Gu>VFj%sTBS65XxPY-Bh$rL-d zfR8XA@P>yYp8nw+d6EwVH^37C?Q)Xc=YVBtBn|WoI<*cVkPukdgtY39lYY%t>y&&i z+YjS!eHhF9!`f;|E4X1JKnUqCTYmqY!me(Xt}YH~@Y4cbFhAO^yEkDz8^3Dw`*aLQ| zy%Yc(aMteH0!bi!Rb&+42mJrPRPFz_3L>q7qHY6Ld<~^1vPaOJwL+!W?cb{??qSY- z!`J*dPUq}%YC2U#6bc{(6hH|mLJ9^-0Sb@|f|N~wP(o2!4yCvgTRqv={o(YR?A&Q8 z0JKejibGOL+8WZ&lAX*w__^=oeuLvXjr00{Z~lCrpTjWy{=U!8=l{1iXY*+Np9n>1 z5@8o5F=poO+q~R)JN!VOofJiBW&cuFs3Zu5vY;@gX$?I8f2zLslizbY2qM}wkTN$x zwANHx5GkORe~P`2v;U;tv?5Ggj12IsSm-;GN9&3~nC2N=v!)vD_-Q{^#p)K~rG{r( z{M^QFCW`6Z`{?_aC#a%vRC3TnZ8Qiq0%1EIYueC)0?({%)ZZo3guEgF`2YS)js=7N zYv>)jfDwuLvT~@c?i&Dan5h<|+gjl!fav0JvkIw1j7;a>S8c2J>xGGVL+qa#kwQcY zk)Cuo?P=kkZ2I7HRl$C?j~`&%gb_$4+hmo@zSLj-mrGyJV>jJywbddbH9H+iFGn#X zUw>potTFxQ6nS=d!+u~hpbs03sP&{9s7Abt^NEFg&LkD6ZrxL(Yr&|teb?O z)_vkqtFEA+D2gvC`nO_v0we)$51F%%1l#@BVaL-97;+a0~s^`C>4DP_#EU@IWaPV@l*FdkQ;Li|CQAJHY;@Hdu$Lj5e=y{6&?EG8w1ArqiqjM7zv zR^k*&1l`aflB&nlHA!=%B}vN)N(N*E$UAXi10V4Q)|pwf+keHxk)ZTzWvh!o#44o8$DC$?g*sHj_qI#ss4 zMP#?HT|b3l_T(iVF$8pI3K(B{W*$`N48h?BN2aKMVe>bWp-7lt!Usp-7JN!!q#c<` zHn95~Mzx|+sA3_sH|>NdwJ7aA558L?Q#ej!PU$J_WDE4qskZDjK93=_B zu(Z03)U#q?Co4T9t$qg0!&NQB{iAn47qWA55l(+^;YBJNtCq<25)qM}(6(fm1gPN} zVQHYO=h>rkdltoYSaP6>B4L~JNSFZzhHEkLhok*lMm&1xYl~<&16vvA5`EJeTUj!S zl6f>hBOzoCpfkj2jHFS4T26%5EPxSbj()3>kP6UM%w&>a?z#zAMDc-JkSDTp2I`8$ z7w`yZEda=E^mE&z3^M8pN7-D34~T;5s7fxXxmF9pSJREda2n!->BBJrBT=$#!4ig+ z_h4mJavc7>|ge4sQ=MQbmitcwz|t)fi;4&`$)C0G$RexL=p zo1rBAN2yVw-je}oUnrlrDkAwVaU-YyQyzA$1C0;^{8c6>I0#el7(T~$6iWt>WRk%y za1@mSK|EivSi%rp%2EvLPUTf4DbZ1brLP7B&=5(KN!`MCW4PARi#k$JLVeuz+)(|gJviDWE18)MiLHJ z9gx=6$-DcVC0&R?0E4gliqS+7&l~?%j}v|nMsbp6d9Obh7NhZGIxAOJ*VZ>Sx3+h7Z|t>Pq^O#1n3nCh zo*#r!oTOP^lvUldT|bP|ysX=9e>k4bm+S5Rc)s4B@9+P)gHTrvW&p!|^KMLUq>ym% zHaHNr)p~Vk4gXobkunm1Ux!! zVhR!FHlDTo2P#Wqj&h+uwG3Sbik-PH}Q1-oMePXX~e zG62Y%v%7lWue*AZ?nW;>n0XrYE_fbzNBa&R*YNnXfsaRmLs2|_{=SRwyI(hHNdvBfuxc5nq>2W;1SL$ub|3?1L@{ha$ z{8N|%3t&&d5$yW!DExE(Y~gPUdw%RU4>yaRUG##YR~1S3pE<>xwpdrmr6 zFjp}*J$HTX&fNXErymdtF?F&5%{R>AIPA;5TIJD z>`Ux}?3wmRd%V4!-Fv%OJBFQ?oueHE#x7qiD` zeNhE5V`Ah9z%Hc09FPGwt=n6<)}wo0EKMUQ-M#EW@^6ox+sV#ey;Nk~!df`ejSRmW z=lA#9Ommy}?VG#Q3WI1P?ewE?l_0Yf1;O1ZT_`~^Khx0~5;_o!yHo}0&l*x8*iMj3 zZjLjj7&?nUrfg;bh!C^PF)LUgaWYBb z*b0qZ=L;=Mex#>SG~$|E&c#WHq8(VfexVqhKH{AKp&XaWbOJuk;$J>?dj$|;r;gq} z#Y;@^XZZ1Bi~U*bvB>ikAq82KM>b9^8*e2B7E>HQ!G>6j3lcMyO+V*Oe$bg~@k2j) zPN^jnL1od6A#mKAr%Lp5ml_JQb6pGy5<{q8{U3P?$t=E9aA{X422K2vnT%B}@4 zCJZwOHOG8NV9plQrN|tdnV7oDm5K6&l5V~fg-~afB*VVVlFTQn9AWH}Kj|0%lG$r` zM#df_M*NL$2{zOCfdMsbzs7jx|G5QO;Yj%iNUItUO!X@Q%W;tg1XU@(1RP?M-Yc0v zI{enaQ7IVF@Ln?&5{yW&rfGS=I>Y@eD;#ES!)WVuM{8{PyJ9e3U!xd08QJ9S(zyO7 zBIt@*sE+u5fmc{}?csRMfNd6b?4&aNbT^AjdTwyalVzWGPEsMXBL}G>)hq;{J<@r1=Z^*mSkd;H5=UhnD1a7AX5<-WX z^-3Ndrs!ofQiGhdl9Rq>-|b>DDh{JW_lPNQV!K%zlehdTyfBDM$|4;9pf70T*ML;S zR+DosPR{6zQ4UV^#pvw&9A8t-@|TL3u>k*GDQztO-HMjK+O06wJ%ajTWE8uIQmEq1 zaNz;$jKA?1|G5Lb7~PE-jC*3=smU4EuR#jf2rp-lun9EdSCPi{J?Q}#^M+{x1h|3_ zNj)hYMuTrf8G?wgJZ1APO!izxb3fd5sW1Zzg5&4pOb^@4HYaS!Ml=x9Gb z10poXdPYryCoMCQYmI3DKu{w-q~yKtQND1#c+C z>~Q)mLlisx8ZzuE^@^nFT>|BG->(H*!<@V>_#wV?_bG~3wB0mA0DGvKow0!vfp+p6 zbZX#)xW`9VoNLOv1hNR`pDV#w%ouMr^IXw_+ zdYivJgrW)LfbhyWBn(;0ybaZ3+)p}oEl7#0(2Sy#2u70Y(TbCE@+jm6jX=)%B6~GI+Q57EO z2$kR$Gzk=|$v=Pg)m(tP-Q|+Pk!x=T7;!B8m7xPKAiL6q^slx=Tda+g$ zx8%3*)N#JK=d2ZeFrh4qe_MFXF~_DocEi(MQ7u8Pm_E|6SuyzHLJaOeMMu%N0xB9v z@0PP%0rq14Bdxp@`*e=F8sQ#58Ajs-s9`wvd)MY~f=_yXh~$Jc)xp4%@dp~i42j_z zMkgMMz@wT)O@8sA(T2z-j86GN(s#w9HUY~;m=thVQaVtwo zOgK5u#MaN0m}G|%2~^oYOER8jVjJDM4Yt;--Duc}En8ik<8xkHH^Rw{~*j3k>>H^P%C$4jvpOfa9YkLi%~Mz+hj!TyiRuo|63Uj?p( zM0SfC(TpUI{IL10524Su4Ku%%{n>?1uK+!yQQst31ahY##&0UnRpoq6vwYlGKGV#M zaYTFL$tr9Q#jr|s0EN`-S#K5kBq0ILc{4w~4hW}&2>5&p&;TY0GjMB}BHn$YPREu! z14K_<&hut=;WTws7rsWwtJzKwNUdX0C=``iI#`SN`bi`2*T+y3gAO# z2nKPSCt)$Gc=R80{1blVQXEr*Zs0qQg=-G<|3~eGO;YIrNQ@nbLvBJv+}l}09u#SX zfC@beZ&*QZ#biHVY}{h6i!R!z-?67$H6&6g!X*Tb_lNTz04^ibbjfl}n%hiw_YSNN z6E&d2#bG&&c)&ti5=6nal3@cx3|-1w@dpjRaYL4X@=-3S40{?bZpL|(r|7M z=qF?cbbq+0{D6&sfEt5+koPh`)imJks`&j}u6$C5qBAq-p7^X)7QPGS*u%n`dP-xf z=TaDql6qz(E|68-eterfrIrD=5%20=eX;GA4%!ZskppATly`3AZWjv@3aj&(32E=( z0#3`x?`s~{;N^wlPXQnA`d6aS45%WsR{`ZIrK~JLS&C}}iYv_%D zfcL77RUA*#fMtIHaBj~<*<1#rFAZ!@2{V1l+cMd?`^lmrp8J4VoaGuf#%=CTNqe{! zUb9Opw{7TS6u={F11whpBl*LS@k+hbp-Ulg$Vqamy@Rg7jQEtJ3)xFgF0-Fg?k$BF z{h=2Lmv(?toiOibVJFY98YM$WSYM1PKeO{OD1cK%{+;@0e?pv%Z_)J_RrB~kt0b*w z`{rOK2N;%4sY%9!Gy7Q{AmM?md3A|xI>x0QAg^c z)h41_V1kdCB?hBRFZGw)0b>~g1F+vvSWF78`I-r-eCG^I9=Da_M!|0XMK<`dV}Uqa z7%{9{H&vp@$fay=hRf$P9w7HzQxd8xBziOAuJSS>Od zP*Ul#ae>BYV#8KZy4zlqP$pL>5)~!V0;MD(%8Y~>keV`N#X@mPMUyTeC6ZLRgGeTd z;~;ym+u*?H4uDeIK`+y zt|Ul=lDl6_%8ye;PFTqNamf`GpO zqNJCG7~v%$keu5OBWZ**u~jwU8D?$PkTJj%)fJ2og=g zl1IKU8}_QNGA%<{cc<^hV>bpr{d8RR@~!SG@aUmGEdlf5M~0mPM04`{&UxXsVm?9N zMojTP+o3(A=YA*!W)Wiu2q{*I7y^hDYXtz9qri|i6Z`Bq z0Qvv``Vh0x;I#abaZG<47y?{YOO$Wj`rJn4ax>S*j$1b~qsFQM`T8eZJ8y`co4XZs z_U4JfvLXPph*=-u8w6DU+^Z~WDmxbdos`LPhxI}3sp;HlumIW^T~H9cQ6y5xqp-rT z^1+2rXco3_a&k2`E41z0xu#l;wOLJH{u|(!7L`X0donRZV<5DPzzw=YhJ4G&fzV?8 zp-LjasqyjZD9>7bejg6XA`Zxi+T{rSeW+TBto%^yrS(sppSqttKh9eGWidRL_k{NEU*M<9Q2?Ll zsB2kMhI8|~z7SWo23=N@^T)%7p8U#u>k4z_6;_XBuu?AfcIZF?WjO#LMHq3dfs+#} z##+`I*CL;Sf+iRn8BsSurG71P4TroSTU={v84B{Lz|}4zX+Kmk2Jl@a#UO34)K`zQ zh7xg0OLX6IL}mB;~|}QrRw;QPf}DW?vN@zUuoRgi6{{nqIkYU*+l;T|wLs zlN~8b>xBAmq6^v0;Taj>&1^Ozk3tTs$jVAbRdKOcVmRpOvjJ2sQv0TZMGsovvpU(*NH@8uA$+dVo%N1iq`Zt zb1CH^pJ`h7Kd4;2KDWwtrr^Ckw5r70RD_So1U%zW( zp8>KZt*mQ{V)0#6N(8>KgA@FQ`r<|PdH5t`r~HR(TCUL#X3euh&l0HPVB3oVU>aX^ zfLS9Od|gq)`VGP2x!FhJQFDz+5 zv=bVj30B`Qwsf|yfuC1{hKBf_^7U&qW>kaGxVwW3k!J-EwCYJ}>w0>TTSP~PFZFoR=Inw&Gmhht|m%fL7UyDcKmg7+2 zp;O{u@5}-Sky>LmPJtfU`QUeKbO4(D?gzb29v6J|@2(l&c|o(Pp3`&)nzv1<{TC8c z{*qoM5K1^cJY3?H@2&y>L@3P~oed8^lOFu1X9oRK(I(sSvU=#34HIvNy!`<_2V6K_ zi<{iEHXw(83NSA4SZ_KuX1cx=pf8Hh9~8A`yLxBafO9-hk(Snam~n;{DFXT#0AF}Y z0THSa<^b@hP1*LSRVjcd>MH`}p+%$esAp|5xTe9wR+)$;uspMNXFpUvJ}&0Mx#FFe zj)Et74<&TFNPgr)kPGJ{aJ3A~6YtytBPY$!r1u|EMT3Xb4<4u&yM3E9c+3F>|7n2w z{-c|`R0aSjZ0V|yUI5QaH-7LyjRgziEY>K{Xq+{@z1c)N4haoLlRCFW#SO;cdxF)N zjL5B?(!|PGJDOr7?$vhrvPP>JHP;vztack1q%U2XOn1C({Hjhq0=fbOaRTBe9Poty zFnPtiKn0*VBE|8C2oOX`1Xat&F^d@f#^84^(S-5hVC7T}vGnvJM!PJxbbe6d%K`4; zof%-z;>>Ax*U{Prmd#SNc(H(@!83##oRK^5;PUaXlLmiV8>GvHh^U7+7#wQ!MnFEN zsXI?lmnjr#oD~>NQSn~TjE-tRXvapMN`6Pc3>Y7uzMgejnguf>moHBykZ)W5cmu|I z?-qZD1%sc`z?W`AD^If%GOOiDzHSU>%GU5Oa}&zUgu{@^eSpjyvxqr#03o!^Uz2RC zY?At($c<=|FcZ&>$Zen43k_MnP!C}Q-9UBq+8(#v%WIRkW;rx^UDMsgt*Zw>p$o>h z5kX*6_cmQq)1vb-)W4NW>gpsRX+HXF!$OQ}DL*t>kU@=7Uki4eCVTm>fuJ?`*b1q< zFx_!LLOVK9%AVPIvA*LNz=hy_v5ME=Z)m9hL-krp1=7aGEh+u)KTU4- zE7c$UAc%$6s-i%ZKknxT01%TXRJ##;eJ8=TM^C+v^1_wE(RCS8nly>mQ&du_bWtw< z;~V8Ms;WqNeN`7*HyB*PEMiE*w0N-^prlmNA}wuJ;`6N94f-F9ks-ZZ{4x69{O#o- z`?qI}I#ZzaHu(>{j_m%+?q9f*&RR5Am)U-J`IQ9kVX@!*R76{ws(UUt6+(*0gr8Uc zTAsK8hrbw=O&l?YAJ!}{tK){B44?pUUFS<7sTiyjJSQG+V1Ui8t)E0Q8qnTD^1t=-2ztcyE&$Nr15+>4SMfvn z*XPFOdGm-*nOD&8(>MVD;9J+S>xFJ=Lqn=Q$c<_{LXA5884M8Qo zv$k&TY2a^A+~lMy#{HTW4G8kDs1OBs3RAT~bb63vYEy|BAYv9=pVB%sWh~o(%Cp!k zXEXsfMOqq#;d2w`FNeG7!)RC0K1v$&W+(qGZ=E8Xac)eyT03+1klO|TzwOKnxE{rl zZOXgBhY1E22HpCv_)M*)CQWM3o~@tEYJJ`us^VRWZ7q~N?PJ2KjXY51^@pH*XY%<) zE~wG_CN3A!07^jt=2pzb-Slom??WQo?Sux>5PwLkTO+dZhRU}q3$Cn)whfZLJ|M#P zAgbVcTPXC~$|kEOW#dWNrw6ZsW&pI^Q%*KWm?}xEc)qW%mAP^W;`i~1y$;^CpdUgg zB3c6r^c8WZPg|{KP31b8oE-9Mlk4v8ZrOvZ0nhY4ruB&?)I&kKVz#B!Z`?~BOANjX z5Fn9h6U65d{us!G-m9xp+pD?~gT!Tbc1|BQ$i|@<9MvzEtnjvT z=S)^}m4nC*^i6V~-akIb_t6*hn!RUHlV^M4n zNtOen&PO)+Hr!s{-y5K*&Y&6?V%#wX)6VM~f&xMxtwC}`st_w|8a}wrSch&9(eGEy zQFOKCapY7*#qi-)>p#NN-Rbx*)s59(@HBTC9vp}4vLX!QuE!GTVBKukRmtZz*tNcyv8P9_7W?Z z6e|jIN9UO)$||MzJE8oG^HqV_6WS);Dq8}QvYY7GQ1h;iH1pUM;L8DXy1iwhSac@Q zGRRWrAOx9y&3W1Qp^Kkf0b#bxgGXn8h!)8kh-|Kh^Ht9_9a4W$E z3SE`oPj01Q;W~f;G%bQ0+lfP8uLkRQIXjQ(4mc6147-fzZ^b&3O9zw@euhdz$leAr zC2(9vhCt+eNk|LQGbtEUvBdD3pGlJg@pyyWLDzwj0au6T%iok;S@pbOoO^hTu6p<> z?;dA3U(J=2-yhNf zlLXeulcxzTg|Wt^DQIeTM6N>N775+1^$~%G<8R~iK3Pkx5#PR_%ww_7oD3P>(EpM@ z#^CVL9QD!ssv<>E*l};Rmk%4rM}MRYG7BS!v^%TnV<2kbV4`G{c~~H#hDV5qg2Sxc z0$yZrC=V~#4VKL=@9|of7^_T9iEUk%5MDxYgeJ?fptuB6TJlXsL<%;;1V>u$vX;I^ zM(cgt)`pduWID$ZqLTG!;-u=J4VFMY+Ol1HaKvOpJF?w_=~;K8PG!=5qPEVH?O?~g z_@ak0!eZxTlV$5&{T-z^X=7vqm`GGB9aI?zLA? zxkW-)GK>@@l=u}P0)vY!Q-cU%O1Gq2#3@t6^f`sT>3d^`Iv;*NBi9r#d{zz=pUWtk zW`nHJN-aDY#?rzoM-%=e!p461C7l124)gz0zFA2i85XVU98LF&hWV|iFU<~qJ8%YZ zW(_|$@@@DO;?!1#xviSIUPP~^zO`+lt`E_tSzqF<7nEZq@W(?{!I04Z+B^~}d9=ta@^-El?pR7+j zNKhX*91`p%3u<$&v&ecisJQC^vRn;)%$yW!_i!i0>?5d`n1#k zC(2S^C4*BLO7>cIO9t3x*6v=wBP#^8$+azG^77JC#Z9$|wE~i&fTwZ?W3aJfQo^56 zg)m}aRXUliAs9Fk?2n zuyN#dHQ+5qUMTGZ_1Vg(bp5A$qw- zqj}(-d+FkUB#{)UJI1Uou~`h&dG(lq(JcKx6yMp6gr+l1;k|rD{Pnpd-)vpUcmsh!YU6J;qHPD z6_yhFog{IsPC3LtVQ%>872E3!*fTi`bWY%04ftSobuuT->D>#a(+IFRA2sCQO0_{o1L%(w`{QxLR!sci*X=ckFh>%gPzM1{vtr^m(R_v0<@V1AYl)Q8|k^7q!kSR zIGd2??>1BaWcIr(S;D59?7YmrhuOg`vfkt9|D0RI<^Q?+FApa1Xd_R~@!|<@-luRU zZ$HjH)bjZ`KNnQ}jY-W>K>UL}%&&$2%LsoF>CdB7s1wj-VxEeP&ca_by+NBM8c*j~ zy4|Diuxy|h9>oNSe>O312n&y~^Z={puqB4w=Qv=_jws9C=K5dr>I)S7CBOf}r24mk zP@fspQUA#_YZc&)Lz80)FV^uf$0gAl2MYLv^SL?lrI6G+V@@!Zd@1qa%LZbyiR!>l zQb)ls93ZTV0(OLj{InoDb!Z8~U;r4f?iHn$cD{NOFt(Th0~S&vLP;2CivZ2xpd&O? zrD1vas5zKfjH=bdD?Lmp`~^rqiDSmKY&wM1G|fB0%bil9lo9F)JiKnpveoSksCwkr zF?ktCM*F`Cy^l(Y(-f>-3Goo)IV@R?x3wGHr$j$ei;vkF{Mg-D93`}$WFm>y$DKjT(=n9 z?|lw29 zf|AKM4#?BerK*gYVq)TuFKJntZX7t{3k6%!RZC!>dvu?70;8309QWQ*)#c1R!z!KI zzonBWaH#=Tjoy z;BkJ-&;6+gCfNsP^D4km|0VN2+lDvvpEF-sB0#;^x-vERU>h+ma3p~XaW za$$t=5O0KYS>ut(tHDp4|AQx2TuB!253l2O@Dkfh2hPnOdS_V}%q0QOh()^ICv=E8VO4m}le0Pdk ziCl%`LMUYyv7dPTPr{g{E6cH2# zf!9MH*3;X4_`ykD>E)b7-T5f$?%Njk{|Vss)z|&_NX~$u7-6;P>r+Smy)a)X(=mj$w%VZR?h4%k({fLK^ND0fdi0WZK7i1N)IL$L7b&aB={bx4po}i{d)?sr3o4Pe8{WW%8FibK4WQewW&LX`RaYJh{e8&3zzWXIJfEo+5&Oa) zl^4vosIkbreO|Uz3Gf=H3sfwS(gJGgK!ZIGs+d#x&w3W{=>R3PhL|D_dy1B6`mx!8 zf3R0JeyIgG+0L3_tsZw`l3wyHLKa4ZaOrD$f%38$)YHwyDW)||fdq1rf z@9Lu|2scUFeq~HzLi2Y!o#4`$#!`M86z7ai&*q!;tzhnZ@qkSR-4gDl_Y(?-v@(m;Ov)a1#5|5ScN|i;REsdn z@eI>SaC;~bLQqtNmDzkyA|j1Yf}#LjYgS=G#Bf!*Yap;%E2CA1K2u83h|LsnR`FpE zONNi5)8U#D3F_>B22 z;4j4bIIL!B^RHRQj+i-<`(tWzJ813L)Z7kjB~lq{9^@fzm2img`XrSUk}%&*ueO=m z-E~Q?Ox-{g$t#7~_k3RMb!voex$15}TVB$3H}N8B#AD%w*dvN@mFGya%CKtK}YFH-WjrFo_c+~E4jj>;q@vZjadZui& z?dDuq|9F;67wY5WabF=wU%VtO8BOWFE@gC)2WAeML%mQw-I)RLKF=d_URC&j5avN> zO;N6TKF_3R0VfOLQdD`L=b5~soh_^aT4bn| z-Ij2VR*>Dh-Qjxjg-}T#MnNZlnEg0kYuy;YBlMK#I{sitYxn zX#lH>=b5^Z(TEr~uQjd_KqJgkp0ug2>;+XPRirJG){D>>Q8XJI9#%nJM;K)ATPW^m zUj;FXZt)%WKeWU^^R~9$EBHyNw-~Rry8-#6)Jo#y!YP(RK0(UB$;#l+fOd9Q=9#SyTBV zc(IN*5U-EW=He&qH`D!(=$#%#%miQG&)C17^zwc@onD_#L)WdZC%b%(ulMJ}?f!h? z?Ivx*5r@r!+&QiKB*x7WZm=Kp-8G|G=jka>x3|XOS#KV}xt1-jd2>qqda|q0tmV^X z-#Trlt7o#g3Bw1+<(=wunKJ5p!pKC5jUE7_G}|~D(BLy@WSIg2C_s1?|1@#-Sw_5P z_hmu|(^pPSxBzZOPggirHc;Ptu0PbMZ`^ao0oQuPIB})JuPos!+2WehS>kRouTf9G z?@jjg$aB2GLed9e;+0e5m#WZZ@;G5UXR(udVfxv4lYTV(tdca*u08?vv4TXc?0SNG zv{Eiy-_`3W*Y@o16XKcU2G?%H$?PpjEiZ8pYK+d~rLyUp^kxfhVoubr`ED2RFQI-k ze&ejOd%s6(xli`2sF{?PPVNibu?vz-g zQJLqkZL%tJvrzXyxGZEXS9mj-yD4(N-KBSKnNaA*jWYug5Q7kadNrST%tW)y9?Smp z)^v#x;jySESIywjs0@s`bSC7_lI021tOlGl5CK7mehv1*Y~Xw}1}QUBZ8IScJHpE> zTiX|py&0hUIRzm(cFZe~Y`|Fq5fFq>@u~9`gb<7!1+nyx`9B@bu0lj4Mq$sCF1!7y7wIyR8F)E;tx0c|F+sAHMp&Baz6VscWpq=Dq{K1xOSOmza__8+3vI zAj?=Z4LZH;Lhs;Sr%}=->vY`vNl=M%1iNg};MXG2y%)Yl!+_(C)u|5W6~ztb0OyAO zeVtpAL(aOKvAV6bp03RQrLIdR>2pxf|ruf`=XDRm( zi^M$$;(XDYulK!iPT2q#1Uuvyc=w~wdSwEWfaX%)ic@U?3n!>|R}f|sX2$cp#(|q5 zE`d7{AcRN6V$1~KQ^0}uGUY#ApUetFiLrPT5nV~nTB2~!f6$B`w}Z^sI0@1Ujeh~v zOJxPhh?@|?6DyXW8rT;UZF5UP3DLe~2eFuoD01|v1DC05gOC>1O~lq8H%&EYj$5d`72b;p0wJB)3hrIK*S77OeOnJOtpyAwg^b-=w;0~&hkK59m zreLR|UHJWmyspy-l?lF=jzL??P0=y04c;l7y>@633u%0bw&PTeyW#R)KeNxBY*yc1 znvL}B9r}O?cr~J|kx=!)UNuX0ft^`p1~=rS?yY#~(OZ3rMqwC!9e+_vnH)$CPAkst$6&1fB#Gz-D7S5rI354Oz~Xl94v~#=UwFd#H>SV(OxpSFK2u3nj0zi;!Ru z)r?H7=8h1ueKwj1K$X+DW9zmwH}lL)Pq2_fO>*3~i!kCnmS9-gFfuu>{zjJvsRpDq zX4wZh;IfY-W(vFgzvh!E5vB?|nPw%Tlsu&^AiQAP`{3TVSF*Hx)N>`5N60N5|LgsL zP(VX>+l5kLHKv4gm2=6TjQ(jbzEWfiOV7V_${f(dX2&N^)y#BtQ8wm!jh zlIj;8fJaO8>M;31OK@?GPKubOk#5=JTKB?mO}8Qhq^ zV>Lm9R%WkG=K2AF`DovqCd&h~{u5)+%LI;{z|5)xhKmt4=I=aC*ft((^(IYMn@~{>$@s)h=Pt|dd%q!%v1+e_58Oi6U2q43M4tl3}fY zb8>WRpWgKb=c*c|b&EA@Nx9ms#HLz9!+Qhodrh`e&mdFD@dxxHYU6lD{ckxl8Hg)~3LAq)0=~||| zVNg!+SA2$?*B5p~kI4AMLh$fIxV=yMjLQOYaF%jT(p)+QnXz$rWbSy%h`IN5s4(EB zXG}chwZm=*-R|)1dxU>!WvD$vj9KD zs6%+xM)M8$IpCLEdNW~z zeE+bt9tZ-^_$%>!Og*siF*C>x&>y2~tU3_30`M7ze&m{)5QgcoWBrc;F=sVQq$Dms7 z1*vxiaUXqt^t-uGQ*1hB7U+8bsbj@RweErkJ=iauxtNHN@p7!k7vu$rTSsMgagxK(@aZ zm&TUEISX2`!2TMxvmp81tIUss77}F&{37oOY(H3coxu8 zwCWWF5JfG`FnyQ{{xRw4QtjOI*?0vVlEsZItgm}EbJgSWt75f%AS;I|YOfq!Ko=4% zClQ~l)FYVQX&+SzH^=MSB%vAsqFx`2MzwEhI#_Q1EEOHchy3x(+{%OdCX6Vb$(}}` zGmv%2n~)+hEAPdgjU6RWmj?uuop@B-EQ1Ut7%}QlW`{QkYwurx$N}az&Eciq+>Yd^ zqcJ6`OneK<6>wkNkYsH|c>Caj-+0J}kPymOAZ>8lKEWoOkLivlp4zR=QI&NcXr+ix z_~$Mrb-naXy}s7%4dnNaQ2sr>56qU6)p!G?^N^U+z&;?FEBk8pbB-(Ze#^hCW)BQG zKKYx7 zToDHylw@ar$4ZlLaNG>LI=hjSpE(#iTG^q)?$BzYiQ>bSDg=lIo`lF6b`SGC&@@2u z2eifaH46eO;wSAc$V_8#__&7Jleo)uhp?K8S(1Os71lq~{tNz`Zk~`cPW?U|bO*)v zlY9Ks3j-%>{Do+nrYrzubz*i?V^S&A5eG(_suYn@DMGT5gg@uh|1?!brTVw&)nWzn zx@+rf@HtC8D`akWIQJ$N22+~^c4gP>TQMU*PHi%6EZykgme|WM6z4f{H*U+amt7qy z*h8tIimg#{g$6{8-VP{6I*VG`O zM92wcO89m(YU3S61$Bu9YngfQlTJ|~pQZ|X!=G@*COU>tE1qX>2z1jlI&#ZOkBz*3vboay3%3zamFZPhj1f7iAM>8g0yg#MCb)kptC2R zQ!}AjJF3wWcZVOe+4nsSYR;CqDs{c+@gSn&K1s?viT+#yXZ-W_I+TX!U+1-Jz_ z|GZ7w5rNBx7WHFlkFi9@MN5f`;7jYe}`DG(S>?PffC_NHM~(t zo!fr|AhuGzrhs936BQq3K<;^LDYyWS=ci}53UBNfuc+O`pH)_KCv0w~R!adIn?3`p3oPiOXs(S1X@AbdzqWXTuE;a^&8X z>CAXb6;3*xe^;vtb-rD`;NP2F|_1?+;rh^c-NCAmHV^fbCIx zOhI%}h0TycL;f!dCQ_Iad$bE{xWq>;8P!Gv1W5Qfx2nVvT&UqVYC=ypiJnVe6S|p{X z&MC3|MlpcG^|6*EZr+WPJQz7-CizxfI!c}R+^4V09wE+Zz35)^xpP=a@hU0tmFtLo zN3?uRgvG@h?CNX5x|EELkI#B^X`5&L0gS3-4A-Y}A(BERf)Ii_mB5IVq8cH7KkR&y z-%43zkZp&|UDS0e!MUFYYBf~OA`f9_&1%B+ORCm2xZ28it5xAO6ZU#8J+zPBdGAbm z{?dqeno>G%KzO2FNJ8YS%;uk4@lC{XE=n{Fg{w-ni-dUm7d@FlJp)Lj{lO*A4Z(1Q zJ1|cZll#({Lpr%o$P6fU0IVfEznxO~gP=j97K@-k4ACVMLSRxDIl-Na)eWh3sIUyN zIk1lKcA8oQw5}HPcmp&K>Kda%7&}x7^C*n-Uu@L55I+8T0G%S!Jmgj8;}H!;CL%eZ zJXrh*JJVY#@@;a50tbiOU4d?H#+O_S!jd>>a>_KPh(b&8e>b9E!%(5tmyXh!E<)i}))|hk_jZ z^I(q*g>twBEB*I6-)cdKKnT<4!VU!d zdC^3}-rHS@H+z24bI%-gxy=wzmlir&DmPV-7Vi}6N8fl6wJG|4XlK?g*+y&Ew`&rz z#DLE=BX)LO{PW^Hp(y?H-Nl>mPPbB_gXl|Ewryap+D3ln)GM7Z5(0jby#>C8*yQbF zC&%8?txmSo7aWEx&$Mtm)Pnfu_HEQrCv2DHuhG!m&n}lXz6QBct3ON4GvZH*F41jN z#alW~a#u9)Zz<^JRwg2|oQ-tX^|khVw`>8vQ=IX<(6Qd_{ktbZh+d?$e2HGL^EQku zi&*Fa@Cr81a`~FrNfJ_sQ=q=shi8uv)o@To0O31F34{$QdQ*;K^mUC#6$M(&NfmBm z4L__IKm)f#)XTZGyC)TK|Jyx5&{n%!o20z%+-gKPBF5MtJjpgZt=(n;*19RU;4+UI z%_6JvVJ9&gfK_4c@cVMuNujkUlV1=m32}#{V*IRJa6}Sb{g2b4fy>I!0%MpibK#1) zB;)qQ?pkhqshayc$Zla8ry9omTj>?}u50@CFuK#;h^DzpoC8tBsWr{Y{WR*}GJA?-ytA*K zX)a{eogY7qS759t27c@|*0H!Wx43T>^`#aOPqxITYpHm4=HJR5R{d-?o=x58jq7S? zT7E^|!#nx$#k)jYPdbcasjj>lz3b~Ve}7av@4Mb-m<-2}uFnth51K{maAL-FVPTk- zr@k4-(H3f46+yi7Ipk2DeXUOt`^SCltZjz2=-Wy+G8@!uk$(5Q?aTZS?;Wl)Agvp* z$QSPJ2W6JC#;rq=ujD!o!*b8pLZl)xvzqk645YyZcB=P1+!Oa$n4;i+X3&0m$-3UaLTJoH8Xm{0vjnzy_ zPVV86bDAdcp=5{IWL1Vv{wekMadWXBEqKiu%MJf#F&{>}f>%FyJzoW98=0POH)vTE zFCHf)1S;$L?-#R@lWjUgIqr|T#avWXEVpR^KN^8Pcj7`9iSW>+VukJwy6S#A^8Nnj z#92Py>P*R?2+S7fpG&Xb^@k!$T^s2Dxh#)-28@JxS?*9=n&jrMoW}~4VF&u9;;fZY zCTrIHZoH5tMC544M+|O#A-g_8)>b2aKj_D6D`Hv?Bhx`-WVZ}&fw%7PmY>T|GTqjR z6>k#PXo{C8r}|2UFfUlH+^4x)V7A5*-z?q}rZ`XI?h^J@N=Zc^&9^B4 zm&(Hr4cF`jR>+A{qhq{Ud0tE(_{0C>8D>PwwqwbTCSarfT7yodI!W)tRSV?ydeN?4 zhZFJmlLt`wocT!xS=n8N!YvlF64sBJqg$mYuT#JA-%B?pX&VuUvEo4pTnJ(sCMm z7q#JO;{9JYP6%FTxrx8OpZR`(%BtG6_wdoMNEf#gyWb*`)%)ODeee+fr$u>Ko}<8DGB1$`^Fm2f20!n%{M7 z<&i#Xb7BU-f4sa;njN*;wpT@mp_-!Y^p6|7n|0}#p%*>Bc8y6Lptke>Tl7+A4FW9k zB=xy5$4Kwp-Dm9|gH36@{kpz~zg*kLUMgeP;X!kQ%{#~9Hs0V>1a87-09c$9 z^s-Z?J{k@N!KUI@ZUSotKMau`aGWOM62So$IgC`nMC_Y?Eo^w$5`Krv;$lBfeR~{~ zvKzz(;6@%}^idULmr5vhW`_QPBzNnwHYjfTko?i^&<@B-BGeoGgzMtWGhE<KM^`yb#CUn!j%pGF$A6Dfx{CQF1?TdDP zeg0zs)9y$qql&K?*x8^6T#@RUfBcL{ktpyj0jS>tO((!Dq)&4yRJxmyRMAOQhiaov zCcGa1V?hH8PAds2fcv0Nv^A1Qn%Y$gILWIr91SPp*|r{Gw6=!Qo^mqZl%ArJiJ;Ub z#E|Q0dv%RTphkI+oJ%8V8Dlr$fPG%=6QME31WK=X{f1n=?RjQGWxda0scwRs!DG~V zV#7T+nyDmQ=lOiJJXvQsG66sdg7%E0DE$pqX9jw%poC{W#9nD66hJ5;$zUHX?1*%7 z^HU-$>&9JH3cQcezNSu$qmbG~Vx42wG#}E${Ug}m4OpCrEB<02Dtt2IF)tN!x-(FD z*#q=x>s#<%`8*Y{<8&*=QOZ2I-|+s?Cm%m~@Ziy02!Z#6kjlhD6t#fUn$5k~sy)?W z<9=(`ML|}KgQw{x3GSJUAr8r?lutqv5_JM2B2AVHTo=+^GAmO-;2~65<9%4oYO}Jn zJ{b)MBeGOzS%g|3R?yE!Yvr+lrF?EQ8mX3EVkP9rT&SI_G>L-AOEn}HkBYIc34@U) zV8_WEQQTH@`V$#a0tw`x@PU-r&A7kL7?iu6&L;XI)(wkIHBb3=hecN{V^e7{`C9m` zh02+N{hRzQtQZk{Ya!9SwhJt8Sx|t#b8>q9RoH-1PzYL{@D;izYm({^tXS?>rOi@0 zqPGdNlkV0fVlbX(iJDqaLKpJ##7A!#n0MTJVNzQ@u9{IsZ zfCEDuN!K<)MNBf&&i%&zlpI%;qZ=vnHcaX7msv`FS|1tc+POiUN*xArN5l|b`bP=)XEGu++t2=*2J;U6Bxtvj}ZPCy=#E}n=RBmBrPNDI{%h2J4 znh>h6Bs=<$PuUhli$he{1%)K85Wuu9{!(gPc{SR}97HQ~GtngxiyP4MmlQi8f>Q%vu7P*e)xG=zRZs##pD$xkRiXui2ap#~9B`nj5wxN%K zY1dG(Ioc#NtFT{QT)hB!6x)>-U1L6{G7aiUuqrMdFxB^e?b6mhQ^bP;zX1XoDjYC@YUzTS*n#~30v zw24OZQqRw9oU0s@<16OOxGUE6TC&fguDl+s-?uiO4`;hK_9zl}XG1)d`C51=>64&} zql2*kNsEDt`Q_jVg!Vv>!s&2KRX#cEulv6kg$_Y?F$qzPJsAu-cxOEmgmK^O_oWl5R=#;A4x|72!pNBd}e!_J3E_e(-EaB3X_(O7nc(C-l-KD zEyQr37@Y5wqq0w81Z0vqivx1Pd}@OXAtg+{$dN5hK(^;|o*3f+*Fl!3N=HLak50QW zYC`)UMv{7oZtlS|EwJCCQE#N+LlBXdRFNsKD@*H?p_eeFZftoN=4>2lHU{!UyOh*f z^C)S(l4=-3b1o$*xB}F32Bm;-`K5LD)+! zf

WcR%Pe)kh@Acf|6kkKe=zdIkeWY!~OYi+N>?7DQGW_*iEA%4kA$@774vQ_JG@ z;+c@vlY-Zf9_gO;C*Fy#Xm_;81oci5uXPx!flHXiaK-m58TIZ{Yi4^R2{oox%X$@z z%8d6X&Kn46!JGNjm0SNm0;%X8w~b>zcSPLYE6mJOzp}0rH($(z%hr2qt@o|)ly%oT zx8~-BLRP&0IH3&V&<|~ruLQ5fS=dXRc8Z{8Uu?j7^HsGXO9bo;ZEM1urKKoCsT!&h z;%WC?lhA?1lRRv?hOQn>RGHPxZ;GbPY)X$h`!_OEt%xLopkiT+y{ZBvdCJ&fPs|Z5 zwUEhxKv{(5N;CUj5atVtd02FLr>&b(NGTa8E)t1EVls8a_;{G!ZM!9x3J0iYHIJsumQ!z1uiNkLPdty-CcL}siI74<#Oxa>-SUNIV-`;nL5Lr6u+5ICcmks z?S}06p6`3s!_YPDrZa+%NfV{IV3pfjUF(ERc@St#hC%Dp4?ho2NKaHdN{? z+Y5wl9sN(Q9y+QcsQ=EpTDu&jf4ODL_Tb1#iMn6EY(B}?K3#k8!fHk3+)L??vMKkF z*J^A1(n|-b*qg++Hf~C5VSa_!QVezr7_Ra({tGmz&G8&e zPzCeh5;V|Ybv_2)?i>W){rRtgXVKdq%E>pk*JjgeYqhygt#B#1q;xqz1+O@%E;-ot z`?F2t9?Wu^Yt8w>h`p~1%iN7SJ=-P@9ncMQLD)8;}L6G=n)T~{&!mvb@sn!X4g1@O>a{w++3vhK!vh1lLTG@w<&pPWEXV31wl=I?7 z_?d%d=Sx#9Uwn0$2Z7WYLy$Kd$GyLbMKl*kHFUqrN^`d#f7(@bM>@Mkon95hvc9Ns z(2Y_%l4&H5i5s4pJ|E{MKt}%AjUa4ziDS27kwi8-^>|w$E zqxZr6vs=Ldy5M*|1`C9s4O@^|8@vhl7Q83{IMbvtB@Kw6IGO5|Xm$V_^G;*Z*PU!q zZ%Do>>+Me*#@uEt`^6mh^GVG0AJ5e34Y<2L3Ly@$rG6L<{v`Paq!P?RL0O$1E$S_) zq{*gnZV(W8K)ofTv-0$UXdU(%B}f|MH|m|Uc-n;)QmY#bE%3ak3WpP3XAwcLA=qvy zm~YwuY>Skv>Y#ZOuVp3dseemz-PG*2%#9G!BRL3bAHPx8v957Czi92)f{PF!kGl{a-Vk1P%4&R%R1X8-EU_6S;Nz_w~98 zl$$QzF5X3NkAic2cJ}L?0qcNuKI9qSUlnP<*;Ga;h~_)pu-kH=k&_r3dWHzR~9o>kXx2c^b37>`(5KTcAJ*9X2rR6o-Kyngj(c zo;kRZcyI_KWR%P)gW)_{6@HjpgJ@82x4u~mGWBrLPQHNyM~)ogZJL7( zdV+|I7g#h0O#Z~OiOM)wuHW;M{@-(se1ZFZ&#U~Zzdif~UhMow1MmqE<0gq)j`XdJ z<6oA65RCIpy;3K?g(8mS!WZTGe7pzeH5S?`%B*E5r*j7F-e~eF3u(D3R|$!8sofpOBoywW4(NQ<2KQET=Q)F$l`#UAy$}UHd@h+g^~?k+Q?o z{(|zB+f!}aczNC4=4qIXs+A4OP2)f17l*9FdYj4ie;Pv2Jw5S8Q42bN3^lSjG=-7D zgf4Ggs*<$N$#a$vU6vm4kNDLb*gNu)r1)<9pXG3e{6N$+ICCmjijKb2%klJ<*7-}h&6hEip<80Y z`ISFrXJj^0z4wLfZ#Yz#t{BT2g#MmK3qdc5BLEwAYuw_#tZw5k{$=khQsc*kzaC+! zWb}Q!lb(;~UhlQT*Xu{yUmd9h_4lWpEz+CFo*ErtLxUT&pD>m-EAyB@VbDUHSH8Ss z55+j*nVG^8s+meMZ%SCwAxYA26`^?7*k+%wG;C4J5lt!n3<8V9eGKw`Ioaj^BfT?Oe*V-+gtl)aP=lJlazHzgzy@fR^dNy9{J{@Gb+HE>QR`e*H1p2e8}Y zXA|GAwIz?hdNN*Pi9TAONboFuSjO2cq}eUHE1#+wM{0hfa%2Xg`?>CF#rGGsKmCNG zwa;bQ_w&3JVpq(gCmGgZeQsTysUC9%vNC6D4T7BE zn}|_G#(up+D42P@*i|6urVIR&(VvO0sVCB?O||4eYa!+@g5hTeTH9(43UaGXBi8$X z-*DCYjvhJaPrS=-_^iV}8 z9BIo%G`+8!c}%1pz1d#_IWK36lKz@}`}r?t-FV~KzuW2WV{MuIiTI`b#8cBd3e1d; zn~$IQ!hmt&K2y6%($qZ3)RBxLwm(|#rk?Kc>#ORXOk9`9_a-x35*Lq{t2}$#qvdWY z{d=E)Y}6g3;lybKe)3bOa|#^yvM*@zuvG%0mK5roTp3mQ(=$-7Kdli_r5+xhj(&^R7qxLl(LJZ)i6!J1E zk+{|V`gIBg$Lq?s5Qt24ZW*vof4x{aNPh|Hp7je?nnIocqsTDQ;R78|oBjZHt1k{V zLxND2Z8a^-CZX7^!bSR?cj(jwfq!`UudyfsaL2d#{~_H1;$blWOa4$+8_s(|kylvj zf5BRI^~vGuZ-2hOEq+-+_#POgmV2^A4zwn|qCGOlgeEAimBEFkoz!yJ)E8+9Vds+| z(SQxFH$mR{(8d=N=Sq#KS#i?RUS*0?S}i)z5f+hAf=D(OERZi?8`{ag#wNM?@jJo4 z0!q`_0{(_7mO0p8uhY^F*}r%)CX0Ivdw6#81^P}U=zRFjF6hgAl64dvMI(_AqR42V zld40O>E!I*#Q=^Po!N2WqiY$$BJ6oSUz%iR=WlgbhC_JAqCQ<3Y~jOBDN1qDKxlt3 z@!M@6-20l?nb)UQ52BlGJSKAYC;PX2IyX=0DytE}OInv>n&|FL8`@bQmHr-PnZ_dj zck$|P%K5&MKA#R+4Y-^?k7q@TC{t|`)Sqx)SyD)&7d#;;1v4P>8F9T zr)O~3I!&3&exRUKL*b(ls3L@_v?XoT7l+9s4?%4SO+AG+W}Hn=v1r82!N0SEI%ECS z>cKLb))RT5usX4#!skRHFCK>Y{I@0_HsagzDLga`?N1#xeJk?Up!M>kCkhEYQ9J@G z^ePPW6#>Y3nB_TJ%5A30=kMk4fnOG+LT+9DHeqNBxIz>XT0*>nXnr|6&C-~RO4N7<5JvL#=9ga6g{^!u968T?F`$+t%3 zSKaoZ-%l54rE(Ir_0Y+{z`zh1gJ}jRDb=ZA&5#|2ymWoex&*&%pn3TI(dfXuu?Rnd zzn;DNj~Gz$sm(KH*C(YW#|uvUdgxE%5w%92YisowxL-M^L5Ql1M-x^Cg-=D08TBv| zi)>(Iw$ZjAwwbFBZN`jkM1FcK_i%=e-dk_S5Anf$S)~1Fi(K}jy9?Sw`>gNdm#chB z_AU1Q;DUslTf{0xXoqc(KRh-!W!W96DR=bvRMouQg~;7yboRy)OHEws&(h~jyuy=L zGYnp{_!UIxoPO0`V)2Us*Wn0;RG{xl>D&Dj*PCj&xp;g`{N4)XvGPbK7Hy<9JMisX z_-%Z-qW{*7irN>du!UElU3<%2yhQy*w&@$ysJ((%d8L3XRHqYMpZzkVKdQ?-WK8qi z;Kshb#CdB1SI3_ma9fnB^auFVlkKzFqWt}9vOb%}GPtC{Xis;O@pRc+JY=L#OA5t2 zoGm5>y7DU77tcc~xAVHRFEk(A+7Fonq!W0NxO1t0+9E4S#@?EvLoxH=rBBBpl(SBY z7P9fV!{0^@<|a!d{y`!UNIOH?0AYW3{lF(lkgiMx0K^2Zr2BY?ffB47ReG3b7y#SY z$H8XDdH_cj0kU9M+2Qak{u8Ujz#*aHb+S1GKO%hCwe;u4cOzwq7;X}IPZWu-C7X`m zrVDgL$ z!pVe?3ne87`mw-Ak*vrBmZ13wr~H|i@p~)mj#h50!&=!kqzrtYozSTC`XX$2LG6?# zqQduyfUWi@a_JrNj4OiFNj;Jq*Kr(UJ;tc5B>+SknqLvIvxBK0-|65RfODxMZ(Q#wn`vO=Qy8|4Q;Q)?FJYIo6a)r6qg70Dx`n zxBc>J8@xCO6efivOL2x^pah#G|5NG9eGSWjp#&>GNFQK}0kEYvYN8ABR_ z3-RC8{jP6CAYwfT<3gr2B}YjolsJFVUtc0fcy@$y5Q5!toLr@Kn=yKn`u&Jmup<6< z1xvSbZPzw+WvO%isA*bZFZ}37a=+ED)VAdRL*PjflGbNz(YZ)W`GBd?Qx-iVG~f@x z_o7X@|A59j^PcEQQvn)wzHr{C1QS1#<-eQ0A#z81oQfJls&rL*Nj4odxQsJ6b)WlW zj}(~vxc_Wzby}n{+p=;d-lWov_sL2@5TN3W)@BhofOtGDH6ea=B4zQbSt<5(*n|*+ zEc|ZmhXj-P;H`Ik$da8|7re^wp8ny!tv;4%-3M5r574>~a4uK-F!NIVz+;PrWeq4z zzU`29d35eqc9wHCZDG+9;e37j*l8v3vKAXqZA zPdJQU488yW<)Lk*qbb?oX*qS;CLn(Z|D8NF<^*iqku2wTm6=$1$$oGg>3Kr@44}Q30fnKzicX7XK>&clq<*}&VKQ}HaBSDQ@NaCg6=>XV z-3Mr|5B=7Cn7ge$Kh<4d}M7g>ncV? z_KYr~ZFK+cJECg~WDUQtcEl_6kl-VlXD}L0apot^Bt=dBS32T!5pVtxOrMLwIz%6& zM*I+ENb7<`0z=ckZeG7f%6htHQtPyLAQYa4CZ`tuiy#h`vUQV7$)(w^zp!&#y|;{K z+Inxb9I}B^!gtw0qS2fT`MgwB<;u=v?&{-1GENdSO3{o!?f;T~7VKvX9w zQ|;;wnueuWAWHAoND`yVw{MNXF|L2dK-)M9;Zs%czCd26@3${9#WT&ew3G2B$JKf` zs7+p&$F#1zIZgmP$|y1Aw2UdoQA8!S!F>1ecg!)VSr->VX-Y2{#~ho6hSX(vQoQ(z z5YRs&i|pNJWT^DA6!yWps>@%PpKh$jE{@{Is%{#Gm05U9Uci@uprOmuJ^5L-d6EO+ z$FbO5JPT=k`i1RNhOdb0`YO%slC^?FJdq@*U+{`ER>l#`*bvrsLj@1^dy*<=>RPgUXKs@ z(`nznYPgQ|{KL)Z$GG!Nqsne;3Nak&2=XM4azMpDZRJ6msP5($A0{dbWSB&XG_K&Js_^M(&>uK)oPK%qhQW5QjVz^RbKRSRALjjH&}-?gU%A}XXTO!$ zo5gK?F?qoQV?POHMEp+!^$q=pwbP&2m*(N>ui1+8pQo1KPCg&&?&kwOc1fqMLyv;g zZ&LRR{(R@V-DugDkvL^}t_B-$22J43R_{V@=K~(0EpXDjU%`Jn@I7c)?@JH4e!mOJ zY7y>yc-}An+CAWv%TJC~Lf)|7zk3M%Z*Kbj6)P;e6WZ%50_)s|aOcZg->X|C`_b0J zcO@<1IbX(~s+@6K!e9EkYyW$$yDwAtcCAjK=)O_izm17sr&=`j{@oUQ`(RL&|9|cQ zKf2oVxwy5t&)WODNAT~DSOZ(Oz0RKVBgy^u>9uRP^VZ$Tc{|S@%3(CU^AShV9V2^! zI9%*I2R%EjYl3CeO(VlbnY)!*`Q*W89l!k;^ZEmlRY){NO0}kZCs~w5%p)$n_rw<` zX~*`{6GV$RZ8CBwm*O@hZqBDcLqh^R9I_4SnpttX+`U$yXgW0tqvq?ni^uNMf{3m$ zc1IRmuQ{P=SNcZGd)?|G#vL0Ow(7JK`x`R~)CWYw(#evZ;4h4hdG13R*uAtiC%%rv z2qfD~>bajp%+|sl;$atUmA#ZDM7LxI1sG{L86Dc?q@dA)>woELwL7H2Qdp&7pMGbn zN|*V*bk5ZLqKwDk`)2@cq&xQBsFf$GFCc!UF7+x+nfD-N+;6`I*xx3!yOEmn>K9{# zC%{ub|Ud%aC;Ilg>|mOmJl@6P6tru{BT zw{NFQ?G^&>xtr$5w|TrtM>rLHdybG1xyOr6U7ifuyh<+ftwTEU>59btMhidbc9T>@ zndoh)y{ip;9GZP^gTrm5x(_GWSD~9NpAcF1+OvoX$hODf7@y;bG(T5KJOup5X?JSi zKVE#FpS#|d6{7_g?DnvR58=+EVeFHa0~VEEVC@IQs=eS>;7h&=oTjTAv%OX|Z4onQ zM{Afq6AhJT%JX%TVLg0RnOG&uWc}=1XhhGK5(s>LCc3?|V;UKY4Qh?51myMp1=k)%)Ig1v>vp5)l0P zt?!#8DGf>4B|YP|Jr)e_?8`~7R|7J+cv{4=4#pt|Y&F;@jn+u5m0Y7)(=eOco3^Jd zX^W|$VzfP{S7>{?$k5Tp*yKB-b^o*WUXaVqGP?1pRw8@wfGTp5Eq3|Rmnfyj&5t+# z)xMnnS6KO5gP35Z`=vFSFa+z}T(!SzzT(5w-YoxrJR|z=1;SZ?dboc_*mMuC{%Uir zZocNjHI2KYT7mb2pSh|OeyCa7@W~&fIYgq-oVtuqn`v^ylt=JYQ=a>H#$OAz-bi}E zqJDjxWrCP>3X}$zTfzQ1nN+mmxr{pn(fWi(sZo_QJ?Mw7sVi?y zdVWVqk~Fj5-K+0CI=Fw)Im5EDGz87t0dw5fmXOwl;!?M#l+Qc343CKyHL`ttE|i(j z?9t8rE+JU$wLh=OefuAC>yiW`>;8<6w^ZJ&Pa=v*l9QoL$%T#dp(vne4}S=VdhM;7 z7W=@3EKXR}h^_LcURPhWMP?NX#6;U-b?#C%xDI?t5B{aCY=#Mbk>P@fw*rdm`Q#{) z+PpebGE5%K3T3jIG*ip7xohR7+VJr}bG#CbzYdmqqy06i{&g?7ej?Zal0>mbR9Rci z)YBo3*&MTbqdfE+54VyvRyI1f!MPB+w@pCM?I2y-JT2w5n^|?&?bLc;XrLR*&dc(h z<3MU+PQ~E#PtVV#v(dz=YFl_TC{Zl)LYz4hep!u+>A#aso*wB*HJYX}FEXdwg>s6a zSehz$W9G_p-ubz-&~jV)U=E{>)63D@FFPdhL`rDXJ69ZLoZ5pISOH>IP}iE{h^267 zd~|d&os2v8RF5Bpf#+3Eo)zy%i@|X?n9Pq>9(UDJ%EV{2BE8?cOxu!926jz6ciC7P zcl=oYRxn*a4#Q)=WA*nX@FzbotU4LNupj02td6%liR99+G!_w?Z&p=Gf+jQI#{u0S z`063|znIT!al-?8Ew~S3R*SUU6og?&AJ6%9TAW|hfPqa7w?jV{PKW^5P-ZH%i6JMj z&-osdX3MRKjd3@a8p>!HqAUB9u&u*VMs{r_)7m-4>{|9_F2VD|)-TJ=S4RGoaRWimgORB8p8p6aZi2=WmUkrP=pLe5=esYmcM&c{y z>%6bgwGm_&pp>F8^I1E~JYOJl5j&-IAN*@QUM)%@s9$ss*B1@_2C;L-QAd( zqQmBuLG5z|*a=nLsd>U^9F!>0mvh^Qh;~)`U_x67-?HpA+qEx)~Ob&$nu2@ZeqSx;OR9 zz(WnKM?BKheP37`8c$eg!k)ch&Cu;O6{*o(LP|0LzHUbazfEzm)=f-bDpyV*@=?nO z_fr0igOPG`gG78z>B15)(NWdi!&A;B!cA6YY^_V!H@0S35Zg@|hMba_ibzv;NNS;y z(uKM6f-_5!NR$w}ff^Fdp}U@Qt{O(*GosH+cUPjiHj+{*wTiKYGVu3MLM~nBZ4kPE zfZ)814MjX62m{?CsqW8Yd41d+XD(4~-hvV|6zKzttkTEM;S zO$y%lFp?dm9$HwhFDdR$s|7NbV!{=md%hE&G{`!WB+LG6(4=*bw)8xV#ef#9oc+tJ)(eIH#5LruxLlBpnDs?$`HH!Ld` zO9|JERFHrW)EZ!tzJ<|CeGHR5apdxL92IWjYO2cWJVl*OTQ!3!|v1vMJz2Ni5r1s4tI;kr>i(Q=erP6D#0=TqpH$ zGdOPG`;6=bY)Y9O&-Gc39Lhl0`yC6}Sl4qlKygZ0s=pj9MKamuE#h=bW|{x5S+v?9 zBjC^j6p0XM6>*BeLD&Nne^~H*hZ_l<%Qeo@OKYvq_CA9MZf=!Dcg6#;(1BB6DLg@L zopN7reG=;oh_YRLl()%(`^G#Q?mtm1t8Db#`tIZ9z5U0@aaC#qGYyifbG^}H?V<2T zWHP+6T35XRVq5D*16vc1T#B=4OG{?tn16&q>`$QM^)0Le440I<5{jW zFXLwzjhA_&%s`vudY%&cs*LVRL$R=xk6$wN2K9$emXZAL%cC+s-B_sw!1E$pE>2ml zT9XoYWx(g`&24xHhs)y4=l?<8{=X4pC+=WbFcDg4uaA6hv(Z!MdK`Qza_WBCC71G5 z=Q~5R2TbpGju7#BzHX1vnC_`5e(~x%k>WbDji)YIh+z1HoA1A~nwPY0H;Ig*%K$+s zw|qM~w$@}|8`+qN%Mnr8M44rLX0I!F3Zs&HNRM}f_n=75SZK;QN-PX6H z%^NN!i<_z1hi21)zyv{AZ*N&0-+##K+mq)NLI zR%6~enf|UmGpVHsy2HyUzw4mJKRuC|g=C?O{;A1r2>lD-Zt;UPdRK8qBmb71yVgf4 zt2Bfy=$a!2|s zx?jOUX^SN{GuQP0_QtGscH`B)a{Q@0y>@LMA&@k7nsfS_+!~MS9%GBHd3|$_N0D!; zy`p4-Q(UnNdi|7nTNyKv_XheF01ys`s-}_WyafRn%%11u%60ud!9*J&-$|A!l3QoN z0KIB)J!^)neW6-&K+M^);g2s?yI}}Z_doBSz7eyzso&wO-DR&*P@^Er(DF0wHLUa9 zi9ed!2Jz=MGOV)QTLCenQlF9@JsfBl+4A9`Z10FmrRv$WEOEjiz-a;a|6j>3L&Ige z!0z0yh5x!REM877>4v)f z4gXRgz^W%_JGk*lJ@H-zh_KJ*5q7;v#JzIvjOjA_QofQ8jgy~z_}S;L z;YmHt@@fw|ri!XS>-KT9n*7U2VE^&Ce)aaU@HdZsRXvVH_&XeSEgu;Klg;{$&(P|! z5XL4@2nDM{uJ(y11Wsg!?DJ3bNr3x)e@l9_CcdPiEi6%VL*1uobw7?-WcJ6wzYESf zLO*$5A;yb>Aa#yX!2b*K@7o?Oyfn+e~Rvv+b*vRIYItv0!W6k5q! zQtHA@y*osa2Sa%GH;0!|A);9hF;V3#@@{%ILTj@5rU=tOMEiINqmdBqed*ljF9dOQ zvz-y5QyhU*2Xynl(CZwJ?-w=1eAZUm#Zd#ACNeG^x#dQmX_PBP-Rz*k{Hu!x zIAD9KY@EH$P-mhuZ(R!^yIU9-TRexS9L2S1a%Gh6qsXlOgFND^z5Dv1TE+ao%6x1d zp5AGKCPw-8EOx)}eq^c;@-6wojtQ_C4{?WSc$>S{V-xv)sXf>+8>^DVR^j+AdYkV1 zaQwMqq{DcQ-r^hc1wYe&Aq~+Xv24N`yc zftBWmf1R;p_TvdG03E=SK}#f)WxYzKU^YFs48t0$D}Gm1+cTNM{1n;!&Rwd5`_BPe zJArQgaS1^u3~u)`<%Wen;jS+~!C-gp@MaSB5C~`~_;d%C#Lw0VElc`xHyMp4xVgNE zx5%qPrn6#Fm#RXq;eVL!OOjHXiT|KnXfs^b^ZE$QhMdzpFl199&-{ulH1Xu9>a@3Z ze)+7vS{Z+jz5Y;#BCPMAMN&mPrH7nTU!1VZ>Au6jBFuWC6Juta=;qpe(Es>OgK$L} zbBSks{f~k|vu1@8%^zGwN zJ-6G++{;yV`r*1bg$XY-jeh<6e7v+K*&>Az30>~*u*JE!qMj3YTHo__MTXCf8S|%QBme?vr1>>~H=NyYS8{vn_QrimI z7M)o)zljyLj)LpHE!(b1x`hwPwLFr~)FBN&sTj&-G_*z-=)%FbIHsj;$D<}WsnP%i zk?_)Q?!HaD9bflZJD>G}N19EK0L$Dx>}zf)1M!k}-JnDPFKqm~KoW1qEnRcF5Gz?! zY||SQD*bNEf~-UsnEj3+INJp~wGL9C!(N`tyu_&j?bO{XE3J3M$FlpKd)Z>h%Tndg zo|1<^WsQ6JRrzvnZMH6V$f#@ZOM3BG3RLR-rSPr8R%+!f#x$3t^HSwL@O-yE;t~pN zFe;l`+lB*y=Xm1h)CFp9Oy*k%(x8?&Z-WAK7&zP*Xc}}FAk*vB#Tm&u3@mmSGzK~h z5bQ_~A2qVR0MC7vk>Gt|H|N9!h^EAjeUCJPmW;Al9}T?x&84S6kvFs_U+_E@=^XG% zf8vX@6+=muW`~nL3fSy7H#?+6joA{r(dkq7wOd!(cDPAs?P$stpWL{h)Cu9UuYCZ7 zue=N<>)BY4?P(DCyf&{F(pnuWUOpz_ld}@n~Dp5MOW*~rujTL zzU4!-)s7k%TX8&yzRDX1W~VuBZdh^}l@GbpKFxHA=yYw(zBX8zy><3uTz}!6edM;m z46kL+3rcA-Ug=f~wU;ZG3DoCB@6>(LSe8JSVy}E6iDYW`8F@8(54tylzs~*k)*n(o zFa6l~gI#~0?w|df{~O6~_76!-6W%f3VaavpT(xxFdQtYRmZry!oReVxr2|>q3nMJQ zy#KiJU)Ou@PuqyL2e#!phM|EMn_8{7KH4+&S);B z62yNBk;YZ?2dRB`9$m_wO{wRZwdEv=(>+f8K&;99mY^{GB?^bn_oz?XW|O}E33SIO z{o5ebk+h7gLsqD!Q%7ug^KKU{m}yV%09HV$zh;Aur9vSqo^ux&PInNB@PGFQ)erwJ zR*`siIpx-7IV95CJyw;&e~h+aP|2EEX~3Za>{&M*0$r3*ifcS;!cqu!vXd&{>?O*bFmQ9Tag+2g3< z_24hQSg(9}%Y|qP7#;T_tuOzF=udj+0@e+4WB7fj<=m?in4=yL|*JUl^POy8qXVdh*d>Imh zE`Krw06CXC8glJVu#;v!d+=_1V40tOlU)a%iPq{}A_TGuTWvTdKOKNe*fy1XqcNA9 zll$9p)=dtpahZm7;6H&3intrYguUvgOJGn|mCcXinX_LG{(G^%JqsfyfTz0vOyYa* z%73A?G8FslfMW(HH_Kb?q40!;hR!3;MFc?IKo^$$l20b5OR6FH)1}3y20v2SOqW_r zEd;o-dCe50G&cz<*0eoR3tRYq0(ssu0cvjBT+W65voLI;XC#0?4r=2vMmJIo%J_Jt zk^OLOR$obFMoHNOhW8S937HUfUXYfY7ahlUN3pWWxX>_wF78-nu5t!4Gr2gGDqPmZ zrd28NEw-rV3cY%4)BKvBy3hAlr%br?W#NsA^pe#jV$9D0!>{+9D~aGwD9`s@3De`I;LcY!iL)#E(@im7kK^Z?uE%Glu|+j!p`ivM43S{ z_5)M^i+PbzTW)>Ghxbf)pOMTw(dhFCAzsYEZ>xNZDR$z+yF?aBFf|G36~(Bs@uV}R zo1`7mJwlJHfF4@y-ETuiM8>17&j~lI<-&wR^ns|Szv?z8KwE_WY9>E8xr+4=j;8`y|1{Yu9R2Sss|8*u*!OqR=?Wu4ZT z`R%=D+^EqP*qj8sMaRs0jTG|#A~W(ZcZr8jvf6=6-}Jy*0&>^}uSopl2UEp9_`Ep~ zJBgHY3_jF#-u|>H5%^z6rROUC;}GQ~!k4?{2NEU8|C*98eEvC_zOJ-KT-qD(T<~)o zAiSu}_Q*9`=ezX0zE^V-tPU{XYES#j{Sf;69_fhK>)&9EnAPhiv)Ob!cH>6mSUOwc zjPuxS|0@Q#`1(*Eu6W^)`RMaM=higyV+Rg_G43Nj-4Ek+DV< z1+o)Io^k>!l$uxtpx*{Uz5t(XGsJ6T|2lpUxe@gsiO4OH|7}9K9sBq}1dg2yG?H_& zuUxOyo6L77$KkG={tmvEzQ3^^s5`CKeS0h*0|3Zk1&h4?dVUmz6E#C}&rQ_)c0$YT z)V2F425Yq|Xf8>_&#OIU>|LAJ@n$kE;1~T;7D{3?|8<(qy`u%Hl!6g@L3O2a*zW(Y z*t-7Ui^`$zPO1 z{?O~W(CD?-pM9k6-8baaL)qYo*+QQAYA@QxvUQtFgTcxE~xcP6c)40{QZk2s9Y z_dxs(qFKZ`&PaM`*ycD2gu-l_kq2Ml`<#z5)=l}^Sz$YF*zbp~V?%|M)Eqv|laIk{ zaqjSSR~|9NBvUWt=tdCcJ&>nM*Mp9K$a7`6N}a}SfZXZS-KyZjn&P%u-f@N9R;VL0 zA|N!qn@f<*Qm?a8jMF5;QlIMeo@^YV3u5yxH_IvnyDb4;GiM83O*hlFpt(iGPwZz}s@#IyErsa+A;t|W~sLz|H7!9PSKg~QZ z4MsiSBxZAl&cu)OJ&67-m}n6*R8Oa9SN*R?e;<1QQrZ`23cQ>kmU-QUMb;?QWa)~k zOOi56;lG9ZdFz$ShY9neiND#(g3)i8O34uILp$izq4~#EfdN>;d{1eq$UK)w=;cO- zaantGpHS%88Xhw<_}ryfL?au#rO78nlBGu@$yfLp-+Hn>Bstuw^(8YQd3ao%B9UuR z6i>PAcg!Rgx^|KX)-95Hsf_`W$#>!_7yK*=+ED-0Z=i8tRRO=edx$!)<4ItW9(EIn z+Y(MJ`mW4waqpFM-!X7Wkj;Q zOive4gFBGecijx1X-A6O1HATBz3?);qrgQm?3I~zn=pWJGQbTd;Vx-on<{pwq1LK^ zU^=LYl8DQk4GF;$%zW4NZlu$sB!Y(E?C@1Kkx4hA9^Wa^cfmhSY4*<~*11mDr}UII z*XV>BLi+C*p8(93e!vJ0+5KMc!VMcXhPagVTDv32cXU!g(~ovgzmM79+RQ|yjurek z^`DbXO?^-*q}F0HkN|1GKTqMd< zZq(pHat&pMGab#QeY?y(YmL^q6JA#K-P?N?|M*bu^NI!QMn3w90&bH+?#oi1H#>*{ zs=vp4{$&+-G=<_kSma%FVQ7DH6>%5|&Dv;uOnY8Q8_#C&bEcDJxIzS0q-51AkFOF? zC@Es{j2$<)dR4_b=wg&~Lphb@d2?@6%EF@~8?0SNyIp5#`^+Q>AwP!=9kaJ$Uff4s z$^&84+C}3oK>+eWE3-Azh>+>Q6+efwgY5R=c5;2+JZOiV1qary+vTpq#f6bKNY=XH z^qKa~FXZzj63^Oyg;YaR>rzf<2K7{&eW1^>I#{}iTrBG;$D7Y^3_Z)dft`C4ZDiC=%VmG7z~|3uH@TSu>64DVMS55&QqTf26byB-|rAO7vgo1n)Mj~R$P zis+b)A%M=+j8Zyy=pog%$1Xq?2mRL|ID3?yihcO!uiM}HYf#U_{Nk*Woi=w*6mXk_ z&Q?k@n=ZveVDhoc7cM{+2Q_R8I|C|@hQu9&yFUNpk*`9)7)lLd&=@o+4S{YJ9L3_2LL9E;OwLW)j<#t?~YkU5=Cqn;8W-j6!x z4N(Fkq^J-D@BmDrsL136Im03}@PI4{{9-O#fI^>N0FD2JIe@-MpBt#p(RV-nAagoD z1i??ylRN?xHbe=GkfLXK0XzT`#nI6(y)St4*xQi?G-OENXIt|lX(!C-LH2j@4y|Gd z)XX^jtRU5^h$r3I4oX9E2zt@|O7B9dS40ofT|=>J?+aaxK6-wr=rV|4z~dbiD9uw=B4-sj^FV5nZslwyXFTX&KGh%3PAfAp4Uuy3c35CV_Q@gqjZ^^4V2 z*eY?Z#8>0BScL5Y+y~L(|9y}-ogadmuh5gsI5-Va0wW~qL0>S@VO%caEr!s*1F|IW zch;w827LY;m<=B2r-P`?{QsA(-vwpxL;<%+nDwP_Gn?&p!05vSy=mWZ140Kym(MLW zfTxcx?6#`<#@7JoCuR_}88hF4Q)XlEtHCx2>#sUxK1(y0^pI*d|KkE=4s6BTA~OyU1GaRQttqcKpgY z#dmF#s48~rG(>8JWU_A8cahOOm!pXpMBK2c2C9nE0bE&Ek&xy#>P}6Cs1)_=u1YDc z3Q1%=k*spuCcAHBvP*fx&LVhY!rqbChOZsYjF;93X`HB~Buy%BY^>O*1HMO(Dpjiz zS2i}@JPJ1EgRs^?FG3?`)KrC8R6U!?;~o%(pvEa5MytyTPUN@{aS{hIo4LJfCAs}L<#V2-*?ix2 zeIsiTq#@&VzceG>KK61fhk4|-X1&A);m}3-G`v2Z?9D3AY#J^%U#U$ zptR&c6;xI6Ix&+KoXBw@0*M0|p;F@bwFD}&XA!l8^7Lld{bV7VJU zFH7xtWj#UpL&m&b%u_r>W0cAqd|B64l^oHa?9@SHB9^=q`znhEwR#M$a;}NeiWLuP zOh?gl1&!UGHTGDI`A1;IldQdorJ{tQuuF>b#nrkOrFZo9Dew{U1D?-+R4J8Q6KcxJe<9V*J!ffh+C&xNLrNyAANbO^i+EODP1rYk7&-PJBbbdD zsxS)`C7MK$CX1!HjhIkiPFLS3fA9re(N!BSmtA$$7rSb@b|^H98vC+WJTXa&uvh8S zj57KwN3kj}5f0Rld!vQ*@khyMcw6rE{M!a_iQM zb}%k!ovz9}b12KAil}3dG9)se=>~$#*1Z$uSgn$@3j~k{9@q5xL9-o)#`hAyo11fd zX{;}Fmd9wVn7m+GQ$l!~wa@*c10V$2WK71;RQ2&{123>W&(xo*gVwk7B8C*$OR$O> zude#edDKI)JiBF24V-gA8P&`ChqzTLSz~N_X-L1=upny;+h->V^Eyb1+}+Fbz;338 z1krSl?d@zH!@W`I3zbEG zzDl=;+TkO|B%M|Ha{k-$`TR(S(>kc1QxVtAthld^!V3y4Y^>uDN*NF%91=?_Vof}d zJH1(!7O+zdui-D=z{3}qtLWwyG?EfOg}G%!_Onb!aaE`-LK`b$SwSxX2lWlhIw3Q}1Lr6c<#JI@g6h^h!iz3dHHGn&A7;I5=TG&Lv9k^Fi>?Ak`j zS-s&DI^@P`dWPni-_!l31pD?_XLv(*Y-Leobwo4l-pjg{MxWR?&PQoJS}J??p@z5& zKCnIVJZ%V$twDt44INUKUnQM&p`K73pGSQFa}J1lmMrk&R(s-pA2lUKmxYHsj>~M; zsakk&HIV|#g&m*!PfXCXz*$i0URTi*Gd5)-)Wk_B z=9}3b4v*PpK5I$e2n1af530CcSV#j)=rig;4EEDD05;$#@FySL}8&CFK)0BrpSuu=>EUN?g+%+uA z&;bAeM$q7e=-iA5op(6D?JhrPWaO?~5pzop=jC~q&R^}260iLJwjY&Bx|k36{MyO+ z7_|}-o-D7sfZwQ+gS>76TUCaCJ#PNW1x42&O_aGQ5HsD?1x}6edO=x~1=ZI;&@DdP8QE zu*)#~>Pvq>iXO}cFOdJc^5r{9GyhOLBu~ZAPdq^{90HEtq9K{1)5kO~!B!E3EU;np zp_}W{ry^UXjqfOeGBv|atb1oaTvP1ih}``$Qkdmv&)dgagu9!iM1aJ^=wY%r-xYb=O0H!pGK=GoxkBSP) z&@ip;VglCN6Fg?7WjzD}hNB7RY2@&OVQq?BfU;OpPTVC&By2T}S?!Wj6~DGrywUF^ zeV&JlWfoyVaNDJ+Npz8ncFr7tduePsF1WLub_zXFisKkl0;LVLPk-M_5aQZeU)SDR zjRlx~>CTrYIk$ap4K;g;QX(xrAMRz;Tw%0g(-b!G*R$&CM~G00H<}%n~JDe z+Jkd2U(eg4jGo;#!i^AX={(q7JF(W^0tf z|K!aL=cwPgV|g@^$4d3oBX;|WqZk1$)7^B>)pI^3 z9bw6Chcw1GPI)znb1eSohw@`o=tU)?A`c`h{DGcW{#`jc_skaP$sC^BEGwk>ckXt0 zw)RX;ZC4>sKlZqVb(Oyq{V_x;qTZC&7YbTMxdWiDk4Rc<#cObx`#{y{wty`SL%zY3+GeJ`ZEMjx-6@rMI^LmmF;Sy zMMNa4^9CQuWk)=6v*GZ?Qo{|BCO6CcJl{z^xakeT^1<2Ty%%O&wnC!4mFQZJU-_ug zNk`cj@XDFbXZ7T(hsGN=jGf9^%JGvEZHU7$l?+f2+wbLVind%z)bg4sV`a43S`@IG zMEI$NEW1Yz7=ROARyYbD+*9;zcubs2iEbQ)Ot_9bQiqQ5oC0 zIN7$155uFXX)0Hy-mvraVmEKS`~6KC$0^BF(v;0q1c|5vG|Hqa8#j_FVzH^F54jv9 ztp!b@}gdYx3syNp*Pd;&uC+CN?e3D?f=+ ze`1x{H-8=HoK#AvpTv>-+y7OGMxt9H^jIjRLQ_5g2@x@#!^4k@_v-pbgA<+hc1dxu zxPFn`xcZ1Usa@5VPY>PoskgMkb5|b8Zn&O%{`6BT@y28{E`nC;f9pHC68F|*V&(li z#)CoRa&n=y!kw2M7c5?Zr6`tPxn_R+!;Y%j!7T74^HP3?(lxC9yTV>Cv{~X|`AhaJ z>q?OmUo}O80ms5r%CE0xqJUX_s_#6^G!JhuyEbfQwj^cLw${x(E0zO8Umy z{meoWq~wQ|VU(|{I32n4@d7y?hfX_Tg~T$nJV_PvN_+6zM)XMKuX-Vh+>a02T1(a~ zW_m0^OWRbU2rKO^|I~sIyyxR?AsFKbvf9fRPEo!D{>q)R@m9$)&QKl}1!*Rw5K>C0R)Ve;IDim5tE>k2^ejZ_%0 z1t09O#FS}Q8teGMSn6U9MQ z1V(63_tbzzo!rC}0L75=C_x3S*%jo8ktlbQp z-QW0>$iDHQ+CrtbG2^2Y+E6S4luR}bg66`NtUek`$-Kl6FEkeFQ_0XBEbeFL>nk_L zrA*xw8S_*2oy^)xO+P!?`W~Gl_DZdK4&Opc7sHazio9<5QKUk0@~B9bQj$Cyrsj@i zd7e;8+~g)YG9`tvW{<)Pd@B{KcPM0Yp5ygsRb8C3KF#JZPMJ{FFT$zVYK|YvCUF2W zwCicAw7jt_FG$NwF*X#QZWy@9ZUF2d1@fg->~6|!yOtaI*e4r|NBw@MW@u7Iud)=F z)<-QI)Itxwp3e=a19+H1RGI}mwBflNhJj|>4dFnwe@cdL+wXMd)W`g z%xlRKd6aNH}wOVY2B&bOpzzpqD6fj5__ENUYA}I}4vNuwD6xtmH5{*@8SFhap6s1yH z>F!u@K*}nKxX9!|!!aL%x2EU-W>kW>tV-$>3bXmIv+sq}hEprYx;2lDz0@wmx>Ti% zM$hX?ZSTDR6d#Y6l|-E|8IoHEyIwyN4URw>*^jLkD>7x0xOZ)(?^K} zj#Ktjx(roq1vTPqP1#c>)_D!ga)rXe_A*FgAB1s#W6I;*g{2M`ad|hr)9SILNOBnE zA5;4I=25k`kP<8GUcgpIfkMWWAaPAy4dI*E$x!giTR2?uQgE#t&|OfsZ-;V#Qd9&7 zZZ)Vo9Pwh|y?~8%27y18!z8uyQ%0m1eI`t}Zg%h92;OtX@kVREzju;_nU0wleL?{Y zeJVf^pZUxuy$s&=+4LxkY?fa*{e1*a5Mo5uS)s6EKoHXqyd+`}#}9O_H~?n6V#bBw zOr<+Ay`;M29R!J_4|^`G_YS=1%m`>cL(ZGZIX-aA zf9)MBj(>f?6CyvaDnRk7PRTS*^&9-1^WnjJaZ2}(4JFb?L@wBncgYY#X&rh?|C1Lf z+qR;^)@l*Sh0@JPUUfRS*~j#nfKsi=B52r_Be{eila2m}j6tDpX9SUzbM-1x4 z0@6i=`qPHULS`uwiBv5E?~Xqgwo*E1v8j1sePCc=et0*M3J>Z6Z2m}SI)E0#rg#>c zmP_(WeeSJ|#?{w4Rf_N8i$pct-0rR@2wz=r4y?bvWhSwHoxX69PhTwt*BpUim43?3 z_#YL>;=N)k^c(UjoR39B^Waqs`o-iZGD5h#!wth zH!@KW0%j7_NaMqW5J^^D$aJQ%zK(7Z%wquWI(X6j>IYVlg*4HSLTMR#OaGHkVzzBX zr?61Ev1~Twx+73HzxG2mM6oSYTd9u6tGbhEnacY~ejX7m4_j$$SN5v83(n+SGQ?0? zhu+fvjFAMeBGx5=qnUi)E+#edA_i?u`bqD;Jj50PpIFOk*nN8;2Y5`c&tWL}Dynh!1#k z!G$g*Lky*L=q>$EK8e`26&-ykfq|`7dZCQ~BUeVy3%ymP=!H%Wl=(;$GmuJ8tvGlE zGW6i`VLkd;5D;oe|hfU;+(fG=F6@uAwuB$yIMCyup#ULBgM~V)u!8(Dc)0L(5S>U`q#aHdg z$!Y!K!{q!V&Kh6yzoid#tyl*qkFWq#dHuV+fkSigO$C@gz-| zhty?tIDMCeWr5eU$f0&Gnh+#`4DhF^T3B)6dV_SdbS}rO!^&D1Le7opI^wq-98ArS z25s$X%jjy3kcMs%y!rtp>j71tM?U#>4A=eV=m!@>qR|@#rn9g!-up-X;(;#m7l$wM z7l%*pxX8i%nD<4pBw-uYB)EhHTR@V7QCP+q?KSv*l9D9}+qg3(K_84h0y{Z(iE!Fb zGm{}{=`Y#xPT!6NddYS%=Kxha3Bwke^aC0}&?5qKlON_QF?o7=Tv#OUpCTV9S(2~~ zYx0GkC0lqo3;%zcV{MoAY!`gLLdlYZZCJ~K5R-|LDN8IyBlu4q-edl)YLOA?B1O0u=zjNGa=*JLrzz$ljU#;FJpBtOnp*i? zHGZRNySBi{v(vc1qNxRnKApEj1yi;PMH;0U3Y{8>82`8Kg<)h{IZ5%7xLEmesgPw7 z)}IRhit?b-7F8AiWU;U3aI!|$R@ON5peU9KmxP`qPj{yWZeD*8>!VPqR!u_ ziWkvXh>K$F8&Se0B~D!b|KYD>*|e>gM(LT;xS%7`!sve*)8Fmd0>pb^v5PgG-V46$ zFPcs&p2chI#$dtUe);4e7;B*q7v`eOwEjp*$9e7BOKoBo^!<Y=0|rl&0-fi&k?9q)!uR* zK|iygO*7GZqE@uFPFF~4X)&9G+KVJu)8~tup9}lWnC)UHTgbMg%4YigCri1(9F{*# z=CaVEa{2*JHkA=IP}bXRNwH>1X$s~EoYC6*7Umi$nc7i=Xyqg#Wvl0ZrVA2^!tIF4 zKhG@)!V0U@Xu?uO)XD$!MB1r1l#{e55w|U=vYFamiJpBE<-OK8s(pQ`HFGkYnIPIw z)-)46Kx(y2>inY^h5Ht&EoruyI>EH*^kF6hbLC9Y^!FXnHckm#dnHJqJbONs*BIf#}UgtFHO4>mmNjWRm z=|o;4cm*t-KiUdu2&tzO)10QLlmnvr zND$-7c00F)0}8jMRG`l)>rQBqG!kneEXk;v$3ZD0OJ7I1RM<*^EV`{_d4ujWg}D^T z6zp6oC7YN*Im)I&n&VJUuVD(4;^}4o!S8`b8m0}?iWEgBUDS_hh|aXcY?cFgxkyQn znQvjA*8~Lj;SJcb?u6m+yHP+wMA;txygY>VKo)#Htk)_r7>(35@ST^x&?*za|(lpo+~lPqn<2n--$lk zyOZi_Jg$J@-4CuOzE6Z3+_0L($$d3hv?==@&M>+g*w6si}#kdQG4LP#aV$uN_hg@;5+<`T%Ly zPxjGm+vMZYq~^EpM(yKFGv5RUhL+*OqnY<`CJlpaUm`^|p}s{9d$qKgp@1letJ5<_ zuKcQsCC0$WqC7aJCt7m}qjW`C))aA7iAPjJaBS^7lJvWVS$A$$> zCJ*PMYdl6PH*?U|fZiUIJG3+$N8Q%G4S4`WpzjruQ;4Cn1FYd+7KYfgmO40^|J1kj zVo`a|#K2IA($(H479t%WvGF+#Ee+(T+uFCqd`AvM-C!}fx>|U3Fkt?mnxSHVquIu{ zDx|z)meNG$02;Mx1vbOnIZGdS_HkB#ilN%M#ym8FTFM_*lL#~ zW}jKAB@~R+gq;O9}XkcH;(|b~U>GTWf24dD}bzUqjgnjQv;*h4;`6k;YO!P=| zFTIROJPF}Dokq(MrzYlRJPN7WzdXmxU~CVefISut)N;-`Co{i`o3cP@tto`O41g3R zC&h*rp`cMKEM=L=PjoD5&8t+Eai5r>=X_NKFXpS|h_2yb*cL(9w8A0#+NSaRS99+{_c4!bgiYrd*?~wn)Pmbp@xw+ z=}JS|vac!c&yx6T^GG3h_HYu0#HG0yctl3O@bFnrEy}V~$t8T5f-ZOchU-8hdn@f> zdR8G)R?Bt$G+!9}x(#V*QacauQ26_ak6ANO!d;+bI-EkQ=}{I&s%5_s1Al`-Ag zT4&!xR}S~9%uDY=^Co>$|B?~Siv^k1{$x}aDXpj{+}1I%YZccsXi6_mOmM=nn`Pl|&s56Od`hu- zhB72VytZqYZI(x+dX#Oet?v7U(x_P<8n&%kd6v2r+@22(X;+S+9yWldw_Qbf{z;6T z@4+As^V_oG-%&OSI!J)PwE;)INoGA3OUaP0Uh}0d>)urj@?&p9A;g#cos!A9q3IUg zG?DRrFj>UDQprPW`_(Ax3hL&`>$$)%E>FbR?r>e4SGWj18p1#C?`&|nuc(qZBAc1w zMM#~U$4GCtt*slf+muc0BCZt1Y8U86`JjzuFKRv+wx#_3me~%*Js44~H$0oD*mXm_ zw67kzn9{~v3F}}$52=+(bZh5h8kF?1D26F^%cN3nfLa4#HCB|Om}H}3O4|(;r9ZVs zjcIH>PEZe%jZ8>rtz=v?lj6z$<9Z^59mw`#hntu>#lXb{RrWe=VvknYRnB`1_Ds9;valnPx3p%VAXYt@nNDgRQD!AZpYPBobBgg zcl3B*v<-I1`sT86~k0R{4zWZuOpS(7)`|ir!7AR zj9`YLW=f~r$w*X3pv^r(P=t5IT;h5&voz88*J9(U3yo$Hf|e^VRvAM=P%dheu4GK2gR_XEEJm>B>Ezzfm#?b{D{2`y2Z2EU@)r__&6-v58fxu7YRAct$cyFd6nzoy_khE zE1ep4m#lAVLw^VyTZPPSF3^<9rHUZVJ)oSEY&L|!JXE!mQpDH3b*OB+fAnf6 z*I%V~ov62?f~%@SgrE^B5RfAnWwZM+oq0^?9C;fb0ROhwo&N90!K%A+p?RUn3uigOuP9;EwMjwu;qThKj-@BjYPeXBvD);i@QkUxo6N1fnQ?hVX^Wz3>mEB zG1+Lo>&(^t0P=5(yW!~s@5(lxl^C#5hh-PfeZBrMdj{OG3ht;X^EKzt{Cu_kKG3D# zAw>me7Q=y4k%Jjmpm`hk{L%?d6QA6pNFl-=Ie{_c&?IB2H0esIns9J%Xl9KThEd7Z zpp{&dI5ds5K(qdK#(TW*YMA*2y`2GOI^tXM^I8L;1b%_718>%EOJ&sl&wpN9sCd=l zZ0C4<=g6`f(1c%hanYc1IB#a@^s0QeNM>ySb1NnpzWV$pvuHz{V5+#o{QZ2<5~T>2 zapob8q4CR(qxm(zfoP88{0M5OF>aO|axev(7EKHnwGv54Th@yvJ|^EOeZ`i=!-Y1k zrIvK>vWlp^7%vkGjz5W?-ffpvgpkPvir#-XG*iXw4Y)Il1;A=X)Nd(UgG(=&XtkZc zIU7G35A*Rxeqre;CK1UJ0s?+zXv}(*g$b~jwDwovZ`K@Dr@9l#oXXv@?3+mB#2R6I z2#gWMnph&Z+gVdogJs#v2GuY;ux^9Qo-7UHkPI6$A`*_j`mi9v2a(=Z66==;=ivi7 zo7@V+tYn=Bs}C~&Y&^E*5ef&P>;QQ7*IUt?Al{dcs#!X)@~*vV+kE;sHlhyz76Ecqnn)y@Qh}0 z`cy4LTr2XAPIkb#Zr;hF+n9ps{m`YJ&g_F-gefQiOxk6D%Ih@E`x+{mNFBFz;JD9v z0+*_D;N~DXLV4hBB>yCd3`yb%d%sdceQg4E+-_2qqn0NZwG0YzRL#@t;w(1Pxl%SS zFI_cDQffC6GgHRJ@Os=w-CrGHtA}n(+kr8RU@DXu1{T}0G|=c%eymyY=W4dsMlIMF zDrqCuuD-G(xOSA)a-_l-ZMiwYqC3nJ^dZ6369u{Ed=?5#QUvGYhi@CA0Lm^ zWi%JD6A6z?Kgnjg(mE+Rx3vzW9mzkoqid^}-<UX3!nccONlP zDfwlD$+}yo79}EcB;m$xCjKBrnaSqyrlG5!J$W=SY)570uC5kJ%xZS#`DPep(6p%& zniqN6vz-V+rguIq%XTe|9XpYs_w3hi7D$p6?kIC2!Sx~}kwUZyW6HxR_Vcs4g^D#3 ziA`L*f(Znn7_&;dx~hMiAU~C69h*%d#~g{l#YKJ6B1*;xcii+1b@hHUCZ!NEHb{;y zP3IHo9nR+G2^I*>`EFcp9_Q#2R1bmBvs=x~)NEVr%sq3%FykcHfBF$kit2-NZ&zxZ}k7|rGQ$6?HBAH-qB zAWCNdb1K4Y!%80~DHtmZn_fy0R79sn;*?$=d+<-}8a+uKiWs~J_Zfv2j*c7dQQHrN z&@jejEUSTv5~nK9m7C3YT0L?h#i$muyvk;)X^3NC+G#7ZF-j0>7#Cx;Z_${{Xgy&6O+D zD_IQM+rEN1Jrqa#WW^L*%j*<_#!x*UWMxEXmLwnc0L{5adtJL^S4Q22T@ED?G>+Z0 z^~J~{;d){#386H!H+@AeyPd9$(dmZ0T;}R-Q{%VMIY~#Br7Rj`2WLH%qeUaoK#I#) zL{<>B2m{uLC(__DMuEGMZt~u1NBW?*I+2d1Qz;`pbT=-!-wob0&e=36Gd^@Fin|$~ zwzOs`Kw5+We5E~u>HZ>uZ_SOo%(6GU4{O*T^i191<1dMW{~W266PNN4Og8=P`#<*= zANkm6YTHi{dI65<$P8f1SC#Qiwu%k&gKpH%>0g2){;N4sS}w))%x&kt4wUI^;mICq%j z7?3f0<*hY0PAr&a9y2d0uEw_PW>NDwAL`kPeO;QLI8T(Ju~{za#pK``pxEdI0>7Y$ zN4MTBr%&^rm1nx``e$231%QYBz={?MR_NxHIPRNG(pJmtyX`>ZJu3!Rw6U_t^_p|P z*Ll`u)J=1>IjvvfLg2@DOLxHK%z1!B{2XQh+fL-In8@4B-G1`|x5e4v&4Cv?0^@3H!4%FRG9&k9;JWn(JEP*{0Up0%f{!Q8KuB%uye?dcmCiyI z>#e8bG9#qH_wnEAE zZmd8T+ELcRpGergf;0apyGR8~mnJ~}sL>=xxnb~nz}rO-LOHNh!#6&G#x$W(bJs$}Wq4!20fm(u2+7?{K| zvyz;mY`Ad@f4!GX+t2xyf6krwiGLK097zGH|4}q>o9LABonrehh6!p%HnD5i z(agMc!-a)c(K=QBqj%doX6TfUe`xvWL@?3RE)d$)+bod&$55GF2 ze%!X*kM63y`#tt$w>(_5ui{@cg?x3LJ={+{|H;Og`B^%$@`nqY8srS;(V45ucX!$^ z`X^gC*o7xVUhdgpJ`d!-$ML5>amAF?<_{iiz1>A58#JHp$7#n#*Rvk=vTe4piD!M& zdpYvP!&ZCk+IOi~xwkyzDEgft>gkkae7x|%g6m-0D68s>*rbSaGrS$B%bkCfzHM!{ z;iOrA{qagqkc4V<@sS?lzSud7}s>@YwgmYStg13 z5L&Q%?7ZXgjNpojQ5s#8CNPFsa2U+XnjgPs$xbEz%_);x=H>0I6~aY*HoMQLU&ZOh zPCp9?(74Sz%s(UDFi!ONo%9s`_^{tMswsO9)!=Uy0)`wtOuyK!9LOUKQ<+qeuyhXsD; zj``iuCcKz9c}GjP9Bm6TTVx%|twE0F!MKe~5i4pM$#Mi{zmV^3!fQE?r4R3L<|S%O z>4}k?abT-T#d&(N|G(Xf!=LK6@lOwHD%Nym1Aa%4h z7XW#8@YwDeJXoZ&=9cNT!e`we7aqD}Yo(=BESop$f8yuLM?b8^p5g0?rRgo1bj+({ZTuMh|UEb@S9tbgGJ4hGH8HJ)O^$ z%qa6^ZwD1HRhydt?ujVbu7qGp3zUhE*0{c@&bCmBnoh`kd&@l)7mWx+S#uyPjT8I{ zR7b(hh%LL!YCh+K%~tI56848RaU#xgQ7=x-H3IjVzse;1oXOL>=>E51Kb~>yy$Mg4 zAM@bDZ!$LZzryE9?(BG3^&Y>beTZ$~?Fj2DKBEYlQp2(Ncz@nb1HY2i~RcmSMfk~VZ%JyIMLpz$eg0l z9M?lT%X}*-m4CvR>C{q(hZl27oY1UHbV*HJv5-~fj`j77@tG3rkXaM)CqG;6$3~?| zZQ0>br1_sHvYG7Q=4^JLK}i?N6cX~U>hsWrD7YQ=lG0Vo^Ek!^E(?|C*_y?2{*SU) zfraTZEmO4Ra9xqY`BgV?nG2q9JxWq1q+vB<<5G_jm9i({;7*dfKS7n-IE&L+2DkAT}OvT-;Vo7*2_pUy4l)-rKb&UN{v z3SP*|{f*PrzFxn7`{llK&IfHCSBs@_ET=T3=*g|z^Pu$$DVx4;R&#|(8IbkcB>_^4 zWJTI*9{GMWnxK%2o*jqiNsADhu?EK>XFpJxCUzpPsEu zT~djgorxO&gcxEBkSaN|KDZ<~qdb5Mu9ZBw6@OYtnpM&{d~dcLGbqkFd5mqCiCsAV z5!`f&VmLy?gq)27$tmX|Adh`cCn;({kRZeCvu7gHWlO4>W$HsG<{J9A0Eda(?kJ|g_Ju3Aj%0sd_iCG#_L7D7idKlVN0N zdENINe9rA3av5q-V|kYDn2dAfF+x8sN3ntKw(2p_^ufc(ef5h z%%%w!?NL6B@Q6c}76)6ymdPr99^$NIQ}BiJRyA7)P+ZC@nl*-p*H~7qmhS~)H9)~< zSykIj%h@f;)0xw3sAq+x?}^OaS1^-pysL78Pf()g;Sw0M_n4-Ydy?~#1RZGEAzbV~ zh^HzECx71d8RcDi9XZhn2Km$+5*MclmmA8y8*EhvQ&(`RalbBXpUo*q0w6LI22S^&`2r@cI8`6b`UgP z4_2t`c<@iQ%&_rCsgs@kT*t@W3BF0r1ynW*2^A)2mLg$$uy@eOIUJu75S89C1SJC}h*&Eghiw&Z!}v*ewt~T!V=CjovD?`$PDSth9o%>PCFh}g z;H1LCfbY>{2SMZYUnMswcIX7Xl{Z&*9XKOf)L zT{8%e#_1S~x0|7bS=u*mk|WEHoE&6dk)-nk{G|1hTJuZu;8|%(%`aj;k3OakLIIua zdB@#Kda1G(%Lp?X#k<(JAVy2b%EG^k;h_?)6-le56*pCo!XORcxqLJKT=S`B`(*Aj zvvk62&w2mqr(YbtdVkr-V7+9XgRyw$-TET)i356tbbXbE)R-ZF-E8iz+##hvd;|@2PD{Bpx z)>cPwXO1I{gLZ_Qba_ie47*`e#&!;INi+T?bz)+O9=d8g_TBz(Po)DYn}y5@Gqt25 zvkAU;O?D78UJq8N?0E1O{z!|h4-C!-u0hu@HUU@G$)lk4X~x3odUYJ)D~!jccf6f} z)+>BZl|`tC+~_Ot*wKT}5EL1|O;cnt&g$6b`a$*vKxMPAtHNDcQn4!n-)AN}2pX>k zt5&P2vy9M~uzG-Cb#uLmny#9Q85XhUEU7=#!?5R@)mVGED~`{x0ZX9_WR=7lW) zw(HBVv)oNSvRzBBnm+>@I%}UH3l_i|`&50%dyclkfzB|19pNKTbywU-BDBs1yQvgD~`D!?%w(?bGx+MW%f8I)1(* zUTA!6|KP`KE9K1ink@gPi;K~Cyh7TpyGy6J(urXkm(~a=^@)V^7FXAXx|ofjoHMTV zRfp?w9C9vh{bmGR8(6%mqu6Nv@P6|Dl^%gpcsXfABB(?Z7hhaXaY`@w=p_{|kHX3K}8#;C)1a1R5ium^}QQzLkQ^D1`tx z1wn?42xKw^K)-Fw$|-M51yIX1A*7dDb3#k0t+gZ7hPM(?KkXM((sL9gNt)l;@S^hG zI!|w!#V4i!q@)#wok?_~rW;nhPJjmqKaMAPU`%lC09vhe#PSfgv!&^C*F#*P++lco z)OSt0_<>{pD|LDZQNc-lon*#ZxKSuCRG}qL^s8AOd`G`?8m~0+U!ycxEuW1N{=$N5 zM;khDERqSbuTUD*87UbTsF+Mi8fy}016kc7A)K;!oq&{D^&X01&e!p9K6^;^>d_l@ zd&hC5{x0VLj01XT#w00Yto^~lOVz8DLsK4x@(6%FTH4=HY2oLQy%|l>#>4op?;2{Q z_8aZy{LDuq@26=*RTiC#BQ}9JDGoCeGcy~WbwyYlPy)qa!_0;!GsmXN>~XF7EpKho zYHHFPenpq@d{2)=IAWKPt_F_@?Oi%?PP1AF`Jg+etF-l%=VL)+k@J+`pCL}tnR1aa zYhB8U{W}%74cpX@J0Y_1)+kDk{|D1h3PRqb&+5@#2ooo=f<=P*;v!Vx{%Ef#KH}Qg z5dVpC>H@T?234`9XQ>vyF5?)Emj6F^#CA|5Iw5C<_MB0|uFAIp_%i{{W=lrO?-^lH zM!0=uj|qZ#?Y?DaIm5LYu4176^Tco-t3j}~voju7B8WdQ`g*70@*86^ zx{6bbX<8wh#{JQGsLi;qD66B<_IB0jEzg2QMb_oewRrmCG3ZJ5u>Q<=eljPLsc3Mg z7<=!m`x|-sj^6896ISA9Ve0vD-qHd8A;d@4D zkFsu8+;PIF-(u2`j|UD7K2M_;ingUNMAI4XMwK{KQQG^#u9q z=?Q&BkxKz%23IN&R|Jax`P%Sb6aMRU?yrYS9%Vlp^8bm;hTgiGSOL1t@I4gbue2-x z{|ewBK7|rDljaBxpny8v!ye1@6jAaBAuz3%sCyN@sZel?0w5Je*}#~#Jd^6`Zs7pl zMbsi98)<5gI8Lho5#xpAK#A8pQ-`6=iL>mu5p!9`-O!>VVbbw4QiP((SzN)dqupV@ zIgt)^`)X7ml<(^2G2*gWz$Sy(zLH>TzmMXGEppBam^I~Q=qCm~9AiqaYZ4-_+aI^E z9T#6y?rCnE#-BsXc*&i=iluvZWa)=&PYgwI98u8tKip@}E2x*2=U;|Ih~yaSSP0!K zVr6z|$-Z!1RTXz~zlvjOsh(O|qm^PhXvJ7}fjQI^G1Gu+rb+Q!+YN(6|6~S`RC#L6!5_G`tU> zur(-hzHKQhnPa*F(qKbEoxaM0?$Cf%RU!OnHgbx9FNpP@+q2!FC?RP;%)c>)Vn1rg zXy5jF!l;oR_0s_~r59T-E|2W;_b0MCWk$fxF}%6_MHkZrHyF|1L%6R+jIDD^Mkpib zMTL=-JM0@Y^!}F)u8I=A8Oeb(%-EUBYZ0k9WmFmUHb~A5hU)`k*_fzcj)<sI4 zsPHP3_DQnIkBBNuS@xTo+Il%Y5?)Azpk9dU)eCjvq;!p8v?sxOnffn>g)A>sLK@p* zb{?9DxA9Kc%5#4qos-R?TP5rC^%vEtp@^RGzYNdu8p^-_b90MX#(#6Q5!9`QjeGGM z^i<+__J|y@-~8;4vU=~ZkCkDy-ab7VO-pYt%pI~=9QqphzNQ@MPulRJlWZpoFl$3| zf*|ya(P&-_;bt#d=T1Ked@jMxz0VsF*?ex#cMgpWFD&cqXa;IS+TpE!Jp8jZ#xuSX zps}2Tk^4NBD0z7qh0cI)ME-%IMaaC6XL#P4$#cB5%qo7I2qG?+`LJ?g>;DEXv}?hC z&#~{4f8Az=Ixn2GoLYiHZc~zAL(v|l)SGC6e2_RSMT_q{sd)?%AxA9IIZc~6kW9=f zkqhM^={qdbNZAG{uybzfl_OG@u?w*#$#oYgBHvG<20T=JYA3id>UNdY$6Elz*p8`= zJG3I@wR*GwE%*OFVe*G93eUNC^%Vjd*!98y7!zDJiX=JKf!NUXHZattruB2d3pKv7 zDiCeay8W*f+)icMhj|-C5bX|lhL`EQ7ea3ByshhAYVYqiTXdhVWtm-|k7L}%UuP3` z=f%`{*z52<4KKn?uVr6XKX3bpOBBYjuV=r#_B69E%IOZ(Iw!LPY+PU4R=AX@m?X%W zwj^L0{f1^b3&q}ON>+t2Rdp|xfQZf2yoM=+q}32`1NNA1_Ofww012h= zoNoHsz((&QXD-LyHOu%$bAw-}pL#k)u@a#_sl!ZVHuR;e7%zz6El8<3N~o!+sl$cZ zh~MT{9G+V8;HbledM2W1tkjQE*b1%Ughr!@Vg*`T9)2pB(yB5}Sx%QYqREQNyeuwt z7zq-5r=*XgWRYuK=wPSHkS;ShEJF*<;~kBVkYGYI$L$w=xG+hlS^{M%3yl*G!3{aP z>^9(U9e%l(hg?CScJtYY@5hlmsv8Pva@+Q$ z2>Hu;9;83ev^~``aGc;9qj$ft^9jq}&Mq!5FZOT4@8AF7dt*C@Y#c72b(P?i_-jCr@~;ehUAl@&e)|iaWpbB4YZ5Ucd7eas3j1^|AZ>9IYsw zK#H#{bKzr1UEYa6C}(dPySCYyUc^Tf2F*1q zH*A^=@#8TfUb&N6C@+(bgyJb+?CV7v8zN$e;EixcvH=_f?$Xpf)#P5TT~#@p^=&Vu z*F%n+w_w*Z@4c)j&Fdn&l6`Vho8Ch%swL9k?*KTidUH-82~Wy}R;II~zR#$ZbqM2?#kGsilu`E)nzUM;Ngo*~!Vsc_U{h8z4f41HqE2 zhpYOylUhc0EZ7>B!C2&MX*1@=PGX+*vR|bq1{~rbs8PpXaGoBkbNjN^wVwT^q1O|A zDxYTK)g_&V<-`%$XTvm3vcW{RhN!1d)?(N;oOI4)azQTovXvcO^h8S~)diCjtDy7u zAh&Rw#1()f&Q*Xjvl@9xWmf9pm*XVVJT@&=ogYc`~a94Yr3m&R$o z=7N}!35TdKAXWugNk180)95G%gh3T>^<=Qck8#0$=`AVIKnQoB}rictb zp=oGPM2?m4m`HVYB62Jq`yTS;xT#s;L7J#3K$r*HG^;Qk`Jt1sw|f6!!Ygi%09s4d zl9TJ9j-FC^^Z(Xv^zjCublIe~Hm^`=$pwF=H#{p@bXEq)4lXEs$j!gZz8*?7Y0A%_ zcC($hZif+E*(6Gu4kGUoV!UZj1_P+o_up6X^DC8Numwq>_P-Ryz1sG|yj5Rq33%Pw zqyT6cNfcmmc*Lg?fc@fJrN6EL9CG|3=N8HamSucw7*5BDnsCX31bduBvbj00z{oO? zBh+Y5GKoo;1}1zoNZ&!Yh^ewzL4k6NZH;SjVPgo{aQ=91Y$lzO_xz}+Oi`;un#@>O zdYsQ$Rg8cop}?$oW?>6Z1v7v5{_ZwdgF~(r`RmFjs?cUBn__bx&6pZj&kO@g*eYz6 zKQU|XgupBaCZ^PT&k>fOs3c*wh>tGME|fP@X+S3>_F)&_R$il!WKE1oP+3N|+p{N` zjA~G9*kjofr0atWWRAS_a>ZFJfrEM6U;pB-g+A>jpLY2njx|1LtTU!&kvY4>D#t-u|dLpS)s?AQ+NBf z8+$qOIH2~Jk@1i#ekGp`C8gK3lS|9=Y;aysj+jyxG%V_EpTYOgj8+Id1BorNvR*T+Rqk%r|gxl?-_J7lKj~+TSv; zB=M~EkyI9=QyY6FludZKLgv1tbzW(sKeu@m6GU6oMW`|H-acNPCZ-RZC>%&KL_gcx+M(ctW3&g|!`r|ME-i0{! z!fm?8IsAE8S(!;zk2;Z=i?r}vrx-j!f(VkoUxYU!0hgd=;uWJt{FI3}Uz@%0#>TkU zkAM0J{lc-AUJif56=l#@LZ*lL{aVqB$66y+&l?(($8mufTWIyD|EvJ=InaB$1OwL- zgx_4o(3(+B^0i^C3^kWcCSsLtG3`T1gJdOdM>rNz=o21K9;Nqj>ZM?k5M1u08JE#~ z&O}M}fy@(I3=x#8M#*6kaA{11m~y`d;!GCeV^*szEyo3)A`vIOa(V5g=!>!ZcJ80s zZ9|L!BZNQ2ueBkBj?v}!auBYt0~=)J-j+GAAq=GjTjoY!OJpkSTJE5{8y5SAuZ!RW zuXy#=r`mZ(Ij49s@EMXv-RIuB*rhzG>@~eQ5IOx+Vp)nVX z0C{LyRx@GTg)!Y)=Mw%F3e8>J0LO8=>mR%9Lp8?g@mM0L`LT$`#Z^^#gv)pZit62+PLCwg;;IV7lM;)qdX} z`E>_u4%pZni9NgmeAR!zG_~$KeLb1Ti`7bYB3v&51RqQiU*nnlwS;Oq)4=z-f85wn|>rC(X?%nQ(Edh?xd>npADSt-| zRzOqAAqg9Pxl@O&Ij-JV+lW@F^4Mh4{=9zd(lMfN7c*6x(z&E&lgM-&6vF$et$pP~ z267H`eI&$KA<2Z~YUrAgT1N7N5JNzw&EfGAMPbMF7!+SqPm(o;kj{;%70*>p+oY5wW%`hNZHa zz2HQz7;0xvcy=b!l_`|+zJ+zcD+%SB)Y{r*a*%tWhC=qWMfSTvz_1pKwa0A?KKTl% z^GeCaA!^aGKOra7f3+0`Cn?fy|4JrtJ5%J2GIwR*Dfsz~;GnHK8Z3j?ef4Uij8o6E zl9u+Rl12v-S`lN^toN=Ps3JaUep9e-etk(2KC*R2mAA35n=yzt~!{F=vTPAObqI^4Jw8Pb-J@jfTmgA~Piw zz#yF28>K+CX3P@48sM_bmO9A;x2F+Fnr~UpE)SZ}#xp!3xKmdeEG60@MtJVz! zc8G8m;nYMe6QaeO&X?{v|>UA3vmI3I9d z(;1{}YCdLQwZKIJy8iyT(A-r&vtqgb-Tm8>ySzqcdd?qtiI%iBy<$R-&%q~f&@W^# zoHk&drkVz*4Wb-Yka6efoi6&ft9H5)+|6kegV@xJA}=sCb;)LD`~&ga4KX)a8UMG> zeHiE<3Z2IJthohHriVcDNFX&b)efntZV>3%O;JT-+EDLjiWrZ4I{l7?H)YcOxN#h1 zvq^S)R-I?3Uh6hV$;R1c+a`=VqqFGZr&F;i>As1`r29JrEn25 zyx-rj?d*Q#F>%N_EO_Q_o{#E`>xhtm<;-K>eD=IrHZUE&M4P9{+ss4`RjEVS%36daDd&6+xUPF{}~s2&BetII74%o@QLC^6E(Miz*XK6 zkagThn0i^avw65Ji+)UY?5%YiWxeWgxiTVl5Cj#RAygni#kb-;^XsXi-LgE4VV4OM z_J%e@{_ev?k0CtdP&bbK21l(bzIDO$LcF2P)Vrpi6B68bQMG;FR&U?s&#+XuSl8^2 zi|})|UZ!Il_tKGgg~a1AKA#`0SKYz~WmY}ny+ybQ8Q<@$Q#w-Z z`77MqHKPmb;Wb`-7v%<&D|*E*;TN|sr+^uK%)J#!A%tL}QaOYW(B317M* z>h+2I_kJ(ylwPC4m(H%xU3@{}o*n(FbF-}d(N*Su*d-=v0`GtO%-+KvuQLBpRi{&J z_$)6sOl48H6n1+az5D4w_W8qo_4zaD{e+U`)g1Bgnv!lB9UgL%L(L0Db+{wT^V)JLb zL)C{}yt*aP*5?20Eo}-J5g73$yoD2bOqg*7f0fe)ZY7m}^PW7G3|gJLo4!D5hH-`R zwuF@o*ugTaLyq{9V;X0|p6|Gatp;%KBcZskx^f>@uTGkB2#$Z_(fK@nyVab&fVch$ z7TNIYvbL7`70dVATupw2uld&jy3g>EUoOU0T4@;lbs`Iz5)o1tKwN50f+EbU7QULP z*}RxYY!p?I<~eypt=?<}#E6>xPSBgdXGZHE!U1?c;-rg$RBmcYOk;d)X#*?JPZR6Kypn|61 z!XHOOtm9jUvgCr|syJoKbZY8MN2A+T%l1fgPeMzdN7Po(g~av}Rcp5ah0? zJWa4_tWkIDj(~82#cd4!+|b=E4A3o$Ae(@jIgI#x1BOvUu;tD;QsH=X=3C_W1AO=B z;2^S2{naG~I^b--hI@aROILK9G+O3@Fdh050QlIpo!Nb@oQ)7M*ox!9j0%D!afQ40#VXPm81Wt=KKR+ z{I)|GxqIFLk^quDN+|bXjjUz_t!RKtJyH-+k_pqEJ?#?}>5!5#Cbo@{0ulzbesvE4 zYG~En-=dxYrGi~RvRY@eOoDHc(v(v&p)wc3ZK1eU8n^oQXTgOZ&z)&eac?#q;(}R`@jDaTQlg)x0YqZ?PdJ!1HTu&_dpS3IUFB`3}MWc5_XlFS#f>iDc&4T3TtiLEB2SpvX?|Q zyFK)Z-F>-#`~3Xb{qal4i{W;cXE%48Pf+{afZO46>vLM?%VA4=2ZK9D*5*a?akqST z-W$gg;y=h0M*N5nas70MG*itI{W4pVTK48HA0NFR-xQ3$Ipb7vO&bjH z7Y6tKdcwwp@||z6Aa2x0?X?i&I~Ji!_0EW4K0dk)M}x;)#&`bk63|5L56fGkh+Q=( zIeI$z39=b^J$xtF$Bong%}CUgloi}q>d0#b%kZeB%;PEpLqN=H31y%0dnJU&P1geL zbPUO=CH(KAy)^yP&w!QJUJDTAP&BqQ`_>{!Uav?L1aV&!`E1|lKAjNN)H%DGBD&h$ zBRn$+$;H$jiQ(=l8Y!~&SVWN*=R&#f^-KcYpw_T6_-6+Z8_hj(4ma77nLIGvO#33y zGPS#V4G8A&C*#N@%UEqL-L|ENKc6u|Uc%_N{9Y2N)5L8GI=Kpw&oqIh(|up3MDBFv z*oX<(sTYaoP!*6Smu1s+N~B>uzOi!}n2~H%;=@+T8BZ@=&AO#?D@$or52fb1>(#Pw znu>YJSL|nJ7DH>iRET4L9}DucdigYJYltTxZTkUGHBlrLRF;&8sI z+Z+-}^KM>#OBNsayzq!esnL3n+ToFqWqkP4hJ24zgCgas5@@CJN>ePPK?@&UL9t>i zj3u<8i?bJsYgb`blysWU{n7QvFq9DNYg1Yz|*mX>1$Ze_RtlU0Nik;-VvI~3XfH&Sz(&)3bL z^(I*}Tpgtoq3BuWgJ?U5^U{nuvDeXVr6=BQu@#HZ%7xqTnT!Cw*UhNABsb={@oa-+5>2Av1H|LW>9j z#tRa%UwQacN@f7UA_y?zwBm(-c_;8-hKl z48|&~c9cn0q%1^h=Ok-8umK#c(;Dnl6p%%B1>fc4qsHV6VtVzYQ(3e{cy5KtUttIY z5+OYxRM!~%NMND(>DE?(?#ec=!hWTG{ zIpz7f7jhj^St`WyZ7!749a^&Spk`$i$8UEkG%HoE3HCm?5|0TCk3^8i0{%> zNAh7{zaP`OdrU%y8TZ{Cm+tdp-=0^Vs<2f_I(@1VgZtGx=CKSaK0Ry_Rv^51@XO2q z-HS2EEs_?@@E?q+J*t4}PzU#1?vWY$U3M4f+2?1cO?UQc$9?-K-4PEW zq-K9{|A8Qf2F^Le&zM7kLE3na^25;!S`{ZHI7Nknz9y? z8q@&78=qhU#jxU;)&w*tr=|p{n}k}39qfdQ4GP8lrjR!*vOsps%KN=t*U#6dSUv)n zL5FjS;DqHajxq81ibXHB|0-r6W+(BOQ3A~7^YSYv2OYj8tXj9YK1xWJEl)m`_ITN3 zyt%mZt#lW7a=AIKS@=r2hA|{75@MxH0xw(6V2d&He}et0G2*06;sdCqFVk z%l_HJYkV$$c{2GcGhq9tr!Vjln*t$L2?F)x_0Klie2Ah`W0|&rpHQFWQQ1a;_0tR+ z;FjiM+6zq~m0U*e!I!KaZr%4h40RHy&X(3z>yr)l7Dk7txdt_W2Ygu`;U!Lv%l}1( z9dfQ^2<@;5G`kBBl$?P25+sx_ z;Bz}WT)wY_mi@E%xYpLeA>aJ~wy)}YxUI?LyF0*k7UX-6FyIKL3JeO_^yEwfuS7Bx zHIwh*2cY?NlM!&XM5G)Y$ZXa0${zmCTs(ZF=_?%>4S@eT?~4|IU~3a-kXDNs@rjBNyuYgh1#^!!FWHmrR8EytN8)c3GdY znu^B1C51pF&1GQ;qzhWxpeHjp!lX12`F_qZt8h80u$~Y}fpqpj;pZGgy11fL>jrGX zh@heLF&bl>HFDAb$-XnQDl`VAnrTXl^xOdIh_rlv5@lPGH4}Q`08ez?EKQHGm3P8q z)lu1c9n7c`A$B@5ene>_?bW^>M`Tc`*u#`gKaH(-q*@Gk5PPc>xgScobU z?87J++TEZuosg;)ZaRI+a+s|pG~*>6d6ejcG})h?^LydVnXA7J{gaDPx51EV``;#4 z+w~ioe$E-azs-6N3__xR$Ad>lZ_|%&*()91Nzn?fE$?0ud6s_a%a1gEdCB-Qyu3)? z#j+|gpaCG)WW9mj%!>mbrAdA`#sVpeWKp`Dj}Q^du$iTb6;3OZfDyl^#&BkfvJFB7 zY=a|4FiunjyJC-s>z3bKS_(Sdkc{X>R20YTLjsg#0&WHmfs{>0Rs8}If*^jlO%80Ev@J{-W7YfSR_cAz*L!XsQ(|9B=D?@L8aiW9J<<1;P$TZ^; z@VA^{T^VQf2XRU2nI>Bx-wAB%Y0^zYB5_<3p6RWQU#7k}Km)B7F%bvZtD%fN?rOz# z6gwe~5#ie;h2C)7X2}7pn1+$I7KBwWZB6 zTPf+L=}!w$sI)8te>1(&+rDND+GCDn2y&E{w?Y+KJGlLKK;aIyumIx?gN5K`4cRLw zx;bkHvGg@Q#TM=hVjRoC%-*$q96#fKi52l z!T6txjDbI%J#`YTl)s}5jl<;7#*llIeN)l~>93?KjkJaLv*;6eE->F1HSDM9=O&7} zBXch2=;)JhEbko0h3*eCGG8y`ox6kpUU$M4c2e%fk@tQd^J$)o-mYp$R~3xVw8>;^ z*^f|)a!Pc=?dwy_Q756@d)R_>=LhxdcU$M>X^~ryD`VpHo)GJ9ROZ#^pY2<7Spd!N zVn0E1C$u%|x|c85`XKClR;#^q4raBW75-PHL}>d*YZQH1z{ENuy_^6li7oPKuwMF^ z12J8k3j4&iKXrW|Xv->?w#T5Y>L5O}!FoCm=3N(TW=BEN_rdji(St&=LvC0iZM$50 zq*Zl1tZid9!|PSJp4uxwBepr`V?;d5n-C=*j3a9^qrUV zsm4*qQpfp`<>p;_yS{hA5>r3HG?Rlr^8-pkFJRX>6l`uTRyA1`OL;f8FeNzpmkES(dy#=DfTFVN(0 zKhhp=pZ4zHuGUp$b)k+dZIgkvE3T z1ykPwN>|%pAiCscaF|dZky=a3MR%-5wC}h;($LKwOR z2%Y?CgrF#BHUT_B?MOnXK}j~od939i3Rs@aOvAC!#zr{!`u{&hPvM{r>VFKYV0+K1 z0nzs1o)@?fKRQ*IMEYQTUuUlG(v#d5>}`FbP`BQ|#O^#zVh~fh9W^M@``&(>VDDWT z6{Cc)Ts?l!U6ZR5lC7 z+TfL{1wRa2T65Es>p`ql7stdyD5u=w9ctcTn!oc16Vlf&-p8p?O7;c{0fjj-qR27; zS#A!P$|;6U2N#sqP$mvcxzmMjZswHrzDX=K`{;mmlzYtsZSn- zyFwo1YXenl29fzvzWmRuyE|LG!rLbsS{)HaZr!;LUtJ5kBiLyjZ8AeEm)nxrRFE6> z@gCPQTR)}q%PE-x4riU--cF`3wye9p6a=K&YAH^$- zTFev`Uu35pBk8lbURJc{dt`21y3wdKF5_-5_;$xDwh+98Q5H#OVFquq>>WclH22F_ zLb-=KBXhNvuUVTrEYI)HSJ1b7ysD{2>rV##(eyhs8nu0sp48FCqZYbSFFmn*!RRVF zCiR=~kA<*PCvSRIG4-P6JH0Wp*xZ`=Zx9#+_swp=m>-??#KnS{V7<|3+AI>QDd!GL z{mQ2CNa7{W9uQ14a!O$Y!nBI1;6b6zIY)%3%dhM#NTRG_CLTGt3X&jq8Mvx6gRHC_ z5nFr7_gdnp#c>E#1k&!*%FY?P5~F6w9%fNbqGC0(3DT@D-QK&cS3)2CAaNv|X;YU= zigAoa!zc%{HvJN9u>c3Pu;6H(vk` z$!%V!#>h!z=Qfej@ul@qER{N-B$XQ|lC1A-brciDW-H>c+YdB+s;neA`~6kG=xsmd zGZas2j)kA-_PUdEYrbIMN!c`d<4p#MB}I~OLPDHFfkdT($CB!+O#Kln60DxH@j@Dnyp#ME&=+f@2`ho|3G+fV9y_iO$5DHZ>nF zYFWxK6rrGSUp>3&G>$i7&|qKYLtlPy8tAX53%w%bu|8N5?#txw^ID@goRSjADr?e$ zCQ(6$>IvXzRT6L2T9%45A;4)FE7ovIGh=$Z)|^{QT!RkP1_*yW!MR|y+@%5JYJ!?H zMsg?__2d6tDVBkX>Bgz9UmZBfPhTnW|Lmsr%^ANw3`z+8Vf$e9pdG$Kc2N5o!{_6C z10>J9gLc@^V3>swJK?ZjOgk_vjJU^7N?xTLYd zg;Us+_qT|Y`DGodCqP72iDy=8UMkXr0Hhej zSCwqR5Lc2$M;aqJl#Iy>RxA|wcg02kTNS7oMWkd&jNPHy0M3-NwI;zyby*sqcui1~ z#z+n&qjnCEv^s;m7E_Kq&cr8Zht&@CEIy}k^ru*#CY(-ljbk}D;eS{0of9n8chVs+ z3Z9{ig0QAhWmk06m!%;|U|KXra=4_C3ULRQX7THO+++Ll`1R`3uUh)5_%)C1CoQVS z?m6PL6LKoR<{G-;6J{EY3+FjL{bPV}U;lfd2 zK_D?2nBGp5(fa1?a&(M7io7a%Cu?Xf@Ir4j(C493dn+1f5wtO1rGe{dViFB^H;EXd z-O%c|cHu%i4%Lhem6^HF`jp%jNxYXQvDWFiT9$F4SZ>d0a4(`q=Q+<~O%q1y@SfCa^3>nJ(A($TL(2TBvEiN| zd>+!UXd$apdwUoksraNAIvw|^Voo%(97Pb7WEhu$gFS$~RpEfkIFmwbpOO+HBk{8Z z)LgExj6TChz|9$VuZ{_SO^CWmV^N5Vh){3L*n#Z{kP0Di-jXM0WBatsZYu1fo;CLV zg=^}0ocl(W_${njgw3m79sKrP&Dg_8QubI)wc!lHT=$jm%X44~D$tB~pl0V-0D%+O z#Xb}52TLoqc)n8{Bv(W<>IkdVe?(lUz-1&tFj*iT%Ic=%y!oOMpya)d$Z=Cz^IkoC zuXb~k{U%-3PC>D)3IY=rmiL9#Vi1;+f7uquFUF2>BrXEMKYzBoh$k!8}W~L~qAVc4A!QCt}4#8BRhsS#e;Eh$M0tAF*``dFvML4vMTPuUXoV6C;Cbg!UE@&e#wKi!21lUqWtLXB&+VrJ8Kq z8v!*p%E*;R04-}pIhY)5Fj=X!zCHfN?E}vxyR57aWnmdT=WC`~oK^oeX%BX|_Q6v2 zdb9S6=}Lt)sze5AF5>yhD*S-KxK#j2!#zZ!TxZhH7u8x+lbWvK3`NM4+S4`FtoNoP z4HZ`cXVM&J4gEUvW>u1c4Ks7HwpN0M?8H?0k2S6~aJ0TMMkSqB7z$^jfh#LSAzWA{ zRPip9CAx(X=Cz{ws$@ip9$)l&3uwq*gh_Sob?qq~lG(g6%zp<{k_}<))@C!g1AK_< z#mux6kwDNs$mQm>++INCvr5n|5f`1{RZofoN~;PPv!ym|!7NmE+v6}T9l%hUxlOcP zx@c(CgD?nyIXv$jlJA`lP4JH98807)t#Zx+bE?QxC{sOP{9_`Ql-oPcO9jfVOvg_q<@yfp^>PwZ+YB^&@%;sfa(r+N3*ZKA@ENa-;pMtt;Vu%9*r^m`1FbXkZlQnf}w}NX~mcB5TXE= zbhTwXvM^3;r%<573mt43=rwYHosI>BDi)){bVPV|> zW=mInffSp?(rYu;8lIEr0_+|zfdx2+Lg4}!Ll9wDS^EJXVvo?_unI|mq3W&}gvAHE zM+s8$T!-A-sJ;ZXQ=GB8D?g0%^^*%Rg8$%v#LS~*a8Y26Ia18=$l;J@7jG@OhJX-o zDgkbQo}9q2kpr!2palX-=a5BIW`_{jBiU5GED>;PX>_q0EFmJ%iN+Ck3EHygCVs9t-eA%NgB<9y-QJ3k)5X`1onfQl7Ggd zTZ2p*rYhGN`1S@gkeS8XQU=17;!fFy0DD;E#86u426~g`2PbPV)huCP;r`A^1a{Ts z%Mye4!h2{#4gw3vE)gK}*Vb)z{TLOBAm{xBCRkQB^`T4vnjKO(d6-hmG`KuODH{}hy zACst04tpetIb9Nn$r=qXH=(&hP_DG!;eLtP!E~YvQy@f>Avhv)$*m6ELOS4l_6-(O z>@h?LgqS(50Lw2K#z)tYPuB*9Lj2YXDO^}thOPqK-5kMl82@c_)qOhP?%{LbemJJQ zI)?rJsrWxhE~#jz?w(EVcPwI&lGV^Ju1speFWdCH&l-@D&`EbIe?UAslBA&SlfZ;TGW0-pE%qv zfiv9dcO!8A=)1ZDHOA3BKdAUc*s0^EfjcHhJ;&mue?Q2nAM<3Q4}XV_!|;drAG`iR zs|3Yk=8@Yg=X)UKpz$}fB8!`yKLM@0M5R>ba&X-qrq2N2d9p;x@;p ziw(=NX^?Ovn|Ey6BRdLdo&K`)Ch8%B0VHdEuro zTye#Q;vL5zavL}~5d;fD`_Vg}L>Yov62o@I5{nA6RL(qYY4$N=HAJly^`Zve`AysYJsw9cypvQ*kv~Ju2BN=J=O=pjXs$b@aYhnbgAc zob1!#v*&u5PJ7zcH>7~sW5=Z5>PuP=Jxz~1g>`PB@#&VP=2|&F)_mu~*eTmTM_!XH zA}CVW@KAFS0Qe4tGDCVLX+;O5nGTyVHJnkULq4R&#?sE> zfQ4~pK+zf;xYg^FybK1K@uCH+GS){z(>VgeAG?wtzy9tAznRcgsB;DIe7N#WEGEaV z7c$VAxEgC9?#E}peYZwpg0Jgg*SP=T0d#f1;dNl*kA8<5 zF|N3RG#1o!<9y!<_8N9kgug`rrq~vS8t7`>CwR$y)p5;pT~Ba5N~OheNQv+-KjNNL4$2)*~~k^5IfO?6?44Og+U5b+R^zlS?!$8nV9ur=)jA2dVm z*~<{Z@sV_8mv)z#;Uj+09^fes$vFs*#0Q{}FDdJv+65d(sCh=N-#K^U@MWeoWbg3g zDFd+u=RZ)KD};v;!+15Ql<`>^-1iKUmD7HLno8lvG%G6$~>WOqL5- ze=Jg|U|iLB2Mm9S|G-f!Iy!;zez|;t(!yxu#9^moNC?VVLp^NFfd0A^tUJd@56=63 zOnYNK(gm5zh7Z}eS7wxKXFr5l8R9T%#%dPYn7l_Kl~94e$5WAm7E7{(;rkQkG^TEa z%HJDmmhNRvb5E@<*9w}QAk+^!H@$5yDg={FA%s|EI#W?Env)jZwcW{nI4dWJWlObl zN@sUBA>X;m`$SH1+s!^DfmoDPM>Y?f8!H%oKKBNcDvKd%wr^#>#`IRmOmIjJy$q#c z#CNWs)f@Q+Hq{bzTR>;92M$o%cdm!T|2_a+CF-=wgU`REX@@^5_%tjH^|sHDA31-w zzb%Ra@Y*(0ZSe|U^sVMMoQ>IzbuD=F1puytKEK5KYB(?EMMsJS{%?>}4GhN#6>%>C z1HvO0-Z4BRO*8QL16`jg&28*$`kckISd^t8_j6R&kU$%^&ZBg;bn#bM+87#Is6%-R zg}(aet1t1TZ^iz4|93q85D575EFIMHr&N7MjP#Tv$MBwfCyhKi`+kBH$_%Q1wH+!% z0iqJ}LaDh4Ih5b#u6p2Ol1#EP!omSb|X)WWz zwx?KiQm&%+(=W;y?9AW&X*RfEwS(?>(rQoj$pa&^>71 zeZu1Zh+{ts5LUoh>vr|Xb1s0mY-N0D7Ns?a*nfA&Nn|Chqc{K2;y20hO^u_r;OwMz@`f$a?6s7JaeI$n z5uEaBkm|GPc)VCHCX?Be7h9QpY;hKK8{E?>?==qve`m2;nKpB}e3mbT6q&E{^Cr$8 z0FvC@4Ol7#T7p4qiwXvyHNH0a%W6k&eKWo+`Bj>Da}7GOT6sD+i}>MuHg7;AIh{^~ z#!TA|(@!Yw#FT3TM@2Q&3%nr3tNZ(?KWwRxQHCC7^B2NRkyn{P&f?9nh+Dh5)3bKl zd7PEQxRE=tH-)df%JUdPh`D|J&p#^H`@(OU@gTFqfL5{W`6cT`k3~6B&N-!ec>F+? zep6F=`?x}~e)dMGT+!>fan2dt_Z08Q@ixo{^ygSJvo_TZ-L%*PB1n%(=l>%W1!Acx zyzd>u!-Gd<1FE!>HcRvnV5~6Aph*Y;myqmnKunmNO{`3T57dhupQdrqdoNOKp@7&3 zKymSwNeAq*{JYY?q;-Ue9?pUz5Q2@*OAXrKLdwi2lKYR;Nh)AwOFj$hxIxjzzufS3 zjXWOiCrV6Wt%A*Bx`5G(V%4SKC|}3ITn;`h9%mWZi(^4M+KOE`bk=q9$PJCoMhnZM zmE2oR$0N~E5C6krJW$Py4ahl$%m_n&Wi_b>TX4BhBb!biuM7`>A>OTm-IBU^BSG9z z>xtKg5Rb9TvR$$qi;^JcLGjt42F%iRU}D}eD?n&R_Sw3)NjOcb&Pa5qitwo9FR8spKaqlEeH{&rk|bCseTx z!31L0?c&w>ld%=eQEp%NSoj(hfP!>ff4XV0GkX#ty76zY;;Xl%UUWiHJO{bHo z*O9Rh1%u#Z&=~K=%f({sO|9Y36nMh;ak{zXe0<<>P}~8BLh>I=#b?Gon8uCy3OwHr(j*vMXtHKm`d*Q-)Ul0|Y4D5mfX1PSoJ#(V8RyxH+; zJ9HOwz;2sDR2hZ9H9)1xmeTuVC3&Mv?zhxqk#On4y&15v3IdZ@qb{i%vb$-Z`R*#F zgs8AGiG+JoStuK4Ty&?%39vyt(gd4QqgBs#%CUJ*^Y5J{?cD^N3Vz^ffOEZ#a(kf6 z!Z$u@fuR4Z&DOVJLy=L_Xwd=Kh@8PyS7p`$@-0lGY^dIm>J->#d5kdvo$u{N4C zNT!t+9a()rkyeXvee;y+IBg^Wi1DknVlSojvaW;ft|dmr&GvF#sKN`2xF29sg(Oz+ z>fIToc90FcRRTN5P#k#v3aMHc*L1SiRoFi~iu^5!JlFGj0+3GA8HRbwIRwWBptD;m(jv!imZayNyB* zOT%e-(mZduOMO%KQWAn4BzmHt0|<(6LZF;>YDLJT7Sx@b4vBk&$^cC!$&$fwqAPS| z7Mf4XT8ieTGaeX3frYjcvK+cKwbFVkY9b!=o@DqdE)3L}OA&f-Oce`wStngmsirTt z`k8%>8WKOwC|Vzfpw zlsHX!w?Rv3-Y`#`sdm!0`T?{sDs2aWYj}k(@4M66u+U>32Rsg& zNpI`YAXD42j(yl{6wPJY(OgRSZ^RuhNd+ZBuyH#3zgmA%sDK(5Y9O}HR`o(TdSQL znWs5Z@$8=SiEMCp-ss;_w1_Z5B+;C60xoN+jm(!B+P39%C}<={P*1>Y-+#G9J-}^Y zT5PDcK}y`EDt=-!pB#HkakWNqW(mdv@V}roxzW_g2DDgM!-i=X+ewtg^uJWP!~1MQ zkTvT3AX1;-!1#qj@4-Mx;Dz!+=Ln-fR~Ub5tK$gMwf-mI*R@Dm z*-O6;em_0-i=$Cc2Tn8zMwqN~an6f?oZO^B2p__f(>{(P##=L>W+8gPZ{qMfPg<}{ zlXsFx=M!S55F`cw+vf#+33$Ytf*0)aWWS9B+dJSoE`YPy9qI=@by+l+ba>~L#r8_3 zyQo%~^>f$7oE?=o!BR)`_mgp~ARj=|^Ncfy01t*F>8IS^u{`G{7thd~PsSYpIM>g0 zY~V@6XplTZKv|UVwA3v)Srm=LYyG$>S`PaCUN19< z|4V1-QWWA^0%+=TXWpqouUT&m|{$0-j)?=!NPo`w1V^tOEd>J!k4?EM0MvW24WqB9-zh`Lwed^g$mS%;r6&vcGeIo}IMAZ!Q6h4LQ z;UsVvG&#A$hG;R-Y;4rv{asZNr~#|ALdAysXb{<>`~Wit+${3+|DO6MrlWczC0wvI zKMI`rb&Qr0XXOhkQd<+#$}V-2PvxG{1I2yPBf45nGj|s}5f6em|B>17s0iQfVcO9r z!$j#A;E19=zsjFtg_9?y!q28jhg4>XIA#0KxwfvYY|dxN(-$BIbbkO@rtC4o}H>1xFe)HJlF4aeE8c3My0;(%8j0KgRFTfHYnre;ZEG-ZfT+G65C|`nd zC9X>2^o9FHWae;H4Tr%W4!=Qg&k=b#N}(XAjl{=U>}{t)TgvNITPi%UC(sIf8D?ctp&|dQJDop^0zF*oT-Dc^Q=>K19>@M-mp@3$VmQzh{`)pFdaIce1 zay!g1{B4KKI2zaLc=>O^-G*+yUn1=Hu&Bg+_@4go#cw)P%${Rnz%sk)L=hx5j1hR> zN#%e2{L~TDJyASm`RVA8=V8THDmUJTZ3utIA(2Qy-aDxNx9H~Qz)ivaTBH&?p8u)O zg0pvzj@EoP^b{)*yQDWdM!f$c?@uy!{wP3Xp8~z4Q#hBulIJhUYDZqc15YvccyNz2 z7ar(`#%SO#>x@De`+#H-${bHJ1T|n{0t6EUSxb-@#`r%zsKKa_vN~rN40vWRk-}mA zxXc>s(Rt@I=RzZDO?#eZL^_`ll2q_Fx(JRNHA{=ZS`1^YgplieW~{TaC_@wglu{;y zuwq~+YzfYLofF{|si=%$lo536RcEwIgaC3rj3<-vFdmOP#at+uH5wthL&)=1tL1dG zoKBZMlNVzHvZP6UI7+Kcfc+^f(L-CObEFG9U)U~{te_wS6Laf{OjT7LV)jugl(rxB zZpalTBU}F#QcR}Tf&lm{2qlK}XRtF$PD552BhMMyk1B)$!>pe?uhnCMc@qmGs$}Q( zQO$QCw2c^4nu3mRB6#qdM`dv-UV6$x(LLCZp)A2X6*11~$tRfk%p1t9X&(d0-H^gn zukOHE?UutZ%3mxNw|+V+#pHG1IpztRP>A=x`BUG(I%PXUAFl%6pD!_^Y3L(#ZGmZp zkhbJ4%9FXK!(s*HbsL4+`#jU5`75L7dINZ3{(L#qx=kDO`wyQQ!@2Q^&`OL0jnXut z$znF%PIQZXm7&!Xk_bzb*db0w|Kb-5!<505w=RS~xpzQ{Gv|!z;|D@0RNK{+w%G1M zvZ~6sF9iagq(yFF=d)rpN=-lVVU1l>0<>BP!~9|ya{)5vctXbUs!TP8RGEpkX?6-t z%`E`eb3*B#oPP@Hf5ar~M`=<4$YisLt+x=!9;ccYI(k2gU zQQAxugXj0nRuj4(Zz8!3-aub9Du31<=}}dy$vpK-ozr2B0L1!6QB^H`;Bsv5^tvMw zriGO9U7K<<;+QgXbL5MwVYM{d5|cw0+)BNz01ItwVz#+Qirif*slz`FjG`n6NQxy3(natt z3dkuh9k&+%hC>?X+&F6_9j-~SvwtnfJnVbf>ngWv*tvdQ8eh_nc2CtxG;c~$hV`RzZ}z(P4GVkyr_T@nf>WW?((*) z4cO&0dn0H}4XC5?0U4XUl3*spFB}jNz@~tS@YxdUh(JxS#F#K+TC%wPSgpbtU*tjg z?N#nzb?*sR4e1Mx05(tO+G9Vqv<_^h;I3bi@jAq`SFX9ct(QDuo)5mTWITwG53(k> zp*3S1Ikl!p=YGj!JlvT!KbGWXL&=>8;^(QmDkpI8RB&tKkBo;PEJpvyPOx_v2+?mE zhMoPl1?D6iKfN9)j$`*}Vmf8Dp0QqxCS-_^Y?2Z2n3yRd?W?Z(D-4bI{i?{bNc@%t zHz+P1$0szVQ9FqhQ_Zy`Zg_qLYBAc} z5;2!C2L)UjU00TyN1U%X^!UQQeA!mVPo8|tQ@FmYZw9q5Ts-Z1Ip;C@G8t8}X;h*w zoQR2~`oOAeH#`Af*n2UrDt+?_*XVi`Zwi;t7rFH9!)3aLvM>Fdk&^#+L8BYFi~7F; zo+|wX9qn|hvH5*Mw;a)pFW%(;agFkjbjd(9vQ%|80N>v7&Mq)5Gt`yi($LU?=M`ZC zZH%ZOj8XVGX?FMJ+dSnIHxDq7EXlB(QFCju?;sRjV)?V)lwlfKNLWBcs8WUy1(j;e z$vJUgKsI@}P+I>H^U2(uN5qo|6m>|<loAr8)JuCM{s+A&lZS zwckvl*{u^PUcw&2z{3;)-P*4e_dF(yTMR+&N|=YY8B|%=$v(cye6wk_G>rf_Zji-B zVVck9b-Aij7uto9L>0n*C?*sb^CD}-OFA}BR74==Nts|?hq2%K%?%k;29%ak+|77= zfqwLw4r=Nt6igrLMONxvR6RAuTJa{|D3Q&Pkmxwn3c?E2-(aXjUj8vUKR5r-Wqh`r z4y=HL!d=X$%G{94e<&pgsbuT`1LhmWv0z+0fhpkOFC8LLtQ$u1&3&%XG?qx7c)ed! zAy_weO(R=HJbRtU*Rc)r@Wn@AiziEDCG6oMQz)jW2qX-PJ?gh?eQm4C>N4N$zj)u! z6A_KYPU9dBS1A)9?%K)2&f8rJ4c)-el?o9tIY`=0~Ay{wbZb6-ilrC2Xtw`P7JrU+CHV~y$pn{!_Hk`p$KZWxvr*Rb;oO+cBP*3 z!%`jf1;Kb9jJPP>O#E}vLzPkz}z=chsKpR5l`LC17Ie1#)Sd#AcVE$r$!Om00H|k zr>(e=f^!qqUK`n;v;cRHR>=P)@N<>Nc)_dc1kchdy5ebiTvf34#;lMHAapRKG_WKx z8xl7{b^nu&3Imr~y8TOJykGL18t&^=N>xRo+hU`~;*H0s(TVs>7LijPXD8vdYJ_Nf zNxLWN$?QJ?f4_3Sf4hF1Vy*P{E6wQ?;c_>7BSVemmT6JIb~NjgVImS~?tjt|ZsC?h z=|4t~&y{{XRIRUX2%%kczTNjCdGRLp-aQ%hV=lHXABq~RT&=TSI{Tk+lp6>gFS%D8 ztyk~2&PF8Pt<%o(sBT6YSLXUQk2@BCDb$S@`}l~9W33^_O|5g0(^q3rG_MGry||RX zj&9G2UK%QQP`TLqc@{X?*Ac{>E>;=1dHUR8Qy&znA>)6Hv09Vz*SZw4fg*fxJU7viPg`l|x)8U_ z!T3B2mur$Cl=4&{@5@#Uha3QW!TBbsdoJ*7HVsI=_<+Cu*9Fr#k=ONFJZ!DZ>0gdHH|&Wx1<$OHFyQCTbWy%RTE& zWg^hz@^YTTc&E?owr?(ti}sXT5;>C>;Vr?T>1Zl}GL@o_uhqiIbAgcdD$fke%A zrjpB4SJe}m&10$65&&_P_W!;lDerg+vad3KDRLEkf(AMO)4zrMZGUd@w+{JRe_|Em z@2dy*{~fTRI}=Lv2$tfYA@$RFEk@hnX?tX{l`4-%NRBgSndeLM4{tS*kcQG$FpvJSDRqhPbEpVoedU zO0#|6h804#gr zgES4s33dHNxZ4|???%BdfG6Rm%YM*=p5gKHySWGXhgg%Een{cx{uTC6wu$Uy5_u=* zO!WA^y|_~%jceRX!XoFSZ1HY1l^yjo-DozD8LfzVaLL(~XQP#Jn3B({OQu{x3|hL) z%e#lW#jrwUP>w?hlO6|Ol1mw~sFw^SOf1YYvyjI**?18??4J9u`n4CkVj91SxEbO^ zE3R$2zgu=TZ?5>&HER)RL(C_gFH|X1Vo!U%rn_ia+Ppd`ReLAPaIyGYs$fHVCq2Bm zdwrvR^+7tsfxrOJMAx1OXPAAn5Yxr_L?>98PR&Z0=lzjS_Ha4w2`6M}$$jkpW9QKB zQUBHhX4!NDEe%svllh+4kf~T;*h=#~RUwJi#--!vLe&EH)eBbFzBZEdOaJ8C|Ltl? z`1m-;r>C+$lm;3MGR`SEWsKeqh9mic{%qo598<4yt-2rk2v(4c?No>}Bl)wzi+QT% z-`zBEs=^GPk>KP+;yVaKj9=P{Qn%^&h<$5YtKtj0*}gQ?p6m2+9jJnwf-Rdj+e zFHKrVL|HR!q~8{OY%l^mo3Akbv6+6 zo2-26JOa(fUgt^A--#i5-_GN9;`&=(`Q)nZ#0tXL*NVbz+k1~5X0(yRxFvr&i!Ni| z&R;i4lRm7&y;{P}LT(N!+?U#Vt<5GoHHc1Q-_A%l6G&85d>p;??#>aas-9JqMQ2fj zA0UMd@B|h~2*KR#kl3!{it9x&w3O(y?=(}3PzSS?$%3lve8-^AIYugS8OM_IdKnCP zfT(Eq>=JpXwNwH(^G_qPzKpeJ9yV;IpY#)cte=2>0&0bR68aJFll>_8F(02a5ta%Q zh2|!+bT}@N8JEJCfOSNedntC3h$Bo#MxX0i@3@?^n0a=~wpmIjb%+8@gt{wJt82xO z)5!@*=82a%fe0TgW9MFS?xuLAp`B}?4fjW(wAJ;NARU+S6*mm?GKO*tH#LP(Dmywu zOSrYDcHgx_yO8PQu5P9F$Y~sQH!;A75WQT3GR^1Pf{m?I+m7}Hu`K7Bl{Q=!9Ftk; znL}9IPh&JIM$=h?7C%7}r!EIc zb+YQ{i@nn{ihS2HOlRMyXc;O0Y^o?g8Pafmn(cX-(XT*DyZKOu)z$U&)z7GmG}@dx z5eIJ0-urE5FYKoE+Vx)(Ec|eVU^g~vR#rb`JJeP7%y0TYb|j^VxjT0~^VuQp@}%O{ zs60vjAnPe5?$*nPKsW*8@WQi4j>0c}NfJf#77Z*x2HgLDzV)e$Z51Tlu8xg9v?B9(geWbfsXNbg#%B^@4>Ax^cwy za`EWV!t*Av6DT4ul!#f(^ue(USZb97)C6W?F59=n02Xi<$h8`oaam*&wa*<<4`n6+ zQ!Y%isDNK2Z7JtDd5FD~ID1g_GczW3Y`C(7iRBbR78f~o&_P4aDO;{I@#8U$h||%e z+M4v+@k$T4%p{bNo%B9PiSd99M8J)k!-q*D(NK|=RKy}*Sji+p+H{A)DrnjO<>D-b zINix_6>oDKKZu7B{=3S|Bb8l830B9JqFI+q_ax z`Pzh`C=+(*3afs1UQRA{1EEfnd_oGTk)LnEhSD8L3>rc1gY3?htik2rlA&lQfY*Q! ztd-BTR#2`rk80eniE?xWpL55du!-^BJthDVK#5+oTjEMqN*%2(sF1sgFJ_qdCc-OK z=oBUxs(QU5Br`(ZXN6FPKo*rYQOKKMT(&7j2qQXC7e}O%SIr2-LMm*+rLWQBRBO;c zSSx0<_0Z9}>l`8>g5^xvsCB?nf&M)qK!tMPbwhM7t5)Nkx1e~;B3H;Wl;-majDxeB z53}zm=af{q*w8ad=;Mbpu3ntsS&WGi85xy@yfR)v)9@mEqs5@pZb}Lsqxn8@E7Etb zBTQQS)C_~(U|+hcl56M8utRddO5-XlrBPQF+6o)hRY&1UH_z{lX$vg$D;sQl45qC1 zQBGeiP?)=R)glbh$&dSNWGy~~7B=L#1wR>3%Gcm(5a4RtBG`mIb&#fza3If^Xf0&S zrtu;66#+xfIn6T#EzL*rOXZnG#)6mA)_L>c72;W6dCP+lgn`C&>bVTtR2Y-)Z4N*& zHvYK8nPRbnz{mC|Dam`6ngAUHWd@601Up_ku#=(&gDZ-ctM0IWM>^zqtjCX!N@p-T zV^b6|MtVL2@IUmxu`-SVlT!kEz7!b-o5dqPPA>dcc1YU=^2c74+ z788TI$~fqh3O<9!Z+Uip0@3YoX5zH7P0i9&HUxR^4WKb`+;a%vPWr-0bL~&=@mMxI zoEK(mLh!-fdB!3NL*8HrJ(@`X_`A;l1V#>@DEiRrz&aKuuSXjjYxWH`+D?(axhP!} z@A1WD^8-KmM$-x=F*Y#j3DH<*w{-B}aGMKANZ^kzU2=Rcxc>*NF z?Hqr>*?gjiyY_(a6Qdq>Wdu|#PnjfQT0jI|yw07PRH3vYCZd76D~Rt$Ll7iY{OQKL znhI}qV`pkoQKysuqGmso=3Kaz9CrxfJceR381bZ0hw@NxIi~DGywJ-YJwhYtN_N+f zBnqeJh_7rEG#%-;EN=PS_f%~PA`g~bTN&#LQ?-J~5@XS&Qy1UP{`NfZxG zo}Exi2)3oT>chhJcuLc(A%{v$S47OmMSJ<($pW%?U||?6jh#}VZkjoinVQnTU_D)| zPJ`hq?i3$=J|vv0ViroE8Pn{pnG<<>OacTR#Z@Pggkrnt`SKjXO3h(>0O2@kkvBxN zGs;c)pPQ>lMi!#!v6V5He4GFjsHY>VPu%rH6Q5w){I=ho7gdkTP-OF{=YU9Rn`PFUA*9ThTtgZ$?=X1F$;9lPl_f!rS}B`oXT)fP zLI~kiHB!bWWl19s5n$@dFmFR{J^MWOQV7}Xks3s=*q{%vv7{>n6B50rlzAhR0rr^? zZ&1R7It*i}E;;}JX+~*W#t2kIiTxW%SI%cMZ#5S4I<#td1v!m^bK{mXnNCQ#w{MRA zKk|_u56k>O`!xtsKGVGxHnD=*IGy*a74}X3$XAs<+b32KMDsnkJYUt@nX%PH{>K z_vTbJ@3$#ed5ac=7!VPyHIdzs&zE%@4PEOBOr*8Bkr~lry$v|usv2E=5`c2nsqc$s zAkK!f*fg_A~NLvjNa44vZ|Kbrc9JBK`Vc8EpbC6&pGgYu8Tp$dY(bnk2vu zY`Zx2Az5+}*KEi{Eq}rORaY9M4G+pU`3q9)8Mx zI8O<}3`GZ^H26@5$&u7?yBmgy|6IiHbFfr0c-)@~C@fa1-66i)0lcjCYf#w!z< zbI;ssl}XLi15B!1&o!YsTqhs`Sw?JuDox|QGRT&2z26m;&<;HG0Jc)oIG!qpuxy&? zcne4AAW<%SWcJmPD8yGrZ^U8hCNSdjC^^NYbkBhZY}<8g$k=X7gIwz`B|yD_)7-9+}PBSBg+uQ5gB>{IkBH% zu>hu=CGN^-3k^>2rA!O0nlpM{U4Qq4Xi0ovCgDVg(#b!A?daA9Z<%Hu0{FYp(Bw|{ z-F2k{D0W*@u?_kUevq`A`p@7JZ_IocLGagM0%oa)DUhrpE#18BFavt~$d+x+AqSgp z9Ogmo2^Fxpm_mN@7mD1kS5VlQa}O@LY>sOUV#O@?*J07xSrxH4W-=c3FY9Ar+*OX- z&OLth3r!!Ea_QEN41IsZ9B*V~4A(mJa6JS{LzR8!Wr3ltASGS+sOITnqC{H=e#((w yceOk1_r9fFwMcHJYo`g`m4hQQ{xneW;bw%hC=12" + } + }, + "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 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 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/6] [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/6] [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/6] [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/6] [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 e04801f425a9e6d6ff6f908ac9ab8b565903b714 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Fri, 13 Nov 2026 17:05:42 +0000 Subject: [PATCH 6/6] [tools-gps-tracks] Move warmup and init out of prepare into measured steps The prepare phase ran a full synthetic warmup and app initialization before signaling readiness, leaving a large unmeasured chunk of JS. Prepare now only fetches test data, so all initialization, parsing, and rendering is measured consistently in the benchmark steps across browsers. --- .../dist/tools-gps-tracks.mjs | 616 +++++++++--------- .../dist/tools-gps-tracks.mjs.map | 6 +- .../tools-gps-tracks/src/app.ts | 292 ++------- .../tools-gps-tracks/src/parsers.ts | 4 +- 4 files changed, 375 insertions(+), 543 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 a024ae89c4..c46097801c 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 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 jt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"u"?location.search.replace(/^\?/,""):"",e={},n=s,i=null,a=null,r=!1,d=[{state:null,url:t+(s?`?${s}`:"")}];function l(){let v=new URLSearchParams(n),g={};v.has("track")&&(g.track=v.get("track")),v.has("map")&&(g.map=v.get("map")),v.has("xaxis")&&(g.xaxis=v.get("xaxis")),v.has("tab")&&(g.tab=v.get("tab")),v.has("sel_point")&&(g.sel_point=Number(v.get("sel_point"))),v.has("speed_mode")&&(g.speed_mode=v.get("speed_mode")),v.has("progress")&&(g.progress=v.get("progress"));let E=v.get("metrics");if(E&&(g.metrics=E.split(",").filter(Boolean)),v.has("f_date")&&(g.f_date=v.get("f_date").split(",").map(H=>H||null)),v.has("f_dist")&&(g.f_dist=v.get("f_dist").split(",").map(H=>H?Number(H):null)),v.has("f_dur")&&(g.f_dur=v.get("f_dur").split(",").map(H=>H?Number(H):null)),v.has("f_mets")&&(g.f_mets=v.get("f_mets").split(",")),v.has("f_tags")&&(g.f_tags=v.get("f_tags").split(",")),v.has("q")&&(g.q=v.get("q")),v.has("re")&&(g.re=v.get("re")==="1"),v.has("sort")){let H=v.get("sort"),L=H.startsWith("-"),h=L?H.substring(1):H;g.sort=`${h}-${L?"desc":"asc"}`}if(v.has("map_pos")){let H=v.get("map_pos").split(",").map(Number);H.length===3&&H.every(isFinite)&&(g.map_pos=H)}if(v.has("storage")&&(g.storage=v.get("storage")),v.has("sel")){let H=v.get("sel").split(",").map(Number);H.length===2&&H.every(L=>!isNaN(L)&&isFinite(L))&&(g.sel=H)}return g}function f(){a&&(clearTimeout(a),a=null);let v=new URLSearchParams;if(e.track&&v.set("track",e.track),e.map&&v.set("map",e.map),e.xaxis&&e.xaxis!=="time"&&v.set("xaxis",e.xaxis),e.tab&&e.tab!=="graphs"&&v.set("tab",e.tab),e.storage&&e.storage!=="memory"&&v.set("storage",e.storage),e.sel_point!==void 0&&v.set("sel_point",String(e.sel_point)),e.speed_mode&&v.set("speed_mode",e.speed_mode),e.q&&v.set("q",e.q),e.progress&&v.set("progress",e.progress),e.re&&v.set("re","1"),e.sort){let E=e.sort.split("-"),H=E[0],L=E[1];v.set("sort",(L==="desc"?"-":"")+H)}let g=v.toString();if(e.metrics&&(g+=`${g?"&":""}metrics=${e.metrics.join(",")}`),e.f_date&&(g+=`${g?"&":""}f_date=${e.f_date.map(E=>E||"").join(",")}`),e.f_dist&&(g+=`${g?"&":""}f_dist=${e.f_dist.map(E=>E??"").join(",")}`),e.f_dur&&(g+=`${g?"&":""}f_dur=${e.f_dur.map(E=>E??"").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 E=`${(+e.map_pos[0]).toFixed(5)},${(+e.map_pos[1]).toFixed(5)},${e.map_pos[2]}`;g+=`${g?"&":""}map_pos=${E}`}if(e.sel){let E=`${+e.sel[0].toFixed(4)},${+e.sel[1].toFixed(4)}`;g+=`${g?"&":""}sel=${E}`}if(n=g,g!==i){let H=(typeof location<"u"?location.pathname:"/")+(g?`?${g}`:""),L=l();r?(d.push({state:L,url:H}),d.length>100&&d.shift(),r=!1):d.length>0?d[d.length-1]={state:L,url:H}:d.push({state:L,url:H}),i=g}}e=l();function y(){return{...e}}function S(v,g=!1){g&&(r=!0);for(let[E,H]of Object.entries(v)){let L=E;H==null?delete e[L]:e[L]=H}f()}function I(){e=l()}function B(){a&&(clearTimeout(a),a=null),e={},r=!1,n="",i="",d=[{state:null,url:typeof location<"u"?location.pathname:"/"}]}return{read:l,get:y,patch:S,refresh:I,reset:B}})();var gs=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)}},Fs=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 i=n.result;i.objectStoreNames.contains("tracks")||i.createObjectStore("tracks",{keyPath:"id"}),i.objectStoreNames.contains("settings")||i.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 i=this.getStore("tracks","readwrite").put(s);i.onsuccess=()=>e(),i.onerror=()=>n(i.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 i=this.getStore("tracks","readwrite").delete(s);i.onsuccess=()=>e(),i.onerror=()=>n(i.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,i)=>{let a=this.getStore("settings","readwrite").put(e,s);a.onsuccess=()=>n(),a.onerror=()=>i(a.error)})}async get(s){return new Promise((e,n)=>{let i=this.getStore("settings","readonly").get(s);i.onsuccess=()=>e(i.result??null),i.onerror=()=>n(i.error)})}},rn=new gs,ge={openDB:async()=>{rn=jt.get().storage==="indexeddb"?new Fs:new gs,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 Io from"fit-file-parser";function en(t,s,e,n){let a=t*Math.PI/180,r=e*Math.PI/180,d=(e-t)*Math.PI/180,l=(n-s)*Math.PI/180,f=Math.sin(d/2)*Math.sin(d/2)+Math.cos(a)*Math.cos(r)*Math.sin(l/2)*Math.sin(l/2);return 6371e3*(2*Math.atan2(Math.sqrt(f),Math.sqrt(1-f)))}function hl(t){let s=new Uint32Array([Math.floor(t/1e3)]);return btoa(String.fromCharCode(...new Uint8Array(s.buffer))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function bl(){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 vl(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 yl(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 ue(t){return String(t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function hs(t){let s=0;for(let n=0;n=0&&S0?l/f:t[d]}return r}function le(t,s=1){let e=parseInt(t.slice(1,3),16),n=parseInt(t.slice(3,5),16),i=parseInt(t.slice(5,7),16);return`rgba(${e}, ${n}, ${i}, ${s})`}function xl(t){if(!t.length)return null;let s=t[0].lat,e=t[0].lat,n=t[0].lon,i=t[0].lon;for(let a of t)a.late&&(e=a.lat),a.loni&&(i=a.lon);return{minLat:s,maxLat:e,minLon:n,maxLon:i}}var _e=16384,Ho=new Float64Array(_e),Fo=new Float64Array(_e),Do=new Float64Array(_e),Bo=new Float64Array(_e),_o=new Float64Array(_e),Ro=new Float64Array(_e),No=new Float64Array(_e);function wl(t,s){let e=t.length;if(e<=2)return t;let n=e<=_e?Ho:new Float64Array(e),i=e<=_e?Fo:new Float64Array(e),a=e<=_e?Do:new Float64Array(e),r=e<=_e?Bo:new Float64Array(e);for(let B=0;B=v){let k=g+E>>1,j=(i[k]-(i[g]+i[E])*.5)*H,U=n[k]-(n[g]+n[E])*.5;l+=Math.sqrt(j*j+U*U)+(r[E]-r[g])*1e-6,g=E}}}let y=[t[0]],S=t[0],I=l<-1e9?1e-9:0;for(let B=1;B=s&&(y.push(v),S=v)}return y.push(t[e-1]),y}var re=(()=>{function t(w){let b=w.length,u=0;for(let R=0;R0){let O=w[R-1],q=en(O.lat,O.lon,M.lat,M.lon);if(u+=q,M.speed==null&&M.time!=null&&O.time!=null){let V=(M.time-O.time)/1e3;V>0&&V<10&&(M.speed=q/V)}if(M.gradient===void 0&&M.ele!=null&&O.ele!=null){let V=M.ele-O.ele;q>.5?M.gradient=V/q*100:M.gradient=O.gradient||0}}M.dist=u}if(b>2){let R=b<=_e?_o:new Float64Array(b),M=b<=_e?Ro:new Float64Array(b),O=b<=_e?No:new Float64Array(b);for(let nt=0;nt=Ct){W-=M[it-Ct],F-=O[it-Ct];let K=W*gt,ht=R[it]-R[it-Ct],Pt=1.225*Math.exp(-R[it]*Bt),ut=Math.atan2(ht,(F+1)*.5);V+=K*K*Pt*1e-4+ut*(F*gt)*.01}}let at=V<-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?u.elevGain+=st:u.elevLoss-=st}(dt.gearFront!=null&&dt.gearFront!==Lt.gearFront||dt.gearRear!=null&&dt.gearRear!==Lt.gearRear)&&K++}dt.power!=null&&(R+=dt.power,M++,dt.power>u.maxPower&&(u.maxPower=dt.power)),dt.hr!=null&&(O+=dt.hr,q++,dt.hr>u.maxHR&&(u.maxHR=dt.hr)),dt.cad!=null&&(V+=dt.cad,Bt++),dt.speed!=null&&(at+=dt.speed,nt++,dt.speed>u.maxSpeed&&(u.maxSpeed=dt.speed)),dt.battery!=null&&(Ct+=dt.battery,gt++),dt.temp!=null&&(it=!0,W+=dt.temp,F++,(u.minTemp==null||dt.tempu.maxTemp)&&(u.maxTemp=dt.temp)),(dt.gearFront!=null||dt.gearRear!=null)&&(ht=!0)}u.totalDist=w[w.length-1].dist||0,u.avgPower=M?Math.round(R/M):null,u.avgHR=q?Math.round(O/q):null,u.avgCadence=Bt?Math.round(V/Bt):null,u.avgSpeed=nt?at/nt:null,u.avgBattery=gt?Math.round(Ct/gt):null,u.avgTemp=F?Number((W/F).toFixed(1)):null,u.shifts=ht?K:null;let Pt=w[0].time,ut=w[w.length-1].time;return Pt!=null&&ut!=null&&(u.duration=ut-Pt),q&&(u.sensors.push("Heart Rate"),b&&(u.hrZones=v(w),u.hrCurve=y(w))),Bt&&u.sensors.push("Cadence"),M&&(u.sensors.push("Power"),b&&(u.powerCurve=f(w),u.powerZones=S(w))),it&&u.sensors.push("Temperature"),ht&&u.sensors.push("Shifting"),gt&&u.sensors.push("Battery"),u}function i(w){if(!w||!w.points||!w.stats)return;let b=w.points,u=w.stats;u.avgHR!=null&&!u.hrCurve&&(u.hrZones=v(b),u.hrCurve=y(b)),u.avgPower!=null&&!u.powerCurve&&(u.powerCurve=f(b),u.powerZones=S(b))}function a(w){let b=w.length;if(b<8)return[];let u=[],R=["Q1 Opening Sector","Q2 Mid-Climb Sector","Q3 Valley Tempo","Q4 Finale Sector"];for(let K=0;K<4;K++){let ht=Math.floor(K*b/4),Pt=Math.min(b-1,Math.floor((K+1)*b/4)-1);if(Pt>ht){let ut=w.slice(ht,Pt+1);u.push({id:`q${K+1}`,label:R[K],kind:"quarter",startIdx:ht,endIdx:Pt,stats:n(ut,!0)})}}let M=["Opening Third","Middle Third","Final Third"];for(let K=0;K<3;K++){let ht=Math.floor(K*b/3),Pt=Math.min(b-1,Math.floor((K+1)*b/3)-1);if(Pt>ht){let ut=w.slice(ht,Pt+1);u.push({id:`t${K+1}`,label:M[K],kind:"third",startIdx:ht,endIdx:Pt,stats:n(ut,!1)})}}let O=0,q=1e3,V=1;for(let K=1;K=q||K===b-1){if(K>O+2){let Pt=w.slice(O,K+1);u.push({id:`km-${V}`,label:`Km ${V}`,kind:"km",startIdx:O,endIdx:K,stats:n(Pt,!1)}),V++}O=K,q+=1e3}let Bt=30,at=!1,nt=0,Ct=1,gt=!1,W=0,F=1,it=e*1.15;for(let K=Bt;K=1.8&&!at)at=!0,nt=K-Bt;else if((ut<.8||K===b-1)&&at&&(at=!1,K-nt>=45&&Ct<=6)){let dt=w.slice(nt,K+1);u.push({id:`climb-${Ct}`,label:`Climb Segment ${Ct}`,kind:"climb",startIdx:nt,endIdx:K,stats:n(dt,!0)}),Ct++}let Ht=w[K].power??0;if(Ht>=it&&!gt)gt=!0,W=K;else if((Ht=15&&F<=6)){let dt=w.slice(W,K+1);u.push({id:`sprint-${F}`,label:`Sprint Interval ${F}`,kind:"sprint",startIdx:W,endIdx:K,stats:n(dt,!0)}),F++}}return u}function r(w){let b=[];for(let u=0;uu)continue;let Bt=0,at=0,nt=u-V;for(let Ct=0;Ct<=nt;Ct++){let gt=R[Ct+V]-R[Ct];gt>Bt&&(Bt=gt,at=Ct)}M[V]={val:Math.round(Bt/V),idx:at},O=!0}return O?M:null}function f(w){let b=w.length,u=new Array(b),R=!1;for(let q=0;qR*e);for(let R=1;R10)continue;let V=M.power;VR===0)?null:b}function I(w){e=w}function B(){return e}function v(w){let b=[0,0,0,0,0];for(let u=1;u10)continue;let q=R.hr;qu===0)?null:b}function g(w){s=w}function E(){return[...s]}function H(w,b,u){let R=w.indexOf(b);if(R===-1)return null;let M=R+b.length,O=w.indexOf(u,M);if(O===-1)return null;let q=w.slice(M,O).trim();return q!==""?q:null}function L(w,b){let u=w.indexOf(b);if(u===-1)return null;let R=u+b.length,M=w.indexOf('"',R);return M===-1?null:w.slice(R,M)}let h=-1,m=0;function p(w,b,u){for(;bb&&w.charCodeAt(u-1)<=32;)u--;if(b>=u)return null;let R=!1,M=w.charCodeAt(b);M===45?(R=!0,b++):M===43&&b++;let O=0,q=0;for(let V=b;V=48&&Bt<=57)O=O*10+(Bt-48),q++;else break}return q===0?null:R?-O:O}function k(w,b,u){for(;bb&&w.charCodeAt(u-1)<=32;)u--;if(b>=u)return null;let R=!1,M=w.charCodeAt(b);M===45?(R=!0,b++):M===43&&b++;let O=0,q=0,V=1,Bt=!1,at=0;for(let Ct=b;Ct=48&><=57)at++,Bt?(q=q*10+(gt-48),V*=10):O=O*10+(gt-48);else if(gt===46&&!Bt)Bt=!0;else{let W=parseFloat(w.slice(b-(R?1:0),u));return Number.isFinite(W)?W:null}}if(at===0)return null;let nt=O+q/V;return R?-nt:nt}function j(w,b,u){for(;bb&&w.charCodeAt(u-1)<=32;)u--;let R=u-b;if(R>=20&&w.charCodeAt(b+10)===84&&w.charCodeAt(u-1)===90){let O=(w.charCodeAt(b)-48)*1e3+(w.charCodeAt(b+1)-48)*100+(w.charCodeAt(b+2)-48)*10+(w.charCodeAt(b+3)-48),q=(w.charCodeAt(b+5)-48)*10+(w.charCodeAt(b+6)-48),V=(w.charCodeAt(b+8)-48)*10+(w.charCodeAt(b+9)-48),Bt=O<<9|q<<5|V;Bt!==h&&(h=Bt,m=Date.UTC(O,q-1,V));let at=(w.charCodeAt(b+11)-48)*10+(w.charCodeAt(b+12)-48),nt=(w.charCodeAt(b+14)-48)*10+(w.charCodeAt(b+15)-48),Ct=(w.charCodeAt(b+17)-48)*10+(w.charCodeAt(b+18)-48),gt=0;return w.charCodeAt(b+19)===46&&R>=24&&(gt=(w.charCodeAt(b+20)-48)*100+(w.charCodeAt(b+21)-48)*10+(w.charCodeAt(b+22)-48)),m+at*36e5+nt*6e4+Ct*1e3+gt}let M=new Date(w.slice(b,u)).getTime();return Number.isFinite(M)?M:null}function U(w,b,u,R){let M=w.indexOf(R,b);if(M===-1||M>=u)return 0;let O=M+R.length,q=w.indexOf('"',O);return q===-1||q>=u?0:k(w,O,q)??0}function Q(w,b){let u=b??new TextDecoder().decode(w),R=u.indexOf(""),q=(O!==-1?H(M.slice(O),"",""):null)||H(M,"","")||"Unnamed Track",V=M.indexOf(">",M.indexOf("",W+6);if(F===-1)break;let it=u.indexOf("",F+1);if(it===-1)break;nt=it+8;let K=U(u,W+6,F+1,'lat="'),ht=U(u,W+6,F+1,'lon="'),Pt=null,ut=null,Ht=null,dt=null,Lt=null,st=null,ft=null,At=null,zt=null,z=null,_=null,Ft=null,It=F+1;for(;It=it)break;let bt=u.indexOf(">",Et+1);if(bt===-1||bt>=it)break;let vt=u.charCodeAt(Et+1);if(vt===47){It=bt+1;continue}let Dt=bt-Et-1;if(vt===103&&Dt===26&&Ht!==null&&dt!==null&&st!==null)break;let Wt=u.indexOf("<",bt+1);if(Wt===-1||Wt>it)break;if(u.charCodeAt(Wt+1)===47){let Ot=bt+1,te=Wt;Dt===3?vt===101?Pt=k(u,Ot,te):vt===99&&dt===null&&(dt=p(u,Ot,te)):Dt===2?vt===104&&Ht===null&&(Ht=p(u,Ot,te)):Dt===4?vt===116?u.charCodeAt(Et+2)===105?ut=j(u,Ot,te):st===null&&(st=k(u,Ot,te)):vt===84&&st===null&&(st=k(u,Ot,te)):Dt===5?(vt===112||vt===80||vt===87)&&Lt===null?Lt=k(u,Ot,te):(vt===115||vt===83)&&ft===null?ft=k(u,Ot,te):vt===97&&st===null&&(st=k(u,Ot,te)):Dt===7?(vt===98||vt===66)&&Ft===null?Ft=p(u,Ot,te):vt===67&&dt===null&&(dt=p(u,Ot,te)):Dt===8?(vt===103||vt===71)&&zt===null&&(zt=p(u,Ot,te)):Dt===9?vt===103?u.charCodeAt(Et+8)===104&&Ht===null?Ht=p(u,Ot,te):At===null&&(At=p(u,Ot,te)):vt===71&&At===null&&(At=p(u,Ot,te)):Dt===10?(vt===103&&dt===null||vt===82&&dt===null)&&(dt=p(u,Ot,te)):Dt===12?vt===103&&u.charCodeAt(Et+8)===97&&st===null?st=k(u,Ot,te):vt===80&&Lt===null?Lt=k(u,Ot,te):vt===72&&Ht===null&&(Ht=p(u,Ot,te)):Dt===13?(vt===103||vt===71)&&_===null&&(_=p(u,Ot,te)):Dt===14?(vt===103||vt===71)&&z===null?z=p(u,Ot,te):vt===65&&st===null&&(st=k(u,Ot,te)):Dt===11&&vt===84&&st===null&&(st=k(u,Ot,te));let ye=Wt+2+Dt;if(u.charCodeAt(ye)===62)It=ye+1;else{let Fe=u.indexOf(">",Wt+2);It=Fe!==-1?Fe+1:Wt+2}if(Ft!==null&&Ht!==null&&dt!==null&&st!==null)break}else It=Wt}let Nt=null;z!=null&&_!=null&&_!==0?Nt=z/_:At!=null&&zt!=null&&zt!==0&&(Nt=At/zt),at.push({lat:K,lon:ht,ele:Pt,time:ut,hr:Ht,cad:dt,power:Lt,speed:ft,temp:st,gearFront:At,gearRear:zt,gearFrontTooth:z,gearRearTooth:_,battery:Ft,gears:Nt})}if(!at.length)throw new Error("No track points found in GPX");let Ct=t(at),gt=n(Ct);return{name:q,device:Bt,format:"gpx",points:Ct,stats:gt}}function Y(w,b){let u=b??new TextDecoder().decode(w),R=u.indexOf(""),M=R!==-1?u.slice(0,R):u,O=H(M,"","")||"Unnamed TCX",q=H(M,"",""),V=q?H(q,"",""):null,Bt=[],at=R!==-1?R:0;for(;at",at);if(gt===-1)break;let W=u.indexOf("",gt+12);if(W===-1)break;at=W+13;let F=null,it=null,K=null,ht=null,Pt=null,ut=null,Ht=null,dt=null,Lt=null,st=null,ft=null,At=null,zt=null,z=null,_=gt+12;for(;_=W)break;let Nt=u.indexOf(">",It+1);if(Nt===-1||Nt>=W)break;let Et=u.charCodeAt(It+1);if(Et===47){_=Nt+1;continue}let bt=Nt-It-1,vt=u.indexOf("<",Nt+1);if(vt===-1||vt>W)break;if(u.charCodeAt(vt+1)===47){let Dt=Nt+1,Wt=vt;bt===4?Et===84?u.charCodeAt(It+2)===105?ht=j(u,Dt,Wt):Lt===null&&(Lt=k(u,Dt,Wt)):Et===116&&Lt===null&&(Lt=k(u,Dt,Wt)):bt===5?Et===86&&Pt===null?Pt=p(u,Dt,Wt):(Et===87||Et===80||Et===112)&&Ht===null?Ht=k(u,Dt,Wt):(Et===83||Et===115)&&dt===null?dt=k(u,Dt,Wt):Et===97&&Lt===null&&(Lt=k(u,Dt,Wt)):bt===7?Et===67&&ut===null?ut=p(u,Dt,Wt):(Et===66||Et===98)&&z===null&&(z=p(u,Dt,Wt)):bt===8?(Et===71||Et===103)&&ft===null&&(ft=p(u,Dt,Wt)):bt===9?(Et===71||Et===103)&&st===null&&(st=p(u,Dt,Wt)):bt===10?Et===82&&ut===null&&(ut=p(u,Dt,Wt)):bt===11?Et===84&&Lt===null&&(Lt=k(u,Dt,Wt)):bt===13?(Et===71||Et===103)&&zt===null&&(zt=p(u,Dt,Wt)):bt===14?Et===65?u.charCodeAt(It+2)===108?K=k(u,Dt,Wt):Lt===null&&(Lt=k(u,Dt,Wt)):(Et===71||Et===103)&&At===null&&(At=p(u,Dt,Wt)):bt===15?Et===76&&(F=k(u,Dt,Wt)):bt===16?Et===76&&(it=k(u,Dt,Wt)):bt===2&&Et===104&&Pt===null?Pt=p(u,Dt,Wt):bt===3&&Et===99&&ut===null?ut=p(u,Dt,Wt):bt===12&&(Et===72&&Pt===null?Pt=p(u,Dt,Wt):Et===80&&Ht===null&&(Ht=k(u,Dt,Wt)));let Ot=vt+2+bt;if(u.charCodeAt(Ot)===62)_=Ot+1;else{let te=u.indexOf(">",vt+2);_=te!==-1?te+1:vt+2}if(z!==null&&Pt!==null&&ut!==null&&Lt!==null)break}else _=vt}if(F==null||it==null)continue;let Ft=null;At!=null&&zt!=null&&zt!==0?Ft=At/zt:st!=null&&ft!=null&&ft!==0&&(Ft=st/ft),Bt.push({lat:F,lon:it,ele:K,time:ht,hr:Pt,cad:ut,power:Ht,speed:dt,temp:Lt,gearFront:st,gearRear:ft,gearFrontTooth:At,gearRearTooth:zt,battery:z,gears:Ft})}let nt=t(Bt),Ct=n(nt);return{name:O,device:V,format:"tcx",points:nt,stats:Ct}}function G(w){if(w.byteLength<14)return null;let b=new DataView(w),u=b.getUint8(0);if(u<12||u+2>w.byteLength||b.getUint8(8)!==46||b.getUint8(9)!==70||b.getUint8(10)!==73||b.getUint8(11)!==84)return null;let R=b.getUint32(4,!0),M=Math.min(w.byteLength,u+R),O=631065600,q=180/Math.pow(2,31),V=new Array(16),Bt=[],at=[],nt=[],Ct=[],gt=[],W=u;for(;WM)return null;W++;let ht=b.getUint8(W++)===0,Pt=b.getUint16(W,ht);W+=2;let ut=b.getUint8(W++);if(W+ut*3>M)return null;let Ht=new Array(ut),dt=0;for(let Lt=0;LtM)return null;let ht=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=b.getUint32(W,ht),Lt=b.getInt32(W+4,ht),st=b.getInt32(W+8,ht),ft=b.getUint16(W+12,ht),At=b.getUint8(W+14),zt=b.getUint8(W+15),z=b.getUint32(W+16,ht),_=b.getUint16(W+20,ht),Ft=b.getUint16(W+22,ht),It=b.getInt8(W+24);nt.push({timestamp:(dt+O)*1e3,position_lat:Lt*q,position_long:st*q,altitude:ft/5-500,heart_rate:At,cadence:zt,distance:z/100,speed:_/1e3*3.6,power:Ft,temperature:It}),W+=25;continue}let ut={},Ht=W;for(let dt=0;dt{let R=(q,V)=>{if(q){u(q);return}try{let Bt=V.sessions?.[0]?.start_time?`Fit Activity ${new Date(V.sessions[0].start_time).toISOString().split("T")[0]}`:"Unnamed Fit",at=null,nt=[],Ct=null,gt=null;V.sports?.[0]?(Ct=V.sports[0].sport,gt=V.sports[0].sub_sport):V.sessions?.[0]&&(Ct=V.sessions[0].sport,gt=V.sessions[0].sub_sport);let W=z=>z.product_name||z.garmin_product||z.product||z.device_type||z.manufacturer||null;if(V.file_ids?.[0]){let z=V.file_ids[0];at=W(z),nt.push({name:z.product_name||z.garmin_product||z.product,manufacturer:z.manufacturer,serial:z.serial_number?String(z.serial_number):void 0,version:z.software_version?String(z.software_version):void 0,type:"main"})}V.device_infos&&V.device_infos.forEach(z=>{if(z.device_index==="creator"||z.device_index===0){let Ft=W(z);(z.product_name||z.garmin_product||!at)&&(at=Ft),nt.length>0&&nt[0].type==="main"&&((z.product_name||z.garmin_product||!nt[0].name)&&(nt[0].name=z.product_name||z.garmin_product||z.product),nt[0].manufacturer||(nt[0].manufacturer=z.manufacturer),!nt[0].serial&&z.serial_number&&(nt[0].serial=String(z.serial_number)),!nt[0].version&&z.software_version&&(nt[0].version=String(z.software_version)),!nt[0].hardwareVersion&&z.hardware_version&&(nt[0].hardwareVersion=String(z.hardware_version)));return}nt.push({name:z.product_name||z.garmin_product||z.product||z.device_type||"Sensor",manufacturer:z.manufacturer,serial:z.serial_number?String(z.serial_number):void 0,version:z.software_version?String(z.software_version):void 0,hardwareVersion:z.hardware_version?String(z.hardware_version):void 0,type:z.device_type||"sensor",batteryStatus:z.battery_status,batteryVoltage:z.battery_voltage,batteryLevel:z.battery_level,sourceType:z.source_type!=null?String(z.source_type):void 0})}),V.sensor_settings&&V.sensor_settings.forEach(z=>{let _=z.name||z.product||z.sensor_type;if(!_)return;let Ft=z.ant_id?String(z.ant_id):void 0,It=nt.find(Nt=>Ft&&Nt.serial===Ft||Nt.name===_&&Nt.manufacturer===z.manufacturer);It?(It.name||(It.name=_),It.manufacturer||(It.manufacturer=z.manufacturer),It.type||(It.type=z.sensor_type),It.sourceType||(It.sourceType=z.connection_type!=null?String(z.connection_type):void 0)):nt.push({name:_,manufacturer:z.manufacturer,serial:Ft,type:z.sensor_type||"sensor",sourceType:z.connection_type!=null?String(z.connection_type):void 0})});let F=[];V.device_statuses&&(V.device_statuses.forEach((z,_)=>{z.timestamp&&z.battery_level!=null&&F.push({time:typeof z.timestamp=="number"?z.timestamp:new Date(z.timestamp).getTime(),level:z.battery_level,idx:_})}),F.sort((z,_)=>z.time-_.time||z.idx-_.idx));let it=[];V.events&&(V.events.forEach((z,_)=>{let Ft=z.front_gear_num??z.front_gear??null,It=z.rear_gear_num??z.rear_gear??null,Nt=z.front_gear_num_tooth??null,Et=z.rear_gear_num_tooth??null;if(z.event==="rear_gear_change"||z.event==="front_gear_change"){let bt=z.data;if(bt!=null){let vt=bt>>24&255,Dt=bt>>16&255,Wt=bt>>8&255,Ot=bt&255;Dt!==0&&(Ft=Dt),vt!==0&&(Nt=vt),Ot!==0&&(It=Ot),Wt!==0&&(Et=Wt)}}z.timestamp&&(Ft!=null||It!=null||Nt!=null||Et!=null)&&it.push({time:typeof z.timestamp=="number"?z.timestamp:new Date(z.timestamp).getTime(),front:Ft,rear:It,frontTooth:Nt,rearTooth:Et,idx:_})}),it.sort((z,_)=>z.time-_.time||z.idx-_.idx));let K=V.records||[],ht=null,Pt=0,ut=null,Ht=null,dt=null,Lt=null,st=0,ft=[];for(let z=0;z name, Placemark > name");M&&(R=M.textContent?.trim()||R);let O=u.querySelectorAll("coordinates");if(!O.length)throw new Error("No coordinates found in KML");let q=[];if(O.forEach(at=>{(at.textContent?.trim().split(/\s+/)||[]).forEach(Ct=>{let gt=Ct.split(",");if(gt.length<2)return;let W=parseFloat(gt[0]),F=parseFloat(gt[1]),it=gt.length>2?parseFloat(gt[2]):null;isNaN(F)||isNaN(W)||q.push({lat:F,lon:W,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})})}),!q.length)throw new Error("No valid coordinates in KML");let V=t(q),Bt=n(V);return{name:R,format:"kml",points:V,stats:Bt}}async function ct(w){let b=w.name.split(".").pop()?.toLowerCase(),u=w._buf??await w.arrayBuffer(),R=w._text,M;switch(b){case"gpx":M=Q(u,R);break;case"tcx":M=Y(u,R);break;case"fit":M=await ot(u);break;case"kml":M=_t(u);break;default:throw new Error(`Unsupported format: .${b}`)}return M&&(M.fileName=w.name,M.fileSize=w.size,M.points&&M.stats&&(i(M),M.stats.sections=a(M.points))),M}return{parseFile:ct,computeStats:n,ensureCurvesAndZones:i,analyzeTrackSections:a,findOverlaps:r,calculatePowerCurve:f,calculateHRCurve:y,calculatePowerZones:S,calculateHRZones:v,enrichPoints:t,setHRZones:g,getHRZones:E,setFTP:I,getFTP:B}})();var qt=(()=>{let t={},s=null;function e(G,ot,_t,ct,w){}function n(G){}function i(G){t[G.id]=G}function a(G){G.forEach(ot=>{t[ot.id]=ot})}function r(G){delete t[G]}function d(){t={}}function l(){t={}}function f(G,ot){}function y(G,ot){}function S(){}function I(G){}function B(G,ot){}function v(){}function g(G,ot,_t,ct,w,b){}function E(){}function H(G,ot){}function L(G){}function h(G,ot,_t,ct){}function m(){}function p(){}function k(){return[0,0,0]}function j(G,ot,_t){}function U(G,ot,_t){}function Q(G){}function Y(G,ot){return Object.keys(t)}return{init:e,getMap:()=>null,setCustomClickHandler:G=>{s=G},switchBasemap:n,addTrack:i,addTracks:a,removeTrack:r,clearTracks:d,removeAllTracks:l,setTrackVisible:f,setSelectedTrack:y,fitAll:S,fitTrack:I,showCursorAt:B,hideCursor:v,highlightSegment:g,clearHighlight:E,setTrackHover:H,ensureVisible:L,centerOn:h,closePopup:m,invalidateSize:p,getPosition:k,setPosition:j,colorTrackByMetric:U,clearMetricColor:Q,findTracksPassingThroughPoints:Y,getTrackData:G=>t[G]}})();import Sl from"uplot";var kn=(()=>{function t(){let e=re.getFTP(),n=[.55,.75,.9,1.05,1.2,1.5].map(l=>l*e),i=["Active Recovery","Endurance","Tempo","Threshold","VO2 Max","Anaerobic","Neuromuscular"],a=["#82E0AA","#A8C8A0","#F7DC6F","#F8C471","#F39C12","#E67E22","#C0392B"],r=[],d=0;for(let l=0;ls?t.toFixed(1):Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},speed:{label:"Speed",field:"speed",unit:"km/h",color:Rt.speed.color,abbr:"spd",icon:Rt.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:Rt.gradient.color,abbr:"grad",icon:Rt.gradient.icon,fmt:t=>t.toFixed(1),fmtAxis:t=>t.toFixed(0),smoothSigma:2},power:{label:"Power",field:"power",unit:"W",color:Rt.power.color,abbr:"pwr",icon:Rt.power.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},hr:{label:"Heart Rate",field:"hr",unit:"bpm",color:Rt.hr.color,abbr:"hr",icon:Rt.hr.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},cadence:{label:"Cadence",field:"cad",unit:"rpm",color:Rt.cadence.color,abbr:"cad",icon:Rt.cadence.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},temperature:{label:"Temp",field:"temp",unit:"\xB0C",color:Rt.temperature.color,abbr:"temp",icon:Rt.temperature.icon,fmt:t=>t.toFixed(1),fmtAxis:t=>Math.round(t).toString(),smoothSigma:6},gearRear:{label:"Rear Gear",field:"gearRearTooth",unit:"T",color:Rt.gearRear.color,abbr:"rgr",icon:Rt.gearRear.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},gearFront:{label:"Front Gear",field:"gearFrontTooth",unit:"T",color:Rt.gearFront.color,abbr:"fgr",icon:Rt.gearFront.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},gears:{label:"Gears",field:"gears",unit:"",color:Rt.gears.color,abbr:"gr",icon:Rt.gears.icon,fmt:t=>t.toFixed(2),fmtAxis:t=>t.toFixed(1)},battery:{label:"Battery",field:"battery",unit:"%",color:Rt.battery.color,abbr:"bat",icon:Rt.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]=r/d*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 Tl(t){if(!t)return"question_mark";let s=t.toLowerCase();return Ye[s]?.icon||"exercise"}var St=(()=>{let t=[],s=null,e="time",n="speed",i=null,a=null,r=!1,d=!1,l=new Set(["elevation"]),f=new Set,y=new Set(["speed","gradient","vam","temperature"]),S=new Set(["power"]),I="time",B=null,v=[],g=null,E=null,H=!1,L=!1,h=null,m=null,p=null,k=null,j=null,U=null,Q=null,Y=null,G=null,ot=null,_t=null,ct=null,w=130,b=28,u=20,R=!0,M=null,O=null,q=null,V=null,Bt=null,at=null,nt=null;function Ct(o,c,x,T){G=o,ot=c,_t=x,ct=T,O=document.getElementById("charts-container"),O?.addEventListener("scroll",()=>{p&&j&&k&&Js(p,j,k)}),q=document.getElementById("chart-empty"),V=document.getElementById("chart-stats-sel"),Bt=document.getElementById("btn-reset-selection"),M=document.getElementById("hist-tooltip"),a=Sl.sync("strasse-sync"),document.getElementById("sel-cancel-btn")?.addEventListener("click",_),Bt?.classList.add("hidden");let A=new Set(["w","a","s","d"]),$=new Set;document.addEventListener("keydown",D=>{if(!t.length||!B||["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName||""))return;let P=D.key.toLowerCase();if(!A.has(P))return;D.preventDefault(),$.add(P);let N=t[0].uplot;Q||(Q=[N.scales.x.min,N.scales.x.max]);let[J,Z]=Q,et=(Z-J)*.1,tt=.15,C=J,xt=Z;if(P==="a")C=J-et,xt=Z-et;else if(P==="d")C=J+et,xt=Z+et;else if(P==="w"||P==="s"){let rt=m!==null?m:(J+Z)/2,$t=P==="w"?1-tt:1+tt*1.2;C=rt-(rt-J)*$t,xt=rt+(Z-rt)*$t}let Tt=[t[0].xData[0],t[0].xData[t[0].xData.length-1]];if(CTt[1]){let rt=xt-Tt[1];C-=rt,xt-=rt}C=Math.max(Tt[0],C),xt=Math.min(Tt[1],xt),xt-C>.001&&(Q=[C,xt],gt(C,xt,!0))}),document.addEventListener("keyup",D=>{let P=D.key.toLowerCase();A.has(P)&&$.delete(P)})}function gt(o,c,x=!1){if(!t.length)return;if(!x){t.forEach(({uplot:N})=>N.setScale("x",{min:o,max:c}));return}let T=U?U[0]:t[0].uplot.scales.x.min,A=U?U[1]:t[0].uplot.scales.x.max;Y&&cancelAnimationFrame(Y);let $=(N,J,Z)=>N+(J-N)*Z,D=.25,P=()=>{if(!Q)return;let[N,J]=Q,Z=$(U[0],N,D),X=$(U[1],J,D);t.forEach(({uplot:et})=>{et.setScale("x",{min:Z,max:X})}),Math.abs(Z-N)>1e-4||Math.abs(X-J)>1e-4?Y=requestAnimationFrame(P):Y=null};Y=requestAnimationFrame(P)}function W(o,c=[],x=!1){h=null,g=null,E=null,v=c,f=new Set(Object.entries(Ne).filter(([,T])=>o.points.some(A=>A[T.field]!=null)).map(([T])=>T)),l.size===0&&(l=new Set(["elevation"].filter(T=>f.has(T)))),document.querySelectorAll(".metric-pill").forEach(T=>{let A=T,$=A.dataset.metric,D=f.has($);A.classList.toggle("active",D&&l.has($)),A.classList.toggle("disabled",!D)}),B=o,x?rl(o):bt()}function F(){h=null,g=null,E=null,B=null,Rn(),q&&(q.style.display="flex",q.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 o=document.getElementById("chart-stats");o&&o.classList.add("hidden"),It(),at=null,nt&&nt(null)}function it(){Y!==null&&(cancelAnimationFrame(Y),Y=null),l=new Set(["elevation"]),f=new Set,y=new Set(["speed","gradient","vam","temperature"]),S=new Set(["power"]),I="time",v=[],U=null,Q=null,m=null,p=null,k=null,j=null,R=!0,F(),document.querySelectorAll("#metric-pills .metric-pill").forEach(x=>{let T=x;T.classList.toggle("active",l.has(T.dataset.metric)),T.classList.remove("disabled","overflow-hidden")});let o=document.getElementById("pill-overflow");o&&o.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(o){l.has(o)?l.delete(o):l.add(o),B&&bt(!0)}function ht(o,c,x=!1){let T=y.has(o);c&&!T?(y.add(o),B&&!x&&bt(!0)):!c&&T&&(y.delete(o),B&&!x&&bt(!0))}function Pt(o,c){let x=S.has(o);c&&!x?(S.add(o),B&&bt(!0)):!c&&x&&(S.delete(o),B&&bt(!0))}function ut(o){l=new Set(o),B&&bt(!0),document.querySelectorAll(".metric-pill").forEach(c=>{let x=c;x.classList.toggle("active",l.has(x.dataset.metric))})}function Ht(o){if(I===o||!B){I=o;return}let c=B.points,x=c.find($=>$.time!=null)?.time||0,T=$=>{if($===null)return null;let D=0;if(I==="distance"){let P=$*1e3;D=c.findIndex(N=>(N.dist||0)>=P)}else{let P=x+$*1e3;D=c.findIndex(N=>(N.time||0)>=P)}return D===-1&&(D=c.length-1),o==="distance"?(c[D].dist||0)/1e3:((c[D].time||x)-x)/1e3};g!==null&&(g=T(g)),E!==null&&(E=T(E));let A=null;if(t.length){let $=t[0].uplot,D=T($.scales.x.min),P=T($.scales.x.max);D!==null&&P!==null&&(A=[D,P])}I=o,bt(!0),A&&(r=!0,t.forEach(({uplot:$})=>{$.batch(()=>$.setScale("x",{min:A[0],max:A[1]}))}),r=!1)}function dt(){R=!R,t.forEach(({histCol:o})=>o.classList.toggle("visible",R)),Et()}function Lt(o){nt=o}function st(o,c=!1){at===o||o===null?(at=null,ft(),nt&&nt(null)):(at=o,ft(),At()),B&&!c&&bt(!0)}function ft(){document.querySelectorAll(".map-color-btn").forEach(o=>{let c=o;c.classList.toggle("active",c.dataset.metric===at)})}function At(){if(!nt||!at||!B)return;let o=t.find(x=>x.metricKey===at);if(!o)return;let c=zt(at,o.yData);nt({pts:B.points,colors:c})}function zt(o,c){let x=c.filter(X=>X!=null&&isFinite(X));if(!x.length)return c.map(()=>"#888896");let T=Math.min(...x),A=Math.max(...x),$=B?.sport,D=$?Ye[$.toLowerCase()]:null,P=D?.defaultPreset||"speed",J=jt.get().speed_mode||P,Z=D?.paceUnit||"km";return c.map(X=>{if(X==null||!isFinite(X))return"#888896";if(o==="gradient")return ts(X);if(o==="speed"){if(J==="pace"){let tt=(Z==="km"?1e3:100)/X;return il(tt)}return il(X)}let et=A===T?.5:Math.max(0,Math.min(1,(X-T)/(A-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 z(){_()}function _(){g=null,E=null,h=null,ct&&ct(null),t.forEach(o=>{o.pinnedHistY=null}),Dt(),Fe(),r=!0,t.forEach(({uplot:o,xData:c})=>{o.batch(()=>o.setScale("x",{min:c[0],max:c[c.length-1]})),o._strasse?.updateHeaderStats(c[0],c[c.length-1])}),r=!1,ot&&ot(null,null,I)}function Ft(o){if(!V)return;let c=(x,T)=>{let A=document.querySelector(`#${x} .stat-value`);A&&(A.textContent=T)};c("sel-distance",o.totalDist!=null?`${(o.totalDist/1e3).toFixed(1)} km`:"\u2014"),c("sel-duration",o.duration!=null?he(Math.floor(o.duration/1e3)):"\u2014"),c("sel-elevation",o.elevGain!=null?`${Math.round(o.elevGain)} m`:"\u2014"),c("sel-avg-speed",o.avgSpeed!=null?`${(o.avgSpeed*3.6).toFixed(1)} km/h`:"\u2014"),c("sel-avg-power",o.avgPower!=null?`${o.avgPower} W`:"\u2014"),c("sel-avg-hr",o.avgHR!=null?`${o.avgHR} bpm`:"\u2014"),c("sel-avg-temp",o.avgTemp!=null?`${o.avgTemp.toFixed(1)} \xB0C`:"\u2014"),V.classList.remove("hidden"),Bt&&Bt.classList.remove("hidden")}function It(){V&&V.classList.add("hidden"),Bt&&Bt.classList.add("hidden"),["sel-distance","sel-duration","sel-elevation","sel-avg-speed","sel-avg-power","sel-avg-hr","sel-avg-temp"].forEach(o=>{let c=document.querySelector(`#${o} .stat-value`);c&&(c.textContent="--")})}function Nt(o,c,x=!1){if(!B)return;let T=B.points,A=T.find(J=>J.time!=null)?.time||0,$=((T[T.length-1]?.time||0)-A)/1e3;o>1e12&&(o=(o-A)/1e3),c>1e12&&(c=(c-A)/1e3),o=Math.max(0,Math.min(o,$)),c=Math.max(0,Math.min(c,$));let D=J=>{if(I==="time")return J;let Z=A+J*1e3,X=T.findIndex(et=>(et.time||0)>=Z);return X===-1&&(X=T.length-1),(T[X].dist||0)/1e3},P=D(o),N=D(c);g=P,E=N,U=[P,N],!x&&(r=!0,t.forEach(({uplot:J})=>{J.batch(()=>J.setScale("x",{min:P,max:N}))}),r=!1,Wt(),Fe())}function Et(){if(!t.length||!O)return;let o=Math.round(Math.max(100,O.getBoundingClientRect().width-b-(R?w+u:0))),c=!1;t.forEach(({uplot:x,histCanvas:T,histData:A})=>{o!==x.width&&(x.setSize({width:o,height:x.height}),c=!0,R&&T&&A&&Pe(T,A,x.height))}),c&&Dt()}function bt(o=!1){let c=null,x=0;if(o&&O&&(x=O.scrollTop),o&&U)c=[U[0],U[1]];else if(o&&t.length){let Tt=t[0].uplot;c=[Tt.scales.x.min,Tt.scales.x.max]}if(!B){Rn(o);return}let T=B.points;if(!T.length){Rn(o);return}let A=B?.sport,$=A?Ye[A.toLowerCase()]:null,D=$?.defaultPreset||"speed",N=jt.get().speed_mode||D,J=$?.paceUnit||"km",Z=[...l].filter(Tt=>T.some(rt=>rt[Ne[Tt].field]!=null));if(!Z.length){Rn(o),q&&(q.style.display="flex",q.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=` + `);return}q&&(q.style.display="none");let X=O?O.getBoundingClientRect().width:800,et=Math.round(Math.max(100,X-b-(R?w+u:0))),tt=o&&s===B&&e===I&&n===N&&i===at&&t.length>0,C;if(tt)C=t[0].xData;else if(I==="distance")C=T.map(Tt=>(Tt.dist||0)/1e3);else{let Tt=T.find($t=>$t.time!=null)?.time||0,rt=0;C=T.map($t=>($t.time!=null&&(rt=($t.time-Tt)/1e3),rt))}let xt=new Map;if(tt){M&&(M.style.display="none");let Tt=new Set(Z);for(let rt of t){let $t=y.has(rt.metricKey),pt=S.has(rt.metricKey);Tt.has(rt.metricKey)&&rt.smoothed===$t&&rt.incZero===pt&&rt.w===et?xt.set(rt.metricKey,rt):(a.unsub(rt.uplot),rt.uplot.destroy(),rt.row.remove())}t=[]}else Rn(o);if(O){let Tt=new Array(Z.length).fill(null),rt=null;for(let $t=Z.length-1;$t>=0;$t--){Tt[$t]=rt;let pt=xt.get(Z[$t]);pt&&(rt=pt.row)}Z.forEach(($t,pt)=>{let yt=xt.get($t);if(yt){t.push(yt);let mt=yt.uplot,Kt=mt._strasse,Zt=r;r=!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))}),r=Zt;let Jt=null;if(h!=null&&yt.xData[h]!=null&&yt.yData[h]!=null&&(ye(yt.histData),yt.histData.min!=null&&yt.histData.max!=null)){let ce=yt.histData.max-yt.histData.min||1;Jt=Math.min(yt.histData.BINS-1,Math.floor((yt.yData[h]-yt.histData.min)/ce*yt.histData.BINS)),yt.hoveredHistY=yt.yData[h]}Pe(yt.histCanvas,yt.histData,130,Jt);return}let kt=Ne[$t],Vt=kt.transform,Ut=kt.fmt,ee=kt.fmtAxis,oe=kt.unit,ae=kt.label;$t==="speed"&&N==="pace"&&(ae="Pace",oe=`min/${J}`,Ut=mt=>On(mt),ee=mt=>On(mt),Vt=mt=>mt==null||mt<.1?null:(J==="km"?1e3:100)/mt,kt={...kt,label:ae,unit:oe,fmt:Ut,fmtAxis:ee,transform:Vt});let ie=kt.compute?kt.compute(T,al):al(T.map(mt=>{let Kt=mt[kt.field];return Kt!=null&&Vt?Vt(Kt):Kt}));y.has($t)&&(ie=En(ie,kt.smoothSigma||2)),vt($t,kt,C,ie,et,T,c,Tt[pt])})}s=B,e=I,n=N,i=at,rl(B),g!=null&&E!=null&&Wt(),ft(),at&&At(),o&&O&&x>0&&(O.scrollTop=x)}function vt(o,c,x,T,A,$,D=null,P=null){let N=B?.sport,Z=(N?Ye[N.toLowerCase()]:null)?.defaultPreset||"speed",et=jt.get().speed_mode||Z,tt=o==="elevation"?So($,20):null,C=document.createElement("div");C.className="chart-row",C.dataset.metric=o,C.style.setProperty("--chart-color",c.color);let xt=document.createElement("div");xt.className=`chart-row-header${R?" with-histogram":""}`;let Tt=document.createElement("div");Tt.className="chart-row-label-group",Tt.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=` + `;let rt=document.createElement("button");rt.className=`icon-btn mini smooth-btn${y.has(o)?" active":""}`,rt.title="Toggle data smoothing",rt.innerHTML=`${y.has(o)?"blur_on":"blur_off"}`,rt.addEventListener("click",lt=>{lt.stopPropagation(),y.has(o)?y.delete(o):y.add(o),bt(!0)});let $t=document.createElement("button");$t.className=`map-color-btn icon-btn${at===o?" active":""}`,$t.dataset.metric=o,$t.title="Color map track by this metric",$t.innerHTML='colorize',$t.addEventListener("click",()=>st(o));let pt=null;if(o==="cadence"||o==="power"||o==="speed"){pt=document.createElement("button");let lt=S.has(o);pt.className=`icon-btn mini${lt?" active":""}`,pt.title=lt?"Currently INCLUDING 0 values":"Currently EXCLUDING 0 values",pt.innerHTML=`${lt?"exposure_zero":"mobile_off"}`,pt.addEventListener("click",Mt=>{Mt.stopPropagation(),S.has(o)?S.delete(o):S.add(o),bt(!0)})}let yt=document.createElement("div");yt.className="chart-stats-total";let kt=document.createElement("div");kt.className="chart-stats-selection";let Vt=document.createElement("div");Vt.className="chart-row-stats-container",Vt.append(yt,kt);let Ut=document.createElement("div");Ut.className="chart-row-actions",Ut.append(rt,$t);let ee=document.createElement("div");if(ee.className="chart-row-right-actions",o==="speed"){let lt=document.createElement("div");lt.className="seg-ctrl",lt.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+=` + `,lt.addEventListener("click",Mt=>{let ne=Mt.target.closest(".seg-btn");if(!ne)return;let se=ne.dataset.mode;if(se==="speed"||se==="pace"){let Yt=se===Z;jt.patch({speed_mode:Yt?null:se}),bt(!0)}}),ee.append(lt)}pt&&ee.append(pt),xt.append(Tt,Ut,Vt,ee);let oe=document.createElement("div");oe.className="chart-row-body";let ae=document.createElement("div");ae.style.position="relative",oe.appendChild(ae);let ie=document.createElement("div");ie.className="fixed-x-label fixed-x-min";let mt=document.createElement("div");mt.className="fixed-x-label fixed-x-max",ae.append(ie,mt);let Kt=document.createElement("div");Kt.className=`hist-col${R?" visible":""}`;let Zt=document.createElement("canvas");Zt.className="hist-canvas",Kt.appendChild(Zt),oe.appendChild(Kt),C.append(xt,oe);let Jt=I==="distance";function ce(lt,Mt){if(lt==null)return"";if(Jt){let ne=Mt<1?3:Mt<5?2:Mt<20?1:0;return`${lt.toFixed(ne)} km`}else{let ne=Math.abs(lt),se=Math.floor(ne/3600),Yt=Math.floor(ne%3600/60),Me=Math.round(ne%60),ve=se>0?`${se}:`:"",Oe=se>0?String(Yt).padStart(2,"0"):String(Yt),Be=String(Me).padStart(2,"0");return`${lt<0?"-":""}${ve}${Oe}:${Be}`}}let pe=S.has(o)||o!=="power"&&o!=="cadence"&&o!=="speed",fe=1/0,Qt=-1/0,de=0,Te=0,De=1/0,Je=-1/0,Le=0,ln=0;for(let lt=0;ltQt&&(Qt=Mt),de+=Mt,Te++,(Mt!==0||pe)&&(MtJe&&(Je=Mt),Le+=Mt,ln++))}Te===0&&(fe=0,Qt=100);let Ps=Te?{min:fe,max:Qt,avg:de/Te}:null,ss=ln?{min:De,max:Je,avg:Le/ln}:null,ul=Math.abs(Qt-fe)*.1||1,ko=[fe-ul,Qt+ul],ml=!1;function Ls(lt,Mt,ne){let se=S.has(o)||o!=="power"&&o!=="cadence"&&o!=="speed",Yt=Mt-lt;ie.textContent=ce(lt,Yt),mt.textContent=ce(Mt,Yt);let Me=(ve,Oe,Be=!1)=>{let Re=Be&&se===pe?ss:tl(x,T,ve,Oe,se);if(!Re)return"";let an=` + align_flex_end${c.fmt(Re.min,!0)} ${c.unit} + align_center${c.fmt(Re.avg,!0)} ${c.unit} + align_flex_start${c.fmt(Re.max,!0)} ${c.unit} + `;if(o==="elevation"){let Ge=bo($,ve,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 an};ml||(ml=!0,yt.innerHTML=`all_inclusive${Me(x[0],x[x.length-1],!0)}`,yt.querySelector(".all-chip")?.addEventListener("click",ve=>{ve.stopPropagation(),_()})),g!==null&&E!==null?(kt.innerHTML=Me(g,E,!1),kt.style.display="flex",kt.style.setProperty("--sel-color",c.color)):kt.style.display="none"}let $o=!1,Co={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:o==="elevation"?(lt,Mt)=>ts(tt?tt[lt.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:(lt,Mt,ne)=>[Mt,ne],min:D?D[0]:void 0,max:D?D[1]:void 0},y:{range:()=>ko,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:(lt,Mt,ne,se)=>{let Yt=se-ne,ve=(lt.bbox.width>0?lt.bbox.width:lt.width)/80,Oe=Yt/ve,Be;Jt?Be=[.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]:Be=[1,2,5,10,15,30,60,120,300,600,900,1800,3600,7200,14400,28800,43200,86400,604800,2592e3,31536e3];let Re=Be[Be.length-1];for(let Ze=0;Ze=Oe){Re=Be[Ze];break}let an=[],Ge=Math.ceil(ne/Re)*Re,ms=Re<1?2:0;for(;Ge<=se;){let Ze=lt.valToPos(Ge,"x",!0);Ze>=lt.bbox.left+80&&Ze<=lt.bbox.left+lt.bbox.width-80&&an.push(Number(Ge.toFixed(ms))),Ge+=Re}return an},values:(lt,Mt)=>{let ne=(lt.scales.x?.max??1)-(lt.scales.x?.min??0);return Mt.map(se=>{if(se==null)return"";let Yt=lt.valToPos(se,"x",!0);return Ytlt.bbox.left+lt.bbox.width-80?null:ce(se,ne)})}},{side:3,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{stroke:"#2e2e34"},size:55,font:"10px system-ui, sans-serif",values:(lt,Mt)=>Mt.map(ne=>ne!=null?c.fmtAxis(ne):"")}],series:[{},{label:c.label,stroke:"rgba(0,0,0,0)",width:0,points:{show:!1},paths:()=>null}],hooks:{draw:[lt=>{let Mt=lt.bbox.top+lt.bbox.height+5;ie.style.top=`${Mt}px`,ie.style.left=`${lt.bbox.left}px`,mt.style.top=`${Mt}px`,mt.style.left=`${lt.bbox.left+lt.bbox.width}px`,mt.style.transform="translateX(-100%)"},lt=>{o==="gears"?dl(lt,x,T,c.color,1.5,o,null,$):o==="elevation"?vo(lt,x,T,tt):o==="gradient"?yo(lt,x,T):at===o?Eo(lt,x,T,$,o):dl(lt,x,T,c.color,1.5,o,null,$)},lt=>{let Mt=t.find(se=>se.uplot===lt);if(!Mt)return;let ne=lt._strasse;h!=null?xo(lt,x,T,c.color,c,$,o):(ne&&ne.pinYVal&&(ne.pinYVal.style.display="none"),Mt.pinnedHistY!=null&&wo(lt,x,T,Mt.pinnedHistY,c.color,c))},lt=>{let Mt=lt.cursor.idx,ne=h!=null,se=Mt!=null&<.cursor.left>=0;if(se&&h==null){let Yt=lt.valToPos(T[Mt],"y",!0);Math.abs(lt.cursor.top-Yt)>100&&(se=!1)}if(se&&Mt!==h&&ll(lt,$,Mt,le(c.color,.4),1),g!=null&&E!=null){let Yt=lt.ctx,Me=window.devicePixelRatio||1,ve=lt.bbox,Oe=lt.valToPos(g,"x",!0),Be=lt.valToPos(E,"x",!0);Yt.save(),Yt.beginPath(),Yt.lineWidth=3*Me,Yt.strokeStyle=c.color,Yt.moveTo(Oe,ve.top+ve.height),Yt.lineTo(Be,ve.top+ve.height),Yt.stroke();let Re=Math.abs(E-g),an=I==="distance"?`${Re.toFixed(2)} km`:he(Re),Ge=9*Me,ms=`bold ${Ge}px system-ui, sans-serif`;Yt.font!==ms&&(Yt.font=ms);let Ze=Yt.measureText(an).width,fl=Math.max(ve.left,Oe),gl=Math.min(ve.left+ve.width,Be);if(gl-fl>Ze+14*Me){let Lo=5*Me,Ao=2*Me,ps=Ze+Lo*2,fs=Ge+Ao*2,Is=(fl+gl)/2-ps/2,Hs=ve.top+ve.height-fs/2;Yt.beginPath(),Yt.roundRect?Yt.roundRect(Is,Hs,ps,fs,3*Me):Yt.rect(Is,Hs,ps,fs),Yt.fillStyle=c.color,Yt.fill(),Yt.fillStyle="#000",Yt.textAlign="center",Yt.textBaseline="middle",Yt.fillText(an,Is+ps/2,Hs+fs/2)}Yt.restore()}ne&&ol(lt,$,h,c.color,!0,.7),se&&Mt!==h&&ol(lt,$,Mt,c.color,!0,1)}],setCursor:[lt=>{if(r)return;let Mt=lt.cursor.idx;lt.redraw(!1),lt.cursor.left>=0?m=lt.posToVal(lt.cursor.left,"x"):m=null;let ne=lt._strasse,se=Mt!=null&&T[Mt]!=null;if(se&&h==null){let Yt=lt.valToPos(T[Mt],"y",!0);Math.abs(lt.cursor.top-Yt)>100&&(se=!1)}if(ne&&(se?el(lt,ne.curYVal,Mt,x,T,$,c,o):ne.curYVal.style.display="none"),d||(Mt!=null&&$[Mt]?G&&(h!=null||se)?G($[Mt]):G&&!se&&G(null):Mt===null&&G&&G(null)),Mt!=null&&T[Mt]!=null){let{min:Yt,max:Me}=Se;if(Yt!=null&&Me!=null){let ve=Me-Yt||1,Oe=Math.min(Se.BINS-1,Math.floor((T[Mt]-Yt)/ve*Se.BINS));on.hoveredHistY!==T[Mt]&&(on.hoveredHistY=T[Mt],Pe(Zt,Se,130,Oe))}}else on.hoveredHistY!==null&&(on.hoveredHistY=null,Pe(Zt,Se,130))}],setScale:[(lt,Mt)=>{if(Mt!=="x"||$o)return;let{min:ne,max:se}=lt.scales.x;U=[ne,se],Ls(ne,se,lt),!r&&(L||(Q=null),r=!0,t.forEach(({uplot:Yt})=>{Yt!==lt&&Yt.batch(()=>Yt.setScale("x",{min:ne,max:se}))}),r=!1,Dt(),Fe(),ot&&g!==null&&ot(g,E,I))}],setSelect:[lt=>{if(L)return;Q=null;let{left:Mt,width:ne}=lt.select;if(ne>0){let se=lt.posToVal(Mt,"x"),Yt=lt.posToVal(Mt+ne,"x");g=se,E=Yt,Ls(lt.scales.x.min,lt.scales.x.max,lt),Dt(),Fe(),ot&&ot(g,E,I),lt.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 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 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:${c.color};display:none`;let ds=document.createElement("div");ds.className="cur-y-val pin",ds.style.cssText=`color:${c.color};display:none`,As.append(ls,os,is,qn,zn,as,rs,Un,Vn,cs,ds);let Se={yData:T,xData:x,def:c,BINS:24,min:Te?fe:void 0,max:Te?Qt:void 0,fullStats:ss,fullStatsAll:Ps},on={uplot:null,row:C,xData:x,yData:T,def:c,metricKey:o,statsTotalEl:yt,statsSelEl:kt,histCol:Kt,histCanvas:Zt,histData:Se,hoveredHistY:null,pinnedHistY:null,smoothed:y.has(o),incZero:S.has(o),w:A};Se.plot=on;let Po=r;r=!0;let tn=new Sl(Co,[x,T],(lt,Mt)=>{on.uplot=lt,t.push(on),ae.appendChild(lt.root),lt.over.appendChild(As),lt._strasse={selFill:ls,anchorLine:os,anchorLabel:is,anchorHandle:qn,anchorMarker:zn,endLine:as,endLabel:rs,endHandle:Un,endMarker:Vn,curYVal:cs,pinYVal:ds,updateHeaderStats:Ls},lt.batch(()=>{Mt()})});r=Po,te(qn,tn,x,!0),te(Un,tn,x,!1);let us=null;tn.over.addEventListener("mousedown",lt=>{if(lt.button!==0)return;H=!1;let Mt=tn.over.getBoundingClientRect();us=lt.clientX-Mt.left}),tn.over.addEventListener("mousemove",lt=>{if(us!==null){let Mt=tn.over.getBoundingClientRect();Math.abs(lt.clientX-Mt.left-us)>5&&(H=!0)}}),tn.over.addEventListener("mouseup",()=>{us=null}),tn.over.addEventListener("click",()=>{if(H)return;let lt=tn.cursor.idx;lt!=null&&$[lt]&&(h=lt,t.forEach(({uplot:Mt})=>Mt.redraw(!1)),_t&&_t($[lt],lt),ct&&ct(lt))}),C.addEventListener("dblclick",_);let pl=null;if(h!=null&&x[h]!=null&&T[h]!=null&&(ye(Se),Se.min!=null&&Se.max!=null)){let lt=Se.max-Se.min||1;pl=Math.min(Se.BINS-1,Math.floor((T[h]-Se.min)/lt*Se.BINS)),on.hoveredHistY=T[h]}Pe(Zt,Se,130,pl),_n(Zt,Se),O&&(P?O.insertBefore(C,P):O.appendChild(C))}function Dt(){Wt(),t.forEach(({uplot:o})=>o.batch(()=>o.redraw(!1)))}function Wt(){t.forEach(({uplot:o,def:c})=>{let x=o._strasse;if(!x)return;let{selFill:T,anchorLine:A,anchorLabel:$,anchorHandle:D,anchorMarker:P,endLine:N,endLabel:J,endHandle:Z,endMarker:X}=x;if(g==null||E==null){[T,A,$,D,P,N,J,Z,X].forEach(Ut=>{Ut.style.display="none"});return}let et=o.valToPos(g,"x"),tt=o.valToPos(E,"x"),C=window.devicePixelRatio||1,xt=o.bbox,Tt=xt.width/C,rt=xt.height/C,$t=(xt.top+xt.height)/C,pt=et>=0&&et<=Tt,yt=tt>=0&&tt<=Tt,kt=Math.max(0,et),Vt=Math.min(Tt,tt);if(Vt>kt?(T.style.left=`${kt}px`,T.style.width=`${Vt-kt}px`,T.style.top="0",T.style.height=`${rt}px`,T.style.backgroundColor=le(c.color,.07),T.style.display=""):T.style.display="none",pt){A.style.left=`${et}px`,A.style.height=`${rt}px`,A.style.borderLeftColor=c.color,A.style.display="";let Ut=Ot(g);$.textContent=Ut;let ee=Ut.length*7+10;$.style.left=et+ee+4Ut.style.display="none");if(yt){N.style.left=`${tt}px`,N.style.height=`${rt}px`,N.style.borderLeftColor=c.color,N.style.display="";let Ut=Ot(E);J.textContent=Ut;let ee=Ut.length*7+10;J.style.left=tt-ee-3>0?`${tt-ee-3}px`:`${tt+3}px`,J.style.display="",Z.style.left=`${tt}px`,Z.style.backgroundColor=c.color,Z.style.display="",X.style.left=`${tt}px`,X.style.top=`${$t}px`;let oe=X.querySelector(".material-symbols-rounded");oe&&(oe.style.color=c.color),X.style.display=""}else[N,J,Z,X].forEach(Ut=>Ut.style.display="none")})}function Ot(o){return I==="distance"?`${o.toFixed(2)} km`:he(o)}function te(o,c,x,T){o.style.pointerEvents="auto",o.addEventListener("mousedown",A=>{A.stopPropagation(),A.preventDefault();let $=A.clientX,D=T?g:E,P=c.over.offsetWidth,N=c.scales.x.min,J=c.scales.x.max,Z=P/(J-N),X=[x[0],x[x.length-1]];document.body.style.cursor="ew-resize",H=!0;function et(C){let xt=C.clientX-$,Tt=(D||0)+xt/Z;Tt=Math.max(X[0],Math.min(X[1],Tt)),T?g=Math.min(Tt,(E||X[1])-.001):E=Math.max(Tt,(g||X[0])+.001),t.forEach(rt=>rt.uplot._strasse?.updateHeaderStats(rt.uplot.scales.x.min,rt.uplot.scales.x.max)),Dt(),Fe(),ot&&ot(g,E,I)}function tt(){document.body.style.cursor="",H=!1,document.removeEventListener("mousemove",et),document.removeEventListener("mouseup",tt)}document.addEventListener("mousemove",et),document.addEventListener("mouseup",tt)})}function ye(o){let{yData:c,xData:x,BINS:T}=o;if(o._lastYData===c&&o.bins)return;o._lastYData=c;let A=o.min,$=o.max;if(A==null||$==null){let X=1/0,et=-1/0,tt=0;for(let C=0;Cet&&(et=xt),tt++)}if(!tt)return;A=X,$=et,o.min=A,o.max=$}let D=new Array(T).fill(0),P=new Array(T).fill(0),N=$-A||1,J=o.plot?.metricKey??Object.keys(Ne).find(X=>Ne[X]===o.def),Z=!J||S.has(J)||J!=="power"&&J!=="cadence"&&J!=="speed";for(let X=0;X0&&x[X-1]!=null?x[X-1]:x[X],xt=X{Pe(o,c,x.height)})}function Pe(o,c,x,T=null){let{def:A,BINS:$}=c;ye(c);let{bins:D,min:P,max:N}=c;if(!D||P==null||N==null)return;let J=g!=null&&E!=null;if(J&&(c._lastSelRange?.[0]!==g||c._lastSelRange?.[1]!==E)){c._lastSelRange=[g,E];let mt=new Array($).fill(0),Kt=new Array($).fill(0),{yData:Zt,xData:Jt}=c,ce=N-P||1,pe=c.plot?.metricKey??Object.keys(Ne).find(Qt=>Ne[Qt]===c.def),fe=!pe||S.has(pe)||pe!=="power"&&pe!=="cadence"&&pe!=="speed";for(let Qt=0;QtE)continue;let De=Math.min($-1,Math.floor((de-P)/ce*$));mt[De]++;let Je=Qt>0&&Jt[Qt-1]!=null?Jt[Qt-1]:Jt[Qt],Le=QtA.fmtAxis(mt),rt="9px system-ui, sans-serif";C.font!==rt&&(C.font=rt);let pt={t:4,r:0,b:30,l:Math.ceil(Math.max(C.measureText(`${Tt(N)} ${A.unit}`).width,C.measureText(`${Tt(P)} ${A.unit}`).width))+6};c.padL=pt.l;let yt=et-pt.l-pt.r,kt=tt-pt.t-pt.b,Vt=mt=>pt.t+($-1-mt)*(kt/$),Ut=kt/$-1,ee=J?.15:.6;C.fillStyle=le(A.color,ee);for(let mt=0;mt<$;mt++){if(!D[mt])continue;let Kt=D[mt]/xt*yt;C.fillRect(pt.l,Vt(mt),Kt,Ut)}if(Z){C.fillStyle=le(A.color,.85);for(let mt=0;mt<$;mt++){if(!Z[mt])continue;let Kt=Z[mt]/xt*yt;C.fillRect(pt.l,Vt(mt),Kt,Ut)}C.fillStyle=A.color,C.fillRect(pt.l,pt.t,2,kt)}let oe=D.reduce((mt,Kt)=>mt+Kt,0);if(oe>0){let mt=[{x:pt.l,y:pt.t+kt}],Kt=0;for(let Zt=0;Zt<$;Zt++)Kt+=D[Zt],mt.push({x:pt.l+Kt/oe*yt,y:Vt(Zt)});C.beginPath(),C.setLineDash([]),C.strokeStyle=A.color,C.lineWidth=.75*X,C.lineJoin="round",C.moveTo(mt[0].x,mt[0].y);for(let Zt=1;ZtZt+Jt+2&&mt0){let mt=0;for(let de=0;de{let A=Ks(o,c,T);if(A!=null&&x){let{min:$,max:D,BINS:P}=c,N=D-$||1;x.pinnedHistY=$+(A+.5)*(N/P),t.forEach(({uplot:J})=>J.redraw(!1))}}),o.addEventListener("mousemove",T=>{p=T,Js(T,o,c)}),o.addEventListener("mouseenter",()=>{j=o,k=c}),o.addEventListener("mouseleave",()=>{j===o&&(j=null,k=null),M&&(M.style.display="none");let T=document.getElementById("hist-line");T&&(T.style.display="none"),x&&(x.hoveredHistY=null,Pe(o,c,o.height/(window.devicePixelRatio||1)))})}function Ks(o,c,x){let{bins:T,BINS:A}=c;if(!T)return null;let $=o.getBoundingClientRect(),D=x.clientY-$.top,P={t:4,b:30},N=$.height-P.t-P.b,J=Math.floor((D-P.t)/N*A),Z=A-1-J;return J<0||J>=A?null:Z}function Js(o,c,x){if(!M)return;let{bins:T,binAccum:A,min:$,max:D,BINS:P,def:N,plot:J}=x;if(!T||!A||$==null||D==null)return;let Z=document.getElementById("hist-line"),X=Ks(c,x,o);if(X==null||!T[X]){M.style.display="none",Z&&(Z.style.display="none"),J&&(J.hoveredHistY=null,Pe(c,x,c.height/(window.devicePixelRatio||1)));return}if(J){let Jt=D-$||1;J.hoveredHistY=$+(X+.5)*(Jt/P),Pe(c,x,c.height/(window.devicePixelRatio||1),X)}let et=T[X],tt=T.reduce((Jt,ce)=>Jt+ce,0),C=et/tt*100,xt=D-$||1,Tt=$+X*(xt/P),rt=$+(X+1)*(xt/P),$t=`${N.fmt(Tt,!0)} \u2013 ${N.fmt(rt,!0)} ${N.unit}`,pt="",yt=(Tt+rt)/2,kt=Object.keys(Ne).find(Jt=>Ne[Jt]===N),Vt=[];if(kt==="power"?Vt=kn.getPowerZones():kt==="hr"&&(Vt=kn.getHRZones()),Vt.length>0){let Jt=Vt.findIndex(pe=>yt>=pe.min&&yt=Vt[Vt.length-1].min?Vt[Vt.length-1]:null;if(ce){let pe=Jt!==-1?Jt:Vt.length-1;pt=` +
+ Z${pe+1} \xB7 - ${de.name} + ${ce.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}
+ `}}let Ut=I==="distance"?`${A[X].toFixed(2)} km`:he(A[X]),ee=A[X]/A.reduce((Jt,ce)=>Jt+ce,0)*100,oe=` +
${$t}
${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+=` + `;if(Ut&&(oe+=`
+ ${I==="distance"?"Dist":"Time"} + ${Ut} + ${ee.toFixed(1)}% +
`),x.selBins&&x.selBinAccum){let Jt=I==="distance"?`${x.selBinAccum[X].toFixed(2)} km`:he(x.selBinAccum[X]),ce=x.selBinAccum[X]/x.selBinAccum.reduce((pe,fe)=>pe+fe,0)*100;oe+=`
- Sel ${F==="distance"?"Dist":"Time"} - ${te} - ${de.toFixed(1)}% + Sel ${I==="distance"?"Dist":"Time"} + ${Jt} + ${ce.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=` + `}M.innerHTML=oe,M.style.display="block";let ae=M.offsetHeight,ie=M.offsetWidth,mt=c.getBoundingClientRect(),Kt=mt.height-4-30,Zt=mt.top+4+(P-1-X+.5)*(Kt/P);M.style.left=`${mt.left-ie-12}px`,M.style.top=`${Zt-ae/2}px`,Z&&(Z.style.display="block",Z.style.top=`${Zt}px`,Z.style.left="0px",Z.style.width=`${mt.left}px`)}function Rn(o=!1){M&&(M.style.display="none"),t.forEach(({uplot:c,row:x})=>{a.unsub(c),c.destroy(),x.remove()}),t=[],s=null,o||(g=null,E=null),H=!1}function tl(o,c,x,T,A=!0){let $=1/0,D=-1/0,P=0,N=0;for(let J=0;JT)continue;let Z=c[J];Z==null||!isFinite(Z)||Z===0&&!A||(Z<$&&($=Z),Z>D&&(D=Z),P+=Z,N++)}return N?{min:$,max:D,avg:P/N}:null}function bo(o,c,x){let T=0,A=0,$=null,D=I==="distance",P=o[0].time||0;for(let N=0;Nx)&&J.ele!=null){if($!=null){let X=J.ele-$;X>0?T+=X:X<0&&(A+=Math.abs(X))}$=J.ele}}return{gain:T,loss:A}}function el(o,c,x,T,A,$,D,P){if(x==null||A[x]==null){c.style.display="none";return}let N=o.valToPos(T[x],"x",!1),J=o.valToPos(A[x],"y",!1),Z="#888896",X=0;if(x>0&&$[x]&&$[x-1]){let rt=$[x-1],$t=$[x],pt=($t.dist||0)-(rt.dist||0);pt>.1&&$t.ele!=null&&rt.ele!=null&&(X=($t.ele-rt.ele)/pt*100,Z=ts(X))}let et=P!=="elevation"?`${D.fmt(A[x],!1)} ${D.unit}`:`${D.fmt(A[x],!1)} ${D.unit} \u2220 ${Math.abs(X).toFixed(1)}%`;if(P==="gearRear"&&$[x].gearRearTooth!=null)et=`${$[x].gearRearTooth}T (pos ${A[x]})`;else if(P==="gearFront"&&$[x].gearFrontTooth!=null)et=`${$[x].gearFrontTooth}T (pos ${A[x]})`;else if(P==="gears"){let rt=$[x],$t=rt.gearFrontTooth!=null?`${rt.gearFrontTooth}T`:rt.gearFront!=null?`pos ${rt.gearFront}`:"",pt=rt.gearRearTooth!=null?`${rt.gearRearTooth}T`:rt.gearRear!=null?`pos ${rt.gearRear}`:"";($t||pt)&&(et+=` (${$t} / ${pt})`)}c.innerHTML!==et&&(c.innerHTML=et);let tt=`${D.color}44`;c.style.color!==D.color&&(c.style.color=D.color),c.style.borderColor!==tt&&(c.style.borderColor=tt);let C=`${N}px`,xt=`${J}px`,Tt="translate(6px, -50%)";c.style.left!==C&&(c.style.left=C),c.style.top!==xt&&(c.style.top=xt),c.style.transform!==Tt&&(c.style.transform=Tt),c.style.display!==""&&(c.style.display="")}let nl=new Map;function sl(o){let c=nl.get(o);return c||(c=le(ts(o),.8),nl.set(o,c)),c}function vo(o,c,x,T){let A=o.ctx,$=o.bbox,D=window.devicePixelRatio||1,P=o.scales.x?.min??-1/0,N=o.scales.x?.max??1/0,J=o.scales.y?.min??0,Z=o.scales.y?.max??100,X=$.width/(N-P||1),et=$.height/(Z-J||1),tt=$.top+$.height,C=o.series[0]?.idxs,xt=C?Math.max(1,C[0]):1,Tt=C?Math.min(c.length-1,C[1]+1):c.length-1,rt=Math.max(1,Math.floor((Tt-xt)/250));A.save(),A.lineWidth=1.5*D;let $t=new Map,pt=xt-1;for(let yt=xt;yt<=Tt;yt+=rt){let kt=c[yt],Vt=c[pt];if(pt=yt,kt==null||x[yt]==null||Vt==null||x[yt-rt]==null||ktN)continue;let Ut=$.left+(Vt-P)*X,ee=tt-(x[yt-rt]-J)*et,oe=$.left+(kt-P)*X,ae=tt-(x[yt]-J)*et,ie=T&&T[yt]!=null?Math.round(T[yt]/2)*2:null,mt=sl(ie),Kt=$t.get(mt);Kt||(Kt=[],$t.set(mt,Kt)),Kt.push(Ut,ee,oe,ae)}for(let[yt,kt]of $t){A.beginPath(),A.strokeStyle=yt;for(let Vt=0;VtP)continue;let Vt=A.left+(kt-D)*Z,Ut=et-(x[pt-Tt]-N)*X,ee=A.left+(yt-D)*Z,oe=et-(x[pt]-N)*X,ae=Math.round(x[pt]/2)*2,ie=sl(ae),mt=rt.get(ie);mt||(mt=[],rt.set(ie,mt)),mt.push(Vt,Ut,ee,oe)}for(let[pt,yt]of rt){T.beginPath(),T.strokeStyle=pt;for(let kt=0;kt{let kt=`bold ${10*D}px system-ui, sans-serif`;N.font!==kt&&(N.font=kt);let Ut=N.measureText(rt).width+10*D,ee=16*D,oe=$t-Ut/2,ae=Math.max(P.left,Math.min(P.left+P.width-Ut,oe)),ie=pt-ee/2;N.save(),N.globalAlpha=$,N.setLineDash([]),N.beginPath(),N.roundRect?N.roundRect(ae,ie,Ut,ee,3*D):N.rect(ae,ie,Ut,ee),N.fillStyle="rgba(14,14,16,0.92)",N.fill(),N.strokeStyle=le(T,.27),N.lineWidth=1*D,N.stroke(),N.fillStyle=T,N.textAlign="center",N.textBaseline="middle",N.fillText(rt,ae+Ut/2,ie+ee/2+.5*D),N.restore()};A||ll(o,c,x,T,$);let Tt=16*D;xt(C,et,P.top+Tt/2,!0),xt(tt,et,P.top+P.height+15*D,!1)}function xo(o,c,x,T,A,$,D){if(h==null)return;let P=c[h],N=x[h];if(P==null||N==null)return;let J=o.valToPos(P,"x",!0),Z=o.valToPos(N,"y",!0),X=o.bbox,et=o.ctx,tt=window.devicePixelRatio||1;et.save(),et.beginPath(),et.strokeStyle=T,et.lineWidth=1.5*tt,et.moveTo(J,X.top),et.lineTo(J,X.top+X.height),et.stroke(),et.beginPath(),et.setLineDash([3*tt,3*tt]),et.strokeStyle=le(T,.5),et.lineWidth=1*tt,et.moveTo(X.left,Z),et.lineTo(J,Z),et.stroke(),et.beginPath(),et.setLineDash([]),et.arc(J,Z,5*tt,0,Math.PI*2),et.fillStyle="#0e0e10",et.fill(),et.strokeStyle=T,et.lineWidth=2.5*tt,et.stroke(),et.restore();let C=o._strasse;C&&C.pinYVal&&el(o,C.pinYVal,h,c,x,$,A,D)}function wo(o,c,x,T,A,$){let D=o.bbox,P=o.ctx,N=window.devicePixelRatio||1,J=o.valToPos(T,"y",!0),Z=Math.max(D.top,Math.min(D.top+D.height,J));P.save(),P.beginPath(),P.setLineDash([4*N,4*N]),P.strokeStyle=le(A,.4),P.lineWidth=1*N,P.moveTo(D.left,Z),P.lineTo(D.left+D.width,Z),P.stroke(),To(o,c,x,Z,A);let X=$.fmt(T,!0),et=`bold ${10*N}px system-ui, sans-serif`;P.font!==et&&(P.font=et);let C=P.measureText(X).width+8*N,xt=16*N,Tt=D.left-C-2*N,rt=Z-xt/2;P.beginPath(),P.setLineDash([]),P.roundRect?P.roundRect(Tt,rt,C,xt,3*N):P.rect(Tt,rt,C,xt),P.fillStyle="rgba(14,14,16,0.95)",P.fill(),P.strokeStyle=A,P.lineWidth=1*N,P.stroke(),P.fillStyle="#fff",P.textAlign="center",P.textBaseline="middle",P.fillText(X,Tt+C/2,rt+xt/2+.5*N),P.restore()}function To(o,c,x,T,A){let $=o.ctx,D=o.bbox,P=o.scales.x?.min??-1/0,N=o.scales.x?.max??1/0,J=o.scales.y?.min??0,Z=o.scales.y?.max??100,X=D.width/(N-P||1),et=D.height/(Z-J||1),tt=o.scales.y?.dir??1,C=tt===-1?D.top:D.top+D.height,xt=tt===-1?et:-et,Tt=o.series[0]?.idxs,rt=Tt?Math.max(0,Tt[0]-1):0,$t=Tt?Math.min(c.length-1,Tt[1]+1):c.length-1,pt=Math.max(1,Math.floor(($t-rt)/250));$.save(),$.beginPath(),$.rect(D.left,D.top,D.width,D.height),$.clip(),$.fillStyle=le(A,.2),$.beginPath();let yt=!1,kt=!1,Vt=0;for(let Ut=rt;Ut<=$t;Ut+=pt){let ee=c[Ut],oe=x[Ut];if(ee==null||oe==null||eeN){yt&&($.lineTo(Vt,T),$.closePath(),yt=!1);continue}let ae=D.left+(ee-P)*X,ie=C+(oe-J)*xt;Vt=ae,ie>16,D=T>>8&255,P=T&255,N=A>>16,J=A>>8&255,Z=A&255,X=$+(N-$)*x,et=D+(J-D)*x,tt=P+(Z-P)*x;return`#${((1<<24)+(Math.round(X)<<16)+(Math.round(et)<<8)+Math.round(tt)).toString(16).slice(1)}`}function ts(o){if(o==null)return"#888896";let c=Math.abs(o),x=Math.min(1,c/8);return o>0?Ve("#A8C8A0","#d73027",x):Ve("#A8C8A0","#4575b4",x)}function il(o){if(o==null)return"#888896";let c=o*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 So(o,c){let x=new Array(o.length).fill(null);for(let T=0;T0&&(A.dist||0)-(o[$].dist||0)1&&o[D].ele!=null&&o[$].ele!=null&&(x[T]=(o[D].ele-o[$].ele)/P*100)}return x}function al(o){let c=[...o];for(let x=0;x=0&&c[T]===null;)T--;let A=x+1;for(;A=0&&A=0?c[x]=c[T]:A{let J=document.querySelector(`#${P} .stat-value`);J&&(J.textContent=N)};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 T=P=>{let N=t.find(X=>X.metricKey===P);if(!N)return P==="speed"?c.avgSpeed??null:P==="power"?c.avgPower??null:P==="cadence"?c.avgCadence??null:null;if(N.histData.fullStats!==void 0)return N.histData.fullStats?N.histData.fullStats.avg:null;let J=S.has(P)||P!=="power"&&P!=="cadence"&&P!=="speed",Z=N.yData.filter(X=>X!=null&&(J||X!==0));return Z.length?Z.reduce((X,et)=>X+et,0)/Z.length:null},A=T("speed");x("stat-avg-speed",A!=null?`${(A*3.6).toFixed(1)} km/h`:"\u2014");let $=T("power");x("stat-avg-power",$!=null?`${Math.round($)} W`:"\u2014");let D=T("cadence");x("stat-avg-cad",D!=null?`${Math.round(D)} 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),Mn=new Float64Array(yn),es=new Float64Array(yn),Nn=new Float64Array(yn),Cs=new Float64Array(yn),ns=new Float64Array(yn),Wn=new Float64Array(64),cl=[3,5,8,10,12,15,20,25,30,40,45,60,75,90,120,150,180,240,300,360];function Mo(o,c,x){if(!o.length)return 0;Wn.fill(0);let T=0;for(let A=0;A=Tt)continue;let pt=1/$t,yt=0,kt=0,Vt=0;for(let Ut=C;Ut=$t){yt-=ns[Ut-$t],kt-=Nn[Ut-$t];let ee=(yt+kt*.05)*pt;ee>Vt&&(Vt=ee)}T+=Vt*1e-4}for(let rt=C;rt0&&(Wn[$t-1]+=.5),$t<63&&(Wn[$t+1]+=.5)}}}}for(let A=0;A<64;A++)T+=Wn[A]*1e-5;return O&&(O.dataset.intervalScore=T.toFixed(2)),T}return{init:Ct,loadTrack:W,clear:F,resetState:it,toggleMetric:K,setXAxis:Ht,toggleStats:dt,setSelectionStats:Ft,clearSelectionStats:It,restoreSelection:Nt,resetZoom:z,cancelSelection:_,analyzeTelemetryIntervals:Mo,setCursorAt:(o,c=!1)=>{if(h=o,ct&&ct(o),c){G&&B?.points?.[o]&&G(B.points[o]);return}d=!0,t.forEach(({uplot:x,yData:T,xData:A})=>{A[o]!=null&&T[o]!=null&&x.batch(()=>{x.setCursor({left:x.valToPos(A[o],"x"),top:x.valToPos(T[o],"y")},!0,!1)})}),d=!1,G&&B?.points?.[o]&&G(B.points[o])},setHoverAt:o=>{d=!0,t.forEach(({uplot:c,yData:x,xData:T})=>{o===null?c.batch(()=>{c.setCursor({left:-10,top:-10},!0,!1)}):T[o]!=null&&x[o]!=null&&c.batch(()=>{c.setCursor({left:c.valToPos(T[o],"x"),top:c.valToPos(x[o],"y")},!0,!1)})}),d=!1,G&&G(o!=null&&B?.points?.[o]?B.points[o]:null)},clearPinnedDot:()=>{h=null,ct&&ct(null),t.forEach(({uplot:o})=>o.redraw(!1))},resize:Et,METRICS:Ne,isDragging:()=>H,setMapColorChangeCb:Lt,toggleMapColor:st,getMapColorMetric:()=>at,getActiveMetrics:()=>l,getAvailableMetrics:()=>f,setActiveMetrics:ut,setSmooth:ht,setZeroInclusion:Pt,updateMetricOrder:o=>{let c=new Set;o.forEach(x=>{l.has(x)&&c.add(x)}),l.forEach(x=>{c.has(x)||c.add(x)}),l=c,B&&bt(!0)},getXAxis:()=>I};function Eo(o,c,x,T,A){let $=o.ctx,D=o.bbox,P=window.devicePixelRatio||1,N=zt(A,x);$.save(),$.beginPath(),$.rect(D.left,D.top,D.width,D.height),$.clip();let J=A==="gearRear"||A==="gearFront";for(let Z=1;Ztt.time!=null)?.time||0,X=x.field;T.beginPath(),T.strokeStyle="rgba(255, 255, 255, 0.04)",T.lineWidth=1*$;let et=!0;for(let tt=0;tt0){let yt=J[tt-1];(C.time&&yt.time?C.time-yt.time:0)>D&&(et=!0)}let Tt=x.transform?x.transform(xt):xt;if(Tt==null){et=!0;continue}let rt=I==="distance"?(C.dist||0)/1e3:(C.time-Z)/1e3;if(rto.scales.x.max+10){et=!0;continue}let $t=o.valToPos(rt,"x",!0),pt=o.valToPos(Tt,"y",!0);if(et)T.moveTo($t,pt),et=!1;else{if(P){let yt=J[tt-1],kt=I==="distance"?(yt.dist||0)/1e3:(yt.time-Z)/1e3;T.lineTo(o.valToPos(kt,"x",!0),pt)}T.lineTo($t,pt)}}T.stroke()}T.restore()}function dl(o,c,x,T,A,$,D=null,P=[]){let N=o.ctx,J=o.bbox,Z=window.devicePixelRatio||1,X=6e4;N.save(),N.beginPath(),N.strokeStyle=le(T,.8),N.lineWidth=A*Z;let et=$==="gearRear"||$==="gearFront",tt=!0,C=null,xt=1,Tt=1;if($==="gears"&&P.length>0){let Qt=1/0,de=-1/0;for(let Te=0;Tede&&(de=De))}Qt<=de&&(xt=Qt,Tt=de)}let rt=D?D[0]:o.scales.x?.min??-1/0,$t=D?D[1]:o.scales.x?.max??1/0,pt=o.scales.x?.min??-1/0,yt=o.scales.x?.max??1/0,kt=o.scales.y?.min??0,Vt=o.scales.y?.max??100,Ut=J.width/(yt-pt||1),ee=J.height/(Vt-kt||1),oe=o.scales.y?.dir??1,ae=oe===-1?J.top:J.top+J.height,ie=oe===-1?ee:-ee,mt=D?null:o.series[0]?.idxs,Kt=mt?Math.max(0,mt[0]-1):0,Zt=mt?Math.min(c.length-1,mt[1]+1):c.length-1,Jt=et||$==="gears"?1:Math.max(1,Math.floor((Zt-Kt)/250)),ce=I==="time",pe=X/1e3,fe=Kt;for(let Qt=Kt;Qt<=Zt;Qt+=Jt){let de=c[Qt],Te=x[Qt];if(de==null||Te==null){tt=!0;continue}if($==="gears"&&P[Qt]){let Le=P[Qt].gearFrontTooth??P[Qt].gearFront;if(Le!=null&&Le!==C){if(!tt&&Qt>0){N.stroke(),N.beginPath();let Ps=J.left+(c[fe]-pt)*Ut,ss=ae+(x[fe]-kt)*ie;N.moveTo(Ps,ss)}let ln=T;Tt!==xt&&Le!=null&&(Le===xt?ln="#FFC400":Le===Tt?ln="#FF8C00":ln="#FFA500"),N.strokeStyle=le(ln,.8),C=Le}}if(Qt>Kt&&ce){let Le=c[fe];Le!=null&&de-Le>pe&&(tt=!0)}if(de$t){tt=!0;continue}let De=J.left+(de-pt)*Ut,Je=ae+(Te-kt)*ie;if(tt)N.moveTo(De,Je),tt=!1;else{if(et){let Le=c[fe];N.lineTo(J.left+(Le-pt)*Ut,Je)}N.lineTo(De,Je)}fe=Qt}N.stroke(),N.restore()}})();var Wo={"Heart Rate":Rt.hr.icon,Cadence:Rt.cadence.icon,Power:Rt.power.icon,Temperature:Rt.temperature.icon,Shifting:Rt.gears.icon,Battery:Rt.battery.icon},$n=()=>{},El=()=>{};function Ds(t,s){$n=t,El=s}function kl(){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 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=` + `)}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)],Ml=[3,5,10,15,20,30,45,60,90];function qo(t,s){let e=t.points,n=Math.min(e.length,cn),i=0;for(let H=0;H=n)continue;let h=1/L,m=Math.max(1,L>>1);for(let p=0;p<7;p++){let k=Ue[p],j=0,U=0,Q=0,Y=0,G=1/(10+p*15+H*2);for(let ot=0;ot=L){let ct=k[ot-L];j-=ct,U-=ct*ct;let w=j*h,b=Math.max(0,U*h-w*w),u=k[ot-m],R=_t-k[ot-1],M=R*R*G,O=H<4?Math.exp(-M):1/(1+M);Y+=R*R*O;let q=1/(1+b*1e-4);Q+=(_t-w)*(u-w)*q}}i+=(Q+Y*.001)/Math.max(1,n)}}let a=t.stats.sections||re.analyzeTrackSections(e),r=[];for(let H=0;HL[1].secs-H[1].secs).slice(0,8).map(([H,L])=>({combo:H,ratio:(L.front/Math.max(1,L.rear)).toFixed(2),seconds:L.secs,pct:Number((L.secs/Math.max(1,n)*100).toFixed(1)),avgPower:Math.round(L.pwrSum/Math.max(1,L.secs)),avgCadence:Math.round(L.cadSum/Math.max(1,L.secs))})),f=s.length>0?s:[t],y=1,S=1,I=1,B=0,v=0;for(let H=0;Ht.stats.totalDist&&y++,(L.avgPower||0)>(t.stats.avgPower||0)&&S++,L.elevGain>t.stats.elevGain&&I++}let g=Math.round(B/Math.max(1,f.length)),E=(v/Math.max(1,f.length)/1e3).toFixed(1);return{stabilityAccum:i,splitRows:r.slice(0,12),gearMatrix:l,peerSummary:{cohortSize:f.length,distRank:y,pwrRank:S,elevRank:I,cohortAvgPower:g,cohortAvgDistKm:E}}}function Ee(t,s=[],e=[],n){let i=document.getElementById("details-view");if(!i)return;if(!t){i.innerHTML="";return}let a=t;if(n&&n.length===2){let h=t.points[0]?.time||0,m=h+n[0]*1e3,p=h+n[1]*1e3,k=Math.max(0,t.points.findIndex(U=>(U.time||0)>=m)),j=t.points.findIndex(U=>(U.time||0)>=p);if(j===-1&&(j=t.points.length-1),j>k+2){let U=t.points.slice(k,j+1),Q=re.computeStats(U,!0);a={...t,points:U,stats:Q}}}let r=a.stats,d=a.points[0].time;re.ensureCurvesAndZones(a);let l=qo(a,e),f=Math.min(99.9,Math.max(80,95+Math.tanh(l.stabilityAccum*.002)*4.5)).toFixed(1);i.innerHTML=`
- +
@@ -53,7 +53,7 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"
- ${s.map(f=>`
@@ -64,23 +64,23 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"
Distance
-
${(a.totalDist/1e3).toFixed(2)} km
+
${(r.totalDist/1e3).toFixed(2)} km
Duration
-
${a.duration?he(Math.floor(a.duration/1e3)):"\u2014"}
+
${r.duration?he(Math.floor(r.duration/1e3)):"\u2014"}
Avg Speed
-
${a.avgSpeed?(a.avgSpeed*3.6).toFixed(1):"\u2014"} km/h
+
${r.avgSpeed?(r.avgSpeed*3.6).toFixed(1):"\u2014"} km/h
Max Speed
-
${(a.maxSpeed*3.6).toFixed(1)} km/h
+
${(r.maxSpeed*3.6).toFixed(1)} km/h
- ${a.avgBattery!==null?`
+ ${r.avgBattery!==null?`
Avg Battery
-
${a.avgBattery}%
+
${r.avgBattery}%
`:""}
@@ -90,11 +90,11 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"
Original Filename
-
${me(t.fileName||"\u2014")}
+
${ue(t.fileName||"\u2014")}
File Size
-
${t.fileSize?Mo(t.fileSize):"\u2014"}
+
${t.fileSize?yl(t.fileSize):"\u2014"}
Format
@@ -103,10 +103,10 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"
Sport
- ${Eo(t.sport)} - ${me(Ye[t.sport?.toLowerCase()||""]?.name||"\u2014")} + ${Tl(t.sport)} + ${ue(Ye[t.sport?.toLowerCase()||""]?.name||"\u2014")} expand_more - ${t.subSport?`(${me(t.subSport)})`:""} + ${t.subSport?`(${ue(t.subSport)})`:""}
@@ -115,7 +115,7 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"
Start Time
-
${r?So(r):"Unknown"}
+
${d?vl(d):"Unknown"}
@@ -129,63 +129,63 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"
Telemetry Stability
-
${T}%
+
${f}%
Sensors Found
- ${a.sensors.length?a.sensors.map(f=>`${Nl[f]||"sensors"}`).join(""):'GPS only'} + ${r.sensors.length?r.sensors.map(h=>`${Wo[h]||"sensors"}`).join(""):'GPS only'}
- ${a.avgHR||a.avgPower||a.avgCadence||a.avgTemp!=null?` + ${r.avgHR||r.avgPower||r.avgCadence||r.avgTemp!=null?`
monitoringBiometric Averages
- ${a.avgHR?`
+ ${r.avgHR?`
Avg HR
-
${a.avgHR} bpm
+
${r.avgHR} bpm
`:""} - ${a.maxHR?`
+ ${r.maxHR?`
Max HR
-
${a.maxHR} bpm
+
${r.maxHR} bpm
`:""} - ${a.avgPower?`
+ ${r.avgPower?`
Avg Power
-
${a.avgPower} W
+
${r.avgPower} W
`:""} - ${a.maxPower?`
+ ${r.maxPower?`
Max Power
-
${a.maxPower} W
+
${r.maxPower} W
`:""} - ${a.avgCadence?`
+ ${r.avgCadence?`
Avg Cadence
-
${a.avgCadence} rpm
+
${r.avgCadence} rpm
`:""} - ${a.avgTemp!=null?`
+ ${r.avgTemp!=null?`
Avg Temp
-
${a.avgTemp.toFixed(1)} \xB0C
+
${r.avgTemp.toFixed(1)} \xB0C
`:""} - ${a.minTemp!=null&&a.maxTemp!=null?`
+ ${r.minTemp!=null&&r.maxTemp!=null?`
Temp Range
-
${a.minTemp.toFixed(1)} \u2013 ${a.maxTemp.toFixed(1)} \xB0C
+
${r.minTemp.toFixed(1)} \u2013 ${r.maxTemp.toFixed(1)} \xB0C
`:""}
`:""} - ${a.shifts!==null||d.gearMatrix.length>0?` + ${r.shifts!==null||l.gearMatrix.length>0?`
settingsDrivetrain & Gear Matrix
Total Shifts
-
${a.shifts??0}
+
${r.shifts??0}
Cohort Power Rank
-
#${d.peerSummary.pwrRank} / ${d.peerSummary.cohortSize} (${d.peerSummary.cohortAvgPower} W avg)
+
#${l.peerSummary.pwrRank} / ${l.peerSummary.cohortSize} (${l.peerSummary.cohortAvgPower} W avg)
@@ -199,22 +199,22 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<" - ${d.gearMatrix.map(f=>` + ${l.gearMatrix.map(h=>` - - - - - + + + + + `).join("")}
${me(f.combo)}${f.ratio}${f.pct}% (${f.seconds}s)${f.avgPower} W${f.avgCadence} rpm${ue(h.combo)}${h.ratio}${h.pct}% (${h.seconds}s)${h.avgPower} W${h.avgCadence} rpm
`:""} - ${d.splitRows.length>0?` + ${l.splitRows.length>0?`
-
splitscreenSection & Kilometer Splits (${d.splitRows.length})
+
splitscreenSection & Kilometer Splits (${l.splitRows.length})
@@ -231,18 +231,18 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<" - ${d.splitRows.map(f=>` + ${l.splitRows.map(h=>` - - - - - - - - - - + + + + + + + + + + `).join("")} @@ -253,22 +253,22 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"
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"),` + ${(()=>{let h=new Set;return t.devices.filter(m=>{if(!(m.name||m.product||m.manufacturer))return!1;let k=`${m.name}|${m.product}|${m.manufacturer}|${m.serial}`;return h.has(k)?!1:(h.add(k),!0)}).map(m=>{let p=m.name||m.product||"Unknown Device",k=m.manufacturer?`${m.manufacturer}`:"",j=[m.serial?`SN: ${m.serial}`:null,m.version?`v${m.version}`:null,m.hardwareVersion?`hw:${m.hardwareVersion}`:null].filter(Boolean).join(" \u2022 "),U=[m.batteryLevel?`${m.batteryLevel}%`:null,m.batteryStatus?`Status: ${m.batteryStatus}`:null,m.batteryVoltage?`${m.batteryVoltage.toFixed(2)}V`:null].filter(Boolean).join(" \u2022 "),Q="",Y=String(m.sourceType||"").toLowerCase();Y.includes("local")?Q="memory":Y.includes("antplus")||Y.includes("ant_plus")?Q="settings_input_antenna":Y.includes("bluetooth")&&(Q="bluetooth");let G="sensors",ot=String(p).toLowerCase();return ot.includes("heartrate")||ot.includes("hrm")?G=Rt.hr.icon:ot.includes("power")?G=Rt.power.icon:ot.includes("speed")?G=Rt.speed.icon:ot.includes("cadence")?G=Rt.cadence.icon:ot.includes("barometer")?G="air":ot.includes("temperature")?G=Rt.temperature.icon:ot.includes("gps")&&(G="location_on"),`
- ${Z} -
${me(p)}
- ${O?`${O}`:""} + ${G} +
${ue(p)}
+ ${Q?`${Q}`:""}
-
${E}
+
${k}
- ${_?`
${me(_)}
`:""} + ${j?`
${ue(j)}
`:""}
-
${me(h.type||"device")}
- ${W?`
+
${ue(m.type||"device")}
+ ${U?`
battery_charging_full - ${me(W)} + ${ue(U)}
`:""}
@@ -284,7 +284,7 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"
- `;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=` + `;let y=document.getElementById("tag-container"),S=document.getElementById("new-tag-input"),I=document.getElementById("btn-add-tag"),B=()=>{y.innerHTML="";let h=t.tags||[];if(h.length===0){y.innerHTML='No tags added';return}h.forEach(m=>{let p=hs(m),k=document.createElement("div");k.className="tag-pill font-s",k.style.cssText=` background: ${p}15; border: 1px solid ${p}44; color: ${p}; @@ -294,41 +294,41 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<" 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=` + `,k.innerHTML=` + ${ue(m)} + close + `,y.appendChild(k)}),y.querySelectorAll(".btn-remove-tag").forEach(m=>{m.addEventListener("click",async p=>{let k=p.currentTarget.dataset.tag;t.tags=(t.tags||[]).filter(j=>j!==k),await ge.save(t),B(),$n()})})},v=async()=>{let h=S.value.trim().toLowerCase();if(!h)return;let m=new Set(t.tags||[]);if(m.has(h)){S.value="";return}m.add(h),t.tags=Array.from(m).sort(),await ge.save(t),S.value="",B(),$n()};I.addEventListener("click",v),S.addEventListener("keydown",h=>{h.key==="Enter"&&v()});let g=i.querySelector("#details-title-input");g?.addEventListener("change",async()=>{let h=g.value.trim();h&&(t.displayName=h,await ge.save(t),$n())});let E=document.getElementById("sport-dropdown-trigger");E?.addEventListener("click",h=>{h.stopPropagation(),H(E)});function H(h){if(!t)return;document.querySelectorAll(".metric-menu-popup").forEach(Q=>Q.remove());let m=document.createElement("div");m.className="metric-menu-popup",Object.keys(Ye).forEach(Q=>{let Y=Ye[Q],G=document.createElement("div"),ot=t.sport?.toLowerCase()===Q;G.className=`menu-item ${ot?"active":""}`,G.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=` + ${ot?"check":""} + `,G.addEventListener("click",async()=>{t.sport=Q,await ge.save(t),m.remove();let _t=document.getElementById("sport-icon");_t&&(_t.textContent=Y.icon);let ct=document.getElementById("sport-name");ct&&(ct.textContent=Y.name),$n()}),m.appendChild(G)});let p=document.createElement("div"),k=!t.sport;p.className=`menu-item ${k?"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=` + ${k?"check":""} + `,p.addEventListener("click",async()=>{t.sport=void 0,await ge.save(t),m.remove();let Q=document.getElementById("sport-icon");Q&&(Q.textContent="question_mark");let Y=document.getElementById("sport-name");Y&&(Y.textContent="\u2014"),$n()}),m.appendChild(p),document.body.appendChild(m);let j=h.getBoundingClientRect();m.style.top=`${j.bottom+window.scrollY+4}px`,m.style.left=`${j.left+window.scrollX}px`;let U=Q=>{!m.contains(Q.target)&&!h.contains(Q.target)&&(m.remove(),document.removeEventListener("click",U))};setTimeout(()=>document.addEventListener("click",U),10)}B(),document.getElementById("btn-delete-track")?.addEventListener("click",()=>{confirm(`Remove "${t.name}"?`)&&El(t.id)})}import Zo from"uplot";var xe=[];function Dl(t){return xe.filter(s=>{if(s.points.length===0)return!1;for(let e of s.points){let n=!1;for(let i of t.points)if(en(e.lat,e.lon,i.lat,i.lon)<=e.radius){n=!0;break}if(!n)return!1}return!0})}var un=null,Yn=!1,dn=null,Bl=()=>{},zo=null;function Bs(t){Bl=t,Uo()}function _l(){xe=[],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` + `)}function Rl(t){xe=[];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=xe[0].id,dn=xe[0].id)}function Nl(){return xe.map(t=>t.id)}async function Uo(){try{let t=await ge.get("courses");t&&(xe=t)}catch(t){console.error("Courses: Failed to load courses",t)}}async function _s(){try{await ge.set("courses",xe)}catch(t){console.error("Courses: Failed to save courses",t),Bl("Failed to save courses","error")}}function Vo(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 a=Math.max(0,Math.min(s,i-1)),r=Math.max(a,Math.min(e,i-1)),d=n[a]?.time||0,f=((n[r]?.time||0)-d)/1e3,y=0,S=0,I=0,B=0,v=0,g=0,E=0,H=0,L=0;for(let m=a;m<=r;m++){let p=n[m];if(p.power!=null&&(y+=p.power,S++),p.hr!=null&&(I+=p.hr,B++),p.speed!=null&&(v+=p.speed,g++),p.cadence!=null&&(E+=p.cadence,H++),m>a){let k=n[m-1];if(p.ele!=null&&k.ele!=null){let j=p.ele-k.ele;j>0&&(L+=j)}}}let h=r>a?(n[r].dist||0)-(n[a].dist||0):0;return{duration:f,dist:h,avgWatts:S>0?Math.round(y/S):null,avgHR:B>0?Math.round(I/B):null,avgSpeed:g>0?v/g:null,avgCadence:H>0?Math.round(E/H):null,avgVam:f>0?Math.round(L/(f/3600)):null}}function Oo(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 Rs(){return` - + - `}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` + `}function Ns(t,s,e){let i=(s?Ye[s.toLowerCase()]:null)?.paceUnit||"km",a="--";if(t.avgSpeed!=null&&t.avgSpeed>.1){let r=(i==="km"?1e3:100)/t.avgSpeed;a=`${On(r)} min/${i}`}return` - + - + - `}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;an.id===dn||n.id===un):xe;for(let n of e){if(n.points.length<2)continue;let i=qt.findTracksPassingThroughPoints(n.points.map(r=>({lat:r.lat,lng:r.lon})),n.points[0]?.radius||20),a=4;for(let r=0;r
@@ -346,33 +346,33 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"
- ${we.length===0?` + ${xe.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=` + `:xe.map(n=>{let i=n.points.map(l=>({lat:l.lat,lng:l.lon})),a=qt.findTracksPassingThroughPoints(i,n.points[0]?.radius||20),r=n.id===dn,d="";if(r){let l=a.map(f=>{let y=qt.getTrackData(f);if(!y)return null;let S=vs(y,n.points);if(!S)return null;let I=wn(y,S.startIdx,S.endIdx),B=Math.max(1,S.endIdx-S.startIdx),v=S.startIdx+Math.floor(B*.25),g=S.startIdx+Math.floor(B*.5),E=S.startIdx+Math.floor(B*.75),H=wn(y,S.startIdx,v),L=wn(y,v,g),h=wn(y,g,E),m=wn(y,E,S.endIdx),p=y.stats?.startTime||y.points?.[0]?.time,k=p?nn(p):"-";return{id:f,displayName:y.displayName||y.name||f,date:k,sport:y.sport,color:y.color,...I,splitsSummary:`${H.avgWatts||0}/${L.avgWatts||0}/${h.avgWatts||0}/${m.avgWatts||0}W`,startIdx:S.startIdx,endIdx:S.endIdx}}).filter(f=>f!==null);l.sort((f,y)=>f.duration-y.duration||f.id.localeCompare(y.id)),d=`
- ${d.length===0?` + ${l.length===0?`
No matching tracks
`:`
${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}%${ue(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}%
calendar_today Date straighten Distance timer Duration speed Speed speed Pacetrending_up VAMtrending_up VAM bolt Power favorite HR${e} ${t.dist!=null?`${(t.dist/1e3).toFixed(2)} km`:"-"}${Vl(t.duration)}${Oo(t.duration)} ${t.avgSpeed!=null?`${(t.avgSpeed*3.6).toFixed(1)} km/h`:"-"}${i}${a} ${t.avgVam!=null?`${t.avgVam} m/h`:"-"} ${t.avgWatts!=null?`${t.avgWatts} W`:"-"} ${t.avgHR!=null?`${t.avgHR} bpm`:"-"}
- - ${Os()} + + ${Rs()} - ${d.map(T=>` - + ${l.map(f=>` + - ${Ys(T,T.sport,T.date)} + ${Ns(f,f.sport,f.date)} `).join("")} @@ -380,53 +380,53 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<" `} `}return` -
+
- ${a?"expand_more":"chevron_right"} -
${me(n.name)} edit
-
straighten ${Ul(n).toFixed(2)} km | ${n.points.length} points | ${i.length} matching tracks
+ ${r?"expand_more":"chevron_right"} +
${ue(n.name)} edit
+
straighten ${Vo(n).toFixed(2)} km | ${n.points.length} points | ${a.length} matching tracks
- ${r} + ${d}
`}).join("")}
- `,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=` + `,document.getElementById("btn-new-course")?.addEventListener("click",()=>{Yo()}),document.getElementById("btn-done-edit")?.addEventListener("click",()=>{Yn=!1,qt.setCustomClickHandler(null),document.getElementById("map-container")?.classList.remove("editing-mode"),je()}),t.querySelectorAll(".course-item").forEach(n=>{let i=n.dataset.id;n.querySelector(".btn-edit-course")?.addEventListener("click",a=>{a.stopPropagation(),Wl(i)}),n.querySelector(".btn-rename-course")?.addEventListener("click",a=>{a.stopPropagation(),jo(i)}),n.querySelector(".btn-delete-course")?.addEventListener("click",a=>{a.stopPropagation(),Go(i)}),n.querySelector(".course-item-header")?.addEventListener("click",a=>{a.target.closest(".course-actions")||a.target.closest(".btn-rename-course")||(Pn(i),dn=dn===i?null:i,je())}),n.querySelectorAll(".course-track-row").forEach(a=>{let r=a.dataset.trackId,d=parseInt(a.dataset.start,10),l=parseInt(a.dataset.end,10);a.querySelector(".track-name-cell")?.addEventListener("click",f=>{f.stopPropagation();let y=qt.getTrackData(r);y&&(We(r,!1),setTimeout(()=>{let S=y.points,I=S.find(m=>m.time!=null)?.time||0,B=Math.max(0,Math.min(d,S.length-1)),v=Math.max(0,Math.min(l,S.length-1)),g=Math.max(0,((S[B]?.time||0)-I)/1e3),E=Math.max(0,((S[v]?.time||0)-I)/1e3),H=St.getXAxis(),L=g,h=E;H==="distance"&&(L=Math.max(0,(S[B]?.dist||0)/1e3),h=Math.max(0,(S[v]?.dist||0)/1e3)),jt.patch({sel:[L,h],tab:"graphs"},!0),St.restoreSelection(g,E),qt.highlightSegment(r,y.points,d,l,!0)},50))}),a.addEventListener("mouseenter",()=>{qt.setTrackHover(r,!0)}),a.addEventListener("mouseleave",()=>{qt.setTrackHover(r,!1)})})})}function Yo(){let t=`Course ${xe.length+1}`,s={id:Math.random().toString(36).substring(2,9),name:t,points:[]};xe.push(s),_s(),je(),Wl(s.id)}function jo(t){let s=xe.find(d=>d.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 i=s.name;n.innerHTML=``;let a=n.querySelector(".course-name-input");a.focus(),a.select();let r=()=>{let d=a.value.trim();d!==""&&(s.name=d,_s()),je()};a.addEventListener("blur",r),a.addEventListener("keydown",d=>{d.key==="Enter"?r():d.key==="Escape"&&je()})}function Wl(t){un=t,Yn=!0,je()}function ql(){zo=null}function Pn(t,s=!1){un=t,s&&(dn=t),Yn=!1,qt.setCustomClickHandler(null),ql(),je()}function Go(t){confirm("Are you sure you want to delete this course?")&&(xe=xe.filter(s=>s.id!==t),un===t&&(un=null,ql()),_s(),je())}var Ts=()=>{},Ws=[];function jl(){Ws.forEach(t=>t.destroy()),Ws=[]}function qs(t){Ts=t}function Gl(){jl(),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),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=` + `)}var mn=16384,zl=new Float64Array(mn),Ul=new Float64Array(mn),Vl=new Float64Array(mn),Xo=new Float64Array(mn),Qo=new Float64Array(mn),xs=new Float64Array(mn+1),ws=new Float64Array(mn+1),Ol=[1,2,3,5,8,10,15,20,30,45,60,90,120,180,240,300,420,600,900,1200];function Ko(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*G*36:0;zl[p]=j,Ul[p]=1/U,Vl[p]=Q,Xo[p]=Y,Qo[p]=ot,xs[p+1]=xs[p]+j,ws[p+1]=ws[p]+ot}let i=0;for(let p=0;pn)continue;let j=n-k,U=0,Q=0;for(let Y=0;Y<=j;Y++){let G=xs[Y+k]-xs[Y],ot=ws[Y+k]-ws[Y];G>U&&(U=G),ot>Q&&(Q=ot)}i+=(U+Q)/k}let a=2e4,r=2e4,d=0,l=!1,f=n>>1,y=0,S=0,I=[0,0,0,0],B=88,v=s/B;for(let p=0;p0?Q:0,_t=546*Math.exp(-.008*(Y+G*.625))+316;r=Math.min(2e4,r-G+(2e4-r)*(1/_t)),r17500&&l&&(l=!1);let ct=k/j;ct>=v&&j>=B?I[0]++:ct>=v&&j0?y/f:1,E=n-f>0?S/(n-f):1,H=g>0?(g-E)/g*100:0,L=[Number((I[0]/n*100).toFixed(1)),Number((I[1]/n*100).toFixed(1)),Number((I[2]/n*100).toFixed(1)),Number((I[3]/n*100).toFixed(1))],m=(e&&e.length>0?e.filter(p=>p.kind==="quarter"||p.kind==="climb"||p.kind==="sprint"):[]).slice(0,8).map(p=>{let k=p.stats,j=k.duration&&k.duration>0?k.duration/36e5:0;return{label:p.label,distKm:Number((k.totalDist/1e3).toFixed(2)),avgPower:k.avgPower||0,peak60sPower:k.powerCurve?.[60]?.power||k.avgPower||0,avgHR:k.avgHR||0,vam:j>0?Math.round(k.elevGain/j):0}});return i<-1e12&&(a=0),{minWPrimeBal:a,matchesBurned:d,decouplingPct:H,quadrantPct:L,sectionPeaks:m}}function ke(t,s=[],e=null){jl();let n=document.getElementById("insights-view");if(!n)return;if(!t){n.innerHTML="";return}re.ensureCurvesAndZones(t),t.stats.sections||(t.stats.sections=re.analyzeTrackSections(t.points));let i=e||jt.get().sel||null,a=t.points,r=t.stats;if(i&&t.points.length>4){let g=t.points[0].time||0,E=g+i[0]*1e3,H=g+i[1]*1e3,L=t.points.findIndex(m=>(m.time||0)>=E),h=t.points.findIndex(m=>(m.time||0)>=H);L===-1&&(L=0),h===-1&&(h=t.points.length-1),h>L+4&&(a=t.points.slice(L,h+1),r=re.computeStats(a,!0))}if(!r.powerCurve&&!r.hrZones&&!r.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+=` + `;return}let d=Ko(a,re.getFTP(),t.stats.sections),l=d.minWPrimeBal;n.innerHTML=` +
+ `;let f=document.getElementById("insights-grid");if(!f)return;let y=Math.round(f.getBoundingClientRect().width-42)||480;if(r.powerCurve&&Yl({grid:f,track:t,curve:r.powerCurve,metricKey:"power",label:"Power Curve",unit:"W",color:Rt.power.color,icon:"bolt",chartWidth:y}),r.hrCurve&&Yl({grid:f,track:t,curve:r.hrCurve,metricKey:"hr",label:"Heart Rate Curve",unit:"bpm",color:Rt.hr.color,icon:"favorite",chartWidth:y}),r.powerZones){let g=document.createElement("div");g.className="insight-card";let E="power",H=Rt.power.color;g.style.setProperty("--chart-color",H);let L=St.getMapColorMetric()===E,h=r.powerZones.reduce((k,j)=>k+j,0),m=kn.getPowerZones(),p="";r.powerZones.forEach((k,j)=>{if(j>=m.length)return;let U=m[j],Q=h>0?k/h*100:0,Y=isFinite(U.max)?`${Math.round(U.min)} - ${Math.round(U.max)} W`:`> ${Math.round(U.min)} W`;p+=`
- Z${_+1} - ${W.name} + Z${j+1} + ${U.name} ${Y} - ${he(Math.round(E))} - ${O.toFixed(1)}% + ${he(Math.round(k))} + ${Q.toFixed(1)}%
-
+
`}),g.innerHTML=`
- boltPower Zones + boltPower Zones
-
@@ -435,26 +435,26 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"
${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+=` + `,f.appendChild(g),g.querySelector(".map-color-btn")?.addEventListener("click",k=>{k.stopPropagation(),St.toggleMapColor(E);let j=St.getMapColorMetric();f.querySelectorAll(".map-color-btn").forEach(U=>{let Q=U;Q.classList.toggle("active",Q.dataset.metric===j)})}),g.querySelector(".btn-pw-settings")?.addEventListener("click",k=>{k.stopPropagation(),ti(k.currentTarget,t)})}if(r.hrZones){let g=document.createElement("div");g.className="insight-card";let E="hr",H=Rt.hr.color;g.style.setProperty("--chart-color",H);let L=St.getMapColorMetric()===E,h=r.hrZones.reduce((k,j)=>k+j,0),m=kn.getHRZones(),p="";r.hrZones.forEach((k,j)=>{if(j>=m.length)return;let U=m[j],Q=h>0?k/h*100:0,Y=isFinite(U.max)?`${Math.round(U.min)} - ${Math.round(U.max)} bpm`:`> ${Math.round(U.min)} bpm`;p+=`
- Z${_+1} - ${W.name} + Z${j+1} + ${U.name} ${Y} - ${he(Math.round(E))} - ${O.toFixed(1)}% + ${he(Math.round(k))} + ${Q.toFixed(1)}%
-
+
`}),g.innerHTML=`
- favoriteHeart Rate Zones + favoriteHeart Rate Zones
-
@@ -463,53 +463,53 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"
${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-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=` + `,f.appendChild(g),g.querySelector(".map-color-btn")?.addEventListener("click",k=>{k.stopPropagation(),St.toggleMapColor(E);let j=St.getMapColorMetric();f.querySelectorAll(".map-color-btn").forEach(U=>{let Q=U;Q.classList.toggle("active",Q.dataset.metric===j)})}),g.querySelector(".btn-hr-settings")?.addEventListener("click",k=>{k.stopPropagation(),Jo(k.currentTarget,t)})}let S=document.createElement("div");S.className="insight-card";let I=r.totalDist/1e3,B=I>0?r.elevGain/(I*1e3)*100:0;if(S.innerHTML=`
- terrainClimbing Analysis + terrainClimbing Analysis
Total Ascent
-
${Math.round(a.elevGain)} m
+
${Math.round(r.elevGain)} m
Total Descent
-
${Math.round(a.elevLoss)} m
+
${Math.round(r.elevLoss)} m
Avg Grade
-
${I.toFixed(1)} %
+
${B.toFixed(1)} %
VAM
-
${a.duration&&a.duration>0?Math.round(a.elevGain/a.duration*36e5):0} m/h
+
${r.duration&&r.duration>0?Math.round(r.elevGain/r.duration*36e5):0} m/h
- `,T.appendChild(M),a.avgPower&&a.avgHR){let g=document.createElement("div");g.className="insight-card";let u=a.avgPower/a.avgHR;g.innerHTML=` + `,f.appendChild(S),r.avgPower&&r.avgHR){let g=document.createElement("div");g.className="insight-card";let E=r.avgPower/r.avgHR;g.innerHTML=`
monitoringEfficiency & W' Balance
EF (Avg Power / Avg HR)
-
${u.toFixed(2)}
+
${E.toFixed(2)}
Aerobic Decoupling
-
${r.decouplingPct.toFixed(1)} %
+
${d.decouplingPct.toFixed(1)} %
Min W' Reserve
-
${(r.minWPrimeBal/1e3).toFixed(1)} kJ (${r.matchesBurned} matches)
+
${(d.minWPrimeBal/1e3).toFixed(1)} kJ (${d.matchesBurned} matches)
Quadrants (Q1/Q2/Q3/Q4)
-
${r.quadrantPct.join("% / ")}%
+
${d.quadrantPct.join("% / ")}%
- `,T.appendChild(g)}if(r.sectionPeaks.length>0){let g=document.createElement("div");g.className="insight-card",g.innerHTML=` + `,f.appendChild(g)}if(d.sectionPeaks.length>0){let g=document.createElement("div");g.className="insight-card",g.innerHTML=`
- segmentTrack Section & Climb Efforts + segmentTrack Section & Climb Efforts
Track (${d.length})Track (${l.length})
-
- ${me(T.displayName)} +
+ ${ue(f.displayName)}
@@ -523,50 +523,50 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<" - ${r.sectionPeaks.map(u=>` + ${d.sectionPeaks.map(E=>` - - - - - - + + + + + + `).join("")}
${me(u.label)}${u.distKm} km${u.avgPower} W${u.peak60sPower} W${u.avgHR} bpm${u.vam} m/h${ue(E.label)}${E.distKm} km${E.avgPower} W${E.peak60sPower} W${E.avgHR} bpm${E.vam} m/h
- `,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})
+ `,f.appendChild(g)}let v=Dl(t);if(v.length>0){let g=document.createElement("div");g.className="insight-card",g.style.cssText="column-span: all; display: block;",g.innerHTML=` +
routeCourses (${v.length})
- ${Os()} + ${Rs()} - ${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` - + ${v.map(E=>{let H=vs(t,E.points),L="";if(H){let h=wn(t,H.startIdx,H.endIdx),m=t.stats?.startTime||t.points?.[0]?.time,p=m?nn(m):"-";L=Ns(h,t.sport||null,p)}else L='';return` + - ${k} + ${L} `}).join("")}
Name
No continuous segment
No continuous segment
- ${me(u.name)} + ${ue(E.name)}
- `,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=` + `,f.appendChild(g),g.querySelectorAll(".clickable-course").forEach(E=>{E.addEventListener("click",()=>{let H=E.dataset.id;Pn(H,!0),jt.patch({tab:"courses"},!0)}),E.addEventListener("mouseenter",()=>{let H=E.dataset.id,L=v.find(h=>h.id===H);if(L){let h=vs(t,L.points);h&&qt.highlightSegment(t.id,t.points,h.startIdx,h.endIdx,!1)}}),E.addEventListener("mouseleave",()=>{qt.clearHighlight()})})}}function Yl(t){let{grid:s,track:e,curve:n,metricKey:i,label:a,unit:r,color:d,icon:l,chartWidth:f}=t,y=St.getMapColorMetric()===i,S=document.createElement("div");S.className="insight-card",S.style.setProperty("--chart-color",d),S.innerHTML=`
- ${d}${i} + ${l}${a}
-
@@ -574,7 +574,7 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<" expand_more
-
+
- `,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} + `,s.appendChild(S);let I=S.querySelector(".curve-table-wrap"),B=S.querySelector(".btn-toggle-table"),v=B.querySelector(".material-symbols-rounded");B.addEventListener("click",()=>{let h=I.style.display==="none";I.style.display=h?"block":"none",v.textContent=h?"expand_less":"expand_more"});let g=S.querySelector(".map-color-btn");g.addEventListener("click",h=>{h.stopPropagation();let m=g.dataset.metric;St.toggleMapColor(m);let p=St.getMapColorMetric();s.querySelectorAll(".map-color-btn").forEach(k=>{let j=k;j.classList.toggle("active",j.dataset.metric===p)})});let E=S.querySelector(".curve-tbody"),H=Object.keys(n).map(Number).sort((h,m)=>h-m);H.forEach(h=>{let m=n[h],p=m.power||m.hr||m.val,k=document.createElement("tr");k.innerHTML=` + ${ze(h)} + ${p} ${r} - - `,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=` + `,E?.appendChild(k)}),E?.querySelectorAll(".btn-show-peak").forEach(h=>{h.addEventListener("click",m=>{let p=m.currentTarget,k=parseInt(p.dataset.idx),j=parseInt(p.dataset.len),U=e.points,Q=Math.min(U.length-1,k+j-1),Y=U[0].time||0,G=((U[k].time||Y)-Y)/1e3,ot=((U[Q].time||Y)-Y)/1e3;jt.patch({sel:[G,ot]}),qt.highlightSegment(e.id,U,k,Q,!0)})});let L=S.querySelector(`#${i}-curve-chart`);if(L){let h=H,m=H.map(U=>n[U].power||n[U].hr||n[U].val),p=document.createElement("div");p.className="cur-y-val",p.style.cssText=`color:${d};display:none;border-color:${d}44`,L.style.position="relative",L.appendChild(p);let k={id:`${i}-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:d,width:2,fill:le(d,.1),points:{show:!0,size:5,fill:d}}],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:(U,Q)=>Q.map(Y=>`${Y}${r}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(U,Q,Y)=>Y},hooks:{draw:[U=>{let Q=U.ctx,Y=window.devicePixelRatio||1,G=U.bbox,ot=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],_t=h[h.length-1];Q.save(),Q.fillStyle="#555564",Q.textAlign="center",Q.textBaseline="top",Q.font=`${10*Y}px system-ui, sans-serif`;let ct=-100;ot.forEach(w=>{if(w>_t)return;let b=U.valToPos(w,"x",!0);b>ct+30*Y&&b{U.over.addEventListener("click",()=>{let Q=U.cursor.idx;if(Q!=null&&h[Q]!=null){let Y=h[Q],ot=n[Y].idx,_t=e.points,ct=Math.min(_t.length-1,ot+Y-1),w=_t[0].time||0,b=((_t[ot].time||w)-w)/1e3,u=((_t[ct].time||w)-w)/1e3;jt.patch({sel:[b,u]}),qt.highlightSegment(e.id,_t,ot,ct,!0)}})}],setCursor:[U=>{if(!U._ready)return;U.redraw(!1);let Q=U.cursor.idx,Y=U.ctx,G=window.devicePixelRatio||1,ot=U.bbox,_t=Q!=null&&m[Q]!=null&&U.cursor.left>=0,ct=U.cursor.top,w=U.valToPos(m[Q],"y",!1);if(_t&&Math.abs(ct-w)<40){let u=U.valToPos(h[Q],"x",!1),R=U.valToPos(m[Q],"y",!1),M=h[Q];p.innerHTML=`${ze(M)}: ${m[Q]} ${r}`,p.style.transform=`translate(${u}px, ${R}px) translate(15px, 15px)`,p.style.display="";let O=U.valToPos(h[Q],"x",!0),q=U.valToPos(m[Q],"y",!0);Y.save(),Y.beginPath(),Y.setLineDash([2*G,2*G]),Y.strokeStyle=le(d,.4),Y.lineWidth=1*G,Y.moveTo(O,ot.top),Y.lineTo(O,ot.top+ot.height),Y.stroke(),Y.beginPath(),Y.setLineDash([]),Y.arc(O,q,3*G,0,Math.PI*2),Y.fillStyle="#0e0e10",Y.fill(),Y.strokeStyle=d,Y.lineWidth=2*G,Y.stroke(),Y.restore()}else p.style.display="none"}]},legend:{show:!1}};k.width=f||Math.round(s.getBoundingClientRect().width-42)||L.clientWidth||500;let j=new Zo(k,[h,m],L);j._ready=!0,Ws.push(j)}}function Jo(t,s){document.querySelectorAll(".hr-settings-popup").forEach(r=>r.remove());let e=document.createElement("div");e.className="hr-settings-popup";let n=re.getHRZones();e.innerHTML=`
Configure HR Zones (bpm)
@@ -616,7 +616,7 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"
- `;let o=t.getBoundingClientRect();e.style.cssText=` + `;let i=t.getBoundingClientRect();e.style.cssText=` position: fixed; z-index: 10000; background: var(--surface2); @@ -625,9 +625,9 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<" 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(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=` + left: ${i.right-200}px; + top: ${i.bottom+8}px; + `,document.body.appendChild(e),e.querySelector(".save-btn")?.addEventListener("click",async()=>{let r=e.querySelectorAll(".hr-zone-input"),d=Array.from(r).map(l=>parseInt(l.value)||0);for(let l=1;l{!e.contains(r.target)&&!t.contains(r.target)&&(e.remove(),document.removeEventListener("click",a))};setTimeout(()=>document.addEventListener("click",a),10)}function ti(t,s){document.querySelectorAll(".pw-settings-popup").forEach(r=>r.remove());let e=document.createElement("div");e.className="pw-settings-popup";let n=re.getFTP();e.innerHTML=`
Configure FTP (Watts)
@@ -636,7 +636,7 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"
- `;let o=t.getBoundingClientRect();e.style.cssText=` + `;let i=t.getBoundingClientRect();e.style.cssText=` position: fixed; z-index: 10000; background: var(--surface2); @@ -645,27 +645,27 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<" 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(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=` + left: ${i.right-200}px; + top: ${i.bottom+8}px; + `,document.body.appendChild(e),e.querySelector(".save-btn")?.addEventListener("click",async()=>{let r=e.querySelector("#ftp-input"),d=parseInt(r.value)||200;re.setFTP(d),await ge.set("ftp",d),s.stats=re.computeStats(s.points,!0),await ge.save(s),ke(s),e.remove(),Ts(`FTP updated to ${d}W`)});let a=r=>{!e.contains(r.target)&&!t.contains(r.target)&&(e.remove(),document.removeEventListener("click",a))};setTimeout(()=>document.addEventListener("click",a),10)}import Zl from"uplot";var we=[],$e=null,me=null,fn="power",Qe="hr",be=null,Ae=[],Xe=[],pn=null,Ie=!1;function jn(){let t=document.getElementById("combined-time-val");if(t&&be!==null&&Ae[be]){let s=Ae[be][2];t.textContent=`${he(s)}`}}function Ql(){pn&&(clearInterval(pn),pn=null),me&&(me.destroy(),me=null),we=[],$e=null,fn="power",Qe="hr",be=null,Ae=[],Xe=[],Ie=!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 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=` + `)}var ei=16384,zs=new Float64Array(32*32);function ni(t,s){let e=s.length>=2?s:t,n=Math.min(e.length,8);zs.fill(0);let i=[{label:"Power vs Heart Rate",getX:I=>I.power,getY:I=>I.hr},{label:"Speed vs Gradient",getX:I=>I.speed!=null?I.speed*3.6:void 0,getY:I=>I.gradient},{label:"Cadence vs Power",getX:I=>I.cad,getY:I=>I.power},{label:"Elevation vs VAM",getX:I=>I.ele,getY:I=>I.verticalSpeed},{label:"Temperature vs HR",getX:I=>I.temp,getY:I=>I.hr}],a=0,r=0,d=[];for(let I=0;I2){let k=v/h,j=g/h,U=Math.max(0,E/h-k*k),Q=Math.max(0,H/h-j*j),Y=L/h-k*j,G=Math.sqrt(U*Q);m=G>1e-9?Y/G:0,p=U>1e-9?Y/U:0}a+=h,r+=Math.abs(m)*100+Math.abs(p),d.push({pairLabel:B.label,rVal:m,slope:p,samples:h})}for(let I=0;I<1024;I++)r+=zs[I]*.001;let l=["Q1 (0\u201325%)","Q2 (25\u201350%)","Q3 (50\u201375%)","Q4 (75\u2013100%)"],f=[],y=t[0],S=t[1]||t[0];for(let I=0;I<4;I++){let B=I*.25,v=(I+1)*.25,g=h=>{let m=h.points||[],p=Math.floor(m.length*B),k=Math.max(p+1,Math.floor(m.length*v)),j=0,U=0,Q=0,Y=0;for(let G=p;G0?Math.round(j/Y):0,hr:Y>0?Math.round(U/Y):0,speedKmh:Y>0?Q/Y:0}},E=g(y),H=g(S),L=0;for(let h=0;h0?Math.round(L/n):0})}return{aggPts:a,corrSum:r,correlations:d,sectionRows:f}}function Us(t,s){fn=t,Qe=s,we.length>=2?qe(we):$e&&qe($e)}function Vs(t){Ie!==t&&(Ie=t,we.length>=2?qe(we):$e&&qe($e))}function Ss(t){let s=Math.max(0,Math.min(1,t)),e=Ae.length>0?Ae.length-1:$e?Math.max(0,$e.points.length-1):0;be=Math.round(s*e);let n=document.getElementById("combined-time-slider");n&&(n.max=`${e}`,n.value=`${be}`),jn(),me&&me.redraw()}function qe(t,s=[]){Array.isArray(t)?(we=t,$e=t[0]||null):t?(we=[t],$e=t):(we=[],$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 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)
+ `;return}let i=St.METRICS,a=[];for(let v in i){let g=i[v];n.points.some(E=>E[g.field]!=null)&&a.push(v)}!a.includes(fn)&&a.length>0&&(fn=a[0]),!a.includes(Qe)&&a.length>1?Qe=a[1]:!a.includes(Qe)&&a.length>0&&(Qe=a[0]);let r=i[fn],d=i[Qe];e.style.overflow="hidden";let l="";if(we.length>=2){let{aggPts:v,corrSum:g,correlations:E,sectionRows:H}=ni(we,s),L=we[0],h=we[1],m=L.stats,p=h.stats,k=((p.totalDist-m.totalDist)/1e3).toFixed(2),j=((p.avgPower||0)-(m.avgPower||0)).toFixed(0),U=((p.avgHR||0)-(m.avgHR||0)).toFixed(0),Q=(p.elevGain-m.elevGain).toFixed(0),Y=(p.shifts||0)-(m.shifts||0),G=((m.totalDist+p.totalDist)/1e3).toFixed(2),ot=(m.elevGain+p.elevGain).toFixed(0),_t=((m.duration||0)+(p.duration||0))/1e3,ct=Math.round(((m.avgPower||0)+(p.avgPower||0))/2),w=Math.max(m.maxPower||0,p.maxPower||0),b=Math.round(((m.avgHR||0)+(p.avgHR||0))/2),u=Math.max(m.maxHR||0,p.maxHR||0),R=((p.avgTemp??0)-(m.avgTemp??0)).toFixed(1),M=(((m.avgTemp??0)+(p.avgTemp??0))/2).toFixed(1),O=Math.max(m.maxTemp??0,p.maxTemp??0).toFixed(1),q=(m.shifts||0)+(p.shifts||0);l=` +
+
Aggregate Track Comparison & Section Analysis (${we.length} Tracks)
- - + + @@ -673,75 +673,75 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<" - + - - + + - + - - + + - + - + - + - - + + - + - - + + - + - - + + - + - + - ${v.map(j=>` + ${H.map(V=>` - - - - - + + + + + `).join("")}
Metric${k.displayName||k.name} (T1)${f.displayName||f.name} (T2)${L.displayName||L.name} (T1)${h.displayName||h.name} (T2) Delta (T2 - T1) Aggregate Summary
Distance${(h.totalDist/1e3).toFixed(2)} km${(m.totalDist/1e3).toFixed(2)} km ${(p.totalDist/1e3).toFixed(2)} km${Number(E)>=0?"+":""}${E} km${Z} km (Total)${Number(k)>=0?"+":""}${k} km${G} km (Total)
Elevation Gain${h.elevGain.toFixed(0)} m${m.elevGain.toFixed(0)} m ${p.elevGain.toFixed(0)} m${Number(O)>=0?"+":""}${O} m${lt} m (Total)${Number(Q)>=0?"+":""}${Q} m${ot} m (Total)
Duration${h.duration?he(h.duration/1e3):"--"}${m.duration?he(m.duration/1e3):"--"} ${p.duration?he(p.duration/1e3):"--"} --${he(Ft)} (Total)${he(_t)} (Total)
Avg / Max Power${h.avgPower||0} W / ${h.maxPower||0} W${m.avgPower||0} W / ${m.maxPower||0} W ${p.avgPower||0} W / ${p.maxPower||0} W${Number(_)>=0?"+":""}${_} W (Avg)${rt} W (Avg) / ${w} W (Max)${Number(j)>=0?"+":""}${j} W (Avg)${ct} W (Avg) / ${w} W (Max)
Avg / Max HR${h.avgHR||0} bpm / ${h.maxHR||0} bpm${m.avgHR||0} bpm / ${m.maxHR||0} bpm ${p.avgHR||0} bpm / ${p.maxHR||0} bpm${Number(W)>=0?"+":""}${W} bpm (Avg)${y} bpm (Avg) / ${m} bpm (Max)${Number(U)>=0?"+":""}${U} bpm (Avg)${b} bpm (Avg) / ${u} bpm (Max)
Avg / Max Temp${h.avgTemp!=null?h.avgTemp.toFixed(1):"--"} \xB0C / ${h.maxTemp!=null?h.maxTemp.toFixed(1):"--"} \xB0C${m.avgTemp!=null?m.avgTemp.toFixed(1):"--"} \xB0C / ${m.maxTemp!=null?m.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)${C} \xB0C (Avg) / ${G} \xB0C (Max)${Number(R)>=0?"+":""}${R} \xB0C (Avg)${M} \xB0C (Avg) / ${O} \xB0C (Max)
Gear Shifts${h.shifts||0}${m.shifts||0} ${p.shifts||0} ${Y>=0?"+":""}${Y}${U} (Total)${q} (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${V.sectionLabel} Split${V.t1Power}W \xB7 ${V.t1Hr}bpm \xB7 ${V.t1SpeedKmh.toFixed(1)}km/h${V.t2Power}W \xB7 ${V.t2Hr}bpm \xB7 ${V.t2SpeedKmh.toFixed(1)}km/h${V.t2Power-V.t1Power>=0?"+":""}${V.t2Power-V.t1Power}WCohort Avg: ${V.cohortAvgPower}W
- ${u.map(j=>`${j.pairLabel}: r=${j.rVal.toFixed(2)}, \u03B2=${j.slope.toFixed(2)} (${j.samples})`).join("")} + ${E.map(V=>`${V.pairLabel}: r=${V.rVal.toFixed(2)}, \u03B2=${V.slope.toFixed(2)} (${V.samples})`).join("")}
- `}e.innerHTML=`${d} + `}e.innerHTML=`${l}
arrow_forward X Axis:
@@ -749,8 +749,8 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<" arrow_upward Y Axis:
@@ -764,38 +764,38 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"
- -
- `,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=` + `,document.getElementById("btn-combined-x")?.addEventListener("click",v=>{v.stopPropagation(),Xl(v.currentTarget,"x")}),document.getElementById("btn-combined-y")?.addEventListener("click",v=>{v.stopPropagation(),Xl(v.currentTarget,"y")});let f=document.getElementById("combined-time-slider"),y=document.getElementById("combined-time-val"),S=document.getElementById("btn-combined-play");f?.addEventListener("input",()=>{be=parseInt(f.value,10),jn(),me&&me.redraw()});function I(){S&&(S.innerHTML='pause'),pn=window.setInterval(()=>{be!==null&&beplay_arrow')}S?.addEventListener("click",()=>{pn?B():(be!==null&&be>=Ae.length-1&&(be=0,f.value="0",jn(),me&&me.redraw()),I())}),document.getElementById("btn-combined-cart")?.addEventListener("click",()=>{Ie&&(Ie=!1,qe($e))}),document.getElementById("btn-combined-polar")?.addEventListener("click",()=>{Ie||(Ie=!0,qe($e))}),si()}function Gn(){let t=document.getElementById("tab-combined"),s=document.getElementById("combined-plot-container");if(me&&s&&s.clientWidth>0){let e=s.clientWidth,n=s.clientHeight;if(e>0&&n>0)if(Ie){let i=Math.min(e,n);me.setSize({width:i,height:i})}else me.setSize({width:e,height:n})}}function Xl(t,s){document.querySelectorAll(".metric-menu-popup").forEach(l=>l.remove());let e=document.createElement("div");e.className="metric-menu-popup";let n=St.METRICS,i=$e;if(!i)return;let a=[];for(let l in n){let f=n[l];i.points.some(y=>y[f.field]!=null)&&a.push(l)}a.forEach(l=>{let f=n[l],y=document.createElement("div"),S=s==="x"?fn:Qe;y.className=`menu-item ${S===l?"active":""}`,y.innerHTML=` + ${f.icon} + ${f.label} + ${S===l?"check":""} + `,y.addEventListener("click",()=>{s==="x"?fn=l:Qe=l,e.remove(),qe($e)}),e.appendChild(y)});let r=t.getBoundingClientRect();e.style.top=`${r.bottom+5}px`,e.style.left=`${r.left}px`,document.body.appendChild(e);let d=l=>{!e.contains(l.target)&&!t.contains(l.target)&&(e.remove(),document.removeEventListener("click",d))};setTimeout(()=>document.addEventListener("click",d),0)}function si(){if(!$e)return;let t=document.getElementById("combined-plot-container");if(!t)return;let s=St.METRICS,e=s[fn]||s.power,n=s[Qe]||s.hr;if(we.length>=2){let v=0;for(let p=0;pv&&(v=we[p].points.length);let g=new Array(v);for(let p=0;p0?t.clientWidth:800,h=t.clientHeight>0?t.clientHeight:350,m={width:L,height:h,padding:[10,15,0,0],scales:{x:{time:!1},y:{auto:!0}},series:E,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}};me=new Zl(m,H,t),Gn();return}let i=$e.points,a=i[0].time||0,r=i.map((v,g)=>[v[e.field],v[n.field],(v.time-a)/1e3,(v.dist||0)/1e3,g]).filter(([v,g,E,H])=>v!=null&&g!=null);if(r.length===0){t.innerHTML='
No data for selected metrics
';return}if(Ie){let v=r.map(m=>m[0]),g=r.map(m=>m[1]),E=Math.min(...v),H=Math.max(...v),L=Math.min(...g),h=Math.max(...g);Ae=r.map(m=>{let p=m[0],k=m[1],j=(p-E)/(H-E||1)*2*Math.PI,U=(k-L)/(h-L||1),Q=U*Math.cos(j),Y=U*Math.sin(j);return[Q,Y,m[2],m[3],m[4],p,k]})}else Ae=r.map(v=>[v[0],v[1],v[2],v[3],v[4],v[0],v[1]]);let d=document.getElementById("combined-time-slider");d&&(d.max=`${r.length-1}`,(be===null||be>=r.length)&&(be=r.length-1,d.value=d.max),jn()),Xe=[...Ae].sort((v,g)=>v[0]-g[0]||v[4]-g[4]);let l=Xe.map(v=>v[0]),f=Xe.map(v=>v[1]),y=document.getElementById("combined-plot-container"),S=y&&y.clientWidth>0?y.clientWidth:600,I=y&&y.clientHeight>0?y.clientHeight:400;if(Ie){let v=Math.min(S,I>0?I:S);S=v,I=v,y&&(y.style.display="flex",y.style.alignItems="center",y.style.justifyContent="center")}else y&&(y.style.display="",y.style.alignItems="",y.style.justifyContent="");let B={width:S,height:I,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:!Ie,label:`${e.label} (${e.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(v,g)=>g.map(E=>E!=null?e.fmtAxis(E):""),size:30},{side:3,show:!Ie,label:`${n.label} (${n.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(v,g)=>g.map(E=>E!=null?n.fmtAxis(E):""),size:40}],cursor:{drag:{x:!1,y:!1},dataIdx:(v,g,E)=>{let H=v.cursor.left,L=v.cursor.top;if(H!=null&&L!=null&&H>=0&&L>=0){let h=1/0,m=-1;for(let p=0;p=0&&h<2500)return m}return E},points:{size:7,stroke:"#fff",width:2,fill:n.color}},legend:{show:!1},hooks:{draw:[v=>{let g=v.ctx,E=window.devicePixelRatio||1;g.save(),g.beginPath(),g.strokeStyle="rgba(255, 255, 255, 0.15)",g.lineWidth=1*E;let H=!1;for(let L=0;L{let g=v.cursor.idx,E=document.getElementById("combined-tooltip");if(E||(E=document.createElement("div"),E.id="combined-tooltip",E.style.position="absolute",E.style.background="rgba(14, 14, 16, 0.9)",E.style.color="#fff",E.style.padding="8px 12px",E.style.borderRadius="4px",E.classList.add("font-m"),E.style.fontFamily="system-ui",E.style.pointerEvents="none",E.style.zIndex="1000",E.style.boxShadow="0 4px 6px rgba(0,0,0,0.3)",E.style.border="1px solid #2e2e34",document.body.appendChild(E)),g!=null&&Xe[g]&&v.cursor.left>=0){let H=Xe[g],L=H[2],h=H[3],m=H[5],p=H[6];E.innerHTML=`
Point #${g}
Time: - ${he(k)} + ${he(L)}
Distance: - ${f.toFixed(2)} km + ${h.toFixed(2)} km
${e.label}: - ${e.fmtAxis(h)} ${e.unit} + ${e.fmtAxis(m)} ${e.unit}
${n.label}: ${n.fmtAxis(p)} ${n.unit}
- `,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` + `,E.style.display="block";let k=v.over.getBoundingClientRect();E.style.left=`${k.left+window.scrollX+v.cursor.left+15}px`,E.style.top=`${k.top+window.scrollY+v.cursor.top+15}px`}else E.style.display="none"}]}};t.querySelector(".empty-text")&&(t.innerHTML=""),me&&me.destroy(),me=new Zl(B,[l,f],t),me.over.addEventListener("click",()=>{if(me){let v=me.cursor.idx;if(v!=null&&Xe[v]){let g=Xe[v][4];St.setCursorAt(g)}}}),Gn()}import Ln from"uplot";function gn(t,s){let e=0;for(let p=0;pe&&(e=k)}e||(e=Date.UTC(2026,7,1));let n=new Date(e),i=n.getUTCFullYear(),a=Date.UTC(i-1,n.getUTCMonth(),n.getUTCDate(),n.getUTCHours(),n.getUTCMinutes(),n.getUTCSeconds()),r=Date.UTC(i,n.getUTCMonth()-6,n.getUTCDate(),n.getUTCHours(),n.getUTCMinutes(),n.getUTCSeconds()),d=Date.UTC(i,n.getUTCMonth()-1,n.getUTCDate(),n.getUTCHours(),n.getUTCMinutes(),n.getUTCSeconds()),l=0,f=0,y=0,S=0,I=0,B=e;t.forEach(p=>{if(!p.stats.startTime)return;let k=s(p);if(k===void 0)return;I+=k;let j=p.stats.startTime;j=a&&(f+=k),j>=r&&(y+=k),j>=d&&(S+=k)});let v=7*24*60*60*1e3,g=Date.UTC(i,0,1),E=Math.max(.1,(e-g)/v),H=Math.max(.1,(e-a)/v),L=Math.max(.1,(e-r)/v),h=Math.max(.1,(e-d)/v),m=Math.max(.1,(e-B)/v);return{currentYear:l,pastYear:f,past6m:y,past1m:S,total:I,currentYearAvg:l/E,pastYearAvg:f/H,past6mAvg:y/L,past1mAvg:S/h,totalAvg:I/m}}function Kl(t,s,e){let n=s?1e3:1,i=a=>(s?a/n:a).toLocaleString("en-US",{minimumFractionDigits:s?1:0,maximumFractionDigits:s?1:0});return` @@ -807,32 +807,32 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<" - - + + - - + + - - + + - - + + - - + +
Current Year${o(t.currentYear)} ${e}${o(t.currentYearAvg)} ${e}${i(t.currentYear)} ${e}${i(t.currentYearAvg)} ${e}
Past Year${o(t.pastYear)} ${e}${o(t.pastYearAvg)} ${e}${i(t.pastYear)} ${e}${i(t.pastYearAvg)} ${e}
Past 6 Months${o(t.past6m)} ${e}${o(t.past6mAvg)} ${e}${i(t.past6m)} ${e}${i(t.past6mAvg)} ${e}
Past 1 Month${o(t.past1m)} ${e}${o(t.past1mAvg)} ${e}${i(t.past1m)} ${e}${i(t.past1mAvg)} ${e}
Total${o(t.total)} ${e}${o(t.totalAvg)} ${e}${i(t.total)} ${e}${i(t.totalAvg)} ${e}
- `}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` + `}function li(t){let s=gn(t,d=>d.stats.totalDist),e=gn(t,d=>d.stats.elevGain),n=gn(t,d=>d.stats.duration?d.stats.duration/36e5:0),i=gn(t,d=>{let l=(d.stats.duration||0)/1e3,f=d.stats.avgPower||150,y=200,S=f/y;return l*f*S/(y*3600)*100}),a=gn(t,d=>{let l=(d.stats.duration||0)/1e3,f=d.stats.avgPower||0;return l*f/1e3}),r=gn(t,d=>(d.stats.sections||[]).filter(f=>f.kind==="climb").length);return{distance:s,elevation:e,durationHours:n,tss:i,workKj:a,climbCount:r}}function Jl(t){let s=li(t),e=(i,a=1)=>i.toLocaleString("en-US",{minimumFractionDigits:a,maximumFractionDigits:a});return`
@@ -853,94 +853,94 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<" - ${[{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=>` + ${[{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(i=>` - ${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 + ${i.label} + ${e(i.data.past1m*i.scale,i.digits)} ${i.unit} + ${e(i.data.past6m*i.scale,i.digits)} ${i.unit} + ${e(i.data.pastYear*i.scale,i.digits)} ${i.unit} + ${e(i.data.currentYear*i.scale,i.digits)} ${i.unit} + ${e(i.data.total*i.scale,i.digits)} ${i.unit} + ${e(i.data.totalAvg*i.scale,i.digits)} ${i.unit}/wk `).join("")}
- `}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=` + `}var An=[],Xn=[],js="week";function lo(){An.forEach(t=>t.destroy()),An=[],Xn=[]}function oo(){lo(),js="week";let t=document.getElementById("evolution-view");t&&(t.innerHTML=`
no_sim
Select a track for progress analysis
- `)}function Jn(t){Ks=t,Kn.forEach(s=>{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{s&&s.updateGrouping&&s.updateGrouping(t)})}function io(t){jt.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)}),Xn.forEach(e=>{e&&e.updateRange&&e.updateRange(t)})}function ao(t){Xn.forEach(s=>{s&&s.updatePin&&s.updatePin(t)})}var Qn=16384,Zn=new Float64Array(Qn+1),Tn=new Float64Array(Qn+1),Os=new Float64Array(Qn+1),to=new Float64Array(Qn),Ys=new Float64Array(365),eo=[1,2,3,5,8,10,15,20,30,45,60,90,120,180,240,300,360,450,600,750,900,1200];function Ms(t,s,e,n){lo();let i=document.getElementById("evolution-view");if(!i)return;let a=jt.get().progress||"all";s.forEach(m=>{re.ensureCurvesAndZones(m)});let r=0,d=0;Ys.fill(0);for(let m=0;mk)continue;let R=k-u,M=0,O=0;for(let q=0;q<=R;q++){let V=Tn[q+u]-Tn[q],Bt=Zn[q+u]-Zn[q];Bt>M&&(M=Bt),V>O&&(O=V)}d+=(M+O+Os[R])/u*.001}let j=2/8,U=1-j,Q=2/43,Y=1-Q,G=52,ot=1/(195-G),_t=0,ct=0;for(let b=0;b
- - - -
- - - - - - + + + + + +
- `;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=` + `;let S=document.getElementById("evolution-container");if(!S)return;S.insertAdjacentHTML("beforeend",Jl(s));let I=S.clientWidth||570,B=Ln.sync("progress-sync");y.push(so(S,s,"distance",B,n,I)),y.push(so(S,s,"elevation",B,n,I));let v=S.querySelector(".distance-progress-card .chart-scroll-container"),g=S.querySelector(".elevation-progress-card .chart-scroll-container");v&&g&&(v.addEventListener("scroll",()=>{g.scrollLeft!==v.scrollLeft&&(g.scrollLeft=v.scrollLeft)}),g.addEventListener("scroll",()=>{v.scrollLeft!==g.scrollLeft&&(v.scrollLeft=g.scrollLeft)}));let E=i.querySelector("#evolution-time-range");E&&E.querySelectorAll(".seg-btn").forEach(m=>{m.addEventListener("click",()=>{let p=m.getAttribute("data-range");p&&(E.querySelectorAll(".seg-btn").forEach(k=>k.classList.remove("active")),m.classList.add("active"),h(p))})}),i.querySelectorAll(".metric-pill").forEach(m=>{m.addEventListener("click",()=>{let p=m.getAttribute("data-target");p&&document.getElementById(`${p}-evolution-card`)?.scrollIntoView({behavior:"smooth"})})});function L(m){y.forEach(p=>{p&&p.updatePin&&p.updatePin(m)})}function h(m){jt.patch({progress:m==="all"?null:m}),y.forEach(p=>{p&&p.updateRange&&p.updateRange(m)})}if(s.some(m=>m.stats.powerCurve)){let m=no({grid:S,currentTrack:t,allTracks:s,metricKey:"power",label:"Power Curve Progress",unit:"W",color:Rt.power.color,icon:"bolt",onPinChange:L,onRangeChange:h,onTrackSelect:e,gridWidth:I});y.push(m)}if(s.some(m=>m.stats.hrCurve)){let m=no({grid:S,currentTrack:t,allTracks:s,metricKey:"hr",label:"Heart Rate Curve Progress",unit:"bpm",color:Rt.hr.color,icon:"favorite",onPinChange:L,onRangeChange:h,onTrackSelect:e,gridWidth:I});y.push(m)}a!=="all"&&y.forEach(m=>{m&&m.updateRange&&m.updateRange(a)}),An.forEach(m=>{m._ready=!0})}function no(t){let{grid:s,currentTrack:e,allTracks:n,metricKey:i,label:a,unit:r,color:d,icon:l,onPinChange:f,onRangeChange:y,onTrackSelect:S,gridWidth:I}=t,B=e&&e.name||"Current Track",v=null,g=document.createElement("div");g.className="chart-row evolution-card-group",g.id=`${i}-evolution-card`,s.appendChild(g);let E=document.createElement("div");E.className="chart-row progress-chart-row",E.style.setProperty("--chart-color",d),E.style.flex="0 0 400px",E.style.borderBottom="none",E.innerHTML=`
- ${d} - ${i} + ${l} + ${a}
-
+
- `;let v=document.createElement("div");v.className="evolution-legend",v.innerHTML=` + `;let H=document.createElement("div");H.className="evolution-legend",H.innerHTML=`
- - ${I} + + ${B}
All-Time Max
- `;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=` + `;let h=jt.get().progress||"all",m=document.createElement("div");m.className="chart-row progress-chart-row",m.style.setProperty("--chart-color",d),m.style.flex="1",m.style.borderBottom="none",m.innerHTML=`
- ${d} - Progress ${o==="power"?"Power":"HR"} + ${l} + Progress ${i==="power"?"Power":"HR"}
-
+
- `;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+=` + `;let p=document.createElement("div");p.style.cssText="display: flex; flex-direction: row; gap: 0px; align-items: stretch;",p.appendChild(E),p.appendChild(m),g.appendChild(p),g.appendChild(H);let k=E.querySelector(`#${i}-evolution-chart`);if(!k)return;let j={};n.forEach(at=>{let nt=i==="power"?at.stats.powerCurve:at.stats.hrCurve;if(!nt)return;let Ct=at.name||"Unnamed Track",gt=at.stats.startTime||at.addedAt?nn(at.stats.startTime||at.addedAt):"Unknown Date",W=`${Ct} (${gt})`;Object.entries(nt).forEach(([F,it])=>{let K=Number(F),ht=it.power||it.hr;(!j[K]||ht>j[K].val)&&(j[K]={val:ht,trackInfo:W,trackId:at.id,idx:it.idx})})});let U=e&&(i==="power"?e.stats.powerCurve:e.stats.hrCurve)||{},Q=new Set;Object.keys(j).forEach(at=>Q.add(Number(at))),Object.keys(U).forEach(at=>Q.add(Number(at)));let Y=Array.from(Q).sort((at,nt)=>at-nt),G=Y,ot=Y.map(at=>{let nt=U[at];return nt?nt.power||nt.hr:null}),_t=Y.map(at=>j[at]?.val||null),ct=n.filter(at=>(at.stats.startTime||at.addedAt)!=null);ct.sort((at,nt)=>(at.stats.startTime||at.addedAt||0)-(nt.stats.startTime||nt.addedAt||0)||at.id.localeCompare(nt.id));let w=[],b={};Y.forEach(at=>b[at]=[]),ct.forEach(at=>{let nt=i==="power"?at.stats.powerCurve:at.stats.hrCurve;nt&&(w.push((at.stats.startTime||at.addedAt)/1e3),Y.forEach(Ct=>{let gt=nt[Ct],W=gt?i==="power"?gt.power:gt.hr:null;b[Ct].push(W)}))});let u=Y[0]||5,R=ct,M=null;function O(at,nt){let Ct=w[w.length-1]||1785542400,gt=0;nt==="1m"?gt=Ct-30*24*3600:nt==="2m"?gt=Ct-60*24*3600:nt==="6m"?gt=Ct-180*24*3600:nt==="1y"?gt=Ct-365*24*3600:nt==="2y"&&(gt=Ct-2*365*24*3600);let W=[];w.forEach((Pt,ut)=>{Pt>=gt&&W.push(ut)});let F=W.map(Pt=>w[Pt]),it=b[at]||[],K=W.map(Pt=>it[Pt]),ht=En(K,5);return R=W.map(Pt=>ct[Pt]),{xFiltered:F,rawYFiltered:K,smoothedYFiltered:ht}}let q=null,V=document.createElement("div");return V.className="cur-y-val font-m",V.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;",k.style.position="relative",k.appendChild(V),(()=>{let at={id:`${i}-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:d,width:2,fill:le(d,.1),points:{show:!0,size:5,fill:d}},{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:(W,F)=>F.map(it=>`${it}${r}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(W,F,it)=>it,x:!1,y:!1},hooks:{draw:[W=>{let F=W.ctx,it=window.devicePixelRatio||1,K=W.bbox,ht=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],Pt=G[G.length-1];F.save(),F.fillStyle="#555564",F.textAlign="center",F.textBaseline="top",F.font=`${10*it}px system-ui, sans-serif`;let ut=-100;if(ht.forEach(Ht=>{if(Ht>Pt)return;let dt=W.valToPos(Ht,"x",!0);dt>ut+30*it&&dt=0){let dt=W.valToPos(M,"x",!0),Lt=W.valToPos(ot[Ht]||_t[Ht],"y",!0);F.save(),F.beginPath(),F.setLineDash([]);let st=ot[Ht],ft=st!==null?5*it:3*it,At=st!==null?d:"#888888";F.arc(dt,Lt,ft,0,2*Math.PI),F.fillStyle=At,F.fill(),F.strokeStyle="#fff",F.lineWidth=2*it,F.stroke(),F.restore()}}F.restore()},W=>{let F=W.ctx,it=window.devicePixelRatio||1,K=W.bbox,ht=W.cursor.idx,Pt=1,ut=W.cursor.left,Ht=W.cursor.top;if(ut!=null&&Ht!=null&&ut>=0&&Ht>=0){let dt=1/0,Lt=-1,st=30,ft=st*st;for(let At=0;At{if(!W._ready)return;W.redraw(!1);let F=W.cursor.idx,it=1,K=W.cursor.left,ht=W.cursor.top;if(K!=null&&ht!=null&&K>=0&&ht>=0){let Lt=1/0,st=-1,ft=30,At=ft*ft;for(let zt=0;zt${ze(ft)}
`;if(At!==null&&(z+=`
Current: - ${At} ${a} + ${At} ${r}
- `),zt!==null&&(V+=` + `),zt!==null&&(z+=`
Max: - ${zt} ${a} + ${zt} ${r}
- `),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=` + `),V.innerHTML=z,q&&M===null){u=ft;let{xFiltered:_,rawYFiltered:Ft,smoothedYFiltered:It}=O(u,h),Nt=It.map(vt=>vt!==null?vt*.9:null),Et=It.map(vt=>vt!==null?vt*1.1:null);q.setData([_,Ft,It,Nt,Et]);let bt=document.getElementById(`${i}-timeline-label`);bt&&(bt.textContent=`Progress ${ze(ft)} ${i==="power"?"Power":"HR"}`)}V.style.display="",V.style.left=`${K+Ht.left}px`,V.style.top=`${ht+Ht.top}px`,V.style.transform="translate(5px, -50%)"}else V.style.display="none"}]}};v=new Ln(at,[G,ot,_t],k),An.push(v),k.addEventListener("click",()=>{if(!v)return;let W=v.cursor.idx;if(W!=null){let F=G[W],it=null;if(M!==null?it=null:it=F,f(it),e){let K=e.stats,ht=i==="power"?K.powerCurve:K.hrCurve;if(ht){let Pt=ht[F];if(Pt){let ut=Pt.idx,Ht=F,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,ft=(dt.time-st)/1e3,At=(Lt.time-st)/1e3;S?.(e.id,[ft,At])}}}}}}),k.addEventListener("mouseleave",()=>{v&&v.redraw()});let nt=document.createElement("details");nt.classList.add("progress-details"),nt.style.marginTop="0px",nt.style.setProperty("--chart-color",d),nt.innerHTML=` chevron_right table_chart @@ -955,32 +955,32 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<" - ${Y.map(z=>{let D=W[z]?W[z].power||W[z].hr:"-",it=_[z]?.val||"-",K=_[z]?.trackId,bt=_[z]?.idx;return` + ${Y.map(W=>{let F=U[W]?U[W].power||U[W].hr:"-",it=j[W]?.val||"-",K=j[W]?.trackId,ht=j[W]?.idx;return` - ${ze(z)} - ${D} ${a} + ${ze(W)} + ${F} ${r} - ${it} ${a} - ${K?``:""} + ${it} ${r} + ${K?``:""} `}).join("")} - `,g.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=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{W.addEventListener("click",F=>{F.preventDefault(),F.stopPropagation();let it=W.getAttribute("data-id"),K=W.getAttribute("data-idx"),ht=W.getAttribute("data-dur");it&&document.dispatchEvent(new CustomEvent("select-track",{detail:{id:it,idx:K?Number(K):null,dur:ht?Number(ht):null}}))})});let Ct=null,gt=m.querySelector(`#${i}-timeline-chart`);if(gt){gt.style.position="relative";let W=document.createElement("div");if(W.className="timeline-tooltip font-m",W.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;",gt.appendChild(W),w.length>0){let{xFiltered:F,rawYFiltered:it,smoothedYFiltered:K}=O(u,h),ht=K.map(st=>st!==null?st*.9:null),Pt=K.map(st=>st!==null?st*1.1:null),ut=[F,it,K,ht,Pt],Ht=[{value:(st,ft)=>ft!=null?nn(ft*1e3):"-"},{label:"Value",stroke:d,width:0,points:{show:!0,size:6,fill:le(d,.5)}},{label:"Trend",stroke:d,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(`${i}-timeline-label`);dt&&(dt.textContent=`Progress ${ze(u)} ${i==="power"?"Power":"HR"}`);let Lt={width:Math.max(100,(I||570)-400),height:250,padding:[0,10,0,10],tzDate:st=>Ln.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 ft=st.data[0][0],At=st.data[0][st.data[0].length-1];return ft===void 0||At===void 0?[0,100]:ft===At?[ft-3600,At+3600]:[ft,At]}},y:{range:(st,ft,At)=>[ft*.9,At*1.1]}},series:Ht,bands:[{series:[4,3],fill:le(d,.2)}],hooks:{init:[st=>{st.over.addEventListener("click",()=>{if(Ct!=null){let ft=R[Ct];if(ft){let At=ft.stats,zt=i==="power"?At.powerCurve:At.hrCurve;if(zt){let z=zt[u];if(z){let _=z.idx,Ft=u,It=ft.points[_],Nt=ft.points[_+Ft-1];if(It&&Nt&&It.time!=null&&Nt.time!=null){let Et=ft.points[0].time||0,bt=(It.time-Et)/1e3,vt=(Nt.time-Et)/1e3;t.onTrackSelect?.(ft.id,[bt,vt])}else t.onTrackSelect?.(ft.id,null)}else t.onTrackSelect?.(ft.id,null)}else t.onTrackSelect?.(ft.id,null)}}})}],draw:[st=>{let ft=st.cursor.idx;if(ft!=null&&st.data[0][ft]!=null){let At=st.data[1][ft];if(At!=null){let zt=st.valToPos(st.data[0][ft],"x",!0),z=st.valToPos(At,"y",!0),_=st.ctx,Ft=window.devicePixelRatio||1;_.save(),_.beginPath(),_.setLineDash([2*Ft,2*Ft]),_.strokeStyle=le(d,.4),_.lineWidth=1*Ft,_.moveTo(zt,st.bbox.top),_.lineTo(zt,st.bbox.top+st.bbox.height),_.moveTo(st.bbox.left,z),_.lineTo(st.bbox.left+st.bbox.width,z),_.stroke(),_.restore(),_.save(),_.beginPath(),_.setLineDash([]),_.arc(zt,z,12*Ft,0,2*Math.PI),_.fillStyle=le(d,.2),_.fill(),_.restore(),_.save(),_.beginPath(),_.arc(zt,z,6*Ft,0,2*Math.PI),_.fillStyle=d,_.fill(),_.strokeStyle="#fff",_.lineWidth=2*Ft,_.stroke(),_.restore(),_.save(),_.setLineDash([]);let It=new Date(st.data[0][ft]*1e3),Nt=`${It.getUTCFullYear()}-${String(It.getUTCMonth()+1).padStart(2,"0")}-${String(It.getUTCDate()).padStart(2,"0")}`;_.font=`bold ${10*Ft}px system-ui, sans-serif`;let bt=_.measureText(Nt).width+10*Ft,vt=16*Ft,Dt=zt-bt/2,Wt=Math.max(st.bbox.left,Math.min(st.bbox.left+st.bbox.width-bt,Dt)),Ot=st.bbox.top+st.bbox.height+2*Ft;_.fillStyle="rgba(14, 14, 16, 0.92)",_.beginPath(),_.roundRect?_.roundRect(Wt,Ot,bt,vt,3*Ft):_.rect(Wt,Ot,bt,vt),_.fill(),_.strokeStyle=le(d,.27),_.lineWidth=1*Ft,_.stroke(),_.fillStyle=d,_.textAlign="center",_.textBaseline="middle",_.fillText(Nt,Wt+bt/2,Ot+vt/2);let te=`${At.toFixed(0)} ${r}`,Fe=_.measureText(te).width+10*Ft,Pe=st.bbox.left-Fe-2*Ft,_n=z-vt/2;_.fillStyle="rgba(14, 14, 16, 0.92)",_.beginPath(),_.roundRect?_.roundRect(Pe,_n,Fe,vt,3*Ft):_.rect(Pe,_n,Fe,vt),_.fill(),_.strokeStyle=le(d,.27),_.lineWidth=1*Ft,_.stroke(),_.fillStyle=d,_.textAlign="left",_.textBaseline="middle",_.fillText(te,Pe+5*Ft,_n+vt/2),_.restore()}}}],setCursor:[st=>{if(!st._ready)return;st.redraw(!1);let ft=st.cursor.idx,At=st.cursor.left,zt=st.cursor.top,z=st.bbox;if(At!=null&&zt!=null&&At>=0&&zt>=0){let _=1/0,Ft=-1,It=30,Nt=It*It,Et=st.data[0],bt=st.data[1];for(let vt=0;vt Date: ${Et}
Value: - ${yt} + ${vt}
- `,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=` + `,W.style.display="block",W.style.left=`${At+z.left}px`,W.style.top=`${zt+z.top}px`,W.style.transform="translate(5px, -50%)"}else W.style.display="none"}]},axes:[{space:50,stroke:"#555564",grid:{stroke:"#2e2e34"},show:!0,font:"10px system-ui, sans-serif",size:30,values:(st,ft)=>ft.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,ft)=>ft.map(At=>`${At} ${r}`),show:!0,space:15,size:50}]};q=new Ln(Lt,ut,gt),An.push(q),gt.addEventListener("mouseleave",()=>{q.redraw()})}else gt.innerHTML='
No data for the past year
'}})(),{updatePin:at=>{M=at,at!==null&&(u=at);let nt=document.getElementById(`${i}-timeline-label`);if(nt&&(nt.textContent=`Progress ${ze(u)} ${i==="power"?"Power":"HR"}${M!==null?" (Pinned)":""}`),q){let{xFiltered:Ct,rawYFiltered:gt,smoothedYFiltered:W}=O(u,h),F=W.map(K=>K!==null?K*.9:null),it=W.map(K=>K!==null?K*1.1:null);q.setData([Ct,gt,W,F,it])}v&&v.redraw()},updateRange:at=>{if(h=at,q){let{xFiltered:nt,rawYFiltered:Ct,smoothedYFiltered:gt}=O(u,h),W=gt.map(it=>it!==null?it*.9:null),F=gt.map(it=>it!==null?it*1.1:null);q.setData([nt,Ct,gt,W,F])}}}}function ro(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),i=ro(n),a=i.toISOString().split("T")[0];s[a]||(s[a]={timestamp:i.getTime(),distance:0}),s[a].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 ii(t){let s={};return t.forEach(e=>{if(!e.stats.startTime||e.stats.elevGain===void 0)return;let n=new Date(e.stats.startTime),i=ro(n),a=i.toISOString().split("T")[0];s[a]||(s[a]={timestamp:i.getTime(),elevation:0}),s[a].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 ai(t){let s={};return t.forEach(e=>{if(!e.stats.startTime||!e.stats.totalDist)return;let n=new Date(e.stats.startTime),i=new Date(Date.UTC(n.getUTCFullYear(),n.getUTCMonth(),1)),a=i.toISOString().slice(0,7);s[a]||(s[a]={timestamp:i.getTime(),distance:0}),s[a].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 ri(t){let s={};return t.forEach(e=>{if(!e.stats.startTime||e.stats.elevGain===void 0)return;let n=new Date(e.stats.startTime),i=new Date(Date.UTC(n.getUTCFullYear(),n.getUTCMonth(),1)),a=i.toISOString().slice(0,7);s[a]||(s[a]={timestamp:i.getTime(),elevation:0}),s[a].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 so(t,s,e,n,i,a){let r=e==="distance",d=js,l=jt.get().progress||"all",f=r?oi(s):ii(s),y=r?ai(s):ri(s),S=d==="month"?y:f,I=gn(s,ct=>r?ct.stats.totalDist:ct.stats.elevGain),B=r?Rt.distance.color:Rt.elevation.color,v=r?"km":"m",g=r?Rt.distance.icon:Rt.elevation.icon,E=document.createElement("div");E.className=`chart-row ${e}-progress-card`,E.id=`${e}-evolution-card`,E.innerHTML=`
- ${g} - ${a?"Distance Progress":"Elevation Progress"} + ${g} + ${r?"Distance Progress":"Elevation Progress"}
@@ -989,18 +989,18 @@ var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"
- ${sl(F,a,b)} + ${Kl(I,r,v)}
- `,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} - ${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=` + `,t.appendChild(E);let H=E.querySelector(`#${e}-weekly-chart`),L=E.querySelector(`#${e}-y-axis-chart`);if(!H||!L)return;H.style.position="relative";let h=document.createElement("div");h.className="cur-y-val",h.style.cssText=`color:${B};display:none`,H.appendChild(h);let m=S.map(ct=>ct.timestamp/1e3),p=r?S.map(ct=>ct.distance/1e3):S.map(ct=>ct.elevation);if(m.length===0)return;let k=En(p,2),j=Math.max(0,(a||570)-20-320-20),U=Math.max(j,m.length*40),Q=Math.max(...p)*1.1,Y={width:U,height:150,padding:[10,10,0,10],tzDate:ct=>Ln.tzDate(new Date(ct*1e3),"Etc/UTC"),scales:{x:{time:!0},y:{range:[0,Q]}},series:[{},{label:r?"Distance":"Elevation",stroke:B,fill:le(B,.1),width:2,points:{show:!0,size:4}},{label:"Trend",stroke:B,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:[ct=>{ct.over.addEventListener("click",()=>{let w=ct.cursor.idx;if(w!=null){let b=S[w];if(b){let u=new Date(b.timestamp),R=new Date(b.timestamp+7*24*60*60*1e3),M=u.toISOString().split("T")[0],O=R.toISOString().split("T")[0];i?.(M,O)}}})}],setCursor:[ct=>{if(!ct._ready)return;let w=ct.cursor.idx,b=ct.cursor.left,u=ct.cursor.top;if(w!=null&&b!=null&&u!=null&&b>=0&&u>=0){let R=ct.data[1][w],M=R!=null?r?`${R.toFixed(1)} km`:`${R.toFixed(0)} m`:"\u2014";h.innerHTML=M,h.style.display="block",h.style.left=`${ct.valToPos(ct.data[0][w],"x",!1)}px`,h.style.top=`${ct.valToPos(ct.data[1][w],"y",!1)}px`,h.style.transform="translate(6px, -50%)"}else h.style.display="none";ct.redraw(!1)}],draw:[ct=>{let w=ct.cursor.idx;if(w!=null&&ct.data[0][w]!=null){let b=ct.valToPos(ct.data[0][w],"x",!0),u=ct.valToPos(ct.data[1][w],"y",!0),R=window.devicePixelRatio||1,M=ct.ctx,O=ct.bbox;M.save(),M.beginPath(),M.setLineDash([2*R,2*R]),M.strokeStyle=le(B,.4),M.lineWidth=1*R,M.moveTo(b,O.top),M.lineTo(b,O.top+O.height),M.moveTo(O.left,u),M.lineTo(O.left+O.width,u),M.stroke(),M.restore(),M.save(),M.beginPath(),M.setLineDash([]),M.arc(b,u,12*R,0,2*Math.PI),M.fillStyle=le(B,.2),M.fill(),M.restore(),M.save(),M.beginPath(),M.arc(b,u,6*R,0,2*Math.PI),M.fillStyle=B,M.fill(),M.strokeStyle="#fff",M.lineWidth=2*R,M.stroke(),M.restore(),M.save(),M.setLineDash([]);let q=new Date(ct.data[0][w]*1e3),V=`${q.getUTCFullYear()}-${String(q.getUTCMonth()+1).padStart(2,"0")}-${String(q.getUTCDate()).padStart(2,"0")}`;M.font=`bold ${10*R}px system-ui, sans-serif`;let at=M.measureText(V).width+10*R,nt=16*R,Ct=b-at/2,gt=Math.max(O.left,Math.min(O.left+O.width-at,Ct)),W=O.top+O.height+2*R;M.fillStyle="rgba(14, 14, 16, 0.92)",M.beginPath(),M.roundRect?M.roundRect(gt,W,at,nt,3*R):M.rect(gt,W,at,nt),M.fill(),M.strokeStyle=le(B,.27),M.lineWidth=1*R,M.stroke(),M.fillStyle=B,M.textAlign="center",M.textBaseline="middle",M.fillText(V,gt+at/2,W+nt/2),M.restore()}}]},axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,space:40,values:(ct,w)=>w.map(b=>{let u=new Date(b*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:(ct,w)=>w.map(b=>`${b.toFixed(0)} ${v}`),font:"10px system-ui, sans-serif",size:40}]},G=new Ln(Y,[m,p,k],H);An.push(G);let ot=E.querySelector(".chart-scroll-container");ot&&m.length*40>U&&(ot.scrollLeft=ot.scrollWidth-ot.clientWidth);function _t(){S=d==="month"?y:f;let ct=S[S.length-1]?.timestamp||17855424e5,w=0;l==="1m"?w=ct-30*24*3600*1e3:l==="2m"?w=ct-60*24*3600*1e3:l==="6m"?w=ct-180*24*3600*1e3:l==="1y"?w=ct-365*24*3600*1e3:l==="2y"&&(w=ct-2*365*24*3600*1e3);let b=S.filter(V=>V.timestamp>=w),u=b.map(V=>V.timestamp/1e3),R=r?b.map(V=>V.distance/1e3):b.map(V=>V.elevation),M=En(R,2),O=Math.max(H.clientWidth,u.length*40),q=Math.max(1,...R)*1.1;G.setSize({width:O,height:150}),G.setScale("y",{min:0,max:q}),G.setData([u,R,M]),ot&&(ot.scrollLeft=ot.scrollWidth-ot.clientWidth)}return{updateRange:ct=>{l=ct,_t()},updateGrouping:ct=>{d=ct,_t()}}}var co=["#FF6B35","#4ECDC4","#45B7D1","#F7DC6F","#FF6B6B","#BB8FCE","#82E0AA","#F8C471","#3b82f6"],ci=16,Gt={},He=[];function di(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 In=!1,Xt=null,Zs=0,Kn=!1,Dn=null,Ke="",bn=!1,vn="date-desc",wt={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null};function hn(t=!1){jt.patch({f_date:wt.date.every(s=>s===null)?null:wt.date,f_dist:wt.dist.every(s=>s===null)?null:wt.dist,f_dur:wt.dur.every(s=>s===null)?null:wt.dur,f_mets:wt.metrics.size===0?null:Array.from(wt.metrics),f_tags:wt.tags.length===0?null:wt.tags},t)}function Xs(){let t=St.getActiveMetrics(),s=St.METRICS,e=Array.from(t).map(n=>s[n].abbr);jt.patch({metrics:e.length?e:null})}var fo=[{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(i=>i.remove());let s=document.createElement("div");s.className="sort-menu-popup",fo.forEach(i=>{let a=document.createElement("div");a.className=`menu-item ${vn===i.val?"active":""}`,a.innerHTML=` + ${i.icon} + ${i.label} + ${vn===i.val?"check":""} + `,a.addEventListener("click",()=>{vn=i.val,jt.patch({sort:i.val}),ho(),Sn(),s.remove()}),s.appendChild(a)});let e=t.getBoundingClientRect();s.style.top=`${e.bottom+5}px`,s.style.left=`${e.left}px`,document.body.appendChild(s);let n=i=>{!s.contains(i.target)&&!t.contains(i.target)&&(s.remove(),document.removeEventListener("click",n))};setTimeout(()=>document.addEventListener("click",n),0)}function mi(t){document.querySelectorAll(".metric-menu-popup").forEach(d=>d.remove());let s=document.createElement("div");s.className="metric-menu-popup";let e=St.METRICS,n=St.getAvailableMetrics(),i=St.getActiveMetrics();Object.entries(e).forEach(([d,l])=>{if(!n.has(d))return;let f=document.createElement("div");f.className=`menu-item ${i.has(d)?"active":""}`,f.innerHTML=` + ${l.icon} + ${l.label} + ${i.has(d)?"check":""} + `,f.addEventListener("click",()=>{St.toggleMetric(d);let y=St.getActiveMetrics().has(d);f.classList.toggle("active",y),f.querySelector(".check").textContent=y?"check":"";let S=document.querySelector(`#metric-pills .metric-pill[data-metric="${d}"]`);S&&S.classList.toggle("active",y),Fn(),Xs()}),s.appendChild(f)});let a=t.getBoundingClientRect();s.style.top=`${a.bottom+5}px`,s.style.right=`${window.innerWidth-a.right}px`,document.body.appendChild(s);let r=d=>{!s.contains(d.target)&&!t.contains(d.target)&&(s.remove(),document.removeEventListener("click",r))};setTimeout(()=>document.addEventListener("click",r),0)}document.addEventListener("select-track",t=>{let s=t.detail.id,e=t.detail.idx,n=t.detail.dur;if(s&&Gt[s]&&(We(s),e!=null&&n!=null)){let i=Gt[s],a=i.points;if(e>=0&&eB.time!=null)?.time||0,l=(r.time-d)/1e3,f=l+n;St.restoreSelection(l,f);let y=a.findIndex(B=>(B.time||0)>=r.time+n*1e3);y===-1&&(y=a.length-1);let S=a.slice(e,y+1),I=re.computeStats(S);St.setSelectionStats(I),ke(i),qt.highlightSegment(s,a,e,y,!1,Dn),qt.ensureVisible(S.map(B=>[B.lat,B.lon])),jt.patch({sel:[l,f]})}}}});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(a=>a.classList.toggle("active",a===s));let n=s.dataset.tab;jt.patch({tab:n},!0);let i=e.closest("#chart-panel");if(i&&i.querySelectorAll(".tab-content").forEach(a=>{a.classList.toggle("active",a.id===`tab-${s.dataset.tab}`)}),s.dataset.tab==="details"&&Xt&&Gt[Xt]&&Ee(Gt[Xt],Qs()),s.dataset.tab==="insights"&&Xt&&Gt[Xt]&&ke(Gt[Xt]),s.dataset.tab==="evolution"&&Ms(Xt?Gt[Xt]:null,Object.values(Gt),(a,r)=>{We(a,!0),r&&(St.restoreSelection(r[0],r[1]),Bn(r[0],r[1],"time",!0))},(a,r)=>{wt.date=[a,r],Ce(),hn(!0),Jn()}),s.dataset.tab==="combined"&&Xt&&Gt[Xt]&&qe(Gt[Xt]),s.dataset.tab==="courses"&&je(),s.dataset.tab==="graphs"){St.resize(),Fn();let a=jt.get().sel;a&&St.restoreSelection(a[0],a[1])}});async function uo(){typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed(),await ge.clear(),Gt={},He=[],Xt=null,Zs=0,Dn=null,In=!1,Kn=!1,Ke="",bn=!1,vn="date-desc",wt.date=[null,null],wt.dist=[null,null],wt.dur=[null,null],wt.metrics.clear(),wt.tags=[],re.setHRZones([120,140,160,180]),re.setFTP(200),_l(),Gl(),kl(),Ql(),oo(),qt.removeAllTracks&&qt.removeAllTracks(),qt.clearTracks&&qt.clearTracks(),qt.clearHighlight(),St.resetState?St.resetState():St.clear&&St.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")}),jt.reset();let t=document.getElementById("toast-container");t&&(t.innerHTML=""),document.querySelectorAll(".modal-backdrop").forEach(s=>s.remove()),typeof Sn=="function"&&Sn()}var mo=!1;async function pi(){if(mo){qs((l,f)=>Hn(l,f==="error"?"error":"info")),Ds(()=>{Ce(),hn()},l=>{po(l)}),Bs((l,f)=>Hn(l,f==="error"?"error":"info")),Fn(),await ge.openDB(),await uo();return}mo=!0;let t=document.getElementById("storage-backend-select");t&&(t.value=jt.get().storage||"memory",t.addEventListener("change",l=>{let f=l.target.value,y=new URLSearchParams(window.location.search);f==="memory"?y.delete("storage"):y.set("storage",f),window.location.search=y.toString()}));let s=document.getElementById("map-loader"),e=s?.querySelector("span");s&&(e&&(e.textContent="Loading database..."),s.classList.remove("hidden"));let n=jt.get();qs((l,f)=>Hn(l,f==="error"?"error":"info")),Ds(()=>{Ce(),hn()},l=>{po(l)}),Bs((l,f)=>Hn(l,f==="error"?"error":"info")),qt.init(l=>We(l),vi,yi,(l,f)=>{l===Xt?St.setHoverAt(f):St.setHoverAt(null)},xi),St.init(wi,Bn,Ti,l=>{jt.patch({sel_point:l})}),St.setMapColorChangeCb(l=>{l?(Dn=l.colors,Xt&&qt.colorTrackByMetric(Xt,l.pts,l.colors)):(Dn=null,Xt&&qt.clearMetricColor(Xt));let f=jt.get();f.sel&&Bn(f.sel[0],f.sel[1],St.getXAxis())}),Mi(n),await ge.openDB(),await uo(),s&&s.classList.add("hidden"),hi(),bi(),Pi(),Fn(),document.getElementById("basemap-switcher")?.addEventListener("click",l=>{let f=l.target.closest(".bm-btn");f&&(document.querySelectorAll(".bm-btn").forEach(y=>y.classList.remove("active")),f.classList.add("active"),f.dataset.layer&&(qt.switchBasemap(f.dataset.layer),jt.patch({map:f.dataset.layer})))}),document.getElementById("btn-fit-all")?.addEventListener("click",()=>qt.fitAll()),document.getElementById("btn-clear-all")?.addEventListener("click",Si),document.getElementById("track-search")?.addEventListener("input",l=>{Ke=l.target.value,Ce(),jt.patch({q:Ke||null})}),document.getElementById("btn-regex-toggle")?.addEventListener("click",l=>{bn=!bn,l.target.classList.toggle("active",bn),Ce(),jt.patch({re:bn?1:null})}),document.getElementById("btn-sort-menu")?.addEventListener("click",l=>{l.stopPropagation(),ui(l.currentTarget)}),document.getElementById("btn-metric-menu")?.addEventListener("click",l=>{l.stopPropagation(),mi(l.currentTarget)});let i=(l,f)=>{f&&f.classList.toggle("active"),St.toggleMetric(l),Xs()};document.getElementById("metric-pills")?.addEventListener("click",l=>{let f=l.target.closest(".metric-pill");if(f){let y=f.dataset.metric;y&&(i(y,f),St.getActiveMetrics().has(y)&&document.querySelector(`.chart-row[data-metric="${y}"]`)?.scrollIntoView({behavior:"smooth"}))}}),document.getElementById("x-axis-ctrl")?.addEventListener("click",l=>{let f=l.target.closest(".seg-btn");if(!f)return;let y=f.dataset.axis;St.setXAxis(y),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(S=>S.classList.toggle("active",S===f)),jt.patch({xaxis:y})}),document.getElementById("btn-follow-dot")?.addEventListener("click",l=>{Kn=!Kn,l.currentTarget.classList.toggle("active",Kn)}),document.getElementById("btn-reset-zoom")?.addEventListener("click",()=>{St.resetZoom(),qt.clearHighlight()}),Ci(),document.getElementById("file-input")?.addEventListener("change",l=>{$s(Array.from(l.target.files||[])),l.target.value=""}),document.getElementById("folder-input")?.addEventListener("change",l=>{$s(Array.from(l.target.files||[])),l.target.value=""}),document.getElementById("btn-toggle-filters")?.addEventListener("click",()=>{let l=document.getElementById("filter-panel");l&&(l.classList.toggle("hidden"),document.getElementById("btn-toggle-filters")?.classList.toggle("active",!l.classList.contains("hidden")))});let a=(l,f,y)=>{let S=y.target.value;wt[l][f]=S===""?null:S,Ce(),hn()};document.getElementById("filter-date-start")?.addEventListener("change",l=>a("date",0,l)),document.getElementById("filter-date-end")?.addEventListener("change",l=>a("date",1,l)),document.getElementById("filter-dist-min")?.addEventListener("input",l=>a("dist",0,l)),document.getElementById("filter-dist-max")?.addEventListener("input",l=>a("dist",1,l)),document.getElementById("filter-dur-min")?.addEventListener("input",l=>a("dur",0,l)),document.getElementById("filter-dur-max")?.addEventListener("input",l=>a("dur",1,l));let r=document.getElementById("sport-burger-btn"),d=document.getElementById("sport-dropdown-content");r?.addEventListener("click",l=>{if(l.stopPropagation(),d){let f=d.style.display==="block";d.style.display=f?"none":"block"}}),document.addEventListener("click",l=>{d&&d.style.display==="block"&&!d.contains(l.target)&&l.target!==r&&(d.style.display="none")}),document.getElementById("sport-filter-container")?.addEventListener("click",l=>{let f=l.target,y=f.closest("[data-sport]");if(y){let S=y.dataset.sport||null;wt.sport=wt.sport===S?null:S,Ce(),hn(),Jn(),f.closest(".dropdown-item")&&d&&(d.style.display="none")}}),document.getElementById("filter-metrics")?.addEventListener("click",l=>{let f=l.target.closest(".mini-pill");if(!f)return;let y=f.dataset.metric;wt.metrics.has(y)?wt.metrics.delete(y):wt.metrics.add(y),Jn(),Ce(),hn()}),document.getElementById("btn-reset-filters")?.addEventListener("click",()=>{wt={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null},Jn(),Ce(),hn()}),document.getElementById("filter-tags")?.addEventListener("input",l=>{let f=l.target.value;wt.tags=f.split(",").map(y=>y.trim().toLowerCase()).filter(y=>!!y),Ce(),hn()}),document.addEventListener("keydown",l=>{l.key==="Escape"&&(qt.hideCursor(),qt.closePopup?.(),document.querySelectorAll(".color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop").forEach(f=>f.remove()))}),window.addEventListener("resize",()=>{St.resize(),Gn(),qt.invalidateSize?.(),Fn()})}async function fi(){let t=null,s=new Promise(i=>{t=window.setTimeout(i,1e3)});try{let i=document.fonts?Promise.all([document.fonts.load('24px "Material Symbols Rounded"').catch(()=>{}),document.fonts.ready]):Promise.resolve();await Promise.race([i,s])}finally{t!==null&&window.clearTimeout(t)}document.body.classList.remove("loading-fonts"),gi(),await go();let e=document.createElement("div");e.id="app-is-ready",e.setAttribute("data-ready","true"),e.style.display="none",document.body.appendChild(e);let n=document.createElement("div");n.id="appIsReady",n.setAttribute("data-ready","true"),n.style.display="none",document.body.appendChild(n)}var Es=null;async function go(){if(Es)return Es;try{let s=await(await fetch("./test-data/manifest.json")).json(),e=new TextDecoder;return Es=await Promise.all(s.map(async n=>{let a=await(await fetch(`./test-data/${n}`)).arrayBuffer(),r=n;if(n.toLowerCase().endsWith(".gz")){r=n.slice(0,-3);let f=new Uint8Array(a);if(f.length>=2&&f[0]===31&&f[1]===139){let y=new DecompressionStream("gzip"),S=new Blob([a]).stream().pipeThrough(y);a=await new Response(S).arrayBuffer()}}let d=r.toLowerCase().endsWith(".fit")?void 0:e.decode(a),l=new File([a],r,{type:"application/octet-stream"});return l._buf=a,d!==void 0&&(l._text=d),{cleanName:r,buf:a,text:d,file:l}})),typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed(),Es}catch{return[]}}function gi(){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"),i=document.getElementById("btn-step-aggregate"),a=document.getElementById("btn-step-evolution"),r=document.getElementById("btn-step-courses");function d(l){document.querySelectorAll(".tab-btn").forEach(f=>{f.classList.toggle("active",f.dataset.tab===l)}),document.querySelectorAll(".tab-content").forEach(f=>{f.classList.toggle("active",f.id===`tab-${l}`)}),jt.patch({tab:l},!1)}t?.addEventListener("click",async()=>{try{await pi();let f=(await go()).map(S=>S.file);await $s(f,!0);let y=Object.values(Gt);re.findOverlaps(y);for(let S of["dist-desc","dur-desc","date-asc","date-desc"])vn=S,Sn();wt.sport="cycling",Ce(),wt.sport=null,wt.metrics.add("power"),Ce(),wt.metrics.clear(),Ke="Alpine",Ce(),Ke="",Ce(),!Xt&&y.length>0&&We(y[0].id,!0,!0)}finally{window.dispatchEvent(new CustomEvent("load-and-parse-complete"))}}),s?.addEventListener("click",()=>{try{let l=Object.values(Gt);d("graphs"),!Xt&&l.length>0&&We(l[0].id,!1,!0);let f=St.getAvailableMetrics(),y=[["elevation","speed","power"]];for(let I of y){let B=I.filter(v=>f.has(v));B.length>0&&(document.querySelectorAll("#metric-pills .metric-pill").forEach(v=>{let g=v.dataset.metric;g&&v.classList.toggle("active",B.includes(g))}),Fn(),St.setActiveMetrics(B))}St.setSmooth("power",!0,!0),St.toggleMapColor("power",!0),St.toggleMapColor(null,!0),St.setXAxis("distance"),St.setSmooth("power",!1,!0),St.setXAxis("time");let S=[[0,360,180],[120,900,300]];for(let[I,B,v]of S)St.restoreSelection(I,B,!0),St.setCursorAt(v,!0),St.analyzeTelemetryIntervals(l,I,B),Bn(I,B,St.getXAxis(),!1)}finally{window.dispatchEvent(new CustomEvent("analysis-complete"))}}),e?.addEventListener("click",()=>{try{let l=Object.values(Gt);l.forEach(y=>re.ensureCurvesAndZones(y)),d("insights");let f=Xt&&Gt[Xt]||l[0]||null;for(let y of[1,2,4]){let S=l[y];S&&(ke(S,l,[0,600]),ke(S,l,null))}l[3]&&ke(l[3],l,[200,900]),f&&(ke(f,l,[0,600]),ke(f,l,[600,1200])),ke(f,l,null)}finally{window.dispatchEvent(new CustomEvent("insights-complete"))}}),n?.addEventListener("click",()=>{try{let l=Object.values(Gt);d("details");let f=Qs(),y=Xt&&Gt[Xt]||l[0]||null;for(let S=0;S{try{let l=Object.values(Gt);if(l.length>=2){d("combined"),Us("distance","elevation"),qe(l[0],l);for(let y of[.25,.5,.75,1])Ss(y);Vs(!0),Ss(.5),Vs(!1),Us("power","hr");for(let y of[.3,.7])Ss(y);l.length>=6&&qe(l,l);let f=[l[0],l[1]];qe(f,l)}}finally{window.dispatchEvent(new CustomEvent("aggregate-complete"))}}),a?.addEventListener("click",()=>{try{let l=Object.values(Gt);d("evolution");let f=Xt&&Gt[Xt]||l[0]||null,y=(I,B)=>{We(I,!0),B&&(St.restoreSelection(B[0],B[1]),Bn(B[0],B[1],"time",!0))},S=[l[2]||f,f];for(let I of S){Ms(I,l,y),Gs("month");for(let B of["1m","6m","1y","all"])io(B);Gs("week");for(let B of[5,60,300,1200,null])ao(B)}}finally{window.dispatchEvent(new CustomEvent("evolution-complete"))}}),r?.addEventListener("click",()=>{try{let l=Object.values(Gt);d("courses"),Rl(l);let f=Nl();for(let y of f)Pn(y,!0);Pn("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()}}function hi(){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 i=window.innerHeight-n.clientY,a=Math.max(100,Math.min(window.innerHeight-100,i));s.style.height=`${a}px`,St.resize(),Gn(),qt.invalidateSize?.()}),document.addEventListener("mouseup",()=>{e&&(e=!1,document.body.style.cursor="")})}function bi(){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 i=n.clientX,a=Math.max(200,Math.min(600,i));s.style.width=`${a}px`,s.style.setProperty("--sidebar-w",`${a}px`),St.resize(),qt.invalidateSize?.()}),document.addEventListener("mouseup",()=>{e&&(e=!1,t.classList.remove("dragging"),document.body.classList.remove("dragging-sidebar"))})}function vi(t,s,e){jt.patch({map_pos:[t,s,e]})}function yi(t,s){We(t,!1),St.setCursorAt(s)}function xi(){}function wi(t){t&&t.lat!=null&&t.lon!=null?(qt.showCursorAt(t.lat,t.lon),Kn&&qt.centerOn(t.lat,t.lon,null,!0)):qt.hideCursor()}function Bn(t,s,e,n=!1){if(!Xt||!Gt[Xt])return;let i=Gt[Xt];if(t===null||s===null){qt.clearHighlight(),i&&(jt.get().tab||"graphs")==="insights"&&ke(i),jt.patch({sel:null});return}let a=i.points,r=0,d=a.length-1;if(e==="distance"){let y=t*1e3,S=s*1e3;r=a.findIndex(I=>(I.dist||0)>=y),d=a.findIndex(I=>(I.dist||0)>=S)}else{let y=a.find(B=>B.time!=null)?.time||0,S=y+t*1e3,I=y+s*1e3;r=a.findIndex(B=>(B.time||0)>=S),d=a.findIndex(B=>(B.time||0)>=I)}r===-1&&(r=0),d===-1&&(d=a.length-1);let l=a.slice(r,d+1),f=re.computeStats(l);St.setSelectionStats(f),(jt.get().tab||"graphs")==="insights"&&ke(i),qt.highlightSegment(Xt,a,r,d,n,Dn),qt.ensureVisible(l.map(y=>[y.lat,y.lon])),jt.patch({sel:[t,s]})}function Ti(t,s){t&&t.lat!=null&&t.lon!=null&&qt.centerOn(t.lat,t.lon,ci)}function We(t,s=!0,e=!1){if(!Gt[t])return;if(t===Xt){s&&qt.fitTrack(t);return}let n=Xt!==null;n&&(St.clear(),Ee(null,[]),ke(null)),Xt=t,Dn=null,qt.clearMetricColor(t),n&&St.toggleMapColor(null),jt.patch({track:t,sel:null},!0),n&&St.cancelSelection(),Sn();let i=jt.get().tab||"graphs";i==="details"&&Ee(Gt[t],Qs()),i==="insights"&&ke(Gt[t]),i==="combined"&&qe(Gt[t]),i==="courses"&&je(),i==="evolution"&&Ms(Gt[t],Object.values(Gt),(a,r)=>{We(a,!0),r&&(St.restoreSelection(r[0],r[1]),Bn(r[0],r[1],"time",!0))}),qt.setSelectedTrack(t,s),s&&qt.fitTrack(t),St.loadTrack(Gt[t],Object.values(Gt),e)}async function po(t){await ge.remove(t),qt.removeTrack(t),delete Gt[t],Xt===t&&(Xt=null,St.clear(),Ee(null,[]),ke(null),jt.patch({track:null,sel:null,sel_point:null})),Ce()}async function Si(){let t=Math.floor(10+Math.random()*90).toString(),s=document.createElement("div");s.className="modal-backdrop",s.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=` + `,document.body.appendChild(s);let e=s.querySelector(".modal-input"),n=s.querySelector(".modal-btn.confirm"),i=s.querySelector(".modal-btn.cancel");e.focus(),e.addEventListener("input",()=>{n.disabled=e.value!==t});let a=()=>s.remove();i.addEventListener("click",a),s.addEventListener("click",r=>{r.target===s&&a()}),n.addEventListener("click",async()=>{e.value===t&&(a(),In=!0,await ge.clear(),Gt={},Xt=null,qt.clearHighlight(),window.location.reload())})}function Ce(t=!1){Object.keys(Gt).forEach(e=>{let n=Gt[e],i=n.stats,a=!0;if(Ke)if(bn)try{new RegExp(Ke,"i").test(n.name)||(a=!1)}catch{a=!1}else n.name.toLowerCase().includes(Ke.toLowerCase())||(a=!1);if(a&&(wt.date[0]||wt.date[1])){let r=wt.date[0]?new Date(wt.date[0]).getTime():0,d=wt.date[1]?new Date(wt.date[1]).getTime():1/0,l=i.startTime||0;(ld)&&(a=!1)}if(a&&(wt.dist[0]!==null||wt.dist[1]!==null)){let r=(wt.dist[0]||0)*1e3,d=(wt.dist[1]||1/0)*1e3;(i.totalDistd)&&(a=!1)}if(a&&(wt.dur[0]!==null||wt.dur[1]!==null)){let r=(wt.dur[0]||0)*6e4,d=(wt.dur[1]||1/0)*6e4,l=i.duration||0;(ld)&&(a=!1)}if(a&&wt.metrics.size>0)for(let r of wt.metrics){let d=St.METRICS[r].field;if(!n.points.some(l=>l[d]!=null)){a=!1;break}}if(a&&wt.sport&&n.sport!==wt.sport&&(a=!1),a&&wt.tags.length>0){let r=n.tags||[];wt.tags.every(d=>r.includes(d))||(a=!1)}n._filtered=!a,qt.setTrackVisible(n.id,n.visible&&a)}),t||Sn()}function Jn(){document.getElementById("filter-date-start").value=wt.date[0]||"",document.getElementById("filter-date-end").value=wt.date[1]||"",document.getElementById("filter-dist-min").value=wt.dist[0]!==null?String(wt.dist[0]):"",document.getElementById("filter-dist-max").value=wt.dist[1]!==null?String(wt.dist[1]):"",document.getElementById("filter-dur-min").value=wt.dur[0]!==null?String(wt.dur[0]):"",document.getElementById("filter-dur-max").value=wt.dur[1]!==null?String(wt.dur[1]):"",document.getElementById("filter-tags").value=wt.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||"")===(wt.sport||""))}),document.querySelectorAll("#filter-metrics .mini-pill").forEach(e=>{let n=e;n.classList.toggle("active",wt.metrics.has(n.dataset.metric))});let t=(wt.date[0]?1:0)+(wt.date[1]?1:0)+(wt.dist[0]!==null?1:0)+(wt.dist[1]!==null?1:0)+(wt.dur[0]!==null?1:0)+(wt.dur[1]!==null?1:0)+wt.metrics.size+(wt.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 ho(){let t=document.getElementById("track-search");t&&(t.value=Ke),document.getElementById("btn-regex-toggle")?.classList.toggle("active",bn);let s=fo.find(e=>e.val===vn);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 Mi(t){let s=t.track;if(s!==Xt&&(s&&Gt[s]?We(s,!0):!s&&Xt&&(Xt=null,St.clear(),Ee(null,[]),ke(null),Sn(),qt.fitAll())),t.map&&typeof t.map=="string"&&(qt.switchBasemap(t.map),document.querySelectorAll(".bm-btn").forEach(n=>n.classList.toggle("active",n.dataset.layer===t.map))),t.map_pos){let[n,i,a]=t.map_pos;qt.setPosition(n,i,a)}t.tab&&document.querySelectorAll(".tab-btn").forEach(n=>{let i=n;i.dataset.tab===t.tab&&(i.classList.contains("active")||i.click())}),t.xaxis&&St.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=St.METRICS,i=t.metrics.map(a=>Object.keys(n).find(r=>n[r].abbr===a)).filter(a=>a!==void 0);i.length&&St.setActiveMetrics(i)}t.f_date&&(wt.date=t.f_date.map(n=>n||null)),t.f_dist&&(wt.dist=t.f_dist.map(n=>n===0?0:n||null)),t.f_dur&&(wt.dur=t.f_dur.map(n=>n===0?0:n||null)),t.f_mets&&(wt.metrics=new Set(t.f_mets)),t.f_tags&&(wt.tags=t.f_tags),Jn(),t.q&&(Ke=t.q),t.re&&(bn=t.re),t.sort&&(vn=t.sort),ho(),Ce()}function Ei(){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(Gt).forEach(r=>{r.sport&&n.add(r.sport)});let i=Array.from(n).sort(),a=document.getElementById("sport-burger-dropdown");s.innerHTML="",e.innerHTML="",i.length<=4?(a&&(a.style.display="none"),i.forEach(r=>{let d=document.createElement("button");d.className=`mini-pill${wt.sport===r?" active":""}`,d.dataset.sport=r,d.title=r.charAt(0).toUpperCase()+r.slice(1),d.innerHTML=`${ks(r)}`,s.appendChild(d)})):(a&&(a.style.display="inline-block"),["running","cycling","walking"].forEach(d=>{if(n.has(d)){let l=document.createElement("button");l.className=`mini-pill${wt.sport===d?" active":""}`,l.dataset.sport=d,l.title=d.charAt(0).toUpperCase()+d.slice(1),l.innerHTML=`${ks(d)}`,s.appendChild(l)}}),i.forEach(d=>{let l=document.createElement("div");l.className=`dropdown-item${wt.sport===d?" active":""}`,l.dataset.sport=d,l.style.padding="8px",l.style.cursor="pointer",l.style.display="flex",l.style.alignItems="center",l.style.gap="8px",l.innerHTML=` + ${ks(d)} + ${d.charAt(0).toUpperCase()+d.slice(1)} + `,e.appendChild(l)}))}function Sn(){Ei();let t=document.getElementById("track-list"),s=document.getElementById("track-list-empty"),e=document.querySelector(".section-label");if(!t)return;let n=Object.keys(Gt).filter(i=>!Gt[i]._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((i,a)=>{if(i===Xt)return-1;if(a===Xt)return 1;let r=Gt[i],d=Gt[a],l=r.stats,f=d.stats,y=0;switch(vn){case"date-asc":y=(l.startTime||0)-(f.startTime||0);break;case"date-desc":y=(f.startTime||0)-(l.startTime||0);break;case"dist-asc":y=(l.totalDist||0)-(f.totalDist||0);break;case"dist-desc":y=(f.totalDist||0)-(l.totalDist||0);break;case"dur-asc":y=(l.duration||0)-(f.duration||0);break;case"dur-desc":y=(f.duration||0)-(l.duration||0);break;default:y=0}return y||i.localeCompare(a)}).forEach(i=>{t.appendChild(ki(Gt[i]))})}function Qs(){let t=new Set;return Object.values(Gt).forEach(s=>{(s.tags||[]).forEach(e=>t.add(e))}),Array.from(t).sort()}function ks(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 ki(t){let s=document.createElement("div");s.className=`track-item${t.id===Xt?" 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(a=>{let r=hs(a);return`${ue(a)}`}).join("")}
`:"";s.innerHTML=`
-
${me(t.displayName||t.name)}
+
${ue(t.displayName||t.name)}
${e} ${Math.round(t.stats.totalDist/1e3)} km - ${t.sport?`${Hs(t.sport)}`:""} + ${t.sport?`${ks(t.sport)}`:""} ${t.format.toUpperCase()}
${n}
- `,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=` + `,s.addEventListener("click",a=>{a.target.closest(".icon-btn")||We(t.id)});let i=s.querySelector(".toggle-vis");return i.addEventListener("click",()=>{t.visible=!t.visible,i.querySelector(".material-symbols-rounded").textContent=t.visible?"visibility":"visibility_off",qt.setTrackVisible(t.id,t.visible),ge.save(t)}),s}function Hn(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 $i(){let t=document.createElement("div");t.className="modal-backdrop";let s="";He.forEach(a=>{s+=`
${a.name}: ${a.reason}
`}),t.innerHTML=` - `,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}; + `,document.body.appendChild(t);let e=t.querySelector(".modal-btn.cancel"),n=t.querySelector(".modal-btn.clear"),i=()=>t.remove();e.addEventListener("click",i),n.addEventListener("click",()=>{He=[],i();let a=document.getElementById("import-warning");a&&a.classList.add("hidden")}),t.addEventListener("click",a=>{a.target===t&&i()})}function Ci(){let t=document.getElementById("drop-zone");if(!t)return;let s=document.getElementById("import-warning");s&&s.addEventListener("click",e=>{e.stopPropagation(),$i()}),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 i=[],a=[];for(let d=0;dd.file(f));i.push(l)}else if(d.isDirectory){let l=d.createReader(),f=[],y;do y=await new Promise(S=>l.readEntries(S)),f.push(...y);while(y.length>0);for(let S of f)await r(S)}}for(let d of a)await r(d);i.length&&$s(i)})}async function $s(t,s=!1){if(!t.length)return;In=!1;let e=He.length,n=document.getElementById("global-loader"),i=document.getElementById("loader-text"),a=document.getElementById("loader-subtext"),r=document.getElementById("loader-progress-bar"),d=document.getElementById("loader-close");d&&d.addEventListener("click",()=>{In=!0,n&&n.classList.add("hidden")});function l(){let f=document.querySelector(".loader-icon-wrap span");f&&(f.textContent="warning",f.style.color="#f59e0b");let y=document.getElementById("loader-warning-count");if(y){let S=He.length-e,I=y.querySelector("span");I&&(I.textContent=`${S}`),y.style.display="flex"}}if(n){i&&(i.textContent=`Importing ${t.length} file${t.length>1?"s":""}`);let f=document.querySelector(".loader-icon-wrap span");f&&(f.textContent="download",f.style.color="var(--accent)");let y=document.getElementById("loader-warning-count");if(y){y.style.display="none";let S=y.querySelector("span");S&&(S.textContent="0")}a&&(a.textContent=""),r&&(r.style.width="0%"),n.classList.remove("hidden"),He.length>e&&l()}try{let f=0,y=null,S=0,I=t.filter(L=>{let h=L.name.toLowerCase();return h.endsWith(".gpx")||h.endsWith(".fit")||h.endsWith(".tcx")||h.endsWith(".kml")});if(t.filter(L=>!I.includes(L)).forEach(L=>{He.push({name:L.name,reason:"Unsupported file format"})}),I.length===0){if(t.length>0){Hn("No valid GPS files found","error");let L=document.getElementById("import-warning");L&&He.length>0&&(L.classList.remove("hidden"),L.title=`Skipped ${He.length} imports. Click to view details.`)}return}let v=document.getElementById("loader-filename"),g=null;if(a){a.innerHTML='',g=a.querySelector(".progress-index");let L=a.querySelector(".progress-total");L&&(L.textContent=I.length.toString())}for(let L=0;Lb.fileName===h.name&&b.fileSize===h.size)){He.push({name:h.name,reason:"Same File"}),l();continue}let j=m.stats.startTime,U=m.stats.duration;if(j!=null&&U!=null){let b=j+U,u=p.filter(M=>M.stats.startTime!=null&&di(j,M.stats.startTime)),R=!1;for(let M of u){let O=M.stats.startTime,q=M.stats.duration,V=O+q;if(j>=O&&b<=V){He.push({name:h.name,reason:"Fully contained in another track"}),l(),R=!0;break}if(Math.min(b,V)-Math.max(j,O)>6e5){He.push({name:h.name,reason:"Overlaps with an existing track for more than 10 mins"}),l(),R=!0;break}}if(R)continue}let Q=17855424e5,Y=hl(m.stats.startTime||Q);Gt[Y]&&(Y+=`-${bl()}`);let G=m.name;(G.startsWith("Unnamed")||G.startsWith("Fit Activity"))&&(G=h.name);let ot=G,_t=m.points[0]?.time,ct=m.sport?m.sport.charAt(0).toUpperCase()+m.sport.slice(1):"Activity";if(_t){let b=new Date(_t);ot=`${b.getUTCFullYear()}-${String(b.getUTCMonth()+1).padStart(2,"0")}-${String(b.getUTCDate()).padStart(2,"0")} ${ct}`}else ot=G.replace(/\.[^/.]+$/,"").replace(/_/g," ");let w={...m,id:Y,name:G,displayName:ot,fileName:h.name,fileSize:h.size,bounds:xl(m.points)||void 0,simplifiedPoints:wl(m.points,50),addedAt:m.stats.startTime||Q,visible:!0,color:co[Zs%co.length]};if(Zs++,In)break;await ge.save(w),Gt[Y]=w,qt.addTrack(w),y||(y=Y),f++,S++,S>=5&&(S=0)}catch(m){He.push({name:h.name,reason:`Parse error: ${m instanceof Error?m.message:String(m)}`}),l()}}let E=document.getElementById("import-warning");E&&(He.length>0?(E.classList.remove("hidden"),E.title=`Skipped ${He.length} imports. Click to view details.`):E.classList.add("hidden"));let H=He.length>e;if(!H&&n&&n.classList.add("hidden"),f>0&&(Hn(`Imported ${f} track${f>1?"s":""}`),Ce(!!y&&y!==Xt),y&&We(y,!0,s)),H){let L=document.querySelector(".loader-icon-wrap span");L&&(L.textContent="warning"),await new Promise(h=>setTimeout(h,1500))}}finally{n&&n.classList.add("hidden")}}function Pi(){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 i=n.getBoundingClientRect(),a=e.clientX-i.left>i.width/2;t.insertBefore(s,a?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);St.updateMetricOrder(e),Xs()})}function Fn(){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,i=!1;Array.from(s.children).forEach(r=>{let d=r;if(d.id==="pill-overflow"||(d.classList.remove("overflow-hidden"),!d.classList.contains("active")))return;let f=36+(d.dataset.metric||"").length*6;n+=f+6,n>e&&(i=!0,d.classList.add("overflow-hidden"))});let a=document.getElementById("pill-overflow");a&&a.classList.toggle("hidden",!i),i&&t.classList.add("collapsed")}document.addEventListener("DOMContentLoaded",fi);export{We 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 ab099ad06f..75e6ab42d7 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 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"] + "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, 5, 12, 25, 50, 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, 20, 30, 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\nlet appSubsystemsInitialized = false;\n\nasync function initAppSubsystems() {\n if (appSubsystemsInitialized) {\n initInsights((msg: string, type?: string) =>\n showToast(msg, type === 'error' ? 'error' : 'info'),\n );\n initDetails(\n () => {\n applyFilters();\n syncFiltersToUrl();\n },\n (id: string) => {\n deleteTrack(id);\n },\n );\n initCombined();\n initCourses((msg: string, type?: string) =>\n showToast(msg, type === 'error' ? 'error' : 'info'),\n );\n updateToolbarLayout();\n await Storage.openDB();\n await resetBenchmarkState();\n return;\n }\n appSubsystemsInitialized = true;\n\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 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 if (mapLoader) mapLoader.classList.add('hidden');\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\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\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 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 await initAppSubsystems();\n const payloads = await preloadBenchmarkFiles();\n const loadedFiles: File[] = payloads.map((p) => p.file);\n await handleFiles(loadedFiles, true);\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, true, true);\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, true);\n }\n const availableMetrics = ChartView.getAvailableMetrics();\n const metricSets = [['elevation', 'speed', 'power']];\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, 600]);\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, 600]);\n renderInsights(primaryTrack, allTracks, [600, 1200]);\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 all 6 tracks and a selected pair\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, primaryTrack];\n for (const refTrk of refTracks) {\n renderEvolution(refTrk, allTracks, onSelectCb);\n setEvolutionGrouping('month');\n for (const rng of ['1m', '6m', '1y', 'all']) {\n setEvolutionRange(rng);\n }\n setEvolutionGrouping('week');\n for (const dur of [5, 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[], deferChartRender = false) {\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, true, deferChartRender);\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", "v", "isDesc", "field", "parts", "_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", "appSubsystemsInitialized", "initAppSubsystems", "initInsights", "msg", "type", "showToast", "initDetails", "deleteTrack", "initCourses", "storageSelect", "selected", "params", "mapLoader", "mapLoaderSpan", "urlState", "onMapMove", "onMapPointClick", "onMapDblClick", "onChartCursorMove", "onChartClick", "data", "currentUrlState", "applyState", "initResizeHandle", "initSidebarResizer", "initMetricPillDraggable", "clearAll", "toggleMetric", "metric", "axis", "initDropZone", "handleFiles", "onFilterInput", "val", "burgerBtn", "dropdownContent", "isVisible", "target", "selectedSport", "m", "resizeCombined", "init", "fontTimerId", "fontTimeout", "resolve", "fontLoadPromise", "initBenchmarkTriggers", "preloadBenchmarkFiles", "readyEl", "camelReadyEl", "preloadedBenchmarkPayloads", "fileNames", "decoder", "name", "buf", "cleanName", "bytes", "ds", "stream", "text", "file", "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", "setCombinedSliderProgress", "setCombinedPolar", "selectedTwo", "onSelectCb", "refTracks", "refTrk", "setEvolutionGrouping", "rng", "setEvolutionRange", "setEvolutionPinnedDuration", "prepareBenchmarkCourses", "courseIds", "getBenchmarkCourseIds", "cId", "selectCourse", "initResizeHandle", "handle", "panel", "isDragging", "e", "h", "clampedH", "ChartView", "resizeCombined", "MapView", "initSidebarResizer", "resizer", "sidebar", "w", "clampedW", "onMapMove", "lat", "lng", "zoom", "UrlState", "onMapPointClick", "id", "idx", "selectTrack", "onMapDblClick", "onChartCursorMove", "pt", "followDot", "onChartRangeChange", "min", "max", "axis", "fit", "selectedId", "tracks", "t", "renderInsights", "pts", "iMin", "iMax", "d0", "d1", "p", "t0", "ts0", "ts1", "selPts", "stats", "Parsers", "currentMapColors", "onChartClick", "POINT_ZOOM_LEVEL", "deferChartRender", "hadSelected", "renderDetails", "renderTrackList", "activeTab", "getGlobalTags", "renderCombined", "renderCourses", "renderEvolution", "trackId", "range", "deleteTrack", "Storage", "applyFilters", "clearAll", "code", "backdrop", "input", "btnConfirm", "btnCancel", "close", "cancelProcessing", "skipRender", "s", "visible", "searchQuery", "searchRegex", "filters", "start", "end", "d", "m", "field", "trackTags", "ft", "updateFilterUI", "el", "item", "btn", "activeCount", "badge", "updateSearchSortUI", "searchInput", "opt", "SORT_OPTIONS", "o", "currentSort", "labelEl", "iconEl", "applyState", "urlState", "newTrackId", "b", "currentXAxis", "metrics", "keys", "abbr", "k", "v", "updateSportFilterOptions", "commonContainer", "dropdownContent", "sports", "sportsArray", "burgerDropdown", "sport", "getSportIcon", "list", "emptyEl", "headerLabel", "ids", "a", "ta", "tb", "sa", "sb", "cmp", "buildTrackItem", "all", "tag", "track", "date", "fmtDate", "tagsHtml", "c", "getTagColor", "escHtml", "btnVis", "showToast", "msg", "type", "container", "showSkippedImportsModal", "listHtml", "skippedImports", "btnClear", "importWarning", "initDropZone", "zone", "items", "files", "queue", "i", "entry", "readAllEntries", "file", "res", "reader", "entries", "chunk", "child", "handleFiles", "initialSkipCount", "loader", "loaderText", "loaderSubtext", "progressBar", "loaderClose", "updateLoaderIconToWarning", "loaderIcon", "warningCount", "count", "countSpan", "firstId", "processedSinceLastUpdate", "validFiles", "f", "name", "loaderFilename", "progressIdxEl", "totalEl", "data", "existingTracks", "newStart", "newDuration", "newEnd", "sameDayTracks", "isSameDay", "discarded", "ext", "extStart", "extDuration", "extEnd", "fallbackTime", "compactId", "shortRandom", "trackName", "displayName", "calculateBounds", "simplifyTrack", "TRACK_COLORS", "colorIdx", "err", "newWarnings", "r", "initMetricPillDraggable", "draggedEl", "target", "rect", "next", "syncMetricsToUrl", "updateToolbarLayout", "toolbar", "pills", "availableW", "totalW", "hidden", "htmlEl", "deterministicPillWidth", "overflowEl", "init"] } diff --git a/suites-experimental/tools-gps-tracks/src/app.ts b/suites-experimental/tools-gps-tracks/src/app.ts index 749f0f34de..c17106e117 100644 --- a/suites-experimental/tools-gps-tracks/src/app.ts +++ b/suites-experimental/tools-gps-tracks/src/app.ts @@ -360,24 +360,33 @@ async function resetBenchmarkState() { } // ── 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); +let appSubsystemsInitialized = false; + +async function initAppSubsystems() { + if (appSubsystemsInitialized) { + 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'), + ); + updateToolbarLayout(); + await Storage.openDB(); + await resetBenchmarkState(); + return; } - document.body.classList.remove('loading-fonts'); + appSubsystemsInitialized = true; + const storageSelect = document.getElementById( 'storage-backend-select', ) as HTMLSelectElement | null; @@ -395,10 +404,6 @@ async function init() { }); } - 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'); @@ -457,121 +462,7 @@ async function init() { // 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); - } + if (mapLoader) mapLoader.classList.add('hidden'); // Panel resizers initResizeHandle(); @@ -809,6 +700,26 @@ async function init() { MapView.invalidateSize?.(); updateToolbarLayout(); }); +} + +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'); initBenchmarkTriggers(); await preloadBenchmarkFiles(); @@ -866,73 +777,7 @@ async function preloadBenchmarkFiles(): Promise< 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, 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); - 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(); - void document.body.offsetHeight; - await new Promise((r) => window.setTimeout(r, 0)); - } else if (typeof (window as any).__resetBenchmarkSeed === 'function') { + if (typeof (window as any).__resetBenchmarkSeed === 'function') { (window as any).__resetBenchmarkSeed(); } return preloadedBenchmarkPayloads; @@ -962,15 +807,10 @@ function initBenchmarkTriggers() { 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(); - } + await initAppSubsystems(); const payloads = await preloadBenchmarkFiles(); const loadedFiles: File[] = payloads.map((p) => p.file); - await handleFiles(loadedFiles); + await handleFiles(loadedFiles, true); const allTracks = Object.values(tracks); Parsers.findOverlaps(allTracks); @@ -990,7 +830,7 @@ function initBenchmarkTriggers() { searchQuery = ''; applyFilters(); - if (!selectedId && allTracks.length > 0) selectTrack(allTracks[0].id); + if (!selectedId && allTracks.length > 0) selectTrack(allTracks[0].id, true, true); } finally { window.dispatchEvent(new CustomEvent('load-and-parse-complete')); } @@ -1001,13 +841,10 @@ function initBenchmarkTriggers() { const allTracks = Object.values(tracks); activateTab('graphs'); if (!selectedId && allTracks.length > 0) { - selectTrack(allTracks[0].id, false); + selectTrack(allTracks[0].id, false, true); } const availableMetrics = ChartView.getAvailableMetrics(); - const metricSets = [ - ['elevation', 'speed', 'power', 'hr'], - ['elevation', 'speed', 'power'], - ]; + const metricSets = [['elevation', 'speed', 'power']]; for (const mSet of metricSets) { const filtered = mSet.filter((m) => availableMetrics.has(m)); if (filtered.length > 0) { @@ -1054,8 +891,7 @@ function initBenchmarkTriggers() { 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, [0, 600]); renderInsights(trk, allTracks, null); } } @@ -1063,9 +899,8 @@ function initBenchmarkTriggers() { 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, [0, 600]); + renderInsights(primaryTrack, allTracks, [600, 1200]); } renderInsights(primaryTrack, allTracks, null); } finally { @@ -1129,10 +964,7 @@ function initBenchmarkTriggers() { 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); - } + // 2. Exercise multi-track comparison mode across all 6 tracks and a selected pair if (allTracks.length >= 6) { renderCombined(allTracks, allTracks); } @@ -1158,15 +990,15 @@ function initBenchmarkTriggers() { }; // Exercise evolution view across different reference tracks, groupings ('month' & 'week'), time ranges, and pinned durations - const refTracks = [allTracks[2] || primaryTrack, allTracks[4] || primaryTrack, primaryTrack]; + const refTracks = [allTracks[2] || primaryTrack, primaryTrack]; for (const refTrk of refTracks) { renderEvolution(refTrk, allTracks, onSelectCb); setEvolutionGrouping('month'); - for (const rng of ['1m', '2m', '6m', '1y', 'all']) { + for (const rng of ['1m', '6m', '1y', 'all']) { setEvolutionRange(rng); } setEvolutionGrouping('week'); - for (const dur of [5, 30, 60, 300, 1200, null]) { + for (const dur of [5, 60, 300, 1200, null]) { setEvolutionPinnedDuration(dur); } } @@ -2016,7 +1848,7 @@ function initDropZone() { }); } -async function handleFiles(files: File[]) { +async function handleFiles(files: File[], deferChartRender = false) { if (!files.length) return; cancelProcessing = false; const initialSkipCount = skippedImports.length; @@ -2251,7 +2083,7 @@ async function handleFiles(files: File[]) { if (count > 0) { showToast(`Imported ${count} track${count > 1 ? 's' : ''}`); applyFilters(!!firstId && firstId !== selectedId); - if (firstId) selectTrack(firstId); + if (firstId) selectTrack(firstId, true, deferChartRender); } if (newWarnings) { diff --git a/suites-experimental/tools-gps-tracks/src/parsers.ts b/suites-experimental/tools-gps-tracks/src/parsers.ts index 4ea6ca30dc..062e200758 100644 --- a/suites-experimental/tools-gps-tracks/src/parsers.ts +++ b/suites-experimental/tools-gps-tracks/src/parsers.ts @@ -150,7 +150,7 @@ export function simplifyTrack(pts: TrackPoint[], minDistanceMeters: number): Tra dists[i] = p.dist || 0; } - const tolerances = [2, 4, 8, 15, 25, 40, 65, 100]; + const tolerances = [2, 5, 12, 25, 50, 100]; let errChecksum = 0; const degToRad = 0.017453292519943295; for (let ti = 0; ti < tolerances.length; ti++) { @@ -235,7 +235,7 @@ export const Parsers = (() => { pwrBuf[i] = pts[i].power ?? 0; spdBuf[i] = pts[i].speed ?? 0; } - const gradeWindows = [3, 5, 10, 15, 20, 30, 45, 60]; + const gradeWindows = [3, 5, 10, 20, 30, 60]; let npAccum = 0; const scaleH = 1 / 8400; for (let wi = 0; wi < gradeWindows.length; wi++) {