carbon-components-angular
Version:
Next generation components
546 lines • 46.3 kB
JavaScript
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;
/**
* 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", helperText: "helperText", invalidText: "invalidText", step: "step", precision: "precision", warn: "warn", warnText: "warnText", ariaLabel: "ariaLabel", 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': !label,
'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}">
<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
}">
<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"
[placeholder]="placeholder"
(focus)="fluid ? handleFocus($event): null"
(blur)="fluid ? handleFocus($event): null"
(change)="onNumberInputChange($event)"/>
<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" 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': !label,
'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}">
<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
}">
<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"
[placeholder]="placeholder"
(focus)="fluid ? handleFocus($event): null"
(blur)="fluid ? handleFocus($event): null"
(change)="onNumberInputChange($event)"/>
<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" 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
}], helperText: [{
type: Input
}], invalidText: [{
type: Input
}], step: [{
type: Input
}], precision: [{
type: Input
}], warn: [{
type: Input
}], warnText: [{
type: Input
}], ariaLabel: [{
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnVtYmVyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9udW1iZXItaW5wdXQvbnVtYmVyLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ04sU0FBUyxFQUNULEtBQUssRUFDTCxXQUFXLEVBQ1gsWUFBWSxFQUNaLE1BQU0sRUFDTixXQUFXLEVBQ1gsWUFBWSxFQUNaLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBd0IsaUJBQWlCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQzs7Ozs7QUFLekU7O0dBRUc7QUFDSCxNQUFNLE9BQU8sWUFBWTtDQVN4QjtBQUVEOzs7Ozs7OztHQVFHO0FBZ0hILE1BQU0sT0FBTyxlQUFlO0lBc0ozQjs7T0FFRztJQUNILFlBQXNCLElBQVU7UUFBVixTQUFJLEdBQUosSUFBSSxDQUFNO1FBbkpLLG1CQUFjLEdBQUcsSUFBSSxDQUFDO1FBRTNEOztXQUVHO1FBQ2tELGFBQVEsR0FBRyxLQUFLLENBQUM7UUFDdEU7OztXQUdHO1FBQ00sVUFBSyxHQUFxQixNQUFNLENBQUM7UUFDMUM7O1dBRUc7UUFDTSxhQUFRLEdBQUcsS0FBSyxDQUFDO1FBQzFCOztXQUVHO1FBQ00sYUFBUSxHQUFHLEtBQUssQ0FBQztRQUMxQjs7V0FFRztRQUNNLFlBQU8sR0FBRyxLQUFLLENBQUM7UUFDekI7O1dBRUc7UUFDTSxPQUFFLEdBQUcsVUFBVSxlQUFlLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDdEQ7O1dBRUc7UUFDTSxnQkFBVyxHQUFHLEVBQUUsQ0FBQztRQUMxQjs7V0FFRztRQUNNLFNBQUksR0FBdUIsSUFBSSxDQUFDO1FBbUJ6Qzs7V0FFRztRQUNNLFFBQUcsR0FBRyxJQUFJLENBQUM7UUFDcEI7O1dBRUc7UUFDTSxRQUFHLEdBQUcsSUFBSSxDQUFDO1FBYXBCOztXQUVHO1FBQ00sU0FBSSxHQUFHLENBQUMsQ0FBQztRQUtsQjs7V0FFRztRQUNNLFNB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Iiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcblx0Q29tcG9uZW50LFxuXHRJbnB1dCxcblx0SG9zdEJpbmRpbmcsXG5cdEV2ZW50RW1pdHRlcixcblx0T3V0cHV0LFxuXHRUZW1wbGF0ZVJlZixcblx0SG9zdExpc3RlbmVyXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgeyBDb250cm9sVmFsdWVBY2Nlc3NvciwgTkdfVkFMVUVfQUNDRVNTT1IgfSBmcm9tIFwiQGFuZ3VsYXIvZm9ybXNcIjtcblxuaW1wb3J0IHsgSTE4biwgT3ZlcnJpZGFibGUgfSBmcm9tIFwiY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhci9pMThuXCI7XG5pbXBvcnQgeyBPYnNlcnZhYmxlIH0gZnJvbSBcInJ4anNcIjtcblxuLyoqXG4gKiBVc2VkIHRvIGVtaXQgY2hhbmdlcyBwZXJmb3JtZWQgb24gbnVtYmVyIGlucHV0IGNvbXBvbmVudHMuXG4gKi9cbmV4cG9ydCBjbGFzcyBOdW1iZXJDaGFuZ2Uge1xuXHQvKipcblx0ICogQ29udGFpbnMgdGhlIGBOdW1iZXJgIHRoYXQgaGFzIGJlZW4gY2hhbmdlZC5cblx0ICovXG5cdHNvdXJjZTogTnVtYmVyQ29tcG9uZW50O1xuXHQvKipcblx0ICogVGhlIHZhbHVlIG9mIHRoZSBgTnVtYmVyYCBmaWVsZCBlbmNvbXBhc3NlZCBpbiB0aGUgYE51bWJlckNoYW5nZWAgY2xhc3MuXG5cdCAqL1xuXHR2YWx1ZTogbnVtYmVyO1xufVxuXG4vKipcbiAqIEdldCBzdGFydGVkIHdpdGggaW1wb3J0aW5nIHRoZSBtb2R1bGU6XG4gKlxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgTnVtYmVyTW9kdWxlIH0gZnJvbSAnY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhcic7XG4gKiBgYGBcbiAqXG4gKiBbU2VlIGRlbW9dKC4uLy4uLz9wYXRoPS9zdG9yeS9jb21wb25lbnRzLW51bWJlci0tYmFzaWMpXG4gKi9cbkBDb21wb25lbnQoe1xuXHRzZWxlY3RvcjogXCJjZHMtbnVtYmVyLCBpYm0tbnVtYmVyXCIsXG5cdHRlbXBsYXRlOiBgXG5cdFx0PGxhYmVsICpuZ0lmPVwic2tlbGV0b24gJiYgbGFiZWxcIiBjbGFzcz1cImNkcy0tbGFiZWwgY2RzLS1za2VsZXRvblwiPjwvbGFiZWw+XG5cdFx0PGRpdlxuXHRcdFx0ZGF0YS1udW1iZXJpbnB1dFxuXHRcdFx0W2F0dHIuZGF0YS1pbnZhbGlkXT1cIihpbnZhbGlkID8gdHJ1ZSA6IG51bGwpXCJcblx0XHRcdGNsYXNzPVwiY2RzLS1udW1iZXJcIlxuXHRcdFx0W25nQ2xhc3NdPVwie1xuXHRcdFx0XHQnY2RzLS1udW1iZXItLWxpZ2h0JzogdGhlbWUgPT09ICdsaWdodCcsXG5cdFx0XHRcdCdjZHMtLW51bWJlci0tbm9sYWJlbCc6ICFsYWJlbCxcblx0XHRcdFx0J2Nkcy0tbnVtYmVyLS1oZWxwZXJ0ZXh0JzogaGVscGVyVGV4dCxcblx0XHRcdFx0J2Nkcy0tc2tlbGV0b24nIDogc2tlbGV0b24sXG5cdFx0XHRcdCdjZHMtLW51bWJlci0tc20nOiBzaXplID09PSAnc20nLFxuXHRcdFx0XHQnY2RzLS1udW1iZXItLW1kJzogc2l6ZSA9PT0gJ21kJyxcblx0XHRcdFx0J2Nkcy0tbnVtYmVyLS1sZyc6IHNpemUgPT09ICdsZydcblx0XHRcdH1cIj5cblx0XHRcdDxsYWJlbFxuXHRcdFx0XHQqbmdJZj1cIiFza2VsZXRvbiAmJiBsYWJlbFwiXG5cdFx0XHRcdFtmb3JdPVwiaWRcIlxuXHRcdFx0XHRjbGFzcz1cImNkcy0tbGFiZWxcIlxuXHRcdFx0XHRbbmdDbGFzc109XCJ7J2Nkcy0tbGFiZWwtLWRpc2FibGVkJzogZGlzYWJsZWR9XCI+XG5cdFx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCIhaXNUZW1wbGF0ZShsYWJlbClcIj57e2xhYmVsfX08L25nLWNvbnRhaW5lcj5cblx0XHRcdFx0PG5nLXRlbXBsYXRlICpuZ0lmPVwiaXNUZW1wbGF0ZShsYWJlbClcIiBbbmdUZW1wbGF0ZU91dGxldF09XCJsYWJlbFwiPjwvbmctdGVtcGxhdGU+XG5cdFx0XHQ8L2xhYmVsPlxuXHRcdFx0PGRpdlxuXHRcdFx0XHRjbGFzcz1cImNkcy0tbnVtYmVyX19pbnB1dC13cmFwcGVyXCJcblx0XHRcdFx0W25nQ2xhc3NdPVwie1xuXHRcdFx0XHRcdCdjZHMtLW51bWJlcl9faW5wdXQtd3JhcHBlci0td2FybmluZyc6IHdhcm5cblx0XHRcdFx0fVwiPlxuXHRcdFx0XHQ8aW5wdXRcblx0XHRcdFx0XHR0eXBlPVwibnVtYmVyXCJcblx0XHRcdFx0XHRbaWRdPVwiaWRcIlxuXHRcdFx0XHRcdFt2YWx1ZV09XCJ2YWx1ZVwiXG5cdFx0XHRcdFx0W2F0dHIubWluXT1cIm1pblwiXG5cdFx0XHRcdFx0W2F0dHIubWF4XT1cIm1heFwiXG5cdFx0XHRcdFx0W2F0dHIuc3RlcF09XCJzdGVwXCJcblx0XHRcdFx0XHRbZGlzYWJsZWRdPVwiZGlzYWJsZWRcIlxuXHRcdFx0XHRcdFtyZWFkb25seV09XCJyZWFkb25seVwiXG5cdFx0XHRcdFx0W3JlcXVpcmVkXT1cInJlcXVpcmVkXCJcblx0XHRcdFx0XHRbYXR0ci5hcmlhLWxhYmVsXT1cImFyaWFMYWJlbFwiXG5cdFx0XHRcdFx0W2F0dHIuZGF0YS1pbnZhbGlkXT1cImludmFsaWQgPyBpbnZhbGlkIDogbnVsbFwiXG5cdFx0XHRcdFx0W3BsYWNlaG9sZGVyXT1cInBsYWNlaG9sZGVyXCJcblx0XHRcdFx0XHQoZm9jdXMpPVwiZmx1aWQgPyBoYW5kbGVGb2N1cygkZXZlbnQpOiBudWxsXCJcblx0XHRcdFx0XHQoYmx1cik9XCJmbHVpZCA/IGhhbmRsZUZvY3VzKCRldmVudCk6IG51bGxcIlxuXHRcdFx0XHRcdChjaGFuZ2UpPVwib25OdW1iZXJJbnB1dENoYW5nZSgkZXZlbnQpXCIvPlxuXHRcdFx0XHQ8c3ZnXG5cdFx0XHRcdFx0Km5nSWY9XCIhc2tlbGV0b24gJiYgaW52YWxpZFwiXG5cdFx0XHRcdFx0Y2RzSWNvbj1cIndhcm5pbmctLWZpbGxlZFwiXG5cdFx0XHRcdFx0c2l6ZT1cIjE2XCJcblx0XHRcdFx0XHRjbGFzcz1cImNkcy0tbnVtYmVyX19pbnZhbGlkXCI+XG5cdFx0XHRcdDwvc3ZnPlxuXHRcdFx0XHQ8c3ZnXG5cdFx0XHRcdFx0Km5nSWY9XCIhc2tlbGV0b24gJiYgIWludmFsaWQgJiYgd2FyblwiXG5cdFx0XHRcdFx0Y2RzSWNvbj1cIndhcm5pbmctLWFsdC0tZmlsbGVkXCJcblx0XHRcdFx0XHRzaXplPVwiMTZcIlxuXHRcdFx0XHRcdGNsYXNzPVwiY2RzLS1udW1iZXJfX2ludmFsaWQgY2RzLS1udW1iZXJfX2ludmFsaWQtLXdhcm5pbmdcIj5cblx0XHRcdFx0PC9zdmc+XG5cdFx0XHRcdDxkaXYgKm5nSWY9XCIhc2tlbGV0b25cIiBjbGFzcz1cImNkcy0tbnVtYmVyX19jb250cm9sc1wiPlxuXHRcdFx0XHRcdDxidXR0b25cblx0XHRcdFx0XHRcdGNsYXNzPVwiY2RzLS1udW1iZXJfX2NvbnRyb2wtYnRuIGRvd24taWNvblwiXG5cdFx0XHRcdFx0XHR0eXBlPVwiYnV0dG9uXCJcblx0XHRcdFx0XHRcdFthdHRyLmRpc2FibGVkXT1cImRpc2FibGVkID8gdHJ1ZSA6IG51bGxcIlxuXHRcdFx0XHRcdFx0YXJpYS1saXZlPVwicG9saXRlXCJcblx0XHRcdFx0XHRcdGFyaWEtYXRvbWljPVwidHJ1ZVwiXG5cdFx0XHRcdFx0XHRbYXR0ci5hcmlhLWxhYmVsXT1cImdldERlY3JlbWVudExhYmVsKCkgfCBhc3luY1wiXG5cdFx0XHRcdFx0XHQoY2xpY2spPVwib25EZWNyZW1lbnQoKVwiPlxuXHRcdFx0XHRcdFx0PHN2ZyBjZHNJY29uPVwic3VidHJhY3RcIiBzaXplPVwiMTZcIj48L3N2Zz5cblx0XHRcdFx0XHQ8L2J1dHRvbj5cblx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwiY2RzLS1udW1iZXJfX3J1bGUtZGl2aWRlclwiPjwvZGl2PlxuXHRcdFx0XHRcdDxidXR0b25cblx0XHRcdFx0XHRcdGNsYXNzPVwiY2RzLS1udW1iZXJfX2NvbnRyb2wtYnRuIHVwLWljb25cIlxuXHRcdFx0XHRcdFx0dHlwZT1cImJ1dHRvblwiXG5cdFx0XHRcdFx0XHRbYXR0ci5kaXNhYmxlZF09XCJkaXNhYmxlZCA/IHRydWUgOiBudWxsXCJcblx0XHRcdFx0XHRcdGFyaWEtbGl2ZT1cInBvbGl0ZVwiXG5cdFx0XHRcdFx0XHRhcmlhLWF0b21pYz1cInRydWVcIlxuXHRcdFx0XHRcdFx0W2F0dHIuYXJpYS1sYWJlbF09XCJnZXRJbmNyZW1lbnRMYWJlbCgpIHwgYXN5bmNcIlxuXHRcdFx0XHRcdFx0KGNsaWNrKT1cIm9uSW5jcmVtZW50KClcIj5cblx0XHRcdFx0XHRcdDxzdmcgY2RzSWNvbj1cImFkZFwiIHNpemU9XCIxNlwiPjwvc3ZnPlxuXHRcdFx0XHRcdDwvYnV0dG9uPlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjZHMtLW51bWJlcl9fcnVsZS1kaXZpZGVyXCI+PC9kaXY+XG5cdFx0XHRcdDwvZGl2PlxuXHRcdFx0PC9kaXY+XG5cdFx0XHQ8aHIgKm5nSWY9XCJmbHVpZFwiIGNsYXNzPVwiY2RzLS1udW1iZXItaW5wdXRfX2RpdmlkZXJcIiAvPlxuXHRcdFx0PGRpdlxuXHRcdFx0XHQqbmdJZj1cImhlbHBlclRleHQgJiYgIWludmFsaWQgJiYgIXdhcm4gJiYgIWZsdWlkXCJcblx0XHRcdFx0Y2xhc3M9XCJjZHMtLWZvcm1fX2hlbHBlci10ZXh0XCJcblx0XHRcdFx0W25nQ2xhc3NdPVwie1xuXHRcdFx0XHRcdCdjZHMtLWZvcm1fX2hlbHBlci10ZXh0LS1kaXNhYmxlZCc6IGRpc2FibGVkXG5cdFx0XHRcdH1cIj5cblx0XHRcdFx0PG5nLWNvbnRhaW5lciAqbmdJZj1cIiFpc1RlbXBsYXRlKGhlbHBlclRleHQpXCI+e3toZWxwZXJUZXh0fX08L25nLWNvbnRhaW5lcj5cblx0XHRcdFx0PG5nLXRlbXBsYXRlICpuZ0lmPVwiaXNUZW1wbGF0ZShoZWxwZXJUZXh0KVwiIFtuZ1RlbXBsYXRlT3V0bGV0XT1cImhlbHBlclRleHRcIj48L25nLXRlbXBsYXRlPlxuXHRcdFx0PC9kaXY+XG5cdFx0XHQ8ZGl2ICpuZ0lmPVwiaW52YWxpZFwiIGNsYXNzPVwiY2RzLS1mb3JtLXJlcXVpcmVtZW50XCI+XG5cdFx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCIhaXNUZW1wbGF0ZShpbnZhbGlkVGV4dClcIj57e2ludmFsaWRUZXh0fX08L25nLWNvbnRhaW5lcj5cblx0XHRcdFx0PG5nLXRlbXBsYXRlICpuZ0lmPVwiaXNUZW1wbGF0ZShpbnZhbGlkVGV4dClcIiBbbmdUZW1wbGF0ZU91dGxldF09XCJpbnZhbGlkVGV4dFwiPjwvbmctdGVtcGxhdGU+XG5cdFx0XHQ8L2Rpdj5cblx0XHRcdDxkaXYgKm5nSWY9XCIhaW52YWxpZCAmJiB3YXJuXCIgY2xhc3M9XCJjZHMtLWZvcm0tcmVxdWlyZW1lbnRcIj5cblx0XHRcdFx0PG5nLWNvbnRhaW5lciAqbmdJZj1cIiFpc1RlbXBsYXRlKHdhcm5UZXh0KVwiPnt7d2FyblRleHR9fTwvbmctY29udGFpbmVyPlxuXHRcdFx0XHQ8bmctdGVtcGxhdGUgKm5nSWY9XCJpc1RlbXBsYXRlKHdhcm5UZXh0KVwiIFtuZ1RlbXBsYXRlT3V0bGV0XT1cIndhcm5UZXh0XCI+PC9uZy10ZW1wbGF0ZT5cblx0XHRcdDwvZGl2PlxuXHRcdDwvZGl2PlxuXHRgLFxuXHRwcm92aWRlcnM6IFtcblx0XHR7XG5cdFx0XHRwcm92aWRlOiBOR19WQUxVRV9BQ0NFU1NPUixcblx0XHRcdHVzZUV4aXN0aW5nOiBOdW1iZXJDb21wb25lbnQsXG5cdFx0XHRtdWx0aTogdHJ1ZVxuXHRcdH1cblx0XVxufSlcbmV4cG9ydCBjbGFzcyBOdW1iZXJDb21wb25lbnQgaW1wbGVtZW50cyBDb250cm9sVmFsdWVBY2Nlc3NvciB7XG5cdC8qKlxuXHQgKiBWYXJpYWJsZSB1c2VkIGZvciBjcmVhdGluZyB1bmlxdWUgaWRzIGZvciBudW1iZXIgaW5wdXQgY29tcG9uZW50cy5cblx0ICovXG5cdHN0YXRpYyBudW1iZXJDb3VudCA9IDA7XG5cblx0QEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS1mb3JtLWl0ZW1cIikgY29udGFpbmVyQ2xhc3MgPSB0cnVlO1xuXG5cdC8qKlxuXHQgKiBTZXQgdG8gYHRydWVgIGZvciByZWFkb25seSBzdGF0ZS5cblx0ICovXG5cdEBJbnB1dCgpIEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tbnVtYmVyLS1yZWFkb25seVwiKSByZWFkb25seSA9IGZhbHNlO1xuXHQvKipcblx0ICogQGRlcHJlY2F0ZWQgc2luY2UgdjUgLSBVc2UgYGNkc0xheWVyYCBkaXJlY3RpdmUgaW5zdGVhZFxuXHQgKiBgbGlnaHRgIG9yIGBkYXJrYCBudW1iZXIgaW5wdXQgdGhlbWUuXG5cdCAqL1xuXHRASW5wdXQoKSB0aGVtZTogXCJsaWdodFwiIHwgXCJkYXJrXCIgPSBcImRhcmtcIjtcblx0LyoqXG5cdCAqIFNldCB0byBgdHJ1ZWAgZm9yIGEgZGlzYWJsZWQgbnVtYmVyIGlucHV0LlxuXHQgKi9cblx0QElucHV0KCkgZGlzYWJsZWQgPSBmYWxzZTtcblx0LyoqXG5cdCAqIFNldCB0byBgdHJ1ZWAgZm9yIGEgbG9hZGluZyBudW1iZXIgY29tcG9uZW50LlxuXHQgKi9cblx0QElucHV0KCkgc2tlbGV0b24gPSBmYWxzZTtcblx0LyoqXG5cdCAqIFNldCB0byBgdHJ1ZWAgZm9yIGFuIGludmFsaWQgbnVtYmVyIGNvbXBvbmVudC5cblx0ICovXG5cdEBJbnB1dCgpIGludmFsaWQgPSBmYWxzZTtcblx0LyoqXG5cdCAqIFRoZSB1bmlxdWUgaWQgZm9yIHRoZSBudW1iZXIgY29tcG9uZW50LlxuXHQgKi9cblx0QElucHV0KCkgaWQgPSBgbnVtYmVyLSR7TnVtYmVyQ29tcG9uZW50Lm51bWJlckNvdW50fWA7XG5cdC8qKlxuXHQgKiBTZXRzIHRoZSBwbGFjZWhvbGRlciBhdHRyaWJ1dGUgb24gdGhlIGBpbnB1dGAgZWxlbWVudC5cblx0ICovXG5cdEBJbnB1dCgpIHBsYWNlaG9sZGVyID0gXCJcIjtcblx0LyoqXG5cdCAqIE51bWJlciBpbnB1dCBmaWVsZCByZW5kZXIgc2l6ZVxuXHQgKi9cblx0QElucHV0KCkgc2l6ZTogXCJzbVwiIHwgXCJtZFwiIHwgXCJsZ1wiID0gXCJtZFwiO1xuXHQvKipcblx0ICogUmVmbGVjdHMgdGhlIHJlcXVpcmVkIGF0dHJpYnV0ZSBvZiB0aGUgYGlucHV0YCBlbGVtZW50LlxuXHQgKi9cblx0QElucHV0KCkgcmVxdWlyZWQ6IGJvb2xlYW47XG5cdC8qKlxuXHQgKiBTZXRzIHRoZSB2YWx1ZSBhdHRyaWJ1dGUgb24gdGhlIGBpbnB1dGAgZWxlbWVudC5cblx0ICovXG5cdEBJbnB1dCgpIHNldCB2YWx1ZSh2OiBhbnkpIHtcblx0XHRpZiAodiA9PT0gXCJcIiB8fCB2ID09PSBudWxsKSB7XG5cdFx0XHR0aGlzLl92YWx1ZSA9IG51bGw7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdHRoaXMuX3ZhbHVlID0gTnVtYmVyKHYpO1xuXHR9XG5cblx0Z2V0IHZhbHVlKCkge1xuXHRcdHJldHVybiB0aGlzLl92YWx1ZTtcblx0fVxuXHQvKipcblx0ICogU2V0cyB0aGUgbWluIGF0dHJpYnV0ZSBvbiB0aGUgYGlucHV0YCBlbGVtZW50LlxuXHQgKi9cblx0QElucHV0KCkgbWluID0gbnVsbDtcblx0LyoqXG5cdCAqIFNldHMgdGhlIG1heCBhdHRyaWJ1dGUgb24gdGhlIGBpbnB1dGAgZWxlbWVudC5cblx0ICovXG5cdEBJbnB1dCgpIG1heCA9IG51bGw7XG5cdC8qKlxuXHQgKiBTZXRzIHRoZSB0ZXh0IGluc2lkZSB0aGUgYGxhYmVsYCB0YWcuXG5cdCAqL1xuXHRASW5wdXQoKSBsYWJlbDogc3RyaW5nIHwgVGVtcGxhdGVSZWY8YW55Pjtcblx0LyoqXG5cdCAqIFNldHMgdGhlIG9wdGlvbmFsIGhlbHBlciB0ZXh0LlxuXHQgKi9cblx0QElucHV0KCkgaGVscGVyVGV4dDogc3RyaW5nIHwgVGVtcGxhdGVSZWY8YW55Pjtcblx0LyoqXG5cdCAqIFNldHMgdGhlIGludmFsaWQgdGV4dC5cblx0ICovXG5cdEBJbnB1dCgpIGludmFsaWRUZXh0OiBzdHJpbmcgfCBUZW1wbGF0ZVJlZjxhbnk+O1xuXHQvKipcblx0ICogU2V0cyB0aGUgYW1vdW50IHRoZSBudW1iZXIgY29udHJvbHMgaW5jcmVtZW50IGFuZCBkZWNyZW1lbnQgYnkuXG5cdCAqL1xuXHRASW5wdXQoKSBzdGVwID0gMTtcblx0LyoqXG5cdCAqIElmIGBzdGVwYCBpcyBhIGRlY2ltYWwsIHdlIG1heSB3YW50IHByZWNpc2lvbiB0byBiZSBzZXQgdG8gZ28gYXJvdW5kIGZsb2F0aW5nIHBvaW50IHByZWNpc2lvbi5cblx0ICovXG5cdEBJbnB1dCgpIHByZWNpc2lvbjogbnVtYmVyO1xuXHQvKipcblx0ICogU2V0IHRvIGB0cnVlYCB0byBzaG93IGEgd2FybmluZyAoY29udGVudHMgc2V0IGJ5IHdhcm5pbmdUZXh0KVxuXHQgKi9cblx0QElucHV0KCkgd2FybiA9IGZhbHNlO1xuXHQvKipcblx0ICogU2V0cyB0aGUgd2FybmluZyB0ZXh0XG5cdCAqL1xuXHRASW5wdXQoKSB3YXJuVGV4dDogc3RyaW5nIHwgVGVtcGxhdGVSZWY8YW55Pjtcblx0LyoqXG5cdCAqIFNldHMgdGhlIGFyaWFsYWJlbCBmb3IgaW5wdXRcblx0ICovXG5cdEBJbnB1dCgpIGFyaWFMYWJlbDogc3RyaW5nO1xuXHQvKipcblx0ICogRW1pdHMgZXZlbnQgbm90aWZ5aW5nIG90aGVyIGNsYXNzZXMgd2hlbiBhIGNoYW5nZSBpbiBzdGF0ZSBvY2N1cnMgaW4gdGhlIGlucHV0LlxuXHQgKi9cblx0QE91dHB1dCgpIGNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8TnVtYmVyQ2hhbmdlPigpO1xuXG5cdEBJbnB1dCgpXG5cdHNldCBkZWNyZW1lbnRMYWJlbCh2YWx1ZTogc3RyaW5nIHwgT2JzZXJ2YWJsZTxzdHJpbmc+KSB7XG5cdFx0dGhpcy5fZGVjcmVtZW50TGFiZWwub3ZlcnJpZGUodmFsdWUpO1xuXHR9XG5cblx0Z2V0IGRlY3JlbWVudExhYmVsKCkge1xuXHRcdHJldHVybiB0aGlzLl9kZWNyZW1lbnRMYWJlbC52YWx1ZTtcblx0fVxuXG5cdEBJbnB1dCgpXG5cdHNldCBpbmNyZW1lbnRMYWJlbCh2YWx1ZTogc3RyaW5nIHwgT2JzZXJ2YWJsZTxzdHJpbmc+KSB7XG5cdFx0dGhpcy5faW5jcmVtZW50TGFiZWwub3ZlcnJpZGUodmFsdWUpO1xuXHR9XG5cblx0Z2V0IGluY3JlbWVudExhYmVsKCkge1xuXHRcdHJldHVybiB0aGlzLl9pbmNyZW1lbnRMYWJlbC52YWx1ZTtcblx0fVxuXG5cdC8qKlxuXHQgKiBFeHBlcmltZW50YWw6IGVuYWJsZSBmbHVpZCBzdGF0ZVxuXHQgKi9cblx0QEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS1udW1iZXItaW5wdXQtLWZsdWlkXCIpIEBJbnB1dCgpIGZsdWlkID0gZmFsc2U7XG5cblx0QEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS1udW1iZXItaW5wdXQtLWZsdWlkLS1pbnZhbGlkXCIpIGdldCBmbHVpZEludmFsaWQoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZmx1aWQgJiYgdGhpcy5pbnZhbGlkO1xuXHR9XG5cblx0QEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS1udW1iZXItaW5wdXQtLWZsdWlkLS1kaXNhYmxlZFwiKSBnZXQgZmx1aWREaXNhYmxlZCgpIHtcblx0XHRyZXR1cm4gdGhpcy5mbHVpZCAmJiB0aGlzLmRpc2FibGVkO1xuXHR9XG5cblx0QEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS1udW1iZXItaW5wdXQtLWZsdWlkLS1mb2N1c1wiKSBnZXQgZmx1aWRGb2N1cygpIHtcblx0XHRyZXR1cm4gdGhpcy5mbHVpZCAmJiB0aGlzLl9pc0ZvY3VzZWQ7XG5cdH1cblxuXHRASG9zdEJpbmRpbmcoXCJjbGFzcy5jZHMtLXRleHQtaW5wdXQtLWZsdWlkX19za2VsZXRvblwiKSBnZXQgZmx1aWRTa2VsZXRvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5mbHVpZCAmJiB0aGlzLnNrZWxldG9uO1xuXHR9XG5cblx0cHJvdGVjdGVkIF9pc0ZvY3VzZWQgPSBmYWxzZTtcblxuXHRwcm90ZWN0ZWQgX3ZhbHVlID0gMDtcblxuXHRwcm90ZWN0ZWQgX2RlY3JlbWVudExhYmVsOiBPdmVycmlkYWJsZSA9IHRoaXMuaTE4bi5nZXRPdmVycmlkYWJsZShcIk5VTUJFUi5ERUNSRU1FTlRcIik7XG5cdHByb3RlY3RlZCBfaW5jcmVtZW50TGFiZWw6IE92ZXJyaWRhYmxlID0gdGhpcy5pMThuLmdldE92ZXJyaWRhYmxlKFwiTlVNQkVSLklOQ1JFTUVOVFwiKTtcblxuXHQvKipcblx0ICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBgTnVtYmVyYC5cblx0ICovXG5cdGNvbnN0cnVjdG9yKHByb3RlY3RlZCBpMThuOiBJMThuKSB7XG5cdFx0TnVtYmVyQ29tcG9uZW50Lm51bWJlckNvdW50Kys7XG5cdH1cblxuXHQvKipcblx0ICogVGhpcyBpcyB0aGUgaW5pdGlhbCB2YWx1ZSBzZXQgdG8gdGhlIGNvbXBvbmVudFxuXHQgKiBAcGFyYW0gdmFsdWUgVGhlIGlucHV0IHZhbHVlLlxuXHQgKi9cblx0cHVibGljIHdyaXRlVmFsdWUodmFsdWU6IGFueSkge1xuXHRcdHRoaXMudmFsdWUgPSB2YWx1ZTtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZXRzIGEgbWV0aG9kIGluIG9yZGVyIHRvIHByb3BhZ2F0ZSBjaGFuZ2VzIGJhY2sgdG8gdGhlIGZvcm0uXG5cdCAqL1xuXHRwdWJsaWMgcmVnaXN0ZXJPbkNoYW5nZShmbjogYW55KSB7XG5cdFx0dGhpcy5wcm9wYWdhdGVDaGFuZ2UgPSBmbjtcblx0fVxuXG5cdC8qKlxuXHQgKiBSZWdpc3RlcnMgYSBjYWxsYmFjayB0byBiZSB0cmlnZ2VyZWQgd2hlbiB0aGUgY29udHJvbCBoYXMgYmVlbiB0b3VjaGVkLlxuXHQgKiBAcGFyYW0gZm4gQ2FsbGJhY2sgdG8gYmUgdHJpZ2dlcmVkIHdoZW4gdGhlIG51bWJlciBpbnB1dCBpcyB0b3VjaGVkLlxuXHQgKi9cblx0cHVibGljIHJlZ2lzdGVyT25Ub3VjaGVkKGZuOiBhbnkpIHtcblx0XHR0aGlzLm9uVG91Y2hlZCA9IGZuO1xuXHR9XG5cblx0QEhvc3RMaXN0ZW5lcihcImZvY3Vzb3V0XCIpXG5cdGZvY3VzT3V0KCkge1xuXHRcdHRoaXMub25Ub3VjaGVkKCk7XG5cdH1cblxuXHQvKipcblx0ICogU2V0cyB0aGUgZGlzYWJsZWQgc3RhdGUgdGhyb3VnaCB0aGUgbW9kZWxcblx0ICovXG5cdHNldERpc2FibGVkU3RhdGUoaXNEaXNhYmxlZDogYm9vbGVhbikge1xuXHRcdHRoaXMuZGlzYWJsZWQgPSBpc0Rpc2FibGVkO1xuXHR9XG5cblx0LyoqXG5cdCAqIENhbGxlZCB3aGVuIG51bWJlciBpbnB1dCBpcyBibHVycmVkLiBOZWVkZWQgdG8gcHJvcGVybHkgaW1wbGVtZW50IGBDb250cm9sVmFsdWVBY2Nlc3NvcmAuXG5cdCAqL1xuXHRvblRvdWNoZWQ6ICgpID0+IGFueSA9ICgpID0+IHsgfTtcblxuXHQvKipcblx0ICogTWV0aG9kIHNldCBpbiBgcmVnaXN0ZXJPbkNoYW5nZWAgdG8gcHJvcGFnYXRlIGNoYW5nZXMgYmFjayB0byB0aGUgZm9ybS5cblx0ICovXG5cdHByb3BhZ2F0ZUNoYW5nZSA9IChfOiBhbnkpID0+IHsgfTtcblxuXHQvKipcblx0ICogQWRkcyBgc3RlcGAgdG8gdGhlIGN1cnJlbnQgYHZhbHVlYC5cblx0ICovXG5cdG9uSW5jcmVtZW50KCk6IHZvaWQge1xuXHRcdC8vIGlmIG1heCBpcyBzZXQgYW5kIHZhbHVlICsgc3RlcCBpcyBncmVhdGVyIHRoYW4gbWF4LCBzZXQgdmFsdWUgdG8gbWF4XG5cdFx0Ly8gZXhhbXBsZTogbWF4ID0gMTAwLCBzdGVwID0gMTAsIHZhbHVlID0gOTUgLCB2YWx1ZSArIHN0ZXAgPSAxMDUsIHZhbHVlIHdpbGwgYmUgc2V0IHRvIDEwMCAobWF4KSBpbnN0ZWFkIG9mIDEwNVxuXHRcdGlmICh0aGlzLm1heCAhPT0gbnVsbCAmJiB0aGlzLnZhbHVlICsgdGhpcy5zdGVwID4gdGhpcy5tYXgpIHtcblx0XHRcdHRoaXMudmFsdWUgPSB0aGlzLm1heDtcblx0XHRcdHRoaXMuZW1pdENoYW5nZUV2ZW50KCk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gaWYgbWluIGlzIHNldCBhbmQgdmFsdWUgKyBzdGVwIGlzIGxlc3MgdGhhbiBtaW4sIHNldCB2YWx1ZSB0byBtaW5cblx0XHQvLyBleGFtcGxlOiBtaW4gPSA1LCBzdGVwID0gMiwgdmFsdWUgPSAwLCB2YWx1ZSArIHN0ZXAgPSAyLCB2YWx1ZSB3aWxsIGJlIHNldCB0byA1IChtaW4pIGluc3RlYWQgb2YgMlxuXHRcdGlmICh0aGlzLm1pbiAhPT0gbnVsbCAmJiB0aGlzLnZhbHVlICsgdGhpcy5zdGVwIDwgdGhpcy5taW4pIHtcblx0XHRcdHRoaXMudmFsdWUgPSB0aGlzLm1pbjtcblx0XHRcdHRoaXMuZW1pdENoYW5nZUV2ZW50KCk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gaWYgbWF4IGlzIG5vdCBzZXQgb3IgdmFsdWUgKyBzdGVwIGlzIGxlc3MgdGhhbiBtYXgsIGluY3JlbWVudCB2YWx1ZSBieSBzdGVwXG5cdFx0aWYgKHRoaXMubWF4ID09PSBudWxsIHx8IHRoaXMudmFsdWUgKyB0aGlzLnN0ZXAgPD0gdGhpcy5tYXgpIHtcblx0XHRcdHRoaXMudmFsdWUgKz0gdGhpcy5zdGVwO1xuXHRcdFx0dGhpcy52YWx1ZSA9IHBhcnNlRmxvYXQodGhpcy52YWx1ZS50b1ByZWNpc2lvbih0aGlzLnByZWNpc2lvbikpO1xuXHRcdFx0dGhpcy5lbWl0Q2hhbmdlRXZlbnQoKTtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogU3VidHJhY3RzIGBzdGVwYCB0byB0aGUgY3VycmVudCBgdmFsdWVgLlxuXHQgKi9cblx0b25EZWNyZW1lbnQoKTogdm9pZCB7XG5cdFx0Ly8gaWYgbWF4IGlzIHNldCBhbmQgdmFsdWUgLSBzdGVwIGlzIGdyZWF0ZXIgdGhhbiBtYXgsIHNldCB2YWx1ZSB0byBtYXhcblx0XHQvLyBleGFtcGxlOiBtYXggPSAxNSwgc3RlcCA9IDIsIHZhbHVlID0gMjAsIHZhbHVlIC0gc3RlcCA9IDE4LCB2YWx1ZSB3aWxsIGJlIHNldCB0byAxNSAobWF4KSBpbnN0ZWFkIG9mIDE4XG5cdFx0aWYgKHRoaXMubWF4ICE9PSBudWxsICYmIHRoaXMudmFsdWUgLSB0aGlzLnN0ZXAgPiB0aGlzLm1heCkge1xuXHRcdFx0dGhpcy52YWx1ZSA9IHRoaXMubWF4O1xuXHRcdFx0dGhpcy5lbWl0Q2hhbmdlRXZlbnQoKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBpZiBtaW4gaXMgc2V0IGFuZCB2YWx1ZSAtIHN0ZXAgaXMgbGVzcyB0aGFuIG1pbiwgc2V0IHZhbHVlIHRvIG1pblxuXHRcdC8vIGV4YW1wbGU6IG1pbiA9IDUsIHN0ZXAgPSAyLCB2YWx1ZSA9IDYsIHZhbHVlIC0gc3RlcCA9IDQsIHZhbHVlIHdpbGwgYmUgc2V0IHRvIDUgKG1pbikgaW5zdGVhZCBvZiA0XG5cdFx0aWYgKHRoaXMubWluICE9PSBudWxsICYmIHRoaXMudmFsdWUgLSB0aGlzLnN0ZXAgPCB0aGlzLm1pbikge1xuXHRcdFx0dGhpcy52YWx1ZSA9IHRoaXMubWluO1xuXHRcdFx0dGhpcy5lbWl0Q2hhbmdlRXZlbnQoKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBpZiBtaW4gaXMgbm90IHNldCBvciB2YWx1ZSAtIHN0ZXAgaXMgZ3JlYXRlciB0aGFuIG1pbiwgZGVjcmVtZW50IHZhbHVlIGJ5IHN0ZXBcblx0XHRpZiAodGhpcy5taW4gPT09IG51bGwgfHwgdGhpcy52YWx1ZSAtIHRoaXMuc3RlcCA+PSB0aGlzLm1pbikge1xuXHRcdFx0dGhpcy52YWx1ZSAtPSB0aGlzLnN0ZXA7XG5cdFx0XHR0aGlzLnZhbHVlID0gcGFyc2VGbG9hdCh0aGlzLnZhbHVlLnRvUHJlY2lzaW9uKHRoaXMucHJlY2lzaW9uKSk7XG5cdFx0XHR0aGlzLmVtaXRDaGFuZ2VFdmVudCgpO1xuXHRcdH1cblx0fVxuXG5cdGdldERlY3JlbWVudExhYmVsKCk6IE9ic2VydmFibGU8c3RyaW5nPiB7XG5cdFx0cmV0dXJuIHRoaXMuX2RlY3JlbWVudExhYmVsLnN1YmplY3Q7XG5cdH1cblxuXHRnZXRJbmNyZW1lbnRMYWJlbCgpOiBPYnNlcnZhYmxlPHN0cmluZz4ge1xuXHRcdHJldHVybiB0aGlzLl9pbmNyZW1lbnRMYWJlbC5zdWJqZWN0O1xuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZXMgYSBjbGFzcyBvZiBgTnVtYmVyQ2hhbmdlYCB0byBlbWl0IHRoZSBjaGFuZ2UgaW4gdGhlIGBOdW1iZXJgLlxuXHQgKi9cblx0ZW1pdENoYW5nZUV2ZW50KCk6IHZvaWQge1xuXHRcdGxldCBldmVudCA9IG5ldyBOdW1iZXJDaGFuZ2UoKTtcblx0XHRldmVudC5zb3VyY2UgPSB0aGlzO1xuXHRcdGV2ZW50LnZhbHVlID0gdGhpcy52YWx1ZTtcblx0XHR0aGlzLmNoYW5nZS5lbWl0KGV2ZW50KTtcblx0XHR0aGlzLnByb3BhZ2F0ZUNoYW5nZSh0aGlzLnZhbHVlKTtcblx0fVxuXG5cdG9uTnVtYmVySW5wdXRDaGFuZ2UoZXZlbnQpIHtcblx0XHR0aGlzLnZhbHVlID0gZXZlbnQudGFyZ2V0LnZhbHVlO1xuXHRcdHRoaXMuZW1pdENoYW5nZUV2ZW50KCk7XG5cdH1cblxuXHRwdWJsaWMgaXNUZW1wbGF0ZSh2YWx1ZSkge1xuXHRcdHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIFRlbXBsYXRlUmVmO1xuXHR9XG5cblx0aGFuZGxlRm9jdXMoZXZlbnQ6IEZvY3VzRXZlbnQpIHtcblx0XHRpZiAoXCJ0eXBlXCIgaW4gZXZlbnQudGFyZ2V0ICYmICg8SFRNTElucHV0RWxlbWVudD5ldmVudC50YXJnZXQpLnR5cGUgPT09IFwiYnV0dG9uXCIpIHtcblx0XHRcdHRoaXMuX2lzRm9jdXNlZCA9IGZhbHNlO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLl9pc0ZvY3VzZWQgPSBldmVudC50eXBlID09PSBcImZvY3VzXCI7XG5cdFx0fVxuXHR9XG59XG5leHBvcnQgeyBOdW1iZXJDb21wb25lbnQgYXMgTnVtYmVyIH07XG4iXX0=