Some checks failed
CI / skinny-install (aco) (push) Successful in 54s
CI / skinny-install (api) (push) Successful in 32s
CI / skinny-install (bcda) (push) Successful in 33s
CI / skinny-install (bib) (push) Successful in 30s
CI / skinny-install (bls) (push) Successful in 26s
CI / lint-test (push) Successful in 3m19s
CI / skinny-install (ccw) (push) Successful in 27s
CI / skinny-install (cms) (push) Successful in 32s
CI / skinny-install (cli) (push) Successful in 38s
CI / skinny-install (conf) (push) Successful in 33s
CI / skinny-install (opps) (push) Successful in 43s
Infra CI / notebooks (push) Successful in 7s
Infra CI / zotero (push) Successful in 7s
Infra CI / docs (push) Failing after 10s
Infra CI / api (push) Successful in 13s
Infra CI / mc (push) Successful in 7s
CI / skinny-install (perf) (push) Successful in 31s
CI / skinny-install (pfs) (push) Successful in 30s
CI / skinny-install (rex) (push) Successful in 31s
Deploy / build-scan-report (push) Failing after 1m47s
Rip and replace nature/loch with fhirworx — a Federal Register / data journalism aesthetic inspired by hti5.org. Typography: Playfair Display for display headings, Source Serif 4 for reading body, JetBrains Mono reserved for IDs, labels, metadata (docket codes, commit hashes, query editors, file paths, ports). Stripped carpet-bombed font-family: mono !important across inject.css and per-service sheets; kept mono only where load-bearing (th, pre/code, query editors, span IDs, badge/chip/tag, bucket names, query IDs). Palette: warm cream (#F7F5F0) background, near-black warm foreground, deep federal navy (#1C2B3A) primary/sidebar, indigo chart scale + teal (support) + amber (opposition) semantic accents. PALETTE extended to 8 colours (+ plum, gray, sepia) for categorical notebook charts. Rename (no backwards compat): - assets/nature.py → assets/fhirworx.py - assets/css/loch.css → assets/css/fhirworx.css - theme-loch.css → theme-fhirworx.css (Gitea) - Altair theme registered as "fhirworx" via new alt.theme.register decorator API, eliminating the altair 5.5 deprecation warning - Traefik inject-loch middleware → inject-fhirworx - Gitea DEFAULT_THEME=fhirworx - Delete empty theme-throwback.css stub Rewrote infra/nginx/index.html and infra/gitea/custom/templates/home.tmpl with editorial masthead (rule-line + Playfair headline + mono identifier + serif tagline + rule-line-thin), SERVICES eyebrow + Infrastructure h2, tiles with .tile-eyebrow / .tile-title / .tile-desc / .tile-port structure. Stripped letter-spacing: 2-4px tricks and text-transform: uppercase from non-metadata elements across all per-service sheets. Propagated import renames: src/conf/connect.py, src/aco/dag.py, notebooks/acodb_explorer.py, tests/conf/test_connect.py, tests/test_notebook_layout.py, docs/src/css/custom.css, README.md, README.md.j2, compose.yml, infra/traefik/dynamic/services.yml.
400 lines
30 KiB
HTML
400 lines
30 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>PFS Equation Explorer</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;600;700&family=Source+Serif+4:ital,wght@0,300;0,400;0,600;1,400&family=JetBrains+Mono:wght@400;500;600&display=swap">
|
|
<link rel="stylesheet" href="https://unpkg.com/katex@0.16/dist/katex.min.css">
|
|
<script src="https://unpkg.com/katex@0.16/dist/katex.min.js"></script>
|
|
<style>
|
|
:root {
|
|
/* HTI-5 palette */
|
|
--bg: #F7F5F0; --panel: #FAFAF7; --panel-hi: #EDEBE6;
|
|
--border: #D4D0C8; --text: #1A1A18; --muted: #6B6B68; --dim: #9B9B98;
|
|
/* Node-kind colours — Tableau-style but on light bg */
|
|
--c-mul: #C0392B; --c-dot: #2E8B6E; --c-add: #2E3D8F;
|
|
--c-vec: #A85800; --c-scalar: #7448C0; --c-ref: #1A7090;
|
|
--c-fn: #C8702A; --c-cond: #9B2E5A;
|
|
}
|
|
* { margin:0; padding:0; box-sizing:border-box; }
|
|
body {
|
|
background: var(--bg); color: var(--text);
|
|
font-family: "Source Serif 4", Georgia, serif;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
/* ── Header ────────────────────────── */
|
|
header {
|
|
padding: 24px 32px 0;
|
|
display: flex; align-items: baseline; gap: 16px;
|
|
}
|
|
header h1 {
|
|
font-size: 20px; font-weight: 700; color: var(--text);
|
|
font-family: "Playfair Display", Georgia, serif;
|
|
letter-spacing: -0.3px;
|
|
}
|
|
header .subtitle {
|
|
font-size: 13px; color: var(--muted);
|
|
}
|
|
|
|
/* ── Tabs ───────────────────────────── */
|
|
.tabs {
|
|
display: flex; gap: 2px; padding: 16px 32px 0;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
.tab {
|
|
padding: 8px 20px; font-size: 13px; font-weight: 500;
|
|
color: var(--muted); cursor: pointer; border-radius: 6px 6px 0 0;
|
|
border: 1px solid transparent; border-bottom: none;
|
|
transition: all 0.15s; user-select: none;
|
|
}
|
|
.tab:hover { color: var(--text); background: var(--panel); }
|
|
.tab.active {
|
|
color: var(--text); background: var(--panel);
|
|
border-color: var(--border);
|
|
}
|
|
|
|
/* ── Main layout ───────────────────── */
|
|
.content { padding: 0 32px 32px; }
|
|
.eq-section { display: none; }
|
|
.eq-section.active { display: block; }
|
|
|
|
/* ── Equation card ─────────────────── */
|
|
.eq-card {
|
|
background: var(--panel); border: 1px solid var(--border);
|
|
border-radius: 10px; padding: 28px 32px; margin: 20px 0;
|
|
text-align: center; overflow-x: auto;
|
|
}
|
|
.eq-card .katex { font-size: 1.3em; }
|
|
.eq-desc {
|
|
font-size: 13px; color: var(--muted); text-align: center;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
/* ── Two-column: tree + detail ─────── */
|
|
.columns {
|
|
display: grid; grid-template-columns: 1fr 360px; gap: 20px;
|
|
align-items: start;
|
|
}
|
|
@media (max-width: 900px) {
|
|
.columns { grid-template-columns: 1fr; }
|
|
}
|
|
|
|
/* ── Tree ───────────────────────────── */
|
|
.tree {
|
|
display: flex; flex-direction: column; gap: 1px;
|
|
}
|
|
.node {
|
|
display: flex; align-items: center; gap: 8px;
|
|
padding: 5px 10px; border-radius: 5px; cursor: pointer;
|
|
transition: background 0.12s;
|
|
}
|
|
.node:hover { background: var(--panel); }
|
|
.node.selected { background: var(--panel-hi); outline: 1px solid var(--c-add); }
|
|
.node-indent { flex-shrink: 0; }
|
|
.node-icon {
|
|
width: 22px; height: 22px; border-radius: 4px;
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
font-size: 11px; font-weight: 700; flex-shrink: 0;
|
|
}
|
|
.ki-Mul { background: color-mix(in srgb, var(--c-mul) 20%, transparent); color: var(--c-mul); }
|
|
.ki-Dot { background: color-mix(in srgb, var(--c-dot) 20%, transparent); color: var(--c-dot); }
|
|
.ki-Add { background: color-mix(in srgb, var(--c-add) 20%, transparent); color: var(--c-add); }
|
|
.ki-Vector { background: color-mix(in srgb, var(--c-vec) 20%, transparent); color: var(--c-vec); }
|
|
.ki-Scalar { background: color-mix(in srgb, var(--c-scalar) 20%, transparent); color: var(--c-scalar); }
|
|
.ki-Ref { background: color-mix(in srgb, var(--c-ref) 20%, transparent); color: var(--c-ref); }
|
|
.ki-Fn { background: color-mix(in srgb, var(--c-fn) 20%, transparent); color: var(--c-fn); }
|
|
.ki-Cond { background: color-mix(in srgb, var(--c-cond) 20%, transparent); color: var(--c-cond); }
|
|
.node-label { font-size: 13px; }
|
|
.node-meta { font-size: 11px; color: var(--dim); margin-left: auto; white-space: nowrap; }
|
|
|
|
/* ── Detail panel ──────────────────── */
|
|
.detail {
|
|
background: var(--panel); border: 1px solid var(--border);
|
|
border-radius: 10px; padding: 20px; position: sticky; top: 20px;
|
|
min-height: 200px;
|
|
}
|
|
.detail-empty {
|
|
color: var(--dim); font-size: 13px; padding: 40px 0; text-align: center;
|
|
}
|
|
.detail h3 {
|
|
font-size: 14px; color: var(--text); margin-bottom: 12px;
|
|
font-weight: 600; letter-spacing: -0.2px;
|
|
}
|
|
.detail-latex {
|
|
background: var(--panel-hi); border-radius: 6px; padding: 14px;
|
|
margin-bottom: 14px; text-align: center; overflow-x: auto;
|
|
}
|
|
.detail-doc {
|
|
font-size: 13px; color: var(--muted); line-height: 1.6; margin-bottom: 12px;
|
|
}
|
|
.detail-meta { font-size: 12px; color: var(--muted); }
|
|
.detail-meta div { margin-bottom: 5px; }
|
|
.detail-meta b { color: var(--text); }
|
|
.cite-tag {
|
|
display: inline-block; background: var(--panel-hi); border-radius: 3px;
|
|
padding: 1px 7px; margin: 1px 2px; font-size: 11px; color: var(--c-ref);
|
|
}
|
|
|
|
/* ── Stats bar ─────────────────────── */
|
|
.stats {
|
|
display: flex; gap: 20px; padding: 8px 0; margin-top: 8px;
|
|
font-size: 12px; color: var(--muted); flex-wrap: wrap;
|
|
}
|
|
.stats span { display: inline-flex; align-items: center; gap: 4px; }
|
|
.stats .dot {
|
|
width: 8px; height: 8px; border-radius: 50%; display: inline-block;
|
|
}
|
|
|
|
/* ── Evaluator ─────────────────────── */
|
|
.evaluator {
|
|
background: var(--panel); border: 1px solid var(--border);
|
|
border-radius: 10px; padding: 20px; margin-top: 20px;
|
|
}
|
|
.evaluator h3 {
|
|
font-size: 14px; color: var(--text); margin-bottom: 14px; font-weight: 600;
|
|
}
|
|
.eval-grid {
|
|
display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
|
gap: 8px; margin-bottom: 14px;
|
|
}
|
|
.eval-field {
|
|
display: flex; align-items: center; gap: 6px;
|
|
}
|
|
.eval-field label {
|
|
font-size: 12px; color: var(--muted); min-width: 72px; text-align: right;
|
|
}
|
|
.eval-field input {
|
|
width: 90px; padding: 4px 8px; border-radius: 4px;
|
|
border: 1px solid var(--border); background: var(--panel-hi);
|
|
color: var(--text); font-size: 13px; font-family: inherit;
|
|
}
|
|
.eval-field input:focus {
|
|
outline: none; border-color: var(--c-add);
|
|
}
|
|
.eval-result {
|
|
font-size: 22px; font-weight: 600; color: var(--text);
|
|
display: flex; align-items: baseline; gap: 8px;
|
|
}
|
|
.eval-result small {
|
|
font-size: 12px; font-weight: 400; color: var(--muted);
|
|
}
|
|
|
|
/* ── Legend ─────────────────────────── */
|
|
.legend {
|
|
display: flex; gap: 12px; flex-wrap: wrap; padding: 12px 0 4px;
|
|
font-size: 12px; color: var(--muted);
|
|
}
|
|
.legend span {
|
|
display: inline-flex; align-items: center; gap: 4px;
|
|
}
|
|
.legend .swatch {
|
|
width: 10px; height: 10px; border-radius: 3px; display: inline-block;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<header>
|
|
<h1>PFS Equation Explorer</h1>
|
|
<span class="subtitle">Physician Fee Schedule — equation tree introspection</span>
|
|
</header>
|
|
|
|
<div class="tabs" id="tabs"></div>
|
|
|
|
<div class="content" id="content"></div>
|
|
|
|
<script>
|
|
// ── Data ─────────────────────────────────────────────────
|
|
const EQS = JSON.parse(atob("W3sia2V5IjogIlBGU19QQVlNRU5UIiwgInRpdGxlIjogIlBGUyBQYXltZW50IiwgImRlc2MiOiAiUEZTIHBheW1lbnQgPSBnZW8tYWRqdXN0ZWQgUlZVIHRvdGFsIFx1MDBkNyBjb252ZXJzaW9uIGZhY3RvciIsICJsYXRleCI6ICJcXGJlZ2lue2JtYXRyaXh9IFxcdGV4dHtXb3JrXFxfUlZVfSBcXFxcIFxcYmVnaW57Y2FzZXN9IFxcdGV4dHtGXFxfUEVcXF9SVlV9ICYgXFx0ZXh0e2lmIGZhY2lsaXR5fSBcXFxcIFxcdGV4dHtORlxcX1BFXFxfUlZVfSAmIFxcdGV4dHtvdGhlcndpc2V9IFxcZW5ke2Nhc2VzfSBcXFxcIFxcdGV4dHtNUFxcX1JWVX0gXFxlbmR7Ym1hdHJpeH0gXFxjZG90IFxcYmVnaW57Ym1hdHJpeH0gXFx0ZXh0e1dvcmtcXF9HUENJfSBcXFxcIFxcdGV4dHtQRVxcX0dQQ0l9IFxcXFwgXFx0ZXh0e01QXFxfR1BDSX0gXFxlbmR7Ym1hdHJpeH0gXFx0aW1lcyBcXHRleHR7Q0Z9IiwgInRleHQiOiAiUGF5bWVudCA9IEdlby1BZGp1c3RlZCBSVlVzIFx1MDBkNyBDRlxuICBHZW8tQWRqdXN0ZWQgUlZVcyA9IFJWVXMgXHUwMGI3IEdQQ0lzXG4gICAgUlZVcyA9IFtXb3JrX1JWVSwgUEVfUlZVLCBNUF9SVlVdXG4gICAgR1BDSXMgPSBbV29ya19HUENJLCBQRV9HUENJLCBNUF9HUENJXVxuICBDRiAgKCQvUlZVKSIsICJub2RlcyI6IFt7ImlkIjogMCwgInBhcmVudCI6IG51bGwsICJsYWJlbCI6ICJQYXltZW50IiwgImtpbmQiOiAiTXVsIiwgImRvYyI6ICJQRlMgcGF5bWVudCA9IGdlby1hZGp1c3RlZCBSVlUgdG90YWwgeCBjb252ZXJzaW9uIGZhY3RvciIsICJjaXRlIjogWyJtb2R1bGU6cGZzIiwgInJ1bGU6Y21zLTE4MDctZiIsICJzb3VyY2U6ZmVkZXJhbC1yZWdpc3RlciJdLCAibGF0ZXgiOiAiXFxiZWdpbntibWF0cml4fSBcXHRleHR7V29ya1xcX1JWVX0gXFxcXCBcXGJlZ2lue2Nhc2VzfSBcXHRleHR7RlxcX1BFXFxfUlZVfSAmIFxcdGV4dHtpZiBmYWNpbGl0eX0gXFxcXCBcXHRleHR7TkZcXF9QRVxcX1JWVX0gJiBcXHRleHR7b3RoZXJ3aXNlfSBcXGVuZHtjYXNlc30gXFxcXCBcXHRleHR7TVBcXF9SVlV9IFxcZW5ke2JtYXRyaXh9IFxcY2RvdCBcXGJlZ2lue2JtYXRyaXh9IFxcdGV4dHtXb3JrXFxfR1BDSX0gXFxcXCBcXHRleHR7UEVcXF9HUENJfSBcXFxcIFxcdGV4dHtNUFxcX0dQQ0l9IFxcZW5ke2JtYXRyaXh9IFxcdGltZXMgXFx0ZXh0e0NGfSJ9LCB7ImlkIjogMSwgInBhcmVudCI6IDAsICJsYWJlbCI6ICJHZW8tQWRqdXN0ZWQgUlZVcyIsICJraW5kIjogIkRvdCIsICJkb2MiOiAiU3VtIG9mIGVhY2ggUlZVIGNvbXBvbmVudCBtdWx0aXBsaWVkIGJ5IGl0cyBnZW9ncmFwaGljIGluZGV4IiwgImNpdGUiOiBbXSwgImxhdGV4IjogIlxcYmVnaW57Ym1hdHJpeH0gXFx0ZXh0e1dvcmtcXF9SVlV9IFxcXFwgXFxiZWdpbntjYXNlc30gXFx0ZXh0e0ZcXF9QRVxcX1JWVX0gJiBcXHRleHR7aWYgZmFjaWxpdHl9IFxcXFwgXFx0ZXh0e05GXFxfUEVcXF9SVlV9ICYgXFx0ZXh0e290aGVyd2lzZX0gXFxlbmR7Y2FzZXN9IFxcXFwgXFx0ZXh0e01QXFxfUlZVfSBcXGVuZHtibWF0cml4fSBcXGNkb3QgXFxiZWdpbntibWF0cml4fSBcXHRleHR7V29ya1xcX0dQQ0l9IFxcXFwgXFx0ZXh0e1BFXFxfR1BDSX0gXFxcXCBcXHRleHR7TVBcXF9HUENJfSBcXGVuZHtibWF0cml4fSJ9LCB7ImlkIjogMiwgInBhcmVudCI6IDEsICJsYWJlbCI6ICJSVlVzIiwgImtpbmQiOiAiVmVjdG9yIiwgImRvYyI6ICIiLCAiY2l0ZSI6IFtdLCAibGF0ZXgiOiAiXFxiZWdpbntibWF0cml4fSBcXHRleHR7V29ya1xcX1JWVX0gXFxcXCBcXGJlZ2lue2Nhc2VzfSBcXHRleHR7RlxcX1BFXFxfUlZVfSAmIFxcdGV4dHtpZiBmYWNpbGl0eX0gXFxcXCBcXHRleHR7TkZcXF9QRVxcX1JWVX0gJiBcXHRleHR7b3RoZXJ3aXNlfSBcXGVuZHtjYXNlc30gXFxcXCBcXHRleHR7TVBcXF9SVlV9IFxcZW5ke2JtYXRyaXh9In0sIHsiaWQiOiAzLCAicGFyZW50IjogMiwgImxhYmVsIjogIldvcmtfUlZVIiwgImtpbmQiOiAiUmVmIiwgImRvYyI6ICJQaHlzaWNpYW4gd29yayByZWxhdGl2ZSB2YWx1ZSB1bml0cyIsICJjaXRlIjogWyJmaWxlOnJ2dSIsICJtb2R1bGU6cGZzIiwgInNvdXJjZTpjbXMtd2Vic2l0ZSIsICJ0YWJsZTpwZnMucnZ1Il0sICJsYXRleCI6ICJcXHRleHR7V29ya1xcX1JWVX0iLCAidGFibGUiOiAicGZzLnJ2dSIsICJjb2x1bW4iOiAid29ya19ydnUifSwgeyJpZCI6IDQsICJwYXJlbnQiOiAyLCAibGFiZWwiOiAiUEVfUlZVIiwgImtpbmQiOiAiQ29uZCIsICJkb2MiOiAiUHJhY3RpY2UgZXhwZW5zZSBSVlVzIFx1MjAxNCBmYWNpbGl0eSBvciBub24tZmFjaWxpdHkgYnkgcGxhY2Ugb2Ygc2VydmljZSIsICJjaXRlIjogW10sICJsYXRleCI6ICJcXGJlZ2lue2Nhc2VzfSBcXHRleHR7RlxcX1BFXFxfUlZVfSAmIFxcdGV4dHtpZiBmYWNpbGl0eX0gXFxcXCBcXHRleHR7TkZcXF9QRVxcX1JWVX0gJiBcXHRleHR7b3RoZXJ3aXNlfSBcXGVuZHtjYXNlc30ifSwgeyJpZCI6IDUsICJwYXJlbnQiOiA0LCAibGFiZWwiOiAiRl9QRV9SVlUiLCAia2luZCI6ICJSZWYiLCAiZG9jIjogIkZhY2lsaXR5IHByYWN0aWNlIGV4cGVuc2UgUlZVcyIsICJjaXRlIjogWyJmaWxlOnJ2dSIsICJtb2R1bGU6cGZzIiwgInNvdXJjZTpjbXMtd2Vic2l0ZSIsICJ0YWJsZTpwZnMucnZ1Il0sICJsYXRleCI6ICJcXHRleHR7RlxcX1BFXFxfUlZVfSIsICJ0YWJsZSI6ICJwZnMucnZ1IiwgImNvbHVtbiI6ICJmYWNfcGVfcnZ1In0sIHsiaWQiOiA2LCAicGFyZW50IjogNCwgImxhYmVsIjogIk5GX1BFX1JWVSIsICJraW5kIjogIlJlZiIsICJkb2MiOiAiTm9uLWZhY2lsaXR5IHByYWN0aWNlIGV4cGVuc2UgUlZVcyIsICJjaXRlIjogWyJmaWxlOnJ2dSIsICJtb2R1bGU6cGZzIiwgInNvdXJjZTpjbXMtd2Vic2l0ZSIsICJ0YWJsZTpwZnMucnZ1Il0sICJsYXRleCI6ICJcXHRleHR7TkZcXF9QRVxcX1JWVX0iLCAidGFibGUiOiAicGZzLnJ2dSIsICJjb2x1bW4iOiAibm9uX2ZhY19wZV9ydnUifSwgeyJpZCI6IDcsICJwYXJlbnQiOiAyLCAibGFiZWwiOiAiTVBfUlZVIiwgImtpbmQiOiAiUmVmIiwgImRvYyI6ICJNYWxwcmFjdGljZSBSVlVzIiwgImNpdGUiOiBbImZpbGU6cnZ1IiwgIm1vZHVsZTpwZnMiLCAic291cmNlOmNtcy13ZWJzaXRlIiwgInRhYmxlOnBmcy5ydnUiXSwgImxhdGV4IjogIlxcdGV4dHtNUFxcX1JWVX0iLCAidGFibGUiOiAicGZzLnJ2dSIsICJjb2x1bW4iOiAibXBfcnZ1In0sIHsiaWQiOiA4LCAicGFyZW50IjogMSwgImxhYmVsIjogIkdQQ0lzIiwgImtpbmQiOiAiVmVjdG9yIiwgImRvYyI6ICIiLCAiY2l0ZSI6IFtdLCAibGF0ZXgiOiAiXFxiZWdpbntibWF0cml4fSBcXHRleHR7V29ya1xcX0dQQ0l9IFxcXFwgXFx0ZXh0e1BFXFxfR1BDSX0gXFxcXCBcXHRleHR7TVBcXF9HUENJfSBcXGVuZHtibWF0cml4fSJ9LCB7ImlkIjogOSwgInBhcmVudCI6IDgsICJsYWJlbCI6ICJXb3JrX0dQQ0kiLCAia2luZCI6ICJSZWYiLCAiZG9jIjogIldvcmsgR1BDSSBcdTIwMTQgYWRqdXN0cyBmb3IgbG9jYWwgcGh5c2ljaWFuIGNvbXBlbnNhdGlvbiIsICJjaXRlIjogWyJmaWxlOmdwY2kiLCAibW9kdWxlOnBmcyIsICJzb3VyY2U6ZmVkZXJhbC1yZWdpc3RlciIsICJ0YWJsZTpwZnMuZ3BjaSJdLCAibGF0ZXgiOiAiXFx0ZXh0e1dvcmtcXF9HUENJfSIsICJ0YWJsZSI6ICJwZnMuZ3BjaSIsICJjb2x1bW4iOiAid29ya19ncGNpIn0sIHsiaWQiOiAxMCwgInBhcmVudCI6IDgsICJsYWJlbCI6ICJQRV9HUENJIiwgImtpbmQiOiAiUmVmIiwgImRvYyI6ICJQRSBHUENJIFx1MjAxNCBhZGp1c3RzIGZvciBsb2NhbCBvZmZpY2UgcmVudCwgc3RhZmYsIGVxdWlwbWVudCIsICJjaXRlIjogWyJmaWxlOmdwY2kiLCAibW9kdWxlOnBmcyIsICJzb3VyY2U6ZmVkZXJhbC1yZWdpc3RlciIsICJ0YWJsZTpwZnMuZ3BjaSJdLCAibGF0ZXgiOiAiXFx0ZXh0e1BFXFxfR1BDSX0iLCAidGFibGUiOiAicGZzLmdwY2kiLCAiY29sdW1uIjogInBlX2dwY2kifSwgeyJpZCI6IDExLCAicGFyZW50IjogOCwgImxhYmVsIjogIk1QX0dQQ0kiLCAia2luZCI6ICJSZWYiLCAiZG9jIjogIk1QIEdQQ0kgXHUyMDE0IGFkanVzdHMgZm9yIGxvY2FsIG1hbHByYWN0aWNlIHByZW1pdW1zIiwgImNpdGUiOiBbImZpbGU6Z3BjaSIsICJtb2R1bGU6cGZzIiwgInNvdXJjZTpmZWRlcmFsLXJlZ2lzdGVyIiwgInRhYmxlOnBmcy5ncGNpIl0sICJsYXRleCI6ICJcXHRleHR7TVBcXF9HUENJfSIsICJ0YWJsZSI6ICJwZnMuZ3BjaSIsICJjb2x1bW4iOiAibXBfZ3BjaSJ9LCB7ImlkIjogMTIsICJwYXJlbnQiOiAwLCAibGFiZWwiOiAiQ0YiLCAia2luZCI6ICJTY2FsYXIiLCAiZG9jIjogIkNvbnZlcnNpb24gZmFjdG9yIFx1MjAxNCBzZXQgYW5udWFsbHkgaW4gdGhlIEZpbmFsIFJ1bGUiLCAiY2l0ZSI6IFsibW9kdWxlOnBmcyIsICJzb3VyY2U6ZmVkZXJhbC1yZWdpc3RlciJdLCAibGF0ZXgiOiAiXFx0ZXh0e0NGfSIsICJ1bml0IjogIiQvUlZVIn1dLCAic3RhdHMiOiB7InNvdXJjZXMiOiBbInBmcy5ncGNpIiwgInBmcy5ydnUiXSwgInJlZnMiOiBbIldvcmtfUlZVIiwgIkZfUEVfUlZVIiwgIk5GX1BFX1JWVSIsICJNUF9SVlUiLCAiV29ya19HUENJIiwgIlBFX0dQQ0kiLCAiTVBfR1BDSSJdLCAic2NhbGFycyI6IFsiQ0YiXSwgImRlcHRoIjogNCwgImNpdGF0aW9ucyI6IDMzLCAibm9kZV9jb3VudCI6IDEzfX0sIHsia2V5IjogIkRJUkVDVF9QRSIsICJ0aXRsZSI6ICJEaXJlY3QgUEUiLCAiZGVzYyI6ICJEaXJlY3QgcHJhY3RpY2UgZXhwZW5zZSA9IGxhYm9yICsgc3VwcGx5ICsgZXF1aXBtZW50IiwgImxhdGV4IjogIlxcdGV4dHtMYWJvclxcX0Nvc3R9KFxcY2RvdHMpICsgXFx0ZXh0e1N1cHBseVxcX0Nvc3R9KFxcY2RvdHMpICsgXFx0ZXh0e0VxdWlwbWVudFxcX0Nvc3R9KFxcY2RvdHMpIiwgInRleHQiOiAiRGlyZWN0X1BFID0gTGFib3JfQ29zdCArIFN1cHBseV9Db3N0ICsgRXF1aXBtZW50X0Nvc3RcbiAgTGFib3JfQ29zdChORl9NaW51dGVzLCBGX01pbnV0ZXMsIFJhdGUvTWluKVxuICBTdXBwbHlfQ29zdChORl9RdHksIEZfUXR5LCBVbml0X1ByaWNlKVxuICBFcXVpcG1lbnRfQ29zdChQcmljZSwgTGlmZSwgTWlucy9ZciwgTWFpbnQpIiwgIm5vZGVzIjogW3siaWQiOiAwLCAicGFyZW50IjogbnVsbCwgImxhYmVsIjogIkRpcmVjdF9QRSIsICJraW5kIjogIkFkZCIsICJkb2MiOiAiRGlyZWN0IHByYWN0aWNlIGV4cGVuc2UgPSBsYWJvciArIHN1cHBseSArIGVxdWlwbWVudCIsICJjaXRlIjogWyJtb2R1bGU6cGZzIiwgInJ1bGU6Y21zLTE4MDctZiIsICJzb3VyY2U6ZmVkZXJhbC1yZWdpc3RlciJdLCAibGF0ZXgiOiAiXFx0ZXh0e0xhYm9yXFxfQ29zdH0oXFxjZG90cykgKyBcXHRleHR7U3VwcGx5XFxfQ29zdH0oXFxjZG90cykgKyBcXHRleHR7RXF1aXBtZW50XFxfQ29zdH0oXFxjZG90cykifSwgeyJpZCI6IDEsICJwYXJlbnQiOiAwLCAibGFiZWwiOiAiTGFib3JfQ29zdCIsICJraW5kIjogIkZuIiwgImRvYyI6ICJTdW0gb2YgKG1pbnV0ZXMgeCByYXRlX3Blcl9taW51dGUpIG92ZXIgYWxsIGNsaW5pY2FsIGxhYm9yIGFjdGl2aXRpZXMiLCAiY2l0ZSI6IFtdLCAibGF0ZXgiOiAiXFx0ZXh0e0xhYm9yXFxfQ29zdH0oXFxjZG90cykifSwgeyJpZCI6IDIsICJwYXJlbnQiOiAxLCAibGFiZWwiOiAiTkZfTWludXRlcyIsICJraW5kIjogIlJlZiIsICJkb2MiOiAiIiwgImNpdGUiOiBbImZpbGU6cGUtbGFib3IiLCAibW9kdWxlOnBmcyIsICJzb3VyY2U6Y21zLXdlYnNpdGUiLCAidGFibGU6cGZzLmNsaW5pY2FsX2xhYm9yIl0sICJsYXRleCI6ICJcXHRleHR7TkZcXF9NaW51dGVzfSIsICJ0YWJsZSI6ICJwZnMuY2xpbmljYWxfbGFib3IiLCAiY29sdW1uIjogIm5mX21pbnV0ZXMifSwgeyJpZCI6IDMsICJwYXJlbnQiOiAxLCAibGFiZWwiOiAiRl9NaW51dGVzIiwgImtpbmQiOiAiUmVmIiwgImRvYyI6ICIiLCAiY2l0ZSI6IFsiZmlsZTpwZS1sYWJvciIsICJtb2R1bGU6cGZzIiwgInNvdXJjZTpjbXMtd2Vic2l0ZSIsICJ0YWJsZTpwZnMuY2xpbmljYWxfbGFib3IiXSwgImxhdGV4IjogIlxcdGV4dHtGXFxfTWludXRlc30iLCAidGFibGUiOiAicGZzLmNsaW5pY2FsX2xhYm9yIiwgImNvbHVtbiI6ICJmX21pbnV0ZXMifSwgeyJpZCI6IDQsICJwYXJlbnQiOiAxLCAibGFiZWwiOiAiUmF0ZS9NaW4iLCAia2luZCI6ICJSZWYiLCAiZG9jIjogIiIsICJjaXRlIjogWyJmaWxlOnBlLWxhYm9yIiwgIm1vZHVsZTpwZnMiLCAic291cmNlOmNtcy13ZWJzaXRlIiwgInRhYmxlOnBmcy5jbGluaWNhbF9sYWJvciJdLCAibGF0ZXgiOiAiXFx0ZXh0e1JhdGUvTWlufSIsICJ0YWJsZSI6ICJwZnMuY2xpbmljYWxfbGFib3IiLCAiY29sdW1uIjogInJhdGVfcGVyX21pbnV0ZSJ9LCB7ImlkIjogNSwgInBhcmVudCI6IDAsICJsYWJlbCI6ICJTdXBwbHlfQ29zdCIsICJraW5kIjogIkZuIiwgImRvYyI6ICJTdW0gb2YgKHF1YW50aXR5IHggdW5pdF9wcmljZSkgb3ZlciBhbGwgc3VwcGx5IGl0ZW1zIiwgImNpdGUiOiBbXSwgImxhdGV4IjogIlxcdGV4dHtTdXBwbHlcXF9Db3N0fShcXGNkb3RzKSJ9LCB7ImlkIjogNiwgInBhcmVudCI6IDUsICJsYWJlbCI6ICJORl9RdHkiLCAia2luZCI6ICJSZWYiLCAiZG9jIjogIiIsICJjaXRlIjogWyJmaWxlOnBlLXN1cHBseSIsICJtb2R1bGU6cGZzIiwgInNvdXJjZTpjbXMtd2Vic2l0ZSIsICJ0YWJsZTpwZnMubWVkaWNhbF9zdXBwbHkiXSwgImxhdGV4IjogIlxcdGV4dHtORlxcX1F0eX0iLCAidGFibGUiOiAicGZzLm1lZGljYWxfc3VwcGx5IiwgImNvbHVtbiI6ICJuZl9xdWFudGl0eSJ9LCB7ImlkIjogNywgInBhcmVudCI6IDUsICJsYWJlbCI6ICJGX1F0eSIsICJraW5kIjogIlJlZiIsICJkb2MiOiAiIiwgImNpdGUiOiBbImZpbGU6cGUtc3VwcGx5IiwgIm1vZHVsZTpwZnMiLCAic291cmNlOmNtcy13ZWJzaXRlIiwgInRhYmxlOnBmcy5tZWRpY2FsX3N1cHBseSJdLCAibGF0ZXgiOiAiXFx0ZXh0e0ZcXF9RdHl9IiwgInRhYmxlIjogInBmcy5tZWRpY2FsX3N1cHBseSIsICJjb2x1bW4iOiAiZl9xdWFudGl0eSJ9LCB7ImlkIjogOCwgInBhcmVudCI6IDUsICJsYWJlbCI6ICJVbml0X1ByaWNlIiwgImtpbmQiOiAiUmVmIiwgImRvYyI6ICIiLCAiY2l0ZSI6IFsiZmlsZTpwZS1zdXBwbHkiLCAibW9kdWxlOnBmcyIsICJzb3VyY2U6Y21zLXdlYnNpdGUiLCAidGFibGU6cGZzLm1lZGljYWxfc3VwcGx5Il0sICJsYXRleCI6ICJcXHRleHR7VW5pdFxcX1ByaWNlfSIsICJ0YWJsZSI6ICJwZnMubWVkaWNhbF9zdXBwbHkiLCAiY29sdW1uIjogInVuaXRfcHJpY2UifSwgeyJpZCI6IDksICJwYXJlbnQiOiAwLCAibGFiZWwiOiAiRXF1aXBtZW50X0Nvc3QiLCAia2luZCI6ICJGbiIsICJkb2MiOiAiU3VtIG9mIGFtb3J0aXplZCBlcXVpcG1lbnQgY29zdDogKHByaWNlIC8gbGlmZSAvIG1pbnNfeXIpIHggKDEgKyBtYWludCkgeCB0aW1lIiwgImNpdGUiOiBbXSwgImxhdGV4IjogIlxcdGV4dHtFcXVpcG1lbnRcXF9Db3N0fShcXGNkb3RzKSJ9LCB7ImlkIjogMTAsICJwYXJlbnQiOiA5LCAibGFiZWwiOiAiUHJpY2UiLCAia2luZCI6ICJSZWYiLCAiZG9jIjogIiIsICJjaXRlIjogWyJmaWxlOnBlLWVxdWlwbWVudCIsICJtb2R1bGU6cGZzIiwgInNvdXJjZTpjbXMtd2Vic2l0ZSIsICJ0YWJsZTpwZnMubWVkaWNhbF9lcXVpcG1lbnQiXSwgImxhdGV4IjogIlxcdGV4dHtQcmljZX0iLCAidGFibGUiOiAicGZzLm1lZGljYWxfZXF1aXBtZW50IiwgImNvbHVtbiI6ICJ1bml0X3ByaWNlIn0sIHsiaWQiOiAxMSwgInBhcmVudCI6IDksICJsYWJlbCI6ICJMaWZlIiwgImtpbmQiOiAiUmVmIiwgImRvYyI6ICIiLCAiY2l0ZSI6IFsiZmlsZTpwZS1lcXVpcG1lbnQiLCAibW9kdWxlOnBmcyIsICJzb3VyY2U6Y21zLXdlYnNpdGUiLCAidGFibGU6cGZzLm1lZGljYWxfZXF1aXBtZW50Il0sICJsYXRleCI6ICJcXHRleHR7TGlmZX0iLCAidGFibGUiOiAicGZzLm1lZGljYWxfZXF1aXBtZW50IiwgImNvbHVtbiI6ICJ1c2VmdWxfbGlmZSJ9LCB7ImlkIjogMTIsICJwYXJlbnQiOiA5LCAibGFiZWwiOiAiTWlucy9ZciIsICJraW5kIjogIlJlZiIsICJkb2MiOiAiIiwgImNpdGUiOiBbImZpbGU6cGUtZXF1aXBtZW50IiwgIm1vZHVsZTpwZnMiLCAic291cmNlOmNtcy13ZWJzaXRlIiwgInRhYmxlOnBmcy5tZWRpY2FsX2VxdWlwbWVudCJdLCAibGF0ZXgiOiAiXFx0ZXh0e01pbnMvWXJ9IiwgInRhYmxlIjogInBmcy5tZWRpY2FsX2VxdWlwbWVudCIsICJjb2x1bW4iOiAibWludXRlc19wZXJfeWVhciJ9LCB7ImlkIjogMTMsICJwYXJlbnQiOiA5LCAibGFiZWwiOiAiTWFpbnQiLCAia2luZCI6ICJSZWYiLCAiZG9jIjogIiIsICJjaXRlIjogWyJmaWxlOnBlLWVxdWlwbWVudCIsICJtb2R1bGU6cGZzIiwgInNvdXJjZTpjbXMtd2Vic2l0ZSIsICJ0YWJsZTpwZnMubWVkaWNhbF9lcXVpcG1lbnQiXSwgImxhdGV4IjogIlxcdGV4dHtNYWludH0iLCAidGFibGUiOiAicGZzLm1lZGljYWxfZXF1aXBtZW50IiwgImNvbHVtbiI6ICJtYWludGVuYW5jZV9mYWN0b3IifV0sICJzdGF0cyI6IHsic291cmNlcyI6IFsicGZzLmNsaW5pY2FsX2xhYm9yIiwgInBmcy5tZWRpY2FsX2VxdWlwbWVudCIsICJwZnMubWVkaWNhbF9zdXBwbHkiXSwgInJlZnMiOiBbIk5GX01pbnV0ZXMiLCAiRl9NaW51dGVzIiwgIlJhdGUvTWluIiwgIk5GX1F0eSIsICJGX1F0eSIsICJVbml0X1ByaWNlIiwgIlByaWNlIiwgIkxpZmUiLCAiTWlucy9ZciIsICJNYWludCJdLCAic2NhbGFycyI6IFtdLCAiZGVwdGgiOiAyLCAiY2l0YXRpb25zIjogNDMsICJub2RlX2NvdW50IjogMTR9fSwgeyJrZXkiOiAiTVBQUiIsICJ0aXRsZSI6ICJNUFBSIiwgImRlc2MiOiAiTXVsdGlwbGUgUHJvY2VkdXJlIFBheW1lbnQgUmVkdWN0aW9uIiwgImxhdGV4IjogIlxcYmVnaW57Y2FzZXN9IFxcdGV4dHtQRVxcX1JWVX0gJiBcXHRleHR7aWYgcmFuayA9PSAxfSBcXFxcIFxcdGV4dHtQRVxcX1JWVX0gXFx0aW1lcyBcXHVuZGVyYnJhY2V7MC41fV97XFx0ZXh0ezEtcmVkdWN0aW9ufX0gJiBcXHRleHR7b3RoZXJ3aXNlfSBcXGVuZHtjYXNlc30iLCAidGV4dCI6ICJBZGp1c3RlZF9QRSAgaWYgcmFuayA9PSAxOlxuICBQRV9SVlUgIFtwZnMucnZ1Lm5vbl9mYWNfcGVfcnZ1XVxuICBlbHNlOlxuICBSZWR1Y2VkX1BFID0gUEVfUlZVIFx1MDBkNyAxLXJlZHVjdGlvblxuICAgIFBFX1JWVSAgW3Bmcy5ydnUubm9uX2ZhY19wZV9ydnVdXG4gICAgMS1yZWR1Y3Rpb24gPSAwLjUiLCAibm9kZXMiOiBbeyJpZCI6IDAsICJwYXJlbnQiOiBudWxsLCAibGFiZWwiOiAiQWRqdXN0ZWRfUEUiLCAia2luZCI6ICJDb25kIiwgImRvYyI6ICJNdWx0aXBsZSBQcm9jZWR1cmUgUGF5bWVudCBSZWR1Y3Rpb24gXHUyMDE0IGZ1bGwgUEUgZm9yIGhpZ2hlc3QtdmFsdWVkLCByZWR1Y2VkIGZvciByZXN0IiwgImNpdGUiOiBbIm1vZHVsZTpwZnMiLCAicnVsZTpjbXMtMTgwNy1mIiwgInNvdXJjZTpmZWRlcmFsLXJlZ2lzdGVyIl0sICJsYXRleCI6ICJcXGJlZ2lue2Nhc2VzfSBcXHRleHR7UEVcXF9SVlV9ICYgXFx0ZXh0e2lmIHJhbmsgPT0gMX0gXFxcXCBcXHRleHR7UEVcXF9SVlV9IFxcdGltZXMgXFx1bmRlcmJyYWNlezAuNX1fe1xcdGV4dHsxLXJlZHVjdGlvbn19ICYgXFx0ZXh0e290aGVyd2lzZX0gXFxlbmR7Y2FzZXN9In0sIHsiaWQiOiAxLCAicGFyZW50IjogMCwgImxhYmVsIjogIlBFX1JWVSIsICJraW5kIjogIlJlZiIsICJkb2MiOiAiIiwgImNpdGUiOiBbXSwgImxhdGV4IjogIlxcdGV4dHtQRVxcX1JWVX0iLCAidGFibGUiOiAicGZzLnJ2dSIsICJjb2x1bW4iOiAibm9uX2ZhY19wZV9ydnUifSwgeyJpZCI6IDIsICJwYXJlbnQiOiAwLCAibGFiZWwiOiAiUmVkdWNlZF9QRSIsICJraW5kIjogIk11bCIsICJkb2MiOiAiIiwgImNpdGUiOiBbXSwgImxhdGV4IjogIlxcdGV4dHtQRVxcX1JWVX0gXFx0aW1lcyBcXHVuZGVyYnJhY2V7MC41fV97XFx0ZXh0ezEtcmVkdWN0aW9ufX0ifSwgeyJpZCI6IDMsICJwYXJlbnQiOiAyLCAibGFiZWwiOiAiUEVfUlZVIiwgImtpbmQiOiAiUmVmIiwgImRvYyI6ICIiLCAiY2l0ZSI6IFtdLCAibGF0ZXgiOiAiXFx0ZXh0e1BFXFxfUlZVfSIsICJ0YWJsZSI6ICJwZnMucnZ1IiwgImNvbHVtbiI6ICJub25fZmFjX3BlX3J2dSJ9LCB7ImlkIjogNCwgInBhcmVudCI6IDIsICJsYWJlbCI6ICIxLXJlZHVjdGlvbiIsICJraW5kIjogIlNjYWxhciIsICJkb2MiOiAiNTAlIFBFIHJlZHVjdGlvbiBmb3IgcmFuayA+IDEiLCAiY2l0ZSI6IFtdLCAibGF0ZXgiOiAiXFx1bmRlcmJyYWNlezAuNX1fe1xcdGV4dHsxLXJlZHVjdGlvbn19IiwgInZhbHVlIjogMC41fV0sICJzdGF0cyI6IHsic291cmNlcyI6IFsicGZzLnJ2dSJdLCAicmVmcyI6IFsiUEVfUlZVIiwgIlBFX1JWVSJdLCAic2NhbGFycyI6IFsiMS1yZWR1Y3Rpb24iXSwgImRlcHRoIjogMiwgImNpdGF0aW9ucyI6IDMsICJub2RlX2NvdW50IjogNX19LCB7ImtleSI6ICJJTlRFTlNJVFkiLCAidGl0bGUiOiAiSW50ZW5zaXR5IiwgImRlc2MiOiAiVGltZS1pbnRlbnNpdHkgcmF0aW8gPSBXb3JrX1JWVSAvIFRvdGFsX1RpbWUiLCAibGF0ZXgiOiAiXFx0ZXh0e1dvcmtcXF9SVlV9IFxcdGltZXMgXFx0ZXh0ezEvVG90YWxcXF9UaW1lfSIsICJ0ZXh0IjogIkludGVuc2l0eSA9IFdvcmtfUlZVIFx1MDBkNyAxL1RvdGFsX1RpbWVcbiAgV29ya19SVlUgIFtwZnMucGh5c2ljaWFuX3dvcmtfdGltZS53b3JrX3J2dV1cbiAgMS9Ub3RhbF9UaW1lIiwgIm5vZGVzIjogW3siaWQiOiAwLCAicGFyZW50IjogbnVsbCwgImxhYmVsIjogIkludGVuc2l0eSIsICJraW5kIjogIk11bCIsICJkb2MiOiAiVGltZS1pbnRlbnNpdHkgcmF0aW8gPSBXb3JrX1JWVSAvIFRvdGFsX1RpbWUiLCAiY2l0ZSI6IFsibW9kdWxlOnBmcyIsICJydWxlOmNtcy0xODA3LWYiLCAic291cmNlOmZlZGVyYWwtcmVnaXN0ZXIiXSwgImxhdGV4IjogIlxcdGV4dHtXb3JrXFxfUlZVfSBcXHRpbWVzIFxcdGV4dHsxL1RvdGFsXFxfVGltZX0ifSwgeyJpZCI6IDEsICJwYXJlbnQiOiAwLCAibGFiZWwiOiAiV29ya19SVlUiLCAia2luZCI6ICJSZWYiLCAiZG9jIjogIiIsICJjaXRlIjogWyJtb2R1bGU6cGZzIiwgInNvdXJjZTpjbXMtd2Vic2l0ZSIsICJ0YWJsZTpwZnMucGh5c2ljaWFuX3dvcmtfdGltZSJdLCAibGF0ZXgiOiAiXFx0ZXh0e1dvcmtcXF9SVlV9IiwgInRhYmxlIjogInBmcy5waHlzaWNpYW5fd29ya190aW1lIiwgImNvbHVtbiI6ICJ3b3JrX3J2dSJ9LCB7ImlkIjogMiwgInBhcmVudCI6IDAsICJsYWJlbCI6ICIxL1RvdGFsX1RpbWUiLCAia2luZCI6ICJTY2FsYXIiLCAiZG9jIjogIlJlY2lwcm9jYWwgb2YgdG90YWwgcGh5c2ljaWFuIHRpbWUiLCAiY2l0ZSI6IFtdLCAibGF0ZXgiOiAiXFx0ZXh0ezEvVG90YWxcXF9UaW1lfSJ9XSwgInN0YXRzIjogeyJzb3VyY2VzIjogWyJwZnMucGh5c2ljaWFuX3dvcmtfdGltZSJdLCAicmVmcyI6IFsiV29ya19SVlUiXSwgInNjYWxhcnMiOiBbIjEvVG90YWxfVGltZSJdLCAiZGVwdGgiOiAxLCAiY2l0YXRpb25zIjogNiwgIm5vZGVfY291bnQiOiAzfX1d"));
|
|
const EVAL_DEFAULTS = JSON.parse(atob("eyJXb3JrX1JWVSI6IDEuNSwgIlBFX1JWVSI6IDEuMjEsICJNUF9SVlUiOiAwLjA5LCAiV29ya19HUENJIjogMS4wMjQsICJQRV9HUENJIjogMC45ODgsICJNUF9HUENJIjogMC41NzQsICJDRiI6IDMyLjM0NjV9"));
|
|
|
|
const KIND_ICON = {
|
|
Mul: "\u00d7", Dot: "\u00b7", Add: "+", Vector: "[ ]",
|
|
Scalar: "#", Ref: "\u2192", Fn: "f()", Cond: "?"
|
|
};
|
|
const KIND_COLORS = {
|
|
Mul: "var(--c-mul)", Dot: "var(--c-dot)", Add: "var(--c-add)",
|
|
Vector: "var(--c-vec)", Scalar: "var(--c-scalar)", Ref: "var(--c-ref)",
|
|
Fn: "var(--c-fn)", Cond: "var(--c-cond)"
|
|
};
|
|
|
|
// ── Build tabs + sections ────────────────────────────────
|
|
const tabsEl = document.getElementById("tabs");
|
|
const contentEl = document.getElementById("content");
|
|
|
|
EQS.forEach((eq, i) => {
|
|
// Tab
|
|
const tab = document.createElement("div");
|
|
tab.className = "tab" + (i === 0 ? " active" : "");
|
|
tab.textContent = eq.title;
|
|
tab.dataset.idx = i;
|
|
tab.onclick = () => activate(i);
|
|
tabsEl.appendChild(tab);
|
|
|
|
// Section
|
|
const sec = document.createElement("div");
|
|
sec.className = "eq-section" + (i === 0 ? " active" : "");
|
|
sec.id = "sec-" + i;
|
|
sec.innerHTML = buildSection(eq, i);
|
|
contentEl.appendChild(sec);
|
|
});
|
|
|
|
function activate(idx) {
|
|
document.querySelectorAll(".tab").forEach(t => t.classList.toggle("active", +t.dataset.idx === idx));
|
|
document.querySelectorAll(".eq-section").forEach(s => s.classList.remove("active"));
|
|
document.getElementById("sec-" + idx).classList.add("active");
|
|
renderAllKatex();
|
|
}
|
|
|
|
// ── Section builder ──────────────────────────────────────
|
|
function buildSection(eq, idx) {
|
|
const s = eq.stats;
|
|
let html = '';
|
|
|
|
// Description
|
|
html += '<p class="eq-desc">' + esc(eq.desc) + '</p>';
|
|
|
|
// Main equation card
|
|
html += '<div class="eq-card"><div class="katex-render" data-latex="' + attr(eq.latex) + '"></div></div>';
|
|
|
|
// Legend
|
|
html += '<div class="legend">';
|
|
for (const [k, v] of Object.entries(KIND_COLORS)) {
|
|
html += '<span><span class="swatch" style="background:' + v + '"></span>' + k + '</span>';
|
|
}
|
|
html += '</div>';
|
|
|
|
// Stats
|
|
html += '<div class="stats">';
|
|
html += '<span><span class="dot" style="background:var(--c-ref)"></span>' + s.node_count + ' nodes</span>';
|
|
html += '<span><span class="dot" style="background:var(--c-dot)"></span>depth ' + s.depth + '</span>';
|
|
html += '<span><span class="dot" style="background:var(--c-scalar)"></span>' + s.sources.length + ' sources</span>';
|
|
html += '<span><span class="dot" style="background:var(--c-cond)"></span>' + s.citations + ' citations</span>';
|
|
html += '</div>';
|
|
|
|
// Columns: tree + detail
|
|
html += '<div class="columns">';
|
|
|
|
// Tree
|
|
html += '<div class="tree" id="tree-' + idx + '">';
|
|
eq.nodes.forEach(n => {
|
|
const d = getDepth(n, eq.nodes);
|
|
html += '<div class="node" data-nid="' + n.id + '" data-eq="' + idx + '" onclick="showDetail(' + idx + ',' + n.id + ')">';
|
|
html += '<span class="node-indent" style="width:' + (d * 20) + 'px"></span>';
|
|
html += '<span class="node-icon ki-' + n.kind + '">' + (KIND_ICON[n.kind] || "?") + '</span>';
|
|
html += '<span class="node-label">' + esc(n.label) + '</span>';
|
|
let meta = '';
|
|
if (n.table) meta = n.table + '.' + n.column;
|
|
else if (n.value !== undefined) meta = n.value + (n.unit ? ' ' + n.unit : '');
|
|
if (meta) html += '<span class="node-meta">' + esc(meta) + '</span>';
|
|
html += '</div>';
|
|
});
|
|
html += '</div>';
|
|
|
|
// Detail panel
|
|
html += '<div class="detail" id="detail-' + idx + '"><div class="detail-empty">Click a node to inspect</div></div>';
|
|
|
|
html += '</div>'; // .columns
|
|
|
|
// Evaluator (only for PFS_PAYMENT)
|
|
if (eq.key === "PFS_PAYMENT") {
|
|
html += '<div class="evaluator" id="evaluator">';
|
|
html += '<h3>Evaluate</h3>';
|
|
html += '<div class="eval-grid">';
|
|
for (const [k, v] of Object.entries(EVAL_DEFAULTS)) {
|
|
html += '<div class="eval-field">';
|
|
html += '<label>' + esc(k) + '</label>';
|
|
html += '<input type="number" step="any" value="' + v + '" data-var="' + esc(k) + '" oninput="recalc()">';
|
|
html += '</div>';
|
|
}
|
|
html += '</div>';
|
|
html += '<div class="eval-result" id="eval-result">$<span id="eval-value">--</span><small>Payment</small></div>';
|
|
html += '</div>';
|
|
}
|
|
|
|
return html;
|
|
}
|
|
|
|
// ── Detail panel ─────────────────────────────────────────
|
|
function showDetail(eqIdx, nodeId) {
|
|
const eq = EQS[eqIdx];
|
|
const n = eq.nodes.find(x => x.id === nodeId);
|
|
if (!n) return;
|
|
|
|
// Highlight
|
|
document.querySelectorAll("#tree-" + eqIdx + " .node").forEach(el => el.classList.remove("selected"));
|
|
document.querySelector('#tree-' + eqIdx + ' [data-nid="' + nodeId + '"]').classList.add("selected");
|
|
|
|
const panel = document.getElementById("detail-" + eqIdx);
|
|
let html = '';
|
|
html += '<h3>' + esc(n.label) + ' <span style="font-weight:400;color:var(--muted);font-size:12px">' + n.kind + '</span></h3>';
|
|
html += '<div class="detail-latex"><div class="katex-render" data-latex="' + attr(n.latex) + '"></div></div>';
|
|
if (n.doc) html += '<div class="detail-doc">' + esc(n.doc) + '</div>';
|
|
|
|
html += '<div class="detail-meta">';
|
|
if (n.table) html += '<div>Source: <b>' + esc(n.table) + '</b>.' + esc(n.column) + '</div>';
|
|
if (n.value !== undefined) html += '<div>Value: <b>' + n.value + '</b>' + (n.unit ? ' ' + n.unit : '') + '</div>';
|
|
if (n.cite && n.cite.length) {
|
|
html += '<div>Citations: ' + n.cite.map(c => '<span class="cite-tag">' + esc(c) + '</span>').join('') + '</div>';
|
|
}
|
|
html += '</div>';
|
|
|
|
panel.innerHTML = html;
|
|
renderAllKatex();
|
|
}
|
|
|
|
// ── Evaluator ────────────────────────────────────────────
|
|
function recalc() {
|
|
const vals = {};
|
|
document.querySelectorAll("#evaluator input").forEach(inp => {
|
|
vals[inp.dataset.var] = parseFloat(inp.value) || 0;
|
|
});
|
|
// PFS Payment = (Work_RVU*Work_GPCI + PE_RVU*PE_GPCI + MP_RVU*MP_GPCI) * CF
|
|
const dot = vals.Work_RVU * vals.Work_GPCI
|
|
+ vals.PE_RVU * vals.PE_GPCI
|
|
+ vals.MP_RVU * vals.MP_GPCI;
|
|
const payment = dot * vals.CF;
|
|
document.getElementById("eval-value").textContent = payment.toFixed(2);
|
|
}
|
|
|
|
// ── KaTeX rendering ──────────────────────────────────────
|
|
function renderAllKatex() {
|
|
document.querySelectorAll(".katex-render").forEach(el => {
|
|
if (el.dataset.rendered) return;
|
|
const latex = el.dataset.latex;
|
|
if (!latex) return;
|
|
try {
|
|
katex.render(latex, el, { displayMode: true, throwOnError: false });
|
|
el.dataset.rendered = "1";
|
|
} catch(e) {
|
|
el.textContent = latex;
|
|
}
|
|
});
|
|
}
|
|
|
|
// ── Utilities ────────────────────────────────────────────
|
|
function getDepth(node, nodes) {
|
|
let d = 0, cur = node;
|
|
while (cur.parent !== null) { d++; cur = nodes[cur.parent]; }
|
|
return d;
|
|
}
|
|
|
|
function esc(s) {
|
|
const d = document.createElement("div");
|
|
d.textContent = s;
|
|
return d.innerHTML;
|
|
}
|
|
|
|
function attr(s) {
|
|
return s.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">");
|
|
}
|
|
|
|
// ── Init ─────────────────────────────────────────────────
|
|
renderAllKatex();
|
|
if (document.getElementById("evaluator")) recalc();
|
|
</script>
|
|
</body>
|
|
</html> |