carbon-components-angular
Version:
Next generation components
379 lines (377 loc) • 32.2 kB
JavaScript
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" }, 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"
(remove)="removeFile(fileItem)"
[size]="fileItemSize">
</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"], 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"
(remove)="removeFile(fileItem)"
[size]="fileItemSize">
</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
}], filesChange: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZS11cGxvYWRlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZmlsZS11cGxvYWRlci9maWxlLXVwbG9hZGVyLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ04sU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBQ04sU0FBUyxFQUNULFlBQVksRUFDWixXQUFXLEVBQ1gsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUF3QixpQkFBaUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7Ozs7QUFLekUsTUFBTSxJQUFJLEdBQUcsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBRXZCOzs7Ozs7OztHQVFHO0FBMEVILE1BQU0sT0FBTyxZQUFZO0lBZ0Z4QixZQUFzQixJQUFVO1FBQVYsU0FBSSxHQUFKLElBQUksQ0FBTTtRQTNFaEM7Ozs7V0FJRztRQUNNLGVBQVUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUM7UUFDekQ7O1dBRUc7UUFDTSxlQUFVLEdBQThELFNBQVMsQ0FBQztRQVMzRjs7V0FFRztRQUNNLFdBQU0sR0FBRyxFQUFFLENBQUM7UUFDckI7Ozs7V0FJRztRQUNNLGFBQVEsR0FBRyxJQUFJLENBQUM7UUFDekI7O1dBRUc7UUFDTSxhQUFRLEdBQUcsS0FBSyxDQUFDO1FBSzFCOztXQUVHO1FBQ00saUJBQVksR0FBdUIsSUFBSSxDQUFDO1FBQ2pEOztXQUVHO1FBQ00sU0FBSSxHQUFHLEtBQUssQ0FBQztRQUt0Qjs7V0FFRztRQUNNLG1CQUFjLEdBQUcsaUJBQWlCLFlBQVksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBSzVFOztXQUVHO1FBQ00sVUFBSyxHQUFHLElBQUksR0FBRyxFQUFZLENBQUM7UUFDckM7O1dBRUc7UUFDTSxhQUFRLEdBQUcsS0FBSyxDQUFDO1FBRWhCLGdCQUFXLEdBQUcs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QUN6QixLQUFLLEVBQUUsSUFBSTt5QkFDWDtxQkFDRDtpQkFDRDsyRkFXUyxVQUFVO3NCQUFsQixLQUFLO2dCQUlHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBSUcsS0FBSztzQkFBYixLQUFLO2dCQUlHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBSUcsTUFBTTtzQkFBZCxLQUFLO2dCQU1HLFFBQVE7c0JBQWhCLEtBQUs7Z0JBSUcsUUFBUTtzQkFBaEIsS0FBSztnQkFJRyxJQUFJO3NCQUFaLEtBQUs7Z0JBSUcsWUFBWTtzQkFBcEIsS0FBSztnQkFJRyxJQUFJO3NCQUFaLEtBQUs7Z0JBSUcsUUFBUTtzQkFBaEIsS0FBSztnQkFJRyxjQUFjO3NCQUF0QixLQUFLO2dCQUlrQixTQUFTO3NCQUFoQyxTQUFTO3VCQUFDLFdBQVc7Z0JBSWIsS0FBSztzQkFBYixLQUFLO2dCQUlHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBRUksV0FBVztzQkFBcEIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG5cdENvbXBvbmVudCxcblx0SW5wdXQsXG5cdE91dHB1dCxcblx0Vmlld0NoaWxkLFxuXHRFdmVudEVtaXR0ZXIsXG5cdFRlbXBsYXRlUmVmXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgeyBDb250cm9sVmFsdWVBY2Nlc3NvciwgTkdfVkFMVUVfQUNDRVNTT1IgfSBmcm9tIFwiQGFuZ3VsYXIvZm9ybXNcIjtcblxuaW1wb3J0IHsgSTE4biB9IGZyb20gXCJjYXJib24tY29tcG9uZW50cy1hbmd1bGFyL2kxOG5cIjtcbmltcG9ydCB7IEZpbGVJdGVtIH0gZnJvbSBcIi4vZmlsZS1pdGVtLmludGVyZmFjZVwiO1xuXG5jb25zdCBub29wID0gKCkgPT4geyB9O1xuXG4vKipcbiAqIEdldCBzdGFydGVkIHdpdGggaW1wb3J0aW5nIHRoZSBtb2R1bGU6XG4gKlxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgRmlsZVVwbG9hZGVyTW9kdWxlIH0gZnJvbSAnY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhcic7XG4gKiBgYGBcbiAqXG4gKiBbU2VlIGRlbW9dKC4uLy4uLz9wYXRoPS9zdG9yeS9jb21wb25lbnRzLWZpbGUtdXBsb2FkZXItLWJhc2ljKVxuICovXG5AQ29tcG9uZW50KHtcblx0c2VsZWN0b3I6IFwiY2RzLWZpbGUtdXBsb2FkZXIsIGlibS1maWxlLXVwbG9hZGVyXCIsXG5cdHRlbXBsYXRlOiBgXG5cdFx0PG5nLWNvbnRhaW5lciAqbmdJZj1cIiFza2VsZXRvbjsgZWxzZSBza2VsZXRvblRlbXBsYXRlXCI+XG5cdFx0XHQ8bGFiZWwgW2Zvcl09XCJmaWxlVXBsb2FkZXJJZFwiIGNsYXNzPVwiY2RzLS1maWxlLS1sYWJlbFwiPnt7dGl0bGV9fTwvbGFiZWw+XG5cdFx0XHQ8cCBjbGFzcz1cImNkcy0tbGFiZWwtZGVzY3JpcHRpb25cIiByb2xlPVwiYWxlcnRcIj57e2Rlc2NyaXB0aW9ufX08L3A+XG5cdFx0XHQ8ZGl2IGNsYXNzPVwiY2RzLS1maWxlXCI+XG5cdFx0XHRcdDxsYWJlbFxuXHRcdFx0XHRcdCpuZ0lmPVwiZHJvcFwiXG5cdFx0XHRcdFx0Y2xhc3M9XCJjZHMtLWZpbGUtYnJvd3NlLWJ0blwiXG5cdFx0XHRcdFx0KGtleXVwLmVudGVyKT1cImZpbGVJbnB1dC5jbGljaygpXCJcblx0XHRcdFx0XHQoa2V5dXAuc3BhY2UpPVwiZmlsZUlucHV0LmNsaWNrKClcIlxuXHRcdFx0XHRcdFtuZ0NsYXNzXT1cInsnY2RzLS1maWxlLWJyb3dzZS1idG4tLWRpc2FibGVkJzogZGlzYWJsZWR9XCJcblx0XHRcdFx0XHR0YWJpbmRleD1cIjBcIj5cblx0XHRcdFx0XHQ8ZGl2XG5cdFx0XHRcdFx0XHRjbGFzcz1cImNkcy0tZmlsZV9fZHJvcC1jb250YWluZXJcIlxuXHRcdFx0XHRcdFx0W25nQ2xhc3NdPVwieydjZHMtLWZpbGVfX2Ryb3AtY29udGFpbmVyLS1kcmFnLW92ZXInOiBkcmFnT3Zlcn1cIlxuXHRcdFx0XHRcdFx0cm9sZT1cImJ1dHRvblwiXG5cdFx0XHRcdFx0XHQoY2xpY2spPVwiZmlsZUlucHV0LmNsaWNrKClcIlxuXHRcdFx0XHRcdFx0W2F0dHIuZm9yXT1cImZpbGVVcGxvYWRlcklkXCJcblx0XHRcdFx0XHRcdChkcmFnb3Zlcik9XCJvbkRyYWdPdmVyKCRldmVudClcIlxuXHRcdFx0XHRcdFx0KGRyYWdsZWF2ZSk9XCJvbkRyYWdMZWF2ZSgkZXZlbnQpXCJcblx0XHRcdFx0XHRcdChkcm9wKT1cIm9uRHJvcCgkZXZlbnQpXCI+XG5cdFx0XHRcdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiIWlzVGVtcGxhdGUoZHJvcFRleHQpXCI+e3tkcm9wVGV4dH19PC9uZy1jb250YWluZXI+XG5cdFx0XHRcdFx0XHQ8bmctdGVtcGxhdGUgKm5nSWY9XCJpc1RlbXBsYXRlKGRyb3BUZXh0KVwiIFtuZ1RlbXBsYXRlT3V0bGV0XT1cImRyb3BUZXh0XCI+PC9uZy10ZW1wbGF0ZT5cblx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0PC9sYWJlbD5cblx0XHRcdFx0PGJ1dHRvblxuXHRcdFx0XHRcdCpuZ0lmPVwiIWRyb3BcIlxuXHRcdFx0XHRcdHR5cGU9XCJidXR0b25cIlxuXHRcdFx0XHRcdFtjZHNCdXR0b25dPVwiYnV0dG9uVHlwZVwiXG5cdFx0XHRcdFx0KGNsaWNrKT1cImZpbGVJbnB1dC5jbGljaygpXCJcblx0XHRcdFx0XHRbYXR0ci5mb3JdPVwiZmlsZVVwbG9hZGVySWRcIlxuXHRcdFx0XHRcdFtzaXplXT1cInNpemVcIlxuXHRcdFx0XHRcdFtkaXNhYmxlZF09XCJkaXNhYmxlZFwiPlxuXHRcdFx0XHRcdHt7YnV0dG9uVGV4dH19XG5cdFx0XHRcdDwvYnV0dG9uPlxuXHRcdFx0XHQ8aW5wdXRcblx0XHRcdFx0XHQjZmlsZUlucHV0XG5cdFx0XHRcdFx0dHlwZT1cImZpbGVcIlxuXHRcdFx0XHRcdGNsYXNzPVwiY2RzLS1maWxlLWlucHV0XCJcblx0XHRcdFx0XHRbYWNjZXB0XT1cImFjY2VwdFwiXG5cdFx0XHRcdFx0W2lkXT1cImZpbGVVcGxvYWRlcklkXCJcblx0XHRcdFx0XHRbbXVsdGlwbGVdPVwibXVsdGlwbGVcIlxuXHRcdFx0XHRcdHRhYmluZGV4PVwiLTFcIlxuXHRcdFx0XHRcdChjaGFuZ2UpPVwib25GaWxlc0FkZGVkKClcIlxuXHRcdFx0XHRcdFtkaXNhYmxlZF09XCJkaXNhYmxlZFwiLz5cblx0XHRcdFx0PGRpdiBjbGFzcz1cImNkcy0tZmlsZS1jb250YWluZXJcIj5cblx0XHRcdFx0XHQ8bmctY29udGFpbmVyICpuZ0Zvcj1cImxldCBmaWxlSXRlbSBvZiBmaWxlc1wiPlxuXHRcdFx0XHRcdFx0PGNkcy1maWxlXG5cdFx0XHRcdFx0XHRcdFtmaWxlSXRlbV09XCJmaWxlSXRlbVwiXG5cdFx0XHRcdFx0XHRcdChyZW1vdmUpPVwicmVtb3ZlRmlsZShmaWxlSXRlbSlcIlxuXHRcdFx0XHRcdFx0XHRbc2l6ZV09XCJmaWxlSXRlbVNpemVcIj5cblx0XHRcdFx0XHRcdDwvY2RzLWZpbGU+XG5cdFx0XHRcdFx0PC9uZy1jb250YWluZXI+XG5cdFx0XHRcdDwvZGl2PlxuXHRcdFx0PC9kaXY+XG5cdFx0PC9uZy1jb250YWluZXI+XG5cblx0XHQ8bmctdGVtcGxhdGUgI3NrZWxldG9uVGVtcGxhdGU+XG5cdFx0XHQ8ZGl2IGNsYXNzPVwiY2RzLS1za2VsZXRvbl9fdGV4dFwiIHN0eWxlPVwid2lkdGg6IDEwMHB4XCI+PC9kaXY+XG5cdFx0XHQ8ZGl2IGNsYXNzPVwiY2RzLS1za2VsZXRvbl9fdGV4dFwiIHN0eWxlPVwid2lkdGg6IDIyNXB4XCI+PC9kaXY+XG5cdFx0XHQ8YnV0dG9uIGNkc0J1dHRvbiBza2VsZXRvbj1cInRydWVcIj48L2J1dHRvbj5cblx0XHQ8L25nLXRlbXBsYXRlPlxuXHRgLFxuXHRwcm92aWRlcnM6IFtcblx0XHR7XG5cdFx0XHRwcm92aWRlOiBOR19WQUxVRV9BQ0NFU1NPUixcblx0XHRcdHVzZUV4aXN0aW5nOiBGaWxlVXBsb2FkZXIsXG5cdFx0XHRtdWx0aTogdHJ1ZVxuXHRcdH1cblx0XVxufSlcbmV4cG9ydCBjbGFzcyBGaWxlVXBsb2FkZXIgaW1wbGVtZW50cyBDb250cm9sVmFsdWVBY2Nlc3NvciB7XG5cdC8qKlxuXHQgKiBDb3VudGVyIHVzZWQgdG8gY3JlYXRlIHVuaXF1ZSBpZHMgZm9yIGZpbGUtdXBsb2FkZXIgY29tcG9uZW50c1xuXHQgKi9cblx0c3RhdGljIGZpbGVVcGxvYWRlckNvdW50ID0gMDtcblx0LyoqXG5cdCAqIEFjY2Vzc2libGUgdGV4dCBmb3IgdGhlIGJ1dHRvbiB0aGF0IG9wZW5zIHRoZSB1cGxvYWQgd2luZG93LlxuXHQgKlxuXHQgKiBEZWZhdWx0cyB0byB0aGUgYEZJTEVfVVBMT0FERVIuT1BFTmAgdmFsdWUgZnJvbSB0aGUgaTE4biBzZXJ2aWNlXG5cdCAqL1xuXHRASW5wdXQoKSBidXR0b25UZXh0ID0gdGhpcy5pMThuLmdldCgpLkZJTEVfVVBMT0FERVIuT1BFTjtcblx0LyoqXG5cdCAqIFR5cGUgc2V0IGZvciBidXR0b25cblx0ICovXG5cdEBJbnB1dCgpIGJ1dHRvblR5cGU6IFwicHJpbWFyeVwiIHwgXCJzZWNvbmRhcnlcIiB8IFwidGVydGlhcnlcIiB8IFwiZ2hvc3RcIiB8IFwiZGFuZ2VyXCIgPSBcInByaW1hcnlcIjtcblx0LyoqXG5cdCAqIFRleHQgc2V0IHRvIHRoZSB0aXRsZVxuXHQgKi9cblx0QElucHV0KCkgdGl0bGU6IHN0cmluZztcblx0LyoqXG5cdCAqIFRleHQgc2V0IHRvIHRoZSBkZXNjcmlwdGlvblxuXHQgKi9cblx0QElucHV0KCkgZGVzY3JpcHRpb246IHN0cmluZztcblx0LyoqXG5cdCAqIFNwZWNpZnkgdGhlIHR5cGVzIG9mIGZpbGVzIHRoYXQgdGhlIGlucHV0IHNob3VsZCBiZSBhYmxlIHRvIHJlY2VpdmVcblx0ICovXG5cdEBJbnB1dCgpIGFjY2VwdCA9IFtdO1xuXHQvKipcblx0ICogU2V0IHRvIGBmYWxzZWAgdG8gdGVsbCB0aGUgY29tcG9uZW50IHRvIG9ubHkgYWNjZXB0IGEgc2luZ2xlIGZpbGUgb24gdXBsb2FkLlxuXHQgKlxuXHQgKiBEZWZhdWx0cyB0byBgdHJ1ZWAuIEFjY2VwdHMgbXVsdGlwbGUgZmlsZXMuXG5cdCAqL1xuXHRASW5wdXQoKSBtdWx0aXBsZSA9IHRydWU7XG5cdC8qKlxuXHQgKiBTZXQgdG8gYHRydWVgIGZvciBhIGxvYWRpbmcgZmlsZSB1cGxvYWRlci5cblx0ICovXG5cdEBJbnB1dCgpIHNrZWxldG9uID0gZmFsc2U7XG5cdC8qKlxuXHQgKiBTZXRzIHRoZSBzaXplIG9mIHRoZSBidXR0b24uXG5cdCAqL1xuXHRASW5wdXQoKSBzaXplOiBcInNtXCIgfCBcIm1kXCIgfCBcImxnXCI7XG5cdC8qKlxuXHQgKiBTZXRzIHRoZSBzaXplIG9mIHRoZSBmaWxlIGl0ZW1zXG5cdCAqL1xuXHRASW5wdXQoKSBmaWxlSXRlbVNpemU6IFwic21cIiB8IFwibWRcIiB8IFwibGdcIiA9IFwibGdcIjtcblx0LyoqXG5cdCAqIFNldCB0byBgdHJ1ZWAgdG8gZW5hYmxlIGRyYWcgYW5kIGRyb3AuXG5cdCAqL1xuXHRASW5wdXQoKSBkcm9wID0gZmFsc2U7XG5cdC8qKlxuXHQgKiBTZXRzIHRoZSB0ZXh0IHNob3duIGluIGRyYWcgYW5kIGRyb3AgYm94LlxuXHQgKi9cblx0QElucHV0KCkgZHJvcFRleHQ6IHN0cmluZyB8IFRlbXBsYXRlUmVmPGFueT47XG5cdC8qKlxuXHQgKiBQcm92aWRlcyBhIHVuaXF1ZSBpZCBmb3IgdGhlIHVuZGVybHlpbmcgYDxpbnB1dD5gIG5vZGVcblx0ICovXG5cdEBJbnB1dCgpIGZpbGVVcGxvYWRlcklkID0gYGZpbGUtdXBsb2FkZXItJHtGaWxlVXBsb2FkZXIuZmlsZVVwbG9hZGVyQ291bnR9YDtcblx0LyoqXG5cdCAqIE1haW50YWlucyBhIHJlZmVyZW5jZSB0byB0aGUgdmlldyBET00gZWxlbWVudCBvZiB0aGUgdW5kZXJseWluZyA8aW5wdXQ+IG5vZGVcblx0ICovXG5cdEBWaWV3Q2hpbGQoXCJmaWxlSW5wdXRcIikgZmlsZUlucHV0O1xuXHQvKipcblx0ICogVGhlIGxpc3Qgb2YgZmlsZXMgdGhhdCBoYXZlIGJlZW4gc3VibWl0dGVkIHRvIGJlIHVwbG9hZGVkXG5cdCAqL1xuXHRASW5wdXQoKSBmaWxlcyA9IG5ldyBTZXQ8RmlsZUl0ZW0+KCk7XG5cdC8qKlxuXHQgKiBTZXQgdG8gYHRydWVgIHRvIGRpc2FibGUgdXBsb2FkIGJ1dHRvblxuXHQgKi9cblx0QElucHV0KCkgZGlzYWJsZWQgPSBmYWxzZTtcblxuXHRAT3V0cHV0KCkgZmlsZXNDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPGFueT4oKTtcblxuXHQvKipcblx0ICogQ29udHJvbHMgdGhlIHN0YXRlIG9mIHRoZSBkcmFnIGFuZCBkcm9wIGZpbGUgY29udGFpbmVyXG5cdCAqL1xuXHRwdWJsaWMgZHJhZ092ZXIgPSBmYWxzZTtcblxuXHRwcm90ZWN0ZWQgb25Ub3VjaGVkQ2FsbGJhY2s6ICgpID0+IHZvaWQgPSBub29wO1xuXHRwcm90ZWN0ZWQgb25DaGFuZ2VDYWxsYmFjazogKF86IFNldDxGaWxlSXRlbT4pID0+IHZvaWQgPSBub29wO1xuXG5cdGNvbnN0cnVjdG9yKHByb3RlY3RlZCBpMThuOiBJMThuKSB7XG5cdFx0RmlsZVVwbG9hZGVyLmZpbGVVcGxvYWRlckNvdW50Kys7XG5cdH1cblxuXHQvKipcblx0ICogU3BlY2lmaWVzIHRoZSBwcm9wZXJ0eSB0byBiZSB1c2VkIGFzIHRoZSByZXR1cm4gdmFsdWUgdG8gYG5nTW9kZWxgIGFuZCByZWFjdGl2ZSBmb3Jtcy5cblx0ICogVXBkYXRlcyBgdGhpcy5maWxlc2AuXG5cdCAqL1xuXHRnZXQgdmFsdWUoKTogU2V0PEZpbGVJdGVtPiB7XG5cdFx0cmV0dXJuIHRoaXMuZmlsZXM7XG5cdH1cblx0c2V0IHZhbHVlKHY6IFNldDxGaWxlSXRlbT4pIHtcblx0XHRpZiAodiAhPT0gdGhpcy5maWxlcykge1xuXHRcdFx0dGhpcy5maWxlcyA9IHY7XG5cdFx0XHR0aGlzLm9uQ2hhbmdlQ2FsbGJhY2sodik7XG5cdFx0fVxuXHR9XG5cblx0b25CbHVyKCkge1xuXHRcdHRoaXMub25Ub3VjaGVkQ2FsbGJhY2soKTtcblx0fVxuXG5cdGdldCBmaWxlTGlzdCgpIHtcblx0XHRyZXR1cm4gQXJyYXkuZnJvbSh0aGlzLmZpbGVJbnB1dC5uYXRpdmVFbGVtZW50LmZpbGVzKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBQcm9wYWdhdGVzIHRoZSBpbmplY3RlZCBgdmFsdWVgLlxuXHQgKi9cblx0d3JpdGVWYWx1ZSh2YWx1ZTogU2V0PEZpbGVJdGVtPikge1xuXHRcdGlmICh2YWx1ZSAhPT0gdGhpcy52YWx1ZSkge1xuXHRcdFx0dGhpcy5maWxlcyA9IHZhbHVlO1xuXHRcdH1cblx0fVxuXG5cdGNyZWF0ZUZpbGVJdGVtKGZpbGUpOiBGaWxlSXRlbSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdHVwbG9hZGVkOiBmYWxzZSxcblx0XHRcdHN0YXRlOiBcImVkaXRcIixcblx0XHRcdGludmFsaWQ6IGZhbHNlLFxuXHRcdFx0aW52YWxpZFRleHQ6IFwiXCIsXG5cdFx0XHRmaWxlOiBmaWxlXG5cdFx0fTtcblx0fVxuXG5cdG9uRmlsZXNBZGRlZCgpIHtcblx0XHRjb25zdCBuZXdGaWxlcyA9IG5ldyBTZXQ8RmlsZUl0ZW0+KHRoaXMuZmlsZXMpO1xuXHRcdGlmICghdGhpcy5tdWx0aXBsZSkge1xuXHRcdFx0bmV3RmlsZXMuY2xlYXIoKTtcblx0XHR9XG5cdFx0Zm9yIChsZXQgZmlsZSBvZiB0aGlzLmZpbGVMaXN0KSB7XG5cdFx0XHRjb25zdCBmaWxlSXRlbSA9IHRoaXMuY3JlYXRlRmlsZUl0ZW0oZmlsZSk7XG5cdFx0XHRuZXdGaWxlcy5hZGQoZmlsZUl0ZW0pO1xuXHRcdH1cblxuXHRcdHRoaXMudmFsdWUgPSBuZXdGaWxlcztcblx0XHR0aGlzLmZpbGVzQ2hhbmdlLmVtaXQobmV3RmlsZXMpO1xuXHR9XG5cblx0b25EcmFnT3ZlcihldmVudCkge1xuXHRcdGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0aWYgKHRoaXMuZGlzYWJsZWQpIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0dGhpcy5kcmFnT3ZlciA9IHRydWU7XG5cdH1cblxuXHRvbkRyYWdMZWF2ZShldmVudCkge1xuXHRcdGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0dGhpcy5kcmFnT3ZlciA9IGZhbHNlO1xuXHR9XG5cblx0b25Ecm9wKGV2ZW50KSB7XG5cdFx0ZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG5cdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRpZiAodGhpcy5kaXNhYmxlZCkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGNvbnN0IHRyYW5zZmVycmVkRmlsZXM6IEFycmF5PEZpbGU+ID0gQXJyYXkuZnJvbShldmVudC5kYXRhVHJhbnNmZXIuZmlsZXMpO1xuXHRcdGNvbnN0IG5ld0ZpbGVzID0gbmV3IFNldDxGaWxlSXRlbT4odGhpcy5maWxlcyk7XG5cblx0XHR0cmFuc2ZlcnJlZEZpbGVzLmZpbHRlcigoeyBuYW1lLCB0eXBlIH0pID0+IHtcblx0XHRcdC8vIEdldCB0aGUgZmlsZSBleHRlbnNpb24gYW5kIGFkZCBhIFwiLlwiIHRvIHRoZSBiZWdpbm5pbmcuXG5cdFx0XHRjb25zdCBmaWxlRXh0ZW5zaW9uID0gbmFtZS5zcGxpdChcIi5cIikucG9wKCkucmVwbGFjZSgvXi8sIFwiLlwiKTtcblx0XHRcdC8vIENoZWNrIGlmIHRoZSBhY2NlcHQgYXJyYXkgY29udGFpbnMgdGhlIG1pbWUgdHlwZSBvciBleHRlbnNpb24gb2YgdGhlIGZpbGUuXG5cdFx0XHRyZXR1cm4gdGhpcy5hY2NlcHQuaW5jbHVkZXModHlwZSkgfHwgdGhpcy5hY2NlcHQuaW5jbHVkZXMoZmlsZUV4dGVuc2lvbikgfHwgIXRoaXMuYWNjZXB0Lmxlbmd0aDtcblx0XHR9KS5mb3JFYWNoKGZpbGUgPT4ge1xuXHRcdFx0aWYgKCFuZXdGaWxlcy5zaXplIHx8IHRoaXMubXVsdGlwbGUpIHtcblx0XHRcdFx0Y29uc3QgZmlsZUl0ZW0gPSB0aGlzLmNyZWF0ZUZpbGVJdGVtKGZpbGUpO1xuXHRcdFx0XHRuZXdGaWxlcy5hZGQoZmlsZUl0ZW0pO1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0dGhpcy52YWx1ZSA9IG5ld0ZpbGVzO1xuXHRcdHRoaXMuZmlsZXNDaGFuZ2UuZW1pdChuZXdGaWxlcyk7XG5cdFx0dGhpcy5kcmFnT3ZlciA9IGZhbHNlO1xuXHR9XG5cblx0cmVtb3ZlRmlsZShmaWxlSXRlbSkge1xuXHRcdC8vIERlbGV0aW5nIGFuIGl0ZW0gZnJvbSB0aGlzLmZpbGVzIHJlbW92ZXMgdGhlIDxpYm0tZmlsZT4gY29tcG9uZW50LFxuXHRcdC8vIHdoaWNoIHRyaWdnZXJzIGl0cyBuZ09uRGVzdHJveSgpLCB3aGljaCBmaXJlcyB0aGUgKHJlbW92ZSkgZXZlbnQgYWdhaW4uXG5cdFx0Ly8gU28sIChyZW1vdmUpIG1heSBkb3VibGUtZmlyZSBhbmQgd2UgbmVlZCB0byBoYW5kbGUgaXQgaGVyZS5cblx0XHRpZiAodGhpcy5maWxlcyAmJiB0aGlzLmZpbGVzLmhhcyhmaWxlSXRlbSkpIHtcblx0XHRcdGNvbnN0IG5ld0ZpbGVzID0gbmV3IFNldDxGaWxlSXRlbT4odGhpcy5maWxlcyk7XG5cdFx0XHRuZXdGaWxlcy5kZWxldGUoZmlsZUl0ZW0pO1xuXHRcdFx0dGhpcy5maWxlc0NoYW5nZS5lbWl0KG5ld0ZpbGVzKTtcblx0XHRcdHRoaXMudmFsdWUgPSBuZXdGaWxlcztcblx0XHR9XG5cdFx0dGhpcy5maWxlSW5wdXQubmF0aXZlRWxlbWVudC52YWx1ZSA9IFwiXCI7XG5cdH1cblxuXHRwdWJsaWMgaXNUZW1wbGF0ZSh2YWx1ZSkge1xuXHRcdHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIFRlbXBsYXRlUmVmO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJlZ2lzdGVycyB0aGUgaW5qZWN0ZWQgZnVuY3Rpb24gdG8gY29udHJvbCB0aGUgdG91Y2ggdXNlIG9mIHRoZSBgRmlsZVVwbG9hZGVyYC5cblx0ICovXG5cdHJlZ2lzdGVyT25Ub3VjaGVkKGZuOiBhbnkpIHtcblx0XHR0aGlzLm9uVG91Y2hlZENhbGxiYWNrID0gZm47XG5cdH1cblx0LyoqXG5cdCAqIFNldHMgYSBtZXRob2QgaW4gb3JkZXIgdG8gcHJvcGFnYXRlIGNoYW5nZXMgYmFjayB0byB0aGUgZm9ybS5cblx0ICovXG5cdHJlZ2lzdGVyT25DaGFuZ2UoZm46IGFueSkge1xuXHRcdHRoaXMub25DaGFuZ2VDYWxsYmFjayA9IGZuO1xuXHR9XG5cblx0LyoqXG5cdCAqIGBDb250cm9sVmFsdWVBY2Nlc3NvcmAgbWV0aG9kIHRvIHByb2dyYW1tYXRpY2FsbHkgZGlzYWJsZSB0aGUgY2hlY2tib3guXG5cdCAqXG5cdCAqIGV4OiBgdGhpcy5mb3JtR3JvdXAuZ2V0KFwibXlGaWxlVXBsb2FkZXJcIikuZGlzYWJsZSgpO2Bcblx0ICpcblx0ICogQHBhcmFtIGlzRGlzYWJsZWQgYHRydWVgIHRvIGRpc2FibGUgdGhlIGZpbGUgdXBsb2FkZXJcblx0ICovXG5cdHNldERpc2FibGVkU3RhdGUoaXNEaXNhYmxlZDogYm9vbGVhbikge1xuXHRcdHRoaXMuZGlzYWJsZWQgPSBpc0Rpc2FibGVkO1xuXHR9XG59XG4iXX0=