angular-archwizard
Version:
An Angular 9+ module containing a wizard component and its supporting components and directives
380 lines • 40.7 kB
JavaScript
import { __decorate, __metadata } from "tslib";
import { Component, ContentChildren, HostBinding, Input, QueryList, } from '@angular/core';
import { WizardStep } from '../util/wizard-step.interface';
import { MovingDirection } from '../util/moving-direction.enum';
import { ConfigurableNavigationMode } from '../navigation/configurable-navigation-mode';
/**
* The `aw-wizard` component defines the root component of a wizard.
* Through the setting of input parameters for the `aw-wizard` component it's possible to change the location and size
* of its navigation bar.
*
* ### Syntax
* ```html
* <aw-wizard [navBarLocation]="location of navigation bar" [navBarLayout]="layout of navigation bar">
* ...
* </aw-wizard>
* ```
*
* ### Example
*
* Without completion step:
*
* ```html
* <aw-wizard navBarLocation="top" navBarLayout="small">
* <aw-wizard-step>...</aw-wizard-step>
* <aw-wizard-step>...</aw-wizard-step>
* </aw-wizard>
* ```
*
* With completion step:
*
* ```html
* <aw-wizard navBarLocation="top" navBarLayout="small">
* <aw-wizard-step>...</aw-wizard-step>
* <aw-wizard-step>...</aw-wizard-step>
* <aw-wizard-completion-step>...</aw-wizard-completion-step>
* </aw-wizard>
* ```
*
* @author Marc Arndt
*/
let WizardComponent = class WizardComponent {
/**
* Constructor
*/
constructor() {
/**
* The location of the navigation bar inside the wizard.
* This location can be either top, bottom, left or right
*/
this.navBarLocation = 'top';
/**
* The layout of the navigation bar inside the wizard.
* The layout can be either small, large-filled, large-empty or large-symbols
*/
this.navBarLayout = 'small';
/**
* The direction in which the steps inside the navigation bar should be shown.
* The direction can be either `left-to-right` or `right-to-left`
*/
this.navBarDirection = 'left-to-right';
this._defaultStepIndex = 0;
/**
* True, if the navigation bar shouldn't be used for navigating
*/
this.disableNavigationBar = false;
/**
* The navigation mode used to navigate inside the wizard
*
* For outside access, use the [[navigation]] getter.
*/
this._navigation = new ConfigurableNavigationMode();
/**
* An array representation of all wizard steps belonging to this model
*
* For outside access, use the [[wizardSteps]] getter.
*/
this._wizardSteps = [];
/**
* The index of the currently visible and selected step inside the wizardSteps QueryList.
* If this wizard contains no steps, currentStepIndex is -1
*
* Note: Do not modify this field directly. Instead, use navigation methods:
* [[goToStep]], [[goToPreviousStep]], [[goToNextStep]].
*/
this.currentStepIndex = -1;
}
/**
* The initially selected step, represented by its index
* Beware: This initial default is only used if no wizard step has been enhanced with the `selected` directive
*/
get defaultStepIndex() {
// This value can be either:
// - the index of a wizard step with a `selected` directive, or
// - the default step index, set in the [[WizardComponent]]
const foundDefaultStep = this.wizardSteps.find(step => step.defaultSelected);
if (foundDefaultStep) {
return this.getIndexOfStep(foundDefaultStep);
}
else {
return this._defaultStepIndex;
}
}
set defaultStepIndex(defaultStepIndex) {
this._defaultStepIndex = defaultStepIndex;
}
/**
* Returns true if this wizard uses a horizontal orientation.
* The wizard uses a horizontal orientation, iff the navigation bar is shown at the top or bottom of this wizard
*
* @returns True if this wizard uses a horizontal orientation
*/
get horizontalOrientation() {
return this.navBarLocation === 'top' || this.navBarLocation === 'bottom';
}
/**
* Returns true if this wizard uses a vertical orientation.
* The wizard uses a vertical orientation, iff the navigation bar is shown at the left or right of this wizard
*
* @returns True if this wizard uses a vertical orientation
*/
get verticalOrientation() {
return this.navBarLocation === 'left' || this.navBarLocation === 'right';
}
/**
* Initialization work
*/
ngAfterContentInit() {
// add a subscriber to the wizard steps QueryList to listen to changes in the DOM
this.wizardStepsQueryList.changes.subscribe(changedWizardSteps => {
this.updateWizardSteps(changedWizardSteps.toArray());
});
// initialize the model
this.updateWizardSteps(this.wizardStepsQueryList.toArray());
// finally reset the whole wizard component
setTimeout(() => this.reset());
}
/**
* The WizardStep object belonging to the currently visible and selected step.
* The currentStep is always the currently selected wizard step.
* The currentStep can be either completed, if it was visited earlier,
* or not completed, if it is visited for the first time or its state is currently out of date.
*
* If this wizard contains no steps, currentStep is null
*/
get currentStep() {
if (this.hasStep(this.currentStepIndex)) {
return this.wizardSteps[this.currentStepIndex];
}
else {
return null;
}
}
/**
* The completeness of the wizard.
* If the wizard has been completed, i.e. all steps are either completed or optional, this value is true, otherwise it is false
*/
get completed() {
return this.wizardSteps.every(step => step.completed || step.optional);
}
/**
* An array representation of all wizard steps belonging to this model
*/
get wizardSteps() {
return this._wizardSteps;
}
/**
* Updates the wizard steps to the new array
*
* @param wizardSteps The updated wizard steps
*/
updateWizardSteps(wizardSteps) {
// the wizard is currently not in the initialization phase
if (this.wizardSteps.length > 0 && this.currentStepIndex > -1) {
this.currentStepIndex = wizardSteps.indexOf(this.wizardSteps[this.currentStepIndex]);
}
this._wizardSteps = wizardSteps;
}
/**
* The navigation mode used to navigate inside the wizard
*/
get navigation() {
return this._navigation;
}
/**
* Updates the navigation mode for this wizard component
*
* @param navigation The updated navigation mode
*/
set navigation(navigation) {
this._navigation = navigation;
}
/**
* Checks if a given index `stepIndex` is inside the range of possible wizard steps inside this wizard
*
* @param stepIndex The to be checked index of a step inside this wizard
* @returns True if the given `stepIndex` is contained inside this wizard, false otherwise
*/
hasStep(stepIndex) {
return this.wizardSteps.length > 0 && 0 <= stepIndex && stepIndex < this.wizardSteps.length;
}
/**
* Checks if this wizard has a previous step, compared to the current step
*
* @returns True if this wizard has a previous step before the current step
*/
hasPreviousStep() {
return this.hasStep(this.currentStepIndex - 1);
}
/**
* Checks if this wizard has a next step, compared to the current step
*
* @returns True if this wizard has a next step after the current step
*/
hasNextStep() {
return this.hasStep(this.currentStepIndex + 1);
}
/**
* Checks if this wizard is currently inside its last step
*
* @returns True if the wizard is currently inside its last step
*/
isLastStep() {
return this.wizardSteps.length > 0 && this.currentStepIndex === this.wizardSteps.length - 1;
}
/**
* Finds the [[WizardStep]] at the given index `stepIndex`.
* If no [[WizardStep]] exists at the given index an Error is thrown
*
* @param stepIndex The given index
* @returns The found [[WizardStep]] at the given index `stepIndex`
* @throws An `Error` is thrown, if the given index `stepIndex` doesn't exist
*/
getStepAtIndex(stepIndex) {
if (!this.hasStep(stepIndex)) {
throw new Error(`Expected a known step, but got stepIndex: ${stepIndex}.`);
}
return this.wizardSteps[stepIndex];
}
/**
* Finds the index of the step with the given `stepId`.
* If no step with the given `stepId` exists, `-1` is returned
*
* @param stepId The given step id
* @returns The found index of a step with the given step id, or `-1` if no step with the given id is included in the wizard
*/
getIndexOfStepWithId(stepId) {
return this.wizardSteps.findIndex(step => step.stepId === stepId);
}
/**
* Finds the index of the given [[WizardStep]] `step`.
* If the given [[WizardStep]] is not contained inside this wizard, `-1` is returned
*
* @param step The given [[WizardStep]]
* @returns The found index of `step` or `-1` if the step is not included in the wizard
*/
getIndexOfStep(step) {
return this.wizardSteps.indexOf(step);
}
/**
* Calculates the correct [[MovingDirection]] value for a given `destinationStep` compared to the `currentStepIndex`.
*
* @param destinationStep The given destination step
* @returns The calculated [[MovingDirection]]
*/
getMovingDirection(destinationStep) {
let movingDirection;
if (destinationStep > this.currentStepIndex) {
movingDirection = MovingDirection.Forwards;
}
else if (destinationStep < this.currentStepIndex) {
movingDirection = MovingDirection.Backwards;
}
else {
movingDirection = MovingDirection.Stay;
}
return movingDirection;
}
/**
* Checks, whether a wizard step, as defined by the given destination index, can be transitioned to.
*
* This method controls navigation by [[goToStep]], [[goToPreviousStep]], and [[goToNextStep]] directives.
* Navigation by navigation bar is governed by [[isNavigable]].
*
* @param destinationIndex The index of the destination step
* @returns A [[Promise]] containing `true`, if the destination step can be transitioned to and false otherwise
*/
canGoToStep(destinationIndex) {
return this.navigation.canGoToStep(this, destinationIndex);
}
/**
* Tries to transition to the wizard step, as denoted by the given destination index.
*
* Note: You do not have to call [[canGoToStep]] before calling [[goToStep]].
* The [[canGoToStep]] method will be called automatically.
*
* @param destinationIndex The index of the destination wizard step, which should be entered
* @param preFinalize An event emitter, to be called before the step has been transitioned
* @param postFinalize An event emitter, to be called after the step has been transitioned
*/
goToStep(destinationIndex, preFinalize, postFinalize) {
return this.navigation.goToStep(this, destinationIndex, preFinalize, postFinalize);
}
/**
* Tries to transition the wizard to the previous step
*
* @param preFinalize An event emitter, to be called before the step has been transitioned
* @param postFinalize An event emitter, to be called after the step has been transitioned
*/
goToPreviousStep(preFinalize, postFinalize) {
return this.navigation.goToStep(this, this.currentStepIndex - 1, preFinalize, postFinalize);
}
/**
* Tries to transition the wizard to the next step
*
* @param preFinalize An event emitter, to be called before the step has been transitioned
* @param postFinalize An event emitter, to be called after the step has been transitioned
*/
goToNextStep(preFinalize, postFinalize) {
return this.navigation.goToStep(this, this.currentStepIndex + 1, preFinalize, postFinalize);
}
/**
* Checks, whether the wizard step, located at the given index, can be navigated to using the navigation bar.
*
* @param destinationIndex The index of the destination step
* @returns True if the step can be navigated to, false otherwise
*/
isNavigable(destinationIndex) {
return this.navigation.isNavigable(this, destinationIndex);
}
/**
* Resets the state of this wizard.
*/
reset() {
this.navigation.reset(this);
}
};
__decorate([
ContentChildren(WizardStep, { descendants: true }),
__metadata("design:type", QueryList)
], WizardComponent.prototype, "wizardStepsQueryList", void 0);
__decorate([
Input(),
__metadata("design:type", Object)
], WizardComponent.prototype, "navBarLocation", void 0);
__decorate([
Input(),
__metadata("design:type", Object)
], WizardComponent.prototype, "navBarLayout", void 0);
__decorate([
Input(),
__metadata("design:type", Object)
], WizardComponent.prototype, "navBarDirection", void 0);
__decorate([
Input(),
__metadata("design:type", Number),
__metadata("design:paramtypes", [Number])
], WizardComponent.prototype, "defaultStepIndex", null);
__decorate([
Input(),
__metadata("design:type", Object)
], WizardComponent.prototype, "disableNavigationBar", void 0);
__decorate([
HostBinding('class.horizontal'),
__metadata("design:type", Boolean),
__metadata("design:paramtypes", [])
], WizardComponent.prototype, "horizontalOrientation", null);
__decorate([
HostBinding('class.vertical'),
__metadata("design:type", Boolean),
__metadata("design:paramtypes", [])
], WizardComponent.prototype, "verticalOrientation", null);
WizardComponent = __decorate([
Component({
selector: 'aw-wizard',
template: "<aw-wizard-navigation-bar\n [direction]=\"navBarDirection\"\n *ngIf=\"navBarLocation == 'top' || navBarLocation == 'left'\"\n [ngClass]=\"{\n 'vertical': navBarLocation == 'left',\n 'horizontal': navBarLocation == 'top',\n 'small': navBarLayout == 'small',\n 'large-filled': navBarLayout == 'large-filled',\n 'large-filled-symbols': navBarLayout == 'large-filled-symbols',\n 'large-empty': navBarLayout == 'large-empty',\n 'large-empty-symbols': navBarLayout == 'large-empty-symbols'\n }\">\n</aw-wizard-navigation-bar>\n\n<div [ngClass]=\"{\n 'wizard-steps': true,\n 'vertical': navBarLocation == 'left' || navBarLocation == 'right',\n 'horizontal': navBarLocation == 'top' || navBarLocation == 'bottom'\n}\">\n <ng-content></ng-content>\n</div>\n\n<aw-wizard-navigation-bar\n [direction]=\"navBarDirection\"\n *ngIf=\"navBarLocation == 'bottom' || navBarLocation == 'right'\"\n [ngClass]=\"{\n 'vertical': navBarLocation == 'right',\n 'horizontal': navBarLocation == 'bottom',\n 'small': navBarLayout == 'small',\n 'large-filled': navBarLayout == 'large-filled',\n 'large-filled-symbols': navBarLayout == 'large-filled-symbols',\n 'large-empty': navBarLayout == 'large-empty',\n 'large-empty-symbols': navBarLayout == 'large-empty-symbols'\n }\">\n</aw-wizard-navigation-bar>\n"
}),
__metadata("design:paramtypes", [])
], WizardComponent);
export { WizardComponent };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2l6YXJkLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL2FuZ3VsYXItYXJjaHdpemFyZC8iLCJzb3VyY2VzIjpbImxpYi9jb21wb25lbnRzL3dpemFyZC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sRUFFTCxTQUFTLEVBQ1QsZUFBZSxFQUNmLFdBQVcsRUFDWCxLQUFLLEVBQ0wsU0FBUyxHQUVWLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFBQyxVQUFVLEVBQUMsTUFBTSwrQkFBK0IsQ0FBQztBQUN6RCxPQUFPLEVBQUMsZUFBZSxFQUFDLE1BQU0sK0JBQStCLENBQUM7QUFDOUQsT0FBTyxFQUFDLDBCQUEwQixFQUFDLE1BQU0sNENBQTRDLENBQUM7QUFFdEY7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrQ0c7QUFLSCxJQUFhLGVBQWUsR0FBNUIsTUFBYSxlQUFlO0lBZ0YxQjs7T0FFRztJQUNIO1FBNUVBOzs7V0FHRztRQUVJLG1CQUFjLEdBQUcsS0FBSyxDQUFDO1FBRTlCOzs7V0FHRztRQUVJLGlCQUFZLEdBQUcsT0FBTyxDQUFDO1FBRTlCOzs7V0FHRztRQUVJLG9CQUFlLEdBQUcsZUFBZSxDQUFDO1FBdUJqQyxzQkFBaUIsR0FBRyxDQUFDLENBQUM7UUFFOUI7O1dBRUc7UUFFSSx5QkFBb0IsR0FBRyxLQUFLLENBQUM7UUFFcEM7Ozs7V0FJRztRQUNLLGdCQUFXLEdBQW1CLElBQUksMEJBQTBCLEVBQUUsQ0FBQztRQUV2RTs7OztXQUlHO1FBQ0ssaUJBQVksR0FBaUIsRUFBRSxDQUFDO1FBRXhDOzs7Ozs7V0FNRztRQUNJLHFCQUFnQixHQUFHLENBQUMsQ0FBQyxDQUFDO0lBTTdCLENBQUM7SUF4REQ7OztPQUdHO0lBRUgsSUFBVyxnQkFBZ0I7UUFDekIsNEJBQTRCO1FBQzVCLCtEQUErRDtRQUMvRCwyREFBMkQ7UUFFM0QsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMs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LGdCQUF3QjtRQUN6QyxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUs7UUFDVixJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUM5QixDQUFDO0NBQ0YsQ0FBQTtBQWxWQztJQURDLGVBQWUsQ0FBQyxVQUFVLEVBQUUsRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFLENBQUM7OEJBQ3RCLFNBQVM7NkRBQWE7QUFPbkQ7SUFEQyxLQUFLLEVBQUU7O3VEQUNzQjtBQU85QjtJQURDLEtBQUssRUFBRTs7cURBQ3NCO0FBTzlCO0lBREMsS0FBSyxFQUFFOzt3REFDaUM7QUFPekM7SUFEQyxLQUFLLEVBQUU7Ozt1REFhUDtBQVVEO0lBREMsS0FBSyxFQUFFOzs2REFDNEI7QUFzQ3BDO0lBREMsV0FBVyxDQUFDLGtCQUFrQixDQUFDOzs7NERBRy9CO0FBU0Q7SUFEQyxXQUFXLENBQUMsZ0JBQWdCLENBQUM7OzswREFHN0I7QUExR1UsZUFBZTtJQUozQixTQUFTLENBQUM7UUFDVCxRQUFRLEVBQUUsV0FBVztRQUNyQixpMENBQW9DO0tBQ3JDLENBQUM7O0dBQ1csZUFBZSxDQXVWM0I7U0F2VlksZUFBZSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEFmdGVyQ29udGVudEluaXQsXG4gIENvbXBvbmVudCxcbiAgQ29udGVudENoaWxkcmVuLFxuICBIb3N0QmluZGluZyxcbiAgSW5wdXQsXG4gIFF1ZXJ5TGlzdCxcbiAgRXZlbnRFbWl0dGVyLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7TmF2aWdhdGlvbk1vZGV9IGZyb20gJy4uL25hdmlnYXRpb24vbmF2aWdhdGlvbi1tb2RlLmludGVyZmFjZSc7XG5pbXBvcnQge1dpemFyZFN0ZXB9IGZyb20gJy4uL3V0aWwvd2l6YXJkLXN0ZXAuaW50ZXJmYWNlJztcbmltcG9ydCB7TW92aW5nRGlyZWN0aW9ufSBmcm9tICcuLi91dGlsL21vdmluZy1kaXJlY3Rpb24uZW51bSc7XG5pbXBvcnQge0NvbmZpZ3VyYWJsZU5hdmlnYXRpb25Nb2RlfSBmcm9tICcuLi9uYXZpZ2F0aW9uL2NvbmZpZ3VyYWJsZS1uYXZpZ2F0aW9uLW1vZGUnO1xuXG4vKipcbiAqIFRoZSBgYXctd2l6YXJkYCBjb21wb25lbnQgZGVmaW5lcyB0aGUgcm9vdCBjb21wb25lbnQgb2YgYSB3aXphcmQuXG4gKiBUaHJvdWdoIHRoZSBzZXR0aW5nIG9mIGlucHV0IHBhcmFtZXRlcnMgZm9yIHRoZSBgYXctd2l6YXJkYCBjb21wb25lbnQgaXQncyBwb3NzaWJsZSB0byBjaGFuZ2UgdGhlIGxvY2F0aW9uIGFuZCBzaXplXG4gKiBvZiBpdHMgbmF2aWdhdGlvbiBiYXIuXG4gKlxuICogIyMjIFN5bnRheFxuICogYGBgaHRtbFxuICogPGF3LXdpemFyZCBbbmF2QmFyTG9jYXRpb25dPVwibG9jYXRpb24gb2YgbmF2aWdhdGlvbiBiYXJcIiBbbmF2QmFyTGF5b3V0XT1cImxheW91dCBvZiBuYXZpZ2F0aW9uIGJhclwiPlxuICogICAgIC4uLlxuICogPC9hdy13aXphcmQ+XG4gKiBgYGBcbiAqXG4gKiAjIyMgRXhhbXBsZVxuICpcbiAqIFdpdGhvdXQgY29tcGxldGlvbiBzdGVwOlxuICpcbiAqIGBgYGh0bWxcbiAqIDxhdy13aXphcmQgbmF2QmFyTG9jYXRpb249XCJ0b3BcIiBuYXZCYXJMYXlvdXQ9XCJzbWFsbFwiPlxuICogICAgIDxhdy13aXphcmQtc3RlcD4uLi48L2F3LXdpemFyZC1zdGVwPlxuICogICAgIDxhdy13aXphcmQtc3RlcD4uLi48L2F3LXdpemFyZC1zdGVwPlxuICogPC9hdy13aXphcmQ+XG4gKiBgYGBcbiAqXG4gKiBXaXRoIGNvbXBsZXRpb24gc3RlcDpcbiAqXG4gKiBgYGBodG1sXG4gKiA8YXctd2l6YXJkIG5hdkJhckxvY2F0aW9uPVwidG9wXCIgbmF2QmFyTGF5b3V0PVwic21hbGxcIj5cbiAqICAgICA8YXctd2l6YXJkLXN0ZXA+Li4uPC9hdy13aXphcmQtc3RlcD5cbiAqICAgICA8YXctd2l6YXJkLXN0ZXA+Li4uPC9hdy13aXphcmQtc3RlcD5cbiAqICAgICA8YXctd2l6YXJkLWNvbXBsZXRpb24tc3RlcD4uLi48L2F3LXdpemFyZC1jb21wbGV0aW9uLXN0ZXA+XG4gKiA8L2F3LXdpemFyZD5cbiAqIGBgYFxuICpcbiAqIEBhdXRob3IgTWFyYyBBcm5kdFxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdhdy13aXphcmQnLFxuICB0ZW1wbGF0ZVVybDogJ3dpemFyZC5jb21wb25lbnQuaHRtbCcsXG59KVxuZXhwb3J0IGNsYXNzIFdpemFyZENvbXBvbmVudCBpbXBsZW1lbnRzIEFmdGVyQ29udGVudEluaXQge1xuICAvKipcbiAgICogQSBRdWVyeUxpc3QgY29udGFpbmluZyBhbGwgW1tXaXphcmRTdGVwXV1zIGluc2lkZSB0aGlzIHdpemFyZFxuICAgKi9cbiAgQENvbnRlbnRDaGlsZHJlbihXaXphcmRTdGVwLCB7IGRlc2NlbmRhbnRzOiB0cnVlIH0pXG4gIHB1YmxpYyB3aXphcmRTdGVwc1F1ZXJ5TGlzdDogUXVlcnlMaXN0PFdpemFyZFN0ZXA+O1xuXG4gIC8qKlxuICAgKiBUaGUgbG9jYXRpb24gb2YgdGhlIG5hdmlnYXRpb24gYmFyIGluc2lkZSB0aGUgd2l6YXJkLlxuICAgKiBUaGlzIGxvY2F0aW9uIGNhbiBiZSBlaXRoZXIgdG9wLCBib3R0b20sIGxlZnQgb3IgcmlnaHRcbiAgICovXG4gIEBJbnB1dCgpXG4gIHB1YmxpYyBuYXZCYXJMb2NhdGlvbiA9ICd0b3AnO1xuXG4gIC8qKlxuICAgKiBUaGUgbGF5b3V0IG9mIHRoZSBuYXZpZ2F0aW9uIGJhciBpbnNpZGUgdGhlIHdpemFyZC5cbiAgICogVGhlIGxheW91dCBjYW4gYmUgZWl0aGVyIHNtYWxsLCBsYXJnZS1maWxsZWQsIGxhcmdlLWVtcHR5IG9yIGxhcmdlLXN5bWJvbHNcbiAgICovXG4gIEBJbnB1dCgpXG4gIHB1YmxpYyBuYXZCYXJMYXlvdXQgPSAnc21hbGwnO1xuXG4gIC8qKlxuICAgKiBUaGUgZGlyZWN0aW9uIGluIHdoaWNoIHRoZSBzdGVwcyBpbnNpZGUgdGhlIG5hdmlnYXRpb24gYmFyIHNob3VsZCBiZSBzaG93bi5cbiAgICogVGhlIGRpcmVjdGlvbiBjYW4gYmUgZWl0aGVyIGBsZWZ0LXRvLXJpZ2h0YCBvciBgcmlnaHQtdG8tbGVmdGBcbiAgICovXG4gIEBJbnB1dCgpXG4gIHB1YmxpYyBuYXZCYXJEaXJlY3Rpb24gPSAnbGVmdC10by1yaWdodCc7XG5cbiAgLyoqXG4gICAqIFRoZSBpbml0aWFsbHkgc2VsZWN0ZWQgc3RlcCwgcmVwcmVzZW50ZWQgYnkgaXRzIGluZGV4XG4gICAqIEJld2FyZTogVGhpcyBpbml0aWFsIGRlZmF1bHQgaXMgb25seSB1c2VkIGlmIG5vIHdpemFyZCBzdGVwIGhhcyBiZWVuIGVuaGFuY2VkIHdpdGggdGhlIGBzZWxlY3RlZGAgZGlyZWN0aXZlXG4gICAqL1xuICBASW5wdXQoKVxuICBwdWJsaWMgZ2V0IGRlZmF1bHRTdGVwSW5kZXgoKTogbnVtYmVyIHtcbiAgICAvLyBUaGlzIHZhbHVlIGNhbiBiZSBlaXRoZXI6XG4gICAgLy8gLSB0aGUgaW5kZXggb2YgYSB3aXphcmQgc3RlcCB3aXRoIGEgYHNlbGVjdGVkYCBkaXJlY3RpdmUsIG9yXG4gICAgLy8gLSB0aGUgZGVmYXVsdCBzdGVwIGluZGV4LCBzZXQgaW4gdGhlIFtbV2l6YXJkQ29tcG9uZW50XV1cblxuICAgIGNvbnN0IGZvdW5kRGVmYXVsdFN0ZXAgPSB0aGlzLndpemFyZFN0ZXBzLmZpbmQoc3RlcCA9PiBzdGVwLmRlZmF1bHRTZWxlY3RlZCk7XG5cbiAgICBpZiAoZm91bmREZWZhdWx0U3RlcCkge1xuICAgICAgcmV0dXJuIHRoaXMuZ2V0SW5kZXhPZlN0ZXAoZm91bmREZWZhdWx0U3RlcCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB0aGlzLl9kZWZhdWx0U3RlcEluZGV4O1xuICAgIH1cbiAgfVxuICBwdWJsaWMgc2V0IGRlZmF1bHRTdGVwSW5kZXgoZGVmYXVsdFN0ZXBJbmRleDogbnVtYmVyKSB7XG4gICAgdGhpcy5fZGVmYXVsdFN0ZXBJbmRleCA9IGRlZmF1bHRTdGVwSW5kZXg7XG4gIH1cbiAgcHJpdmF0ZSBfZGVmYXVsdFN0ZXBJbmRleCA9IDA7XG5cbiAgLyoqXG4gICAqIFRydWUsIGlmIHRoZSBuYXZpZ2F0aW9uIGJhciBzaG91bGRuJ3QgYmUgdXNlZCBmb3IgbmF2aWdhdGluZ1xuICAgKi9cbiAgQElucHV0KClcbiAgcHVibGljIGRpc2FibGVOYXZpZ2F0aW9uQmFyID0gZmFsc2U7XG5cbiAgLyoqXG4gICAqIFRoZSBuYXZpZ2F0aW9uIG1vZGUgdXNlZCB0byBuYXZpZ2F0ZSBpbnNpZGUgdGhlIHdpemFyZFxuICAgKlxuICAgKiBGb3Igb3V0c2lkZSBhY2Nlc3MsIHVzZSB0aGUgW1tuYXZpZ2F0aW9uXV0gZ2V0dGVyLlxuICAgKi9cbiAgcHJpdmF0ZSBfbmF2aWdhdGlvbjogTmF2aWdhdGlvbk1vZGUgPSBuZXcgQ29uZmlndXJhYmxlTmF2aWdhdGlvbk1vZGUoKTtcblxuICAvKipcbiAgICogQW4gYXJyYXkgcmVwcmVzZW50YXRpb24gb2YgYWxsIHdpemFyZCBzdGVwcyBiZWxvbmdpbmcgdG8gdGhpcyBtb2RlbFxuICAgKlxuICAgKiBGb3Igb3V0c2lkZSBhY2Nlc3MsIHVzZSB0aGUgW1t3aXphcmRTdGVwc11dIGdldHRlci5cbiAgICovXG4gIHByaXZhdGUgX3dpemFyZFN0ZXBzOiBXaXphcmRTdGVwW10gPSBbXTtcblxuICAvKipcbiAgICogVGhlIGluZGV4IG9mIHRoZSBjdXJyZW50bHkgdmlzaWJsZSBhbmQgc2VsZWN0ZWQgc3RlcCBpbnNpZGUgdGhlIHdpemFyZFN0ZXBzIFF1ZXJ5TGlzdC5cbiAgICogSWYgdGhpcyB3aXphcmQgY29udGFpbnMgbm8gc3RlcHMsIGN1cnJlbnRTdGVwSW5kZXggaXMgLTFcbiAgICpcbiAgICogTm90ZTogRG8gbm90IG1vZGlmeSB0aGlzIGZpZWxkIGRpcmVjdGx5LiAgSW5zdGVhZCwgdXNlIG5hdmlnYXRpb24gbWV0aG9kczpcbiAgICogW1tnb1RvU3RlcF1dLCBbW2dvVG9QcmV2aW91c1N0ZXBdXSwgW1tnb1RvTmV4dFN0ZXBdXS5cbiAgICovXG4gIHB1YmxpYyBjdXJyZW50U3RlcEluZGV4ID0gLTE7XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdG9yXG4gICAqL1xuICBjb25zdHJ1Y3RvcigpIHtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRydWUgaWYgdGhpcyB3aXphcmQgdXNlcyBhIGhvcml6b250YWwgb3JpZW50YXRpb24uXG4gICAqIFRoZSB3aXphcmQgdXNlcyBhIGhvcml6b250YWwgb3JpZW50YXRpb24sIGlmZiB0aGUgbmF2aWdhdGlvbiBiYXIgaXMgc2hvd24gYXQgdGhlIHRvcCBvciBib3R0b20gb2YgdGhpcyB3aXphcmRcbiAgICpcbiAgICogQHJldHVybnMgVHJ1ZSBpZiB0aGlzIHdpemFyZCB1c2VzIGEgaG9yaXpvbnRhbCBvcmllbnRhdGlvblxuICAgKi9cbiAgQEhvc3RCaW5kaW5nKCdjbGFzcy5ob3Jpem9udGFsJylcbiAgcHVibGljIGdldCBob3Jpem9udGFsT3JpZW50YXRpb24oKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMubmF2QmFyTG9jYXRpb24gPT09ICd0b3AnIHx8IHRoaXMubmF2QmFyTG9jYXRpb24gPT09ICdib3R0b20nO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiB0aGlzIHdpemFyZCB1c2VzIGEgdmVydGljYWwgb3JpZW50YXRpb24uXG4gICAqIFRoZSB3aXphcmQgdXNlcyBhIHZlcnRpY2FsIG9yaWVudGF0aW9uLCBpZmYgdGhlIG5hdmlnYXRpb24gYmFyIGlzIHNob3duIGF0IHRoZSBsZWZ0IG9yIHJpZ2h0IG9mIHRoaXMgd2l6YXJkXG4gICAqXG4gICAqIEByZXR1cm5zIFRydWUgaWYgdGhpcyB3aXphcmQgdXNlcyBhIHZlcnRpY2FsIG9yaWVudGF0aW9uXG4gICAqL1xuICBASG9zdEJpbmRpbmcoJ2NsYXNzLnZlcnRpY2FsJylcbiAgcHVibGljIGdldCB2ZXJ0aWNhbE9yaWVudGF0aW9uKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLm5hdkJhckxvY2F0aW9uID09PSAnbGVmdCcgfHwgdGhpcy5uYXZCYXJMb2NhdGlvbiA9PT0gJ3JpZ2h0JztcbiAgfVxuXG4gIC8qKlxuICAgKiBJbml0aWFsaXphdGlvbiB3b3JrXG4gICAqL1xuICBwdWJsaWMgbmdBZnRlckNvbnRlbnRJbml0KCk6IHZvaWQge1xuICAgIC8vIGFkZCBhIHN1YnNjcmliZXIgdG8gdGhlIHdpemFyZCBzdGVwcyBRdWVyeUxpc3QgdG8gbGlzdGVuIHRvIGNoYW5nZXMgaW4gdGhlIERPTVxuICAgIHRoaXMud2l6YXJkU3RlcHNRdWVyeUxpc3QuY2hhbmdlcy5zdWJzY3JpYmUoY2hhbmdlZFdpemFyZFN0ZXBzID0+IHtcbiAgICAgIHRoaXMudXBkYXRlV2l6YXJkU3RlcHMoY2hhbmdlZFdpemFyZFN0ZXBzLnRvQXJyYXkoKSk7XG4gICAgfSk7XG5cbiAgICAvLyBpbml0aWFsaXplIHRoZSBtb2RlbFxuICAgIHRoaXMudXBkYXRlV2l6YXJkU3RlcHModGhpcy53aXphcmRTdGVwc1F1ZXJ5TGlzdC50b0FycmF5KCkpO1xuXG4gICAgLy8gZmluYWxseSByZXNldCB0aGUgd2hvbGUgd2l6YXJkIGNvbXBvbmVudFxuICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy5yZXNldCgpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgV2l6YXJkU3RlcCBvYmplY3QgYmVsb25naW5nIHRvIHRoZSBjdXJyZW50bHkgdmlzaWJsZSBhbmQgc2VsZWN0ZWQgc3RlcC5cbiAgICogVGhlIGN1cnJlbnRTdGVwIGlzIGFsd2F5cyB0aGUgY3VycmVudGx5IHNlbGVjdGVkIHdpemFyZCBzdGVwLlxuICAgKiBUaGUgY3VycmVudFN0ZXAgY2FuIGJlIGVpdGhlciBjb21wbGV0ZWQsIGlmIGl0IHdhcyB2aXNpdGVkIGVhcmxpZXIsXG4gICAqIG9yIG5vdCBjb21wbGV0ZWQsIGlmIGl0IGlzIHZpc2l0ZWQgZm9yIHRoZSBmaXJzdCB0aW1lIG9yIGl0cyBzdGF0ZSBpcyBjdXJyZW50bHkgb3V0IG9mIGRhdGUuXG4gICAqXG4gICAqIElmIHRoaXMgd2l6YXJkIGNvbnRhaW5zIG5vIHN0ZXBzLCBjdXJyZW50U3RlcCBpcyBudWxsXG4gICAqL1xuICBwdWJsaWMgZ2V0IGN1cnJlbnRTdGVwKCk6IFdpemFyZFN0ZXAge1xuICAgIGlmICh0aGlzLmhhc1N0ZXAodGhpcy5jdXJyZW50U3RlcEluZGV4KSkge1xuICAgICAgcmV0dXJuIHRoaXMud2l6YXJkU3RlcHNbdGhpcy5jdXJyZW50U3RlcEluZGV4XTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjb21wbGV0ZW5lc3Mgb2YgdGhlIHdpemFyZC5cbiAgICogSWYgdGhlIHdpemFyZCBoYXMgYmVlbiBjb21wbGV0ZWQsIGkuZS4gYWxsIHN0ZXBzIGFyZSBlaXRoZXIgY29tcGxldGVkIG9yIG9wdGlvbmFsLCB0aGlzIHZhbHVlIGlzIHRydWUsIG90aGVyd2lzZSBpdCBpcyBmYWxzZVxuICAgKi9cbiAgcHVibGljIGdldCBjb21wbGV0ZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMud2l6YXJkU3RlcHMuZXZlcnkoc3RlcCA9PiBzdGVwLmNvbXBsZXRlZCB8fCBzdGVwLm9wdGlvbmFsKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbiBhcnJheSByZXByZXNlbnRhdGlvbiBvZiBhbGwgd2l6YXJkIHN0ZXBzIGJlbG9uZ2luZyB0byB0aGlzIG1vZGVsXG4gICAqL1xuICBwdWJsaWMgZ2V0IHdpemFyZFN0ZXBzKCk6IFdpemFyZFN0ZXBbXSB7XG4gICAgcmV0dXJuIHRoaXMuX3dpemFyZFN0ZXBzO1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgdGhlIHdpemFyZCBzdGVwcyB0byB0aGUgbmV3IGFycmF5XG4gICAqXG4gICAqIEBwYXJhbSB3aXphcmRTdGVwcyBUaGUgdXBkYXRlZCB3aXphcmQgc3RlcHNcbiAgICovXG4gIHByaXZhdGUgdXBkYXRlV2l6YXJkU3RlcHMod2l6YXJkU3RlcHM6IFdpemFyZFN0ZXBbXSk6IHZvaWQge1xuICAgIC8vIHRoZSB3aXphcmQgaXMgY3VycmVudGx5IG5vdCBpbiB0aGUgaW5pdGlhbGl6YXRpb24gcGhhc2VcbiAgICBpZiAodGhpcy53aXphcmRTdGVwcy5sZW5ndGggPiAwICYmIHRoaXMuY3VycmVudFN0ZXBJbmRleCA+IC0xKSB7XG4gICAgICB0aGlzLmN1cnJlbnRTdGVwSW5kZXggPSB3aXphcmRTdGVwcy5pbmRleE9mKHRoaXMud2l6YXJkU3RlcHNbdGhpcy5jdXJyZW50U3RlcEluZGV4XSk7XG4gICAgfVxuXG4gICAgdGhpcy5fd2l6YXJkU3RlcHMgPSB3aXphcmRTdGVwcztcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgbmF2aWdhdGlvbiBtb2RlIHVzZWQgdG8gbmF2aWdhdGUgaW5zaWRlIHRoZSB3aXphcmRcbiAgICovXG4gIHB1YmxpYyBnZXQgbmF2aWdhdGlvbigpOiBOYXZpZ2F0aW9uTW9kZSB7XG4gICAgcmV0dXJuIHRoaXMuX25hdmlnYXRpb247XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlcyB0aGUgbmF2aWdhdGlvbiBtb2RlIGZvciB0aGlzIHdpemFyZCBjb21wb25lbnRcbiAgICpcbiAgICogQHBhcmFtIG5hdmlnYXRpb24gVGhlIHVwZGF0ZWQgbmF2aWdhdGlvbiBtb2RlXG4gICAqL1xuICBwdWJsaWMgc2V0IG5hdmlnYXRpb24obmF2aWdhdGlvbjogTmF2aWdhdGlvbk1vZGUpIHtcbiAgICB0aGlzLl9uYXZpZ2F0aW9uID0gbmF2aWdhdGlvbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgYSBnaXZlbiBpbmRleCBgc3RlcEluZGV4YCBpcyBpbnNpZGUgdGhlIHJhbmdlIG9mIHBvc3NpYmxlIHdpemFyZCBzdGVwcyBpbnNpZGUgdGhpcyB3aXphcmRcbiAgICpcbiAgICogQHBhcmFtIHN0ZXBJbmRleCBUaGUgdG8gYmUgY2hlY2tlZCBpbmRleCBvZiBhIHN0ZXAgaW5zaWRlIHRoaXMgd2l6YXJkXG4gICAqIEByZXR1cm5zIFRydWUgaWYgdGhlIGdpdmVuIGBzdGVwSW5kZXhgIGlzIGNvbnRhaW5lZCBpbnNpZGUgdGhpcyB3aXphcmQsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgcHVibGljIGhhc1N0ZXAoc3RlcEluZGV4OiBudW1iZXIpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy53aXphcmRTdGVwcy5sZW5ndGggPiAwICYmIDAgPD0gc3RlcEluZGV4ICYmIHN0ZXBJbmRleCA8IHRoaXMud2l6YXJkU3RlcHMubGVuZ3RoO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGlzIHdpemFyZCBoYXMgYSBwcmV2aW91cyBzdGVwLCBjb21wYXJlZCB0byB0aGUgY3VycmVudCBzdGVwXG4gICAqXG4gICAqIEByZXR1cm5zIFRydWUgaWYgdGhpcyB3aXphcmQgaGFzIGEgcHJldmlvdXMgc3RlcCBiZWZvcmUgdGhlIGN1cnJlbnQgc3RlcFxuICAgKi9cbiAgcHVibGljIGhhc1ByZXZpb3VzU3RlcCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5oYXNTdGVwKHRoaXMuY3VycmVudFN0ZXBJbmRleCAtIDEpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGlzIHdpemFyZCBoYXMgYSBuZXh0IHN0ZXAsIGNvbXBhcmVkIHRvIHRoZSBjdXJyZW50IHN0ZXBcbiAgICpcbiAgICogQHJldHVybnMgVHJ1ZSBpZiB0aGlzIHdpemFyZCBoYXMgYSBuZXh0IHN0ZXAgYWZ0ZXIgdGhlIGN1cnJlbnQgc3RlcFxuICAgKi9cbiAgcHVibGljIGhhc05leHRTdGVwKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmhhc1N0ZXAodGhpcy5jdXJyZW50U3RlcEluZGV4ICsgMSk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoaXMgd2l6YXJkIGlzIGN1cnJlbnRseSBpbnNpZGUgaXRzIGxhc3Qgc3RlcFxuICAgKlxuICAgKiBAcmV0dXJucyBUcnVlIGlmIHRoZSB3aXphcmQgaXMgY3VycmVudGx5IGluc2lkZSBpdHMgbGFzdCBzdGVwXG4gICAqL1xuICBwdWJsaWMgaXNMYXN0U3RlcCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy53aXphcmRTdGVwcy5sZW5ndGggPiAwICYmIHRoaXMuY3VycmVudFN0ZXBJbmRleCA9PT0gdGhpcy53aXphcmRTdGVwcy5sZW5ndGggLSAxO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmRzIHRoZSBbW1dpemFyZFN0ZXBdXSBhdCB0aGUgZ2l2ZW4gaW5kZXggYHN0ZXBJbmRleGAuXG4gICAqIElmIG5vIFtbV2l6YXJkU3RlcF1dIGV4aXN0cyBhdCB0aGUgZ2l2ZW4gaW5kZXggYW4gRXJyb3IgaXMgdGhyb3duXG4gICAqXG4gICAqIEBwYXJhbSBzdGVwSW5kZXggVGhlIGdpdmVuIGluZGV4XG4gICAqIEByZXR1cm5zIFRoZSBmb3VuZCBbW1dpemFyZFN0ZXBdXSBhdCB0aGUgZ2l2ZW4gaW5kZXggYHN0ZXBJbmRleGBcbiAgICogQHRocm93cyBBbiBgRXJyb3JgIGlzIHRocm93biwgaWYgdGhlIGdpdmVuIGluZGV4IGBzdGVwSW5kZXhgIGRvZXNuJ3QgZXhpc3RcbiAgICovXG4gIHB1YmxpYyBnZXRTdGVwQXRJbmRleChzdGVwSW5kZXg6IG51bWJlcik6IFdpemFyZFN0ZXAge1xuICAgIGlmICghdGhpcy5oYXNTdGVwKHN0ZXBJbmRleCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgYSBrbm93biBzdGVwLCBidXQgZ290IHN0ZXBJbmRleDogJHtzdGVwSW5kZXh9LmApO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLndpemFyZFN0ZXBzW3N0ZXBJbmRleF07XG4gIH1cblxuICAvKipcbiAgICogRmluZHMgdGhlIGluZGV4IG9mIHRoZSBzdGVwIHdpdGggdGhlIGdpdmVuIGBzdGVwSWRgLlxuICAgKiBJZiBubyBzdGVwIHdpdGggdGhlIGdpdmVuIGBzdGVwSWRgIGV4aXN0cywgYC0xYCBpcyByZXR1cm5lZFxuICAgKlxuICAgKiBAcGFyYW0gc3RlcElkIFRoZSBnaXZlbiBzdGVwIGlkXG4gICAqIEByZXR1cm5zIFRoZSBmb3VuZCBpbmRleCBvZiBhIHN0ZXAgd2l0aCB0aGUgZ2l2ZW4gc3RlcCBpZCwgb3IgYC0xYCBpZiBubyBzdGVwIHdpdGggdGhlIGdpdmVuIGlkIGlzIGluY2x1ZGVkIGluIHRoZSB3aXphcmRcbiAgICovXG4gIHB1YmxpYyBnZXRJbmRleE9mU3RlcFdpdGhJZChzdGVwSWQ6IHN0cmluZyk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMud2l6YXJkU3RlcHMuZmluZEluZGV4KHN0ZXAgPT4gc3RlcC5zdGVwSWQgPT09IHN0ZXBJZCk7XG4gIH1cblxuICAvKipcbiAgICogRmluZHMgdGhlIGluZGV4IG9mIHRoZSBnaXZlbiBbW1dpemFyZFN0ZXBdXSBgc3RlcGAuXG4gICAqIElmIHRoZSBnaXZlbiBbW1dpemFyZFN0ZXBdXSBpcyBub3QgY29udGFpbmVkIGluc2lkZSB0aGlzIHdpemFyZCwgYC0xYCBpcyByZXR1cm5lZFxuICAgKlxuICAgKiBAcGFyYW0gc3RlcCBUaGUgZ2l2ZW4gW1tXaXphcmRTdGVwXV1cbiAgICogQHJldHVybnMgVGhlIGZvdW5kIGluZGV4IG9mIGBzdGVwYCBvciBgLTFgIGlmIHRoZSBzdGVwIGlzIG5vdCBpbmNsdWRlZCBpbiB0aGUgd2l6YXJkXG4gICAqL1xuICBwdWJsaWMgZ2V0SW5kZXhPZlN0ZXAoc3RlcDogV2l6YXJkU3RlcCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMud2l6YXJkU3RlcHMuaW5kZXhPZihzdGVwKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGVzIHRoZSBjb3JyZWN0IFtbTW92aW5nRGlyZWN0aW9uXV0gdmFsdWUgZm9yIGEgZ2l2ZW4gYGRlc3RpbmF0aW9uU3RlcGAgY29tcGFyZWQgdG8gdGhlIGBjdXJyZW50U3RlcEluZGV4YC5cbiAgICpcbiAgICogQHBhcmFtIGRlc3RpbmF0aW9uU3RlcCBUaGUgZ2l2ZW4gZGVzdGluYXRpb24gc3RlcFxuICAgKiBAcmV0dXJucyBUaGUgY2FsY3VsYXRlZCBbW01vdmluZ0RpcmVjdGlvbl1dXG4gICAqL1xuICBwdWJsaWMgZ2V0TW92aW5nRGlyZWN0aW9uKGRlc3RpbmF0aW9uU3RlcDogbnVtYmVyKTogTW92aW5nRGlyZWN0aW9uIHtcbiAgICBsZXQgbW92aW5nRGlyZWN0aW9uOiBNb3ZpbmdEaXJlY3Rpb247XG5cbiAgICBpZiAoZGVzdGluYXRpb25TdGVwID4gdGhpcy5jdXJyZW50U3RlcEluZGV4KSB7XG4gICAgICBtb3ZpbmdEaXJlY3Rpb24gPSBNb3ZpbmdEaXJlY3Rpb24uRm9yd2FyZHM7XG4gICAgfSBlbHNlIGlmIChkZXN0aW5hdGlvblN0ZXAgPCB0aGlzLmN1cnJlbnRTdGVwSW5kZXgpIHtcbiAgICAgIG1vdmluZ0RpcmVjdGlvbiA9IE1vdmluZ0RpcmVjdGlvbi5CYWNrd2FyZHM7XG4gICAgfSBlbHNlIHtcbiAgICAgIG1vdmluZ0RpcmVjdGlvbiA9IE1vdmluZ0RpcmVjdGlvbi5TdGF5O1xuICAgIH1cblxuICAgIHJldHVybiBtb3ZpbmdEaXJlY3Rpb247XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzLCB3aGV0aGVyIGEgd2l6YXJkIHN0ZXAsIGFzIGRlZmluZWQgYnkgdGhlIGdpdmVuIGRlc3RpbmF0aW9uIGluZGV4LCBjYW4gYmUgdHJhbnNpdGlvbmVkIHRvLlxuICAgKlxuICAgKiBUaGlzIG1ldGhvZCBjb250cm9scyBuYXZpZ2F0aW9uIGJ5IFtbZ29Ub1N0ZXBdXSwgW1tnb1RvUHJldmlvdXNTdGVwXV0sIGFuZCBbW2dvVG9OZXh0U3RlcF1dIGRpcmVjdGl2ZXMuXG4gICAqIE5hdmlnYXRpb24gYnkgbmF2aWdhdGlvbiBiYXIgaXMgZ292ZXJuZWQgYnkgW1tpc05hdmlnYWJsZV1dLlxuICAgKlxuICAgKiBAcGFyYW0gZGVzdGluYXRpb25JbmRleCBUaGUgaW5kZXggb2YgdGhlIGRlc3RpbmF0aW9uIHN0ZXBcbiAgICogQHJldHVybnMgQSBbW1Byb21pc2VdXSBjb250YWluaW5nIGB0cnVlYCwgaWYgdGhlIGRlc3RpbmF0aW9uIHN0ZXAgY2FuIGJlIHRyYW5zaXRpb25lZCB0byBhbmQgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBwdWJsaWMgY2FuR29Ub1N0ZXAoZGVzdGluYXRpb25JbmRleDogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgcmV0dXJuIHRoaXMubmF2aWdhdGlvbi5jYW5Hb1RvU3RlcCh0aGlzLCBkZXN0aW5hdGlvbkluZGV4KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcmllcyB0byB0cmFuc2l0aW9uIHRvIHRoZSB3aXphcmQgc3RlcCwgYXMgZGVub3RlZCBieSB0aGUgZ2l2ZW4gZGVzdGluYXRpb24gaW5kZXguXG4gICAqXG4gICAqIE5vdGU6IFlvdSBkbyBub3QgaGF2ZSB0byBjYWxsIFtbY2FuR29Ub1N0ZXBdXSBiZWZvcmUgY2FsbGluZyBbW2dvVG9TdGVwXV0uXG4gICAqIFRoZSBbW2NhbkdvVG9TdGVwXV0gbWV0aG9kIHdpbGwgYmUgY2FsbGVkIGF1dG9tYXRpY2FsbHkuXG4gICAqXG4gICAqIEBwYXJhbSBkZXN0aW5hdGlvbkluZGV4IFRoZSBpbmRleCBvZiB0aGUgZGVzdGluYXRpb24gd2l6YXJkIHN0ZXAsIHdoaWNoIHNob3VsZCBiZSBlbnRlcmVkXG4gICAqIEBwYXJhbSBwcmVGaW5hbGl6ZSBBbiBldmVudCBlbWl0dGVyLCB0byBiZSBjYWxsZWQgYmVmb3JlIHRoZSBzdGVwIGhhcyBiZWVuIHRyYW5zaXRpb25lZFxuICAgKiBAcGFyYW0gcG9zdEZpbmFsaXplIEFuIGV2ZW50IGVtaXR0ZXIsIHRvIGJlIGNhbGxlZCBhZnRlciB0aGUgc3RlcCBoYXMgYmVlbiB0cmFuc2l0aW9uZWRcbiAgICovXG4gIHB1YmxpYyBnb1RvU3RlcChkZXN0aW5hdGlvbkluZGV4OiBudW1iZXIsIHByZUZpbmFsaXplPzogRXZlbnRFbWl0dGVyPHZvaWQ+LCBwb3N0RmluYWxpemU/OiBFdmVudEVtaXR0ZXI8dm9pZD4pOiB2b2lkIHtcbiAgICByZXR1cm4gdGhpcy5uYXZpZ2F0aW9uLmdvVG9TdGVwKHRoaXMsIGRlc3RpbmF0aW9uSW5kZXgsIHByZUZpbmFsaXplLCBwb3N0RmluYWxpemUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyaWVzIHRvIHRyYW5zaXRpb24gdGhlIHdpemFyZCB0byB0aGUgcHJldmlvdXMgc3RlcFxuICAgKlxuICAgKiBAcGFyYW0gcHJlRmluYWxpemUgQW4gZXZlbnQgZW1pdHRlciwgdG8gYmUgY2FsbGVkIGJlZm9yZSB0aGUgc3RlcCBoYXMgYmVlbiB0cmFuc2l0aW9uZWRcbiAgICogQHBhcmFtIHBvc3RGaW5hbGl6ZSBBbiBldmVudCBlbWl0dGVyLCB0byBiZSBjYWxsZWQgYWZ0ZXIgdGhlIHN0ZXAgaGFzIGJlZW4gdHJhbnNpdGlvbmVkXG4gICAqL1xuICBwdWJsaWMgZ29Ub1ByZXZpb3VzU3RlcChwcmVGaW5hbGl6ZT86IEV2ZW50RW1pdHRlcjx2b2lkPiwgcG9zdEZpbmFsaXplPzogRXZlbnRFbWl0dGVyPHZvaWQ+KTogdm9pZCB7XG4gICAgcmV0dXJuIHRoaXMubmF2aWdhdGlvbi5nb1RvU3RlcCh0aGlzLCB0aGlzLmN1cnJlbnRTdGVwSW5kZXggLSAxLCBwcmVGaW5hbGl6ZSwgcG9zdEZpbmFsaXplKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcmllcyB0byB0cmFuc2l0aW9uIHRoZSB3aXphcmQgdG8gdGhlIG5leHQgc3RlcFxuICAgKlxuICAgKiBAcGFyYW0gcHJlRmluYWxpemUgQW4gZXZlbnQgZW1pdHRlciwgdG8gYmUgY2FsbGVkIGJlZm9yZSB0aGUgc3RlcCBoYXMgYmVlbiB0cmFuc2l0aW9uZWRcbiAgICogQHBhcmFtIHBvc3RGaW5hbGl6ZSBBbiBldmVudCBlbWl0dGVyLCB0byBiZSBjYWxsZWQgYWZ0ZXIgdGhlIHN0ZXAgaGFzIGJlZW4gdHJhbnNpdGlvbmVkXG4gICAqL1xuICBwdWJsaWMgZ29Ub05leHRTdGVwKHByZUZpbmFsaXplPzogRXZlbnRFbWl0dGVyPHZvaWQ+LCBwb3N0RmluYWxpemU/OiBFdmVudEVtaXR0ZXI8dm9pZD4pOiB2b2lkIHtcbiAgICByZXR1cm4gdGhpcy5uYXZpZ2F0aW9uLmdvVG9TdGVwKHRoaXMsIHRoaXMuY3VycmVudFN0ZXBJbmRleCArIDEsIHByZUZpbmFsaXplLCBwb3N0RmluYWxpemUpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcywgd2hldGhlciB0aGUgd2l6YXJkIHN0ZXAsIGxvY2F0ZWQgYXQgdGhlIGdpdmVuIGluZGV4LCBjYW4gYmUgbmF2aWdhdGVkIHRvIHVzaW5nIHRoZSBuYXZpZ2F0aW9uIGJhci5cbiAgICpcbiAgICogQHBhcmFtIGRlc3RpbmF0aW9uSW5kZXggVGhlIGluZGV4IG9mIHRoZSBkZXN0aW5hdGlvbiBzdGVwXG4gICAqIEByZXR1cm5zIFRydWUgaWYgdGhlIHN0ZXAgY2FuIGJlIG5hdmlnYXRlZCB0bywgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBwdWJsaWMgaXNOYXZpZ2FibGUoZGVzdGluYXRpb25JbmRleDogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMubmF2aWdhdGlvbi5pc05hdmlnYWJsZSh0aGlzLCBkZXN0aW5hdGlvbkluZGV4KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNldHMgdGhlIHN0YXRlIG9mIHRoaXMgd2l6YXJkLlxuICAgKi9cbiAgcHVibGljIHJlc2V0KCk6IHZvaWQge1xuICAgIHRoaXMubmF2aWdhdGlvbi5yZXNldCh0aGlzKTtcbiAgfVxufVxuIl19