UNPKG

carbon-components-angular

Version:
387 lines (385 loc) 33.3 kB
import { Component, Input, Output, ViewChild, EventEmitter, TemplateRef } from "@angular/core"; import { NG_VALUE_ACCESSOR } from "@angular/forms"; import * as i0 from "@angular/core"; import * as i1 from "carbon-components-angular/i18n"; import * as i2 from "@angular/common"; import * as i3 from "carbon-components-angular/button"; import * as i4 from "./file.component"; const noop = () => { }; /** * Get started with importing the module: * * ```typescript * import { FileUploaderModule } from 'carbon-components-angular'; * ``` * * [See demo](../../?path=/story/components-file-uploader--basic) */ export class FileUploader { constructor(i18n) { this.i18n = i18n; /** * Accessible text for the button that opens the upload window. * * Defaults to the `FILE_UPLOADER.OPEN` value from the i18n service */ this.buttonText = this.i18n.get().FILE_UPLOADER.OPEN; /** * Type set for button */ this.buttonType = "primary"; /** * Specify the types of files that the input should be able to receive */ this.accept = []; /** * Set to `false` to tell the component to only accept a single file on upload. * * Defaults to `true`. Accepts multiple files. */ this.multiple = true; /** * Set to `true` for a loading file uploader. */ this.skeleton = false; /** * Sets the size of the file items */ this.fileItemSize = "lg"; /** * Set to `true` to enable drag and drop. */ this.drop = false; /** * Provides a unique id for the underlying `<input>` node */ this.fileUploaderId = `file-uploader-${FileUploader.fileUploaderCount}`; /** * The list of files that have been submitted to be uploaded */ this.files = new Set(); /** * Set to `true` to disable upload button */ this.disabled = false; this.filesChange = new EventEmitter(); /** * Controls the state of the drag and drop file container */ this.dragOver = false; this.onTouchedCallback = noop; this.onChangeCallback = noop; FileUploader.fileUploaderCount++; } /** * Specifies the property to be used as the return value to `ngModel` and reactive forms. * Updates `this.files`. */ get value() { return this.files; } set value(v) { if (v !== this.files) { this.files = v; this.onChangeCallback(v); } } onBlur() { this.onTouchedCallback(); } get fileList() { return Array.from(this.fileInput.nativeElement.files); } /** * Propagates the injected `value`. */ writeValue(value) { if (value !== this.value) { this.files = value; } } createFileItem(file) { return { uploaded: false, state: "edit", invalid: false, invalidText: "", file: file }; } onFilesAdded() { const newFiles = new Set(this.files); if (!this.multiple) { newFiles.clear(); } for (let file of this.fileList) { const fileItem = this.createFileItem(file); newFiles.add(fileItem); } this.value = newFiles; this.filesChange.emit(newFiles); } onDragOver(event) { event.stopPropagation(); event.preventDefault(); if (this.disabled) { return; } this.dragOver = true; } onDragLeave(event) { event.stopPropagation(); event.preventDefault(); this.dragOver = false; } onDrop(event) { event.stopPropagation(); event.preventDefault(); if (this.disabled) { return; } const transferredFiles = Array.from(event.dataTransfer.files); const newFiles = new Set(this.files); transferredFiles.filter(({ name, type }) => { // Get the file extension and add a "." to the beginning. const fileExtension = name.split(".").pop().replace(/^/, "."); // Check if the accept array contains the mime type or extension of the file. return this.accept.includes(type) || this.accept.includes(fileExtension) || !this.accept.length; }).forEach(file => { if (!newFiles.size || this.multiple) { const fileItem = this.createFileItem(file); newFiles.add(fileItem); } }); this.value = newFiles; this.filesChange.emit(newFiles); this.dragOver = false; } removeFile(fileItem) { // Deleting an item from this.files removes the <ibm-file> component, // which triggers its ngOnDestroy(), which fires the (remove) event again. // So, (remove) may double-fire and we need to handle it here. if (this.files && this.files.has(fileItem)) { const newFiles = new Set(this.files); newFiles.delete(fileItem); this.filesChange.emit(newFiles); this.value = newFiles; } this.fileInput.nativeElement.value = ""; } isTemplate(value) { return value instanceof TemplateRef; } /** * Registers the injected function to control the touch use of the `FileUploader`. */ registerOnTouched(fn) { this.onTouchedCallback = fn; } /** * Sets a method in order to propagate changes back to the form. */ registerOnChange(fn) { this.onChangeCallback = fn; } /** * `ControlValueAccessor` method to programmatically disable the checkbox. * * ex: `this.formGroup.get("myFileUploader").disable();` * * @param isDisabled `true` to disable the file uploader */ setDisabledState(isDisabled) { this.disabled = isDisabled; } } /** * Counter used to create unique ids for file-uploader components */ FileUploader.fileUploaderCount = 0; FileUploader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FileUploader, deps: [{ token: i1.I18n }], target: i0.ɵɵFactoryTarget.Component }); FileUploader.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: FileUploader, selector: "cds-file-uploader, ibm-file-uploader", inputs: { buttonText: "buttonText", buttonType: "buttonType", title: "title", description: "description", accept: "accept", multiple: "multiple", skeleton: "skeleton", size: "size", fileItemSize: "fileItemSize", drop: "drop", dropText: "dropText", fileUploaderId: "fileUploaderId", files: "files", disabled: "disabled", fileNameTpl: "fileNameTpl", fileActionsTpl: "fileActionsTpl" }, outputs: { filesChange: "filesChange" }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: FileUploader, multi: true } ], viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: ` <ng-container *ngIf="!skeleton; else skeletonTemplate"> <label [for]="fileUploaderId" class="cds--file--label">{{title}}</label> <p class="cds--label-description" role="alert">{{description}}</p> <div class="cds--file"> <label *ngIf="drop" class="cds--file-browse-btn" (keyup.enter)="fileInput.click()" (keyup.space)="fileInput.click()" [ngClass]="{'cds--file-browse-btn--disabled': disabled}" tabindex="0"> <div class="cds--file__drop-container" [ngClass]="{'cds--file__drop-container--drag-over': dragOver}" role="button" (click)="fileInput.click()" [attr.for]="fileUploaderId" (dragover)="onDragOver($event)" (dragleave)="onDragLeave($event)" (drop)="onDrop($event)"> <ng-container *ngIf="!isTemplate(dropText)">{{dropText}}</ng-container> <ng-template *ngIf="isTemplate(dropText)" [ngTemplateOutlet]="dropText"></ng-template> </div> </label> <button *ngIf="!drop" type="button" [cdsButton]="buttonType" (click)="fileInput.click()" [attr.for]="fileUploaderId" [size]="size" [disabled]="disabled"> {{buttonText}} </button> <input #fileInput type="file" class="cds--file-input" [accept]="accept" [id]="fileUploaderId" [multiple]="multiple" tabindex="-1" (change)="onFilesAdded()" [disabled]="disabled"/> <div class="cds--file-container"> <ng-container *ngFor="let fileItem of files"> <cds-file [fileItem]="fileItem" [nameTpl]="fileNameTpl" [actionsTpl]="fileActionsTpl" [size]="fileItemSize" (remove)="removeFile(fileItem)"> </cds-file> </ng-container> </div> </div> </ng-container> <ng-template #skeletonTemplate> <div class="cds--skeleton__text" style="width: 100px"></div> <div class="cds--skeleton__text" style="width: 225px"></div> <button cdsButton skeleton="true"></button> </ng-template> `, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.Button, selector: "[cdsButton], [ibmButton]", inputs: ["ibmButton", "cdsButton", "size", "skeleton", "iconOnly", "isExpressive"] }, { kind: "component", type: i4.FileComponent, selector: "cds-file, ibm-file", inputs: ["translations", "fileItem", "size", "nameTpl", "actionsTpl"], outputs: ["remove"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FileUploader, decorators: [{ type: Component, args: [{ selector: "cds-file-uploader, ibm-file-uploader", template: ` <ng-container *ngIf="!skeleton; else skeletonTemplate"> <label [for]="fileUploaderId" class="cds--file--label">{{title}}</label> <p class="cds--label-description" role="alert">{{description}}</p> <div class="cds--file"> <label *ngIf="drop" class="cds--file-browse-btn" (keyup.enter)="fileInput.click()" (keyup.space)="fileInput.click()" [ngClass]="{'cds--file-browse-btn--disabled': disabled}" tabindex="0"> <div class="cds--file__drop-container" [ngClass]="{'cds--file__drop-container--drag-over': dragOver}" role="button" (click)="fileInput.click()" [attr.for]="fileUploaderId" (dragover)="onDragOver($event)" (dragleave)="onDragLeave($event)" (drop)="onDrop($event)"> <ng-container *ngIf="!isTemplate(dropText)">{{dropText}}</ng-container> <ng-template *ngIf="isTemplate(dropText)" [ngTemplateOutlet]="dropText"></ng-template> </div> </label> <button *ngIf="!drop" type="button" [cdsButton]="buttonType" (click)="fileInput.click()" [attr.for]="fileUploaderId" [size]="size" [disabled]="disabled"> {{buttonText}} </button> <input #fileInput type="file" class="cds--file-input" [accept]="accept" [id]="fileUploaderId" [multiple]="multiple" tabindex="-1" (change)="onFilesAdded()" [disabled]="disabled"/> <div class="cds--file-container"> <ng-container *ngFor="let fileItem of files"> <cds-file [fileItem]="fileItem" [nameTpl]="fileNameTpl" [actionsTpl]="fileActionsTpl" [size]="fileItemSize" (remove)="removeFile(fileItem)"> </cds-file> </ng-container> </div> </div> </ng-container> <ng-template #skeletonTemplate> <div class="cds--skeleton__text" style="width: 100px"></div> <div class="cds--skeleton__text" style="width: 225px"></div> <button cdsButton skeleton="true"></button> </ng-template> `, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: FileUploader, multi: true } ] }] }], ctorParameters: function () { return [{ type: i1.I18n }]; }, propDecorators: { buttonText: [{ type: Input }], buttonType: [{ type: Input }], title: [{ type: Input }], description: [{ type: Input }], accept: [{ type: Input }], multiple: [{ type: Input }], skeleton: [{ type: Input }], size: [{ type: Input }], fileItemSize: [{ type: Input }], drop: [{ type: Input }], dropText: [{ type: Input }], fileUploaderId: [{ type: Input }], fileInput: [{ type: ViewChild, args: ["fileInput"] }], files: [{ type: Input }], disabled: [{ type: Input }], fileNameTpl: [{ type: Input }], fileActionsTpl: [{ type: Input }], filesChange: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZS11cGxvYWRlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZmlsZS11cGxvYWRlci9maWxlLXVwbG9hZGVyLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ04sU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBQ04sU0FBUyxFQUNULFlBQVksRUFDWixXQUFXLEVBQ1gsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUF3QixpQkFBaUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7Ozs7QUFLekUsTUFBTSxJQUFJLEdBQUcsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBRXZCOzs7Ozs7OztHQVFHO0FBNEVILE1BQU0sT0FBTyxZQUFZO0lBZ0d4QixZQUFzQixJQUFVO1FBQVYsU0FBSSxHQUFKLElBQUksQ0FBTTtRQTNGaEM7Ozs7V0FJRztRQUNNLGVBQVUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUM7UUFDekQ7O1dBRUc7UUFDTSxlQUFVLEdBUUUsU0FBUyxDQUFDO1FBUy9COztXQUVHO1FBQ00sV0FBTSxHQUFHLEVBQUUsQ0FBQztRQUNyQjs7OztXQUlHO1FBQ00sYUFBUSxHQUFHLElBQUksQ0FBQztRQUN6Qjs7V0FFRztRQUNNLGFBQVEsR0FBRyxLQUFLLENBQUM7UUFLMUI7O1dBRUc7UUFDTSxpQkFBWSxHQUF1QixJQUFJLENBQUM7UUFDakQ7O1dBRUc7UUFDTSxTQUFJLEdBQUcsS0FBSyxDQUFDO1FBS3RCOztXQUVHO1FBQ00sbUJBQWMsR0FBRyxpQkFBaUIsWUFBWSxDQUFDLGlCQUFpQixFQUFFLENBQUM7UUFLNUU7O1dBRUc7UUFDTSxVQUFLLEdBQUcsSUFBSSxHQUFHLEVBQVksQ0FBQztRQUNyQzs7V0FFRztRQUNNLGFBQVEsR0FBRyxLQUFLLENBQUM7UUFVaEIsZ0JBQVcsR0FBRyxJ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OzRCQUN6QixLQUFLLEVBQUUsSUFBSTt5QkFDWDtxQkFDRDtpQkFDRDsyRkFXUyxVQUFVO3NCQUFsQixLQUFLO2dCQUlHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBWUcsS0FBSztzQkFBYixLQUFLO2dCQUlHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBSUcsTUFBTTtzQkFBZCxLQUFLO2dCQU1HLFFBQVE7c0JBQWhCLEtBQUs7Z0JBSUcsUUFBUTtzQkFBaEIsS0FBSztnQkFJRyxJQUFJO3NCQUFaLEtBQUs7Z0JBSUcsWUFBWTtzQkFBcEIsS0FBSztnQkFJRyxJQUFJO3NCQUFaLEtBQUs7Z0JBSUcsUUFBUTtzQkFBaEIsS0FBSztnQkFJRyxjQUFjO3NCQUF0QixLQUFLO2dCQUlrQixTQUFTO3NCQUFoQyxTQUFTO3VCQUFDLFdBQVc7Z0JBSWIsS0FBSztzQkFBYixLQUFLO2dCQUlHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBSUcsV0FBVztzQkFBbkIsS0FBSztnQkFJRyxjQUFjO3NCQUF0QixLQUFLO2dCQUVJLFdBQVc7c0JBQXBCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuXHRDb21wb25lbnQsXG5cdElucHV0LFxuXHRPdXRwdXQsXG5cdFZpZXdDaGlsZCxcblx0RXZlbnRFbWl0dGVyLFxuXHRUZW1wbGF0ZVJlZlxufSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0IHsgQ29udHJvbFZhbHVlQWNjZXNzb3IsIE5HX1ZBTFVFX0FDQ0VTU09SIH0gZnJvbSBcIkBhbmd1bGFyL2Zvcm1zXCI7XG5cbmltcG9ydCB7IEkxOG4gfSBmcm9tIFwiY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhci9pMThuXCI7XG5pbXBvcnQgeyBGaWxlSXRlbSB9IGZyb20gXCIuL2ZpbGUtaXRlbS5pbnRlcmZhY2VcIjtcblxuY29uc3Qgbm9vcCA9ICgpID0+IHsgfTtcblxuLyoqXG4gKiBHZXQgc3RhcnRlZCB3aXRoIGltcG9ydGluZyB0aGUgbW9kdWxlOlxuICpcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IEZpbGVVcGxvYWRlck1vZHVsZSB9IGZyb20gJ2NhcmJvbi1jb21wb25lbnRzLWFuZ3VsYXInO1xuICogYGBgXG4gKlxuICogW1NlZSBkZW1vXSguLi8uLi8/cGF0aD0vc3RvcnkvY29tcG9uZW50cy1maWxlLXVwbG9hZGVyLS1iYXNpYylcbiAqL1xuQENvbXBvbmVudCh7XG5cdHNlbGVjdG9yOiBcImNkcy1maWxlLXVwbG9hZGVyLCBpYm0tZmlsZS11cGxvYWRlclwiLFxuXHR0ZW1wbGF0ZTogYFxuXHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCIhc2tlbGV0b247IGVsc2Ugc2tlbGV0b25UZW1wbGF0ZVwiPlxuXHRcdFx0PGxhYmVsIFtmb3JdPVwiZmlsZVVwbG9hZGVySWRcIiBjbGFzcz1cImNkcy0tZmlsZS0tbGFiZWxcIj57e3RpdGxlfX08L2xhYmVsPlxuXHRcdFx0PHAgY2xhc3M9XCJjZHMtLWxhYmVsLWRlc2NyaXB0aW9uXCIgcm9sZT1cImFsZXJ0XCI+e3tkZXNjcmlwdGlvbn19PC9wPlxuXHRcdFx0PGRpdiBjbGFzcz1cImNkcy0tZmlsZVwiPlxuXHRcdFx0XHQ8bGFiZWxcblx0XHRcdFx0XHQqbmdJZj1cImRyb3BcIlxuXHRcdFx0XHRcdGNsYXNzPVwiY2RzLS1maWxlLWJyb3dzZS1idG5cIlxuXHRcdFx0XHRcdChrZXl1cC5lbnRlcik9XCJmaWxlSW5wdXQuY2xpY2soKVwiXG5cdFx0XHRcdFx0KGtleXVwLnNwYWNlKT1cImZpbGVJbnB1dC5jbGljaygpXCJcblx0XHRcdFx0XHRbbmdDbGFzc109XCJ7J2Nkcy0tZmlsZS1icm93c2UtYnRuLS1kaXNhYmxlZCc6IGRpc2FibGVkfVwiXG5cdFx0XHRcdFx0dGFiaW5kZXg9XCIwXCI+XG5cdFx0XHRcdFx0PGRpdlxuXHRcdFx0XHRcdFx0Y2xhc3M9XCJjZHMtLWZpbGVfX2Ryb3AtY29udGFpbmVyXCJcblx0XHRcdFx0XHRcdFtuZ0NsYXNzXT1cInsnY2RzLS1maWxlX19kcm9wLWNvbnRhaW5lci0tZHJhZy1vdmVyJzogZHJhZ092ZXJ9XCJcblx0XHRcdFx0XHRcdHJvbGU9XCJidXR0b25cIlxuXHRcdFx0XHRcdFx0KGNsaWNrKT1cImZpbGVJbnB1dC5jbGljaygpXCJcblx0XHRcdFx0XHRcdFthdHRyLmZvcl09XCJmaWxlVXBsb2FkZXJJZFwiXG5cdFx0XHRcdFx0XHQoZHJhZ292ZXIpPVwib25EcmFnT3ZlcigkZXZlbnQpXCJcblx0XHRcdFx0XHRcdChkcmFnbGVhdmUpPVwib25EcmFnTGVhdmUoJGV2ZW50KVwiXG5cdFx0XHRcdFx0XHQoZHJvcCk9XCJvbkRyb3AoJGV2ZW50KVwiPlxuXHRcdFx0XHRcdFx0PG5nLWNvbnRhaW5lciAqbmdJZj1cIiFpc1RlbXBsYXRlKGRyb3BUZXh0KVwiPnt7ZHJvcFRleHR9fTwvbmctY29udGFpbmVyPlxuXHRcdFx0XHRcdFx0PG5nLXRlbXBsYXRlICpuZ0lmPVwiaXNUZW1wbGF0ZShkcm9wVGV4dClcIiBbbmdUZW1wbGF0ZU91dGxldF09XCJkcm9wVGV4dFwiPjwvbmctdGVtcGxhdGU+XG5cdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdDwvbGFiZWw+XG5cdFx0XHRcdDxidXR0b25cblx0XHRcdFx0XHQqbmdJZj1cIiFkcm9wXCJcblx0XHRcdFx0XHR0eXBlPVwiYnV0dG9uXCJcblx0XHRcdFx0XHRbY2RzQnV0dG9uXT1cImJ1dHRvblR5cGVcIlxuXHRcdFx0XHRcdChjbGljayk9XCJmaWxlSW5wdXQuY2xpY2soKVwiXG5cdFx0XHRcdFx0W2F0dHIuZm9yXT1cImZpbGVVcGxvYWRlcklkXCJcblx0XHRcdFx0XHRbc2l6ZV09XCJzaXplXCJcblx0XHRcdFx0XHRbZGlzYWJsZWRdPVwiZGlzYWJsZWRcIj5cblx0XHRcdFx0XHR7e2J1dHRvblRleHR9fVxuXHRcdFx0XHQ8L2J1dHRvbj5cblx0XHRcdFx0PGlucHV0XG5cdFx0XHRcdFx0I2ZpbGVJbnB1dFxuXHRcdFx0XHRcdHR5cGU9XCJmaWxlXCJcblx0XHRcdFx0XHRjbGFzcz1cImNkcy0tZmlsZS1pbnB1dFwiXG5cdFx0XHRcdFx0W2FjY2VwdF09XCJhY2NlcHRcIlxuXHRcdFx0XHRcdFtpZF09XCJmaWxlVXBsb2FkZXJJZFwiXG5cdFx0XHRcdFx0W211bHRpcGxlXT1cIm11bHRpcGxlXCJcblx0XHRcdFx0XHR0YWJpbmRleD1cIi0xXCJcblx0XHRcdFx0XHQoY2hhbmdlKT1cIm9uRmlsZXNBZGRlZCgpXCJcblx0XHRcdFx0XHRbZGlzYWJsZWRdPVwiZGlzYWJsZWRcIi8+XG5cdFx0XHRcdDxkaXYgY2xhc3M9XCJjZHMtLWZpbGUtY29udGFpbmVyXCI+XG5cdFx0XHRcdFx0PG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgZmlsZUl0ZW0gb2YgZmlsZXNcIj5cblx0XHRcdFx0XHRcdDxjZHMtZmlsZVxuXHRcdFx0XHRcdFx0XHRbZmlsZUl0ZW1dPVwiZmlsZUl0ZW1cIlxuXHRcdFx0XHRcdFx0XHRbbmFtZVRwbF09XCJmaWxlTmFtZVRwbFwiXG5cdFx0XHRcdFx0XHRcdFthY3Rpb25zVHBsXT1cImZpbGVBY3Rpb25zVHBsXCJcblx0XHRcdFx0XHRcdFx0W3NpemVdPVwiZmlsZUl0ZW1TaXplXCJcblx0XHRcdFx0XHRcdFx0KHJlbW92ZSk9XCJyZW1vdmVGaWxlKGZpbGVJdGVtKVwiPlxuXHRcdFx0XHRcdFx0PC9jZHMtZmlsZT5cblx0XHRcdFx0XHQ8L25nLWNvbnRhaW5lcj5cblx0XHRcdFx0PC9kaXY+XG5cdFx0XHQ8L2Rpdj5cblx0XHQ8L25nLWNvbnRhaW5lcj5cblxuXHRcdDxuZy10ZW1wbGF0ZSAjc2tlbGV0b25UZW1wbGF0ZT5cblx0XHRcdDxkaXYgY2xhc3M9XCJjZHMtLXNrZWxldG9uX190ZXh0XCIgc3R5bGU9XCJ3aWR0aDogMTAwcHhcIj48L2Rpdj5cblx0XHRcdDxkaXYgY2xhc3M9XCJjZHMtLXNrZWxldG9uX190ZXh0XCIgc3R5bGU9XCJ3aWR0aDogMjI1cHhcIj48L2Rpdj5cblx0XHRcdDxidXR0b24gY2RzQnV0dG9uIHNrZWxldG9uPVwidHJ1ZVwiPjwvYnV0dG9uPlxuXHRcdDwvbmctdGVtcGxhdGU+XG5cdGAsXG5cdHByb3ZpZGVyczogW1xuXHRcdHtcblx0XHRcdHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuXHRcdFx0dXNlRXhpc3Rpbmc6IEZpbGVVcGxvYWRlcixcblx0XHRcdG11bHRpOiB0cnVlXG5cdFx0fVxuXHRdXG59KVxuZXhwb3J0IGNsYXNzIEZpbGVVcGxvYWRlciBpbXBsZW1lbnRzIENvbnRyb2xWYWx1ZUFjY2Vzc29yIHtcblx0LyoqXG5cdCAqIENvdW50ZXIgdXNlZCB0byBjcmVhdGUgdW5pcXVlIGlkcyBmb3IgZmlsZS11cGxvYWRlciBjb21wb25lbnRzXG5cdCAqL1xuXHRzdGF0aWMgZmlsZVVwbG9hZGVyQ291bnQgPSAwO1xuXHQvKipcblx0ICogQWNjZXNzaWJsZSB0ZXh0IGZvciB0aGUgYnV0dG9uIHRoYXQgb3BlbnMgdGhlIHVwbG9hZCB3aW5kb3cuXG5cdCAqXG5cdCAqIERlZmF1bHRzIHRvIHRoZSBgRklMRV9VUExPQURFUi5PUEVOYCB2YWx1ZSBmcm9tIHRoZSBpMThuIHNlcnZpY2Vcblx0ICovXG5cdEBJbnB1dCgpIGJ1dHRvblRleHQgPSB0aGlzLmkxOG4uZ2V0KCkuRklMRV9VUExPQURFUi5PUEVOO1xuXHQvKipcblx0ICogVHlwZSBzZXQgZm9yIGJ1dHRvblxuXHQgKi9cblx0QElucHV0KCkgYnV0dG9uVHlwZTpcblx0XHR8IFwicHJpbWFyeVwiXG5cdFx0fCBcInNlY29uZGFyeVwiXG5cdFx0fCBcInRlcnRpYXJ5XCJcblx0XHR8IFwiZ2hvc3RcIlxuXHRcdHwgXCJkYW5nZXJcIlxuXHRcdHwgXCJkYW5nZXItLXByaW1hcnlcIlxuXHRcdHwgXCJkYW5nZXItLXRlcnRpYXJ5XCJcblx0XHR8IFwiZGFuZ2VyLS1naG9zdFwiID0gXCJwcmltYXJ5XCI7XG5cdC8qKlxuXHQgKiBUZXh0IHNldCB0byB0aGUgdGl0bGVcblx0ICovXG5cdEBJbnB1dCgpIHRpdGxlOiBzdHJpbmc7XG5cdC8qKlxuXHQgKiBUZXh0IHNldCB0byB0aGUgZGVzY3JpcHRpb25cblx0ICovXG5cdEBJbnB1dCgpIGRlc2NyaXB0aW9uOiBzdHJpbmc7XG5cdC8qKlxuXHQgKiBTcGVjaWZ5IHRoZSB0eXBlcyBvZiBmaWxlcyB0aGF0IHRoZSBpbnB1dCBzaG91bGQgYmUgYWJsZSB0byByZWNlaXZlXG5cdCAqL1xuXHRASW5wdXQoKSBhY2NlcHQgPSBbXTtcblx0LyoqXG5cdCAqIFNldCB0byBgZmFsc2VgIHRvIHRlbGwgdGhlIGNvbXBvbmVudCB0byBvbmx5IGFjY2VwdCBhIHNpbmdsZSBmaWxlIG9uIHVwbG9hZC5cblx0ICpcblx0ICogRGVmYXVsdHMgdG8gYHRydWVgLiBBY2NlcHRzIG11bHRpcGxlIGZpbGVzLlxuXHQgKi9cblx0QElucHV0KCkgbXVsdGlwbGUgPSB0cnVlO1xuXHQvKipcblx0ICogU2V0IHRvIGB0cnVlYCBmb3IgYSBsb2FkaW5nIGZpbGUgdXBsb2FkZXIuXG5cdCAqL1xuXHRASW5wdXQoKSBza2VsZXRvbiA9IGZhbHNlO1xuXHQvKipcblx0ICogU2V0cyB0aGUgc2l6ZSBvZiB0aGUgYnV0dG9uLlxuXHQgKi9cblx0QElucHV0KCkgc2l6ZTogXCJzbVwiIHwgXCJtZFwiIHwgXCJsZ1wiO1xuXHQvKipcblx0ICogU2V0cyB0aGUgc2l6ZSBvZiB0aGUgZmlsZSBpdGVtc1xuXHQgKi9cblx0QElucHV0KCkgZmlsZUl0ZW1TaXplOiBcInNtXCIgfCBcIm1kXCIgfCBcImxnXCIgPSBcImxnXCI7XG5cdC8qKlxuXHQgKiBTZXQgdG8gYHRydWVgIHRvIGVuYWJsZSBkcmFnIGFuZCBkcm9wLlxuXHQgKi9cblx0QElucHV0KCkgZHJvcCA9IGZhbHNlO1xuXHQvKipcblx0ICogU2V0cyB0aGUgdGV4dCBzaG93biBpbiBkcmFnIGFuZCBkcm9wIGJveC5cblx0ICovXG5cdEBJbnB1dCgpIGRyb3BUZXh0OiBzdHJpbmcgfCBUZW1wbGF0ZVJlZjxhbnk+O1xuXHQvKipcblx0ICogUHJvdmlkZXMgYSB1bmlxdWUgaWQgZm9yIHRoZSB1bmRlcmx5aW5nIGA8aW5wdXQ+YCBub2RlXG5cdCAqL1xuXHRASW5wdXQoKSBmaWxlVXBsb2FkZXJJZCA9IGBmaWxlLXVwbG9hZGVyLSR7RmlsZVVwbG9hZGVyLmZpbGVVcGxvYWRlckNvdW50fWA7XG5cdC8qKlxuXHQgKiBNYWludGFpbnMgYSByZWZlcmVuY2UgdG8gdGhlIHZpZXcgRE9NIGVsZW1lbnQgb2YgdGhlIHVuZGVybHlpbmcgPGlucHV0PiBub2RlXG5cdCAqL1xuXHRAVmlld0NoaWxkKFwiZmlsZUlucHV0XCIpIGZpbGVJbnB1dDtcblx0LyoqXG5cdCAqIFRoZSBsaXN0IG9mIGZpbGVzIHRoYXQgaGF2ZSBiZWVuIHN1Ym1pdHRlZCB0byBiZSB1cGxvYWRlZFxuXHQgKi9cblx0QElucHV0KCkgZmlsZXMgPSBuZXcgU2V0PEZpbGVJdGVtPigpO1xuXHQvKipcblx0ICogU2V0IHRvIGB0cnVlYCB0byBkaXNhYmxlIHVwbG9hZCBidXR0b25cblx0ICovXG5cdEBJbnB1dCgpIGRpc2FibGVkID0gZmFsc2U7XG5cdC8qKlxuXHQgKiBDdXN0b20gdGVtcGxhdGUgdXNlZCB0byByZW5kZXIgdGhlIGZpbGUgbmFtZSBvZiB1cGxvYWRlZCBmaWxlc1xuXHQgKi9cblx0QElucHV0KCkgZmlsZU5hbWVUcGw6IFRlbXBsYXRlUmVmPHVua25vd24+O1xuXHQvKipcblx0ICogQ3VzdG9tIHRlbXBsYXRlIHVzZWQgdG8gcmVuZGVyIHRoZSBmaWxlIGFjdGlvbnMgb2YgdXBsb2FkZWQgZmlsZXNcblx0ICovXG5cdEBJbnB1dCgpIGZpbGVBY3Rpb25zVHBsOiBUZW1wbGF0ZVJlZjx1bmtub3duPjtcblxuXHRAT3V0cHV0KCkgZmlsZXNDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPGFueT4oKTtcblxuXHQvKipcblx0ICogQ29udHJvbHMgdGhlIHN0YXRlIG9mIHRoZSBkcmFnIGFuZCBkcm9wIGZpbGUgY29udGFpbmVyXG5cdCAqL1xuXHRwdWJsaWMgZHJhZ092ZXIgPSBmYWxzZTtcblxuXHRwcm90ZWN0ZWQgb25Ub3VjaGVkQ2FsbGJhY2s6ICgpID0+IHZvaWQgPSBub29wO1xuXHRwcm90ZWN0ZWQgb25DaGFuZ2VDYWxsYmFjazogKF86IFNldDxGaWxlSXRlbT4pID0+IHZvaWQgPSBub29wO1xuXG5cdGNvbnN0cnVjdG9yKHByb3RlY3RlZCBpMThuOiBJMThuKSB7XG5cdFx0RmlsZVVwbG9hZGVyLmZpbGVVcGxvYWRlckNvdW50Kys7XG5cdH1cblxuXHQvKipcblx0ICogU3BlY2lmaWVzIHRoZSBwcm9wZXJ0eSB0byBiZSB1c2VkIGFzIHRoZSByZXR1cm4gdmFsdWUgdG8gYG5nTW9kZWxgIGFuZCByZWFjdGl2ZSBmb3Jtcy5cblx0ICogVXBkYXRlcyBgdGhpcy5maWxlc2AuXG5cdCAqL1xuXHRnZXQgdmFsdWUoKTogU2V0PEZpbGVJdGVtPiB7XG5cdFx0cmV0dXJuIHRoaXMuZmlsZXM7XG5cdH1cblx0c2V0IHZhbHVlKHY6IFNldDxGaWxlSXRlbT4pIHtcblx0XHRpZiAodiAhPT0gdGhpcy5maWxlcykge1xuXHRcdFx0dGhpcy5maWxlcyA9IHY7XG5cdFx0XHR0aGlzLm9uQ2hhbmdlQ2FsbGJhY2sodik7XG5cdFx0fVxuXHR9XG5cblx0b25CbHVyKCkge1xuXHRcdHRoaXMub25Ub3VjaGVkQ2FsbGJhY2soKTtcblx0fVxuXG5cdGdldCBmaWxlTGlzdCgpIHtcblx0XHRyZXR1cm4gQXJyYXkuZnJvbSh0aGlzLmZpbGVJbnB1dC5uYXRpdmVFbGVtZW50LmZpbGVzKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBQcm9wYWdhdGVzIHRoZSBpbmplY3RlZCBgdmFsdWVgLlxuXHQgKi9cblx0d3JpdGVWYWx1ZSh2YWx1ZTogU2V0PEZpbGVJdGVtPikge1xuXHRcdGlmICh2YWx1ZSAhPT0gdGhpcy52YWx1ZSkge1xuXHRcdFx0dGhpcy5maWxlcyA9IHZhbHVlO1xuXHRcdH1cblx0fVxuXG5cdGNyZWF0ZUZpbGVJdGVtKGZpbGUpOiBGaWxlSXRlbSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdHVwbG9hZGVkOiBmYWxzZSxcblx0XHRcdHN0YXRlOiBcImVkaXRcIixcblx0XHRcdGludmFsaWQ6IGZhbHNlLFxuXHRcdFx0aW52YWxpZFRleHQ6IFwiXCIsXG5cdFx0XHRmaWxlOiBmaWxlXG5cdFx0fTtcblx0fVxuXG5cdG9uRmlsZXNBZGRlZCgpIHtcblx0XHRjb25zdCBuZXdGaWxlcyA9IG5ldyBTZXQ8RmlsZUl0ZW0+KHRoaXMuZmlsZXMpO1xuXHRcdGlmICghdGhpcy5tdWx0aXBsZSkge1xuXHRcdFx0bmV3RmlsZXMuY2xlYXIoKTtcblx0XHR9XG5cdFx0Zm9yIChsZXQgZmlsZSBvZiB0aGlzLmZpbGVMaXN0KSB7XG5cdFx0XHRjb25zdCBmaWxlSXRlbSA9IHRoaXMuY3JlYXRlRmlsZUl0ZW0oZmlsZSk7XG5cdFx0XHRuZXdGaWxlcy5hZGQoZmlsZUl0ZW0pO1xuXHRcdH1cblxuXHRcdHRoaXMudmFsdWUgPSBuZXdGaWxlcztcblx0XHR0aGlzLmZpbGVzQ2hhbmdlLmVtaXQobmV3RmlsZXMpO1xuXHR9XG5cblx0b25EcmFnT3ZlcihldmVudCkge1xuXHRcdGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0aWYgKHRoaXMuZGlzYWJsZWQpIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0dGhpcy5kcmFnT3ZlciA9IHRydWU7XG5cdH1cblxuXHRvbkRyYWdMZWF2ZShldmVudCkge1xuXHRcdGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0dGhpcy5kcmFnT3ZlciA9IGZhbHNlO1xuXHR9XG5cblx0b25Ecm9wKGV2ZW50KSB7XG5cdFx0ZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG5cdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRpZiAodGhpcy5kaXNhYmxlZCkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGNvbnN0IHRyYW5zZmVycmVkRmlsZXM6IEFycmF5PEZpbGU+ID0gQXJyYXkuZnJvbShldmVudC5kYXRhVHJhbnNmZXIuZmlsZXMpO1xuXHRcdGNvbnN0IG5ld0ZpbGVzID0gbmV3IFNldDxGaWxlSXRlbT4odGhpcy5maWxlcyk7XG5cblx0XHR0cmFuc2ZlcnJlZEZpbGVzLmZpbHRlcigoeyBuYW1lLCB0eXBlIH0pID0+IHtcblx0XHRcdC8vIEdldCB0aGUgZmlsZSBleHRlbnNpb24gYW5kIGFkZCBhIFwiLlwiIHRvIHRoZSBiZWdpbm5pbmcuXG5cdFx0XHRjb25zdCBmaWxlRXh0ZW5zaW9uID0gbmFtZS5zcGxpdChcIi5cIikucG9wKCkucmVwbGFjZSgvXi8sIFwiLlwiKTtcblx0XHRcdC8vIENoZWNrIGlmIHRoZSBhY2NlcHQgYXJyYXkgY29udGFpbnMgdGhlIG1pbWUgdHlwZSBvciBleHRlbnNpb24gb2YgdGhlIGZpbGUuXG5cdFx0XHRyZXR1cm4gdGhpcy5hY2NlcHQuaW5jbHVkZXModHlwZSkgfHwgdGhpcy5hY2NlcHQuaW5jbHVkZXMoZmlsZUV4dGVuc2lvbikgfHwgIXRoaXMuYWNjZXB0Lmxlbmd0aDtcblx0XHR9KS5mb3JFYWNoKGZpbGUgPT4ge1xuXHRcdFx0aWYgKCFuZXdGaWxlcy5zaXplIHx8IHRoaXMubXVsdGlwbGUpIHtcblx0XHRcdFx0Y29uc3QgZmlsZUl0ZW0gPSB0aGlzLmNyZWF0ZUZpbGVJdGVtKGZpbGUpO1xuXHRcdFx0XHRuZXdGaWxlcy5hZGQoZmlsZUl0ZW0pO1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0dGhpcy52YWx1ZSA9IG5ld0ZpbGVzO1xuXHRcdHRoaXMuZmlsZXNDaGFuZ2UuZW1pdChuZXdGaWxlcyk7XG5cdFx0dGhpcy5kcmFnT3ZlciA9IGZhbHNlO1xuXHR9XG5cblx0cmVtb3ZlRmlsZShmaWxlSXRlbSkge1xuXHRcdC8vIERlbGV0aW5nIGFuIGl0ZW0gZnJvbSB0aGlzLmZpbGVzIHJlbW92ZXMgdGhlIDxpYm0tZmlsZT4gY29tcG9uZW50LFxuXHRcdC8vIHdoaWNoIHRyaWdnZXJzIGl0cyBuZ09uRGVzdHJveSgpLCB3aGljaCBmaXJlcyB0aGUgKHJlbW92ZSkgZXZlbnQgYWdhaW4uXG5cdFx0Ly8gU28sIChyZW1vdmUpIG1heSBkb3VibGUtZmlyZSBhbmQgd2UgbmVlZCB0byBoYW5kbGUgaXQgaGVyZS5cblx0XHRpZiAodGhpcy5maWxlcyAmJiB0aGlzLmZpbGVzLmhhcyhmaWxlSXRlbSkpIHtcblx0XHRcdGNvbnN0IG5ld0ZpbGVzID0gbmV3IFNldDxGaWxlSXRlbT4odGhpcy5maWxlcyk7XG5cdFx0XHRuZXdGaWxlcy5kZWxldGUoZmlsZUl0ZW0pO1xuXHRcdFx0dGhpcy5maWxlc0NoYW5nZS5lbWl0KG5ld0ZpbGVzKTtcblx0XHRcdHRoaXMudmFsdWUgPSBuZXdGaWxlcztcblx0XHR9XG5cdFx0dGhpcy5maWxlSW5wdXQubmF0aXZlRWxlbWVudC52YWx1ZSA9IFwiXCI7XG5cdH1cblxuXHRwdWJsaWMgaXNUZW1wbGF0ZSh2YWx1ZSkge1xuXHRcdHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIFRlbXBsYXRlUmVmO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJlZ2lzdGVycyB0aGUgaW5qZWN0ZWQgZnVuY3Rpb24gdG8gY29udHJvbCB0aGUgdG91Y2ggdXNlIG9mIHRoZSBgRmlsZVVwbG9hZGVyYC5cblx0ICovXG5cdHJlZ2lzdGVyT25Ub3VjaGVkKGZuOiBhbnkpIHtcblx0XHR0aGlzLm9uVG91Y2hlZENhbGxiYWNrID0gZm47XG5cdH1cblx0LyoqXG5cdCAqIFNldHMgYSBtZXRob2QgaW4gb3JkZXIgdG8gcHJvcGFnYXRlIGNoYW5nZXMgYmFjayB0byB0aGUgZm9ybS5cblx0ICovXG5cdHJlZ2lzdGVyT25DaGFuZ2UoZm46IGFueSkge1xuXHRcdHRoaXMub25DaGFuZ2VDYWxsYmFjayA9IGZuO1xuXHR9XG5cblx0LyoqXG5cdCAqIGBDb250cm9sVmFsdWVBY2Nlc3NvcmAgbWV0aG9kIHRvIHByb2dyYW1tYXRpY2FsbHkgZGlzYWJsZSB0aGUgY2hlY2tib3guXG5cdCAqXG5cdCAqIGV4OiBgdGhpcy5mb3JtR3JvdXAuZ2V0KFwibXlGaWxlVXBsb2FkZXJcIikuZGlzYWJsZSgpO2Bcblx0ICpcblx0ICogQHBhcmFtIGlzRGlzYWJsZWQgYHRydWVgIHRvIGRpc2FibGUgdGhlIGZpbGUgdXBsb2FkZXJcblx0ICovXG5cdHNldERpc2FibGVkU3RhdGUoaXNEaXNhYmxlZDogYm9vbGVhbikge1xuXHRcdHRoaXMuZGlzYWJsZWQgPSBpc0Rpc2FibGVkO1xuXHR9XG59XG4iXX0=