UNPKG

ngx-dropzone-ivy

Version:

A highly configurable dropzone component for Angular.

261 lines 35.8 kB
import { Component, EventEmitter, Output, Input, ViewChild, ContentChildren, QueryList, HostBinding, HostListener, Self, ElementRef } from '@angular/core'; import { NgxDropzoneService } from '../ngx-dropzone.service'; import { coerceBooleanProperty, coerceNumberProperty } from '../helpers'; import { NgxDropzonePreviewComponent } from '../ngx-dropzone-preview/ngx-dropzone-preview.component'; import * as i0 from "@angular/core"; import * as i1 from "../ngx-dropzone.service"; import * as i2 from "@angular/common"; export class NgxDropzoneComponent { constructor(service) { this.service = service; /** Emitted when any files were added or rejected. */ this.change = new EventEmitter(); /** Set the accepted file types. Defaults to '*'. */ this.accept = '*'; this._disabled = false; this._multiple = true; this._maxFileSize = undefined; this._expandable = false; this._disableClick = false; this._processDirectoryDrop = false; this._isHovered = false; } get _hasPreviews() { return !!this._previewChildren.length; } /** Disable any user interaction with the component. */ get disabled() { return this._disabled; } set disabled(value) { this._disabled = coerceBooleanProperty(value); if (this._isHovered) { this._isHovered = false; } } /** Allow the selection of multiple files. */ get multiple() { return this._multiple; } set multiple(value) { this._multiple = coerceBooleanProperty(value); } /** Set the maximum size a single file may have. */ get maxFileSize() { return this._maxFileSize; } set maxFileSize(value) { this._maxFileSize = coerceNumberProperty(value); } /** Allow the dropzone container to expand vertically. */ get expandable() { return this._expandable; } set expandable(value) { this._expandable = coerceBooleanProperty(value); } /** Open the file selector on click. */ get disableClick() { return this._disableClick; } set disableClick(value) { this._disableClick = coerceBooleanProperty(value); } /** Allow dropping directories. */ get processDirectoryDrop() { return this._processDirectoryDrop; } set processDirectoryDrop(value) { this._processDirectoryDrop = coerceBooleanProperty(value); } /** Show the native OS file explorer to select files. */ _onClick() { if (!this.disableClick) { this.showFileSelector(); } } _onDragOver(event) { if (this.disabled) { return; } this.preventDefault(event); this._isHovered = true; } _onDragLeave() { this._isHovered = false; } _onDrop(event) { if (this.disabled) { return; } this.preventDefault(event); this._isHovered = false; // if processDirectoryDrop is not enabled or webkitGetAsEntry is not supported we handle the drop as usual if (!this.processDirectoryDrop || !DataTransferItem.prototype.webkitGetAsEntry) { this.handleFileDrop(event.dataTransfer.files); // if processDirectoryDrop is enabled and webkitGetAsEntry is supported we can extract files from a dropped directory } else { const droppedItems = event.dataTransfer.items; if (droppedItems.length > 0) { const droppedFiles = []; const droppedDirectories = []; // seperate dropped files from dropped directories for easier handling for (let i = 0; i < droppedItems.length; i++) { const entry = droppedItems[i].webkitGetAsEntry(); if (entry.isFile) { droppedFiles.push(event.dataTransfer.files[i]); } else if (entry.isDirectory) { droppedDirectories.push(entry); } } // create a DataTransfer const droppedFilesList = new DataTransfer(); droppedFiles.forEach((droppedFile) => { droppedFilesList.items.add(droppedFile); }); // if no directory is dropped we are done and can call handleFileDrop if (!droppedDirectories.length && droppedFilesList.items.length) { this.handleFileDrop(droppedFilesList.files); } // if directories are dropped we extract the files from these directories one-by-one and add it to droppedFilesList if (droppedDirectories.length) { const extractFilesFromDirectoryCalls = []; for (const droppedDirectory of droppedDirectories) { extractFilesFromDirectoryCalls.push(this.extractFilesFromDirectory(droppedDirectory)); } // wait for all directories to be proccessed to add the extracted files afterwards Promise.all(extractFilesFromDirectoryCalls).then((allExtractedFiles) => { allExtractedFiles.reduce((a, b) => [...a, ...b]).forEach((extractedFile) => { droppedFilesList.items.add(extractedFile); }); this.handleFileDrop(droppedFilesList.files); }); } } } } extractFilesFromDirectory(directory) { async function getFileFromFileEntry(fileEntry) { try { return await new Promise((resolve, reject) => fileEntry.file(resolve, reject)); } catch (err) { console.log('Error converting a fileEntry to a File: ', err); } } return new Promise((resolve, reject) => { const files = []; const dirReader = directory.createReader(); // we need this to be a recursion because of this issue: https://bugs.chromium.org/p/chromium/issues/detail?id=514087 const readEntries = () => { dirReader.readEntries(async (dirItems) => { if (!dirItems.length) { resolve(files); } else { const fileEntries = dirItems.filter((dirItem) => dirItem.isFile); for (const fileEntry of fileEntries) { const file = await getFileFromFileEntry(fileEntry); files.push(file); } readEntries(); } }); }; readEntries(); }); } showFileSelector() { if (!this.disabled) { this._fileInput.nativeElement.click(); } } _onFilesSelected(event) { const files = event.target.files; this.handleFileDrop(files); // Reset the native file input element to allow selecting the same file again this._fileInput.nativeElement.value = ''; // fix(#32): Prevent the default event behaviour which caused the change event to emit twice. this.preventDefault(event); } handleFileDrop(files) { const result = this.service.parseFileList(files, this.accept, this.maxFileSize, this.multiple); this.change.next({ addedFiles: result.addedFiles, rejectedFiles: result.rejectedFiles, source: this }); } preventDefault(event) { event.preventDefault(); event.stopPropagation(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NgxDropzoneComponent, deps: [{ token: i1.NgxDropzoneService, self: true }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: NgxDropzoneComponent, selector: "ngx-dropzone, [ngx-dropzone]", inputs: { accept: "accept", disabled: "disabled", multiple: "multiple", maxFileSize: "maxFileSize", expandable: "expandable", disableClick: "disableClick", processDirectoryDrop: "processDirectoryDrop", id: "id", ariaLabel: ["aria-label", "ariaLabel"], ariaLabelledby: ["aria-labelledby", "ariaLabelledby"], ariaDescribedBy: ["aria-describedby", "ariaDescribedBy"] }, outputs: { change: "change" }, host: { listeners: { "click": "_onClick()", "dragover": "_onDragOver($event)", "dragleave": "_onDragLeave()", "drop": "_onDrop($event)" }, properties: { "class.ngx-dz-disabled": "this.disabled", "class.expandable": "this.expandable", "class.unclickable": "this.disableClick", "class.ngx-dz-hovered": "this._isHovered" } }, providers: [NgxDropzoneService], queries: [{ propertyName: "_previewChildren", predicate: NgxDropzonePreviewComponent, descendants: true }], viewQueries: [{ propertyName: "_fileInput", first: true, predicate: ["fileInput"], descendants: true, static: true }], ngImport: i0, template: "<input #fileInput type=\"file\" [id]=\"id\" [multiple]=\"multiple\" [accept]=\"accept\" [disabled]=\"disabled\"\r\n (change)=\"_onFilesSelected($event)\" [attr.aria-label]=\"ariaLabel\" [attr.aria-labelledby]=\"ariaLabelledby\"\r\n [attr.aria-describedby]=\"ariaDescribedBy\">\r\n<ng-content select=\"ngx-dropzone-label\" *ngIf=\"!_hasPreviews\"></ng-content>\r\n<ng-content select=\"ngx-dropzone-preview\"></ng-content>\r\n<ng-content></ng-content>\r\n", styles: [":host{display:flex;align-items:center;height:180px;background:#fff;cursor:pointer;color:#717386;border:2px dashed #717386;border-radius:5px;font-size:16px;overflow-x:auto}:host.ngx-dz-hovered{border-style:solid}:host.ngx-dz-disabled{opacity:.5;cursor:no-drop;pointer-events:none}:host.expandable{overflow:hidden;height:unset;min-height:180px;flex-wrap:wrap}:host.unclickable{cursor:default}:host ::ng-deep ngx-dropzone-label{text-align:center;z-index:10;margin:10px auto}:host input{width:.1px;height:.1px;opacity:0;overflow:hidden;position:absolute;z-index:-1}:host input:focus+::ng-deep ngx-dropzone-label{outline:1px dotted #000;outline:-webkit-focus-ring-color auto 5px}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NgxDropzoneComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-dropzone, [ngx-dropzone]', providers: [NgxDropzoneService], template: "<input #fileInput type=\"file\" [id]=\"id\" [multiple]=\"multiple\" [accept]=\"accept\" [disabled]=\"disabled\"\r\n (change)=\"_onFilesSelected($event)\" [attr.aria-label]=\"ariaLabel\" [attr.aria-labelledby]=\"ariaLabelledby\"\r\n [attr.aria-describedby]=\"ariaDescribedBy\">\r\n<ng-content select=\"ngx-dropzone-label\" *ngIf=\"!_hasPreviews\"></ng-content>\r\n<ng-content select=\"ngx-dropzone-preview\"></ng-content>\r\n<ng-content></ng-content>\r\n", styles: [":host{display:flex;align-items:center;height:180px;background:#fff;cursor:pointer;color:#717386;border:2px dashed #717386;border-radius:5px;font-size:16px;overflow-x:auto}:host.ngx-dz-hovered{border-style:solid}:host.ngx-dz-disabled{opacity:.5;cursor:no-drop;pointer-events:none}:host.expandable{overflow:hidden;height:unset;min-height:180px;flex-wrap:wrap}:host.unclickable{cursor:default}:host ::ng-deep ngx-dropzone-label{text-align:center;z-index:10;margin:10px auto}:host input{width:.1px;height:.1px;opacity:0;overflow:hidden;position:absolute;z-index:-1}:host input:focus+::ng-deep ngx-dropzone-label{outline:1px dotted #000;outline:-webkit-focus-ring-color auto 5px}\n"] }] }], ctorParameters: function () { return [{ type: i1.NgxDropzoneService, decorators: [{ type: Self }] }]; }, propDecorators: { _previewChildren: [{ type: ContentChildren, args: [NgxDropzonePreviewComponent, { descendants: true }] }], _fileInput: [{ type: ViewChild, args: ['fileInput', { static: true }] }], change: [{ type: Output }], accept: [{ type: Input }], disabled: [{ type: Input }, { type: HostBinding, args: ['class.ngx-dz-disabled'] }], multiple: [{ type: Input }], maxFileSize: [{ type: Input }], expandable: [{ type: Input }, { type: HostBinding, args: ['class.expandable'] }], disableClick: [{ type: Input }, { type: HostBinding, args: ['class.unclickable'] }], processDirectoryDrop: [{ type: Input }], id: [{ type: Input }], ariaLabel: [{ type: Input, args: ['aria-label'] }], ariaLabelledby: [{ type: Input, args: ['aria-labelledby'] }], ariaDescribedBy: [{ type: Input, args: ['aria-describedby'] }], _isHovered: [{ type: HostBinding, args: ['class.ngx-dz-hovered'] }], _onClick: [{ type: HostListener, args: ['click'] }], _onDragOver: [{ type: HostListener, args: ['dragover', ['$event']] }], _onDragLeave: [{ type: HostListener, args: ['dragleave'] }], _onDrop: [{ type: HostListener, args: ['drop', ['$event']] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWRyb3B6b25lLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1kcm9wem9uZS9zcmMvbGliL25neC1kcm9wem9uZS9uZ3gtZHJvcHpvbmUuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWRyb3B6b25lL3NyYy9saWIvbmd4LWRyb3B6b25lL25neC1kcm9wem9uZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxlQUFlLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzSixPQUFPLEVBQUMsa0JBQWtCLEVBQWUsTUFBTSx5QkFBeUIsQ0FBQztBQUN6RSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDekUsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sd0RBQXdELENBQUM7Ozs7QUFjckcsTUFBTSxPQUFPLG9CQUFvQjtJQUUvQixZQUNrQixPQUEyQjtRQUEzQixZQUFPLEdBQVAsT0FBTyxDQUFvQjtRQWM3QyxxREFBcUQ7UUFDbEMsV0FBTSxHQUFHLElBQUksWUFBWSxFQUEwQixDQUFDO1FBRXZFLG9EQUFvRDtRQUMzQyxXQUFNLEdBQUcsR0FBRyxDQUFDO1FBZWQsY0FBUyxHQUFHLEtBQUssQ0FBQztRQVVsQixjQUFTLEdBQUcsSUFBSSxDQUFDO1FBVWpCLGlCQUFZLEdBQVcsU0FBUyxDQUFDO1FBV2pDLGdCQUFXLEdBQVksS0FBSyxDQUFDO1FBVzdCLGtCQUFhLEdBQUcsS0FBSyxDQUFDO1FBVXRCLDBCQUFxQixHQUFHLEtBQUssQ0FBQztRQVN0QyxlQUFVLEdBQUcsS0FBSyxD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QyxtQkFBbUI7Z0JBVzVCLG9CQUFvQjtzQkFEdkIsS0FBSztnQkFVRyxFQUFFO3NCQUFWLEtBQUs7Z0JBQ2UsU0FBUztzQkFBN0IsS0FBSzt1QkFBQyxZQUFZO2dCQUNPLGNBQWM7c0JBQXZDLEtBQUs7dUJBQUMsaUJBQWlCO2dCQUNHLGVBQWU7c0JBQXpDLEtBQUs7dUJBQUMsa0JBQWtCO2dCQUd6QixVQUFVO3NCQURULFdBQVc7dUJBQUMsc0JBQXNCO2dCQUtuQyxRQUFRO3NCQURQLFlBQVk7dUJBQUMsT0FBTztnQkFRckIsV0FBVztzQkFEVixZQUFZO3VCQUFDLFVBQVUsRUFBRSxDQUFDLFFBQVEsQ0FBQztnQkFXcEMsWUFBWTtzQkFEWCxZQUFZO3VCQUFDLFdBQVc7Z0JBTXpCLE9BQU87c0JBRE4sWUFBWTt1QkFBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgT3V0cHV0LCBJbnB1dCwgVmlld0NoaWxkLCBDb250ZW50Q2hpbGRyZW4sIFF1ZXJ5TGlzdCwgSG9zdEJpbmRpbmcsIEhvc3RMaXN0ZW5lciwgU2VsZiwgRWxlbWVudFJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQge05neERyb3B6b25lU2VydmljZSwgUmVqZWN0ZWRGaWxlfSBmcm9tICcuLi9uZ3gtZHJvcHpvbmUuc2VydmljZSc7XHJcbmltcG9ydCB7IGNvZXJjZUJvb2xlYW5Qcm9wZXJ0eSwgY29lcmNlTnVtYmVyUHJvcGVydHkgfSBmcm9tICcuLi9oZWxwZXJzJztcclxuaW1wb3J0IHsgTmd4RHJvcHpvbmVQcmV2aWV3Q29tcG9uZW50IH0gZnJvbSAnLi4vbmd4LWRyb3B6b25lLXByZXZpZXcvbmd4LWRyb3B6b25lLXByZXZpZXcuY29tcG9uZW50JztcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgTmd4RHJvcHpvbmVDaGFuZ2VFdmVudCB7XHJcbiAgc291cmNlOiBOZ3hEcm9wem9uZUNvbXBvbmVudDtcclxuICBhZGRlZEZpbGVzOiBGaWxlW107XHJcbiAgcmVqZWN0ZWRGaWxlczogUmVqZWN0ZWRGaWxlW107XHJcbn1cclxuXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnbmd4LWRyb3B6b25lLCBbbmd4LWRyb3B6b25lXScsXHJcbiAgdGVtcGxhdGVVcmw6ICcuL25neC1kcm9wem9uZS5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVVcmxzOiBbJy4vbmd4LWRyb3B6b25lLmNvbXBvbmVudC5zY3NzJ10sXHJcbiAgcHJvdmlkZXJzOiBbTmd4RHJvcHpvbmVTZXJ2aWNlXVxyXG59KVxyXG5leHBvcnQgY2xhc3MgTmd4RHJvcHpvbmVDb21wb25lbnQge1xyXG5cclxuICBjb25zdHJ1Y3RvcihcclxuICAgIEBTZWxmKCkgcHJpdmF0ZSBzZXJ2aWNlOiBOZ3hEcm9wem9uZVNlcnZpY2VcclxuICApIHt9XHJcblxyXG4gIC8qKiBBIGxpc3Qgb2YgdGhlIGNvbnRlbnQtcHJvamVjdGVkIHByZXZpZXcgY2hpbGRyZW4uICovXHJcbiAgQENvbnRlbnRDaGlsZHJlbihOZ3hEcm9wem9uZVByZXZpZXdDb21wb25lbnQsIHsgZGVzY2VuZGFudHM6IHRydWUgfSlcclxuICBfcHJldmlld0NoaWxkcmVuOiBRdWVyeUxpc3Q8Tmd4RHJvcHpvbmVQcmV2aWV3Q29tcG9uZW50PjtcclxuXHJcbiAgZ2V0IF9oYXNQcmV2aWV3cygpOiBib29sZWFuIHtcclxuICAgIHJldHVybiAhIXRoaXMuX3ByZXZpZXdDaGlsZHJlbi5sZW5ndGg7XHJcbiAgfVxyXG5cclxuICAvKiogQSB0ZW1wbGF0ZSByZWZlcmVuY2UgdG8gdGhlIG5hdGl2ZSBmaWxlIGlucHV0IGVsZW1lbnQuICovXHJcbiAgQFZpZXdDaGlsZCgnZmlsZUlucHV0JywgeyBzdGF0aWM6IHRydWUgfSkgX2ZpbGVJbnB1dDogRWxlbWVudFJlZjtcclxuXHJcbiAgLyoqIEVtaXR0ZWQgd2hlbiBhbnkgZmlsZXMgd2VyZSBhZGRlZCBvciByZWplY3RlZC4gKi9cclxuICBAT3V0cHV0KCkgcmVhZG9ubHkgY2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxOZ3hEcm9wem9uZUNoYW5nZUV2ZW50PigpO1xyXG5cclxuICAvKiogU2V0IHRoZSBhY2NlcHRlZCBmaWxlIHR5cGVzLiBEZWZhdWx0cyB0byAnKicuICovXHJcbiAgQElucHV0KCkgYWNjZXB0ID0gJyonO1xyXG5cclxuICAvKiogRGlzYWJsZSBhbnkgdXNlciBpbnRlcmFjdGlvbiB3aXRoIHRoZSBjb21wb25lbnQuICovXHJcbiAgQElucHV0KClcclxuICBASG9zdEJpbmRpbmcoJ2NsYXNzLm5neC1kei1kaXNhYmxlZCcpXHJcbiAgZ2V0IGRpc2FibGVkKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMuX2Rpc2FibGVkO1xyXG4gIH1cclxuICBzZXQgZGlzYWJsZWQodmFsdWU6IGJvb2xlYW4pIHtcclxuICAgIHRoaXMuX2Rpc2FibGVkID0gY29lcmNlQm9vbGVhblByb3BlcnR5KHZhbHVlKTtcclxuXHJcbiAgICBpZiAodGhpcy5faXNIb3ZlcmVkKSB7XHJcbiAgICAgIHRoaXMuX2lzSG92ZXJlZCA9IGZhbHNlO1xyXG4gICAgfVxyXG4gIH1cclxuICBwcml2YXRlIF9kaXNhYmxlZCA9IGZhbHNlO1xyXG5cclxuICAvKiogQWxsb3cgdGhlIHNlbGVjdGlvbiBvZiBtdWx0aXBsZSBmaWxlcy4gKi9cclxuICBASW5wdXQoKVxyXG4gIGdldCBtdWx0aXBsZSgpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLl9tdWx0aXBsZTtcclxuICB9XHJcbiAgc2V0IG11bHRpcGxlKHZhbHVlOiBib29sZWFuKSB7XHJcbiAgICB0aGlzLl9tdWx0aXBsZSA9IGNvZXJjZUJvb2xlYW5Qcm9wZXJ0eSh2YWx1ZSk7XHJcbiAgfVxyXG4gIHByaXZhdGUgX211bHRpcGxlID0gdHJ1ZTtcclxuXHJcbiAgLyoqIFNldCB0aGUgbWF4aW11bSBzaXplIGEgc2luZ2xlIGZpbGUgbWF5IGhhdmUuICovXHJcbiAgQElucHV0KClcclxuICBnZXQgbWF4RmlsZVNpemUoKTogbnVtYmVyIHtcclxuICAgIHJldHVybiB0aGlzLl9tYXhGaWxlU2l6ZTtcclxuICB9XHJcbiAgc2V0IG1heEZpbGVTaXplKHZhbHVlOiBudW1iZXIpIHtcclxuICAgIHRoaXMuX21heEZpbGVTaXplID0gY29lcmNlTnVtYmVyUHJvcGVydHkodmFsdWUpO1xyXG4gIH1cclxuICBwcml2YXRlIF9tYXhGaWxlU2l6ZTogbnVtYmVyID0gdW5kZWZpbmVkO1xyXG5cclxuICAvKiogQWxsb3cgdGhlIGRyb3B6b25lIGNvbnRhaW5lciB0byBleHBhbmQgdmVydGljYWxseS4gKi9cclxuICBASW5wdXQoKVxyXG4gIEBIb3N0QmluZGluZygnY2xhc3MuZXhwYW5kYWJsZScpXHJcbiAgZ2V0IGV4cGFuZGFibGUoKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gdGhpcy5fZXhwYW5kYWJsZTtcclxuICB9XHJcbiAgc2V0IGV4cGFuZGFibGUodmFsdWU6IGJvb2xlYW4pIHtcclxuICAgIHRoaXMuX2V4cGFuZGFibGUgPSBjb2VyY2VCb29sZWFuUHJvcGVydHkodmFsdWUpO1xyXG4gIH1cclxuICBwcml2YXRlIF9leHBhbmRhYmxlOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gIC8qKiBPcGVuIHRoZSBmaWxlIHNlbGVjdG9yIG9uIGNsaWNrLiAqL1xyXG4gIEBJbnB1dCgpXHJcbiAgQEhvc3RCaW5kaW5nKCdjbGFzcy51bmNsaWNrYWJsZScpXHJcbiAgZ2V0IGRpc2FibGVDbGljaygpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLl9kaXNhYmxlQ2xpY2s7XHJcbiAgfVxyXG4gIHNldCBkaXNhYmxlQ2xpY2sodmFsdWU6IGJvb2xlYW4pIHtcclxuICAgIHRoaXMuX2Rpc2FibGVDbGljayA9IGNvZXJjZUJvb2xlYW5Qcm9wZXJ0eSh2YWx1ZSk7XHJcbiAgfVxyXG4gIHByaXZhdGUgX2Rpc2FibGVDbGljayA9IGZhbHNlO1xyXG5cclxuICAvKiogQWxsb3cgZHJvcHBpbmcgZGlyZWN0b3JpZXMuICovXHJcbiAgQElucHV0KClcclxuICBnZXQgcHJvY2Vzc0RpcmVjdG9yeURyb3AoKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gdGhpcy5fcHJvY2Vzc0RpcmVjdG9yeURyb3A7XHJcbiAgfVxyXG4gIHNldCBwcm9jZXNzRGlyZWN0b3J5RHJvcCh2YWx1ZTogYm9vbGVhbikge1xyXG4gICAgdGhpcy5fcHJvY2Vzc0RpcmVjdG9yeURyb3AgPSBjb2VyY2VCb29sZWFuUHJvcGVydHkodmFsdWUpO1xyXG4gIH1cclxuICBwcml2YXRlIF9wcm9jZXNzRGlyZWN0b3J5RHJvcCA9IGZhbHNlO1xyXG5cclxuICAvKiogRXhwb3NlIHRoZSBpZCwgYXJpYS1sYWJlbCwgYXJpYS1sYWJlbGxlZGJ5IGFuZCBhcmlhLWRlc2NyaWJlZGJ5IG9mIHRoZSBuYXRpdmUgZmlsZSBpbnB1dCBmb3IgcHJvcGVyIGFjY2Vzc2liaWxpdHkuICovXHJcbiAgQElucHV0KCkgaWQ6IHN0cmluZztcclxuICBASW5wdXQoJ2FyaWEtbGFiZWwnKSBhcmlhTGFiZWw6IHN0cmluZztcclxuICBASW5wdXQoJ2FyaWEtbGFiZWxsZWRieScpIGFyaWFMYWJlbGxlZGJ5OiBzdHJpbmc7XHJcbiAgQElucHV0KCdhcmlhLWRlc2NyaWJlZGJ5JykgYXJpYURlc2NyaWJlZEJ5OiBzdHJpbmc7XHJcblxyXG4gIEBIb3N0QmluZGluZygnY2xhc3Mubmd4LWR6LWhvdmVyZWQnKVxyXG4gIF9pc0hvdmVyZWQgPSBmYWxzZTtcclxuXHJcbiAgLyoqIFNob3cgdGhlIG5hdGl2ZSBPUyBmaWxlIGV4cGxvcmVyIHRvIHNlbGVjdCBmaWxlcy4gKi9cclxuICBASG9zdExpc3RlbmVyKCdjbGljaycpXHJcbiAgX29uQ2xpY2soKSB7XHJcbiAgICBpZiAoIXRoaXMuZGlzYWJsZUNsaWNrKSB7XHJcbiAgICAgIHRoaXMuc2hvd0ZpbGVTZWxlY3RvcigpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgQEhvc3RMaXN0ZW5lcignZHJhZ292ZXInLCBbJyRldmVudCddKVxyXG4gIF9vbkRyYWdPdmVyKGV2ZW50KSB7XHJcbiAgICBpZiAodGhpcy5kaXNhYmxlZCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5wcmV2ZW50RGVmYXVsdChldmVudCk7XHJcbiAgICB0aGlzLl9pc0hvdmVyZWQgPSB0cnVlO1xyXG4gIH1cclxuXHJcbiAgQEhvc3RMaXN0ZW5lcignZHJhZ2xlYXZlJylcclxuICBfb25EcmFnTGVhdmUoKSB7XHJcbiAgICB0aGlzLl9pc0hvdmVyZWQgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIEBIb3N0TGlzdGVuZXIoJ2Ryb3AnLCBbJyRldmVudCddKVxyXG4gIF9vbkRyb3AoZXZlbnQpIHtcclxuICAgIGlmICh0aGlzLmRpc2FibGVkKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLnByZXZlbnREZWZhdWx0KGV2ZW50KTtcclxuICAgIHRoaXMuX2lzSG92ZXJlZCA9IGZhbHNlO1xyXG5cclxuICAgIC8vIGlmIHByb2Nlc3NEaXJlY3RvcnlEcm9wIGlzIG5vdCBlbmFibGVkIG9yIHdlYmtpdEdldEFzRW50cnkgaXMgbm90IHN1cHBvcnRlZCB3ZSBoYW5kbGUgdGhlIGRyb3AgYXMgdXN1YWxcclxuICAgIGlmICghdGhpcy5wcm9jZXNzRGlyZWN0b3J5RHJvcCB8fCAhRGF0YVRyYW5zZmVySXRlbS5wcm90b3R5cGUud2Via2l0R2V0QXNFbnRyeSkge1xyXG4gICAgICB0aGlzLmhhbmRsZUZpbGVEcm9wKGV2ZW50LmRhdGFUcmFuc2Zlci5maWxlcyk7XHJcblxyXG4gICAgLy8gaWYgcHJvY2Vzc0RpcmVjdG9yeURyb3AgaXMgZW5hYmxlZCBhbmQgd2Via2l0R2V0QXNFbnRyeSBpcyBzdXBwb3J0ZWQgd2UgY2FuIGV4dHJhY3QgZmlsZXMgZnJvbSBhIGRyb3BwZWQgZGlyZWN0b3J5XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjb25zdCBkcm9wcGVkSXRlbXM6IERhdGFUcmFuc2Zlckl0ZW1bXSA9IGV2ZW50LmRhdGFUcmFuc2Zlci5pdGVtcztcclxuXHJcbiAgICAgIGlmIChkcm9wcGVkSXRlbXMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgIGNvbnN0IGRyb3BwZWRGaWxlczogRmlsZVtdID0gW107XHJcbiAgICAgICAgY29uc3QgZHJvcHBlZERpcmVjdG9yaWVzID0gW107XHJcblxyXG4gICAgICAgIC8vIHNlcGVyYXRlIGRyb3BwZWQgZmlsZXMgZnJvbSBkcm9wcGVkIGRpcmVjdG9yaWVzIGZvciBlYXNpZXIgaGFuZGxpbmdcclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGRyb3BwZWRJdGVtcy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgY29uc3QgZW50cnkgPSBkcm9wcGVkSXRlbXNbaV0ud2Via2l0R2V0QXNFbnRyeSgpO1xyXG4gICAgICAgICAgaWYgKGVudHJ5LmlzRmlsZSkge1xyXG4gICAgICAgICAgICBkcm9wcGVkRmlsZXMucHVzaChldmVudC5kYXRhVHJhbnNmZXIuZmlsZXNbaV0pO1xyXG4gICAgICAgICAgfSBlbHNlIGlmIChlbnRyeS5pc0RpcmVjdG9yeSkge1xyXG4gICAgICAgICAgICBkcm9wcGVkRGlyZWN0b3JpZXMucHVzaChlbnRyeSk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBjcmVhdGUgYSBEYXRhVHJhbnNmZXJcclxuICAgICAgICBjb25zdCBkcm9wcGVkRmlsZXNMaXN0ID0gbmV3IERhdGFUcmFuc2ZlcigpO1xyXG4gICAgICAgIGRyb3BwZWRGaWxlcy5mb3JFYWNoKChkcm9wcGVkRmlsZSkgPT4ge1xyXG4gICAgICAgICAgZHJvcHBlZEZpbGVzTGlzdC5pdGVtcy5hZGQoZHJvcHBlZEZpbGUpO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBpZiBubyBkaXJlY3RvcnkgaXMgZHJvcHBlZCB3ZSBhcmUgZG9uZSBhbmQgY2FuIGNhbGwgaGFuZGxlRmlsZURyb3BcclxuICAgICAgICBpZiAoIWRyb3BwZWREaXJlY3Rvcmllcy5sZW5ndGggJiYgZHJvcHBlZEZpbGVzTGlzdC5pdGVtcy5sZW5ndGgpIHtcclxuICAgICAgICAgIHRoaXMuaGFuZGxlRmlsZURyb3AoZHJvcHBlZEZpbGVzTGlzdC5maWxlcyk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBpZiBkaXJlY3RvcmllcyBhcmUgZHJvcHBlZCB3ZSBleHRyYWN0IHRoZSBmaWxlcyBmcm9tIHRoZXNlIGRpcmVjdG9yaWVzIG9uZS1ieS1vbmUgYW5kIGFkZCBpdCB0byBkcm9wcGVkRmlsZXNMaXN0XHJcbiAgICAgICAgaWYgKGRyb3BwZWREaXJlY3Rvcmllcy5sZW5ndGgpIHtcclxuICAgICAgICAgIGNvbnN0IGV4dHJhY3RGaWxlc0Zyb21EaXJlY3RvcnlDYWxscyA9IFtdO1xyXG5cclxuICAgICAgICAgIGZvciAoY29uc3QgZHJvcHBlZERpcmVjdG9yeSBvZiBkcm9wcGVkRGlyZWN0b3JpZXMpIHtcclxuICAgICAgICAgICAgZXh0cmFjdEZpbGVzRnJvbURpcmVjdG9yeUNhbGxzLnB1c2godGhpcy5leHRyYWN0RmlsZXNGcm9tRGlyZWN0b3J5KGRyb3BwZWREaXJlY3RvcnkpKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAvLyB3YWl0IGZvciBhbGwgZGlyZWN0b3JpZXMgdG8gYmUgcHJvY2Nlc3NlZCB0byBhZGQgdGhlIGV4dHJhY3RlZCBmaWxlcyBhZnRlcndhcmRzXHJcbiAgICAgICAgICBQcm9taXNlLmFsbChleHRyYWN0RmlsZXNGcm9tRGlyZWN0b3J5Q2FsbHMpLnRoZW4oKGFsbEV4dHJhY3RlZEZpbGVzOiBhbnlbXSkgPT4ge1xyXG4gICAgICAgICAgICBhbGxFeHRyYWN0ZWRGaWxlcy5yZWR1Y2UoKGEsIGIpID0+IFsuLi5hLCAuLi5iXSkuZm9yRWFjaCgoZXh0cmFjdGVkRmlsZTogRmlsZSkgPT4ge1xyXG4gICAgICAgICAgICAgIGRyb3BwZWRGaWxlc0xpc3QuaXRlbXMuYWRkKGV4dHJhY3RlZEZpbGUpO1xyXG4gICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgICAgIHRoaXMuaGFuZGxlRmlsZURyb3AoZHJvcHBlZEZpbGVzTGlzdC5maWxlcyk7XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgZXh0cmFjdEZpbGVzRnJvbURpcmVjdG9yeShkaXJlY3RvcnkpIHtcclxuICAgIGFzeW5jIGZ1bmN0aW9uIGdldEZpbGVGcm9tRmlsZUVudHJ5KGZpbGVFbnRyeSkge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIHJldHVybiBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiBmaWxlRW50cnkuZmlsZShyZXNvbHZlLCByZWplY3QpKTtcclxuICAgICAgfSBjYXRjaCAoZXJyKSB7XHJcbiAgICAgICAgY29uc29sZS5sb2coJ0Vycm9yIGNvbnZlcnRpbmcgYSBmaWxlRW50cnkgdG8gYSBGaWxlOiAnLCBlcnIpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgICAgY29uc3QgZmlsZXM6IEZpbGVbXSA9IFtdO1xyXG5cclxuICAgICAgY29uc3QgZGlyUmVhZGVyID0gZGlyZWN0b3J5LmNyZWF0ZVJlYWRlcigpO1xyXG5cclxuICAgICAgLy8gd2UgbmVlZCB0aGlzIHRvIGJlIGEgcmVjdXJzaW9uIGJlY2F1c2Ugb2YgdGhpcyBpc3N1ZTogaHR0cHM6Ly9idWdzLmNocm9taXVtLm9yZy9wL2Nocm9taXVtL2lzc3Vlcy9kZXRhaWw/aWQ9NTE0MDg3XHJcbiAgICAgIGNvbnN0IHJlYWRFbnRyaWVzID0gKCkgPT4ge1xyXG4gICAgICAgIGRpclJlYWRlci5yZWFkRW50cmllcyhhc3luYyhkaXJJdGVtcykgPT4ge1xyXG4gICAgICAgICAgaWYgKCFkaXJJdGVtcy5sZW5ndGgpIHtcclxuICAgICAgICAgICAgcmVzb2x2ZShmaWxlcyk7XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBjb25zdCBmaWxlRW50cmllcyA9IGRpckl0ZW1zLmZpbHRlcigoZGlySXRlbSkgPT4gZGlySXRlbS5pc0ZpbGUpO1xyXG5cclxuICAgICAgICAgICAgZm9yIChjb25zdCBmaWxlRW50cnkgb2YgZmlsZUVudHJpZXMpIHtcclxuICAgICAgICAgICAgICBjb25zdCBmaWxlOiBhbnkgPSBhd2FpdCBnZXRGaWxlRnJvbUZpbGVFbnRyeShmaWxlRW50cnkpO1xyXG4gICAgICAgICAgICAgIGZpbGVzLnB1c2goZmlsZSk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIHJlYWRFbnRyaWVzKCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH07XHJcbiAgICAgIHJlYWRFbnRyaWVzKCk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHNob3dGaWxlU2VsZWN0b3IoKSB7XHJcbiAgICBpZiAoIXRoaXMuZGlzYWJsZWQpIHtcclxuICAgICAgKHRoaXMuX2ZpbGVJbnB1dC5uYXRpdmVFbGVtZW50IGFzIEhUTUxJbnB1dEVsZW1lbnQpLmNsaWNrKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBfb25GaWxlc1NlbGVjdGVkKGV2ZW50KSB7XHJcbiAgICBjb25zdCBmaWxlczogRmlsZUxpc3QgPSBldmVudC50YXJnZXQuZmlsZXM7XHJcbiAgICB0aGlzLmhhbmRsZUZpbGVEcm9wKGZpbGVzKTtcclxuXHJcbiAgICAvLyBSZXNldCB0aGUgbmF0aXZlIGZpbGUgaW5wdXQgZWxlbWVudCB0byBhbGxvdyBzZWxlY3RpbmcgdGhlIHNhbWUgZmlsZSBhZ2FpblxyXG4gICAgdGhpcy5fZmlsZUlucHV0Lm5hdGl2ZUVsZW1lbnQudmFsdWUgPSAnJztcclxuXHJcbiAgICAvLyBmaXgoIzMyKTogUHJldmVudCB0aGUgZGVmYXVsdCBldmVudCBiZWhhdmlvdXIgd2hpY2ggY2F1c2VkIHRoZSBjaGFuZ2UgZXZlbnQgdG8gZW1pdCB0d2ljZS5cclxuICAgIHRoaXMucHJldmVudERlZmF1bHQoZXZlbnQpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBoYW5kbGVGaWxlRHJvcChmaWxlczogRmlsZUxpc3QpIHtcclxuICAgIGNvbnN0IHJlc3VsdCA9IHRoaXMuc2VydmljZS5wYXJzZUZpbGVMaXN0KGZpbGVzLCB0aGlzLmFjY2VwdCwgdGhpcy5tYXhGaWxlU2l6ZSwgdGhpcy5tdWx0aXBsZSk7XHJcblxyXG4gICAgdGhpcy5jaGFuZ2UubmV4dCh7XHJcbiAgICAgIGFkZGVkRmlsZXM6IHJlc3VsdC5hZGRlZEZpbGVzLFxyXG4gICAgICByZWplY3RlZEZpbGVzOiByZXN1bHQucmVqZWN0ZWRGaWxlcyxcclxuICAgICAgc291cmNlOiB0aGlzXHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgcHJldmVudERlZmF1bHQoZXZlbnQ6IERyYWdFdmVudCkge1xyXG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcclxuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gIH1cclxufVxyXG4iLCI8aW5wdXQgI2ZpbGVJbnB1dCB0eXBlPVwiZmlsZVwiIFtpZF09XCJpZFwiIFttdWx0aXBsZV09XCJtdWx0aXBsZVwiIFthY2NlcHRdPVwiYWNjZXB0XCIgW2Rpc2FibGVkXT1cImRpc2FibGVkXCJcclxuICAoY2hhbmdlKT1cIl9vbkZpbGVzU2VsZWN0ZWQoJGV2ZW50KVwiIFthdHRyLmFyaWEtbGFiZWxdPVwiYXJpYUxhYmVsXCIgW2F0dHIuYXJpYS1sYWJlbGxlZGJ5XT1cImFyaWFMYWJlbGxlZGJ5XCJcclxuICBbYXR0ci5hcmlhLWRlc2NyaWJlZGJ5XT1cImFyaWFEZXNjcmliZWRCeVwiPlxyXG48bmctY29udGVudCBzZWxlY3Q9XCJuZ3gtZHJvcHpvbmUtbGFiZWxcIiAqbmdJZj1cIiFfaGFzUHJldmlld3NcIj48L25nLWNvbnRlbnQ+XHJcbjxuZy1jb250ZW50IHNlbGVjdD1cIm5neC1kcm9wem9uZS1wcmV2aWV3XCI+PC9uZy1jb250ZW50PlxyXG48bmctY29udGVudD48L25nLWNvbnRlbnQ+XHJcbiJdfQ==