@lautarobock/file-input
Version:
Angular Material File Input
249 lines • 36.5 kB
JavaScript
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { Component, ContentChild, Directive, forwardRef, Input, Optional, Self, ViewChild, ViewEncapsulation } from '@angular/core';
import { mixinErrorState } from '@angular/material/core';
import { MatFormFieldControl } from '@angular/material/form-field';
import { Subject } from 'rxjs';
import * as i0 from "@angular/core";
import * as i1 from "@angular/cdk/platform";
import * as i2 from "@angular/forms";
import * as i3 from "@angular/material/core";
import * as i4 from "@angular/common";
import * as i5 from "@angular/material/button";
import * as i6 from "@angular/material/icon";
import * as i7 from "@angular/material/form-field";
let nextUniqueId = 0;
const _NgxMatInputMixinBase = mixinErrorState(class {
constructor(_defaultErrorStateMatcher, _parentForm, _parentFormGroup,
/** @docs-private */
ngControl) {
this._defaultErrorStateMatcher = _defaultErrorStateMatcher;
this._parentForm = _parentForm;
this._parentFormGroup = _parentFormGroup;
this.ngControl = ngControl;
this.stateChanges = new Subject();
}
});
export class NgxMatFileInputIcon {
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgxMatFileInputIcon, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: NgxMatFileInputIcon, selector: "[ngxMatFileInputIcon]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgxMatFileInputIcon, decorators: [{
type: Directive,
args: [{
selector: '[ngxMatFileInputIcon]'
}]
}] });
export class NgxMatFileInputComponent extends _NgxMatInputMixinBase {
get disabled() {
if (this.ngControl && this.ngControl.disabled !== null) {
return this.ngControl.disabled;
}
return this._disabled;
}
set disabled(value) {
this._disabled = coerceBooleanProperty(value);
if (this.focused) {
this.focused = false;
this.stateChanges.next();
}
}
get id() { return this._id; }
set id(value) { this._id = value || this._uid; }
get multiple() { return this._multiple; }
set multiple(value) {
this._multiple = coerceBooleanProperty(value);
}
get required() { return this._required; }
set required(value) { this._required = coerceBooleanProperty(value); }
get value() { return this._value; }
set value(value) {
this._value = value;
}
get readonly() { return this._readonly; }
set readonly(value) { this._readonly = coerceBooleanProperty(value); }
/**
* Limiting accepted file types
* Example: accept="image/png, image/jpeg" or accept=".png, .jpg, .jpeg" — Accept PNG or JPEG files.
*/
get accept() { return this._accept; }
set accept(value) {
this._accept = value;
}
constructor(_elementRef, _platform, _cd, ngControl, _parentForm, _parentFormGroup, _defaultErrorStateMatcher) {
super(_defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl);
this._elementRef = _elementRef;
this._platform = _platform;
this._cd = _cd;
this.ngControl = ngControl;
this.color = 'primary';
this.fileNames = null;
this._uid = `ngx-mat-fileinput-${nextUniqueId++}`;
this.stateChanges = new Subject();
this.focused = false;
this.controlType = 'ngx-mat-file-input';
this.autofilled = false;
/** Function when touched */
this._onTouched = () => { };
/** Function when changed */
this._onChange = () => { };
this._disabled = false;
this._multiple = false;
this.placeholder = 'Choose a file';
this.separator = ',';
this._required = false;
this._readonly = true;
this.id = this.id;
if (this.ngControl) {
this.ngControl.valueAccessor = this;
}
}
ngOnChanges() {
this.stateChanges.next();
}
ngOnDestroy() {
this.stateChanges.complete();
}
ngDoCheck() {
if (this.ngControl) {
this.updateErrorState();
}
}
// Implemented as part of ControlValueAccessor.
writeValue(value) {
this._updateInputValue(value);
}
// Implemented as part of ControlValueAccessor.
registerOnChange(fn) {
this._onChange = fn;
}
// Implemented as part of ControlValueAccessor.
registerOnTouched(fn) {
this._onTouched = fn;
}
// Implemented as part of ControlValueAccessor.
setDisabledState(isDisabled) {
this.disabled = isDisabled;
this.stateChanges.next();
}
/** Focuses the input. */
focus(options) {
this._inputValueRef.nativeElement.focus(options);
}
_focusChanged(isFocused) {
if (isFocused !== this.focused && (!this.readonly || !isFocused)) {
this.focused = isFocused;
this.stateChanges.next();
}
}
/** Mark the field as touched */
_markAsTouched() {
this._onTouched();
this._cd.markForCheck();
this.stateChanges.next();
}
_isBadInput() {
let validity = this._inputValueRef.nativeElement.validity;
return validity && validity.badInput;
}
get empty() {
return !this._inputValueRef.nativeElement.value && !this._isBadInput() &&
!this.autofilled;
}
get shouldLabelFloat() {
return this.focused || !this.empty;
}
setDescribedByIds(ids) {
this._ariaDescribedby = ids.join(' ');
}
openFilePicker(event) {
this._inputFileRef.nativeElement.click();
if (event) {
event.preventDefault();
event.stopPropagation();
}
this._markAsTouched();
}
handleFiles(filelist) {
if (filelist.length > 0) {
const files = new Array();
for (let i = 0; i < filelist.length; i++) {
files.push(filelist.item(i));
}
this._updateInputValue(files);
this._resetInputFile();
this._onChange(this.multiple ? files : files[0]);
}
}
/** Handles a click on the control's container. */
onContainerClick(event) { }
;
_resetInputFile() {
this._inputFileRef.nativeElement.value = "";
}
_updateInputValue(files) {
let text = null;
if (files) {
if (Array.isArray(files)) {
text = this._multiple
? files.map(x => x.name).join(this.separator)
: files[0].name;
}
else {
text = files.name != null ? files.name : null;
}
}
this._inputValueRef.nativeElement.value = text;
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgxMatFileInputComponent, deps: [{ token: i0.ElementRef }, { token: i1.Platform }, { token: i0.ChangeDetectorRef }, { token: i2.NgControl, optional: true, self: true }, { token: i2.NgForm, optional: true }, { token: i2.FormGroupDirective, optional: true }, { token: i3.ErrorStateMatcher }], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: NgxMatFileInputComponent, selector: "ngx-mat-file-input", inputs: { color: "color", disabled: "disabled", id: "id", multiple: "multiple", placeholder: "placeholder", separator: "separator", required: "required", errorStateMatcher: "errorStateMatcher", value: "value", readonly: "readonly", accept: "accept" }, host: { classAttribute: "ngx-mat-file-input" }, providers: [
{ provide: MatFormFieldControl, useExisting: forwardRef((() => NgxMatFileInputComponent)) }
], queries: [{ propertyName: "_customIcon", first: true, predicate: NgxMatFileInputIcon, descendants: true }], viewQueries: [{ propertyName: "_inputFileRef", first: true, predicate: ["inputFile"], descendants: true, static: true }, { propertyName: "_inputValueRef", first: true, predicate: ["inputValue"], descendants: true, static: true }], exportAs: ["ngx-mat-file-input"], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<input #inputValue autocomplete=\"off\"\r\n class=\"mat-mdc-input-element mat-mdc-form-field-input-control mdc-text-field__input\" [attr.id]='id'\r\n [attr.placeholder]='placeholder' [disabled]='disabled' [required]='required' [attr.readonly]='readonly || null'\r\n [attr.aria-describedby]='_ariaDescribedby || null' [attr.aria-invalid]='errorState'\r\n [attr.aria-required]='required.toString()'>\r\n<div class=\"mat-mdc-form-field-suffix\">\r\n <button matSuffix mat-icon-button [color]=\"color\" class=\"button-browse\" (click)=\"openFilePicker($event)\" type=\"button\"\r\n [disabled]=\"disabled\">\r\n <mat-icon *ngIf=\"!_customIcon\" class=\"ngx-mat-file-input--default-icon\">attach_file</mat-icon>\r\n <ng-content select=\"[ngxMatFileInputIcon]\"></ng-content>\r\n </button>\r\n</div>\r\n<input type=\"file\" #inputFile (change)=\"handleFiles($event.target.files)\" class=\"input-file\" [multiple]=\"multiple\"\r\n [accept]=\"accept\">", styles: [".mat-mdc-form-field-appearance-outline .mat-form-field-prefix .ngx-mat-file-input--default-icon,.mat-mdc-form-field-appearance-outline .mat-form-field-suffix .ngx-mat-file-input--default-icon{width:1em}.mat-mdc-form-field:not(.mat-form-field-appearance-outline) .mat-form-field-prefix .ngx-mat-file-input--default-icon,.mat-mdc-form-field:not(.mat-form-field-appearance-outline) .mat-form-field-suffix .ngx-mat-file-input--default-icon{display:block;width:1.5em;height:1.5em}.mat-mdc-form-field:not(.mat-form-field-appearance-outline) .mat-form-field-prefix .mat-icon-button .ngx-mat-file-input--default-icon,.mat-mdc-form-field:not(.mat-form-field-appearance-outline) .mat-form-field-suffix .mat-icon-button .ngx-mat-file-input--default-icon{margin:auto}.ngx-mat-file-input{display:flex;line-height:18px;align-items:center}.ngx-mat-file-input .input-file{display:block;visibility:hidden;width:0;height:0}\n"], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i5.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i7.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgxMatFileInputComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-mat-file-input', encapsulation: ViewEncapsulation.None, host: {
'class': 'ngx-mat-file-input'
}, providers: [
{ provide: MatFormFieldControl, useExisting: forwardRef((() => NgxMatFileInputComponent)) }
], exportAs: 'ngx-mat-file-input', template: "<input #inputValue autocomplete=\"off\"\r\n class=\"mat-mdc-input-element mat-mdc-form-field-input-control mdc-text-field__input\" [attr.id]='id'\r\n [attr.placeholder]='placeholder' [disabled]='disabled' [required]='required' [attr.readonly]='readonly || null'\r\n [attr.aria-describedby]='_ariaDescribedby || null' [attr.aria-invalid]='errorState'\r\n [attr.aria-required]='required.toString()'>\r\n<div class=\"mat-mdc-form-field-suffix\">\r\n <button matSuffix mat-icon-button [color]=\"color\" class=\"button-browse\" (click)=\"openFilePicker($event)\" type=\"button\"\r\n [disabled]=\"disabled\">\r\n <mat-icon *ngIf=\"!_customIcon\" class=\"ngx-mat-file-input--default-icon\">attach_file</mat-icon>\r\n <ng-content select=\"[ngxMatFileInputIcon]\"></ng-content>\r\n </button>\r\n</div>\r\n<input type=\"file\" #inputFile (change)=\"handleFiles($event.target.files)\" class=\"input-file\" [multiple]=\"multiple\"\r\n [accept]=\"accept\">", styles: [".mat-mdc-form-field-appearance-outline .mat-form-field-prefix .ngx-mat-file-input--default-icon,.mat-mdc-form-field-appearance-outline .mat-form-field-suffix .ngx-mat-file-input--default-icon{width:1em}.mat-mdc-form-field:not(.mat-form-field-appearance-outline) .mat-form-field-prefix .ngx-mat-file-input--default-icon,.mat-mdc-form-field:not(.mat-form-field-appearance-outline) .mat-form-field-suffix .ngx-mat-file-input--default-icon{display:block;width:1.5em;height:1.5em}.mat-mdc-form-field:not(.mat-form-field-appearance-outline) .mat-form-field-prefix .mat-icon-button .ngx-mat-file-input--default-icon,.mat-mdc-form-field:not(.mat-form-field-appearance-outline) .mat-form-field-suffix .mat-icon-button .ngx-mat-file-input--default-icon{margin:auto}.ngx-mat-file-input{display:flex;line-height:18px;align-items:center}.ngx-mat-file-input .input-file{display:block;visibility:hidden;width:0;height:0}\n"] }]
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i1.Platform }, { type: i0.ChangeDetectorRef }, { type: i2.NgControl, decorators: [{
type: Optional
}, {
type: Self
}] }, { type: i2.NgForm, decorators: [{
type: Optional
}] }, { type: i2.FormGroupDirective, decorators: [{
type: Optional
}] }, { type: i3.ErrorStateMatcher }], propDecorators: { _inputFileRef: [{
type: ViewChild,
args: ['inputFile', { static: true }]
}], _inputValueRef: [{
type: ViewChild,
args: ['inputValue', { static: true }]
}], _customIcon: [{
type: ContentChild,
args: [NgxMatFileInputIcon]
}], color: [{
type: Input
}], disabled: [{
type: Input
}], id: [{
type: Input
}], multiple: [{
type: Input
}], placeholder: [{
type: Input
}], separator: [{
type: Input
}], required: [{
type: Input
}], errorStateMatcher: [{
type: Input
}], value: [{
type: Input
}], readonly: [{
type: Input
}], accept: [{
type: Input
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZS1pbnB1dC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9maWxlLWlucHV0L3NyYy9saWIvZmlsZS1pbnB1dC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9maWxlLWlucHV0L3NyYy9saWIvZmlsZS1pbnB1dC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUU5RCxPQUFPLEVBQXFCLFNBQVMsRUFBRSxZQUFZLEVBQUUsU0FBUyxFQUF1QixVQUFVLEVBQUUsS0FBSyxFQUFhLFFBQVEsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRXZMLE9BQU8sRUFBMEMsZUFBZSxFQUFnQixNQUFNLHdCQUF3QixDQUFDO0FBQy9HLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ25FLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7Ozs7Ozs7OztBQUcvQixJQUFJLFlBQVksR0FBRyxDQUFDLENBQUM7QUFFckIsTUFBTSxxQkFBcUIsR0FBRyxlQUFlLENBQzNDO0lBSUUsWUFDUyx5QkFBNEMsRUFDNUMsV0FBbUIsRUFDbkIsZ0JBQW9DO0lBQzNDLG9CQUFvQjtJQUNiLFNBQW9CO1FBSnBCLDhCQUF5QixHQUF6Qix5QkFBeUIsQ0FBbUI7UUFDNUMsZ0JBQVcsR0FBWCxXQUFXLENBQVE7UUFDbkIscUJBQWdCLEdBQWhCLGdCQUFnQixDQUFvQjtRQUVwQyxjQUFTLEdBQVQsU0FBUyxDQUFXO1FBUHBCLGlCQUFZLEdBQUcsSUFBSSxPQUFPLEVBQVEsQ0FBQztJQVF4QyxDQUFDO0NBQ04sQ0FDRixDQUFDO0FBS0YsTUFBTSxPQUFPLG1CQUFtQjtrSUFBbkIsbUJBQW1CO3NIQUFuQixtQkFBbUI7OzRGQUFuQixtQkFBbUI7a0JBSC9CLFNBQVM7bUJBQUM7b0JBQ1QsUUFBUSxFQUFFLHVCQUF1QjtpQkFDbEM7O0FBZ0JELE1BQU0sT0FBTyx3QkFBeUIsU0FBUSxxQkFBcUI7SUE2QmpFLElBQ0ksUUFBUTtRQUNWLElBQUksSUFBSSxDQUFDLFNBQVMsSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUN2RCxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDO1FBQ2pDLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUM7SUFDeEIsQ0FBQztJQUNELElBQUksUUFBUSxDQUFDLEtBQWM7UUFDekIsSUFBSSxDQUFDLFNBQVMsR0FBRyxxQkFBcUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM5QyxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNqQixJQUFJLENBQUMsT0FBTyxHQUFHLEtBQUssQ0FBQztZQUNyQixJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQzNCLENBQUM7SUFDSCxDQUFDO0lBR0QsSUFDSSxFQUFFLEtBQWEsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNyQyxJQUFJLEVBQUUsQ0FBQyxLQUFhLElBQUksSUFBSSxDQUFDLEdBQUcsR0FBRyxLQUFLLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFHeEQsSUFDSSxRQUFRLEtBQWMsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQztJQUNsRCxJQUFJLFFBQVEsQ0FBQyxLQUFjO1FBQ3pCLElBQUksQ0FBQyxTQUFTLEdBQUcscUJBQXFCLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDaEQsQ0FBQztJQU1ELElBQ0ksUUFBUSxLQUFjLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDbEQsSUFBSSxRQUFRLENBQUMsS0FBYyxJQUFJLElBQUksQ0FBQyxTQUFTLEdBQUcscUJBQXFCLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBSy9FLElBQ0ksS0FBSyxLQUFzQixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQ3BELElBQUksS0FBSyxDQUFDLEtBQXNCO1FBQzlCLElBQUksQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDO0lBQ3RCLENBQUM7SUFHRCxJQUNJLFFBQVEsS0FBYyxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO0lBQ2xELElBQUksUUFBUSxDQUFDLEtBQWMsSUFBSSxJQUFJLENBQUMsU0FBUyxHQUFHLHFCQUFxQixDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUcvRTs7O09BR0c7SUFDSCxJQUNJLE1BQU0sS0FBYSxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQzdDLElBQUksTUFBTSxDQUFDLEtBQWE7UUFDdEIsSUFBSSxDQUFDLE9BQU8sR0FBRyxLQUFLLENBQUM7SUFDdkIsQ0FBQztJQUdELFlBQXNCLFdBQW1GLEVBQzdGLFNBQW1CLEVBQ3JCLEdBQXNCLEVBQ0gsU0FBb0IsRUFDbkMsV0FBbUIsRUFDbkIsZ0JBQW9DLEVBQ2hELHlCQUE0QztRQUM1QyxLQUFLLENBQUMseUJBQXlCLEVBQUUsV0FBVyxFQUFFLGdCQUFnQixFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBUHZELGdCQUFXLEdBQVgsV0FBVyxDQUF3RTtRQUM3RixjQUFTLEdBQVQsU0FBUyxDQUFVO1FBQ3JCLFFBQUcsR0FBSCxHQUFHLENBQW1CO1FBQ0gsY0FBUyxHQUFULFNBQVMsQ0FBVztRQXBGeEMsVUFBSyxHQUFpQixTQUFTLENBQUM7UUFFbEMsY0FBUyxHQUFXLElBQUksQ0FBQztRQUV0QixTQUFJLEdBQUcscUJBQXFCLFlBQVksRUFBRSxFQUFFLENBQUM7UUFJOUMsaUJBQVksR0FBa0IsSUFBSSxPQUFPLEVBQVEsQ0FBQztRQUMzRCxZQUFPLEdBQVksS0FBSyxDQUFDO1FBRXpCLGdCQUFXLEdBQVcsb0JBQW9CLENBQUM7UUFDM0MsZUFBVSxHQUFZLEtBQUssQ0FBQztRQUU1Qiw0QkFBNEI7UUFDNUIsZUFBVSxHQUFHLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUV2Qiw0QkFBNEI7UUFDNUIsY0FBUyxHQUFxQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFnQjlDLGNBQVMsR0FBRyxLQUFLLENBQUM7UUFZbEIsY0FBUyxHQUFHLEtBQUssQ0FBQztRQUVuQixnQkFBVyxHQUFXLGVBQWUsQ0FBQztRQUN0QyxjQUFTLEdBQVcsR0FBRyxDQUFDO1FBS3ZCLGNBQVMsR0FBRyxLQUFLLENBQUM7UUFjcEIsY0FBUyxHQUFHLElBQUksQ0FBQztRQXNCdkIsSUFBSSxDQUFDLEVBQUUsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBRWxCLElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ25CLElBQUksQ0FBQyxTQUFTLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQztRQUN0QyxDQUFDO0lBRUgsQ0FBQztJQUdELFdBQVc7UUFDVCxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQzNCLENBQUM7SUFFRCxXQUFXO1FBQ1QsSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUMvQixDQUFDO0lBRUQsU0FBUztRQUNQLElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ25CLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBQzFCLENBQUM7SUFDSCxDQUFDO0lBRUQsK0NBQStDO0lBQy9DLFVBQVUsQ0FBQyxLQUFzQjtRQUMvQixJQUFJLENBQUMsaUJBQWlCLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDaEMsQ0FBQztJQUVELCtDQUErQztJQUMvQyxnQkFBZ0IsQ0FBQyxFQUF3QjtRQUN2QyxJQUFJLENBQUMsU0FBUyxHQUFHLEVBQUUsQ0FBQztJQUN0QixDQUFDO0lBRUQsK0NBQStDO0lBQy9DLGlCQUFpQixDQUFDLEVBQWM7UUFDOUIsSUFBSSxDQUFDLFVBQVUsR0FBRyxFQUFFLENBQUM7SUFDdkIsQ0FBQztJQUVELCtDQUErQztJQUMvQyxnQkFBZ0IsQ0FBQyxVQUFtQjtRQUNsQyxJQUFJLENBQUMsUUFBUSxHQUFHLFVBQVUsQ0FBQztRQUMzQixJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQzNCLENBQUM7SUFFRCx5QkFBeUI7SUFDekIsS0FBSyxDQUFDLE9BQXNCO1FBQzFCLElBQUksQ0FBQyxjQUFjLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNuRCxDQUFDO0lBRUQsYUFBYSxDQUFDLFNBQWtCO1FBQzlCLElBQUksU0FBUyxLQUFLLElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxRQUFRLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1lBQ2pFLElBQUksQ0FBQyxPQUFPLEdBQUcsU0FBUyxDQUFDO1lBQ3pCLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDM0IsQ0FBQztJQUVILENBQUM7SUFFRCxnQ0FBZ0M7SUFDaEMsY0FBYztRQUNaLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNsQixJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVTLFdBQVc7UUFDbkIsSUFBSSxRQUFRLEdBQUksSUFBSSxDQUFDLGNBQWMsQ0FBQyxhQUFrQyxDQUFDLFFBQVEsQ0FBQztRQUNoRixPQUFPLFFBQVEsSUFBSSxRQUFRLENBQUMsUUFBUSxDQUFDO0lBQ3ZDLENBQUM7SUFFRCxJQUFJLEtBQUs7UUFDUCxPQUFPLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxhQUFhLENBQUMsS0FBSyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRTtZQUNwRSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUM7SUFDckIsQ0FBQztJQUVELElBQUksZ0JBQWdCO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUM7SUFDckMsQ0FBQztJQUVELGlCQUFpQixDQUFDLEdBQWE7UUFDN0IsSUFBSSxDQUFDLGdCQUFnQixHQUFHLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDeEMsQ0FBQztJQUVELGNBQWMsQ0FBQyxLQUFrQjtRQUMvQixJQUFJLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUN6QyxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ1YsS0FBSyxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3ZCLEtBQUssQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUMxQixDQUFDO1FBQ0QsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQ3hCLENBQUM7SUFFRCxXQUFXLENBQUMsUUFBa0I7UUFDNUIsSUFBSSxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3hCLE1BQU0sS0FBSyxHQUFnQixJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ3ZDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7Z0JBQ3pDLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQy9CLENBQUM7WUFDRCxJQUFJLENBQUMsaUJBQWlCLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDOUIsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBQ3ZCLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNuRCxDQUFDO0lBQ0gsQ0FBQztJQUVELGtEQUFrRDtJQUNsRCxnQkFBZ0IsQ0FBQyxLQUFpQixJQUFJLENBQUM7SUFBQSxDQUFDO0lBRWhDLGVBQWU7UUFDckIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUMsS0FBSyxHQUFHLEVBQUUsQ0FBQztJQUM5QyxDQUFDO0lBRU8saUJBQWlCLENBQUMsS0FBc0I7UUFDOUMsSUFBSSxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBQ2hCLElBQUksS0FBSyxFQUFFLENBQUM7WUFDVixJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDekIsSUFBSSxHQUFHLElBQUksQ0FBQyxTQUFTO29CQUNuQixDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQztvQkFDN0MsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7WUFDcEIsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLElBQUksR0FBRyxLQUFLLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1lBQ2hELENBQUM7UUFDSCxDQUFDO1FBRUQsSUFBSSxDQUFDLGNBQWMsQ0FBQyxhQUFhLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQztJQUNqRCxDQUFDO2tJQTlOVSx3QkFBd0I7c0hBQXhCLHdCQUF3Qix5VkFMeEI7WUFDVCxFQUFFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFDLEdBQUcsRUFBRSxDQUFDLHdCQUF3QixFQUFDLEVBQUU7U0FDMUYsbUVBVWEsbUJBQW1CLHFXQ25EbkMsazhCQWFvQjs7NEZEK0JQLHdCQUF3QjtrQkFicEMsU0FBUzsrQkFDRSxvQkFBb0IsaUJBR2YsaUJBQWlCLENBQUMsSUFBSSxRQUMvQjt3QkFDSixPQUFPLEVBQUUsb0JBQW9CO3FCQUM5QixhQUNVO3dCQUNULEVBQUUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLFdBQVcsRUFBRSxVQUFVLEVBQUMsR0FBRyxFQUFFLHlCQUF5QixFQUFDLEVBQUU7cUJBQzFGLFlBQ1Msb0JBQW9COzswQkErRjNCLFFBQVE7OzBCQUFJLElBQUk7OzBCQUNoQixRQUFROzswQkFDUixRQUFRO3lFQTVGdUMsYUFBYTtzQkFBOUQsU0FBUzt1QkFBQyxXQUFXLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFO2dCQUNXLGNBQWM7c0JBQWhFLFNBQVM7dUJBQUMsWUFBWSxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRTtnQkFHTixXQUFXO3NCQUE3QyxZQUFZO3VCQUFDLG1CQUFtQjtnQkFFeEIsS0FBSztzQkFBYixLQUFLO2dCQXFCRixRQUFRO3NCQURYLEtBQUs7Z0JBaUJGLEVBQUU7c0JBREwsS0FBSztnQkFNRixRQUFRO3NCQURYLEtBQUs7Z0JBT0csV0FBVztzQkFBbkIsS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLO2dCQUdGLFFBQVE7c0JBRFgsS0FBSztnQkFLRyxpQkFBaUI7c0JBQXpCLEtBQUs7Z0JBR0YsS0FBSztzQkFEUixLQUFLO2dCQVFGLFFBQVE7c0JBRFgsS0FBSztnQkFVRixNQUFNO3NCQURULEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjb2VyY2VCb29sZWFuUHJvcGVydHkgfSBmcm9tICdAYW5ndWxhci9jZGsvY29lcmNpb24nO1xyXG5pbXBvcnQgeyBQbGF0Zm9ybSB9IGZyb20gJ0Bhbmd1bGFyL2Nkay9wbGF0Zm9ybSc7XHJcbmltcG9ydCB7IENoYW5nZURldGVjdG9yUmVmLCBDb21wb25lbnQsIENvbnRlbnRDaGlsZCwgRGlyZWN0aXZlLCBEb0NoZWNrLCBFbGVtZW50UmVmLCBmb3J3YXJkUmVmLCBJbnB1dCwgT25EZXN0cm95LCBPcHRpb25hbCwgU2VsZiwgVmlld0NoaWxkLCBWaWV3RW5jYXBzdWxhdGlvbiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBDb250cm9sVmFsdWVBY2Nlc3NvciwgRm9ybUdyb3VwRGlyZWN0aXZlLCBOZ0NvbnRyb2wsIE5nRm9ybSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcclxuaW1wb3J0IHsgQ2FuVXBkYXRlRXJyb3JTdGF0ZSwgRXJyb3JTdGF0ZU1hdGNoZXIsIG1peGluRXJyb3JTdGF0ZSwgVGhlbWVQYWxldHRlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvY29yZSc7XHJcbmltcG9ydCB7IE1hdEZvcm1GaWVsZENvbnRyb2wgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9mb3JtLWZpZWxkJztcclxuaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyBGaWxlT3JBcnJheUZpbGUgfSBmcm9tICcuL2ZpbGUtaW5wdXQtdHlwZSc7XHJcblxyXG5sZXQgbmV4dFVuaXF1ZUlkID0gMDtcclxuXHJcbmNvbnN0IF9OZ3hNYXRJbnB1dE1peGluQmFzZSA9IG1peGluRXJyb3JTdGF0ZShcclxuICBjbGFzcyB7XHJcblxyXG4gICAgcmVhZG9ubHkgc3RhdGVDaGFuZ2VzID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcclxuXHJcbiAgICBjb25zdHJ1Y3RvcihcclxuICAgICAgcHVibGljIF9kZWZhdWx0RXJyb3JTdGF0ZU1hdGNoZXI6IEVycm9yU3RhdGVNYXRjaGVyLFxyXG4gICAgICBwdWJsaWMgX3BhcmVudEZvcm06IE5nRm9ybSxcclxuICAgICAgcHVibGljIF9wYXJlbnRGb3JtR3JvdXA6IEZvcm1Hcm91cERpcmVjdGl2ZSxcclxuICAgICAgLyoqIEBkb2NzLXByaXZhdGUgKi9cclxuICAgICAgcHVibGljIG5nQ29udHJvbDogTmdDb250cm9sLFxyXG4gICAgKSB7IH1cclxuICB9LFxyXG4pO1xyXG5cclxuQERpcmVjdGl2ZSh7XHJcbiAgc2VsZWN0b3I6ICdbbmd4TWF0RmlsZUlucHV0SWNvbl0nXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBOZ3hNYXRGaWxlSW5wdXRJY29uIHsgfVxyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICduZ3gtbWF0LWZpbGUtaW5wdXQnLFxyXG4gIHRlbXBsYXRlVXJsOiAnZmlsZS1pbnB1dC5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVVcmxzOiBbJ2ZpbGUtaW5wdXQuY29tcG9uZW50LnNjc3MnXSxcclxuICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lLFxyXG4gIGhvc3Q6IHtcclxuICAgICdjbGFzcyc6ICduZ3gtbWF0LWZpbGUtaW5wdXQnXHJcbiAgfSxcclxuICBwcm92aWRlcnM6IFtcclxuICAgIHsgcHJvdmlkZTogTWF0Rm9ybUZpZWxkQ29udHJvbCwgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gTmd4TWF0RmlsZUlucHV0Q29tcG9uZW50KSB9XHJcbiAgXSxcclxuICBleHBvcnRBczogJ25neC1tYXQtZmlsZS1pbnB1dCdcclxufSlcclxuZXhwb3J0IGNsYXNzIE5neE1hdEZpbGVJbnB1dENvbXBvbmVudCBleHRlbmRzIF9OZ3hNYXRJbnB1dE1peGluQmFzZSBpbXBsZW1lbnRzIE1hdEZvcm1GaWVsZENvbnRyb2w8RmlsZU9yQXJyYXlGaWxlPixcclxuICBPbkRlc3Ryb3ksIERvQ2hlY2ssIENhblVwZGF0ZUVycm9yU3RhdGUsIENvbnRyb2xWYWx1ZUFjY2Vzc29yIHtcclxuXHJcbiAgQFZpZXdDaGlsZCgnaW5wdXRGaWxlJywgeyBzdGF0aWM6IHRydWUgfSkgcHJpdmF0ZSBfaW5wdXRGaWxlUmVmOiBFbGVtZW50UmVmO1xyXG4gIEBWaWV3Q2hpbGQoJ2lucHV0VmFsdWUnLCB7IHN0YXRpYzogdHJ1ZSB9KSBwcml2YXRlIF9pbnB1dFZhbHVlUmVmOiBFbGVtZW50UmVmO1xyXG5cclxuICAvKiogQ3VzdG9tIGljb24gc2V0IGJ5IHRoZSBjb25zdW1lci4gKi9cclxuICBAQ29udGVudENoaWxkKE5neE1hdEZpbGVJbnB1dEljb24pIF9jdXN0b21JY29uOiBOZ3hNYXRGaWxlSW5wdXRJY29uO1xyXG5cclxuICBASW5wdXQoKSBjb2xvcjogVGhlbWVQYWxldHRlID0gJ3ByaW1hcnknO1xyXG5cclxuICBwdWJsaWMgZmlsZU5hbWVzOiBzdHJpbmcgPSBudWxsO1xyXG5cclxuICBwcm90ZWN0ZWQgX3VpZCA9IGBuZ3gtbWF0LWZpbGVpbnB1dC0ke25leHRVbmlxdWVJZCsrfWA7XHJcbiAgcHJvdGVjdGVkIF9wcmV2aW91c05hdGl2ZVZhbHVlOiBhbnk7XHJcbiAgX2FyaWFEZXNjcmliZWRieTogc3RyaW5nO1xyXG5cclxuICByZWFkb25seSBzdGF0ZUNoYW5nZXM6IFN1YmplY3Q8dm9pZD4gPSBuZXcgU3ViamVjdDx2b2lkPigpO1xyXG4gIGZvY3VzZWQ6IGJvb2xlYW4gPSBmYWxzZTtcclxuICBlcnJvclN0YXRlOiBib29sZWFuO1xyXG4gIGNvbnRyb2xUeXBlOiBzdHJpbmcgPSAnbmd4LW1hdC1maWxlLWlucHV0JztcclxuICBhdXRvZmlsbGVkOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gIC8qKiBGdW5jdGlvbiB3aGVuIHRvdWNoZWQgKi9cclxuICBfb25Ub3VjaGVkID0gKCkgPT4geyB9O1xyXG5cclxuICAvKiogRnVuY3Rpb24gd2hlbiBjaGFuZ2VkICovXHJcbiAgX29uQ2hhbmdlOiAodmFsdWU6IEZpbGVPckFycmF5RmlsZSkgPT4gdm9pZCA9ICgpID0+IHsgfTtcclxuXHJcbiAgQElucHV0KClcclxuICBnZXQgZGlzYWJsZWQoKTogYm9vbGVhbiB7XHJcbiAgICBpZiAodGhpcy5uZ0NvbnRyb2wgJiYgdGhpcy5uZ0NvbnRyb2wuZGlzYWJsZWQgIT09IG51bGwpIHtcclxuICAgICAgcmV0dXJuIHRoaXMubmdDb250cm9sLmRpc2FibGVkO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRoaXMuX2Rpc2FibGVkO1xyXG4gIH1cclxuICBzZXQgZGlzYWJsZWQodmFsdWU6IGJvb2xlYW4pIHtcclxuICAgIHRoaXMuX2Rpc2FibGVkID0gY29lcmNlQm9vbGVhblByb3BlcnR5KHZhbHVlKTtcclxuICAgIGlmICh0aGlzLmZvY3VzZWQpIHtcclxuICAgICAgdGhpcy5mb2N1c2VkID0gZmFsc2U7XHJcbiAgICAgIHRoaXMuc3RhdGVDaGFuZ2VzLm5leHQoKTtcclxuICAgIH1cclxuICB9XHJcbiAgcHJvdGVjdGVkIF9kaXNhYmxlZCA9IGZhbHNlO1xyXG5cclxuICBASW5wdXQoKVxyXG4gIGdldCBpZCgpOiBzdHJpbmcgeyByZXR1cm4gdGhpcy5faWQ7IH1cclxuICBzZXQgaWQodmFsdWU6IHN0cmluZykgeyB0aGlzLl9pZCA9IHZhbHVlIHx8IHRoaXMuX3VpZDsgfVxyXG4gIHByb3RlY3RlZCBfaWQ6IHN0cmluZztcclxuXHJcbiAgQElucHV0KClcclxuICBnZXQgbXVsdGlwbGUoKTogYm9vbGVhbiB7IHJldHVybiB0aGlzLl9tdWx0aXBsZTsgfVxyXG4gIHNldCBtdWx0aXBsZSh2YWx1ZTogYm9vbGVhbikge1xyXG4gICAgdGhpcy5fbXVsdGlwbGUgPSBjb2VyY2VCb29sZWFuUHJvcGVydHkodmFsdWUpO1xyXG4gIH1cclxuICBwcm90ZWN0ZWQgX211bHRpcGxlID0gZmFsc2U7XHJcblxyXG4gIEBJbnB1dCgpIHBsYWNlaG9sZGVyOiBzdHJpbmcgPSAnQ2hvb3NlIGEgZmlsZSc7XHJcbiAgQElucHV0KCkgc2VwYXJhdG9yOiBzdHJpbmcgPSAnLCc7XHJcblxyXG4gIEBJbnB1dCgpXHJcbiAgZ2V0IHJlcXVpcmVkKCk6IGJvb2xlYW4geyByZXR1cm4gdGhpcy5fcmVxdWlyZWQ7IH1cclxuICBzZXQgcmVxdWlyZWQodmFsdWU6IGJvb2xlYW4pIHsgdGhpcy5fcmVxdWlyZWQgPSBjb2VyY2VCb29sZWFuUHJvcGVydHkodmFsdWUpOyB9XHJcbiAgcHJvdGVjdGVkIF9yZXF1aXJlZCA9IGZhbHNlO1xyXG5cclxuICBASW5wdXQoKSBlcnJvclN0YXRlTWF0Y2hlcjogRXJyb3JTdGF0ZU1hdGNoZXI7XHJcblxyXG4gIEBJbnB1dCgpXHJcbiAgZ2V0IHZhbHVlKCk6IEZpbGVPckFycmF5RmlsZSB7IHJldHVybiB0aGlzLl92YWx1ZTsgfVxyXG4gIHNldCB2YWx1ZSh2YWx1ZTogRmlsZU9yQXJyYXlGaWxlKSB7XHJcbiAgICB0aGlzLl92YWx1ZSA9IHZhbHVlO1xyXG4gIH1cclxuICBwcm90ZWN0ZWQgX3ZhbHVlOiBGaWxlT3JBcnJheUZpbGU7XHJcblxyXG4gIEBJbnB1dCgpXHJcbiAgZ2V0IHJlYWRvbmx5KCk6IGJvb2xlYW4geyByZXR1cm4gdGhpcy5fcmVhZG9ubHk7IH1cclxuICBzZXQgcmVhZG9ubHkodmFsdWU6IGJvb2xlYW4pIHsgdGhpcy5fcmVhZG9ubHkgPSBjb2VyY2VCb29sZWFuUHJvcGVydHkodmFsdWUpOyB9XHJcbiAgcHJpdmF0ZSBfcmVhZG9ubHkgPSB0cnVlO1xyXG5cclxuICAvKipcclxuICAgKiBMaW1pdGluZyBhY2NlcHRlZCBmaWxlIHR5cGVzXHJcbiAgICogRXhhbXBsZTogYWNjZXB0PVwiaW1hZ2UvcG5nLCBpbWFnZS9qcGVnXCIgb3IgYWNjZXB0PVwiLnBuZywgLmpwZywgLmpwZWdcIiDigJQgQWNjZXB0IFBORyBvciBKUEVHIGZpbGVzLlxyXG4gICAqL1xyXG4gIEBJbnB1dCgpXHJcbiAgZ2V0IGFjY2VwdCgpOiBzdHJpbmcgeyByZXR1cm4gdGhpcy5fYWNjZXB0OyB9XHJcbiAgc2V0IGFjY2VwdCh2YWx1ZTogc3RyaW5nKSB7XHJcbiAgICB0aGlzLl9hY2NlcHQgPSB2YWx1ZTtcclxuICB9XHJcbiAgcHJpdmF0ZSBfYWNjZXB0OiBzdHJpbmc7XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByb3RlY3RlZCBfZWxlbWVudFJlZjogRWxlbWVudFJlZjxIVE1MSW5wdXRFbGVtZW50IHwgSFRNTFNlbGVjdEVsZW1lbnQgfCBIVE1MVGV4dEFyZWFFbGVtZW50PixcclxuICAgIHByb3RlY3RlZCBfcGxhdGZvcm06IFBsYXRmb3JtLFxyXG4gICAgcHJpdmF0ZSBfY2Q6IENoYW5nZURldGVjdG9yUmVmLFxyXG4gICAgQE9wdGlvbmFsKCkgQFNlbGYoKSBwdWJsaWMgbmdDb250cm9sOiBOZ0NvbnRyb2wsXHJcbiAgICBAT3B0aW9uYWwoKSBfcGFyZW50Rm9ybTogTmdGb3JtLFxyXG4gICAgQE9wdGlvbmFsKCkgX3BhcmVudEZvcm1Hcm91cDogRm9ybUdyb3VwRGlyZWN0aXZlLFxyXG4gICAgX2RlZmF1bHRFcnJvclN0YXRlTWF0Y2hlcjogRXJyb3JTdGF0ZU1hdGNoZXIpIHtcclxuICAgIHN1cGVyKF9kZWZhdWx0RXJyb3JTdGF0ZU1hdGNoZXIsIF9wYXJlbnRGb3JtLCBfcGFyZW50Rm9ybUdyb3VwLCBuZ0NvbnRyb2wpO1xyXG5cclxuICAgIHRoaXMuaWQgPSB0aGlzLmlkO1xyXG5cclxuICAgIGlmICh0aGlzLm5nQ29udHJvbCkge1xyXG4gICAgICB0aGlzLm5nQ29udHJvbC52YWx1ZUFjY2Vzc29yID0gdGhpcztcclxuICAgIH1cclxuXHJcbiAgfVxyXG5cclxuXHJcbiAgbmdPbkNoYW5nZXMoKSB7XHJcbiAgICB0aGlzLnN0YXRlQ2hhbmdlcy5uZXh0KCk7XHJcbiAgfVxyXG5cclxuICBuZ09uRGVzdHJveSgpIHtcclxuICAgIHRoaXMuc3RhdGVDaGFuZ2VzLmNvbXBsZXRlKCk7XHJcbiAgfVxyXG5cclxuICBuZ0RvQ2hlY2soKSB7XHJcbiAgICBpZiAodGhpcy5uZ0NvbnRyb2wpIHtcclxuICAgICAgdGhpcy51cGRhdGVFcnJvclN0YXRlKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBJbXBsZW1lbnRlZCBhcyBwYXJ0IG9mIENvbnRyb2xWYWx1ZUFjY2Vzc29yLlxyXG4gIHdyaXRlVmFsdWUodmFsdWU6IEZpbGVPckFycmF5RmlsZSk6IHZvaWQge1xyXG4gICAgdGhpcy5fdXBkYXRlSW5wdXRWYWx1ZSh2YWx1ZSk7XHJcbiAgfVxyXG5cclxuICAvLyBJbXBsZW1lbnRlZCBhcyBwYXJ0IG9mIENvbnRyb2xWYWx1ZUFjY2Vzc29yLlxyXG4gIHJlZ2lzdGVyT25DaGFuZ2UoZm46ICh2YWx1ZTogYW55KSA9PiB2b2lkKTogdm9pZCB7XHJcbiAgICB0aGlzLl9vbkNoYW5nZSA9IGZuO1xyXG4gIH1cclxuXHJcbiAgLy8gSW1wbGVtZW50ZWQgYXMgcGFydCBvZiBDb250cm9sVmFsdWVBY2Nlc3Nvci5cclxuICByZWdpc3Rlck9uVG91Y2hlZChmbjogKCkgPT4gdm9pZCk6IHZvaWQge1xyXG4gICAgdGhpcy5fb25Ub3VjaGVkID0gZm47XHJcbiAgfVxyXG5cclxuICAvLyBJbXBsZW1lbnRlZCBhcyBwYXJ0IG9mIENvbnRyb2xWYWx1ZUFjY2Vzc29yLlxyXG4gIHNldERpc2FibGVkU3RhdGUoaXNEaXNhYmxlZDogYm9vbGVhbik6IHZvaWQge1xyXG4gICAgdGhpcy5kaXNhYmxlZCA9IGlzRGlzYWJsZWQ7XHJcbiAgICB0aGlzLnN0YXRlQ2hhbmdlcy5uZXh0KCk7XHJcbiAgfVxyXG5cclxuICAvKiogRm9jdXNlcyB0aGUgaW5wdXQuICovXHJcbiAgZm9jdXMob3B0aW9ucz86IEZvY3VzT3B0aW9ucyk6IHZvaWQge1xyXG4gICAgdGhpcy5faW5wdXRWYWx1ZVJlZi5uYXRpdmVFbGVtZW50LmZvY3VzKG9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgX2ZvY3VzQ2hhbmdlZChpc0ZvY3VzZWQ6IGJvb2xlYW4pIHtcclxuICAgIGlmIChpc0ZvY3VzZWQgIT09IHRoaXMuZm9jdXNlZCAmJiAoIXRoaXMucmVhZG9ubHkgfHwgIWlzRm9jdXNlZCkpIHtcclxuICAgICAgdGhpcy5mb2N1c2VkID0gaXNGb2N1c2VkO1xyXG4gICAgICB0aGlzLnN0YXRlQ2hhbmdlcy5uZXh0KCk7XHJcbiAgICB9XHJcblxyXG4gIH1cclxuXHJcbiAgLyoqIE1hcmsgdGhlIGZpZWxkIGFzIHRvdWNoZWQgKi9cclxuICBfbWFya0FzVG91Y2hlZCgpIHtcclxuICAgIHRoaXMuX29uVG91Y2hlZCgpO1xyXG4gICAgdGhpcy5fY2QubWFya0ZvckNoZWNrKCk7XHJcbiAgICB0aGlzLnN0YXRlQ2hhbmdlcy5uZXh0KCk7XHJcbiAgfVxyXG5cclxuICBwcm90ZWN0ZWQgX2lzQmFkSW5wdXQoKSB7XHJcbiAgICBsZXQgdmFsaWRpdHkgPSAodGhpcy5faW5wdXRWYWx1ZVJlZi5uYXRpdmVFbGVtZW50IGFzIEhUTUxJbnB1dEVsZW1lbnQpLnZhbGlkaXR5O1xyXG4gICAgcmV0dXJuIHZhbGlkaXR5ICYmIHZhbGlkaXR5LmJhZElucHV0O1xyXG4gIH1cclxuXHJcbiAgZ2V0IGVtcHR5KCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuICF0aGlzLl9pbnB1dFZhbHVlUmVmLm5hdGl2ZUVsZW1lbnQudmFsdWUgJiYgIXRoaXMuX2lzQmFkSW5wdXQoKSAmJlxyXG4gICAgICAhdGhpcy5hdXRvZmlsbGVkO1xyXG4gIH1cclxuXHJcbiAgZ2V0IHNob3VsZExhYmVsRmxvYXQoKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gdGhpcy5mb2N1c2VkIHx8ICF0aGlzLmVtcHR5O1xyXG4gIH1cclxuXHJcbiAgc2V0RGVzY3JpYmVkQnlJZHMoaWRzOiBzdHJpbmdbXSkge1xyXG4gICAgdGhpcy5fYXJpYURlc2NyaWJlZGJ5ID0gaWRzLmpvaW4oJyAnKTtcclxuICB9XHJcblxyXG4gIG9wZW5GaWxlUGlja2VyKGV2ZW50PzogTW91c2VFdmVudCkge1xyXG4gICAgdGhpcy5faW5wdXRGaWxlUmVmLm5hdGl2ZUVsZW1lbnQuY2xpY2soKTtcclxuICAgIGlmIChldmVudCkge1xyXG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgIH1cclxuICAgIHRoaXMuX21hcmtBc1RvdWNoZWQoKTtcclxuICB9XHJcblxyXG4gIGhhbmRsZUZpbGVzKGZpbGVsaXN0OiBGaWxlTGlzdCkge1xyXG4gICAgaWYgKGZpbGVsaXN0Lmxlbmd0aCA+IDApIHtcclxuICAgICAgY29uc3QgZmlsZXM6IEFycmF5PEZpbGU+ID0gbmV3IEFycmF5KCk7XHJcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZmlsZWxpc3QubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICBmaWxlcy5wdXNoKGZpbGVsaXN0Lml0ZW0oaSkpO1xyXG4gICAgICB9XHJcbiAgICAgIHRoaXMuX3VwZGF0ZUlucHV0VmFsdWUoZmlsZXMpO1xyXG4gICAgICB0aGlzLl9yZXNldElucHV0RmlsZSgpO1xyXG4gICAgICB0aGlzLl9vbkNoYW5nZSh0aGlzLm11bHRpcGxlID8gZmlsZXMgOiBmaWxlc1swXSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKiogSGFuZGxlcyBhIGNsaWNrIG9uIHRoZSBjb250cm9sJ3MgY29udGFpbmVyLiAqL1xyXG4gIG9uQ29udGFpbmVyQ2xpY2soZXZlbnQ6IE1vdXNlRXZlbnQpIHsgfTtcclxuXHJcbiAgcHJpdmF0ZSBfcmVzZXRJbnB1dEZpbGUoKSB7XHJcbiAgICB0aGlzLl9pbnB1dEZpbGVSZWYubmF0aXZlRWxlbWVudC52YWx1ZSA9IFwiXCI7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIF91cGRhdGVJbnB1dFZhbHVlKGZpbGVzOiBGaWxlT3JBcnJheUZpbGUpIHtcclxuICAgIGxldCB0ZXh0ID0gbnVsbDtcclxuICAgIGlmIChmaWxlcykge1xyXG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShmaWxlcykpIHtcclxuICAgICAgICB0ZXh0ID0gdGhpcy5fbXVsdGlwbGVcclxuICAgICAgICAgID8gZmlsZXMubWFwKHggPT4geC5uYW1lKS5qb2luKHRoaXMuc2VwYXJhdG9yKVxyXG4gICAgICAgICAgOiBmaWxlc1swXS5uYW1lO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRleHQgPSBmaWxlcy5uYW1lICE9IG51bGwgPyBmaWxlcy5uYW1lIDogbnVsbDtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuX2lucHV0VmFsdWVSZWYubmF0aXZlRWxlbWVudC52YWx1ZSA9IHRleHQ7XHJcbiAgfVxyXG5cclxufVxyXG4iLCI8aW5wdXQgI2lucHV0VmFsdWUgYXV0b2NvbXBsZXRlPVwib2ZmXCJcclxuICBjbGFzcz1cIm1hdC1tZGMtaW5wdXQtZWxlbWVudCAgbWF0LW1kYy1mb3JtLWZpZWxkLWlucHV0LWNvbnRyb2wgbWRjLXRleHQtZmllbGRfX2lucHV0XCIgW2F0dHIuaWRdPSdpZCdcclxuICBbYXR0ci5wbGFjZWhvbGRlcl09J3BsYWNlaG9sZGVyJyBbZGlzYWJsZWRdPSdkaXNhYmxlZCcgW3JlcXVpcmVkXT0ncmVxdWlyZWQnIFthdHRyLnJlYWRvbmx5XT0ncmVhZG9ubHkgfHwgbnVsbCdcclxuICBbYXR0ci5hcmlhLWRlc2NyaWJlZGJ5XT0nX2FyaWFEZXNjcmliZWRieSB8fCBudWxsJyBbYXR0ci5hcmlhLWludmFsaWRdPSdlcnJvclN0YXRlJ1xyXG4gIFthdHRyLmFyaWEtcmVxdWlyZWRdPSdyZXF1aXJlZC50b1N0cmluZygpJz5cclxuPGRpdiBjbGFzcz1cIm1hdC1tZGMtZm9ybS1maWVsZC1zdWZmaXhcIj5cclxuICA8YnV0dG9uIG1hdFN1ZmZpeCBtYXQtaWNvbi1idXR0b24gW2NvbG9yXT1cImNvbG9yXCIgY2xhc3M9XCJidXR0b24tYnJvd3NlXCIgKGNsaWNrKT1cIm9wZW5GaWxlUGlja2VyKCRldmVudClcIiB0eXBlPVwiYnV0dG9uXCJcclxuICAgIFtkaXNhYmxlZF09XCJkaXNhYmxlZFwiPlxyXG4gICAgPG1hdC1pY29uICpuZ0lmPVwiIV9jdXN0b21JY29uXCIgY2xhc3M9XCJuZ3gtbWF0LWZpbGUtaW5wdXQtLWRlZmF1bHQtaWNvblwiPmF0dGFjaF9maWxlPC9tYXQtaWNvbj5cclxuICAgIDxuZy1jb250ZW50IHNlbGVjdD1cIltuZ3hNYXRGaWxlSW5wdXRJY29uXVwiPjwvbmctY29udGVudD5cclxuICA8L2J1dHRvbj5cclxuPC9kaXY+XHJcbjxpbnB1dCB0eXBlPVwiZmlsZVwiICNpbnB1dEZpbGUgKGNoYW5nZSk9XCJoYW5kbGVGaWxlcygkZXZlbnQudGFyZ2V0LmZpbGVzKVwiIGNsYXNzPVwiaW5wdXQtZmlsZVwiIFttdWx0aXBsZV09XCJtdWx0aXBsZVwiXHJcbiAgW2FjY2VwdF09XCJhY2NlcHRcIj4iXX0=