ng-wizard
Version:
Angular ng-wizard - Angular wizard | stepper
439 lines • 65.9 kB
JavaScript
import { Component, ContentChildren, Input, Output, EventEmitter, } from '@angular/core';
import { of, isObservable } from 'rxjs';
import { STEP_STATUS, STEP_STATE, TOOLBAR_POSITION, STEP_DIRECTION, STEP_POSITION, } from '../../utils/enums';
import { merge } from '../../utils/functions';
import { NgWizardStep, } from '../../utils/interfaces';
import * as i0 from "@angular/core";
import * as i1 from "../../services/ng-wizard-data.service";
import * as i2 from "@angular/common";
export class NgWizardComponent {
ngWizardDataService;
steps;
_pConfig;
get pConfig() {
return this._pConfig || {};
}
set pConfig(config) {
this._pConfig = config;
}
config;
stepChanged = new EventEmitter();
themeChanged = new EventEmitter();
reset = new EventEmitter();
styles = {};
showToolbarTop = false;
showPreviousButton = false;
showNextButton = false;
showToolbarBottom = false;
showExtraButtons = false;
currentStepIndex = null; // Active step index
currentStep; // Active step
resetWizardWatcher;
showNextStepWatcher;
showPreviousStepWatcher;
showStepWatcher;
setThemeWatcher;
constructor(ngWizardDataService) {
this.ngWizardDataService = ngWizardDataService;
}
ngAfterContentInit() {
this._backupStepStates();
this._init();
// Set toolbar
this._setToolbar();
// Assign plugin events
this._setEvents();
this.resetWizardWatcher = this.ngWizardDataService.resetWizard$.subscribe(() => this._reset());
this.showNextStepWatcher = this.ngWizardDataService.showNextStep$.subscribe(() => this._showNextStep());
this.showPreviousStepWatcher =
this.ngWizardDataService.showPreviousStep$.subscribe(() => this._showPreviousStep());
this.showStepWatcher = this.ngWizardDataService.showStep$.subscribe((index) => this._showStep(index));
this.setThemeWatcher = this.ngWizardDataService.setTheme$.subscribe((theme) => this._setTheme(theme));
}
_init() {
// set config
let defaultConfig = this.ngWizardDataService.getDefaultConfig();
this.config = merge(defaultConfig, this.pConfig);
// set step states
this._initSteps();
// Set the elements
this._initStyles();
// Show the initial step
this._showStep(this.config.selected);
}
_initSteps() {
this.steps.forEach((step, index) => {
step.index = index;
step.status = step.status || STEP_STATUS.untouched;
step.state = step.state || STEP_STATE.normal;
});
// Mark previous steps of the active step as done
if (this.config.selected > 0 &&
this.config.anchorSettings.markDoneStep &&
this.config.anchorSettings.markAllPreviousStepsAsDone) {
this.steps.forEach((step) => {
if (step.state != STEP_STATE.disabled &&
step.state != STEP_STATE.hidden) {
step.status =
step.index < this.config.selected ? STEP_STATUS.done : step.status;
}
});
}
}
_backupStepStates() {
this.steps.forEach((step) => {
step.initialStatus = step.status;
step.initialState = step.state;
});
}
_restoreStepStates() {
this.steps.forEach((step) => {
step.status = step.initialStatus;
step.state = step.initialState;
});
}
// PRIVATE FUNCTIONS
_initStyles() {
// Set the main element
this.styles.main = 'ng-wizard-main ng-wizard-theme-' + this.config.theme;
// Set anchor elements
this.styles.step = 'nav-item'; // li
// Make the anchor clickable
if (this.config.anchorSettings.enableAllAnchors &&
this.config.anchorSettings.anchorClickable) {
this.styles.step += ' clickable';
}
// Set the toolbar styles
this.styles.toolbarTop =
'btn-toolbar ng-wizard-toolbar ng-wizard-toolbar-top justify-content-' +
this.config.toolbarSettings.toolbarButtonPosition;
this.styles.toolbarBottom =
'btn-toolbar ng-wizard-toolbar ng-wizard-toolbar-bottom justify-content-' +
this.config.toolbarSettings.toolbarButtonPosition;
// Set previous&next buttons
this.styles.previousButton = 'btn btn-secondary ng-wizard-btn-prev';
this.styles.nextButton = 'btn btn-secondary ng-wizard-btn-next';
}
_setToolbar() {
this.showToolbarTop =
this.config.toolbarSettings.toolbarPosition == TOOLBAR_POSITION.top ||
this.config.toolbarSettings.toolbarPosition == TOOLBAR_POSITION.both;
this.showToolbarBottom =
this.config.toolbarSettings.toolbarPosition == TOOLBAR_POSITION.bottom ||
this.config.toolbarSettings.toolbarPosition == TOOLBAR_POSITION.both;
this.showPreviousButton = this.config.toolbarSettings.showPreviousButton;
this.showNextButton = this.config.toolbarSettings.showNextButton;
this.showExtraButtons =
this.config.toolbarSettings.toolbarExtraButtons &&
this.config.toolbarSettings.toolbarExtraButtons.length > 0;
}
_setEvents() {
//TODO: keyNavigation
// Keyboard navigation event
if (this.config.keyNavigation) {
// $(document).keyup(function (e) {
// mi._keyNav(e);
// });
}
}
_getStepCssClass(selectedStep) {
let stepClass = this.styles.step;
switch (selectedStep.state) {
case STEP_STATE.disabled:
stepClass += ' disabled';
break;
case STEP_STATE.error:
stepClass += ' danger';
break;
case STEP_STATE.hidden:
stepClass += ' hidden';
break;
}
switch (selectedStep.status) {
case STEP_STATUS.done:
stepClass += ' done';
break;
case STEP_STATUS.active:
stepClass += ' active';
break;
}
return stepClass;
}
_showSelectedStep(event, selectedStep) {
event.preventDefault();
if (!this.config.anchorSettings.anchorClickable) {
return;
}
if (!this.config.anchorSettings.enableAnchorOnDoneStep &&
selectedStep.status == STEP_STATUS.done) {
return;
}
if (selectedStep.index != this.currentStepIndex) {
if (this.config.anchorSettings.enableAllAnchors &&
this.config.anchorSettings.anchorClickable) {
this._showStep(selectedStep.index);
}
else {
if (selectedStep.status == STEP_STATUS.done) {
this._showStep(selectedStep.index);
}
}
}
}
_showNextStep(event) {
if (event) {
event.preventDefault();
}
// Find the next not disabled & hidden step
let filteredSteps = this.steps.filter((step) => {
return (step.index >
(this.currentStepIndex == null ? -1 : this.currentStepIndex) &&
step.state != STEP_STATE.disabled &&
step.state != STEP_STATE.hidden);
});
if (filteredSteps.length == 0) {
if (!this.config.cycleSteps) {
return;
}
this._showStep(0);
}
else {
this._showStep(filteredSteps.shift().index);
}
}
_showPreviousStep(event) {
if (event) {
event.preventDefault();
}
// Find the previous not disabled & hidden step
let filteredSteps = this.steps.filter((step) => {
return (step.index <
(this.currentStepIndex == null && this.config.cycleSteps
? this.steps.length
: this.currentStepIndex) &&
step.state != STEP_STATE.disabled &&
step.state != STEP_STATE.hidden);
});
if (filteredSteps.length == 0) {
if (!this.config.cycleSteps) {
return;
}
this._showStep(this.steps.length - 1);
}
else {
this._showStep(filteredSteps.pop().index);
}
}
_showStep(selectedStepIndex) {
// If step not found, skip
if (selectedStepIndex >= this.steps.length || selectedStepIndex < 0) {
return;
}
// If current step is requested again, skip
if (selectedStepIndex == this.currentStepIndex) {
return;
}
let selectedStep = this.steps.toArray()[selectedStepIndex];
// If it is a disabled or hidden step, skip
if (selectedStep.state == STEP_STATE.disabled ||
selectedStep.state == STEP_STATE.hidden) {
return;
}
this._showLoader();
this._isStepChangeValid(selectedStep, this.currentStep && this.currentStep.canExit)
.toPromise()
.then((isValid) => {
if (isValid) {
return this._isStepChangeValid(selectedStep, selectedStep.canEnter).toPromise();
}
return of(isValid).toPromise();
})
.then((isValid) => {
if (isValid) {
// Load step content
this._loadStepContent(selectedStep);
}
})
.finally(() => this._hideLoader());
}
_isStepChangeValid(selectedStep, condition) {
if (typeof condition === typeof true) {
return of(condition);
}
else if (condition instanceof Function) {
let direction = this._getStepDirection(selectedStep.index);
let result = condition({
direction: direction,
fromStep: this.currentStep,
toStep: selectedStep,
});
if (isObservable(result)) {
return result;
}
else if (typeof result === typeof true) {
return of(result);
}
else {
return of(false);
}
}
return of(true);
}
_loadStepContent(selectedStep) {
// Update controls
this._setAnchor(selectedStep);
// Set the buttons based on the step
this._setButtons(selectedStep.index);
// Trigger "stepChanged" event
const args = {
step: selectedStep,
previousStep: this.currentStep,
direction: this._getStepDirection(selectedStep.index),
position: this._getStepPosition(selectedStep.index),
};
this.stepChanged.emit(args);
this.ngWizardDataService.stepChanged(args);
// Update the current index
this.currentStepIndex = selectedStep.index;
this.currentStep = selectedStep;
}
_setAnchor(selectedStep) {
// Current step anchor > Remove other classes and add done class
if (this.currentStep) {
this.currentStep.status = STEP_STATUS.untouched;
if (this.config.anchorSettings.markDoneStep) {
this.currentStep.status = STEP_STATUS.done;
if (this.config.anchorSettings.removeDoneStepOnNavigateBack) {
this.steps.forEach((step) => {
if (step.index > selectedStep.index) {
step.status = STEP_STATUS.untouched;
}
});
}
}
}
// Next step anchor > Remove other classes and add active class
selectedStep.status = STEP_STATUS.active;
}
_setButtons(index) {
// Previous/Next Button enable/disable based on step
if (!this.config.cycleSteps) {
if (0 >= index) {
this.styles.previousButton =
'btn btn-secondary ng-wizard-btn-prev disabled';
}
else {
this.styles.previousButton = 'btn btn-secondary ng-wizard-btn-prev';
}
if (this.steps.length - 1 <= index) {
this.styles.nextButton =
'btn btn-secondary ng-wizard-btn-next disabled';
}
else {
this.styles.nextButton = 'btn btn-secondary ng-wizard-btn-next';
}
}
}
_extraButtonClicked(button) {
if (button.event) {
button.event();
}
}
// HELPER FUNCTIONS
_keyNav(event) {
// Keyboard navigation
switch (event.which) {
case 37:
// left
this._showPreviousStep(event);
event.preventDefault();
break;
case 39:
// right
this._showNextStep(event);
event.preventDefault();
break;
default:
return; // exit this handler for other keys
}
}
_showLoader() {
this.styles.main =
'ng-wizard-main ng-wizard-theme-' +
this.config.theme +
' ng-wizard-loading';
}
_hideLoader() {
this.styles.main = 'ng-wizard-main ng-wizard-theme-' + this.config.theme;
}
_getStepDirection(selectedStepIndex) {
return this.currentStepIndex != null &&
this.currentStepIndex != selectedStepIndex
? this.currentStepIndex < selectedStepIndex
? STEP_DIRECTION.forward
: STEP_DIRECTION.backward
: null;
}
_getStepPosition(selectedStepIndex) {
return selectedStepIndex == 0
? STEP_POSITION.first
: selectedStepIndex == this.steps.length - 1
? STEP_POSITION.final
: STEP_POSITION.middle;
}
// PUBLIC FUNCTIONS
_setTheme(theme) {
if (this.config.theme == theme) {
return;
}
this.config.theme = theme;
this.styles.main = 'ng-wizard-main ng-wizard-theme-' + this.config.theme;
// Trigger "themeChanged" event
this.themeChanged.emit(this.config.theme);
}
_reset() {
// Reset all elements and classes
this.currentStepIndex = null;
this.currentStep = null;
this._restoreStepStates();
this._init();
// Trigger "reset" event
this.reset.emit();
}
ngOnDestroy() {
if (this.resetWizardWatcher) {
this.resetWizardWatcher.unsubscribe();
}
if (this.showNextStepWatcher) {
this.showNextStepWatcher.unsubscribe();
}
if (this.showPreviousStepWatcher) {
this.showPreviousStepWatcher.unsubscribe();
}
if (this.showStepWatcher) {
this.showStepWatcher.unsubscribe();
}
if (this.setThemeWatcher) {
this.setThemeWatcher.unsubscribe();
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: NgWizardComponent, deps: [{ token: i1.NgWizardDataService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.12", type: NgWizardComponent, selector: "ng-wizard", inputs: { pConfig: ["config", "pConfig"] }, outputs: { stepChanged: "stepChanged", themeChanged: "themeChanged", reset: "reset" }, queries: [{ propertyName: "steps", predicate: NgWizardStep }], ngImport: i0, template: "<div id=\"ngwizard\" [ngClass]=\"styles.main\">\r\n <ul class=\"nav nav-tabs step-anchor\">\r\n <li\r\n *ngFor=\"let step of steps; let i = index\"\r\n [ngClass]=\"_getStepCssClass(step)\"\r\n >\r\n <a\r\n href=\"#step-{{ i }}\"\r\n (click)=\"_showSelectedStep($event, step)\"\r\n *ngIf=\"!step.isHidden\"\r\n class=\"nav-link\"\r\n >{{ step.title }}<br /><small>{{ step.description }}</small></a\r\n >\r\n </li>\r\n </ul>\r\n\r\n <div *ngIf=\"showToolbarTop\" [ngClass]=\"styles.toolbarTop\">\r\n <div class=\"btn-group mr-2 ng-wizard-btn-group\" role=\"group\">\r\n <button\r\n *ngIf=\"showPreviousButton\"\r\n [ngClass]=\"styles.previousButton\"\r\n type=\"button\"\r\n (click)=\"_showPreviousStep($event)\"\r\n >\r\n {{ config!.lang!.previous }}\r\n </button>\r\n <button\r\n *ngIf=\"showNextButton\"\r\n [ngClass]=\"styles.nextButton\"\r\n type=\"button\"\r\n (click)=\"_showNextStep($event)\"\r\n >\r\n {{ config!.lang!.next }}\r\n </button>\r\n </div>\r\n\r\n <div\r\n *ngIf=\"showExtraButtons\"\r\n class=\"btn-group mr-2 ng-wizard-btn-group-extra\"\r\n role=\"group\"\r\n >\r\n <button\r\n *ngFor=\"\r\n let button of config!.toolbarSettings!.toolbarExtraButtons;\r\n let j = index\r\n \"\r\n [ngClass]=\"button.class\"\r\n type=\"button\"\r\n (click)=\"_extraButtonClicked(button)\"\r\n >\r\n {{ button.text }}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"ng-wizard-container tab-content\">\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n <div *ngIf=\"showToolbarBottom\" [ngClass]=\"styles.toolbarBottom\">\r\n <div class=\"btn-group mr-2 ng-wizard-btn-group\" role=\"group\">\r\n <button\r\n *ngIf=\"showPreviousButton\"\r\n [ngClass]=\"styles.previousButton\"\r\n type=\"button\"\r\n (click)=\"_showPreviousStep($event)\"\r\n >\r\n {{ config!.lang!.previous }}\r\n </button>\r\n <button\r\n *ngIf=\"showNextButton\"\r\n [ngClass]=\"styles.nextButton\"\r\n type=\"button\"\r\n (click)=\"_showNextStep($event)\"\r\n >\r\n {{ config!.lang!.next }}\r\n </button>\r\n </div>\r\n\r\n <div\r\n *ngIf=\"showExtraButtons\"\r\n class=\"btn-group mr-2 ng-wizard-btn-group-extra\"\r\n role=\"group\"\r\n >\r\n <button\r\n *ngFor=\"\r\n let button of config!.toolbarSettings!.toolbarExtraButtons;\r\n let j = index\r\n \"\r\n [ngClass]=\"button.class\"\r\n type=\"button\"\r\n (click)=\"_extraButtonClicked(button)\"\r\n >\r\n {{ button.text }}\r\n </button>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: NgWizardComponent, decorators: [{
type: Component,
args: [{ selector: 'ng-wizard', template: "<div id=\"ngwizard\" [ngClass]=\"styles.main\">\r\n <ul class=\"nav nav-tabs step-anchor\">\r\n <li\r\n *ngFor=\"let step of steps; let i = index\"\r\n [ngClass]=\"_getStepCssClass(step)\"\r\n >\r\n <a\r\n href=\"#step-{{ i }}\"\r\n (click)=\"_showSelectedStep($event, step)\"\r\n *ngIf=\"!step.isHidden\"\r\n class=\"nav-link\"\r\n >{{ step.title }}<br /><small>{{ step.description }}</small></a\r\n >\r\n </li>\r\n </ul>\r\n\r\n <div *ngIf=\"showToolbarTop\" [ngClass]=\"styles.toolbarTop\">\r\n <div class=\"btn-group mr-2 ng-wizard-btn-group\" role=\"group\">\r\n <button\r\n *ngIf=\"showPreviousButton\"\r\n [ngClass]=\"styles.previousButton\"\r\n type=\"button\"\r\n (click)=\"_showPreviousStep($event)\"\r\n >\r\n {{ config!.lang!.previous }}\r\n </button>\r\n <button\r\n *ngIf=\"showNextButton\"\r\n [ngClass]=\"styles.nextButton\"\r\n type=\"button\"\r\n (click)=\"_showNextStep($event)\"\r\n >\r\n {{ config!.lang!.next }}\r\n </button>\r\n </div>\r\n\r\n <div\r\n *ngIf=\"showExtraButtons\"\r\n class=\"btn-group mr-2 ng-wizard-btn-group-extra\"\r\n role=\"group\"\r\n >\r\n <button\r\n *ngFor=\"\r\n let button of config!.toolbarSettings!.toolbarExtraButtons;\r\n let j = index\r\n \"\r\n [ngClass]=\"button.class\"\r\n type=\"button\"\r\n (click)=\"_extraButtonClicked(button)\"\r\n >\r\n {{ button.text }}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"ng-wizard-container tab-content\">\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n <div *ngIf=\"showToolbarBottom\" [ngClass]=\"styles.toolbarBottom\">\r\n <div class=\"btn-group mr-2 ng-wizard-btn-group\" role=\"group\">\r\n <button\r\n *ngIf=\"showPreviousButton\"\r\n [ngClass]=\"styles.previousButton\"\r\n type=\"button\"\r\n (click)=\"_showPreviousStep($event)\"\r\n >\r\n {{ config!.lang!.previous }}\r\n </button>\r\n <button\r\n *ngIf=\"showNextButton\"\r\n [ngClass]=\"styles.nextButton\"\r\n type=\"button\"\r\n (click)=\"_showNextStep($event)\"\r\n >\r\n {{ config!.lang!.next }}\r\n </button>\r\n </div>\r\n\r\n <div\r\n *ngIf=\"showExtraButtons\"\r\n class=\"btn-group mr-2 ng-wizard-btn-group-extra\"\r\n role=\"group\"\r\n >\r\n <button\r\n *ngFor=\"\r\n let button of config!.toolbarSettings!.toolbarExtraButtons;\r\n let j = index\r\n \"\r\n [ngClass]=\"button.class\"\r\n type=\"button\"\r\n (click)=\"_extraButtonClicked(button)\"\r\n >\r\n {{ button.text }}\r\n </button>\r\n </div>\r\n </div>\r\n</div>\r\n" }]
}], ctorParameters: () => [{ type: i1.NgWizardDataService }], propDecorators: { steps: [{
type: ContentChildren,
args: [NgWizardStep]
}], pConfig: [{
type: Input,
args: ['config']
}], stepChanged: [{
type: Output
}], themeChanged: [{
type: Output
}], reset: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctd2l6YXJkLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25nLXdpemFyZC9zcmMvbGliL2NvbXBvbmVudHMvbmctd2l6YXJkL25nLXdpemFyZC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZy13aXphcmQvc3JjL2xpYi9jb21wb25lbnRzL25nLXdpemFyZC9uZy13aXphcmQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFHVCxlQUFlLEVBRWYsS0FBSyxFQUNMLE1BQU0sRUFDTixZQUFZLEdBQ2IsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFnQixFQUFFLEVBQWMsWUFBWSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBRWxFLE9BQU8sRUFFTCxXQUFXLEVBQ1gsVUFBVSxFQUNWLGdCQUFnQixFQUNoQixjQUFjLEVBQ2QsYUFBYSxHQUNkLE1BQU0sbUJBQW1CLENBQUM7QUFDM0IsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzlDLE9BQU8sRUFHTCxZQUFZLEdBR2IsTUFBTSx3QkFBd0IsQ0FBQzs7OztBQU9oQyxNQUFNLE9BQU8saUJBQWlCO0lBMkNSO0lBekNiLEtBQUssQ0FBMEI7SUFFdEMsUUFBUSxDQUFpQjtJQUN6QixJQUFJLE9BQU87UUFDVCxPQUFPLElBQUksQ0FBQyxRQUFRLElBQUksRUFBRSxDQUFDO0lBQzdCLENBQUM7SUFFRCxJQUNJLE9BQU8sQ0FBQyxNQUFzQjtRQUNoQyxJQUFJLENBQUMsUUFBUSxHQUFHLE1BQU0sQ0FBQztJQUN6QixDQUFDO0lBRUQsTUFBTSxDQUFpQjtJQUViLFdBQVcsR0FBRyxJQUFJLFlBQVksRUFBbUIsQ0FBQztJQUNsRCxZQUFZLEdBQUcsSUFBSSxZQUFZLEVBQVMsQ0FBQztJQUN6QyxLQUFLLEdBQUcsSUFBSSxZQUFZLEVBQVEsQ0FBQztJQUUzQyxNQUFNLEdBT0YsRUFBRSxDQUFDO0lBRVAsY0FBYyxHQUFZLEtBQUssQ0FBQztJQUNoQyxrQkFBa0IsR0FBWSxLQUFLLENBQUM7SUFDcEMsY0FBYyxHQUFZLEtBQUssQ0FBQztJQUNoQyxpQkFBaUIsR0FBWSxLQUFLLENBQUM7SUFDbkMsZ0JBQWdCLEdBQVksS0FBSyxDQUFDO0lBQ2xDLGdCQUFnQixHQUFXLElBQUksQ0FBQyxDQUFDLG9CQUFvQjtJQUNyRCxXQUFXLENBQWUsQ0FBQyxjQUFjO0lBRXpDLGtCQUFrQixDQUFlO0lBQ2pDLG1CQUFtQixDQUFlO0lBQ2xDLHVCQUF1QixDQUFlO0lBQ3RDLGVBQWUsQ0FBZTtJQUM5QixlQUFlLENBQWU7SUFFOUIsWUFBb0IsbUJBQXdDO1FBQXhDLHdCQUFtQixHQUFuQixtQkFBbUIsQ0FBcUI7SUFBRyxDQUFDO0lBRWhFLGtCQUFrQjtRQUNoQixJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUV6QixJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7UUFFYixjQUFjO1FBQ2QsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBRW5CLHVCQUF1QjtRQUN2QixJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFFbEIsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUN2RSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQ3BCLENBQUM7UUFDRixJQUFJLENBQUMsbUJBQW1CLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLGFBQWEsQ0FBQyxTQUFTLENBQ3pFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FDM0IsQ0FBQztRQUNGLElBQUksQ0FBQyx1QkFBdUI7WUFDMUIsSUFBSSxDQUFDLG1CQUFtQixDQUFDLGlCQUFpQixDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsQ0FDeEQsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQ3pCLENBQUM7UUFDSixJQUFJLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUNqRSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FDakMsQ0FBQztRQUNGLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQ2pFLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUNqQyxDQUFDO0lBQ0osQ0FBQztJQUVELEtBQUs7UUFDSCxhQUFhO1FBQ2IsSUFBSSxhQUFhLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFDaEUsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsYUFBYSxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUVqRCxrQkFBa0I7UUFDbEIsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBRWxCLG1CQUFtQjtRQUNuQixJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7UUFFbkIsd0JBQXdCO1FBQ3hCLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN2QyxDQUFDO0lBRUQsVUFBVTtRQUNSLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFO1lBQ2pDLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1lBQ25CLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sSUFBSSxXQUFXLENBQUMsU0FBUyxDQUFDO1lBQ25ELElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDO1FBQy9DLENBQUMsQ0FBQyxDQUFDO1FBRUgsaURBQWlEO1FBQ2pELElBQ0UsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEdBQUcsQ0FBQztZQUN4QixJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxZQUFZO1lBQ3ZDLElBQUksQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLDBCQUEwQixFQUNyRCxDQUFDO1lBQ0QsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtnQkFDMUIsSUFDRSxJQUFJLENBQUMsS0FBSyxJQUFJLFVBQVUsQ0FBQyxRQUFRO29CQUNqQyxJQUFJLENBQUMsS0FBSyxJQUFJLFVBQVUsQ0FBQyxNQUFNLEVBQy9CLENBQUM7b0JBQ0QsSUFBSSxDQUFDLE1BQU07d0JBQ1QsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQztnQkFDdkUsQ0FBQztZQUNILENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztJQUNILENBQUM7SUFFRCxpQkFBaUI7UUFDZixJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFO1lBQzFCLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQztZQUNqQyxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUM7UUFDakMsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsa0JBQWtCO1FBQ2hCLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUU7WUFDMUIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDO1lBQ2pDLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQztRQUNqQyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxvQkFBb0I7SUFDcEIsV0FBVztRQUNULHVCQUF1QjtRQUN2QixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksR0FBRyxpQ0FBaUMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQztRQUV6RSxzQkFBc0I7UUFDdEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEdBQUcsVUFBVSxDQUFDLENBQUMsS0FBSztRQUVwQyw0QkFBNEI7UUFDNUIsSUFDRSxJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxnQkFBZ0I7WUFDM0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsZUFBZSxFQUMxQyxDQUFDO1lBQ0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLElBQUksWUFBWSxDQUFDO1FBQ25DLENBQUM7UUFFRCx5QkFBeUI7UUFDekIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVO1lBQ3BCLHNFQUFzRTtnQkFDdEUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMscUJBQXFCLENBQUM7UUFDcEQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhO1lBQ3ZCLHlFQUF5RTtnQkFDekUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMscUJBQXFCLENBQUM7UUFFcEQsNEJBQTRCO1FBQzVCLElBQUksQ0FBQyxNQUFNLENBQUMsY0FBYyxHQUFHLHNDQUFzQyxDQUFDO1FBQ3BFLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxHQUFHLHNDQUFzQyxDQUFDO0lBQ2xFLENBQUM7SUFFRCxXQUFXO1FBQ1QsSUFBSSxDQUFDLGNBQWM7WUFDakIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsZUFBZSxJQUFJLGdCQUFnQixDQUFDLEdBQUc7Z0JBQ25FLElBQUksQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLGVBQWUsSUFBSSxnQkFBZ0IsQ0FBQyxJQUFJLENBQUM7UUFFdkUsSUFBSSxDQUFDLGlCQUFpQjtZQUNwQixJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxlQUFlLElBQUksZ0JBQWdCLENBQUMsTUFBTTtnQkFDdEUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsZUFBZSxJQUFJLGdCQUFnQixDQUFDLElBQUksQ0FBQztRQUV2RSxJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsa0JBQWtCLENBQUM7UUFDekUsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxjQUFjLENBQUM7UUFFakUsSUFBSSxDQUFDLGdCQUFnQjtZQUNuQixJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxtQkFBbUI7Z0JBQy9DLElBQUksQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLG1CQUFtQixDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7SUFDL0QsQ0FBQztJQUVELFVBQVU7UUFDUixxQkFBcUI7UUFDckIsNEJBQTRCO1FBQzVCLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUM5QixtQ0FBbUM7WUFDbkMsbUJBQW1CO1lBQ25CLE1BQU07UUFDUixDQUFDO0lBQ0gsQ0FBQztJQUVELGdCQUFnQixDQUFDLFlBQTBCO1FBQ3pDLElBQUksU0FBUyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDO1FBRWpDLFFBQVEsWUFBWSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQzNCLEtBQUssVUFBVSxDQUFDLFFBQVE7Z0JBQ3RCLFNBQVMsSUFBSSxXQUFXLENBQUM7Z0JBQ3pCLE1BQU07WUFDUixLQUFLLFVBQVUsQ0FBQyxLQUFLO2dCQUNuQixTQUFTLElBQUksU0FBUyxDQUFDO2dCQUN2QixNQUFNO1lBQ1IsS0FBSyxVQUFVLENBQUMsTUFBTTtnQkFDcEIsU0FBUyxJQUFJLFNBQVMsQ0FBQztnQkFDdkIsTUFBTTtRQUNWLENBQUM7UUFFRCxRQUFRLFlBQVksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUM1QixLQUFLLFdBQVcsQ0FBQyxJQUFJO2dCQUNuQixTQUFTLElBQUksT0FBTyxDQUFDO2dCQUNyQixNQUFNO1lBQ1IsS0FBSyxXQUFXLENBQUMsTUFBTTtnQkFDckIsU0FBUyxJQUFJLFNBQVMsQ0FBQztnQkFDdkIsTUFBTTtRQUNWLENBQUM7UUFFRCxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBRUQsaUJBQWlCLENBQUMsS0FBWSxFQUFFLFlBQTBCO1FBQ3hELEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUV2QixJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDaEQsT0FBTztRQUNULENBQUM7UUFFRCxJQUNFLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsc0JBQXNCO1lBQ2xELFlBQVksQ0FBQyxNQUFNLElBQUksV0FBVyxDQUFDLElBQUksRUFDdkMsQ0FBQztZQUNELE9BQU87UUFDVCxDQUFDO1FBRUQsSUFBSSxZQUFZLENBQUMsS0FBSyxJQUFJLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQ2hELElBQ0UsSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsZ0JBQWdCO2dCQUMzQyxJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxlQUFlLEVBQzFDLENBQUM7Z0JBQ0QsSUFBSSxDQUFDLFNBQVMsQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDckMsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLElBQUksWUFBWSxDQUFDLE1BQU0sSUFBSSxXQUFXLENBQUMsSUFBSSxFQUFFLENBQUM7b0JBQzVDLElBQUksQ0FBQyxTQUFTLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUNyQyxDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQsYUFBYSxDQUFDLEtBQWE7UUFDekIsSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUNWLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUN6QixDQUFDO1FBQ0QsMkNBQTJDO1FBQzNDLElBQUksYUFBYSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUU7WUFDN0MsT0FBTyxDQUNMLElBQUksQ0FBQyxLQUFLO2dCQUNSLENBQUMsSUFBSSxDQUFDLGdCQUFnQixJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDOUQsSUFBSSxDQUFDLEtBQUssSUFBSSxVQUFVLENBQUMsUUFBUTtnQkFDakMsSUFBSSxDQUFDLEtBQUssSUFBSSxVQUFVLENBQUMsTUFBTSxDQUNoQyxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLGFBQWEsQ0FBQyxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDOUIsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQzVCLE9BQU87WUFDVCxDQUFDO1lBRUQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNwQixDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksQ0FBQyxTQUFTLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzlDLENBQUM7SUFDSCxDQUFDO0lBRUQsaUJBQWlCLENBQUMsS0FBYTtRQUM3QixJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ1YsS0FBSyxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ3pCLENBQUM7UUFDRCwrQ0FBK0M7UUFDL0MsSUFBSSxhQUFhLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtZQUM3QyxPQUFPLENBQ0wsSUFBSSxDQUFDLEtBQUs7Z0JBQ1IsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLElBQUksSUFBSSxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVTtvQkFDdEQsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTTtvQkFDbkIsQ0FBQyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDNUIsSUFBSSxDQUFDLEtBQUssSUFBSSxVQUFVLENBQUMsUUFBUTtnQkFDakMsSUFBSSxDQUFDLEtBQUssSUFBSSxVQUFVLENBQUMsTUFBTSxDQUNoQyxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLGFBQWEsQ0FBQyxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDOUIsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQzVCLE9BQU87WUFDVCxDQUFDO1lBRUQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztRQUN4QyxDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksQ0FBQyxTQUFTLENBQUMsYUFBYSxDQUFDLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzVDLENBQUM7SUFDSCxDQUFDO0lBRUQsU0FBUyxDQUFDLGlCQUF5QjtRQUNqQywwQkFBMEI7UUFDMUIsSUFBSSxpQkFBaUIsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sSUFBSSxpQkFBaUIsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNwRSxPQUFPO1FBQ1QsQ0FBQztRQUVELDJDQUEyQztRQUMzQyxJQUFJLGlCQUFpQixJQUFJLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQy9DLE9BQU87UUFDVCxDQUFDO1FBRUQsSUFBSSxZQUFZLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBRTNELDJDQUEyQztRQUMzQyxJQUNFLFlBQVksQ0FBQyxLQUFLLElBQUksVUFBVSxDQUFDLFFBQVE7WUFDekMsWUFBWSxDQUFDLEtBQUssSUFBSSxVQUFVLENBQUMsTUFBTSxFQUN2QyxDQUFDO1lBQ0QsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7UUFFbkIsSUFBSSxDQUFDLGtCQUFrQixDQUNyQixZQUFZLEVBQ1osSUFBSSxDQUFDLFdBQVcsSUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FDN0M7YUFDRSxTQUFTLEVBQUU7YUFDWCxJQUFJLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRTtZQUNoQixJQUFJLE9BQU8sRUFBRSxDQUFDO2dCQUNaLE9BQU8sSUFBSSxDQUFDLGtCQUFrQixDQUM1QixZQUFZLEVBQ1osWUFBWSxDQUFDLFFBQVEsQ0FDdEIsQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNoQixDQUFDO1lBRUQsT0FBTyxFQUFFLENBQUMsT0FBTyxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDakMsQ0FBQyxDQUFDO2FBQ0QsSUFBSSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7WUFDaEIsSUFBSSxPQUFPLEVBQUUsQ0FBQztnQkFDWixvQkFBb0I7Z0JBQ3BCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUN0QyxDQUFDO1FBQ0gsQ0FBQyxDQUFDO2FBQ0QsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZDLENBQUM7SUFFTyxrQkFBa0IsQ0FDeEIsWUFBMEIsRUFDMUIsU0FFaUU7UUFFakUsSUFBSSxPQUFPLFNBQVMsS0FBSyxPQUFPLElBQUksRUFBRSxDQUFDO1lBQ3JDLE9BQU8sRUFBRSxDQUFVLFNBQVMsQ0FBQyxDQUFDO1FBQ2hDLENBQUM7YUFBTSxJQUFJLFNBQVMsWUFBWSxRQUFRLEVBQUUsQ0FBQztZQUN6QyxJQUFJLFNBQVMsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQzNELElBQUksTUFBTSxHQUFHLFNBQVMsQ0FBQztnQkFDckIsU0FBUyxFQUFFLFNBQVM7Z0JBQ3BCLFFBQVEsRUFBRSxJQUFJLENBQUMsV0FBVztnQkFDMUIsTUFBTSxFQUFFLFlBQVk7YUFDckIsQ0FBQyxDQUFDO1lBRUgsSUFBSSxZQUFZLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztnQkFDekIsT0FBTyxNQUFNLENBQUM7WUFDaEIsQ0FBQztpQkFBTSxJQUFJLE9BQU8sTUFBTSxLQUFLLE9BQU8sSUFBSSxFQUFFLENBQUM7Z0JBQ3pDLE9BQU8sRUFBRSxDQUFVLE1BQU0sQ0FBQyxDQUFDO1lBQzdCLENBQUM7aUJBQU0sQ0FBQztnQkFDTixPQUFPLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNuQixDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU8sRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2xCLENBQUM7SUFFRCxnQkFBZ0IsQ0FBQyxZQUEwQjtRQUN6QyxrQkFBa0I7UUFDbEIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUM5QixvQ0FBb0M7UUFDcEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFckMsOEJBQThCO1FBQzlCLE1BQU0sSUFBSSxHQUFvQjtZQUM1QixJQUFJLEVBQUUsWUFBWTtZQUNsQixZQUFZLEVBQUUsSUFBSSxDQUFDLFdBQVc7WUFDOUIsU0FBUyxFQUFFLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDO1lBQ3JELFFBQVEsRUFBRSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQztTQUNwRCxDQUFDO1FBQ0YsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDNUIsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUUzQywyQkFBMkI7UUFDM0IsSUFBSSxDQUFDLGdCQUFnQixHQUFHLFlBQVksQ0FBQyxLQUFLLENBQUM7UUFDM0MsSUFBSSxDQUFDLFdBQVcsR0FBRyxZQUFZLENBQUM7SUFDbEMsQ0FBQztJQUVELFVBQVUsQ0FBQyxZQUEwQjtRQUNuQyxnRUFBZ0U7UUFDaEUsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDckIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEdBQUcsV0FBVyxDQUFDLFNBQVMsQ0FBQztZQUVoRCxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUM1QyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sR0FBRyxXQUFXLENBQUMsSUFBSSxDQUFDO2dCQUUzQyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLDRCQUE0QixFQUFFLENBQUM7b0JBQzVELElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUU7d0JBQzFCLElBQUksSUFBSSxDQUFDLEtBQUssR0FBRyxZQUFZLENBQUMsS0FBSyxFQUFFLENBQUM7NEJBQ3BDLElBQUksQ0FBQyxNQUFNLEdBQUcsV0FBVyxDQUFDLFNBQVMsQ0FBQzt3QkFDdEMsQ0FBQztvQkFDSCxDQUFDLENBQUMsQ0FBQztnQkFDTCxDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7UUFFRCwrREFBK0Q7UUFDL0QsWUFBWSxDQUFDLE1BQU0sR0FBRyxXQUFXLENBQUMsTUFBTSxDQUFDO0lBQzNDLENBQUM7SUFFRCxXQUFXLENBQUMsS0FBYTtRQUN2QixvREFBb0Q7UUFDcEQsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDNUIsSUFBSSxDQUFDLElBQUksS0FBSyxFQUFFLENBQUM7Z0JBQ2YsSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjO29CQUN4QiwrQ0FBK0MsQ0FBQztZQUNwRCxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLEdBQUcsc0NBQXNDLENBQUM7WUFDdEUsQ0FBQztZQUVELElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLEtBQUssRUFBRSxDQUFDO2dCQUNuQyxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVU7b0JBQ3BCLCtDQUErQyxDQUFDO1lBQ3BELENBQUM7aUJBQU0sQ0FBQztnQkFDTixJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsR0FBRyxzQ0FBc0MsQ0FBQztZQUNsRSxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRCxtQkFBbUIsQ0FBQyxNQUFxQjtRQUN2QyxJQUFJLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNqQixNQUFNLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDakIsQ0FBQztJQUNILENBQUM7SUFFRCxtQkFBbUI7SUFDbkIsT0FBTyxDQUFDLEtBQW9CO1FBQzFCLHNCQUFzQjtRQUN0QixRQUFRLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNwQixLQUFLLEVBQUU7Z0JBQ0wsT0FBTztnQkFDUCxJQUFJLENBQUMsaUJBQWlCLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQzlCLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDdkIsTUFBTTtZQUNSLEtBQUssRUFBRTtnQkFDTCxRQUFRO2dCQUNSLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQzFCLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDdkIsTUFBTTtZQUNSO2dCQUNFLE9BQU8sQ0FBQyxtQ0FBbUM7UUFDL0MsQ0FBQztJQUNILENBQUM7SUFFRCxXQUFXO1FBQ1QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJO1lBQ2QsaUNBQWlDO2dCQUNqQyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUs7Z0JBQ2pCLG9CQUFvQixDQUFDO0lBQ3pCLENBQUM7SUFFRCxXQUFXO1FBQ1QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEdBQUcsaUNBQWlDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUM7SUFDM0UsQ0FBQztJQUVELGlCQUFpQixDQUFDLGlCQUF5QjtRQUN6QyxPQUFPLElBQUksQ0FBQyxnQkFBZ0IsSUFBSSxJQUFJO1lBQ2xDLElBQUksQ0FBQyxnQkFBZ0IsSUFBSSxpQkFBaUI7WUFDMUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxpQkFBaUI7Z0JBQ3pDLENBQUMsQ0FBQyxjQUFjLENBQUMsT0FBTztnQkFDeEIsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxRQUFRO1lBQzNCLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFDWCxDQUFDO0lBRUQsZ0JBQWdCLENBQUMsaUJBQXlCO1FBQ3hDLE9BQU8saUJBQWlCLElBQUksQ0FBQztZQUMzQixDQUFDLENBQUMsYUFBYSxDQUFDLEtBQUs7WUFDckIsQ0FBQyxDQUFDLGlCQUFpQixJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUM7Z0JBQzVDLENBQUMsQ0FBQyxhQUFhLENBQUMsS0FBSztnQkFDckIsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUM7SUFDM0IsQ0FBQztJQUVELG1CQUFtQjtJQUNuQixTQUFTLENBQUMsS0FBWTtRQUNwQixJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQy9CLE9BQU87UUFDVCxDQUFDO1FBRUQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQzFCLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxHQUFHLGlDQUFpQyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDO1FBRXpFLCtCQUErQjtRQUMvQixJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzVDLENBQUM7SUFFRCxNQUFNO1FBQ0osaUNBQWlDO1FBQ2pDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUM7UUFDN0IsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7UUFDeEIsSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFDMUIsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBRWIsd0JBQXdCO1FBQ3hCLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDcEIsQ0FBQztJQUVELFdBQVc7UUFDVCxJQUFJLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1lBQzVCLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUN4QyxDQUFDO1FBRUQsSUFBSSxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztZQUM3QixJQUFJLENBQUMsbUJBQW1CLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDekMsQ0FBQztRQUVELElBQUksSUFBSSxDQUFDLHVCQUF1QixFQUFFLENBQUM7WUFDakMsSUFBSSxDQUFDLHVCQUF1QixDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQzdDLENBQUM7UUFFRCxJQUFJLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUN6QixJQUFJLENBQUMsZUFBZSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ3JDLENBQUM7UUFFRCxJQUFJLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUN6QixJQUFJLENBQUMsZUFBZSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ3JDLENBQUM7SUFDSCxDQUFDO3dHQTdnQlUsaUJBQWlCOzRGQUFqQixpQkFBaUIsME1BQ1gsWUFBWSw2QkNuQy9CLDgwRkFrR0E7OzRGRGhFYSxpQkFBaUI7a0JBTDdCLFNBQVM7K0JBQ0UsV0FBVzt3RkFNZCxLQUFLO3NCQURYLGVBQWU7dUJBQUMsWUFBWTtnQkFTekIsT0FBTztzQkFEVixLQUFLO3VCQUFDLFFBQVE7Z0JBT0wsV0FBVztzQkFBcEIsTUFBTTtnQkFDRyxZQUFZO3NCQUFyQixNQUFNO2dCQUNHLEtBQUs7c0JBQWQsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcbiAgQ29tcG9uZW50LFxyXG4gIE9uRGVzdHJveSxcclxuICBBZnRlckNvbnRlbnRJbml0LFxyXG4gIENvbnRlbnRDaGlsZHJlbixcclxuICBRdWVyeUxpc3QsXHJcbiAgSW5wdXQsXHJcbiAgT3V0cHV0LFxyXG4gIEV2ZW50RW1pdHRlcixcclxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgU3Vic2NyaXB0aW9uLCBvZiwgT2JzZXJ2YWJsZSwgaXNPYnNlcnZhYmxlIH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IE5nV2l6YXJkRGF0YVNlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9uZy13aXphcmQtZGF0YS5zZXJ2aWNlJztcclxuaW1wb3J0IHtcclxuICBUSEVNRSxcclxuICBTVEVQX1NUQVRVUyxcclxuICBTVEVQX1NUQVRFLFxyXG4gIFRPT0xCQVJfUE9TSVRJT04sXHJcbiAgU1RFUF9ESVJFQ1RJT04sXHJcbiAgU1RFUF9QT1NJVElPTixcclxufSBmcm9tICcuLi8uLi91dGlscy9lbnVtcyc7XHJcbmltcG9ydCB7IG1lcmdlIH0gZnJvbSAnLi4vLi4vdXRpbHMvZnVuY3Rpb25zJztcclxuaW1wb3J0IHtcclxuICBOZ1dpemFyZENvbmZpZyxcclxuICBTdGVwQ2hhbmdlZEFyZ3MsXHJcbiAgTmdXaXphcmRTdGVwLFxyXG4gIFN0ZXBWYWxpZGF0aW9uQXJncyxcclxuICBUb29sYmFyQnV0dG9uLFxyXG59IGZyb20gJy4uLy4uL3V0aWxzL2ludGVyZmFjZXMnO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICduZy13aXphcmQnLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9uZy13aXphcmQuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsczogWycuL25nLXdpemFyZC5jb21wb25lbnQuc2NzcyddLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgTmdXaXphcmRDb21wb25lbnQgaW1wbGVtZW50cyBPbkRlc3Ryb3ksIEFmdGVyQ29udGVudEluaXQge1xyXG4gIEBDb250ZW50Q2hpbGRyZW4oTmdXaXphcmRTdGVwKVxyXG4gIHB1YmxpYyBzdGVwczogUXVlcnlMaXN0PE5nV2l6YXJkU3RlcD47XHJcblxyXG4gIF9wQ29uZmlnOiBOZ1dpemFyZENvbmZpZztcclxuICBnZXQgcENvbmZpZygpOiBOZ1dpemFyZENvbmZpZyB7XHJcbiAgICByZXR1cm4gdGhpcy5fcENvbmZpZyB8fCB7fTtcclxuICB9XHJcblxyXG4gIEBJbnB1dCgnY29uZmlnJylcclxuICBzZXQgcENvbmZpZyhjb25maWc6IE5nV2l6YXJkQ29uZmlnKSB7XHJcbiAgICB0aGlzLl9wQ29uZmlnID0gY29uZmlnO1xyXG4gIH1cclxuXHJcbiAgY29uZmlnOiBOZ1dpemFyZENvbmZpZztcclxuXHJcbiAgQE91dHB1dCgpIHN0ZXBDaGFuZ2VkID0gbmV3IEV2ZW50RW1pdHRlcjxTdGVwQ2hhbmdlZEFyZ3M+KCk7XHJcbiAgQE91dHB1dCgpIHRoZW1lQ2hhbmdlZCA9IG5ldyBFdmVudEVtaXR0ZXI8VEhFTUU+KCk7XHJcbiAgQE91dHB1dCgpIHJlc2V0ID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xyXG5cclxuICBzdHlsZXM6IHtcclxuICAgIG1haW4/OiBzdHJpbmc7XHJcbiAgICBzdGVwPzogc3RyaW5nO1xyXG4gICAgcHJldmlvdXNCdXR0b24/OiBzdHJpbmc7XHJcbiAgICBuZXh0QnV0dG9uPzogc3RyaW5nO1xyXG4gICAgdG9vbGJhclRvcD86IHN0cmluZztcclxuICAgIHRvb2xiYXJCb3R0b20/OiBzdHJpbmc7XHJcbiAgfSA9IHt9O1xyXG5cclxuICBzaG93VG9vbGJhclRvcDogYm9vbGVhbiA9IGZhbHNlO1xyXG4gIHNob3dQcmV2aW91c0J1dHRvbjogYm9vbGVhbiA9IGZhbHNlO1xyXG4gIHNob3dOZXh0QnV0dG9uOiBib29sZWFuID0gZmFsc2U7XHJcbiAgc2hvd1Rvb2xiYXJCb3R0b206IGJvb2xlYW4gPSBmYWxzZTtcclxuICBzaG93RXh0cmFCdXR0b25zOiBib29sZWFuID0gZmFsc2U7XHJcbiAgY3VycmVudFN0ZXBJbmRleDogbnVtYmVyID0gbnVsbDsgLy8gQWN0aXZlIHN0ZXAgaW5kZXhcclxuICBjdXJyZW50U3RlcDogTmdXaXphcmRTdGVwOyAvLyBBY3RpdmUgc3RlcFxyXG5cclxuICByZXNldFdpemFyZFdhdGNoZXI6IFN1YnNjcmlwdGlvbjtcclxuICBzaG93TmV4dFN0ZXBXYXRjaGVyOiBTdWJzY3JpcHRpb247XHJcbiAgc2hvd1ByZXZpb3VzU3RlcFdhdGNoZXI6IFN1YnNjcmlwdGlvbjtcclxuICBzaG93U3RlcFdhdGNoZXI6IFN1YnNjcmlwdGlvbjtcclxuICBzZXRUaGVtZVdhdGNoZXI6IFN1YnNjcmlwdGlvbjtcclxuXHJcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBuZ1dpemFyZERhdGFTZXJ2aWNlOiBOZ1dpemFyZERhdGFTZXJ2aWNlKSB7fVxyXG5cclxuICBuZ0FmdGVyQ29udGVudEluaXQoKSB7XHJcbiAgICB0aGlzLl9iYWNrdXBTdGVwU3RhdGVzKCk7XHJcblxyXG4gICAgdGhpcy5faW5pdCgpO1xyXG5cclxuICAgIC8vIFNldCB0b29sYmFyXHJcbiAgICB0aGlzLl9zZXRUb29sYmFyKCk7XHJcblxyXG4gICAgLy8gQXNzaWduIHBsdWdpbiBldmVudHNcclxuICAgIHRoaXMuX3NldEV2ZW50cygpO1xyXG5cclxuICAgIHRoaXMucmVzZXRXaXphcmRXYXRjaGVyID0gdGhpcy5uZ1dpemFyZERhdGFTZXJ2aWNlLnJlc2V0V2l6YXJkJC5zdWJzY3JpYmUoXHJcbiAgICAgICgpID0+IHRoaXMuX3Jlc2V0KClcclxuICAgICk7XHJcbiAgICB0aGlzLnNob3dOZXh0U3RlcFdhdGNoZXIgPSB0aGlzLm5nV2l6YXJkRGF0YVNlcnZpY2Uuc2hvd05leHRTdGVwJC5zdWJzY3JpYmUoXHJcbiAgICAgICgpID0+IHRoaXMuX3Nob3dOZXh0U3RlcCgpXHJcbiAgICApO1xyXG4gICAgdGhpcy5zaG93UHJldmlvdXNTdGVwV2F0Y2hlciA9XHJcbiAgICAgIHRoaXMubmdXaXphcmREYXRhU2VydmljZS5zaG93UHJldmlvdXNTdGVwJC5zdWJzY3JpYmUoKCkgPT5cclxuICAgICAgICB0aGlzLl9zaG93UHJldmlvdXNTdGVwKClcclxuICAgICAgKTtcclxuICAgIHRoaXMuc2hvd1N0ZXBXYXRjaGVyID0gdGhpcy5uZ1dpemFyZERhdGFTZXJ2aWNlLnNob3dTdGVwJC5zdWJzY3JpYmUoXHJcbiAgICAgIChpbmRleCkgPT4gdGhpcy5fc2hvd1N0ZXAoaW5kZXgpXHJcbiAgICApO1xyXG4gICAgdGhpcy5zZXRUaGVtZVdhdGNoZXIgPSB0aGlzLm5nV2l6YXJkRGF0YVNlcnZpY2Uuc2V0VGhlbWUkLnN1YnNjcmliZShcclxuICAgICAgKHRoZW1lKSA9PiB0aGlzLl9zZXRUaGVtZSh0aGVtZSlcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBfaW5pdCgpIHtcclxuICAgIC8vIHNldCBjb25maWdcclxuICAgIGxldCBkZWZhdWx0Q29uZmlnID0gdGhpcy5uZ1dpemFyZERhdGFTZXJ2aWNlLmdldERlZmF1bHRDb25maWcoKTtcclxuICAgIHRoaXMuY29uZmlnID0gbWVyZ2UoZGVmYXVsdENvbmZpZywgdGhpcy5wQ29uZmlnKTtcclxuXHJcbiAgICAvLyBzZXQgc3RlcCBzdGF0ZXNcclxuICAgIHRoaXMuX2luaXRTdGVwcygpO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZWxlbWVudHNcclxuICAgIHRoaXMuX2luaXRTdHlsZXMoKTtcclxuXHJcbiAgICAvLyBTaG93IHRoZSBpbml0aWFsIHN0ZXBcclxuICAgIHRoaXMuX3Nob3dTdGVwKHRoaXMuY29uZmlnLnNlbGVjdGVkKTtcclxuICB9XHJcblxyXG4gIF9pbml0U3RlcHMoKSB7XHJcbiAgICB0aGlzLnN0ZXBzLmZvckVhY2goKHN0ZXAsIGluZGV4KSA9PiB7XHJcbiAgICAgIHN0ZXAuaW5kZXggPSBpbmRleDtcclxuICAgICAgc3RlcC5zdGF0dXMgPSBzdGVwLnN0YXR1cyB8fCBTVEVQX1NUQVRVUy51bnRvdWNoZWQ7XHJcbiAgICAgIHN0ZXAuc3RhdGUgPSBzdGVwLnN0YXRlIHx8IFNURVBfU1RBVEUubm9ybWFsO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gTWFyayBwcmV2aW91cyBzdGVwcyBvZiB0aGUgYWN0aXZlIHN0ZXAgYXMgZG9uZVxyXG4gICAgaWYgKFxyXG4gICAgICB0aGlzLmNvbmZpZy5zZWxlY3RlZCA+IDAgJiZcclxuICAgICAgdGhpcy5jb25maWcuYW5jaG9yU2V0dGluZ3MubWFya0RvbmVTdGVwICYmXHJcbiAgICAgIHRoaXMuY29uZmlnLmFuY2hvclNldHRpbmdzLm1hcmtBbGxQcmV2aW91c1N0ZXBzQXNEb25lXHJcbiAgICApIHtcclxuICAgICAgdGhpcy5zdGVwcy5mb3JFYWNoKChzdGVwKSA9PiB7XHJcbiAgICAgICAgaWYgKFxyXG4gICAgICAgICAgc3RlcC5zdGF0ZSAhPSBTVEVQX1NUQVRFLmRpc2FibGVkICYmXHJcbiAgICAgICAgICBzdGVwLnN0YXRlICE9IFNURVBfU1RBVEUuaGlkZGVuXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICBzdGVwLnN0YXR1cyA9XHJcbiAgICAgICAgICAgIHN0ZXAuaW5kZXggPCB0aGlzLmNvbmZpZy5zZWxlY3RlZCA/IFNURVBfU1RBVFVTLmRvbmUgOiBzdGVwLnN0YXR1cztcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgX2JhY2t1cFN0ZXBTdGF0ZXMoKSB7XHJcbiAgICB0aGlzLnN0ZXBzLmZvckVhY2goKHN0ZXApID0+IHtcclxuICAgICAgc3RlcC5pbml0aWFsU3RhdHVzID0gc3RlcC5zdGF0dXM7XHJcbiAgICAgIHN0ZXAuaW5pdGlhbFN0YXRlID0gc3RlcC5zdGF0ZTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgX3Jlc3RvcmVTdGVwU3RhdGVzKCkge1xyXG4gICAgdGhpcy5zdGVwcy5mb3JFYWNoKChzdGVwKSA9PiB7XHJcbiAgICAgIHN0ZXAuc3RhdHVzID0gc3RlcC5pbml0aWFsU3RhdHVzO1xyXG4gICAgICBzdGVwLnN0YXRlID0gc3RlcC5pbml0aWFsU3RhdGU7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8vIFBSSVZBVEUgRlVOQ1RJT05TXHJcbiAgX2luaXRTdHlsZXMoKSB7XHJcbiAgICAvLyBTZXQgdGhlIG1haW4gZWxlbWVudFxyXG4gICAgdGhpcy5zdHlsZXMubWFpbiA9ICduZy13aXphcmQtbWFpbiBuZy13aXphcmQtdGhlbWUtJyArIHRoaXMuY29uZmlnLnRoZW1lO1xyXG5cclxuICAgIC8vIFNldCBhbmNob3IgZWxlbWVudHNcclxuICAgIHRoaXMuc3R5bGVzLnN0ZXAgPSAnbmF2LWl0ZW0nOyAvLyBsaVxyXG5cclxuICAgIC8vIE1ha2UgdGhlIGFuY2hvciBjbGlja2FibGVcclxuICAgIGlmIChcclxuICAgICAgdGhpcy5jb25maWcuYW5jaG9yU2V0dGluZ3MuZW5hYmxlQWxsQW5jaG9ycyAmJlxyXG4gICAgICB0aGlzLmNvbmZpZy5hbmNob3JTZXR0aW5ncy5hbmNob3JDbGlja2FibGVcclxuICAgICkge1xyXG4gICAgICB0aGlzLnN0eWxlcy5zdGVwICs9ICcgY2xpY2thYmxlJztcclxuICAgIH1cclxuXHJcbiAgICAvLyBTZXQgdGhlIHRvb2xiYXIgc3R5bGVzXHJcbiAgICB0aGlzLnN0eWxlcy50b29sYmFyVG9wID1cclxuICAgICAgJ2J0bi10b29sYmFyIG5nLXdpemFyZC10b29sYmFyIG5nLXdpemFyZC10b29sYmFyLXRvcCBqdXN0aWZ5LWNvbnRlbnQtJyArXHJcbiAgICAgIHRoaXMuY29uZmlnLnRvb2xiYXJTZXR0aW5ncy50b29sYmFyQnV0dG9uUG9zaXRpb247XHJcbiAgICB0aGlzLnN0eWxlcy50b29sYmFyQm90dG9tID1cclxuICAgICAgJ2J0bi10b29sYmFyIG5nLXdpemFyZC10b29sYmFyIG5nLXdpemFyZC10b29sYmFyLWJvdHRvbSBqdXN0aWZ5LWNvbnRlbnQtJyArXHJcbiAgICAgIHRoaXMuY29uZmlnLnRvb2xiYXJTZXR0aW5ncy50b29sYmFyQnV0dG9uUG9zaXRpb247XHJcblxyXG4gICAgLy8gU2V0IHByZXZpb3VzJm5leHQgYnV0dG9uc1xyXG4gICAgdGhpcy5zdHlsZXMucHJldmlvdXNCdXR0b24gPSAnYnRuIGJ0bi1zZWNvbmRhcnkgbmctd2l6YXJkLWJ0bi1wcmV2JztcclxuICAgIHRoaXMuc3R5bGVzLm5leHRCdXR0b24gPSAnYnRuIGJ0bi1zZWNvbmRhcnkgbmctd2l6YXJkLWJ0bi1uZXh0JztcclxuICB9XHJcblxyXG4gIF9zZXRUb29sYmFyKCkge1xyXG4gICAgdGhpcy5zaG93VG9vbGJhclRvcCA9XHJcbiAgICAgIHRoaXMuY29uZmlnLnRvb2xiYXJTZXR0aW5ncy50b29sYmFyUG9zaXRpb24gPT0gVE9PTEJBUl9QT1NJVElPTi50b3AgfHxcclxuICAgICAgdGhpcy5jb25maWcudG9vbGJhclNldHRpbmdzLnRvb2xiYXJQb3NpdGlvbiA9PSBUT09MQkFSX1BPU0lUSU9OLmJvdGg7XHJcblxyXG4gICAgdGhpcy5zaG93VG9vbGJhckJvdHRvbSA9XHJcbiAgICAgIHRoaXMuY29uZmlnLnRvb2xiYXJTZXR0aW5ncy50b29sYmFyUG9zaXRpb24gPT0gVE9PTEJBUl9QT1NJVElPTi5ib3R0b20gfHxcclxuICAgICAgdGhpcy5jb25maWcudG9vbGJhclNldHRpbmdzLnRvb2xiYXJQb3NpdGlvbiA9PSBUT09MQkFSX1BPU0lUSU9OLmJvdGg7XHJcblxyXG4gICAgdGhpcy5zaG93UHJldmlvdXNCdXR0b24gPSB0aGlzLmNvbmZpZy50b29sYmFyU2V0dGluZ3Muc2hvd1ByZXZpb3VzQnV0dG9uO1xyXG4gICAgdGhpcy5zaG93TmV4dEJ1dHRvbiA9IHRoaXMuY29uZmlnLnRvb2xiYXJTZXR0aW5ncy5zaG93TmV4dEJ1dHRvbjtcclxuXHJcbiAgICB0aGlzLnNob3dFeHRyYUJ1dHRvbnMgPVxyXG4gICAgICB0aGlzLmNvbmZpZy50b29sYmFyU2V0dGluZ3MudG9vbGJhckV4dHJhQnV0dG9ucyAmJlxyXG4gICAgICB0aGlzLmNvbmZpZy50b29sYmFyU2V0dGluZ3MudG9vbGJhckV4dHJhQnV0dG9ucy5sZW5ndGggPiAwO1xyXG4gIH1cclxuXHJcbiAgX3NldEV2ZW50cygpIHtcclxuICAgIC8vVE9ETzoga2V5TmF2aWdhdGlvblxyXG4gICAgLy8gS2V5Ym9hcmQgbmF2aWdhdGlvbiBldmVudFxyXG4gICAgaWYgKHRoaXMuY29uZmlnLmtleU5hdmlnYXRpb24pIHtcclxuICAgICAgLy8gJChkb2N1bWVudCkua2V5dXAoZnVuY3Rpb24gKGUpIHtcclxuICAgICAgLy8gICBtaS5fa2V5TmF2KGUpO1xyXG4gICAgICAvLyB9KTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIF9nZXRTdGVwQ3NzQ2xhc3Moc2VsZWN0ZWRTdGVwOiBOZ1dpemFyZFN0ZXApIHtcclxuICAgIGxldCBzdGVwQ2xhc3MgPSB0aGlzLnN0eWxlcy5zdGVwO1xyXG5cclxuICAgIHN3aXRjaCAoc2VsZWN0ZWRTdGVwLnN0YXRlKSB7XHJcbiAgICAgIGNhc2UgU1RFUF9TVEFURS5kaXNhYmxlZDpcclxuICAgICAgICBzdGVwQ2xhc3MgKz0gJyBkaXNhYmxlZCc7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGNhc2UgU1RFUF9TVEFURS5lcnJvcjpcclxuICAgICAgICBzdGVwQ2xhc3MgKz0gJyBkYW5nZXInO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBjYXNlIFNURVBfU1RBVEUuaGlkZGVuOlxyXG4gICAgICAgIHN0ZXBDbGFzcyArPSAnIGhpZGRlbic7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICB9XHJcblxyXG4gICAgc3dpdGNoIChzZWxlY3RlZFN0ZXAuc3RhdHVzKSB7XHJcbiAgICAgIGNhc2UgU1RFUF9TVEFUVVMuZG9uZTpcclxuICAgICAgICBzdGVwQ2xhc3MgKz0gJyBkb25lJztcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSBTVEVQX1NUQVRVUy5hY3RpdmU6XHJcbiAgICAgICAgc3RlcENsYXNzICs9ICcgYWN0aXZlJztcclxuICAgICAgICBicmVhaztcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gc3RlcENsYXNzO1xyXG4gIH1cclxuXHJcbiAgX3Nob3dTZWxlY3RlZFN0ZXAoZ