PageSourceSearch

https://support.jdownloader.org/resources/assets/general/js/main.js?v=5.7.5

js jdownloader.org collected 2026-09-24 09:39:22 UTC 23,646 bytes, 654 lines download raw bytes

1// SupportPal global namespace, we use App because the help widget uses SupportPal.
2var App = function () {
3  'use strict';
4
5  // Create a public methods object
6  var modules = {
7    env: $('meta[name="environment"]').prop('content') || "production"
8  };
9
10  /**
11   * Add a module or function to the namespace.
12   *
13   * @param  {String}   name The name of the module.
14   * @param  {Object}   obj  The module object.
15   */
16  modules.extend = function (name, obj) {
17    if (typeof modules[name] !== "undefined") {
18      throw new Error("A module with name '" + name + "' already exists.");
19    }
20    modules[name] = obj;
21  };
22
23  // Return public methods object
24  return modules;
25}();
26
27// flatpickr.
28if (typeof Lang !== 'undefined') {
29  flatpickr.localize({
30    weekdays: {
31      shorthand: [Lang.get('general.sun'), Lang.get('general.mon'), Lang.get('general.tue'), Lang.get('general.wed'), Lang.get('general.thu'), Lang.get('general.fri'), Lang.get('general.sat')],
32      longhand: [Lang.get('general.sunday'), Lang.get('general.monday'), Lang.get('general.tuesday'), Lang.get('general.wednesday'), Lang.get('general.thursday'), Lang.get('general.friday'), Lang.get('general.saturday')]
33    },
34    months: {
35      shorthand: [Lang.get('general.jan'), Lang.get('general.feb'), Lang.get('general.mar'), Lang.get('general.apr'), Lang.get('general.may'), Lang.get('general.jun'), Lang.get('general.jul'), Lang.get('general.aug'), Lang.get('general.sep'), Lang.get('general.oct'), Lang.get('general.nov'), Lang.get('general.dec')],
36      longhand: [Lang.get('general.january'), Lang.get('general.february'), Lang.get('general.march'), Lang.get('general.april'), Lang.get('general.may'), Lang.get('general.june'), Lang.get('general.july'), Lang.get('general.august'), Lang.get('general.september'), Lang.get('general.october'), Lang.get('general.november'), Lang.get('general.december')]
37    },
38    firstDayOfWeek: 1,
39    ordinal: function (nth) {
40      var s = nth % 100;
41      if (s > 3 && s < 21) return Lang.get('general.ordinal_th');
42      switch (s % 10) {
43        case 1:
44          return Lang.get('general.ordinal_st');
45        case 2:
46          return Lang.get('general.ordinal_nd');
47        case 3:
48          return Lang.get('general.ordinal_rd');
49        default:
50          return Lang.get('general.ordinal_th');
51      }
52    },
53    rangeSeparator: Lang.get('general.range_separator'),
54    weekAbbreviation: Lang.get('general.week_abbr'),
55    scrollTitle: Lang.get('general.scroll_to_increment'),
56    toggleTitle: Lang.get('general.click_to_toggle'),
57    amPM: [Lang.get('general.am'), Lang.get('general.pm')],
58    yearAriaLabel: Lang.choice('general.year', 1),
59    hourAriaLabel: Lang.choice('general.hour', 1),
60    minuteAriaLabel: Lang.choice('general.min', 1),
61    time_24hr: true
62  });
63}
64
65// Date picker.
66$.fn.datepicker = function (options) {
67  var defaults = {
68    // Convert from PHP date format to flatpickr format.
69    dateFormat: $('meta[name=date_format]').prop('content').replace('jS', 'J').replace(/([^a-zA-Z])/g, "\\\\$1"),
70    // RTL support for the arrows.
71    nextArrow: '<span class="rtl:sp-hidden"><i class="fas fa-chevron-right" aria-hidden="true"></i></span><span class="ltr:sp-hidden"><i class="fas fa-chevron-left" aria-hidden="true"></i></span>',
72    prevArrow: '<span class="rtl:sp-hidden"><i class="fas fa-chevron-left" aria-hidden="true"></i></span><span class="ltr:sp-hidden"><i class="fas fa-chevron-right" aria-hidden="true"></i></span>'
73  };
74  return $(this).each(function () {
75    // Quick fix to stop flatpickr being loaded twice on an input
76    if (this.className.indexOf('flatpickr-input') === -1) {
77      $(this).flatpickr($.extend(true, defaults, options));
78    }
79  });
80};
81
82// Time picker.
83$.fn.timepicker = function (options) {
84  var defaults = {
85    // Convert from PHP date format to flatpickr format.
86    dateFormat: $('meta[name=time_format]').prop('content').replace('g', 'h').replace('a', 'K').replace('A', 'K').replace(/([^a-zA-Z])/g, "\\\\$1"),
87    enableTime: true,
88    noCalendar: true,
89    time_24hr: !($('meta[name=time_format]').prop('content').indexOf('g') > -1)
90  };
91  return $(this).each(function () {
92    // Quick fix to stop flatpickr being loaded twice on an input
93    if (this._flatpickr === undefined) {
94      $(this).flatpickr($.extend(true, defaults, options));
95    }
96  });
97};
98
99// isWindow was deprecated in jQuery 3.3.0
100function isWindow(obj) {
101  return obj !== null && obj !== undefined && obj === obj.window;
102}
103
104// jQuery print event callback helpers.
105//   - https://gist.github.com/shaliko/4110822#gistcomment-1543771
106//   - https://www.tjvantoll.com/2012/06/15/detecting-print-requests-with-javascript/
107$.fn.beforeprint = function (callback) {
108  return $(this).each(function () {
109    if (!isWindow(this)) {
110      return;
111    }
112    if (this.onbeforeprint !== undefined) {
113      $(this).on('beforeprint', callback);
114    } else if (this.matchMedia) {
115      this.matchMedia('print').addListener(callback);
116    }
117  });
118};
119$.fn.afterprint = function (callback) {
120  return $(this).each(function () {
121    if (!isWindow(this)) {
122      return;
123    }
124    if (this.onafterprint !== undefined) {
125      $(this).on('afterprint', callback);
126    } else if (this.matchMedia) {
127      $(this).one('mouseover', callback); // https://stackoverflow.com/a/15662720/2653593
128    }
129  });
130};
131
132// Polyfill for matches, closest and find (IE11), needed for tippy.js
133// https://developer.mozilla.org/en-US/docs/Web/API/Element/matches#Polyfill
134if (!Element.prototype.matches) {
135  Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
136}
137// https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
138if (!Element.prototype.closest) {
139  Element.prototype.closest = function (s) {
140    var el = this;
141    do {
142      if (el.matches(s)) return el;
143      el = el.parentElement || el.parentNode;
144    } while (el !== null && el.nodeType === 1);
145    return null;
146  };
147}
148// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find#Polyfill
149if (!Array.prototype.find) {
150  Object.defineProperty(Array.prototype, 'find', {
151    value: function (predicate) {
152      // 1. Let O be ? ToObject(this value).
153      if (this == null) {
154        throw TypeError('"this" is null or not defined');
155      }
156      var o = Object(this);
157
158      // 2. Let len be ? ToLength(? Get(O, "length")).
159      var len = o.length >>> 0;
160
161      // 3. If IsCallable(predicate) is false, throw a TypeError exception.
162      if (typeof predicate !== 'function') {
163        throw TypeError('predicate must be a function');
164      }
165
166      // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
167      var thisArg = arguments[1];
168
169      // 5. Let k be 0.
170      var k = 0;
171
172      // 6. Repeat, while k < len
173      while (k < len) {
174        // a. Let Pk be ! ToString(k).
175        // b. Let kValue be ? Get(O, Pk).
176        // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
177        // d. If testResult is true, return kValue.
178        var kValue = o[k];
179        if (predicate.call(thisArg, kValue, k, o)) {
180          return kValue;
181        }
182        // e. Increase k by 1.
183        k++;
184      }
185
186      // 7. Return undefined.
187      return undefined;
188    },
189    configurable: true,
190    writable: true
191  });
192}
193
194// Reverse items in selector.
195// https://www.mail-archive.com/[email protected]/msg04272.html
196$.fn.reverse = function () {
197  return this.pushStack(this.get().reverse(), arguments);
198};
199
200/**
201 * Add a new item to DOM container. This function expects a classname:input[name$="[id]"] to be present
202 * for every unique DOM item within the container.
203 *
204 * @param className
205 * @param container
206 * @returns {number}
207 */
208function addNewItem(className, container) {
209  // Clone the element
210  var newElem = $(className + ':first').clone();
211
212  // Clear the input values from the cloned DOM
213  newElem.removeClass('first');
214
215  // Update the index.. god damn you Laravel
216  // Longwinded but ensures a unique key
217  // Find the highest index first and add one
218  var re = /^\w+\[(\d+)?]\[\w+]?$/;
219  var m,
220    index = 0;
221  $(className + ' :input[name$="[id]"]').each(function () {
222    if ((m = re.exec($(this).attr('name'))) !== null) {
223      if (typeof m[1] != 'undefined') {
224        if ((m = parseInt(m[1])) >= index) {
225          index = m + 1;
226        }
227      }
228    }
229  });
230
231  // Update all the indexes in the new element
232  newElem.find(':input, label').each(function () {
233    var elem = $(this);
234    elem.prop('disabled', false);
235    ['name', 'for', 'id'].map(function (attribute) {
236      var attr = elem.attr(attribute);
237      if (/^\w+\[(\d+)?](\[[\w:-]+])*(\[\])?$/g.test(attr)) {
238        elem.attr(attribute, attr.replace(/\[(\d+)?]/, '[' + index + ']'));
239      }
240    });
241  });
242
243  // Where do we want to put it?
244  if (typeof container !== 'undefined') {
245    // Append cloned DOM to the end of the parent container
246    $(container).append(newElem);
247  } else {
248    // Append cloned DOM to the end of the list
249    $(className + ':last').after(newElem);
250  }
251
252  // Make it visible
253  newElem.removeClass('sp-hidden');
254
255  // Auto select first option of dropdowns - fix for firefox
256  newElem.find('select').each(function () {
257    $(this).find('option:first').prop('selected', 'selected');
258  });
259  return index;
260}
261
262// Wait for DOM to load before running the below.
263$(function () {
264  // Tooltip - tippy.js
265  tippy.delegate(document.body, {
266    content: function (reference) {
267      var title = reference.getAttribute('title');
268      reference.removeAttribute('title');
269      reference.setAttribute('data-tippy-content', title);
270      return title;
271    },
272    onShow: function (instance) {
273      return instance.reference.hasAttribute('data-tippy-content') && !instance.reference.classList.contains('tox-edit-area__iframe') && !instance.reference.classList.contains('tox-collection__item') && (!instance.reference.classList.contains('tox-button') || instance.reference.classList.contains('tox-button--icon')) && instance.reference.getAttribute('data-tippy-content').length > 0;
274    },
275    target: '[title]',
276    touch: ['hold', 500],
277    zIndex: 10052
278  });
279
280  // Logout handler.
281  $('.logout-link').on('click', function (e) {
282    e.preventDefault();
283    var $form = $('<form>', {
284      method: $(this).data('method'),
285      action: $(this).data('url')
286    }).hide().append($('<input>', {
287      type: "hidden",
288      name: "_token",
289      value: $('meta[name=csrf_token]').prop('content')
290    }));
291    $(document.body).append($form);
292    $form.submit();
293  });
294
295  // Global event events.
296  // Avoid polluting the $(document) space with too many event listeners, try to place as close to element as possible
297  // otherwise performance will be affected (https://api.jquery.com/on/).
298  $(document.body)
299  // Tabs toggling
300  .on('click', 'ul.sp-tabs li', function () {
301    // Don't do this if it's an actual link.
302    if ($(this).find('a[href]:not([href="#"])').length) {
303      return;
304    }
305
306    // Get name of tab
307    var name = $(this).attr('id');
308
309    // Hide current div
310    $(this).parent().siblings('div.sp-tab-content').hide();
311    // Show new div
312    $('#tab' + name).show();
313
314    // Remove active from old tab
315    $(this).parent().find('li.sp-active').removeClass('sp-active');
316    // Set to active
317    $(this).addClass('sp-active');
318  })
319  // For dropdowns
320  .on('click', '.sp-dropdown-container .sp-dropdown li.sp-dropdown-item-interactive', function (e) {
321    e.stopImmediatePropagation();
322  }).on('click', '.sp-dropdown-container .sp-button, .sp-dropdown-container .sp-action, .sp-dropdown-container .sp-dropdown li', function () {
323    var $dropdown = $(this).parents('.sp-dropdown-container').find('.sp-dropdown');
324    if ($dropdown.is(':visible')) {
325      $dropdown.hide();
326      $dropdown.trigger('sp.dropdown.hide');
327    } else {
328      $dropdown.show();
329      $dropdown.trigger('sp.dropdown.show');
330    }
331  })
332  // Hide dropdown if clicking outside the dropdown div
333  .on('click', function (event) {
334    $('.sp-dropdown-container').not($(event.target).closest('.sp-dropdown-container')).find('.sp-dropdown:visible').hide();
335  })
336  // For opening/collapsing collapsible boxes
337  .on('click', '.sp-collapsible', function () {
338    $(this).find('.fas.fa-chevron-down, .fas.fa-chevron-up').toggleClass('fa-chevron-down fa-chevron-up');
339    $(this).next().toggle(500);
340  })
341  // Smooth scrolling for anchors
342  .on('click', 'a[href^="#"]', function (event) {
343    event.preventDefault();
344    var target = document.getElementById($.attr(this, 'href').substring(1));
345    if (target !== null) {
346      $('html, body, #content').animate({
347        scrollTop: $(target).offset().top - $('header.sp-sticky').height() - 24
348      }, 500);
349    }
350  })
351  // Close alerts
352  .on('click', '.sp-alert .sp-alert-close', function () {
353    $(this).parent().slideToggle(300);
354  });
355
356  // Handle anchors on page load
357  const hash = window.location.hash.substring(1);
358  var target;
359  if (hash !== '' && (target = document.getElementById(hash)) !== null) {
360    // Now scroll to anchor
361    $('html, body, #content').animate({
362      scrollTop: $(target).offset().top - $('header.sp-sticky').height() - 24
363    }, 500);
364  }
365
366  // Global AJAX setup handler to add the CSRF token to ALL POST requests.
367  $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
368    if (options.type.toLowerCase() === "post" || options.type.toLowerCase() === "put" || options.type.toLowerCase() === "delete") {
369      jqXHR.setRequestHeader('X-CSRF-Token', $('meta[name=csrf_token]').prop('content'));
370    }
371  });
372
373  // Register localisation settings.
374  if (typeof Lang !== 'undefined') {
375    // Timeago
376    timeago.register('supportpal', function (number, index, total_sec) {
377      // Convert weeks to days.
378      if ([8, 9].indexOf(index) !== -1) {
379        total_sec = parseInt(total_sec / 86400);
380      }
381      return [[Lang.get('general.just_now'), Lang.get('general.shortly')], [L
381ang.choice('general.minutes_ago', 1, {
382        'number': 1
383      }), Lang.choice('general.in_minutes', 1, {
384        'number': 1
385      })], [Lang.choice('general.minutes_ago', 1, {
386        'number': 1
387      }), Lang.choice('general.in_minutes', 1, {
388        'number': 1
389      })], [Lang.choice('general.minutes_ago', 2, {
390        'number': '%s'
391      }), Lang.choice('general.in_minutes', 2, {
392        'number': '%s'
393      })], [Lang.choice('general.hours_ago', 1, {
394        'number': 1
395      }), Lang.choice('general.in_hours', 1, {
396        'number': 1
397      })], [Lang.choice('general.hours_ago', 2, {
398        'number': '%s'
399      }), Lang.choice('general.in_hours', 2, {
400        'number': '%s'
401      })], [Lang.choice('general.days_ago', 1, {
402        'number': 1
403      }), Lang.choice('general.in_days', 1, {
404        'number': 1
405      })], [Lang.choice('general.days_ago', 2, {
406        'number': '%s'
407      }), Lang.choice('general.in_days', 2, {
408        'number': '%s'
409      })], [Lang.choice('general.days_ago', 2, {
410        'number': total_sec
411      }), Lang.choice('general.in_days', 2, {
412        'number': total_sec
413      })], [Lang.choice('general.days_ago', 2, {
414        'number': total_sec
415      }), Lang.choice('general.in_days', 2, {
416        'number': total_sec
417      })], [Lang.choice('general.months_ago', 1, {
418        'number': 1
419      }), Lang.choice('general.in_months', 1, {
420        'number': 1
421      })], [Lang.choice('general.months_ago', 2, {
422        'number': '%s'
423      }), Lang.choice('general.in_months', 2, {
424        'number': '%s'
425      })], [Lang.choice('general.years_ago', 1, {
426        'number': 1
427      }), Lang.choice('general.in_years', 1, {
428        'number': 1
429      })], [Lang.choice('general.years_ago', 2, {
430        'number': '%s'
431      }), Lang.choice('general.in_years', 2, {
432        'number': '%s'
433      })]][index];
434    });
435
436    // Initialise global timeAgo variable (used in several other files).
437    window.timeAgo = new timeago();
438    timeAgo.setLocale("supportpal");
439
440    // Hide/Show Password library defaults.
441    $.extend(true, $.fn.hideShowPassword.defaults, {
442      show: false,
443      innerToggle: 'focus',
444      states: {
445        shown: {
446          toggle: {
447            content: Lang.get('general.hide'),
448            attr: {
449              title: ''
450            }
451          }
452        },
453        hidden: {
454          toggle: {
455            content: Lang.get('general.show'),
456            attr: {
457              title: ''
458            }
459          }
460        }
461      },
462      toggle: {
463        className: 'sp-button-sm'
464      }
465    });
466    $('input[type=password]').hideShowPassword();
467
468    // Selectize defaults.
469    $.extend(true, $.fn.selectize.defaults, {
470      render: {
471        option_create: function (data, escape) {
472          var item = Lang.get('core.add_selectize', {
473            item: escape(data.input)
474          });
475          return '<div class="create">' + item + '</div>';
476        }
477      }
478    });
479  }
480
481  /**
482   * Get the form row that the error element sits in.
483   *
484   * @param  {HTMLElement} element
485   * @returns {jQuery}
486   */
487  function getErrorElementRow(element) {
488    return $(element).closest('.sp-form-row');
489  }
490
491  /**
492   * Get the wrapper element around the element that failed validation.
493   *
494   * @param  {HTMLElement} element
495   * @returns {jQuery}
496   */
497  function getErrorElementWrapper(element) {
498    if ($(element).parents('.sp-validation-container').length) {
499      return $(element).parents('.sp-validation-container');
500    }
501    if ($(element).parents('.sp-email-address').length) {
502      return $(element).parents('.sp-email-address');
503    }
504    if ($(element).parents('.sp-phone-number').length) {
505      return $(element).parents('.sp-phone-number');
506    }
507    var $row = getErrorElementRow(element);
508    return $row.find(':input:not(:button)').length > 1 && !$(element).parent('.sp-editor-container').length && !$(element).parent('.hideShowPassword-wrapper').length && !$(element).parent('.sp-input-translatable-container').length && !$(element).parent('.sp-input-group').length && !$(element).next().has('selectize') && $(element).prop('type') !== 'checkbox' && $(element).prop('type') !== 'radio' ? $(element) : $row;
509  }
510
511  /**
512   * Get the container that we're going to add the error message after.
513   *
514   * @param element
515   * @returns {*}
516   */
517  function getErrorContainer(element) {
518    var position = element;
519
520    // If it's codemirror, show/hide button, phone input, input group container, recaptcha, a checkbox or radio, add after parent
521    if (element.parent('.sp-editor-container').length || element.parent('.codemirror-box').length || element.parent('.hideShowPassword-wrapper').length || element.parent('.iti').length || element.parent('.sp-input-group').length || element.parent().parent('.g-recaptcha').length || element.prop('type') === 'checkbox' || element.prop('type') === 'radio') {
522      position = element.parent();
523    }
524
525    // If it's editor, selectize, add after sibling.
526    if (element.next().hasClass('tox-tinymce') || element.next().hasClass('selectize-control')) {
527      position = element.next();
528    }
529
530    // If it's got a translatable model, add afterwards.
531    if (element.next().hasClass('fa-language')) {
532      position = element.next().next();
533    }
534
535    // If it's phone input, add after row.
536    if (element.parent('.iti').length) {
537      position = position.parent().parent();
538    }
539
540    // If it's a checkbox or radio, make sure we put the error after the last element.
541    if (position.is('label') && (element.prop('type') === 'checkbox' || element.prop('type') === 'radio')) {
542      position = position.siblings().last('label');
543    }
544    return position;
545  }
546
547  // jQuery validate.
548  $.validator.setDefaults({
549    ignore: '[contenteditable=\'true\']',
550    errorElement: 'span',
551    errorClass: 'sp-input-error',
552    wrapper: 'div',
553    errorPlacement: function (error, element) {
554      error.insertAfter(getErrorContainer(element));
555    },
556    highlight: function (element, errorClass, validClass) {
557      getErrorElementWrapper(element).addClass('sp-input-has-error');
558    },
559    unhighlight: function (element, errorClass, validClass) {
560      getErrorElementWrapper(element).removeClass('sp-input-has-error');
561
562      // If phone input, it's the next element which is the hidden input.
563      if ($(element).parent('.iti').length) {
564        element = $(element).next();
565      }
566
567      // Hide error if it's "pending" (remote validation).
568      var describer = $(element).attr("aria-describedby");
569      if (describer) {
570        getErrorElementRow(element).find('#' + this.escapeCssMeta(describer)).hide();
571      }
572    },
573    success: function (label, element) {
574      //
575    },
576    // Custom submit handler.
577    submitHandler: function (form) {
578      // CodeMirror saves when form submit events are fired. We need to manually trigger an event to update it,
579      // so that jquery-validation has the correct form data.
580      $(form).find('.sc-textarea').each((i, el) => el.sourcecode.save());
581      $(form).find('input[type="submit"], button[type="submit"]').prop('disabled', true);
582
583      // Validate the form.
584      if (this.form()) {
585        // Handle remote validation rules.
586        if (this.pendingRequest) {
587          this.formSubmitted = true;
588          return false;
589        }
590
591        // Form is valid, trigger form submission event.
592        $(form).trigger('form:submit');
593
594        // If the form is marked as using AJAX, then return false to prevent the page refreshing.
595        if (typeof $(form).data('ajax') !== "undefined") {
596          return false;
597        }
598
599        // Submit the form (will cause the page to refresh etc).
600        form.submit();
601      } else {
602        $(form).find('input[type="submit"], button[type="submit"]').prop('disabled', false);
603        this.focusInvalid();
604        return false;
605      }
606    },
607    focusInvalid: true,
608    invalidHandler: function (event, validator) {
609      // Enable submit button again (necessary for invalid remote validation).
610      $(this).find(':submit').prop('disabled', false);
611    },
612    showErrors: function (errorMap, errorList) {
613      // Run default error message handler.
614      this.defaultShowErrors();
615
616      // Move the screen to show the first error message.
617      $.each(errorList, function (key, error) {
618        var $elm = getErrorContainer($(error.element));
619
620        // If the error is on another tab, switch to it.
621        if ($elm.parents('.sp-tab-content').length) {
622          var id = $elm.parents('.sp-tab-content').attr('id');
623          if (typeof id !== 'undefined' && id.substring(0, 3) === 'tab') {
624            $('.sp-tabs li#' + id.substring(3)).trigger('click');
625          }
626        }
627
628        // If the error is in a translatable model, open it.
629        if ($elm.parent().hasClass('sp-translation')) {
630          var $translatableInput = $elm.parents('.sp-input-translatable');
631          $translatableInput.find('.fa-language').click();
632
633          // If the translation is not visible, select it from the dropdown.
634          if (!$elm.parent().is(':visible')) {
635            var $selectize = $translatableInput.find('select[name=sp-translation-add]')[0].selectize;
636            if (typeof $selectize !== 'undefined') {
637              $selectize.addItem($elm.parent().data('locale'), false);
638            }
639          }
640        }
641
642        // Make sure the element is visible otherwise it will scroll to the top of the page.
643        if ($elm.is(':visible')) {
644          $('html, body, #content').animate({
645            scrollTop: $elm.position().top - 44
646          }, 1000);
647
648          // Break loop.
649          return false;
650        }
651      });
652    }
653  });
654});

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.