PageSourceSearch

https://file-assist.com/lite/js/aws.js?v=fgy23HcUgaOWFMvLTKPt7q-Rcck8vdE8fXDjMZq5ego

js file-assist.com collected 2026-10-08 06:55:08 UTC 27,624 bytes, 724 lines download raw bytes

1jQuery(document).ajaxError(function (e, xhr, settings) {
2    if (window._env == "web") {
3        //global login redirect
4        if (xhr.status == 401) {
5            //if a it's from exchange server, prevent redirection
6            if (xhr.url && xhr.url.indexOf("/api/v1/hostedstorage/") > -1) {
7                return;
8            }
9            if (xhr.getResponseHeader("x-auth-changed") == "true") {
10                if (xhr.authChanged)
11                    return;
12                xhr.authChanged = true;
13                alertMessage("USER_AUTHENTICATION_CHANGED");
14            }
15            else {
16                var logoutUrl = AppUrls.Logout + "?ClientId=" + $("#hdnClientId").val();
17                if (xhr.responseJSON != null && xhr.responseJSON.errorCode != null) {
18                    logoutUrl = logoutUrl + "&errorCode=" + xhr.responseJSON.errorCode;
19                } else {
20                    logoutUrl = logoutUrl + "&errorCode=e2006";
21                }
22                window.location.href = logoutUrl;
23            }
24
25        }
26        else if (xhr.status == 424) {
27            if (xhr.responseJSON != null && xhr.responseJSON.errorCode != null) {
28                if (xhr.responseJSON.errorCode == "LINKED_SERVER_CONNECTION_FAILURE") {
29                    showEmptySearch(true);
30                }
31            }
32        }
33        else if (xhr.status == 409) {
34            if (xhr.responseJSON != null && xhr.responseJSON.errorCode != null) {
35                if (xhr.responseJSON.errorCode == "FOLDER_NOT_FOUND") {
36                    notify("error", getMessage("ROOT_FOLDER_NOT_FOUND"), "#file-list", true);
37                }
38            }
39        }
40        else if (xhr.status == 404) { //Fixed dom-based vulnarabilities found in burp scan: Data is read from window.location.href and passed to window.location.href via the following statements:
41            if (settings.suppressNotFound)
42                return;
43            var url = new URL(xhr.url);
44            if (url.origin != window.location.origin)
45                return;
46            var siteurl = window.location.origin;
47            var lite = "/lite/";
48            if (window.location.pathname.toLowerCase().indexOf(lite) == 0) {
49                siteurl = window.location.origin + lite;
50            } else {
51                siteurl = siteurl + "/";
52            }
53            window.location.href = siteurl + "404";
54        }
55        else if (xhr.status == 500) {
56            var err = getMessage("e1000");
57            if (jQuery("#response").length == 0) {
58                fasTable.toast.show("Error", err);
59            } else {
60                notify("error", getMessage("e1000"), '#response', true);
61            }
62        }
63    }
64    else if (window._env == "guest") {
65        if (xhr.status == 401) {
66            window.location.reload();
67        }
68    }
69
70});
71
72jQuery.ajaxSetup({
73    beforeSend: function (xhr, settings) {
74        if (settings.url.indexOf('api.autodesk.com') == -1)
75            xhr.setRequestHeader("x-uid", window._xuid);
76    }
77});
78
79var ajax = function (obj) {
80    if (obj.method === "POST") {
81        //add token if not set
82        obj.headers = obj.headers || {};
83        obj.headers["X-CSRF-TOKEN"] = obj.headers["X-CSRF-TOKEN"] || window._xsrf;
84    }
85    var override = jQuery.extend({
86        beforeSend: function (request, settings) {
87            if (obj.headers && !isAws(obj.url)) {
88                for (var key in obj.headers) {
89                    if (key.toLowerCase() == "host") {
90                        delete obj.headers[key];
91                        continue;
92                    }
93                    request.setRequestHeader(key, obj.headers[key]);
94                }
95            }
96
97            request.setRequestHeader("x-uid", window._xuid);
98            request.url = settings.url;
99        },
100        cache: false,
101        processData: obj.method !== "PUT"
102    }, obj);
103    var xhr = null;
104    var promise = new Promise(function (resolve, reject) {
105        override.success = function (data) {
106            resolve(data);
107        }
108        override.error = function (err) {
109            if (obj.notifyPanel && err.responseJSON && err.responseJSON.errorCode) {
110                notify("error", getMessage(err.responseJSON.errorCode, err.responseJSON.data), obj.notifyPanel);
111            }
112            reject(err);
113        }
114        xhr = jQuery.ajax(override);
115    });
116    promise.abort = function () {
117        promise.catch(function (ex) {
118            //do nothing
119        });
120        xhr.abort();
121    }
122    promise.xhr = xhr;
123    return promise;
124}
125jQuery.fn.serializeObject = function () {
126    var o = {};
127    var a = this.serializeArray();
128    $.each(a, function () {
129        if (o[this.name]) {
130            if (!o[this.name].push) {
131                o[this.name] = [o[this.name]];
132            }
133            o[this.name].push(this.value || '');
134        } else {
135            o[this.name] = this.value || '';
136        }
137    });
138    return o;
139};
140
141var isFunction = function (variable) {
142    return variable && typeof (variable) == "function";
143}
144var notify = function (type, msg, target, hideClose) {
145    var element = jQuery("<div role='alert' />");
146    var alertType = "fade show alert alert-dismissible error-div-notify";
147    element.addClass(alertType);
148    if (type == "error") {
149        element.addClass("alert-danger");
150        element.append("<span class='fa fa-exclamation-circle text-danger me-2'></span>");
151    }
152    else if (type == "success") {
153        element.addClass("alert-success");
154        element.append("<span class='fa fa-check-circle me-2 text-success'></span>");
155    }
156    else if (type == "info") {
157        element.addClass("alert-secondary");
158        element.append("<span class='fa fa-info-circle me-2'></span>");
159    }
160    else if (type == "warning") {
161        element.addClass("alert-warning");
162        element.append("<span class='fa fa-exclamation-triangle me-2'></span>");
163    }
164    element.append("<span>" + msg + "</span>");
165    if (!hideClose) {
166        var close = jQuery(
167            '<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>');
168        element.append(close);
169    }
170
171    if (target) {
172        jQuery(target).html("");
173        jQuery(target).append(element);
174    } else {
175        jQuery("body").append(element);
176        element.css("top", 10);
177        element.fadeIn();
178    }
179}
180var showFormLoader = function (formId, loaderSize, message) {
181    if (!formId.startsWith('#')) {
182        formId = '#' + formId;
183    }
184    var spinner = loaderSize == 'm'
185        ? '<span style="font-size:50px" class="fas fa-spinner fa-pulse"></span>'
186        : '<span class="fas fa-spinner fa-pulse"></span>';
187    var msgHtml = message
188        ? '<div class="ajax-grayout-loader-message mt-2 px-3">' + $('<div/>').text(message).html() + '</div>'
189        : '';
190    jQuery(formId).append('<div class="ajax-grayout-loader" style="flex-direction:column">' + spinner + msgHtml + '</div>');
191}
192var setFormLoaderMessage = function (formId, message) {
193    if (!formId.startsWith('#')) {
194        formId = '#' + formId;
195    }
196    var $loader = jQuery(formId).find(".ajax-grayout-loader");
197    if (!$loader.length) {
198        return;
199    }
200    var $msg = $loader.find('.ajax-grayout-loader-message');
201    if (!$msg.length) {
202        $loader.append('<div class="ajax-grayout-loader-message mt-2 px-3"></div>');
203        $msg = $loader.find('.ajax-grayout-loader-message');
204    }
205    $msg.text(message || '');
206}
207var hideFormLoader = function (formId) {
208    if (!formId.startsWith('#')) {
209        formId = '#' + formId;
210    }
211    jQuery(formId).find(".ajax-grayout-loader").remove();
212}
213var markErrorField = function (element) {
214    let $element = element;
215    if (!(element instanceof jQuery)) {
216        $element = $(element);
217    }
218    $element.addClass('error-field');
219    $element.focus();
220}
221var initAjaxForm = function (formId, options) {
222    formId = "#" + formId;
223    var submitter = null;
224    options = jQuery.extend({},
225        {
226            extraData: null,
227            expectsHtmlResponse: false,
228            onError: function () { },
229            onSuccess: function () { }
230        },
231        options);
232    jQuery(formId).submit(function (e) {
233        submitter = e.originalEvent ? e.originalEvent.submitter : null;
234        e.preventDefault();
235    })
236        .validate({
237            invalidHandler: options.invalidHandler,
238            submitHandler: function (form) {
239                var extraData = options.extraData;
240                if (isFunction(options.extraData)) {
241                    extraData = options.extraData();
242                    if (!extraData) {
243                        if (options.onError)
244                            options.onError();
245                        return;
246                    }
247                }
248                //get form object
249                var object = jQuery(form).serializeObject();
250                //add additional parameters
251                object = jQuery.extend(object, extraData);
252                if (options.beforeSubmit) {
253                    if (!options.beforeSubmit(object))
254                        return;
255                }
256                var method = jQuery(form).attr("method") || "post";
257                var action = jQuery(form).attr("action") || window.location.href;
258
259                var submitBtn = jQuery(form).find("button[type=submit]:focus");
260
261                if (submitBtn) {
262                    var formAction = submitBtn.attr('formAction');
263                    if (formAction)
264                        action = formAction;
265                }
266
267                var enableControls = function () {
268                    //remove loader                    
269                    hideFormLoader(formId);
270                };
271
272                var disableControls = function () {
273                    //Create loader
274                    showFormLoader(formId, options.loaderSize)
275                };
276
277                jQuery(formId).find('[name]').removeClass('error-field');
278                disableControls();
279                var ajaxOptions = {
280                    url: action,
281                    data: object,
282                    method: method
283                };
284                if (options.notifyPanel) {
285                    jQuery(options.notifyPanel).html("");
286                }
287                ajax(ajaxOptions)
288                    .then(function (response) {
289                        enableControls();
290                        if (options.expectsHtmlResponse || !response.responseJSON || response.success) {
291                            if (options.onSuccess)
292                                options.onSuccess(response, submitter);
293                        } else {
294
295                            if (options.notifyPanel && response.errorCode) {
296                                notify("error", getMessage(response.errorCode, response.data), options.notifyPanel);
297                            }
298
299                            if (options.onError) {
300                                options.onError(response, submitter);
301                            }
302                        }
303                    })
304                    .catch(function (response) {
305                        if (response.responseJSON)
306                            response = response.responseJSON;
307                        enableControls();
308                        if (options.notifyPanel && response.errorCode) {
309                            if (options.disableNotifyError && options.disableNotifyError.includes(response.errorCode)) {
310                                //no notify // its us in folder properties confirmation window
311                            } else {
312                                notify("error", getMessage(response.errorCode, response.data), options.notifyPanel);
313                            }
314
315                            if (response.errorCodes) {
316                                var fileds = Object.keys(response.errorCodes);
317                                if (fileds.length > 0) {
318                                    var fieldName = fileds[0];
319                                    fieldName = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
320                                    if (fieldName.includes('.')) {
321                                        let fieldId = fieldName.replace('.', '_');
322                                        $fieldName = $(formId).find('#' + fieldId);
323                                    } else {
324                                        $fieldName = $(formId).find('[name=' + fieldName + ']');
325                                    }
326                                    markErrorField($fieldName);
327                                }
328                            }
329                        }
330                        if (options.onError)
331                            options.onError(response, submitter);
332                    });
333            },
334            errorPlacement: options.errorPlacement
335        });
336
337    //add step false for input time as it conflicts with jquery validation plugin
338    jQuery(formId + ' input[type="time"]').each(function () { jQuery(this).rules('add', { step: fal
338se }); });
339}
340
341var isHosted = function (url) {
342    return url.indexOf("hostedstorage") != -1;
343}
344
345var isRelativeHosted = function (url) {
346    return url.startsWith("/");
347}
348var isAws = function (url) {
349    return url.indexOf("amazonaws") != -1;
350}
351var isAzureFileShare = function (url) {
352    return url.indexOf("file.core.windows.net") != -1;
353}
354var isAzureBlob = function (url) {
355    return url.indexOf("blob.core.windows.net") != -1;
356}
357var getSignedUrlForFile = function (verb, key, contentType, withHeaders, keyIsId, overwrite) {
358    var obj = {
359        verb: verb,
360        key: key,
361        contentType: contentType,
362        withHeaders: withHeaders,
363        overwrite: overwrite
364    };
365    if (keyIsId)
366        obj.id = key;
367    return ajax({
368        url: AppUrls.GetProviderCorsUrlForFile,
369        method: "POST",
370        data: obj,
371        dataType: "json"
372    });
373}
374
375var getSignedUrlForFolder = function (fileRequests, parentPath, data, options) {
376    options = options || {};
377    if (typeof _uploadAction == 'undefined')
378        _uploadAction = 0;
379    data = jQuery.extend({
380        files: fileRequests,
381        parentPath: parentPath,
382        uploadAction: _uploadAction
383    }, data);
384    let ajaxHandle = ajax({
385        url: options.fetchUrl || AppUrls.GetProviderCorsUrlForFolder,
386        method: "POST",
387        data: data,
388        dataType: "json"
389    });
390    return ajaxHandle;
391}
392var getSignedUrlForProfile = function (fileRequests, parentPath, uploadAction) {
393    $("#error").html("");
394    return ajax({
395        url: AppUrls.GetCorsUploadUrlForProfile,
396        method: "POST",
397        data: {
398            files: fileRequests,
399            parentPath: parentPath,
400            uploadAction: uploadAction
401        },
402        dataType: "json"
403    });
404}
405var getSignedUrlForContactImage = function (fileRequests, parentPath, uploadAction) {
406    $("#error").html("");
407    return ajax({
408        url: AppUrls.createGetImageUploadUrl,
409        method: "POST",
410        data: {
411            files: fileRequests,
412            parentPath: parentPath,
413            uploadAction: uploadAction
414        },
415        dataType: "json"
416    });
417}
418
419var createChunks = function (file, cSize) {
420    let startPointer = 0;
421    let endPointer = file.size;
422    let chunks = [];
423    while (startPointer < endPointer) {
424        let newStartPointer = startPointer + cSize;
425        let chunk = file.slice(startPointer, newStartPointer);
426        chunk.dirPath = file.dirPath;
427        chunks.push(chunk);
428        startPointer = newStartPointer;
429    }
430    return chunks;
431}
432
433var blobUpload = function (signedUrl, headers, blob, onProgress, onError) {
434    var htmlFile = blob;
435    if (!isAws(signedUrl) && !isAzureBlob(signedUrl)) {
436        var formData = new FormData();
437        formData.append("file", htmlFile);
438        blob = formData;
439    }
440    return ajax({
441        url: signedUrl,
442        method: isHosted(signedUrl) ? "POST" : "PUT",
443        data: blob,
444        headers: isAws(signedUrl) ? null : headers,
445        cache: false,
446        contentType: isAws(signedUrl) || isAzureBlob(signedUrl) ? "multipart/form-data" : false,
447        error: onError,
448        processData: !isHosted(signedUrl),
449        xhr: function () {
450            var started_at = new Date();
451            var xhr = new window.XMLHttpRequest();
452            xhr.upload.addEventListener("progress", function (evt) {
453                if (evt.lengthComputable) {
454                    var loaded = evt.loaded;
455                    var total = evt.total;
456                    var percentComplete = ((loaded / total) * 100).toFixed(2);
457                    var seconds_elapsed = (new Date().getTime() - started_at.getTime()) / 1000;
458                    var bytes_per_second = seconds_elapsed ? loaded / seconds_elapsed : 0;
459                    var Kbytes_per_second = bytes_per_second / 1024;
460                    var remaining_bytes = total - loaded;
461                    var seconds_remaining = seconds_elapsed ? remaining_bytes / bytes_per_second : 'calculating';
462
463                    if (onProgress)
464                        onProgress(percentComplete, secondsToString(seconds_remaining), Kbytes_per_second, loaded, total);
465                }
466            }, false);
467            xhr.onreadystatechange = function (e) {
468                if (xhr.readyState === 4) {
469                    if (xhr.status == 200) {
470                        percentComplete = 100;
471                    }
472                }
473            }
474            return xhr;
475        }
476    });
477}
478
479var awsUpload = function (signedUrl, headers, file, fileRequest, onProgress, uploadSessionInfo, extraData, checkinComment) {
480    var htmlFile = file;
481    var fileSize = (file ? file.size : 0) || 0;
482    if (!isRelativeHosted(signedUrl) && !isAws(signedUrl) && !isAzureBlob(signedUrl) && !isAzureFileShare(signedUrl)) {
483        var formData = new FormData();
484        formData.append("file", htmlFile);
485        file = formData;
486    }
487
488    if(headers)
489        //delete the host header
490        delete headers['host'];
491    var percentComplete = 0;
492    return ajax({
493        url: signedUrl,
494        method: isHosted(signedUrl) || isRelativeHosted(signedUrl) ? "POST" : "PUT",
495        data: file,
496        cache: false,
497        processData: isRelativeHosted(signedUrl),
498        headers: isAws(signedUrl) ? null : headers,
499        contentType: isAws(signedUrl) || isAzureBlob(signedUrl) ? "multipart/form-data" : (isRelativeHosted(signedUrl) ? "application/x-www-form-urlencoded" : false),
500        xhrFields: {
501            withCredentials: isHosted(signedUrl)
502        },
503        crossDomain: isHosted(signedUrl),
504        xhr: function () {
505            var started_at = new Date();
506            var xhr = new window.XMLHttpRequest();
507            var seconds_elapsed, bytes_per_second, Kbytes_per_second, remaining_bytes, seconds_remaining;
508            xhr.upload.addEventListener("progress", function (evt) {
509                if (evt.lengthComputable) {
510
511                    var total = evt.total;
512                    var percent = (evt.loaded / total);
513                    percentComplete = (percent * 100).toFixed(2);
514                    let loaded = percent * fileSize;
515                    seconds_elapsed = (new Date().getTime() - started_at.getTime()) / 1000;
516                    bytes_per_second = seconds_elapsed ? loaded / seconds_elapsed : 0;
517                    Kbytes_per_second = bytes_per_second / 1024;
518                    remaining_bytes = total - loaded;
519                    seconds_remaining = seconds_elapsed ? remaining_bytes / bytes_per_second : 'calculating';
520
521                    if (onProgress)
522                        onProgress(percentComplete, secondsToString(seconds_remaining), Kbytes_per_second, loaded);
523                }
524            }, false);
525            //if (window._env == "guest") {
526            //    xhr.onreadystatechange = function (e) {
527            //        if (xhr.readyState === 4) {
528            //            if (xhr.status === 200 || xhr.status === 201) {
529            //                percentComplete = 100;
530            //                insertUploadActivity(htmlFile, fileRequest, seconds_elapsed, uploadSessionInfo, null, null, extraData, checkinComment);
531            //            }
532            //        }
533            //    }
534            //}
535
536            return xhr;
537        }
538    });
539}
540
541var insertUploadActivity = function (file, fileRequest, secondsElapsed, uploadSessionInfo, type, chunkNum, extraData, checkinComment) {
542    var data = jQuery.extend({
543        fileName: file != null ? file.name : null,
544        fileSize: file != null ? file.size : null,
545        timeTakenInSeconds: Math.round(secondsElapsed),
546        uploadPath: fileRequest != null ? fileRequest.key : null,
547        SessionInfo: uploadSessionInfo,
548        uploadActivityType: type,
549        failedAtChunk: chunkNum,
550        CheckInComments: checkinComment
551    }, extraData);
552    ajax({
553        url: AppUrls.InsertUploadActivity,
554        method: "POST",
555        data: data
556    });
557}
558var sendCheckInUploadMail = function (fileKeyStr, parentPath, checkinEmail, checkinComments, isSendEmail, uploadSessionInfo) {
559    ajax({
560        url: AppUrls.SendCheckinUploadMail,
561        method: "POST",
562        data: {
563            keySsv: fileKeyStr,
564            parentPath: parentPath,
565            checkinEmailAddress: checkinEmail,
566            checkinComments: checkinComments,
567            isSendCheckinEmail: isSendEmail,
568            SessionInfo: 'WEB-' + uploadSessionInfo
569        }
570    }).then(function (response) {
571        var fileKeys = fileKeyStr.split("\n");
572        for (let i = 0; i < fileKeys.length; i++) {
573            let fetchSourcekey = fasTable.getObjectByKey(fileKeys[i]);
574            if (fetchSourcekey && fetchSourcekey.fileFolderProperties) {
575                fetchSourcekey.fileFolderProperties.isFileCheckedOut = false;
576                fasTable.updateObjectRow(fetchSourcekey, true);
577            }
578        }
579
580    });
581}
582var uploadPostProcess = function (fileKeyStr, parentPath, uploadSessionInfo) {
583    if (!uploadSessionInfo.startsWith("WEB-")) {
584        uploadSessionInfo = 'WEB-' + uploadSessionInfo;
585    }
586    ajax({
587        url: AppUrls.PostUploadProcess,
588        method: "POST",
589        data: {
590            keySsv: fileKeyStr,
591            parentPath: parentPath,
592            SessionInfo: uploadSessionInfo
593        }
594    });
595}
596function secondsToString(seconds) {
597    if (seconds <= 1)
598        return "processing uploaded item";
599    var numyears = Math.floor(seconds / 31536000);
600    var numdays = Math.floor((seconds % 31536000) / 86400);
601    var numhours = Math.floor(((seconds % 31536000) % 86400) / 3600);
602    var numminutes = Math.floor((((seconds % 31536000) % 86400) % 3600) / 60);
603    var numseconds = (((seconds % 31536000) % 86400) % 3600) % 60;
604    var str = "";
605    if (numyears > 0)
606        str += Math.round(numyears) + " " + Humanize.pluralize(numyears, "year", "years") + " ";
607    if (numdays > 0)
608        str += Math.round(numdays) + " " + Humanize.pluralize(numdays, "day", "days") + " ";
609    if (numhours > 0)
610        str += Math.round(numhours) + " " + Humanize.pluralize(numhours, "hour", "hours") + " ";
611    if (numminutes > 0)
612        str += Math.round(numminutes) + " " + Humanize.pluralize(numminutes, "minute", "minutes") + " ";
613    if (numseconds > 0)
614        str += Math.round(numseconds) + " " + Humanize.pluralize(numseconds, "second", "seconds");
615    return str + " left";
616
617}
618
619var initDownloadProgress = function (stopAutoClose, timeout, floatingIndicatorOption) {
620    timeout = timeout || 30;
621    let timerId = null;
622    let m = showAsModal('',
623        {
624            body: jQuery("#downloadProgress").clone().html(),
625            hideclose: true,
626            hideok: true,
627            hideHeader: true,
628            aftershow: function () {
629                m.find("#loader").html(typeof htmlJs != 'undefined' ? htmlJs.getMiniLoader() : fasModel.getMiniLoader());
630            }
631        });
632
633    m.on("hide.bs.modal", function (e) {
634        var hideEnable = m.data('hideEnable');
635        return hideEnable == true;
636    });
637
638    m.enableHide = function () {
639        m.data('hideEnable', true);
640    };
641
642    m.close = function (clearIntreval = true) {
643        m.enableHide();
644        m.modal('hide');
645        if (clearIntreval) {
646            clearTimeout(timerId);
647            if (m.floatingIndicator)
648                m.floatingIndicator.close();
649        }
650    };
651
652    if (!stopAutoClose) {
653        //hide after 10 seconds
654        timerId = setTimeout(function () {
655            if (m) {
656                m.close(false);
657                if (floatingIndicatorOption) {
658                    m.floatingIndicator = createFloatingIndicator(floatingIndicatorOption);
659                }
660            }
661        }, 10000)
662    }
663    else {
664        timerId = setTimeout(function () {
665            if (m) {
666                m.close(false);
667
668                if (floatingIndicatorOption) {
669                    m.floatingIndicator = createFloatingIndicator(floatingIndicatorOption);
670                }
671            }
672        }, timeout * 1000)
673    }
674    return m;
675}
676
677function createFloatingIndicator(options) {
678    if (!options)
679        options = {};
680
681    let defaults = {
682        centerIcon: 'fa-download',
683    };
684    let settings = $.extend({}, defaults, options);
685
686    let btn = createElement('div', {
687        className: 'bg-secondary text-white cursor-pointer position-fixed bottom-0 end-0 m-4 rounded-circle shadow d-flex align-items-center justify-content-center',
688        style: 'width:50px;height:50px;z-index:1050;'
689    });
690    let loader = createElement('span', {
691        className: 'position-relative d-inline-flex align-items-center justify-content-center',
692        style: 'width:32px;height:32px;'
693    });
694    let spinner = createElement('span', {
695        className: 'spinner-border',
696        style: 'width:32px;height:32px;'
697    });
698    let downloadIcon = createElement('i', {
699        className: settings.centerIcon + ' fa position-absolute top-50 start-50 translate-middle',
700        style: 'font-size:0.75rem;'
701    });
702    loader.appendChild(spinner);
703    loader.appendChild(downloadIcon);
704    btn.appendChild(loader);
705    btn.addEventListener('mouseenter', function () {
706        downloadIcon.classList.replace(settings.centerIcon, 'fa-times');
707        $(btn).tooltip({ title: 'Close' });
708    });
709    btn.addEventListener('mouseleave', function () {
710        downloadIcon.classList.replace('fa-times', settings.centerIcon);
711    });
712    btn.addEventListener('click', function () {
713        if (downloadIcon.classList.contains('fa-times')) {
714            $(btn).tooltip('dispose');
715            btn.close();
716        }
717    });
718    btn.close = function () {
719        dispatchCustomEvent('close', null, btn);
720        btn.remove();
721    }
722    $('body').append(btn);
723    return btn;
724}

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.