UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

384 lines 50.3 kB
import { Injectable } from '@angular/core'; import { InventoryBinaryService, SystemOptionsService } from '@c8y/client'; import { every, first, flatten, get, isNaN, isUndefined, keys, map, uniq, min } from 'lodash-es'; import { saveAs } from 'file-saver'; import { BehaviorSubject, Observable, of, throwError } from 'rxjs'; import { catchError, switchMap, startWith, share } from 'rxjs/operators'; import * as i0 from "@angular/core"; import * as i1 from "@c8y/client"; export var GENERIC_FILE_TYPE; (function (GENERIC_FILE_TYPE) { GENERIC_FILE_TYPE["ARCHIVE"] = "archive"; GENERIC_FILE_TYPE["AUDIO"] = "audio"; GENERIC_FILE_TYPE["CODE"] = "code"; GENERIC_FILE_TYPE["EXCEL"] = "excel"; GENERIC_FILE_TYPE["IMAGE"] = "image"; GENERIC_FILE_TYPE["PDF"] = "pdf"; GENERIC_FILE_TYPE["POWERPOINT"] = "powerpoint"; GENERIC_FILE_TYPE["TEXT"] = "text"; GENERIC_FILE_TYPE["VIDEO"] = "video"; GENERIC_FILE_TYPE["WORD"] = "word"; GENERIC_FILE_TYPE["EPL"] = "epl"; })(GENERIC_FILE_TYPE || (GENERIC_FILE_TYPE = {})); export class FilesService { constructor(systemOptionsService, inventoryBinaryService) { this.systemOptionsService = systemOptionsService; this.inventoryBinaryService = inventoryBinaryService; this.DEFAULT_BYTES_LIMIT = 52428800; this.FILENAME_MAX_LENGTH = 128; this.fileTypeExtensionsMap = { [GENERIC_FILE_TYPE.ARCHIVE]: { exts: ['7z', 'apk', 'cab', 'gz', 'iso', 'jar', 'rar', 'tar', 'zip'] }, [GENERIC_FILE_TYPE.AUDIO]: { exts: [ '3gp', 'aiff', 'aac', 'amr', 'm4a', 'm4p', 'mp3', 'oga', 'ogg', 'raw', 'wav', 'wma' ] }, [GENERIC_FILE_TYPE.CODE]: { exts: ['aspx', 'exe', 'htm', 'html', 'jad', 'js', 'json', 'jsp', 'php', 'xml'] }, [GENERIC_FILE_TYPE.EXCEL]: { exts: ['xls', 'xlsx'] }, [GENERIC_FILE_TYPE.IMAGE]: { exts: ['bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff', 'svg', 'ico', 'apng', 'webp'] }, [GENERIC_FILE_TYPE.PDF]: { exts: ['pdf'] }, [GENERIC_FILE_TYPE.POWERPOINT]: { exts: ['ppt', 'pptx'] }, [GENERIC_FILE_TYPE.TEXT]: { exts: ['txt'] }, [GENERIC_FILE_TYPE.VIDEO]: { exts: ['asf', 'avi', 'flv', 'mov', 'mp4', 'ogv', 'qt', 'rm', 'rmvb', 'wmv', '3gp'] }, [GENERIC_FILE_TYPE.WORD]: { exts: ['doc', 'docx'] }, [GENERIC_FILE_TYPE.EPL]: { exts: ['mon'] } }; this.fileSizeLimitCfg = { systemOption: { category: 'files', key: 'max.size' }, defaultBytesLimit: this.DEFAULT_BYTES_LIMIT, actualBytesLimit: undefined }; } /** * Checks if files have valid size. * @param files Files to check. * @returns Returns true if each file has the correct size. */ async haveValidSizes(files, maxFileSizeInBytes) { const limit = min([maxFileSizeInBytes, await this.loadBytesSizeLimit()]); return every(files, (f) => { return this.size(f) <= limit; }); } /** * Checks the system file size limit, if not available returns the default value. * Default limit: [DEFAULT_BYTES_LIMIT]{@link DEFAULT_BYTES_LIMIT} * @returns Returns promise with the limit value. */ async loadBytesSizeLimit() { let bytesLimit = this.DEFAULT_BYTES_LIMIT; if (this.fileSizeLimitCfg.actualBytesLimit) { return this.fileSizeLimitCfg.actualBytesLimit; } const { systemOption } = this.fileSizeLimitCfg; try { const { data: { value: actualBytesLimit } } = await this.systemOptionsService.detail(systemOption); if (!actualBytesLimit) { return bytesLimit; } const parsedActualBytesLimit = parseInt(actualBytesLimit, 10); if (isNaN(parsedActualBytesLimit)) { return bytesLimit; } this.fileSizeLimitCfg.actualBytesLimit = parsedActualBytesLimit; bytesLimit = parsedActualBytesLimit; } catch (error) { // do nothing } return bytesLimit; } /** * Checks the size of the file * @param file File to check. * @returns Returns size of the file in bytes. */ size(file) { const fileLength = get(file, 'length') || get(file, 'size'); const attachments = get(file, '_attachments'); const attachmentsObj = get(attachments, first(keys(attachments))); return isUndefined(fileLength) ? get(attachmentsObj, 'length') : fileLength; } /** * Checks whether files have allowed extensions. * If the accept parameter is not specified, all extensions are accepted. * @param files Files to check. * @param accept String of comma separated file extensions and generic types ([GENERIC_FILE_TYPE]{@link GENERIC_FILE_TYPE}), e.g. .zip,.7z,excel. * @returns Returns true if each file has allowed extension. */ haveValidExtensions(files, accept) { if (!accept) { return true; } const filesArray = files.item ? Array.from(files) : Array.isArray(files) ? files : [files]; const filesExts = filesArray.map((file) => this.getFileExtension(file)?.toLowerCase()); const allowedExts = this.extractFileExtensions(accept); return filesExts.every(ext => allowedExts.includes(ext)); } /** * Checks if file names have allowed extension. * If the accept parameter is not specified, all extensions are accepted. * @param fileNames The file names to check. * @param accept String of comma separated file extensions and generic types ([GENERIC_FILE_TYPE]{@link GENERIC_FILE_TYPE}), e.g. .zip,.7z,excel. * @returns Returns true if each file has allowed extension. */ fileNamesHaveValidExtension(fileNames, accept) { if (!accept) { return true; } fileNames = Array.isArray(fileNames) ? fileNames : [fileNames]; const filesExts = fileNames.map((file) => this.getFileExtension(file)?.toLowerCase()); const allowedExts = this.extractFileExtensions(accept); return filesExts.every(ext => allowedExts.includes(ext)); } /** * Checks if each file has a valid filename length. * @param files Files to check. * @returns Returns true if each file has a valid filename length. */ checkMaxLength(files) { return every(files, (f) => { return this.FILENAME_MAX_LENGTH > f.name.length; }); } /** * Extracts the file extension. * @param fileOrFileName File or name of file from which the extension should be extracted. * @returns Returns the file extension or undefined if the file has no extension. */ getFileExtension(fileOrFileName) { const fileNameAndFileExt = (typeof fileOrFileName === 'string' ? fileOrFileName : fileOrFileName.name).split('.'); if (fileNameAndFileExt.length === 1) { // no file ext return undefined; } return fileNameAndFileExt.pop(); } /** * List of file extensions. * @returns Returns list of file extensions. */ getFileExtensions() { return uniq(flatten(map(this.fileTypeExtensionsMap, ({ exts }) => exts))); } /** * The list of generic file types. * @returns Returns the list of generic file types. */ getGenericFileTypes() { return Object.keys(this.fileTypeExtensionsMap); } /** * @ignore */ mapGenericFileTypesToExtensions(genericFileTypes = []) { const fileExts = genericFileTypes.map(gT => { const { exts } = this.fileTypeExtensionsMap[gT]; return exts; }); return uniq(flatten(fileExts)); } /** * Extracts a list of file extensions from a string. * Can accept generic file types check: [GENERIC_FILE_TYPE]{@link GENERIC_FILE_TYPE}. * * @param str String from which the file extensions are extracted (comma separated values). * Accepted string format: * * ".zip,.iso", * * "zip,ISO", * * "archive". * Important: generic types cannot contain a dot. All values with a dot are treated as a normal extension. * @returns Returns a list of the file extensions. */ extractFileExtensions(str) { if (!str) { return []; } const types = str.split(',').map(t => t.toLowerCase().trim()); const genericTypes = types.filter((t) => this.isGenericType(t)); const defaultFileExts = types.filter((t) => !this.isGenericType(t)); const allTypes = [ ...this.mapGenericFileTypesToExtensions(genericTypes), ...defaultFileExts ].map(t => t.replace('.', '')); return uniq(allTypes); } /** * Converts a file to a base64 image string. * * @param file The file to convert to base 64. * @returns The image string in base64 format. */ toBase64(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => resolve(String(reader.result)); reader.onerror = error => reject(error); }); } /** * Allows to get a File representation of an managed object binary. Can be used * to convert this file toBase64 to show it to the end-user. * @param binary The binary managed object * @returns The file representation. */ async getFile(binary) { const res = await this.inventoryBinaryService.download(binary.id); const arrayBuffer = await res.arrayBuffer(); return new File([arrayBuffer], binary.name, { type: binary.contentType }); } /** * Allows to calculate the hash sum of the provided file. * @param file The file to hash. * @returns The SHA-256 hash of the file. */ async getHashSumOfFile(file) { const buffer = await file.arrayBuffer(); const hashBuffer = await crypto.subtle.digest('SHA-256', buffer); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map(bytes => bytes.toString(16).padStart(2, '0')).join(''); return hashHex; } /** * Allows to download a file (opens the browser download prompt). * @param binary The binary managed object. */ async download(binary) { const file = await this.getFile(binary); saveAs(file); } /** * Loads the file to JavaScript memory. * Returns an observable that emits progression status object, * and after download is completed, blob property is populated with Blob result object. * Unsubscribing from the returned observable aborts the file fetch request. * * @param binary The binary managed object. */ fetchFileWithProgress$(binary) { const progress = { totalBytes: +binary.length, bufferedBytes: 0, percentage: 0, bytesPerSecond: 0 }; return of(new AbortController()).pipe(switchMap(async (abortController) => ({ abortController, startTimestamp: new Date().getTime(), response: await this.inventoryBinaryService.download(binary.id, { signal: abortController.signal }) })), switchMap(({ response, abortController, startTimestamp }) => this.processResponse$(abortController, response, startTimestamp, progress, binary.type)), startWith(progress), share(), catchError(err => throwError(err))); } uploadFileWithProgress$(file) { const uploadStartTimestamp = new Date().getTime(); const subject = new BehaviorSubject({ percentage: 0, totalBytes: null, bufferedBytes: 0, bytesPerSecond: 0 }); const onProgress = (event) => { const eventTimestamp = new Date().getTime(); const duration = eventTimestamp - uploadStartTimestamp; subject.next({ percentage: Math.round((event.loaded / event.total) * 100), totalBytes: event.total, bufferedBytes: event.loaded, bytesPerSecond: Math.round(event.loaded / Math.round(duration / 1000)) }); }; const xhr = this.inventoryBinaryService.createWithProgress(file, onProgress); const uploadPromise = this.inventoryBinaryService.getXMLHttpResponse(xhr); uploadPromise.then(() => { subject.complete(); }); return subject.asObservable(); } processResponse$(abortController, response, startTimestamp, progress, binaryType) { return new Observable(sub => { const reader = response.body.getReader(); const chunks = []; const readStream = async () => { try { while (true) { const { done, value } = await reader.read(); if (done) { progress.blob = new Blob(chunks, { type: binaryType }); sub.next({ ...progress }); sub.complete(); break; } chunks.push(value); progress.bufferedBytes += value.length; const currentTimestamp = new Date().getTime(); const timestampDiff = currentTimestamp - startTimestamp; progress.bytesPerSecond = Math.round(progress.bufferedBytes / Math.round(timestampDiff / 1000)); progress.percentage = Math.round((progress.bufferedBytes / progress.totalBytes) * 100); sub.next({ ...progress }); } } catch (e) { abortController.abort(); sub.error(e); } }; readStream(); return { unsubscribe() { abortController.abort(); sub.complete(); } }; }); } isGenericType(type) { return Object.values(GENERIC_FILE_TYPE).includes(type); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilesService, deps: [{ token: i1.SystemOptionsService }, { token: i1.InventoryBinaryService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilesService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilesService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: i1.SystemOptionsService }, { type: i1.InventoryBinaryService }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZXMuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2NvcmUvY29tbW9uL2ZpbGVzLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBR0wsc0JBQXNCLEVBQ3RCLG9CQUFvQixFQUNyQixNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ2pHLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDcEMsT0FBTyxFQUFFLGVBQWUsRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLFVBQVUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNuRSxPQUFPLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7OztBQVd6RSxNQUFNLENBQU4sSUFBWSxpQkFZWDtBQVpELFdBQVksaUJBQWlCO0lBQzNCLHdDQUFtQixDQUFBO0lBQ25CLG9DQUFlLENBQUE7SUFDZixrQ0FBYSxDQUFBO0lBQ2Isb0NBQWUsQ0FBQTtJQUNmLG9DQUFlLENBQUE7SUFDZixnQ0FBVyxDQUFBO0lBQ1gsOENBQXlCLENBQUE7SUFDekIsa0NBQWEsQ0FBQTtJQUNiLG9DQUFlLENBQUE7SUFDZixrQ0FBYSxDQUFBO0lBQ2IsZ0NBQVcsQ0FBQTtBQUNiLENBQUMsRUFaVyxpQkFBaUIsS0FBakIsaUJBQWlCLFFBWTVCO0FBRUQsTUFBTSxPQUFPLFlBQVk7SUE4RHZCLFlBQ1Usb0JBQTBDLEVBQzFDLHNCQUE4QztRQUQ5Qyx5QkFBb0IsR0FBcEIsb0JBQW9CLENBQXNCO1FB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Q0FBQyxDQUFDO1lBQ0YsVUFBVSxFQUFFLENBQUM7WUFFYixPQUFPO2dCQUNMLFdBQVc7b0JBQ1QsZUFBZSxDQUFDLEtBQUssRUFBRSxDQUFDO29CQUN4QixHQUFHLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQ2pCLENBQUM7YUFDRixDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU8sYUFBYSxDQUFDLElBQVk7UUFDaEMsT0FBTyxNQUFNLENBQUMsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUMsUUFBUSxDQUFDLElBQXlCLENBQUMsQ0FBQztJQUM5RSxDQUFDOytHQXpaVSxZQUFZO21IQUFaLFlBQVksY0FEQyxNQUFNOzs0RkFDbkIsWUFBWTtrQkFEeEIsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1xuICBJRmV0Y2hSZXNwb25zZSxcbiAgSU1hbmFnZWRPYmplY3RCaW5hcnksXG4gIEludmVudG9yeUJpbmFyeVNlcnZpY2UsXG4gIFN5c3RlbU9wdGlvbnNTZXJ2aWNlXG59IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7IGV2ZXJ5LCBmaXJzdCwgZmxhdHRlbiwgZ2V0LCBpc05hTiwgaXNVbmRlZmluZWQsIGtleXMsIG1hcCwgdW5pcSwgbWluIH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IHNhdmVBcyB9IGZyb20gJ2ZpbGUtc2F2ZXInO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBPYnNlcnZhYmxlLCBvZiwgdGhyb3dFcnJvciB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgY2F0Y2hFcnJvciwgc3dpdGNoTWFwLCBzdGFydFdpdGgsIHNoYXJlIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgU3RyZWFtIH0gZnJvbSAnc3RyZWFtJztcblxuZXhwb3J0IGludGVyZmFjZSBJRmV0Y2hXaXRoUHJvZ3Jlc3Mge1xuICB0b3RhbEJ5dGVzOiBudW1iZXI7XG4gIGJ1ZmZlcmVkQnl0ZXM6IG51bWJlcjtcbiAgcGVyY2VudGFnZTogbnVtYmVyO1xuICBieXRlc1BlclNlY29uZDogbnVtYmVyO1xuICBibG9iPzogQmxvYjtcbn1cblxuZXhwb3J0IGVudW0gR0VORVJJQ19GSUxFX1RZUEUge1xuICBBUkNISVZFID0gJ2FyY2hpdmUnLFxuICBBVURJTyA9ICdhdWRpbycsXG4gIENPREUgPSAnY29kZScsXG4gIEVYQ0VMID0gJ2V4Y2VsJyxcbiAgSU1BR0UgPSAnaW1hZ2UnLFxuICBQREYgPSAncGRmJyxcbiAgUE9XRVJQT0lOVCA9ICdwb3dlcnBvaW50JyxcbiAgVEVYVCA9ICd0ZXh0JyxcbiAgVklERU8gPSAndmlkZW8nLFxuICBXT1JEID0gJ3dvcmQnLFxuICBFUEwgPSAnZXBsJ1xufVxuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBGaWxlc1NlcnZpY2Uge1xuICByZWFkb25seSBERUZBVUxUX0JZVEVTX0xJTUlUID0gNTI0Mjg4MDA7XG4gIHJlYWRvbmx5IEZJTEVOQU1FX01BWF9MRU5HVEggPSAxMjg7XG5cbiAgZmlsZVR5cGVFeHRlbnNpb25zTWFwID0ge1xuICAgIFtHRU5FUklDX0ZJTEVfVFlQRS5BUkNISVZFXToge1xuICAgICAgZXh0czogWyc3eicsICdhcGsnLCAnY2FiJywgJ2d6JywgJ2lzbycsICdqYXInLCAncmFyJywgJ3RhcicsICd6aXAnXSBhcyBjb25zdFxuICAgIH0sXG4gICAgW0dFTkVSSUNfRklMRV9UWVBFLkFVRElPXToge1xuICAgICAgZXh0czogW1xuICAgICAgICAnM2dwJyxcbiAgICAgICAgJ2FpZmYnLFxuICAgICAgICAnYWFjJyxcbiAgICAgICAgJ2FtcicsXG4gICAgICAgICdtNGEnLFxuICAgICAgICAnbTRwJyxcbiAgICAgICAgJ21wMycsXG4gICAgICAgICdvZ2EnLFxuICAgICAgICAnb2dnJyxcbiAgICAgICAgJ3JhdycsXG4gICAgICAgICd3YXYnLFxuICAgICAgICAnd21hJ1xuICAgICAgXSBhcyBjb25zdFxuICAgIH0sXG4gICAgW0dFTkVSSUNfRklMRV9UWVBFLkNPREVdOiB7XG4gICAgICBleHRzOiBbJ2FzcHgnLCAnZXhlJywgJ2h0bScsICdodG1sJywgJ2phZCcsICdqcycsICdqc29uJywgJ2pzcCcsICdwaHAnLCAneG1sJ10gYXMgY29uc3RcbiAgICB9LFxuICAgIFtHRU5FUklDX0ZJTEVfVFlQRS5FWENFTF06IHtcbiAgICAgIGV4dHM6IFsneGxzJywgJ3hsc3gnXSBhcyBjb25zdFxuICAgIH0sXG4gICAgW0dFTkVSSUNfRklMRV9UWVBFLklNQUdFXToge1xuICAgICAgZXh0czogWydibXAnLCAnZ2lmJywgJ2pwZWcnLCAnanBnJywgJ3BuZycsICd0aWZmJywgJ3N2ZycsICdpY28nLCAnYXBuZycsICd3ZWJwJ10gYXMgY29uc3RcbiAgICB9LFxuICAgIFtHRU5FUklDX0ZJTEVfVFlQRS5QREZdOiB7XG4gICAgICBleHRzOiBbJ3BkZiddIGFzIGNvbnN0XG4gICAgfSxcbiAgICBbR0VORVJJQ19GSUxFX1RZUEUuUE9XRVJQT0lOVF06IHtcbiAgICAgIGV4dHM6IFsncHB0JywgJ3BwdHgnXSBhcyBjb25zdFxuICAgIH0sXG4gICAgW0dFTkVSSUNfRklMRV9UWVBFLlRFWFRdOiB7XG4gICAgICBleHRzOiBbJ3R4dCddIGFzIGNvbnN0XG4gICAgfSxcbiAgICBbR0VORVJJQ19GSUxFX1RZUEUuVklERU9dOiB7XG4gICAgICBleHRzOiBbJ2FzZicsICdhdmknLCAnZmx2JywgJ21vdicsICdtcDQnLCAnb2d2JywgJ3F0JywgJ3JtJywgJ3JtdmInLCAnd212JywgJzNncCddIGFzIGNvbnN0XG4gICAgfSxcbiAgICBbR0VORVJJQ19GSUxFX1RZUEUuV09SRF06IHtcbiAgICAgIGV4dHM6IFsnZG9jJywgJ2RvY3gnXSBhcyBjb25zdFxuICAgIH0sXG4gICAgW0dFTkVSSUNfRklMRV9UWVBFLkVQTF06IHtcbiAgICAgIGV4dHM6IFsnbW9uJ10gYXMgY29uc3RcbiAgICB9XG4gIH0gYXMgY29uc3Qgc2F0aXNmaWVzIHsgW2tleTogc3RyaW5nXTogeyBleHRzOiBSZWFkb25seUFycmF5PHN0cmluZz4gfSB9O1xuXG4gIHByaXZhdGUgZmlsZVNpemVMaW1pdENmZyA9IHtcbiAgICBzeXN0ZW1PcHRpb246IHtcbiAgICAgIGNhdGVnb3J5OiAnZmlsZXMnLFxuICAgICAga2V5OiAnbWF4LnNpemUnXG4gICAgfSxcbiAgICBkZWZhdWx0Qnl0ZXNMaW1pdDogdGhpcy5ERUZBVUxUX0JZVEVTX0xJTUlULFxuICAgIGFjdHVhbEJ5dGVzTGltaXQ6IHVuZGVmaW5lZFxuICB9O1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgc3lzdGVtT3B0aW9uc1NlcnZpY2U6IFN5c3RlbU9wdGlvbnNTZXJ2aWNlLFxuICAgIHByaXZhdGUgaW52ZW50b3J5QmluYXJ5U2VydmljZTogSW52ZW50b3J5QmluYXJ5U2VydmljZVxuICApIHt9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiBmaWxlcyBoYXZlIHZhbGlkIHNpemUuXG4gICAqIEBwYXJhbSBmaWxlcyBGaWxlcyB0byBjaGVjay5cbiAgICogQHJldHVybnMgUmV0dXJucyB0cnVlIGlmIGVhY2ggZmlsZSBoYXMgdGhlIGNvcnJlY3Qgc2l6ZS5cbiAgICovXG4gIGFzeW5jIGhhdmVWYWxpZFNpemVzKGZpbGVzOiBGaWxlTGlzdCwgbWF4RmlsZVNpemVJbkJ5dGVzPzogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgbGltaXQgPSBtaW4oW21heEZpbGVTaXplSW5CeXRlcywgYXdhaXQgdGhpcy5sb2FkQnl0ZXNTaXplTGltaXQoKV0pO1xuICAgIHJldHVybiBldmVyeShmaWxlcywgKGY6IEZpbGUpID0+IHtcbiAgICAgIHJldHVybiB0aGlzLnNpemUoZikgPD0gbGltaXQ7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIHRoZSBzeXN0ZW0gZmlsZSBzaXplIGxpbWl0LCBpZiBub3QgYXZhaWxhYmxlIHJldHVybnMgdGhlIGRlZmF1bHQgdmFsdWUuXG4gICAqIERlZmF1bHQgbGltaXQ6IFtERUZBVUxUX0JZVEVTX0xJTUlUXXtAbGluayBERUZBVUxUX0JZVEVTX0xJTUlUfVxuICAgKiBAcmV0dXJucyBSZXR1cm5zIHByb21pc2Ugd2l0aCB0aGUgbGltaXQgdmFsdWUuXG4gICAqL1xuICBhc3luYyBsb2FkQnl0ZXNTaXplTGltaXQoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBsZXQgYnl0ZXNMaW1pdCA9IHRoaXMuREVGQVVMVF9CWVRFU19MSU1JVDtcbiAgICBpZiAodGhpcy5maWxlU2l6ZUxpbWl0Q2ZnLmFjdHVhbEJ5dGVzTGltaXQpIHtcbiAgICAgIHJldHVybiB0aGlzLmZpbGVTaXplTGltaXRDZmcuYWN0dWFsQnl0ZXNMaW1pdDtcbiAgICB9XG4gICAgY29uc3QgeyBzeXN0ZW1PcHRpb24gfSA9IHRoaXMuZmlsZVNpemVMaW1pdENmZztcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCB7XG4gICAgICAgIGRhdGE6IHsgdmFsdWU6IGFjdHVhbEJ5dGVzTGltaXQgfVxuICAgICAgfSA9IGF3YWl0IHRoaXMuc3lzdGVtT3B0aW9uc1NlcnZpY2UuZGV0YWlsKHN5c3RlbU9wdGlvbik7XG5cbiAgICAgIGlmICghYWN0dWFsQnl0ZXNMaW1pdCkge1xuICAgICAgICByZXR1cm4gYnl0ZXNMaW1pdDtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcGFyc2VkQWN0dWFsQnl0ZXNMaW1pdCA9IHBhcnNlSW50KGFjdHVhbEJ5dGVzTGltaXQsIDEwKTtcbiAgICAgIGlmIChpc05hTihwYXJzZWRBY3R1YWxCeXRlc0xpbWl0KSkge1xuICAgICAgICByZXR1cm4gYnl0ZXNMaW1pdDtcbiAgICAgIH1cblxuICAgICAgdGhpcy5maWxlU2l6ZUxpbWl0Q2ZnLmFjdHVhbEJ5dGVzTGltaXQgPSBwYXJzZWRBY3R1YWxCeXRlc0xpbWl0O1xuICAgICAgYnl0ZXNMaW1pdCA9IHBhcnNlZEFjdHVhbEJ5dGVzTGltaXQ7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIC8vIGRvIG5vdGhpbmdcbiAgICB9XG4gICAgcmV0dXJuIGJ5dGVzTGltaXQ7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIHRoZSBzaXplIG9mIHRoZSBmaWxlXG4gICAqIEBwYXJhbSBmaWxlIEZpbGUgdG8gY2hlY2suXG4gICAqIEByZXR1cm5zIFJldHVybnMgc2l6ZSBvZiB0aGUgZmlsZSBpbiBieXRlcy5cbiAgICovXG4gIHNpemUoZmlsZTogRmlsZSB8IElNYW5hZ2VkT2JqZWN0QmluYXJ5KTogbnVtYmVyIHtcbiAgICBjb25zdCBmaWxlTGVuZ3RoID0gZ2V0KGZpbGUsICdsZW5ndGgnKSB8fCBnZXQoZmlsZSwgJ3NpemUnKTtcbiAgICBjb25zdCBhdHRhY2htZW50cyA9IGdldChmaWxlLCAnX2F0dGFjaG1lbnRzJyk7XG4gICAgY29uc3QgYXR0YWNobWVudHNPYmogPSBnZXQoYXR0YWNobWVudHMsIGZpcnN0KGtleXMoYXR0YWNobWVudHMpKSk7XG4gICAgcmV0dXJuIGlzVW5kZWZpbmVkKGZpbGVMZW5ndGgpID8gZ2V0KGF0dGFjaG1lbnRzT2JqLCAnbGVuZ3RoJykgOiBmaWxlTGVuZ3RoO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyB3aGV0aGVyIGZpbGVzIGhhdmUgYWxsb3dlZCBleHRlbnNpb25zLlxuICAgKiBJZiB0aGUgYWNjZXB0IHBhcmFtZXRlciBpcyBub3Qgc3BlY2lmaWVkLCBhbGwgZXh0ZW5zaW9ucyBhcmUgYWNjZXB0ZWQuXG4gICAqIEBwYXJhbSBmaWxlcyBGaWxlcyB0byBjaGVjay5cbiAgICogQHBhcmFtIGFjY2VwdCBTdHJpbmcgb2YgY29tbWEgc2VwYXJhdGVkIGZpbGUgZXh0ZW5zaW9ucyBhbmQgZ2VuZXJpYyB0eXBlcyAoW0dFTkVSSUNfRklMRV9UWVBFXXtAbGluayBHRU5FUklDX0ZJTEVfVFlQRX0pLCBlLmcuIC56aXAsLjd6LGV4Y2VsLlxuICAgKiBAcmV0dXJucyAgUmV0dXJucyB0cnVlIGlmIGVhY2ggZmlsZSBoYXMgYWxsb3dlZCBleHRlbnNpb24uXG4gICAqL1xuICBoYXZlVmFsaWRFeHRlbnNpb25zKGZpbGVzOiBGaWxlTGlzdCB8IEZpbGUgfCBGaWxlW10sIGFjY2VwdDogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgaWYgKCFhY2NlcHQpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBjb25zdCBmaWxlc0FycmF5ID0gKGZpbGVzIGFzIEZpbGVMaXN0KS5pdGVtXG4gICAgICA/IEFycmF5LmZyb20oZmlsZXMgYXMgRmlsZUxpc3QpXG4gICAgICA6IEFycmF5LmlzQXJyYXkoZmlsZXMpXG4gICAgICAgID8gZmlsZXNcbiAgICAgICAgOiBbZmlsZXNdO1xuXG4gICAgY29uc3QgZmlsZXNFeHRzID0gZmlsZXNBcnJheS5tYXAoKGZpbGU6IEZpbGUpID0+IHRoaXMuZ2V0RmlsZUV4dGVuc2lvbihmaWxlKT8udG9Mb3dlckNhc2UoKSk7XG4gICAgY29uc3QgYWxsb3dlZEV4dHMgPSB0aGlzLmV4dHJhY3RGaWxlRXh0ZW5zaW9ucyhhY2NlcHQpO1xuICAgIHJldHVybiBmaWxlc0V4dHMuZXZlcnkoZXh0ID0+IGFsbG93ZWRFeHRzLmluY2x1ZGVzKGV4dCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiBmaWxlIG5hbWVzIGhhdmUgYWxsb3dlZCBleHRlbnNpb24uXG4gICAqIElmIHRoZSBhY2NlcHQgcGFyYW1ldGVyIGlzIG5vdCBzcGVjaWZpZWQsIGFsbCBleHRlbnNpb25zIGFyZSBhY2NlcHRlZC5cbiAgICogQHBhcmFtIGZpbGVOYW1lcyBUaGUgZmlsZSBuYW1lcyB0byBjaGVjay5cbiAgICogQHBhcmFtIGFjY2VwdCBTdHJpbmcgb2YgY29tbWEgc2VwYXJhdGVkIGZpbGUgZXh0ZW5zaW9ucyBhbmQgZ2VuZXJpYyB0eXBlcyAoW0dFTkVSSUNfRklMRV9UWVBFXXtAbGluayBHRU5FUklDX0ZJTEVfVFlQRX0pLCBlLmcuIC56aXAsLjd6LGV4Y2VsLlxuICAgKiBAcmV0dXJucyAgUmV0dXJucyB0cnVlIGlmIGVhY2ggZmlsZSBoYXMgYWxsb3dlZCBleHRlbnNpb24uXG4gICAqL1xuICBmaWxlTmFtZXNIYXZlVmFsaWRFeHRlbnNpb24oZmlsZU5hbWVzOiBzdHJpbmcgfCBzdHJpbmdbXSwgYWNjZXB0OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICBpZiAoIWFjY2VwdCkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGZpbGVOYW1lcyA9IEFycmF5LmlzQXJyYXkoZmlsZU5hbWVzKSA/IGZpbGVOYW1lcyA6IFtmaWxlTmFtZXNdO1xuICAgIGNvbnN0IGZpbGVzRXh0cyA9IGZpbGVOYW1lcy5tYXAoKGZpbGU6IHN0cmluZykgPT4gdGhpcy5nZXRGaWxlRXh0ZW5zaW9uKGZpbGUpPy50b0xvd2VyQ2FzZSgpKTtcbiAgICBjb25zdCBhbGxvd2VkRXh0cyA9IHRoaXMuZXh0cmFjdEZpbGVFeHRlbnNpb25zKGFjY2VwdCk7XG4gICAgcmV0dXJuIGZpbGVzRXh0cy5ldmVyeShleHQgPT4gYWxsb3dlZEV4dHMuaW5jbHVkZXMoZXh0KSk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGVhY2ggZmlsZSBoYXMgYSB2YWxpZCBmaWxlbmFtZSBsZW5ndGguXG4gICAqIEBwYXJhbSBmaWxlcyBGaWxlcyB0byBjaGVjay5cbiAgICogQHJldHVybnMgUmV0dXJucyB0cnVlIGlmIGVhY2ggZmlsZSBoYXMgYSB2YWxpZCBmaWxlbmFtZSBsZW5ndGguXG4gICAqL1xuICBjaGVja01heExlbmd0aChmaWxlczogRmlsZUxpc3QpOiBib29sZWFuIHtcbiAgICByZXR1cm4gZXZlcnkoZmlsZXMsIChmOiBGaWxlKSA9PiB7XG4gICAgICByZXR1cm4gdGhpcy5GSUxFTkFNRV9NQVhfTEVOR1RIID4gZi5uYW1lLmxlbmd0aDtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHRyYWN0cyB0aGUgZmlsZSBleHRlbnNpb24uXG4gICAqIEBwYXJhbSBmaWxlT3JGaWxlTmFtZSBGaWxlIG9yIG5hbWUgb2YgZmlsZSBmcm9tIHdoaWNoIHRoZSBleHRlbnNpb24gc2hvdWxkIGJlIGV4dHJhY3RlZC5cbiAgICogQHJldHVybnMgUmV0dXJucyB0aGUgZmlsZSBleHRlbnNpb24gb3IgdW5kZWZpbmVkIGlmIHRoZSBmaWxlIGhhcyBubyBleHRlbnNpb24uXG4gICAqL1xuICBnZXRGaWxlRXh0ZW5zaW9uKGZpbGVPckZpbGVOYW1lOiBGaWxlIHwgc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCBmaWxlTmFtZUFuZEZpbGVFeHQgPSAoXG4gICAgICB0eXBlb2YgZmlsZU9yRmlsZU5hbWUgPT09ICdzdHJpbmcnID8gZmlsZU9yRmlsZU5hbWUgOiBmaWxlT3JGaWxlTmFtZS5uYW1lXG4gICAgKS5zcGxpdCgnLicpO1xuICAgIGlmIChmaWxlTmFtZUFuZEZpbGVFeHQubGVuZ3RoID09PSAxKSB7XG4gICAgICAvLyBubyBmaWxlIGV4dFxuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgcmV0dXJuIGZpbGVOYW1lQW5kRmlsZUV4dC5wb3AoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMaXN0IG9mIGZpbGUgZXh0ZW5zaW9ucy5cbiAgICogQHJldHVybnMgUmV0dXJucyBsaXN0IG9mIGZpbGUgZXh0ZW5zaW9ucy5cbiAgICovXG4gIGdldEZpbGVFeHRlbnNpb25zKCk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gdW5pcShmbGF0dGVuKG1hcCh0aGlzLmZpbGVUeXBlRXh0ZW5zaW9uc01hcCwgKHsgZXh0cyB9KSA9PiBleHRzKSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBsaXN0IG9mIGdlbmVyaWMgZmlsZSB0eXBlcy5cbiAgICogQHJldHVybnMgUmV0dXJucyB0aGUgbGlzdCBvZiBnZW5lcmljIGZpbGUgdHlwZXMuXG4gICAqL1xuICBnZXRHZW5lcmljRmlsZVR5cGVzKCk6IEdFTkVSSUNfRklMRV9UWVBFW10ge1xuICAgIHJldHVybiBPYmplY3Qua2V5cyh0aGlzLmZpbGVUeXBlRXh0ZW5zaW9uc01hcCkgYXMgR0VORVJJQ19GSUxFX1RZUEVbXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAaWdub3JlXG4gICAqL1xuICBtYXBHZW5lcmljRmlsZVR5cGVzVG9FeHRlbnNpb25zKGdlbmVyaWNGaWxlVHlwZXM6IEdFTkVSSUNfRklMRV9UWVBFW10gPSBbXSk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCBmaWxlRXh0cyA9IGdlbmVyaWNGaWxlVHlwZXMubWFwKGdUID0+IHtcbiAgICAgIGNvbnN0IHsgZXh0cyB9ID0gdGhpcy5maWxlVHlwZUV4dGVuc2lvbnNNYXBbZ1RdO1xuICAgICAgcmV0dXJuIGV4dHM7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gdW5pcShmbGF0dGVuKGZpbGVFeHRzKSk7XG4gIH1cbiAgLyoqXG4gICAqIEV4dHJhY3RzIGEgbGlzdCBvZiBmaWxlIGV4dGVuc2lvbnMgZnJvbSBhIHN0cmluZy5cbiAgICogQ2FuIGFjY2VwdCBnZW5lcmljIGZpbGUgdHlwZXMgY2hlY2s6IFtHRU5FUklDX0ZJTEVfVFlQRV17QGxpbmsgR0VORVJJQ19GSUxFX1RZUEV9LlxuICAgKlxuICAgKiBAcGFyYW0gc3RyIFN0cmluZyBmcm9tIHdoaWNoIHRoZSBmaWxlIGV4dGVuc2lvbnMgYXJlIGV4dHJhY3RlZCAoY29tbWEgc2VwYXJhdGVkIHZhbHVlcykuXG4gICAqIEFjY2VwdGVkIHN0cmluZyBmb3JtYXQ6XG4gICAqICogXCIuemlwLC5pc29cIixcbiAgICogKiBcInppcCxJU09cIixcbiAgICogKiBcImFyY2hpdmVcIi5cbiAgICogSW1wb3J0YW50OiBnZW5lcmljIHR5cGVzIGNhbm5vdCBjb250YWluIGEgZG90LiBBbGwgdmFsdWVzIHdpdGggYSBkb3QgYXJlIHRyZWF0ZWQgYXMgYSBub3JtYWwgZXh0ZW5zaW9uLlxuICAgKiBAcmV0dXJucyBSZXR1cm5zIGEgbGlzdCBvZiB0aGUgZmlsZSBleHRlbnNpb25zLlxuICAgKi9cbiAgZXh0cmFjdEZpbGVFeHRlbnNpb25zKHN0cjogc3RyaW5nKTogc3RyaW5nW10ge1xuICAgIGlmICghc3RyKSB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuICAgIGNvbnN0IHR5cGVzID0gc3RyLnNwbGl0KCcsJykubWFwKHQgPT4gdC50b0xvd2VyQ2FzZSgpLnRyaW0oKSk7XG5cbiAgICBjb25zdCBnZW5lcmljVHlwZXMgPSB0eXBlcy5maWx0ZXIoKHQ6IHN0cmluZykgPT4gdGhpcy5pc0dlbmVyaWNUeXBlKHQpKTtcbiAgICBjb25zdCBkZWZhdWx0RmlsZUV4dHMgPSB0eXBlcy5maWx0ZXIoKHQ6IHN0cmluZykgPT4gIXRoaXMuaXNHZW5lcmljVHlwZSh0KSk7XG5cbiAgICBjb25zdCBhbGxUeXBlcyA9IFtcbiAgICAgIC4uLnRoaXMubWFwR2VuZXJpY0ZpbGVUeXBlc1RvRXh0ZW5zaW9ucyhnZW5lcmljVHlwZXMgYXMgR0VORVJJQ19GSUxFX1RZUEVbXSksXG4gICAgICAuLi5kZWZhdWx0RmlsZUV4dHNcbiAgICBdLm1hcCh0ID0+IHQucmVwbGFjZSgnLicsICcnKSk7XG5cbiAgICByZXR1cm4gdW5pcShhbGxUeXBlcyk7XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydHMgYSBmaWxlIHRvIGEgYmFzZTY0IGltYWdlIHN0cmluZy5cbiAgICpcbiAgICogQHBhcmFtIGZpbGUgVGhlIGZpbGUgdG8gY29udmVydCB0byBiYXNlIDY0LlxuICAgKiBAcmV0dXJucyBUaGUgaW1hZ2Ugc3RyaW5nIGluIGJhc2U2NCBmb3JtYXQuXG4gICAqL1xuICB0b0Jhc2U2NChmaWxlOiBGaWxlKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3QgcmVhZGVyID0gbmV3IEZpbGVSZWFkZXIoKTtcbiAgICAgIHJlYWRlci5yZWFkQXNEYXRhVVJMKGZpbGUpO1xuICAgICAgcmVhZGVyLm9ubG9hZCA9ICgpID0+IHJlc29sdmUoU3RyaW5nKHJlYWRlci5yZXN1bHQpKTtcbiAgICAgIHJlYWRlci5vbmVycm9yID0gZXJyb3IgPT4gcmVqZWN0KGVycm9yKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbGxvd3MgdG8gZ2V0IGEgRmlsZSByZXByZXNlbnRhdGlvbiBvZiBhbiBtYW5hZ2VkIG9iamVjdCBiaW5hcnkuIENhbiBiZSB1c2VkXG4gICAqIHRvIGNvbnZlcnQgdGhpcyBmaWxlIHRvQmFzZTY0IHRvIHNob3cgaXQgdG8gdGhlIGVuZC11c2VyLlxuICAgKiBAcGFyYW0gYmluYXJ5IFRoZSBiaW5hcnkgbWFuYWdlZCBvYmplY3RcbiAgICogQHJldHVybnMgVGhlIGZpbGUgcmVwcmVzZW50YXRpb24uXG4gICAqL1xuICBhc3luYyBnZXRGaWxlKGJpbmFyeTogSU1hbmFnZWRPYmplY3RCaW5hcnkpOiBQcm9taXNlPEZpbGU+IHtcbiAgICBjb25zdCByZXMgPSBhd2FpdCB0aGlzLmludmVudG9yeUJpbmFyeVNlcnZpY2UuZG93bmxvYWQoYmluYXJ5LmlkKTtcbiAgICBjb25zdCBhcnJheUJ1ZmZlciA9IGF3YWl0IHJlcy5hcnJheUJ1ZmZlcigpO1xuICAgIHJldHVybiBuZXcgRmlsZShbYXJyYXlCdWZmZXJdLCBiaW5hcnkubmFtZSwgeyB0eXBlOiBiaW5hcnkuY29udGVudFR5cGUgfSk7XG4gIH1cblxuICAvKipcbiAgICogQWxsb3dzIHRvIGNhbGN1bGF0ZSB0aGUgaGFzaCBzdW0gb2YgdGhlIHByb3ZpZGVkIGZpbGUuXG4gICAqIEBwYXJhbSBmaWxlIFRoZSBmaWxlIHRvIGhhc2guXG4gICAqIEByZXR1cm5zIFRoZSBTSEEtMjU2IGhhc2ggb2YgdGhlIGZpbGUuXG4gICAqL1xuICBhc3luYyBnZXRIYXNoU3VtT2ZGaWxlKGZpbGU6IEZpbGUgfCBCbG9iKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBidWZmZXIgPSBhd2FpdCBmaWxlLmFycmF5QnVmZmVyKCk7XG4gICAgY29uc3QgaGFzaEJ1ZmZlciA9IGF3YWl0IGNyeXB0by5zdWJ0bGUuZGlnZXN0KCdTSEEtMjU2JywgYnVmZmVyKTtcbiAgICBjb25zdCBoYXNoQXJyYXkgPSBBcnJheS5mcm9tKG5ldyBVaW50OEFycmF5KGhhc2hCdWZmZXIpKTtcbiAgICBjb25zdCBoYXNoSGV4ID0gaGFzaEFycmF5Lm1hcChieXRlcyA9PiBieXRlcy50b1N0cmluZygxNikucGFkU3RhcnQoMiwgJzAnKSkuam9pbignJyk7XG4gICAgcmV0dXJuIGhhc2hIZXg7XG4gIH1cblxuICAvKipcbiAgICogQWxsb3dzIHRvIGRvd25sb2FkIGEgZmlsZSAob3BlbnMgdGhlIGJyb3dzZXIgZG93bmxvYWQgcHJvbXB0KS5cbiAgICogQHBhcmFtIGJpbmFyeSBUaGUgYmluYXJ5IG1hbmFnZWQgb2JqZWN0LlxuICAgKi9cbiAgYXN5bmMgZG93bmxvYWQoYmluYXJ5OiBJTWFuYWdlZE9iamVjdEJpbmFyeSkge1xuICAgIGNvbnN0IGZpbGUgPSBhd2FpdCB0aGlzLmdldEZpbGUoYmluYXJ5KTtcbiAgICBzYXZlQXMoZmlsZSk7XG4gIH1cblxuICAvKipcbiAgICogTG9hZHMgdGhlIGZpbGUgdG8gSmF2YVNjcmlwdCBtZW1vcnkuXG4gICAqIFJldHVybnMgYW4gb2JzZXJ2YWJsZSB0aGF0IGVtaXRzIHByb2dyZXNzaW9uIHN0YXR1cyBvYmplY3QsXG4gICAqIGFuZCBhZnRlciBkb3dubG9hZCBpcyBjb21wbGV0ZWQsIGJsb2IgcHJvcGVydHkgaXMgcG9wdWxhdGVkIHdpdGggQmxvYiByZXN1bHQgb2JqZWN0LlxuICAgKiBVbnN1YnNjcmliaW5nIGZyb20gdGhlIHJldHVybmVkIG9ic2VydmFibGUgYWJvcnRzIHRoZSBmaWxlIGZldGNoIHJlcXVlc3QuXG4gICAqXG4gICAqIEBwYXJhbSBiaW5hcnkgVGhlIGJpbmFyeSBtYW5hZ2VkIG9iamVjdC5cbiAgICovXG4gIGZldGNoRmlsZVdpdGhQcm9ncmVzcyQoYmluYXJ5OiBJTWFuYWdlZE9iamVjdEJpbmFyeSk6IE9ic2VydmFibGU8SUZldGNoV2l0aFByb2dyZXNzPiB7XG4gICAgY29uc3QgcHJvZ3Jlc3M6IElGZXRjaFdpdGhQcm9ncmVzcyA9IHtcbiAgICAgIHRvdGFsQnl0ZXM6ICtiaW5hcnkubGVuZ3RoLFxuICAgICAgYnVmZmVyZWRCeXRlczogMCxcbiAgICAgIHBlcmNlbnRhZ2U6IDAsXG4gICAgICBieXRlc1BlclNlY29uZDogMFxuICAgIH07XG5cbiAgICByZXR1cm4gb2YobmV3IEFib3J0Q29udHJvbGxlcigpKS5waXBlKFxuICAgICAgc3dpdGNoTWFwKGFzeW5jIGFib3J0Q29udHJvbGxlciA9PiAoe1xuICAgICAgICBhYm9ydENvbnRyb2xsZXIsXG4gICAgICAgIHN0YXJ0VGltZXN0YW1wOiBuZXcgRGF0ZSgpLmdldFRpbWUoKSxcbiAgICAgICAgcmVzcG9uc2U6IGF3YWl0IHRoaXMuaW52ZW50b3J5QmluYXJ5U2VydmljZS5kb3dubG9hZChiaW5hcnkuaWQsIHtcbiAgICAgICAgICBzaWduYWw6IGFib3J0Q29udHJvbGxlci5zaWduYWxcbiAgICAgICAgfSlcbiAgICAgIH0pKSxcbiAgICAgIHN3aXRjaE1hcCgoeyByZXNwb25zZSwgYWJvcnRDb250cm9sbGVyLCBzdGFydFRpbWVzdGFtcCB9KSA9PlxuICAgICAgICB0aGlzLnByb2Nlc3NSZXNwb25zZSQoYWJvcnRDb250cm9sbGVyLCByZXNwb25zZSwgc3RhcnRUaW1lc3RhbXAsIHByb2dyZXNzLCBiaW5hcnkudHlwZSlcbiAgICAgICksXG4gICAgICBzdGFydFdpdGgocHJvZ3Jlc3MpLFxuICAgICAgc2hhcmUoKSxcbiAgICAgIGNhdGNoRXJyb3IoZXJyID0+IHRocm93RXJyb3IoZXJyKSlcbiAgICApO1xuICB9XG5cbiAgdXBsb2FkRmlsZVdpdGhQcm9ncmVzcyQoZmlsZTogU3RyZWFtIHwgQnVmZmVyIHwgRmlsZSB8IEJsb2IpOiBPYnNlcnZhYmxlPElGZXRjaFdpdGhQcm9ncmVzcz4ge1xuICAgIGNvbnN0IHVwbG9hZFN0YXJ0VGltZXN0YW1wID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG4gICAgY29uc3Qgc3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8SUZldGNoV2l0aFByb2dyZXNzPih7XG4gICAgICBwZXJjZW50YWdlOiAwLFxuICAgICAgdG90YWxCeXRlczogbnVsbCxcbiAgICAgIGJ1ZmZlcmVkQnl0ZXM6IDAsXG4gICAgICBieXRlc1BlclNlY29uZDogMFxuICAgIH0pO1xuICAgIGNvbnN0IG9uUHJvZ3Jlc3MgPSAoZXZlbnQ6IFByb2dyZXNzRXZlbnQpID0+IHtcbiAgICAgIGNvbnN0IGV2ZW50VGltZXN0YW1wID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG4gICAgICBjb25zdCBkdXJhdGlvbiA9IGV2ZW50VGltZXN0YW1wIC0gdXBsb2FkU3RhcnRUaW1lc3RhbXA7XG4gICAgICBzdWJqZWN0Lm5leHQoe1xuICAgICAgICBwZXJjZW50YWdlOiBNYXRoLnJvdW5kKChldmVudC5sb2FkZWQgLyBldmVudC50b3RhbCkgKiAxMDApLFxuICAgICAgICB0b3RhbEJ5dGVzOiBldmVudC50b3RhbCxcbiAgICAgICAgYnVmZmVyZWRCeXRlczogZXZlbnQubG9hZGVkLFxuICAgICAgICBieXRlc1BlclNlY29uZDogTWF0aC5yb3VuZChldmVudC5sb2FkZWQgLyBNYXRoLnJvdW5kKGR1cmF0aW9uIC8gMTAwMCkpXG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgY29uc3QgeGhyID0gdGhpcy5pbnZlbnRvcnlCaW5hcnlTZXJ2aWNlLmNyZWF0ZVdpdGhQcm9ncmVzcyhmaWxlLCBvblByb2dyZXNzKTtcbiAgICBjb25zdCB1cGxvYWRQcm9taXNlID0gdGhpcy5pbnZlbnRvcnlCaW5hcnlTZXJ2aWNlLmdldFhNTEh0dHBSZXNwb25zZSh4aHIpO1xuICAgIHVwbG9hZFByb21pc2UudGhlbigoKSA9PiB7XG4gICAgICBzdWJqZWN0LmNvbXBsZXRlKCk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gc3ViamVjdC5hc09ic2VydmFibGUoKTtcbiAgfVxuXG4gIHByaXZhdGUgcHJvY2Vzc1Jlc3BvbnNlJChcbiAgICBhYm9ydENvbnRyb2xsZXI6IEFib3J0Q29udHJvbGxlcixcbiAgICByZXNwb25zZTogSUZldGNoUmVzcG9uc2UsXG4gICAgc3RhcnRUaW1lc3RhbXA6IG51bWJlcixcbiAgICBwcm9ncmVzczogSUZldGNoV2l0aFByb2dyZXNzLFxuICAgIGJpbmFyeVR5cGU6IHN0cmluZ1xuICApOiBPYnNlcnZhYmxlPElGZXRjaFdpdGhQcm9ncmVzcz4ge1xuICAgIHJldHVybiBuZXcgT2JzZXJ2YWJsZShzdWIgPT4ge1xuICAgICAgY29uc3QgcmVhZGVyID0gcmVzcG9uc2UuYm9keS5nZXRSZWFkZXIoKTtcbiAgICAgIGNvbnN0IGNodW5rcyA9IFtdO1xuXG4gICAgICBjb25zdCByZWFkU3RyZWFtID0gYXN5bmMgKCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgICAgICBjb25zdCB7IGRvbmUsIHZhbHVlIH0gPSBhd2FpdCByZWFkZXIucmVhZCgpO1xuXG4gICAgICAgICAgICBpZiAoZG9uZSkge1xuICAgICAgICAgICAgICBwcm9ncmVzcy5ibG9iID0gbmV3IEJsb2IoY2h1bmtzLCB7IHR5cGU6IGJpbmFyeVR5cGUgfSk7XG4gICAgICAgICAgICAgIHN1Yi5uZXh0KHsgLi4ucHJvZ3Jlc3MgfSk7XG4gICAgICAgICAgICAgIHN1Yi5jb21wbGV0ZSgpO1xuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY2h1bmtzLnB1c2godmFsdWUpO1xuXG4gICAgICAgICAgICBwcm9ncmVzcy5idWZmZXJlZEJ5dGVzICs9IHZhbHVlLmxlbmd0aDtcbiAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRUaW1lc3RhbXAgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcbiAgICAgICAgICAgIGNvbnN0IHRpbWVzdGFtcERpZmYgPSBjdXJyZW50VGltZXN0YW1wIC0gc3RhcnRUaW1lc3RhbXA7XG4gICAgICAgICAgICBwcm9ncmVzcy5ieXRlc1BlclNlY29uZCA9IE1hdGgucm91bmQoXG4gICAgICAgICAgICAgIHByb2dyZXNzLmJ1ZmZlcmVkQnl0ZXMgLyBNYXRoLnJvdW5kKHRpbWVzdGFtcERpZmYgLyAxMDAwKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHByb2dyZXNzLnBlcmNlbnRhZ2UgPSBNYXRoLnJvdW5kKChwcm9ncmVzcy5idWZmZXJlZEJ5dGVzIC8gcHJvZ3Jlc3MudG90YWxCeXRlcykgKiAxMDApO1xuICAgICAgICAgICAgc3ViLm5leHQoeyAuLi5wcm9ncmVzcyB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICBhYm9ydENvbnRyb2xsZXIuYWJvcnQoKTtcbiAgICAgICAgICBzdWIuZXJyb3IoZSk7XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgICByZWFkU3RyZWFtKCk7XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIHVuc3Vic2NyaWJlKCkge1xuICAgICAgICAgIGF