1const bpMobile = 980; 2let isMobile = window.innerWidth <= bpMobile; 3const inEditor = window.pagenow && ["post", "page", "specialpage"].includes(pagenow); 4let canvOrigElements = []; 5let canvElements = []; 6let allSwipers = []; 7 8function updateCanvasPositions() 9{ 10 for (let i = 0; i < canvElements.length; i++) 11 { 12 const ne = canvElements[i]; 13 const r = canvOrigElements[i].getBoundingClientRect(); 14 if (!ne) return; 15 const curr = ne.getBoundingClientRect(); 16 if (curr) 17 if (Math.floor(r.top) != Math.floor(curr.top) || Math.floor(r.width) != Math.floor(curr.width) || Math.floor(r.height) != Math.floor(curr.height)) 18 { 19 ne.style.top = r.y + window.scrollY + "px"; 20 ne.style.zIndex = 1; 21 ne.style.left = r.x + "px"; 22 ne.style.width = r.width + "px"; 23 ne.style.height = r.height + "px"; 24 ne.setAttribute("width", r.width * window.devicePixelRatio); 25 ne.setAttribute("height", r.height * window.devicePixelRatio); 26 } 27 } 28} 29 30function cloneAsCanvas(q, addclass) 31{ 32 const elements = document.querySelectorAll(q); 33 34 for (let i = 0; i < elements.length; i++) 35 { 36 const r = elements[i].getBoundingClientRect(); 37 const ne = document.createElement("canvas"); 38 ne.style.position = "absolute"; 39 // ne.style.border = "1px solid red"; 40 ne.style.backgroundColor = "gray"; 41 ne.style.zIndex = 1; 42 ne.classList.add("bggradient"); 43 ne.dataset.gradient = addclass; 44 45 canvElements.push(ne); 46 canvOrigElements.push(elements[i]); 47 48 // elements[i].prepend(ne); 49 document.body.appendChild(ne); 50 } 51 52} 53 54const map = function (x, _oldMin, _oldMax, _newMin, _newMax, _easing = 0, clamp = true) 55{ 56 if (clamp) 57 { 58 if (x >= _oldMax) return _newMax; 59 if (x <= _oldMin) return _newMin; 60 } 61 62 let reverseInput = false; 63 const oldMin = Math.min(_oldMin, _oldMax); 64 const oldMax = Math.max(_oldMin, _oldMax); 65 if (oldMin != _oldMin) reverseInput = true; 66 67 let reverseOutput = false; 68 const newMin = Math.min(_newMin, _newMax); 69 const newMax = Math.max(_newMin, _newMax); 70 if (newMin != _newMin) reverseOutput = true; 71 72 let portion = 0; 73 let r = 0; 74 75 if (reverseInput) portion = ((oldMax - x) * (newMax - newMin)) / (oldMax - oldMin); 76 else portion = ((x - oldMin) * (newMax - newMin)) / (oldMax - oldMin); 77 78 if (reverseOutput) r = newMax - portion; 79 else r = portion + newMin; 80 81 if (!_easing) return r; 82 if (_easing == 1) 83 { 84 // smoothstep 85 x = Math.max(0, Math.min(1, (r - _newMin) / (_newMax - _newMin))); 86 return _newMin + x * x * (3 - 2 * x) * (_newMax - _newMin); 87 } 88 if (_easing == 2) 89 { 90 // smootherstep 91 x = Math.max(0, Math.min(1, (r - _newMin) / (_newMax - _newMin))); 92 return _newMin + x * x * x * (x * (x * 6 - 15) + 10) * (_newMax - _newMin); 93 } 94 95 return r; 96}; 97 98function setupSwiper(el) 99{ 100 if (!el || el.classList.contains("initialized")) return; 101 102 let numSlides = parseFloat(el.dataset.ssize); 103 if (numSlides == 2) numSlides = 1; 104 if (numSlides == 3) numSlides = 3.5; 105 if (numSlides == 4) numSlides = 4.5; 106 if (isMobile) numSlides = Math.min(numSlides, 1.5); 107 108 const center = numSlides == 1; 109 let loop = true; 110 111 const slides = el.getElementsByClassName("swiper-slide"); 112 if (slides.length < Math.floor(numSlides) + 1) loop = false; 113 114 // if (window.swiper)window.swiper.destroy(true); 115 const o = { 116 "direction": "horizontal", 117 "loop": loop, 118 "slidesPerView": numSlides, 119 "allowTouchMove": !inEditor, 120 121 "centeredSlides": center, 122 "spaceBetween": 20, 123 "controller": { 124 "inverse": true, 125 }, 126 127 "navigation": { 128 "nextEl": ".swipenext" + el.dataset.id, 129 "prevEl": ".swipeprev" + el.dataset.id, 130 }, 131 132 }; 133 134 if (el.dataset.pagination) 135 o.pagination = { 136 "el": ".swipepagination", 137 "type": "fraction", 138 }; 139 140 // if (numSlides != 3) 141 // o.navigation = { 142 // "nextEl": ".swipenext" + el.dataset.id, 143 // "prevEl": ".swipeprev" + el.dataset.id, 144 // }; 145 146 const swiper = new Swiper(el, o); 147 el.classList.add("initialized"); 148 allSwipers.push(swiper); 149 150 // swiper.disable(); 151 return swiper; 152} 153 154function closeBurgerMenu() 155{ 156 document.getElementById("burgerMenu").style.display = "none"; 157 document.getElementById("burgerMenuButton").classList.add("iconBurger"); 158 document.getElementById("burgerMenuButton").classList.remove("iconX"); 159 document.body.style.overflow = "auto"; 160 161} 162 163function toggleBrgsBrgsMenu() 164{ 165 if (document.getElementById("burgerMenu").style.display == "block") 166 { 167 // hide 168 closeBurgerMenu(); 169 } 170 else 171 { 172 // show 173 document.getElementById("burgerMenu").style.display = "block"; 174 document.getElementById("burgerMenuButton").classList.remove("iconBurger"); 175 document.getElementById("burgerMenuButton").classList.add("iconX"); 176 document.body.style.overflow = "hidden"; 177 } 178} 179 180function closeModalGallery() 181{ 182 document.getElementById("modalGallery").innerHTML = ""; 183 document.getElementById("modalBg").style.display = "none"; 184 document.getElementById("modalClose").style.display = "none"; 185 document.getElementById("modalGallery").style.display = "none"; 186} 187 188function modalGallery(ele, idx) 189{ 190 let images = JSON.parse(ele.parentElement.dataset.tdn); 191 images = images.filter((image) => { return image.id !== "placeholder"; }); 192 193 let str = 194 "<div id=\"modalGalleryInner\" class=\"swiper myswiper\" data-ssize=\"1\" data-id=\"Modal\">" + 195 "<div class=\"swiper-wrapper\">"; 196 197 for (let i = idx; i < images.length + idx; i++) 198 { 199 str += 200 "<div class=\"swiper-slide modalSlide\"> " + 201 "<div class=\"sizer\"" + 202 " style=\"background-image:url(" + images[i % images.length].url + ");background-position:50% 50%;background-repeat:no-repeat;background-size:contain;" + 203 "\">" + 204 "</div>" + 205 "</div>"; 206 } 207 208 str += 209 "</div>" + 210 "</div>" + 211 "<div class='swiperArrow swiper-button-next swipenextModal'></div>" + 212 "<div class='swiperArrow swiper-button-prev swipeprevModal'></div>"; 213 214 document.getElementById("modalGallery").innerHTML = str; 215 document.getElementById("modalBg").style.display = "block"; 216 document.getElementById("modalGallery").style.display = "block"; 217 document.getElementById("modalClose").style.display = "block"; 218 setupSwiper(document.getElementById("modalGalleryInner")); 219} 220 221function setupHero() 222{ 223 const m = window.innerWidth <= bpMobile; 224 if (m != isMobile) 225 { 226 isMobile = m; 227 pageLoadActions(); 228 } 229 230 if (isMobile) 231 { 232 const elGradient = document.getElementById("heroGradient"); 233 const elHeroText = document.getElementById("heroHeaderText"); 234 if (elGradient) elGradient.remove(); 235 if (elHeroText) elHeroText.parentElement.classList.add(elHeroText.dataset.gradient); 236 if (elHeroText) elHeroText.parentElement.style.paddingBottom = "var(--spacing)"; 237 238 } 239 else 240 { 241 const img = document.getElementById("postHeaderImage"); 242 const pht = document.getElementById("postHeaderText"); 243 const socialBar = document.getElementById("headerSocialIcons"); 244 if (img && socialBar) 245 { 246 const r = img.getBoundingClientRect(); 247 const rpht = pht.getBoundingClientRect(); 248 socialBar.style.marginLeft = r.left - rpht.left + "px"; 249 } 250 251 const elGradient = document.getElementById("heroGradient"); 252 const elHImage = document.getElementById("heroImage"); 253 if (elHImage && elGradient) 254 { 255 const rect = elHImage.getBoundingClientRect(); 256 elGradient.style.height = rect.height + "px"; 257 } 258 } 259 260} 261 262function updateSliderButtons() 263{ 264 const elArrows = document.getElementsByClassName("arrowCircleCenter"); 265 for (let i = 0; i < elArrows.length; i++) 266 { 267 let parent = elArrows[i].parentElement; 268 if (elArrows[i].dataset.centerin) 269 { 270 parent = document.querySelector(elArrows[i].dataset.centerin) || parent; 271 } 272 const pr = parent.getBoundingClientRect(); 273 if (isMobile) 274 { 275 if (elArrows[i].classList.contains("swiperoutside-button-prev")) 276 { 277 elArrows[i].style.left = 5 + "px"; 278 } 279 else 280 { 281 elArrows[i].style.left = "unset"; 282 elArrows[i].style.right = 34 + 25 + "px"; 283 } 284 elArrows[i].style.marginTop = (pr.height / 2 - 40) + "px"; 285 } 286 else 287 { 288 elArrows[i].style.marginTop = (pr.height / 2 - 40) + "px"; 289 } 290 } 291} 292 293function updatesliders(eles = null, forceUpdate = false) 294{ 295 if (!eles) eles = document.getElementsByClassName("myswiper"); 296 for (let i = 0; i < eles.length; i++) 297 { 298 const el = eles[i]; 299 if (forceUpdate) el.classList.remove("initialized"); 300 setupSwiper(el); 301 } 302 updateSliderButtons(); 303} 304 305function initSearch() 306{ 307 const si = document.getElementById("pumasearch"); 308 if (si) 309 { 310 si.addEventListener("keyup", (e) => 311 { 312 if (e.code == "Enter") document.location.href = "/?s=" + si.value; 313 }); 314 si.focus(); 315 } 316} 317 318function getCookies() 319{ 320 return Object.fromEntries(document.cookie.split("; ").map((v) => 321 { 322 return v.split(/=(.*)/s).map(decodeURIComponent); 323 })); 324} 325 326function getUserConsent() 327{ 328 if (!themeConfig.consentManager.load) 329 { 330 const cookies = getCookies(); 331 return cookies.givenConsent ? JSON.parse(cookies.givenConsent) : {}; 332 } 333 else 334 { 335 return true; 336 } 337} 338 339function userGaveConsent(category) 340{ 341 if (!themeConfig.consentManager.load) 342 { 343 const userConsent = getUserConsent(); 344 return userConsent[category]; 345 } 346 else 347 { 348 return true; 349 } 350} 351 352function acceptCookies() 353{ 354 const expirationDate = new Date(); 355 expirationDate.setFullYear(expirationDate.getFullYear() + 1); 356 document.cookie = "cookieConsent=true;expires=" + expirationDate.toUTCString() + ";path=/"; 357 document.getElementById("cookieBanner").style.display = "none"; 358} 359 360function cookieBanner() 361{ 362 const cookies = getCookies(); 363 const wasWarned = cookies.cookieConsent; 364 if (!wasWarned) 365 { 366 const cookieBanner = document.getElementById("cookieBanner"); 367 if (cookieBanner) cookieBanner.style.display = "block"; 368 } 369} 370 371function toggleDarkMode() 372{ 373 const dm = localStorage.getItem("darkMode") == "true"; 374 localStorage.setItem("darkMode", String(!dm)); 375 updateDarkMode(); 376 closeBurgerMenu(); 377} 378 379function updateDarkMode() 380{ 381 // const el = document.getElementsByClassName("wp-block-post-content")[0] || document.body; 382 const el = document.body; 383 if (!el) return console.log("no darkmode ele found"); 384 el.classList.remove("dark"); 385 el.classList.remove("bright"); 386 387 if (localStorage.getItem("darkMode") === "true") el.classList.add("dark"); 388 else el.classList.add("bright"); 389} 390 391function updateHeaderScrollSize() 392{ 393 const maxScroll = 700; 394 isMobile = window.innerWidth <= bpMobile; 395 396 let min = 0; 397 if (isMobile) min = 10; 398 399 const p = map(window.scrollY, 0, maxScroll, 30, min, 1); 400 const el = document.getElementsByClassName("rowHeader")[0]; 401 402 if (!el) return; 403 el.style.paddingTop = p + "px"; 404 el.style.paddingBottom = p + "px"; 405 406 const s = map(window.scrollY, 0, maxScroll, 38, 20, 1); 407 const el3 = document.getElementsByClassName("stickyVertCenter"); 408 const s2 = map(window.scrollY, 0, maxScroll, 5, 20, 1); 409 for (let i = 0; i < el3.length; i++) 410 { 411 el3[i].style.paddingTop = s + "px"; 412 el3[i].style.paddingBottom = s2 + "px"; 413 } 414 415 const logo = document.getElementsByClassName("site-logo")[0]; 416 const rightnav = document.getElementsByClassName("rightnav")[0]; 417 const s3 = map(window.scrollY, 0, maxScroll, 0, 20, 1); 418 if (logo) logo.style.height = 50 - s3 + "px"; 419 if (logo) logo.style.marginTop = s3 / 2 + "px"; 420 if (rightnav) rightnav.style.height = 40 - s3 + "px"; 421 422 const elLangSelect = document.getElementsByClassName("langSelectContainer")[0]; 423 const elPopup = document.getElementsByClassName("opopup")[0]; 424 if (elPopup) 425 { 426 const s4 = map(window.scrollY, 0, maxScroll, 0, 2, 1); 427 elPopup.style.marginTop = Math.floor(elLangSelect.getBoundingClientRect().height + elLangSelect.getBoundingClientRect().top - 44) / 2 + s4 + "px"; 428 } 429 430 const header = document.getElementsByTagName("header")[0]; 431 // const headerSpacer = document.getElementById("headerspacer"); 432 // if (header && headerSpacer)headerSpacer.style.height = 433 document.documentElement.style.setProperty("--headSpace", header.getBoundingClientRect().height + "px"); 434 // document.documentElement.style.setProperty("--headSpace", 130 + "px"); 435 436} 437 438function initAccessibility() 439{ 440 const clickableElements = document.getElementsByClassName("clickable"); 441 for (let i = 0; i < clickableElements.length; i++) 442 { 443 if (clickableElements[i].onclick) 444 { 445 clickableElements[i].onkeypress = clickableElements[i].onclick; 446 clickableElements[i].setAttribute("tabindex", "0"); 447 } 448 } 449 450 document.body.addEventListener("keyup", (e) => 451 { 452 if (e.code == "Tab") 453 { 454 console.log("tabbb"); 455 for (let i = 0; i < allSwipers.length; i++) 456 { 457 allSwipers[i].disable(); 458 } 459 const clickableElements = document.getElementsByClassName("swiper-wrapper"); 460 for (let i = 0; i < clickableElements.length; i++) 461 { 462 clickableElements[i].style.overflow = "auto"; 463 } 464 const headerEle = document.getElementById("heroHeaderText"); 465 headerEle.style.overflow = "initial"; 466 467 } 468 }); 469} 470 471function loadArticles(what, elementSelector, button, replace = false, paramOverride = false) 472{ 473 const oldText = button.innerText; 474 const text = button.querySelector(".text"); 475 text.innerText = button.dataset.loadingtxt; 476 const indicator = button.querySelector(".loadingIndicator"); 477 if (indicator) indicator.classList.remove("hidden"); 478 479 const allTargets = document.querySelectorAll(elementSelector); 480 const targetElement = allTargets[0]; 481 const page = replace ? 1 : parseInt(button.dataset.nextpage); 482 const param = paramOverride || button.dataset.param; 483 const options = { 484 "method": "POST", 485 "body": JSON.stringify({ 486 what, 487 param, 488 page 489 }) 490 }; 491 fetch("/wp-json/frontend/articles/more", options).then((response) => 492 { 493 response.text().then((content) => 494 { 495 if (replace) 496 { 497 button.dataset.param = param; 498 button.dataset.nextpage = "2"; 499 targetElement.outerHTML = content; 500 for (let i = 1; i < allTargets.length; i++) 501 { 502 allTargets[i].remove(); 503 } 504 } 505 else 506 { 507 button.dataset.param = param;
508 button.dataset.nextpage = String(page + 1); 509 const template = document.createElement("div"); 510 template.innerHTML = content.trim(); 511 targetElement.appendChild(template.querySelector(".articlegrid")); 512 // targetElement.innerHTML += content; 513 } 514 if (button) 515 { 516 text.innerText = oldText; 517 if (response.headers && response.headers.get("x-last-page")) 518 { 519 button.classList.add("hidden"); 520 } 521 else 522 { 523 button.classList.remove("hidden"); 524 } 525 } 526 if (indicator) indicator.classList.add("hidden"); 527 }); 528 }).catch((e) => 529 { 530 console.error("E", e); 531 }); 532} 533 534function addFilter(element, event) 535{ 536 event.preventDefault(); 537 event.stopPropagation(); 538 if (element.classList.contains("active")) return; 539 element.classList.add("active"); 540 const filterElement = element.closest("#filters"); 541 const activeElements = Array.from(filterElement.querySelectorAll(".button.active")); 542 if (activeElements.length === 1) 543 { 544 const url = new URL(element.href); 545 window.history.pushState(null, null, url.pathname); 546 window.addEventListener("popstate", () => 547 { 548 document.location.href = window.location.href; 549 }); 550 } 551 552 const param = activeElements.map((activeElement) => 553 { 554 return activeElement.dataset.catid; 555 }).join(","); 556 loadArticles("category", ".articlegrid", document.getElementById("loadMore"), true, param); 557 558 if (activeElements.length !== 0) 559 { 560 const removeAll = document.getElementById("removeAll"); 561 if (removeAll) removeAll.classList.remove("hidden"); 562 } 563 else 564 { 565 const removeAll = document.getElementById("removeAll"); 566 if (removeAll) removeAll.classList.add("hidden"); 567 } 568 569} 570 571function removeFilter(element, event) 572{ 573 event.preventDefault(); 574 event.stopPropagation(); 575 const filterLink = element.closest(".active"); 576 if (!filterLink) return; 577 578 const filterElement = element.closest("#filters"); 579 let activeElements = Array.from(filterElement.querySelectorAll(".button.active")); 580 if (activeElements.length === 1) 581 { 582 document.location.href = filterElement.dataset.parenturl; 583 return; 584 } 585 filterLink.classList.remove("active"); 586 activeElements = Array.from(filterElement.querySelectorAll(".button.active")); 587 if (activeElements.length === 1) 588 { 589 const url = new URL(activeElements[0].href); 590 window.history.pushState(null, null, url.pathname); 591 window.addEventListener("popstate", () => 592 { 593 document.location.href = window.location.href; 594 }); 595 } 596 597 const param = activeElements.map((activeElement) => 598 { 599 return activeElement.dataset.catid; 600 }).join(","); 601 loadArticles("category", ".articlegrid", document.getElementById("loadMore"), true, param); 602 603 if (activeElements.length !== 0) 604 { 605 const removeAll = document.getElementById("removeAll"); 606 if (removeAll) removeAll.classList.remove("hidden"); 607 } 608 else 609 { 610 const removeAll = document.getElementById("removeAll"); 611 if (removeAll) removeAll.classList.add("hidden"); 612 } 613 614} 615 616/// ///////////////////////////////// 617// init stuff... 618 619const pageLoadActions = () => 620{ 621 updateDarkMode(); 622 updatesliders(); 623 // setupHero(); 624 updateSliderButtons(); 625 initSearch(); 626 initAccessibility(); 627 628 setTimeout(() => 629 { 630 updateHeaderScrollSize(); 631 setupHero(); 632 }, 100); 633}; 634 635// on page load 636document.addEventListener("DOMContentLoaded", () => 637{ 638 if (inEditor) 639 { 640 const partials = document.querySelectorAll("[type='text/x-handlebars-partial']"); 641 partials.forEach((partialElement) => 642 { 643 const template = decodeHTML(partialElement.textContent); 644 Handlebars.registerPartial(partialElement.dataset.name, template); 645 }); 646 } 647 else 648 { 649 pageLoadActions(); 650 } 651}); 652 653window.addEventListener("editorBlockAdded", ({ "detail": blockIds }) => 654{ 655 // console.log("added", blocks); 656}); 657 658window.addEventListener("editorBlockLoaded", ({ "detail": data }) => 659{ 660 const attributes = data.attributes; 661 const element = data.element; 662 if (element) 663 { 664 const sliders = element.querySelectorAll(".myswiper"); 665 if (sliders) 666 { 667 setTimeout(updatesliders, 1000); // TODO: remove this timeout 668 } 669 } 670}); 671 672window.addEventListener("editorBlockSaved", ({ "detail": data }) => 673{ 674 // const attributes = data.attributes; 675 // const element = data.element; 676 // console.log("saved", blocks); 677}); 678 679window.addEventListener("editorBlockRemoved", ({ "detail": blockIds }) => 680{ 681 // console.log("removed", blocks); 682}); 683 684window.addEventListener("editorReady", () => 685{ 686 // console.log("editor ready"); 687 pageLoadActions(); 688}); 689 690window.addEventListener("load", () => 691{ 692 cookieBanner(); 693 if (inEditor) 694 { 695 updateDarkMode(); 696 } 697}); 698 699window.addEventListener("resize", () => 700{ 701 setTimeout(() => 702 { 703 updateSliderButtons(); 704 setupHero(); 705 updateHeaderScrollSize(); 706 updateCanvasPositions(); 707 }, 50); 708}); 709 710document.addEventListener("scroll", () => 711{ 712 updateHeaderScrollSize(); 713}); 714 715// when cables stuff loaded 716document.addEventListener("CABLES.jsLoaded", function (event) 717{ 718 function showError(initiator, ...args) 719 { 720 CABLES.logErrorConsole("[" + initiator + "]", ...args); 721 document.body.classList.remove("glgradients"); 722 } 723 724 if (inEditor || isMobile) return; 725 726 // CABLES.patch = new CABLES.Patch({ 727 // "patch": CABLES.exportedPatch, 728 // "prefixAssetPath": "", 729 // "assetPath": "assets/", 730 // "jsPath": "js/", 731 // "onError": showError, 732 // "doRequestAnimation": false, 733 // "containerElement": document.body 734 // // "onPatchLoaded": patchInitialized, 735 // // "onFinishedLoading": patchFinishedLoading, 736 // // "canvas": { "alpha": true, "premultipliedAlpha": true } // make canvas transparent 737 // }); 738 739 cloneAsCanvas(".gradient1", "1"); 740 cloneAsCanvas(".gradient2", "2"); 741 cloneAsCanvas(".gradient3", "3"); 742 cloneAsCanvas(".gradient4", "4"); 743 cloneAsCanvas(".gradient5", "5"); 744 updateCanvasPositions(); 745 746 setInterval(() => 747 { 748 updateCanvasPositions(); 749 }, 500); 750 console.log("aaa", document.documentElement.style.getPropertyValue("--wp-admin--admin-bar--height")); 751 const eles = document.getElementsByClassName("navEle"); 752 for (let i = 0; i < eles.length; i++) 753 { 754 console.log( 755 document.getElementsByClassName("navEle")[i].getBoundingClientRect() 756 ); 757 } 758 759 CABLES.patchGradients = new CABLES.Patch({ 760 "patch": CABLES.exportedPatches.zwNKaV, 761 "prefixAssetPath": "", 762 "assetPath": "assets/", 763 "jsPath": "js/", 764 "onError": showError, 765 "glCanvasId": "glcanvas", 766 "glCanvasResizeToWindow": true, 767 // "containerElement": document.body 768 // "onPatchLoaded": patchInitialized, 769 "onFinishedLoading": () => 770 { 771 document.body.classList.add("glgradients"); 772 }, 773 "canvas": { 774 "alpha": true, 775 "premultipliedAlpha": true 776 } // make canvas transparent 777 }); 778}); 779const darkmodeInterval = setInterval(() => 780{ 781 782 if (!document.body) return; 783 if ( 784 !document.body.classList.contains("dark") && 785 !document.body.classList.contains("bright") 786 ) 787 { 788 console.warn("content has no bright/dark mode class...."); 789 updateDarkMode(); 790 } 791 else 792 { 793 clearInterval(darkmodeInterval); 794 } 795 796}, 500);
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.