@clr/angular
Version:
Angular components for Clarity
472 lines • 62.9 kB
JavaScript
/*
* Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/
import { isPlatformBrowser } from '@angular/common';
import { Component, ContentChild, ContentChildren, EventEmitter, Inject, Input, Output, PLATFORM_ID, ViewChild, } from '@angular/core';
import { filter } from 'rxjs/operators';
import { uniqueIdFactory } from '../utils/id-generator/id-generator.service';
import { ButtonHubService } from './providers/button-hub.service';
import { HeaderActionService } from './providers/header-actions.service';
import { PageCollectionService } from './providers/page-collection.service';
import { WizardNavigationService } from './providers/wizard-navigation.service';
import { ClrWizardHeaderAction } from './wizard-header-action';
import { ClrWizardPage } from './wizard-page';
import { ClrWizardTitle } from './wizard-title';
import * as i0 from "@angular/core";
import * as i1 from "../utils";
import * as i2 from "./providers/wizard-navigation.service";
import * as i3 from "./providers/page-collection.service";
import * as i4 from "./providers/button-hub.service";
import * as i5 from "./providers/header-actions.service";
import * as i6 from "@angular/common";
import * as i7 from "../modal/modal";
import * as i8 from "../modal/modal-body";
import * as i9 from "./wizard-stepnav";
export class ClrWizard {
constructor(platformId, commonStrings, navService, pageCollection, buttonService, headerActionService, differs) {
this.platformId = platformId;
this.commonStrings = commonStrings;
this.navService = navService;
this.pageCollection = pageCollection;
this.buttonService = buttonService;
this.headerActionService = headerActionService;
/**
* Set the aria-label for the stepnav section of the wizard. Set using `[clrWizardStepnavAriaLabel]` input.
*/
this.stepnavAriaLabel = this.commonStrings.keys.wizardStepnavAriaLabel;
/**
* Set the modal size of the wizard. Set using `[clrWizardSize]` input.
*/
this.size = 'xl';
/**
* Tells the modal part of the wizard whether it should have a close "X"
* in the top right corner. Set using `[clrWizardClosable]` input.
*/
this.closable = true;
/**
* Emits when the wizard is opened or closed.
* Listen via `(clrWizardOpenChange)` event.
*/
this._openChanged = new EventEmitter(false);
/**
* Emits when the wizard is canceled. Listen via `(clrWizardOnCancel)` event.
* Can be combined with the `[clrWizardPreventDefaultCancel]` input to create
* wizard-level custom cancel routines.
*/
this.onCancel = new EventEmitter(false);
/**
* Emits when the wizard is completed. Listen via `(clrWizardOnFinish)` event.
* Can be combined with the `[clrWizardPreventDefaultNext]` input to create
* wizard-level custom completion routines.
*/
this.wizardFinished = new EventEmitter(false);
/**
* Emits when the wizard is reset. Listen via `(clrWizardOnReset)` event.
*/
this.onReset = new EventEmitter(false);
/**
* Emits when the current page has changed. Listen via `(clrWizardCurrentPageChanged)` event.
* output. Useful for non-blocking validation.
*/
this.currentPageChanged = new EventEmitter(false);
/**
* Emits when the wizard moves to the next page. Listen via `(clrWizardOnNext)` event.
* Can be combined with the `[clrWizardPreventDefaultNext]` input to create
* wizard-level custom navigation routines, which are useful for validation.
*/
this.onMoveNext = new EventEmitter(false);
/**
* Emits when the wizard moves to the previous page. Can be useful for validation.
* Listen via `(clrWizardOnPrevious)` event.
*/
this.onMovePrevious = new EventEmitter(false);
this._open = false;
this.wizardId = uniqueIdFactory();
this._forceForward = false;
this._stopNext = false;
this._stopCancel = false;
this._stopNavigation = false;
this._disableStepnav = false;
this.subscriptions = [];
this.subscriptions.push(this.listenForNextPageChanges(), this.listenForPreviousPageChanges(), this.listenForCancelChanges(), this.listenForFinishedChanges(), this.listenForPageChanges());
this.differ = differs.find([]).create(null);
}
/**
* Resets page completed states when navigating backwards.
* Set using `[clrWizardForceForwardNavigation]` input.
*/
get forceForward() {
return this._forceForward;
}
set forceForward(value) {
this._forceForward = !!value;
this.navService.forceForwardNavigation = value;
}
/**
* Toggles open/close of the wizard component.
* Set using the `[clrWizardOpen]` input.
*/
set clrWizardOpen(open) {
if (open) {
this.buttonService.buttonsReady = true;
}
this._open = open;
}
/**
* Prevents ClrWizard from moving to the next page or closing itself on finishing.
* Set using the `[clrWizardPreventDefaultNext]` input. Note that using stopNext
* will require you to create your own calls to .next() and .finish() in your
* host component to make the ClrWizard work as expected.
*/
get stopNext() {
return this._stopNext;
}
set stopNext(value) {
this._stopNext = !!value;
this.navService.wizardHasAltNext = value;
}
/**
* Prevents ClrWizard from closing when the cancel button or close "X" is clicked.
* Set using the `[clrWizardPreventDefaultCancel]` input.
*
* Note that using stopCancel will require you to create your own calls to `close()` in your host compone`nt
* to make the ClrWizard work as expected. Useful for doing checks or prompts
* before closing a ClrWizard.
*/
get stopCancel() {
return this._stopCancel;
}
set stopCancel(value) {
this._stopCancel = !!value;
this.navService.wizardHasAltCancel = value;
}
/**
* Prevents ClrWizard from performing any form of navigation away from the current
* page. Set using the `[clrWizardPreventNavigation]` input.
* Note that stopNavigation is meant to freeze the wizard in place, typically
* during a long validation or background action where you want the wizard to
* display loading content but not allow the user to execute navigation in
* the stepnav, close X, or the back, finish, or next buttons.
*/
get stopNavigation() {
return this._stopNavigation;
}
set stopNavigation(value) {
this._stopNavigation = !!value;
this.navService.wizardStopNavigation = value;
}
/**
* Prevents clicks on the links in the stepnav from working.
* Set using `[clrWizardDisableStepnav]` input.
* A more granular bypassing of navigation which can be useful when your
* ClrWizard is in a state of completion and you don't want users to be
* able to jump backwards and change things.
*/
get disableStepnav() {
return this._disableStepnav;
}
set disableStepnav(value) {
this._disableStepnav = !!value;
this.navService.wizardDisableStepnav = value;
}
get currentPage() {
return this.navService.currentPage;
}
set currentPage(page) {
this.navService.goTo(page, true);
}
get isLast() {
return this.navService.currentPageIsLast;
}
get isFirst() {
return this.navService.currentPageIsFirst;
}
ngAfterContentInit() {
this.pageCollection.pages = this.pages;
this.headerActionService.wizardHeaderActions = this.headerActions;
}
ngDoCheck() {
this.updateNavOnPageChanges();
}
ngOnDestroy() {
this.subscriptions.forEach(s => s.unsubscribe());
}
/**
* Marks Wizard as finished. By default it does not execute event
* emissions or checks before completing and closing. This method is commonly
* used as part of an alternative navigation with `[clrWizardPreventDefaultNext]`.
*
* If `skipChecksAndEmits` is true, the wizard will complete and close
* regardless of the state of its current page. This is useful for alternative
* navigation where event emissions have already been done and firing them again
* may cause an event loop.
*/
finish(skipChecksAndEmits = true) {
if (skipChecksAndEmits) {
this.forceFinish();
}
else {
this.navService.finish();
}
}
/**
* Marks the wizard as finished but does run checks and emissions.
* Good for a last step in an alternate workflow. Does the same thing as
* calling `ClrWizard.finish(true)` or `ClrWizard.finish()` without a parameter.
*/
forceFinish() {
if (this.stopNavigation) {
return;
}
this.close();
}
/**
* Opens the wizard. If there is no current page defined, sets the first page in the wizard to be current.
*/
open() {
this._open = true;
if (!this.currentPage) {
this.navService.setFirstPageCurrent();
}
// Only render buttons when wizard is opened, to avoid chocolate errors
this.buttonService.buttonsReady = true;
this._openChanged.emit(true);
}
/**
* Closes the wizard. Call this directly instead of `cancel()` to implement alternative cancel functionality.
*/
close() {
if (this.stopNavigation) {
return;
}
this._open = false;
this._openChanged.emit(false);
}
/**
* Used to open and close the wizard. By default the wizard will
* close if invoked with no parameter. If parameter is true wizard will open
* else if false will close.
*/
toggle(open) {
if (open) {
this.open();
}
else {
this.close();
}
}
/**
* Moves the wizard to the previous page.
*/
previous() {
this.navService.previous();
}
/**
* By default, `next()` does not execute event emissions.
* This method is commonly called as part of an alternative navigation
* with `[clrWizardPreventDefaultNext]`. The wizard will move to the next page
* regardless of the state of its current page. This is useful for alternative
* navigation where event emissions have already been done and firing them again
* may cause an event loop.
*
* If `skipChecksAndEmits` is false, the wizard will execute default checks
* and emit events as normal. This is useful for custom buttons or programmatic
* workflows that are not executing the wizards default checks and emissions.
* It is another way to navigate without having to rewrite the wizard’s default
* functionality from scratch.
*/
next(skipChecksAndEmits = true) {
if (skipChecksAndEmits) {
this.forceNext();
}
else {
this.navService.next();
}
}
/**
* Moves the wizard to the next page without the checks and emissions.
* Good for a last step in an alternate workflow.
* Alias for `ClrWizard.next(true)` or `ClrWizard.next()`
*/
forceNext() {
this.navService.forceNext();
}
/**
* Cancels and closes the wizard. Do not use this for an override of the cancel
* the functionality with `[clrWizardPreventDefaultCancel]`, `[clrWizardPreventPageDefaultCancel]`,
* or `[clrWizardPagePreventDefault]` because it will initiate the same checks
* and event emissions that invoked your event handler. Use `ClrWizard.close()` instead.
*/
cancel() {
this.navService.cancel();
}
/**
* Overrides behavior of the underlying modal to avoid collisions with
* alternative cancel functionality. In most cases, use `ClrWizard.cancel()` instead.
*/
modalCancel() {
if (this.closable) {
this.checkAndCancel();
}
}
/**
* Checks for alternative cancel flows defined at the current page or
* wizard level. Performs a canceled if not. Emits events that initiate
* the alternative cancel outputs `(clrWizardPageOnCancel)` and `(clrWizardOnCancel)`.
*/
checkAndCancel() {
const currentPage = this.currentPage;
const currentPageHasOverrides = currentPage.stopCancel || currentPage.preventDefault;
if (this.stopNavigation) {
return;
}
currentPage.pageOnCancel.emit();
if (!currentPageHasOverrides) {
this.onCancel.emit();
}
if (!this.stopCancel && !currentPageHasOverrides) {
this.close();
}
}
/**
* Navigates to a given page in the Wizard. Navigation will invoke the wizard’s default
* checks and event emissions.
*
* The format of the expected ID parameter can be found in the return of the
* ClrWizardPage.id getter, usually prefixed with `clr-wizard-page-` and then either a
* numeric ID or the ID specified for the `ClrWizardPage` component’s `id` input.
*/
goTo(pageId) {
if (!pageId) {
return;
}
this.navService.goTo(pageId);
}
/**
* Reset sets all WizardPages to incomplete and sets the first page in the `ClrWizard` to
* be the current page, resetting the wizard navigation.
* Use `(clrWizardOnReset)` event to reset the data or model of your wizard.
*/
reset() {
this.pageCollection.reset();
this.onReset.next();
}
listenForNextPageChanges() {
return this.navService.movedToNextPage.pipe(filter(() => isPlatformBrowser(this.platformId))).subscribe(() => {
this.onMoveNext.emit();
this.pageTitle?.nativeElement.focus();
});
}
listenForPreviousPageChanges() {
return this.navService.movedToPreviousPage.pipe(filter(() => isPlatformBrowser(this.platformId))).subscribe(() => {
this.onMovePrevious.emit();
this.pageTitle?.nativeElement.focus();
});
}
listenForCancelChanges() {
return this.navService.notifyWizardCancel.subscribe(() => this.checkAndCancel());
}
listenForFinishedChanges() {
return this.navService.wizardFinished.subscribe(() => this.emitWizardFinished());
}
listenForPageChanges() {
return this.navService.currentPageChanged.subscribe(() => {
// Added to address VPAT-749:
// When clicking on a wizard tab, focus should move to that
// tabs content to make the wizard more accessible.
this.pageTitle?.nativeElement.focus();
this.currentPageChanged.emit();
});
}
updateNavOnPageChanges() {
const changes = this.differ.diff(this.pages);
if (changes) {
changes.forEachAddedItem(() => this.navService.updateNavigation());
changes.forEachRemovedItem(() => this.navService.updateNavigation());
}
}
emitWizardFinished() {
if (!this.stopNext) {
this.forceFinish();
}
this.wizardFinished.emit();
}
}
ClrWizard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizard, deps: [{ token: PLATFORM_ID }, { token: i1.ClrCommonStringsService }, { token: i2.WizardNavigationService }, { token: i3.PageCollectionService }, { token: i4.ButtonHubService }, { token: i5.HeaderActionService }, { token: i0.IterableDiffers }], target: i0.ɵɵFactoryTarget.Component });
ClrWizard.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrWizard, selector: "clr-wizard", inputs: { stepnavAriaLabel: ["clrWizardStepnavAriaLabel", "stepnavAriaLabel"], size: ["clrWizardSize", "size"], closable: ["clrWizardClosable", "closable"], forceForward: ["clrWizardForceForwardNavigation", "forceForward"], clrWizardOpen: "clrWizardOpen", stopNext: ["clrWizardPreventDefaultNext", "stopNext"], stopCancel: ["clrWizardPreventDefaultCancel", "stopCancel"], stopNavigation: ["clrWizardPreventNavigation", "stopNavigation"], disableStepnav: ["clrWizardDisableStepnav", "disableStepnav"] }, outputs: { _openChanged: "clrWizardOpenChange", onCancel: "clrWizardOnCancel", wizardFinished: "clrWizardOnFinish", onReset: "clrWizardOnReset", currentPageChanged: "clrWizardCurrentPageChanged", onMoveNext: "clrWizardOnNext", onMovePrevious: "clrWizardOnPrevious" }, host: { properties: { "class.clr-wizard": "true", "class.wizard-md": "size == 'md'", "class.wizard-lg": "size == 'lg'", "class.wizard-xl": "size == 'xl'", "class.lastPage": "navService.currentPageIsLast" } }, providers: [WizardNavigationService, PageCollectionService, ButtonHubService, HeaderActionService], queries: [{ propertyName: "wizardTitle", first: true, predicate: ClrWizardTitle, descendants: true }, { propertyName: "pages", predicate: ClrWizardPage, descendants: true }, { propertyName: "headerActions", predicate: ClrWizardHeaderAction }], viewQueries: [{ propertyName: "pageTitle", first: true, predicate: ["pageTitle"], descendants: true }], ngImport: i0, template: "<!--\n ~ Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<clr-modal\n [clrModalOpen]=\"_open\"\n [clrModalSize]=\"size\"\n [clrModalClosable]=\"closable\"\n [clrModalStaticBackdrop]=\"true\"\n [clrModalPreventClose]=\"true\"\n (clrModalAlternateClose)=\"modalCancel()\"\n [clrModalLabelledById]=\"wizardId\"\n>\n <div class=\"modal-nav clr-wizard-stepnav-wrapper\" role=\"region\" [attr.aria-label]=\"stepnavAriaLabel\">\n <div class=\"clr-wizard-title\" id=\"{{wizardId}}\" role=\"heading\" [attr.aria-level]=\"wizardTitle.headingLevel || 1\">\n <ng-content select=\"clr-wizard-title\"></ng-content>\n </div>\n <clr-wizard-stepnav></clr-wizard-stepnav>\n </div>\n\n <div class=\"modal-title\" role=\"heading\" [attr.aria-level]=\"navService.currentPage.pageTitle.headingLevel || 2\">\n <span tabindex=\"-1\" #pageTitle class=\"modal-title-text\">\n <ng-template [ngTemplateOutlet]=\"navService.currentPageTitle\"></ng-template>\n </span>\n\n <div class=\"modal-header-actions-wrapper\" *ngIf=\"headerActionService.displayHeaderActionsWrapper\">\n <div *ngIf=\"headerActionService.showWizardHeaderActions\">\n <ng-content select=\"clr-wizard-header-action\"></ng-content>\n </div>\n <div *ngIf=\"headerActionService.currentPageHasHeaderActions\">\n <ng-template [ngTemplateOutlet]=\"navService.currentPage.headerActions\"></ng-template>\n </div>\n </div>\n </div>\n\n <div class=\"modal-body\">\n <main clr-wizard-pages-wrapper class=\"clr-wizard-content\">\n <ng-content></ng-content>\n </main>\n </div>\n <div class=\"modal-footer clr-wizard-footer\">\n <div class=\"clr-wizard-footer-buttons\">\n <div\n *ngIf=\"navService.currentPage && !navService.currentPage.hasButtons\"\n class=\"clr-wizard-footer-buttons-wrapper\"\n >\n <ng-content select=\"clr-wizard-button\"></ng-content>\n </div>\n <div\n *ngIf=\"navService.currentPage && navService.currentPage.hasButtons\"\n class=\"clr-wizard-footer-buttons-wrapper\"\n >\n <ng-template [ngTemplateOutlet]=\"navService.currentPage.buttons\"></ng-template>\n </div>\n </div>\n </div>\n</clr-modal>\n", dependencies: [{ kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i7.ClrModal, selector: "clr-modal", inputs: ["clrModalOpen", "clrModalClosable", "clrModalCloseButtonAriaLabel", "clrModalSize", "clrModalStaticBackdrop", "clrModalSkipAnimation", "clrModalPreventClose", "clrModalLabelledById"], outputs: ["clrModalOpenChange", "clrModalAlternateClose"] }, { kind: "directive", type: i8.ClrModalBody, selector: ".modal-body" }, { kind: "component", type: i9.ClrWizardStepnav, selector: "clr-wizard-stepnav" }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizard, decorators: [{
type: Component,
args: [{ selector: 'clr-wizard', providers: [WizardNavigationService, PageCollectionService, ButtonHubService, HeaderActionService], host: {
'[class.clr-wizard]': 'true',
'[class.wizard-md]': "size == 'md'",
'[class.wizard-lg]': "size == 'lg'",
'[class.wizard-xl]': "size == 'xl'",
'[class.lastPage]': 'navService.currentPageIsLast',
}, template: "<!--\n ~ Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<clr-modal\n [clrModalOpen]=\"_open\"\n [clrModalSize]=\"size\"\n [clrModalClosable]=\"closable\"\n [clrModalStaticBackdrop]=\"true\"\n [clrModalPreventClose]=\"true\"\n (clrModalAlternateClose)=\"modalCancel()\"\n [clrModalLabelledById]=\"wizardId\"\n>\n <div class=\"modal-nav clr-wizard-stepnav-wrapper\" role=\"region\" [attr.aria-label]=\"stepnavAriaLabel\">\n <div class=\"clr-wizard-title\" id=\"{{wizardId}}\" role=\"heading\" [attr.aria-level]=\"wizardTitle.headingLevel || 1\">\n <ng-content select=\"clr-wizard-title\"></ng-content>\n </div>\n <clr-wizard-stepnav></clr-wizard-stepnav>\n </div>\n\n <div class=\"modal-title\" role=\"heading\" [attr.aria-level]=\"navService.currentPage.pageTitle.headingLevel || 2\">\n <span tabindex=\"-1\" #pageTitle class=\"modal-title-text\">\n <ng-template [ngTemplateOutlet]=\"navService.currentPageTitle\"></ng-template>\n </span>\n\n <div class=\"modal-header-actions-wrapper\" *ngIf=\"headerActionService.displayHeaderActionsWrapper\">\n <div *ngIf=\"headerActionService.showWizardHeaderActions\">\n <ng-content select=\"clr-wizard-header-action\"></ng-content>\n </div>\n <div *ngIf=\"headerActionService.currentPageHasHeaderActions\">\n <ng-template [ngTemplateOutlet]=\"navService.currentPage.headerActions\"></ng-template>\n </div>\n </div>\n </div>\n\n <div class=\"modal-body\">\n <main clr-wizard-pages-wrapper class=\"clr-wizard-content\">\n <ng-content></ng-content>\n </main>\n </div>\n <div class=\"modal-footer clr-wizard-footer\">\n <div class=\"clr-wizard-footer-buttons\">\n <div\n *ngIf=\"navService.currentPage && !navService.currentPage.hasButtons\"\n class=\"clr-wizard-footer-buttons-wrapper\"\n >\n <ng-content select=\"clr-wizard-button\"></ng-content>\n </div>\n <div\n *ngIf=\"navService.currentPage && navService.currentPage.hasButtons\"\n class=\"clr-wizard-footer-buttons-wrapper\"\n >\n <ng-template [ngTemplateOutlet]=\"navService.currentPage.buttons\"></ng-template>\n </div>\n </div>\n </div>\n</clr-modal>\n" }]
}], ctorParameters: function () { return [{ type: undefined, decorators: [{
type: Inject,
args: [PLATFORM_ID]
}] }, { type: i1.ClrCommonStringsService }, { type: i2.WizardNavigationService }, { type: i3.PageCollectionService }, { type: i4.ButtonHubService }, { type: i5.HeaderActionService }, { type: i0.IterableDiffers }]; }, propDecorators: { stepnavAriaLabel: [{
type: Input,
args: ['clrWizardStepnavAriaLabel']
}], size: [{
type: Input,
args: ['clrWizardSize']
}], closable: [{
type: Input,
args: ['clrWizardClosable']
}], _openChanged: [{
type: Output,
args: ['clrWizardOpenChange']
}], onCancel: [{
type: Output,
args: ['clrWizardOnCancel']
}], wizardFinished: [{
type: Output,
args: ['clrWizardOnFinish']
}], onReset: [{
type: Output,
args: ['clrWizardOnReset']
}], currentPageChanged: [{
type: Output,
args: ['clrWizardCurrentPageChanged']
}], onMoveNext: [{
type: Output,
args: ['clrWizardOnNext']
}], onMovePrevious: [{
type: Output,
args: ['clrWizardOnPrevious']
}], pageTitle: [{
type: ViewChild,
args: ['pageTitle']
}], pages: [{
type: ContentChildren,
args: [ClrWizardPage, { descendants: true }]
}], headerActions: [{
type: ContentChildren,
args: [ClrWizardHeaderAction]
}], wizardTitle: [{
type: ContentChild,
args: [ClrWizardTitle]
}], forceForward: [{
type: Input,
args: ['clrWizardForceForwardNavigation']
}], clrWizardOpen: [{
type: Input,
args: ['clrWizardOpen']
}], stopNext: [{
type: Input,
args: ['clrWizardPreventDefaultNext']
}], stopCancel: [{
type: Input,
args: ['clrWizardPreventDefaultCancel']
}], stopNavigation: [{
type: Input,
args: ['clrWizardPreventNavigation']
}], disableStepnav: [{
type: Input,
args: ['clrWizardDisableStepnav']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2l6YXJkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvYW5ndWxhci9zcmMvd2l6YXJkL3dpemFyZC50cyIsIi4uLy4uLy4uLy4uL3Byb2plY3RzL2FuZ3VsYXIvc3JjL3dpemFyZC93aXphcmQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7OztHQUlHO0FBRUgsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDcEQsT0FBTyxFQUVMLFNBQVMsRUFDVCxZQUFZLEVBQ1osZUFBZSxFQUdmLFlBQVksRUFDWixNQUFNLEVBQ04sS0FBSyxFQUdMLE1BQU0sRUFDTixXQUFXLEVBRVgsU0FBUyxHQUNWLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUd4QyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFDN0UsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDbEUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFDekUsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDNUUsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sdUNBQXVDLENBQUM7QUFDaEYsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDL0QsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUM5QyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7Ozs7Ozs7Ozs7O0FBY2hELE1BQU0sT0FBTyxTQUFTO0lBOEVwQixZQUMrQixVQUFlLEVBQ3BDLGFBQXNDLEVBQ3ZDLFVBQW1DLEVBQ25DLGNBQXFDLEVBQ3JDLGFBQStCLEVBQy9CLG1CQUF3QyxFQUMvQyxPQUF3QjtRQU5LLGVBQVUsR0FBVixV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QWhDLFNBQVM7dUJBQUMsV0FBVztnQkFDaUMsS0FBSztzQkFBM0QsZUFBZTt1QkFBQyxhQUFhLEVBQUUsRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFO2dCQUNiLGFBQWE7c0JBQXBELGVBQWU7dUJBQUMscUJBQXFCO2dCQUtFLFdBQVc7c0JBQWxELFlBQVk7dUJBQUMsY0FBYztnQkFtQ3hCLFlBQVk7c0JBRGYsS0FBSzt1QkFBQyxpQ0FBaUM7Z0JBY3BDLGFBQWE7c0JBRGhCLEtBQUs7dUJBQUMsZUFBZTtnQkFlbEIsUUFBUTtzQkFEWCxLQUFLO3VCQUFDLDZCQUE2QjtnQkFrQmhDLFVBQVU7c0JBRGIsS0FBSzt1QkFBQywrQkFBK0I7Z0JBa0JsQyxjQUFjO3NCQURqQixLQUFLO3VCQUFDLDRCQUE0QjtnQkFpQi9CLGNBQWM7c0JBRGpCLEtBQUs7dUJBQUMseUJBQXlCIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIENvcHlyaWdodCAoYykgMjAxNi0yMDIzIFZNd2FyZSwgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICogVGhpcyBzb2Z0d2FyZSBpcyByZWxlYXNlZCB1bmRlciBNSVQgbGljZW5zZS5cbiAqIFRoZSBmdWxsIGxpY2Vuc2UgaW5mb3JtYXRpb24gY2FuIGJlIGZvdW5kIGluIExJQ0VOU0UgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgcHJvamVjdC5cbiAqL1xuXG5pbXBvcnQgeyBpc1BsYXRmb3JtQnJvd3NlciB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQge1xuICBBZnRlckNvbnRlbnRJbml0LFxuICBDb21wb25lbnQsXG4gIENvbnRlbnRDaGlsZCxcbiAgQ29udGVudENoaWxkcmVuLFxuICBEb0NoZWNrLFxuICBFbGVtZW50UmVmLFxuICBFdmVudEVtaXR0ZXIsXG4gIEluamVjdCxcbiAgSW5wdXQsXG4gIEl0ZXJhYmxlRGlmZmVycyxcbiAgT25EZXN0cm95LFxuICBPdXRwdXQsXG4gIFBMQVRGT1JNX0lELFxuICBRdWVyeUxpc3QsXG4gIFZpZXdDaGlsZCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGZpbHRlciB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuaW1wb3J0IHsgQ2xyQ29tbW9uU3RyaW5nc1NlcnZpY2UgfSBmcm9tICcuLi91dGlscyc7XG5pbXBvcnQgeyB1bmlxdWVJZEZhY3RvcnkgfSBmcm9tICcuLi91dGlscy9pZC1nZW5lcmF0b3IvaWQtZ2VuZXJhdG9yLnNlcnZpY2UnO1xuaW1wb3J0IHsgQnV0dG9uSHViU2VydmljZSB9IGZyb20gJy4vcHJvdmlkZXJzL2J1dHRvbi1odWIuc2VydmljZSc7XG5pbXBvcnQgeyBIZWFkZXJBY3Rpb25TZXJ2aWNlIH0gZnJvbSAnLi9wcm92aWRlcnMvaGVhZGVyLWFjdGlvbnMuc2VydmljZSc7XG5pbXBvcnQgeyBQYWdlQ29sbGVjdGlvblNlcnZpY2UgfSBmcm9tICcuL3Byb3ZpZGVycy9wYWdlLWNvbGxlY3Rpb24uc2VydmljZSc7XG5pbXBvcnQgeyBXaXphcmROYXZpZ2F0aW9uU2VydmljZSB9IGZyb20gJy4vcHJvdmlkZXJzL3dpemFyZC1uYXZpZ2F0aW9uLnNlcnZpY2UnO1xuaW1wb3J0IHsgQ2xyV2l6YXJkSGVhZGVyQWN0aW9uIH0gZnJvbSAnLi93aXphcmQtaGVhZGVyLWFjdGlvbic7XG5pbXBvcnQgeyBDbHJXaXphcmRQYWdlIH0gZnJvbSAnLi93aXphcmQtcGFnZSc7XG5pbXBvcnQgeyBDbHJXaXphcmRUaXRsZSB9IGZyb20gJy4vd2l6YXJkLXRpdGxlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnY2xyLXdpemFyZCcsXG4gIHByb3ZpZGVyczogW1dpemFyZE5hdmlnYXRpb25TZXJ2aWNlLCBQYWdlQ29sbGVjdGlvblNlcnZpY2UsIEJ1dHRvbkh1YlNlcnZpY2UsIEhlYWRlckFjdGlvblNlcnZpY2VdLFxuICB0ZW1wbGF0ZVVybDogJy4vd2l6YXJkLmh0bWwnLFxuICBob3N0OiB7XG4gICAgJ1tjbGFzcy5jbHItd2l6YXJkXSc6ICd0cnVlJyxcbiAgICAnW2NsYXNzLndpemFyZC1tZF0nOiBcInNpemUgPT0gJ21kJ1wiLFxuICAgICdbY2xhc3Mud2l6YXJkLWxnXSc6IFwic2l6ZSA9PSAnbGcnXCIsXG4gICAgJ1tjbGFzcy53aXphcmQteGxdJzogXCJzaXplID09ICd4bCdcIixcbiAgICAnW2NsYXNzLmxhc3RQYWdlXSc6ICduYXZTZXJ2aWNlLmN1cnJlbnRQYWdlSXNMYXN0JyxcbiAgfSxcbn0pXG5leHBvcnQgY2xhc3MgQ2xyV2l6YXJkIGltcGxlbWVudHMgT25EZXN0cm95LCBBZnRlckNvbnRlbnRJbml0LCBEb0NoZWNrIHtcbiAgLyoqXG4gICAqIFNldCB0aGUgYXJpYS1sYWJlbCBmb3IgdGhlIHN0ZXBuYXYgc2VjdGlvbiBvZiB0aGUgd2l6YXJkLiBTZXQgdXNpbmcgYFtjbHJXaXphcmRTdGVwbmF2QXJpYUxhYmVsXWAgaW5wdXQuXG4gICAqL1xuICBASW5wdXQoJ2NscldpemFyZFN0ZXBuYXZBcmlhTGFiZWwnKSBzdGVwbmF2QXJpYUxhYmVsID0gdGhpcy5jb21tb25TdHJpbmdzLmtleXMud2l6YXJkU3RlcG5hdkFyaWFMYWJlbDtcblxuICAvKipcbiAgICogU2V0IHRoZSBtb2RhbCBzaXplIG9mIHRoZSB3aXphcmQuIFNldCB1c2luZyBgW2NscldpemFyZFNpemVdYCBpbnB1dC5cbiAgICovXG4gIEBJbnB1dCgnY2xyV2l6YXJkU2l6ZScpIHNpemUgPSAneGwnO1xuXG4gIC8qKlxuICAgKiBUZWxscyB0aGUgbW9kYWwgcGFydCBvZiB0aGUgd2l6YXJkIHdoZXRoZXIgaXQgc2hvdWxkIGhhdmUgYSBjbG9zZSBcIlhcIlxuICAgKiBpbiB0aGUgdG9wIHJpZ2h0IGNvcm5lci4gU2V0IHVzaW5nIGBbY2xyV2l6YXJkQ2xvc2FibGVdYCBpbnB1dC5cbiAgICovXG4gIEBJbnB1dCgnY2xyV2l6YXJkQ2xvc2FibGUnKSBjbG9zYWJsZSA9IHRydWU7XG5cbiAgLyoqXG4gICAqIEVtaXRzIHdoZW4gdGhlIHdpemFyZCBpcyBvcGVuZWQgb3IgY2xvc2VkLlxuICAgKiBMaXN0ZW4gdmlhIGAoY2xyV2l6YXJkT3BlbkNoYW5nZSlgIGV2ZW50LlxuICAgKi9cbiAgQE91dHB1dCgnY2xyV2l6YXJkT3BlbkNoYW5nZScpIF9vcGVuQ2hhbmdlZCA9IG5ldyBFdmVudEVtaXR0ZXI8Ym9vbGVhbj4oZmFsc2UpO1xuXG4gIC8qKlxuICAgKiBFbWl0cyB3aGVuIHRoZSB3aXphcmQgaXMgY2FuY2VsZWQuIExpc3RlbiB2aWEgYChjbHJXaXphcmRPbkNhbmNlbClgIGV2ZW50LlxuICAgKiBDYW4gYmUgY29tYmluZWQgd2l0aCB0aGUgYFtjbHJXaXphcmRQcmV2ZW50RGVmYXVsdENhbmNlbF1gIGlucHV0IHRvIGNyZWF0ZVxuICAgKiB3aXphcmQtbGV2ZWwgY3VzdG9tIGNhbmNlbCByb3V0aW5lcy5cbiAgICovXG4gIEBPdXRwdXQoJ2NscldpemFyZE9uQ2FuY2VsJykgb25DYW5jZWwgPSBuZXcgRXZlbnRFbWl0dGVyPGFueT4oZmFsc2UpO1xuXG4gIC8qKlxuICAgKiBFbWl0cyB3aGVuIHRoZSB3aXphcmQgaXMgY29tcGxldGVkLiBMaXN0ZW4gdmlhIGAoY2xyV2l6YXJkT25GaW5pc2gpYCBldmVudC5cbiAgICogQ2FuIGJlIGNvbWJpbmVkIHdpdGggdGhlIGBbY2xyV2l6YXJkUHJldmVudERlZmF1bHROZXh0XWAgaW5wdXQgdG8gY3JlYXRlXG4gICAqIHdpemFyZC1sZXZlbCBjdXN0b20gY29tcGxldGlvbiByb3V0aW5lcy5cbiAgICovXG4gIEBPdXRwdXQoJ2NscldpemFyZE9uRmluaXNoJykgd2l6YXJkRmluaXNoZWQgPSBuZXcgRXZlbnRFbWl0dGVyPGFueT4oZmFsc2UpO1xuXG4gIC8qKlxuICAgKiBFbWl0cyB3aGVuIHRoZSB3aXphcmQgaXMgcmVzZXQuIExpc3RlbiB2aWEgYChjbHJXaXphcmRPblJlc2V0KWAgZXZlbnQuXG4gICAqL1xuICBAT3V0cHV0KCdjbHJXaXphcmRPblJlc2V0Jykgb25SZXNldCA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PihmYWxzZSk7XG5cbiAgLyoqXG4gICAqIEVtaXRzIHdoZW4gdGhlIGN1cnJlbnQgcGFnZSBoYXMgY2hhbmdlZC4gTGlzdGVuIHZpYSBgKGNscldpemFyZEN1cnJlbnRQYWdlQ2hhbmdlZClgIGV2ZW50LlxuICAgKiBvdXRwdXQuIFVzZWZ1bCBmb3Igbm9uLWJsb2NraW5nIHZhbGlkYXRpb24uXG4gICAqL1xuICBAT3V0cHV0KCdjbHJXaXphcmRDdXJyZW50UGFnZUNoYW5nZWQnKSBjdXJyZW50UGFnZUNoYW5nZWQgPSBuZXcgRXZlbnRFbWl0dGVyPGFueT4oZmFsc2UpO1xuXG4gIC8qKlxuICAgKiBFbWl0cyB3aGVuIHRoZSB3aXphcmQgbW92ZXMgdG8gdGhlIG5leHQgcGFnZS4gTGlzdGVuIHZpYSBgKGNscldpemFyZE9uTmV4dClgIGV2ZW50LlxuICAgKiBDYW4gYmUgY29tYmluZWQgd2l0aCB0aGUgYFtjbHJXaXphcmRQcmV2ZW50RGVmYXVsdE5leHRdYCBpbnB1dCB0byBjcmVhdGVcbiAgICogd2l6YXJkLWxldmVsIGN1c3RvbSBuYXZpZ2F0aW9uIHJvdXRpbmVzLCB3aGljaCBhcmUgdXNlZnVsIGZvciB2YWxpZGF0aW9uLlxuICAgKi9cbiAgQE91dHB1dCgnY2xyV2l6YXJkT25OZXh0Jykgb25Nb3ZlTmV4dCA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PihmYWxzZSk7XG5cbiAgLyoqXG4gICAqIEVtaXRzIHdoZW4gdGhlIHdpemFyZCBtb3ZlcyB0byB0aGUgcHJldmlvdXMgcGFnZS4gQ2FuIGJlIHVzZWZ1bCBmb3IgdmFsaWRhdGlvbi5cbiAgICogTGlzdGVuIHZpYSBgKGNscldpemFyZE9uUHJldmlvdXMpYCBldmVudC5cbiAgICovXG4gIEBPdXRwdXQoJ2NscldpemFyZE9uUHJldmlvdXMnKSBvbk1vdmVQcmV2aW91cyA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PihmYWxzZSk7XG5cbiAgQFZpZXdDaGlsZCgncGFnZVRpdGxlJykgcGFnZVRpdGxlOiBFbGVtZW50UmVmO1xuICBAQ29udGVudENoaWxkcmVuKENscldpemFyZFBhZ2UsIHsgZGVzY2VuZGFudHM6IHRydWUgfSkgcGFnZXM6IFF1ZXJ5TGlzdDxDbHJXaXphcmRQYWdlPjtcbiAgQENvbnRlbnRDaGlsZHJlbihDbHJXaXphcmRIZWFkZXJBY3Rpb24pIGhlYWRlckFjdGlvbnM6IFF1ZXJ5TGlzdDxDbHJXaXphcmRIZWFkZXJBY3Rpb24+O1xuXG4gIF9vcGVuID0gZmFsc2U7XG4gIHdpemFyZElkID0gdW5pcXVlSWRGYWN0b3J5KCk7XG5cbiAgQENvbnRlbnRDaGlsZChDbHJXaXphcmRUaXRsZSkgcHJvdGVjdGVkIHdpemFyZFRpdGxlOiBDbHJXaXphcmRUaXRsZTtcblxuICBwcml2YXRlIF9mb3JjZUZvcndhcmQgPSBmYWxzZTtcbiAgcHJpdmF0ZSBfc3RvcE5leHQgPSBmYWxzZTtcbiAgcHJpdmF0ZSBfc3RvcENhbmNlbCA9IGZhbHNlO1xuICBwcml2YXRlIF9zdG9wTmF2aWdhdGlvbiA9IGZhbHNlO1xuICBwcml2YXRlIF9kaXNhYmxlU3RlcG5hdiA9IGZhbHNlO1xuICBwcml2YXRlIGRpZmZlcjogYW55OyAvLyBmb3IgbWFya2luZyB3aGVuIHRoZSBjb2xsZWN0aW9uIG9mIHdpemFyZCBwYWdlcyBoYXMgYmVlbiBhZGRlZCB0byBvciBkZWxldGVkIGZyb21cbiAgcHJpdmF0ZSBzdWJzY3JpcHRpb25zOiBTdWJzY3JpcHRpb25bXSA9IFtdO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIEBJbmplY3QoUExBVEZPUk1fSUQpIHByaXZhdGUgcGxhdGZvcm1JZDogYW55LFxuICAgIHByaXZhdGUgY29tbW9uU3RyaW5nczogQ2xyQ29tbW9uU3RyaW5nc1NlcnZpY2UsXG4gICAgcHVibGljIG5hdlNlcnZpY2U6IFdpemFyZE5hdmlnYXRpb25TZXJ2aWNlLFxuICAgIHB1YmxpYyBwYWdlQ29sbGVjdGlvbjogUGFnZUNvbGxlY3Rpb25TZXJ2aWNlLFxuICAgIHB1YmxpYyBidXR0b25TZXJ2aWNlOiBCdXR0b25IdWJTZXJ2aWNlLFxuICAgIHB1YmxpYyBoZWFkZXJBY3Rpb25TZXJ2aWNlOiBIZWFkZXJBY3Rpb25TZXJ2aWNlLFxuICAgIGRpZmZlcnM6IEl0ZXJhYmxlRGlmZmVyc1xuICApIHtcbiAgICB0aGlzLnN1YnNjcmlwdGlvbnMucHVzaChcbiAgICAgIHRoaXMubGlzdGVuRm9yTmV4dFBhZ2VDaGFuZ2VzKCksXG4gICAgICB0aGlzLmxpc3RlbkZvclByZXZpb3VzUGFnZUNoYW5nZXMoKSxcbiAgICAgIHRoaXMubGlzdGVuRm9yQ2FuY2VsQ2hhbmdlcygpLFxuICAgICAgdGhpcy5saXN0ZW5Gb3JGaW5pc2hlZENoYW5nZXMoKSxcbiAgICAgIHRoaXMubGlzdGVuRm9yUGFnZUNoYW5nZXMoKVxuICAgICk7XG5cbiAgICB0aGlzLmRpZmZlciA9IGRpZmZlcnMuZmluZChbXSkuY3JlYXRlKG51bGwpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc2V0cyBwYWdlIGNvbXBsZXRlZCBzdGF0ZXMgd2hlbiBuYXZpZ2F0aW5nIGJhY2t3YXJkcy5cbiAgICogU2V0IHVzaW5nIGBbY2xyV2l6YXJkRm9yY2VGb3J3YXJkTmF2aWdhdGlvbl1gIGlucHV0LlxuICAgKi9cbiAgQElucHV0KCdjbHJXaXphcmRGb3JjZUZvcndhcmROYXZpZ2F0aW9uJylcbiAgZ2V0IGZvcmNlRm9yd2FyZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5fZm9yY2VGb3J3YXJkO1xuICB9XG4gIHNldCBmb3JjZUZvcndhcmQodmFsdWU6IGJvb2xlYW4pIHtcbiAgICB0aGlzLl9mb3JjZUZvcndhcmQgPSAhIXZhbHVlO1xuICAgIHRoaXMubmF2U2VydmljZS5mb3JjZUZvcndhcmROYXZpZ2F0aW9uID0gdmFsdWU7XG4gIH1cblxuICAvKipcbiAgICogVG9nZ2xlcyBvcGVuL2Nsb3NlIG9mIHRoZSB3aXphcmQgY29tcG9uZW50LlxuICAgKiBTZXQgdXNpbmcgdGhlIGBbY2xyV2l6YXJkT3Blbl1gIGlucHV0LlxuICAgKi9cbiAgQElucHV0KCdjbHJXaXphcmRPcGVuJylcbiAgc2V0IGNscldpemFyZE9wZW4ob3BlbjogYm9vbGVhbikge1xuICAgIGlmIChvcGVuKSB7XG4gICAgICB0aGlzLmJ1dHRvblNlcnZpY2UuYnV0dG9uc1JlYWR5ID0gdHJ1ZTtcbiAgICB9XG4gICAgdGhpcy5fb3BlbiA9IG9wZW47XG4gIH1cblxuICAvKipcbiAgICogUHJldmVudHMgQ2xyV2l6YXJkIGZyb20gbW92aW5nIHRvIHRoZSBuZXh0IHBhZ2Ugb3IgY2xvc2luZyBpdHNlbGYgb24gZmluaXNoaW5nLlxuICAgKiBTZXQgdXNpbmcgdGhlIGBbY2xyV2l6YXJkUHJldmVudERlZmF1bHROZXh0XWAgaW5wdXQuIE5vdGUgdGhhdCB1c2luZyBzdG9wTmV4dFxuICAgKiB3aWxsIHJlcXVpcmUgeW91IHRvIGNyZWF0ZSB5b3VyIG93biBjYWxscyB0byAubmV4dCgpIGFuZCAuZmluaXNoKCkgaW4geW91clxuICAgKiBob3N0IGNvbXBvbmVudCB0byBtYWtlIHRoZSBDbHJXaXphcmQgd29yayBhcyBleHBlY3RlZC5cbiAgICovXG4gIEBJbnB1dCgnY2xyV2l6YXJkUHJldmVudERlZmF1bHROZXh0JylcbiAgZ2V0IHN0b3BOZXh0KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9zdG9wTmV4dDtcbiAgfVxuICBzZXQgc3RvcE5leHQodmFsdWU6IGJvb2xlYW4pIHtcbiAgICB0aGlzLl9zdG9wTmV4dCA9ICEhdmFsdWU7XG4gICAgdGhpcy5uYXZTZXJ2aWNlLndpemFyZEhhc0FsdE5leHQgPSB2YWx1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcmV2ZW50cyBDbHJXaXphcmQgZnJvbSBjbG9zaW5nIHdoZW4gdGhlIGNhbmNlbCBidXR0b24gb3IgY2xvc2UgXCJYXCIgaXMgY2xpY2tlZC5cbiAgICogU2V0IHVzaW5nIHRoZSBgW2NscldpemFyZFByZXZlbnREZWZhdWx0Q2FuY2VsXWAgaW5wdXQuXG4gICAqXG4gICAqIE5vdGUgdGhhdCB1c2luZyBzdG9wQ2FuY2VsIHdpbGwgcmVxdWlyZSB5b3UgdG8gY3JlYXRlIHlvdXIgb3duIGNhbGxzIHRvIGBjbG9zZSgpYCBpbiB5b3VyIGhvc3QgY29tcG9uZWBudFxuICAgKiB0byBtYWtlIHRoZSBDbHJXaXphcmQgd29yayBhcyBleHBlY3RlZC4gVXNlZnVsIGZvciBkb2luZyBjaGVja3Mgb3IgcHJvbXB0c1xuICAgKiBiZWZvcmUgY2xvc2luZyBhIENscldpemFyZC5cbiAgICovXG4gIEBJbnB1dCgnY2xyV2l6YXJkUHJldmVudERlZmF1bHRDYW5jZWwnKVxuICBnZXQgc3RvcENhbmNlbCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5fc3RvcENhbmNlbDtcbiAgfVxuICBzZXQgc3RvcENhbmNlbCh2YWx1ZTogYm9vbGVhbikge1xuICAgIHRoaXMuX3N0b3BDYW5jZWwgPSAhIXZhbHVlO1xuICAgIHRoaXMubmF2U2VydmljZS53aXphcmRIYXNBbHRDYW5jZWwgPSB2YWx1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcmV2ZW50cyBDbHJXaXphcmQgZnJvbSBwZXJmb3JtaW5nIGFueSBmb3JtIG9mIG5hdmlnYXRpb24gYXdheSBmcm9tIHRoZSBjdXJyZW50XG4gICAqIHBhZ2UuIFNldCB1c2luZyB0aGUgYFtjbHJXaXphcmRQcmV2ZW50TmF2aWdhdGlvbl1gIGlucHV0LlxuICAgKiBOb3RlIHRoYXQgc3RvcE5hdmlnYXRpb24gaXMgbWVhbnQgdG8gZnJlZXplIHRoZSB3aXphcmQgaW4gcGxhY2UsIHR5cGljYWxseVxuICAgKiBkdXJpbmcgYSBsb25nIHZhbGlkYXRpb24gb3IgYmFja2dyb3VuZCBhY3Rpb24gd2hlcmUgeW91IHdhbnQgdGhlIHdpemFyZCB0b1xuICAgKiBkaXNwbGF5IGxvYWRpbmcgY29udGVudCBidXQgbm90IGFsbG93IHRoZSB1c2VyIHRvIGV4ZWN1dGUgbmF2aWdhdGlvbiBpblxuICAgKiB0aGUgc3RlcG5hdiwgY2xvc2UgWCwgb3IgdGhlICBiYWNrLCBmaW5pc2gsIG9yIG5leHQgYnV0dG9ucy5cbiAgICovXG4gIEBJbnB1dCgnY2xyV2l6YXJkUHJldmVudE5hdmlnYXRpb24nKVxuICBnZXQgc3RvcE5hdmlnYXRpb24oKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuX3N0b3BOYXZpZ2F0aW9uO1xuICB9XG4gIHNldCBzdG9wTmF2aWdhdGlvbih2YWx1ZTogYm9vbGVhbikge1xuICAgIHRoaXMuX3N0b3BOYXZpZ2F0aW9uID0gISF2YWx1ZTtcbiAgICB0aGlzLm5hdlNlcnZpY2Uud2l6YXJkU3RvcE5hdmlnYXRpb24gPSB2YWx1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcmV2ZW50cyBjbGlja3Mgb24gdGhlIGxpbmtzIGluIHRoZSBzdGVwbmF2IGZyb20gd29ya2luZy5cbiAgICogU2V0IHVzaW5nIGBbY2xyV2l6YXJkRGlzYWJsZVN0ZXBuYXZdYCBpbnB1dC5cbiAgICogQSBtb3JlIGdyYW51bGFyIGJ5cGFzc2luZyBvZiBuYXZpZ2F0aW9uIHdoaWNoIGNhbiBiZSB1c2VmdWwgd2hlbiB5b3VyXG4gICAqIENscldpemFyZCBpcyBpbiBhIHN0YXRlIG9mIGNvbXBsZXRpb24gYW5kIHlvdSBkb24ndCB3YW50IHVzZXJzIHRvIGJlXG4gICAqIGFibGUgdG8ganVtcCBiYWNrd2FyZHMgYW5kIGNoYW5nZSB0aGluZ3MuXG4gICAqL1xuICBASW5wdXQoJ2NscldpemFyZERpc2FibGVTdGVwbmF2JylcbiAgZ2V0IGRpc2FibGVTdGVwbmF2KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9kaXNhYmxlU3RlcG5hdjtcbiAgfVxuICBzZXQgZGlzYWJsZVN0ZXBuYXYodmFsdWU6IGJvb2xlYW4pIHtcbiAgICB0aGlzLl9kaXNhYmxlU3RlcG5hdiA9ICEhdmFsdWU7XG4gICAgdGhpcy5uYXZTZXJ2aWNlLndpemFyZERpc2FibGVTdGVwbmF2ID0gdmFsdWU7XG4gIH1cblxuICBnZXQgY3VycmVudFBhZ2UoKTogQ2xyV2l6YXJkUGFnZSB7XG4gICAgcmV0dXJuIHRoaXMubmF2U2VydmljZS5jdXJyZW50UGFnZTtcbiAgfVxuICBzZXQgY3VycmVudFBhZ2UocGFnZTogQ2xyV2l6YXJkUGFnZSkge1xuICAgIHRoaXMubmF2U2VydmljZS5nb1RvKHBhZ2UsIHRydWUpO1xuICB9XG5cbiAgZ2V0IGlzTGFzdCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5uYXZTZXJ2aWNlLmN1cnJlbnRQYWdlSXNMYXN0O1xuICB9XG5cbiAgZ2V0IGlzRmlyc3QoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMubmF2U2VydmljZS5jdXJyZW50UGFnZUlzRmlyc3Q7XG4gIH1cblxuICBuZ0FmdGVyQ29udGVudEluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5wYWdlQ29sbGVjdGlvbi5wYWdlcyA9IHRoaXMucGFnZXM7XG4gICAgdGhpcy5oZWFkZXJBY3Rpb25TZXJ2aWNlLndpemFyZEhlYWRlckFjdGlvbnMgPSB0aGlzLmhlYWRlckFjdGlvbnM7XG4gIH1cblxuICBuZ0RvQ2hlY2soKTogdm9pZCB7XG4gICAgdGhpcy51cGRhdGVOYXZPblBhZ2VDaGFuZ2VzKCk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLnN1YnNjcmlwdGlvbnMuZm9yRWFjaChzID0+IHMudW5zdWJzY3JpYmUoKSk7XG4gIH1cblxuICAvKipcbiA