@ux-aspects/ux-aspects
Version:
Open source user interface framework for building modern, responsive, mobile big data applications
224 lines • 34.5 kB
JavaScript
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