UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

127 lines 25.1 kB
import { Component, EventEmitter, Inject, Input } from '@angular/core'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; import { DomSanitizer } from '@angular/platform-browser'; import { first, takeUntil } from 'rxjs/operators'; import { Subject } from 'rxjs'; import { AlertService, FilesService, gettext, GainsightService } from '@c8y/ngx-components'; import { PRODUCT_EXPERIENCE_FILE_PREVIEW } from './file-preview-product-experience.constants'; import { DOWNLOAD_EMITTER } from './download-emitter.token'; import * as i0 from "@angular/core"; import * as i1 from "ngx-bootstrap/modal"; import * as i2 from "@angular/platform-browser"; import * as i3 from "@c8y/ngx-components"; import * as i4 from "@angular/common"; /** * A component which shows a button that opens a modal with the preview of a binary managed object. * This component requires CSP 'blob:' rule for img-src and media-src to be set. * * ```html * <c8y-file-preview [mo]="managedObject"> * <button customButton>Preview</button> * </c8y-file-preview> * ``` * If no custom button provided, the component will use the default search icon button instead. * */ export class FilePreviewComponent { set _mo(mo) { this.mo = mo; this.setContentType(); } constructor(downloadEmitter, modalRef, modalService, sanitizer, filesService, alertService, gainsightService) { this.downloadEmitter = downloadEmitter; this.modalRef = modalRef; this.modalService = modalService; this.sanitizer = sanitizer; this.filesService = filesService; this.alertService = alertService; this.gainsightService = gainsightService; this.contentType = 'unsupported'; this.BUFFERING_STATUS_TEXT = gettext('{{speed}}/s - {{bufferedBytes}} of {{totalBytes}} buffered ({{percentage}}%)'); this.destroy$ = new Subject(); downloadEmitter.pipe(takeUntil(this.destroy$)).subscribe(id => { if (this.dataUrl && this.mo.id !== id) { this.removeDownloadedFile(); } }); } ngOnDestroy() { this.removeDownloadedFile(); this.destroy$.next(true); this.destroy$.complete(); } async openModal(template) { this.modalRef = this.modalService.show(template, { ariaDescribedby: 'modal-body', ariaLabelledBy: 'modal-title', ignoreBackdropClick: true }); this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_FILE_PREVIEW.EVENTS.FILE_PREVIEW, { component: PRODUCT_EXPERIENCE_FILE_PREVIEW.COMPONENTS.FILE_PREVIEW_COMPONENT, action: PRODUCT_EXPERIENCE_FILE_PREVIEW.ACTIONS.OPEN_PREVIEW }); if (this.dataUrl) { return; } this.downloadEmitter.emit(this.mo.id); const subscription = this.filesService .fetchFileWithProgress$(this.mo) .pipe(takeUntil(this.destroy$)) .subscribe(progress => { this.progress = progress; if (this.progress.blob) { this.dataUrl = URL.createObjectURL(progress.blob); this.safeDataUrl = this.sanitizer.bypassSecurityTrustUrl(this.dataUrl); } }, e => { this.modalRef.hide(); this.alertService.addServerFailure(e); }); this.modalRef.onHide.pipe(first(), takeUntil(this.destroy$)).subscribe(() => { subscription.unsubscribe(); }); } removeDownloadedFile() { URL.revokeObjectURL(this.dataUrl); delete this.dataUrl; delete this.safeDataUrl; } setContentType() { if (!this.mo || !this.mo.hasOwnProperty('c8y_IsBinary')) { // eslint-disable-next-line no-console console.warn('Provided Managed object is not binary'); this.contentType = 'unsupported'; return; } if (this.mo.contentType.startsWith('image/')) { this.contentType = 'image'; } else if (this.mo.contentType.startsWith('video/')) { this.contentType = 'video'; } else if (this.mo.contentType.startsWith('text/')) { // @TODO: Implement in future this.contentType = 'unsupported'; } else if (this.mo.contentType.startsWith('application/json')) { // @TODO: Implement in future this.contentType = 'unsupported'; } else { this.contentType = 'unsupported'; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilePreviewComponent, deps: [{ token: DOWNLOAD_EMITTER }, { token: i1.BsModalRef }, { token: i1.BsModalService }, { token: i2.DomSanitizer }, { token: i3.FilesService }, { token: i3.AlertService }, { token: i3.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: FilePreviewComponent, selector: "c8y-file-preview", inputs: { _mo: ["mo", "_mo"] }, ngImport: i0, template: "<div\n class=\"d-inline-block\"\n *ngIf=\"contentType !== 'unsupported'\"\n (click)=\"openModal(modalTemplate)\"\n>\n <div #customButtonRef>\n <ng-content select=\"[customButton]\"></ng-content>\n </div>\n\n <ng-container *ngIf=\"!customButtonRef.children.length\">\n <button [title]=\"'Preview file' | translate\" type=\"button\" class=\"btn btn-default btn-icon\">\n <i c8yIcon=\"search\"></i>\n </button>\n </ng-container>\n</div>\n\n<ng-template #modalTemplate>\n <c8y-modal\n [title]=\"mo.name\"\n [customFooter]=\"false\"\n (onClose)=\"modalRef.hide()\"\n (onDismiss)=\"modalRef.hide()\"\n [labels]=\"{ cancel: '', ok: 'Close' | translate }\"\n class=\"text-break-word\"\n >\n <div class=\"text-center d-block\" *ngIf=\"!dataUrl\">\n <c8y-loading layout=\"application\" [progress]=\"progress.percentage\"></c8y-loading>\n {{\n BUFFERING_STATUS_TEXT\n | translate\n : {\n totalBytes: progress.totalBytes | bytes,\n bufferedBytes: progress.bufferedBytes | bytes,\n percentage: progress.percentage,\n speed: progress.bytesPerSecond | bytes\n }\n }}\n </div>\n\n <ng-container *ngIf=\"dataUrl\" [ngSwitch]=\"contentType\" id=\"modal-body\">\n <ng-container *ngSwitchCase=\"'image'\">\n <img class=\"fit-w\" alt=\"safeDataUrl\" [src]=\"safeDataUrl\" />\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'video'\">\n <video controls autoplay class=\"fit-w\">\n <source [src]=\"safeDataUrl\" />\n {{ 'Your browser does not support the video tag.' | translate }}\n </video>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'text'\">\n <!-- @TODO: Implement text viewer-->\n text\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'json'\">\n <!-- @TODO: Implement json viewer-->\n json\n </ng-container>\n\n <ng-container *ngSwitchDefault></ng-container>\n </ng-container>\n </c8y-modal>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i3.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i4.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i4.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "component", type: i3.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: i3.ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "pipe", type: i3.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.BytesPipe, name: "bytes" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilePreviewComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-file-preview', template: "<div\n class=\"d-inline-block\"\n *ngIf=\"contentType !== 'unsupported'\"\n (click)=\"openModal(modalTemplate)\"\n>\n <div #customButtonRef>\n <ng-content select=\"[customButton]\"></ng-content>\n </div>\n\n <ng-container *ngIf=\"!customButtonRef.children.length\">\n <button [title]=\"'Preview file' | translate\" type=\"button\" class=\"btn btn-default btn-icon\">\n <i c8yIcon=\"search\"></i>\n </button>\n </ng-container>\n</div>\n\n<ng-template #modalTemplate>\n <c8y-modal\n [title]=\"mo.name\"\n [customFooter]=\"false\"\n (onClose)=\"modalRef.hide()\"\n (onDismiss)=\"modalRef.hide()\"\n [labels]=\"{ cancel: '', ok: 'Close' | translate }\"\n class=\"text-break-word\"\n >\n <div class=\"text-center d-block\" *ngIf=\"!dataUrl\">\n <c8y-loading layout=\"application\" [progress]=\"progress.percentage\"></c8y-loading>\n {{\n BUFFERING_STATUS_TEXT\n | translate\n : {\n totalBytes: progress.totalBytes | bytes,\n bufferedBytes: progress.bufferedBytes | bytes,\n percentage: progress.percentage,\n speed: progress.bytesPerSecond | bytes\n }\n }}\n </div>\n\n <ng-container *ngIf=\"dataUrl\" [ngSwitch]=\"contentType\" id=\"modal-body\">\n <ng-container *ngSwitchCase=\"'image'\">\n <img class=\"fit-w\" alt=\"safeDataUrl\" [src]=\"safeDataUrl\" />\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'video'\">\n <video controls autoplay class=\"fit-w\">\n <source [src]=\"safeDataUrl\" />\n {{ 'Your browser does not support the video tag.' | translate }}\n </video>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'text'\">\n <!-- @TODO: Implement text viewer-->\n text\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'json'\">\n <!-- @TODO: Implement json viewer-->\n json\n </ng-container>\n\n <ng-container *ngSwitchDefault></ng-container>\n </ng-container>\n </c8y-modal>\n</ng-template>\n" }] }], ctorParameters: () => [{ type: i0.EventEmitter, decorators: [{ type: Inject, args: [DOWNLOAD_EMITTER] }] }, { type: i1.BsModalRef }, { type: i1.BsModalService }, { type: i2.DomSanitizer }, { type: i3.FilesService }, { type: i3.AlertService }, { type: i3.GainsightService }], propDecorators: { _mo: [{ type: Input, args: ['mo'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZS1wcmV2aWV3LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2ZpbGUtcHJldmlldy9maWxlLXByZXZpZXcuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vZmlsZS1wcmV2aWV3L2ZpbGUtcHJldmlldy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUEwQixNQUFNLGVBQWUsQ0FBQztBQUMvRixPQUFPLEVBQUUsVUFBVSxFQUFFLGNBQWMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRWpFLE9BQU8sRUFBRSxZQUFZLEVBQVcsTUFBTSwyQkFBMkIsQ0FBQztBQUNsRSxPQUFPLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUNMLFlBQVksRUFDWixZQUFZLEVBQ1osT0FBTyxFQUVQLGdCQUFnQixFQUNqQixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBRSwrQkFBK0IsRUFBRSxNQUFNLDZDQUE2QyxDQUFDO0FBQzlGLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDBCQUEwQixDQUFDOzs7Ozs7QUFFNUQ7Ozs7Ozs7Ozs7O0dBV0c7QUFLSCxNQUFNLE9BQU8sb0JBQW9CO0lBQy9CLElBQ0ksR0FBRyxDQUFDLEVBQXdCO1FBQzlCLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDO1FBQ2IsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQ3hCLENBQUM7SUFjRCxZQUNvQyxlQUFxQyxFQUNoRSxRQUFvQixFQUNuQixZQUE0QixFQUM1QixTQUF1QixFQUN2QixZQUEwQixFQUMxQixZQUEwQixFQUMxQixnQkFBa0M7UUFOUixvQkFBZSxHQUFmLGVBQWUsQ0FBc0I7UUFD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QUFDO1FBQ25DLENBQUM7YUFBTSxDQUFDO1lBQ04sSUFBSSxDQUFDLFdBQVcsR0FBRyxhQUFhLENBQUM7UUFDbkMsQ0FBQztJQUNILENBQUM7K0dBNUdVLG9CQUFvQixrQkFvQnJCLGdCQUFnQjttR0FwQmYsb0JBQW9CLHdGQ2hDakMsMGpFQWlFQTs7NEZEakNhLG9CQUFvQjtrQkFKaEMsU0FBUzsrQkFDRSxrQkFBa0I7OzBCQXVCekIsTUFBTTsyQkFBQyxnQkFBZ0I7K01BbEJ0QixHQUFHO3NCQUROLEtBQUs7dUJBQUMsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgRXZlbnRFbWl0dGVyLCBJbmplY3QsIElucHV0LCBPbkRlc3Ryb3ksIFRlbXBsYXRlUmVmIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBCc01vZGFsUmVmLCBCc01vZGFsU2VydmljZSB9IGZyb20gJ25neC1ib290c3RyYXAvbW9kYWwnO1xuaW1wb3J0IHsgSU1hbmFnZWRPYmplY3RCaW5hcnkgfSBmcm9tICdAYzh5L2NsaWVudCc7XG5pbXBvcnQgeyBEb21TYW5pdGl6ZXIsIFNhZmVVcmwgfSBmcm9tICdAYW5ndWxhci9wbGF0Zm9ybS1icm93c2VyJztcbmltcG9ydCB7IGZpcnN0LCB0YWtlVW50aWwgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQge1xuICBBbGVydFNlcnZpY2UsXG4gIEZpbGVzU2VydmljZSxcbiAgZ2V0dGV4dCxcbiAgSUZldGNoV2l0aFByb2dyZXNzLFxuICBHYWluc2lnaHRTZXJ2aWNlXG59IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgUFJPRFVDVF9FWFBFUklFTkNFX0ZJTEVfUFJFVklFVyB9IGZyb20gJy4vZmlsZS1wcmV2aWV3LXByb2R1Y3QtZXhwZXJpZW5jZS5jb25zdGFudHMnO1xuaW1wb3J0IHsgRE9XTkxPQURfRU1JVFRFUiB9IGZyb20gJy4vZG93bmxvYWQtZW1pdHRlci50b2tlbic7XG5cbi8qKlxuICogQSBjb21wb25lbnQgd2hpY2ggc2hvd3MgYSBidXR0b24gdGhhdCBvcGVucyBhIG1vZGFsIHdpdGggdGhlIHByZXZpZXcgb2YgYSBiaW5hcnkgbWFuYWdlZCBvYmplY3QuXG4gKiBUaGlzIGNvbXBvbmVudCByZXF1aXJlcyBDU1AgJ2Jsb2I6JyBydWxlIGZvciBpbWctc3JjIGFuZCBtZWRpYS1zcmMgdG8gYmUgc2V0LlxuICpcbiAqIGBgYGh0bWxcbiAqIDxjOHktZmlsZS1wcmV2aWV3IFttb109XCJtYW5hZ2VkT2JqZWN0XCI+XG4gKiAgICAgPGJ1dHRvbiBjdXN0b21CdXR0b24+UHJldmlldzwvYnV0dG9uPlxuICogPC9jOHktZmlsZS1wcmV2aWV3PlxuICogYGBgXG4gKiBJZiBubyBjdXN0b20gYnV0dG9uIHByb3ZpZGVkLCB0aGUgY29tcG9uZW50IHdpbGwgdXNlIHRoZSBkZWZhdWx0IHNlYXJjaCBpY29uIGJ1dHRvbiBpbnN0ZWFkLlxuICpcbiAqL1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LWZpbGUtcHJldmlldycsXG4gIHRlbXBsYXRlVXJsOiAnLi9maWxlLXByZXZpZXcuY29tcG9uZW50Lmh0bWwnXG59KVxuZXhwb3J0IGNsYXNzIEZpbGVQcmV2aWV3Q29tcG9uZW50IGltcGxlbWVudHMgT25EZXN0cm95IHtcbiAgQElucHV0KCdtbycpXG4gIHNldCBfbW8obW86IElNYW5hZ2VkT2JqZWN0QmluYXJ5KSB7XG4gICAgdGhpcy5tbyA9IG1vO1xuICAgIHRoaXMuc2V0Q29udGVudFR5cGUoKTtcbiAgfVxuICBtbzogSU1hbmFnZWRPYmplY3RCaW5hcnk7XG5cbiAgY29udGVudFR5cGU6ICdpbWFnZScgfCAndmlkZW8nIHwgJ3RleHQnIHwgJ2pzb24nIHwgJ3Vuc3VwcG9ydGVkJyA9ICd1bnN1cHBvcnRlZCc7XG4gIHByb2dyZXNzOiBJRmV0Y2hXaXRoUHJvZ3Jlc3M7XG5cbiAgZGF0YVVybDogc3RyaW5nO1xuICBzYWZlRGF0YVVybDogU2FmZVVybDtcbiAgQlVGRkVSSU5HX1NUQVRVU19URVhUID0gZ2V0dGV4dChcbiAgICAne3tzcGVlZH19L3MgLSB7e2J1ZmZlcmVkQnl0ZXN9fSBvZiB7e3RvdGFsQnl0ZXN9fSBidWZmZXJlZCAoe3twZXJjZW50YWdlfX0lKSdcbiAgKTtcblxuICBwcml2YXRlIGRlc3Ryb3kkOiBTdWJqZWN0PGFueT4gPSBuZXcgU3ViamVjdCgpO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIEBJbmplY3QoRE9XTkxPQURfRU1JVFRFUikgcHJpdmF0ZSBkb3dubG9hZEVtaXR0ZXI6IEV2ZW50RW1pdHRlcjxzdHJpbmc+LFxuICAgIHB1YmxpYyBtb2RhbFJlZjogQnNNb2RhbFJlZixcbiAgICBwcml2YXRlIG1vZGFsU2VydmljZTogQnNNb2RhbFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBzYW5pdGl6ZXI6IERvbVNhbml0aXplcixcbiAgICBwcml2YXRlIGZpbGVzU2VydmljZTogRmlsZXNTZXJ2aWNlLFxuICAgIHByaXZhdGUgYWxlcnRTZXJ2aWNlOiBBbGVydFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBnYWluc2lnaHRTZXJ2aWNlOiBHYWluc2lnaHRTZXJ2aWNlXG4gICkge1xuICAgIGRvd25sb2FkRW1pdHRlci5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSkuc3Vic2NyaWJlKGlkID0+IHtcbiAgICAgIGlmICh0aGlzLmRhdGFVcmwgJiYgdGhpcy5tby5pZCAhPT0gaWQpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVEb3dubG9hZGVkRmlsZSgpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5yZW1vdmVEb3dubG9hZGVkRmlsZSgpO1xuICAgIHRoaXMuZGVzdHJveSQubmV4dCh0cnVlKTtcbiAgICB0aGlzLmRlc3Ryb3kkLmNvbXBsZXRlKCk7XG4gIH1cblxuICBhc3luYyBvcGVuTW9kYWwodGVtcGxhdGU6IFRlbXBsYXRlUmVmPGFueT4pIHtcbiAgICB0aGlzLm1vZGFsUmVmID0gdGhpcy5tb2RhbFNlcnZpY2Uuc2hvdyh0ZW1wbGF0ZSwge1xuICAgICAgYXJpYURlc2NyaWJlZGJ5OiAnbW9kYWwtYm9keScsXG4gICAgICBhcmlhTGFiZWxsZWRCeTogJ21vZGFsLXRpdGxlJyxcbiAgICAgIGlnbm9yZUJhY2tkcm9wQ2xpY2s6IHRydWVcbiAgICB9KTtcblxuICAgIHRoaXMuZ2FpbnNpZ2h0U2VydmljZS50cmlnZ2VyRXZlbnQoUFJPRFVDVF9FWFBFUklFTkNFX0ZJTEVfUFJFVklFVy5FVkVOVFMuRklMRV9QUkVWSUVXLCB7XG4gICAgICBjb21wb25lbnQ6IFBST0RVQ1RfRVhQRVJJRU5DRV9GSUxFX1BSRVZJRVcuQ09NUE9ORU5UUy5GSUxFX1BSRVZJRVdfQ09NUE9ORU5ULFxuICAgICAgYWN0aW9uOiBQUk9EVUNUX0VYUEVSSUVOQ0VfRklMRV9QUkVWSUVXLkFDVElPTlMuT1BFTl9QUkVWSUVXXG4gICAgfSk7XG5cbiAgICBpZiAodGhpcy5kYXRhVXJsKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5kb3dubG9hZEVtaXR0ZXIuZW1pdCh0aGlzLm1vLmlkKTtcblxuICAgIGNvbnN0IHN1YnNjcmlwdGlvbiA9IHRoaXMuZmlsZXNTZXJ2aWNlXG4gICAgICAuZmV0Y2hGaWxlV2l0aFByb2dyZXNzJCh0aGlzLm1vKVxuICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKVxuICAgICAgLnN1YnNjcmliZShcbiAgICAgICAgcHJvZ3Jlc3MgPT4ge1xuICAgICAgICAgIHRoaXMucHJvZ3Jlc3MgPSBwcm9ncmVzcztcbiAgICAgICAgICBpZiAodGhpcy5wcm9ncmVzcy5ibG9iKSB7XG4gICAgICAgICAgICB0aGlzLmRhdGFVcmwgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKHByb2dyZXNzLmJsb2IpO1xuICAgICAgICAgICAgdGhpcy5zYWZlRGF0YVVybCA9IHRoaXMuc2FuaXRpemVyLmJ5cGFzc1NlY3VyaXR5VHJ1c3RVcmwodGhpcy5kYXRhVXJsKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGUgPT4ge1xuICAgICAgICAgIHRoaXMubW9kYWxSZWYuaGlkZSgpO1xuICAgICAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLmFkZFNlcnZlckZhaWx1cmUoZSk7XG4gICAgICAgIH1cbiAgICAgICk7XG5cbiAgICB0aGlzLm1vZGFsUmVmLm9uSGlkZS5waXBlKGZpcnN0KCksIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSkuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgIHN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSByZW1vdmVEb3dubG9hZGVkRmlsZSgpOiB2b2lkIHtcbiAgICBVUkwucmV2b2tlT2JqZWN0VVJMKHRoaXMuZGF0YVVybCk7XG4gICAgZGVsZXRlIHRoaXMuZGF0YVVybDtcbiAgICBkZWxldGUgdGhpcy5zYWZlRGF0YVVybDtcbiAgfVxuXG4gIHByaXZhdGUgc2V0Q29udGVudFR5cGUoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLm1vIHx8ICF0aGlzLm1vLmhhc093blByb3BlcnR5KCdjOHlfSXNCaW5hcnknKSkge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGVcbiAgICAgIGNvbnNvbGUud2FybignUHJvdmlkZWQgTWFuYWdlZCBvYmplY3QgaXMgbm90IGJpbmFyeScpO1xuICAgICAgdGhpcy5jb250ZW50VHlwZSA9ICd1bnN1cHBvcnRlZCc7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMubW8uY29udGVudFR5cGUuc3RhcnRzV2l0aCgnaW1hZ2UvJykpIHtcbiAgICAgIHRoaXMuY29udGVudFR5cGUgPSAnaW1hZ2UnO1xuICAgIH0gZWxzZSBpZiAodGhpcy5tby5jb250ZW50VHlwZS5zdGFydHNXaXRoKCd2aWRlby8nKSkge1xuICAgICAgdGhpcy5jb250ZW50VHlwZSA9ICd2aWRlbyc7XG4gICAgfSBlbHNlIGlmICh0aGlzLm1vLmNvbnRlbnRUeXBlLnN0YXJ0c1dpdGgoJ3RleHQvJykpIHtcbiAgICAgIC8vIEBUT0RPOiBJbXBsZW1lbnQgaW4gZnV0dXJlXG4gICAgICB0aGlzLmNvbnRlbnRUeXBlID0gJ3Vuc3VwcG9ydGVkJztcbiAgICB9IGVsc2UgaWYgKHRoaXMubW8uY29udGVudFR5cGUuc3RhcnRzV2l0aCgnYXBwbGljYXRpb24vanNvbicpKSB7XG4gICAgICAvLyBAVE9ETzogSW1wbGVtZW50IGluIGZ1dHVyZVxuICAgICAgdGhpcy5jb250ZW50VHlwZSA9ICd1bnN1cHBvcnRlZCc7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuY29udGVudFR5cGUgPSAndW5zdXBwb3J0ZWQnO1xuICAgIH1cbiAgfVxufVxuIiwiPGRpdlxuICBjbGFzcz1cImQtaW5saW5lLWJsb2NrXCJcbiAgKm5nSWY9XCJjb250ZW50VHlwZSAhPT0gJ3Vuc3VwcG9ydGVkJ1wiXG4gIChjbGljayk9XCJvcGVuTW9kYWwobW9kYWxUZW1wbGF0ZSlcIlxuPlxuICA8ZGl2ICNjdXN0b21CdXR0b25SZWY+XG4gICAgPG5nLWNvbnRlbnQgc2VsZWN0PVwiW2N1c3RvbUJ1dHRvbl1cIj48L25nLWNvbnRlbnQ+XG4gIDwvZGl2PlxuXG4gIDxuZy1jb250YWluZXIgKm5nSWY9XCIhY3VzdG9tQnV0dG9uUmVmLmNoaWxkcmVuLmxlbmd0aFwiPlxuICAgIDxidXR0b24gW3RpdGxlXT1cIidQcmV2aWV3IGZpbGUnIHwgdHJhbnNsYXRlXCIgdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYnRuIGJ0bi1kZWZhdWx0IGJ0bi1pY29uXCI+XG4gICAgICA8aSBjOHlJY29uPVwic2VhcmNoXCI+PC9pPlxuICAgIDwvYnV0dG9uPlxuICA8L25nLWNvbnRhaW5lcj5cbjwvZGl2PlxuXG48bmctdGVtcGxhdGUgI21vZGFsVGVtcGxhdGU+XG4gIDxjOHktbW9kYWxcbiAgICBbdGl0bGVdPVwibW8ubmFtZVwiXG4gICAgW2N1c3RvbUZvb3Rlcl09XCJmYWxzZVwiXG4gICAgKG9uQ2xvc2UpPVwibW9kYWxSZWYuaGlkZSgpXCJcbiAgICAob25EaXNtaXNzKT1cIm1vZGFsUmVmLmhpZGUoKVwiXG4gICAgW2xhYmVsc109XCJ7IGNhbmNlbDogJycsIG9rOiAnQ2xvc2UnIHwgdHJhbnNsYXRlIH1cIlxuICAgIGNsYXNzPVwidGV4dC1icmVhay13b3JkXCJcbiAgPlxuICAgIDxkaXYgY2xhc3M9XCJ0ZXh0LWNlbnRlciBkLWJsb2NrXCIgKm5nSWY9XCIhZGF0YVVybFwiPlxuICAgICAgPGM4eS1sb2FkaW5nIGxheW91dD1cImFwcGxpY2F0aW9uXCIgW3Byb2dyZXNzXT1cInByb2dyZXNzLnBlcmNlbnRhZ2VcIj48L2M4eS1sb2FkaW5nPlxuICAgICAge3tcbiAgICAgICAgQlVGRkVSSU5HX1NUQVRVU19URVhUXG4gICAgICAgICAgfCB0cmFuc2xhdGVcbiAgICAgICAgICAgIDoge1xuICAgICAgICAgICAgICAgIHRvdGFsQnl0ZXM6IHByb2dyZXNzLnRvdGFsQnl0ZXMgfCBieXRlcyxcbiAgICAgICAgICAgICAgICBidWZmZXJlZEJ5dGVzOiBwcm9ncmVzcy5idWZmZXJlZEJ5dGVzIHwgYnl0ZXMsXG4gICAgICAgICAgICAgICAgcGVyY2VudGFnZTogcHJvZ3Jlc3MucGVyY2VudGFnZSxcbiAgICAgICAgICAgICAgICBzcGVlZDogcHJvZ3Jlc3MuYnl0ZXNQZXJTZWNvbmQgfCBieXRlc1xuICAgICAgICAgICAgICB9XG4gICAgICB9fVxuICAgIDwvZGl2PlxuXG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImRhdGFVcmxcIiBbbmdTd2l0Y2hdPVwiY29udGVudFR5cGVcIiBpZD1cIm1vZGFsLWJvZHlcIj5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nU3dpdGNoQ2FzZT1cIidpbWFnZSdcIj5cbiAgICAgICAgPGltZyBjbGFzcz1cImZpdC13XCIgYWx0PVwic2FmZURhdGFVcmxcIiBbc3JjXT1cInNhZmVEYXRhVXJsXCIgLz5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICA8bmctY29udGFpbmVyICpuZ1N3aXRjaENhc2U9XCIndmlkZW8nXCI+XG4gICAgICAgIDx2aWRlbyBjb250cm9scyBhdXRvcGxheSBjbGFzcz1cImZpdC13XCI+XG4gICAgICAgICAgPHNvdXJjZSBbc3JjXT1cInNhZmVEYXRhVXJsXCIgLz5cbiAgICAgICAgICB7eyAnWW91ciBicm93c2VyIGRvZXMgbm90IHN1cHBvcnQgdGhlIHZpZGVvIHRhZy4nIHwgdHJhbnNsYXRlIH19XG4gICAgICAgIDwvdmlkZW8+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdTd2l0Y2hDYXNlPVwiJ3RleHQnXCI+XG4gICAgICAgIDwhLS0gICAgICAgIEBUT0RPOiBJbXBsZW1lbnQgdGV4dCB2aWV3ZXItLT5cbiAgICAgICAgdGV4dFxuICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nU3dpdGNoQ2FzZT1cIidqc29uJ1wiPlxuICAgICAgICA8IS0tICAgICAgICBAVE9ETzogSW1wbGVtZW50IGpzb24gdmlld2VyLS0+XG4gICAgICAgIGpzb25cbiAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICA8bmctY29udGFpbmVyICpuZ1N3aXRjaERlZmF1bHQ+PC9uZy1jb250YWluZXI+XG4gICAgPC9uZy1jb250YWluZXI+XG4gIDwvYzh5LW1vZGFsPlxuPC9uZy10ZW1wbGF0ZT5cbiJdfQ==