UNPKG

carbon-components-angular

Version:
597 lines 50.5 kB
import { Component, Input, HostBinding, EventEmitter, Output, TemplateRef, HostListener } from "@angular/core"; import { NG_VALUE_ACCESSOR } from "@angular/forms"; import * as i0 from "@angular/core"; import * as i1 from "carbon-components-angular/i18n"; import * as i2 from "@angular/common"; import * as i3 from "carbon-components-angular/icon"; /** * Used to emit changes performed on number input components. */ export class NumberChange { } /** * Get started with importing the module: * * ```typescript * import { NumberModule } from 'carbon-components-angular'; * ``` * * [See demo](../../?path=/story/components-number--basic) */ export class NumberComponent { /** * Creates an instance of `Number`. */ constructor(i18n) { this.i18n = i18n; this.containerClass = true; /** * Set to `true` for readonly state. */ this.readonly = false; /** * @deprecated since v5 - Use `cdsLayer` directive instead * `light` or `dark` number input theme. */ this.theme = "dark"; /** * Set to `true` for a disabled number input. */ this.disabled = false; /** * Set to `true` for a loading number component. */ this.skeleton = false; /** * Set to `true` for an invalid number component. */ this.invalid = false; /** * The unique id for the number component. */ this.id = `number-${NumberComponent.numberCount}`; /** * Sets the placeholder attribute on the `input` element. */ this.placeholder = ""; /** * Number input field render size */ this.size = "md"; /** * Sets the min attribute on the `input` element. */ this.min = null; /** * Sets the max attribute on the `input` element. */ this.max = null; /** * Sets the amount the number controls increment and decrement by. */ this.step = 1; /** * Set to `true` to show a warning (contents set by warningText) */ this.warn = false; /** * Visually hide the label while keeping it available for screen readers. */ this.hideLabel = false; /** * Hide the increment / decrement controls. */ this.hideSteppers = false; /** * `inputmode` attribute hint for mobile keyboards. * Instruct the browser which keyboard to display on mobile devices. Defaults * to `decimal`, but note that standard numeric keyboards vary across devices * and operating systems. * * https://css-tricks.com/everything-you-ever-wanted-to-know-about-inputmode/ */ this.inputMode = "decimal"; /** * Emits event notifying other classes when a change in state occurs in the input. */ this.change = new EventEmitter(); /** * Experimental: enable fluid state */ this.fluid = false; this._isFocused = false; this._value = 0; this._decrementLabel = this.i18n.getOverridable("NUMBER.DECREMENT"); this._incrementLabel = this.i18n.getOverridable("NUMBER.INCREMENT"); /** * Called when number input is blurred. Needed to properly implement `ControlValueAccessor`. */ this.onTouched = () => { }; /** * Method set in `registerOnChange` to propagate changes back to the form. */ this.propagateChange = (_) => { }; NumberComponent.numberCount++; } /** * Sets the value attribute on the `input` element. */ set value(v) { if (v === "" || v === null) { this._value = null; return; } this._value = Number(v); } get value() { return this._value; } set decrementLabel(value) { this._decrementLabel.override(value); } get decrementLabel() { return this._decrementLabel.value; } set incrementLabel(value) { this._incrementLabel.override(value); } get incrementLabel() { return this._incrementLabel.value; } get fluidInvalid() { return this.fluid && this.invalid; } get fluidDisabled() { return this.fluid && this.disabled; } get fluidFocus() { return this.fluid && this._isFocused; } get fluidSkeleton() { return this.fluid && this.skeleton; } /** * This is the initial value set to the component * @param value The input value. */ writeValue(value) { this.value = value; } /** * Sets a method in order to propagate changes back to the form. */ registerOnChange(fn) { this.propagateChange = fn; } /** * Registers a callback to be triggered when the control has been touched. * @param fn Callback to be triggered when the number input is touched. */ registerOnTouched(fn) { this.onTouched = fn; } focusOut() { this.onTouched(); } /** * Sets the disabled state through the model */ setDisabledState(isDisabled) { this.disabled = isDisabled; } /** * Adds `step` to the current `value`. */ onIncrement() { // if max is set and value + step is greater than max, set value to max // example: max = 100, step = 10, value = 95 , value + step = 105, value will be set to 100 (max) instead of 105 if (this.max !== null && this.value + this.step > this.max) { this.value = this.max; this.emitChangeEvent(); return; } // if min is set and value + step is less than min, set value to min // example: min = 5, step = 2, value = 0, value + step = 2, value will be set to 5 (min) instead of 2 if (this.min !== null && this.value + this.step < this.min) { this.value = this.min; this.emitChangeEvent(); return; } // if max is not set or value + step is less than max, increment value by step if (this.max === null || this.value + this.step <= this.max) { this.value += this.step; this.value = parseFloat(this.value.toPrecision(this.precision)); this.emitChangeEvent(); } } /** * Subtracts `step` to the current `value`. */ onDecrement() { // if max is set and value - step is greater than max, set value to max // example: max = 15, step = 2, value = 20, value - step = 18, value will be set to 15 (max) instead of 18 if (this.max !== null && this.value - this.step > this.max) { this.value = this.max; this.emitChangeEvent(); return; } // if min is set and value - step is less than min, set value to min // example: min = 5, step = 2, value = 6, value - step = 4, value will be set to 5 (min) instead of 4 if (this.min !== null && this.value - this.step < this.min) { this.value = this.min; this.emitChangeEvent(); return; } // if min is not set or value - step is greater than min, decrement value by step if (this.min === null || this.value - this.step >= this.min) { this.value -= this.step; this.value = parseFloat(this.value.toPrecision(this.precision)); this.emitChangeEvent(); } } getDecrementLabel() { return this._decrementLabel.subject; } getIncrementLabel() { return this._incrementLabel.subject; } /** * Creates a class of `NumberChange` to emit the change in the `Number`. */ emitChangeEvent() { let event = new NumberChange(); event.source = this; event.value = this.value; this.change.emit(event); this.propagateChange(this.value); } onNumberInputChange(event) { this.value = event.target.value; this.emitChangeEvent(); } isTemplate(value) { return value instanceof TemplateRef; } handleFocus(event) { if ("type" in event.target && event.target.type === "button") { this._isFocused = false; } else { this._isFocused = event.type === "focus"; } } } /** * Variable used for creating unique ids for number input components. */ NumberComponent.numberCount = 0; NumberComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NumberComponent, deps: [{ token: i1.I18n }], target: i0.ɵɵFactoryTarget.Component }); NumberComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: NumberComponent, selector: "cds-number, ibm-number", inputs: { readonly: "readonly", theme: "theme", disabled: "disabled", skeleton: "skeleton", invalid: "invalid", id: "id", placeholder: "placeholder", size: "size", required: "required", value: "value", min: "min", max: "max", label: "label", decorator: "decorator", helperText: "helperText", invalidText: "invalidText", step: "step", precision: "precision", warn: "warn", warnText: "warnText", ariaLabel: "ariaLabel", hideLabel: "hideLabel", hideSteppers: "hideSteppers", inputMode: "inputMode", pattern: "pattern", decrementLabel: "decrementLabel", incrementLabel: "incrementLabel", fluid: "fluid" }, outputs: { change: "change" }, host: { listeners: { "focusout": "focusOut()" }, properties: { "class.cds--form-item": "this.containerClass", "class.cds--number--readonly": "this.readonly", "class.cds--number-input--fluid": "this.fluid", "class.cds--number-input--fluid--invalid": "this.fluidInvalid", "class.cds--number-input--fluid--disabled": "this.fluidDisabled", "class.cds--number-input--fluid--focus": "this.fluidFocus", "class.cds--text-input--fluid__skeleton": "this.fluidSkeleton" } }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: NumberComponent, multi: true } ], ngImport: i0, template: ` <label *ngIf="skeleton && label" class="cds--label cds--skeleton"></label> <div data-numberinput [attr.data-invalid]="(invalid ? true : null)" class="cds--number" [ngClass]="{ 'cds--number--light': theme === 'light', 'cds--number--nolabel': hideLabel || !label, 'cds--number--nosteppers': hideSteppers, 'cds--number--helpertext': helperText, 'cds--skeleton' : skeleton, 'cds--number--sm': size === 'sm', 'cds--number--md': size === 'md', 'cds--number--lg': size === 'lg' }"> <label *ngIf="!skeleton && label" [for]="id" class="cds--label" [ngClass]="{ 'cds--label--disabled': disabled, 'cds--visually-hidden': hideLabel }"> <ng-container *ngIf="!isTemplate(label)">{{label}}</ng-container> <ng-template *ngIf="isTemplate(label)" [ngTemplateOutlet]="label"></ng-template> </label> <div class="cds--number__input-wrapper" [ngClass]="{ 'cds--number__input-wrapper--warning': warn, 'cds--number__input-wrapper--decorator': !!decorator }"> <input type="number" [id]="id" [value]="value" [attr.min]="min" [attr.max]="max" [attr.step]="step" [disabled]="disabled" [readonly]="readonly" [required]="required" [attr.aria-label]="ariaLabel" [attr.data-invalid]="invalid ? invalid : null" [attr.inputmode]="inputMode || null" [attr.pattern]="pattern || null" [placeholder]="placeholder" (focus)="fluid ? handleFocus($event): null" (blur)="fluid ? handleFocus($event): null" (change)="onNumberInputChange($event)"/> <ng-container *ngIf="decorator"> <div class="cds--number__input-inner-wrapper--decorator"> <ng-template [ngTemplateOutlet]="decorator"></ng-template> </div> </ng-container> <svg *ngIf="!skeleton && invalid" cdsIcon="warning--filled" size="16" class="cds--number__invalid"> </svg> <svg *ngIf="!skeleton && !invalid && warn" cdsIcon="warning--alt--filled" size="16" class="cds--number__invalid cds--number__invalid--warning"> </svg> <div *ngIf="!skeleton && !hideSteppers" class="cds--number__controls"> <button class="cds--number__control-btn down-icon" type="button" [attr.disabled]="disabled ? true : null" aria-live="polite" aria-atomic="true" [attr.aria-label]="getDecrementLabel() | async" (click)="onDecrement()"> <svg cdsIcon="subtract" size="16"></svg> </button> <div class="cds--number__rule-divider"></div> <button class="cds--number__control-btn up-icon" type="button" [attr.disabled]="disabled ? true : null" aria-live="polite" aria-atomic="true" [attr.aria-label]="getIncrementLabel() | async" (click)="onIncrement()"> <svg cdsIcon="add" size="16"></svg> </button> <div class="cds--number__rule-divider"></div> </div> </div> <hr *ngIf="fluid" class="cds--number-input__divider" /> <div *ngIf="helperText && !invalid && !warn && !fluid" class="cds--form__helper-text" [ngClass]="{ 'cds--form__helper-text--disabled': disabled }"> <ng-container *ngIf="!isTemplate(helperText)">{{helperText}}</ng-container> <ng-template *ngIf="isTemplate(helperText)" [ngTemplateOutlet]="helperText"></ng-template> </div> <div *ngIf="invalid" class="cds--form-requirement"> <ng-container *ngIf="!isTemplate(invalidText)">{{invalidText}}</ng-container> <ng-template *ngIf="isTemplate(invalidText)" [ngTemplateOutlet]="invalidText"></ng-template> </div> <div *ngIf="!invalid && warn" class="cds--form-requirement"> <ng-container *ngIf="!isTemplate(warnText)">{{warnText}}</ng-container> <ng-template *ngIf="isTemplate(warnText)" [ngTemplateOutlet]="warnText"></ng-template> </div> </div> `, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NumberComponent, decorators: [{ type: Component, args: [{ selector: "cds-number, ibm-number", template: ` <label *ngIf="skeleton && label" class="cds--label cds--skeleton"></label> <div data-numberinput [attr.data-invalid]="(invalid ? true : null)" class="cds--number" [ngClass]="{ 'cds--number--light': theme === 'light', 'cds--number--nolabel': hideLabel || !label, 'cds--number--nosteppers': hideSteppers, 'cds--number--helpertext': helperText, 'cds--skeleton' : skeleton, 'cds--number--sm': size === 'sm', 'cds--number--md': size === 'md', 'cds--number--lg': size === 'lg' }"> <label *ngIf="!skeleton && label" [for]="id" class="cds--label" [ngClass]="{ 'cds--label--disabled': disabled, 'cds--visually-hidden': hideLabel }"> <ng-container *ngIf="!isTemplate(label)">{{label}}</ng-container> <ng-template *ngIf="isTemplate(label)" [ngTemplateOutlet]="label"></ng-template> </label> <div class="cds--number__input-wrapper" [ngClass]="{ 'cds--number__input-wrapper--warning': warn, 'cds--number__input-wrapper--decorator': !!decorator }"> <input type="number" [id]="id" [value]="value" [attr.min]="min" [attr.max]="max" [attr.step]="step" [disabled]="disabled" [readonly]="readonly" [required]="required" [attr.aria-label]="ariaLabel" [attr.data-invalid]="invalid ? invalid : null" [attr.inputmode]="inputMode || null" [attr.pattern]="pattern || null" [placeholder]="placeholder" (focus)="fluid ? handleFocus($event): null" (blur)="fluid ? handleFocus($event): null" (change)="onNumberInputChange($event)"/> <ng-container *ngIf="decorator"> <div class="cds--number__input-inner-wrapper--decorator"> <ng-template [ngTemplateOutlet]="decorator"></ng-template> </div> </ng-container> <svg *ngIf="!skeleton && invalid" cdsIcon="warning--filled" size="16" class="cds--number__invalid"> </svg> <svg *ngIf="!skeleton && !invalid && warn" cdsIcon="warning--alt--filled" size="16" class="cds--number__invalid cds--number__invalid--warning"> </svg> <div *ngIf="!skeleton && !hideSteppers" class="cds--number__controls"> <button class="cds--number__control-btn down-icon" type="button" [attr.disabled]="disabled ? true : null" aria-live="polite" aria-atomic="true" [attr.aria-label]="getDecrementLabel() | async" (click)="onDecrement()"> <svg cdsIcon="subtract" size="16"></svg> </button> <div class="cds--number__rule-divider"></div> <button class="cds--number__control-btn up-icon" type="button" [attr.disabled]="disabled ? true : null" aria-live="polite" aria-atomic="true" [attr.aria-label]="getIncrementLabel() | async" (click)="onIncrement()"> <svg cdsIcon="add" size="16"></svg> </button> <div class="cds--number__rule-divider"></div> </div> </div> <hr *ngIf="fluid" class="cds--number-input__divider" /> <div *ngIf="helperText && !invalid && !warn && !fluid" class="cds--form__helper-text" [ngClass]="{ 'cds--form__helper-text--disabled': disabled }"> <ng-container *ngIf="!isTemplate(helperText)">{{helperText}}</ng-container> <ng-template *ngIf="isTemplate(helperText)" [ngTemplateOutlet]="helperText"></ng-template> </div> <div *ngIf="invalid" class="cds--form-requirement"> <ng-container *ngIf="!isTemplate(invalidText)">{{invalidText}}</ng-container> <ng-template *ngIf="isTemplate(invalidText)" [ngTemplateOutlet]="invalidText"></ng-template> </div> <div *ngIf="!invalid && warn" class="cds--form-requirement"> <ng-container *ngIf="!isTemplate(warnText)">{{warnText}}</ng-container> <ng-template *ngIf="isTemplate(warnText)" [ngTemplateOutlet]="warnText"></ng-template> </div> </div> `, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: NumberComponent, multi: true } ] }] }], ctorParameters: function () { return [{ type: i1.I18n }]; }, propDecorators: { containerClass: [{ type: HostBinding, args: ["class.cds--form-item"] }], readonly: [{ type: Input }, { type: HostBinding, args: ["class.cds--number--readonly"] }], theme: [{ type: Input }], disabled: [{ type: Input }], skeleton: [{ type: Input }], invalid: [{ type: Input }], id: [{ type: Input }], placeholder: [{ type: Input }], size: [{ type: Input }], required: [{ type: Input }], value: [{ type: Input }], min: [{ type: Input }], max: [{ type: Input }], label: [{ type: Input }], decorator: [{ type: Input }], helperText: [{ type: Input }], invalidText: [{ type: Input }], step: [{ type: Input }], precision: [{ type: Input }], warn: [{ type: Input }], warnText: [{ type: Input }], ariaLabel: [{ type: Input }], hideLabel: [{ type: Input }], hideSteppers: [{ type: Input }], inputMode: [{ type: Input }], pattern: [{ type: Input }], change: [{ type: Output }], decrementLabel: [{ type: Input }], incrementLabel: [{ type: Input }], fluid: [{ type: HostBinding, args: ["class.cds--number-input--fluid"] }, { type: Input }], fluidInvalid: [{ type: HostBinding, args: ["class.cds--number-input--fluid--invalid"] }], fluidDisabled: [{ type: HostBinding, args: ["class.cds--number-input--fluid--disabled"] }], fluidFocus: [{ type: HostBinding, args: ["class.cds--number-input--fluid--focus"] }], fluidSkeleton: [{ type: HostBinding, args: ["class.cds--text-input--fluid__skeleton"] }], focusOut: [{ type: HostListener, args: ["focusout"] }] } }); export { NumberComponent as Number }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnVtYmVyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9udW1iZXItaW5wdXQvbnVtYmVyLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ04sU0FBUyxFQUNULEtBQUssRUFDTCxXQUFXLEVBQ1gsWUFBWSxFQUNaLE1BQU0sRUFDTixXQUFXLEVBQ1gsWUFBWSxFQUNaLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBd0IsaUJBQWlCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQzs7Ozs7QUFLekU7O0dBRUc7QUFDSCxNQUFNLE9BQU8sWUFBWTtDQVN4QjtBQUVEOzs7Ozs7OztHQVFHO0FBNEhILE1BQU0sT0FBTyxlQUFlO0lBZ0wzQjs7T0FFRztJQUNILFlBQXNCLElBQVU7UUFBVixTQUFJLEdBQUosSUFBSSxDQUFNO1FBN0tLLG1CQUFjLEdBQUcsSUFBSSxDQUFDO1FBRTNEOztXQUVHO1FBQ2tELGFBQVEsR0FBRyxLQUFLLENBQUM7UUFDdEU7OztXQUdHO1FBQ00sVUFBSyxHQUFxQixNQUFNLENBQUM7UUFDMUM7O1dBRUc7UUFDTSxhQUFRLEdBQUcsS0FBSyxDQUFDO1FBQzFCOztXQUVHO1FBQ00sYUFBUSxHQUFHLEtBQUssQ0FBQztRQUMxQjs7V0FFRztRQUNNLFlBQU8sR0FBRyxLQUFLLENBQUM7UUFDekI7O1dBRUc7UUFDTSxPQUFFLEdBQUcsVUFBVSxlQUFlLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDdEQ7O1dBRUc7UUFDTSxnQkFBVyxHQUFHLEVBQUUsQ0FBQztRQUMxQjs7V0FFRztRQUNNLFNBQUksR0FBdUIsSUFBSSxDQUFDO1FBbUJ6Qzs7V0FFRztRQUNNLFFBQUcsR0FBRyxJQUFJLENBQUM7UUFDcEI7O1dBRUc7UUFDTSxRQUFHLEdBQUcsSUFBSSxDQUFDO1FBa0JwQjs7V0FFRztRQUNNLFNBQUksR0FBRyxDQUFDLENBQUM7UUFLbEI7O1dBRUc7UUFDTSxT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QUE1RCxXQUFXO3VCQUFDLGdDQUFnQzs7c0JBQUcsS0FBSztnQkFFTyxZQUFZO3NCQUF2RSxXQUFXO3VCQUFDLHlDQUF5QztnQkFJTyxhQUFhO3NCQUF6RSxXQUFXO3VCQUFDLDBDQUEwQztnQkFJRyxVQUFVO3NCQUFuRSxXQUFXO3VCQUFDLHVDQUF1QztnQkFJTyxhQUFhO3NCQUF2RSxXQUFXO3VCQUFDLHdDQUF3QztnQkEwQ3JELFFBQVE7c0JBRFAsWUFBWTt1QkFBQyxVQUFVOztBQWtIekIsT0FBTyxFQUFFLGVBQWUsSUFBSSxNQUFNLEVBQUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG5cdENvbXBvbmVudCxcblx0SW5wdXQsXG5cdEhvc3RCaW5kaW5nLFxuXHRFdmVudEVtaXR0ZXIsXG5cdE91dHB1dCxcblx0VGVtcGxhdGVSZWYsXG5cdEhvc3RMaXN0ZW5lclxufSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0IHsgQ29udHJvbFZhbHVlQWNjZXNzb3IsIE5HX1ZBTFVFX0FDQ0VTU09SIH0gZnJvbSBcIkBhbmd1bGFyL2Zvcm1zXCI7XG5cbmltcG9ydCB7IEkxOG4sIE92ZXJyaWRhYmxlIH0gZnJvbSBcImNhcmJvbi1jb21wb25lbnRzLWFuZ3VsYXIvaTE4blwiO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSB9IGZyb20gXCJyeGpzXCI7XG5cbi8qKlxuICogVXNlZCB0byBlbWl0IGNoYW5nZXMgcGVyZm9ybWVkIG9uIG51bWJlciBpbnB1dCBjb21wb25lbnRzLlxuICovXG5leHBvcnQgY2xhc3MgTnVtYmVyQ2hhbmdlIHtcblx0LyoqXG5cdCAqIENvbnRhaW5zIHRoZSBgTnVtYmVyYCB0aGF0IGhhcyBiZWVuIGNoYW5nZWQuXG5cdCAqL1xuXHRzb3VyY2U6IE51bWJlckNvbXBvbmVudDtcblx0LyoqXG5cdCAqIFRoZSB2YWx1ZSBvZiB0aGUgYE51bWJlcmAgZmllbGQgZW5jb21wYXNzZWQgaW4gdGhlIGBOdW1iZXJDaGFuZ2VgIGNsYXNzLlxuXHQgKi9cblx0dmFsdWU6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBHZXQgc3RhcnRlZCB3aXRoIGltcG9ydGluZyB0aGUgbW9kdWxlOlxuICpcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IE51bWJlck1vZHVsZSB9IGZyb20gJ2NhcmJvbi1jb21wb25lbnRzLWFuZ3VsYXInO1xuICogYGBgXG4gKlxuICogW1NlZSBkZW1vXSguLi8uLi8/cGF0aD0vc3RvcnkvY29tcG9uZW50cy1udW1iZXItLWJhc2ljKVxuICovXG5AQ29tcG9uZW50KHtcblx0c2VsZWN0b3I6IFwiY2RzLW51bWJlciwgaWJtLW51bWJlclwiLFxuXHR0ZW1wbGF0ZTogYFxuXHRcdDxsYWJlbCAqbmdJZj1cInNrZWxldG9uICYmIGxhYmVsXCIgY2xhc3M9XCJjZHMtLWxhYmVsIGNkcy0tc2tlbGV0b25cIj48L2xhYmVsPlxuXHRcdDxkaXZcblx0XHRcdGRhdGEtbnVtYmVyaW5wdXRcblx0XHRcdFthdHRyLmRhdGEtaW52YWxpZF09XCIoaW52YWxpZCA/IHRydWUgOiBudWxsKVwiXG5cdFx0XHRjbGFzcz1cImNkcy0tbnVtYmVyXCJcblx0XHRcdFtuZ0NsYXNzXT1cIntcblx0XHRcdFx0J2Nkcy0tbnVtYmVyLS1saWdodCc6IHRoZW1lID09PSAnbGlnaHQnLFxuXHRcdFx0XHQnY2RzLS1udW1iZXItLW5vbGFiZWwnOiBoaWRlTGFiZWwgfHwgIWxhYmVsLFxuXHRcdFx0XHQnY2RzLS1udW1iZXItLW5vc3RlcHBlcnMnOiBoaWRlU3RlcHBlcnMsXG5cdFx0XHRcdCdjZHMtLW51bWJlci0taGVscGVydGV4dCc6IGhlbHBlclRleHQsXG5cdFx0XHRcdCdjZHMtLXNrZWxldG9uJyA6IHNrZWxldG9uLFxuXHRcdFx0XHQnY2RzLS1udW1iZXItLXNtJzogc2l6ZSA9PT0gJ3NtJyxcblx0XHRcdFx0J2Nkcy0tbnVtYmVyLS1tZCc6IHNpemUgPT09ICdtZCcsXG5cdFx0XHRcdCdjZHMtLW51bWJlci0tbGcnOiBzaXplID09PSAnbGcnXG5cdFx0XHR9XCI+XG5cdFx0XHQ8bGFiZWxcblx0XHRcdFx0Km5nSWY9XCIhc2tlbGV0b24gJiYgbGFiZWxcIlxuXHRcdFx0XHRbZm9yXT1cImlkXCJcblx0XHRcdFx0Y2xhc3M9XCJjZHMtLWxhYmVsXCJcblx0XHRcdFx0W25nQ2xhc3NdPVwie1xuXHRcdFx0XHRcdCdjZHMtLWxhYmVsLS1kaXNhYmxlZCc6IGRpc2FibGVkLFxuXHRcdFx0XHRcdCdjZHMtLXZpc3VhbGx5LWhpZGRlbic6IGhpZGVMYWJlbFxuXHRcdFx0XHR9XCI+XG5cdFx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCIhaXNUZW1wbGF0ZShsYWJlbClcIj57e2xhYmVsfX08L25nLWNvbnRhaW5lcj5cblx0XHRcdFx0PG5nLXRlbXBsYXRlICpuZ0lmPVwiaXNUZW1wbGF0ZShsYWJlbClcIiBbbmdUZW1wbGF0ZU91dGxldF09XCJsYWJlbFwiPjwvbmctdGVtcGxhdGU+XG5cdFx0XHQ8L2xhYmVsPlxuXHRcdFx0PGRpdlxuXHRcdFx0XHRjbGFzcz1cImNkcy0tbnVtYmVyX19pbnB1dC13cmFwcGVyXCJcblx0XHRcdFx0W25nQ2xhc3NdPVwie1xuXHRcdFx0XHRcdCdjZHMtLW51bWJlcl9faW5wdXQtd3JhcHBlci0td2FybmluZyc6IHdhcm4sXG5cdFx0XHRcdFx0J2Nkcy0tbnVtYmVyX19pbnB1dC13cmFwcGVyLS1kZWNvcmF0b3InOiAhIWRlY29yYXRvclxuXHRcdFx0XHR9XCI+XG5cdFx0XHRcdDxpbnB1dFxuXHRcdFx0XHRcdHR5cGU9XCJudW1iZXJcIlxuXHRcdFx0XHRcdFtpZF09XCJpZFwiXG5cdFx0XHRcdFx0W3ZhbHVlXT1cInZhbHVlXCJcblx0XHRcdFx0XHRbYXR0ci5taW5dPVwibWluXCJcblx0XHRcdFx0XHRbYXR0ci5tYXhdPVwibWF4XCJcblx0XHRcdFx0XHRbYXR0ci5zdGVwXT1cInN0ZXBcIlxuXHRcdFx0XHRcdFtkaXNhYmxlZF09XCJkaXNhYmxlZFwiXG5cdFx0XHRcdFx0W3JlYWRvbmx5XT1cInJlYWRvbmx5XCJcblx0XHRcdFx0XHRbcmVxdWlyZWRdPVwicmVxdWlyZWRcIlxuXHRcdFx0XHRcdFthdHRyLmFyaWEtbGFiZWxdPVwiYXJpYUxhYmVsXCJcblx0XHRcdFx0XHRbYXR0ci5kYXRhLWludmFsaWRdPVwiaW52YWxpZCA/IGludmFsaWQgOiBudWxsXCJcblx0XHRcdFx0XHRbYXR0ci5pbnB1dG1vZGVdPVwiaW5wdXRNb2RlIHx8IG51bGxcIlxuXHRcdFx0XHRcdFthdHRyLnBhdHRlcm5dPVwicGF0dGVybiB8fCBudWxsXCJcblx0XHRcdFx0XHRbcGxhY2Vob2xkZXJdPVwicGxhY2Vob2xkZXJcIlxuXHRcdFx0XHRcdChmb2N1cyk9XCJmbHVpZCA/IGhhbmRsZUZvY3VzKCRldmVudCk6IG51bGxcIlxuXHRcdFx0XHRcdChibHVyKT1cImZsdWlkID8gaGFuZGxlRm9jdXMoJGV2ZW50KTogbnVsbFwiXG5cdFx0XHRcdFx0KGNoYW5nZSk9XCJvbk51bWJlcklucHV0Q2hhbmdlKCRldmVudClcIi8+XG5cdFx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCJkZWNvcmF0b3JcIj5cblx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwiY2RzLS1udW1iZXJfX2lucHV0LWlubmVyLXdyYXBwZXItLWRlY29yYXRvclwiPlxuXHRcdFx0XHRcdFx0PG5nLXRlbXBsYXRlIFtuZ1RlbXBsYXRlT3V0bGV0XT1cImRlY29yYXRvclwiPjwvbmctdGVtcGxhdGU+XG5cdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdDwvbmctY29udGFpbmVyPlxuXHRcdFx0XHQ8c3ZnXG5cdFx0XHRcdFx0Km5nSWY9XCIhc2tlbGV0b24gJiYgaW52YWxpZFwiXG5cdFx0XHRcdFx0Y2RzSWNvbj1cIndhcm5pbmctLWZpbGxlZFwiXG5cdFx0XHRcdFx0c2l6ZT1cIjE2XCJcblx0XHRcdFx0XHRjbGFzcz1cImNkcy0tbnVtYmVyX19pbnZhbGlkXCI+XG5cdFx0XHRcdDwvc3ZnPlxuXHRcdFx0XHQ8c3ZnXG5cdFx0XHRcdFx0Km5nSWY9XCIhc2tlbGV0b24gJiYgIWludmFsaWQgJiYgd2FyblwiXG5cdFx0XHRcdFx0Y2RzSWNvbj1cIndhcm5pbmctLWFsdC0tZmlsbGVkXCJcblx0XHRcdFx0XHRzaXplPVwiMTZcIlxuXHRcdFx0XHRcdGNsYXNzPVwiY2RzLS1udW1iZXJfX2ludmFsaWQgY2RzLS1udW1iZXJfX2ludmFsaWQtLXdhcm5pbmdcIj5cblx0XHRcdFx0PC9zdmc+XG5cdFx0XHRcdDxkaXYgKm5nSWY9XCIhc2tlbGV0b24gJiYgIWhpZGVTdGVwcGVyc1wiIGNsYXNzPVwiY2RzLS1udW1iZXJfX2NvbnRyb2xzXCI+XG5cdFx0XHRcdFx0PGJ1dHRvblxuXHRcdFx0XHRcdFx0Y2xhc3M9XCJjZHMtLW51bWJlcl9fY29udHJvbC1idG4gZG93bi1pY29uXCJcblx0XHRcdFx0XHRcdHR5cGU9XCJidXR0b25cIlxuXHRcdFx0XHRcdFx0W2F0dHIuZGlzYWJsZWRdPVwiZGlzYWJsZWQgPyB0cnVlIDogbnVsbFwiXG5cdFx0XHRcdFx0XHRhcmlhLWxpdmU9XCJwb2xpdGVcIlxuXHRcdFx0XHRcdFx0YXJpYS1hdG9taWM9XCJ0cnVlXCJcblx0XHRcdFx0XHRcdFthdHRyLmFyaWEtbGFiZWxdPVwiZ2V0RGVjcmVtZW50TGFiZWwoKSB8IGFzeW5jXCJcblx0XHRcdFx0XHRcdChjbGljayk9XCJvbkRlY3JlbWVudCgpXCI+XG5cdFx0XHRcdFx0XHQ8c3ZnIGNkc0ljb249XCJzdWJ0cmFjdFwiIHNpemU9XCIxNlwiPjwvc3ZnPlxuXHRcdFx0XHRcdDwvYnV0dG9uPlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjZHMtLW51bWJlcl9fcnVsZS1kaXZpZGVyXCI+PC9kaXY+XG5cdFx0XHRcdFx0PGJ1dHRvblxuXHRcdFx0XHRcdFx0Y2xhc3M9XCJjZHMtLW51bWJlcl9fY29udHJvbC1idG4gdXAtaWNvblwiXG5cdFx0XHRcdFx0XHR0eXBlPVwiYnV0dG9uXCJcblx0XHRcdFx0XHRcdFthdHRyLmRpc2FibGVkXT1cImRpc2FibGVkID8gdHJ1ZSA6IG51bGxcIlxuXHRcdFx0XHRcdFx0YXJpYS1saXZlPVwicG9saXRlXCJcblx0XHRcdFx0XHRcdGFyaWEtYXRvbWljPVwidHJ1ZVwiXG5cdFx0XHRcdFx0XHRbYXR0ci5hcmlhLWxhYmVsXT1cImdldEluY3JlbWVudExhYmVsKCkgfCBhc3luY1wiXG5cdFx0XHRcdFx0XHQoY2xpY2spPVwib25JbmNyZW1lbnQoKVwiPlxuXHRcdFx0XHRcdFx0PHN2ZyBjZHNJY29uPVwiYWRkXCIgc2l6ZT1cIjE2XCI+PC9zdmc+XG5cdFx0XHRcdFx0PC9idXR0b24+XG5cdFx0XHRcdFx0PGRpdiBjbGFzcz1cImNkcy0tbnVtYmVyX19ydWxlLWRpdmlkZXJcIj48L2Rpdj5cblx0XHRcdFx0PC9kaXY+XG5cdFx0XHQ8L2Rpdj5cblx0XHRcdDxociAqbmdJZj1cImZsdWlkXCIgY2xhc3M9XCJjZHMtLW51bWJlci1pbnB1dF9fZGl2aWRlclwiIC8+XG5cdFx0XHQ8ZGl2XG5cdFx0XHRcdCpuZ0lmPVwiaGVscGVyVGV4dCAmJiAhaW52YWxpZCAmJiAhd2FybiAmJiAhZmx1aWRcIlxuXHRcdFx0XHRjbGFzcz1cImNkcy0tZm9ybV9faGVscGVyLXRleHRcIlxuXHRcdFx0XHRbbmdDbGFzc109XCJ7XG5cdFx0XHRcdFx0J2Nkcy0tZm9ybV9faGVscGVyLXRleHQtLWRpc2FibGVkJzogZGlzYWJsZWRcblx0XHRcdFx0fVwiPlxuXHRcdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiIWlzVGVtcGxhdGUoaGVscGVyVGV4dClcIj57e2hlbHBlclRleHR9fTwvbmctY29udGFpbmVyPlxuXHRcdFx0XHQ8bmctdGVtcGxhdGUgKm5nSWY9XCJpc1RlbXBsYXRlKGhlbHBlclRleHQpXCIgW25nVGVtcGxhdGVPdXRsZXRdPVwiaGVscGVyVGV4dFwiPjwvbmctdGVtcGxhdGU+XG5cdFx0XHQ8L2Rpdj5cblx0XHRcdDxkaXYgKm5nSWY9XCJpbnZhbGlkXCIgY2xhc3M9XCJjZHMtLWZvcm0tcmVxdWlyZW1lbnRcIj5cblx0XHRcdFx0PG5nLWNvbnRhaW5lciAqbmdJZj1cIiFpc1RlbXBsYXRlKGludmFsaWRUZXh0KVwiPnt7aW52YWxpZFRleHR9fTwvbmctY29udGFpbmVyPlxuXHRcdFx0XHQ8bmctdGVtcGxhdGUgKm5nSWY9XCJpc1RlbXBsYXRlKGludmFsaWRUZXh0KVwiIFtuZ1RlbXBsYXRlT3V0bGV0XT1cImludmFsaWRUZXh0XCI+PC9uZy10ZW1wbGF0ZT5cblx0XHRcdDwvZGl2PlxuXHRcdFx0PGRpdiAqbmdJZj1cIiFpbnZhbGlkICYmIHdhcm5cIiBjbGFzcz1cImNkcy0tZm9ybS1yZXF1aXJlbWVudFwiPlxuXHRcdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiIWlzVGVtcGxhdGUod2FyblRleHQpXCI+e3t3YXJuVGV4dH19PC9uZy1jb250YWluZXI+XG5cdFx0XHRcdDxuZy10ZW1wbGF0ZSAqbmdJZj1cImlzVGVtcGxhdGUod2FyblRleHQpXCIgW25nVGVtcGxhdGVPdXRsZXRdPVwid2FyblRleHRcIj48L25nLXRlbXBsYXRlPlxuXHRcdFx0PC9kaXY+XG5cdFx0PC9kaXY+XG5cdGAsXG5cdHByb3ZpZGVyczogW1xuXHRcdHtcblx0XHRcdHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuXHRcdFx0dXNlRXhpc3Rpbmc6IE51bWJlckNvbXBvbmVudCxcblx0XHRcdG11bHRpOiB0cnVlXG5cdFx0fVxuXHRdXG59KVxuZXhwb3J0IGNsYXNzIE51bWJlckNvbXBvbmVudCBpbXBsZW1lbnRzIENvbnRyb2xWYWx1ZUFjY2Vzc29yIHtcblx0LyoqXG5cdCAqIFZhcmlhYmxlIHVzZWQgZm9yIGNyZWF0aW5nIHVuaXF1ZSBpZHMgZm9yIG51bWJlciBpbnB1dCBjb21wb25lbnRzLlxuXHQgKi9cblx0c3RhdGljIG51bWJlckNvdW50ID0gMDtcblxuXHRASG9zdEJpbmRpbmcoXCJjbGFzcy5jZHMtLWZvcm0taXRlbVwiKSBjb250YWluZXJDbGFzcyA9IHRydWU7XG5cblx0LyoqXG5cdCAqIFNldCB0byBgdHJ1ZWAgZm9yIHJlYWRvbmx5IHN0YXRlLlxuXHQgKi9cblx0QElucHV0KCkgQEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS1udW1iZXItLXJlYWRvbmx5XCIpIHJlYWRvbmx5ID0gZmFsc2U7XG5cdC8qKlxuXHQgKiBAZGVwcmVjYXRlZCBzaW5jZSB2NSAtIFVzZSBgY2RzTGF5ZXJgIGRpcmVjdGl2ZSBpbnN0ZWFkXG5cdCAqIGBsaWdodGAgb3IgYGRhcmtgIG51bWJlciBpbnB1dCB0aGVtZS5cblx0ICovXG5cdEBJbnB1dCgpIHRoZW1lOiBcImxpZ2h0XCIgfCBcImRhcmtcIiA9IFwiZGFya1wiO1xuXHQvKipcblx0ICogU2V0IHRvIGB0cnVlYCBmb3IgYSBkaXNhYmxlZCBudW1iZXIgaW5wdXQuXG5cdCAqL1xuXHRASW5wdXQoKSBkaXNhYmxlZCA9IGZhbHNlO1xuXHQvKipcblx0ICogU2V0IHRvIGB0cnVlYCBmb3IgYSBsb2FkaW5nIG51bWJlciBjb21wb25lbnQuXG5cdCAqL1xuXHRASW5wdXQoKSBza2VsZXRvbiA9IGZhbHNlO1xuXHQvKipcblx0ICogU2V0IHRvIGB0cnVlYCBmb3IgYW4gaW52YWxpZCBudW1iZXIgY29tcG9uZW50LlxuXHQgKi9cblx0QElucHV0KCkgaW52YWxpZCA9IGZhbHNlO1xuXHQvKipcblx0ICogVGhlIHVuaXF1ZSBpZCBmb3IgdGhlIG51bWJlciBjb21wb25lbnQuXG5cdCAqL1xuXHRASW5wdXQoKSBpZCA9IGBudW1iZXItJHtOdW1iZXJDb21wb25lbnQubnVtYmVyQ291bnR9YDtcblx0LyoqXG5cdCAqIFNldHMgdGhlIHBsYWNlaG9sZGVyIGF0dHJpYnV0ZSBvbiB0aGUgYGlucHV0YCBlbGVtZW50LlxuXHQgKi9cblx0QElucHV0KCkgcGxhY2Vob2xkZXIgPSBcIlwiO1xuXHQvKipcblx0ICogTnVtYmVyIGlucHV0IGZpZWxkIHJlbmRlciBzaXplXG5cdCAqL1xuXHRASW5wdXQoKSBzaXplOiBcInNtXCIgfCBcIm1kXCIgfCBcImxnXCIgPSBcIm1kXCI7XG5cdC8qKlxuXHQgKiBSZWZsZWN0cyB0aGUgcmVxdWlyZWQgYXR0cmlidXRlIG9mIHRoZSBgaW5wdXRgIGVsZW1lbnQuXG5cdCAqL1xuXHRASW5wdXQoKSByZXF1aXJlZDogYm9vbGVhbjtcblx0LyoqXG5cdCAqIFNldHMgdGhlIHZhbHVlIGF0dHJpYnV0ZSBvbiB0aGUgYGlucHV0YCBlbGVtZW50LlxuXHQgKi9cblx0QElucHV0KCkgc2V0IHZhbHVlKHY6IGFueSkge1xuXHRcdGlmICh2ID09PSBcIlwiIHx8IHYgPT09IG51bGwpIHtcblx0XHRcdHRoaXMuX3ZhbHVlID0gbnVsbDtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0dGhpcy5fdmFsdWUgPSBOdW1iZXIodik7XG5cdH1cblxuXHRnZXQgdmFsdWUoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX3ZhbHVlO1xuXHR9XG5cdC8qKlxuXHQgKiBTZXRzIHRoZSBtaW4gYXR0cmlidXRlIG9uIHRoZSBgaW5wdXRgIGVsZW1lbnQuXG5cdCAqL1xuXHRASW5wdXQoKSBtaW4gPSBudWxsO1xuXHQvKipcblx0ICogU2V0cyB0aGUgbWF4IGF0dHJpYnV0ZSBvbiB0aGUgYGlucHV0YCBlbGVtZW50LlxuXHQgKi9cblx0QElucHV0KCkgbWF4ID0gbnVsbDtcblx0LyoqXG5cdCAqIFNldHMgdGhlIHRleHQgaW5zaWRlIHRoZSBgbGFiZWxgIHRhZy5cblx0ICovXG5cdEBJbnB1dCgpIGxhYmVsOiBzdHJpbmcgfCBUZW1wbGF0ZVJlZjxhbnk+O1xuXHQvKipcblx0ICogKipFeHBlcmltZW50YWwqKjogT3B0aW9uYWwgZGVjb3JhdG9yIChlLmcuIEFJIGxhYmVsKS5cblx0ICovXG5cdEBJbnB1dCgpIGRlY29yYXRvcjogVGVtcGxhdGVSZWY8YW55PjtcblxuXHQvKipcblx0ICogU2V0cyB0aGUgb3B0aW9uYWwgaGVscGVyIHRleHQuXG5cdCAqL1xuXHRASW5wdXQoKSBoZWxwZXJUZXh0OiBzdHJpbmcgfCBUZW1wbGF0ZVJlZjxhbnk+O1xuXHQvKipcblx0ICogU2V0cyB0aGUgaW52YWxpZCB0ZXh0LlxuXHQgKi9cblx0QElucHV0KCkgaW52YWxpZFRleHQ6IHN0cmluZyB8IFRlbXBsYXRlUmVmPGFueT47XG5cdC8qKlxuXHQgKiBTZXRzIHRoZSBhbW91bnQgdGhlIG51bWJlciBjb250cm9scyBpbmNyZW1lbnQgYW5kIGRlY3JlbWVudCBieS5cblx0ICovXG5cdEBJbnB1dCgpIHN0ZXAgPSAxO1xuXHQvKipcblx0ICogSWYgYHN0ZXBgIGlzIGEgZGVjaW1hbCwgd2UgbWF5IHdhbnQgcHJlY2lzaW9uIHRvIGJlIHNldCB0byBnbyBhcm91bmQgZmxvYXRpbmcgcG9pbnQgcHJlY2lzaW9uLlxuXHQgKi9cblx0QElucHV0KCkgcHJlY2lzaW9uOiBudW1iZXI7XG5cdC8qKlxuXHQgKiBTZXQgdG8gYHRydWVgIHRvIHNob3cgYSB3YXJuaW5nIChjb250ZW50cyBzZXQgYnkgd2FybmluZ1RleHQpXG5cdCAqL1xuXHRASW5wdXQoKSB3YXJuID0gZmFsc2U7XG5cdC8qKlxuXHQgKiBTZXRzIHRoZSB3YXJuaW5nIHRleHRcblx0ICovXG5cdEBJbnB1dCgpIHdhcm5UZXh0OiBzdHJpbmcgfCBUZW1wbGF0ZVJlZjxhbnk+O1xuXHQvKipcblx0ICogU2V0cyB0aGUgYXJpYWxhYmVsIGZvciBpbnB1dFxuXHQgKi9cblx0QElucHV0KCkgYXJpYUxhYmVsOiBzdHJpbmc7XG5cdC8qKlxuXHQgKiBWaXN1YWxseSBoaWRlIHRoZSBsYWJlbCB3aGlsZSBrZWVwaW5nIGl0IGF2YWlsYWJsZSBmb3Igc2NyZWVuIHJlYWRlcnMuXG5cdCAqL1xuXHRASW5wdXQoKSBoaWRlTGFiZWwgPSBmYWxzZTtcblx0LyoqXG5cdCAqIEhpZGUgdGhlIGluY3JlbWVudCAvIGRlY3JlbWVudCBjb250cm9scy5cblx0ICovXG5cdEBJbnB1dCgpIGhpZGVTdGVwcGVycyA9IGZhbHNlO1xuXHQvKipcblx0ICogYGlucHV0bW9kZWAgYXR0cmlidXRlIGhpbnQgZm9yIG1vYmlsZSBrZXlib2FyZHMuXG5cdCAqIEluc3RydWN0IHRoZSBicm93c2VyIHdoaWNoIGtleWJvYXJkIHRvIGRpc3BsYXkgb24gbW9iaWxlIGRldmljZXMuIERlZmF1bHRzXG5cdCAqIHRvIGBkZWNpbWFsYCwgYnV0IG5vdGUgdGhhdCBzdGFuZGFyZCBudW1lcmljIGtleWJvYXJkcyB2YXJ5IGFjcm9zcyBkZXZpY2VzXG5cdCAqIGFuZCBvcGVyYXRpbmcgc3lzdGVtcy5cblx0ICpcblx0ICogaHR0cHM6Ly9jc3MtdHJpY2tzLmNvbS9ldmVyeXRoaW5nLXlvdS1ldmVyLXdhbnRlZC10by1rbm93LWFib3V0LWlucHV0bW9kZS9cblx0ICovXG5cdEBJbnB1dCgpIGlucHV0TW9kZSA9IFwiZGVjaW1hbFwiO1xuXHQvKipcblx0ICogYHBhdHRlcm5gIGF0dHJpYnV0ZSBhcHBsaWVkIHRvIHRoZSB1bmRlcmx5aW5nIGA8aW5wdXQ+YC5cblx0ICovXG5cdEBJbnB1dCgpIHBhdHRlcm46IHN0cmluZztcblx0LyoqXG5cdCAqIEVtaXRzIGV2ZW50IG5vdGlmeWluZyBvdGhlciBjbGFzc2VzIHdoZW4gYSBjaGFuZ2UgaW4gc3RhdGUgb2NjdXJzIGluIHRoZSBpbnB1dC5cblx0ICovXG5cdEBPdXRwdXQoKSBjaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPE51bWJlckNoYW5nZT4oKTtcblxuXHRASW5wdXQoKVxuXHRzZXQgZGVjcmVtZW50TGFiZWwodmFsdWU6IHN0cmluZyB8IE9ic2VydmFibGU8c3RyaW5nPikge1xuXHRcdHRoaXMuX2RlY3JlbWVudExhYmVsLm92ZXJyaWRlKHZhbHVlKTtcblx0fVxuXG5cdGdldCBkZWNyZW1lbnRMYWJlbCgpIHtcblx0XHRyZXR1cm4gdGhpcy5fZGVjcmVtZW50TGFiZWwudmFsdWU7XG5cdH1cblxuXHRASW5wdXQoKVxuXHRzZXQgaW5jcmVtZW50TGFiZWwodmFsdWU6IHN0cmluZyB8IE9ic2VydmFibGU8c3RyaW5nPikge1xuXHRcdHRoaXMuX2luY3JlbWVudExhYmVsLm92ZXJyaWRlKHZhbHVlKTtcblx0fVxuXG5cdGdldCBpbmNyZW1lbnRMYWJlbCgpIHtcblx0XHRyZXR1cm4gdGhpcy5faW5jcmVtZW50TGFiZWwudmFsdWU7XG5cdH1cblxuXHQvKipcblx0ICogRXhwZXJpbWVudGFsOiBlbmFibGUgZmx1aWQgc3RhdGVcblx0ICovXG5cdEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tbnVtYmVyLWlucHV0LS1mbHVpZFwiKSBASW5wdXQoKSBmbHVpZCA9IGZhbHNlO1xuXG5cdEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tbnVtYmVyLWlucHV0LS1mbHVpZC0taW52YWxpZFwiKSBnZXQgZmx1aWRJbnZhbGlkKCkge1xuXHRcdHJldHVybiB0aGlzLmZsdWlkICYmIHRoaXMuaW52YWxpZDtcblx0fVxuXG5cdEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tbnVtYmVyLWlucHV0LS1mbHVpZC0tZGlzYWJsZWRcIikgZ2V0IGZsdWlkRGlzYWJsZWQoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZmx1aWQgJiYgdGhpcy5kaXNhYmxlZDtcblx0fVxuXG5cdEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tbnVtYmVyLWlucHV0LS1mbHVpZC0tZm9jdXNcIikgZ2V0IGZsdWlkRm9jdXMoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZmx1aWQgJiYgdGhpcy5faXNGb2N1c2VkO1xuXHR9XG5cblx0QEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS10ZXh0LWlucHV0LS1mbHVpZF9fc2tlbGV0b25cIikgZ2V0IGZsdWlkU2tlbGV0b24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuZmx1aWQgJiYgdGhpcy5za2VsZXRvbjtcblx0fVxuXG5cdHByb3RlY3RlZCBfaXNGb2N1c2VkID0gZmFsc2U7XG5cblx0cHJvdGVjdGVkIF92YWx1ZSA9IDA7XG5cblx0cHJvdGVjdGVkIF9kZWNyZW1lbnRMYWJlbDogT3ZlcnJpZGFibGUgPSB0aGlzLmkxOG4uZ2V0T3ZlcnJpZGFibGUoXCJOVU1CRVIuREVDUkVNRU5UXCIpO1xuXHRwcm90ZWN0ZWQgX2luY3JlbWVudExhYmVsOiBPdmVycmlkYWJsZSA9IHRoaXMuaTE4bi5nZXRPdmVycmlkYWJsZShcIk5VTUJFUi5JTkNSRU1FTlRcIik7XG5cblx0LyoqXG5cdCAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgYE51bWJlcmAuXG5cdCAqL1xuXHRjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgaTE4bjogSTE4bikge1xuXHRcdE51bWJlckNvbXBvbmVudC5udW1iZXJDb3VudCsrO1xuXHR9XG5cblx0LyoqXG5cdCAqIFRoaXMgaXMgdGhlIGluaXRpYWwgdmFsdWUgc2V0IHRvIHRoZSBjb21wb25lbnRcblx0ICogQHBhcmFtIHZhbHVlIFRoZSBpbnB1dCB2YWx1ZS5cblx0ICovXG5cdHB1YmxpYyB3cml0ZVZhbHVlKHZhbHVlOiBhbnkpIHtcblx0XHR0aGlzLnZhbHVlID0gdmFsdWU7XG5cdH1cblxuXHQvKipcblx0ICogU2V0cyBhIG1ldGhvZCBpbiBvcmRlciB0byBwcm9wYWdhdGUgY2hhbmdlcyBiYWNrIHRvIHRoZSBmb3JtLlxuXHQgKi9cblx0cHVibGljIHJlZ2lzdGVyT25DaGFuZ2UoZm46IGFueSkge1xuXHRcdHRoaXMucHJvcGFnYXRlQ2hhbmdlID0gZm47XG5cdH1cblxuXHQvKipcblx0ICogUmVnaXN0ZXJzIGEgY2FsbGJhY2sgdG8gYmUgdHJpZ2dlcmVkIHdoZW4gdGhlIGNvbnRyb2wgaGFzIGJlZW4gdG91Y2hlZC5cblx0ICogQHBhcmFtIGZuIENhbGxiYWNrIHRvIGJlIHRyaWdnZXJlZCB3aGVuIHRoZSBudW1iZXIgaW5wdXQgaXMgdG91Y2hlZC5cblx0ICovXG5cdHB1YmxpYyByZWdpc3Rlck9uVG91Y2hlZChmbjogYW55KSB7XG5cdFx0dGhpcy5vblRvdWNoZWQgPSBmbjtcblx0fVxuXG5cdEBIb3N0TGlzdGVuZXIoXCJmb2N1c291dFwiKVxuXHRmb2N1c091dCgpIHtcblx0XHR0aGlzLm9uVG91Y2hlZCgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldHMgdGhlIGRpc2FibGVkIHN0YXRlIHRocm91Z2ggdGhlIG1vZGVsXG5cdCAqL1xuXHRzZXREaXNhYmxlZFN0YXRlKGlzRGlzYWJsZWQ6IGJvb2xlYW4pIHtcblx0XHR0aGlzLmRpc2FibGVkID0gaXNEaXNhYmxlZDtcblx0fVxuXG5cdC8qKlxuXHQgKiBDYWxsZWQgd2hlbiBudW1iZXIgaW5wdXQgaXMgYmx1cnJlZC4gTmVlZGVkIHRvIHByb3Blcmx5IGltcGxlbWVudCBgQ29udHJvbFZhbHVlQWNjZXNzb3JgLlxuXHQgKi9cblx0b25Ub3VjaGVkOiAoKSA9PiBhbnkgPSAoKSA9PiB7IH07XG5cblx0LyoqXG5cdCAqIE1ldGhvZCBzZXQgaW4gYHJlZ2lzdGVyT25DaGFuZ2VgIHRvIHByb3BhZ2F0ZSBjaGFuZ2VzIGJhY2sgdG8gdGhlIGZvcm0uXG5cdCAqL1xuXHRwcm9wYWdhdGVDaGFuZ2UgPSAoXzogYW55KSA9PiB7IH07XG5cblx0LyoqXG5cdCAqIEFkZHMgYHN0ZXBgIHRvIHRoZSBjdXJyZW50IGB2YWx1ZWAuXG5cdCAqL1xuXHRvbkluY3JlbWVudCgpOiB2b2lkIHtcblx0XHQvLyBpZiBtYXggaXMgc2V0IGFuZCB2YWx1ZSArIHN0ZXAgaXMgZ3JlYXRlciB0aGFuIG1heCwgc2V0IHZhbHVlIHRvIG1heFxuXHRcdC8vIGV4YW1wbGU6IG1heCA9IDEwMCwgc3RlcCA9IDEwLCB2YWx1ZSA9IDk1ICwgdmFsdWUgKyBzdGVwID0gMTA1LCB2YWx1ZSB3aWxsIGJlIHNldCB0byAxMDAgKG1heCkgaW5zdGVhZCBvZiAxMDVcblx0XHRpZiAodGhpcy5tYXggIT09IG51bGwgJiYgdGhpcy52YWx1ZSArIHRoaXMuc3RlcCA+IHRoaXMubWF4KSB7XG5cdFx0XHR0aGlzLnZhbHVlID0gdGhpcy5tYXg7XG5cdFx0XHR0aGlzLmVtaXRDaGFuZ2VFdmVudCgpO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIGlmIG1pbiBpcyBzZXQgYW5kIHZhbHVlICsgc3RlcCBpcyBsZXNzIHRoYW4gbWluLCBzZXQgdmFsdWUgdG8gbWluXG5cdFx0Ly8gZXhhbXBsZTogbWluID0gNSwgc3RlcCA9IDIsIHZhbHVlID0gMCwgdmFsdWUgKyBzdGVwID0gMiwgdmFsdWUgd2lsbCBiZSBzZXQgdG8gNSAobWluKSBpbnN0ZWFkIG9mIDJcblx0XHRpZiAodGhpcy5taW4gIT09IG51bGwgJiYgdGhpcy52YWx1ZSArIHRoaXMuc3RlcCA8IHRoaXMubWluKSB7XG5cdFx0XHR0aGlzLnZhbHVlID0gdGhpcy5taW47XG5cdFx0XHR0aGlzLmVtaXRDaGFuZ2VFdmVudCgpO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIGlmIG1heCBpcyBub3Qgc2V0IG9yIHZhbHVlICsgc3RlcCBpcyBsZXNzIHRoYW4gbWF4LCBpbmNyZW1lbnQgdmFsdWUgYnkgc3RlcFxuXHRcdGlmICh0aGlzLm1heCA9PT0gbnVsbCB8fCB0aGlzLnZhbHVlICsgdGhpcy5zdGVwIDw9IHRoaXMubWF4KSB7XG5cdFx0XHR0aGlzLnZhbHVlICs9IHRoaXMuc3RlcDtcblx0XHRcdHRoaXMudmFsdWUgPSBwYXJzZUZsb2F0KHRoaXMudmFsdWUudG9QcmVjaXNpb24odGhpcy5wcmVjaXNpb24pKTtcblx0XHRcdHRoaXMuZW1pdENoYW5nZUV2ZW50KCk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIFN1YnRyYWN0cyBgc3RlcGAgdG8gdGhlIGN1cnJlbnQgYHZhbHVlYC5cblx0ICovXG5cdG9uRGVjcmVtZW50KCk6IHZvaWQge1xuXHRcdC8vIGlmIG1heCBpcyBzZXQgYW5kIHZhbHVlIC0gc3RlcCBpcyBncmVhdGVyIHRoYW4gbWF4LCBzZXQgdmFsdWUgdG8gbWF4XG5cdFx0Ly8gZXhhbXBsZTogbWF4ID0gMTUsIHN0ZXAgPSAyLCB2YWx1ZSA9IDIwLCB2YWx1ZSAtIHN0ZXAgPSAxOCwgdmFsdWUgd2lsbCBiZSBzZXQgdG8gMTUgKG1heCkgaW5zdGVhZCBvZiAxOFxuXHRcdGlmICh0aGlzLm1heCAhPT0gbnVsbCAmJiB0aGlzLnZhbHVlIC0gdGhpcy5zdGVwID4gdGhpcy5tYXgpIHtcblx0XHRcdHRoaXMudmFsdWUgPSB0aGlzLm1heDtcblx0XHRcdHRoaXMuZW1pdENoYW5nZUV2ZW50KCk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gaWYgbWluIGlzIHNldCBhbmQgdmFsdWUgLSBzdGVwIGlzIGxlc3MgdGhhbiBtaW4sIHNldCB2YWx1ZSB0byBtaW5cblx0XHQvLyBleGFtcGxlOiBtaW4gPSA1LCBzdGVwID0gMiwgdmFsdWUgPSA2LCB2YWx1ZSAtIHN0ZXAgPSA0LCB2YWx1ZSB3aWxsIGJlIHNldCB0byA1IChtaW4pIGluc3RlYWQgb2YgNFxuXHRcdGlmICh0aGlzLm1pbiAhPT0gbnVsbCAmJiB0aGlzLnZhbHVlIC0gdGhpcy5zdGVwIDwgdGhpcy5taW4pIHtcblx0XHRcdHRoaXMudmFsdWUgPSB0aGlzLm1pbjtcblx0XHRcdHRoaXMuZW1pdENoYW5nZUV2ZW50KCk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gaWYgbWluIGlzIG5vdCBzZXQgb3IgdmFsdWUgLSBzdGVwIGlzIGdyZWF0ZXIgdGhhbiBtaW4sIGRlY3JlbWVudCB2YWx1ZSBieSBzdGVwXG5cdFx0aWYgKHRoaXMubWluID09PSBudWxsIHx8IHRoaXMudmFsdWUgLSB0aGlzLnN0ZXAgPj0gdGhpcy5taW4pIHtcblx0XHRcdHRoaXMudmFsdWUgLT0gdGhpcy5zdGVwO1xuXHRcdFx0dGhpcy52YWx1ZSA9IHBhcnNlRmxvYXQodGhpcy52YWx1ZS50b1ByZWNpc2lvbih0aGlzLnByZWNpc2lvbikpO1xuXHRcdFx0dGhpcy5lbWl0Q2hhbmdlRXZlbnQoKTtcblx0XHR9XG5cdH1cblxuXHRnZXREZWNyZW1lbnRMYWJlbCgpOiBPYnNlcnZhYmxlPHN0cmluZz4ge1xuXHRcdHJldHVybiB0aGlzLl9kZWNyZW1lbnRMYWJlbC5zdWJqZWN0O1xuXHR9XG5cblx0Z2V0SW5jcmVtZW50TGFiZWwoKTogT2JzZXJ2YWJsZTxzdHJpbmc+IHtcblx0XHRyZXR1cm4gdGhpcy5faW5jcmVtZW50TGFiZWwuc3ViamVjdDtcblx0fVxuXG5cdC8qKlxuXHQgKiBDcmVhdGVzIGEgY2xhc3Mgb2YgYE51bWJlckNoYW5nZWAgdG8gZW1pdCB0aGUgY2hhbmdlIGluIHRoZSBgTnVtYmVyYC5cblx0ICovXG5cdGVtaXRDaGFuZ2VFdmVudCgpOiB2b2lkIHtcblx0XHRsZXQgZXZlbnQgPSBuZXcgTnVtYmVyQ2hhbmdlKCk7XG5cdFx0ZXZlbnQuc291cmNlID0gdGhpcztcblx0XHRldmVudC52YWx1ZSA9IHRoaXMudmFsdWU7XG5cdFx0dGhpcy5jaGFuZ2UuZW1pdChldmVudCk7XG5cdFx0dGhpcy5wcm9wYWdhdGVDaGFuZ2UodGhpcy52YWx1ZSk7XG5cdH1cblxuXHRvbk51bWJlcklucHV0Q2hhbmdlKGV2ZW50KSB7XG5cdFx0dGhpcy52YWx1ZSA9IGV2ZW50LnRhcmdldC52YWx1ZTtcblx0XHR0aGlzLmVtaXRDaGFuZ2VFdmVudCgpO1xuXHR9XG5cblx0cHVibGljIGlz