ngx-custom-numeric-range-form-field
Version:
Angular material numeric range form field
164 lines • 28.8 kB
JavaScript
import { ChangeDetectionStrategy, Component, EventEmitter, Host, Input, Output, Self } from '@angular/core';
import { FormControl } from '@angular/forms';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { NumericRangeFormService } from '../form/numeric-range-form.service';
import * as i0 from "@angular/core";
import * as i1 from "@angular/forms";
import * as i2 from "../form/numeric-range-form.service";
import * as i3 from "@angular/material/form-field";
import * as i4 from "../control/numeric-range-form-field-control.component";
import * as i5 from "@angular/material/icon";
import * as i6 from "@angular/common";
export class NumericRangeFormFieldContainerComponent {
constructor(controlDirective, formService, changeDetectorRef) {
this.controlDirective = controlDirective;
this.formService = formService;
this.changeDetectorRef = changeDetectorRef;
this.appearance = 'outline';
this.floatLabel = 'always';
this.minPlaceholder = 'From';
this.maxPlaceholder = 'To';
this.readonly = false;
this.minReadonly = false;
this.maxReadonly = false;
this.resettable = true;
this.requiredErrorMessage = 'Field is required!';
this.minimumErrorMessage = 'Minimum has been reached!';
this.maximumErrorMessage = 'Maximum has exceeded!';
this.invalidRangeErrorMessage = 'Inserted range is not valid!';
this.minimumControlName = 'minimum';
this.maximumControlName = 'maximum';
this.updateOn = 'change';
this.controlStyle = '';
this.blurred = new EventEmitter();
this.enterPressed = new EventEmitter();
this.numericRangeChanged = new EventEmitter();
this.formGroup = this.formService.formGroup;
this.control = new FormControl();
this.unsubscribe$ = new Subject();
this.onTouched = () => { };
this.controlDirective.valueAccessor = this;
}
get minimumControl() {
return this.formService.minimumControl;
}
get maximumControl() {
return this.formService.maximumControl;
}
ngOnInit() {
this.formService.init(this.minimumControlName, this.maximumControlName, this.updateOn);
this.setSyncValidator(this.controlDirective.control.validator);
this.setAsyncValidator(this.controlDirective.control.asyncValidator);
this.controlDirective.control.setValidators([this.validate.bind(this)]); // overrides the parent control validators by sending out errors from validate()
this.controlDirective.control.updateValueAndValidity({ emitEvent: false });
this.changeDetectorRef.detectChanges();
}
ngOnDestroy() {
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
writeValue(value) {
value === null
? this.control.reset()
: this.control.setValue(value, {
emitEvent: false
});
}
registerOnChange(fn) {
this.control.valueChanges.pipe(takeUntil(this.unsubscribe$)).subscribe(fn);
}
registerOnTouched(fn) {
this.onTouched = fn;
}
setDisabledState(isDisabled) {
isDisabled ? this.control.disable() : this.control.enable();
}
validate(control) {
const errors = {
...this.minimumControl.errors,
...this.maximumControl.errors
};
return Object.keys(errors).length ? errors : null;
}
onEnterPressed() {
this.enterPressed.emit();
}
onBlur() {
this.onTouched();
this.blurred.emit();
}
onRangeValuesChanged(value) {
this.numericRangeChanged.emit(value);
}
onReset() {
this.formGroup.reset();
}
setSyncValidator(validator) {
if (!validator) {
return;
}
this.control.addValidators(validator); // sets the validators from parent control
this.control.updateValueAndValidity();
}
setAsyncValidator(asyncValidator) {
if (!asyncValidator) {
return;
}
this.control.addAsyncValidators(asyncValidator);
this.control.updateValueAndValidity();
}
}
NumericRangeFormFieldContainerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: NumericRangeFormFieldContainerComponent, deps: [{ token: i1.NgControl, self: true }, { token: i2.NumericRangeFormService, host: true }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
NumericRangeFormFieldContainerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.5", type: NumericRangeFormFieldContainerComponent, selector: "ngx-numeric-range-form-field", inputs: { label: "label", appearance: "appearance", floatLabel: "floatLabel", minPlaceholder: "minPlaceholder", maxPlaceholder: "maxPlaceholder", readonly: "readonly", minReadonly: "minReadonly", maxReadonly: "maxReadonly", resettable: "resettable", required: "required", requiredErrorMessage: "requiredErrorMessage", minimumErrorMessage: "minimumErrorMessage", maximumErrorMessage: "maximumErrorMessage", invalidRangeErrorMessage: "invalidRangeErrorMessage", minimumControlName: "minimumControlName", maximumControlName: "maximumControlName", updateOn: "updateOn", controlStyle: "controlStyle" }, outputs: { blurred: "blurred", enterPressed: "enterPressed", numericRangeChanged: "numericRangeChanged" }, providers: [NumericRangeFormService], ngImport: i0, template: "<mat-form-field\r\n\t[appearance]=\"appearance\"\r\n\t[floatLabel]=\"floatLabel\"\r\n\tclass=\"numeric-range-field\"\r\n>\r\n\t<mat-label>{{ label }}</mat-label>\r\n\t<ngx-numeric-range-form-field-control\r\n\t\tid=\"numeric-range-form-control\"\r\n\t\t[style]=\"controlStyle\"\r\n\t\t[formControl]=\"control\"\r\n\t\t[minPlaceholder]=\"minPlaceholder\"\r\n\t\t[maxPlaceholder]=\"maxPlaceholder\"\r\n\t\t[readonly]=\"readonly\"\r\n\t\t[minReadonly]=\"minReadonly\"\r\n\t\t[maxReadonly]=\"maxReadonly\"\r\n\t\t[required]=\"required\"\r\n\t\t[minimumControlName]=\"minimumControlName\"\r\n\t\t[maximumControlName]=\"maximumControlName\"\r\n\t\t(blurred)=\"onBlur()\"\r\n\t\t(enterPressed)=\"onEnterPressed()\"\r\n\t\t(numericRangeChanged)=\"onRangeValuesChanged($event)\"\r\n\t></ngx-numeric-range-form-field-control>\r\n\r\n\t<mat-icon\r\n\t\t(click)=\"onReset()\"\r\n\t\t*ngIf=\"\r\n\t\t\tresettable &&\r\n\t\t\t!readonly &&\r\n\t\t\t!minReadonly &&\r\n\t\t\t!maxReadonly &&\r\n\t\t\t(minimumControl.value !== null || maximumControl.value !== null) &&\r\n\t\t\t!formGroup.disabled\r\n\t\t\"\r\n\t\tcolor=\"primary\"\r\n\t\tclass=\"pointer\"\r\n\t\tmatSuffix\r\n\t\t>close\r\n\t</mat-icon>\r\n\r\n\t<mat-error\r\n\t\t*ngIf=\"\r\n\t\t\tminimumControl.hasError('required') || maximumControl.hasError('required')\r\n\t\t\"\r\n\t>\r\n\t\t{{ requiredErrorMessage }}\r\n\t</mat-error>\r\n\r\n\t<mat-error\r\n\t\t*ngIf=\"minimumControl.hasError('min') || maximumControl.hasError('min')\"\r\n\t>\r\n\t\t{{ minimumErrorMessage }}\r\n\t</mat-error>\r\n\r\n\t<mat-error\r\n\t\t*ngIf=\"minimumControl.hasError('max') || maximumControl.hasError('max')\"\r\n\t>\r\n\t\t{{ maximumErrorMessage }}\r\n\t</mat-error>\r\n\r\n\t<mat-error\r\n\t\t*ngIf=\"\r\n\t\t\tformGroup.hasError('notValidRange') &&\r\n\t\t\t!minimumControl.errors &&\r\n\t\t\t!maximumControl.errors\r\n\t\t\"\r\n\t>\r\n\t\t{{ invalidRangeErrorMessage }}\r\n\t</mat-error>\r\n</mat-form-field>\r\n", styles: [":host .numeric-range-field{width:100%}:host mat-icon{cursor:context-menu}:host .pointer{cursor:pointer}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i4.NumericRangeFormFieldControlComponent, selector: "ngx-numeric-range-form-field-control", inputs: ["value", "placeholder", "minPlaceholder", "maxPlaceholder", "readonly", "minReadonly", "maxReadonly", "required", "disabled", "errorStateMatcher", "autofilled", "minimumControlName", "maximumControlName", "updateOn"], outputs: ["blurred", "enterPressed", "numericRangeChanged"] }, { type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i3.MatLabel, selector: "mat-label" }, { type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatSuffix, selector: "[matSuffix]" }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: NumericRangeFormFieldContainerComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-numeric-range-form-field', changeDetection: ChangeDetectionStrategy.OnPush, providers: [NumericRangeFormService], template: "<mat-form-field\r\n\t[appearance]=\"appearance\"\r\n\t[floatLabel]=\"floatLabel\"\r\n\tclass=\"numeric-range-field\"\r\n>\r\n\t<mat-label>{{ label }}</mat-label>\r\n\t<ngx-numeric-range-form-field-control\r\n\t\tid=\"numeric-range-form-control\"\r\n\t\t[style]=\"controlStyle\"\r\n\t\t[formControl]=\"control\"\r\n\t\t[minPlaceholder]=\"minPlaceholder\"\r\n\t\t[maxPlaceholder]=\"maxPlaceholder\"\r\n\t\t[readonly]=\"readonly\"\r\n\t\t[minReadonly]=\"minReadonly\"\r\n\t\t[maxReadonly]=\"maxReadonly\"\r\n\t\t[required]=\"required\"\r\n\t\t[minimumControlName]=\"minimumControlName\"\r\n\t\t[maximumControlName]=\"maximumControlName\"\r\n\t\t(blurred)=\"onBlur()\"\r\n\t\t(enterPressed)=\"onEnterPressed()\"\r\n\t\t(numericRangeChanged)=\"onRangeValuesChanged($event)\"\r\n\t></ngx-numeric-range-form-field-control>\r\n\r\n\t<mat-icon\r\n\t\t(click)=\"onReset()\"\r\n\t\t*ngIf=\"\r\n\t\t\tresettable &&\r\n\t\t\t!readonly &&\r\n\t\t\t!minReadonly &&\r\n\t\t\t!maxReadonly &&\r\n\t\t\t(minimumControl.value !== null || maximumControl.value !== null) &&\r\n\t\t\t!formGroup.disabled\r\n\t\t\"\r\n\t\tcolor=\"primary\"\r\n\t\tclass=\"pointer\"\r\n\t\tmatSuffix\r\n\t\t>close\r\n\t</mat-icon>\r\n\r\n\t<mat-error\r\n\t\t*ngIf=\"\r\n\t\t\tminimumControl.hasError('required') || maximumControl.hasError('required')\r\n\t\t\"\r\n\t>\r\n\t\t{{ requiredErrorMessage }}\r\n\t</mat-error>\r\n\r\n\t<mat-error\r\n\t\t*ngIf=\"minimumControl.hasError('min') || maximumControl.hasError('min')\"\r\n\t>\r\n\t\t{{ minimumErrorMessage }}\r\n\t</mat-error>\r\n\r\n\t<mat-error\r\n\t\t*ngIf=\"minimumControl.hasError('max') || maximumControl.hasError('max')\"\r\n\t>\r\n\t\t{{ maximumErrorMessage }}\r\n\t</mat-error>\r\n\r\n\t<mat-error\r\n\t\t*ngIf=\"\r\n\t\t\tformGroup.hasError('notValidRange') &&\r\n\t\t\t!minimumControl.errors &&\r\n\t\t\t!maximumControl.errors\r\n\t\t\"\r\n\t>\r\n\t\t{{ invalidRangeErrorMessage }}\r\n\t</mat-error>\r\n</mat-form-field>\r\n", styles: [":host .numeric-range-field{width:100%}:host mat-icon{cursor:context-menu}:host .pointer{cursor:pointer}\n"] }]
}], ctorParameters: function () { return [{ type: i1.NgControl, decorators: [{
type: Self
}] }, { type: i2.NumericRangeFormService, decorators: [{
type: Host
}] }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { label: [{
type: Input
}], appearance: [{
type: Input
}], floatLabel: [{
type: Input
}], minPlaceholder: [{
type: Input
}], maxPlaceholder: [{
type: Input
}], readonly: [{
type: Input
}], minReadonly: [{
type: Input
}], maxReadonly: [{
type: Input
}], resettable: [{
type: Input
}], required: [{
type: Input
}], requiredErrorMessage: [{
type: Input
}], minimumErrorMessage: [{
type: Input
}], maximumErrorMessage: [{
type: Input
}], invalidRangeErrorMessage: [{
type: Input
}], minimumControlName: [{
type: Input
}], maximumControlName: [{
type: Input
}], updateOn: [{
type: Input
}], controlStyle: [{
type: Input
}], blurred: [{
type: Output
}], enterPressed: [{
type: Output
}], numericRangeChanged: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnVtZXJpYy1yYW5nZS1mb3JtLWZpZWxkLWNvbnRhaW5lci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtbnVtZXJpYy1yYW5nZS1mb3JtLWZpZWxkL3NyYy9saWIvY29udGFpbmVyL251bWVyaWMtcmFuZ2UtZm9ybS1maWVsZC1jb250YWluZXIuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LW51bWVyaWMtcmFuZ2UtZm9ybS1maWVsZC9zcmMvbGliL2NvbnRhaW5lci9udW1lcmljLXJhbmdlLWZvcm0tZmllbGQtY29udGFpbmVyLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFDTix1QkFBdUIsRUFFdkIsU0FBUyxFQUNULFlBQVksRUFDWixJQUFJLEVBQ0osS0FBSyxFQUdMLE1BQU0sRUFDTixJQUFJLEVBQ0osTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUlOLFdBQVcsRUFNWCxNQUFNLGdCQUFnQixDQUFDO0FBS3hCLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzNDLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLG9DQUFvQyxDQUFDOzs7Ozs7OztBQVM3RSxNQUFNLE9BQU8sdUNBQXVDO0lBd0NuRCxZQUNpQixnQkFBMkIsRUFDM0IsV0FBb0MsRUFDNUMsaUJBQW9DO1FBRjVCLHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBVztRQUMzQixnQkFBVyxHQUFYLFdBQVcsQ0FBeUI7UUFDNUMsc0JBQWlCLEdBQWpCLGlCQUFpQixDQUFtQjtRQXhDcEMsZUFBVSxHQUEyQixTQUFTLENBQUM7UUFDL0MsZUFBVSxHQUFtQixRQUFRLENBQUM7UUFDdEMsbUJBQWMsR0FBRyxNQUFNLENBQUM7UUFDeEIsbUJBQWMs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bmd1bGFyL2Nkay9hMTF5L2lucHV0LW1vZGFsaXR5L2lucHV0LW1vZGFsaXR5LWRldGVjdG9yJztcclxuaW1wb3J0IHtcclxuXHRDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcclxuXHRDaGFuZ2VEZXRlY3RvclJlZixcclxuXHRDb21wb25lbnQsXHJcblx0RXZlbnRFbWl0dGVyLFxyXG5cdEhvc3QsXHJcblx0SW5wdXQsXHJcblx0T25EZXN0cm95LFxyXG5cdE9uSW5pdCxcclxuXHRPdXRwdXQsXHJcblx0U2VsZlxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQge1xyXG5cdEFic3RyYWN0Q29udHJvbCxcclxuXHRBc3luY1ZhbGlkYXRvckZuLFxyXG5cdENvbnRyb2xWYWx1ZUFjY2Vzc29yLFxyXG5cdEZvcm1Db250cm9sLFxyXG5cdEZvcm1Hcm91cCxcclxuXHROZ0NvbnRyb2wsXHJcblx0VmFsaWRhdGlvbkVycm9ycyxcclxuXHRWYWxpZGF0b3IsXHJcblx0VmFsaWRhdG9yRm5cclxufSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB7XHJcblx0RmxvYXRMYWJlbFR5cGUsXHJcblx0TWF0Rm9ybUZpZWxkQXBwZWFyYW5jZVxyXG59IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2Zvcm0tZmllbGQnO1xyXG5pbXBvcnQgeyBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuaW1wb3J0IHsgTnVtZXJpY1JhbmdlRm9ybVNlcnZpY2UgfSBmcm9tICcuLi9mb3JtL251bWVyaWMtcmFuZ2UtZm9ybS5zZXJ2aWNlJztcclxuXHJcbkBDb21wb25lbnQoe1xyXG5cdHNlbGVjdG9yOiAnbmd4LW51bWVyaWMtcmFuZ2UtZm9ybS1maWVsZCcsXHJcblx0dGVtcGxhdGVVcmw6ICcuL251bWVyaWMtcmFuZ2UtZm9ybS1maWVsZC1jb250YWluZXIuY29tcG9uZW50Lmh0bWwnLFxyXG5cdHN0eWxlVXJsczogWycuL251bWVyaWMtcmFuZ2UtZm9ybS1maWVsZC1jb250YWluZXIuY29tcG9uZW50LnNjc3MnXSxcclxuXHRjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcclxuXHRwcm92aWRlcnM6IFtOdW1lcmljUmFuZ2VGb3JtU2VydmljZV1cclxufSlcclxuZXhwb3J0IGNsYXNzIE51bWVyaWNSYW5nZUZvcm1GaWVsZENvbnRhaW5lckNvbXBvbmVudFxyXG5cdGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3ksIENvbnRyb2xWYWx1ZUFjY2Vzc29yLCBWYWxpZGF0b3Ige1xyXG5cdEBJbnB1dCgpIGxhYmVsOiBzdHJpbmc7XHJcblx0QElucHV0KCkgYXBwZWFyYW5jZTogTWF0Rm9ybUZpZWxkQXBwZWFyYW5jZSA9ICdvdXRsaW5lJztcclxuXHRASW5wdXQoKSBmbG9hdExhYmVsOiBGbG9hdExhYmVsVHlwZSA9ICdhbHdheXMnO1xyXG5cdEBJbnB1dCgpIG1pblBsYWNlaG9sZGVyID0gJ0Zyb20nO1xyXG5cdEBJbnB1dCgpIG1heFBsYWNlaG9sZGVyID0gJ1RvJztcclxuXHRASW5wdXQoKSByZWFkb25seSA9IGZhbHNlO1xyXG5cdEBJbnB1dCgpIG1pblJlYWRvbmx5ID0gZmFsc2U7XHJcblx0QElucHV0KCkgbWF4UmVhZG9ubHkgPSBmYWxzZTtcclxuXHRASW5wdXQoKSByZXNldHRhYmxlID0gdHJ1ZTtcclxuXHRASW5wdXQoKSByZXF1aXJlZDogYm9vbGVhbjtcclxuXHRASW5wdXQoKSByZXF1aXJlZEVycm9yTWVzc2FnZSA9ICdGaWVsZCBpcyByZXF1aXJlZCEnO1xyXG5cdEBJbnB1dCgpIG1pbmltdW1FcnJvck1lc3NhZ2UgPSAnTWluaW11bSBoYXMgYmVlbiByZWFjaGVkISc7XHJcblx0QElucHV0KCkgbWF4aW11bUVycm9yTWVzc2FnZSA9ICdNYXhpbXVtIGhhcyBleGNlZWRlZCEnO1xyXG5cdEBJbnB1dCgpIGludmFsaWRSYW5nZUVycm9yTWVzc2FnZSA9ICdJbnNlcnRlZCByYW5nZSBpcyBub3QgdmFsaWQhJztcclxuXHRASW5wdXQoKSBtaW5pbXVtQ29udHJvbE5hbWUgPSAnbWluaW11bSc7XHJcblx0QElucHV0KCkgbWF4aW11bUNvbnRyb2xOYW1lID0gJ21heGltdW0nO1xyXG5cdEBJbnB1dCgpIHVwZGF0ZU9uOiAnY2hhbmdlJyB8ICdibHVyJyB8ICdzdWJtaXQnID0gJ2NoYW5nZSc7XHJcblx0QElucHV0KCkgY29udHJvbFN0eWxlID0gJyc7XHJcblxyXG5cdEBPdXRwdXQoKSBibHVycmVkID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xyXG5cdEBPdXRwdXQoKSBlbnRlclByZXNzZWQgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XHJcblx0QE91dHB1dCgpIG51bWVyaWNSYW5nZUNoYW5nZWQgPSBuZXcgRXZlbnRFbWl0dGVyPGFueT4oKTtcclxuXHJcblx0Zm9ybUdyb3VwOiBGb3JtR3JvdXAgPSB0aGlzLmZvcm1TZXJ2aWNlLmZvcm1Hcm91cDtcclxuXHRjb250cm9sID0gbmV3IEZvcm1Db250cm9sKCk7XHJcblxyXG5cdHByaXZhdGUgdW5zdWJzY3JpYmUkID0gbmV3IFN1YmplY3QoKTtcclxuXHJcblx0b25Ub3VjaGVkID0gKCkgPT4ge307XHJcblxyXG5cdGdldCBtaW5pbXVtQ29udHJvbCgpOiBGb3JtQ29udHJvbCB7XHJcblx0XHRyZXR1cm4gdGhpcy5mb3JtU2VydmljZS5taW5pbXVtQ29udHJvbDtcclxuXHR9XHJcblxyXG5cdGdldCBtYXhpbXVtQ29udHJvbCgpOiBGb3JtQ29udHJvbCB7XHJcblx0XHRyZXR1cm4gdGhpcy5mb3JtU2VydmljZS5tYXhpbXVtQ29udHJvbDtcclxuXHR9XHJcblxyXG5cdGNvbnN0cnVjdG9yKFxyXG5cdFx0QFNlbGYoKSBwcml2YXRlIGNvbnRyb2xEaXJlY3RpdmU6IE5nQ29udHJvbCxcclxuXHRcdEBIb3N0KCkgcHJpdmF0ZSBmb3JtU2VydmljZTogTnVtZXJpY1JhbmdlRm9ybVNlcnZpY2UsXHJcblx0XHRwcml2YXRlIGNoYW5nZURldGVjdG9yUmVmOiBDaGFuZ2VEZXRlY3RvclJlZlxyXG5cdCkge1xyXG5cdFx0dGhpcy5jb250cm9sRGlyZWN0aXZlLnZhbHVlQWNjZXNzb3IgPSB0aGlzO1xyXG5cdH1cclxuXHJcblx0bmdPbkluaXQoKTogdm9pZCB7XHJcblx0XHR0aGlzLmZvcm1TZXJ2aWNlLmluaXQoXHJcblx0XHRcdHRoaXMubWluaW11bUNvbnRyb2xOYW1lLFxyXG5cdFx0XHR0aGlzLm1heGltdW1Db250cm9sTmFtZSxcclxuXHRcdFx0dGhpcy51cGRhdGVPbik7XHJcblx0XHR0aGlzLnNldFN5bmNWYWxpZGF0b3IodGhpcy5jb250cm9sRGlyZWN0aXZlLmNvbnRyb2wudmFsaWRhdG9yKTtcclxuXHRcdHRoaXMuc2V0QXN5bmNWYWxpZGF0b3IodGhpcy5jb250cm9sRGlyZWN0aXZlLmNvbnRyb2wuYXN5bmNWYWxpZGF0b3IpO1xyXG5cclxuXHRcdHRoaXMuY29udHJvbERpcmVjdGl2ZS5jb250cm9sLnNldFZhbGlkYXRvcnMoW3RoaXMudmFsaWRhdGUuYmluZCh0aGlzKV0pOyAvLyBvdmVycmlkZXMgdGhlIHBhcmVudCBjb250cm9sIHZhbGlkYXRvcnMgYnkgc2VuZGluZyBvdXQgZXJyb3JzIGZyb20gdmFsaWRhdGUoKVxyXG5cdFx0dGhpcy5jb250cm9sRGlyZWN0aXZlLmNvbnRyb2wudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSh7IGVtaXRFdmVudDogZmFsc2UgfSk7XHJcblxyXG5cdFx0dGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5kZXRlY3RDaGFuZ2VzKCk7XHJcblx0fVxyXG5cclxuXHRuZ09uRGVzdHJveSgpOiB2b2lkIHtcclxuXHRcdHRoaXMudW5zdWJzY3JpYmUkLm5leHQoKTtcclxuXHRcdHRoaXMudW5zdWJzY3JpYmUkLmNvbXBsZXRlKCk7XHJcblx0fVxyXG5cclxuXHR3cml0ZVZhbHVlKHZhbHVlOiBhbnkpOiB2b2lkIHtcclxuXHRcdHZhbHVlID09PSBudWxsXHJcblx0XHRcdD8gdGhpcy5jb250cm9sLnJlc2V0KClcclxuXHRcdFx0OiB0aGlzLmNvbnRyb2wuc2V0VmFsdWUodmFsdWUsIHtcclxuXHRcdFx0XHRcdGVtaXRFdmVudDogZmFsc2VcclxuXHRcdFx0ICB9KTtcclxuXHR9XHJcblxyXG5cdHJlZ2lzdGVyT25DaGFuZ2UoZm46IGFueSk6IHZvaWQge1xyXG5cdFx0dGhpcy5jb250cm9sLnZhbHVlQ2hhbmdlcy5waXBlKHRha2VVbnRpbCh0aGlzLnVuc3Vic2NyaWJlJCkpLnN1YnNjcmliZShmbik7XHJcblx0fVxyXG5cclxuXHRyZWdpc3Rlck9uVG91Y2hlZChmbjogYW55KTogdm9pZCB7XHJcblx0XHR0aGlzLm9uVG91Y2hlZCA9IGZuO1xyXG5cdH1cclxuXHJcblx0c2V0RGlzYWJsZWRTdGF0ZShpc0Rpc2FibGVkOiBib29sZWFuKTogdm9pZCB7XHJcblx0XHRpc0Rpc2FibGVkID8gdGhpcy5jb250cm9sLmRpc2FibGUoKSA6IHRoaXMuY29udHJvbC5lbmFibGUoKTtcclxuXHR9XHJcblxyXG5cdHZhbGlkYXRlKGNvbnRyb2w6IEFic3RyYWN0Q29udHJvbCk6IFZhbGlkYXRpb25FcnJvcnMgfCBudWxsIHtcclxuXHRcdGNvbnN0IGVycm9ycyA9IHtcclxuXHRcdFx0Li4udGhpcy5taW5pbXVtQ29udHJvbC5lcnJvcnMsXHJcblx0XHRcdC4uLnRoaXMubWF4aW11bUNvbnRyb2wuZXJyb3JzXHJcblx0XHR9O1xyXG5cdFx0cmV0dXJuIE9iamVjdC5rZXlzKGVycm9ycykubGVuZ3RoID8gZXJyb3JzIDogbnVsbDtcclxuXHR9XHJcblxyXG5cdG9uRW50ZXJQcmVzc2VkKCk6IHZvaWQge1xyXG5cdFx0dGhpcy5lbnRlclByZXNzZWQuZW1pdCgpO1xyXG5cdH1cclxuXHJcblx0b25CbHVyKCk6IHZvaWQge1xyXG5cdFx0dGhpcy5vblRvdWNoZWQoKTtcclxuXHRcdHRoaXMuYmx1cnJlZC5lbWl0KCk7XHJcblx0fVxyXG5cclxuXHRvblJhbmdlVmFsdWVzQ2hhbmdlZCh2YWx1ZTogYW55KTogdm9pZCB7XHJcblx0XHR0aGlzLm51bWVyaWNSYW5nZUNoYW5nZWQuZW1pdCh2YWx1ZSk7XHJcblx0fVxyXG5cclxuXHRvblJlc2V0KCk6IHZvaWQge1xyXG5cdFx0dGhpcy5mb3JtR3JvdXAucmVzZXQoKTtcclxuXHR9XHJcblxyXG5cdHByaXZhdGUgc2V0U3luY1ZhbGlkYXRvcih2YWxpZGF0b3I6IFZhbGlkYXRvckZuKTogdm9pZCB7XHJcblx0XHRpZiAoIXZhbGlkYXRvcikge1xyXG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5jb250cm9sLmFkZFZhbGlkYXRvcnModmFsaWRhdG9yKTsgLy8gc2V0cyB0aGUgdmFsaWRhdG9ycyBmcm9tIHBhcmVudCBjb250cm9sXHJcblx0XHR0aGlzLmNvbnRyb2wudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSgpO1xyXG5cdH1cclxuXHJcblx0cHJpdmF0ZSBzZXRBc3luY1ZhbGlkYXRvcihhc3luY1ZhbGlkYXRvcjogQXN5bmNWYWxpZGF0b3JGbik6IHZvaWQge1xyXG5cdFx0aWYgKCFhc3luY1ZhbGlkYXRvcikge1xyXG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5jb250cm9sLmFkZEFzeW5jVmFsaWRhdG9ycyhhc3luY1ZhbGlkYXRvcik7XHJcblx0XHR0aGlzLmNvbnRyb2wudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSgpO1xyXG5cdH1cclxufVxyXG4iLCI8bWF0LWZvcm0tZmllbGRcclxuXHRbYXBwZWFyYW5jZV09XCJhcHBlYXJhbmNlXCJcclxuXHRbZmxvYXRMYWJlbF09XCJmbG9hdExhYmVsXCJcclxuXHRjbGFzcz1cIm51bWVyaWMtcmFuZ2UtZmllbGRcIlxyXG4+XHJcblx0PG1hdC1sYWJlbD57eyBsYWJlbCB9fTwvbWF0LWxhYmVsPlxyXG5cdDxuZ3gtbnVtZXJpYy1yYW5nZS1mb3JtLWZpZWxkLWNvbnRyb2xcclxuXHRcdGlkPVwibnVtZXJpYy1yYW5nZS1mb3JtLWNvbnRyb2xcIlxyXG5cdFx0W3N0eWxlXT1cImNvbnRyb2xTdHlsZVwiXHJcblx0XHRbZm9ybUNvbnRyb2xdPVwiY29udHJvbFwiXHJcblx0XHRbbWluUGxhY2Vob2xkZXJdPVwibWluUGxhY2Vob2xkZXJcIlxyXG5cdFx0W21heFBsYWNlaG9sZGVyXT1cIm1heFBsYWNlaG9sZGVyXCJcclxuXHRcdFtyZWFkb25seV09XCJyZWFkb25seVwiXHJcblx0XHRbbWluUmVhZG9ubHldPVwibWluUmVhZG9ubHlcIlxyXG5cdFx0W21heFJlYWRvbmx5XT1cIm1heFJlYWRvbmx5XCJcclxuXHRcdFtyZXF1aXJlZF09XCJyZXF1aXJlZFwiXHJcblx0XHRbbWluaW11bUNvbnRyb2xOYW1lXT1cIm1pbmltdW1Db250cm9sTmFtZVwiXHJcblx0XHRbbWF4aW11bUNvbnRyb2xOYW1lXT1cIm1heGltdW1Db250cm9sTmFtZVwiXHJcblx0XHQoYmx1cnJlZCk9XCJvbkJsdXIoKVwiXHJcblx0XHQoZW50ZXJQcmVzc2VkKT1cIm9uRW50ZXJQcmVzc2VkKClcIlxyXG5cdFx0KG51bWVyaWNSYW5nZUNoYW5nZWQpPVwib25SYW5nZVZhbHVlc0NoYW5nZWQoJGV2ZW50KVwiXHJcblx0Pjwvbmd4LW51bWVyaWMtcmFuZ2UtZm9ybS1maWVsZC1jb250cm9sPlxyXG5cclxuXHQ8bWF0LWljb25cclxuXHRcdChjbGljayk9XCJvblJlc2V0KClcIlxyXG5cdFx0Km5nSWY9XCJcclxuXHRcdFx0cmVzZXR0YWJsZSAmJlxyXG5cdFx0XHQhcmVhZG9ubHkgJiZcclxuXHRcdFx0IW1pblJlYWRvbmx5ICYmXHJcblx0XHRcdCFtYXhSZWFkb25seSAmJlxyXG5cdFx0XHQobWluaW11bUNvbnRyb2wudmFsdWUgIT09IG51bGwgfHwgbWF4aW11bUNvbnRyb2wudmFsdWUgIT09IG51bGwpICYmXHJcblx0XHRcdCFmb3JtR3JvdXAuZGlzYWJsZWRcclxuXHRcdFwiXHJcblx0XHRjb2xvcj1cInByaW1hcnlcIlxyXG5cdFx0Y2xhc3M9XCJwb2ludGVyXCJcclxuXHRcdG1hdFN1ZmZpeFxyXG5cdFx0PmNsb3NlXHJcblx0PC9tYXQtaWNvbj5cclxuXHJcblx0PG1hdC1lcnJvclxyXG5cdFx0Km5nSWY9XCJcclxuXHRcdFx0bWluaW11bUNvbnRyb2wuaGFzRXJyb3IoJ3JlcXVpcmVkJykgfHwgbWF4aW11bUNvbnRyb2wuaGFzRXJyb3IoJ3JlcXVpcmVkJylcclxuXHRcdFwiXHJcblx0PlxyXG5cdFx0e3sgcmVxdWlyZWRFcnJvck1lc3NhZ2UgfX1cclxuXHQ8L21hdC1lcnJvcj5cclxuXHJcblx0PG1hdC1lcnJvclxyXG5cdFx0Km5nSWY9XCJtaW5pbXVtQ29udHJvbC5oYXNFcnJvcignbWluJykgfHwgbWF4aW11bUNvbnRyb2wuaGFzRXJyb3IoJ21pbicpXCJcclxuXHQ+XHJcblx0XHR7eyBtaW5pbXVtRXJyb3JNZXNzYWdlIH19XHJcblx0PC9tYXQtZXJyb3I+XHJcblxyXG5cdDxtYXQtZXJyb3JcclxuXHRcdCpuZ0lmPVwibWluaW11bUNvbnRyb2wuaGFzRXJyb3IoJ21heCcpIHx8IG1heGltdW1Db250cm9sLmhhc0Vycm9yKCdtYXgnKVwiXHJcblx0PlxyXG5cdFx0e3sgbWF4aW11bUVycm9yTWVzc2FnZSB9fVxyXG5cdDwvbWF0LWVycm9yPlxyXG5cclxuXHQ8bWF0LWVycm9yXHJcblx0XHQqbmdJZj1cIlxyXG5cdFx0XHRmb3JtR3JvdXAuaGFzRXJyb3IoJ25vdFZhbGlkUmFuZ2UnKSAmJlxyXG5cdFx0XHQhbWluaW11bUNvbnRyb2wuZXJyb3JzICYmXHJcblx0XHRcdCFtYXhpbXVtQ29udHJvbC5lcnJvcnNcclxuXHRcdFwiXHJcblx0PlxyXG5cdFx0e3sgaW52YWxpZFJhbmdlRXJyb3JNZXNzYWdlIH19XHJcblx0PC9tYXQtZXJyb3I+XHJcbjwvbWF0LWZvcm0tZmllbGQ+XHJcbiJdfQ==