File size: 22,737 Bytes
28c70af d1c88ba 28c70af d1c88ba 28c70af | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | <!doctype html><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!important}</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> |