UNPKG

@ux-aspects/ux-aspects

Version:

Open source user interface framework for building modern, responsive, mobile big data applications

224 lines 34.5 kB
import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, HostListener, Input, Output, forwardRef, inject, } from '@angular/core'; import { FormGroupDirective, NG_VALUE_ACCESSOR } from '@angular/forms'; import * as i0 from "@angular/core"; import * as i1 from "../icon/icon.component"; import * as i2 from "@angular/forms"; let uniqueId = 0; export const NUMBER_PICKER_VALUE_ACCESSOR = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NumberPickerComponent), multi: true, }; export class NumberPickerComponent { constructor() { this._formGroup = inject(FormGroupDirective, { optional: true }); this._changeDetector = inject(ChangeDetectorRef); this._step = 1; this._disabled = false; this._value = 0; this._focused = false; // eslint-disable-next-line @typescript-eslint/no-empty-function this._propagateChange = (_) => { }; // eslint-disable-next-line @typescript-eslint/no-empty-function this._touchedChange = () => { }; /** Sets the id of the number picker. The child input will have this value with a -input suffix as its id. */ this.id = `ux-number-picker-${uniqueId++}`; /** Define the precision of floating point values */ this.precision = Number.MAX_SAFE_INTEGER.toString().length - 1; /** If two way binding is used this value will be updated any time the number picker value changes. */ this.valueChange = new EventEmitter(); /** Store the current valid state */ this._valid = true; /** This is a flag to indicate when the component has been destroyed to avoid change detection being made after the component * is no longer instantiated. A workaround for Angular Forms bug (https://github.com/angular/angular/issues/27803) */ this._isDestroyed = false; this._readonly = false; } /** Specified if this is a readonly input. */ set readonly(value) { this._readonly = coerceBooleanProperty(value); } get readonly() { return this._readonly; } /** Sets the value displayed in the number picker component. */ get value() { return this._value; } set value(value) { if (this._value !== value) { this._value = value; this._valid = this.isValid(); } } /** Defines the minimum value the number picker can set. */ get min() { return this._min; } set min(value) { this._min = coerceNumberProperty(value); } /** Defines the maximum value the number picker can set. */ get max() { return this._max; } set max(value) { this._max = coerceNumberProperty(value); } /** Defines the amount the number picker should increase or decrease when the buttons or arrow keys are used. */ set step(value) { if (typeof value === 'function') { this._step = value; } else { this._step = coerceNumberProperty(value); } } /** Indicate if the number picker is disabled or not. */ get disabled() { return this._disabled; } set disabled(value) { this._disabled = coerceBooleanProperty(value); } get inputId() { return this.id + '-input'; } ngOnChanges() { this._valid = this.isValid(); } ngOnDestroy() { this._isDestroyed = true; } getStep(direction) { return typeof this._step === 'number' ? this._step : this._step(this.value, direction); } increment(event) { if (event) { event.preventDefault(); } if (!this.disabled && !this.readonly) { this.value = Math.max(Math.min(this.value + this.getStep(StepDirection.Increment), this.getMaxValueForComparison()), this.getMinValueForComparison()); // account for javascripts terrible handling of floating point numbers this.value = parseFloat(this.value.toPrecision(this.precision)); // emit the value to the Output and Angular forms this._emitValueChange(this.value); } } decrement(event) { if (event) { event.preventDefault(); } if (!this.disabled && !this.readonly) { this.value = Math.min(Math.max(this.value - this.getStep(StepDirection.Decrement), this.getMinValueForComparison()), this.getMaxValueForComparison()); // account for javascripts terrible handling of floating point numbers this.value = parseFloat(this.value.toPrecision(this.precision)); // emit the value to the Output and Angular forms this._emitValueChange(this.value); } } isValid() { return (this.value >= this.getMinValueForComparison() && this.value <= this.getMaxValueForComparison()); } onScroll(event) { if (!this._focused) { return; } // get the distance scrolled const scrollValue = event.deltaY || event.wheelDelta; // increment or decrement accordingly scrollValue < 0 ? this.increment(event) : this.decrement(event); } writeValue(value) { if (value !== undefined) { this._value = value; this._valid = this.isValid(); // if the component is not destroyed then run change detection // workaround for Angular bug (https://portal.digitalsafe.net/browse/EL-3694) if (!this._isDestroyed) { this._changeDetector.detectChanges(); } } } registerOnChange(fn) { this._propagateChange = fn; } registerOnTouched(fn) { this._touchedChange = fn; } setDisabledState(isDisabled) { this.disabled = isDisabled; this._changeDetector.markForCheck(); } /** Set the value and emit the change to the output and Angular forms. */ _emitValueChange(value) { // This is a workaround for angular bug https://github.com/angular/angular/issues/12540 if (value === this._lastValue) { return; } this._lastValue = value; this.valueChange.emit(value); this._propagateChange(value); } getMaxValueForComparison() { return this.max === undefined || this.max === null ? Infinity : this.max; } getMinValueForComparison() { return this.min === undefined || this.min === null ? -Infinity : this.min; } onFocusIn() { this._focused = true; } onFocusOut() { this._focused = false; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: NumberPickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.12", type: NumberPickerComponent, selector: "ux-number-picker, ux-number-picker-inline", inputs: { id: "id", ariaLabel: ["aria-label", "ariaLabel"], labelledBy: ["aria-labelledby", "labelledBy"], precision: "precision", placeholder: "placeholder", required: "required", readonly: "readonly", value: "value", min: "min", max: "max", step: "step", disabled: "disabled" }, outputs: { valueChange: "valueChange" }, host: { listeners: { "focusin": "onFocusIn()", "focusout": "onFocusOut()" }, properties: { "class.ux-number-picker-invalid": "!_valid && !disabled && !_formGroup" } }, providers: [NUMBER_PICKER_VALUE_ACCESSOR], usesOnChanges: true, ngImport: i0, template: "<input\n type=\"number\"\n [id]=\"inputId\"\n role=\"spinbutton\"\n class=\"form-control number-picker-input\"\n [(ngModel)]=\"value\"\n (ngModelChange)=\"_emitValueChange($event)\"\n [min]=\"min\"\n [max]=\"max\"\n [required]=\"required\"\n [attr.placeholder]=\"placeholder\"\n [readonly]=\"readonly\"\n (blur)=\"_touchedChange()\"\n (keydown.ArrowDown)=\"decrement($event)\"\n (keydown.ArrowUp)=\"increment($event)\"\n (wheel)=\"onScroll($event)\"\n step=\"any\"\n [disabled]=\"disabled\"\n [attr.aria-valuemin]=\"min\"\n [attr.aria-valuenow]=\"value\"\n [attr.aria-valuemax]=\"max\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-labelledby]=\"labelledBy\"\n/>\n\n<div class=\"number-picker-controls\">\n <div\n class=\"number-picker-control number-picker-control-up\"\n (click)=\"increment($event); _touchedChange()\"\n [class.disabled]=\"disabled || value >= max || readonly\"\n >\n <ux-icon name=\"up\"></ux-icon>\n </div>\n\n <div\n class=\"number-picker-control number-picker-control-down\"\n (click)=\"decrement($event); _touchedChange()\"\n [class.disabled]=\"disabled || value <= min || readonly\"\n >\n <ux-icon name=\"down\"></ux-icon>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: i1.IconComponent, selector: "ux-icon", inputs: ["name", "size", "rotate", "flipHorizontal", "flipVertical"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: NumberPickerComponent, decorators: [{ type: Component, args: [{ selector: 'ux-number-picker, ux-number-picker-inline', providers: [NUMBER_PICKER_VALUE_ACCESSOR], changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class.ux-number-picker-invalid]': '!_valid && !disabled && !_formGroup', }, template: "<input\n type=\"number\"\n [id]=\"inputId\"\n role=\"spinbutton\"\n class=\"form-control number-picker-input\"\n [(ngModel)]=\"value\"\n (ngModelChange)=\"_emitValueChange($event)\"\n [min]=\"min\"\n [max]=\"max\"\n [required]=\"required\"\n [attr.placeholder]=\"placeholder\"\n [readonly]=\"readonly\"\n (blur)=\"_touchedChange()\"\n (keydown.ArrowDown)=\"decrement($event)\"\n (keydown.ArrowUp)=\"increment($event)\"\n (wheel)=\"onScroll($event)\"\n step=\"any\"\n [disabled]=\"disabled\"\n [attr.aria-valuemin]=\"min\"\n [attr.aria-valuenow]=\"value\"\n [attr.aria-valuemax]=\"max\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-labelledby]=\"labelledBy\"\n/>\n\n<div class=\"number-picker-controls\">\n <div\n class=\"number-picker-control number-picker-control-up\"\n (click)=\"increment($event); _touchedChange()\"\n [class.disabled]=\"disabled || value >= max || readonly\"\n >\n <ux-icon name=\"up\"></ux-icon>\n </div>\n\n <div\n class=\"number-picker-control number-picker-control-down\"\n (click)=\"decrement($event); _touchedChange()\"\n [class.disabled]=\"disabled || value <= min || readonly\"\n >\n <ux-icon name=\"down\"></ux-icon>\n </div>\n</div>\n" }] }], propDecorators: { id: [{ type: Input }], ariaLabel: [{ type: Input, args: ['aria-label'] }], labelledBy: [{ type: Input, args: ['aria-labelledby'] }], precision: [{ type: Input }], placeholder: [{ type: Input }], required: [{ type: Input }], readonly: [{ type: Input }], valueChange: [{ type: Output }], value: [{ type: Input }], min: [{ type: Input }], max: [{ type: Input }], step: [{ type: Input }], disabled: [{ type: Input }], onFocusIn: [{ type: HostListener, args: ['focusin'] }], onFocusOut: [{ type: HostListener, args: ['focusout'] }] } }); export var StepDirection; (function (StepDirection) { StepDirection[StepDirection["Increment"] = 0] = "Increment"; StepDirection[StepDirection["Decrement"] = 1] = "Decrement"; })(StepDirection || (StepDirection = {})); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnVtYmVyLXBpY2tlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy9udW1iZXItcGlja2VyL251bWJlci1waWNrZXIuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvbnVtYmVyLXBpY2tlci9udW1iZXItcGlja2VyLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBZ0IscUJBQXFCLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUNsRyxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsWUFBWSxFQUNaLFlBQVksRUFDWixLQUFLLEVBR0wsTUFBTSxFQUNOLFVBQVUsRUFDVixNQUFNLEdBQ1AsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUF3QixrQkFBa0IsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7O0FBRTdGLElBQUksUUFBUSxHQUFHLENBQUMsQ0FBQztBQUVqQixNQUFNLENBQUMsTUFBTSw0QkFBNEIsR0FBRztJQUMxQyxPQUFPLEVBQUUsaUJBQWlCO0lBQzFCLFdBQVcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMscUJBQXFCLENBQUM7SUFDcEQsS0FBSyxFQUFFLElBQUk7Q0FDWixDQUFDO0FBV0YsTUFBTSxPQUFPLHFCQUFxQjtJQVRsQztRQVVXLGVBQVUsR0FBRyxNQUFNLENBQUMsa0JBQWtCLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUVwRCxvQkFBZSxHQUFHLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBSXJELFVBQUssR0FBbUUsQ0FBQyxDQUFDO1FBQzFFLGNBQVMsR0FBWSxLQUFLLENBQUM7UUFDM0IsV0FBTSxHQUFXLENBQUMsQ0FBQztRQUVuQixhQUFRLEdB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QUM7SUFHRCxTQUFTO1FBQ1AsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7SUFDdkIsQ0FBQztJQUdELFVBQVU7UUFDUixJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztJQUN4QixDQUFDOytHQTlPVSxxQkFBcUI7bUdBQXJCLHFCQUFxQiw4aUJBTnJCLENBQUMsNEJBQTRCLENBQUMsK0NDM0IzQyw2eENBMENBOzs0RkRUYSxxQkFBcUI7a0JBVGpDLFNBQVM7K0JBQ0UsMkNBQTJDLGFBRTFDLENBQUMsNEJBQTRCLENBQUMsbUJBQ3hCLHVCQUF1QixDQUFDLE1BQU0sUUFDekM7d0JBQ0osa0NBQWtDLEVBQUUscUNBQXFDO3FCQUMxRTs4QkFvQlEsRUFBRTtzQkFBVixLQUFLO2dCQUdlLFNBQVM7c0JBQTdCLEtBQUs7dUJBQUMsWUFBWTtnQkFHTyxVQUFVO3NCQUFuQyxLQUFLO3VCQUFDLGlCQUFpQjtnQkFHZixTQUFTO3NCQUFqQixLQUFLO2dCQUdHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBR0csUUFBUTtzQkFBaEIsS0FBSztnQkFHTyxRQUFRO3NCQUFwQixLQUFLO2dCQVNJLFdBQVc7c0JBQXBCLE1BQU07Z0JBSUgsS0FBSztzQkFEUixLQUFLO2dCQWNGLEdBQUc7c0JBRE4sS0FBSztnQkFXRixHQUFHO3NCQUROLEtBQUs7Z0JBV0YsSUFBSTtzQkFEUCxLQUFLO2dCQVdGLFFBQVE7c0JBRFgsS0FBSztnQkE0SU4sU0FBUztzQkFEUixZQUFZO3VCQUFDLFNBQVM7Z0JBTXZCLFVBQVU7c0JBRFQsWUFBWTt1QkFBQyxVQUFVOztBQVExQixNQUFNLENBQU4sSUFBWSxhQUdYO0FBSEQsV0FBWSxhQUFhO0lBQ3ZCLDJEQUFTLENBQUE7SUFDVCwyREFBUyxDQUFBO0FBQ1gsQ0FBQyxFQUhXLGFBQWEsS0FBYixhQUFhLFFBR3hCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQm9vbGVhbklucHV0LCBjb2VyY2VCb29sZWFuUHJvcGVydHksIGNvZXJjZU51bWJlclByb3BlcnR5IH0gZnJvbSAnQGFuZ3VsYXIvY2RrL2NvZXJjaW9uJztcbmltcG9ydCB7XG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgQ29tcG9uZW50LFxuICBFdmVudEVtaXR0ZXIsXG4gIEhvc3RMaXN0ZW5lcixcbiAgSW5wdXQsXG4gIE9uQ2hhbmdlcyxcbiAgT25EZXN0cm95LFxuICBPdXRwdXQsXG4gIGZvcndhcmRSZWYsXG4gIGluamVjdCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb250cm9sVmFsdWVBY2Nlc3NvciwgRm9ybUdyb3VwRGlyZWN0aXZlLCBOR19WQUxVRV9BQ0NFU1NPUiB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcblxubGV0IHVuaXF1ZUlkID0gMDtcblxuZXhwb3J0IGNvbnN0IE5VTUJFUl9QSUNLRVJfVkFMVUVfQUNDRVNTT1IgPSB7XG4gIHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuICB1c2VFeGlzdGluZzogZm9yd2FyZFJlZigoKSA9PiBOdW1iZXJQaWNrZXJDb21wb25lbnQpLFxuICBtdWx0aTogdHJ1ZSxcbn07XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3V4LW51bWJlci1waWNrZXIsIHV4LW51bWJlci1waWNrZXItaW5saW5lJyxcbiAgdGVtcGxhdGVVcmw6ICcuL251bWJlci1waWNrZXIuY29tcG9uZW50Lmh0bWwnLFxuICBwcm92aWRlcnM6IFtOVU1CRVJfUElDS0VSX1ZBTFVFX0FDQ0VTU09SXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIGhvc3Q6IHtcbiAgICAnW2NsYXNzLnV4LW51bWJlci1waWNrZXItaW52YWxpZF0nOiAnIV92YWxpZCAmJiAhZGlzYWJsZWQgJiYgIV9mb3JtR3JvdXAnLFxuICB9LFxufSlcbmV4cG9ydCBjbGFzcyBOdW1iZXJQaWNrZXJDb21wb25lbnQgaW1wbGVtZW50cyBDb250cm9sVmFsdWVBY2Nlc3NvciwgT25EZXN0cm95LCBPbkNoYW5nZXMge1xuICByZWFkb25seSBfZm9ybUdyb3VwID0gaW5qZWN0KEZvcm1Hcm91cERpcmVjdGl2ZSwgeyBvcHRpb25hbDogdHJ1ZSB9KTtcblxuICBwcml2YXRlIHJlYWRvbmx5IF9jaGFuZ2VEZXRlY3RvciA9IGluamVjdChDaGFuZ2VEZXRlY3RvclJlZik7XG5cbiAgcHJpdmF0ZSBfbWluOiBudW1iZXI7XG4gIHByaXZhdGUgX21heDogbnVtYmVyO1xuICBwcml2YXRlIF9zdGVwOiBudW1iZXIgfCAoKHZhbHVlOiBudW1iZXIsIGRpcmVjdGlvbjogU3RlcERpcmVjdGlvbikgPT4gbnVtYmVyKSA9IDE7XG4gIHByaXZhdGUgX2Rpc2FibGVkOiBib29sZWFuID0gZmFsc2U7XG4gIHByaXZhdGUgX3ZhbHVlOiBudW1iZXIgPSAwO1xuICBwcml2YXRlIF9sYXN0VmFsdWU6IG51bWJlcjtcbiAgcHJpdmF0ZSBfZm9jdXNlZDogYm9vbGVhbiA9IGZhbHNlO1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWVtcHR5LWZ1bmN0aW9uXG4gIHByaXZhdGUgX3Byb3BhZ2F0ZUNoYW5nZSA9IChfOiBudW1iZXIpID0+IHt9O1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWVtcHR5LWZ1bmN0aW9uXG4gIF90b3VjaGVkQ2hhbmdlID0gKCkgPT4ge307XG5cbiAgLyoqIFNldHMgdGhlIGlkIG9mIHRoZSBudW1iZXIgcGlja2VyLiBUaGUgY2hpbGQgaW5wdXQgd2lsbCBoYXZlIHRoaXMgdmFsdWUgd2l0aCBhIC1pbnB1dCBzdWZmaXggYXMgaXRzIGlkLiAqL1xuICBASW5wdXQoKSBpZDogc3RyaW5nID0gYHV4LW51bWJlci1waWNrZXItJHt1bmlxdWVJZCsrfWA7XG5cbiAgLyoqIFByb3ZpZGUgYW4gYXJpYSBsYWJlbCBmb3IgdGhlIG51bWJlciBwaWNrZXIuICovXG4gIEBJbnB1dCgnYXJpYS1sYWJlbCcpIGFyaWFMYWJlbDogc3RyaW5nO1xuXG4gIC8qKiBQcm92aWRlIGFuIGFyaWEgbGFiZWxsZWRieSBhdHRyaWJ1dGUgKi9cbiAgQElucHV0KCdhcmlhLWxhYmVsbGVkYnknKSBsYWJlbGxlZEJ5OiBzdHJpbmc7XG5cbiAgLyoqIERlZmluZSB0aGUgcHJlY2lzaW9uIG9mIGZsb2F0aW5nIHBvaW50IHZhbHVlcyAqL1xuICBASW5wdXQoKSBwcmVjaXNpb246IG51bWJlciA9IE51bWJlci5NQVhfU0FGRV9JTlRFR0VSLnRvU3RyaW5nKCkubGVuZ3RoIC0gMTtcblxuICAvKiogVGhlIHBsYWNlaG9sZGVyIHRleHQgd2hpY2ggYXBwZWFycyBpbiB0aGUgdGV4dCBpbnB1dCBhcmVhIHdoZW4gaXQgaXMgZW1wdHkuKi9cbiAgQElucHV0KCkgcGxhY2Vob2xkZXI6IHN0cmluZztcblxuICAvKiogU3BlY2lmaWVkIGlmIHRoaXMgaXMgYSByZXF1aXJlZCBpbnB1dC4gKi9cbiAgQElucHV0KCkgcmVxdWlyZWQ6IGJvb2xlYW47XG5cbiAgLyoqIFNwZWNpZmllZCBpZiB0aGlzIGlzIGEgcmVhZG9ubHkgaW5wdXQuICovXG4gIEBJbnB1dCgpIHNldCByZWFkb25seSh2YWx1ZTogYm9vbGVhbikge1xuICAgIHRoaXMuX3JlYWRvbmx5ID0gY29lcmNlQm9vbGVhblByb3BlcnR5KHZhbHVlKTtcbiAgfVxuXG4gIGdldCByZWFkb25seSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5fcmVhZG9ubHk7XG4gIH1cblxuICAvKiogSWYgdHdvIHdheSBiaW5kaW5nIGlzIHVzZWQgdGhpcyB2YWx1ZSB3aWxsIGJlIHVwZGF0ZWQgYW55IHRpbWUgdGhlIG51bWJlciBwaWNrZXIgdmFsdWUgY2hhbmdlcy4gKi9cbiAgQE91dHB1dCgpIHZhbHVlQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxudW1iZXI+KCk7XG5cbiAgLyoqIFNldHMgdGhlIHZhbHVlIGRpc3BsYXllZCBpbiB0aGUgbnVtYmVyIHBpY2tlciBjb21wb25lbnQuICovXG4gIEBJbnB1dCgpXG4gIGdldCB2YWx1ZSgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLl92YWx1ZTtcbiAgfVxuXG4gIHNldCB2YWx1ZSh2YWx1ZTogbnVtYmVyKSB7XG4gICAgaWYgKHRoaXMuX3ZhbHVlICE9PSB2YWx1ZSkge1xuICAgICAgdGhpcy5fdmFsdWUgPSB2YWx1ZTtcbiAgICAgIHRoaXMuX3ZhbGlkID0gdGhpcy5pc1ZhbGlkKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqIERlZmluZXMgdGhlIG1pbmltdW0gdmFsdWUgdGhlIG51bWJlciBwaWNrZXIgY2FuIHNldC4gKi9cbiAgQElucHV0KClcbiAgZ2V0IG1pbigpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLl9taW47XG4gIH1cblxuICBzZXQgbWluKHZhbHVlKSB7XG4gICAgdGhpcy5fbWluID0gY29lcmNlTnVtYmVyUHJvcGVydHkodmFsdWUpO1xuICB9XG5cbiAgLyoqIERlZmluZXMgdGhlIG1heGltdW0gdmFsdWUgdGhlIG51bWJlciBwaWNrZXIgY2FuIHNldC4gKi9cbiAgQElucHV0KClcbiAgZ2V0IG1heCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLl9tYXg7XG4gIH1cblxuICBzZXQgbWF4KHZhbHVlKSB7XG4gICAgdGhpcy5fbWF4ID0gY29lcmNlTnVtYmVyUHJvcGVydHkodmFsdWUpO1xuICB9XG5cbiAgLyoqIERlZmluZXMgdGhlIGFtb3VudCB0aGUgbnVtYmVyIHBpY2tlciBzaG91bGQgaW5jcmVhc2Ugb3IgZGVjcmVhc2Ugd2hlbiB0aGUgYnV0dG9ucyBvciBhcnJvdyBrZXlzIGFyZSB1c2VkLiAqL1xuICBASW5wdXQoKVxuICBzZXQgc3RlcCh2YWx1ZTogbnVtYmVyIHwgKCh2YWx1ZTogbnVtYmVyLCBkaXJlY3Rpb246IFN0ZXBEaXJlY3Rpb24pID0+IG51bWJlcikpIHtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICB0aGlzLl9zdGVwID0gdmFsdWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuX3N0ZXAgPSBjb2VyY2VOdW1iZXJQcm9wZXJ0eSh2YWx1ZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqIEluZGljYXRlIGlmIHRoZSBudW1iZXIgcGlja2VyIGlzIGRpc2FibGVkIG9yIG5vdC4gKi9cbiAgQElucHV0KClcbiAgZ2V0IGRpc2FibGVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9kaXNhYmxlZDtcbiAgfVxuXG4gIHNldCBkaXNhYmxlZCh2YWx1ZSkge1xuICAgIHRoaXMuX2Rpc2FibGVkID0gY29lcmNlQm9vbGVhblByb3BlcnR5KHZhbHVlKTtcbiAgfVxuXG4gIGdldCBpbnB1dElkKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuaWQgKyAnLWlucHV0JztcbiAgfVxuXG4gIC8qKiBTdG9yZSB0aGUgY3VycmVudCB2YWxpZCBzdGF0ZSAqL1xuICBfdmFsaWQ6IGJvb2xlYW4gPSB0cnVlO1xuXG4gIC8qKiBUaGlzIGlzIGEgZmxhZyB0byBpbmRpY2F0ZSB3aGVuIHRoZSBjb21wb25lbnQgaGFzIGJlZW4gZGVzdHJveWVkIHRvIGF2b2lkIGNoYW5nZSBkZXRlY3Rpb24gYmVpbmcgbWFkZSBhZnRlciB0aGUgY29tcG9uZW50XG4gICAqICBpcyBubyBsb25nZXIgaW5zdGFudGlhdGVkLiBBIHdvcmthcm91bmQgZm9yIEFuZ3VsYXIgRm9ybXMgYnVnIChodHRwczovL2dpdGh1Yi5jb20vYW5ndWxhci9hbmd1bGFyL2lzc3Vlcy8yNzgwMykgKi9cbiAgcHJpdmF0ZSBfaXNEZXN0cm95ZWQ6IGJvb2xlYW4gPSBmYWxzZTtcbiAgcHJpdmF0ZSBfcmVhZG9ubHk6IGJvb2xlYW4gPSBmYWxzZTtcblxuICBuZ09uQ2hhbmdlcygpOiB2b2lkIHtcbiAgICB0aGlzLl92YWxpZCA9IHRoaXMuaXNWYWxpZCgpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5faXNEZXN0cm95ZWQgPSB0cnVlO1xuICB9XG5cbiAgZ2V0U3RlcChkaXJlY3Rpb246IFN0ZXBEaXJlY3Rpb24pOiBudW1iZXIge1xuICAgIHJldHVybiB0eXBlb2YgdGhpcy5fc3RlcCA9PT0gJ251bWJlcicgPyB0aGlzLl9zdGVwIDogdGhpcy5fc3RlcCh0aGlzLnZhbHVlLCBkaXJlY3Rpb24pO1xuICB9XG5cbiAgaW5jcmVtZW50KGV2ZW50PzogTW91c2VFdmVudCB8IEtleWJvYXJkRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoZXZlbnQpIHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmRpc2FibGVkICYmICF0aGlzLnJlYWRvbmx5KSB7XG4gICAgICB0aGlzLnZhbHVlID0gTWF0aC5tYXgoXG4gICAgICAgIE1hdGgubWluKFxuICAgICAgICAgIHRoaXMudmFsdWUgKyB0aGlzLmdldFN0ZXAoU3RlcERpcmVjdGlvbi5JbmNyZW1lbnQpLFxuICAgICAgICAgIHRoaXMuZ2V0TWF4VmFsdWVGb3JDb21wYXJpc29uKClcbiAgICAgICAgKSxcbiAgICAgICAgdGhpcy5nZXRNaW5WYWx1ZUZvckNvbXBhcmlzb24oKVxuICAgICAgKTtcblxuICAgICAgLy8gYWNjb3VudCBmb3IgamF2YXNjcmlwdHMgdGVycmlibGUgaGFuZGxpbmcgb2YgZmxvYXRpbmcgcG9pbnQgbnVtYmVyc1xuICAgICAgdGhpcy52YWx1ZSA9IHBhcnNlRmxvYXQodGhpcy52YWx1ZS50b1ByZWNpc2lvbih0aGlzLnByZWNpc2lvbikpO1xuXG4gICAgICAvLyBlbWl0IHRoZSB2YWx1ZSB0byB0aGUgT3V0cHV0IGFuZCBBbmd1bGFyIGZvcm1zXG4gICAgICB0aGlzLl9lbWl0VmFsdWVDaGFuZ2UodGhpcy52YWx1ZSk7XG4gICAgfVxuICB9XG5cbiAgZGVjcmVtZW50KGV2ZW50PzogTW91c2VFdmVudCB8IEtleWJvYXJkRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoZXZlbnQpIHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmRpc2FibGVkICYmICF0aGlzLnJlYWRvbmx5KSB7XG4gICAgICB0aGlzLnZhbHVlID0gTWF0aC5taW4oXG4gICAgICAgIE1hdGgubWF4KFxuICAgICAgICAgIHRoaXMudmFsdWUgLSB0aGlzLmdldFN0ZXAoU3RlcERpcmVjdGlvbi5EZWNyZW1lbnQpLFxuICAgICAgICAgIHRoaXMuZ2V0TWluVmFsdWVGb3JDb21wYXJpc29uKClcbiAgICAgICAgKSxcbiAgICAgICAgdGhpcy5nZXRNYXhWYWx1ZUZvckNvbXBhcmlzb24oKVxuICAgICAgKTtcblxuICAgICAgLy8gYWNjb3VudCBmb3IgamF2YXNjcmlwdHMgdGVycmlibGUgaGFuZGxpbmcgb2YgZmxvYXRpbmcgcG9pbnQgbnVtYmVyc1xuICAgICAgdGhpcy52YWx1ZSA9IHBhcnNlRmxvYXQodGhpcy52YWx1ZS50b1ByZWNpc2lvbih0aGlzLnByZWNpc2lvbikpO1xuXG4gICAgICAvLyBlbWl0IHRoZSB2YWx1ZSB0byB0aGUgT3V0cHV0IGFuZCBBbmd1bGFyIGZvcm1zXG4gICAgICB0aGlzLl9lbWl0VmFsdWVDaGFuZ2UodGhpcy52YWx1ZSk7XG4gICAgfVxuICB9XG5cbiAgaXNWYWxpZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gKFxuICAgICAgdGhpcy52YWx1ZSA+PSB0aGlzLmdldE1pblZhbHVlRm9yQ29tcGFyaXNvbigpICYmIHRoaXMudmFsdWUgPD0gdGhpcy5nZXRNYXhWYWx1ZUZvckNvbXBhcmlzb24oKVxuICAgICk7XG4gIH1cblxuICBvblNjcm9sbChldmVudDogV2hlZWxFdmVudCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5fZm9jdXNlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICAvLyBnZXQgdGhlIGRpc3RhbmNlIHNjcm9sbGVkXG5cbiAgICBjb25zdCBzY3JvbGxWYWx1ZSA9IGV2ZW50LmRlbHRhWSB8fCAoZXZlbnQgYXMgYW55KS53aGVlbERlbHRhO1xuXG4gICAgLy8gaW5jcmVtZW50IG9yIGRlY3JlbWVudCBhY2NvcmRpbmdseVxuICAgIHNjcm9sbFZhbHVlIDwgMCA/IHRoaXMuaW5jcmVtZW50KGV2ZW50KSA6IHRoaXMuZGVjcmVtZW50KGV2ZW50KTtcbiAgfVxuXG4gIHdyaXRlVmFsdWUodmFsdWU6IG51bWJlcik6IHZvaWQge1xuICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLl92YWx1ZSA9IHZhbHVlO1xuICAgICAgdGhpcy5fdmFsaWQgPSB0aGlzLmlzVmFsaWQoKTtcbiAgICAgIC8vIGlmIHRoZSBjb21wb25lbnQgaXMgbm90IGRlc3Ryb3llZCB0aGVuIHJ1biBjaGFuZ2UgZGV0ZWN0aW9uXG4gICAgICAvLyB3b3JrYXJvdW5kIGZvciBBbmd1bGFyIGJ1ZyAoaHR0cHM6Ly9wb3J0YWwuZGlnaXRhbHNhZmUubmV0L2Jyb3dzZS9FTC0zNjk0KVxuICAgICAgaWYgKCF0aGlzLl9pc0Rlc3Ryb3llZCkge1xuICAgICAgICB0aGlzLl9jaGFuZ2VEZXRlY3Rvci5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmVnaXN0ZXJPbkNoYW5nZShmbjogKF86IG51bWJlcikgPT4gdm9pZCk6IHZvaWQge1xuICAgIHRoaXMuX3Byb3BhZ2F0ZUNoYW5nZSA9IGZuO1xuICB9XG5cbiAgcmVnaXN0ZXJPblRvdWNoZWQoZm46ICgpID0+IHZvaWQpOiB2b2lkIHtcbiAgICB0aGlzLl90b3VjaGVkQ2hhbmdlID0gZm47XG4gIH1cblxuICBzZXREaXNhYmxlZFN0YXRlKGlzRGlzYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmRpc2FibGVkID0gaXNEaXNhYmxlZDtcbiAgICB0aGlzLl9jaGFuZ2VEZXRlY3Rvci5tYXJrRm9yQ2hlY2soKTtcbiAgfVxuXG4gIC8qKiBTZXQgdGhlIHZhbHVlIGFuZCBlbWl0IHRoZSBjaGFuZ2UgdG8gdGhlIG91dHB1dCBhbmQgQW5ndWxhciBmb3Jtcy4gKi9cbiAgX2VtaXRWYWx1ZUNoYW5nZSh2YWx1ZTogbnVtYmVyKTogdm9pZCB7XG4gICAgLy8gVGhpcyBpcyBhIHdvcmthcm91bmQgZm9yIGFuZ3VsYXIgYnVnIGh0dHBzOi8vZ2l0aHViLmNvbS9hbmd1bGFyL2FuZ3VsYXIvaXNzdWVzLzEyNTQwXG4gICAgaWYgKHZhbHVlID09PSB0aGlzLl9sYXN0VmFsdWUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5fbGFzdFZhbHVlID0gdmFsdWU7XG4gICAgdGhpcy52YWx1ZUNoYW5nZS5lbWl0KHZhbHVlKTtcbiAgICB0aGlzLl9wcm9wYWdhdGVDaGFuZ2UodmFsdWUpO1xuICB9XG5cbiAgZ2V0TWF4VmFsdWVGb3JDb21wYXJpc29uKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubWF4ID09PSB1bmRlZmluZWQgfHwgdGhpcy5tYXggPT09IG51bGwgPyBJbmZpbml0eSA6IHRoaXMubWF4O1xuICB9XG5cbiAgZ2V0TWluVmFsdWVGb3JDb21wYXJpc29uKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubWluID09PSB1bmRlZmluZWQgfHwgdGhpcy5taW4gPT09IG51bGwgPyAtSW5maW5pdHkgOiB0aGlzLm1pbjtcbiAgfVxuXG4gIEBIb3N0TGlzdGVuZXIoJ2ZvY3VzaW4nKVxuICBvbkZvY3VzSW4oKTogdm9pZCB7XG4gICAgdGhpcy5fZm9jdXNlZCA9IHRydWU7XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdmb2N1c291dCcpXG4gIG9uRm9jdXNPdXQoKTogdm9pZCB7XG4gICAgdGhpcy5fZm9jdXNlZCA9IGZhbHNlO1xuICB9XG5cbiAgc3RhdGljIG5nQWNjZXB0SW5wdXRUeXBlX3JlYWRvbmx5OiBCb29sZWFuSW5wdXQ7XG59XG5cbmV4cG9ydCBlbnVtIFN0ZXBEaXJlY3Rpb24ge1xuICBJbmNyZW1lbnQsXG4gIERlY3JlbWVudCxcbn1cbiIsIjxpbnB1dFxuICAgIHR5cGU9XCJudW1iZXJcIlxuICAgIFtpZF09XCJpbnB1dElkXCJcbiAgICByb2xlPVwic3BpbmJ1dHRvblwiXG4gICAgY2xhc3M9XCJmb3JtLWNvbnRyb2wgbnVtYmVyLXBpY2tlci1pbnB1dFwiXG4gICAgWyhuZ01vZGVsKV09XCJ2YWx1ZVwiXG4gICAgKG5nTW9kZWxDaGFuZ2UpPVwiX2VtaXRWYWx1ZUNoYW5nZSgkZXZlbnQpXCJcbiAgICBbbWluXT1cIm1pblwiXG4gICAgW21heF09XCJtYXhcIlxuICAgIFtyZXF1aXJlZF09XCJyZXF1aXJlZFwiXG4gICAgW2F0dHIucGxhY2Vob2xkZXJdPVwicGxhY2Vob2xkZXJcIlxuICAgIFtyZWFkb25seV09XCJyZWFkb25seVwiXG4gICAgKGJsdXIpPVwiX3RvdWNoZWRDaGFuZ2UoKVwiXG4gICAgKGtleWRvd24uQXJyb3dEb3duKT1cImRlY3JlbWVudCgkZXZlbnQpXCJcbiAgICAoa2V5ZG93bi5BcnJvd1VwKT1cImluY3JlbWVudCgkZXZlbnQpXCJcbiAgICAod2hlZWwpPVwib25TY3JvbGwoJGV2ZW50KVwiXG4gICAgc3RlcD1cImFueVwiXG4gICAgW2Rpc2FibGVkXT1cImRpc2FibGVkXCJcbiAgICBbYXR0ci5hcmlhLXZhbHVlbWluXT1cIm1pblwiXG4gICAgW2F0dHIuYXJpYS12YWx1ZW5vd109XCJ2YWx1ZVwiXG4gICAgW2F0dHIuYXJpYS12YWx1ZW1heF09XCJtYXhcIlxuICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiYXJpYUxhYmVsXCJcbiAgICBbYXR0ci5hcmlhLWxhYmVsbGVkYnldPVwibGFiZWxsZWRCeVwiXG4vPlxuXG48ZGl2IGNsYXNzPVwibnVtYmVyLXBpY2tlci1jb250cm9sc1wiPlxuICAgIDxkaXZcbiAgICAgICAgY2xhc3M9XCJudW1iZXItcGlja2VyLWNvbnRyb2wgbnVtYmVyLXBpY2tlci1jb250cm9sLXVwXCJcbiAgICAgICAgKGNsaWNrKT1cImluY3JlbWVudCgkZXZlbnQpOyBfdG91Y2hlZENoYW5nZSgpXCJcbiAgICAgICAgW2NsYXNzLmRpc2FibGVkXT1cImRpc2FibGVkIHx8IHZhbHVlID49IG1heCB8fCByZWFkb25seVwiXG4gICAgPlxuICAgICAgICA8dXgtaWNvbiBuYW1lPVwidXBcIj48L3V4LWljb24+XG4gICAgPC9kaXY+XG5cbiAgICA8ZGl2XG4gICAgICAgIGNsYXNzPVwibnVtYmVyLXBpY2tlci1jb250cm9sIG51bWJlci1waWNrZXItY29udHJvbC1kb3duXCJcbiAgICAgICAgKGNsaWNrKT1cImRlY3JlbWVudCgkZXZlbnQpOyBfdG91Y2hlZENoYW5nZSgpXCJcbiAgICAgICAgW2NsYXNzLmRpc2FibGVkXT1cImRpc2FibGVkIHx8IHZhbHVlIDw9IG1pbiB8fCByZWFkb25seVwiXG4gICAgPlxuICAgICAgICA8dXgtaWNvbiBuYW1lPVwiZG93blwiPjwvdXgtaWNvbj5cbiAgICA8L2Rpdj5cbjwvZGl2PlxuIl19