UNPKG

ng-zorro-antd

Version:

An enterprise-class UI components based on Ant Design and Angular

251 lines 57 kB
/** * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE */ import { animate, style, transition, trigger } from '@angular/animations'; import { DOCUMENT, NgStyle, NgTemplateOutlet } from '@angular/common'; import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation, inject } from '@angular/core'; import { Subject, fromEvent, of } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; import { NzButtonModule } from 'ng-zorro-antd/button'; import { NzIconModule } from 'ng-zorro-antd/icon'; import { NzProgressModule } from 'ng-zorro-antd/progress'; import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; import * as i0 from "@angular/core"; import * as i1 from "@angular/cdk/platform"; import * as i2 from "ng-zorro-antd/tooltip"; import * as i3 from "ng-zorro-antd/icon"; import * as i4 from "ng-zorro-antd/button"; import * as i5 from "ng-zorro-antd/core/transition-patch"; import * as i6 from "ng-zorro-antd/progress"; const isImageFileType = (type) => !!type && type.indexOf('image/') === 0; const MEASURE_SIZE = 200; export class NzUploadListComponent { get showPic() { return this.listType === 'picture' || this.listType === 'picture-card'; } set items(list) { this.list = list; } genErr(file) { if (file.response && typeof file.response === 'string') { return file.response; } return (file.error && file.error.statusText) || this.locale.uploadError; } extname(url) { const temp = url.split('/'); const filename = temp[temp.length - 1]; const filenameWithoutSuffix = filename.split(/#|\?/)[0]; return (/\.[^./\\]*$/.exec(filenameWithoutSuffix) || [''])[0]; } isImageUrl(file) { if (isImageFileType(file.type)) { return true; } const url = (file.thumbUrl || file.url || ''); if (!url) { return false; } const extension = this.extname(url); if (/^data:image\//.test(url) || /(webp|svg|png|gif|jpg|jpeg|jfif|bmp|dpg)$/i.test(extension)) { return true; } else if (/^data:/.test(url)) { // other file types of base64 return false; } else if (extension) { // other file types which have extension return false; } return true; } getIconType(file) { if (!this.showPic) { return ''; } if (file.isUploading || (!file.thumbUrl && !file.url)) { return 'uploading'; } else { return 'thumbnail'; } } previewImage(file) { if (!isImageFileType(file.type) || !this.platform.isBrowser) { return of(''); } const canvas = this.document.createElement('canvas'); canvas.width = MEASURE_SIZE; canvas.height = MEASURE_SIZE; canvas.style.cssText = `position: fixed; left: 0; top: 0; width: ${MEASURE_SIZE}px; height: ${MEASURE_SIZE}px; z-index: 9999; display: none;`; this.document.body.appendChild(canvas); const ctx = canvas.getContext('2d'); const img = new Image(); const objectUrl = URL.createObjectURL(file); img.src = objectUrl; return fromEvent(img, 'load').pipe(map(() => { const { width, height } = img; let drawWidth = MEASURE_SIZE; let drawHeight = MEASURE_SIZE; let offsetX = 0; let offsetY = 0; if (width < height) { drawHeight = height * (MEASURE_SIZE / width); offsetY = -(drawHeight - drawWidth) / 2; } else { drawWidth = width * (MEASURE_SIZE / height); offsetX = -(drawWidth - drawHeight) / 2; } try { ctx.drawImage(img, offsetX, offsetY, drawWidth, drawHeight); } catch { } const dataURL = canvas.toDataURL(); this.document.body.removeChild(canvas); URL.revokeObjectURL(objectUrl); return dataURL; })); } genThumb() { if (!this.platform.isBrowser) { return; } const win = window; if (!this.showPic || typeof document === 'undefined' || typeof win === 'undefined' || !win.FileReader || !win.File) { return; } this.list .filter(file => file.originFileObj instanceof File && file.thumbUrl === undefined) .forEach(file => { file.thumbUrl = ''; // Caretaker note: we shouldn't use promises here since they're not cancellable. // A promise microtask can be resolved after the view is destroyed. Thus running `detectChanges()` // will cause a runtime exception (`detectChanges()` cannot be run on destroyed views). const dataUrl$ = (this.previewFile ? this.previewFile(file) : this.previewImage(file.originFileObj)).pipe(takeUntil(this.destroy$)); this.ngZone.runOutsideAngular(() => { dataUrl$.subscribe(dataUrl => { this.ngZone.run(() => { file.thumbUrl = dataUrl; this.detectChanges(); }); }); }); }); } showDownload(file) { return !!(this.icons.showDownloadIcon && file.status === 'done'); } fixData() { this.list.forEach(file => { file.isUploading = file.status === 'uploading'; file.message = this.genErr(file); file.linkProps = typeof file.linkProps === 'string' ? JSON.parse(file.linkProps) : file.linkProps; file.isImageUrl = this.previewIsImage ? this.previewIsImage(file) : this.isImageUrl(file); file.iconType = this.getIconType(file); file.showDownload = this.showDownload(file); }); } handlePreview(file, e) { if (!this.onPreview) { return; } e.preventDefault(); return this.onPreview(file); } handleRemove(file, e) { e.preventDefault(); if (this.onRemove) { this.onRemove(file); } return; } handleDownload(file) { if (typeof this.onDownload === 'function') { this.onDownload(file); } else if (file.url) { window.open(file.url); } } // #endregion constructor(cdr, ngZone, platform) { this.cdr = cdr; this.ngZone = ngZone; this.platform = platform; this.list = []; this.locale = {}; this.iconRender = null; this.dir = 'ltr'; this.document = inject(DOCUMENT); this.destroy$ = new Subject(); } detectChanges() { this.fixData(); this.cdr.detectChanges(); } ngOnChanges() { this.fixData(); this.genThumb(); } ngOnDestroy() { this.destroy$.next(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.2", ngImport: i0, type: NzUploadListComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i1.Platform }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.1.2", type: NzUploadListComponent, isStandalone: true, selector: "nz-upload-list", inputs: { locale: "locale", listType: "listType", items: "items", icons: "icons", onPreview: "onPreview", onRemove: "onRemove", onDownload: "onDownload", previewFile: "previewFile", previewIsImage: "previewIsImage", iconRender: "iconRender", dir: "dir" }, host: { properties: { "class.ant-upload-list-rtl": "dir === 'rtl'", "class.ant-upload-list-text": "listType === 'text'", "class.ant-upload-list-picture": "listType === 'picture'", "class.ant-upload-list-picture-card": "listType === 'picture-card'" }, classAttribute: "ant-upload-list" }, exportAs: ["nzUploadList"], usesOnChanges: true, ngImport: i0, template: "@for (file of list; track file) {\n <div class=\"ant-upload-list-{{ listType }}-container\">\n <div\n class=\"ant-upload-list-item ant-upload-list-item-{{ file.status }} ant-upload-list-item-list-type-{{ listType }}\"\n [attr.data-key]=\"file.key\"\n @itemState\n nz-tooltip\n [nzTooltipTitle]=\"file.status === 'error' ? file.message : null\"\n >\n <ng-template #icon>\n @switch (file.iconType) {\n @case ('uploading') {\n <div class=\"ant-upload-list-item-thumbnail\" [class.ant-upload-list-item-file]=\"!file.isUploading\">\n <ng-template [ngTemplateOutlet]=\"iconNode\" [ngTemplateOutletContext]=\"{ $implicit: file }\"></ng-template>\n </div>\n }\n @case ('thumbnail') {\n <a\n class=\"ant-upload-list-item-thumbnail\"\n [class.ant-upload-list-item-file]=\"!file.isImageUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [href]=\"file.url || file.thumbUrl\"\n (click)=\"handlePreview(file, $event)\"\n >\n @if (file.isImageUrl) {\n <img class=\"ant-upload-list-item-image\" [src]=\"file.thumbUrl || file.url\" [attr.alt]=\"file.name\" />\n } @else {\n <ng-template\n [ngTemplateOutlet]=\"iconNode\"\n [ngTemplateOutletContext]=\"{ $implicit: file }\"\n ></ng-template>\n }\n </a>\n }\n @default {\n <div class=\"ant-upload-text-icon\">\n <ng-template [ngTemplateOutlet]=\"iconNode\" [ngTemplateOutletContext]=\"{ $implicit: file }\"></ng-template>\n </div>\n }\n }\n </ng-template>\n\n <ng-template #iconNode let-file>\n @if (!iconRender) {\n @switch (listType) {\n @case ('picture') {\n @if (file.isUploading) {\n <span nz-icon nzType=\"loading\"></span>\n } @else {\n <span nz-icon [nzType]=\"file.isImageUrl ? 'picture' : 'file'\" nzTheme=\"twotone\"></span>\n }\n }\n @case ('picture-card') {\n @if (file.isUploading) {\n {{ locale.uploading }}\n } @else {\n <span nz-icon [nzType]=\"file.isImageUrl ? 'picture' : 'file'\" nzTheme=\"twotone\"></span>\n }\n }\n @default {\n <span nz-icon [nzType]=\"file.isUploading ? 'loading' : 'paper-clip'\"></span>\n }\n }\n } @else {\n <ng-template [ngTemplateOutlet]=\"iconRender\" [ngTemplateOutletContext]=\"{ $implicit: file }\"></ng-template>\n }\n </ng-template>\n\n <ng-template #removeIcon>\n @if (icons.showRemoveIcon) {\n <button\n type=\"button\"\n nz-button\n nzType=\"text\"\n nzSize=\"small\"\n (click)=\"handleRemove(file, $event)\"\n [attr.title]=\"locale.removeFile\"\n class=\"ant-upload-list-item-card-actions-btn\"\n >\n <span nz-icon nzType=\"delete\"></span>\n </button>\n }\n </ng-template>\n\n <ng-template #downloadIcon>\n @if (file.showDownload) {\n <button\n type=\"button\"\n nz-button\n nzType=\"text\"\n nzSize=\"small\"\n (click)=\"handleDownload(file)\"\n [attr.title]=\"locale.downloadFile\"\n class=\"ant-upload-list-item-card-actions-btn\"\n >\n <span nz-icon nzType=\"download\"></span>\n </button>\n }\n </ng-template>\n\n <ng-template #downloadOrDelete>\n @if (listType !== 'picture-card') {\n <span class=\"ant-upload-list-item-card-actions {{ listType === 'picture' ? 'picture' : '' }}\">\n <ng-template [ngTemplateOutlet]=\"downloadIcon\"></ng-template>\n <ng-template [ngTemplateOutlet]=\"removeIcon\"></ng-template>\n </span>\n }\n </ng-template>\n\n <ng-template #preview>\n @if (file.url) {\n <a\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"ant-upload-list-item-name\"\n [attr.title]=\"file.name\"\n [href]=\"file.url\"\n [attr.download]=\"file.linkProps && file.linkProps.download\"\n (click)=\"handlePreview(file, $event)\"\n >\n {{ file.name }}\n </a>\n } @else {\n <span class=\"ant-upload-list-item-name\" [attr.title]=\"file.name\" (click)=\"handlePreview(file, $event)\">\n {{ file.name }}\n </span>\n }\n <ng-template [ngTemplateOutlet]=\"downloadOrDelete\"></ng-template>\n </ng-template>\n\n <div class=\"ant-upload-list-item-info\">\n <span class=\"ant-upload-span\">\n <ng-template [ngTemplateOutlet]=\"icon\"></ng-template>\n <ng-template [ngTemplateOutlet]=\"preview\"></ng-template>\n </span>\n </div>\n @if (listType === 'picture-card' && !file.isUploading) {\n <span class=\"ant-upload-list-item-actions\">\n @if (icons.showPreviewIcon) {\n <a\n [href]=\"file.url || file.thumbUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [attr.title]=\"locale.previewFile\"\n [ngStyle]=\"!(file.url || file.thumbUrl) ? { opacity: 0.5, 'pointer-events': 'none' } : null\"\n (click)=\"handlePreview(file, $event)\"\n >\n <span nz-icon nzType=\"eye\"></span>\n </a>\n }\n @if (file.status === 'done') {\n <ng-template [ngTemplateOutlet]=\"downloadIcon\"></ng-template>\n }\n <ng-template [ngTemplateOutlet]=\"removeIcon\"></ng-template>\n </span>\n }\n @if (file.isUploading) {\n <div class=\"ant-upload-list-item-progress\">\n <nz-progress [nzPercent]=\"file.percent!\" nzType=\"line\" [nzShowInfo]=\"false\" [nzStrokeWidth]=\"2\"></nz-progress>\n </div>\n }\n </div>\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: NzToolTipModule }, { kind: "directive", type: i2.NzTooltipDirective, selector: "[nz-tooltip]", inputs: ["nzTooltipTitle", "nzTooltipTitleContext", "nz-tooltip", "nzTooltipTrigger", "nzTooltipPlacement", "nzTooltipOrigin", "nzTooltipVisible", "nzTooltipMouseEnterDelay", "nzTooltipMouseLeaveDelay", "nzTooltipOverlayClassName", "nzTooltipOverlayStyle", "nzTooltipArrowPointAtCenter", "cdkConnectedOverlayPush", "nzTooltipColor"], outputs: ["nzTooltipVisibleChange"], exportAs: ["nzTooltip"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i3.NzIconDirective, selector: "[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i4.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i5.ɵNzTransitionPatchDirective, selector: "[nz-button], nz-button-group, [nz-icon], [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: NzProgressModule }, { kind: "component", type: i6.NzProgressComponent, selector: "nz-progress", inputs: ["nzShowInfo", "nzWidth", "nzStrokeColor", "nzSize", "nzFormat", "nzSuccessPercent", "nzPercent", "nzStrokeWidth", "nzGapDegree", "nzStatus", "nzType", "nzGapPosition", "nzStrokeLinecap", "nzSteps"], exportAs: ["nzProgress"] }], animations: [ trigger('itemState', [ transition(':enter', [ style({ height: '0', width: '0', opacity: 0 }), animate(150, style({ height: '*', width: '*', opacity: 1 })) ]), transition(':leave', [animate(150, style({ height: '0', width: '0', opacity: 0 }))]) ]) ], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.2", ngImport: i0, type: NzUploadListComponent, decorators: [{ type: Component, args: [{ selector: 'nz-upload-list', exportAs: 'nzUploadList', animations: [ trigger('itemState', [ transition(':enter', [ style({ height: '0', width: '0', opacity: 0 }), animate(150, style({ height: '*', width: '*', opacity: 1 })) ]), transition(':leave', [animate(150, style({ height: '0', width: '0', opacity: 0 }))]) ]) ], host: { class: 'ant-upload-list', '[class.ant-upload-list-rtl]': `dir === 'rtl'`, '[class.ant-upload-list-text]': `listType === 'text'`, '[class.ant-upload-list-picture]': `listType === 'picture'`, '[class.ant-upload-list-picture-card]': `listType === 'picture-card'` }, preserveWhitespaces: false, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [NzToolTipModule, NgTemplateOutlet, NzIconModule, NzButtonModule, NgStyle, NzProgressModule], standalone: true, template: "@for (file of list; track file) {\n <div class=\"ant-upload-list-{{ listType }}-container\">\n <div\n class=\"ant-upload-list-item ant-upload-list-item-{{ file.status }} ant-upload-list-item-list-type-{{ listType }}\"\n [attr.data-key]=\"file.key\"\n @itemState\n nz-tooltip\n [nzTooltipTitle]=\"file.status === 'error' ? file.message : null\"\n >\n <ng-template #icon>\n @switch (file.iconType) {\n @case ('uploading') {\n <div class=\"ant-upload-list-item-thumbnail\" [class.ant-upload-list-item-file]=\"!file.isUploading\">\n <ng-template [ngTemplateOutlet]=\"iconNode\" [ngTemplateOutletContext]=\"{ $implicit: file }\"></ng-template>\n </div>\n }\n @case ('thumbnail') {\n <a\n class=\"ant-upload-list-item-thumbnail\"\n [class.ant-upload-list-item-file]=\"!file.isImageUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [href]=\"file.url || file.thumbUrl\"\n (click)=\"handlePreview(file, $event)\"\n >\n @if (file.isImageUrl) {\n <img class=\"ant-upload-list-item-image\" [src]=\"file.thumbUrl || file.url\" [attr.alt]=\"file.name\" />\n } @else {\n <ng-template\n [ngTemplateOutlet]=\"iconNode\"\n [ngTemplateOutletContext]=\"{ $implicit: file }\"\n ></ng-template>\n }\n </a>\n }\n @default {\n <div class=\"ant-upload-text-icon\">\n <ng-template [ngTemplateOutlet]=\"iconNode\" [ngTemplateOutletContext]=\"{ $implicit: file }\"></ng-template>\n </div>\n }\n }\n </ng-template>\n\n <ng-template #iconNode let-file>\n @if (!iconRender) {\n @switch (listType) {\n @case ('picture') {\n @if (file.isUploading) {\n <span nz-icon nzType=\"loading\"></span>\n } @else {\n <span nz-icon [nzType]=\"file.isImageUrl ? 'picture' : 'file'\" nzTheme=\"twotone\"></span>\n }\n }\n @case ('picture-card') {\n @if (file.isUploading) {\n {{ locale.uploading }}\n } @else {\n <span nz-icon [nzType]=\"file.isImageUrl ? 'picture' : 'file'\" nzTheme=\"twotone\"></span>\n }\n }\n @default {\n <span nz-icon [nzType]=\"file.isUploading ? 'loading' : 'paper-clip'\"></span>\n }\n }\n } @else {\n <ng-template [ngTemplateOutlet]=\"iconRender\" [ngTemplateOutletContext]=\"{ $implicit: file }\"></ng-template>\n }\n </ng-template>\n\n <ng-template #removeIcon>\n @if (icons.showRemoveIcon) {\n <button\n type=\"button\"\n nz-button\n nzType=\"text\"\n nzSize=\"small\"\n (click)=\"handleRemove(file, $event)\"\n [attr.title]=\"locale.removeFile\"\n class=\"ant-upload-list-item-card-actions-btn\"\n >\n <span nz-icon nzType=\"delete\"></span>\n </button>\n }\n </ng-template>\n\n <ng-template #downloadIcon>\n @if (file.showDownload) {\n <button\n type=\"button\"\n nz-button\n nzType=\"text\"\n nzSize=\"small\"\n (click)=\"handleDownload(file)\"\n [attr.title]=\"locale.downloadFile\"\n class=\"ant-upload-list-item-card-actions-btn\"\n >\n <span nz-icon nzType=\"download\"></span>\n </button>\n }\n </ng-template>\n\n <ng-template #downloadOrDelete>\n @if (listType !== 'picture-card') {\n <span class=\"ant-upload-list-item-card-actions {{ listType === 'picture' ? 'picture' : '' }}\">\n <ng-template [ngTemplateOutlet]=\"downloadIcon\"></ng-template>\n <ng-template [ngTemplateOutlet]=\"removeIcon\"></ng-template>\n </span>\n }\n </ng-template>\n\n <ng-template #preview>\n @if (file.url) {\n <a\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"ant-upload-list-item-name\"\n [attr.title]=\"file.name\"\n [href]=\"file.url\"\n [attr.download]=\"file.linkProps && file.linkProps.download\"\n (click)=\"handlePreview(file, $event)\"\n >\n {{ file.name }}\n </a>\n } @else {\n <span class=\"ant-upload-list-item-name\" [attr.title]=\"file.name\" (click)=\"handlePreview(file, $event)\">\n {{ file.name }}\n </span>\n }\n <ng-template [ngTemplateOutlet]=\"downloadOrDelete\"></ng-template>\n </ng-template>\n\n <div class=\"ant-upload-list-item-info\">\n <span class=\"ant-upload-span\">\n <ng-template [ngTemplateOutlet]=\"icon\"></ng-template>\n <ng-template [ngTemplateOutlet]=\"preview\"></ng-template>\n </span>\n </div>\n @if (listType === 'picture-card' && !file.isUploading) {\n <span class=\"ant-upload-list-item-actions\">\n @if (icons.showPreviewIcon) {\n <a\n [href]=\"file.url || file.thumbUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [attr.title]=\"locale.previewFile\"\n [ngStyle]=\"!(file.url || file.thumbUrl) ? { opacity: 0.5, 'pointer-events': 'none' } : null\"\n (click)=\"handlePreview(file, $event)\"\n >\n <span nz-icon nzType=\"eye\"></span>\n </a>\n }\n @if (file.status === 'done') {\n <ng-template [ngTemplateOutlet]=\"downloadIcon\"></ng-template>\n }\n <ng-template [ngTemplateOutlet]=\"removeIcon\"></ng-template>\n </span>\n }\n @if (file.isUploading) {\n <div class=\"ant-upload-list-item-progress\">\n <nz-progress [nzPercent]=\"file.percent!\" nzType=\"line\" [nzShowInfo]=\"false\" [nzStrokeWidth]=\"2\"></nz-progress>\n </div>\n }\n </div>\n </div>\n}\n" }] }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i1.Platform }], propDecorators: { locale: [{ type: Input }], listType: [{ type: Input }], items: [{ type: Input }], icons: [{ type: Input }], onPreview: [{ type: Input }], onRemove: [{ type: Input }], onDownload: [{ type: Input }], previewFile: [{ type: Input }], previewIsImage: [{ type: Input }], iconRender: [{ type: Input }], dir: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBsb2FkLWxpc3QuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vY29tcG9uZW50cy91cGxvYWQvdXBsb2FkLWxpc3QuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vY29tcG9uZW50cy91cGxvYWQvdXBsb2FkLWxpc3QuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBRUgsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRzFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDdEUsT0FBTyxFQUNMLHVCQUF1QixFQUV2QixTQUFTLEVBQ1QsS0FBSyxFQUlMLGlCQUFpQixFQUNqQixNQUFNLEVBQ1AsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFjLE9BQU8sRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzFELE9BQU8sRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFaEQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRXRELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7Ozs7Ozs7O0FBSXhELE1BQU0sZUFBZSxHQUFHLENBQUMsSUFBWSxFQUFXLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBRTFGLE1BQU0sWUFBWSxHQUFHLEdBQUcsQ0FBQztBQXFDekIsTUFBTSxPQUFPLHFC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SUFBSSxtQkFDcEIsdUJBQXVCLENBQUMsTUFBTSxXQUN0QyxDQUFDLGVBQWUsRUFBRSxnQkFBZ0IsRUFBRSxZQUFZLEVBQUUsY0FBYyxFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsQ0FBQyxjQUN6RixJQUFJO2tJQVNQLE1BQU07c0JBQWQsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUVGLEtBQUs7c0JBRFIsS0FBSztnQkFJRyxLQUFLO3NCQUFiLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUNHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBQ0csV0FBVztzQkFBbkIsS0FBSztnQkFDRyxjQUFjO3NCQUF0QixLQUFLO2dCQUNHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBQ0csR0FBRztzQkFBWCxLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2dpdGh1Yi5jb20vTkctWk9SUk8vbmctem9ycm8tYW50ZC9ibG9iL21hc3Rlci9MSUNFTlNFXG4gKi9cblxuaW1wb3J0IHsgYW5pbWF0ZSwgc3R5bGUsIHRyYW5zaXRpb24sIHRyaWdnZXIgfSBmcm9tICdAYW5ndWxhci9hbmltYXRpb25zJztcbmltcG9ydCB7IERpcmVjdGlvbiB9IGZyb20gJ0Bhbmd1bGFyL2Nkay9iaWRpJztcbmltcG9ydCB7IFBsYXRmb3JtIH0gZnJvbSAnQGFuZ3VsYXIvY2RrL3BsYXRmb3JtJztcbmltcG9ydCB7IERPQ1VNRU5ULCBOZ1N0eWxlLCBOZ1RlbXBsYXRlT3V0bGV0IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7XG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgQ29tcG9uZW50LFxuICBJbnB1dCxcbiAgTmdab25lLFxuICBPbkNoYW5nZXMsXG4gIE9uRGVzdHJveSxcbiAgVmlld0VuY2Fwc3VsYXRpb24sXG4gIGluamVjdFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE9ic2VydmFibGUsIFN1YmplY3QsIGZyb21FdmVudCwgb2YgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IG1hcCwgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQgeyBOekJ1dHRvbk1vZHVsZSB9IGZyb20gJ25nLXpvcnJvLWFudGQvYnV0dG9uJztcbmltcG9ydCB7IE56U2FmZUFueSB9IGZyb20gJ25nLXpvcnJvLWFudGQvY29yZS90eXBlcyc7XG5pbXBvcnQgeyBOekljb25Nb2R1bGUgfSBmcm9tICduZy16b3Jyby1hbnRkL2ljb24nO1xuaW1wb3J0IHsgTnpQcm9ncmVzc01vZHVsZSB9IGZyb20gJ25nLXpvcnJvLWFudGQvcHJvZ3Jlc3MnO1xuaW1wb3J0IHsgTnpUb29sVGlwTW9kdWxlIH0gZnJvbSAnbmctem9ycm8tYW50ZC90b29sdGlwJztcblxuaW1wb3J0IHsgTnpJY29uUmVuZGVyVGVtcGxhdGUsIE56U2hvd1VwbG9hZExpc3QsIE56VXBsb2FkRmlsZSwgTnpVcGxvYWRMaXN0VHlwZSB9IGZyb20gJy4vaW50ZXJmYWNlJztcblxuY29uc3QgaXNJbWFnZUZpbGVUeXBlID0gKHR5cGU6IHN0cmluZyk6IGJvb2xlYW4gPT4gISF0eXBlICYmIHR5cGUuaW5kZXhPZignaW1hZ2UvJykgPT09IDA7XG5cbmNvbnN0IE1FQVNVUkVfU0laRSA9IDIwMDtcblxudHlwZSBVcGxvYWRMaXN0SWNvblR5cGUgPSAnJyB8ICd1cGxvYWRpbmcnIHwgJ3RodW1ibmFpbCc7XG5cbmludGVyZmFjZSBVcGxvYWRMaXN0RmlsZSBleHRlbmRzIE56VXBsb2FkRmlsZSB7XG4gIGlzSW1hZ2VVcmw/OiBib29sZWFuO1xuICBpc1VwbG9hZGluZz86IGJvb2xlYW47XG4gIGljb25UeXBlPzogVXBsb2FkTGlzdEljb25UeXBlO1xuICBzaG93RG93bmxvYWQ/OiBib29sZWFuO1xufVxuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICduei11cGxvYWQtbGlzdCcsXG4gIGV4cG9ydEFzOiAnbnpVcGxvYWRMaXN0JyxcbiAgdGVtcGxhdGVVcmw6ICcuL3VwbG9hZC1saXN0LmNvbXBvbmVudC5odG1sJyxcbiAgYW5pbWF0aW9uczogW1xuICAgIHRyaWdnZXIoJ2l0ZW1TdGF0ZScsIFtcbiAgICAgIHRyYW5zaXRpb24oJzplbnRlcicsIFtcbiAgICAgICAgc3R5bGUoeyBoZWlnaHQ6ICcwJywgd2lkdGg6ICcwJywgb3BhY2l0eTogMCB9KSxcbiAgICAgICAgYW5pbWF0ZSgxNTAsIHN0eWxlKHsgaGVpZ2h0OiAnKicsIHdpZHRoOiAnKicsIG9wYWNpdHk6IDEgfSkpXG4gICAgICBdKSxcbiAgICAgIHRyYW5zaXRpb24oJzpsZWF2ZScsIFthbmltYXRlKDE1MCwgc3R5bGUoeyBoZWlnaHQ6ICcwJywgd2lkdGg6ICcwJywgb3BhY2l0eTogMCB9KSldKVxuICAgIF0pXG4gIF0sXG4gIGhvc3Q6IHtcbiAgICBjbGFzczogJ2FudC11cGxvYWQtbGlzdCcsXG4gICAgJ1tjbGFzcy5hbnQtdXBsb2FkLWxpc3QtcnRsXSc6IGBkaXIgPT09ICdydGwnYCxcbiAgICAnW2NsYXNzLmFudC11cGxvYWQtbGlzdC10ZXh0XSc6IGBsaXN0VHlwZSA9PT0gJ3RleHQnYCxcbiAgICAnW2NsYXNzLmFudC11cGxvYWQtbGlzdC1waWN0dXJlXSc6IGBsaXN0VHlwZSA9PT0gJ3BpY3R1cmUnYCxcbiAgICAnW2NsYXNzLmFudC11cGxvYWQtbGlzdC1waWN0dXJlLWNhcmRdJzogYGxpc3RUeXBlID09PSAncGljdHVyZS1jYXJkJ2BcbiAgfSxcbiAgcHJlc2VydmVXaGl0ZXNwYWNlczogZmFsc2UsXG4gIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBpbXBvcnRzOiBbTnpUb29sVGlwTW9kdWxlLCBOZ1RlbXBsYXRlT3V0bGV0LCBOekljb25Nb2R1bGUsIE56QnV0dG9uTW9kdWxlLCBOZ1N0eWxlLCBOelByb2dyZXNzTW9kdWxlXSxcbiAgc3RhbmRhbG9uZTogdHJ1ZVxufSlcbmV4cG9ydCBjbGFzcyBOelVwbG9hZExpc3RDb21wb25lbnQgaW1wbGVtZW50cyBPbkNoYW5nZXMsIE9uRGVzdHJveSB7XG4gIGxpc3Q6IFVwbG9hZExpc3RGaWxlW10gPSBbXTtcblxuICBwcml2YXRlIGdldCBzaG93UGljKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmxpc3RUeXBlID09PSAncGljdHVyZScgfHwgdGhpcy5saXN0VHlwZSA9PT0gJ3BpY3R1cmUtY2FyZCc7XG4gIH1cblxuICBASW5wdXQoKSBsb2NhbGU6IE56U2FmZUFueSA9IHt9O1xuICBASW5wdXQoKSBsaXN0VHlwZSE6IE56VXBsb2FkTGlzdFR5cGU7XG4gIEBJbnB1dCgpXG4gIHNldCBpdGVtcyhsaXN0OiBOelVwbG9hZEZpbGVbXSkge1xuICAgIHRoaXMubGlzdCA9IGxpc3Q7XG4gIH1cbiAgQElucHV0KCkgaWNvbnMhOiBOelNob3dVcGxvYWRMaXN0O1xuICBASW5wdXQoKSBvblByZXZpZXc/OiAoZmlsZTogTnpVcGxvYWRGaWxlKSA9PiB2b2lkO1xuICBASW5wdXQoKSBvblJlbW92ZSE6IChmaWxlOiBOelVwbG9hZEZpbGUpID0+IHZvaWQ7XG4gIEBJbnB1dCgpIG9uRG93bmxvYWQ/OiAoZmlsZTogTnpVcGxvYWRGaWxlKSA9PiB2b2lkO1xuICBASW5wdXQoKSBwcmV2aWV3RmlsZT86IChmaWxlOiBOelVwbG9hZEZpbGUpID0+IE9ic2VydmFibGU8c3RyaW5nPjtcbiAgQElucHV0KCkgcHJldmlld0lzSW1hZ2U/OiAoZmlsZTogTnpVcGxvYWRGaWxlKSA9PiBib29sZWFuO1xuICBASW5wdXQoKSBpY29uUmVuZGVyOiBOekljb25SZW5kZXJUZW1wbGF0ZSB8IG51bGwgPSBudWxsO1xuICBASW5wdXQoKSBkaXI6IERpcmVjdGlvbiA9ICdsdHInO1xuXG4gIHByaXZhdGUgZG9jdW1lbnQ6IERvY3VtZW50ID0gaW5qZWN0KERPQ1VNRU5UKTtcbiAgcHJpdmF0ZSBkZXN0cm95JCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgcHJpdmF0ZSBnZW5FcnIoZmlsZTogTnpVcGxvYWRGaWxlKTogc3RyaW5nIHtcbiAgICBpZiAoZmlsZS5yZXNwb25zZSAmJiB0eXBlb2YgZmlsZS5yZXNwb25zZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgIHJldHVybiBmaWxlLnJlc3BvbnNlO1xuICAgIH1cbiAgICByZXR1cm4gKGZpbGUuZXJyb3IgJiYgZmlsZS5lcnJvci5zdGF0dXNUZXh0KSB8fCB0aGlzLmxvY2FsZS51cGxvYWRFcnJvcjtcbiAgfVxuXG4gIHByaXZhdGUgZXh0bmFtZSh1cmw6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgdGVtcCA9IHVybC5zcGxpdCgnLycpO1xuICAgIGNvbnN0IGZpbGVuYW1lID0gdGVtcFt0ZW1wLmxlbmd0aCAtIDFdO1xuICAgIGNvbnN0IGZpbGVuYW1lV2l0aG91dFN1ZmZpeCA9IGZpbGVuYW1lLnNwbGl0KC8jfFxcPy8pWzBdO1xuICAgIHJldHVybiAoL1xcLlteLi9cXFxcXSokLy5leGVjKGZpbGVuYW1lV2l0aG91dFN1ZmZpeCkgfHwgWycnXSlbMF07XG4gIH1cblxuICBpc0ltYWdlVXJsKGZpbGU6IE56VXBsb2FkRmlsZSk6IGJvb2xlYW4ge1xuICAgIGlmIChpc0ltYWdlRmlsZVR5cGUoZmlsZS50eXBlISkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBjb25zdCB1cmw6IHN0cmluZyA9IChmaWxlLnRodW1iVXJsIHx8IGZpbGUudXJsIHx8ICcnKSBhcyBzdHJpbmc7XG4gICAgaWYgKCF1cmwpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgY29uc3QgZXh0ZW5zaW9uID0gdGhpcy5leHRuYW1lKHVybCk7XG4gICAgaWYgKC9eZGF0YTppbWFnZVxcLy8udGVzdCh1cmwpIHx8IC8od2VicHxzdmd8cG5nfGdpZnxqcGd8anBlZ3xqZmlmfGJtcHxkcGcpJC9pLnRlc3QoZXh0ZW5zaW9uKSkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBlbHNlIGlmICgvXmRhdGE6Ly50ZXN0KHVybCkpIHtcbiAgICAgIC8vIG90aGVyIGZpbGUgdHlwZXMgb2YgYmFzZTY0XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfSBlbHNlIGlmIChleHRlbnNpb24pIHtcbiAgICAgIC8vIG90aGVyIGZpbGUgdHlwZXMgd2hpY2ggaGF2ZSBleHRlbnNpb25cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBwcml2YXRlIGdldEljb25UeXBlKGZpbGU6IFVwbG9hZExpc3RGaWxlKTogVXBsb2FkTGlzdEljb25UeXBlIHtcbiAgICBpZiAoIXRoaXMuc2hvd1BpYykge1xuICAgICAgcmV0dXJuICcnO1xuICAgIH1cbiAgICBpZiAoZmlsZS5pc1VwbG9hZGluZyB8fCAoIWZpbGUudGh1bWJVcmwgJiYgIWZpbGUudXJsKSkge1xuICAgICAgcmV0dXJuICd1cGxvYWRpbmcnO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gJ3RodW1ibmFpbCc7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBwcmV2aWV3SW1hZ2UoZmlsZTogRmlsZSB8IEJsb2IpOiBPYnNlcnZhYmxlPHN0cmluZz4ge1xuICAgIGlmICghaXNJbWFnZUZpbGVUeXBlKGZpbGUudHlwZSkgfHwgIXRoaXMucGxhdGZvcm0uaXNCcm93c2VyKSB7XG4gICAgICByZXR1cm4gb2YoJycpO1xuICAgIH1cblxuICAgIGNvbnN0IGNhbnZhcyA9IHRoaXMuZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG4gICAgY2FudmFzLndpZHRoID0gTUVBU1VSRV9TSVpFO1xuICAgIGNhbnZhcy5oZWlnaHQgPSBNRUFTVVJFX1NJWkU7XG4gICAgY2FudmFzLnN0eWxlLmNzc1RleHQgPSBgcG9zaXRpb246IGZpeGVkOyBsZWZ0OiAwOyB0b3A6IDA7IHdpZHRoOiAke01FQVNVUkVfU0laRX1weDsgaGVpZ2h0OiAke01FQVNVUkVfU0laRX1weDsgei1pbmRleDogOTk5OTsgZGlzcGxheTogbm9uZTtgO1xuICAgIHRoaXMuZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChjYW52YXMpO1xuICAgIGNvbnN0IGN0eCA9IGNhbnZhcy5nZXRDb250ZXh0KCcyZCcpO1xuICAgIGNvbnN0IGltZyA9IG5ldyBJbWFnZSgpO1xuICAgIGNvbnN0IG9iamVjdFVybCA9IFVSTC5jcmVhdGVPYmplY3RVUkwoZmlsZSk7XG4gICAgaW1nLnNyYyA9IG9iamVjdFVybDtcbiAgICByZXR1cm4gZnJvbUV2ZW50KGltZywgJ2xvYWQnKS5waXBlKFxuICAgICAgbWFwKCgpID0+IHtcbiAgICAgICAgY29uc3QgeyB3aWR0aCwgaGVpZ2h0IH0gPSBpbWc7XG5cbiAgICAgICAgbGV0IGRyYXdXaWR0aCA9IE1FQVNVUkVfU0laRTtcbiAgICAgICAgbGV0IGRyYXdIZWlnaHQgPSBNRUFTVVJFX1NJWkU7XG4gICAgICAgIGxldCBvZmZzZXRYID0gMDtcbiAgICAgICAgbGV0IG9mZnNldFkgPSAwO1xuXG4gICAgICAgIGlmICh3aWR0aCA8IGhlaWdodCkge1xuICAgICAgICAgIGRyYXdIZWlnaHQgPSBoZWlnaHQgKiAoTUVBU1VSRV9TSVpFIC8gd2lkdGgpO1xuICAgICAgICAgIG9mZnNldFkgPSAtKGRyYXdIZWlnaHQgLSBkcmF3V2lkdGgpIC8gMjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBkcmF3V2lkdGggPSB3aWR0aCAqIChNRUFTVVJFX1NJWkUgLyBoZWlnaHQpO1xuICAgICAgICAgIG9mZnNldFggPSAtKGRyYXdXaWR0aCAtIGRyYXdIZWlnaHQpIC8gMjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY3R4IS5kcmF3SW1hZ2UoaW1nLCBvZmZzZXRYLCBvZmZzZXRZLCBkcmF3V2lkdGgsIGRyYXdIZWlnaHQpO1xuICAgICAgICB9IGNhdGNoIHt9XG4gICAgICAgIGNvbnN0IGRhdGFVUkwgPSBjYW52YXMudG9EYXRhVVJMKCk7XG4gICAgICAgIHRoaXMuZG9jdW1lbnQuYm9keS5yZW1vdmVDaGlsZChjYW52YXMpO1xuXG4gICAgICAgIFVSTC5yZXZva2VPYmplY3RVUkwob2JqZWN0VXJsKTtcbiAgICAgICAgcmV0dXJuIGRhdGFVUkw7XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGdlblRodW1iKCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5wbGF0Zm9ybS5pc0Jyb3dzZXIpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCB3aW4gPSB3aW5kb3cgYXMgTnpTYWZlQW55O1xuICAgIGlmIChcbiAgICAgICF0aGlzLnNob3dQaWMgfHxcbiAgICAgIHR5cGVvZiBkb2N1bWVudCA9PT0gJ3VuZGVmaW5lZCcgfHxcbiAgICAgIHR5cGVvZiB3aW4gPT09ICd1bmRlZmluZWQnIHx8XG4gICAgICAhd2luLkZpbGVSZWFkZXIgfHxcbiAgICAgICF3aW4uRmlsZVxuICAgICkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmxpc3RcbiAgICAgIC5maWx0ZXIoZmlsZSA9PiBmaWxlLm9yaWdpbkZpbGVPYmogaW5zdGFuY2VvZiBGaWxlICYmIGZpbGUudGh1bWJVcmwgPT09IHVuZGVmaW5lZClcbiAgICAgIC5mb3JFYWNoKGZpbGUgPT4ge1xuICAgICAgICBmaWxlLnRodW1iVXJsID0gJyc7XG4gICAgICAgIC8vIENhcmV0YWtlciBub3RlOiB3ZSBzaG91bGRuJ3QgdXNlIHByb21pc2VzIGhlcmUgc2luY2UgdGhleSdyZSBub3QgY2FuY2VsbGFibGUuXG4gICAgICAgIC8vIEEgcHJvbWlzZSBtaWNyb3Rhc2sgY2FuIGJlIHJlc29sdmVkIGFmdGVyIHRoZSB2aWV3IGlzIGRlc3Ryb3llZC4gVGh1cyBydW5uaW5nIGBkZXRlY3RDaGFuZ2VzKClgXG4gICAgICAgIC8vIHdpbGwgY2F1c2UgYSBydW50aW1lIGV4Y2VwdGlvbiAoYGRldGVjdENoYW5nZXMoKWAgY2Fubm90IGJlIHJ1biBvbiBkZXN0cm95ZWQgdmlld3MpLlxuICAgICAgICBjb25zdCBkYXRhVXJsJCA9ICh0aGlzLnByZXZpZXdGaWxlID8gdGhpcy5wcmV2aWV3RmlsZShmaWxlKSA6IHRoaXMucHJldmlld0ltYWdlKGZpbGUub3JpZ2luRmlsZU9iaiEpKS5waXBlKFxuICAgICAgICAgIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLm5nWm9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PiB7XG4gICAgICAgICAgZGF0YVVybCQuc3Vic2NyaWJlKGRhdGFVcmwgPT4ge1xuICAgICAgICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHtcbiAgICAgICAgICAgICAgZmlsZS50aHVtYlVybCA9IGRhdGFVcmw7XG4gICAgICAgICAgICAgIHRoaXMuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gIH1cblxuICBwcml2YXRlIHNob3dEb3dubG9hZChmaWxlOiBOelVwbG9hZEZpbGUpOiBib29sZWFuIHtcbiAgICByZXR1cm4gISEodGhpcy5pY29ucy5zaG93RG93bmxvYWRJY29uICYmIGZpbGUuc3RhdHVzID09PSAnZG9uZScpO1xuICB9XG5cbiAgcHJpdmF0ZSBmaXhEYXRhKCk6IHZvaWQge1xuICAgIHRoaXMubGlzdC5mb3JFYWNoKGZpbGUgPT4ge1xuICAgICAgZmlsZS5pc1VwbG9hZGluZyA9IGZpbGUuc3RhdHVzID09PSAndXBsb2FkaW5nJztcbiAgICAgIGZpbGUubWVzc2FnZSA9IHRoaXMuZ2VuRXJyKGZpbGUpO1xuICAgICAgZmlsZS5saW5rUHJvcHMgPSB0eXBlb2YgZmlsZS5saW5rUHJvcHMgPT09ICdzdHJpbmcnID8gSlNPTi5wYXJzZShmaWxlLmxpbmtQcm9wcykgOiBmaWxlLmxpbmtQcm9wcztcbiAgICAgIGZpbGUuaXNJbWFnZVVybCA9IHRoaXMucHJldmlld0lzSW1hZ2UgPyB0aGlzLnByZXZpZXdJc0ltYWdlKGZpbGUpIDogdGhpcy5pc0ltYWdlVXJsKGZpbGUpO1xuICAgICAgZmlsZS5pY29uVHlwZSA9IHRoaXMuZ2V0SWNvblR5cGUoZmlsZSk7XG4gICAgICBmaWxlLnNob3dEb3dubG9hZCA9IHRoaXMuc2hvd0Rvd25sb2FkKGZpbGUpO1xuICAgIH0pO1xuICB9XG5cbiAgaGFuZGxlUHJldmlldyhmaWxlOiBOelVwbG9hZEZpbGUsIGU6IEV2ZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLm9uUHJldmlldykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICByZXR1cm4gdGhpcy5vblByZXZpZXcoZmlsZSk7XG4gIH1cblxuICBoYW5kbGVSZW1vdmUoZmlsZTogTnpVcGxvYWRGaWxlLCBlOiBFdmVudCk6IHZvaWQge1xuICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICBpZiAodGhpcy5vblJlbW92ZSkge1xuICAgICAgdGhpcy5vblJlbW92ZShmaWxlKTtcbiAgICB9XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaGFuZGxlRG93bmxvYWQoZmlsZTogTnpVcGxvYWRGaWxlKTogdm9pZCB7XG4gICAgaWYgKHR5cGVvZiB0aGlzLm9uRG93bmxvYWQgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIHRoaXMub25Eb3dubG9hZChmaWxlKTtcbiAgICB9IGVsc2UgaWYgKGZpbGUudXJsKSB7XG4gICAgICB3aW5kb3cub3BlbihmaWxlLnVybCk7XG4gICAgfVxuICB9XG5cbiAgLy8gI2VuZHJlZ2lvblxuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgY2RyOiBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICBwcml2YXRlIG5nWm9uZTogTmdab25lLFxuICAgIHByaXZhdGUgcGxhdGZvcm06IFBsYXRmb3JtXG4gICkge31cblxuICBkZXRlY3RDaGFuZ2VzKCk6IHZvaWQge1xuICAgIHRoaXMuZml4RGF0YSgpO1xuICAgIHRoaXMuY2RyLmRldGVjdENoYW5nZXMoKTtcbiAgfVxuXG4gIG5nT25DaGFuZ2VzKCk6IHZvaWQge1xuICAgIHRoaXMuZml4RGF0YSgpO1xuICAgIHRoaXMuZ2VuVGh1bWIoKTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xuICB9XG59XG4iLCJAZm9yIChmaWxlIG9mIGxpc3Q7IHRyYWNrIGZpbGUpIHtcbiAgPGRpdiBjbGFzcz1cImFudC11cGxvYWQtbGlzdC17eyBsaXN0VHlwZSB9fS1jb250YWluZXJcIj5cbiAgICA8ZGl2XG4gICAgICBjbGFzcz1cImFudC11cGxvYWQtbGlzdC1pdGVtIGFudC11cGxvYWQtbGlzdC1pdGVtLXt7IGZpbGUuc3RhdHVzIH19IGFudC11cGxvYWQtbGlzdC1pdGVtLWxpc3QtdHlwZS17eyBsaXN0VHlwZSB9fVwiXG4gICAgICBbYXR0ci5kYXRhLWtleV09XCJmaWxlLmtleVwiXG4gICAgICBAaXRlbVN0YXRlXG4gICAgICBuei10b29sdGlwXG4gICAgICBbbnpUb29sdGlwVGl0bGVdPVwiZmlsZS5zdGF0dXMgPT09ICdlcnJvcicgPyBmaWxlLm1lc3NhZ2UgOiBudWxsXCJcbiAgICA+XG4gICAgICA8bmctdGVtcGxhdGUgI2ljb24+XG4gICAgICAgIEBzd2l0Y2ggKGZpbGUuaWNvblR5cGUpIHtcbiAgICAgICAgICBAY2FzZSAoJ3VwbG9hZGluZycpIHtcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJhbnQtdXBsb2FkLWxpc3QtaXRlbS10aHVtYm5haWxcIiBbY2xhc3MuYW50LXVwbG9hZC1saXN0LWl0ZW0tZmlsZV09XCIhZmlsZS5pc1VwbG9hZGluZ1wiPlxuICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgW25nVGVtcGxhdGVPdXRsZXRdPVwiaWNvbk5vZGVcIiBbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwieyAkaW1wbGljaXQ6IGZpbGUgfVwiPjwvbmctdGVtcGxhdGU+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICB9XG4gICAgICAgICAgQGNhc2UgKCd0aHVtYm5haWwnKSB7XG4gICAgICAgICAgICA8YVxuICAgICAgICAgICAgICBjbGFzcz1cImFudC11cGxvYWQtbGlzdC1pdGVtLXRodW1ibmFpbFwiXG4gICAgICAgICAgICAgIFtjbGFzcy5hbnQtdXBsb2FkLWxpc3QtaXRlbS1maWxlXT1cIiFmaWxlLmlzSW1hZ2VVcmxcIlxuICAgICAgICAgICAgICB0YXJnZXQ9XCJfYmxhbmtcIlxuICAgICAgICAgICAgICByZWw9XCJub29wZW5lciBub3JlZmVycmVyXCJcbiAgICAgICAgICAgICAgW2hyZWZdPVwiZmlsZS51cmwgfHwgZmlsZS50aHVtYlVybFwiXG4gICAgICAgICAgICAgIChjbGljayk9XCJoYW5kbGVQcmV2aWV3K