PageSourceSearch

https://skyzh.github.io/mini-lsm/book-609e4cb8.js

js skyzh.github.io collected 2026-10-03 09:57:50 UTC 30,932 bytes, 870 lines download raw bytes

1'use strict';
2
3/* global default_theme, default_dark_theme, default_light_theme, hljs, ClipboardJS */
4
5// Fix back button cache problem
6window.onunload = function() { };
7
8// Global variable, shared between modules
9function playground_text(playground, hidden = true) {
10    const code_block = playground.querySelector('code');
11
12    if (window.ace && code_block.classList.contains('editable')) {
13        const editor = window.ace.edit(code_block);
14        return editor.getValue();
15    } else if (hidden) {
16        return code_block.textContent;
17    } else {
18        return code_block.innerText;
19    }
20}
21
22/**
23 * Helper for global keypress handlers so they don't trigger when certain elements are active.
24 * @returns {boolean} True if the keypress handler should be skipped.
25 */
26function mdbook_something_else_has_focus(e) {
27    // Check composedPath in case the event happened from something generated
28    // from the shadowDOM.
29    const target = e.composedPath()[0] || e.target;
30    // If this is the `checkbox-img` input which has the focus, we want to handle it here.
31    if (target.classList.contains('checkbox-img')) {
32        return false;
33    }
34    return /^(?:input|select|textarea)$/i.test(target.nodeName);
35}
36
37(function codeSnippets() {
38    function fetch_with_timeout(url, options, timeout = 6000) {
39        return Promise.race([
40            fetch(url, options),
41            new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout)),
42        ]);
43    }
44
45    const playgrounds = Array.from(document.querySelectorAll('.playground'));
46    if (playgrounds.length > 0) {
47        fetch_with_timeout('https://play.rust-lang.org/meta/crates', {
48            headers: {
49                'Content-Type': 'application/json',
50            },
51            method: 'POST',
52            mode: 'cors',
53        })
54            .then(response => response.json())
55            .then(response => {
56            // get list of crates available in the rust playground
57                const playground_crates = response.crates.map(item => item['id']);
58                playgrounds.forEach(block => handle_crate_list_update(block, playground_crates));
59            });
60    }
61
62    function handle_crate_list_update(playground_block, playground_crates) {
63        // update the play buttons after receiving the response
64        update_play_button(playground_block, playground_crates);
65
66        // and install on change listener to dynamically update ACE editors
67        if (window.ace) {
68            const code_block = playground_block.querySelector('code');
69            if (code_block.classList.contains('editable')) {
70                const editor = window.ace.edit(code_block);
71                editor.addEventListener('change', () => {
72                    update_play_button(playground_block, playground_crates);
73                });
74                // add Ctrl-Enter command to execute rust code
75                editor.commands.addCommand({
76                    name: 'run',
77                    bindKey: {
78                        win: 'Ctrl-Enter',
79                        mac: 'Ctrl-Enter',
80                    },
81                    exec: _editor => run_rust_code(playground_block),
82                });
83            }
84        }
85    }
86
87    // updates the visibility of play button based on `no_run` class and
88    // used crates vs ones available on https://play.rust-lang.org
89    function update_play_button(pre_block, playground_crates) {
90        const play_button = pre_block.querySelector('.play-button');
91
92        // skip if code is `no_run`
93        if (pre_block.querySelector('code').classList.contains('no_run')) {
94            play_button.classList.add('hidden');
95            return;
96        }
97
98        // get list of `extern crate`'s from snippet
99        const txt = playground_text(pre_block);
100        const re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g;
101        const snippet_crates = [];
102        let item;
103        while (item = re.exec(txt)) {
104            snippet_crates.push(item[1]);
105        }
106
107        // check if all used crates are available on play.rust-lang.org
108        const all_available = snippet_crates.every(function(elem) {
109            return playground_crates.indexOf(elem) > -1;
110        });
111
112        if (all_available) {
113            play_button.classList.remove('hidden');
114            play_button.hidden = false;
115        } else {
116            play_button.classList.add('hidden');
117        }
118    }
119
120    function run_rust_code(code_block) {
121        let result_block = code_block.querySelector('.result');
122        if (!result_block) {
123            result_block = document.createElement('code');
124            result_block.className = 'result hljs language-bash';
125
126            code_block.append(result_block);
127        }
128
129        const text = playground_text(code_block);
130        const classes = code_block.querySelector('code').classList;
131        let edition = '2015';
132        classes.forEach(className => {
133            if (className.startsWith('edition')) {
134                edition = className.slice(7);
135            }
136        });
137        const params = {
138            version: 'stable',
139            optimize: '0',
140            code: text,
141            edition: edition,
142        };
143
144        if (text.indexOf('#![feature') !== -1) {
145            params.version = 'nightly';
146        }
147
148        result_block.innerText = 'Running...';
149
150        fetch_with_timeout('https://play.rust-lang.org/evaluate.json', {
151            headers: {
152                'Content-Type': 'application/json',
153            },
154            method: 'POST',
155            mode: 'cors',
156            body: JSON.stringify(params),
157        })
158            .then(response => response.json())
159            .then(response => {
160                if (response.result.trim() === '') {
161                    result_block.innerText = 'No output';
162                    result_block.classList.add('result-no-output');
163                } else {
164                    result_block.innerText = response.result;
165                    result_block.classList.remove('result-no-output');
166                }
167            })
168            .catch(error => result_block.innerText = 'Playground Communication: ' + error.message);
169    }
170
171    // Syntax highlighting Configuration
172    hljs.configure({
173        tabReplace: '    ', // 4 spaces
174        languages: [], // Languages used for auto-detection
175    });
176
177    const code_nodes = Array
178        .from(document.querySelectorAll('code'))
179        // Don't highlight `inline code` blocks in headers.
180        .filter(function(node) {
181            return !node.parentElement.classList.contains('header');
182        });
183
184    if (window.ace) {
185        // language-rust class needs to be removed for editable
186        // blocks or highlightjs will capture events
187        code_nodes
188            .filter(function(node) {
189                return node.classList.contains('editable');
190            })
191            .forEach(function(block) {
192                block.classList.remove('language-rust');
193            });
194
195        code_nodes
196            .filter(function(node) {
197                return !node.classList.contains('editable');
198            })
199            .forEach(function(block) {
200                hljs.highlightBlock(block);
201            });
202    } else {
203        code_nodes.forEach(function(block) {
204            hljs.highlightBlock(block);
205        });
206    }
207
208    // Adding the hljs class gives code blocks the color css
209    // even if highlighting doesn't apply
210    code_nodes.forEach(function(block) {
211        block.classList.add('hljs');
212    });
213
214    Array.from(document.querySelectorAll('code.hljs')).forEach(function(block) {
215
216        const lines = Array.from(block.querySelectorAll('.boring'));
217        // If no lines were hidden, return
218        if (!lines.length) {
219            return;
220        }
221        block.classList.add('hide-boring');
222
223        const buttons = document.createElement('div');
224        buttons.className = 'buttons';
225        buttons.innerHTML = '<button title="Show hidden lines" \
226aria-label="Show hidden lines"></button>';
227        buttons.firstChild.innerHTML = document.getElementById('fa-eye').innerHTML;
228
229        // add expand button
230        const pre_block = block.parentNode;
231        pre_block.insertBefore(buttons, pre_block.firstChild);
232
233        buttons.firstChild.addEventListener('click', function(e) {
234            if (this.title === 'Show hidden lines') {
235                this.innerHTML = document.getElementById('fa-eye-slash').innerHTML;
236                this.title = 'Hide lines';
237                this.setAttribute('aria-label', e.target.title);
238
239                block.classList.remove('hide-boring');
240            } else if (this.title === 'Hide lines') {
241                this.innerHTML = document.getElementById('fa-eye').innerHTML;
242                this.title = 'Show hidden lines';
243                this.setAttribute('aria-label', e.target.title);
244
245                block.classList.add('hide-boring');
246            }
247        });
248    });
249
250    if (window.playground_copyable) {
251        Array.from(document.querySelectorAll('pre code')).forEac
251h(function(block) {
252            const pre_block = block.parentNode;
253            if (!pre_block.classList.contains('playground')) {
254                let buttons = pre_block.querySelector('.buttons');
255                if (!buttons) {
256                    buttons = document.createElement('div');
257                    buttons.className = 'buttons';
258                    pre_block.insertBefore(buttons, pre_block.firstChild);
259                }
260
261                const clipButton = document.createElement('button');
262                clipButton.className = 'clip-button';
263                clipButton.title = 'Copy to clipboard';
264                clipButton.setAttribute('aria-label', clipButton.title);
265                clipButton.innerHTML = '<i class="tooltiptext"></i>';
266
267                buttons.insertBefore(clipButton, buttons.firstChild);
268            }
269        });
270    }
271
272    // Process playground code blocks
273    Array.from(document.querySelectorAll('.playground')).forEach(function(pre_block) {
274        // Add play button
275        let buttons = pre_block.querySelector('.buttons');
276        if (!buttons) {
277            buttons = document.createElement('div');
278            buttons.className = 'buttons';
279            pre_block.insertBefore(buttons, pre_block.firstChild);
280        }
281
282        const runCodeButton = document.createElement('button');
283        runCodeButton.className = 'play-button';
284        runCodeButton.hidden = true;
285        runCodeButton.title = 'Run this code';
286        runCodeButton.setAttribute('aria-label', runCodeButton.title);
287        runCodeButton.innerHTML = document.getElementById('fa-play').innerHTML;
288
289        buttons.insertBefore(runCodeButton, buttons.firstChild);
290        runCodeButton.addEventListener('click', () => {
291            run_rust_code(pre_block);
292        });
293
294        if (window.playground_copyable) {
295            const copyCodeClipboardButton = document.createElement('button');
296            copyCodeClipboardButton.className = 'clip-button';
297            copyCodeClipboardButton.innerHTML = '<i class="tooltiptext"></i>';
298            copyCodeClipboardButton.title = 'Copy to clipboard';
299            copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title);
300
301            buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild);
302        }
303
304        const code_block = pre_block.querySelector('code');
305        if (window.ace && code_block.classList.contains('editable')) {
306            const undoChangesButton = document.createElement('button');
307            undoChangesButton.className = 'reset-button';
308            undoChangesButton.title = 'Undo changes';
309            undoChangesButton.setAttribute('aria-label', undoChangesButton.title);
310            undoChangesButton.innerHTML +=
311                document.getElementById('fa-clock-rotate-left').innerHTML;
312
313            buttons.insertBefore(undoChangesButton, buttons.firstChild);
314
315            undoChangesButton.addEventListener('click', function() {
316                const editor = window.ace.edit(code_block);
317                editor.setValue(editor.originalCode);
318                editor.clearSelection();
319            });
320        }
321    });
322})();
323
324(function themes() {
325    const html = document.querySelector('html');
326    const themeToggleButton = document.getElementById('mdbook-theme-toggle');
327    const themePopup = document.getElementById('mdbook-theme-list');
328    const themeColorMetaTag = document.querySelector('meta[name="theme-color"]');
329    const themeIds = [];
330    themePopup.querySelectorAll('button.theme').forEach(function(el) {
331        themeIds.push(el.id);
332    });
333    const stylesheets = {
334        ayuHighlight: document.querySelector('#mdbook-ayu-highlight-css'),
335        tomorrowNight: document.querySelector('#mdbook-tomorrow-night-css'),
336        highlight: document.querySelector('#mdbook-highlight-css'),
337    };
338
339    function showThemes() {
340        themePopup.style.display = 'block';
341        themeToggleButton.setAttribute('aria-expanded', true);
342        themePopup.querySelector('button#mdbook-theme-' + get_theme()).focus();
343    }
344
345    function updateThemeSelected() {
346        themePopup.querySelectorAll('.theme-selected').forEach(function(el) {
347            el.classList.remove('theme-selected');
348        });
349        const selected = get_saved_theme() ?? 'default_theme';
350        let element = themePopup.querySelector('button#mdbook-theme-' + selected);
351        if (element === null) {
352            // Fall back in case there is no "Default" item.
353            element = themePopup.querySelector('button#mdbook-theme-' + get_theme());
354        }
355        element.classList.add('theme-selected');
356    }
357
358    function hideThemes() {
359        themePopup.style.display = 'none';
360        themeToggleButton.setAttribute('aria-expanded', false);
361        themeToggleButton.focus();
362    }
363
364    function get_saved_theme() {
365        let theme = null;
366        try {
367            theme = localStorage.getItem('mdbook-theme');
368        } catch {
369            // ignore error.
370        }
371        return theme;
372    }
373
374    function delete_saved_theme() {
375        localStorage.removeItem('mdbook-theme');
376    }
377
378    function get_theme() {
379        const theme = get_saved_theme();
380        if (theme === null || theme === undefined || !themeIds.includes('mdbook-theme-' + theme)) {
381            if (typeof default_dark_theme === 'undefined') {
382                // A customized index.hbs might not define this, so fall back to
383                // old behavior of determining the default on page load.
384                return default_theme;
385            }
386            return window.matchMedia('(prefers-color-scheme: dark)').matches
387                ? default_dark_theme
388                : default_light_theme;
389        } else {
390            return theme;
391        }
392    }
393
394    let previousTheme = default_theme;
395    function set_theme(theme, store = true) {
396        let ace_theme;
397
398        if (theme === 'coal' || theme === 'navy') {
399            stylesheets.ayuHighlight.disabled = true;
400            stylesheets.tomorrowNight.disabled = false;
401            stylesheets.highlight.disabled = true;
402
403            ace_theme = 'ace/theme/tomorrow_night';
404        } else if (theme === 'ayu') {
405            stylesheets.ayuHighlight.disabled = false;
406            stylesheets.tomorrowNight.disabled = true;
407            stylesheets.highlight.disabled = true;
408            ace_theme = 'ace/theme/tomorrow_night';
409        } else {
410            stylesheets.ayuHighlight.disabled = true;
411            stylesheets.tomorrowNight.disabled = true;
412            stylesheets.highlight.disabled = false;
413            ace_theme = 'ace/theme/dawn';
414        }
415
416        setTimeout(function() {
417            themeColorMetaTag.content = getComputedStyle(document.documentElement).backgroundColor;
418        }, 1);
419
420        if (window.ace && window.editors) {
421            window.editors.forEach(function(editor) {
422                editor.setTheme(ace_theme);
423            });
424        }
425
426        if (store) {
427            try {
428                localStorage.setItem('mdbook-theme', theme);
429            } catch {
430                // ignore error.
431            }
432        }
433
434        html.classList.remove(previousTheme);
435        html.classList.add(theme);
436        previousTheme = theme;
437        updateThemeSelected();
438    }
439
440    const query = window.matchMedia('(prefers-color-scheme: dark)');
441    query.onchange = function() {
442        set_theme(get_theme(), false);
443    };
444
445    // Set theme.
446    set_theme(get_theme(), false);
447
448    themeToggleButton.addEventListener('click', function() {
449        if (themePopup.style.display === 'block') {
450            hideThemes();
451        } else {
452            showThemes();
453        }
454    });
455
456    themePopup.addEventListener('click', function(e) {
457        let theme;
458        if (e.target.className === 'theme') {
459            theme = e.target.id;
460        } else if (e.target.parentElement.className === 'theme') {
461            theme = e.target.parentElement.id;
462        } else {
463            return;
464        }
465        theme = theme.replace(/^mdbook-theme-/, '');
466
467        if (theme === 'default_theme' || theme === null) {
468            delete_saved_theme();
469            set_theme(get_theme(), false);
470        } else {
471            set_theme(theme);
472        }
473    });
474
475    themePopup.addEventListener('focusout', function(e) {
476        // e.relatedTarget is null in Safari and Firefox on macOS (see workaround below)
477        if (!!e.relatedTarget &&
478            !themeToggleButton.contains(e.relatedTarget) &&
479            !themePopup.contains(e.relatedTarget)
480        ) {
481            hideThemes();
482        }
483    });
484
485    // Should not be needed, but it works around an issue on macOS & iOS:
486    // https://github.com/rust-lang/mdBook/issues/628
487    document.addEventListener('click', function(e) {
488        if (themePopup.style.display === 'block' &&
489            !themeToggleButton.contains(e.target) &&
490            !themePopup.contains(e.target)
491        ) {
492            hideThemes();
493        }
494    });
495
496    document.addEventListener('keydown', function(e) {
497        if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) {
498            return;
499        }
500        if (!themePopup.contains(e.target)) {
501            return;
502        }
503
504        let li;
505        switch (e.key) {
506        case 'Escape':
507            e.preventDefault();
508            hideThemes();
509            break;
510        case 'ArrowUp':
511            e.preventDefault();
512            li = document.activeElement.parentElement;
513            if (li && li.previousElementSibling) {
514                li.previousElementSibling.querySelector('button').focus();
515            }
516            break;
517        case 'ArrowDown':
518            e.preventDefault();
519            li = document.activeElement.parentElement;
520            if (li && li.nextElementSibling) {
521                li.nextElementSibling.querySelector('button').focus();
522            }
523            break;
524        case 'Home':
525            e.preventDefault();
526            themePopup.querySelector('li:first-child button').focus();
527            break;
528        case 'End':
529            e.preventDefault();
530            themePopup.querySelector('li:last-child button').focus();
531            break;
532        }
533    });
534})();
535
536(function sidebar() {
537    const sidebar = document.getElementById('mdbook-sidebar');
538    const sidebarLinks = document.querySelectorAll('#mdbook-sidebar a');
539    const sidebarToggleButton = document.getElementById('mdbook-sidebar-toggle');
540    const sidebarResizeHandle = document.getElementById('mdbook-sidebar-resize-handle');
541    const sidebarCheckbox = document.getElementById('mdbook-sidebar-toggle-anchor');
542    let firstContact = null;
543
544
545    /* Because we cannot change the `display` using only CSS after/before the transition, we
546       need JS to do it. We change the display to prevent the browsers search to find text inside
547       the collapsed sidebar. */
548    if (!document.documentElement.classList.contains('sidebar-visible')) {
549        sidebar.style.display = 'none';
550    }
551    sidebar.addEventListener('transitionend', () => {
552        /* We only change the display to "none" if we're collapsing the sidebar. */
553        if (!sidebarCheckbox.checked) {
554            sidebar.style.display = 'none';
555        }
556    });
557    sidebarToggleButton.addEventListener('click', () => {
558        /* To allow the sidebar expansion animation, we first need to put back the display. */
559        if (!sidebarCheckbox.checked) {
560            sidebar.style.display = '';
561            // Workaround for Safari skipping the animation when changing
562            // `display` and a transform in the same event loop. This forces a
563            // reflow after updating the display.
564            sidebar.offsetHeight;
565        }
566    });
567
568    function showSidebar() {
569        document.documentElement.classList.add('sidebar-visible');
570        Array.from(sidebarLinks).forEach(function(link) {
571            link.setAttribute('tabIndex', 0);
572        });
573        sidebarToggleButton.setAttribute('aria-expanded', true);
574        sidebar.setAttribute('aria-hidden', false);
575        try {
576            localStorage.setItem('mdbook-sidebar', 'visible');
577        } catch {
578            // Ignore error.
579        }
580    }
581
582    function hideSidebar() {
583        document.documentElement.classList.remove('sidebar-visible');
584        Array.from(sidebarLinks).forEach(function(link) {
585            link.setAttribute('tabIndex', -1);
586        });
587        sidebarToggleButton.setAttribute('aria-expanded', false);
588        sidebar.setAttribute('aria-hidden', true);
589        try {
590            localStorage.setItem('mdbook-sidebar', 'hidden');
591        } catch {
592            // Ignore error.
593        }
594    }
595
596    // Toggle sidebar
597    sidebarCheckbox.addEventListener('change', function sidebarToggle() {
598        if (sidebarCheckbox.checked) {
599            const current_width = parseInt(
600                document.documentElement.style.getPropertyValue('--sidebar-target-width'), 10);
601            if (current_width < 150) {
602                document.documentElement.style.setProperty('--sidebar-target-width', '150px');
603            }
604            showSidebar();
605        } else {
606            hideSidebar();
607        }
608    });
609
610    sidebarResizeHandle.addEventListener('mousedown', initResize, false);
611
612    function initResize() {
613        window.addEventListener('mousemove', resize, false);
614        window.addEventListener('mouseup', stopResize, false);
615        document.documentElement.classList.add('sidebar-resizing');
616    }
617    function resize(e) {
618        let pos = e.clientX - sidebar.offsetLeft;
619        if (pos < 20) {
620            hideSidebar();
621        } else {
622            if (!document.documentElement.classList.contains('sidebar-visible')) {
623                showSidebar();
624            }
625            pos = Math.min(pos, window.innerWidth - 100);
626            document.documentElement.style.setProperty('--sidebar-target-width', pos + 'px');
627        }
628    }
629    //on mouseup remove windows functions mousemove & mouseup
630    function stopResize() {
631        document.documentElement.classList.remove('sidebar-resizing');
632        window.removeEventListener('mousemove', resize, false);
633        window.removeEventListener('mouseup', stopResize, false);
634    }
635
636    document.addEventListener('touchstart', function(e) {
637        firstContact = {
638            x: e.touches[0].clientX,
639            time: Date.now(),
640        };
641    }, { passive: true });
642
643    document.addEventListener('touchmove', function(e) {
644        if (!firstContact) {
645            return;
646        }
647
648        const curX = e.touches[0].clientX;
649        const xDiff = curX - firstContact.x,
650            tDiff = Date.now() - firstContact.time;
651
652        if (tDiff < 250 && Math.abs(xDiff) >= 150) {
653            if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300)) {
654                showSidebar();
655            } else if (xDiff < 0 && curX < 300) {
656                hideSidebar();
657            }
658
659            firstContact = null;
660        }
661    }, { passive: true });
662})();
663
664(function chapterNavigation() {
665    function zoomOutImages() {
666        for (const elem of Array.from(document.querySelectorAll('input.checkbox-img'))) {
667            elem.checked = false;
668        }
669    }
670
671    document.addEventListener('keydown', function(e) {
672        if (e.altKey ||
673            e.ctrlKey ||
674            e.metaKey ||
675            window.search && window.search.hasFocus() ||
676            mdbook_something_else_has_focus(e)
677        ) {
678            return;
679        }
680
681        const html = document.querySelector('html');
682
683        function next() {
684            const nextButton = document.querySelector('.nav-chapters.next');
685            if (nextButton) {
686                window.location.href = nextButton.href;
687            }
688        }
689        function prev() {
690            const previousButton = document.querySelector('.nav-chapters.previous');
691            if (previousButton) {
692                window.location.href = previousButton.href;
693            }
694        }
695        function showHelp() {
696            const container = document.getElementById('mdbook-help-container');
697            const overlay = document.getElementById('mdbook-help-popup');
698            container.style.display = 'flex';
699
700            // Clicking outside the popup will dismiss it.
701            const mouseHandler = event => {
702                if (overlay.contains(event.target)) {
703                    return;
704                }
705                if (event.button !== 0) {
706                    return;
707                }
708                event.preventDefault();
709                event.stopPropagation();
710                document.removeEventListener('mousedown', mouseHandler);
711                hideHelp();
712            };
713
714            // Pressing esc will dismiss the popup.
715            const escapeKeyHandler = event => {
716                if (event.key === 'Escape') {
717                    event.preventDefault();
718                    event.stopPropagation();
719                    document.removeEventListener('keydown', escapeKeyHandler, true);
720                    hideHelp();
721                }
722            };
723            document.addEventListener('keydown', escapeKeyHandler, true);
724            document.getElementById('mdbook-help-container')
725                .addEventListener('mousedown', mouseHandler);
726        }
727        function hideHelp() {
728            document.getElementById('mdbook-help-container').style.display = 'none';
729        }
730
731        // Usually needs the Shift key to be pressed
732        switch (e.key) {
733        case '?':
734            e.preventDefault();
735            showHelp();
736            break;
737        case 'Escape':
738            zoomOutImages();
739            break;
740        }
741
742        // Rest of the keys are only active when the Shift key is not pressed
743        if (e.shiftKey) {
744            return;
745        }
746
747        switch (e.key) {
748        case 'ArrowRight':
749            e.preventDefault();
750            if (html.dir === 'rtl') {
751                prev();
752            } else {
753                next();
754            }
755            break;
756        case 'ArrowLeft':
757            e.preventDefault();
758            if (html.dir === 'rtl') {
759                next();
760            } else {
761                prev();
762            }
763            break;
764        }
765    });
766})();
767
768(function clipboard() {
769    const clipButtons = document.querySelectorAll('.clip-button');
770
771    function hideTooltip(elem) {
772        elem.firstChild.innerText = '';
773        elem.className = 'clip-button';
774    }
775
776    function showTooltip(elem, msg) {
777        elem.firstChild.innerText = msg;
778        elem.className = 'clip-button tooltipped';
779    }
780
781    const clipboardSnippets = new ClipboardJS('.clip-button', {
782        text: function(trigger) {
783            hideTooltip(trigger);
784            const playground = trigger.closest('pre');
785            return playground_text(playground, false);
786        },
787    });
788
789    Array.from(clipButtons).forEach(function(clipButton) {
790        clipButton.addEventListener('mouseout', function(e) {
791            hideTooltip(e.currentTarget);
792        });
793    });
794
795    clipboardSnippets.on('success', function(e) {
796        e.clearSelection();
797        showTooltip(e.trigger, 'Copied!');
798    });
799
800    clipboardSnippets.on('error', function(e) {
801        showTooltip(e.trigger, 'Clipboard error!');
802    });
803})();
804
805(function scrollToTop() {
806    const menuTitle = document.querySelector('.menu-title');
807
808    menuTitle.addEventListener('click', function() {
809        document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' });
810    });
811})();
812
813(function controllMenu() {
814    const menu = document.getElementById('mdbook-menu-bar');
815
816    (function controllPosition() {
817        let scrollTop = document.scrollingElement.scrollTop;
818        let prevScrollTop = scrollTop;
819        const minMenuY = -menu.clientHeight - 50;
820        // When the script loads, the page can be at any scroll (e.g. if you refresh it).
821        menu.style.top = scrollTop + 'px';
822        // Same as parseInt(menu.style.top.slice(0, -2), but faster
823        let topCache = menu.style.top.slice(0, -2);
824        menu.classList.remove('sticky');
825        let stickyCache = false; // Same as menu.classList.contains('sticky'), but faster
826        document.addEventListener('scroll', function() {
827            scrollTop = Math.max(document.scrollingElement.scrollTop, 0);
828            // `null` means that it doesn't need to be updated
829            let nextSticky = null;
830            let nextTop = null;
831            const scrollDown = scrollTop > prevScrollTop;
832            const menuPosAbsoluteY = topCache - scrollTop;
833            if (scrollDown) {
834                nextSticky = false;
835                if (menuPosAbsoluteY > 0) {
836                    nextTop = prevScrollTop;
837                }
838            } else {
839                if (menuPosAbsoluteY > 0) {
840                    nextSticky = true;
841                } else if (menuPosAbsoluteY < minMenuY) {
842                    nextTop = prevScrollTop + minMenuY;
843                }
844            }
845            if (nextSticky === true && stickyCache === false) {
846                menu.classList.add('sticky');
847                stickyCache = true;
848            } else if (nextSticky === false && stickyCache === true) {
849                menu.classList.remove('sticky');
850                stickyCache = false;
851            }
852            if (nextTop !== null) {
853                menu.style.top = nextTop + 'px';
854                topCache = nextTop;
855            }
856            prevScrollTop = scrollTop;
857        }, { passive: true });
858    })();
859    (function controllBorder() {
860        function updateBorder() {
861            if (menu.offsetTop === 0) {
862                menu.classList.remove('bordered');
863            } else {
864                menu.classList.add('bordered');
865            }
866        }
867        updateBorder();
868        document.addEventListener('scroll', updateBorder, { passive: true });
869    })();
870})();

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.