PageSourceSearch

https://www.vitisport.cz/viti-chat-okno.js?v=8

js vitisport.cz collected 2026-10-05 01:11:00 UTC 20,585 bytes, 362 lines download raw bytes

1/**
2 * viti-chat-okno.js – CHAT VITI (verze 2: samostatná stránka)
3 *
4 * Načítá se jen přihlášeným, kterým je Viti povolený (viti_login_widget).
5 *  - Na běžných stránkách: plovoucí bublina "Zeptej se Vitiho" = odkaz na
6 *    stránku Viti (na detailu zápasu i s tímto zápasem).
7 *  - Na stránce Viti (#viti-stranka, viti.php): celý chat v layoutu webu.
8 *    U každé nové odpovědi se vloží reklama AdSense – vždy NOVÁ jednotka
9 *    po otázce uživatele (žádné obnovování), mezi otázku a odpověď, tedy
10 *    daleko od pole pro psaní.
11 */
12(function () {
13  'use strict';
14  var C = window.VITI_CHAT || {};
15  var T = C.t || {};
16  var STRANKA = document.getElementById('viti-stranka');
17  if (!C.csrf && !C.anon) { return; }
18  if (C.anon) { STRANKA = null; }                    // nepřihlášený: jen bublina = pozvánka
19  if (/[?&]clanek=viti(&|$)/.test(location.search) && !STRANKA) { return; }   // na stránce Viti bez chatu žádná bublina
20
21  // Detail zápasu: sport a ID z adresy
22  var DET = (function () {
23    var q = new URLSearchParams(location.search);
24    var mapa = { 'match-detail': 'fotbal', 'hokej-match-detail': 'hokej', 'basket-match-detail': 'basket',
25                 'hazena-match-detail': 'hazena', 'baseball-match-detail': 'baseball' };
26    var sp = mapa[q.get('clanek') || ''], fid = q.get('fixture_id');
27    return (sp && fid && /^\d+$/.test(fid)) ? { sport: sp, fid: fid } : null;
28  })();
29
30  var css = document.createElement('style');
31  css.textContent =
32    '#vc-bublina{position:fixed;right:16px;bottom:44px;z-index:99980;display:flex;align-items:center;gap:8px;background:#123698;color:#fff!important;text-decoration:none!important;border-top:3px solid #38bdf8;border-radius:999px;padding:11px 16px 11px 12px;font-weight:700;font-size:14px;line-height:1;font-family:inherit;box-shadow:0 8px 24px rgba(18,54,152,.4)}' +
33    '#vc-bublina .vc-ava{width:26px;height:26px;border-radius:50%;background:#38bdf8;color:#0a2368;display:flex;align-items:center;justify-content:center;font-weight:900;font-size:14px}' +
34    '#vc-bublina .vc-min{margin-left:4px;margin-right:-6px;width:20px;height:20px;border-radius:50%;background:rgba(255,255,255,.18);color:#fff;display:flex;align-items:center;justify-content:center;font-size:15px;line-height:1;font-weight:700;cursor:pointer}' +
35    '#vc-bublina .vc-min:hover{background:rgba(255,255,255,.32)}' +
36    '#vc-bublina.vc-mini{padding:6px;gap:0;opacity:.85;border-top-width:2px}' +
37    '#vc-bublina.vc-mini:hover{opacity:1}' +
38    '#vc-bublina.vc-mini .vc-txt,#vc-bublina.vc-mini .vc-min{display:none}' +
39    '@media (max-width:600px){#vc-bublina{bottom:104px;right:12px;padding:10px 14px 10px 10px;font-size:13px}}' +
40    '.vc-chat{margin-top:14px;background:#f5f7fb;border:1px solid #e2e8f0;border-radius:10px;overflow:hidden}' +
41    '.vc-stav{padding:0 2px 8px;font-size:12px;color:#475569}' +
42    '.vc-stav .vc-pocet.vc-vycerpano{color:#c2410c;font-weight:700}' +
43    '.vc-zpravy{padding:14px;display:flex;flex-direction:column;gap:10px;min-height:160px}' +
44    '.vc-z{max-width:88%;padding:10px 13px;border-radius:12px;font-size:14.5px;line-height:1.5;word-wrap:break-word}' +
45    '.vc-z.vc-a{background:#fff;border:1px solid #e2e8f0;align-self:flex-start;border-top-left-radius:4px}' +
46    '.vc-z.vc-u{background:#123698;color:#fff;align-self:flex-end;border-top-right-radius:4px}' +
47    '.vc-z ul{margin:4px 0;padding-left:18px}.vc-z li{margin:2px 0}.vc-z a{color:#1d4ed8}' +
48    '.vc-zdroje{margin-top:6px;padding-top:6px;border-top:1px solid #eef2f7;font-size:12px}' +
49    '.vc-zdroje a{display:block;color:#475569;text-decoration:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}' +
50    '.vc-pise{font-size:13px;color:#64748b;font-style:italic;align-self:flex-start}' +
51    '.vc-chipy{display:flex;flex-wrap:wrap;gap:6px}' +
52    '.vc-chip{background:#fff;border:1px solid #bfdbfe;color:#123698;border-radius:999px;padding:7px 12px;font-size:13px;font-weight:700;cursor:pointer;font-family:inherit}' +
53    '.vc-chip:hover{background:#eff6ff}' +
54    '.vc-info{font-size:13px;color:#9a3412;background:#fff7ed;border:1px solid #fed7aa;border-radius:8px;padding:9px 11px}' +
55    '.vc-rek{align-self:stretch;text-align:center;margin:6px 0;min-height:90px}' +
56    '.vc-rek span{display:block;font-size:10px;letter-spacing:.5px;text-transform:uppercase;color:#94a3b8;margin-bottom:3px}' +
57    '.vc-dole{position:sticky;bottom:0;border-top:1px solid #e2e8f0;padding:10px;background:#fff}' +
58    '.vc-radek{display:flex;gap:8px;align-items:flex-end}' +
59    '.vc-radek textarea{flex:1;resize:none;border:1px solid #cbd5e1;border-radius:10px;padding:10px 12px;font-size:15px;font-family:inherit;max-height:120px;min-height:44px;line-height:1.35}' +
60    '.vc-radek textarea:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px rgba(59,130,246,.15)}' +
61    '.vc-radek button{background:#123698;color:#fff;border:0;border-radius:10px;padding:0 16px;height:44px;font-weight:800;cursor:pointer;font-family:inherit}' +
62    '.vc-radek button:disabled,.vc-radek textarea:disabled{opacity:.5;cursor:not-allowed}' +
63    '.vc-pozn{font-size:11px;color:#94a3b8;margin-top:6px;text-align:center}' +
64    '.vc-stav{display:flex;align-items:center;justify-content:space-between;gap:10px}' +
65    '.vc-nova{background:none;border:1px solid #bfdbfe;color:#123698;border-radius:6px;padding:4px 10px;font-size:12px;font-weight:700;cursor:pointer;font-family:inherit}' +
66    '.vc-nova:hover{background:#eff6ff}' +
67    '.vc-archiv{margin-top:12px;background:#fff;border:1px solid #e2e8f0;border-radius:10px}' +
68    '.vc-archiv>summary{padding:10px 14px;cursor:pointer;font-weight:700;font-size:13.5px;color:#334155;list-style:none}' +
69    '.vc-archiv>summary::-webkit-details-marker{display:none}' +
70    '.vc-vl{border-top:1px solid #eef2f7}' +
71    '.vc-vl>summary{padding:9px 14px;cursor:pointer;font-size:13px;color:#475569;list-style:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}' +
72    '.vc-vl>summary::-webkit-details-marker{display:none}' +
73    '.vc-vl>summary b{color:#0f172a;margin-right:6px}' +
74    '.vc-vl .vc-zpravy{background:#f8fafc;min-height:0}';
75  document.head.appendChild(css);
76
77  // ================================================================== BUBLINA
78  if (!STRANKA) {
79    var url = C.url || ('/index.php?clanek=viti&lang=' + encodeURIComponent(C.lang || ''));
80    if (DET) { url += '&sport=' + DET.sport + '&fixture_id=' + DET.fid; }
81    var a = document.createElement('a');
82    a.id = 'vc-bublina'; a.href = url; a.rel = 'nofollow';
83    a.innerHTML = '<span class="vc-ava">V</span><span class="vc-txt"></span><span class="vc-min" role="button" aria-label="–">–</span>';
84    a.querySelector('.vc-txt').textContent = DET ? (T.q3 || T.bublina) : (T.bublina || 'Ask Viti');
85    a.title = T.bublina || 'Viti';
86    // Zmenšení na malé kolečko „V“ (zapamatuje se v prohlížeči); kolečko dál vede na stránku Viti
87    var mini = false;
88    try { mini = localStorage.getItem('viti_bublina') === 'mini'; } catch (e) {}
89    if (mini) { a.classList.add('vc-mini'); }
90    a.querySelector('.vc-min').addEventListener('click', function (e) {
91      e.preventDefault(); e.stopPropagation();
92      a.classList.add('vc-mini');
93      try { localStorage.setItem('viti_bublina', 'mini'); } catch (er) {}
94    });
95    document.body.appendChild(a);
96    return;
97  }
98
99  // ================================================================== STRÁNKA VITI
100  var KONTEXT = STRANKA.getAttribute('data-fid') ? { sport: STRANKA.getAttribute('data-sport'), fid: STRANKA.getAttribute('data-fid') } : null;
101  var REKLAMY = STRANKA.getAttribute('data-reklamy') === '1' && !!STRANKA.getAttribute('data-slot');
102  var MAX_REKLAM = 5, reklam = 0;
103
104  // Vlákna: aktuální = zprávy z posledních 3 h novější než "Nová konverzace"
105  // (viti_od_id v localStorage). Starší zprávy (7 dní, z DB) = archiv – jen
106  // k přečtení, bez volání AI. Viti si pamatuje jen aktuální vlákno.
107  var VLAKNO_MS = 3 * 3600 * 1000;
108  var odId = 0;
109  try { odId = parseInt(localStorage.getItem('viti_od_id') || '0', 10) || 0; } catch (e) {}
110  var vse = [];          // {id, ts, v_okne, otazka, odpoved, zdroje}
111  var hist = [];         // aktuální vlákno ve tvaru {r, t, z}
112  var zbyva = null, dalsi = null, limit = null, odesila = false, nacteno = false;
113  function ulozHist() {}
114
115  var archivEl = document.createElement('div');
116  STRANKA.parentNode.insertBefore(archivEl, STRANKA);
117
118  STRANKA.innerHTML =
119    '<div class="vc-chat"><div class="vc-zpravy"></div>' +
120    '<div class="vc-dole"><div class="vc-stav"><span class="vc-pocet"></span><button type="button" class="vc-nova"></button></div><div class="vc-radek"><textarea rows="1" maxlength="1000"></textarea><button type="button" class="vc-poslat"></button></div>' +
121    '<div class="vc-pozn"></div></div></div>';
122  var zpravyEl = STRANKA.querySelector('.vc-zpravy');
123  var pole = STRANKA.querySelector('textarea');
124  var tlacitko = STRANKA.querySelector('.vc-poslat');
125  var stavEl = STRANKA.querySelector('.vc-pocet');
126  var novaBtn = STRANKA.querySelector('.vc-nova');
127  novaBtn.textContent = '+ ' + (T.nova || 'New');
128  novaBtn.style.display = 'none';
129  tlacitko.textContent = T.odeslat || 'Send';
130  pole.placeholder = T.ph || '';
131  STRANKA.querySelector('.vc-pozn').textContent = T.pozn || '';
132
133  function esc(s) { return String(s).replace(/[&<>"']/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]; }); }
134  function formatuj(text) {
135    var radky = esc(text).split(/\n/), html = '', vSeznamu = false;
136    for (var i = 0; i < radky.length; i++) {
137      var r = radky[i], m = r.match(/^\s*[-•]\s+(.*)$/);
138      if (m) { if (!vSeznamu) { html += '<ul>'; vSeznamu = true; } html += '<li>' + m[1] + '</li>'; continue; }
139      if (vSeznamu) { html += '</ul>'; vSeznamu = false; }
140      html += (r.trim() === '' ? '' : r + '<br>');
141    }
142    if (vSeznamu) { html += '</ul>'; }
143    html = html.replace(/\*\*(.+?)\*\*/g, '<b>$1</b>');
144    html = html.replace(/(https?:\/\/[^\s<)]+)/g, '<a href="$1" target="_blank" rel="noopener nofollow">$1</a>');
145    html = html.replace(/(^|[\s(])(\/index\.php\?[^\s<)]+)/g, '$1<a href="$2">$2</a>');
146    return html.replace(/(<br>)+$/, '');
147  }
148  function bublinaZpravy(m) {
149    var d = document.createElement('div');
150    d.className = 'vc-z ' + (m.r === 'u' ? 'vc-u' : 'vc-a');
151    if (m.r === 'u') { d.textContent = m.t; } else { d.innerHTML = formatuj(m.t); }
152    if (m.z && m.z.length) {
153      var z = document.createElement('div'); z.className = 'vc-zdroje';
154      z.appendChild(document.createTextNode((T.zdroje || 'Sources') + ':'));
155      m.z.forEach(function (s) {
156        var l = document.createElement('a'); l.href = s.url; l.target = '_blank'; l.rel = 'noopener nofollow';
157        l.textContent = '🔗 ' + (s.titulek || s.url); z.appendChild(l);
158      });
159      d.appendChild(z);
160    }
161    return d;
162  }
163  function cas(iso) {
164    var d = new Date(iso);
165    // datum + čas (např. 5. 10. 21:34) – u plovoucích 24 h to bývá často až zítra
166    return isNaN(d) ? (iso || '') : d.toLocaleString(C.locale || undefined, { day: 'numeric', month: 'numeric', hour: '2-digit', minute: '2-digit' });
167  }
168  function infoLimit() {
169    var info = document.createElement('div'); info.className = 'vc-info';
170    info.textContent = (T.limit || '').replace('{cas}', cas(dalsi));
171    return info;
172  }
173  function ovladani() {
174    var zamceno = odesila || zbyva === 0;
175    pole.disabled = zamceno; tlacitko.disabled = zamceno;
176    // Lišta nad polem pro otázku (je vidět i u dlouhého chatu):
177    // zbývá X z Y otázek za plovoucích 24 h, po vyčerpání čas další otázky
178    var vycerpano = zbyva === 0 && dalsi;
179    stavEl.classList.toggle('vc-vycerpano', !!vycerpano);
180    stavEl.textContent = vycerpano ? (T.limit || '').replace('{cas}', cas(dalsi))
181      : (zbyva === null) ? '' : (T.zbyva || '').replace('{n}', limit !== null ? zbyva + ' / ' + limit : zbyva) + ' · 24 h';
182    novaBtn.style.display = hist.length ? '' : 'none';
183  }
184
185  // Rozdělení zpráv na aktuální vlákno a archiv (podle mezery > 3 h a "Nová konverzace")
186  function rozdel() {
187    var ted = Date.now(), akt = [], arch = [];
188    for (var i = vse.length - 1; i >= 0; i--) {
189      var m = vse[i];
190      var navazuje = !akt.length ? (ted - m.ts * 1000 < VLAKNO_MS) : (akt[0].ts - m.ts) * 1000 < VLAKNO_MS;
191      if (m.id > odId && navazuje && arch.length === 0) { akt.unshift(m); } else { arch.unshift(m); }
192    }
193    var vlakna = [], cur = null;
194    arch.forEach(function (m) {
195      if (!cur || (m.ts - cur[cur.length - 1].ts) * 1000 >= VLAKNO_MS || (cur[cur.length - 1].id <= odId && m.id > odId)) {
196        cur = []; vlakna.push(cur);
197      }
198      cur.push(m);
199    });
200    hist = [];
201    akt.forEach(function (m) { hist.push({ r: 'u', t: m.otazka }); hist.push({ r: 'a', t: m.odpoved, z: m.zdroje || [] }); });
202    return vlakna.reverse();                         // nejnovější nahoře
203  }
204
205  function vykresliArchiv(vlakna) {
206    archivEl.innerHTML = '';
207    if (!vlakna.length) { return; }
208    var det = document.createElement('details'); det.className = 'vc-archiv';
209    var sum = document.createElement('summary'); sum.textContent = '🕘 ' + (T.predchozi || 'History') + ' (' + vlakna.length + ')';
210    det.appendChild(sum);
211    vlakna.forEach(function (v) {
212      var d = document.createElement('details'); d.className = 'vc-vl';
213      var s2 = document.createElement('summary');
214      var b = document.createElement('b');
215      b.textContent = new Date(v[0].ts * 1000).toLocaleString(C.locale || undefined, { day: 'numeric', month: 'numeric', hour: '2-digit', minute: '2-digit' });
216      s2.appendChild(b); s2.appendChild(document.createTextNode(v[0].otazka));
217      d.appendChild(s2);
218      var z = document.createElement('div'); z.className = 'vc-zpravy';
219      v.forEach(function (m) {
220        z.appendChild(bublinaZpravy({ r: 'u', t: m.otazka }));
221        z.appendChild(bublinaZpravy({ r: 'a', t: m.odpoved, z: m.zdroje || [] }));
222      });
223      d.appendChild(z); det.appendChild(d);
224    });
225    archivEl.appendChild(det);
226  }
227
228  novaBtn.addEventListener('click', function () {
229    if (odesila || !vse.length) { return; }
230    odId = vse[vse.length - 1].id;
231    try { localStorage.setItem('viti_od_id', String(odId)); } catch (e) {}
232    vykresliArchiv(rozdel()); vykresli();
233  });
234
235  // Reklama: nová jednotka AdSense (nikdy obnova stávající)
236  function vlozReklamu(za) {
237    if (!REKLAMY || reklam >= MAX_REKLAM || !za) { return; }
238    reklam++;
239    if (!document.querySelector('script[src*="adsbygoogle.js"]')) {
240      var s = document.createElement('script'); s.async = true; s.crossOrigin = 'anonymous';
241      s.src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=' + STRANKA.getAttribute('data-client');
242      document.head.appendChild(s);
243    }
244    var box = document.createElement('div'); box.className = 'vc-rek';
245    var l = document.createElement('span'); l.textContent = T.reklama || 'Ad';
246    var ins = document.createElement('ins');
247    ins.className = 'adsbygoogle'; ins.style.display = 'block';
248    ins.setAttribute('data-ad-client', STRANKA.getAttribute('data-client'));
249    ins.setAttribute('data-ad-slot', STRANKA.getAttribute('data-slot'));
250    ins.setAttribute('data-ad-format', 'auto');
251    ins.setAttribute('data-full-width-responsive', 'true');
252    box.appendChild(l); box.appendChild(ins);
253    za.parentNode.insertBefore(box, za.nextSibling);
254    try { (window.adsbygoogle = window.adsbygoogle || []).push({}); } catch (e) {}
255  }
256
257  // Úvodní vykreslení (historie z této návštěvy + rychlé volby)
258  function vykresli() {
259    zpravyEl.innerHTML = '';
260    zpravyEl.appendChild(bublinaZpravy({ r: 'a', t: T.uvod || 'Hi!' }));
261    hist.forEach(function (m) { zpravyEl.appendChild(bublinaZpravy(m)); });
262    if (!hist.length || KONTEXT) {
263      var ch = document.createElement('div'); ch.className = 'vc-chipy';
264      (KONTEXT ? [T.q3, T.q2] : [T.q1, T.q2]).forEach(function (q) {
265        if (!q) { return; }
266        var b = document.createElement('button'); b.type = 'button'; b.className = 'vc-chip'; b.textContent = q;
267        b.addEventListener('click', function () { ch.remove(); posli(q); });
268        ch.appendChild(b);
269      });
270      zpravyEl.appendChild(ch);
271    }
272    if (zbyva === 0 && dalsi) { zpravyEl.appendChild(infoLimit()); }
273    ovladani();
274  }
275
276  function api(telo) {
277    return fetch('/viti-chat.php', {
278      method: 'POST', credentials: 'same-origin',
279      headers: { 'Content-Type': 'application/json', 'X-Viti-Csrf': C.csrf },
280      body: JSON.stringify(telo)
281    }).then(function (r) { return r.json().catch(function () { return { ok: false, chyba: 'ai' }; }); });
282  }
283
284  // Odeslání: nové prvky se jen PŘIDÁVAJÍ (dřívější reklamy zůstávají na místě)
285  function posli(text) {
286    text = (text || '').trim();
287    if (!text || odesila || zbyva === 0) { return; }
288    odesila = true;
289    hist.push({ r: 'u', t: text });
290    pole.value = ''; pole.style.height = '';
291    var chipy = zpravyEl.querySelector('.vc-chipy'); if (chipy) { chipy.remove(); }
292    var otazka = bublinaZpravy({ r: 'u', t: text });
293    zpravyEl.appendChild(otazka);
294    var p = document.createElement('div'); p.className = 'vc-pise'; p.textContent = T.pise || '…';
295    zpravyEl.appendChild(p);
296    vlozReklamu(otazka);                              // reklama mezi otázku a odpověď
297    ovladani();
298    p.scrollIntoView({ behavior: 'smooth', block: 'end' });
299
300    var telo = { zprava: text, lang: C.lang || '', od_id: odId };
301    if (KONTEXT) { telo.sport = KONTEXT.sport;
301 telo.fixture_id = KONTEXT.fid; }
302    api(telo).then(function (r) {
303      odesila = false;
304      if (r && r.ok) {
305        hist.push({ r: 'a', t: r.odpoved, z: r.zdroje || [] });
306        vse.push({ id: r.id || 0, ts: Math.floor(Date.now() / 1000), v_okne: 1, otazka: text, odpoved: r.odpoved, zdroje: r.zdroje || [] });
307        zbyva = r.zbyva; dalsi = r.dalsi; if (r.limit != null) { limit = r.limit; }
308        var odp = bublinaZpravy(hist[hist.length - 1]);
309        p.parentNode.replaceChild(odp, p);
310        if (zbyva === 0 && dalsi) { zpravyEl.appendChild(infoLimit()); }
311        ovladani();
312        odp.scrollIntoView({ behavior: 'smooth', block: 'start' });
313        return;
314      }
315      p.remove(); hist.pop(); ulozHist();
316      if (r && r.chyba === 'limit') {
317        otazka.remove(); zbyva = 0; dalsi = r.dalsi; zpravyEl.appendChild(infoLimit()); ovladani(); return;
318      }
319      var e = document.createElement('div'); e.className = 'vc-info';
320      var ch = r && r.chyba;
321      e.textContent = ch === 'pauza' ? T.pauza : (ch === 'blokovan' ? T.blokovan : (ch === 'ip' ? T.ip : T.chyba));
322      if (ch === 'blokovan') { zbyva = 0; dalsi = null; }
323      zpravyEl.appendChild(e);
324      pole.value = text; ovladani();
325    }).catch(function () {
326      odesila = false; p.remove(); hist.pop(); ulozHist(); pole.value = text; ovladani();
327    });
328  }
329
330  tlacitko.addEventListener('click', function () { posli(pole.value); });
331  pole.addEventListener('keydown', function (e) {
332    if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); posli(pole.value); }
333  });
334  pole.addEventListener('input', function () { pole.style.height = 'auto'; pole.style.height = Math.min(120, pole.scrollHeight) + 'px'; });
335
336  vykresli();
337  // Načtení vláken z DB (7 dní) – překreslí jen dokud uživatel nic neposlal
338  api({ akce: 'historie' }).then(function (r) {
339    if (!r || !r.ok) { return; }
340    zbyva = r.zbyva; dalsi = r.dalsi; if (r.limit != null) { limit = r.limit; }
341    if (!hist.length && !odesila) {
342      vse = r.zpravy || [];
343      vykresliArchiv(rozdel());
344      vykresli();
345      // Návrat do rozběhnuté konverzace: posunout na poslední odpověď a pole pro
346      // další otázku (začátek odpovědi nahoře, pole dole). Nové vlákno = stránka od začátku.
347      if (hist.length) {
348        var bubliny = zpravyEl.querySelectorAll('.vc-z.vc-a');
349        var posledni = bubliny[bubliny.length - 1];
350        if (posledni) {
351          setTimeout(function () {
352            posledni.scrollIntoView({ behavior: 'auto', block: 'start' });
353            window.scrollBy(0, -70);                         // kousek nad ní kvůli pevné hlavičce webu
354            if (window.innerWidth > 600 && !pole.disabled) { pole.focus({ preventScroll: true }); }
355          }, 50);
356        }
357      }
358    } else {
359      ovladani();
360    }
361  }).catch(function () {});
362})();

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.