Download docs/index.html from PYTHAI/bankml: direct link, hf CLI and curl.
- Browser
- Download file 22.7 kB
-
https://huggingface.co/spaces/PYTHAI/bankml/resolve/main/docs/index.html
- Command line
-
hf download hf://spaces/PYTHAI/bankml/docs/index.html
-
curl -L -o index.html https://huggingface.co/spaces/PYTHAI/bankml/resolve/main/docs/index.html
22.7 kB
| <html><head><meta charset=utf8><meta name=viewport content="width=device-width,initial-scale=1,viewport-fit=cover"><style>:root{color-scheme:light;box-sizing:border-box;padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px)}html{scroll-padding-top:env(safe-area-inset-top,0px)}body{margin:0;padding:0;font:14px -apple-system,BlinkMacSystemFont,sans-serif;background:#faf9f5;color:#141413}img{max-width:100%}[hidden]:not([hidden=until-found i]){display:none}</style></head><body> | |
| <title>bankml Documentation</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=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans+Condensed:wght@500;600;700&family=IBM+Plex+Sans:ital,wght@0,400;0,500;0,600;1,400&display=swap"> | |
| <style> | |
| /* Layout: a technical-manual reader — a fixed index of documents on the left, the document in a 72ch column, | |
| its own contents on the right on wide screens; one column with a document picker on phones. */ | |
| :root { | |
| --bg: #f6f7f8; /* paper, a hair cooler than white */ | |
| --panel: #ffffff; | |
| --ink: #16202a; /* body text */ | |
| --muted: #5a6875; /* captions, secondary */ | |
| --rule: #d9dee3; /* hairlines */ | |
| --code-bg: #eef1f3; | |
| --accent: #0e6f68; /* the verified state: teal */ | |
| --accent-soft: rgba(14, 111, 104, 0.10); | |
| --gold: #9a6a12; /* Savante's gold, for the one release marker */ | |
| --neg: #b4453a; /* −1 */ | |
| --zero: #7a8793; /* 0 */ | |
| --pos: #0e6f68; /* +1 */ | |
| --f-display: "IBM Plex Sans Condensed", "Arial Narrow", system-ui, sans-serif; | |
| --f-body: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif; | |
| --f-mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace; | |
| color-scheme: light; | |
| } | |
| @media (prefers-color-scheme: dark) { | |
| :root:not([data-theme="light"]) { | |
| --bg: #0f1418; --panel: #151c21; --ink: #dfe6ea; --muted: #93a2ae; --rule: #28323a; --code-bg: #1b242b; | |
| --accent: #4cc3b7; --accent-soft: rgba(76, 195, 183, 0.12); --gold: #d9a23a; --neg: #e07a6f; --zero: #8a98a4; --pos: #4cc3b7; | |
| color-scheme: dark; | |
| } | |
| } | |
| :root[data-theme="dark"] { | |
| --bg: #0f1418; --panel: #151c21; --ink: #dfe6ea; --muted: #93a2ae; --rule: #28323a; --code-bg: #1b242b; | |
| --accent: #4cc3b7; --accent-soft: rgba(76, 195, 183, 0.12); --gold: #d9a23a; --neg: #e07a6f; --zero: #8a98a4; --pos: #4cc3b7; | |
| color-scheme: dark; | |
| } | |
| * { box-sizing: border-box; } | |
| html, body { background: var(--bg); color: var(--ink); } | |
| body { font: 16px/1.62 var(--f-body); } | |
| a { color: var(--accent); text-underline-offset: 2px; } | |
| a:focus-visible, button:focus-visible, select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } | |
| .masthead { | |
| border-bottom: 1px solid var(--rule); background: var(--panel); | |
| padding-inline: 16px; padding-block: 14px 12px; | |
| } | |
| .masthead-inner { max-width: 1320px; margin: 0 auto; display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 18px; } | |
| .brand { font: 700 22px/1.1 var(--f-display); letter-spacing: 0.01em; margin: 0; } | |
| .brand .ver { color: var(--gold); font-weight: 600; margin-left: 6px; } | |
| .tag { font-size: 14px; color: var(--muted); } | |
| .trits { display: inline-flex; gap: 3px; vertical-align: middle; margin-right: 8px; } | |
| .trits i { width: 7px; height: 7px; border-radius: 1px; display: inline-block; } | |
| .trits i:nth-child(1) { background: var(--neg); } .trits i:nth-child(2) { background: var(--zero); } .trits i:nth-child(3) { background: var(--pos); } | |
| .proof { | |
| flex-basis: 100%; font: 500 12.5px/1.5 var(--f-mono); color: var(--muted); letter-spacing: 0.01em; | |
| font-variant-numeric: tabular-nums; | |
| } | |
| .proof b { color: var(--accent); font-weight: 600; } | |
| .shell { max-width: 1320px; margin: 0 auto; padding-inline: 16px; display: grid; grid-template-columns: 236px minmax(0, 1fr) 220px; gap: 36px; } | |
| .nav { position: sticky; top: env(safe-area-inset-top, 0px); align-self: start; max-height: 100vh; overflow-y: auto; padding-block: 22px; } | |
| .nav h2 { font: 600 11px/1 var(--f-mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); margin: 18px 0 8px; } | |
| .nav h2:first-child { margin-top: 0; } | |
| .nav ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; } | |
| .nav a { display: block; padding: 5px 10px; border-radius: 6px; color: var(--ink); text-decoration: none; font-size: 14.5px; } | |
| .nav a small { display: block; color: var(--muted); font-size: 12px; line-height: 1.35; } | |
| .nav a:hover { background: var(--accent-soft); } | |
| .nav a[aria-current="page"] { background: var(--accent-soft); color: var(--accent); font-weight: 600; } | |
| .picker { display: none; } | |
| main { min-width: 0; padding-block: 22px 80px; } | |
| .docmeta { display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: center; font: 12.5px/1.4 var(--f-mono); color: var(--muted); margin-bottom: 10px; } | |
| .docmeta a { color: var(--muted); } | |
| article { max-width: 76ch; } | |
| article h1, article h2, article h3, article h4 { font-family: var(--f-display); line-height: 1.2; text-wrap: balance; scroll-margin-top: 16px; } | |
| article h1 { font-size: 2.05rem; font-weight: 700; margin: 0.2em 0 0.5em; } | |
| article h2 { font-size: 1.45rem; font-weight: 600; margin: 1.9em 0 0.5em; padding-top: 0.4em; border-top: 1px solid var(--rule); } | |
| article h3 { font-size: 1.14rem; font-weight: 600; margin: 1.5em 0 0.4em; } | |
| article h4 { font-size: 1rem; font-weight: 600; margin: 1.3em 0 0.3em; } | |
| article p, article li { max-width: 72ch; } | |
| article ul, article ol { padding-left: 1.4em; } | |
| article li + li { margin-top: 0.2em; } | |
| article code { font: 0.88em/1.4 var(--f-mono); background: var(--code-bg); padding: 0.08em 0.35em; border-radius: 4px; } | |
| article pre { background: var(--code-bg); border: 1px solid var(--rule); border-radius: 8px; padding: 12px 14px; overflow-x: auto; font-size: 13.5px; line-height: 1.5; } | |
| article pre code { background: none; padding: 0; font-size: inherit; } | |
| article blockquote { margin: 1em 0; padding: 0.2em 1em; border-left: 3px solid var(--rule); color: var(--muted); } | |
| article hr { border: 0; border-top: 1px solid var(--rule); margin: 2em 0; } | |
| .tablewrap { overflow-x: auto; margin: 1em 0; border: 1px solid var(--rule); border-radius: 8px; } | |
| article table { border-collapse: collapse; width: 100%; font-size: 14px; font-variant-numeric: tabular-nums; } | |
| article th, article td { text-align: left; vertical-align: top; padding: 7px 10px; border-bottom: 1px solid var(--rule); } | |
| article th { font: 600 12.5px/1.3 var(--f-body); color: var(--muted); background: var(--code-bg); letter-spacing: 0.02em; } | |
| article tr:last-child td { border-bottom: 0; } | |
| article img { max-width: 100%; height: auto; } | |
| article p[align="center"] { text-align: center; } | |
| .badge { display: inline-block; font: 500 11.5px/1.6 var(--f-mono); border: 1px solid var(--rule); border-radius: 4px; padding: 0 6px; margin: 2px; color: var(--muted); } | |
| .status { color: var(--muted); font-style: italic; } | |
| .toc { position: sticky; top: env(safe-area-inset-top, 0px); align-self: start; max-height: 100vh; overflow-y: auto; padding-block: 22px; font-size: 13px; } | |
| .toc h2 { font: 600 11px/1 var(--f-mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); margin: 0 0 8px; } | |
| .toc ol { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; } | |
| .toc a { display: block; color: var(--muted); text-decoration: none; padding: 3px 8px; border-left: 2px solid var(--rule); line-height: 1.35; } | |
| .toc a.l3 { padding-left: 18px; font-size: 12.5px; } | |
| .toc a:hover { color: var(--accent); border-left-color: var(--accent); } | |
| @media (max-width: 1100px) { .shell { grid-template-columns: 220px minmax(0, 1fr); } .toc { display: none; } } | |
| @media (max-width: 760px) { | |
| .shell { grid-template-columns: minmax(0, 1fr); gap: 0; } | |
| .nav { display: none; } | |
| .picker { display: block; padding-block: 14px 0; } | |
| .picker label { font: 600 11px/1 var(--f-mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); display: block; margin-bottom: 6px; } | |
| .picker select { width: 100%; font: 15px var(--f-body); padding: 8px; border-radius: 6px; border: 1px solid var(--rule); background: var(--panel); color: var(--ink); } | |
| article h1 { font-size: 1.65rem; } | |
| } | |
| .masthead .links { margin: 6px 0 0; font: 500 12.5px/1.4 var(--f-mono); } | |
| .masthead .links a { color: inherit; text-decoration: underline; text-underline-offset: 2px; opacity: .85; } | |
| .masthead .links a:hover { opacity: 1; } | |
| @media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } } | |
| </style> | |
| <header class="masthead"> | |
| <div class="masthead-inner"> | |
| <p class="brand"><span class="trits" aria-hidden="true"><i></i><i></i><i></i></span>bankml<span class="ver" id="ver">0.2.7</span></p> | |
| <span class="tag">Verified low-bit inference for the CPU you already have — the documentation, as of <span id="asof">0.2.7</span>.</span> | |
| <p class="links"><a href="https://github.com/cryptoAGI/bankml">GitHub</a> · <a href="https://huggingface.co/spaces/PYTHAI/bankml">Hugging Face</a> · <a href="https://deltaverse.pythai.net/bankml">why bankML</a> · <a href="#thesis">the thesis</a> · <a href="https://github.com/minaiml">minaiml</a> (<a href="https://huggingface.co/spaces/PYTHAI/minaiml">Space</a>)</p> | |
| <div class="proof">gate record 0.3.6: the penalties — repeat, frequency and presence, token-identical to llama-server on <b>56 / 56</b> answers on each of three models, live <b>85 / 85</b> · gate record 0.3.5: JSON schemas — llama-server’s grammar on each template (<b>173 / 173</b> schemas × 3 templates against llama.cpp’s own code) and its answers token-identical on all five native models (<b>28 / 28</b>, <b>11 / 11</b>, <b>56 / 56</b> × 3), the content rule matched on <b>30,063 / 30,063</b> texts per template · <code>bankml create</code>: mindX’s persona layer, made from mindXtrain’s merged output, token-identical end to end (<b>27 / 27</b>, two ways) · gate record 0.3.4: mindX’s own model natively — <code>mindx-gen39</code> and SmolLM2-135M-Instruct (the Llama graph in F16) and Bonsai-1.7B (tied embeddings) token-identical to llama-server b11192: whole model <b>800 / 800</b> and <b>840 / 840</b> rows bit-exact, F16 products <b>552,268 / 552,268</b> elements bit-exact against ggml, seeded sampling <b>40 / 40</b> on each, conversations <b>9 / 9</b>, JSON mode <b>23 / 23</b> · JSON mode — answers under llama-server’s own <code>json_object</code> grammar token-identical, greedy and seeded (<b>23 / 23</b> answers on the 1-bit model, <b>13 / 13</b> on the ternary), and llama.cpp’s grammar sampler matched on <b>1,645 / 1,645</b> whole-vocabulary masks · a C API, <code>libbankml</code>, identical to <code>serve --native</code> · Savante answered by bankML’s own forward pass — whole conversations identical to llama-server on <b>9 / 9</b> turns (text, token counts, prompt-cache reuse) · own forward pass <b>1,064 / 1,064</b> rows bit-exact for the 1-bit and the ternary model · seeded sampling identical on <b>40 / 40</b> continuations · <b>8,188,239,872</b> ternary weights and <b>762 / 762</b> dot products bit-exact against llama.cpp b11192’s compiled library · one ternary token <b>0.222 s vs 2.139 s</b></div> | |
| </div> | |
| </header> | |
| <div class="shell"> | |
| <nav class="nav" aria-label="Documents" id="nav"></nav> | |
| <main> | |
| <div class="picker"><label for="docpick">Document</label><select id="docpick"></select></div> | |
| <div class="docmeta" id="docmeta"></div> | |
| <article id="doc"><p class="status">Loading the document…</p></article> | |
| </main> | |
| <aside class="toc" aria-label="On this page" id="toc"></aside> | |
| </div> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.2/marked.min.js"></script> | |
| <script> | |
| (function () { | |
| const REPO = "https://github.com/cryptoAGI/bankml"; | |
| // Two homes, one file. In the claude.ai artifact the documents are published beside this page, so they load by | |
| // relative path. On GitHub Pages (docs/index.html) they are read from the repository at the latest release. | |
| const FALLBACK_TAG = "v0.3.6"; | |
| let TAG = FALLBACK_TAG; | |
| let SRC = ""; // "" = beside this page; otherwise a raw.githubusercontent.com base | |
| const RAW = "https://raw.githubusercontent.com/cryptoAGI/bankml/"; | |
| const ready = (async () => { | |
| try { const r = await fetch("README.md", { method: "HEAD" }); if (r.ok) return; } catch (e) {} | |
| try { | |
| const r = await fetch("https://api.github.com/repos/cryptoAGI/bankml/releases/latest"); | |
| if (r.ok) { const t = (await r.json()).tag_name; if (/^v\d+\.\d+\.\d+$/.test(t)) TAG = t; } | |
| } catch (e) {} | |
| SRC = RAW + TAG + "/"; | |
| const v = TAG.slice(1); | |
| document.getElementById("ver").textContent = v; | |
| document.getElementById("asof").textContent = v; | |
| })(); | |
| // the documents, by the reader's task; `path` is the file's path in the repository (and in this artifact) | |
| const GROUPS = [ | |
| ["Start", [ | |
| ["readme", "README.md", "Overview", "what bankml is, results, releases"], | |
| ["why", "docs/why-bankml.md", "Why bankML", "the short version: uses, Rust, the road ahead"], | |
| ["usage", "docs/usage.md", "Usage guide", "install, run, models, settings"], | |
| ["install", "docs/install.md", "Install and configure", "every option, variable, service and tuning"], | |
| ["playback", "docs/playback.md", "New to Savante", "her page, her card, listening to her"], | |
| ]], | |
| ["Understand", [ | |
| ["technical", "docs/TECHNICAL.md", "Technical report", "design, method, proofs, thesis"], | |
| ["thesis", "docs/thesis.md", "Thesis", "exactness before speed: the argument and its evidence"], | |
| ["oracles", "docs/oracles.md", "Oracles", "what bankml is checked against"], | |
| ["performance", "docs/PERFORMANCE.md", "Performance", "every number, how it was measured"], | |
| ["research", "docs/research.md", "Research", "the field, with papers"], | |
| ["embedding", "docs/embedding.md", "Embedding", "bge-m3 meaning search"], | |
| ["capi", "docs/CAPI.md", "C API", "embed bankML: libbankml and bankml.h"], | |
| ["ollama", "docs/OLLAMA.md", "Ollama and mindX", "the gap matrix against mindX, phases O1–O8"], | |
| ["huggingface", "docs/huggingface.md", "Hugging Face GPUs", "the Hub's rented GPUs as bankML devices"], | |
| ]], | |
| ["Source", [ | |
| ["modules", "docs/modules/README.md", "Modules", "each source module: usage, advantages, limits"], | |
| ["mod-bankml", "docs/modules/bankml.md", "bankML/bankml.rs", "the crate root: the verification gate, shared types, logging"], | |
| ["mod-gguf", "docs/modules/gguf.md", "bankML/gguf.rs", "the GGUF header parser, the guard, and the read-only…"], | |
| ["mod-sha256", "docs/modules/sha256.md", "bankML/sha256.rs", "SHA-256 for the model pin, and the FORK.json pin scanner"], | |
| ["mod-q1_0", "docs/modules/q1_0.md", "bankML/q1_0.rs", "the 1-bit Q1_0 kernel, the q8_0 activation quantizer,…"], | |
| ["mod-q2_0", "docs/modules/q2_0.md", "bankML/q2_0.rs", "the ternary Q2_0_g64 kernel"], | |
| ["mod-f16", "docs/modules/f16.md", "bankML/f16.rs", "F16 weights, multiplied as the shipped ggml b11192…"], | |
| ["mod-par", "docs/modules/par.md", "bankML/par.rs", "the persistent thread pool and row scheduler for the matmuls"], | |
| ["mod-prompt_cache", "docs/modules/prompt_cache.md", "bankML/prompt_cache.rs", "llama-server's host prompt cache for the one slot"], | |
| ["mod-gpu", "docs/modules/gpu.md", "bankML/gpu/", "the video-card component: find GPUs, verify them, and…"], | |
| ["mod-metrics", "docs/modules/metrics.md", "bankML/metrics.rs", "bankML's own measurements of its answers"], | |
| ["mod-console", "docs/modules/console.md", "sAGI/console.py", "bankML as itself: four tabs, the measured SELF block"], | |
| ["mod-sys", "docs/modules/sys.md", "bankML/sys.rs", "memory, cores and per-process usage from /proc"], | |
| ["mod-forward", "docs/modules/forward.md", "bankML/forward.rs", "the forward pass, bit-exact against llama.cpp b11192's…"], | |
| ["mod-tokenizer", "docs/modules/tokenizer.md", "bankML/tokenizer.rs", "byte-level BPE, token-identical to llama.cpp b11192"], | |
| ["mod-chat", "docs/modules/chat.md", "bankML/chat.rs", "chat templates, byte-identical to llama.cpp b11192"], | |
| ["mod-sampler", "docs/modules/sampler.md", "bankML/sampler.rs", "llama-server's sampler chain, token for token with the…"], | |
| ["mod-grammar", "docs/modules/grammar.md", "bankML/grammar.rs", "llama.cpp's GBNF engine, JSON mode and the content rule"], | |
| ["mod-schema", "docs/modules/schema.md", "bankML/schema.rs", "JSON schema to GBNF, as llama-server b11192 builds it"], | |
| ["mod-native", "docs/modules/native.md", "bankML/native.rs", "the engine behind bankml serve --native"], | |
| ["mod-serve", "docs/modules/serve.md", "bankML/serve.rs", "bankml serve, the verifying loopback gateway"], | |
| ["mod-ollama", "docs/modules/ollama.md", "bankML/ollama.rs", "Ollama's API on bankml serve --native"], | |
| ["mod-create", "docs/modules/create.md", "bankML/create.rs", "bankml create: derived models over pinned bases"], | |
| ["mod-convert", "docs/modules/convert.md", "bankML/convert.rs", "bankml convert: safetensors to GGUF F16, byte-identical…"], | |
| ["mod-main", "docs/modules/main.md", "bankML/main.rs", "the bankml command line"], | |
| ["mod-capi", "docs/modules/capi.md", "capi/src/", "the C API: libbankml.so / libbankml.a"], | |
| ["mod-train", "docs/modules/train.md", "bankML/train/", "mindXtrain in Rust, one verified stage at a time"], | |
| ]], | |
| ["Records", [ | |
| ["changelog", "CHANGELOG.md", "Changelog", "every release"], | |
| ["history", "docs/BUILD_HISTORY.md", "Build history", "how each phase was reached, with its evidence"], | |
| ["testing", "testing/README.md", "Testing", "the gate and its records"], | |
| ["todo", "docs/TODO.md", "TODO", "next, and what was rejected"], | |
| ["upstream", "upstream/README.md", "Upstream kernel", "the Q2_0 patch for llama.cpp"], | |
| ["licensing", "LICENSING.md", "Licensing", "MIT OR Apache-2.0, and the layers"], | |
| ]], | |
| ]; | |
| const DOCS = GROUPS.flatMap(([, d]) => d); | |
| const BY_PATH = Object.fromEntries(DOCS.map(d => [d[1], d])); | |
| const cache = {}; | |
| const $ = (id) => document.getElementById(id); | |
| // the index, and the phone picker | |
| $("nav").innerHTML = GROUPS.map(([g, ds]) => | |
| `<h2>${g}</h2><ul>` + ds.map(([id, , t, s]) => `<li><a href="#${id}" data-id="${id}">${t}<small>${s}</small></a></li>`).join("") + "</ul>" | |
| ).join(""); | |
| $("docpick").innerHTML = DOCS.map(([id, , t]) => `<option value="${id}">${t}</option>`).join(""); | |
| $("docpick").addEventListener("change", (e) => { location.hash = e.target.value; }); | |
| const slug = (t) => t.trim().toLowerCase().replace(/<[^>]+>/g, "").replace(/[^\w\- ]+/g, "").replace(/ /g, "-"); | |
| function resolve(base, rel) { // a path relative to a document, as the repository sees it | |
| const parts = base.split("/").slice(0, -1); | |
| for (const p of rel.split("/")) { | |
| if (p === "..") parts.pop(); else if (p !== "." && p !== "") parts.push(p); | |
| } | |
| return parts.join("/"); | |
| } | |
| async function show(hash) { | |
| await ready; | |
| const [id, anchor] = (hash || "readme").split(".", 2); | |
| const d = DOCS.find(x => x[0] === id) || DOCS[0]; | |
| const [docId, path, title] = d; | |
| document.querySelectorAll("#nav a").forEach(a => a.setAttribute("aria-current", a.dataset.id === docId ? "page" : "false")); | |
| $("docpick").value = docId; | |
| $("docmeta").innerHTML = `<span>${path}</span><a href="${REPO}/blob/${TAG}/${path}" target="_blank" rel="noopener">view on GitHub at ${TAG}</a>`; | |
| let md = cache[path]; | |
| if (md === undefined) { | |
| try { | |
| let r = await fetch(SRC + path); | |
| // a document newer than the release (on GitHub Pages) is read from main | |
| if (!r.ok && SRC.startsWith(RAW)) r = await fetch(RAW + "main/" + path); | |
| if (!r.ok) throw new Error(r.status); | |
| md = cache[path] = await r.text(); | |
| } catch (e) { | |
| $("doc").innerHTML = `<p class="status">This document could not be loaded here. Read it on <a href="${REPO}/blob/${TAG}/${path}" target="_blank" rel="noopener">GitHub</a>.</p>`; | |
| $("toc").innerHTML = ""; | |
| return; | |
| } | |
| } | |
| const art = $("doc"); | |
| art.innerHTML = marked.parse(md, { gfm: true }); | |
| // headings get GitHub-style ids (the documents' own anchors), and the contents list is built from them | |
| const seen = {}; | |
| const heads = [...art.querySelectorAll("h1, h2, h3")]; | |
| heads.forEach(h => { let s = slug(h.textContent); if (seen[s] !== undefined) s = s + "-" + (++seen[s]); else seen[s] = 0; h.id = docId + "." + s; }); | |
| const toc = heads.filter(h => h.tagName !== "H1"); | |
| $("toc").innerHTML = toc.length ? "<h2>On this page</h2><ol>" + toc.map(h => | |
| `<li><a class="${h.tagName === "H3" ? "l3" : ""}" href="#${h.id}">${h.textContent}</a></li>`).join("") + "</ol>" : ""; | |
| // tables scroll inside their own box | |
| art.querySelectorAll("table").forEach(t => { const w = document.createElement("div"); w.className = "tablewrap"; t.replaceWith(w); w.appendChild(t); }); | |
| // images: files published with this page load; other hosts cannot (the badges become text) | |
| art.querySelectorAll("img").forEach(img => { | |
| const src = img.getAttribute("src") || ""; | |
| if (/^https?:/.test(src)) { const b = document.createElement("span"); b.className = "badge"; b.textContent = img.alt || "badge"; img.replaceWith(b); } | |
| else img.src = SRC + resolve(path, src); | |
| }); | |
| // links: another document opens here, an anchor scrolls here, anything else goes to GitHub at the tag | |
| art.querySelectorAll("a[href]").forEach(a => { | |
| const href = a.getAttribute("href"); | |
| if (/^(https?:|mailto:)/.test(href)) { a.target = "_blank"; a.rel = "noopener"; return; } | |
| const [p, frag] = href.split("#"); | |
| if (!p) { a.href = "#" + docId + "." + frag; return; } | |
| const target = resolve(path, p); | |
| const doc = BY_PATH[target]; | |
| if (doc) a.href = "#" + doc[0] + (frag ? "." + frag : ""); | |
| else { a.href = `${REPO}/${/\.[a-z0-9]+$/i.test(target) ? "blob" : "tree"}/${TAG}/${target}`; a.target = "_blank"; a.rel = "noopener"; } | |
| }); | |
| document.title = (docId === "readme" ? "bankml " + TAG.slice(1) + " Documentation" : title + " · bankml " + TAG.slice(1)); | |
| if (anchor) { const el = document.getElementById(docId + "." + anchor); if (el) { el.scrollIntoView(); return; } } | |
| window.scrollTo(0, 0); | |
| } | |
| window.addEventListener("hashchange", () => show(location.hash.slice(1))); | |
| show(location.hash.slice(1)); | |
| })(); | |
| </script> | |
| </body></html> |