gentics-ui-core
Version:
This is the common core framework for the Gentics CMS and Mesh UI, and other Angular applications.
366 lines • 48 kB
JavaScript
import { Component, ElementRef, Input, NgZone, ViewChild } from '@angular/core';
import * as i0 from "@angular/core";
function isPromise(obj) {
return typeof obj === 'object' && obj != null && typeof obj.then === 'function';
}
function isSubscribable(obj) {
return typeof obj === 'object' && obj != null && typeof obj.subscribe === 'function';
}
function noop() { }
/**
* A progress bar that attachs to the top of the parent container and can be used to display activity or progress.
* It can be used for determinate tasks with a known duration and an exact progress
* or for indeterminate tasks for which only start/end calls exist, e.g. an xhr call.
*
* ```html
* <!-- progress bar without a known progress duration (indeterminate) -->
* <gtx-progress-bar [active]="isLoadingData"></gtx-progress-bar>
*
* <!-- progress bar for tasks where the progress is known (determinate)-->
* <gtx-progress-bar [active]="isUploadingFile" [progress]="uploadProgress"></gtx-progress-bar>
*
* <!-- progress bar for a Promise or Observable -->
* <gtx-progress-bar [for]="backgroundProgress$"></gtx-progress-bar>
* ```
*
* ## Using the progress bar with observables
*
* When an observable is assigned to the ProgressBar with "for", the observable should emit numbers
* in the range [0..1] for a determinate progress bar or boolean values for indeterminate progress.
* This will instantly animate the progress bar instead of relying on angular change detection.
*
* ```html
* <gtx-progress-bar [for]="uploadProgress$"></gtx-progress-bar>
* <gtx-progress-bar [for]="anythingLoading$"></gtx-progress-bar>
* ```
* ```typescript
* class MyComponent {
* uploadProgress$: Observable<number>;
* anythingLoading$: Observable<boolean>;
* }
* ```
*
* ## Using the progress bar programmatically inside another component
*
* The ProgressBar instance exposes two public methods, `start()`, `complete()` which can be used
* to manually control the progress bar visibility and progress in a parent component.
*
* ```typescript
* export class App {
* @ViewChild(ProgressBar)
* private progressBar: ProgressBar;
*
* loadUserData() {
* this.progressBar.start();
* restclient.get('/users', (response, users) => {
* this.progressBar.complete();
* if (users) {
* doSomethingWith(users);
* } else {
* handleError(response);
* }
* });
* }
* }
* ```
*/
export class ProgressBar {
constructor(zone) {
this.zone = zone;
this.isActive = false;
this.progressPercentage = 0;
this.indeterminateSpeed = 500;
this.determinate = false;
this.animationRequest = undefined;
this.lastAnimationFrame = undefined;
this.removePendingHandler = noop;
this.cleanupSubscription = noop;
this.wrapperClasses = { add(...cls) { }, remove(...cls) { } };
}
/**
* Shows or hides the progress bar. When no "progress" value
* is provided, the progress bar is in "indeterminate" mode
* and grows until "active" is set to false.
*/
get active() {
return this.isActive;
}
set active(active) {
if (active && !this.isActive) {
this.start();
}
else if (!active && this.isActive) {
this.complete();
}
}
/**
* Sets the progress of the progress bar as a fraction [0...1].
* When set, the progress bar is in "determinate" mode and will only update
* when the "progress" value changes or `complete()` is called.
*/
set progress(progress) {
if (progress == null) {
this.determinate = false;
this.wrapperClasses.add('is-indeterminate');
this.wrapperClasses.remove('is-determinate');
}
else {
this.determinate = true;
this.wrapperClasses.add('is-determinate');
this.wrapperClasses.remove('is-indeterminate');
progress = Math.max(0, Math.min(100 * progress, 100));
if (progress !== this.progressPercentage) {
if (progress == 100) {
this.complete();
}
else {
this.setProgressBarWidth(progress);
}
}
}
}
/**
* Sets the speed of the indeterminate animation required to reach
* 50% of the progress bar. Accepts values like "500ms", "0.5s", 500.
* *Default: 500ms*
*/
set speed(speed) {
if (typeof speed === 'string') {
let match = speed.match(/^(\d+(?:\.\d+)?)(ms|s)?$/);
if (match) {
let factor = (match[2] == 's' ? 1000 : 1);
this.indeterminateSpeed = Number.parseFloat(match[1]) * factor;
}
}
else if (!isNaN(speed)) {
this.indeterminateSpeed = speed;
}
}
/**
* Automatically starts, stops and updates the progress bar for a Promise
* or when an Observable emits values or completes.
*/
set for(promiseOrObservable) {
this.cleanup();
if (promiseOrObservable) {
if (promiseOrObservable !== this.currentPromiseOrObservable) {
this.setProgressBarWidth(0, 'immediate');
this.start(promiseOrObservable);
}
}
else if (this.isActive && this.currentPromiseOrObservable) {
this.cleanupSubscription();
this.complete();
}
}
ngAfterViewInit() {
let wrapper = this.progressBarWrapper && this.progressBarWrapper.nativeElement;
if (wrapper) {
this.wrapperClasses = wrapper.classList;
if (this.isActive) {
this.wrapperClasses.add('visible', this.determinate ? 'is-determinate' : 'is-indeterminate');
this.setProgressBarWidth(this.determinate ? this.progressPercentage : 0, 'immediate');
}
}
}
start(promiseOrObservable) {
if (promiseOrObservable !== this.currentPromiseOrObservable) {
this.cleanupSubscription();
}
if (!this.isActive) {
this.isActive = true;
this.lastAnimationFrame = undefined;
this.wrapperClasses.add('visible', this.determinate ? 'is-determinate' : 'is-indeterminate');
this.wrapperClasses.remove(this.determinate ? 'is-indeterminate' : 'is-determinate');
if (this.determinate) {
this.setProgressBarWidth(this.progressPercentage, 'immediate');
}
else {
this.setProgressBarWidth(0, 'immediate');
this.animateIndeterminate();
}
}
if (isPromise(promiseOrObservable)) {
let observing = true;
promiseOrObservable.then(() => observing && this.complete(), () => observing && this.complete());
this.cleanupSubscription = () => {
observing = false;
this.cleanupSubscription = noop;
};
this.currentPromiseOrObservable = promiseOrObservable;
}
else if (isSubscribable(promiseOrObservable)) {
let sub = promiseOrObservable.subscribe((value) => {
if (typeof value === 'number') {
this.progress = value;
}
else if (value === true && !this.isActive) {
this.start(promiseOrObservable);
}
else if (value === false && this.isActive) {
this.complete();
}
}, (error) => this.complete(), () => this.complete());
this.cleanupSubscription = () => {
sub.unsubscribe();
this.cleanupSubscription = noop;
};
this.currentPromiseOrObservable = promiseOrObservable;
}
}
/**
* Animates the progress bar to 100% and hides it
*/
complete() {
if (this.isActive) {
this.isActive = false;
if (this.determinate) {
if (this.progressPercentage == 100) {
this.fadeOutProgressBar();
}
else {
this.transitionTo100Percent()
.then(() => this.fadeOutProgressBar());
}
}
}
}
ngOnDestroy() {
this.cleanup();
}
cleanup() {
if (this.animationRequest) {
cancelAnimationFrame(this.animationRequest);
this.animationRequest = undefined;
}
this.removePendingHandler();
this.cleanupSubscription();
}
fadeOutProgressBar() {
if (this.removePendingHandler) {
this.removePendingHandler();
}
return new Promise((resolve) => this.zone.run(() => {
let element = this.progressBarWrapper.nativeElement;
const callback = () => {
this.removePendingHandler();
this.setProgressBarWidth(0, 'immediate');
this.zone.run(resolve);
};
this.removePendingHandler = () => {
element.removeEventListener('transitionend', callback);
this.removePendingHandler = noop;
};
element.addEventListener('transitionend', callback);
this.wrapperClasses.remove('visible');
}));
}
setProgressBarWidth(percent, immediate) {
this.progressPercentage = percent;
const nativeElement = this.progressIndicator && this.progressIndicator.nativeElement;
if (nativeElement) {
const style = nativeElement.style;
if (immediate) {
// Don't animate the change
style.transitionDuration = style.webkitTransitionDuration = '0s';
style.width = percent + '%';
let getWidthOnce = nativeElement.offsetWidth;
style.transitionDuration = style.webkitTransitionDuration = '';
}
else {
style.width = percent + '%';
}
}
}
transitionTo100Percent() {
if (this.removePendingHandler) {
this.removePendingHandler();
}
return new Promise(resolve => {
let element = this.progressIndicator.nativeElement;
if (this.determinate) {
// transition the progress indicator in a cancelable way
let callback = () => {
this.removePendingHandler();
this.zone.run(resolve);
};
this.removePendingHandler = () => {
element.removeEventListener('transitionend', callback);
this.removePendingHandler = noop;
};
element.addEventListener('transitionend', callback);
this.setProgressBarWidth(100);
}
else {
// Use requestAnimationFrame() in a cancelable way
let frameRequest;
let waitUntilDone = () => {
if (this.progressPercentage === 100) {
frameRequest = undefined;
resolve();
}
else {
frameRequest = requestAnimationFrame(waitUntilDone);
}
};
frameRequest = requestAnimationFrame(waitUntilDone);
this.removePendingHandler = () => {
cancelAnimationFrame(frameRequest);
this.removePendingHandler = noop;
};
}
});
}
animateIndeterminate() {
this.animationRequest = undefined;
if (this.determinate) {
return;
}
let now = typeof performance === 'object' ? performance.now() : Date.now();
let delta = (now - this.lastAnimationFrame) / 1000;
if (!this.lastAnimationFrame) {
// Animation starting
this.setProgressBarWidth(0);
}
else if (this.isActive) {
// Animate "active" state
let factor = delta * (900 / this.indeterminateSpeed);
let percent = this.progressPercentage + factor * Math.pow(1 - Math.sqrt(100 - this.progressPercentage), 2);
this.setProgressBarWidth(Math.max(0, Math.min(100, percent)));
}
else if (this.progressPercentage < 100) {
// Done - animate to 100%
let speed = (900 / this.indeterminateSpeed);
let factor = speed + Math.max(0, 1 - speed);
let percent = this.progressPercentage + 250 * delta * factor;
this.setProgressBarWidth(Math.max(0, Math.min(100, percent)));
}
else {
this.fadeOutProgressBar();
return;
}
this.lastAnimationFrame = now;
this.animationRequest = requestAnimationFrame(() => this.animateIndeterminate());
}
}
/** @nocollapse */ ProgressBar.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: ProgressBar, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ ProgressBar.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: ProgressBar, selector: "gtx-progress-bar", inputs: { active: "active", progress: "progress", speed: "speed", for: "for" }, viewQueries: [{ propertyName: "progressBarWrapper", first: true, predicate: ["progressBarWrapper"], descendants: true, static: true }, { propertyName: "progressIndicator", first: true, predicate: ["progressIndicator"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"progress-bar-wrapper\" #progressBarWrapper>\n <div class=\"progress-indicator\" #progressIndicator></div>\n</div>\n" });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: ProgressBar, decorators: [{
type: Component,
args: [{ selector: 'gtx-progress-bar', template: "<div class=\"progress-bar-wrapper\" #progressBarWrapper>\n <div class=\"progress-indicator\" #progressIndicator></div>\n</div>\n" }]
}], ctorParameters: function () { return [{ type: i0.NgZone }]; }, propDecorators: { active: [{
type: Input
}], progress: [{
type: Input
}], speed: [{
type: Input
}], for: [{
type: Input
}], progressBarWrapper: [{
type: ViewChild,
args: ['progressBarWrapper', { static: true }]
}], progressIndicator: [{
type: ViewChild,
args: ['progressIndicator', { static: true }]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvZ3Jlc3MtYmFyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3Byb2dyZXNzLWJhci9wcm9ncmVzcy1iYXIuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvcHJvZ3Jlc3MtYmFyL3Byb2dyZXNzLWJhci50cGwuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUMsU0FBUyxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFhLFNBQVMsRUFBQyxNQUFNLGVBQWUsQ0FBQzs7QUFHekYsU0FBUyxTQUFTLENBQUMsR0FBUTtJQUN2QixPQUFPLE9BQU8sR0FBRyxLQUFLLFFBQVEsSUFBSSxHQUFHLElBQUksSUFBSSxJQUFJLE9BQU8sR0FBRyxDQUFDLElBQUksS0FBSyxVQUFVLENBQUM7QUFDcEYsQ0FBQztBQUVELFNBQVMsY0FBYyxDQUFDLEdBQVE7SUFDNUIsT0FBTyxPQUFPLEdBQUcsS0FBSyxRQUFRLElBQUksR0FBRyxJQUFJLElBQUksSUFBSSxPQUFPLEdBQUcsQ0FBQyxTQUFTLEtBQUssVUFBVSxDQUFDO0FBQ3pGLENBQUM7QUFFRCxTQUFTLElBQUksS0FBVSxDQUFDO0FBRXhCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXdERztBQUtILE1BQU0sT0FBTyxXQUFXO0lBNkZwQixZQUFvQixJQUFZO1FBQVosU0FBSSxHQUFKLElBQUksQ0FBUTtRQVh4QixhQUFRLEdBQVksS0FBSyxDQUFDO1FBQzFCLHVCQUFrQixHQUFXLENBQUMsQ0FBQztRQUMvQix1QkFBa0IsR0FBVyxHQUFHLENBQUM7UUFDakMsZ0JBQVcsR0FBWSxLQUFLLENBQUM7UUFDN0IscUJBQWdCLEdBQVcsU0FBUyxDQUFDO1FBQ3JDLHVCQUFrQixHQUFXLFNBQVMsQ0FBQztRQUN2Qyx5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Q0FBQyxrQkFBa0IsRUFBRSxDQUFDO1lBQzFCLE9BQU87U0FDVjtRQUVELElBQUksQ0FBQyxrQkFBa0IsR0FBRyxHQUFHLENBQUM7UUFDOUIsSUFBSSxDQUFDLGdCQUFnQixHQUFHLHFCQUFxQixDQUN6QyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FDcEMsQ0FBQztJQUNOLENBQUM7OzJIQTFUUSxXQUFXOytHQUFYLFdBQVcsdVlDMUV4QixxSUFHQTsyRkR1RWEsV0FBVztrQkFKdkIsU0FBUzsrQkFDSSxrQkFBa0I7NkZBVWYsTUFBTTtzQkFBbEIsS0FBSztnQkFnQk8sUUFBUTtzQkFBcEIsS0FBSztnQkEwQk8sS0FBSztzQkFBakIsS0FBSztnQkFnQk8sR0FBRztzQkFBZixLQUFLO2dCQWM2QyxrQkFBa0I7c0JBQXBFLFNBQVM7dUJBQUMsb0JBQW9CLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFO2dCQUNDLGlCQUFpQjtzQkFBbEUsU0FBUzt1QkFBQyxtQkFBbUIsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0NvbXBvbmVudCwgRWxlbWVudFJlZiwgSW5wdXQsIE5nWm9uZSwgT25EZXN0cm95LCBWaWV3Q2hpbGR9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtTdWJzY3JpYmFibGV9IGZyb20gJ3J4anMnO1xuXG5mdW5jdGlvbiBpc1Byb21pc2Uob2JqOiBhbnkpOiBvYmogaXMgUHJvbWlzZUxpa2U8YW55PiB7XG4gICAgcmV0dXJuIHR5cGVvZiBvYmogPT09ICdvYmplY3QnICYmIG9iaiAhPSBudWxsICYmIHR5cGVvZiBvYmoudGhlbiA9PT0gJ2Z1bmN0aW9uJztcbn1cblxuZnVuY3Rpb24gaXNTdWJzY3JpYmFibGUob2JqOiBhbnkpOiBvYmogaXMgU3Vic2NyaWJhYmxlPGFueT4ge1xuICAgIHJldHVybiB0eXBlb2Ygb2JqID09PSAnb2JqZWN0JyAmJiBvYmogIT0gbnVsbCAmJiB0eXBlb2Ygb2JqLnN1YnNjcmliZSA9PT0gJ2Z1bmN0aW9uJztcbn1cblxuZnVuY3Rpb24gbm9vcCgpOiB2b2lkIHt9XG5cbi8qKlxuICogQSBwcm9ncmVzcyBiYXIgdGhhdCBhdHRhY2hzIHRvIHRoZSB0b3Agb2YgdGhlIHBhcmVudCBjb250YWluZXIgYW5kIGNhbiBiZSB1c2VkIHRvIGRpc3BsYXkgYWN0aXZpdHkgb3IgcHJvZ3Jlc3MuXG4gKiBJdCBjYW4gYmUgdXNlZCBmb3IgZGV0ZXJtaW5hdGUgdGFza3Mgd2l0aCBhIGtub3duIGR1cmF0aW9uIGFuZCBhbiBleGFjdCBwcm9ncmVzc1xuICogb3IgZm9yIGluZGV0ZXJtaW5hdGUgdGFza3MgZm9yIHdoaWNoIG9ubHkgc3RhcnQvZW5kIGNhbGxzIGV4aXN0LCBlLmcuIGFuIHhociBjYWxsLlxuICpcbiAqIGBgYGh0bWxcbiAqIDwhLS0gcHJvZ3Jlc3MgYmFyIHdpdGhvdXQgYSBrbm93biBwcm9ncmVzcyBkdXJhdGlvbiAoaW5kZXRlcm1pbmF0ZSkgLS0+XG4gKiA8Z3R4LXByb2dyZXNzLWJhciBbYWN0aXZlXT1cImlzTG9hZGluZ0RhdGFcIj48L2d0eC1wcm9ncmVzcy1iYXI+XG4gKlxuICogPCEtLSBwcm9ncmVzcyBiYXIgZm9yIHRhc2tzIHdoZXJlIHRoZSBwcm9ncmVzcyBpcyBrbm93biAoZGV0ZXJtaW5hdGUpLS0+XG4gKiA8Z3R4LXByb2dyZXNzLWJhciBbYWN0aXZlXT1cImlzVXBsb2FkaW5nRmlsZVwiIFtwcm9ncmVzc109XCJ1cGxvYWRQcm9ncmVzc1wiPjwvZ3R4LXByb2dyZXNzLWJhcj5cbiAqXG4gKiA8IS0tIHByb2dyZXNzIGJhciBmb3IgYSBQcm9taXNlIG9yIE9ic2VydmFibGUgLS0+XG4gKiA8Z3R4LXByb2dyZXNzLWJhciBbZm9yXT1cImJhY2tncm91bmRQcm9ncmVzcyRcIj48L2d0eC1wcm9ncmVzcy1iYXI+XG4gKiBgYGBcbiAqXG4gKiAjIyBVc2luZyB0aGUgcHJvZ3Jlc3MgYmFyIHdpdGggb2JzZXJ2YWJsZXNcbiAqXG4gKiBXaGVuIGFuIG9ic2VydmFibGUgaXMgYXNzaWduZWQgdG8gdGhlIFByb2dyZXNzQmFyIHdpdGggXCJmb3JcIiwgdGhlIG9ic2VydmFibGUgc2hvdWxkIGVtaXQgbnVtYmVyc1xuICogaW4gdGhlIHJhbmdlIFswLi4xXSBmb3IgYSBkZXRlcm1pbmF0ZSBwcm9ncmVzcyBiYXIgb3IgYm9vbGVhbiB2YWx1ZXMgZm9yIGluZGV0ZXJtaW5hdGUgcHJvZ3Jlc3MuXG4gKiBUaGlzIHdpbGwgaW5zdGFudGx5IGFuaW1hdGUgdGhlIHByb2dyZXNzIGJhciBpbnN0ZWFkIG9mIHJlbHlpbmcgb24gYW5ndWxhciBjaGFuZ2UgZGV0ZWN0aW9uLlxuICpcbiAqIGBgYGh0bWxcbiAqIDxndHgtcHJvZ3Jlc3MtYmFyIFtmb3JdPVwidXBsb2FkUHJvZ3Jlc3MkXCI+PC9ndHgtcHJvZ3Jlc3MtYmFyPlxuICogPGd0eC1wcm9ncmVzcy1iYXIgW2Zvcl09XCJhbnl0aGluZ0xvYWRpbmckXCI+PC9ndHgtcHJvZ3Jlc3MtYmFyPlxuICogYGBgXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjbGFzcyBNeUNvbXBvbmVudCB7XG4gKiAgICAgdXBsb2FkUHJvZ3Jlc3MkOiBPYnNlcnZhYmxlPG51bWJlcj47XG4gKiAgICAgYW55dGhpbmdMb2FkaW5nJDogT2JzZXJ2YWJsZTxib29sZWFuPjtcbiAqIH1cbiAqIGBgYFxuICpcbiAqICMjIFVzaW5nIHRoZSBwcm9ncmVzcyBiYXIgcHJvZ3JhbW1hdGljYWxseSBpbnNpZGUgYW5vdGhlciBjb21wb25lbnRcbiAqXG4gKiBUaGUgUHJvZ3Jlc3NCYXIgaW5zdGFuY2UgZXhwb3NlcyB0d28gcHVibGljIG1ldGhvZHMsIGBzdGFydCgpYCwgYGNvbXBsZXRlKClgIHdoaWNoIGNhbiBiZSB1c2VkXG4gKiB0byBtYW51YWxseSBjb250cm9sIHRoZSBwcm9ncmVzcyBiYXIgdmlzaWJpbGl0eSBhbmQgcHJvZ3Jlc3MgaW4gYSBwYXJlbnQgY29tcG9uZW50LlxuICpcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGV4cG9ydCBjbGFzcyBBcHAge1xuICogICBAVmlld0NoaWxkKFByb2dyZXNzQmFyKVxuICogICBwcml2YXRlIHByb2dyZXNzQmFyOiBQcm9ncmVzc0JhcjtcbiAqXG4gKiAgIGxvYWRVc2VyRGF0YSgpIHtcbiAqICAgICB0aGlzLnByb2dyZXNzQmFyLnN0YXJ0KCk7XG4gKiAgICAgcmVzdGNsaWVudC5nZXQoJy91c2VycycsIChyZXNwb25zZSwgdXNlcnMpID0+IHtcbiAqICAgICAgIHRoaXMucHJvZ3Jlc3NCYXIuY29tcGxldGUoKTtcbiAqICAgICAgIGlmICh1c2Vycykge1xuICogICAgICAgICBkb1NvbWV0aGluZ1dpdGgodXNlcnMpO1xuICogICAgICAgfSBlbHNlIHtcbiAqICAgICAgICAgaGFuZGxlRXJyb3IocmVzcG9uc2UpO1xuICogICAgICAgfVxuICogICAgIH0pO1xuICogICB9XG4gKiB9XG4gKiBgYGBcbiAqL1xuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICdndHgtcHJvZ3Jlc3MtYmFyJyxcbiAgICB0ZW1wbGF0ZVVybDogJy4vcHJvZ3Jlc3MtYmFyLnRwbC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBQcm9ncmVzc0JhciBpbXBsZW1lbnRzIE9uRGVzdHJveSB7XG5cbiAgICAvKipcbiAgICAgKiBTaG93cyBvciBoaWRlcyB0aGUgcHJvZ3Jlc3MgYmFyLiBXaGVuIG5vIFwicHJvZ3Jlc3NcIiB2YWx1ZVxuICAgICAqIGlzIHByb3ZpZGVkLCB0aGUgcHJvZ3Jlc3MgYmFyIGlzIGluIFwiaW5kZXRlcm1pbmF0ZVwiIG1vZGVcbiAgICAgKiBhbmQgZ3Jvd3MgdW50aWwgXCJhY3RpdmVcIiBpcyBzZXQgdG8gZmFsc2UuXG4gICAgICovXG4gICAgQElucHV0KCkgZ2V0IGFjdGl2ZSgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaXNBY3RpdmU7XG4gICAgfVxuICAgIHNldCBhY3RpdmUoYWN0aXZlOiBib29sZWFuKSB7XG4gICAgICAgIGlmIChhY3RpdmUgJiYgIXRoaXMuaXNBY3RpdmUpIHtcbiAgICAgICAgICAgIHRoaXMuc3RhcnQoKTtcbiAgICAgICAgfSBlbHNlIGlmICghYWN0aXZlICYmIHRoaXMuaXNBY3RpdmUpIHtcbiAgICAgICAgICAgIHRoaXMuY29tcGxldGUoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldHMgdGhlIHByb2dyZXNzIG9mIHRoZSBwcm9ncmVzcyBiYXIgYXMgYSBmcmFjdGlvbiBbMC4uLjFdLlxuICAgICAqIFdoZW4gc2V0LCB0aGUgcHJvZ3Jlc3MgYmFyIGlzIGluIFwiZGV0ZXJtaW5hdGVcIiBtb2RlIGFuZCB3aWxsIG9ubHkgdXBkYXRlXG4gICAgICogd2hlbiB0aGUgXCJwcm9ncmVzc1wiIHZhbHVlIGNoYW5nZXMgb3IgYGNvbXBsZXRlKClgIGlzIGNhbGxlZC5cbiAgICAgKi9cbiAgICBASW5wdXQoKSBzZXQgcHJvZ3Jlc3MocHJvZ3Jlc3M6IG51bWJlcikge1xuICAgICAgICBpZiAocHJvZ3Jlc3MgPT0gbnVsbCkge1xuICAgICAgICAgICAgdGhpcy5kZXRlcm1pbmF0ZSA9IGZhbHNlO1xuICAgICAgICAgICAgdGhpcy53cmFwcGVyQ2xhc3Nlcy5hZGQoJ2lzLWluZGV0ZXJtaW5hdGUnKTtcbiAgICAgICAgICAgIHRoaXMud3JhcHBlckNsYXNzZXMucmVtb3ZlKCdpcy1kZXRlcm1pbmF0ZScpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5kZXRlcm1pbmF0ZSA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLndyYXBwZXJDbGFzc2VzLmFkZCgnaXMtZGV0ZXJtaW5hdGUnKTtcbiAgICAgICAgICAgIHRoaXMud3JhcHBlckNsYXNzZXMucmVtb3ZlKCdpcy1pbmRldGVybWluYXRlJyk7XG5cbiAgICAgICAgICAgIHByb2dyZXNzID0gTWF0aC5tYXgoMCwgTWF0aC5taW4oMTAwICogcHJvZ3Jlc3MsIDEwMCkpO1xuICAgICAgICAgICAgaWYgKHByb2dyZXNzICE9PSB0aGlzLnByb2dyZXNzUGVyY2VudGFnZSkge1xuICAgICAgICAgICAgICAgIGlmIChwcm9ncmVzcyA9PSAxMDApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb21wbGV0ZSgpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2V0UHJvZ3Jlc3NCYXJXaWR0aChwcm9ncmVzcyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgc3BlZWQgb2YgdGhlIGluZGV0ZXJtaW5hdGUgYW5pbWF0aW9uIHJlcXVpcmVkIHRvIHJlYWNoXG4gICAgICogNTAlIG9mIHRoZSBwcm9ncmVzcyBiYXIuIEFjY2VwdHMgdmFsdWVzIGxpa2UgXCI1MDBtc1wiLCBcIjAuNXNcIiwgNTAwLlxuICAgICAqICpEZWZhdWx0OiA1MDBtcypcbiAgICAgKi9cbiAgICBASW5wdXQoKSBzZXQgc3BlZWQoc3BlZWQ6IHN0cmluZ3xudW1iZXIpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBzcGVlZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIGxldCBtYXRjaCA9IHNwZWVkLm1hdGNoKC9eKFxcZCsoPzpcXC5cXGQrKT8pKG1zfHMpPyQvKTtcbiAgICAgICAgICAgIGlmIChtYXRjaCkge1xuICAgICAgICAgICAgICAgIGxldCBmYWN0b3IgPSAobWF0Y2hbMl0gPT0gJ3MnID8gMTAwMCA6IDEpO1xuICAgICAgICAgICAgICAgIHRoaXMuaW5kZXRlcm1pbmF0ZVNwZWVkID0gTnVtYmVyLnBhcnNlRmxvYXQobWF0Y2hbMV0pICogZmFjdG9yO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKCFpc05hTihzcGVlZCkpIHtcbiAgICAgICAgICAgIHRoaXMuaW5kZXRlcm1pbmF0ZVNwZWVkID0gc3BlZWQ7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBdXRvbWF0aWNhbGx5IHN0YXJ0cywgc3RvcHMgYW5kIHVwZGF0ZXMgdGhlIHByb2dyZXNzIGJhciBmb3IgYSBQcm9taXNlXG4gICAgICogb3Igd2hlbiBhbiBPYnNlcnZhYmxlIGVtaXRzIHZhbHVlcyBvciBjb21wbGV0ZXMuXG4gICAgICovXG4gICAgQElucHV0KCkgc2V0IGZvcihwcm9taXNlT3JPYnNlcnZhYmxlOiBQcm9taXNlTGlrZTxhbnk+IHwgU3Vic2NyaWJhYmxlPG51bWJlcj4gIHwgU3Vic2NyaWJhYmxlPGJvb2xlYW4+KSB7XG4gICAgICAgIHRoaXMuY2xlYW51cCgpO1xuXG4gICAgICAgIGlmIChwcm9taXNlT3JPYnNlcnZhYmxlKSB7XG4gICAgICAgICAgICBpZiAocHJvbWlzZU9yT2JzZXJ2YWJsZSAhPT0gdGhpcy5jdXJyZW50UHJvbWlzZU9yT2JzZXJ2YWJsZSkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0UHJvZ3Jlc3NCYXJXaWR0aCgwLCAnaW1tZWRpYXRlJyk7XG4gICAgICAgICAgICAgICAgdGhpcy5zdGFydChwcm9taXNlT3JPYnNlcnZhYmxlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLmlzQWN0aXZlICYmIHRoaXMuY3VycmVudFByb21pc2VPck9ic2VydmFibGUpIHtcbiAgICAgICAgICAgIHRoaXMuY2xlYW51cFN1YnNjcmlwdGlvbigpO1xuICAgICAgICAgICAgdGhpcy5jb21wbGV0ZSgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgQFZpZXdDaGlsZCgncHJvZ3Jlc3NCYXJXcmFwcGVyJywgeyBzdGF0aWM6IHRydWUgfSkgcHJvZ3Jlc3NCYXJXcmFwcGVyOiBFbGVtZW50UmVmO1xuICAgIEBWaWV3Q2hpbGQoJ3Byb2dyZXNzSW5kaWNhdG9yJywgeyBzdGF0aWM6IHRydWUgfSkgcHJvZ3Jlc3NJbmRpY2F0b3I6IEVsZW1lbnRSZWY7XG5cbiAgICBwcml2YXRlIGlzQWN0aXZlOiBib29sZWFuID0gZmFsc2U7XG4gICAgcHJpdmF0ZSBwcm9ncmVzc1BlcmNlbnRhZ2U6IG51bWJlciA9IDA7XG4gICAgcHJpdmF0ZSBpbmRldGVybWluYXRlU3BlZWQ6IG51bWJlciA9IDUwMDtcbiAgICBwcml2YXRlIGRldGVybWluYXRlOiBib29sZWFuID0gZmFsc2U7XG4gICAgcHJpdmF0ZSBhbmltYXRpb25SZXF1ZXN0OiBudW1iZXIgPSB1bmRlZmluZWQ7XG4gICAgcHJpdmF0ZSBsYXN0QW5pbWF0aW9uRnJhbWU6IG51bWJlciA9IHVuZGVmaW5lZDtcbiAgICBwcml2YXRlIHJlbW92ZVBlbmRpbmdIYW5kbGVyOiAoKSA9PiB2b2lkID0gbm9vcDtcbiAgICBwcml2YXRlIGNsZWFudXBTdWJzY3JpcHRpb246ICgpID0+IHZvaWQgPSBub29wO1xuICAgIHByaXZhdGUgY3VycmVudFByb21pc2VPck9ic2VydmFibGU6IFByb21pc2VMaWtlPGFueT4gfCBTdWJzY3JpYmFibGU8YW55PjtcbiAgICBwcml2YXRlIHdyYXBwZXJDbGFzc2VzID0geyBhZGQoLi4uY2xzOiBzdHJpbmdbXSk6IHZvaWQge30sIHJlbW92ZSguLi5jbHM6IHN0cmluZ1tdKTogdm9pZCB7fSB9O1xuXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSB6b25lOiBOZ1pvbmUpIHsgfVxuXG4gICAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgICAgICBsZXQgd3JhcHBlcjogSFRNTEVsZW1lbnQgPSB0aGlzLnByb2dyZXNzQmFyV3JhcHBlciAmJiB0aGlzLnByb2dyZXNzQmFyV3JhcHBlci5uYXRpdmVFbGVtZW50O1xuICAgICAgICBpZiAod3JhcHBlcikge1xuICAgICAgICAgICAgdGhpcy53cmFwcGVyQ2xhc3NlcyA9IHdyYXBwZXIuY2xhc3NMaXN0O1xuICAgICAgICAgICAgaWYgKHRoaXMuaXNBY3RpdmUpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndyYXBwZXJDbGFzc2VzLmFkZCgndmlzaWJsZScsIHRoaXMuZGV0ZXJtaW5hdGUgPyAnaXMtZGV0ZXJtaW5hdGUnIDogJ2lzLWluZGV0ZXJtaW5hdGUnKTtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFByb2dyZXNzQmFyV2lkdGgodGhpcy5kZXRlcm1pbmF0ZSA/IHRoaXMucHJvZ3Jlc3NQZXJjZW50YWdlIDogMCwgJ2ltbWVkaWF0ZScpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIFN0YXJ0cyBzaG93aW5nIHRoZSBwcm9ncmVzcyBiYXIgaW4gXCJpbmRldGVybWluYXRlXCIgbW9kZS4gKi9cbiAgICBwdWJsaWMgc3RhcnQoKTogdm9pZDtcblxuICAgIC8qKiBTdGFydHMgYW5pbWF0aW5nIHRoZSBwcm9ncmVzcyBiYXIsIGFuaW1hdGVzIGFzIFwiZmluaXNoZWRcIiB3aGVuIHRoZSBwYXNzZWQgUHJvbWlzZSByZXNvbHZlcy4gKi9cbiAgICBwdWJsaWMgc3RhcnQocHJvbWlzZTogUHJvbWlzZUxpa2U8YW55Pik6IHZvaWQ7XG5cbiAgICAvKiogQW5pbWF0ZXMgdGhlIHByb2dyZXNzIGJhciBieSBkaXNjcmV0ZSB2YWx1ZXMgKFswLi4uMV0pIGVtaXR0ZWQgYnkgdGhlIHBhc3NlZCBvYnNlcnZhYmxlLiAqL1xuICAgIHB1YmxpYyBzdGFydChwcm9ncmVzc09ic2VydmFibGU6IFN1YnNjcmliYWJsZTxudW1iZXI+KTogdm9pZDtcblxuICAgIC8qKlxuICAgICAqIEFuaW1hdGVzIHRoZSBwcm9ncmVzcyBiYXIgYmFzZWQgb24gdGhlIHZhbHVlcyBlbWl0dGVkIGJ5IHRoZSBwYXNzZWQgb2JzZXJ2YWJsZS5cbiAgICAgKiBgdHJ1ZWAgYW5pbWF0ZXMgYXMgXCJhY3RpdmVcIiwgYGZhbHNlYCBhcyBcImNvbXBsZXRlZFwiLlxuICAgICAqL1xuICAgIHB1YmxpYyBzdGFydChwcm9ncmVzc09ic2VydmFibGU6IFN1YnNjcmliYWJsZTxib29sZWFuPik6IHZvaWQ7XG5cbiAgICBwdWJsaWMgc3RhcnQocHJvbWlzZU9yT2JzZXJ2YWJsZT86IFByb21pc2VMaWtlPGFueT4gfCBTdWJzY3JpYmFibGU8bnVtYmVyPiB8IFN1YnNjcmliYWJsZTxib29sZWFuPik6IHZvaWQ7XG5cbiAgICBwdWJsaWMgc3RhcnQocHJvbWlzZU9yT2JzZXJ2YWJsZT86IFByb21pc2VMaWtlPGFueT4gfCBTdWJzY3JpYmFibGU8YW55Pik6IHZvaWQge1xuICAgICAgICBpZiAocHJvbWlzZU9yT2JzZXJ2YWJsZSAhPT0gdGhpcy5jdXJyZW50UHJvbWlzZU9yT2JzZXJ2YWJsZSkge1xuICAgICAgICAgICAgdGhpcy5jbGVhbnVwU3Vic2NyaXB0aW9uKCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIXRoaXMuaXNBY3RpdmUpIHtcbiAgICAgICAgICAgIHRoaXMuaXNBY3RpdmUgPSB0cnVlO1xuICAgICAgICAgICAgdGhpcy5sYXN0QW5pbWF0aW9uRnJhbWUgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICB0aGlzLndyYXBwZXJDbGFzc2VzLmFkZCgndmlzaWJsZScsIHRoaXMuZGV0ZXJtaW5hdGUgPyAnaXMtZGV0ZXJtaW5hdGUnIDogJ2lzLWluZGV0ZXJtaW5hdGUnKTtcbiAgICAgICAgICAgIHRoaXMud3JhcHBlckNsYXNzZXMucmVtb3ZlKHRoaXMuZGV0ZXJtaW5hdGUgPyAnaXMtaW5kZXRlcm1pbmF0ZScgOiAnaXMtZGV0ZXJtaW5hdGUnKTtcblxuICAgICAgICAgICAgaWYgKHRoaXMuZGV0ZXJtaW5hdGUpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFByb2dyZXNzQmFyV2lkdGgodGhpcy5wcm9ncmVzc1BlcmNlbnRhZ2UsICdpbW1lZGlhdGUnKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRQcm9ncmVzc0JhcldpZHRoKDAsICdpbW1lZGlhdGUnKTtcbiAgICAgICAgICAgICAgICB0aGlzLmFuaW1hdGVJbmRldGVybWluYXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaXNQcm9taXNlKHByb21pc2VPck9ic2VydmFibGUpKSB7XG4gICAgICAgICAgICBsZXQgb2JzZXJ2aW5nID0gdHJ1ZTtcbiAgICAgICAgICAgIHByb21pc2VPck9ic2VydmFibGUudGhlbihcbiAgICAgICAgICAgICAgICAoKSA9PiBvYnNlcnZpbmcgJiYgdGhpcy5jb21wbGV0ZSgpLFxuICAgICAgICAgICAgICAgICgpID0+IG9ic2VydmluZyAmJiB0aGlzLmNvbXBsZXRlKClcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICB0aGlzLmNsZWFudXBTdWJzY3JpcHRpb24gPSAoKSA9PiB7XG4gICAgICAgICAgICAgICAgb2JzZXJ2aW5nID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgdGhpcy5jbGVhbnVwU3Vic2NyaXB0aW9uID0gbm9vcDtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRQcm9taXNlT3JPYnNlcnZhYmxlID0gcHJvbWlzZU9yT2JzZXJ2YWJsZTtcbiAgICAgICAgfSBlbHNlIGlmIChpc1N1YnNjcmliYWJsZShwcm9taXNlT3JPYnNlcnZhYmxlKSkge1xuICAgICAgICAgICAgbGV0IHN1YiA9IHByb21pc2VPck9ic2VydmFibGUuc3Vic2NyaWJlKFxuICAgICAgICAgICAgICAgICh2YWx1ZTogbnVtYmVyIHwgYm9vbGVhbikgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wcm9ncmVzcyA9IHZhbHVlO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHZhbHVlID09PSB0cnVlICYmICF0aGlzLmlzQWN0aXZlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnN0YXJ0KHByb21pc2VPck9ic2VydmFibGUpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHZhbHVlID09PSBmYWxzZSAmJiB0aGlzLmlzQWN0aXZlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbXBsZXRlKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIChlcnJvcjogYW55KSA9PiB0aGlzLmNvbXBsZXRlKCksXG4gICAgICAgICAgICAgICAgKCkgPT4gdGhpcy5jb21wbGV0ZSgpXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdGhpcy5jbGVhbnVwU3Vic2NyaXB0aW9uID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgIHN1Yi51bnN1YnNjcmliZSgpO1xuICAgICAgICAgICAgICAgIHRoaXMuY2xlYW51cFN1YnNjcmlwdGlvbiA9IG5vb3A7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50UHJvbWlzZU9yT2JzZXJ2YWJsZSA9IHByb21pc2VPck9ic2VydmFibGU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBbmltYXRlcyB0aGUgcHJvZ3Jlc3MgYmFyIHRvIDEwMCUgYW5kIGhpZGVzIGl0XG4gICAgICovXG4gICAgcHVibGljIGNvbXBsZXRlKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5pc0FjdGl2ZSkge1xuICAgICAgICAgICAgdGhpcy5pc0FjdGl2ZSA9IGZhbHNlO1xuXG4gICAgICAgICAgICBpZiAodGhpcy5kZXRlcm1pbmF0ZSkge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLnByb2dyZXNzUGVyY2VudGFnZSA9PSAxMDApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5mYWRlT3V0UHJvZ3Jlc3NCYXIoKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnRyYW5zaXRpb25UbzEwMFBlcmNlbnQoKVxuICAgICAgICAgICAgICAgICAgICAgICAgLnRoZW4oKCkgPT4gdGhpcy5mYWRlT3V0UHJvZ3Jlc3NCYXIoKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgICAgIHRoaXMuY2xlYW51cCgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgY2xlYW51cCgpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuYW5pbWF0aW9uUmVxdWVzdCkge1xuICAgICAgICAgICAgY2FuY2VsQW5pbWF0aW9uRnJhbWUodGhpcy5hbmltYXRpb25SZXF1ZXN0KTtcbiAgICAgICAgICAgIHRoaXMuYW5pbWF0aW9uUmVxdWVzdCA9IHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucmVtb3ZlUGVuZGluZ0hhbmRsZXIoKTtcbiAgICAgICAgdGhpcy5jbGVhbnVwU3Vic2NyaXB0aW9uKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBmYWRlT3V0UHJvZ3Jlc3NCYXIoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICh0aGlzLnJlbW92ZVBlbmRpbmdIYW5kbGVyKSB7XG4gICAgICAgICAgICB0aGlzLnJlbW92ZVBlbmRpbmdIYW5kbGVyKCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbmV3IFByb21pc2U8dm9pZD4oIChyZXNvbHZlOiAoKSA9PiB2b2lkKSA9PiB0aGlzLnpvbmUucnVuKCgpID0+IHtcbiAgICAgICAgICAgIGxldCBlbGVtZW50ID0gdGhpcy5wcm9ncmVzc0JhcldyYXBwZXIubmF0aXZlRWxlbWVudDtcbiAgICAgICAgICAgIGNvbnN0IGNhbGxiYWNrID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlUGVuZGluZ0hhbmRsZXIoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFByb2dyZXNzQmFyV2lkdGgoMCwgJ2ltbWVkaWF0ZScpO1xuICAgICAgICAgICAgICAgIHRoaXMuem9uZS5ydW4ocmVzb2x2ZSk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgdGhpcy5yZW1vdmVQZW5kaW5nSGFuZGxlciA9ICgpID0+IHtcbiAgICAgICAgICAgICAgICBlbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RyYW5zaXRpb25lbmQnLCBjYWxsYmFjayk7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW1vdmVQZW5kaW5nSGFuZGxlciA9IG5vb3A7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCd0cmFuc2l0aW9uZW5kJywgY2FsbGJhY2spO1xuICAgICAgICAgICAgdGhpcy53cmFwcGVyQ2xhc3Nlcy5yZW1vdmUoJ3Zpc2libGUnKTtcbiAgICAgICAgfSkpO1xuICAgIH1cblxuICAgIHByaXZhdGUgc2V0UHJvZ3Jlc3NCYXJXaWR0aChwZXJjZW50OiBudW1iZXIsIGltbWVkaWF0ZT86IHN0cmluZyk6IHZvaWQge1xuICAgICAgICB0aGlzLnByb2dyZXNzUGVyY2VudGFnZSA9IHBlcmNlbnQ7XG5cbiAgICAgICAgY29uc3QgbmF0aXZlRWxlbWVudDogSFRNTEVsZW1lbnQgPSB0aGlzLnByb2dyZXNzSW5kaWNhdG9yICYmIHRoaXMucHJvZ3Jlc3NJbmRpY2F0b3IubmF0aXZlRWxlbWVudDtcbiAgICAgICAgaWYgKG5hdGl2ZUVsZW1lbnQpIHtcbiAgICAgICAgICAgIGNvbnN0IHN0eWxlID0gbmF0aXZlRWxlbWVudC5zdHlsZTtcbiAgICAgICAgICAgIGlmIChpbW1lZGlhdGUpIHtcbiAgICAgICAgICAgICAgICAvLyBEb24ndCBhbmltYXRlIHRoZSBjaGFuZ2VcbiAgICAgICAgICAgICAgICBzdHlsZS50cmFuc2l0aW9uRHVyYXRpb24gPSBzdHlsZS53ZWJraXRUcmFuc2l0aW9uRHVyYXRpb24gPSAnMHMnO1xuICAgICAgICAgICAgICAgIHN0eWxlLndpZHRoID0gcGVyY2VudCArICclJztcbiAgICAgICAgICAgICAgICBsZXQgZ2V0V2lkdGhPbmNlID0gbmF0aXZlRWxlbWVudC5vZmZzZXRXaWR0aDtcbiAgICAgICAgICAgICAgICBzdHlsZS50cmFuc2l0aW9uRHVyYXRpb24gPSBzdHlsZS53ZWJraXRUcmFuc2l0aW9uRHVyYXRpb24gPSAnJztcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc3R5bGUud2lkdGggPSBwZXJjZW50ICsgJyUnO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSB0cmFuc2l0aW9uVG8xMDBQZXJjZW50KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5yZW1vdmVQZW5kaW5nSGFuZGxlcikge1xuICAgICAgICAgICAgdGhpcy5yZW1vdmVQZW5kaW5nSGFuZGxlcigpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPihyZXNvbHZlID0+IHtcbiAgICAgICAgICAgIGxldCBlbGVtZW50ID0gdGhpcy5wcm9ncmVzc0luZGljYXRvci5uYXRpdmVFbGVtZW50O1xuICAgICAgICAgICAgaWYgKHRoaXMuZGV0ZXJtaW5hdGUpIHtcbiAgICAgICAgICAgICAgICAvLyB0cmFuc2l0aW9uIHRoZSBwcm9ncmVzcyBpbmRpY2F0b3IgaW4gYSBjYW5jZWxhYmxlIHdheVxuICAgICAgICAgICAgICAgIGxldCBjYWxsYmFjayA9ICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZW1vdmVQZW5kaW5nSGFuZGxlcigpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnpvbmUucnVuKHJlc29sdmUpO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdGhpcy5yZW1vdmVQZW5kaW5nSGFuZGxlciA9ICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCd0cmFuc2l0aW9uZW5kJywgY2FsbGJhY2spO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJlbW92ZVBlbmRpbmdIYW5kbGVyID0gbm9vcDtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigndHJhbnNpdGlvbmVuZCcsIGNhbGxiYWNrKTtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFByb2dyZXNzQmFyV2lkdGgoMTAwKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gVXNlIHJlcXVlc3RBbmltYXRpb25GcmFtZSgpIGluIGEgY2FuY2VsYWJsZSB3YXlcbiAgICAgICAgICAgICAgICBsZXQgZnJhbWVSZXF1ZXN0OiBudW1iZXI7XG4gICAgICAgICAgICAgICAgbGV0IHdhaXRVbnRpbERvbmUgPSAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLnByb2dyZXNzUGVyY2VudGFnZSA9PT0gMTAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmcmFtZVJlcXVlc3QgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmcmFtZVJlcXVlc3QgPSByZXF1ZXN0QW5pbWF0aW9uRnJhbWUod2FpdFVudGlsRG9uZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGZyYW1lUmVxdWVzdCA9IHJlcXVlc3RBbmltYXRpb25GcmFtZSh3YWl0VW50aWxEb25lKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbW92ZVBlbmRpbmdIYW5kbGVyID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjYW5jZWxBbmltYXRpb25GcmFtZShmcmFtZVJlcXVlc3QpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJlbW92ZVBlbmRpbmdIYW5kbGVyID0gbm9vcDtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFuaW1hdGVJbmRldGVybWluYXRlKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmFuaW1hdGlvblJlcXVlc3QgPSB1bmRlZmluZWQ7XG4gICAgICAgIGlmICh0aGlzLmRldGVybWluYXRlKSB7IHJldHVybjsgfVxuXG4gICAgICAgIGxldCBub3cgPSB0eXBlb2YgcGVyZm9ybWFuY2UgPT09ICdvYmplY3QnID8gcGVyZm9ybWFuY2Uubm93KCkgOiBEYXRlLm5vdygpO1xuICAgICAgICBsZXQgZGVsdGEgPSAobm93IC0gdGhpcy5sYXN0QW5pbWF0aW9uRnJhbWUpIC8gMTAwMDtcblxuICAgICAgICBpZiAoIXRoaXMubGFzdEFuaW1hdGlvbkZyYW1lKSB7XG4gICAgICAgICAgICAvLyBBbmltYXRpb24gc3RhcnRpbmdcbiAgICAgICAgICAgIHRoaXMuc2V0UHJvZ3Jlc3NCYXJXaWR0aCgwKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLmlzQWN0aXZlKSB7XG4gICAgICAgICAgICAvLyBBbmltYXRlIFwiYWN0aXZlXCIgc3RhdGVcbiAgICAgICAgICAgIGxldCBmYWN0b3IgPSBkZWx0YSAqICg5MDAgLyB0aGlzLmluZGV0ZXJtaW5hdGVTcGVlZCk7XG4gICAgICAgICAgICBsZXQgcGVyY2VudCA9IHRoaXMucHJvZ3Jlc3NQZXJjZW50YWdlICsgZmFjdG9yICogTWF0aC5wb3coMSAtIE1hdGguc3FydCgxMDAgLSB0aGlzLnByb2dyZXNzUGVyY2VudGFnZSksIDIpO1xuICAgICAgICAgICAgdGhpcy5zZXRQcm9ncmVzc0JhcldpZHRoKE1hdGgubWF4KDAsIE1hdGgubWluKDEwMCwgcGVyY2VudCkpKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnByb2dyZXNzUGVyY2VudGFnZSA8IDEwMCkge1xuICAgICAgICAgICAgLy8gRG9uZSAtIGFuaW1hdGUgdG8gMTAwJVxuICAgICAgICAgICAgbGV0IHNwZWVkID0gKDkwMCAvIHRoaXMuaW5kZXRlcm1pbmF0ZVNwZWVkKTtcbiAgICAgICAgICAgIGxldCBmYWN0b3IgPSBzcGVlZCArIE1hdGgubWF4KDAsIDEgLSBzcGVlZCk7XG4gICAgICAgICAgICBsZXQgcGVyY2VudCA9IHRoaXMucHJvZ3Jlc3NQZXJjZW50YWdlICsgMjUwICogZGVsdGEgKiBmYWN0b3I7XG4gICAgICAgICAgICB0aGlzLnNldFByb2dyZXNzQmFyV2lkdGgoTWF0aC5tYXgoMCwgTWF0aC5taW4oMTAwLCBwZXJjZW50KSkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5mYWRlT3V0UHJvZ3Jlc3NCYXIoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMubGFzdEFuaW1hdGlvbkZyYW1lID0gbm93O1xuICAgICAgICB0aGlzLmFuaW1hdGlvblJlcXVlc3QgPSByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoXG4gICAgICAgICAgICAoKSA9PiB0aGlzLmFuaW1hdGVJbmRldGVybWluYXRlKClcbiAgICAgICAgKTtcbiAgICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwicHJvZ3Jlc3MtYmFyLXdyYXBwZXJcIiAjcHJvZ3Jlc3NCYXJXcmFwcGVyPlxuICAgIDxkaXYgY2xhc3M9XCJwcm9ncmVzcy1pbmRpY2F0b3JcIiAjcHJvZ3Jlc3NJbmRpY2F0b3I+PC9kaXY+XG48L2Rpdj5cbiJdfQ==