1console.log("ð [FAQ] BOT_SCRIPT JS SE CARGà âï¸"); 2 3document.addEventListener('DOMContentLoaded', () => { 4 5 /* Root fijo */ 6 let root = document.getElementById('bot-bot-root'); 7 if (!root) { 8 root = document.createElement('div'); 9 root.id = 'bot-bot-root'; 10 root.setAttribute('aria-live', 'polite'); 11 root.setAttribute('aria-atomic', 'true'); 12 document.body.appendChild(root); 13 } 14 15 const launcher = document.getElementById('bot-launcher'); 16 const chat = document.getElementById('bot-chat'); 17 if (!launcher || !chat) return; 18 if (launcher && launcher.parentNode !== root) root.appendChild(launcher); 19 if (chat && chat.parentNode !== root) root.appendChild(chat); 20 /* Sorteo dentro del chat */ 21 22 const overlay = document.getElementById('bot-sorteo'); 23 if (overlay && overlay.parentNode !== chat) chat.appendChild(overlay); 24 25 const status = document.getElementById('bot-status'); 26 const openBtn = document.getElementById('bot-sorteo-btn'); 27 const chatClose = document.getElementById('bot-close'); 28 const chatInput = document.getElementById('bot-input'); 29 30 31 const BASES_PDF_URL = '/wp-content/themes/SANLO2020/sorteo/bases-sorteo-bot.pdf'; 32 33 function setStatus(txt){ 34 if(!status) return; 35 const onlineEl = document.getElementById('statusOnline'); 36 const offlineEl = document.getElementById('statusOffline'); 37 if (txt === 'Online') { 38 onlineEl?.classList.remove('hidden'); 39 onlineEl?.classList.add('visible'); 40 offlineEl?.classList.remove('visible'); 41 offlineEl?.classList.add('hidden'); 42 } else { 43 offlineEl?.classList.remove('hidden'); 44 offlineEl?.classList.add('visible'); 45 onlineEl?.classList.remove('visible'); 46 onlineEl?.classList.add('hidden'); 47 } 48 /* 49 status.classList.toggle('online', txt === 'Online'); 50 const label = status.querySelector('.label'); 51 if (label) label.textContent = txt;*/ 52 } 53 54 function lockScroll(){ 55 const sbw = window.innerWidth - document.documentElement.clientWidth; 56 const y = window.scrollY || document.documentElement.scrollTop || 0; 57 document.body.classList.add('bot-scroll-lock'); 58 document.body.style.position = 'fixed'; 59 document.body.style.top = `-${y}px`; 60 document.body.style.left = '0'; 61 document.body.style.right = '0'; 62 document.body.style.width = '100%'; 63 if (sbw > 0) document.body.style.paddingRight = sbw + 'px'; 64 chat.dataset.scrollY = String(y); 65 } 66 function unlockScroll(){ 67 const y = parseInt(chat.dataset.scrollY || '0', 10); 68 document.body.classList.remove('bot-scroll-lock'); 69 document.body.style.position = ''; 70 document.body.style.top = ''; 71 document.body.style.left = ''; 72 document.body.style.right = ''; 73 document.body.style.width = ''; 74 document.body.style.paddingRight = ''; 75 window.scrollTo(0, y); 76 } 77 function openChat(){ 78 if (chat.classList.contains('open')) return; 79 chat.classList.add('open'); 80 chat.classList.remove('hidden'); 81 lockScroll(); 82 setStatus('Online'); 83 setTimeout(()=> chatInput?.focus(), 140); 84 } 85 function closeChat(){ 86 if (!chat.classList.contains('open')) return; 87 chat.classList.remove('open'); 88 chat.classList.add('hidden'); 89 //setSorteoOpen(false); 90 unlockScroll(); 91 setStatus('Offline'); 92 } 93 94 if (launcher) launcher.onclick = null; 95 launcher?.addEventListener('click', (e)=>{ 96 e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); 97 chat.classList.contains('open') ? closeChat() : openChat(); 98 }, true); 99 100 document.addEventListener('keydown', (e)=>{ if(e.key === 'Escape'){ 101 if (overlay?.classList.contains('open')) { setSorteoOpen(false); } // â guard contra null 102 else { closeChat(); } 103 }} , true); 104 105 /* === NUEVO: X del header del chat, en CAPTURA (cierra siempre) === */ 106 chatClose?.addEventListener('click', (e) => { 107 e.preventDefault(); 108 e.stopPropagation(); 109 e.stopImmediatePropagation(); 110 closeChat(); 111 }, true); 112 113 /* Overlay sorteo */ 114 function resetVideoPoster(){
115 const vid = document.getElementById('cs-video'); 116 if (!vid) return; 117 try{ 118 vid.pause(); 119 if (!isNaN(vid.duration)) vid.currentTime = 0; 120 vid.load(); 121 }catch(_){} 122 } 123 124function setSorteoOpen(open){ 125 if (!overlay) return; 126 127 overlay.classList.toggle('open', open); 128 overlay.style.display = open ? 'flex' : 'none'; 129 overlay.style.pointerEvents = open ? 'auto' : 'none'; 130 openBtn?.setAttribute('aria-expanded', String(open)); 131 chat?.classList.toggle('sorteo-open', open); 132 133 const inputEl = document.getElementById('bot-input'); 134 if (inputEl) { 135 if (open) { inputEl.setAttribute('disabled','disabled'); inputEl.blur(); } 136 else { inputEl.removeAttribute('disabled'); } 137 } 138 139 const body = overlay.querySelector('.cs-body'); 140 141 if (open) { 142 // limpiar banners residuales (p.ej., âya estás participandoâ) 143 window.bot_UI?.clearBanner?.(); 144 145 // reset de scroll para que no quede âcorridoâ 146 try { overlay.scrollTop = 0; } catch(_) {} 147 try { body?.scrollTo?.({ top: 0 }); } catch(_) {} 148 149 // anti-rebote: si no hay contenido para scroll, ocultar overflow 150 if (body) { 151 const noScroll = body.scrollHeight <= body.clientHeight + 1; 152 body.style.overflow = noScroll ? 'hidden' : 'auto'; 153 } 154 155 setTimeout(resetVideoPoster, 0); 156 } else { 157 document.getElementById('cs-video')?.pause?.(); 158 159 // limpiar overlays secundarios al cerrar 160 document.getElementById('bot_overlay_prizes')?.remove(); 161 document.getElementById('bot_host_overlay_form')?.remove(); 162 document.getElementById('bot_golden_ticket')?.remove(); 163 164 // limpiar banners y restaurar overflow para la próxima apertura 165 window.bot_UI?.clearBanner?.(); 166 if (body) body.style.overflow = ''; 167 168 setTimeout(()=> chatInput?.focus(), 140); 169 } 170} 171 setSorteoOpen(false); 172 173 openBtn?.addEventListener('click', (e)=>{ 174 e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); 175 if (!overlay) return; 176 setSorteoOpen(!overlay.classList.contains('open')); 177 }, true); 178 179 // X de overlay (captura, blindada) 180 const csClose = document.getElementById('cs-close'); 181 ['click','pointerup','touchend'].forEach(evt=>{ 182 csClose?.addEventListener(evt, (e)=>{ 183 e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); 184 setSorteoOpen(false); 185 }, { capture:true, passive:false }); 186 }); 187 188 // Navegación interna (video y bases) 189 overlay?.addEventListener('click', (e)=>{ 190 const btn = e.target.closest?.('[data-go]'); 191 if (!btn) return; 192 const v = btn.dataset.go; 193 194 if (v === 'video') { 195 const scroller = overlay.querySelector('.cs-body'); 196 const media = overlay.querySelector('.cs-media'); 197 if (scroller && media) { 198 const top = media.offsetTop - 8; 199 scroller.scrollTo({ top, behavior: 'smooth' }); 200 } 201 const vid = document.getElementById('cs-video'); 202 if (vid) { vid.muted = true; vid.play().catch(()=>{}); } 203 return; 204 } 205 if (v === 'bases') { 206 try { window.open(BASES_PDF_URL, '_blank', 'noopener,noreferrer'); } 207 catch(_) { location.href = BASES_PDF_URL; } 208 return; 209 } 210 }, true); 211 212 botAccions.init('btnSecciones', 'seccionesPopover', 'closeSecciones'); 213 botAccions.init('btnSecciones-mobile', 'seccionesPopover', 'closeSecciones'); 214 botAccions.init('btnFAQ', 'seccionesPopoverFAQ', 'closeSeccionesFAQ'); 215 botAccions.init('btnFAQ-mobile', 'seccionesPopoverFAQ', 'closeSeccionesFAQ'); 216 botAccions.init('btnFixture', 'FixturePopover', 'closeFixture'); 217 botAccions.init('btnFixture-mobile', 'FixturePopover', 'closeSecciones'); 218 botAccions.init('btnProximo', 'ProximoPopover', 'closeProximo'); 219 botAccions.init('btnProximo-mobile', 'ProximoPopover', 'closeSecciones'); 220 botAccions.init('btnHamburger', 'mobileMenuDropdown', 'closeMenu'); 221 botAccions.initDetails(); 222}); 223 224 225var botAccions = { 226 init: (btnId, popoverId, closeId)=> { 227 const btn = document.getElementById(btnId); 228 const pop = document.getElementById(popoverId); 229 const closeBtn = document.getElementById(closeId); 230 231 // â GUARD: si no existe en esta página, no rompas todo el JS 232 if (!btn || !pop) { 233 console.log("ð [FAQ] init skip (faltan nodos):", { btnId, popoverId, closeId, btn: !!btn, pop: !!pop }); 234 return; 235 } 236 237 botAccions.addEvents(btn, closeBtn, pop); 238 }, 239 ismobile: () => { 240 return window.innerWidth <= 520; 241 }, 242 placePopover: (btn, pop) => { 243 const r = btn.getBoundingClientRect(); 244 const popW = pop.offsetWidth || 360; 245 const margin = 10; 246 247 // Posición por defecto: debajo del botón 248 let left = r.left + window.scrollX; 249 let top = r.bottom + window.scrollY - 25; 250 251 if(botAccions.ismobile()){ 252 // Posición por defecto: a la derecha del botón 253 left = left + 10; 254 top = top - 50; 255 } 256 257 // Evitar que se salga por la derecha 258 const maxLeft = window.scrollX + document.documentElement.clientWidth - popW - margin; 259 left = Math.min(left, maxLeft); 260 left = Math.max(left, window.scrollX + margin); 261 262 pop.style.left = `${left}px`; 263 pop.style.top = `${top}px`; 264 }, 265 openPopover: (btn, pop, closeBtn) => { 266 if (!btn || !pop) return; 267 botAccions.placePopover(btn, pop, closeBtn); 268 pop.classList.add('is-open'); 269 pop.setAttribute('aria-hidden', 'false'); 270 }, 271 closePopover: (pop) => { 272 pop.classList.remove('is-open'); 273 pop.setAttribute('aria-hidden', 'true'); 274 botAccions.closeMobilemenu(); 275 }, 276 setBotTextValue: (text) => { 277 const inputEl = document.getElementById('bot-input'); 278 if (!inputEl) return; 279 inputEl.value = text; 280 //bot-send 281 const sendBtn = document.getElementById('bot-send'); 282 sendBtn?.click(); 283 }, 284 closeAllPopovers: () => { 285 const popovers = document.querySelectorAll('.cuervo-popover.is-open');
286 popovers.forEach(pop => botAccions.closePopover(pop)); 287 }, 288 addEvents: (btn, closeBtn, pop)=> { 289 if (!btn || !pop) { 290 console.log("ð [FAQ] addEvents skip (btn/pop null)", { btn: !!btn, pop: !!pop }); 291 return; 292 } 293 294 btn.addEventListener('click', (e) => { 295 e.preventDefault(); 296 e.stopPropagation(); 297 e.stopImmediatePropagation(); 298 299 const wasOpen = pop.classList.contains('is-open'); 300 301 // cerrá todos los demás 302 botAccions.closeAllPopovers(); 303 304 // toggle del actual 305 if (wasOpen) botAccions.closePopover(pop); 306 else botAccions.openPopover(btn, pop, closeBtn); 307 308 }, true); // ð CAPTURE 309 310 closeBtn?.addEventListener('click', (e) => { 311 e.stopPropagation(); 312 botAccions.closePopover(pop); 313 }); 314 315 // Click afuera 316 document.addEventListener('click', (e) => { 317 if (!pop.classList.contains('is-open')) return; 318 if (pop.contains(e.target) || btn.contains(e.target)) return; 319 botAccions.closePopover(pop); 320 }); 321 322 // ESC 323 document.addEventListener('keydown', (e) => { 324 if (e.key === 'Escape') botAccions.closePopover(pop); 325 }); 326 327 // Reposicionar si cambia el viewport 328 window.addEventListener('resize', () => { 329 if (pop.classList.contains('is-open')) botAccions.placePopover(btn, pop); 330 }); 331 332 // Acción al tocar una sección 333 pop.addEventListener('click', (e) => { 334 const item = e.target.closest('.cuervo-item'); 335 if (!item) return; 336 337 const section = item.dataset.section; 338 botAccions.closePopover(pop); 339 340 // ð Integración: acá disparás tu lógica 341 // Ejemplo: enviar al chat / abrir módulo / navegar 342 console.log('Sección elegida:', section); 343 344 botAccions.setBotTextValue(section); 345 346 // Si usás una función de tu bot: 347 // window.CuervoIA?.openSection?.(section); 348 //bot-input 349 }); 350 351 //add option to handle error forms. 352 const formType = document.getElementById('faqcTipo'); 353 if(formType){ 354 formType.addEventListener('change', (e) => { 355 const selectedValue = e.target.value; 356 botAccions.hideForms(); 357 const formToShow = document.getElementById(`form${selectedValue.charAt(0).toUpperCase() + selectedValue.slice(1)}`);; 358 if(formToShow){ 359 formToShow.style.display = 'block'; 360 } 361 }); 362 363 const forms = { 364 error: document.querySelector('#formError'), 365 mejora: document.querySelector('#formMejora'), 366 colaborar: document.querySelector('#formColaborar'), 367 juego: document.querySelector('#formJuego') 368 }; 369 const toast = document.getElementById("faqcToast") || document.getElementById("faqToast"); 370 371 /* 372 Object.values(forms).forEach(f=>{ 373 f?.addEventListener('submit', (e)=>{ 374 e.preventDefault(); 375 if (toast){ 376 toast.textContent='¡Listo! Gracias por tu aporte ðâ¤ï¸'; 377 toast.setAttribute('aria-hidden','false'); 378 setTimeout(()=> toast.setAttribute('aria-hidden','true'), 2200); 379 } 380 e.target.reset(); 381 }, true); 382 }); 383 */ 384 } 385 }, 386 hideForms: () => { 387 const forms = document.querySelectorAll('.faqc-form'); 388 forms.forEach(form => { 389 form.style.display = 'none'; 390 } 391 ); 392 }, 393 initDetails: () => { 394 const detailButtons = document.querySelectorAll('.showDetail'); 395 detailButtons.forEach(button => { 396 button.addEventListener('click', (e) => { 397 const isExpanded = button.getAttribute('aria-expanded') === 'true'; 398 399 button.setAttribute('aria-expanded', String(!isExpanded)); 400 const detailPanel = button.nextElementSibling; 401 if (detailPanel) { 402 detailPanel.classList.add('visible'); 403 detailPanel.classList.remove('hidden'); 404 } 405 botAccions.hideAllDetails(button.getAttribute('data-action')); 406 407 }); 408 }); 409 }, hideAllDetails: (currentButton) => { 410 const detailPanels = document.querySelectorAll('.detailed-answer');
411 detailPanels.forEach(panel => { 412 const panelFor = panel.getAttribute('data-for'); 413 if(panelFor === currentButton) return; 414 panel.classList.add('hidden'); 415 panel.classList.remove('visible'); 416 } 417 ); 418 }, 419 closeMobilemenu: () => { 420 const mobileMenu = document.getElementById('mobileMenuDropdown'); 421 if (mobileMenu && mobileMenu.classList.contains('is-open')) { 422 mobileMenu.classList.remove('is-open'); 423 mobileMenu.setAttribute('aria-hidden', 'true'); 424 } 425 } 426 427}; 428 429(() => { 430 // Bloqueo selectpicker SOLO para #faqcTipo 431 try{ 432 const $ = window.jQuery || window.$; 433 if ($?.fn?.selectpicker){ 434 const _orig = $.fn.selectpicker; 435 $.fn.selectpicker = function(...args){ 436 const tocaFaq = (this.is?.('#faqcTipo')) || (this.find?.('#faqcTipo').length>0); 437 if (tocaFaq) return this; // no lo âenchufesâ 438 return _orig.apply(this, args); 439 }; 440 } 441 }catch{} 442 443 const $ = (s, r=document) => r.querySelector(s); 444 445 // Tomar SIEMPRE el último #faqcOverlay y subirlo al <body> (evita stacking raros) 446 const overlays = Array.from(document.querySelectorAll('#seccionesPopoverFAQ')); 447 if (!overlays.length){ console.warn('[FAQ] No encontré #seccionesPopoverFAQ'); return; } 448 const overlay = overlays[overlays.length - 1]; 449 const panel = overlay.querySelector('.faqc-panel'); 450 451 function pinToTop(){ 452 try{ if (overlay.parentNode !== document.body) document.body.appendChild(overlay); }catch(_){} 453 (panel || overlay).setAttribute('tabindex','-1'); // foco para ESC 454 } 455 pinToTop(); 456 // re-pin suave por si otros scripts inyectan cosas encima 457 { let n=0; const iv=setInterval(()=>{ pinToTop(); if(++n>12) clearInterval(iv); },150); setTimeout(()=>clearInterval(iv),2500); } 458 459 // Estado inicial 460 overlay.setAttribute('aria-hidden','true'); 461 462 // Triggers 463 const btnOpenMain = $('#faqcOpen'); // botón grande (fuera del chat) 464 const btnOpenHeader = $('#bot-faq-btn'); // botón del header del chat (si existe) 465 const btnClose = $('#faqcClose'); // X del panel 466 const toast = $('#faqcToast'); 467 468 function detoxFaqcTipo(){ 469 const tipo = document.querySelector('#faqcOverlay #faqcTipo'); 470 if (!tipo) return; 471 const wrap = tipo.nextElementSibling; 472 if (wrap?.classList?.contains('bootstrap-select')){ 473 wrap.remove(); 474 tipo.classList.remove('bs-select-hidden'); 475 tipo.style.display = 'block'; 476 } 477 } 478 479 function openFAQ(e){ 480 if(e){ e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation?.(); } 481 pinToTop(); 482 overlay.setAttribute('aria-hidden','false'); 483 detoxFaqcTipo(); 484 if (!openFAQ._bsIv) openFAQ._bsIv = setInterval(detoxFaqcTipo, 400); 485 document.body.classList.add('faqc-open'); 486 (panel || overlay).focus?.(); 487 if(!openFAQ._iv){ openFAQ._iv=setInterval(pinToTop,300); } 488 } 489 function closeFAQ(e){ 490 if(e){ e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation?.(); } 491 overlay.setAttribute('aria-hidden','true'); 492 document.body.classList.remove('faqc-open'); 493 if(openFAQ._iv){ clearInterval(openFAQ._iv); openFAQ._iv=null; } 494 if (openFAQ._bsIv){ clearInterval(openFAQ._bsIv); openFAQ._bsIv = null; } 495 } 496 497 // Binds (en captura, para ganar a listeners del theme) 498 btnOpenMain ?.addEventListener('click', openFAQ, true); 499 btnOpenHeader ?.addEventListener('click', openFAQ, true); 500 btnClose ?.addEventListener('click', closeFAQ, true); 501 overlay.addEventListener('click', e=>{ if(e.target===overlay) closeFAQ(e); }, true); 502 document.addEventListener('keydown', e=>{ if(e.key==='Escape' && overlay.getAttribute('aria-hidden')==='false') closeFAQ(e); }, true); 503 504 // Acordeones 505 overlay.addEventListener('click', (e)=>{ 506 const btn = e.target.closest?.('[data-acc]'); if(!btn) return; 507 btn.type='button'; 508 const acc = btn.closest('.faqc-acc'); if(!acc) return; 509 const ex = acc.getAttribute('aria-expanded')==='true'; 510 acc.setAttribute('aria-expanded', String(!ex)); 511 }, true); 512 513 // Selector de tipo (muestra cada form) 514 const tipo = overlay.querySelector('#faqcTipo'); 515 // --- Anti bootstrap-select: forzar el <select> nativo en este acordeón --- 516 if (tipo && tipo.nextElementSibling && tipo.nextElementSibling.classList.contains('bootstrap-select')) { 517 tipo.nextElementSibling.remove(); // saca el wrapper del plugin 518 tipo.classList.remove('bs-select-hidden'); // muestra el <select> real 519 tipo.style.display = 'block'; 520 } 521 522 const forms = { 523 error: overlay.querySelector('#formError'), 524 mejora: overlay.querySelector('#formMejora'), 525 colaborar: overlay.querySelector('#formColab'), 526 juego: overlay.querySelector('#formJuego') 527 }; 528 function show(kind){
529 Object.keys(forms).forEach(k=>{ if(forms[k]) forms[k].style.display = (k===kind?'block':'none'); }); 530 } 531 if (tipo){ 532 tipo.addEventListener('change', e=> show(e.target.value)); show(tipo.value || 'error'); 533 } 534 535 overlay.addEventListener('click', e => { 536 if (e.target.closest('.faqc-btn--pri')) { 537 const t = document.getElementById('faqcToast'); 538 if (t) { t.setAttribute('aria-hidden','false'); setTimeout(()=>t.setAttribute('aria-hidden','true'), 2200); } 539 } 540 }, true); 541 542 // Helpers consola 543 window.FAQ_OPEN = () => openFAQ(); 544 window.FAQ_CLOSE = () => closeFAQ(); 545 546 console.log('[FAQ] listo (estética + fix). Duplicados:', overlays.length); 547 548})(); 549 550// â [FAQ] Listener GLOBAL: siempre captura submit de los forms del FAQ 551document.addEventListener("submit", async (e) => { 552 const form = e.target.closest(".faqc-form"); 553 if (!form) return; 554 555 e.preventDefault(); 556 557 console.log("ð [FAQ] submit capturado", form); 558 559 const kind = form.getAttribute("data-kind") || ""; 560 const formData = new FormData(form); 561 const payload = { kind }; 562 563 formData.forEach((value, key) => { 564 payload[key] = value; 565 }); 566 567 console.log("ð [FAQ] payload", payload); 568 569 try { 570 const res = await fetch("https://casla-rag-service.onrender.com/faqc-submit", { 571 method: "POST", 572 headers: { "Content-Type": "application/json" }, 573 body: JSON.stringify(payload), 574 }); 575 576 console.log("ð [FAQ] backend status", res.status); 577 578 if (!res.ok) throw new Error("HTTP " + res.status); 579 580 const toast = document.getElementById("faqcToast"); 581 if (toast) { 582 toast.textContent = "¡Listo! Gracias por tu aporte ðâ¤ï¸"; 583 toast.setAttribute("aria-hidden", "false"); 584 setTimeout(() => toast.setAttribute("aria-hidden", "true"), 2200); 585 } 586 587 form.reset(); 588 } catch (err) { 589 console.error("ð [FAQ] error enviando", err); 590 alert("â Falló el envÃo. Intentá de nuevo."); 591 } 592}, true); 593 594 595// ð¬ FUNCIONES DE ACLARACIÃN IA 596 function getClarification(length) { 597 const short = [ 598 "Soy una IA ð¤, y a veces me puedo equivocar. ¡Chequeá la info!", 599 "Atención, soy IA ð. Puedo pifiarla. Verificá si algo suena raro.", 600 ]; 601 const medium = [ 602 "Ojo, soy una IA ð¤. Trato de ayudar, pero no siempre acierto. Contrastá los datos si tenés dudas.", 603 "Soy IA y me esfuerzo por responder bien, pero no soy infalible ð. Lo único que tengo seguro es el ðâ¤ï¸ por el Ciclón.", 604 ]; 605 const long = [ 606 "¡Hola! Soy una IA ð¤ y aunque intento darte la mejor respuesta posible, puedo fallar. Contrastá la info y avisame si hay errores. Mi amor por San Lorenzo es 100% real ðâ¤ï¸.", 607 "¿Me creés todo? Ojo, soy una IA ð¤ y a veces meto la pata. Verificá siempre. Lo único que no dudo es que banco al Ciclón a muerte ðµð´.", 608 ]; 609 610 let pool = short; 611 if (length > 300) pool = long; 612 else if (length > 150) pool = medium; 613 614 return pool[Math.floor(Math.random() * pool.length)]; 615 }
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.