PageSourceSearch

https://skyzh.github.io/tiny-llm/toc-2edfc6ae.js

js skyzh.github.io collected 2026-10-03 09:57:58 UTC 27,723 bytes, 455 lines download raw bytes

1// Populate the sidebar
2//
3// This is a script, and not included directly in the page, to control the total size of the book.
4// The TOC contains an entry for each page, so if each page includes a copy of the TOC,
5// the total size of the page becomes O(n**2).
6class MDBookSidebarScrollbox extends HTMLElement {
7    constructor() {
8        super();
9    }
10    connectedCallback() {
11        this.innerHTML = '<ol class="chapter"><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="preface.html">Learn LLM Serving</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="setup.html">Setting Up the Environment</a></span></li><li class="chapter-item expanded "><li class="spacer"></li></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week1-overview.html"><strong aria-hidden="true">1.</strong> Week 1: From Matmul to Text</a></span><ol class="section"><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week1-01-attention.html"><strong aria-hidden="true">1.1.</strong> Attention and Multi-Head Attention</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week1-02-positional-encodings.html"><strong aria-hidden="true">1.2.</strong> Positional Encodings and RoPE</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week1-03-gqa.html"><strong aria-hidden="true">1.3.</strong> Grouped-Query and Multi-Query Attention</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week1-04-rmsnorm-and-mlp.html"><strong aria-hidden="true">1.4.</strong> RMSNorm and MLP</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week1-05-qwen3-model.html"><strong aria-hidden="true">1.5.</strong> The Qwen3 Model</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week1-06-generate-response.html"><strong aria-hidden="true">1.6.</strong> Generating the Response</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week1-07-sampling-prepare.html"><strong aria-hidden="true">1.7.</strong> Sampling and Preparing for Week 2</a></span></li></ol><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week2-overview.html"><strong aria-hidden="true">2.</strong> 🚧 Week 2: A Faster Single Request</a></span><ol class="section"><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week2-01-kv-cache.html"><strong aria-hidden="true">2.1.</strong> 🚧 Day 1: Cache and Measure</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week2-02-quantize-model.html"><strong aria-hidden="true">2.2.</strong> 🚧 Day 2: Keep W4 Packed</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week2-03-simd-matrix-prefill.html"><strong aria-hidden="true">2.3.</strong> 🚧 Day 3: SIMD Matrix Prefill</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week2-04-fused-model-kernels.html"><strong aria-hidden="true">2.4.</strong> 🚧 Day 4: Fused Model Primitives</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week2-05-tiled-prefill-attention.html"><strong aria-hidden="true">2.5.</strong> 🚧 Day 5: Tiled Dense Prefill Attention</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week2-02-benchmark-profile.html"><strong aria-hidden="true">2.6.</strong> Historical Week 2 lesson addresses</a></span><ol class="section"><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week2-03-quantize-model.html"><strong aria-hidden="true">2.6.1.</strong> Earlier quantization lesson</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week2-05-simd-matrix-prefill.html"><strong aria-hidden="true">2.6.2.</strong> Earlier SIMD-prefill lesson</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week2-06-operator-lab.html"><strong aria-hidden="true">2.6.3.</strong> Earlier bounded-decode lab</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week2-07-split-k-prefill.html"><strong aria-hidden="true">2.6.4.</strong> Earlier Split-K lab</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week2-advanced-profiling.html"><strong aria-hidden="true">2.6.5.</strong> Earlier optional macOS capture lab</a></span></li></ol></li></ol><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week3-overview.html"><strong aria-hidden="true">3.</strong> 🚧 Week 3: Build a Mini vLLM</a></span><ol class="section"><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week3-01-continuous-batching.html"><strong aria-hidden="true">3.1.</strong> 🚧 Continuous Batching</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week3-02-chunked-prefill.html"><strong aria-hidden="true">3.2.</strong> 🚧 Chunked Prefill</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week3-03-paged-attention-part1.html"><strong aria-hidden="true">3.3.</strong> 🚧 Paged KV Cache</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week3-04-paged-attention-part2.html"><strong aria-hidden="true">3.4.</strong> 🚧 Direct Paged Attention</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week3-05-flash-attention.html"><strong aria-hidden="true">3.5.</strong> 🚧 Paged FlashAttention</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week3-optional-moe.html"><strong aria-hidden="true">3.6.</strong> 🚧 Day 6 (Optional): Mixture of Experts</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week3-optional-speculative-decoding.html"><strong aria-hidden="true">3.7.</strong> 🚧 Day 7 (Optional): Speculative Decoding</a></span></li></ol><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week4-overview.html"><strong aria-hidden="true">4.</strong> 🚧 Week 4: Build a Coding Agent</a></span><ol class="section"><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week4-01-agent-loop.html"><strong aria-hidden="true">4.1.</strong> 🚧 Day 1: Validated Agent Loop</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week4-02-tools.html"><strong aria-hidden="true">4.2.</strong> 🚧 Day 2: Inspect a Workspace</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week4-03-safe-editing.html"><strong aria-hidden="true">4.3.</strong> 🚧 Day 3: Edit, Validate, and Record</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week4-04-sessions.html"><strong aria-hidden="true">4.4.</strong> 🚧 Day 4: Checkpoint and Resume</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week4-05-compaction.html"><strong aria-hidden="true">4.5.</strong> 🚧 Day 5: Compact Completed Work</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week4-06-steering.html"><strong aria-hidden="true">4.6.</strong> 🚧 Day 6: Inspect and Steer a Paused Agent</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week4-07-evaluation.html"><strong aria-hidden="true">4.7.</strong> 🚧 Day 7: Evaluate Observable Outcomes</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week4-08-fork-steer-select.html"><strong aria-hidden="true">4.8.</strong> 🚧 Day 8: Fork, Steer, and Select</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="week4-09-bound-tool-evidence.html"><strong aria-hidden="true">4.9.</strong> 🚧 Day 9: Bound Tool Evidence</a></span></li></ol><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="appendix-performance.html"><strong aria-hidden="true">5.</strong> 🚧 Appendix: Performance Evidence Ledger</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="sponsor.html"><strong aria-hidden="true">6.</strong> Sponsored by Raft.build</a></span></li><li class="chapter-item expanded "><li class="spacer"></li></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="glossary.html">Glossary Index</a></span></li></ol>';
12        // Set the current, active page, and reveal it if it's hidden
13        let current_page = document.location.href.toString().split('#')[0].split('?')[0];
14        if (current_page.endsWith('/')) {
15            current_page += 'index.html';
16        }
17        const links = Array.prototype.slice.call(this.querySelectorAll('a'));
18        const l = links.length;
19        for (let i = 0; i < l; ++i) {
20            const link = links[i];
21            const href = link.getAttribute('href');
22            if (href && !href.startsWith('#') && !/^(?:[a-z+]+:)?\/\//.test(href)) {
23                link.href = path_to_root + href;
24            }
25            // The 'index' page is supposed to alias the first chapter in the book.
26            // Check both with and without the '.html' suffix to be robust against pretty URLs
27            if (link.href.replace(/\.html$/, '') === current_page.replace(/\.html$/, '')
28                || i === 0
29                && path_to_root === ''
30                && current_page.endsWith('/index.html')) {
31                link.classList.add('active');
32                let parent = link.parentElement;
33                while (parent) {
34                    if (parent.tagName === 'LI' && parent.classList.contains('chapter-item')) {
35                        parent.classList.add('expanded');
36                    }
37                    parent = parent.parentElement;
38                }
39            }
40        }
41        // Track and set sidebar scroll position
42        this.addEventListener('click', e => {
43            if (e.target.tagName === 'A') {
44                const clientRect = e.target.getBoundingClientRect();
45                const sidebarRect = this.getBoundingClientRect();
46                sessionStorage.setItem('sidebar-scroll-offset', clientRect.top - sidebarRect.top);
47            }
48        }, { passive: true });
49        const sidebarScrollOffset = sessionStorage.getItem('sidebar-scroll-offset');
50        sessionStorage.removeItem('sidebar-scroll-offset');
51        if (sidebarScrollOffset !== null) {
52            // preserve sidebar scroll position when navigating via links within sidebar
53            const activeSection = this.querySelector('.active');
54            if (activeSection) {
55                const clientRect = activeSection.getBoundingClientRect();
56                const sidebarRect = this.getBoundingClientRect();
57                const currentOffset = clientRect.top - sidebarRect.top;
58                this.scrollTop += currentOffset - parseFloat(sidebarScrollOffset);
59            }
60        } else {
61            // scroll sidebar to current active section when navigating via
62            // 'next/previous chapter' buttons
63            const activeSection = document.querySelector('#mdbook-sidebar .active');
64            if (activeSection) {
65                activeSection.scrollIntoView({ block: 'center' });
66            }
67        }
68        // Toggle buttons
69        const sidebarAnchorToggles = document.querySelectorAll('.chapter-fold-toggle');
70        function toggleSection(ev) {
71            ev.currentTarget.parentElement.parentElement.classList.toggle('expanded');
72        }
73        Array.from(sidebarAnchorToggles).forEach(el => {
74            el.addEventListener('click', toggleSection);
75        });
76    }
77}
78window.customElements.define('mdbook-sidebar-scrollbox', MDBookSidebarScrollbox);
79
80
81// ---------------------------------------------------------------------------
82// Support for dynamically adding headers to the sidebar.
83
84(function() {
85    // This is used to detect which direction the page has scrolled since the
86    // last scroll event.
87    let lastKnownScrollPosition = 0;
88    // This is the threshold in px from the top of the screen where it will
89    // consider a header the "current" header when scrolling down.
90    const defaultDownThreshold = 150;
91    // Same as defaultDownThreshold, except when scrolling up.
92    const defaultUpThreshold = 300;
93    // The threshold is a virtual horizontal line on the screen where it
94    // considers the "current" header to be above the line. The threshold is
95    // modified dynamically to handle headers that are near the bottom of the
96    // screen, and to slightly offset the behavior when scrolling up vs down.
97    let threshold = defaultDownThreshold;
98    // This is used to disable updates while scrolling. This is needed when
99    // clicking the header in the sidebar, which triggers a scroll event. It
100    // is somewhat finicky to detect when the scroll has finished, so this
101    // uses a relatively dumb system of disabling scroll updates for a short
102    // time after the click.
103    let disableScroll = false;
104    // Array of header elements on the page.
105    let headers;
106    // Array of li elements that are initially collapsed headers in the sidebar.
107    // I'm not sure why eslint seems to have a false positive here.
108    // eslint-disable-next-line prefer-const
109    let headerToggles = [];
110    // This is a debugging tool for the threshold which you can enable in the console.
111    let thresholdDebug = false;
112
113    // Updates the threshold based on the scroll position.
114    function updateThreshold() {
115        const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
116        const windowHeight = window.innerHeight;
117        const documentHeight = document.documentElement.scrollHeight;
118
119        // The number of pixels below the viewport, at most documentHeight.
120        // This is used to push the threshold down to the bottom of the page
121        // as the user scrolls towards the bottom.
122        const pixelsBelow = Math.max(0, documentHeight - (scrollTop + windowHeight));
123        // The number of pixels above the viewport, at least defaultDownThreshold.
124        // Similar to pixelsBelow, this is used to push the threshold back towards
125        // the top when reaching the top of the page.
126        const pixelsAbove = Math.max(0, defaultDownThreshold - scrollTop);
127        // How much the threshold should be offset once it gets close to the
128        // bottom of the page.
129        const bottomAdd = Math.max(0, windowHeight - pixelsBelow - defaultDownThreshold);
130        let adjustedBottomAdd = bottomAdd;
131
132        // Adjusts bottomAdd for a small document. The calculation above
133        // assumes the document is at least twice the windowheight in size. If
134        // it is less than that, then bottomAdd needs to be shrunk
135        // proportional to the difference in size.
136        if (documentHeight < windowHeight * 2) {
137            const maxPixelsBelow = documentHeight - windowHeight;
138            const t = 1 - pixelsBelow / Math.max(1, maxPixelsBelow);
139            const clamp = Math.max(0, Math.min(1, t));
140            adjustedBottomAdd *= clamp;
141        }
142
143        let scrollingDown = true;
144        if (scrollTop < lastKnownScrollPosition) {
145            scrollingDown = false;
146        }
147
148        if (scrollingDown) {
149            // When scrolling down, move the threshold up towards the default
150            // downwards threshold position. If near the bottom of the page,
151            // adjustedBottomAdd will offset the threshold towards the bottom
152            // of the page.
153            const amountScrolledDown = scrollTop - lastKnownScrollPosition;
154            const adjustedDefault = defaultDownThreshold + adjustedBottomAdd;
155            threshold = Math.max(adjustedDefault, threshold - amountScrolledDown);
156        } else {
157            // When scrolling up, move the threshold down towards the default
158            // upwards threshold position. If near the bottom of the page,
159            // quickly transition the threshold back up where it normally
160            // belongs.
161            const amountScrolledUp = lastKnownScrollPosition - scrollTop;
162            const adjustedDefault = defaultUpThreshold - pixelsAbove
163                + Math.max(0, adjustedBottomAdd - defaultDownThreshold);
164            threshold = Math.min(adjustedDefault, threshold + amountScrolledUp);
165        }
166
167        if (documentHeight <= windowHeight) {
168            threshold = 0;
169        }
170
171        if (thresholdDebug) {
172            const id = 'mdbook-threshold-debug-data';
173            let data = document.getElementById(id);
174            if (data === null) {
175                data = document.createElement('div');
176                data.id = id;
177                data.style.cssText = `
178                    position: fixed;
179                    top: 50px;
180                    right: 10px;
181                    background-color: 0xeeeeee;
182                    z-index: 9999;
183                    pointer-events: none;
184                `;
185                document.body.appendChild(data);
186            }
187            data.innerHTML = `
188                <table>
189                  <tr><td>documentHeight</td><td>${documentHeight.toFixed(1)}</td></tr>
190                  <tr><td>windowHeight</td><td>${windowHeight.toFixed(1)}</td></tr>
191                  <tr><td>scrollTop</td><td>${scrollTop.toFixed(1)}</td></tr>
192                  <tr><td>pixelsAbove</td><td>${pixelsAbove.toFixed(1)}</td></tr>
193                  <tr><td>pixelsBelow</td><td>${pixelsBelow.toFixed(1)}</td></tr>
194                  <tr><td>bottomAdd</td><td>${bottomAdd.toFixed(1)}</td></tr>
195                  <tr><td>adjustedBottomAdd</td><td>${adjustedBottomAdd.toFixed(1)}</td></tr>
196                  <tr><td>scrollingDown</td><td>${scrollingDown}</td></tr>
197                  <tr><td>threshold</td><td>${threshold.toFixed(1)}</td></tr>
198                </table>
199            `;
200            drawDebugLine();
201        }
202
203        lastKnownScrollPosition = scrollTop;
204    }
205
206    function drawDebugLine() {
207        if (!document.body) {
208            return;
209        }
210        const id = 'mdbook-threshold-debug-line';
211        const existingLine = document.getElementById(id);
212        if (existingLine) {
213            existingLine.remove();
214        }
215        const line = document.createElement('div');
216        line.id = id;
217        line.style.cssText = `
218            position: fixed;
219            top: ${threshold}px;
220            left: 0;
221            width: 100vw;
222            height: 2px;
223            background-color: red;
224            z-index: 9999;
225            pointer-events: none;
226        `;
227        document.body.appendChild(line);
228    }
229
230    function mdbookEnableThresholdDebug() {
231        thresholdDebug = true;
232        updateThreshold();
233        drawDebugLine();
234    }
235
236    window.mdbookEnableThresholdDebug = mdbookEnableThresholdDebug;
237
238    // Updates which headers in the sidebar should be expanded. If the current
239    // header is inside a collapsed group, then it, and all its parents should
240    // be expanded.
241    function updateHeaderExpanded(currentA) {
242        // Add expanded to all header-item li ancestors.
243        let current = currentA.parentElement;
244        while (current) {
245            if (current.tagName === 'LI' && current.classList.contains('header-item')) {
246                current.classList.add('expanded');
247            }
248            current = current.parentElement;
249        }
250    }
251
252    // Updates which header is marked as the "current" header in the sidebar.
253    // This is done with a virtual Y threshold, where headers at or below
254    // that line will be considered the current one.
255    function updateCurrentHeader() {
256        if (!headers || !headers.length) {
257            return;
258        }
259
260        // Reset the classes, which will be rebuilt below.
261        const els = document.getElementsByClassName('current-header');
262        for (const el of els) {
263            el.classList.remove('current-header');
264        }
265        for (const toggle of headerToggles) {
266            toggle.classList.remove('expanded');
267        }
268
269        // Find the last header that is above the threshold.
270        let lastHeader = null;
271        for (const header of headers) {
272            const rect = header.getBoundingClientRect();
273            if (rect.top <= threshold) {
274                lastHeader = header;
275            } else {
276                break;
277            }
278        }
279        if (lastHeader === null) {
280            lastHeader = headers[0];
281            const rect = lastHeader.getBoundingClientRect();
282            const windowHeight = window.innerHeight;
283            if (rect.top >= windowHeight) {
284                return;
285            }
286        }
287
288        // Get the anchor in the summary.
289        const href = '#' + lastHeader.id;
290        const a = [...document.querySelectorAll('.header-in-summary')]
291            .find(element => element.getAttribute('href') === href);
292        if (!a) {
293            return;
294        }
295
296        a.classList.add('current-header');
297
298        updateHeaderExpanded(a);
299    }
300
301    // Updates which header is "current" based on the threshold line.
302    function reloadCurrentHeader() {
303        if (disableScroll) {
304            return;
305        }
306        updateThreshold();
307        updateCurrentHeader();
308    }
309
310
311    // When clicking on a header in the sidebar, this adjusts the threshold so
312    // that it is located next to the header. This is so that header becomes
313    // "current".
314    function headerThresholdClick(event) {
315        // See disableScroll description why this is done.
316        disableScroll = true;
317        setTimeout(() => {
318            disableScroll = false;
319        }, 100);
320        // requestAnimationFrame is used to delay the update of the "current"
321        // header until after the scroll is done, and the header is in the new
322        // position.
323        requestAnimationFrame(() => {
324            requestAnimationFrame(() => {
325                // Closest is needed because if it has child elements like <code>.
326                const a = event.target.closest('a');
327                const href = a.getAttribute('href');
328                const targetId = href.substring(1);
329                const targetElement = document.getElementById(targetId);
330                if (targetElement) {
331                    threshold = targetElement.getBoundingClientRect().bottom;
332                    updateCurrentHeader();
333                }
334            });
335        });
336    }
337
338    // Takes the nodes from the given head and copies them over to the
339    // destination, along with some filtering.
340    function filterHeader(source, dest) {
341        const clone = source.cloneNode(true);
342        clone.querySelectorAll('mark').forEach(mark => {
343            mark.replaceWith(...mark.childNodes);
344        });
345        dest.append(...clone.childNodes);
346    }
347
348    // Scans page for headers and adds them to the sidebar.
349    document.addEventListener('DOMContentLoaded', function() {
350        const activeSection = document.querySelector('#mdbook-sidebar .active');
351        if (activeSection === null) {
352            return;
353        }
354
355        const main = document.getElementsByTagName('main')[0];
356        headers = Array.from(main.querySelectorAll('h2, h3, h4, h5, h6'))
357            .filter(h => h.id !== '' && h.children.length && h.children[0].tagName === 'A');
358
359        if (headers.length === 0) {
360            return;
361        }
362
363        // Build a tree of headers in the sidebar.
364
365        const stack = [];
366
367        const firstLevel = parseInt(headers[0].tagName.charAt(1));
368        for (let i = 1; i < firstLevel; i++) {
369            const ol = document.createElement('ol');
370            ol.classList.add('section');
371            if (stack.length > 0) {
372                stack[stack.length - 1].ol.appendChild(ol);
373            }
374            stack.push({level: i + 1, ol: ol});
375        }
376
377        // The level where it will start folding deeply nested headers.
378        const foldLevel = 3;
379
380        for (let i = 0; i < headers.length; i++) {
381            const header = headers[i];
382            const level = parseInt(header.tagName.charAt(1));
383
384            const currentLevel = stack[stack.length - 1].level;
385            if (level > currentLevel) {
386                // Begin nesting to this level.
387                for (let nextLevel = currentLevel + 1; nextLevel <= level; nextLevel++) {
388                    const ol = document.createElement('ol');
389                    ol.classList.add('section');
390                    const last = stack[stack.length - 1];
391                    const lastChild = last.ol.lastChild;
392                    // Handle the case where jumping more than one nesting
393                    // level, which doesn't have a list item to place this new
394                    // list inside of.
395                    if (lastChild) {
396                        lastChild.appendChild(ol);
397                    } else {
398                        last.ol.appendChild(ol);
399                    }
400                    stack.push({level: nextLevel, ol: ol});
401                }
402            } else if (level < currentLevel) {
403                while (stack.length > 1 && stack[stack.length - 1].level > level) {
404                    stack.pop();
405                }
406            }
407
408            const li = document.createElement('li');
409            li.classList.add('header-item');
410            li.classList.add('expanded');
411            if (level < foldLevel) {
412                li.classList.add('expanded');
413            }
414            const span = document.createElement('span');
415            span.classList.add('chapter-link-wrapper');
416            const a = document.createElement('a');
417            span.appendChild(a);
418            a.href = '#' + header.id;
419            a.classList.add('header-in-summary');
420            filterHeader(header.children[0], a);
421            a.addEventListener('click', headerThresholdClick);
422            const nextHeader = headers[i + 1];
423            if (nextHeader !== undefined) {
424                const nextLevel = parseInt(nextHeader.tagName.charAt(1));
425                if (nextLevel > level && level >= foldLevel) {
426                    const toggle = document.createElement('a');
427                    toggle.classList.add('chapter-fold-toggle');
428                    toggle.classList.add('header-toggle');
429                    toggle.addEventListener('click', () => {
430                        li.classList.toggle('expanded');
431                    });
432                    const toggleDiv = document.createElement('div');
433                    toggleDiv.textContent = '❱';
434                    toggle.appendChild(toggleDiv);
435                    span.appendChild(toggle);
436                    headerToggles.push(li);
437                }
438            }
439            li.appendChild(span);
440
441            const currentParent = stack[stack.length - 1];
442            currentParent.ol.appendChild(li);
443        }
444
445        const onThisPage = document.createElement('div');
446        onThisPage.classList.add('on-this-page');
447        onThisPage.append(stack[0].ol);
448        const activeItemSpan = activeSection.parentElement;
449        activeItemSpan.after(onThisPage);
450    });
451
452    document.addEventListener('DOMContentLoaded', reloadCurrentHeader);
453    document.addEventListener('scroll', reloadCurrentHeader, { passive: true });
454})();
455

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.