UNPKG

ngx-bootstrap

Version:
925 lines (913 loc) 87.6 kB
import { Injectable, Component, ElementRef, HostListener, Renderer2, Directive, EventEmitter, Input, Output, ViewContainerRef, RendererFactory2, NgModule } from '@angular/core'; import { isBs3, Utils, document as document$1, window as window$1 } from 'ngx-bootstrap/utils'; import { ComponentLoaderFactory } from 'ngx-bootstrap/component-loader'; import { PositioningService } from 'ngx-bootstrap/positioning'; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class BsModalRef { constructor() { /** * Hides the modal */ this.hide = Function; } } BsModalRef.decorators = [ { type: Injectable } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class ModalBackdropOptions { /** * @param {?} options */ constructor(options) { this.animate = true; Object.assign(this, options); } } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class ModalOptions { } ModalOptions.decorators = [ { type: Injectable } ]; const /** @type {?} */ modalConfigDefaults = { backdrop: true, keyboard: true, focus: true, show: false, ignoreBackdropClick: false, class: '', animated: true, initialState: {} }; const /** @type {?} */ CLASS_NAME = { SCROLLBAR_MEASURER: 'modal-scrollbar-measure', BACKDROP: 'modal-backdrop', OPEN: 'modal-open', FADE: 'fade', IN: 'in', // bs3 SHOW: 'show' // bs4 }; const /** @type {?} */ TRANSITION_DURATIONS = { MODAL: 300, BACKDROP: 150 }; const /** @type {?} */ DISMISS_REASONS = { BACKRDOP: 'backdrop-click', ESC: 'esc' }; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class ModalContainerComponent { /** * @param {?} options * @param {?} _element * @param {?} _renderer */ constructor(options, _element, _renderer) { this._element = _element; this._renderer = _renderer; this.isShown = false; this.isModalHiding = false; this.config = Object.assign({}, options); } /** * @return {?} */ ngOnInit() { if (this.isAnimated) { this._renderer.addClass(this._element.nativeElement, CLASS_NAME.FADE); } this._renderer.setStyle(this._element.nativeElement, 'display', 'block'); setTimeout(() => { this.isShown = true; this._renderer.addClass(this._element.nativeElement, isBs3() ? CLASS_NAME.IN : CLASS_NAME.SHOW); }, this.isAnimated ? TRANSITION_DURATIONS.BACKDROP : 0); if (document && document.body) { if (this.bsModalService.getModalsCount() === 1) { this.bsModalService.checkScrollbar(); this.bsModalService.setScrollbar(); } this._renderer.addClass(document.body, CLASS_NAME.OPEN); } if (this._element.nativeElement) { this._element.nativeElement.focus(); } } /** * @param {?} event * @return {?} */ onClick(event) { if (this.config.ignoreBackdropClick || this.config.backdrop === 'static' || event.target !== this._element.nativeElement) { return; } this.bsModalService.setDismissReason(DISMISS_REASONS.BACKRDOP); this.hide(); } /** * @param {?} event * @return {?} */ onEsc(event) { if (!this.isShown) { return; } // tslint:disable-next-line:deprecation if (event.keyCode === 27 || event.key === 'Escape') { event.preventDefault(); } if (this.config.keyboard && this.level === this.bsModalService.getModalsCount()) { this.bsModalService.setDismissReason(DISMISS_REASONS.ESC); this.hide(); } } /** * @return {?} */ ngOnDestroy() { if (this.isShown) { this.hide(); } } /** * @return {?} */ hide() { if (this.isModalHiding || !this.isShown) { return; } this.isModalHiding = true; this._renderer.removeClass(this._element.nativeElement, isBs3() ? CLASS_NAME.IN : CLASS_NAME.SHOW); setTimeout(() => { this.isShown = false; if (document && document.body && this.bsModalService.getModalsCount() === 1) { this._renderer.removeClass(document.body, CLASS_NAME.OPEN); } this.bsModalService.hide(this.level); this.isModalHiding = false; }, this.isAnimated ? TRANSITION_DURATIONS.MODAL : 0); } } ModalContainerComponent.decorators = [ { type: Component, args: [{ selector: 'modal-container', template: ` <div [class]="'modal-dialog' + (config.class ? ' ' + config.class : '')" role="document"> <div class="modal-content"> <ng-content></ng-content> </div> </div> `, host: { class: 'modal', role: 'dialog', tabindex: '-1', '[attr.aria-modal]': 'true' } }] } ]; /** @nocollapse */ ModalContainerComponent.ctorParameters = () => [ { type: ModalOptions, }, { type: ElementRef, }, { type: Renderer2, }, ]; ModalContainerComponent.propDecorators = { "onClick": [{ type: HostListener, args: ['click', ['$event'],] },], "onEsc": [{ type: HostListener, args: ['window:keydown.esc', ['$event'],] },], }; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /** * This component will be added as background layout for modals if enabled */ class ModalBackdropComponent { /** * @param {?} element * @param {?} renderer */ constructor(element, renderer) { this._isShown = false; this.element = element; this.renderer = renderer; } /** * @return {?} */ get isAnimated() { return this._isAnimated; } /** * @param {?} value * @return {?} */ set isAnimated(value) { this._isAnimated = value; // this.renderer.setElementClass(this.element.nativeElement, `${ClassName.FADE}`, value); } /** * @return {?} */ get isShown() { return this._isShown; } /** * @param {?} value * @return {?} */ set isShown(value) { this._isShown = value; if (value) { this.renderer.addClass(this.element.nativeElement, `${CLASS_NAME.IN}`); } else { this.renderer.removeClass(this.element.nativeElement, `${CLASS_NAME.IN}`); } if (!isBs3()) { if (value) { this.renderer.addClass(this.element.nativeElement, `${CLASS_NAME.SHOW}`); } else { this.renderer.removeClass(this.element.nativeElement, `${CLASS_NAME.SHOW}`); } } } /** * @return {?} */ ngOnInit() { if (this.isAnimated) { this.renderer.addClass(this.element.nativeElement, `${CLASS_NAME.FADE}`); Utils.reflow(this.element.nativeElement); } this.isShown = true; } } ModalBackdropComponent.decorators = [ { type: Component, args: [{ selector: 'bs-modal-backdrop', template: ' ', host: { class: CLASS_NAME.BACKDROP } }] } ]; /** @nocollapse */ ModalBackdropComponent.ctorParameters = () => [ { type: ElementRef, }, { type: Renderer2, }, ]; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ const /** @type {?} */ TRANSITION_DURATION = 300; const /** @type {?} */ BACKDROP_TRANSITION_DURATION = 150; /** * Mark any code with directive to show it's content in modal */ class ModalDirective { /** * @param {?} _element * @param {?} _viewContainerRef * @param {?} _renderer * @param {?} clf */ constructor(_element, _viewContainerRef, _renderer, clf) { this._element = _element; this._renderer = _renderer; /** * This event fires immediately when the `show` instance method is called. */ this.onShow = new EventEmitter(); /** * This event is fired when the modal has been made visible to the user * (will wait for CSS transitions to complete) */ this.onShown = new EventEmitter(); /** * This event is fired immediately when * the hide instance method has been called. */ this.onHide = new EventEmitter(); /** * This event is fired when the modal has finished being * hidden from the user (will wait for CSS transitions to complete). */ this.onHidden = new EventEmitter(); this._isShown = false; this.isBodyOverflowing = false; this.originalBodyPadding = 0; this.scrollbarWidth = 0; this.timerHideModal = 0; this.timerRmBackDrop = 0; this.isNested = false; this._backdrop = clf.createLoader(_element, _viewContainerRef, _renderer); } /** * allows to set modal configuration via element property * @param {?} conf * @return {?} */ set config(conf) { this._config = this.getConfig(conf); } /** * @return {?} */ get config() { return this._config; } /** * @return {?} */ get isShown() { return this._isShown; } /** * @param {?} event * @return {?} */ onClick(event) { if (this.config.ignoreBackdropClick || this.config.backdrop === 'static' || event.target !== this._element.nativeElement) { return; } this.dismissReason = DISMISS_REASONS.BACKRDOP; this.hide(event); } /** * @param {?} event * @return {?} */ onEsc(event) { if (!this._isShown) { return; } // tslint:disable-next-line:deprecation if (event.keyCode === 27 || event.key === 'Escape') { event.preventDefault(); } if (this.config.keyboard) { this.dismissReason = DISMISS_REASONS.ESC; this.hide(); } } /** * @return {?} */ ngOnDestroy() { this.config = void 0; if (this._isShown) { this._isShown = false; this.hideModal(); this._backdrop.dispose(); } } /** * @return {?} */ ngOnInit() { this._config = this._config || this.getConfig(); setTimeout(() => { if (this._config.show) { this.show(); } }, 0); } /** * Allows to manually toggle modal visibility * @return {?} */ toggle() { return this._isShown ? this.hide() : this.show(); } /** * Allows to manually open modal * @return {?} */ show() { this.dismissReason = null; this.onShow.emit(this); if (this._isShown) { return; } clearTimeout(this.timerHideModal); clearTimeout(this.timerRmBackDrop); this._isShown = true; this.checkScrollbar(); this.setScrollbar(); if (document$1 && document$1.body) { if (document$1.body.classList.contains(CLASS_NAME.OPEN)) { this.isNested = true; } else { this._renderer.addClass(document$1.body, CLASS_NAME.OPEN); } } this.showBackdrop(() => { this.showElement(); }); } /** * Allows to manually close modal * @param {?=} event * @return {?} */ hide(event) { if (event) { event.preventDefault(); } this.onHide.emit(this); // todo: add an option to prevent hiding if (!this._isShown) { return; } window$1.clearTimeout(this.timerHideModal); window$1.clearTimeout(this.timerRmBackDrop); this._isShown = false; this._renderer.removeClass(this._element.nativeElement, CLASS_NAME.IN); if (!isBs3()) { this._renderer.removeClass(this._element.nativeElement, CLASS_NAME.SHOW); } // this._addClassIn = false; if (this._config.animated) { this.timerHideModal = window$1.setTimeout(() => this.hideModal(), TRANSITION_DURATION); } else { this.hideModal(); } } /** * Private methods \@internal * @param {?=} config * @return {?} */ getConfig(config) { return Object.assign({}, modalConfigDefaults, config); } /** * Show dialog * \@internal * @return {?} */ showElement() { // todo: replace this with component loader usage if (!this._element.nativeElement.parentNode || this._element.nativeElement.parentNode.nodeType !== Node.ELEMENT_NODE) { // don't move modals dom position if (document$1 && document$1.body) { document$1.body.appendChild(this._element.nativeElement); } } this._renderer.setAttribute(this._element.nativeElement, 'aria-hidden', 'false'); this._renderer.setAttribute(this._element.nativeElement, 'aria-modal', 'true'); this._renderer.setStyle(this._element.nativeElement, 'display', 'block'); this._renderer.setProperty(this._element.nativeElement, 'scrollTop', 0); if (this._config.animated) { Utils.reflow(this._element.nativeElement); } // this._addClassIn = true; this._renderer.addClass(this._element.nativeElement, CLASS_NAME.IN); if (!isBs3()) { this._renderer.addClass(this._element.nativeElement, CLASS_NAME.SHOW); } const /** @type {?} */ transitionComplete = () => { if (this._config.focus) { this._element.nativeElement.focus(); } this.onShown.emit(this); }; if (this._config.animated) { setTimeout(transitionComplete, TRANSITION_DURATION); } else { transitionComplete(); } } /** * \@internal * @return {?} */ hideModal() { this._renderer.setAttribute(this._element.nativeElement, 'aria-hidden', 'true'); this._renderer.setStyle(this._element.nativeElement, 'display', 'none'); this.showBackdrop(() => { if (!this.isNested) { if (document$1 && document$1.body) { this._renderer.removeClass(document$1.body, CLASS_NAME.OPEN); } this.resetScrollbar(); } this.resetAdjustments(); this.focusOtherModal(); this.onHidden.emit(this); }); } /** * \@internal * @param {?=} callback * @return {?} */ showBackdrop(callback) { if (this._isShown && this.config.backdrop && (!this.backdrop || !this.backdrop.instance.isShown)) { this.removeBackdrop(); this._backdrop .attach(ModalBackdropComponent) .to('body') .show({ isAnimated: this._config.animated }); this.backdrop = this._backdrop._componentRef; if (!callback) { return; } if (!this._config.animated) { callback(); return; } setTimeout(callback, BACKDROP_TRANSITION_DURATION); } else if (!this._isShown && this.backdrop) { this.backdrop.instance.isShown = false; const /** @type {?} */ callbackRemove = () => { this.removeBackdrop(); if (callback) { callback(); } }; if (this.backdrop.instance.isAnimated) { this.timerRmBackDrop = window$1.setTimeout(callbackRemove, BACKDROP_TRANSITION_DURATION); } else { callbackRemove(); } } else if (callback) { callback(); } } /** * \@internal * @return {?} */ removeBackdrop() { this._backdrop.hide(); } /** * Events tricks * @return {?} */ focusOtherModal() { if (this._element.nativeElement.parentElement == null) { return; } const /** @type {?} */ otherOpenedModals = this._element.nativeElement.parentElement.querySelectorAll('.in[bsModal]'); if (!otherOpenedModals.length) { return; } otherOpenedModals[otherOpenedModals.length - 1].focus(); } /** * \@internal * @return {?} */ resetAdjustments() { this._renderer.setStyle(this._element.nativeElement, 'paddingLeft', ''); this._renderer.setStyle(this._element.nativeElement, 'paddingRight', ''); } /** * \@internal * @return {?} */ checkScrollbar() { this.isBodyOverflowing = document$1.body.clientWidth < window$1.innerWidth; this.scrollbarWidth = this.getScrollbarWidth(); } /** * @return {?} */ setScrollbar() { if (!document$1) { return; } this.originalBodyPadding = parseInt(window$1 .getComputedStyle(document$1.body) .getPropertyValue('padding-right') || 0, 10); if (this.isBodyOverflowing) { document$1.body.style.paddingRight = `${this.originalBodyPadding + this.scrollbarWidth}px`; } } /** * @return {?} */ resetScrollbar() { document$1.body.style.paddingRight = `${this.originalBodyPadding}px`; } /** * @return {?} */ getScrollbarWidth() { const /** @type {?} */ scrollDiv = this._renderer.createElement('div'); this._renderer.addClass(scrollDiv, CLASS_NAME.SCROLLBAR_MEASURER); this._renderer.appendChild(document$1.body, scrollDiv); const /** @type {?} */ scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth; this._renderer.removeChild(document$1.body, scrollDiv); return scrollbarWidth; } } ModalDirective.decorators = [ { type: Directive, args: [{ selector: '[bsModal]', exportAs: 'bs-modal' },] } ]; /** @nocollapse */ ModalDirective.ctorParameters = () => [ { type: ElementRef, }, { type: ViewContainerRef, }, { type: Renderer2, }, { type: ComponentLoaderFactory, }, ]; ModalDirective.propDecorators = { "config": [{ type: Input },], "onShow": [{ type: Output },], "onShown": [{ type: Output },], "onHide": [{ type: Output },], "onHidden": [{ type: Output },], "onClick": [{ type: HostListener, args: ['click', ['$event'],] },], "onEsc": [{ type: HostListener, args: ['keydown.esc', ['$event'],] },], }; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class BsModalService { /** * @param {?} rendererFactory * @param {?} clf */ constructor(rendererFactory, clf) { this.clf = clf; // constructor props this.config = modalConfigDefaults; // tslint:disable-next-line:no-any this.onShow = new EventEmitter(); // tslint:disable-next-line:no-any this.onShown = new EventEmitter(); // tslint:disable-next-line:no-any this.onHide = new EventEmitter(); // tslint:disable-next-line:no-any this.onHidden = new EventEmitter(); this.isBodyOverflowing = false; this.originalBodyPadding = 0; this.scrollbarWidth = 0; this.modalsCount = 0; this.lastDismissReason = ''; this.loaders = []; this._backdropLoader = this.clf.createLoader(null, null, null); this._renderer = rendererFactory.createRenderer(null, null); } /** * Shows a modal * @param {?} content * @param {?=} config * @return {?} */ show(content, config) { this.modalsCount++; this._createLoaders(); this.config = Object.assign({}, modalConfigDefaults, config); this._showBackdrop(); this.lastDismissReason = null; return this._showModal(content); } /** * @param {?} level * @return {?} */ hide(level) { if (this.modalsCount === 1) { this._hideBackdrop(); this.resetScrollbar(); } this.modalsCount = this.modalsCount >= 1 ? this.modalsCount - 1 : 0; setTimeout(() => { this._hideModal(level); this.removeLoaders(level); }, this.config.animated ? TRANSITION_DURATIONS.BACKDROP : 0); } /** * @return {?} */ _showBackdrop() { const /** @type {?} */ isBackdropEnabled = this.config.backdrop || this.config.backdrop === 'static'; const /** @type {?} */ isBackdropInDOM = !this.backdropRef || !this.backdropRef.instance.isShown; if (this.modalsCount === 1) { this.removeBackdrop(); if (isBackdropEnabled && isBackdropInDOM) { this._backdropLoader .attach(ModalBackdropComponent) .to('body') .show({ isAnimated: this.config.animated }); this.backdropRef = this._backdropLoader._componentRef; } } } /** * @return {?} */ _hideBackdrop() { if (!this.backdropRef) { return; } this.backdropRef.instance.isShown = false; const /** @type {?} */ duration = this.config.animated ? TRANSITION_DURATIONS.BACKDROP : 0; setTimeout(() => this.removeBackdrop(), duration); } /** * @param {?} content * @return {?} */ _showModal(content) { const /** @type {?} */ modalLoader = this.loaders[this.loaders.length - 1]; const /** @type {?} */ bsModalRef = new BsModalRef(); const /** @type {?} */ modalContainerRef = modalLoader .provide({ provide: ModalOptions, useValue: this.config }) .provide({ provide: BsModalRef, useValue: bsModalRef }) .attach(ModalContainerComponent) .to('body') .show({ content, isAnimated: this.config.animated, initialState: this.config.initialState, bsModalService: this }); modalContainerRef.instance.level = this.getModalsCount(); bsModalRef.hide = () => { modalContainerRef.instance.hide(); }; bsModalRef.content = modalLoader.getInnerComponent() || null; return bsModalRef; } /** * @param {?} level * @return {?} */ _hideModal(level) { const /** @type {?} */ modalLoader = this.loaders[level - 1]; if (modalLoader) { modalLoader.hide(); } } /** * @return {?} */ getModalsCount() { return this.modalsCount; } /** * @param {?} reason * @return {?} */ setDismissReason(reason) { this.lastDismissReason = reason; } /** * @return {?} */ removeBackdrop() { this._backdropLoader.hide(); this.backdropRef = null; } /** * \@internal * @return {?} */ checkScrollbar() { this.isBodyOverflowing = document.body.clientWidth < window.innerWidth; this.scrollbarWidth = this.getScrollbarWidth(); } /** * @return {?} */ setScrollbar() { if (!document) { return; } this.originalBodyPadding = parseInt(window .getComputedStyle(document.body) .getPropertyValue('padding-right') || '0', 10); if (this.isBodyOverflowing) { document.body.style.paddingRight = `${this.originalBodyPadding + this.scrollbarWidth}px`; } } /** * @return {?} */ resetScrollbar() { document.body.style.paddingRight = `${this.originalBodyPadding}px`; } /** * @return {?} */ getScrollbarWidth() { const /** @type {?} */ scrollDiv = this._renderer.createElement('div'); this._renderer.addClass(scrollDiv, CLASS_NAME.SCROLLBAR_MEASURER); this._renderer.appendChild(document.body, scrollDiv); const /** @type {?} */ scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth; this._renderer.removeChild(document.body, scrollDiv); return scrollbarWidth; } /** * @return {?} */ _createLoaders() { const /** @type {?} */ loader = this.clf.createLoader(null, null, null); this.copyEvent(loader.onBeforeShow, this.onShow); this.copyEvent(loader.onShown, this.onShown); this.copyEvent(loader.onBeforeHide, this.onHide); this.copyEvent(loader.onHidden, this.onHidden); this.loaders.push(loader); } /** * @param {?} level * @return {?} */ removeLoaders(level) { this.loaders.splice(level - 1, 1); this.loaders.forEach((loader, i) => { loader.instance.level = i + 1; }); } /** * @param {?} from * @param {?} to * @return {?} */ copyEvent(from, to) { from.subscribe(() => { to.emit(this.lastDismissReason); }); } } BsModalService.decorators = [ { type: Injectable } ]; /** @nocollapse */ BsModalService.ctorParameters = () => [ { type: RendererFactory2, }, { type: ComponentLoaderFactory, }, ]; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class ModalModule { /** * @return {?} */ static forRoot() { return { ngModule: ModalModule, providers: [BsModalService, ComponentLoaderFactory, PositioningService] }; } } ModalModule.decorators = [ { type: NgModule, args: [{ declarations: [ ModalBackdropComponent, ModalDirective, ModalContainerComponent ], exports: [ModalBackdropComponent, ModalDirective], entryComponents: [ModalBackdropComponent, ModalContainerComponent] },] } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ export { BsModalRef, ModalBackdropOptions, ModalContainerComponent, ModalBackdropComponent, ModalOptions, ModalDirective, ModalModule, BsModalService, CLASS_NAME as ɵa }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWJvb3RzdHJhcC1tb2RhbC5qcy5tYXAiLCJzb3VyY2VzIjpbIm5nOi8vbmd4LWJvb3RzdHJhcC9tb2RhbC9icy1tb2RhbC1yZWYuc2VydmljZS50cyIsIm5nOi8vbmd4LWJvb3RzdHJhcC9tb2RhbC9tb2RhbC1iYWNrZHJvcC5vcHRpb25zLnRzIiwibmc6Ly9uZ3gtYm9vdHN0cmFwL21vZGFsL21vZGFsLW9wdGlvbnMuY2xhc3MudHMiLCJuZzovL25neC1ib290c3RyYXAvbW9kYWwvbW9kYWwtY29udGFpbmVyLmNvbXBvbmVudC50cyIsIm5nOi8vbmd4LWJvb3RzdHJhcC9tb2RhbC9tb2RhbC1iYWNrZHJvcC5jb21wb25lbnQudHMiLCJuZzovL25neC1ib290c3RyYXAvbW9kYWwvbW9kYWwuZGlyZWN0aXZlLnRzIiwibmc6Ly9uZ3gtYm9vdHN0cmFwL21vZGFsL2JzLW1vZGFsLnNlcnZpY2UudHMiLCJuZzovL25neC1ib290c3RyYXAvbW9kYWwvbW9kYWwubW9kdWxlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIEJzTW9kYWxSZWYge1xuICAvKipcbiAgICogUmVmZXJlbmNlIHRvIGEgY29tcG9uZW50IGluc2lkZSB0aGUgbW9kYWwuIE51bGwgaWYgbW9kYWwncyBiZWVuIGNyZWF0ZWQgd2l0aCBUZW1wbGF0ZVJlZlxuICAgKi9cbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLWFueVxuICBjb250ZW50PzogYW55IHwgbnVsbDtcblxuICAvKipcbiAgICogSGlkZXMgdGhlIG1vZGFsXG4gICAqL1xuICBoaWRlOiAoKSA9PiB2b2lkID0gRnVuY3Rpb247XG59XG4iLCJleHBvcnQgY2xhc3MgTW9kYWxCYWNrZHJvcE9wdGlvbnMge1xuICBhbmltYXRlID0gdHJ1ZTtcblxuICBjb25zdHJ1Y3RvcihvcHRpb25zOiBNb2RhbEJhY2tkcm9wT3B0aW9ucykge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcywgb3B0aW9ucyk7XG4gIH1cbn1cbiIsImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENsYXNzTmFtZSwgRGlzbWlzc1JlYXNvbnMsIFNlbGVjdG9yLCBUcmFuc2l0aW9uRHVyYXRpb25zIH0gZnJvbSAnLi9tb2RlbHMnO1xuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgTW9kYWxPcHRpb25zIHtcbiAgLyoqXG4gICAqICBJbmNsdWRlcyBhIG1vZGFsLWJhY2tkcm9wIGVsZW1lbnQuIEFsdGVybmF0aXZlbHksXG4gICAqICBzcGVjaWZ5IHN0YXRpYyBmb3IgYSBiYWNrZHJvcCB3aGljaCBkb2Vzbid0IGNsb3NlIHRoZSBtb2RhbCBvbiBjbGljay5cbiAgICovXG4gIGJhY2tkcm9wPzogYm9vbGVhbiB8ICdzdGF0aWMnO1xuICAvKipcbiAgICogQ2xvc2VzIHRoZSBtb2RhbCB3aGVuIGVzY2FwZSBrZXkgaXMgcHJlc3NlZC5cbiAgICovXG4gIGtleWJvYXJkPzogYm9vbGVhbjtcblxuICBmb2N1cz86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBTaG93cyB0aGUgbW9kYWwgd2hlbiBpbml0aWFsaXplZC5cbiAgICovXG4gIHNob3c/OiBib29sZWFuO1xuICAvKipcbiAgICogSWdub3JlIHRoZSBiYWNrZHJvcCBjbGlja1xuICAgKi9cbiAgaWdub3JlQmFja2Ryb3BDbGljaz86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBDc3MgY2xhc3MgZm9yIG9wZW5lZCBtb2RhbFxuICAgKi9cbiAgY2xhc3M/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUb2dnbGUgYW5pbWF0aW9uXG4gICAqL1xuICBhbmltYXRlZD86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBNb2RhbCBkYXRhXG4gICAqL1xuICBpbml0aWFsU3RhdGU/OiBPYmplY3Q7XG59XG5cblxuZXhwb3J0IGNvbnN0IG1vZGFsQ29uZmlnRGVmYXVsdHM6IE1vZGFsT3B0aW9ucyA9IHtcbiAgYmFja2Ryb3A6IHRydWUsXG4gIGtleWJvYXJkOiB0cnVlLFxuICBmb2N1czogdHJ1ZSxcbiAgc2hvdzogZmFsc2UsXG4gIGlnbm9yZUJhY2tkcm9wQ2xpY2s6IGZhbHNlLFxuICBjbGFzczogJycsXG4gIGFuaW1hdGVkOiB0cnVlLFxuICBpbml0aWFsU3RhdGU6IHt9XG59O1xuXG5leHBvcnQgY29uc3QgQ0xBU1NfTkFNRTogQ2xhc3NOYW1lID0ge1xuICBTQ1JPTExCQVJfTUVBU1VSRVI6ICdtb2RhbC1zY3JvbGxiYXItbWVhc3VyZScsXG4gIEJBQ0tEUk9QOiAnbW9kYWwtYmFja2Ryb3AnLFxuICBPUEVOOiAnbW9kYWwtb3BlbicsXG4gIEZBREU6ICdmYWRlJyxcbiAgSU46ICdpbicsIC8vIGJzM1xuICBTSE9XOiAnc2hvdycgLy8gYnM0XG59O1xuXG5leHBvcnQgY29uc3QgU0VMRUNUT1I6IFNlbGVjdG9yID0ge1xuICBESUFMT0c6ICcubW9kYWwtZGlhbG9nJyxcbiAgREFUQV9UT0dHTEU6ICdbZGF0YS10b2dnbGU9XCJtb2RhbFwiXScsXG4gIERBVEFfRElTTUlTUzogJ1tkYXRhLWRpc21pc3M9XCJtb2RhbFwiXScsXG4gIEZJWEVEX0NPTlRFTlQ6ICcubmF2YmFyLWZpeGVkLXRvcCwgLm5hdmJhci1maXhlZC1ib3R0b20sIC5pcy1maXhlZCdcbn07XG5cbmV4cG9ydCBjb25zdCBUUkFOU0lUSU9OX0RVUkFUSU9OUzogVHJhbnNpdGlvbkR1cmF0aW9ucyA9IHtcbiAgTU9EQUw6IDMwMCxcbiAgQkFDS0RST1A6IDE1MFxufTtcblxuZXhwb3J0IGNvbnN0IERJU01JU1NfUkVBU09OUzogRGlzbWlzc1JlYXNvbnMgPSB7XG4gIEJBQ0tSRE9QOiAnYmFja2Ryb3AtY2xpY2snLFxuICBFU0M6ICdlc2MnXG59O1xuIiwiaW1wb3J0IHtcbiAgQ29tcG9uZW50LFxuICBFbGVtZW50UmVmLFxuICBIb3N0TGlzdGVuZXIsXG4gIE9uRGVzdHJveSxcbiAgT25Jbml0LFxuICBSZW5kZXJlcjJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1xuICBDTEFTU19OQU1FLFxuICBESVNNSVNTX1JFQVNPTlMsXG4gIE1vZGFsT3B0aW9ucyxcbiAgVFJBTlNJVElPTl9EVVJBVElPTlNcbn0gZnJvbSAnLi9tb2RhbC1vcHRpb25zLmNsYXNzJztcbmltcG9ydCB7IEJzTW9kYWxTZXJ2aWNlIH0gZnJvbSAnLi9icy1tb2RhbC5zZXJ2aWNlJztcbmltcG9ydCB7IGlzQnMzIH0gZnJvbSAnbmd4LWJvb3RzdHJhcC91dGlscyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ21vZGFsLWNvbnRhaW5lcicsXG4gIHRlbXBsYXRlOiBgXG4gICAgPGRpdiBbY2xhc3NdPVwiJ21vZGFsLWRpYWxvZycgKyAoY29uZmlnLmNsYXNzID8gJyAnICsgY29uZmlnLmNsYXNzIDogJycpXCIgcm9sZT1cImRvY3VtZW50XCI+XG4gICAgICA8ZGl2IGNsYXNzPVwibW9kYWwtY29udGVudFwiPlxuICAgICAgICA8bmctY29udGVudD48L25nLWNvbnRlbnQ+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgYCxcbiAgaG9zdDoge1xuICAgIGNsYXNzOiAnbW9kYWwnLFxuICAgIHJvbGU6ICdkaWFsb2cnLFxuICAgIHRhYmluZGV4OiAnLTEnLFxuICAgICdbYXR0ci5hcmlhLW1vZGFsXSc6ICd0cnVlJ1xuICB9XG59KVxuZXhwb3J0IGNsYXNzIE1vZGFsQ29udGFpbmVyQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuICBjb25maWc6IE1vZGFsT3B0aW9ucztcbiAgaXNTaG93biA9IGZhbHNlO1xuICBsZXZlbDogbnVtYmVyO1xuICBpc0FuaW1hdGVkOiBib29sZWFuO1xuICBic01vZGFsU2VydmljZTogQnNNb2RhbFNlcnZpY2U7XG4gIHByaXZhdGUgaXNNb2RhbEhpZGluZyA9IGZhbHNlO1xuXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM6IE1vZGFsT3B0aW9ucyxcbiAgICAgICAgICAgICAgcHJvdGVjdGVkIF9lbGVtZW50OiBFbGVtZW50UmVmLFxuICAgICAgICAgICAgICBwcml2YXRlIF9yZW5kZXJlcjogUmVuZGVyZXIyKSB7XG4gICAgdGhpcy5jb25maWcgPSBPYmplY3QuYXNzaWduKHt9LCBvcHRpb25zKTtcbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmlzQW5pbWF0ZWQpIHtcbiAgICAgIHRoaXMuX3JlbmRlcmVyLmFkZENsYXNzKFxuICAgICAgICB0aGlzLl9lbGVtZW50Lm5hdGl2ZUVsZW1lbnQsXG4gICAgICAgIENMQVNTX05BTUUuRkFERVxuICAgICAgKTtcbiAgICB9XG4gICAgdGhpcy5fcmVuZGVyZXIuc2V0U3R5bGUoXG4gICAgICB0aGlzLl9lbGVtZW50Lm5hdGl2ZUVsZW1lbnQsXG4gICAgICAnZGlzcGxheScsXG4gICAgICAnYmxvY2snXG4gICAgKTtcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMuaXNTaG93biA9IHRydWU7XG4gICAgICB0aGlzLl9yZW5kZXJlci5hZGRDbGFzcyhcbiAgICAgICAgdGhpcy5fZWxlbWVudC5uYXRpdmVFbGVtZW50LFxuICAgICAgICBpc0JzMygpID8gQ0xBU1NfTkFNRS5JTiA6IENMQVNTX05BTUUuU0hPV1xuICAgICAgKTtcbiAgICB9LCB0aGlzLmlzQW5pbWF0ZWQgPyBUUkFOU0lUSU9OX0RVUkFUSU9OUy5CQUNLRFJPUCA6IDApO1xuICAgIGlmIChkb2N1bWVudCAmJiBkb2N1bWVudC5ib2R5KSB7XG4gICAgICBpZiAodGhpcy5ic01vZGFsU2VydmljZS5nZXRNb2RhbHNDb3VudCgpID09PSAxKSB7XG4gICAgICAgIHRoaXMuYnNNb2RhbFNlcnZpY2UuY2hlY2tTY3JvbGxiYXIoKTtcbiAgICAgICAgdGhpcy5ic01vZGFsU2VydmljZS5zZXRTY3JvbGxiYXIoKTtcbiAgICAgIH1cbiAgICAgIHRoaXMuX3JlbmRlcmVyLmFkZENsYXNzKGRvY3VtZW50LmJvZHksIENMQVNTX05BTUUuT1BFTik7XG4gICAgfVxuICAgIGlmICh0aGlzLl9lbGVtZW50Lm5hdGl2ZUVsZW1lbnQpIHtcbiAgICAgIHRoaXMuX2VsZW1lbnQubmF0aXZlRWxlbWVudC5mb2N1cygpO1xuICAgIH1cbiAgfVxuXG4gIEBIb3N0TGlzdGVuZXIoJ2NsaWNrJywgWyckZXZlbnQnXSlcbiAgb25DbGljayhldmVudDogTW91c2VFdmVudCk6IHZvaWQge1xuICAgIGlmIChcbiAgICAgIHRoaXMuY29uZmlnLmlnbm9yZUJhY2tkcm9wQ2xpY2sgfHxcbiAgICAgIHRoaXMuY29uZmlnLmJhY2tkcm9wID09PSAnc3RhdGljJyB8fFxuICAgICAgZXZlbnQudGFyZ2V0ICE9PSB0aGlzLl9lbGVtZW50Lm5hdGl2ZUVsZW1lbnRcbiAgICApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5ic01vZGFsU2VydmljZS5zZXREaXNtaXNzUmVhc29uKERJU01JU1NfUkVBU09OUy5CQUNLUkRPUCk7XG4gICAgdGhpcy5oaWRlKCk7XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCd3aW5kb3c6a2V5ZG93bi5lc2MnLCBbJyRldmVudCddKVxuICBvbkVzYyhldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5pc1Nob3duKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOmRlcHJlY2F0aW9uXG4gICAgaWYgKGV2ZW50LmtleUNvZGUgPT09IDI3IHx8IGV2ZW50LmtleSA9PT0gJ0VzY2FwZScpIHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuXG4gICAgaWYgKFxuICAgICAgdGhpcy5jb25maWcua2V5Ym9hcmQgJiZcbiAgICAgIHRoaXMubGV2ZWwgPT09IHRoaXMuYnNNb2RhbFNlcnZpY2UuZ2V0TW9kYWxzQ291bnQoKVxuICAgICkge1xuICAgICAgdGhpcy5ic01vZGFsU2VydmljZS5zZXREaXNtaXNzUmVhc29uKERJU01JU1NfUkVBU09OUy5FU0MpO1xuICAgICAgdGhpcy5oaWRlKCk7XG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaXNTaG93bikge1xuICAgICAgdGhpcy5oaWRlKCk7XG4gICAgfVxuICB9XG5cbiAgaGlkZSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5pc01vZGFsSGlkaW5nIHx8ICF0aGlzLmlzU2hvd24pIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5pc01vZGFsSGlkaW5nID0gdHJ1ZTtcbiAgICB0aGlzLl9yZW5kZXJlci5yZW1vdmVDbGFzcyhcbiAgICAgIHRoaXMuX2VsZW1lbnQubmF0aXZlRWxlbWVudCxcbiAgICAgIGlzQnMzKCkgPyBDTEFTU19OQU1FLklOIDogQ0xBU1NfTkFNRS5TSE9XXG4gICAgKTtcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMuaXNTaG93biA9IGZhbHNlO1xuICAgICAgaWYgKFxuICAgICAgICBkb2N1bWVudCAmJlxuICAgICAgICBkb2N1bWVudC5ib2R5ICYmXG4gICAgICAgIHRoaXMuYnNNb2RhbFNlcnZpY2UuZ2V0TW9kYWxzQ291bnQoKSA9PT0gMVxuICAgICAgKSB7XG4gICAgICAgIHRoaXMuX3JlbmRlcmVyLnJlbW92ZUNsYXNzKGRvY3VtZW50LmJvZHksIENMQVNTX05BTUUuT1BFTik7XG4gICAgICB9XG4gICAgICB0aGlzLmJzTW9kYWxTZXJ2aWNlLmhpZGUodGhpcy5sZXZlbCk7XG4gICAgICB0aGlzLmlzTW9kYWxIaWRpbmcgPSBmYWxzZTtcbiAgICB9LCB0aGlzLmlzQW5pbWF0ZWQgPyBUUkFOU0lUSU9OX0RVUkFUSU9OUy5NT0RBTCA6IDApO1xuICB9XG59XG4iLCJpbXBvcnQgeyBDb21wb25lbnQsIEVsZW1lbnRSZWYsIE9uSW5pdCwgUmVuZGVyZXIyIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmltcG9ydCB7IENMQVNTX05BTUUgfSBmcm9tICcuL21vZGFsLW9wdGlvbnMuY2xhc3MnO1xuaW1wb3J0IHsgaXNCczMsIFV0aWxzIH0gZnJvbSAnbmd4LWJvb3RzdHJhcC91dGlscyc7XG5cblxuLyoqIFRoaXMgY29tcG9uZW50IHdpbGwgYmUgYWRkZWQgYXMgYmFja2dyb3VuZCBsYXlvdXQgZm9yIG1vZGFscyBpZiBlbmFibGVkICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdicy1tb2RhbC1iYWNrZHJvcCcsXG4gIHRlbXBsYXRlOiAnICcsXG4gIGhvc3Q6IHsgY2xhc3M6IENMQVNTX05BTUUuQkFDS0RST1AgfVxufSlcbmV4cG9ydCBjbGFzcyBNb2RhbEJhY2tkcm9wQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgZ2V0IGlzQW5pbWF0ZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuX2lzQW5pbWF0ZWQ7XG4gIH1cblxuICBzZXQgaXNBbmltYXRlZCh2YWx1ZTogYm9vbGVhbikge1xuICAgIHRoaXMuX2lzQW5pbWF0ZWQgPSB2YWx1ZTtcbiAgICAvLyB0aGlzLnJlbmRlcmVyLnNldEVsZW1lbnRDbGFzcyh0aGlzLmVsZW1lbnQubmF0aXZlRWxlbWVudCwgYCR7Q2xhc3NOYW1lLkZBREV9YCwgdmFsdWUpO1xuICB9XG5cbiAgZ2V0IGlzU2hvd24oKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuX2lzU2hvd247XG4gIH1cblxuICBzZXQgaXNTaG93bih2YWx1ZTogYm9vbGVhbikge1xuICAgIHRoaXMuX2lzU2hvd24gPSB2YWx1ZTtcbiAgICBpZiAodmFsdWUpIHtcbiAgICAgIHRoaXMucmVuZGVyZXIuYWRkQ2xhc3MoXG4gICAgICAgIHRoaXMuZWxlbWVudC5uYXRpdmVFbGVtZW50LFxuICAgICAgICBgJHtDTEFTU19OQU1FLklOfWBcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMucmVuZGVyZXIucmVtb3ZlQ2xhc3MoXG4gICAgICAgIHRoaXMuZWxlbWVudC5uYXRpdmVFbGVtZW50LFxuICAgICAgICBgJHtDTEFTU19OQU1FLklOfWBcbiAgICAgICk7XG4gICAgfVxuICAgIGlmICghaXNCczMoKSkge1xuICAgICAgaWYgKHZhbHVlKSB7XG4gICAgICAgIHRoaXMucmVuZGVyZXIuYWRkQ2xhc3MoXG4gICAgICAgICAgdGhpcy5lbGVtZW50Lm5hdGl2ZUVsZW1lbnQsXG4gICAgICAgICAgYCR7Q0xBU1NfTkFNRS5TSE9XfWBcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMucmVuZGVyZXIucmVtb3ZlQ2xhc3MoXG4gICAgICAgICAgdGhpcy5lbGVtZW50Lm5hdGl2ZUVsZW1lbnQsXG4gICAgICAgICAgYCR7Q0xBU1NfTkFNRS5TSE9XfWBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBlbGVtZW50OiBFbGVtZW50UmVmO1xuICByZW5kZXJlcjogUmVuZGVyZXIyO1xuXG4gIHByb3RlY3RlZCBfaXNBbmltYXRlZDogYm9vbGVhbjtcbiAgcHJvdGVjdGVkIF9pc1Nob3duID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3IoZWxlbWVudDogRWxlbWVudFJlZiwgcmVuZGVyZXI6IFJlbmRlcmVyMikge1xuICAgIHRoaXMuZWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgdGhpcy5yZW5kZXJlciA9IHJlbmRlcmVyO1xuICB9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaXNBbmltYXRlZCkge1xuICAgICAgdGhpcy5yZW5kZXJlci5hZGRDbGFzcyhcbiAgICAgICAgdGhpcy5lbGVtZW50Lm5hdGl2ZUVsZW1lbnQsXG4gICAgICAgIGAke0NMQVNTX05BTUUuRkFERX1gXG4gICAgICApO1xuICAgICAgVXRpbHMucmVmbG93KHRoaXMuZWxlbWVudC5uYXRpdmVFbGVtZW50KTtcbiAgICB9XG4gICAgdGhpcy5pc1Nob3duID0gdHJ1ZTtcbiAgfVxufVxuIiwiLyogdHNsaW50OmRpc2FibGU6bWF4LWZpbGUtbGluZS1jb3VudCAqL1xuLy8gdG9kbzogc2hvdWxkIHdlIHN1cHBvcnQgZW5mb3JjZSBmb2N1cyBpbj9cbi8vIHRvZG86IGluIG9yaWdpbmFsIGJzIHRoZXJlIGFyZSB3YXMgYSB3YXkgdG8gcHJldmVudCBtb2RhbCBmcm9tIHNob3dpbmdcbi8vIHRvZG86IG9yaWdpbmFsIG1vZGFsIGhhZCByZXNpemUgZXZlbnRzXG5cbmltcG9ydCB7XG4gIENvbXBvbmVudFJlZiwgRGlyZWN0aXZlLCBFbGVtZW50UmVmLCBFdmVudEVtaXR0ZXIsIEhvc3RMaXN0ZW5lciwgSW5wdXQsXG4gIE9uRGVzdHJveSwgT25Jbml0LCBPdXRwdXQsIFJlbmRlcmVyMiwgVmlld0NvbnRhaW5lclJlZlxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuaW1wb3J0IHsgZG9jdW1lbnQsIHdpbmRvdywgaXNCczMsIFV0aWxzIH0gZnJvbSAnbmd4LWJvb3RzdHJhcC91dGlscyc7XG5pbXBvcnQgeyBNb2RhbEJhY2tkcm9wQ29tcG9uZW50IH0gZnJvbSAnLi9tb2RhbC1iYWNrZHJvcC5jb21wb25lbnQnO1xuaW1wb3J0IHtcbiAgQ0xBU1NfTkFNRSwgRElTTUlTU19SRUFTT05TLCBtb2RhbENvbmZpZ0RlZmF1bHRzLCBNb2RhbE9wdGlvbnNcbn0gZnJvbSAnLi9tb2RhbC1vcHRpb25zLmNsYXNzJztcbmltcG9ydCB7IENvbXBvbmVudExvYWRlciwgQ29tcG9uZW50TG9hZGVyRmFjdG9yeSB9IGZyb20gJ25neC1ib290c3RyYXAvY29tcG9uZW50LWxvYWRlcic7XG5cbmNvbnN0IFRSQU5TSVRJT05fRFVSQVRJT04gPSAzMDA7XG5jb25zdCBCQUNLRFJPUF9UUkFOU0lUSU9OX0RVUkFUSU9OID0gMTUwO1xuXG4vKiogTWFyayBhbnkgY29kZSB3aXRoIGRpcmVjdGl2ZSB0byBzaG93IGl0J3MgY29udGVudCBpbiBtb2RhbCAqL1xuQERpcmVjdGl2ZSh7XG4gIHNlbGVjdG9yOiAnW2JzTW9kYWxdJyxcbiAgZXhwb3J0QXM6ICdicy1tb2RhbCdcbn0pXG5leHBvcnQgY2xhc3MgTW9kYWxEaXJlY3RpdmUgaW1wbGVtZW50cyBPbkRlc3Ryb3ksIE9uSW5pdCB7XG4gIC8qKiBhbGxvd3MgdG8gc2V0IG1vZGFsIGNvbmZpZ3VyYXRpb24gdmlhIGVsZW1lbnQgcHJvcGVydHkgKi9cbiAgQElucHV0KClcbiAgc2V0IGNvbmZpZyhjb25mOiBNb2RhbE9wdGlvbnMpIHtcbiAgICB0aGlzLl9jb25maWcgPSB0aGlzLmdldENvbmZpZyhjb25mKTtcbiAgfVxuXG4gIGdldCBjb25maWcoKTogTW9kYWxPcHRpb25zIHtcbiAgICByZXR1cm4gdGhpcy5fY29uZmlnO1xuICB9XG5cbiAgLyoqIFRoaXMgZXZlbnQgZmlyZXMgaW1tZWRpYXRlbHkgd2hlbiB0aGUgYHNob3dgIGluc3RhbmNlIG1ldGhvZCBpcyBjYWxsZWQuICovXG4gIEBPdXRwdXQoKVxuICBvblNob3c6IEV2ZW50RW1pdHRlcjxNb2RhbERpcmVjdGl2ZT4gPSBuZXcgRXZlbnRFbWl0dGVyPE1vZGFsRGlyZWN0aXZlPigpO1xuICAvKiogVGhpcyBldmVudCBpcyBmaXJlZCB3aGVuIHRoZSBtb2RhbCBoYXMgYmVlbiBtYWRlIHZpc2libGUgdG8gdGhlIHVzZXJcbiAgICogKHdpbGwgd2FpdCBmb3IgQ1NTIHRyYW5zaXRpb25zIHRvIGNvbXBsZXRlKVxuICAgKi9cbiAgQE91dHB1dCgpXG4gIG9uU2hvd246IEV2ZW50RW1pdHRlcjxNb2RhbERpcmVjdGl2ZT4gPSBuZXcgRXZlbnRFbWl0dGVyPE1vZGFsRGlyZWN0aXZlPigpO1xuICAvKiogVGhpcyBldmVudCBpcyBmaXJlZCBpbW1lZGlhdGVseSB3aGVuXG4gICAqIHRoZSBoaWRlIGluc3RhbmNlIG1ldGhvZCBoYXMgYmVlbiBjYWxsZWQuXG4gICAqL1xuICBAT3V0cHV0KClcbiAgb25IaWRlOiBFdmVudEVtaXR0ZXI8TW9kYWxEaXJlY3RpdmU+ID0gbmV3IEV2ZW50RW1pdHRlcjxNb2RhbERpcmVjdGl2ZT4oKTtcbiAgLyoqIFRoaXMgZXZlbnQgaXMgZmlyZWQgd2hlbiB0aGUgbW9kYWwgaGFzIGZpbmlzaGVkIGJlaW5nXG4gICAqIGhpZGRlbiBmcm9tIHRoZSB1c2VyICh3aWxsIHdhaXQgZm9yIENTUyB0cmFuc2l0aW9ucyB0byBjb21wbGV0ZSkuXG4gICAqL1xuICBAT3V0cHV0KClcbiAgb25IaWRkZW46IEV2ZW50RW1pdHRlcjxNb2RhbERpcmVjdGl2ZT4gPSBuZXcgRXZlbnRFbWl0dGVyPE1vZGFsRGlyZWN0aXZlPigpO1xuXG4gIC8qKiBUaGlzIGZpZWxkIGNvbnRhaW5zIGxhc3QgZGlzbWlzcyByZWFzb24uXG4gICAqIFBvc3NpYmxlIHZhbHVlczogYGJhY2tkcm9wLWNsaWNrYCwgYGVzY2AgYW5kIGBudWxsYFxuICAgKiAoaWYgbW9kYWwgd2FzIGNsb3NlZCBieSBkaXJlY3QgY2FsbCBvZiBgLmhpZGUoKWApLlxuICAgKi9cbiAgZGlzbWlzc1JlYXNvbjogc3RyaW5nO1xuXG4gIGdldCBpc1Nob3duKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9pc1Nob3duO1xuICB9XG5cbiAgcHJvdGVjdGVkIF9jb25maWc6IE1vZGFsT3B0aW9ucztcbiAgcHJvdGVjdGVkIF9pc1Nob3duID0gZmFsc2U7XG5cbiAgcHJvdGVjdGVkIGlzQm9keU92ZXJmbG93aW5nID0gZmFsc2U7XG4gIHByb3RlY3RlZCBvcmlnaW5hbEJvZHlQYWRkaW5nID0gMDtcbiAgcHJvdGVjdGVkIHNjcm9sbGJhcldpZHRoID0gMDtcblxuICBwcm90ZWN0ZWQgdGltZXJIaWRlTW9kYWwgPSAwO1xuICBwcm90ZWN0ZWQgdGltZXJSbUJhY2tEcm9wID0gMDtcblxuICAvLyByZWZlcmVuY2UgdG8gYmFja2Ryb3AgY29tcG9uZW50XG4gIHByb3RlY3RlZCBiYWNrZHJvcDogQ29tcG9uZW50UmVmPE1vZGFsQmFja2Ryb3BDb21wb25lbnQ+O1xuICBwcml2YXRlIF9iYWNrZHJvcDogQ29tcG9uZW50TG9hZGVyPE1vZGFsQmFja2Ryb3BDb21wb25lbnQ+O1xuXG4gIHByaXZhdGUgaXNOZXN0ZWQgPSBmYWxzZTtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIF9lbGVtZW50OiBFbGVtZW50UmVmLFxuICAgICAgICAgICAgICBfdmlld0NvbnRhaW5lclJlZjogVmlld0NvbnRhaW5lclJlZixcbiAgICAgICAgICAgICAgcHJpdmF0ZSBfcmVuZGVyZXI6IFJlbmRlcmVyMixcbiAgICAgICAgICAgICAgY2xmOiBDb21wb25lbnRMb2FkZXJGYWN0b3J5KSB7XG4gICAgdGhpcy5fYmFja2Ryb3AgPSBjbGYuY3JlYXRlTG9hZGVyPE1vZGFsQmFja2Ryb3BDb21wb25lbnQ+KFxuICAgICAgX2VsZW1lbnQsXG4gICAgICBfdmlld0NvbnRhaW5lclJlZixcbiAgICAgIF9yZW5kZXJlclxuICAgICk7XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdjbGljaycsIFsnJGV2ZW50J10pXG4gIG9uQ2xpY2soZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoXG4gICAgICB0aGlzLmNvbmZpZy5pZ25vcmVCYWNrZHJvcENsaWNrIHx8XG4gICAgICB0aGlzLmNvbmZpZy5iYWNrZHJvcCA9PT0gJ3N0YXRpYycgfHxcbiAgICAgIGV2ZW50LnRhcmdldCAhPT0gdGhpcy5fZWxlbWVudC5uYXRpdmVFbGVtZW50XG4gICAgKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuZGlzbWlzc1JlYXNvbiA9IERJU01JU1NfUkVBU09OUy5CQUNLUkRPUDtcbiAgICB0aGlzLmhpZGUoZXZlbnQpO1xuICB9XG5cbiAgLy8gdG9kbzogY29uc2lkZXIgcHJldmVudGluZyBkZWZhdWx0IGFuZCBzdG9wcGluZyBwcm9wYWdhdGlvblxuICBASG9zdExpc3RlbmVyKCdrZXlkb3duLmVzYycsIFsnJGV2ZW50J10pXG4gIG9uRXNjKGV2ZW50OiBLZXlib2FyZEV2ZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLl9pc1Nob3duKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpkZXByZWNhdGlvblxuICAgIGlmIChldmVudC5rZXlDb2RlID09PSAyNyB8fCBldmVudC5rZXkgPT09ICdFc2NhcGUnKSB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmNvbmZpZy5rZXlib2FyZCkge1xuICAgICAgdGhpcy5kaXNtaXNzUmVhc29uID0gRElTTUlTU19SRUFTT05TLkVTQztcbiAgICAgIHRoaXMuaGlkZSgpO1xuICAgIH1cbiAgfVxuXG4gIG5nT25EZXN0cm95KCkge1xuICAgIHRoaXMuY29uZmlnID0gdm9pZCAwO1xuICAgIGlmICh0aGlzLl9pc1Nob3duKSB7XG4gICAgICB0aGlzLl9pc1Nob3duID0gZmFsc2U7XG4gICAgICB0aGlzLmhpZGVNb2RhbCgpO1xuICAgICAgdGhpcy5fYmFja2Ryb3AuZGlzcG9zZSgpO1xuICAgIH1cbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuX2NvbmZpZyA9IHRoaXMuX2NvbmZpZyB8fCB0aGlzLmdldENvbmZpZygpO1xuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgaWYgKHRoaXMuX2NvbmZpZy5zaG93KSB7XG4gICAgICAgIHRoaXMuc2hvdygpO1xuICAgICAgfVxuICAgIH0sIDApO1xuICB9XG5cbiAgLyogUHVibGljIG1ldGhvZHMgKi9cblxuICAvKiogQWxsb3dzIHRvIG1hbnVhbGx5IHRvZ2dsZSBtb2RhbCB2aXNpYmlsaXR5ICovXG4gIHRvZ2dsZSgpOiB2b2lkIHtcbiAgICByZXR1cm4gdGhpcy5faXNTaG93biA/IHRoaXMuaGlkZSgpIDogdGhpcy5zaG93KCk7XG4gIH1cblxuICAvKiogQWxsb3dzIHRvIG1hbnVhbGx5IG9wZW4gbW9kYWwgKi9cbiAgc2hvdygpOiB2b2lkIHtcbiAgICB0aGlzLmRpc21pc3NSZWFzb24gPSBudWxsO1xuICAgIHRoaXMub25TaG93LmVtaXQodGhpcyk7XG4gICAgaWYgKHRoaXMuX2lzU2hvd24pIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY2xlYXJUaW1lb3V0KHRoaXMudGltZXJIaWRlTW9kYWwpO1xuICAgIGNsZWFyVGltZW91dCh0aGlzLnRpbWVyUm1CYWNrRHJvcCk7XG5cbiAgICB0aGlzLl9pc1Nob3duID0gdHJ1ZTtcblxuICAgIHRoaXMuY2hlY2tTY3JvbGxiYXIoKTtcbiAgICB0aGlzLnNldFNjcm9sbGJhcigpO1xuXG4gICAgaWYgKGRvY3VtZW50ICYmIGRvY3VtZW50LmJvZHkpIHtcbiAgICAgIGlmIChkb2N1bWVudC5ib2R5LmNsYXNzTGlzdC5jb250YWlucyhDTEFTU19OQU1FLk9QRU4pKSB7XG4gICAgICAgIHRoaXMuaXNOZXN0ZWQgPSB0cnVlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5fcmVuZGVyZXIuYWRkQ2xhc3MoZG9jdW1lbnQuYm9keSwgQ0xBU1NfTkFNRS5PUEVOKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLnNob3dCYWNrZHJvcCgoKSA9PiB7XG4gICAgICB0aGlzLnNob3dFbGVtZW50KCk7XG4gICAgfSk7XG4gIH1cblxuICAvKiogQWxsb3dzIHRvIG1hbnVhbGx5IGNsb3NlIG1vZGFsICovXG4gIGhpZGUoZXZlbnQ/OiBFdmVudCk6IHZvaWQge1xuICAgIGlmIChldmVudCkge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG5cbiAgICB0aGlzLm9uSGlkZS5lbWl0KHRoaXMpO1xuXG4gICAgLy8gdG9kbzogYWRkIGFuIG9wdGlvbiB0byBwcmV2ZW50IGhpZGluZ1xuICAgIGlmICghdGhpcy5faXNTaG93bikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHdpbmRvdy5jbGVhclRpbWVvdXQodGhpcy50aW1lckhpZGVNb2RhbCk7XG4gICAgd2luZG93LmNsZWFyVGltZW91dCh0aGlzLnRpbWVyUm1CYWNrRHJvcCk7XG5cbiAgICB0aGlzLl9pc1Nob3duID0gZmFsc2U7XG4gICAgdGhpcy5fcmVuZGVyZXIucmVtb3ZlQ2xhc3ModGhpcy5fZWxlbWVudC5uYXRpdmVFbGVtZW50LCBDTEFTU19OQU1FLklOKTtcbiAgICBpZiAoIWlzQnMzKCkpIHtcbiAgICAgIHRoaXMuX3JlbmRlcmVyLnJlbW92ZUNsYXNzKHRoaXMuX2VsZW1lbnQubmF0aXZlRWxlbWVudCwgQ0xBU1NfTkFNRS5TSE9XKTtcbiAgICB9XG4gICAgLy8gdGhpcy5fYWRkQ2xhc3NJbiA9IGZhbHNlO1xuXG4gICAgaWYgKHRoaXMuX2NvbmZpZy5hbmltYXRlZCkge1xuICAgICAgdGhpcy50aW1lckhpZGVNb2RhbCA9IHdpbmRvdy5zZXRUaW1lb3V0KFxuICAgICAgICAoKSA9PiB0aGlzLmhpZGVNb2RhbCgpLFxuICAgICAgICBUUkFOU0lUSU9OX0RVUkFUSU9OXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmhpZGVNb2RhbCgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBQcml2YXRlIG1ldGhvZHMgQGludGVybmFsICovXG4gIHByb3RlY3RlZCBnZXRDb25maWcoY29uZmlnPzogTW9kYWxPcHRpb25zKTogTW9kYWxPcHRpb25zIHtcbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbih7fSwgbW9kYWxDb25maWdEZWZhdWx0cywgY29uZmlnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiAgU2hvdyBkaWFsb2dcbiAgICogIEBpbnRlcm5hbFxuICAgKi9cbiAgcHJvdGVjdGVkIHNob3dFbGVtZW50KCk6IHZvaWQge1xuICAgIC8vIHRvZG86IHJlcGxhY2UgdGhpcyB3aXRoIGNvbXBvbmVudCBsb2FkZXIgdXNhZ2VcbiAgICBpZiAoXG4gICAgICAhdGhpcy5fZWxlbWVudC5uYXRpdmVFbGVtZW50LnBhcmVudE5vZGUgfHxcbiAgICAgIHRoaXMuX2VsZW1lbnQubmF0aXZlRWxlbWVudC5wYXJlbnROb2RlLm5vZGVUeXBlICE9PSBOb2RlLkVMRU1FTlRfTk9ERVxuICAgICkge1xuICAgICAgLy8gZG9uJ3QgbW92ZSBtb2RhbHMgZG9tIHBvc2l0aW9uXG4gICAgICBpZiAoZG9jdW1lbnQgJiYgZG9jdW1lbnQuYm9keSkge1xuICAgICAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHRoaXMuX2VsZW1lbnQubmF0aXZlRWxlbWVudCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5fcmVuZGVyZXIuc2V0QXR0cmlidXRlKFxuICAgICAgdGhpcy5fZWxlbWVudC5uYXRpdmVFbGVtZW50LFxuICAgICAgJ2FyaWEtaGlkZGVuJyxcbiAgICAgICdmYWxzZSdcbiAgICApO1xuICAgIHRoaXMuX3JlbmRlcmVyLnNldEF0dHJpYnV0ZShcbiAgICAgIHRoaXMuX2VsZW1lbnQubmF0aXZlRWxlbWVudCxcbiAgICAgICdhcmlhLW1vZGFsJyxcbiAgICAgICd0cnVlJ1xuICAgICk7XG4gICAgdGhpcy5fcmVuZGVyZXIuc2V0U3R5bGUoXG4gICAgICB0aGlzLl9lbGVtZW50Lm5hdGl2ZUVsZW1lbnQsXG4gICAgICAnZGlzcGxheScsXG4gICAgICAnYmxvY2snXG4gICAgKTtcbiAgICB0aGlzLl9yZW5kZXJlci5zZXRQcm9wZXJ0eShcbiAgICAgIHRoaXMuX2VsZW1lbnQubmF0aXZlRWxlbWVudCxcbiAgICAgICdzY3JvbGxUb3AnLFxuICAgICAgMFxuICAgICk7XG5cbiAgICBpZiAodGhpcy5fY29uZmlnLmFuaW1hdGVkKSB7XG4gICAgICBVdGlscy5yZWZsb3codGhpcy5fZWxlbWVudC5uYXRpdmVFbGVtZW50KTtcbiAgICB9XG5cbiAgICAvLyB0aGlzLl9hZGRDbGFzc0luID0gdHJ1ZTtcbiAgICB0aGlzLl9yZW5kZXJlci5hZGRDbGFzcyh0aGlzLl9lbGVtZW50Lm5hdGl2ZUVsZW1lbnQsIENMQVNTX05BTUUuSU4pO1xuICAgIGlmICghaXNCczMoKSkge1xuICAgICAgdGhpcy5fcmVuZGVyZXIuYWRkQ2xhc3ModGhpcy5fZWxlbWVudC5uYXRpdmVFbGVtZW50LCBDTEFTU19OQU1FLlNIT1cpO1xuICAgIH1cblxuICAgIGNvbnN0IHRyYW5zaXRpb25Db21wbGV0ZSA9ICgpID0+IHtcbiAgICAgIGlmICh0aGlzLl9jb25maWcuZm9jdXMpIHtcbiAgICAgICAgdGhpcy5fZWxlbWVudC5uYXRpdmVFbGVtZW50LmZvY3VzKCk7XG4gICAgICB9XG4gICAgICB0aGlzLm9uU2hvd24uZW1pdCh0aGlzKTtcbiAgICB9O1xuXG4gICAgaWYgKHRoaXMuX2NvbmZpZy5hbmltYXRlZCkge1xuICAgICAgc2V0VGltZW91dCh0cmFuc2l0aW9uQ29tcGxldGUsIFRSQU5TSVRJT05fRFVSQVRJT04pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0cmFuc2l0aW9uQ29tcGxldGUoKTtcbiAgICB9XG4gIH1cblxuICAvKiogQGludGVybmFsICovXG4gIHByb3RlY3RlZCBoaWRlTW9kYWwoKTogdm9pZCB7XG4gICAgdGhpcy5fcmVuZGVyZXIuc2V0QXR0cmlidXRlKFxuICAgICAgdGhpcy5fZWxlbWVudC5uYXRpdmVFbGVtZW50LFxuICAgICAgJ2FyaWEtaGlkZGVuJyxcbiAgICAgICd0cnVlJ1xuICAgICk7XG4gICAgdGhpcy5fcmVuZGVyZXIuc2V0U3R5bGUoXG4gICAgICB0aGlzLl9lbGVtZW50Lm5hdGl2ZUVsZW1lbnQsXG4gICAgICAnZGlzcGxheScsXG4gICAgICAnbm9uZSdcbiAgICApO1xuICAgIHRoaXMuc2hvd0JhY2tkcm9wKCgpID0+IHtcbiAgICAgIGlmICghdGhpcy5pc05lc3RlZCkge1xuICAgICAgICBpZiAoZG9jdW1lbnQgJiYgZG9jdW1lbnQuYm9keSkge1xuICAgICAgICAgIHRoaXMuX3JlbmRlcmVyLnJlbW92ZUNsYXNzKGRvY3VtZW50LmJvZHksIENMQVNTX05BTUUuT1BFTik7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5yZXNldFNjcm9sbGJhcigpO1xuICAgICAgfVxuICAgICAgdGhpcy5yZXNldEFkanVzdG1lbnRzKCk7XG4gICAgICB0aGlzLmZvY3VzT3RoZXJNb2RhbCgpO1xuICAgICAgdGhpcy5vbkhpZGRlbi5lbWl0KHRoaXMpO1xuICAgIH0pO1xuICB9XG5cbiAgLy8gdG9kbzogb3JpZ2luYWwgc2hvdyB3YXMgY2FsbGluZyBhIGNhbGxiYWNrIHdoZW4gZG9uZSwgYnV0IHdlIGNhbiB1c2VcbiAgLy8gcHJvbWlzZVxuICAvKiogQGludGVybmFsICovXG4gIHByb3RlY3RlZCBzaG93QmFja2Ryb3AoY2FsbGJhY2s/OiBGdW5jdGlvbik6IHZvaWQge1xuICAgIGlmIChcbiAgICAgIHRoaXMuX2lzU2hvd24gJiZcbiAgICAgIHRoaXMuY29uZmlnLmJhY2tkcm9wICYmXG4gICAgICAoIXRoaXMuYmFja2Ryb3AgfHwgIXRoaXMuYmFja2Ryb3AuaW5zdGFuY2UuaXNTaG93bilcbiAgICApIHtcbiAgICAgIHRoaXMucmVtb3ZlQmFja2Ryb3AoKTtcbiAgICAgIHRoaXMuX2JhY2tkcm9wXG4gICAgICAgIC5hdHRhY2goTW9kYWxCYWNrZHJvcENvbXBvbmVudClcbiAgICAgICAgLnRvKCdib2R5JylcbiAgICAgICAgLnNob3coe2lzQW5pbWF0ZWQ6IHRoaXMuX2NvbmZpZy5hbmltYXRlZH0pO1xuICAgICAgdGhpcy5iYWNrZHJvcCA9IHRoaXMuX2JhY2tkcm9wLl9jb21wb25lbnRSZWY7XG5cbiAgICAgIGlmICghY2FsbGJhY2spIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoIXRoaXMuX2NvbmZpZy5hbmltYXRlZCkge1xuICAgICAgICBjYWxsYmFjaygpO1xuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgc2V0VGltZW91dChjYWxsYmFjaywgQkFDS0RST1BfVFJBTlNJVElPTl9EVVJBVElPTik7XG4gICAgfSBlbHNlIGlmICghdGhpcy5faXNTaG93biAmJiB0aGlzLmJhY2tkcm9wKSB7XG4gICAgICB0aGlzLmJhY2tkcm9wLmluc3RhbmNlLmlzU2hvd24gPSBmYWxzZTtcblxuICAgICAgY29uc3QgY2FsbGJhY2tSZW1vdmUgPSAoKSA9PiB7XG4gICAgICAgIHRoaXMucmVtb3ZlQmFja2Ryb3AoKTtcbiAgICAgICAgaWYgKGNhbGxiYWNrKSB7XG4gICAgICAgICAgY2FsbGJhY2soKTtcbiAg