@y3krulez/angular-archwizard
Version:
The port of angular-archwizard, supporting IVY and thus being compatible with Angular16+
365 lines • 46.5 kB
JavaScript
import { Component, ContentChildren, HostBinding, Input, } from '@angular/core';
import { WizardStep } from '../util/wizard-step.interface';
import { MovingDirection } from '../util/moving-direction.enum';
import { ConfigurableNavigationMode } from '../navigation/configurable-navigation-mode';
import { WIZARD_TOKEN } from '../navigation/wizard.interface';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
import * as i2 from "./wizard-navigation-bar.component";
/**
* 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
*/
export class WizardComponent {
/**
* 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;
}
/**
* 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;
}
/**
* 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);
}
}
WizardComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: WizardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
WizardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: WizardComponent, selector: "aw-wizard", inputs: { navBarLocation: "navBarLocation", navBarLayout: "navBarLayout", navBarDirection: "navBarDirection", defaultStepIndex: "defaultStepIndex", disableNavigationBar: "disableNavigationBar" }, host: { properties: { "class.horizontal": "this.horizontalOrientation", "class.vertical": "this.verticalOrientation" } }, providers: [{ provide: WIZARD_TOKEN, useExisting: WizardComponent }], queries: [{ propertyName: "wizardStepsQueryList", predicate: WizardStep, descendants: true }], ngImport: i0, template: "<aw-wizard-navigation-bar\r\n *ngIf=\"navBarLocation == 'top' || navBarLocation == 'left'\"\r\n [ngClass]=\"{\r\n 'vertical': navBarLocation == 'left',\r\n 'horizontal': navBarLocation == 'top',\r\n 'small': navBarLayout == 'small',\r\n 'large-filled': navBarLayout == 'large-filled',\r\n 'large-filled-symbols': navBarLayout == 'large-filled-symbols',\r\n 'large-empty': navBarLayout == 'large-empty',\r\n 'large-empty-symbols': navBarLayout == 'large-empty-symbols'\r\n }\">\r\n</aw-wizard-navigation-bar>\r\n\r\n<div [ngClass]=\"{\r\n 'wizard-steps': true,\r\n 'vertical': navBarLocation == 'left' || navBarLocation == 'right',\r\n 'horizontal': navBarLocation == 'top' || navBarLocation == 'bottom'\r\n}\">\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n<aw-wizard-navigation-bar\r\n *ngIf=\"navBarLocation == 'bottom' || navBarLocation == 'right'\"\r\n [ngClass]=\"{\r\n 'vertical': navBarLocation == 'right',\r\n 'horizontal': navBarLocation == 'bottom',\r\n 'small': navBarLayout == 'small',\r\n 'large-filled': navBarLayout == 'large-filled',\r\n 'large-filled-symbols': navBarLayout == 'large-filled-symbols',\r\n 'large-empty': navBarLayout == 'large-empty',\r\n 'large-empty-symbols': navBarLayout == 'large-empty-symbols'\r\n }\">\r\n</aw-wizard-navigation-bar>\r\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.WizardNavigationBarComponent, selector: "aw-wizard-navigation-bar" }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: WizardComponent, decorators: [{
type: Component,
args: [{ selector: 'aw-wizard', providers: [{ provide: WIZARD_TOKEN, useExisting: WizardComponent }], template: "<aw-wizard-navigation-bar\r\n *ngIf=\"navBarLocation == 'top' || navBarLocation == 'left'\"\r\n [ngClass]=\"{\r\n 'vertical': navBarLocation == 'left',\r\n 'horizontal': navBarLocation == 'top',\r\n 'small': navBarLayout == 'small',\r\n 'large-filled': navBarLayout == 'large-filled',\r\n 'large-filled-symbols': navBarLayout == 'large-filled-symbols',\r\n 'large-empty': navBarLayout == 'large-empty',\r\n 'large-empty-symbols': navBarLayout == 'large-empty-symbols'\r\n }\">\r\n</aw-wizard-navigation-bar>\r\n\r\n<div [ngClass]=\"{\r\n 'wizard-steps': true,\r\n 'vertical': navBarLocation == 'left' || navBarLocation == 'right',\r\n 'horizontal': navBarLocation == 'top' || navBarLocation == 'bottom'\r\n}\">\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n<aw-wizard-navigation-bar\r\n *ngIf=\"navBarLocation == 'bottom' || navBarLocation == 'right'\"\r\n [ngClass]=\"{\r\n 'vertical': navBarLocation == 'right',\r\n 'horizontal': navBarLocation == 'bottom',\r\n 'small': navBarLayout == 'small',\r\n 'large-filled': navBarLayout == 'large-filled',\r\n 'large-filled-symbols': navBarLayout == 'large-filled-symbols',\r\n 'large-empty': navBarLayout == 'large-empty',\r\n 'large-empty-symbols': navBarLayout == 'large-empty-symbols'\r\n }\">\r\n</aw-wizard-navigation-bar>\r\n" }]
}], ctorParameters: function () { return []; }, propDecorators: { wizardStepsQueryList: [{
type: ContentChildren,
args: [WizardStep, { descendants: true }]
}], navBarLocation: [{
type: Input
}], navBarLayout: [{
type: Input
}], navBarDirection: [{
type: Input
}], defaultStepIndex: [{
type: Input
}], disableNavigationBar: [{
type: Input
}], horizontalOrientation: [{
type: HostBinding,
args: ['class.horizontal']
}], verticalOrientation: [{
type: HostBinding,
args: ['class.vertical']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2l6YXJkLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy93aXphcmQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vc3JjL2xpYi9jb21wb25lbnRzL3dpemFyZC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRUwsU0FBUyxFQUNULGVBQWUsRUFDZixXQUFXLEVBQ1gsS0FBSyxHQUdOLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFBQyxVQUFVLEVBQUMsTUFBTSwrQkFBK0IsQ0FBQztBQUN6RCxPQUFPLEVBQUMsZUFBZSxFQUFDLE1BQU0sK0JBQStCLENBQUM7QUFDOUQsT0FBTyxFQUFDLDBCQUEwQixFQUFDLE1BQU0sNENBQTRDLENBQUM7QUFDdEYsT0FBTyxFQUFFLFlBQVksRUFBVSxNQUFNLGdDQUFnQyxDQUFDOzs7O0FBRXRFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0NHO0FBTUgsTUFBTSxPQUFPLGVBQWU7SUE0QjFCOzs7T0FHRztJQUNILElBQ1csZ0JBQWdCO1FBQ3pCLDRCQUE0QjtRQUM1QiwrREFBK0Q7UUFDL0QsMkRBQTJEO1FBRTNELE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUM7UUFFN0UsSUFBSSxnQkFBZ0IsRUFBRTtZQUNwQixPQUFPLElBQUksQ0FBQyxjQUFjLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztTQUM5QzthQUFNO1lBQ0wsT0FBTyxJQUFJLENBQUMsaUJBQWlCLENBQUM7U0FDL0I7SUFDSCxDQUFDO0lBQ0QsSUFBVyxnQkFBZ0IsQ0FBQyxnQkFBd0I7UUFDbEQsSUFBSSxDQUFDLGlCQUFpQixHQUFHLGdCQUFnQixDQUFDO0lBQzVDLENBQUM7SUFnQ0Q7O09B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LEVBQUUsV0FBVyxFQUFFLFlBQVksQ0FBQyxDQUFDO0lBQzlGLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNJLFdBQVcsQ0FBQyxnQkFBd0I7UUFDekMsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLO1FBQ1YsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDOUIsQ0FBQzs7NkdBdFZVLGVBQWU7aUdBQWYsZUFBZSxrV0FGZixDQUFDLEVBQUUsT0FBTyxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsZUFBZSxFQUFFLENBQUMsK0RBTW5ELFVBQVUsZ0RDM0Q3QixtekNBaUNBOzRGRHNCYSxlQUFlO2tCQUwzQixTQUFTOytCQUNFLFdBQVcsYUFFVixDQUFDLEVBQUUsT0FBTyxFQUFFLFlBQVksRUFBRSxXQUFXLGlCQUFpQixFQUFFLENBQUM7MEVBTzdELG9CQUFvQjtzQkFEMUIsZUFBZTt1QkFBQyxVQUFVLEVBQUUsRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFO2dCQVEzQyxjQUFjO3NCQURwQixLQUFLO2dCQVFDLFlBQVk7c0JBRGxCLEtBQUs7Z0JBUUMsZUFBZTtzQkFEckIsS0FBSztnQkFRSyxnQkFBZ0I7c0JBRDFCLEtBQUs7Z0JBdUJDLG9CQUFvQjtzQkFEMUIsS0FBSztnQkF1Q0sscUJBQXFCO3NCQUQvQixXQUFXO3VCQUFDLGtCQUFrQjtnQkFZcEIsbUJBQW1CO3NCQUQ3QixXQUFXO3VCQUFDLGdCQUFnQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcbiAgQWZ0ZXJDb250ZW50SW5pdCxcclxuICBDb21wb25lbnQsXHJcbiAgQ29udGVudENoaWxkcmVuLFxyXG4gIEhvc3RCaW5kaW5nLFxyXG4gIElucHV0LFxyXG4gIFF1ZXJ5TGlzdCxcclxuICBFdmVudEVtaXR0ZXIsXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7TmF2aWdhdGlvbk1vZGV9IGZyb20gJy4uL25hdmlnYXRpb24vbmF2aWdhdGlvbi1tb2RlLmludGVyZmFjZSc7XHJcbmltcG9ydCB7V2l6YXJkU3RlcH0gZnJvbSAnLi4vdXRpbC93aXphcmQtc3RlcC5pbnRlcmZhY2UnO1xyXG5pbXBvcnQge01vdmluZ0RpcmVjdGlvbn0gZnJvbSAnLi4vdXRpbC9tb3ZpbmctZGlyZWN0aW9uLmVudW0nO1xyXG5pbXBvcnQge0NvbmZpZ3VyYWJsZU5hdmlnYXRpb25Nb2RlfSBmcm9tICcuLi9uYXZpZ2F0aW9uL2NvbmZpZ3VyYWJsZS1uYXZpZ2F0aW9uLW1vZGUnO1xyXG5pbXBvcnQgeyBXSVpBUkRfVE9LRU4sIFdpemFyZCB9IGZyb20gJy4uL25hdmlnYXRpb24vd2l6YXJkLmludGVyZmFjZSc7XHJcblxyXG4vKipcclxuICogVGhlIGBhdy13aXphcmRgIGNvbXBvbmVudCBkZWZpbmVzIHRoZSByb290IGNvbXBvbmVudCBvZiBhIHdpemFyZC5cclxuICogVGhyb3VnaCB0aGUgc2V0dGluZyBvZiBpbnB1dCBwYXJhbWV0ZXJzIGZvciB0aGUgYGF3LXdpemFyZGAgY29tcG9uZW50IGl0J3MgcG9zc2libGUgdG8gY2hhbmdlIHRoZSBsb2NhdGlvbiBhbmQgc2l6ZVxyXG4gKiBvZiBpdHMgbmF2aWdhdGlvbiBiYXIuXHJcbiAqXHJcbiAqICMjIyBTeW50YXhcclxuICogYGBgaHRtbFxyXG4gKiA8YXctd2l6YXJkIFtuYXZCYXJMb2NhdGlvbl09XCJsb2NhdGlvbiBvZiBuYXZpZ2F0aW9uIGJhclwiIFtuYXZCYXJMYXlvdXRdPVwibGF5b3V0IG9mIG5hdmlnYXRpb24gYmFyXCI+XHJcbiAqICAgICAuLi5cclxuICogPC9hdy13aXphcmQ+XHJcbiAqIGBgYFxyXG4gKlxyXG4gKiAjIyMgRXhhbXBsZVxyXG4gKlxyXG4gKiBXaXRob3V0IGNvbXBsZXRpb24gc3RlcDpcclxuICpcclxuICogYGBgaHRtbFxyXG4gKiA8YXctd2l6YXJkIG5hdkJhckxvY2F0aW9uPVwidG9wXCIgbmF2QmFyTGF5b3V0PVwic21hbGxcIj5cclxuICogICAgIDxhdy13aXphcmQtc3RlcD4uLi48L2F3LXdpemFyZC1zdGVwPlxyXG4gKiAgICAgPGF3LXdpemFyZC1zdGVwPi4uLjwvYXctd2l6YXJkLXN0ZXA+XHJcbiAqIDwvYXctd2l6YXJkPlxyXG4gKiBgYGBcclxuICpcclxuICogV2l0aCBjb21wbGV0aW9uIHN0ZXA6XHJcbiAqXHJcbiAqIGBgYGh0bWxcclxuICogPGF3LXdpemFyZCBuYXZCYXJMb2NhdGlvbj1cInRvcFwiIG5hdkJhckxheW91dD1cInNtYWxsXCI+XHJcbiAqICAgICA8YXctd2l6YXJkLXN0ZXA+Li4uPC9hdy13aXphcmQtc3RlcD5cclxuICogICAgIDxhdy13aXphcmQtc3RlcD4uLi48L2F3LXdpemFyZC1zdGVwPlxyXG4gKiAgICAgPGF3LXdpemFyZC1jb21wbGV0aW9uLXN0ZXA+Li4uPC9hdy13aXphcmQtY29tcGxldGlvbi1zdGVwPlxyXG4gKiA8L2F3LXdpemFyZD5cclxuICogYGBgXHJcbiAqXHJcbiAqIEBhdXRob3IgTWFyYyBBcm5kdFxyXG4gKi9cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdhdy13aXphcmQnLFxyXG4gIHRlbXBsYXRlVXJsOiAnd2l6YXJkLmNvbXBvbmVudC5odG1sJyxcclxuICBwcm92aWRlcnM6IFt7IHByb3ZpZGU6IFdJWkFSRF9UT0tFTiwgdXNlRXhpc3Rpbmc6IFdpemFyZENvbXBvbmVudCB9XVxyXG59KVxyXG5leHBvcnQgY2xhc3MgV2l6YXJkQ29tcG9uZW50IGltcGxlbWVudHMgQWZ0ZXJDb250ZW50SW5pdCwgV2l6YXJkIHtcclxuICAvKipcclxuICAgKiBBIFF1ZXJ5TGlzdCBjb250YWluaW5nIGFsbCBbW1dpemFyZFN0ZXBdXXMgaW5zaWRlIHRoaXMgd2l6YXJkXHJcbiAgICovXHJcbiAgQENvbnRlbnRDaGlsZHJlbihXaXphcmRTdGVwLCB7IGRlc2NlbmRhbnRzOiB0cnVlIH0pXHJcbiAgcHVibGljIHdpemFyZFN0ZXBzUXVlcnlMaXN0OiBRdWVyeUxpc3Q8V2l6YXJkU3RlcD47XHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBsb2NhdGlvbiBvZiB0aGUgbmF2aWdhdGlvbiBiYXIgaW5zaWRlIHRoZSB3aXphcmQuXHJcbiAgICogVGhpcyBsb2NhdGlvbiBjYW4gYmUgZWl0aGVyIHRvcCwgYm90dG9tLCBsZWZ0IG9yIHJpZ2h0XHJcbiAgICovXHJcbiAgQElucHV0KClcclxuICBwdWJsaWMgbmF2QmFyTG9jYXRpb24gPSAndG9wJztcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGxheW91dCBvZiB0aGUgbmF2aWdhdGlvbiBiYXIgaW5zaWRlIHRoZSB3aXphcmQuXHJcbiAgICogVGhlIGxheW91dCBjYW4gYmUgZWl0aGVyIHNtYWxsLCBsYXJnZS1maWxsZWQsIGxhcmdlLWVtcHR5IG9yIGxhcmdlLXN5bWJvbHNcclxuICAgKi9cclxuICBASW5wdXQoKVxyXG4gIHB1YmxpYyBuYXZCYXJMYXlvdXQgPSAnc21hbGwnO1xyXG5cclxuICAvKipcclxuICAgKiBUaGUgZGlyZWN0aW9uIGluIHdoaWNoIHRoZSBzdGVwcyBpbnNpZGUgdGhlIG5hdmlnYXRpb24gYmFyIHNob3VsZCBiZSBzaG93bi5cclxuICAgKiBUaGUgZGlyZWN0aW9uIGNhbiBiZSBlaXRoZXIgYGxlZnQtdG8tcmlnaHRgIG9yIGByaWdodC10by1sZWZ0YFxyXG4gICAqL1xyXG4gIEBJbnB1dCgpXHJcbiAgcHVibGljIG5hdkJhckRpcmVjdGlvbiA9ICdsZWZ0LXRvLXJpZ2h0JztcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGluaXRpYWxseSBzZWxlY3RlZCBzdGVwLCByZXByZXNlbnRlZCBieSBpdHMgaW5kZXhcclxuICAgKiBCZXdhcmU6IFRoaXMgaW5pdGlhbCBkZWZhdWx0IGlzIG9ubHkgdXNlZCBpZiBubyB3aXphcmQgc3RlcCBoYXMgYmVlbiBlbmhhbmNlZCB3aXRoIHRoZSBgc2VsZWN0ZWRgIGRpcmVjdGl2ZVxyXG4gICAqL1xyXG4gIEBJbnB1dCgpXHJcbiAgcHVibGljIGdldCBkZWZhdWx0U3RlcEluZGV4KCk6IG51bWJlciB7XHJcbiAgICAvLyBUaGlzIHZhbHVlIGNhbiBiZSBlaXRoZXI6XHJcbiAgICAvLyAtIHRoZSBpbmRleCBvZiBhIHdpemFyZCBzdGVwIHdpdGggYSBgc2VsZWN0ZWRgIGRpcmVjdGl2ZSwgb3JcclxuICAgIC8vIC0gdGhlIGRlZmF1bHQgc3RlcCBpbmRleCwgc2V0IGluIHRoZSBbW1dpemFyZENvbXBvbmVudF1dXHJcblxyXG4gICAgY29uc3QgZm91bmREZWZhdWx0U3RlcCA9IHRoaXMud2l6YXJkU3RlcHMuZmluZChzdGVwID0+IHN0ZXAuZGVmYXVsdFNlbGVjdGVkKTtcclxuXHJcbiAgICBpZiAoZm91bmREZWZhdWx0U3RlcCkge1xyXG4gICAgICByZXR1cm4gdGhpcy5nZXRJbmRleE9mU3RlcChmb3VuZERlZmF1bHRTdGVwKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHJldHVybiB0aGlzLl9kZWZhdWx0U3RlcEluZGV4O1xyXG4gICAgfVxyXG4gIH1cclxuICBwdWJsaWMgc2V0IGRlZmF1bHRTdGVwSW5kZXgoZGVmYXVsdFN0ZXBJbmRleDogbnVtYmVyKSB7XHJcbiAgICB0aGlzLl9kZWZhdWx0U3RlcEluZGV4ID0gZGVmYXVsdFN0ZXBJbmRleDtcclxuICB9XHJcbiAgcHJpdmF0ZSBfZGVmYXVsdFN0ZXBJbmRleCA9IDA7XHJcblxyXG4gIC8qKlxyXG4gICAqIFRydWUsIGlmIHRoZSBuYXZpZ2F0aW9uIGJhciBzaG91bGRuJ3QgYmUgdXNlZCBmb3IgbmF2aWdhdGluZ1xyXG4gICAqL1xyXG4gIEBJbnB1dCgpXHJcbiAgcHVibGljIGRpc2FibGVOYXZpZ2F0aW9uQmFyID0gZmFsc2U7XHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBuYXZpZ2F0aW9uIG1vZGUgdXNlZCB0byBuYXZpZ2F0ZSBpbnNpZGUgdGhlIHdpemFyZFxyXG4gICAqXHJcbiAgICogRm9yIG91dHNpZGUgYWNjZXNzLCB1c2UgdGhlIFtbbmF2aWdhdGlvbl1dIGdldHRlci5cclxuICAgKi9cclxuICBwcml2YXRlIF9uYXZpZ2F0aW9uOiBOYXZpZ2F0aW9uTW9kZSA9IG5ldyBDb25maWd1cmFibGVOYXZpZ2F0aW9uTW9kZSgpO1xyXG5cclxuICAvKipcclxuICAgKiBBbiBhcnJheSByZXByZXNlbnRhdGlvbiBvZiBhbGwgd2l6YXJkIHN0ZXBzIGJlbG9uZ2luZyB0byB0aGlzIG1vZGVsXHJcbiAgICpcclxuICAgKiBGb3Igb3V0c2lkZSBhY2Nlc3MsIHVzZSB0aGUgW1t3aXphcmRTdGVwc11dIGdldHRlci5cclxuICAgKi9cclxuICBwcml2YXRlIF93aXphcmRTdGVwczogV2l6YXJkU3RlcFtdID0gW107XHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBpbmRleCBvZiB0aGUgY3VycmVudGx5IHZpc2libGUgYW5kIHNlbGVjdGVkIHN0ZXAgaW5zaWRlIHRoZSB3aXphcmRTdGVwcyBRdWVyeUxpc3QuXHJcbiAgICogSWYgdGhpcyB3aXphcmQgY29udGFpbnMgbm8gc3RlcHMsIGN1cnJlbnRTdGVwSW5kZXggaXMgLTFcclxuICAgKlxyXG4gICAqIE5vdGU6IERvIG5vdCBtb2RpZnkgdGhpcyBmaWVsZCBkaXJlY3RseS4gIEluc3RlYWQsIHVzZSBuYXZpZ2F0aW9uIG1ldGhvZHM6XHJcbiAgICogW1tnb1RvU3RlcF1dLCBbW2dvVG9QcmV2aW91c1N0ZXBdXSwgW1tnb1RvTmV4dFN0ZXBdXS5cclxuICAgKi9cclxuICBwdWJsaWMgY3VycmVudFN0ZXBJbmRleCA9IC0xO1xyXG5cclxuICAvKipcclxuICAgKiBDb25zdHJ1Y3RvclxyXG4gICAqL1xyXG4gIGNvbnN0cnVjdG9yKCkge1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmV0dXJucyB0cnVlIGlmIHRoaXMgd2l6YXJkIHVzZXMgYSBob3Jpem9udGFsIG9yaWVudGF0aW9uLlxyXG4gICAqIFRoZSB3aXphcmQgdXNlcyBhIGhvcml6b250YWwgb3JpZW50YXRpb24sIGlmZiB0aGUgbmF2aWdhdGlvbiBiYXIgaXMgc2hvd24gYXQgdGhlIHRvcCBvciBib3R0b20gb2YgdGhpcyB3aXphcmRcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIFRydWUgaWYgdGhpcyB3aXphcmQgdXNlcyBhIGhvcml6b250YWwgb3JpZW50YXRpb25cclxuICAgKi9cclxuICBASG9zdEJpbmRpbmcoJ2NsYXNzLmhvcml6b250YWwnKVxyXG4gIHB1YmxpYyBnZXQgaG9yaXpvbnRhbE9yaWVudGF0aW9uKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMubmF2QmFyTG9jYXRpb24gPT09ICd0b3AnIHx8IHRoaXMubmF2QmFyTG9jYXRpb24gPT09ICdib3R0b20nO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmV0dXJucyB0cnVlIGlmIHRoaXMgd2l6YXJkIHVzZXMgYSB2ZXJ0aWNhbCBvcmllbnRhdGlvbi5cclxuICAgKiBUaGUgd2l6YXJkIHVzZXMgYSB2ZXJ0aWNhbCBvcmllbnRhdGlvbiwgaWZmIHRoZSBuYXZpZ2F0aW9uIGJhciBpcyBzaG93biBhdCB0aGUgbGVmdCBvciByaWdodCBvZiB0aGlzIHdpemFyZFxyXG4gICAqXHJcbiAgICogQHJldHVybnMgVHJ1ZSBpZiB0aGlzIHdpemFyZCB1c2VzIGEgdmVydGljYWwgb3JpZW50YXRpb25cclxuICAgKi9cclxuICBASG9zdEJpbmRpbmcoJ2NsYXNzLnZlcnRpY2FsJylcclxuICBwdWJsaWMgZ2V0IHZlcnRpY2FsT3JpZW50YXRpb24oKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gdGhpcy5uYXZCYXJMb2NhdGlvbiA9PT0gJ2xlZnQnIHx8IHRoaXMubmF2QmFyTG9jYXRpb24gPT09ICdyaWdodCc7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBJbml0aWFsaXphdGlvbiB3b3JrXHJcbiAgICovXHJcbiAgcHVibGljIG5nQWZ0ZXJDb250ZW50SW5pdCgpOiB2b2lkIHtcclxuICAgIC8vIGFkZCBhIHN1YnNjcmliZXIgdG8gdGhlIHdpemFyZCBzdGVwcyBRdWVyeUxpc3QgdG8gbGlzdGVuIHRvIGNoYW5nZXMgaW4gdGhlIERPTVxyXG4gICAgdGhpcy53aXphcmRTdGVwc1F1ZXJ5TGlzdC5jaGFuZ2VzLnN1YnNjcmliZShjaGFuZ2VkV2l6YXJkU3RlcHMgPT4ge1xyXG4gICAgICB0aGlzLnVwZGF0ZVdpemFyZFN0ZXBzKGNoYW5nZWRXaXphcmRTdGVwcy50b0FycmF5KCkpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gaW5pdGlhbGl6ZSB0aGUgbW9kZWxcclxuICAgIHRoaXMudXBkYXRlV2l6YXJkU3RlcHModGhpcy53aXphcmRTdGVwc1F1ZXJ5TGlzdC50b0FycmF5KCkpO1xyXG5cclxuICAgIC8vIGZpbmFsbHkgcmVzZXQgdGhlIHdob2xlIHdpemFyZCBjb21wb25lbnRcclxuICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy5yZXNldCgpKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBXaXphcmRTdGVwIG9iamVjdCBiZWxvbmdpbmcgdG8gdGhlIGN1cnJlbnRseSB2aXNpYmxlIGFuZCBzZWxlY3RlZCBzdGVwLlxyXG4gICAqIFRoZSBjdXJyZW50U3RlcCBpcyBhbHdheXMgdGhlIGN1cnJlbnRseSBzZWxlY3RlZCB3aXphcmQgc3RlcC5cclxuICAgKiBUaGUgY3VycmVudFN0ZXAgY2FuIGJlIGVpdGhlciBjb21wbGV0ZWQsIGlmIGl0IHdhcyB2aXNpdGVkIGVhcmxpZXIsXHJcbiAgICogb3Igbm90IGNvbXBsZXRlZCwgaWYgaXQgaXMgdmlzaXRlZCBmb3IgdGhlIGZpcnN0IHRpbWUgb3IgaXRzIHN0YXRlIGlzIGN1cnJlbnRseSBvdXQgb2YgZGF0ZS5cclxuICAgKlxyXG4gICAqIElmIHRoaXMgd2l6YXJkIGNvbnRhaW5zIG5vIHN0ZXBzLCBjdXJyZW50U3RlcCBpcyBudWxsXHJcbiAgICovXHJcbiAgcHVibGljIGdldCBjdXJyZW50U3RlcCgpOiBXaXphcmRTdGVwIHtcclxuICAgIGlmICh0aGlzLmhhc1N0ZXAodGhpcy5jdXJyZW50U3RlcEluZGV4KSkge1xyXG4gICAgICByZXR1cm4gdGhpcy53aXphcmRTdGVwc1t0aGlzLmN1cnJlbnRTdGVwSW5kZXhdO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBUaGUgY29tcGxldGVuZXNzIG9mIHRoZSB3aXphcmQuXHJcbiAgICogSWYgdGhlIHdpemFyZCBoYXMgYmVlbiBjb21wbGV0ZWQsIGkuZS4gYWxsIHN0ZXBzIGFyZSBlaXRoZXIgY29tcGxldGVkIG9yIG9wdGlvbmFsLCB0aGlzIHZhbHVlIGlzIHRydWUsIG90aGVyd2lzZSBpdCBpcyBmYWxzZVxyXG4gICAqL1xyXG4gIHB1YmxpYyBnZXQgY29tcGxldGVkKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMud2l6YXJkU3RlcHMuZXZlcnkoc3RlcCA9PiBzdGVwLmNvbXBsZXRlZCB8fCBzdGVwLm9wdGlvbmFsKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEFuIGFycmF5IHJlcHJlc2VudGF0aW9uIG9mIGFsbCB3aXphcmQgc3RlcHMgYmVsb25naW5nIHRvIHRoaXMgbW9kZWxcclxuICAgKi9cclxuICBwdWJsaWMgZ2V0IHdpemFyZFN0ZXBzKCk6IFdpemFyZFN0ZXBbXSB7XHJcbiAgICByZXR1cm4gdGhpcy5fd2l6YXJkU3RlcHM7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBVcGRhdGVzIHRoZSB3aXphcmQgc3RlcHMgdG8gdGhlIG5ldyBhcnJheVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHdpemFyZFN0ZXBzIFRoZSB1cGRhdGVkIHdpemFyZCBzdGVwc1xyXG4gICAqL1xyXG4gIHByaXZhdGUgdXBkYXRlV2l6YXJkU3RlcHMod2l6YXJkU3RlcHM6IFdpemFyZFN0ZXBbXSk6IHZvaWQge1xyXG4gICAgLy8gdGhlIHdpemFyZCBpcyBjdXJyZW50bHkgbm90IGluIHRoZSBpbml0aWFsaXphdGlvbiBwaGFzZVxyXG4gICAgaWYgKHRoaXMud2l6YXJkU3RlcHMubGVuZ3RoID4gMCAmJiB0aGlzLmN1cnJlbnRTdGVwSW5kZXggPiAtMSkge1xyXG4gICAgICB0aGlzLmN1cnJlbnRTdGVwSW5kZXggPSB3aXphcmRTdGVwcy5pbmRleE9mKHRoaXMud2l6YXJkU3RlcHNbdGhpcy5jdXJyZW50U3RlcEluZGV4XSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5fd2l6YXJkU3RlcHMgPSB3aXphcmRTdGVwcztcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBuYXZpZ2F0aW9uIG1vZGUgdXNlZCB0byBuYXZpZ2F0ZSBpbnNpZGUgdGhlIHdpemFyZFxyXG4gICAqL1xyXG4gIHB1YmxpYyBnZXQgbmF2aWdhdGlvbigpOiBOYXZpZ2F0aW9uTW9kZSB7XHJcbiAgICByZXR1cm4gdGhpcy5fbmF2aWdhdGlvbjtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFVwZGF0ZXMgdGhlIG5hdmlnYXRpb24gbW9kZSBmb3IgdGhpcyB3aXphcmQgY29tcG9uZW50XHJcbiAgICpcclxuICAgKiBAcGFyYW0gbmF2aWdhdGlvbiBUaGUgdXBkYXRlZCBuYXZpZ2F0aW9uIG1vZGVcclxuICAgKi9cclxuICBwdWJsaWMgc2V0IG5hdmlnYXRpb24obmF2aWdhdGlvbjogTmF2aWdhdGlvbk1vZGUpIHtcclxuICAgIHRoaXMuX25hdmlnYXRpb24gPSBuYXZpZ2F0aW9uO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQ2hlY2tzIGlmIGEgZ2l2ZW4gaW5kZXggYHN0ZXBJbmRleGAgaXMgaW5zaWRlIHRoZSByYW5nZSBvZiBwb3NzaWJsZSB3aXphcmQgc3RlcHMgaW5zaWRlIHRoaXMgd2l6YXJkXHJcbiAgICpcclxuICAgKiBAcGFyYW0gc3RlcEluZGV4IFRoZSB0byBiZSBjaGVja2VkIGluZGV4IG9mIGEgc3RlcCBpbnNpZGUgdGhpcyB3aXphcmRcclxuICAgKiBAcmV0dXJucyBUcnVlIGlmIHRoZSBnaXZlbiBgc3RlcEluZGV4YCBpcyBjb250YWluZWQgaW5zaWRlIHRoaXMgd2l6YXJkLCBmYWxzZSBvdGhlcndpc2VcclxuICAgKi9cclxuICBwdWJsaWMgaGFzU3RlcChzdGVwSW5kZXg6IG51bWJlcik6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMud2l6YXJkU3RlcHMubGVuZ3RoID4gMCAmJiAwIDw9IHN0ZXBJbmRleCAmJiBzdGVwSW5kZXggPCB0aGlzLndpemFyZFN0ZXBzLmxlbmd0aDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENoZWNrcyBpZiB0aGlzIHdpemFyZCBoYXMgYSBwcmV2aW91cyBzdGVwLCBjb21wYXJlZCB0byB0aGUgY3VycmVudCBzdGVwXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyBUcnVlIGlmIHRoaXMgd2l6YXJkIGhhcyBhIHByZXZpb3VzIHN0ZXAgYmVmb3JlIHRoZSBjdXJyZW50IHN0ZXBcclxuICAgKi9cclxuICBwdWJsaWMgaGFzUHJldmlvdXNTdGVwKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMuaGFzU3RlcCh0aGlzLmN1cnJlbnRTdGVwSW5kZXggLSAxKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENoZWNrcyBpZiB0aGlzIHdpemFyZCBoYXMgYSBuZXh0IHN0ZXAsIGNvbXBhcmVkIHRvIHRoZSBjdXJyZW50IHN0ZXBcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIFRydWUgaWYgdGhpcyB3aXphcmQgaGFzIGEgbmV4dCBzdGVwIGFmdGVyIHRoZSBjdXJyZW50IHN0ZXBcclxuICAgKi9cclxuICBwdWJsaWMgaGFzTmV4dFN0ZXAoKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gdGhpcy5oYXNTdGVwKHRoaXMuY3VycmVudFN0ZXBJbmRleCArIDEpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQ2hlY2tzIGlmIHRoaXMgd2l6YXJkIGlzIGN1cnJlbnRseSBpbnNpZGUgaXRzIGxhc3Qgc3RlcFxyXG4gICAqXHJcbiAgICogQHJldHVybnMgVHJ1ZSBpZiB0aGUgd2l6YXJkIGlzIGN1cnJlbnRseSBpbnNpZGUgaXRzIGxhc3Qgc3RlcFxyXG4gICAqL1xyXG4gIHB1YmxpYyBpc0xhc3RTdGVwKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMud2l6YXJkU3RlcHMubGVuZ3RoID4gMCAmJiB0aGlzLmN1cnJlbnRTdGVwSW5kZXggPT09IHRoaXMud2l6YXJkU3RlcHMubGVuZ3RoIC0gMTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEZpbmRzIHRoZSBbW1dpemFyZFN0ZXBdXSBhdCB0aGUgZ2l2ZW4gaW5kZXggYHN0ZXBJbmRleGAuXHJcbiAgICogSWYgbm8gW1tXaXphcmRTdGVwXV0gZXhpc3RzIGF0IHRoZSBnaXZlbiBpbmRleCBhbiBFcnJvciBpcyB0aHJvd25cclxuICAgKlxyXG4gICAqIEBwYXJhbSBzdGVwSW5kZXggVGhlIGdpdmVuIGluZGV4XHJcbiAgICogQHJldHVybnMgVGhlIGZvdW5kIFtbV2l6YXJkU3RlcF1dIGF0IHRoZSBnaXZlbiBpbmRleCBgc3RlcEluZGV4YFxyXG4gICAqIEB0aHJvd3MgQW4gYEVycm9yYCBpcyB0aHJvd24sIGlmIHRoZSBnaXZlbiBpbmRleCBgc3RlcEluZGV4YCBkb2Vzbid0IGV4aXN0XHJcbiAgICovXHJcbiAgcHVibGljIGdldFN0ZXBBdEluZGV4KHN0ZXBJbmRleDogbnVtYmVyKTogV2l6YXJkU3RlcCB7XHJcbiAgICBpZiAoIXRoaXMuaGFzU3RlcChzdGVwSW5kZXgpKSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgYSBrbm93biBzdGVwLCBidXQgZ290IHN0ZXBJbmRleDogJHtzdGVwSW5kZXh9LmApO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0aGlzLndpemFyZFN0ZXBzW3N0ZXBJbmRleF07XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBGaW5kcyB0aGUgaW5kZXggb2YgdGhlIHN0ZXAgd2l0aCB0aGUgZ2l2ZW4gYHN0ZXBJZGAuXHJcbiAgICogSWYgbm8gc3RlcCB3aXRoIHRoZSBnaXZlbiBgc3RlcElkYCBleGlzdHMsIGAtMWAgaXMgcmV0dXJuZWRcclxuICAgKlxyXG4gICAqIEBwYXJhbSBzdGVwSWQgVGhlIGdpdmVuIHN0ZXAgaWRcclxuICAgKiBAcmV0dXJucyBUaGUgZm91bmQgaW5kZXggb2YgYSBzdGVwIHdpdGggdGhlIGdpdmVuIHN0ZXAgaWQsIG9yIGAtMWAgaWYgbm8gc3RlcCB3aXRoIHRoZSBnaXZlbiBpZCBpcyBpbmNsdWRlZCBpbiB0aGUgd2l6YXJkXHJcbiAgICovXHJcbiAgcHVibGljIGdldEluZGV4T2ZTdGVwV2l0aElkKHN0ZXBJZDogc3RyaW5nKTogbnVtYmVyIHtcclxuICAgIHJldHVybiB0aGlzLndpemFyZFN0ZXBzLmZpbmRJbmRleChzdGVwID0+IHN0ZXAuc3RlcElkID09PSBzdGVwSWQpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRmluZHMgdGhlIGluZGV4IG9mIHRoZSBnaXZlbiBbW1dpemFyZFN0ZXBdXSBgc3RlcGAuXHJcbiAgICogSWYgdGhlIGdpdmVuIFtbV2l6YXJkU3RlcF1dIGlzIG5vdCBjb250YWluZWQgaW5zaWRlIHRoaXMgd2l6YXJkLCBgLTFgIGlzIHJldHVybmVkXHJcbiAgICpcclxuICAgKiBAcGFyYW0gc3RlcCBUaGUgZ2l2ZW4gW1tXaXphcmRTdGVwXV1cclxuICAgKiBAcmV0dXJucyBUaGUgZm91bmQgaW5kZXggb2YgYHN0ZXBgIG9yIGAtMWAgaWYgdGhlIHN0ZXAgaXMgbm90IGluY2x1ZGVkIGluIHRoZSB3aXphcmRcclxuICAgKi9cclxuICBwdWJsaWMgZ2V0SW5kZXhPZlN0ZXAoc3RlcDogV2l6YXJkU3RlcCk6IG51bWJlciB7XHJcbiAgICByZXR1cm4gdGhpcy53aXphcmRTdGVwcy5pbmRleE9mKHN0ZXApO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQ2FsY3VsYXRlcyB0aGUgY29ycmVjdCBbW01vdmluZ0RpcmVjdGlvbl1dIHZhbHVlIGZvciBhIGdpdmVuIGBkZXN0aW5hdGlvblN0ZXBgIGNvbXBhcmVkIHRvIHRoZSBgY3VycmVudFN0ZXBJbmRleGAuXHJcbiAgICpcclxuICAgKiBAcGFyYW0gZGVzdGluYXRpb25TdGVwIFRoZSBnaXZlbiBkZXN0aW5hdGlvbiBzdGVwXHJcbiAgICogQHJldHVybnMgVGhlIGNhbGN1bGF0ZWQgW1tNb3ZpbmdEaXJlY3Rpb25dXVxyXG4gICAqL1xyXG4gIHB1YmxpYyBnZXRNb3ZpbmdEaXJlY3Rpb24oZGVzdGluYXRpb25TdGVwOiBudW1iZXIpOiBNb3ZpbmdEaXJlY3Rpb24ge1xyXG4gICAgbGV0IG1vdmluZ0RpcmVjdGlvbjogTW92aW5nRGlyZWN0aW9uO1xyXG5cclxuICAgIGlmIChkZXN0aW5hdGlvblN0ZXAgPiB0aGlzLmN1cnJlbnRTdGVwSW5kZXgpIHtcclxuICAgICAgbW92aW5nRGlyZWN0aW9uID0gTW92aW5nRGlyZWN0aW9uLkZvcndhcmRzO1xyXG4gICAgfSBlbHNlIGlmIChkZXN0aW5hdGlvblN0ZXAgPCB0aGlzLmN1cnJlbnRTdGVwSW5kZXgpIHtcclxuICAgICAgbW92aW5nRGlyZWN0aW9uID0gTW92aW5nRGlyZWN0aW9uLkJhY2t3YXJkcztcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIG1vdmluZ0RpcmVjdGlvbiA9IE1vdmluZ0RpcmVjdGlvbi5TdGF5O1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBtb3ZpbmdEaXJlY3Rpb247XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDaGVja3MsIHdoZXRoZXIgYSB3aXphcmQgc3RlcCwgYXMgZGVmaW5lZCBieSB0aGUgZ2l2ZW4gZGVzdGluYXRpb24gaW5kZXgsIGNhbiBiZSB0cmFuc2l0aW9uZWQgdG8uXHJcbiAgICpcclxuICAgKiBUaGlzIG1ldGhvZCBjb250cm9scyBuYXZpZ2F0aW9uIGJ5IFtbZ29Ub1N0ZXBdXSwgW1tnb1RvUHJldmlvdXNTdGVwXV0sIGFuZCBbW2dvVG9OZXh0U3RlcF1dIGRpcmVjdGl2ZXMuXHJcbiAgICogTmF2aWdhdGlvbiBieSBuYXZpZ2F0aW9uIGJhciBpcyBnb3Zlcm5lZCBieSBbW2lzTmF2aWdhYmxlXV0uXHJcbiAgICpcclxuICAgKiBAcGFyYW0gZGVzdGluYXRpb25JbmRleCBUaGUgaW5kZXggb2YgdGhlIGRlc3RpbmF0aW9uIHN0ZXBcclxuICAgKiBAcmV0dXJucyBBIFtbUHJvbWlzZV1dIGNvbnRhaW5pbmcgYHRydWVgLCBpZiB0aGUgZGVzdGluYXRpb24gc3RlcCBjYW4gYmUgdHJhbnNpdGlvbmVkIHRvIGFuZCBmYWxzZSBvdGhlcndpc2VcclxuICAgKi9cclxuICBwdWJsaWMgY2FuR29Ub1N0ZXAoZGVzdGluYXRpb25JbmRleDogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XHJcbiAgICByZXR1cm4gdGhpcy5uYXZpZ2F0aW9uLmNhbkdvVG9TdGVwKHRoaXMsIGRlc3RpbmF0aW9uSW5kZXgpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogVHJpZXMgdG8gdHJhbnNpdGlvbiB0byB0aGUgd2l6YXJkIHN0ZXAsIGFzIGRlbm90ZWQgYnkgdGhlIGdpdmVuIGRlc3RpbmF0aW9uIGluZGV4LlxyXG4gICAqXHJcbiAgICogTm90ZTogWW91IGRvIG5vdCBoYXZlIHRvIGNhbGwgW1tjYW5Hb1RvU3RlcF1dIGJlZm9yZSBjYWxsaW5nIFtbZ29Ub1N0ZXBdXS5cclxuICAgKiBUaGUgW1tjYW5Hb1RvU3RlcF1dIG1ldGhvZCB3aWxsIGJlIGNhbGxlZCBhdXRvbWF0aWNhbGx5LlxyXG4gICAqXHJcbiAgICogQHBhcmFtIGRlc3RpbmF0aW9uSW5kZXggVGhlIGluZGV4IG9mIHRoZSBkZXN0aW5hdGlvbiB3aXphcmQgc3RlcCwgd2hpY2ggc2hvdWxkIGJlIGVudGVyZWRcclxuICAgKiBAcGFyYW0gcHJlRmluYWxpemUgQW4gZXZlbnQgZW1pdHRlciwgdG8gYmUgY2FsbGVkIGJlZm9yZSB0aGUgc3RlcCBoYXMgYmVlbiB0cmFuc2l0aW9uZWRcclxuICAgKiBAcGFyYW0gcG9zdEZpbmFsaXplIEFuIGV2ZW50IGVtaXR0ZXIsIHRvIGJlIGNhbGxlZCBhZnRlciB0aGUgc3RlcCBoYXMgYmVlbiB0cmFuc2l0aW9uZWRcclxuICAgKi9cclxuICBwdWJsaWMgZ29Ub1N0ZXAoZGVzdGluYXRpb25JbmRleDogbnVtYmVyLCBwcmVGaW5hbGl6ZT86IEV2ZW50RW1pdHRlcjx2b2lkPiwgcG9zdEZpbmFsaXplPzogRXZlbnRFbWl0dGVyPHZvaWQ+KTogdm9pZCB7XHJcbiAgICByZXR1cm4gdGhpcy5uYXZpZ2F0aW9uLmdvVG9TdGVwKHRoaXMsIGRlc3RpbmF0aW9uSW5kZXgsIHByZUZpbmFsaXplLCBwb3N0RmluYWxpemUpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogVHJpZXMgdG8gdHJhbnNpdGlvbiB0aGUgd2l6YXJkIHRvIHRoZSBwcmV2aW91cyBzdGVwXHJcbiAgICpcclxuICAgKiBAcGFyYW0gcHJlRmluYWxpemUgQW4gZXZlbnQgZW1pdHRlciwgdG8gYmUgY2FsbGVkIGJlZm9yZSB0aGUgc3RlcCBoYXMgYmVlbiB0cmFuc2l0aW9uZWRcclxuICAgKiBAcGFyYW0gcG9zdEZpbmFsaXplIEFuIGV2ZW50IGVtaXR0ZXIsIHRvIGJlIGNhbGxlZCBhZnRlciB0aGUgc3RlcCBoYXMgYmVlbiB0cmFuc2l0aW9uZWRcclxuICAgKi9cclxuICBwdWJsaWMgZ29Ub1ByZXZpb3VzU3RlcChwcmVGaW5hbGl6ZT86IEV2ZW50RW1pdHRlcjx2b2lkPiwgcG9zdEZpbmFsaXplPzogRXZlbnRFbWl0dGVyPHZvaWQ+KTogdm9pZCB7XHJcbiAgICByZXR1cm4gdGhpcy5uYXZpZ2F0aW9uLmdvVG9TdGVwKHRoaXMsIHRoaXMuY3VycmVudFN0ZXBJbmRleCAtIDEsIHByZUZpbmFsaXplLCBwb3N0RmluYWxpemUpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogVHJpZXMgdG8gdHJhbnNpdGlvbiB0aGUgd2l6YXJkIHRvIHRoZSBuZXh0IHN0ZXBcclxuICAgKlxyXG4gICAqIEBwYXJhbSBwcmVGaW5hbGl6ZSBBbiBldmVudCBlbWl0dGVyLCB0byBiZSBjYWxsZWQgYmVmb3JlIHRoZSBzdGVwIGhhcyBiZWVuIHRyYW5zaXRpb25lZFxyXG4gICAqIEBwYXJhbSBwb3N0RmluYWxpemUgQW4gZXZlbnQgZW1pdHRlciwgdG8gYmUgY2FsbGVkIGFmdGVyIHRoZSBzdGVwIGhhcyBiZWVuIHRyYW5zaXRpb25lZFxyXG4gICAqL1xyXG4gIHB1YmxpYyBnb1RvTmV4dFN0ZXAocHJlRmluYWxpemU/OiBFdmVudEVtaXR0ZXI8dm9pZD4sIHBvc3RGaW5hbGl6ZT86IEV2ZW50RW1pdHRlcjx2b2lkPik6IHZvaWQge1xyXG4gICAgcmV0dXJuIHRoaXMubmF2aWdhdGlvbi5nb1RvU3RlcCh0aGlzLCB0aGlzLmN1cnJlbnRTdGVwSW5kZXggKyAxLCBwcmVGaW5hbGl6ZSwgcG9zdEZpbmFsaXplKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENoZWNrcywgd2hldGhlciB0aGUgd2l6YXJkIHN0ZXAsIGxvY2F0ZWQgYXQgdGhlIGdpdmVuIGluZGV4LCBjYW4gYmUgbmF2aWdhdGVkIHRvIHVzaW5nIHRoZSBuYXZpZ2F0aW9uIGJhci5cclxuICAgKlxyXG4gICAqIEBwYXJhbSBkZXN0aW5hdGlvbkluZGV4IFRoZSBpbmRleCBvZiB0aGUgZGVzdGluYXRpb24gc3RlcFxyXG4gICAqIEByZXR1cm5zIFRydWUgaWYgdGhlIHN0ZXAgY2FuIGJlIG5hdmlnYXRlZCB0bywgZmFsc2Ugb3RoZXJ3aXNlXHJcbiAgICovXHJcbiAgcHVibGljIGlzTmF2aWdhYmxlKGRlc3RpbmF0aW9uSW5kZXg6IG51bWJlcik6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMubmF2aWdhdGlvbi5pc05hdmlnYWJsZSh0aGlzLCBkZXN0aW5hdGlvbkluZGV4KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlc2V0cyB0aGUgc3RhdGUgb2YgdGhpcyB3aXphcmQuXHJcbiAgICovXHJcbiAgcHVibGljIHJlc2V0KCk6IHZvaWQge1xyXG4gICAgdGhpcy5uYXZpZ2F0aW9uLnJlc2V0KHRoaXMpO1xyXG4gIH1cclxufVxyXG4iLCI8YXctd2l6YXJkLW5hdmlnYXRpb24tYmFyXHJcbiAgKm5nSWY9XCJuYXZCYXJMb2NhdGlvbiA9PSAndG9wJyB8fCBuYXZCYXJMb2NhdGlvbiA9PSAnbGVmdCdcIlxyXG4gIFtuZ0NsYXNzXT1cIntcclxuICAgICd2ZXJ0aWNhbCc6IG5hdkJhckxvY2F0aW9uID09ICdsZWZ0JyxcclxuICAgICdob3Jpem9udGFsJzogbmF2QmFyTG9jYXRpb24gPT0gJ3RvcCcsXHJcbiAgICAnc21hbGwnOiBuYXZCYXJMYXlvdXQgPT0gJ3NtYWxsJyxcclxuICAgICdsYXJnZS1maWxsZWQnOiBuYXZCYXJMYXlvdXQgPT0gJ2xhcmdlLWZpbGxlZCcsXHJcbiAgICAnbGFyZ2UtZmlsbGVkLXN5bWJvbHMnOiBuYXZCYXJMYXlvdXQgPT0gJ2xhcmdlLWZpbGxlZC1zeW1ib2xzJyxcclxuICAgICdsYXJnZS1lbXB0eSc6IG5hdkJhckxheW91dCA9PSAnbGFyZ2UtZW1wdHknLFxyXG4gICAgJ2xhcmdlLWVtcHR5LXN5bWJvbHMnOiBuYXZCYXJMYXlvdXQgPT0gJ2xhcmdlLWVtcHR5LXN5bWJvbHMnXHJcbiAgfVwiPlxyXG48L2F3LXdpemFyZC1uYXZpZ2F0aW9uLWJhcj5cclxuXHJcbjxkaXYgW25nQ2xhc3NdPVwie1xyXG4gICd3aXphcmQtc3RlcHMnOiB0cnVlLFxyXG4gICd2ZXJ0aWNhbCc6IG5hdkJhckxvY2F0aW9uID09ICdsZWZ0JyB8fCBuYXZCYXJMb2NhdGlvbiA9PSAncmlnaHQnLFxyXG4gICdob3Jpem9udGFsJzogbmF2QmFyTG9jYXRpb24gPT0gJ3RvcCcgfHwgbmF2QmFyTG9jYXRpb24gPT0gJ2JvdHRvbSdcclxufVwiPlxyXG4gIDxuZy1jb250ZW50PjwvbmctY29udGVudD5cclxuPC9kaXY+XHJcblxyXG48YXctd2l6YXJkLW5hdmlnYXRpb24tYmFyXHJcbiAgKm5nSWY9XCJuYXZCYXJMb2NhdGlvbiA9PSAnYm90dG9tJyB8fCBuYXZCYXJMb2NhdGlvbiA9PSAncmlnaHQnXCJcclxuICBbbmdDbGFzc109XCJ7XHJcbiAgICAndmVydGljYWwnOiBuYXZCYXJMb2NhdGlvbiA9PSAncmlnaHQnLFxyXG4gICAgJ2hvcml6b250YWwnOiBuYXZCYXJMb2NhdGlvbiA9PSAnYm90dG9tJyxcclxuICAgICdzbWFsbCc6IG5hdkJhckxheW91dCA9PSAnc21hbGwnLFxyXG4gICAgJ2xhcmdlLWZpbGxlZCc6IG5hdkJhckxheW91dCA9PSAnbGFyZ2UtZmlsbGVkJyxcclxuICAgICdsYXJnZS1maWxsZWQtc3ltYm9scyc6IG5hdkJhckxheW91dCA9PSAnbGFyZ2UtZmlsbGVkLXN5bWJvbHMnLFxyXG4gICAgJ2xhcmdlLWVtcHR5JzogbmF2QmFyTGF5b3V0ID09ICdsYXJnZS1lbXB0eScsXHJcbiAgICAnbGFyZ2UtZW1wdHktc3ltYm9scyc6IG5hdkJhckxheW91dCA9PSAnbGFyZ2UtZW1wdHktc3ltYm9scydcclxuICB9XCI+XHJcbjwvYXctd2l6YXJkLW5hdmlnYXRpb24tYmFyPlxyXG4iXX0=