mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-09-10 21:26:04 +00:00
One row per repeater whose configured region list is known, answering a question no other view answers: you declare these regions, but were you seen forwarding them? default_scope says what a node's adverts were observed under and transported_scopes (#1751) says what it carried, but nothing lined the declared list up against observed forwarding. The declared side merges every confirmed-scope source the database carries, newest answer per node wins, rather than naming one. On a stock install only nodes.configured_scope (#1865/#1971) exists and it degrades to the one-source case; deployments that collect the same fact another way keep working. Reading a single hard-coded source would have rendered an empty page on the very instance the evidence came from. Declared and observed are compared through normScope, so a leading "#" and a bare region name are one region. Unobserved regions render neutral, not red: absence over a short window is weak evidence, which the page header already states in words. Ported from a long-running fork deployment with its 17 server tests, rewired to the upstream data source, plus 14 frontend cases asserting rendered markup.
237 lines
22 KiB
HTML
237 lines
22 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<link rel="icon" href="favicon.ico" type="image/x-icon">
|
|
<link rel="icon" href="favicon.svg" type="image/svg+xml">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
|
<title>CoreScope</title>
|
|
|
|
<!-- Open Graph / Discord embed -->
|
|
<meta property="og:title" content="CoreScope">
|
|
<meta property="og:description" content="Real-time MeshCore LoRa mesh network analyzer — live packet visualization, node tracking, channel decryption, route analysis, and deep mesh analytics.">
|
|
<meta property="og:image" content="https://raw.githubusercontent.com/Kpa-clawbot/corescope/master/public/og-image.png">
|
|
<meta property="og:image:width" content="1200">
|
|
<meta property="og:image:height" content="630">
|
|
<!-- No og:url: it is the canonical destination OG consumers navigate to, so a
|
|
hardcoded value sends every self-hosted instance's shared links to that one
|
|
host (#1890). Omitted, consumers use the URL they crawled — correct for
|
|
every deployment, no configuration needed. -->
|
|
<meta property="og:type" content="website">
|
|
<meta name="theme-color" content="#0a0a0a">
|
|
|
|
<!-- Twitter Card -->
|
|
<meta name="twitter:card" content="summary_large_image">
|
|
<meta name="twitter:title" content="CoreScope">
|
|
<meta name="twitter:description" content="Real-time MeshCore LoRa mesh network analyzer — live packet visualization, node tracking, channel decryption, and route analysis.">
|
|
<meta name="twitter:image" content="https://raw.githubusercontent.com/Kpa-clawbot/corescope/master/public/og-image.png">
|
|
<!-- PR #893 follow-up: apply persisted theme before stylesheet/paint to prevent
|
|
FOUC (light flash for users who chose dark). Matches keys used by app.js. -->
|
|
<script>
|
|
(function () {
|
|
try {
|
|
var saved = localStorage.getItem('meshcore-theme');
|
|
var t = saved === 'dark' || saved === 'light'
|
|
? saved
|
|
: (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
|
document.documentElement.setAttribute('data-theme', t);
|
|
} catch (_) { /* localStorage may be blocked; CSS handles default */ }
|
|
})();
|
|
</script>
|
|
<link rel="stylesheet" href="style.css?v=__BUST__">
|
|
<link rel="stylesheet" href="route-view.css?v=__BUST__">
|
|
<link rel="stylesheet" href="home.css?v=__BUST__">
|
|
<link rel="stylesheet" href="live.css?v=__BUST__">
|
|
<link rel="stylesheet" href="node-reach.css?v=__BUST__">
|
|
<link rel="stylesheet" href="scope-audit.css?v=__BUST__">
|
|
<link rel="stylesheet" href="node-reach-coverage.css?v=__BUST__">
|
|
<link rel="stylesheet" href="bottom-nav.css?v=__BUST__">
|
|
<link rel="stylesheet" href="nav-drawer.css?v=__BUST__">
|
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
|
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
|
|
crossorigin="anonymous">
|
|
<link rel="stylesheet" href="vendor/MarkerCluster.css?v=__BUST__">
|
|
<link rel="stylesheet" href="vendor/MarkerCluster.Default.css?v=__BUST__">
|
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
|
|
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
|
|
crossorigin="anonymous"></script>
|
|
<script src="vendor/leaflet.markercluster.js?v=__BUST__"></script>
|
|
<script src="https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js"></script>
|
|
<script src="https://unpkg.com/chart.js@4/dist/chart.umd.min.js"></script>
|
|
</head>
|
|
<body>
|
|
<!-- #1380 — Colorblind a11y stretch goal: Brettel/Vienot 1997 dichromatic
|
|
simulation overlay. Toggled by body[data-cb-sim="deut|prot|trit|achromat"].
|
|
Preview-only (not persisted). See public/customize-v2.js radio group. -->
|
|
<svg aria-hidden="true" focusable="false" width="0" height="0" style="position:absolute;width:0;height:0;overflow:hidden" data-cb-sim-defs>
|
|
<defs>
|
|
<filter id="cb-deut" color-interpolation-filters="sRGB">
|
|
<feColorMatrix type="matrix" values="
|
|
0.367 0.861 -0.228 0 0
|
|
0.280 0.673 0.047 0 0
|
|
-0.012 0.043 0.969 0 0
|
|
0 0 0 1 0"/>
|
|
</filter>
|
|
<filter id="cb-prot" color-interpolation-filters="sRGB">
|
|
<feColorMatrix type="matrix" values="
|
|
0.152 1.053 -0.205 0 0
|
|
0.115 0.786 0.099 0 0
|
|
-0.004 -0.048 1.052 0 0
|
|
0 0 0 1 0"/>
|
|
</filter>
|
|
<filter id="cb-trit" color-interpolation-filters="sRGB">
|
|
<feColorMatrix type="matrix" values="
|
|
1.256 -0.077 -0.179 0 0
|
|
-0.078 0.931 0.148 0 0
|
|
0.005 0.691 0.304 0 0
|
|
0 0 0 1 0"/>
|
|
</filter>
|
|
<filter id="cb-achromat" color-interpolation-filters="sRGB">
|
|
<feColorMatrix type="matrix" values="
|
|
0.299 0.587 0.114 0 0
|
|
0.299 0.587 0.114 0 0
|
|
0.299 0.587 0.114 0 0
|
|
0 0 0 1 0"/>
|
|
</filter>
|
|
</defs>
|
|
</svg>
|
|
<style>
|
|
/* #1380 — sim overlay activation (preview-only; cleared on reload). */
|
|
body[data-cb-sim="deut"] { filter: url(#cb-deut); }
|
|
body[data-cb-sim="prot"] { filter: url(#cb-prot); }
|
|
body[data-cb-sim="trit"] { filter: url(#cb-trit); }
|
|
body[data-cb-sim="achromat"] { filter: url(#cb-achromat); }
|
|
</style>
|
|
<a class="skip-link" href="#app">Skip to content</a>
|
|
<nav class="top-nav" role="navigation" aria-label="Main navigation">
|
|
<div class="nav-left">
|
|
<a href="#/" class="nav-brand" aria-label="CoreScope home">
|
|
<svg class="brand-logo" xmlns="http://www.w3.org/2000/svg" width="125" height="36" viewBox="150 10 970 280" aria-hidden="true" focusable="false"><path d="M540 100 A 30 30 0 1 0 540 160" fill="none" stroke="var(--logo-accent)" stroke-width="8" opacity="1.00"/>
|
|
<path d="M540 73 A 57 57 0 1 0 540 187" fill="none" stroke="var(--logo-accent)" stroke-width="8" opacity="0.82"/>
|
|
<path d="M540 46 A 84 84 0 1 0 540 214" fill="none" stroke="var(--logo-accent)" stroke-width="8" opacity="0.64"/>
|
|
<path d="M540 19 A 111 111 0 1 0 540 241" fill="none" stroke="var(--logo-accent)" stroke-width="8" opacity="0.46"/>
|
|
<path d="M660 100 A 30 30 0 1 1 660 160" fill="none" stroke="var(--logo-accent-hi)" stroke-width="8" opacity="1.00"/>
|
|
<path d="M660 73 A 57 57 0 1 1 660 187" fill="none" stroke="var(--logo-accent-hi)" stroke-width="8" opacity="0.82"/>
|
|
<path d="M660 46 A 84 84 0 1 1 660 214" fill="none" stroke="var(--logo-accent-hi)" stroke-width="8" opacity="0.64"/>
|
|
<path d="M660 19 A 111 111 0 1 1 660 241" fill="none" stroke="var(--logo-accent-hi)" stroke-width="8" opacity="0.46"/>
|
|
|
|
<polyline points="540.00,130.00 540.30,130.17 540.60,130.35 540.90,130.53 541.20,130.71 541.50,130.89 541.80,131.07 542.10,131.26 542.40,131.45 542.70,131.64 543.00,131.83 543.30,132.02 543.60,132.21 543.90,132.41 544.20,132.61 544.50,132.80 544.80,133.00 545.10,133.20 545.40,133.40 545.70,133.60 546.00,133.81 546.30,134.01 546.60,134.21 546.90,134.42 547.20,134.62 547.50,134.82 547.80,135.03 548.10,135.23 548.40,135.44 548.70,135.64 549.00,135.84 549.30,136.04 549.60,136.24 549.90,136.44 550.20,136.64 550.50,136.83 550.80,137.02 551.10,137.22 551.40,137.41 551.70,137.59 552.00,137.78 552.30,137.96 552.60,138.14 552.90,138.31 553.20,138.49 553.50,138.66 553.80,138.82 554.10,138.98 554.40,139.14 554.70,139.29 555.00,139.44 555.30,139.58 555.60,139.71 555.90,139.84 556.20,139.97 556.50,140.09 556.80,140.20 557.10,140.31 557.40,140.41 557.70,140.50 558.00,140.59 558.30,140.67 558.60,140.74 558.90,140.80 559.20,140.85 559.50,140.90 559.80,140.94 560.10,140.97 560.40,140.99 560.70,141.00 561.00,141.00 561.30,140.99 561.60,140.97 561.90,140.95 562.20,140.91 562.50,140.86 562.80,140.80 563.10,140.73 563.40,140.65 563.70,140.56 564.00,140.46 564.30,140.35 564.60,140.23 564.90,140.09 565.20,139.95 565.50,139.79 565.80,139.62 566.10,139.44 566.40,139.25 566.70,139.05 567.00,138.84 567.30,138.61 567.60,138.38 567.90,138.13 568.20,137.87 568.50,137.60 568.80,137.33 569.10,137.04 569.40,136.74 569.70,136.43 570.00,136.11 570.30,135.78 570.60,135.45 570.90,135.10 571.20,134.75 571.50,134.38 571.80,134.01 572.10,133.64 572.40,133.25 572.70,132.86 573.00,132.46 573.30,132.06 573.60,131.65 573.90,131.24 574.20,130.82 574.50,130.40 574.80,129.98 575.10,129.56 575.40,129.13 575.70,128.71 576.00,128.28 576.30,127.85 576.60,127.43 576.90,127.00 577.20,126.58 577.50,126.17 577.80,125.75 578.10,125.35 578.40,124.94 578.70,124.55 579.00,124.16 579.30,123.78 579.60,123.41 579.90,123.05 580.20,122.70 580.50,122.36 580.80,122.03 581.10,121.71 581.40,121.41 581.70,121.13 582.00,120.85 582.30,120.60 582.60,120.36 582.90,120.14 583.20,119.93 583.50,119.75 583.80,119.58 584.10,119.43 584.40,119.31 584.70,119.20 585.00,119.12 585.30,119.06 585.60,119.02 585.90,119.00 586.20,119.01 586.50,119.04 586.80,119.09 587.10,119.17 587.40,119.27 587.70,119.39 588.00,119.54 588.30,119.71 588.60,119.91 588.90,120.13 589.20,120.37 589.50,120.64 589.80,120.92 590.10,121.24 590.40,121.57 590.70,121.92 591.00,122.30 591.30,122.69 591.60,123.11 591.90,123.54 592.20,123.99 592.50,124.46 592.80,124.94 593.10,125.44 593.40,125.95 593.70,126.48 594.00,127.01 594.30,127.56 594.60,128.11 594.90,128.67 595.20,129.24 595.50,129.81 595.80,130.38 596.10,130.96 596.40,131.53 596.70,132.10 597.00,132.67 597.30,133.24 597.60,133.79 597.90,134.34 598.20,134.87 598.50,135.40 598.80,135.91 599.10,136.40 599.40,136.88 599.70,137.34 600.00,137.78 600.30,138.19 600.60,138.59 600.90,138.96 601.20,139.30 601.50,139.61 601.80,139.90 602.10,140.15 602.40,140.37 602.70,140.56 603.00,140.72 603.30,140.84 603.60,140.93 603.90,140.98 604.20,141.00 604.50,140.98 604.80,140.92 605.10,140.83 605.40,140.70 605.70,140.53 606.00,140.32 606.30,140.08 606.60,139.80 606.90,139.49 607.20,139.14 607.50,138.75 607.80,138.34 608.10,137.89 608.40,137.42 608.70,136.91 609.00,136.38 609.30,135.82 609.60,135.24 609.90,134.64 610.20,134.01 610.50,133.37 610.80,132.72 611.10,132.05 611.40,131.37 611.70,130.69 612.00,130.00 612.30,129.31 612.60,128.62 612.90,127.93 613.20,127.25 613.50,126.58 613.80,125.91 614.10,125.27 614.40,124.64 614.70,124.03 615.00,123.45 615.30,122.89 615.60,122.36 615.90,121.86 616.20,121.39 616.50,120.96 616.80,120.57 617.10,120.21 617.40,119.90 617.70,119.64 618.00,119.41 618.30,119.24 618.60,119.11 618.90,119.03 619.20,119.00 619.50,119.02 619.80,119.09 620.10,119.21 620.40,119.39 620.70,119.61 621.00,119.88 621.30,120.20 621.60,120.57 621.90,120.98 622.20,121.44 622.50,121.94 622.80,122.48 623.10,123.06 623.40,123.68 623.70,124.33 624.00,125.01 624.30,125.71 624.60,126.44 624.90,127.19 625.20,127.96 625.50,128.73 625.80,129.52 626.10,130.31 626.40,131.10 626.70,131.89 627.00,132.67 627.30,133.44 627.60,134.19 627.90,134.93 628.20,135.63 628.50,136.31 628.80,136.96 629.10,137.57 629.40,138.14 629.70,138.67 630.00,139.15 630.30,139.58 630.60,139.95 630.90,140.28 631.20,140.54 631.50,140.75 631.80,140.90 632.10,140.98 632.40,141.00 632.70,140.96 633.00,140.85 633.30,140.68 633.60,140.44 633.90,140.14 634.20,139.78 634.50,139.36 634.80,138.89 635.10,138.36 635.40,137.78 635.70,137.14 636.00,136.47 636.30,135.75 636.60,134.99 636.90,134.20 637.20,133.38 637.50,132.54 637.80,131.68 638.10,130.81 638.40,129.93 638.70,129.05 639.00,128.17 639.30,127.31 639.60,126.45 639.90,125.62 640.20,124.82 640.50,124.05 640.80,123.31 641.10,122.62 641.40,121.98 641.70,121.39 642.00,120.85 642.30,120.38 642.60,119.97 642.90,119.63 643.20,119.36 643.50,119.17 643.80,119.05 644.10,119.00 644.40,119.03 644.70,119.14 645.00,119.33 645.30,119.59 645.60,119.93 645.90,120.34 646.20,120.83 646.50,121.38 646.80,121.99 647.10,122.67 647.40,123.40 647.70,124.18 648.00,125.01 648.30,125.87 648.60,126.77 648.90,127.69 649.20,128.64 649.50,129.60 649.80,130.56 650.10,131.52 650.40,132.47 650.70,133.40 651.00,134.31 651.30,135.19 651.60,136.02 651.90,136.82 652.20,137.56 652.50,138.24 652.80,138.86 653.10,139.41 653.40,139.88 653.70,140.27 654.00,140.59 654.30,140.81 654.60,140.95 654.90,141.00 655.20,140.96 655.50,140.82 655.80,140.60 656.10,140.29 656.40,139.89 656.70,139.40 657.00,138.84 657.30,138.19 657.60,137.48 657.90,136.70 658.20,135.86 658.50,134.97 658.80,134.03 659.10,133.06 659.40,132.06 659.70,131.03 660.00,130.00" fill="none" stroke="var(--logo-muted)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" opacity="1.0"/>
|
|
<circle class="logo-node-a" cx="540" cy="130" r="13" fill="var(--logo-accent)"/>
|
|
<circle class="logo-node-b" cx="660" cy="130" r="13" fill="var(--logo-accent-hi)"/>
|
|
<g class="brand-wordmark"><text x="426.20" y="161.68" font-family="Aldrich, monospace" font-size="88" text-anchor="end" dominant-baseline="alphabetic" font-weight="700" letter-spacing="4.4" fill="var(--logo-accent)">CORE</text><text x="773.80" y="161.68" font-family="Aldrich, monospace" font-size="88" text-anchor="start" dominant-baseline="alphabetic" font-weight="700" letter-spacing="4.4" fill="var(--logo-accent-hi)">SCOPE</text></g></svg>
|
|
<svg class="brand-mark-only" xmlns="http://www.w3.org/2000/svg" width="60" height="32" viewBox="425 15 250 230" aria-hidden="true" focusable="false"><path d="M540 100 A 30 30 0 1 0 540 160" fill="none" stroke="var(--logo-accent)" stroke-width="8" opacity="1.00"/><path d="M540 73 A 57 57 0 1 0 540 187" fill="none" stroke="var(--logo-accent)" stroke-width="8" opacity="0.82"/><path d="M540 46 A 84 84 0 1 0 540 214" fill="none" stroke="var(--logo-accent)" stroke-width="8" opacity="0.64"/><path d="M540 19 A 111 111 0 1 0 540 241" fill="none" stroke="var(--logo-accent)" stroke-width="8" opacity="0.46"/><path d="M660 100 A 30 30 0 1 1 660 160" fill="none" stroke="var(--logo-accent-hi)" stroke-width="8" opacity="1.00"/><path d="M660 73 A 57 57 0 1 1 660 187" fill="none" stroke="var(--logo-accent-hi)" stroke-width="8" opacity="0.82"/><path d="M660 46 A 84 84 0 1 1 660 214" fill="none" stroke="var(--logo-accent-hi)" stroke-width="8" opacity="0.64"/><path d="M660 19 A 111 111 0 1 1 660 241" fill="none" stroke="var(--logo-accent-hi)" stroke-width="8" opacity="0.46"/><circle class="logo-node-a" cx="540" cy="130" r="13" fill="var(--logo-accent)"/><circle class="logo-node-b" cx="660" cy="130" r="13" fill="var(--logo-accent-hi)"/></svg>
|
|
</a>
|
|
<div class="nav-links">
|
|
<a href="#/home" class="nav-link" data-route="home" data-priority="high">Home</a>
|
|
<a href="#/packets" class="nav-link" data-route="packets" data-priority="high">Packets</a>
|
|
<a href="#/map" class="nav-link" data-route="map" data-priority="high">Map</a>
|
|
<a href="#/live" class="nav-link" data-route="live" data-priority="high"><svg class="ph-icon" aria-hidden="true" focusable="false"><use href="/icons/phosphor-sprite.svg#ph-broadcast"></use></svg> Live</a>
|
|
<a href="#/channels" class="nav-link" data-route="channels">Channels</a>
|
|
<a href="#/nodes" class="nav-link" data-route="nodes" data-priority="high">Nodes</a>
|
|
<a href="#/tools" class="nav-link" data-route="tools">Tools</a>
|
|
<a href="#/observers" class="nav-link" data-route="observers">Observers</a>
|
|
<a href="#/analytics" class="nav-link" data-route="analytics">Analytics</a>
|
|
<a href="#/scope-audit" class="nav-link" data-route="scope-audit">Scope Audit</a>
|
|
<a href="#/perf" class="nav-link" data-route="perf"><svg class="ph-icon" aria-hidden="true" focusable="false"><use href="/icons/phosphor-sprite.svg#ph-lightning"></use></svg> Perf</a>
|
|
<a href="#/audio-lab" class="nav-link" data-route="audio-lab"><svg class="ph-icon" aria-hidden="true" focusable="false"><use href="/icons/phosphor-sprite.svg#ph-music-note"></use></svg> Lab</a>
|
|
</div>
|
|
<div class="nav-more-wrap">
|
|
<button class="nav-btn nav-more-btn" id="navMoreBtn" aria-haspopup="true" aria-expanded="false" aria-controls="navMoreMenu" title="More pages">More ▾</button>
|
|
<div class="nav-more-menu" id="navMoreMenu" role="menu"></div>
|
|
</div>
|
|
</div>
|
|
<div class="nav-right">
|
|
<div class="nav-stats" id="navStats" title="Live stats"></div>
|
|
<div class="nav-fav-wrap">
|
|
<button class="nav-btn" id="favToggle" title="Favorites" aria-label="Favorites"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor-sprite.svg#ph-star-fill"/></svg></button>
|
|
<div class="nav-fav-dropdown" id="favDropdown"></div>
|
|
</div>
|
|
<button class="nav-btn" id="searchToggle" title="Search (Ctrl+K)" aria-label="Search"><svg class="ph-icon" aria-hidden="true" focusable="false"><use href="/icons/phosphor-sprite.svg#ph-magnifying-glass"></use></svg></button>
|
|
<button class="nav-btn" id="customizeToggle" title="Customize theme & branding" aria-label="Customize"><svg class="ph-icon" aria-hidden="true" focusable="false"><use href="/icons/phosphor-sprite.svg#ph-palette"></use></svg></button>
|
|
<label class="theme-toggle" id="darkModeToggle" title="Toggle dark mode">
|
|
<input type="checkbox" id="darkModeCheckbox" role="switch" aria-label="Toggle dark mode">
|
|
<span class="theme-toggle-track" aria-hidden="true">
|
|
<span class="theme-toggle-thumb"></span>
|
|
<span class="theme-toggle-icon theme-toggle-sun"><svg class="ph-icon" aria-hidden="true" focusable="false"><use href="/icons/phosphor-sprite.svg#ph-sun"></use></svg></span>
|
|
<span class="theme-toggle-icon theme-toggle-moon"><svg class="ph-icon" aria-hidden="true" focusable="false"><use href="/icons/phosphor-sprite.svg#ph-moon"></use></svg></span>
|
|
</span>
|
|
</label>
|
|
<button class="nav-btn hamburger" id="hamburger" title="Menu" aria-label="Toggle navigation menu"><svg class="ph-icon" aria-hidden="true" focusable="false"><use href="/icons/phosphor-sprite.svg#ph-list"></use></svg></button>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Search overlay -->
|
|
<div id="searchOverlay" class="search-overlay hidden" role="search" aria-label="Search packets, nodes, channels">
|
|
<div class="search-box">
|
|
<input type="text" id="searchInput" placeholder="Search packets, nodes, channels…" autofocus>
|
|
<div id="searchResults" class="search-results" role="listbox"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<main id="app" role="main"></main>
|
|
|
|
<script src="vendor/qrcode.js"></script>
|
|
<script src="payload-labels.js?v=__BUST__"></script>
|
|
<script src="roles.js?v=__BUST__"></script>
|
|
<script src="map-tile-providers.js?v=__BUST__"></script>
|
|
<script src="cb-presets.js?v=__BUST__"></script>
|
|
<script src="customize-v2.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="region-filter.js?v=__BUST__"></script>
|
|
<script src="area-filter.js?v=__BUST__"></script>
|
|
<script src="hop-resolver.js?v=__BUST__"></script>
|
|
<script src="hop-filter.js?v=__BUST__"></script>
|
|
<script src="hop-display.js?v=__BUST__"></script>
|
|
<script src="warmup-banner.js?v=__BUST__"></script>
|
|
<script src="app.js?v=__BUST__"></script>
|
|
<script src="bottom-nav.js?v=__BUST__"></script>
|
|
<script src="nav-drawer.js?v=__BUST__"></script>
|
|
<script src="touch-gestures.js?v=__BUST__"></script>
|
|
<script src="gesture-hints.js?v=__BUST__"></script>
|
|
<script src="url-state.js?v=__BUST__"></script>
|
|
<script src="home.js?v=__BUST__"></script>
|
|
<script src="table-sort.js?v=__BUST__"></script>
|
|
<script src="packet-filter.js?v=__BUST__"></script>
|
|
<script src="filter-ux.js?v=__BUST__"></script>
|
|
<script src="hash-color.js?v=__BUST__"></script>
|
|
<script src="prefix-reserved.js?v=__BUST__"></script>
|
|
<script src="packet-helpers.js?v=__BUST__"></script>
|
|
<script src="vendor/aes-ecb.js?v=__BUST__"></script>
|
|
<script src="vendor/sha256-hmac.js?v=__BUST__"></script>
|
|
<script src="channel-decrypt.js?v=__BUST__"></script>
|
|
<script src="vendor/jsqr.min.js"></script>
|
|
<script src="channel-qr.js?v=__BUST__"></script>
|
|
<script src="channel-colors.js?v=__BUST__"></script>
|
|
<script src="channel-color-picker.js?v=__BUST__"></script>
|
|
<script src="packets.js?v=__BUST__"></script>
|
|
<script src="geo-filter-overlay.js?v=__BUST__"></script>
|
|
<script src="map.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="route-render.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="route-view-utils.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="route-view.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="channels.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="table-sort.js?v=__BUST__"></script>
|
|
<script src="nodes-export.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="nodes.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="traces.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="path-inspector.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="analytics.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="audio.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="audio-v1-constellation.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="audio-lab.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="drag-manager.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="live.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="observers.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="mqtt-status-panel.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="observer-detail.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="compare.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="node-analytics.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="node-reach-map.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="node-reach-coverage.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="node-reach.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="scope-audit.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="rx-coverage.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="perf.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
<script src="mobile-page-actions.js?v=__BUST__" onerror="console.error('Failed to load:', this.src)"></script>
|
|
</body>
|
|
</html>
|