UNPKG

carbon-components-angular

Version:
479 lines (471 loc) 41.7 kB
import { Component, HostBinding, Input, TemplateRef, ViewChild } from "@angular/core"; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "carbon-components-angular/icon"; /** * Get started with importing the module: * * ```typescript * import { InputModule } from 'carbon-components-angular'; * ``` * * ```html * <cds-text-label> * Label * <input cdsText type="text" class="input-field"> * </cds-text-label> * ``` * * [See demo](../../?path=/story/components-input--basic) */ export class TextInputLabelComponent { /** * Creates an instance of Label. */ constructor(changeDetectorRef) { this.changeDetectorRef = changeDetectorRef; /** * The id of the input item associated with the `Label`. This value is also used to associate the `Label` with * its input counterpart through the 'for' attribute. */ this.labelInputID = "ibm-text-input-" + TextInputLabelComponent.labelCounter++; /** * Set to `true` for a disabled label. */ this.disabled = false; /** * Set to `true` for a loading label. */ this.skeleton = false; /** * Set to `true` for an invalid label component. */ this.invalid = false; /** * Set to `true` to show a warning (contents set by warningText) */ this.warn = false; /** * Experimental: enable fluid state */ this.fluid = false; /** * Set to `true` to hide the label visually, but keep accessible to * screen readers. */ this.hideLabel = false; /** * Set to `true` to render the label and field side-by-side instead of stacked. */ this.inline = false; /** * The render size for the `TextInput`. Used to compute the INLINE label size * variant class (`cds--label--inline--{size}`). */ this.size = "md"; /** * Set to `true` (`maxCount` must be set) to displays a live character * counter alongside the label. */ this.enableCounter = false; // Tracks current character count for the counter display. this.textCount = 0; this.labelClass = true; this.textInputWrapper = true; // Cached reference to the input element, set once in ngAfterViewInit. this._inputElement = null; // Cached listener so it can be removed precisely (avoids anonymous-function leak). this._inputListener = null; } get isInlineWrapper() { return this.inline; } get isReadonly() { return this.wrapper?.nativeElement.querySelector("input")?.readOnly ?? false; } get fluidClass() { return this.fluid && !this.skeleton; } get fluidSkeletonClass() { return this.fluid && this.skeleton; } /** * Sets the id on the input item associated with the `Label` and attaches the * counter listener when `enableCounter` is already `true` on first render. */ ngAfterViewInit() { if (this.wrapper) { // Prioritize setting id to `input` over div const inputElement = this.wrapper.nativeElement.querySelector("input"); if (inputElement) { // avoid overriding ids already set by the user, reuse it instead if (inputElement.id) { this.labelInputID = inputElement.id; this.changeDetectorRef.detectChanges(); } inputElement.setAttribute("id", this.labelInputID); this._inputElement = inputElement; if (this.enableCounter) { this.textCount = inputElement.value?.length || 0; this._attachCounterListener(); } return; } const divElement = this.wrapper.nativeElement.querySelector("div"); if (divElement) { if (divElement.id) { this.labelInputID = divElement.id; this.changeDetectorRef.detectChanges(); } divElement.setAttribute("id", this.labelInputID); } } } /** * Attach/remove listener and seed `textCount` from the textarea's current value. * @param changes */ ngOnChanges(changes) { if (changes.enableCounter && !changes.enableCounter.firstChange) { if (changes.enableCounter.currentValue) { if (this._inputElement) { this.textCount = this._inputElement.value?.length || 0; this._attachCounterListener(); this.changeDetectorRef.detectChanges(); } } else { this._detachCounterListener(); } } } ngAfterContentInit() { this.changeDetectorRef.detectChanges(); } ngOnDestroy() { this._detachCounterListener(); } isTemplate(value) { return value instanceof TemplateRef; } /** * Attaches the input event listener, ensuring it is never added twice. */ _attachCounterListener() { this._detachCounterListener(); if (!this._inputElement) { return; } this._inputListener = (e) => { this.textCount = e.target.value?.length || 0; this.changeDetectorRef.detectChanges(); }; this._inputElement.addEventListener("input", this._inputListener); } /** * Removes the input event listener and clears the cached reference. */ _detachCounterListener() { if (this._inputListener && this._inputElement) { this._inputElement.removeEventListener("input", this._inputListener); this._inputListener = null; } } } /** * Used to build the id of the input item associated with the `Label`. */ TextInputLabelComponent.labelCounter = 0; TextInputLabelComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TextInputLabelComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); TextInputLabelComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: TextInputLabelComponent, selector: "cds-text-label, ibm-text-label", inputs: { labelInputID: "labelInputID", disabled: "disabled", skeleton: "skeleton", labelTemplate: "labelTemplate", textInputTemplate: "textInputTemplate", helperText: "helperText", invalidText: "invalidText", invalid: "invalid", warn: "warn", warnText: "warnText", ariaLabel: "ariaLabel", fluid: "fluid", hideLabel: "hideLabel", inline: "inline", size: "size", enableCounter: "enableCounter", maxCount: "maxCount" }, host: { properties: { "class.cds--text-input-wrapper--inline": "this.isInlineWrapper", "class.cds--text-input-wrapper--readonly": "this.isReadonly", "class.cds--text-input--fluid": "this.fluidClass", "class.cds--text-input--fluid__skeleton": "this.fluidSkeletonClass", "class.cds--form-item": "this.labelClass", "class.cds--text-input-wrapper": "this.textInputWrapper" } }, viewQueries: [{ propertyName: "wrapper", first: true, predicate: ["wrapper"], descendants: true }], usesOnChanges: true, ngImport: i0, template: ` <ng-container *ngIf="skeleton"> <span class="cds--label cds--skeleton"></span> <div class="cds--text-input cds--skeleton"></div> </ng-container> <ng-container *ngIf="!skeleton"> <!-- non-inline: label-wrapper above field; inline: label+validation side-by-side --> <ng-container *ngIf="!inline; else inlineHeader"> <div class="cds--text-input__label-wrapper"> <label [for]="labelInputID" [attr.aria-label]="ariaLabel" class="cds--label" [ngClass]="{ 'cds--label--disabled': disabled, 'cds--visually-hidden': hideLabel }"> <ng-template *ngIf="labelTemplate; else labelContent" [ngTemplateOutlet]="labelTemplate"></ng-template> <ng-template #labelContent> <ng-content></ng-content> </ng-template> </label> <span *ngIf="enableCounter && maxCount" class="cds--label" [ngClass]="{'cds--label--disabled': disabled}" aria-hidden="true"> {{textCount}}/{{maxCount}} </span> </div> </ng-container> <ng-template #inlineHeader> <div class="cds--text-input__label-helper-wrapper"> <div class="cds--text-input__label-wrapper"> <label [for]="labelInputID" [attr.aria-label]="ariaLabel" class="cds--label" [ngClass]="{ 'cds--label--disabled': disabled, 'cds--visually-hidden': hideLabel, 'cds--label--inline': true, 'cds--label--inline--sm': size === 'sm', 'cds--label--inline--md': size === 'md', 'cds--label--inline--lg': size === 'lg' }"> <ng-template *ngIf="labelTemplate" [ngTemplateOutlet]="labelTemplate"></ng-template> </label> </div> <ng-container *ngIf="!fluid"> <ng-container [ngTemplateOutlet]="validationOrHelper"></ng-container> </ng-container> </div> </ng-template> <div class="cds--text-input__field-outer-wrapper" [ngClass]="{'cds--text-input__field-outer-wrapper--inline': inline}"> <div class="cds--text-input__field-wrapper" [ngClass]="{ 'cds--text-input__field-wrapper--warning': warn }" [attr.data-invalid]="(invalid ? true : null)" #wrapper> <svg *ngIf="invalid && !warn" cdsIcon="warning--filled" size="16" class="cds--text-input__invalid-icon"> </svg> <svg *ngIf="!invalid && warn" cdsIcon="warning--alt--filled" size="16" class="cds--text-input__invalid-icon cds--text-input__invalid-icon--warning"> </svg> <ng-template *ngIf="textInputTemplate; else textInputContent" [ngTemplateOutlet]="textInputTemplate"></ng-template> <ng-template #textInputContent> <ng-content select="[cdsText],[ibmText],input[type=text],div"></ng-content> </ng-template> <ng-container *ngIf="fluid"> <hr class="cds--text-input__divider" /> <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> </ng-container> </div> <ng-container *ngIf="!fluid && !inline"> <ng-container [ngTemplateOutlet]="validationOrHelper"></ng-container> </ng-container> </div> </ng-container> <ng-template #validationOrHelper> <div *ngIf="helperText && !invalid && !warn" class="cds--form__helper-text" [ngClass]="{'cds--form__helper-text--disabled': disabled, 'cds--form__helper-text--inline': inline}"> <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> </ng-template> `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TextInputLabelComponent, decorators: [{ type: Component, args: [{ selector: "cds-text-label, ibm-text-label", template: ` <ng-container *ngIf="skeleton"> <span class="cds--label cds--skeleton"></span> <div class="cds--text-input cds--skeleton"></div> </ng-container> <ng-container *ngIf="!skeleton"> <!-- non-inline: label-wrapper above field; inline: label+validation side-by-side --> <ng-container *ngIf="!inline; else inlineHeader"> <div class="cds--text-input__label-wrapper"> <label [for]="labelInputID" [attr.aria-label]="ariaLabel" class="cds--label" [ngClass]="{ 'cds--label--disabled': disabled, 'cds--visually-hidden': hideLabel }"> <ng-template *ngIf="labelTemplate; else labelContent" [ngTemplateOutlet]="labelTemplate"></ng-template> <ng-template #labelContent> <ng-content></ng-content> </ng-template> </label> <span *ngIf="enableCounter && maxCount" class="cds--label" [ngClass]="{'cds--label--disabled': disabled}" aria-hidden="true"> {{textCount}}/{{maxCount}} </span> </div> </ng-container> <ng-template #inlineHeader> <div class="cds--text-input__label-helper-wrapper"> <div class="cds--text-input__label-wrapper"> <label [for]="labelInputID" [attr.aria-label]="ariaLabel" class="cds--label" [ngClass]="{ 'cds--label--disabled': disabled, 'cds--visually-hidden': hideLabel, 'cds--label--inline': true, 'cds--label--inline--sm': size === 'sm', 'cds--label--inline--md': size === 'md', 'cds--label--inline--lg': size === 'lg' }"> <ng-template *ngIf="labelTemplate" [ngTemplateOutlet]="labelTemplate"></ng-template> </label> </div> <ng-container *ngIf="!fluid"> <ng-container [ngTemplateOutlet]="validationOrHelper"></ng-container> </ng-container> </div> </ng-template> <div class="cds--text-input__field-outer-wrapper" [ngClass]="{'cds--text-input__field-outer-wrapper--inline': inline}"> <div class="cds--text-input__field-wrapper" [ngClass]="{ 'cds--text-input__field-wrapper--warning': warn }" [attr.data-invalid]="(invalid ? true : null)" #wrapper> <svg *ngIf="invalid && !warn" cdsIcon="warning--filled" size="16" class="cds--text-input__invalid-icon"> </svg> <svg *ngIf="!invalid && warn" cdsIcon="warning--alt--filled" size="16" class="cds--text-input__invalid-icon cds--text-input__invalid-icon--warning"> </svg> <ng-template *ngIf="textInputTemplate; else textInputContent" [ngTemplateOutlet]="textInputTemplate"></ng-template> <ng-template #textInputContent> <ng-content select="[cdsText],[ibmText],input[type=text],div"></ng-content> </ng-template> <ng-container *ngIf="fluid"> <hr class="cds--text-input__divider" /> <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> </ng-container> </div> <ng-container *ngIf="!fluid && !inline"> <ng-container [ngTemplateOutlet]="validationOrHelper"></ng-container> </ng-container> </div> </ng-container> <ng-template #validationOrHelper> <div *ngIf="helperText && !invalid && !warn" class="cds--form__helper-text" [ngClass]="{'cds--form__helper-text--disabled': disabled, 'cds--form__helper-text--inline': inline}"> <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> </ng-template> ` }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { isInlineWrapper: [{ type: HostBinding, args: ["class.cds--text-input-wrapper--inline"] }], isReadonly: [{ type: HostBinding, args: ["class.cds--text-input-wrapper--readonly"] }], fluidClass: [{ type: HostBinding, args: ["class.cds--text-input--fluid"] }], fluidSkeletonClass: [{ type: HostBinding, args: ["class.cds--text-input--fluid__skeleton"] }], labelInputID: [{ type: Input }], disabled: [{ type: Input }], skeleton: [{ type: Input }], labelTemplate: [{ type: Input }], textInputTemplate: [{ type: Input }], helperText: [{ type: Input }], invalidText: [{ type: Input }], invalid: [{ type: Input }], warn: [{ type: Input }], warnText: [{ type: Input }], ariaLabel: [{ type: Input }], fluid: [{ type: Input }], hideLabel: [{ type: Input }], inline: [{ type: Input }], size: [{ type: Input }], enableCounter: [{ type: Input }], maxCount: [{ type: Input }], wrapper: [{ type: ViewChild, args: ["wrapper", { static: false }] }], labelClass: [{ type: HostBinding, args: ["class.cds--form-item"] }], textInputWrapper: [{ type: HostBinding, args: ["class.cds--text-input-wrapper"] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGV4dC1pbnB1dC1sYWJlbC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW5wdXQvdGV4dC1pbnB1dC1sYWJlbC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUlOLFNBQVMsRUFFVCxXQUFXLEVBQ1gsS0FBSyxFQUlMLFdBQVcsRUFDWCxTQUFTLEVBQ1QsTUFBTSxlQUFlLENBQUM7Ozs7QUFFdkI7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBMkhILE1BQU0sT0FBTyx1QkFBdUI7SUFvSG5DOztPQUVHO0lBQ0gsWUFBc0IsaUJBQW9DO1FBQXBDLHNCQUFpQixHQUFqQixpQkFBaUIsQ0FBbUI7UUFsRzFEOzs7VUFHRTtRQUNPLGlCQUFZLEdBQUcsaUJBQWlCLEdBQUcsdUJBQXVCLENBQUMsWUFBWSxFQUFFLENBQUM7UUFFbkY7O1dBRUc7UUFDTSxhQUFRLEdBQUcsS0FBSyxDQUFDO1FBQzFCOztXQUVHO1FBQ00sYUFBUSxHQUFHLEtBQUssQ0FBQztRQWdCMUI7O1dBRUc7UUFDTSxZQUFPLEdBQUcsS0FBSyxDQUFDO1FBQ3pCOztZQUVJO1FBQ0ssU0FBSSxHQUFHLEtBQUssQ0FBQztRQVV0Qjs7V0FFRztRQUNNLFVBQUssR0FBRyxLQUFLLENBQUM7UUFFdkI7OztXQUdHO1FBQ00sY0FBUyxHQUFHLEtBQUssQ0FBQztRQUUzQjs7V0FFRztRQUNNLFdBQU0sR0FBRyxLQUFLLENBQUM7UUFFeEI7OztXQUdHO1FBQ00sU0FBSSxHQUF1QixJQUFJLENBQUM7UUFFekM7OztXQUdHO1FBQ00sa0JBQWEsR0FBRyxLQUFLLENBQUM7UUFRL0IsMERBQTBEO1FBQzFELGNBQVMsR0FBRyxDQUFDLENBQUM7UUFLdUIsZUFBVSxHQUFHLElBQUksQ0FBQztRQUVULHFCQUFnQixHQUFHLElBQUksQ0FBQztRQUV0RSxzRUFBc0U7UUFDOUQsa0JBQWEsR0FBNEIsSUFBSSxDQUFDO1FBQ3RELG1GQUFt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Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztFQXNIVDtpQkFDRDt3R0FHMEQsZUFBZTtzQkFBeEUsV0FBVzt1QkFBQyx1Q0FBdUM7Z0JBSVEsVUFBVTtzQkFBckUsV0FBVzt1QkFBQyx5Q0FBeUM7Z0JBSUwsVUFBVTtzQkFBMUQsV0FBVzt1QkFBQyw4QkFBOEI7Z0JBSWdCLGtCQUFrQjtzQkFBNUUsV0FBVzt1QkFBQyx3Q0FBd0M7Z0JBVzVDLFlBQVk7c0JBQXBCLEtBQUs7Z0JBS0csUUFBUTtzQkFBaEIsS0FBSztnQkFJRyxRQUFRO3NCQUFoQixLQUFLO2dCQU1HLGFBQWE7c0JBQXJCLEtBQUs7Z0JBQ0csaUJBQWlCO3NCQUF6QixLQUFLO2dCQUlHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBSUcsV0FBVztzQkFBbkIsS0FBSztnQkFJRyxPQUFPO3NCQUFmLEtBQUs7Z0JBSUcsSUFBSTtzQkFBWixLQUFLO2dCQUlHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBSUcsU0FBUztzQkFBakIsS0FBSztnQkFLRyxLQUFLO3NCQUFiLEtBQUs7Z0JBTUcsU0FBUztzQkFBakIsS0FBSztnQkFLRyxNQUFNO3NCQUFkLEtBQUs7Z0JBTUcsSUFBSTtzQkFBWixLQUFLO2dCQU1HLGFBQWE7c0JBQXJCLEtBQUs7Z0JBTUcsUUFBUTtzQkFBaEIsS0FBSztnQkFNbUMsT0FBTztzQkFBL0MsU0FBUzt1QkFBQyxTQUFTLEVBQUUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFO2dCQUVGLFVBQVU7c0JBQTlDLFdBQVc7dUJBQUMsc0JBQXNCO2dCQUVXLGdCQUFnQjtzQkFBN0QsV0FBVzt1QkFBQywrQkFBK0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuXHRBZnRlckNvbnRlbnRJbml0LFxuXHRBZnRlclZpZXdJbml0LFxuXHRDaGFuZ2VEZXRlY3RvclJlZixcblx0Q29tcG9uZW50LFxuXHRFbGVtZW50UmVmLFxuXHRIb3N0QmluZGluZyxcblx0SW5wdXQsXG5cdE9uQ2hhbmdlcyxcblx0T25EZXN0cm95LFxuXHRTaW1wbGVDaGFuZ2VzLFxuXHRUZW1wbGF0ZVJlZixcblx0Vmlld0NoaWxkXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5cbi8qKlxuICogR2V0IHN0YXJ0ZWQgd2l0aCBpbXBvcnRpbmcgdGhlIG1vZHVsZTpcbiAqXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBJbnB1dE1vZHVsZSB9IGZyb20gJ2NhcmJvbi1jb21wb25lbnRzLWFuZ3VsYXInO1xuICogYGBgXG4gKlxuICogYGBgaHRtbFxuICogPGNkcy10ZXh0LWxhYmVsPlxuICogXHRMYWJlbFxuICogXHQ8aW5wdXQgY2RzVGV4dCB0eXBlPVwidGV4dFwiIGNsYXNzPVwiaW5wdXQtZmllbGRcIj5cbiAqIDwvY2RzLXRleHQtbGFiZWw+XG4gKiBgYGBcbiAqXG4gKiBbU2VlIGRlbW9dKC4uLy4uLz9wYXRoPS9zdG9yeS9jb21wb25lbnRzLWlucHV0LS1iYXNpYylcbiAqL1xuQENvbXBvbmVudCh7XG5cdHNlbGVjdG9yOiBcImNkcy10ZXh0LWxhYmVsLCBpYm0tdGV4dC1sYWJlbFwiLFxuXHR0ZW1wbGF0ZTogYFxuXHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCJza2VsZXRvblwiPlxuXHRcdFx0PHNwYW4gY2xhc3M9XCJjZHMtLWxhYmVsIGNkcy0tc2tlbGV0b25cIj48L3NwYW4+XG5cdFx0XHQ8ZGl2IGNsYXNzPVwiY2RzLS10ZXh0LWlucHV0IGNkcy0tc2tlbGV0b25cIj48L2Rpdj5cblx0XHQ8L25nLWNvbnRhaW5lcj5cblx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiIXNrZWxldG9uXCI+XG5cdFx0XHQ8IS0tIG5vbi1pbmxpbmU6IGxhYmVsLXdyYXBwZXIgYWJvdmUgZmllbGQ7IGlubGluZTogbGFiZWwrdmFsaWRhdGlvbiBzaWRlLWJ5LXNpZGUgLS0+XG5cdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiIWlubGluZTsgZWxzZSBpbmxpbmVIZWFkZXJcIj5cblx0XHRcdFx0PGRpdiBjbGFzcz1cImNkcy0tdGV4dC1pbnB1dF9fbGFiZWwtd3JhcHBlclwiPlxuXHRcdFx0XHRcdDxsYWJlbFxuXHRcdFx0XHRcdFx0W2Zvcl09XCJsYWJlbElucHV0SURcIlxuXHRcdFx0XHRcdFx0W2F0dHIuYXJpYS1sYWJlbF09XCJhcmlhTGFiZWxcIlxuXHRcdFx0XHRcdFx0Y2xhc3M9XCJjZHMtLWxhYmVsXCJcblx0XHRcdFx0XHRcdFtuZ0NsYXNzXT1cIntcblx0XHRcdFx0XHRcdFx0J2Nkcy0tbGFiZWwtLWRpc2FibGVkJzogZGlzYWJsZWQsXG5cdFx0XHRcdFx0XHRcdCdjZHMtLXZpc3VhbGx5LWhpZGRlbic6IGhpZGVMYWJlbFxuXHRcdFx0XHRcdFx0fVwiPlxuXHRcdFx0XHRcdFx0PG5nLXRlbXBsYXRlICpuZ0lmPVwibGFiZWxUZW1wbGF0ZTsgZWxzZSBsYWJlbENvbnRlbnRcIiBbbmdUZW1wbGF0ZU91dGxldF09XCJsYWJlbFRlbXBsYXRlXCI+PC9uZy10ZW1wbGF0ZT5cblx0XHRcdFx0XHRcdDxuZy10ZW1wbGF0ZSAjbGFiZWxDb250ZW50PlxuXHRcdFx0XHRcdFx0XHQ8bmctY29udGVudD48L25nLWNvbnRlbnQ+XG5cdFx0XHRcdFx0XHQ8L25nLXRlbXBsYXRlPlxuXHRcdFx0XHRcdDwvbGFiZWw+XG5cdFx0XHRcdFx0PHNwYW5cblx0XHRcdFx0XHRcdCpuZ0lmPVwiZW5hYmxlQ291bnRlciAmJiBtYXhDb3VudFwiXG5cdFx0XHRcdFx0XHRjbGFzcz1cImNkcy0tbGFiZWxcIlxuXHRcdFx0XHRcdFx0W25nQ2xhc3NdPVwieydjZHMtLWxhYmVsLS1kaXNhYmxlZCc6IGRpc2FibGVkfVwiXG5cdFx0XHRcdFx0XHRhcmlhLWhpZGRlbj1cInRydWVcIj5cblx0XHRcdFx0XHRcdHt7dGV4dENvdW50fX0ve3ttYXhDb3VudH19XG5cdFx0XHRcdFx0PC9zcGFuPlxuXHRcdFx0XHQ8L2Rpdj5cblx0XHRcdDwvbmctY29udGFpbmVyPlxuXG5cdFx0XHQ8bmctdGVtcGxhdGUgI2lubGluZUhlYWRlcj5cblx0XHRcdFx0PGRpdiBjbGFzcz1cImNkcy0tdGV4dC1pbnB1dF9fbGFiZWwtaGVscGVyLXdyYXBwZXJcIj5cblx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwiY2RzLS10ZXh0LWlucHV0X19sYWJlbC13cmFwcGVyXCI+XG5cdFx0XHRcdFx0XHQ8bGFiZWxcblx0XHRcdFx0XHRcdFx0W2Zvcl09XCJsYWJlbElucHV0SURcIlxuXHRcdFx0XHRcdFx0XHRbYXR0ci5hcmlhLWxhYmVsXT1cImFyaWFMYWJlbFwiXG5cdFx0XHRcdFx0XHRcdGNsYXNzPVwiY2RzLS1sYWJlbFwiXG5cdFx0XHRcdFx0XHRcdFtuZ0NsYXNzXT1cIntcblx0XHRcdFx0XHRcdFx0XHQnY2RzLS1sYWJlbC0tZGlzYWJsZWQnOiBkaXNhYmxlZCxcblx0XHRcdFx0XHRcdFx0XHQnY2RzLS12aXN1YWxseS1oaWRkZW4nOiBoaWRlTGFiZWwsXG5cdFx0XHRcdFx0XHRcdFx0J2Nkcy0tbGFiZWwtLWlubGluZSc6IHRydWUsXG5cdFx0XHRcdFx0XHRcdFx0J2Nkcy0tbGFiZWwtLWlubGluZS0tc20nOiBzaXplID09PSAnc20nLFxuXHRcdFx0XHRcdFx0XHRcdCdjZHMtLWxhYmVsLS1pbmxpbmUtLW1kJzogc2l6ZSA9PT0gJ21kJyxcblx0XHRcdFx0XHRcdFx0XHQnY2RzLS1sYWJlbC0taW5saW5lLS1sZyc6IHNpemUgPT09ICdsZydcblx0XHRcdFx0XHRcdFx0fVwiPlxuXHRcdFx0XHRcdFx0XHQ8bmctdGVtcGxhdGUgKm5nSWY9XCJsYWJlbFRlbXBsYXRlXCIgW25nVGVtcGxhdGVPdXRsZXRdPVwibGFiZWxUZW1wbGF0ZVwiPjwvbmctdGVtcGxhdGU+XG5cdFx0XHRcdFx0XHQ8L2xhYmVsPlxuXHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCIhZmx1aWRcIj5cblx0XHRcdFx0XHRcdDxuZy1jb250YWluZXIgW25nVGVtcGxhdGVPdXRsZXRdPVwidmFsaWRhdGlvbk9ySGVscGVyXCI+PC9uZy1jb250YWluZXI+XG5cdFx0XHRcdFx0PC9uZy1jb250YWluZXI+XG5cdFx0XHRcdDwvZGl2PlxuXHRcdFx0PC9uZy10ZW1wbGF0ZT5cblxuXHRcdFx0PGRpdlxuXHRcdFx0XHRjbGFzcz1cImNkcy0tdGV4dC1pbnB1dF9fZmllbGQtb3V0ZXItd3JhcHBlclwiXG5cdFx0XHRcdFtuZ0NsYXNzXT1cInsnY2RzLS10ZXh0LWlucHV0X19maWVsZC1vdXRlci13cmFwcGVyLS1pbmxpbmUnOiBpbmxpbmV9XCI+XG5cdFx0XHQ8ZGl2XG5cdFx0XHRcdGNsYXNzPVwiY2RzLS10ZXh0LWlucHV0X19maWVsZC13cmFwcGVyXCJcblx0XHRcdFx0W25nQ2xhc3NdPVwie1xuXHRcdFx0XHRcdCdjZHMtLXRleHQtaW5wdXRfX2ZpZWxkLXdyYXBwZXItLXdhcm5pbmcnOiB3YXJuXG5cdFx0XHRcdH1cIlxuXHRcdFx0XHRcdFthdHRyLmRhdGEtaW52YWxpZF09XCIoaW52YWxpZCA/IHRydWUgOiBudWxsKVwiXG5cdFx0XHRcdFx0I3dyYXBwZXI+XG5cdFx0XHRcdFx0PHN2Z1xuXHRcdFx0XHRcdFx0Km5nSWY9XCJpbnZhbGlkICYmICF3YXJuXCJcblx0XHRcdFx0XHRcdGNkc0ljb249XCJ3YXJuaW5nLS1maWxsZWRcIlxuXHRcdFx0XHRcdFx0c2l6ZT1cIjE2XCJcblx0XHRcdFx0XHRcdGNsYXNzPVwiY2RzLS10ZXh0LWlucHV0X19pbnZhbGlkLWljb25cIj5cblx0XHRcdFx0XHQ8L3N2Zz5cblx0XHRcdFx0XHQ8c3ZnXG5cdFx0XHRcdFx0XHQqbmdJZj1cIiFpbnZhbGlkICYmIHdhcm5cIlxuXHRcdFx0XHRcdFx0Y2RzSWNvbj1cIndhcm5pbmctLWFsdC0tZmlsbGVkXCJcblx0XHRcdFx0XHRcdHNpemU9XCIxNlwiXG5cdFx0XHRcdFx0XHRjbGFzcz1cImNkcy0tdGV4dC1pbnB1dF9faW52YWxpZC1pY29uIGNkcy0tdGV4dC1pbnB1dF9faW52YWxpZC1pY29uLS13YXJuaW5nXCI+XG5cdFx0XHRcdFx0PC9zdmc+XG5cdFx0XHRcdFx0PG5nLXRlbXBsYXRlICpuZ0lmPVwidGV4dElucHV0VGVtcGxhdGU7IGVsc2UgdGV4dElucHV0Q29udGVudFwiIFtuZ1RlbXBsYXRlT3V0bGV0XT1cInRleHRJbnB1dFRlbXBsYXRlXCI+PC9uZy10ZW1wbGF0ZT5cblx0XHRcdFx0XHQ8bmctdGVtcGxhdGUgI3RleHRJbnB1dENvbnRlbnQ+XG5cdFx0XHRcdFx0XHQ8bmctY29udGVudCBzZWxlY3Q9XCJbY2RzVGV4dF0sW2libVRleHRdLGlucHV0W3R5cGU9dGV4dF0sZGl2XCI+PC9uZy1jb250ZW50PlxuXHRcdFx0XHRcdDwvbmctdGVtcGxhdGU+XG5cblx0XHRcdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiZmx1aWRcIj5cblx0XHRcdFx0XHRcdDxociBjbGFzcz1cImNkcy0tdGV4dC1pbnB1dF9fZGl2aWRlclwiIC8+XG5cdFx0XHRcdFx0XHQ8ZGl2ICpuZ0lmPVwiaW52YWxpZFwiIGNsYXNzPVwiY2RzLS1mb3JtLXJlcXVpcmVtZW50XCI+XG5cdFx0XHRcdFx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCIhaXNUZW1wbGF0ZShpbnZhbGlkVGV4dClcIj57e2ludmFsaWRUZXh0fX08L25nLWNvbnRhaW5lcj5cblx0XHRcdFx0XHRcdFx0PG5nLXRlbXBsYXRlICpuZ0lmPVwiaXNUZW1wbGF0ZShpbnZhbGlkVGV4dClcIiBbbmdUZW1wbGF0ZU91dGxldF09XCJpbnZhbGlkVGV4dFwiPjwvbmctdGVtcGxhdGU+XG5cdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdDxkaXYgKm5nSWY9XCIhaW52YWxpZCAmJiB3YXJuXCIgY2xhc3M9XCJjZHMtLWZvcm0tcmVxdWlyZW1lbnRcIj5cblx0XHRcdFx0XHRcdFx0PG5nLWNvbnRhaW5lciAqbmdJZj1cIiFpc1RlbXBsYXRlKHdhcm5UZXh0KVwiPnt7d2FyblRleHR9fTwvbmctY29udGFpbmVyPlxuXHRcdFx0XHRcdFx0XHQ8bmctdGVtcGxhdGUgKm5nSWY9XCJpc1RlbXBsYXRlKHdhcm5UZXh0KVwiIFtuZ1RlbXBsYXRlT3V0bGV0XT1cIndhcm5UZXh0XCI+PC9uZy10ZW1wbGF0ZT5cblx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdDwvbmctY29udGFpbmVyPlxuXHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0PG5nLWNvbnRhaW5lciAqbmdJZj1cIiFmbHVpZCAmJiAhaW5saW5lXCI+XG5cdFx0XHRcdFx0PG5nLWNvbnRhaW5lciBbbmdUZW1wbGF0ZU91dGxldF09XCJ2YWxpZGF0aW9uT3JIZWxwZXJcIj48L25nLWNvbnRhaW5lcj5cblx0XHRcdFx0PC9uZy1jb250YWluZXI+XG5cdFx0XHQ8L2Rpdj5cblx0XHQ8L25nLWNvbnRhaW5lcj5cblxuXHRcdDxuZy10ZW1wbGF0ZSAjdmFsaWRhdGlvbk9ySGVscGVyPlxuXHRcdFx0PGRpdlxuXHRcdFx0XHQqbmdJZj1cImhlbHBlclRleHQgJiYgIWludmFsaWQgJiYgIXdhcm5cIlxuXHRcdFx0XHRjbGFzcz1cImNkcy0tZm9ybV9faGVscGVyLXRleHRcIlxuXHRcdFx0XHRbbmdDbGFzc109XCJ7J2Nkcy0tZm9ybV9faGVscGVyLXRleHQtLWRpc2FibGVkJzogZGlzYWJsZWQsICdjZHMtLWZvcm1fX2hlbHBlci10ZXh0LS1pbmxpbmUnOiBpbmxpbmV9XCI+XG5cdFx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCIhaXNUZW1wbGF0ZShoZWxwZXJUZXh0KVwiPnt7aGVscGVyVGV4dH19PC9uZy1jb250YWluZXI+XG5cdFx0XHRcdDxuZy10ZW1wbGF0ZSAqbmdJZj1cImlzVGVtcGxhdGUoaGVscGVyVGV4dClcIiBbbmdUZW1wbGF0ZU91dGxldF09XCJoZWxwZXJUZXh0XCI+PC9uZy10ZW1wbGF0ZT5cblx0XHRcdDwvZGl2PlxuXHRcdFx0PGRpdiAqbmdJZj1cImludmFsaWRcIiBjbGFzcz1cImNkcy0tZm9ybS1yZXF1aXJlbWVudFwiPlxuXHRcdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiIWlzVGVtcGxhdGUoaW52YWxpZFRleHQpXCI+e3tpbnZhbGlkVGV4dH19PC9uZy1jb250YWluZXI+XG5cdFx0XHRcdDxuZy10ZW1wbGF0ZSAqbmdJZj1cImlzVGVtcGxhdGUoaW52YWxpZFRleHQpXCIgW25nVGVtcGxhdGVPdXRsZXRdPVwiaW52YWxpZFRleHRcIj48L25nLXRlbXBsYXRlPlxuXHRcdFx0PC9kaXY+XG5cdFx0XHQ8ZGl2ICpuZ0lmPVwiIWludmFsaWQgJiYgd2FyblwiIGNsYXNzPVwiY2RzLS1mb3JtLXJlcXVpcmVtZW50XCI+XG5cdFx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCIhaXNUZW1wbGF0ZSh3YXJuVGV4dClcIj57e3dhcm5UZXh0fX08L25nLWNvbnRhaW5lcj5cblx0XHRcdFx0PG5nLXRlbXBsYXRlICpuZ0lmPVwiaXNUZW1wbGF0ZSh3YXJuVGV4dClcIiBbbmdUZW1wbGF0ZU91dGxldF09XCJ3YXJuVGV4dFwiPjwvbmctdGVtcGxhdGU+XG5cdFx0XHQ8L2Rpdj5cblx0XHQ8L25nLXRlbXBsYXRlPlxuXHRgXG59KVxuZXhwb3J0IGNsYXNzIFRleHRJbnB1dExhYmVsQ29tcG9uZW50IGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCwgQWZ0ZXJDb250ZW50SW5pdCwgT25DaGFuZ2VzLCBPbkRlc3Ryb3kge1xuXG5cdEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tdGV4dC1pbnB1dC13cmFwcGVyLS1pbmxpbmVcIikgZ2V0IGlzSW5saW5lV3JhcHBlcigpIHtcblx0XHRyZXR1cm4gdGhpcy5pbmxpbmU7XG5cdH1cblxuXHRASG9zdEJpbmRpbmcoXCJjbGFzcy5jZHMtLXRleHQtaW5wdXQtd3JhcHBlci0tcmVhZG9ubHlcIikgZ2V0IGlzUmVhZG9ubHkoKSB7XG5cdFx0cmV0dXJuIHRoaXMud3JhcHBlcj8ubmF0aXZlRWxlbWVudC5xdWVyeVNlbGVjdG9yKFwiaW5wdXRcIik/LnJlYWRPbmx5ID8/IGZhbHNlO1xuXHR9XG5cblx0QEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS10ZXh0LWlucHV0LS1mbHVpZFwiKSBnZXQgZmx1aWRDbGFzcygpIHtcblx0XHRyZXR1cm4gdGhpcy5mbHVpZCAmJiAhdGhpcy5za2VsZXRvbjtcblx0fVxuXG5cdEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tdGV4dC1pbnB1dC0tZmx1aWRfX3NrZWxldG9uXCIpIGdldCBmbHVpZFNrZWxldG9uQ2xhc3MoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZmx1aWQgJiYgdGhpcy5za2VsZXRvbjtcblx0fVxuXHQvKipcblx0ICogVXNlZCB0byBidWlsZCB0aGUgaWQgb2YgdGhlIGlucHV0IGl0ZW0gYXNzb2NpYXRlZCB3aXRoIHRoZSBgTGFiZWxgLlxuXHQgKi9cblx0c3RhdGljIGxhYmVsQ291bnRlciA9IDA7XG5cdC8qKlxuXHQgKiBUaGUgaWQgb2YgdGhlIGlucHV0IGl0ZW0gYXNzb2NpYXRlZCB3aXRoIHRoZSBgTGFiZWxgLiBUaGlzIHZhbHVlIGlzIGFsc28gdXNlZCB0byBhc3NvY2lhdGUgdGhlIGBMYWJlbGAgd2l0aFxuXHQgKiBpdHMgaW5wdXQgY291bnRlcnBhcnQgdGhyb3VnaCB0aGUgJ2ZvcicgYXR0cmlidXRlLlxuXHQqL1xuXHRASW5wdXQoKSBsYWJlbElucHV0SUQgPSBcImlibS10ZXh0LWlucHV0LVwiICsgVGV4dElucHV0TGFiZWxDb21wb25lbnQubGFiZWxDb3VudGVyKys7XG5cblx0LyoqXG5cdCAqIFNldCB0byBgdHJ1ZWAgZm9yIGEgZGlzYWJsZWQgbGFiZWwuXG5cdCAqL1xuXHRASW5wdXQoKSBkaXNhYmxlZCA9IGZhbHNlO1xuXHQvKipcblx0ICogU2V0IHRvIGB0cnVlYCBmb3IgYSBsb2FkaW5nIGxhYmVsLlxuXHQgKi9cblx0QElucHV0KCkgc2tlbGV0b24gPSBmYWxzZTtcblxuXHQvKipcblx0ICogSGVscGVyIGlucHV0IHByb3BlcnR5IGZvciBlYXNlIG9mIG1pZ3JhdGlvblxuXHQgKiBTaW5jZSB3ZSBjYW5ub3QgcGFzcyBuZy1jb250ZW50IGRvd24gZWFzaWx5IGZyb20gbGFiZWwgY29tcG9uZW50LCB3ZSB3aWxsIGFjY2VwdCB0aGUgdGVtcGxhdGVzXG5cdCAqL1xuXHRASW5wdXQoKSBsYWJlbFRlbXBsYXRlOiBUZW1wbGF0ZVJlZjxhbnk+O1xuXHRASW5wdXQoKSB0ZXh0SW5wdXRUZW1wbGF0ZTogVGVtcGxhdGVSZWY8YW55Pjtcblx0LyoqXG5cdCAqIE9wdGlvbmFsIGhlbHBlciB0ZXh0IHRoYXQgYXBwZWFycyB1bmRlciB0aGUgbGFiZWwuXG5cdCAqL1xuXHRASW5wdXQoKSBoZWxwZXJUZXh0OiBzdHJpbmcgfCBUZW1wbGF0ZVJlZjxhbnk+O1xuXHQvKipcblx0ICogU2V0cyB0aGUgaW52YWxpZCB0ZXh0LlxuXHQgKi9cblx0QElucHV0KCkgaW52YWxpZFRleHQ6IHN0cmluZyB8IFRlbXBsYXRlUmVmPGFueT47XG5cdC8qKlxuXHQgKiBTZXQgdG8gYHRydWVgIGZvciBhbiBpbnZhbGlkIGxhYmVsIGNvbXBvbmVudC5cblx0ICovXG5cdEBJbnB1dCgpIGludmFsaWQgPSBmYWxzZTtcblx0LyoqXG5cdCAgKiBTZXQgdG8gYHRydWVgIHRvIHNob3cgYSB3YXJuaW5nIChjb250ZW50cyBzZXQgYnkgd2FybmluZ1RleHQpXG5cdCAgKi9cblx0QElucHV0KCkgd2FybiA9IGZhbHNlO1xuXHQvKipcblx0ICogU2V0cyB0aGUgd2FybmluZyB0ZXh0XG5cdCAqL1xuXHRASW5wdXQoKSB3YXJuVGV4dDogc3RyaW5nIHwgVGVtcGxhdGVSZWY8YW55Pjtcblx0LyoqXG5cdCAqIFNldCB0aGUgYXJpYWxhYmVsIGZvciBsYWJlbFxuXHQgKi9cblx0QElucHV0KCkgYXJpYUxhYmVsOiBzdHJpbmc7XG5cblx0LyoqXG5cdCAqIEV4cGVyaW1lbnRhbDogZW5hYmxlIGZsdWlkIHN0YXRlXG5cdCAqL1xuXHRASW5wdXQoKSBmbHVpZCA9IGZhbHNlO1xuXG5cdC8qKlxuXHQgKiBTZXQgdG8gYHRydWVgIHRvIGhpZGUgdGhlIGxhYmVsIHZpc3VhbGx5LCBidXQga2VlcCBhY2Nlc3NpYmxlIHRvXG5cdCAqIHNjcmVlbiByZWFkZXJzLlxuXHQgKi9cblx0QElucHV0KCkgaGlkZUxhYmVsID0gZmFsc2U7XG5cblx0LyoqXG5cdCAqIFNldCB0byBgdHJ1ZWAgdG8gcmVuZGVyIHRoZSBsYWJlbCBhbmQgZmllbGQgc2lkZS1ieS1zaWRlIGluc3RlYWQgb2Ygc3RhY2tlZC5cblx0ICovXG5cdEBJbnB1dCgpIGlubGluZSA9IGZhbHNlO1xuXG5cdC8qKlxuXHQgKiBUaGUgcmVuZGVyIHNpemUgZm9yIHRoZSBgVGV4dElucHV0YC4gVXNlZCB0byBjb21wdXRlIHRoZSBJTkxJTkUgbGFiZWwgc2l6ZVxuXHQgKiB2YXJpYW50IGNsYXNzIChgY2RzLS1sYWJlbC0taW5saW5lLS17c2l6ZX1gKS5cblx0ICovXG5cdEBJbnB1dCgpIHNpemU6IFwic21cIiB8IFwibWRcIiB8IFwibGdcIiA9IFwibWRcIjtcblxuXHQvKipcblx0ICogU2V0IHRvIGB0cnVlYCAoYG1heENvdW50YCBtdXN0IGJlIHNldCkgdG8gZGlzcGxheXMgYSBsaXZlIGNoYXJhY3RlclxuXHQgKiBjb3VudGVyIGFsb25nc2lkZSB0aGUgbGFiZWwuXG5cdCAqL1xuXHRASW5wdXQoKSBlbmFibGVDb3VudGVyID0gZmFsc2U7XG5cblx0LyoqXG5cdCAqIE1heGltdW0gbnVtYmVyIG9mIGNoYXJhY3RlcnMgKG9yIHdvcmRzKSBhbGxvd2VkLiBSZXF1aXJlZCBmb3IgdGhlXG5cdCAqIGNvdW50ZXIgdG8gZGlzcGxheS5cblx0ICovXG5cdEBJbnB1dCgpIG1heENvdW50OiBudW1iZXI7XG5cblx0Ly8gVHJhY2tzIGN1cnJlbnQgY2hhcmFjdGVyIGNvdW50IGZvciB0aGUgY291bnRlciBkaXNwbGF5LlxuXHR0ZXh0Q291bnQgPSAwO1xuXG5cdC8vIEB0cy1pZ25vcmVcblx0QFZpZXdDaGlsZChcIndyYXBwZXJcIiwgeyBzdGF0aWM6IGZhbHNlIH0pIHdyYXBwZXI6IEVsZW1lbnRSZWY8SFRNTERpdkVsZW1lbnQ+O1xuXG5cdEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tZm9ybS1pdGVtXCIpIGxhYmVsQ2xhc3MgPSB0cnVlO1xuXG5cdEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tdGV4dC1pbnB1dC13cmFwcGVyXCIpIHRleHRJbnB1dFdyYXBwZXIgPSB0cnVlO1xuXG5cdC8vIENhY2hlZCByZWZlcmVuY2UgdG8gdGhlIGlucHV0IGVsZW1lbnQsIHNldCBvbmNlIGluIG5nQWZ0ZXJWaWV3SW5pdC5cblx0cHJpdmF0ZSBfaW5wdXRFbGVtZW50OiBIVE1MSW5wdXRFbGVtZW50IHwgbnVsbCA9IG51bGw7XG5cdC8vIENhY2hlZCBsaXN0ZW5lciBzbyBpdCBjYW4gYmUgcmVtb3ZlZCBwcmVjaXNlbHkgKGF2b2lkcyBhbm9ueW1vdXMtZnVuY3Rpb24gbGVhaykuXG5cdHByaXZhdGUgX2lucHV0TGlzdGVuZXI6ICgoZTogRXZlbnQpID0+IHZvaWQpIHwgbnVsbCA9IG51bGw7XG5cblx0LyoqXG5cdCAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgTGFiZWwuXG5cdCAqL1xuXHRjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgY2hhbmdlRGV0ZWN0b3JSZWY6IENoYW5nZURldGVjdG9yUmVmKSB7fVxuXG5cdC8qKlxuXHQgKiBTZXRzIHRoZSBpZCBvbiB0aGUgaW5wdXQgaXRlbSBhc3NvY2lhdGVkIHdpdGggdGhlIGBMYWJlbGAgYW5kIGF0dGFjaGVzIHRoZVxuXHQgKiBjb3VudGVyIGxpc3RlbmVyIHdoZW4gYGVuYWJsZUNvdW50ZXJgIGlzIGFscmVhZHkgYHRydWVgIG9uIGZpcnN0IHJlbmRlci5cblx0ICovXG5cdG5nQWZ0ZXJWaWV3SW5pdCgpIHtcblx0XHRpZiAodGhpcy53cmFwcGVyKSB7XG5cdFx0XHQvLyBQcmlvcml0aXplIHNldHRpbmcgaWQgdG8gYGlucHV0YCBvdmVyIGRpdlxuXHRcdFx0Y29uc3QgaW5wdXRFbGVtZW50ID0gdGhpcy53cmFwcGVyLm5hdGl2ZUVsZW1lbnQucXVlcnlTZWxlY3RvcihcImlucHV0XCIpO1xuXHRcdFx0aWYgKGlucHV0RWxlbWVudCkge1xuXHRcdFx0XHQvLyBhdm9pZCBvdmVycmlkaW5nIGlkcyBhbHJlYWR5IHNldCBieSB0aGUgdXNlciwgcmV1c2UgaXQgaW5zdGVhZFxuXHRcdFx0XHRpZiAoaW5wdXRFbGVtZW50LmlkKSB7XG5cdFx0XHRcdFx0dGhpcy5sYWJlbElucHV0SUQgPSBpbnB1dEVsZW1lbnQuaWQ7XG5cdFx0XHRcdFx0dGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5kZXRlY3RDaGFuZ2VzKCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0aW5wdXRFbGVtZW50LnNldEF0dHJpYnV0ZShcImlkXCIsIHRoaXMubGFiZWxJbnB1dElEKTtcblxuXHRcdFx0XHR0aGlzLl9pbnB1dEVsZW1lbnQgPSBpbnB1dEVsZW1lbnQ7XG5cblx0XHRcdFx0aWYgKHRoaXMuZW5hYmxlQ291bnRlcikge1xuXHRcdFx0XHRcdHRoaXMudGV4dENvdW50ID0gaW5wdXRFbGVtZW50LnZhbHVlPy5sZW5ndGggfHwgMDtcblx0XHRcdFx0XHR0aGlzLl9hdHRhY2hDb3VudGVyTGlzdGVuZXIoKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgZGl2RWxlbWVudCA9IHRoaXMud3JhcHBlci5uYXRpdmVFbGVtZW50LnF1ZXJ5U2VsZWN0b3IoXCJkaXZcIik7XG5cdFx0XHRpZiAoZGl2RWxlbWVudCkge1xuXHRcdFx0XHRpZiAoZGl2RWxlbWVudC5pZCkge1xuXHRcdFx0XHRcdHRoaXMubGFiZWxJbnB1dElEID0gZGl2RWxlbWVudC5pZDtcblx0XHRcdFx0XHR0aGlzLmNoYW5nZURldGVjdG9yUmVmLmRldGVjdENoYW5nZXMoKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRkaXZFbGVtZW50LnNldEF0dHJpYnV0ZShcImlkXCIsIHRoaXMubGFiZWxJbnB1dElEKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogQXR0YWNoL3JlbW92ZSBsaXN0ZW5lciBhbmQgc2VlZCBgdGV4dENvdW50YCBmcm9tIHRoZSB0ZXh0YXJlYSdzIGN1cnJlbnQgdmFsdWUuXG5cdCAqIEBwYXJhbSBjaGFuZ2VzXG5cdCAqL1xuXHRuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XG5cdFx0aWYgKGNoYW5nZXMuZW5hYmxlQ291bnRlciAmJiAhY2hhbmdlcy5lbmFibGVDb3VudGVyLmZpcnN0Q2hhbmdlKSB7XG5cdFx0XHRpZiAoY2hhbmdlcy5lbmFibGVDb3VudGVyLmN1cnJlbnRWYWx1ZSkge1xuXHRcdFx0XHRpZiAodGhpcy5faW5wdXRFbGVtZW50KSB7XG5cdFx0XHRcdFx0dGhpcy50ZXh0Q291bnQgPSB0aGlzLl9pbnB1dEVsZW1lbnQudmFsdWU/Lmxlbmd0aCB8fCAwO1xuXHRcdFx0XHRcdHRoaXMuX2F0dGFjaENvdW50ZXJMaXN0ZW5lcigpO1xuXHRcdFx0XHRcdHRoaXMuY2hhbmdlRGV0ZWN0b3JSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aGlzLl9kZXRhY2hDb3VudGVyTGlzdGVuZXIoKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRuZ0FmdGVyQ29udGVudEluaXQoKSB7XG5cdFx0dGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5kZXRlY3RDaGFuZ2VzKCk7XG5cdH1cblxuXHRuZ09uRGVzdHJveSgpIHtcblx0XHR0aGlzLl9kZXRhY2hDb3VudGVyTGlzdGVuZXIoKTtcblx0fVxuXG5cdHB1YmxpYyBpc1RlbXBsYXRlKHZhbHVlKSB7XG5cdFx0cmV0dXJuIHZhbHVlIGluc3RhbmNlb2YgVGVtcGxhdGVSZWY7XG5cdH1cblxuXHQvKipcblx0ICogQXR0YWNoZXMgdGhlIGlucHV0IGV2ZW50IGxpc3RlbmVyLCBlbnN1cmluZyBpdCBpcyBuZXZlciBhZGRlZCB0d2ljZS5cblx0ICovXG5cdHByaXZhdGUgX2F0dGFjaENvdW50ZXJMaXN0ZW5lcigpOiB2b2lkIHtcblx0XHR0aGlzLl9kZXRhY2hDb3VudGVyTGlzdGVuZXIoKTtcblx0XHRpZiAoIXRoaXMuX2lucHV0RWxlbWVudCkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHR0aGlzLl9pbnB1dExpc3RlbmVyID0gKGU6IEV2ZW50KSA9PiB7XG5cdFx0XHR0aGlzLnRleHRDb3VudCA9IChlLnRhcmdldCBhcyBIVE1MSW5wdXRFbGVtZW50KS52YWx1ZT8ubGVuZ3RoIHx8IDA7XG5cdFx0XHR0aGlzLmNoYW5nZURldGVjdG9yUmVmLmRldGVjdENoYW5nZXMoKTtcblx0XHR9O1xuXHRcdHRoaXMuX2lucHV0RWxlbWVudC5hZGRFdmVudExpc3RlbmVyKFwiaW5wdXRcIiwgdGhpcy5faW5wdXRMaXN0ZW5lcik7XG5cdH1cblxuXHQvKipcblx0ICogUmVtb3ZlcyB0aGUgaW5wdXQgZXZlbnQgbGlzdGVuZXIgYW5kIGNsZWFycyB0aGUgY2FjaGVkIHJlZmVyZW5jZS5cblx0ICovXG5cdHByaXZhdGUgX2RldGFjaENvdW50ZXJMaXN0ZW5lcigpOiB2b2lkIHtcblx0XHRpZiAodGhpcy5faW5wdXRMaXN0ZW5lciAmJiB0aGlzLl9pbnB1dEVsZW1lbnQpIHtcblx0XHRcdHRoaXMuX2lucHV0RWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKFwiaW5wdXRcIiwgdGhpcy5faW5wdXRMaXN0ZW5lcik7XG5cdFx0XHR0aGlzLl9pbnB1dExpc3RlbmVyID0gbnVsbDtcblx0XHR9XG5cdH1cbn1cbiJdfQ==