UNPKG

@microsoft/windows-admin-center-sdk

Version:

Microsoft - Windows Admin Center Shell

390 lines 55 kB
import { __decorate, __metadata } from "tslib"; import { Component, ElementRef, Injector, Input, ViewChild } from '@angular/core'; import { Validators } from '@angular/forms'; import { KeyCode } from '@microsoft/windows-admin-center-sdk/core/data/accessibility-manager'; import { SmeSchemaProperty } from '../../../schema/schema-decorator'; import { SimplePropertySchemaFieldLoaderComponent } from '../../../schema/schema-field-host.component'; import { SchemaPrimitiveType } from '../../../schema/schema-models'; import { ValidationAlertSeverity } from '../../validation-alert/validation-alert'; import { SmeInternalFormFieldComponent } from '../form-field.component'; import * as i0 from "@angular/core"; import * as i1 from "@angular/forms"; import * as i2 from "../form-field-accessor.directive"; import * as i3 from "../form-field-validator.directive"; import * as i4 from "../form-field-async-validator.directive"; import * as i5 from "@angular/common"; import * as i6 from "../../validation-alert/validation-alert.component"; import * as i7 from "../../form-field-layout/form-field-layout.component"; const _c0 = ["input"]; const _c1 = ["container"]; const _c2 = ["incrementButton"]; const _c3 = ["decrementButton"]; const _c4 = ["type", "number"]; function NumberFormFieldComponent_span_2_Template(rf, ctx) { if (rf & 1) { i0.ɵɵelementStart(0, "span"); i0.ɵɵtext(1); i0.ɵɵelementEnd(); } if (rf & 2) { const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵadvance(1); i0.ɵɵtextInterpolate(ctx_r0.value); } } function NumberFormFieldComponent_div_3_span_4_Template(rf, ctx) { if (rf & 1) { const _r8 = i0.ɵɵgetCurrentView(); i0.ɵɵelementStart(0, "span", 10)(1, "button", 11, 12); i0.ɵɵlistener("click", function NumberFormFieldComponent_div_3_span_4_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r8); const ctx_r7 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r7.increment()); }); i0.ɵɵelement(3, "span", 13); i0.ɵɵelementEnd(); i0.ɵɵelementStart(4, "button", 11, 14); i0.ɵɵlistener("click", function NumberFormFieldComponent_div_3_span_4_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r8); const ctx_r9 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r9.decrement()); }); i0.ɵɵelement(6, "span", 15); i0.ɵɵelementEnd()(); } if (rf & 2) { const ctx_r4 = i0.ɵɵnextContext(2); i0.ɵɵadvance(1); i0.ɵɵattribute("aria-label", ctx_r4.ariaLabelIncrease); i0.ɵɵadvance(3); i0.ɵɵattribute("aria-label", ctx_r4.ariaLabelDecrease); } } function NumberFormFieldComponent_div_3_Template(rf, ctx) { if (rf & 1) { const _r11 = i0.ɵɵgetCurrentView(); i0.ɵɵelementStart(0, "div", 5, 6)(2, "input", 7, 8); i0.ɵɵlistener("ngModelChange", function NumberFormFieldComponent_div_3_Template_input_ngModelChange_2_listener($event) { i0.ɵɵrestoreView(_r11); const ctx_r10 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r10.value = $event); })("focus", function NumberFormFieldComponent_div_3_Template_input_focus_2_listener($event) { i0.ɵɵrestoreView(_r11); const ctx_r12 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r12.onInputFocus($event)); })("focusout", function NumberFormFieldComponent_div_3_Template_input_focusout_2_listener($event) { i0.ɵɵrestoreView(_r11); const ctx_r13 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r13.onInputFocusOut($event)); })("keydown", function NumberFormFieldComponent_div_3_Template_input_keydown_2_listener($event) { i0.ɵɵrestoreView(_r11); const ctx_r14 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r14.onInputKeydown($event)); }); i0.ɵɵelementEnd(); i0.ɵɵtemplate(4, NumberFormFieldComponent_div_3_span_4_Template, 7, 2, "span", 9); i0.ɵɵelementEnd(); } if (rf & 2) { const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵadvance(2); i0.ɵɵproperty("ngModel", ctx_r1.value)("required", ctx_r1.required)("disabled", ctx_r1.loadingOrDisabled)("max", ctx_r1.max)("min", ctx_r1.min)("step", ctx_r1.step)("placeholder", ctx_r1.placeholder); i0.ɵɵattribute("role", ctx_r1.showSpinButton ? "spinbutton" : null)("aria-valuemax", ctx_r1.max)("aria-valuemin", ctx_r1.min)("aria-label", ctx_r1.label)("aria-required", ctx_r1.required); i0.ɵɵadvance(2); i0.ɵɵproperty("ngIf", ctx_r1.showSpinButton); } } /* eslint-disable max-len */ /* eslint-enable max-len */ export class NumberFormFieldLoaderComponent extends SimplePropertySchemaFieldLoaderComponent { } /** @nocollapse */ NumberFormFieldLoaderComponent.ɵfac = /** @pureOrBreakMyCode */ function () { let ɵNumberFormFieldLoaderComponent_BaseFactory; return function NumberFormFieldLoaderComponent_Factory(t) { return (ɵNumberFormFieldLoaderComponent_BaseFactory || (ɵNumberFormFieldLoaderComponent_BaseFactory = i0.ɵɵgetInheritedFactory(NumberFormFieldLoaderComponent)))(t || NumberFormFieldLoaderComponent); }; }(); /** @nocollapse */ NumberFormFieldLoaderComponent.ɵcmp = /** @pureOrBreakMyCode */ i0.ɵɵdefineComponent({ type: NumberFormFieldLoaderComponent, selectors: [["ng-component"]], features: [i0.ɵɵInheritDefinitionFeature], decls: 2, vars: 14, consts: [["type", "number", 3, "ngModel", "name", "label", "required", "description", "readonly", "disabled", "min", "max", "step", "showSpinButton", "pendingMessage", "customAsyncValidateDisabled", "customAsyncValidateDebounceTime", "ngModelChange", "customValidate", "customAsyncValidate"], ["field", ""]], template: function NumberFormFieldLoaderComponent_Template(rf, ctx) { if (rf & 1) { i0.ɵɵelementStart(0, "sme-form-field", 0, 1); i0.ɵɵlistener("ngModelChange", function NumberFormFieldLoaderComponent_Template_sme_form_field_ngModelChange_0_listener($event) { return ctx.data = $event; })("customValidate", function NumberFormFieldLoaderComponent_Template_sme_form_field_customValidate_0_listener($event) { return ctx.resolveFunction(ctx.propertySchema.customValidation)($event); })("customAsyncValidate", function NumberFormFieldLoaderComponent_Template_sme_form_field_customAsyncValidate_0_listener($event) { return ctx.propertySchema.customAsyncValidation && ctx.resolveFunction(ctx.propertySchema.customAsyncValidation.handler)($event); }); i0.ɵɵelementEnd(); } if (rf & 2) { i0.ɵɵproperty("ngModel", ctx.data)("name", ctx.propertySchema.name)("label", ctx.localize(ctx.propertySchema.label))("required", ctx.propertySchema.required)("description", ctx.localize(ctx.propertySchema.description))("readonly", !!ctx.evalExpression(ctx.propertySchema.readonlyCondition))("disabled", !!(ctx.propertySchema.disabledCondition && ctx.evalExpression(ctx.propertySchema.disabledCondition)))("min", ctx.propertySchema.options && ctx.propertySchema.options.min)("max", ctx.propertySchema.options && ctx.propertySchema.options.max)("step", ctx.propertySchema.options && ctx.propertySchema.options.step)("showSpinButton", ctx.propertySchema.options && ctx.propertySchema.options.showSpinButton)("pendingMessage", ctx.propertySchema.customAsyncValidation && ctx.localize(ctx.propertySchema.customAsyncValidation.pendingMessage))("customAsyncValidateDisabled", ctx.shouldCustomAsyncValidationBeDisabled())("customAsyncValidateDebounceTime", ctx.propertySchema.customAsyncValidation && +ctx.propertySchema.customAsyncValidation.handler); } }, dependencies: function () { return [i1.NgControlStatus, i1.RequiredValidator, i1.NgModel, NumberFormFieldComponent, i2.FormFieldAccessorDirective, i3.FormFieldValidatorDirective, i4.FormFieldAsyncValidatorDirective]; }, encapsulation: 2 }); (function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(NumberFormFieldLoaderComponent, [{ type: Component, args: [{ template: "<sme-form-field #field type=\"number\" [(ngModel)]=\"data\"\r\n [name]=\"propertySchema.name\"\r\n [label]=\"localize(propertySchema.label)\"\r\n [required]=\"propertySchema.required\"\r\n [description]=\"localize(propertySchema.description)\"\r\n [readonly]=\"!!evalExpression(propertySchema.readonlyCondition)\"\r\n [disabled]=\"!!(propertySchema.disabledCondition && evalExpression(propertySchema.disabledCondition))\"\r\n [min]=\"propertySchema.options && propertySchema.options.min\"\r\n [max]=\"propertySchema.options && propertySchema.options.max\"\r\n [step]=\"propertySchema.options && propertySchema.options.step\"\r\n [showSpinButton]=\"propertySchema.options && propertySchema.options.showSpinButton\"\r\n [pendingMessage]=\"propertySchema.customAsyncValidation && localize(propertySchema.customAsyncValidation.pendingMessage)\"\r\n [customAsyncValidateDisabled]=\"shouldCustomAsyncValidationBeDisabled()\"\r\n [customAsyncValidateDebounceTime]=\"propertySchema.customAsyncValidation && +propertySchema.customAsyncValidation.handler\"\r\n (customValidate)=\"resolveFunction(propertySchema.customValidation)($event)\"\r\n (customAsyncValidate)=\"propertySchema.customAsyncValidation && resolveFunction(propertySchema.customAsyncValidation.handler)($event)\">\r\n</sme-form-field>\r\n" }] }], null, null); })(); /** * Accessible number field implementation */ let NumberFormFieldComponent = class NumberFormFieldComponent extends SmeInternalFormFieldComponent { /** * Initializes a new instance of the SliderFormFieldComponent */ constructor(injector) { super(injector); /** * It determine whether to show the spin button. */ this.showSpinButton = false; this.min = 0; // No default maximum/step } /** * The source name to use for logging */ get logSourceName() { return 'NumberFormFieldComponent'; } ngOnInit() { super.ngOnInit(); // If incrementBy is not set, use step. If step is not set default to 1 (one) this.incrementBy = MsftSme.isNullOrUndefined(this.incrementBy) ? MsftSme.isNullOrUndefined(this.step) ? 1 : this.step : this.incrementBy; } /** * Getter aria label increase for spin button increase. */ get ariaLabelIncrease() { return this.strings.MsftSmeShell.Angular.Form.SpinButton.increase.format(this.incrementBy); } /** * Getter aria label increase for spin button decrease. */ get ariaLabelDecrease() { return this.strings.MsftSmeShell.Angular.Form.SpinButton.decrease.format(this.incrementBy); } /** * Handle keydown events on the number input */ onInputKeydown($event) { // In Microsoft Edge and IE, numeric inputs will scroll the page while incrementing/decrementing the number. switch ($event.keyCode) { case KeyCode.UpArrow: { $event.preventDefault(); // firing the click event to trigger the click style to render this.increment(); this.toggleFocusEvent(this.incrementButton, true); setTimeout(() => { this.toggleFocusEvent(this.incrementButton, false); }); break; } case KeyCode.DownArrow: { $event.preventDefault(); // firing the click event to trigger the click style to render this.decrement(); this.toggleFocusEvent(this.decrementButton, true); setTimeout(() => { this.toggleFocusEvent(this.decrementButton, false); }); break; } default: { return; } } } /** * Increments the controls value by 1 "step" */ increment() { let value = MsftSme.isNumber(this.value) ? this.value : this.min - 1; value += this.incrementBy; if (value > this.max) { value = this.max; } this.value = value; } /** * Decrements the controls value by 1 "step" */ decrement() { let value = MsftSme.isNumber(this.value) ? this.value : this.min + 1; value -= this.incrementBy; if (value < this.min) { value = this.min; } this.value = value; } /** * The functionality to focus on the input field */ onInputFocus($event) { if ($event) { $event.preventDefault(); } this.toggleFocusEvent(this.container, true); } /** * The functionality to focus out on the input field * * @param $event the focus event object */ onInputFocusOut($event) { if ($event) { $event.preventDefault(); } this.toggleFocusEvent(this.container, false); } /** * Creates the idBag used by this component to store unique element ids. * id values will be assigned be the @see BaseComponent super class. */ createIdBag() { return { detailsSpan: '' }; } /** * Determines the value to use when clearing the field based on the initial value type */ getClearValue() { return MsftSme.isNullOrUndefined(this.min) ? 0 : this.min; } /** * Performs validation that is internal to this control * @param c The form control attached to this instance */ validate(c) { // if not required, don't process null or empty values for further validation if (!this.required && (MsftSme.isNullOrWhiteSpace(c.value))) { return super.validate(c); } if (!MsftSme.isNumber(this.value)) { return { notANumber: { valid: false, message: this.strings.MsftSmeShell.Angular.Common.Form.Validation.isNumber.format.format(this.fieldName), severity: ValidationAlertSeverity.Error } }; } // angular's min and max validator only work via code. So we implement them here. if (!MsftSme.isNullOrUndefined(this.min) && this.value < this.min) { const errors = Validators.min(this.min)(c); if (errors) { return errors; } } if (!MsftSme.isNullOrUndefined(this.max) && this.value > this.max) { const errors = Validators.max(this.max)(c); if (errors) { return errors; } } if (!MsftSme.isNullOrUndefined(this.step)) { // If step is used check if the current value falls within the range of the legal values const safeRem = this.getSafeRemainder((this.value - this.min), this.step); // Round off to the nearest integer, handle any floating precision errors that may occur const rem = Math.round((safeRem + Number.EPSILON) * 100) / 100; if (rem !== 0) { return { notAMultipleOfStep: { valid: false, message: this.strings.MsftSmeShell.Angular.Common.Form.Validation.IllegalNumber .format(this.fieldName, this.step, this.min), severity: ValidationAlertSeverity.Error } }; } } return super.validate(c); } /** * Gets the remainder of a division operation by converting any decimals to integers first * @param value The number to be divided * @param divisor The dividing number */ getSafeRemainder(value, divisor) { const valueDecimals = (value.toString().split('.')[1] || '').length; const divisorDecimals = (divisor.toString().split('.')[1] || '').length; const maxDecimals = Math.max(valueDecimals, divisorDecimals); const valueInt = parseInt(value.toFixed(maxDecimals).replace('.', ''), 10); const divisorInt = parseInt(divisor.toFixed(maxDecimals).replace('.', ''), 10); return (valueInt % divisorInt) / Math.pow(10, maxDecimals); } /** * It toggles the focus state for passed in UI element * * @param element the element for focusing * @param addClass it determines whether to add or remove class state * @returns void */ toggleFocusEvent(element, addClass = true) { if (!element?.nativeElement) { return; } if (addClass && !element.nativeElement.className.includes('sme-focused')) { element.nativeElement.classList.add('sme-focused'); } if (!addClass && element.nativeElement.className.includes('sme-focused')) { element.nativeElement.classList.remove('sme-focused'); } } }; /** @nocollapse */ NumberFormFieldComponent.ɵfac = function NumberFormFieldComponent_Factory(t) { return new (t || NumberFormFieldComponent)(i0.ɵɵdirectiveInject(i0.Injector)); }; /** @nocollapse */ NumberFormFieldComponent.ɵcmp = /** @pureOrBreakMyCode */ i0.ɵɵdefineComponent({ type: NumberFormFieldComponent, selectors: [["sme-form-field", "type", "number"]], viewQuery: function NumberFormFieldComponent_Query(rf, ctx) { if (rf & 1) { i0.ɵɵviewQuery(_c0, 5); i0.ɵɵviewQuery(_c1, 5); i0.ɵɵviewQuery(_c2, 5); i0.ɵɵviewQuery(_c3, 5); } if (rf & 2) { let _t; i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.input = _t.first); i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.container = _t.first); i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.incrementButton = _t.first); i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.decrementButton = _t.first); } }, inputs: { showSpinButton: "showSpinButton", step: "step", incrementBy: "incrementBy", min: "min", max: "max" }, features: [i0.ɵɵInheritDefinitionFeature], attrs: _c4, decls: 5, vars: 4, consts: [[3, "formField"], [1, "sme-form-field-editor"], [4, "ngIf"], ["class", "sme-number-form-field-container", 4, "ngIf"], [3, "alert"], [1, "sme-number-form-field-container"], ["container", ""], ["type", "number", "autocomplete", "off", 1, "sme-hidden-focus", 3, "ngModel", "required", "disabled", "max", "min", "step", "placeholder", "ngModelChange", "focus", "focusout", "keydown"], ["input", ""], ["class", "sme-arrange-stack-v sme-form-field-number-button-group", 4, "ngIf"], [1, "sme-arrange-stack-v", "sme-form-field-number-button-group"], ["type", "button", "tabindex", "-1", 1, "sme-button-auto-width", 3, "click"], ["incrementButton", ""], [1, "sme-icon", "sme-icon-chevronUpSmall"], ["decrementButton", ""], [1, "sme-icon", "sme-icon-chevronDownSmall"]], template: function NumberFormFieldComponent_Template(rf, ctx) { if (rf & 1) { i0.ɵɵelementStart(0, "sme-form-field-layout", 0)(1, "div", 1); i0.ɵɵtemplate(2, NumberFormFieldComponent_span_2_Template, 2, 1, "span", 2); i0.ɵɵtemplate(3, NumberFormFieldComponent_div_3_Template, 5, 13, "div", 3); i0.ɵɵelementEnd(); i0.ɵɵelement(4, "sme-validation-alert", 4); i0.ɵɵelementEnd(); } if (rf & 2) { i0.ɵɵproperty("formField", ctx); i0.ɵɵadvance(2); i0.ɵɵproperty("ngIf", ctx.readonly); i0.ɵɵadvance(1); i0.ɵɵproperty("ngIf", !ctx.readonly); i0.ɵɵadvance(1); i0.ɵɵproperty("alert", ctx.alert); } }, dependencies: [i5.NgIf, i1.DefaultValueAccessor, i1.NumberValueAccessor, i1.NgControlStatus, i1.RequiredValidator, i1.MinValidator, i1.MaxValidator, i1.NgModel, i6.ValidationAlertComponent, i7.FormFieldLayoutComponent], encapsulation: 2 }); NumberFormFieldComponent = __decorate([ SmeSchemaProperty({ type: SchemaPrimitiveType.Number, format: 'textbox', isDefaultFormat: true, description: 'A single line textbox binding to number data.', loaderComponent: NumberFormFieldLoaderComponent, optionProperties: [ { type: SchemaPrimitiveType.Number, format: 'textbox', name: 'min', label: 'actual_string:Min', defaultValue: 0, required: false, options: { multipleline: false } }, { type: SchemaPrimitiveType.Number, format: 'textbox', name: 'max', label: 'actual_string:Max', defaultValue: 100, required: false, options: { multipleline: false } }, { type: SchemaPrimitiveType.Number, format: 'textbox', name: 'step', label: 'actual_string:Step', defaultValue: 1, required: false, options: { multipleline: false } } ] }), __metadata("design:paramtypes", [Injector]) ], NumberFormFieldComponent); export { NumberFormFieldComponent }; (function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(NumberFormFieldComponent, [{ type: Component, args: [{ selector: 'sme-form-field[type="number"]', template: "<sme-form-field-layout [formField]=\"this\">\r\n <div class=\"sme-form-field-editor\">\r\n <span *ngIf=\"readonly\">{{ value }}</span>\r\n <div #container *ngIf=\"!readonly\" class=\"sme-number-form-field-container\">\r\n <input #input type=\"number\" autocomplete=\"off\" [(ngModel)]=\"value\" class=\"sme-hidden-focus\" [attr.role]=\"showSpinButton ? 'spinbutton': null\"\r\n [required]=\"required\" [disabled]=\"loadingOrDisabled\" [max]=\"max\" [min]=\"min\" [step]=\"step\" [placeholder]=\"placeholder\"\r\n [attr.aria-valuemax]=\"max\" [attr.aria-valuemin]=\"min\" [attr.aria-label]=\"label\" [attr.aria-required]=\"required\"\r\n (focus)=\"onInputFocus($event)\" (focusout)=\"onInputFocusOut($event)\" (keydown)=\"onInputKeydown($event)\">\r\n <span *ngIf=\"showSpinButton\" class=\"sme-arrange-stack-v sme-form-field-number-button-group\">\r\n <button #incrementButton type=\"button\" class=\"sme-button-auto-width\" tabindex=\"-1\" (click)=\"increment()\" [attr.aria-label]=\"ariaLabelIncrease\">\r\n <span class=\"sme-icon sme-icon-chevronUpSmall\"></span>\r\n </button>\r\n <button #decrementButton type=\"button\" class=\"sme-button-auto-width\" tabindex=\"-1\" (click)=\"decrement()\" [attr.aria-label]=\"ariaLabelDecrease\">\r\n <span class=\"sme-icon sme-icon-chevronDownSmall\"></span>\r\n </button>\r\n </span>\r\n </div>\r\n </div>\r\n <sme-validation-alert [alert]=\"alert\"></sme-validation-alert>\r\n</sme-form-field-layout>\r\n" }] }], function () { return [{ type: i0.Injector }]; }, { input: [{ type: ViewChild, args: ['input'] }], container: [{ type: ViewChild, args: ['container'] }], incrementButton: [{ type: ViewChild, args: ['incrementButton'] }], decrementButton: [{ type: ViewChild, args: ['decrementButton'] }], showSpinButton: [{ type: Input }], step: [{ type: Input }], incrementBy: [{ type: Input }], min: [{ type: Input }], max: [{ type: Input }] }); })(); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnVtYmVyLWZvcm0tZmllbGQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vYW5ndWxhci9zcmMvY29udHJvbHMvZm9ybS9mb3JtLWZpZWxkL251bWJlci9udW1iZXItZm9ybS1maWVsZC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9hbmd1bGFyL3NyYy9jb250cm9scy9mb3JtL2Zvcm0tZmllbGQvbnVtYmVyL251bWJlci1mb3JtLWZpZWxkLmNvbXBvbmVudC5odG1sIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vYW5ndWxhci9zcmMvY29udHJvbHMvZm9ybS9mb3JtLWZpZWxkL251bWJlci9udW1iZXItc2NoZW1hLWRyaXZlbi1mb3JtLXRlbXBsYXRlLmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQVUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzFGLE9BQU8sRUFBaUMsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDM0UsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLHFFQUFxRSxDQUFDO0FBQzlGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ3JFLE9BQU8sRUFBRSx3Q0FBd0MsRUFBRSxNQUFNLDZDQUE2QyxDQUFDO0FBQ3ZHLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQ3BFLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLHlDQUF5QyxDQUFDO0FBQ2xGLE9BQU8sRUFBRSw2QkFBNkIsRUFBRSxNQUFNLHlCQUF5QixDQUFDOzs7Ozs7Ozs7Ozs7Ozs7SUNMcEUsNEJBQXVCO0lBQUEsWUFBVztJQUFBLGlCQUFPOzs7SUFBbEIsZUFBVztJQUFYLGtDQUFX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QUFLLEVBQUUsb0JBQW9CO2dCQUMzQixZQUFZLEVBQUUsQ0FBQztnQkFDZixRQUFRLEVBQUUsS0FBSztnQkFDZixPQUFPLEVBQUU7b0JBQ0wsWUFBWSxFQUFFLEtBQUs7aUJBQ3RCO2FBQ0o7U0FDSjtLQUNKLENBQUM7cUNBd0VnQixRQUFRO0dBbkViLHdCQUF3QixDQXFScEM7U0FyUlksd0JBQXdCO3VGQUF4Qix3QkFBd0I7Y0FKcEMsU0FBUzsyQkFDSSwrQkFBK0I7MkRBZ0JsQyxLQUFLO2tCQURYLFNBQVM7bUJBQUMsT0FBTztZQU9YLFNBQVM7a0JBRGYsU0FBUzttQkFBQyxXQUFXO1lBT2YsZUFBZTtrQkFEckIsU0FBUzttQkFBQyxpQkFBaUI7WUFPckIsZUFBZTtrQkFEckIsU0FBUzttQkFBQyxpQkFBaUI7WUFPckIsY0FBYztrQkFEcEIsS0FBSztZQU9DLElBQUk7a0JBRFYsS0FBSztZQU9DLFdBQVc7a0JBRGpCLEtBQUs7WUFPQyxHQUFHO2tCQURULEtBQUs7WUFPQyxHQUFHO2tCQURULEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEVsZW1lbnRSZWYsIEluamVjdG9yLCBJbnB1dCwgT25Jbml0LCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgRm9ybUNvbnRyb2wsIFZhbGlkYXRpb25FcnJvcnMsIFZhbGlkYXRvcnMgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB7IEtleUNvZGUgfSBmcm9tICdAbWljcm9zb2Z0L3dpbmRvd3MtYWRtaW4tY2VudGVyLXNkay9jb3JlL2RhdGEvYWNjZXNzaWJpbGl0eS1tYW5hZ2VyJztcclxuaW1wb3J0IHsgU21lU2NoZW1hUHJvcGVydHkgfSBmcm9tICcuLi8uLi8uLi9zY2hlbWEvc2NoZW1hLWRlY29yYXRvcic7XHJcbmltcG9ydCB7IFNpbXBsZVByb3BlcnR5U2NoZW1hRmllbGRMb2FkZXJDb21wb25lbnQgfSBmcm9tICcuLi8uLi8uLi9zY2hlbWEvc2NoZW1hLWZpZWxkLWhvc3QuY29tcG9uZW50JztcclxuaW1wb3J0IHsgU2NoZW1hUHJpbWl0aXZlVHlwZSB9IGZyb20gJy4uLy4uLy4uL3NjaGVtYS9zY2hlbWEtbW9kZWxzJztcclxuaW1wb3J0IHsgVmFsaWRhdGlvbkFsZXJ0U2V2ZXJpdHkgfSBmcm9tICcuLi8uLi92YWxpZGF0aW9uLWFsZXJ0L3ZhbGlkYXRpb24tYWxlcnQnO1xyXG5pbXBvcnQgeyBTbWVJbnRlcm5hbEZvcm1GaWVsZENvbXBvbmVudCB9IGZyb20gJy4uL2Zvcm0tZmllbGQuY29tcG9uZW50JztcclxuXHJcbi8qIGVzbGludC1kaXNhYmxlIG1heC1sZW4gKi9cclxuQENvbXBvbmVudCh7XHJcbiAgICB0ZW1wbGF0ZVVybDogJy4vbnVtYmVyLXNjaGVtYS1kcml2ZW4tZm9ybS10ZW1wbGF0ZS5odG1sJ1xyXG59KVxyXG4vKiBlc2xpbnQtZW5hYmxlIG1heC1sZW4gKi9cclxuZXhwb3J0IGNsYXNzIE51bWJlckZvcm1GaWVsZExvYWRlckNvbXBvbmVudCBleHRlbmRzIFNpbXBsZVByb3BlcnR5U2NoZW1hRmllbGRMb2FkZXJDb21wb25lbnQge1xyXG59XHJcblxyXG4vKipcclxuICogQWNjZXNzaWJsZSBudW1iZXIgZmllbGQgaW1wbGVtZW50YXRpb25cclxuICovXHJcbkBTbWVTY2hlbWFQcm9wZXJ0eSh7XHJcbiAgICB0eXBlOiBTY2hlbWFQcmltaXRpdmVUeXBlLk51bWJlcixcclxuICAgIGZvcm1hdDogJ3RleHRib3gnLFxyXG4gICAgaXNEZWZhdWx0Rm9ybWF0OiB0cnVlLFxyXG4gICAgZGVzY3JpcHRpb246ICdBIHNpbmdsZSBsaW5lIHRleHRib3ggYmluZGluZyB0byBudW1iZXIgZGF0YS4nLFxyXG4gICAgbG9hZGVyQ29tcG9uZW50OiBOdW1iZXJGb3JtRmllbGRMb2FkZXJDb21wb25lbnQsXHJcbiAgICBvcHRpb25Qcm9wZXJ0aWVzOiBbXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgICB0eXBlOiBTY2hlbWFQcmltaXRpdmVUeXBlLk51bWJlcixcclxuICAgICAgICAgICAgZm9ybWF0OiAndGV4dGJveCcsXHJcbiAgICAgICAgICAgIG5hbWU6ICdtaW4nLFxyXG4gICAgICAgICAgICBsYWJlbDogJ2FjdHVhbF9zdHJpbmc6TWluJyxcclxuICAgICAgICAgICAgZGVmYXVsdFZhbHVlOiAwLFxyXG4gICAgICAgICAgICByZXF1aXJlZDogZmFsc2UsXHJcbiAgICAgICAgICAgIG9wdGlvbnM6IHtcclxuICAgICAgICAgICAgICAgIG11bHRpcGxlbGluZTogZmFsc2VcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0sXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgICB0eXBlOiBTY2hlbWFQcmltaXRpdmVUeXBlLk51bWJlcixcclxuICAgICAgICAgICAgZm9ybWF0OiAndGV4dGJveCcsXHJcbiAgICAgICAgICAgIG5hbWU6ICdtYXgnLFxyXG4gICAgICAgICAgICBsYWJlbDogJ2FjdHVhbF9zdHJpbmc6TWF4JyxcclxuICAgICAgICAgICAgZGVmYXVsdFZhbHVlOiAxMDAsXHJcbiAgICAgICAgICAgIHJlcXVpcmVkOiBmYWxzZSxcclxuICAgICAgICAgICAgb3B0aW9uczoge1xyXG4gICAgICAgICAgICAgICAgbXVsdGlwbGVsaW5lOiBmYWxzZVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICAgIHR5cGU6IFNjaGVtYVByaW1pdGl2ZVR5cGUuTnVtYmVyLFxyXG4gICAgICAgICAgICBmb3JtYXQ6ICd0ZXh0Ym94JyxcclxuICAgICAgICAgICAgbmFtZTogJ3N0ZXAnLFxyXG4gICAgICAgICAgICBsYWJlbDogJ2FjdHVhbF9zdHJpbmc6U3RlcCcsXHJcbiAgICAgICAgICAgIGRlZmF1bHRWYWx1ZTogMSxcclxuICAgICAgICAgICAgcmVxdWlyZWQ6IGZhbHNlLFxyXG4gICAgICAgICAgICBvcHRpb25zOiB7XHJcbiAgICAgICAgICAgICAgICBtdWx0aXBsZWxpbmU6IGZhbHNlXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICBdXHJcbn0pXHJcbkBDb21wb25lbnQoe1xyXG4gICAgc2VsZWN0b3I6ICdzbWUtZm9ybS1maWVsZFt0eXBlPVwibnVtYmVyXCJdJyxcclxuICAgIHRlbXBsYXRlVXJsOiAnLi9udW1iZXItZm9ybS1maWVsZC5jb21wb25lbnQuaHRtbCdcclxufSlcclxuZXhwb3J0IGNsYXNzIE51bWJlckZvcm1GaWVsZENvbXBvbmVudCBleHRlbmRzIFNtZUludGVybmFsRm9ybUZpZWxkQ29tcG9uZW50PG51bWJlcj4gaW1wbGVtZW50cyBPbkluaXQge1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogVGhlIHNvdXJjZSBuYW1lIHRvIHVzZSBmb3IgbG9nZ2luZ1xyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgZ2V0IGxvZ1NvdXJjZU5hbWUoKSB7XHJcbiAgICAgICAgcmV0dXJuICdOdW1iZXJGb3JtRmllbGRDb21wb25lbnQnO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogVGhlIGlucHV0IGZyb20gbnVtYmVyIGZvcm0gZmllbGRcclxuICAgICAqL1xyXG4gICAgQFZpZXdDaGlsZCgnaW5wdXQnKVxyXG4gICAgcHVibGljIGlucHV0OiBFbGVtZW50UmVmO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogVGhlIGNvbnRhaW5lciBmb3IgdGhlIGlucHV0IGJveCBhbmQgc3BpbiBidXR0b25zXHJcbiAgICAgKi9cclxuICAgIEBWaWV3Q2hpbGQoJ2NvbnRhaW5lcicpXHJcbiAgICBwdWJsaWMgY29udGFpbmVyOiBFbGVtZW50UmVmO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogVGhlIGluY3JlbWVudCBidXR0b24gVUkgZWxlbWVudFxyXG4gICAgICovXHJcbiAgICBAVmlld0NoaWxkKCdpbmNyZW1lbnRCdXR0b24nKVxyXG4gICAgcHVibGljIGluY3JlbWVudEJ1dHRvbjogRWxlbWVudFJlZjtcclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoZSBkZWNyZW1lbnQgYnV0dG9uIFVJIGVsZW1lbnRcclxuICAgICAqL1xyXG4gICAgQFZpZXdDaGlsZCgnZGVjcmVtZW50QnV0dG9uJylcclxuICAgIHB1YmxpYyBkZWNyZW1lbnRCdXR0b246IEVsZW1lbnRSZWY7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJdCBkZXRlcm1pbmUgd2hldGhlciB0byBzaG93IHRoZSBzcGluIGJ1dHRvbi5cclxuICAgICAqL1xyXG4gICAgQElucHV0KClcclxuICAgIHB1YmxpYyBzaG93U3BpbkJ1dHRvbiA9IGZhbHNlO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogVGhlIHNpemUgb2YgZWFjaCBtb3ZlbWVudCBvZiB0aGUgc2xpZGVyLlxyXG4gICAgICovXHJcbiAgICBASW5wdXQoKVxyXG4gICAgcHVibGljIHN0ZXA6IG51bWJlcjtcclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoZSBzaXplIG9mIGVhY2ggaW5jcmVtZW50L2RlY3JlbWVudCB2YWx1ZSBvZiB0aGUgc2xpZGVyLlxyXG4gICAgICovXHJcbiAgICBASW5wdXQoKVxyXG4gICAgcHVibGljIGluY3JlbWVudEJ5OiBudW1iZXI7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBUaGUgbWluaW11bSB2YWx1ZSBvZiB0aGUgc2xpZGVyXHJcbiAgICAgKi9cclxuICAgIEBJbnB1dCgpXHJcbiAgICBwdWJsaWMgbWluOiBudW1iZXI7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBUaGUgbWF4aW11bSB2YWx1ZSBvZiB0aGUgc2xpZGVyXHJcbiAgICAgKi9cclxuICAgIEBJbnB1dCgpXHJcbiAgICBwdWJsaWMgbWF4OiBudW1iZXI7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJbml0aWFsaXplcyBhIG5ldyBpbnN0YW5jZSBvZiB0aGUgU2xpZGVyRm9ybUZpZWxkQ29tcG9uZW50XHJcbiAgICAgKi9cclxuICAgIGNvbnN0cnVjdG9yKFxyXG4gICAgICAgIGluamVjdG9yOiBJbmplY3RvclxyXG4gICAgKSB7XHJcbiAgICAgICAgc3VwZXIoaW5qZWN0b3IpO1xyXG4gICAgICAgIHRoaXMubWluID0gMDtcclxuICAgICAgICAvLyBObyBkZWZhdWx0IG1heGltdW0vc3RlcFxyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBuZ09uSW5pdCgpIHtcclxuICAgICAgICBzdXBlci5uZ09uSW5pdCgpO1xyXG5cclxuICAgICAgICAvLyBJZiBpbmNyZW1lbnRCeSBpcyBub3Qgc2V0LCB1c2Ugc3RlcC4gSWYgc3RlcCBpcyBub3Qgc2V0IGRlZmF1bHQgdG8gMSAob25lKVxyXG4gICAgICAgIHRoaXMuaW5jcmVtZW50QnkgPSBNc2Z0U21lLmlzTnVsbE9yVW5kZWZpbmVkKHRoaXMuaW5jcmVtZW50QnkpXHJcbiAgICAgICAgICAgID8gTXNmdFNtZS5pc051bGxPclVuZGVmaW5lZCh0aGlzLnN0ZXApID8gMSA6IHRoaXMuc3RlcFxyXG4gICAgICAgICAgICA6IHRoaXMuaW5jcmVtZW50Qnk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBHZXR0ZXIgYXJpYSBsYWJlbCBpbmNyZWFzZSBmb3Igc3BpbiBidXR0b24gaW5jcmVhc2UuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBnZXQgYXJpYUxhYmVsSW5jcmVhc2UoKTogc3RyaW5nIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5zdHJpbmdzLk1zZnRTbWVTaGVsbC5Bbmd1bGFyLkZvcm0uU3BpbkJ1dHRvbi5pbmNyZWFzZS5mb3JtYXQodGhpcy5pbmNyZW1lbnRCeSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBHZXR0ZXIgYXJpYSBsYWJlbCBpbmNyZWFzZSBmb3Igc3BpbiBidXR0b24gZGVjcmVhc2UuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBnZXQgYXJpYUxhYmVsRGVjcmVhc2UoKTogc3RyaW5nIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5zdHJpbmdzLk1zZnRTbWVTaGVsbC5Bbmd1bGFyLkZvcm0uU3BpbkJ1dHRvbi5kZWNyZWFzZS5mb3JtYXQodGhpcy5pbmNyZW1lbnRCeSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBIYW5kbGUga2V5ZG93biBldmVudHMgb24gdGhlIG51bWJlciBpbnB1dFxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgb25JbnB1dEtleWRvd24oJGV2ZW50OiBLZXlib2FyZEV2ZW50KSB7XHJcbiAgICAgICAgLy8gSW4gTWljcm9zb2Z0IEVkZ2UgYW5kIElFLCBudW1lcmljIGlucHV0cyB3aWxsIHNjcm9sbCB0aGUgcGFnZSB3aGlsZSBpbmNyZW1lbnRpbmcvZGVjcmVtZW50aW5nIHRoZSBudW1iZXIuXHJcbiAgICAgICAgc3dpdGNoICgkZXZlbnQua2V5Q29kZSkge1xyXG4gICAgICAgICAgICBjYXNlIEtleUNvZGUuVXBBcnJvdzoge1xyXG4gICAgICAgICAgICAgICAgJGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgICAgICAgICAvLyBmaXJpbmcgdGhlIGNsaWNrIGV2ZW50IHRvIHRyaWdnZXIgdGhlIGNsaWNrIHN0eWxlIHRvIHJlbmRlclxyXG4gICAgICAgICAgICAgICAgdGhpcy5pbmNyZW1lbnQoKTtcclxuICAgICAgICAgICAgICAgIHRoaXMudG9nZ2xlRm9jdXNFdmVudCh0aGlzLmluY3JlbWVudEJ1dHRvbiwgdHJ1ZSk7XHJcbiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnRvZ2dsZUZvY3VzRXZlbnQodGhpcy5pbmNyZW1lbnRCdXR0b24sIGZhbHNlKTtcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgY2FzZSBLZXlDb2RlLkRvd25BcnJvdzoge1xyXG4gICAgICAgICAgICAgICAgJGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgICAgICAgICAvLyBmaXJpbmcgdGhlIGNsaWNrIGV2ZW50IHRvIHRyaWdnZXIgdGhlIGNsaWNrIHN0eWxlIHRvIHJlbmRlclxyXG4gICAgICAgICAgICAgICAgdGhpcy5kZWNyZW1lbnQoKTtcclxuICAgICAgICAgICAgICAgIHRoaXMudG9nZ2xlRm9jdXNFdmVudCh0aGlzLmRlY3JlbWVudEJ1dHRvbiwgdHJ1ZSk7XHJcbiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnRvZ2dsZUZvY3VzRXZlbnQodGhpcy5kZWNyZW1lbnRCdXR0b24sIGZhbHNlKTtcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgZGVmYXVsdDogeyByZXR1cm47IH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJbmNyZW1lbnRzIHRoZSBjb250cm9scyB2YWx1ZSBieSAxIFwic3RlcFwiXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBpbmNyZW1lbnQoKSB7XHJcbiAgICAgICAgbGV0IHZhbHVlID0gTXNmdFNtZS5pc051bWJlcih0aGlzLnZhbHVlKSA/IHRoaXMudmFsdWUgOiB0aGlzLm1pbiAtIDE7XHJcbiAgICAgICAgdmFsdWUgKz0gdGhpcy5pbmNyZW1lbnRCeTtcclxuICAgICAgICBpZiAodmFsdWUgPiB0aGlzLm1heCkge1xyXG4gICAgICAgICAgICB2YWx1ZSA9IHRoaXMubWF4O1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLnZhbHVlID0gdmFsdWU7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBEZWNyZW1lbnRzIHRoZSBjb250cm9scyB2YWx1ZSBieSAxIFwic3RlcFwiXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBkZWNyZW1lbnQoKSB7XHJcbiAgICAgICAgbGV0IHZhbHVlID0gTXNmdFNtZS5pc051bWJlcih0aGlzLnZhbHVlKSA/IHRoaXMudmFsdWUgOiB0aGlzLm1pbiArIDE7XHJcbiAgICAgICAgdmFsdWUgLT0gdGhpcy5pbmNyZW1lbnRCeTtcclxuICAgICAgICBpZiAodmFsdWUgPCB0aGlzLm1pbikge1xyXG4gICAgICAgICAgICB2YWx1ZSA9IHRoaXMubWluO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLnZhbHVlID0gdmFsdWU7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBUaGUgZnVuY3Rpb25hbGl0eSB0byBmb2N1cyBvbiB0aGUgaW5wdXQgZmllbGRcclxuICAgICAqL1xyXG4gICAgcHVibGljIG9uSW5wdXRGb2N1cygkZXZlbnQpIHtcclxuICAgICAgICBpZiAoJGV2ZW50KSB7XHJcbiAgICAgICAgICAgICRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdGhpcy50b2dnbGVGb2N1c0V2ZW50KHRoaXMuY29udGFpbmVyLCB0cnVlKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoZSBmdW5jdGlvbmFsaXR5IHRvIGZvY3VzIG91dCBvbiB0aGUgaW5wdXQgZmllbGRcclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gJGV2ZW50IHRoZSBmb2N1cyBldmVudCBvYmplY3RcclxuICAgICAqL1xyXG4gICAgcHVibGljIG9uSW5wdXRGb2N1c091dCgkZXZlbnQpIHtcclxuICAgICAgICBpZiAoJGV2ZW50KSB7XHJcbiAgICAgICAgICAgICRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdGhpcy50b2dnbGVGb2N1c0V2ZW50KHRoaXMuY29udGFpbmVyLCBmYWxzZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBDcmVhdGVzIHRoZSBpZEJhZyB1c2VkIGJ5IHRoaXMgY29tcG9uZW50IHRvIHN0b3JlIHVuaXF1ZSBlbGVtZW50IGlkcy5cclxuICAgICAqIGlkIHZhbHVlcyB3aWxsIGJlIGFzc2lnbmVkIGJlIHRoZSBAc2VlIEJhc2VDb21wb25lbnQgc3VwZXIgY2xhc3MuXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBjcmVhdGVJZEJhZygpOiBNc2Z0U21lLlN0cmluZ01hcDxzdHJpbmc+IHtcclxuICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICBkZXRhaWxzU3BhbjogJydcclxuICAgICAgICB9O1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogRGV0ZXJtaW5lcyB0aGUgdmFsdWUgdG8gdXNlIHdoZW4gY2xlYXJpbmcgdGhlIGZpZWxkIGJhc2VkIG9uIHRoZSBpbml0aWFsIHZhbHVlIHR5cGVcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGdldENsZWFyVmFsdWUoKTogbnVtYmVyIHtcclxuICAgICAgICByZXR1cm4gTXNmdFNtZS5pc051bGxPclVuZGVmaW5lZCh0aGlzLm1pbikgPyAwIDogdGhpcy5taW47XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBQZXJmb3JtcyB2YWxpZGF0aW9uIHRoYXQgaXMgaW50ZXJuYWwgdG8gdGhpcyBjb250cm9sXHJcbiAgICAgKiBAcGFyYW0gYyBUaGUgZm9ybSBjb250cm9sIGF0dGFjaGVkIHRvIHRoaXMgaW5zdGFuY2VcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIHZhbGlkYXRlKGM6IEZvcm1Db250cm9sKTogVmFsaWRhdGlvbkVycm9ycyB7XHJcbiAgICAgICAgLy8gaWYgbm90IHJlcXVpcmVkLCBkb24ndCBwcm9jZXNzIG51bGwgb3IgZW1wdHkgdmFsdWVzIGZvciBmdXJ0aGVyIHZhbGlkYXRpb25cclxuICAgICAgICBpZiAoIXRoaXMucmVxdWlyZWQgJiYgKE1zZnRTbWUuaXNOdWxsT3JXaGl0ZVNwYWNlKGMudmFsdWUpKSkge1xyXG4gICAgICAgICAgICByZXR1cm4gc3VwZXIudmFsaWRhdGUoYyk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoIU1zZnRTbWUuaXNOdW1iZXIodGhpcy52YWx1ZSkpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgICAgIG5vdEFOdW1iZXI6IHtcclxuICAgICAgICAgICAgICAgICAgICB2YWxpZDogZmFsc2UsXHJcbiAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogdGhpcy5zdHJpbmdzLk1zZnRTbWVTaGVsbC5Bbmd1bGFyLkNvbW1vbi5Gb3JtLlZhbGlkYXRpb24uaXNOdW1iZXIuZm9ybWF0LmZvcm1hdCh0aGlzLmZpZWxkTmFtZSksXHJcbiAgICAgICAgICAgICAgICAgICAgc2V2ZXJpdHk6IFZhbGlkYXRpb25BbGVydFNldmVyaXR5LkVycm9yXHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIC8vIGFuZ3VsYXIncyBtaW4gYW5kIG1heCB2YWxpZGF0b3Igb25seSB3b3JrIHZpYSBjb2RlLiBTbyB3ZSBpbXBsZW1lbnQgdGhlbSBoZXJlLlxyXG4gICAgICAgIGlmICghTXNmdFNtZS5pc051bGxPclVuZGVmaW5lZCh0aGlzLm1pbikgJiYgdGhpcy52YWx1ZSA8IHRoaXMubWluKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGVycm9ycyA9IFZhbGlkYXRvcnMubWluKHRoaXMubWluKShjKTtcclxuICAgICAgICAgICAgaWYgKGVycm9ycykgeyByZXR1cm4gZXJyb3JzOyB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoIU1zZnRTbWUuaXNOdWxsT3JVbmRlZmluZWQodGhpcy5tYXgpICYmIHRoaXMudmFsdWUgPiB0aGlzLm1heCkge1xyXG4gICAgICAgICAgICBjb25zdCBlcnJvcnMgPSBWYWxpZGF0b3JzLm1heCh0aGlzLm1heCkoYyk7XHJcbiAgICAgICAgICAgIGlmIChlcnJvcnMpIHsgcmV0dXJuIGVycm9yczsgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKCFNc2Z0U21lLmlzTnVsbE9yVW5kZWZpbmVkKHRoaXMuc3RlcCkpIHtcclxuICAgICAgICAgICAgLy8gSWYgc3RlcCBpcyB1c2VkIGNoZWNrIGlmIHRoZSBjdXJyZW50IHZhbHVlIGZhbGxzIHdpdGhpbiB0aGUgcmFuZ2Ugb2YgdGhlIGxlZ2FsIHZhbHVlc1xyXG4gICAgICAgICAgICBjb25zdCBzYWZlUmVtID0gdGhpcy5nZXRTYWZlUmVtYWluZGVyKCh0aGlzLnZhbHVlIC0gdGhpcy5taW4pLCB0aGlzLnN0ZXApO1xyXG4gICAgICAgICAgICAvLyBSb3VuZCBvZmYgdG8gdGhlIG5lYXJlc3QgaW50ZWdlciwgaGFuZGxlIGFueSBmbG9hdGluZyBwcmVjaXNpb24gZXJyb3JzIHRoYXQgbWF5IG9jY3VyXHJcbiAgICAgICAgICAgIGNvbnN0IHJlbSA9IE1hdGgucm91bmQoKHNhZmVSZW0gKyBOdW1iZXIuRVBTSUxPTikgKiAxMDApIC8gMTAwO1xyXG5cclxuICAgICAgICAgICAgaWYgKHJlbSAhPT0gMCkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgICAgICAgICBub3RBTXVsdGlwbGVPZlN0ZXA6IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdmFsaWQ6IGZhbHNlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiB0aGlzLnN0cmluZ3MuTXNmdFNtZVNoZWxsLkFuZ3VsYXIuQ29tbW9uLkZvcm0uVmFsaWRhdGlvbi5JbGxlZ2FsTnVtYmVyXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZm9ybWF0KHRoaXMuZmllbGROYW1lLCB0aGlzLnN0ZXAsIHRoaXMubWluKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgc2V2ZXJpdHk6IFZhbGlkYXRpb25BbGVydFNldmVyaXR5LkVycm9yXHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgcmV0dXJuIHN1cGVyLnZhbGlkYXRlKGMpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogR2V0cyB0aGUgcmVtYWluZGVyIG9mIGEgZGl2aXNpb24gb3BlcmF0aW9uIGJ5IGNvbnZlcnRpbmcgYW55IGRlY2ltYWxzIHRvIGludGVnZXJzIGZpcnN0XHJcbiAgICAgKiBAcGFyYW0gdmFsdWUgVGhlIG51bWJlciB0byBiZSBkaXZpZGVkXHJcbiAgICAgKiBAcGFyYW0gZGl2aXNvciBUaGUgZGl2aWRpbmcgbnVtYmVyXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBnZXRTYWZlUmVtYWluZGVyKHZhbHVlOiBudW1iZXIsIGRpdmlzb3I6IG51bWJlcik6IG51bWJlciB7XHJcbiAgICAgICAgY29uc3QgdmFsdWVEZWNpbWFscyA9ICh2YWx1ZS50b1N0cmluZygpLnNwbGl0KCcuJylbMV0gfHwgJycpLmxlbmd0aDtcclxuICAgICAgICBjb25zdCBkaXZpc29yRGVjaW1hbHMgPSAoZGl2aXNvci50b1N0cmluZygpLnNwbGl0KCcuJylbMV0gfHwgJycpLmxlbmd0aDtcclxuICAgICAgICBjb25zdCBtYXhEZWNpbWFscyA9IE1hdGgubWF4KHZhbHVlRGVjaW1hbHMsIGRpdmlzb3JEZWNpbWFscyk7XHJcbiAgICAgICAgY29uc3QgdmFsdWVJbnQgPSBwYXJzZUludCh2YWx1ZS50b0ZpeGVkKG1heERlY2ltYWxzKS5yZXBsYWNlKCcuJywgJycpLCAxMCk7XHJcbiAgICAgICAgY29uc3QgZGl2aXNvckludCA9IHBhcnNlSW50KGRpdmlzb3IudG9GaXhlZChtYXhEZWNpbWFscykucmVwbGFjZSgnLicsICcnKSwgMTApO1xyXG4gICAgICAgIHJldHVybiAodmFsdWVJbnQgJSBkaXZpc29ySW50KSAvIE1hdGgucG93KDEwLCBtYXhEZW