PageSourceSearch

https://paginas.digital/builder/elements/scripts/smoothscroll.js

js paginas.digital collected 2026-09-29 00:49:01 UTC 26,237 bytes, 790 lines download raw bytes

1//
2// SmoothScroll for websites v1.4.9 (Balazs Galambosi)
3// http://www.smoothscroll.net/
4//
5// Licensed under the terms of the MIT license.
6//
7// You may use it in your theme if you credit me. 
8// It is also free to use on any individual website.
9//
10// Exception:
11// The only restriction is to not publish any  
12// extension for browsers or native application
13// without getting a written permission first.
14//
15
16(function () {
17
18    // Scroll Variables (tweakable)
19    var defaultOptions = {
20
21        // Scrolling Core
22        frameRate: 150, // [Hz]
23        animationTime: 400, // [ms]
24        stepSize: 120, // [px]
25
26        // Pulse (less tweakable)
27        // ratio of "tail" to "acceleration"
28        pulseAlgorithm: true,
29        pulseScale: 8,
30        pulseNormalize: 1,
31
32        // Acceleration
33        accelerationDelta: 20,  // 50
34        accelerationMax: 1,   // 3
35
36        // Keyboard Settings
37        keyboardSupport: false,  // option
38        arrowScroll: 50,    // [px]
39
40        // Other
41        fixedBackground: true,
42        excluded: ''
43    };
44
45    var options = defaultOptions;
46
47
48    // Other Variables
49    var isExcluded = false;
50    var isFrame = false;
51    var direction = { x: 0, y: 0 };
52    var initDone = false;
53    var root = document.documentElement;
54    var activeElement;
55    var observer;
56    var refreshSize;
57    var deltaBuffer = [];
58    var deltaBufferTimer;
59    var isMac = /^Mac/.test(navigator.platform);
60
61    var key = {
62        left: 37, up: 38, right: 39, down: 40, spacebar: 32,
63        pageup: 33, pagedown: 34, end: 35, home: 36
64    };
65    var arrowKeys = { 37: 1, 38: 1, 39: 1, 40: 1 };
66
67    /***********************************************
68     * INITIALIZE
69     ***********************************************/
70
71    /**
72     * Tests if smooth scrolling is allowed. Shuts down everything if not.
73     */
74    function initTest() {
75        if (options.keyboardSupport) {
76            addEvent('keydown', keydown);
77        }
78    }
79
80    /**
81     * Sets up scrolls array, determines if frames are involved.
82     */
83    function init() {
84
85        if (initDone || !document.body) return;
86
87        initDone = true;
88
89        var body = document.body;
90        var html = document.documentElement;
91        var windowHeight = window.innerHeight;
92        var scrollHeight = body.scrollHeight;
93
94        // check compat mode for root element
95        root = (document.compatMode.indexOf('CSS') >= 0) ? html : body;
96        activeElement = body;
97
98        initTest();
99
100        // Checks if this script is running in a frame
101        if (top != self) {
102            isFrame = true;
103        }
104
105        /**
106         * Safari 10 fixed it, Chrome fixed it in v45:
107         * This fixes a bug where the areas left and right to 
108         * the content does not trigger the onmousewheel event
109         * on some pages. e.g.: html, body { height: 100% }
110         */
111        else if (isOldSafari &&
112            scrollHeight > windowHeight &&
113            (body.offsetHeight <= windowHeight ||
114                html.offsetHeight <= windowHeight)) {
115
116            var fullPageElem = document.createElement('div');
117            fullPageElem.style.cssText = 'position:absolute; z-index:-10000; ' +
118                'top:0; left:0; right:0; height:' +
119                root.scrollHeight + 'px';
120            document.body.appendChild(fullPageElem);
121
122            // DOM changed (throttled) to fix height
123            var pendingRefresh;
124            refreshSize = function () {
125                if (pendingRefresh) return; // could also be: clearTimeout(pendingRefresh);
126                pendingRefresh = setTimeout(function () {
127                    if (isExcluded) return; // could be running after cleanup
128                    fullPageElem.style.height = '0';
129                    fullPageElem.style.height = root.scrollHeight + 'px';
130                    pendingRefresh = null;
131                }, 500); // act rarely to stay fast
132            };
133
134            setTimeout(refreshSize, 10);
135
136            addEvent('resize', refreshSize);
137
138            // TODO: attributeFilter?
139            var config = {
140                attributes: true,
141                childList: true,
142                characterData: false
143                // subtree: true
144            };
145
146            observer = new MutationObserver(refreshSize);
147            observer.observe(body, config);
148
149            if (root.offsetHeight <= windowHeight) {
150                var clearfix = document.createElement('div');
151                clearfix.style.clear = 'both';
152                body.appendChild(clearfix);
153            }
154        }
155
156        // disable fixed background
vendor: 6,894 bytes, lines 157-372
157        if (!options.fixedBackground && !isExcluded) {
158            body.style.backgroundAttachment = 'scroll';
159            html.style.backgroundAttachment = 'scroll';
160        }
161    }
162
163    /**
164     * Removes event listeners and other traces left on the page.
165     */
166    function cleanup() {
167        observer && observer.disconnect();
168        removeEvent(wheelEvent, wheel);
169        removeEvent('mousedown', mousedown);
170        removeEvent('keydown', keydown);
171        removeEvent('resize', refreshSize);
172        removeEvent('load', init);
173    }
174
175
176    /************************************************
177     * SCROLLING 
178     ************************************************/
179
180    var que = [];
181    var pending = false;
182    var lastScroll = Date.now();
183
184    /**
185     * Pushes scroll actions to the scrolling queue.
186     */
187    function scrollArray(elem, left, top) {
188
189        directionCheck(left, top);
190
191        if (options.accelerationMax != 1) {
192            var now = Date.now();
193            var elapsed = now - lastScroll;
194            if (elapsed < options.accelerationDelta) {
195                var factor = (1 + (50 / elapsed)) / 2;
196                if (factor > 1) {
197                    factor = Math.min(factor, options.accelerationMax);
198                    left *= factor;
199                    top *= factor;
200                }
201            }
202            lastScroll = Date.now();
203        }
204
205        // push a scroll command
206        que.push({
207            x: left,
208            y: top,
209            lastX: (left < 0) ? 0.99 : -0.99,
210            lastY: (top < 0) ? 0.99 : -0.99,
211            start: Date.now()
212        });
213
214        // don't act if there's a pending queue
215        if (pending) {
216            return;
217        }
218
219        var scrollRoot = getScrollRoot();
220        var isWindowScroll = (elem === scrollRoot || elem === document.body);
221
222        // if we haven't already fixed the behavior, 
223        // and it needs fixing for this sesh
224        if (elem.$scrollBehavior == null && isScrollBehaviorSmooth(elem)) {
225            elem.$scrollBehavior = elem.style.scrollBehavior;
226            elem.style.scrollBehavior = 'auto';
227        }
228
229        var step = function (time) {
230
231            var now = Date.now();
232            var scrollX = 0;
233            var scrollY = 0;
234
235            for (var i = 0; i < que.length; i++) {
236
237                var item = que[i];
238                var elapsed = now - item.start;
239                var finished = (elapsed >= options.animationTime);
240
241                // scroll position: [0, 1]
242                var position = (finished) ? 1 : elapsed / options.animationTime;
243
244                // easing [optional]
245                if (options.pulseAlgorithm) {
246                    position = pulse(position);
247                }
248
249                // only need the difference
250                var x = (item.x * position - item.lastX) >> 0;
251                var y = (item.y * position - item.lastY) >> 0;
252
253                // add this to the total scrolling
254                scrollX += x;
255                scrollY += y;
256
257                // update last values
258                item.lastX += x;
259                item.lastY += y;
260
261                // delete and step back if it's over
262                if (finished) {
263                    que.splice(i, 1); i--;
264                }
265            }
266
267            // scroll left and top
268            if (isWindowScroll) {
269                window.scrollBy(scrollX, scrollY);
270            }
271            else {
272                if (scrollX) elem.scrollLeft += scrollX;
273                if (scrollY) elem.scrollTop += scrollY;
274            }
275
276            // clean up if there's nothing left to do
277            if (!left && !top) {
278                que = [];
279            }
280
281            if (que.length) {
282                requestFrame(step, elem, (1000 / options.frameRate + 1));
283            } else {
284                pending = false;
285                // restore default behavior at the end of scrolling sesh
286                if (elem.$scrollBehavior != null) {
287                    elem.style.scrollBehavior = elem.$scrollBehavior;
288                    elem.$scrollBehavior = null;
289                }
290            }
291        };
292
293        // start a new queue of actions
294        requestFrame(step, elem, 0);
295        pending = true;
296    }
297
298
299    /***********************************************
300     * EVENTS
301     ***********************************************/
302
303    /**
304     * Mouse wheel handler.
305     * @param {Object} event
306     */
307    function wheel(event) {
308
309        if (!initDone) {
310            init();
311        }
312
313        var target = event.target;
314
315        // leave early if default action is prevented   
316        // or it's a zooming event with CTRL 
317        if (event.defaultPrevented || event.ctrlKey) {
318            return true;
319        }
320
321        // leave embedded content alone (flash & pdf)
322        if (isNodeName(activeElement, 'embed') ||
323            (isNodeName(target, 'embed') && /\.pdf/i.test(target.src)) ||
324            isNodeName(activeElement, 'object') ||
325            target.shadowRoot) {
326            return true;
327        }
328
329        var deltaX = -event.wheelDeltaX || event.deltaX || 0;
330        var deltaY = -event.wheelDeltaY || event.deltaY || 0;
331
332        if (isMac) {
333            if (event.wheelDeltaX && isDivisible(event.wheelDeltaX, 120)) {
334                deltaX = -120 * (event.wheelDeltaX / Math.abs(event.wheelDeltaX));
335            }
336            if (event.wheelDeltaY && isDivisible(event.wheelDeltaY, 120)) {
337                deltaY = -120 * (event.wheelDeltaY / Math.abs(event.wheelDeltaY));
338            }
339        }
340
341        // use wheelDelta if deltaX/Y is not available
342        if (!deltaX && !deltaY) {
343            deltaY = -event.wheelDelta || 0;
344        }
345
346        // line based scrolling (Firefox mostly)
347        if (event.deltaMode === 1) {
348            deltaX *= 40;
349            deltaY *= 40;
350        }
351
352        var overflowing = overflowingAncestor(target);
353
354        // nothing to do if there's no element that's scrollable
355        if (!overflowing) {
356            // except Chrome iframes seem to eat wheel events, which we need to 
357            // propagate up, if the iframe has nothing overflowing to scroll
358            if (isFrame && isChrome) {
359                // change target to iframe element itself for the parent frame
360                Object.defineProperty(event, "target", { value: window.frameElement });
361                return parent.wheel(event);
362            }
363            return true;
364        }
365
366        // check if it's a touchpad scroll that should be ignored
367        if (isTouchpad(deltaY)) {
368            return true;
369        }
370
371        // scale by step size
372        // delta is 120 most of the time
373        // synaptics seems to send 1 sometimes
374        if (Math.abs(deltaX) > 1.2) {
375            deltaX *= options.stepSize / 120;
376        }
377        if (Math.abs(deltaY) > 1.2) {
378            deltaY *= options.stepSize / 120;
379        }
380
381        scrollArray(overflowing, deltaX, deltaY);
382        event.preventDefault();
383        scheduleClearCache();
384    }
385
386    /**
387     * Keydown event handler.
388     * @param {Object} event
389     */
390    function keydown(event) {
391
392        var target = event.target;
393        var modifier = event.ctrlKey || event.altKey || event.metaKey ||
394            (event.shiftKey && event.keyCode !== key.spacebar);
395
396        // our own tracked active element could've been removed from the DOM
397        if (!document.body.contains(activeElement)) {
398            activeElement = document.activeElement;
399        }
400
401        // do nothing if user is editing text
402        // or using a modifier key (except shift)
403        // or in a dropdown
404        // or inside interactive elements
405        var inputNodeNames = /^(textarea|select|embed|object)$/i;
406        var buttonTypes = /^(button|submit|radio|checkbox|file|color|image)$/i;
407        if (event.defaultPrevented ||
408            inputNodeNames.test(target.nodeName) ||
409            isNodeName(target, 'input') && !buttonTypes.test(target.type) ||
410            isNodeName(activeElement, 'video') ||
411            isInsideYoutubeVideo(event) ||
412            target.isContentEditable ||
413            modifier) {
414            return true;
415        }
416
417        // [spacebar] should trigger button press, leave it alone
418        if ((isNodeName(target, 'button') ||
419            isNodeName(target, 'input') && buttonTypes.test(target.type)) &&
420            event.keyCode === key.spacebar) {
421            return true;
422        }
423
424        // [arrwow keys] on radio buttons should be left alone
425        if (isNodeName(target, 'input') && target.type == 'radio' &&
426            arrowKeys[event.keyCode]) {
427            return true;
428        }
429
430        var shift, x = 0, y = 0;
431        var overflowing = overflowingAncestor(activeElement);
432
433        if (!overflowing) {
434            // Chrome iframes seem to eat key events, which we need to 
435            // propagate up, if the iframe has nothing overflowing to scroll
436            return (isFrame && isChrome) ? parent.keydown(event) : true;
437        }
438
439        var clientHeight = overflowing.clientHeight;
440
441        if (overflowing == document.body) {
442            clientHeight = window.innerHeight;
443        }
444
445        switch (event.keyCode) {
446            case key.up:
447                y = -options.arrowScroll;
448                break;
449            case key.down:
450                y = options.arrowScroll;
451                break;
452            case key.spacebar: // (+ shift)
453                shift = event.shiftKey ? 1 : -1;
454                y = -shift * clientHeight * 0.9;
455                break;
456            case key.pageup:
457                y = -clientHeight * 0.9;
458                break;
459            case key.pagedown:
460                y = clientHeight * 0.9;
461                break;
462            case key.home:
463                if (overflowing == document.body && document.scrollingElement)
464                    overflowing = document.scrollingElement;
465                y = -overflowing.scrollTop;
466                break;
467            case key.end:
468                var scroll = overflowing.scrollHeight - overflowing.scrollTop;
469                var scrollRemaining = scroll - clientHeight;
470                y = (scrollRemaining > 0) ? scrollRemaining + 10 : 0;
471                break;
472            case key.left:
473                x = -options.arrowScroll;
474                break;
475            case key.right:
476                x = options.arrowScroll;
477                break;
478            default:
479                return true; // a key we don't care about
480        }
481
482        scrollArray(overflowing, x, y);
483        event.preventDefault();
484        scheduleClearCache();
485    }
486
487    /**
488     * Mousedown event only for updating activeElement
489     */
490    function mousedown(event) {
491        activeElement = event.target;
492    }
493
494
495    /***********************************************
496     * OVERFLOW
497     ***********************************************/
498
499    var uniqueID = (function () {
500        var i = 0;
501        return function (el) {
502            return el.uniqueID || (el.uniqueID = i++);
503        };
504    })();
505
506    var cacheX = {}; // cleared out after a scrolling session
507    var cacheY = {}; // cleared out after a scrolling session
508    var clearCacheTimer;
509    var smoothBehaviorForElement = {};
510
511    //setInterval(function () { cache = {}; }, 10 * 1000);
512
513    function scheduleClearCache() {
514        clearTimeout(clearCacheTimer);
515        clearCacheTimer = setInterval(function () {
516            cacheX = cacheY = smoothBehaviorForElement = {};
517        }, 1 * 1000);
518    }
519
520    function setCache(elems, overflowing, x) {
521        var cache = x ? cacheX : cacheY;
522        for (var i = elems.length; i--;)
523            cache[uniqueID(elems[i])] = overflowing;
524        return overflowing;
525    }
526
527    function getCache(el, x) {
528        return (x ? cacheX : cacheY)[uniqueID(el)];
529    }
530
531    //  (body)                (root)
532    //         | hidden | visible | scroll |  auto  |
533    // hidden  |   no   |    no   |   YES  |   YES  |
534    // visible |   no   |   YES   |   YES  |   YES  |
535    // scroll  |   no   |   YES   |   YES  |   YES  |
536    // auto    |   no   |   YES   |   YES  |   YES  |
537
538    function overflowingAncestor(el) {
539        var elems = [];
540        var body = document.body;
541        var rootScrollHeight = root.scrollHeight;
542        do {
543            var cached = getCache(el, false);
544            if (cached) {
545                return setCache(elems, cached);
546            }
547            elems.push(el);
548            if (rootScrollHeight === el.scrollHeight) {
549                var topOverflowsNotHidden = overflowNotHidden(root) && overflowNotHidden(body);
550                var isOverflowCSS = topOverflowsNotHidden || overflowAutoOrScroll(root);
551                if (isFrame && isContentOverflowing(root) ||
552                    !isFrame && isOverflowCSS) {
553                    return setCache(elems, getScrollRoot());
554                }
555            } else if (isContentOverflowing(el) && overflowAutoOrScroll(el)) {
556                return setCache(elems, el);
557            }
558        } while ((el = el.parentElement));
559    }
560
561    function isContentOverflowing(el) {
562        return (el.clientHeight + 10 < el.scrollHeight);
563    }
564
565    // typically for <body> and <html>
566    function overflowNotHidden(el) {
567        var overflow = getComputedStyle(el, '').getPropertyValue('overflow-y');
568        return (overflow !== 'hidden');
569    }
570
571    // for all other elements
572    function overflowAutoOrScroll(el) {
573        var overflow = getComputedStyle(el, '').getPropertyValue('overflow-y');
574        return (overflow === 'scroll' || overflow === 'auto');
575    }
576
577    // for all other elements
578    function isScrollBehaviorSmooth(el) {
579        var id = uniqueID(el);
580        if (smoothBehaviorForElement[id] == null) {
581            var scrollBehavior = getComputedStyle(el, '')['scroll-behavior'];
582            smoothBehaviorForElement[id] = ('smooth' == scrollBehavior);
583        }
584        return smoothBehaviorForElement[id];
585    }
586
587
588    /***********************************************
589     * HELPERS
590     ***********************************************/
591
592    function addEvent(type, fn, arg) {
593        window.addEventListener(type, fn, arg || false);
594    }
595
596    function removeEvent(type, fn, arg) {
597        window.removeEventListener(type, fn, arg || false);
598    }
599
600    function isNodeName(el, tag) {
601        return el && (el.nodeName || '').toLowerCase() === tag.toLowerCase();
602    }
603
604    function directionCheck(x, y) {
605        x = (x > 0) ? 1 : -1;
606        y = (y > 0) ? 1 : -1;
607        if (direction.x !== x || direction.y !== y) {
608            direction.x = x;
609            direction.y = y;
610            que = [];
611            lastScroll = 0;
612        }
613    }
614
615    if (window.localStorage && localStorage.SS_deltaBuffer) {
616        try { // #46 Safari throws in private browsing for localStorage 
617            deltaBuffer = localStorage.SS_deltaBuffer.split(',');
618        } catch (e) { }
619    }
620
621    function isTouchpad(deltaY) {
622        if (!deltaY) return;
623        if (!deltaBuffer.length) {
624            deltaBuffer = [deltaY, deltaY, deltaY];
625        }
626        deltaY = Math.abs(deltaY);
627        deltaBuffer.push(deltaY);
628        deltaBuffer.shift();
629        clearTimeout(deltaBufferTimer);
630        deltaBufferTimer = setTimeout(function () {
631            try { // #46 Safari throws in private browsing for localStorage
632                localStorage.SS_deltaBuffer = deltaBuffer.join(',');
633            } catch (e) { }
634        }, 1000);
635        var dpiScaledWheelDelta = deltaY > 120 && allDeltasDivisableBy(deltaY); // win64 
636        return !allDeltasDivisableBy(120) && !allDeltasDivisableBy(100) && !dpiScaledWheelDelta;
637    }
638
639    function isDivisible(n, divisor) {
640        return (Math.floor(n / divisor) == n / divisor);
641    }
642
643    function allDeltasDivisableBy(divisor) {
644        return (isDivisible(deltaBuffer[0], divisor) &&
645            isDivisible(deltaBuffer[1], divisor) &&
646            isDivisible(deltaBuffer[2], divisor));
647    }
648
649    function isInsideYoutubeVideo(event) {
650        var elem = event.target;
651        var isControl = false;
652        if (document.URL.indexOf('www.youtube.com/watch') != -1) {
653            do {
654                isControl = (elem.classList &&
655                    elem.classList.contains('html5-video-controls'));
656                if (isControl) break;
657            } while ((elem = elem.parentNode));
658        }
659        return isControl;
660    }
661
662    var requestFrame = (function () {
663        return (window.requestAnimationFrame ||
664            window.webkitRequestAnimationFrame ||
665            window.mozRequestAnimationFrame ||
666            function (callback, element, delay) {
667                window.setTimeout(callback, delay || (1000 / 60));
668            });
669    })();
670
671    var MutationObserver = (window.MutationObserver ||
672        window.WebKitMutationObserver ||
673        window.MozMutationObserver);
674
675    var getScrollRoot = (function () {
676        var SCROLL_ROOT = document.scrollingElement;
677        return function () {
678            if (!SCROLL_ROOT) {
679                var dummy = document.createElement('div');
680                dummy.style.cssText = 'height:10000px;width:1px;';
681                document.body.appendChild(dummy);
682                var bodyScrollTop = document.body.scrollTop;
683                var docElScrollTop = document.documentElement.scrollTop;
684                window.scrollBy(0, 3);
685                if (document.body.scrollTop != bodyScrollTop)
686                    (SCROLL_ROOT = document.body);
687                else
688                    (SCROLL_ROOT = document.documentElement);
689                window.scrollBy(0, -3);
690                document.body.removeChild(dummy);
691            }
692            return SCROLL_ROOT;
693        };
694    })();
695
696
697    /***********************************************
698     * PULSE (by Michael Herf)
699     ***********************************************/
700
701    /**
702     * Viscous fluid with a pulse for part and decay for the rest.
703     * - Applies a fixed force over an interval (a damped acceleration), and
704     * - Lets the exponential bleed away the velocity over a longer interval
705     * - Michael Herf, http://stereopsis.com/stopping/
706     */
707    function pulse_(x) {
708        var val, start, expx;
709        // test
710        x = x * options.pulseScale;
711        if (x < 1) { // acceleartion
712            val = x - (1 - Math.exp(-x));
713        } else {     // tail
714            // the previous animation ended here:
715            start = Math.exp(-1);
716            // simple viscous drag
717            x -= 1;
718            expx = 1 - Math.exp(-x);
719            val = start + (expx * (1 - start));
720        }
vendor: 2,293 bytes, lines 721-790
721        return val * options.pulseNormalize;
722    }
723
724    function pulse(x) {
725        if (x >= 1) return 1;
726        if (x <= 0) return 0;
727
728        if (options.pulseNormalize == 1) {
729            options.pulseNormalize /= pulse_(1);
730        }
731        return pulse_(x);
732    }
733
734
735    /***********************************************
736     * FIRST RUN
737     ***********************************************/
738
739    var userAgent = window.navigator.userAgent;
740    var isEdge = /Edge/.test(userAgent); // thank you MS
741    var isChrome = /chrome/i.test(userAgent) && !isEdge;
742    var isSafari = /safari/i.test(userAgent) && !isEdge;
743    var isMobile = /mobile/i.test(userAgent);
744    var isIEWin7 = /Windows NT 6.1/i.test(userAgent) && /rv:11/i.test(userAgent);
745    var isOldSafari = isSafari && (/Version\/8/i.test(userAgent) || /Version\/9/i.test(userAgent));
746    var isEnabledForBrowser = (isChrome || isSafari || isIEWin7) && !isMobile;
747
748    var supportsPassive = false;
749    try {
750        window.addEventListener("test", null, Object.defineProperty({}, 'passive', {
751            get: function () {
752                supportsPassive = true;
753            }
754        }));
755    } catch (e) { }
756
757    var wheelOpt = supportsPassive ? { passive: false } : false;
758    var wheelEvent = 'onwheel' in document.createElement('div') ? 'wheel' : 'mousewheel';
759
760    if (wheelEvent && isEnabledForBrowser) {
761        addEvent(wheelEvent, wheel, wheelOpt);
762        addEvent('mousedown', mousedown);
763        addEvent('load', init);
764    }
765
766
767    /***********************************************
768     * PUBLIC INTERFACE
769     ***********************************************/
770
771    function SmoothScroll(optionsToSet) {
772        for (var key in optionsToSet)
773            if (defaultOptions.hasOwnProperty(key))
774                options[key] = optionsToSet[key];
775    }
776    SmoothScroll.destroy = cleanup;
777
778    if (window.SmoothScrollOptions) // async API
779        SmoothScroll(window.SmoothScrollOptions);
780
781    if (typeof define === 'function' && define.amd)
782        define(function () {
783            return SmoothScroll;
784        });
785    else if ('object' == typeof exports)
786        module.exports = SmoothScroll;
787    else
788        window.SmoothScroll = SmoothScroll;
789
790})();

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.