UNPKG

@ng-bootstrap/ng-bootstrap

Version:
539 lines 56.3 kB
import { ChangeDetectorRef, ContentChild, ContentChildren, DestroyRef, Directive, ElementRef, EventEmitter, inject, Input, Output, TemplateRef, ViewContainerRef, } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { NgbAccordionConfig } from './accordion-config'; import { NgbCollapse } from '../collapse/collapse'; import { isString } from '../util/util'; import * as i0 from "@angular/core"; import * as i1 from "../collapse/collapse"; let nextId = 0; /** * A directive that wraps the content of an accordion item's collapsible body. * * The actual content is provided in a child `ng-template` element. * Depending on the state of the accordion, the template will be either inserted or removed from the DOM. * * @since 14.1.0 */ export class NgbAccordionBody { constructor() { this._vcr = inject(ViewContainerRef); this._element = inject((ElementRef)).nativeElement; this._item = inject(NgbAccordionItem); this._viewRef = null; } ngAfterContentChecked() { if (this._bodyTpl) { if (this._item._shouldBeInDOM) { this._createViewIfNotExists(); } else { this._destroyViewIfExists(); } } } ngOnDestroy() { this._destroyViewIfExists(); } _destroyViewIfExists() { if (this._viewRef) { this._viewRef.destroy(); this._viewRef = null; } } _createViewIfNotExists() { if (!this._viewRef) { this._viewRef = this._vcr.createEmbeddedView(this._bodyTpl); this._viewRef.detectChanges(); for (const node of this._viewRef.rootNodes) { this._element.appendChild(node); } } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbAccordionBody, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.0", type: NgbAccordionBody, isStandalone: true, selector: "[ngbAccordionBody]", host: { properties: { "class.accordion-body": "true" } }, queries: [{ propertyName: "_bodyTpl", first: true, predicate: TemplateRef, descendants: true, static: true }], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbAccordionBody, decorators: [{ type: Directive, args: [{ selector: '[ngbAccordionBody]', standalone: true, host: { '[class.accordion-body]': 'true' }, }] }], propDecorators: { _bodyTpl: [{ type: ContentChild, args: [TemplateRef, { static: true }] }] } }); /** * A directive that wraps the collapsible item's content of the accordion. * * Internally it reuses the [`NgbCollapse` directive](#/components/collapse) * * @since 14.1.0 */ export class NgbAccordionCollapse { constructor() { this.item = inject(NgbAccordionItem); this.ngbCollapse = inject(NgbCollapse); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbAccordionCollapse, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.0", type: NgbAccordionCollapse, isStandalone: true, selector: "[ngbAccordionCollapse]", host: { attributes: { "role": "region" }, properties: { "class.accordion-collapse": "true", "id": "item.collapseId", "attr.aria-labelledby": "item.toggleId" } }, exportAs: ["ngbAccordionCollapse"], hostDirectives: [{ directive: i1.NgbCollapse }], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbAccordionCollapse, decorators: [{ type: Directive, args: [{ exportAs: 'ngbAccordionCollapse', standalone: true, selector: '[ngbAccordionCollapse]', host: { role: 'region', '[class.accordion-collapse]': 'true', '[id]': 'item.collapseId', '[attr.aria-labelledby]': 'item.toggleId', }, hostDirectives: [NgbCollapse], }] }] }); /** * A directive to put on a toggling element inside the accordion item's header. * It will register click handlers that toggle the associated panel and will handle accessibility attributes. * * This directive is used internally by the [`NgbAccordionButton` directive](#/components/accordion/api#NgbAccordionButton). * * @since 14.1.0 */ export class NgbAccordionToggle { constructor() { this.item = inject(NgbAccordionItem); this.accordion = inject(NgbAccordionDirective); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbAccordionToggle, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.0", type: NgbAccordionToggle, isStandalone: true, selector: "[ngbAccordionToggle]", host: { listeners: { "click": "!item.disabled && accordion.toggle(item.id)" }, properties: { "id": "item.toggleId", "class.collapsed": "item.collapsed", "attr.aria-controls": "item.collapseId", "attr.aria-expanded": "!item.collapsed" } }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbAccordionToggle, decorators: [{ type: Directive, args: [{ selector: '[ngbAccordionToggle]', standalone: true, host: { '[id]': 'item.toggleId', '[class.collapsed]': 'item.collapsed', '[attr.aria-controls]': 'item.collapseId', '[attr.aria-expanded]': '!item.collapsed', '(click)': '!item.disabled && accordion.toggle(item.id)', }, }] }] }); /** * A directive to put on a button element inside an accordion item's header. * * If you want a custom markup for the header, you can also use the [`NgbAccordionToggle` directive](#/components/accordion/api#NgbAccordionToggle). * * @since 14.1.0 */ export class NgbAccordionButton { constructor() { this.item = inject(NgbAccordionItem); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbAccordionButton, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.0", type: NgbAccordionButton, isStandalone: true, selector: "button[ngbAccordionButton]", host: { attributes: { "type": "button" }, properties: { "disabled": "item.disabled", "class.accordion-button": "true" } }, hostDirectives: [{ directive: NgbAccordionToggle }], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbAccordionButton, decorators: [{ type: Directive, args: [{ selector: 'button[ngbAccordionButton]', standalone: true, host: { '[disabled]': 'item.disabled', '[class.accordion-button]': 'true', type: 'button', }, hostDirectives: [NgbAccordionToggle], }] }] }); /** * A directive that wraps an accordion item's header. * * @since 14.1.0 */ export class NgbAccordionHeader { constructor() { this.item = inject(NgbAccordionItem); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbAccordionHeader, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.0", type: NgbAccordionHeader, isStandalone: true, selector: "[ngbAccordionHeader]", host: { attributes: { "role": "heading" }, properties: { "class.accordion-header": "true", "class.collapsed": "item.collapsed" } }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbAccordionHeader, decorators: [{ type: Directive, args: [{ selector: '[ngbAccordionHeader]', standalone: true, host: { role: 'heading', '[class.accordion-header]': 'true', '[class.collapsed]': 'item.collapsed', }, }] }] }); /** * A directive that wraps an accordion item: a toggleable header + body that collapses. * * You can get hold of the `NgbAccordionItem` instance in the template with `#item="ngbAccordionItem"`. * It allows to check if the item is collapsed or not, toggle the collapse state, etc. * * Every accordion item has a string ID that is automatically generated in the `ngb-accordion-item-XX` format, unless provided explicitly. * * @since 14.1.0 */ export class NgbAccordionItem { constructor() { this._accordion = inject(NgbAccordionDirective); this._cd = inject(ChangeDetectorRef); this._destroyRef = inject(DestroyRef); this._collapsed = true; this._id = `ngb-accordion-item-${nextId++}`; this._collapseAnimationRunning = false; /** * If `true`, the accordion item will be disabled. * It won't react to user's clicks, but still will be toggelable programmatically. */ this.disabled = false; /** * Event emitted before the expanding animation starts. It has no payload. * * @since 15.1.0 */ this.show = new EventEmitter(); /** * Event emitted when the expanding animation is finished. It has no payload. */ this.shown = new EventEmitter(); /** * Event emitted before the collapsing animation starts. It has no payload. * * @since 15.1.0 */ this.hide = new EventEmitter(); /** * Event emitted when the collapsing animation is finished and before the content is removed from DOM. * It has no payload. */ this.hidden = new EventEmitter(); } /** * Sets the custom ID of the accordion item. It must be unique for the document. * * @param id The ID of the accordion item, must be a non-empty string */ set id(id) { if (isString(id) && id !== '') { this._id = id; } } /** * If `true`, the content of the accordion item's body will be removed from the DOM. It will be just hidden otherwise. * * This property can also be set up on the parent [`NgbAccordion` directive](#/components/accordion/api#NgbAccordionDirective). */ set destroyOnHide(destroyOnHide) { this._destroyOnHide = destroyOnHide; } get destroyOnHide() { return this._destroyOnHide === undefined ? this._accordion.destroyOnHide : this._destroyOnHide; } /** * If `true`, the accordion item will be collapsed. Otherwise, it will be expanded. * * @param collapsed New state of the accordion item. */ set collapsed(collapsed) { if (collapsed) { this.collapse(); } else { this.expand(); } } get collapsed() { return this._collapsed; } get id() { return `${this._id}`; } get toggleId() { return `${this.id}-toggle`; } get collapseId() { return `${this.id}-collapse`; } get _shouldBeInDOM() { return !this.collapsed || this._collapseAnimationRunning || !this.destroyOnHide; } ngAfterContentInit() { const { ngbCollapse } = this._collapse; // we need to disable the animation for the first init ngbCollapse.animation = false; ngbCollapse.collapsed = this.collapsed; // we set the animation to the default of the accordion ngbCollapse.animation = this._accordion.animation; // event forwarding from 'ngbCollapse' to 'ngbAccordion' ngbCollapse.hidden.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(() => { // when the animation finishes we can remove the template from DOM this._collapseAnimationRunning = false; this.hidden.emit(); this._accordion.hidden.emit(this.id); }); ngbCollapse.shown.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(() => { this.shown.emit(); this._accordion.shown.emit(this.id); }); } /** * Toggles an accordion item. */ toggle() { this.collapsed = !this.collapsed; } /** * Expands an accordion item. */ expand() { if (this.collapsed) { // checking if accordion allows to expand the panel in respect to 'closeOthers' flag if (!this._accordion._ensureCanExpand(this)) { return; } this._collapsed = false; // need if the accordion is used inside a component having OnPush change detection strategy this._cd.markForCheck(); // we need force CD to get template into DOM before starting animation to calculate its height correctly // this will synchronously put the item body into DOM, because `this._collapsed` was flipped to `false` this._cd.detectChanges(); // firing events before starting animations this.show.emit(); this._accordion.show.emit(this.id); // we also need to make sure 'animation' flag is up-to- date this._collapse.ngbCollapse.animation = this._accordion.animation; this._collapse.ngbCollapse.collapsed = false; } } /** * Collapses an accordion item. */ collapse() { if (!this.collapsed) { this._collapsed = true; this._collapseAnimationRunning = true; // need if the accordion is used inside a component having OnPush change detection strategy this._cd.markForCheck(); // firing events before starting animations this.hide.emit(); this._accordion.hide.emit(this.id); // we also need to make sure 'animation' flag is up-to- date this._collapse.ngbCollapse.animation = this._accordion.animation; this._collapse.ngbCollapse.collapsed = true; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbAccordionItem, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.0", type: NgbAccordionItem, isStandalone: true, selector: "[ngbAccordionItem]", inputs: { id: ["ngbAccordionItem", "id"], destroyOnHide: "destroyOnHide", disabled: "disabled", collapsed: "collapsed" }, outputs: { show: "show", shown: "shown", hide: "hide", hidden: "hidden" }, host: { properties: { "class.accordion-item": "true", "id": "id" } }, queries: [{ propertyName: "_collapse", first: true, predicate: NgbAccordionCollapse, descendants: true, static: true }], exportAs: ["ngbAccordionItem"], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbAccordionItem, decorators: [{ type: Directive, args: [{ selector: '[ngbAccordionItem]', exportAs: 'ngbAccordionItem', standalone: true, host: { '[class.accordion-item]': 'true', '[id]': 'id', }, }] }], propDecorators: { _collapse: [{ type: ContentChild, args: [NgbAccordionCollapse, { static: true }] }], id: [{ type: Input, args: ['ngbAccordionItem'] }], destroyOnHide: [{ type: Input }], disabled: [{ type: Input }], collapsed: [{ type: Input }], show: [{ type: Output }], shown: [{ type: Output }], hide: [{ type: Output }], hidden: [{ type: Output }] } }); /** * Accordion is a stack of cards that have a header and collapsible body. * * This directive is a container for these items and provides an API to handle them. * * @since 14.1.0 */ export class NgbAccordionDirective { constructor() { this._config = inject(NgbAccordionConfig); this._anItemWasAlreadyExpandedDuringInitialisation = false; /** * If `true`, accordion will be animated. */ this.animation = this._config.animation; /** * If `true`, only one item at the time can stay open. */ this.closeOthers = this._config.closeOthers; /** * If `true`, the content of the accordion items body will be removed from the DOM. It will be just hidden otherwise. * * This property can be overwritten at the [`NgbAccordionItem`](#/components/accordion/api#NgbAccordionItem) level */ this.destroyOnHide = this._config.destroyOnHide; /** * Event emitted before expanding animation starts. The payload is the id of shown accordion item. * * @since 15.1.0 */ this.show = new EventEmitter(); /** * Event emitted when the expanding animation is finished. The payload is the id of shown accordion item. */ this.shown = new EventEmitter(); /** * Event emitted before the collapsing animation starts. The payload is the id of hidden accordion item. * * @since 15.1.0 */ this.hide = new EventEmitter(); /** * Event emitted when the collapsing animation is finished and before the content is removed from DOM. * The payload is the id of hidden accordion item. */ this.hidden = new EventEmitter(); } /** * Toggles an item with the given id. * * It will toggle an item, even if it is disabled. * * @param itemId The id of the item to toggle. */ toggle(itemId) { this._getItem(itemId)?.toggle(); } /** * Expands an item with the given id. * * If `closeOthers` is `true`, it will collapse other panels. * * @param itemId The id of the item to expand. */ expand(itemId) { this._getItem(itemId)?.expand(); } /** * Expands all items. * * If `closeOthers` is `true` and all items are closed, it will open the first one. Otherwise, it will keep the opened one. */ expandAll() { if (this._items) { if (this.closeOthers) { // we check if there is an item open and if it is not we can expand the first item // (otherwise we toggle nothing) if (!this._items.find((item) => !item.collapsed)) { this._items.first.expand(); } } else { this._items.forEach((item) => item.expand()); } } } /** * Collapses an item with the given id. * * Has no effect if the `itemId` does not correspond to any item. * * @param itemId The id of the item to collapse. */ collapse(itemId) { this._getItem(itemId)?.collapse(); } /** * Collapses all items. */ collapseAll() { this._items?.forEach((item) => item.collapse()); } /** * Checks if an item with the given id is expanded. * * If the `itemId` does not correspond to any item, it returns `false`. * * @param itemId The id of the item to check. */ isExpanded(itemId) { const item = this._getItem(itemId); return item ? !item.collapsed : false; } /** * It checks, if the item can be expanded in the current state of the accordion. * With `closeOthers` there can be only one expanded item at a time. * * @internal */ _ensureCanExpand(toExpand) { if (!this.closeOthers) { return true; } // special case during the initialization of the [collapse]="false" inputs // `this._items` QueryList is not yet initialized, but we need to ensure only one item can be expanded at a time if (!this._items) { if (!this._anItemWasAlreadyExpandedDuringInitialisation) { this._anItemWasAlreadyExpandedDuringInitialisation = true; return true; } return false; } // if there is an expanded item, we need to collapse it first this._items.find((item) => !item.collapsed && toExpand !== item)?.collapse(); return true; } _getItem(itemId) { return this._items?.find((item) => item.id === itemId); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbAccordionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.0", type: NgbAccordionDirective, isStandalone: true, selector: "[ngbAccordion]", inputs: { animation: "animation", closeOthers: "closeOthers", destroyOnHide: "destroyOnHide" }, outputs: { show: "show", shown: "shown", hide: "hide", hidden: "hidden" }, host: { properties: { "class.accordion": "true" } }, queries: [{ propertyName: "_items", predicate: NgbAccordionItem }], exportAs: ["ngbAccordion"], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbAccordionDirective, decorators: [{ type: Directive, args: [{ selector: '[ngbAccordion]', standalone: true, exportAs: 'ngbAccordion', host: { '[class.accordion]': 'true' }, }] }], propDecorators: { _items: [{ type: ContentChildren, args: [NgbAccordionItem, { descendants: false }] }], animation: [{ type: Input }], closeOthers: [{ type: Input }], destroyOnHide: [{ type: Input }], show: [{ type: Output }], shown: [{ type: Output }], hide: [{ type: Output }], hidden: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNjb3JkaW9uLmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9hY2NvcmRpb24vYWNjb3JkaW9uLmRpcmVjdGl2ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBR04saUJBQWlCLEVBQ2pCLFlBQVksRUFDWixlQUFlLEVBQ2YsVUFBVSxFQUNWLFNBQVMsRUFDVCxVQUFVLEVBRVYsWUFBWSxFQUNaLE1BQU0sRUFDTixLQUFLLEVBRUwsTUFBTSxFQUVOLFdBQVcsRUFDWCxnQkFBZ0IsR0FDaEIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDaEUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDeEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxjQUFjLENBQUM7OztBQUV4QyxJQUFJLE1BQU0sR0FBRyxDQUFDLENBQUM7QUFFZjs7Ozs7OztHQU9HO0FBTUgsTUFBTSxPQUFPLGdCQUFnQjtJQUw3QjtRQU1TLFNBQUksR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUNoQyxhQUFRLEdBQUcsTUFBTSxDQUFDLENBQUEsVUFBdUIsQ0FBQSxDQUFDLENBQUMsYUFBYSxDQUFDO1FBQ3pELFVBQUssR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUVqQyxhQUFRLEdBQWdDLElBQUksQ0FBQztLQWtDckQ7SUE5QkEscUJBQXFCO1FBQ3BCLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRTtZQUNsQixJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsY0FBYyxFQUFFO2dCQUM5QixJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FBQzthQUM5QjtpQkFBTTtnQkFDTixJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQzth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O2tCQU5qQyxTQUFTO21CQUFDO29CQUNWLFFBQVEsRUFBRSxnQkFBZ0I7b0JBQzFCLFVBQVUsRUFBRSxJQUFJO29CQUNoQixRQUFRLEVBQUUsY0FBYztvQkFDeEIsSUFBSSxFQUFFLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxFQUFFO2lCQUNyQzs4QkFLbUUsTUFBTTtzQkFBeEUsZUFBZTt1QkFBQyxnQkFBZ0IsRUFBRSxFQUFFLFdBQVcsRUFBRSxLQUFLLEVBQUU7Z0JBSWhELFNBQVM7c0JBQWpCLEtBQUs7Z0JBS0csV0FBVztzQkFBbkIsS0FBSztnQkFNRyxhQUFhO3NCQUFyQixLQUFLO2dCQU9JLElBQUk7c0JBQWIsTUFBTTtnQkFLRyxLQUFLO3NCQUFkLE1BQU07Z0JBT0csSUFBSTtzQkFBYixNQUFNO2dCQU1HLE1BQU07c0JBQWYsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG5cdEFmdGVyQ29udGVudENoZWNrZWQsXG5cdEFmdGVyQ29udGVudEluaXQsXG5cdENoYW5nZURldGVjdG9yUmVmLFxuXHRDb250ZW50Q2hpbGQsXG5cdENvbnRlbnRDaGlsZHJlbixcblx0RGVzdHJveVJlZixcblx0RGlyZWN0aXZlLFxuXHRFbGVtZW50UmVmLFxuXHRFbWJlZGRlZFZpZXdSZWYsXG5cdEV2ZW50RW1pdHRlcixcblx0aW5qZWN0LFxuXHRJbnB1dCxcblx0T25EZXN0cm95LFxuXHRPdXRwdXQsXG5cdFF1ZXJ5TGlzdCxcblx0VGVtcGxhdGVSZWYsXG5cdFZpZXdDb250YWluZXJSZWYsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgdGFrZVVudGlsRGVzdHJveWVkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZS9yeGpzLWludGVyb3AnO1xuaW1wb3J0IHsgTmdiQWNjb3JkaW9uQ29uZmlnIH0gZnJvbSAnLi9hY2NvcmRpb24tY29uZmlnJztcbmltcG9ydCB7IE5nYkNvbGxhcHNlIH0gZnJvbSAnLi4vY29sbGFwc2UvY29sbGFwc2UnO1xuaW1wb3J0IHsgaXNTdHJpbmcgfSBmcm9tICcuLi91dGlsL3V0aWwnO1xuXG5sZXQgbmV4dElkID0gMDtcblxuLyoqXG4gKiBBIGRpcmVjdGl2ZSB0aGF0IHdyYXBzIHRoZSBjb250ZW50IG9mIGFuIGFjY29yZGlvbiBpdGVtJ3MgY29sbGFwc2libGUgYm9keS5cbiAqXG4gKiBUaGUgYWN0dWFsIGNvbnRlbnQgaXMgcHJvdmlkZWQgaW4gYSBjaGlsZCBgbmctdGVtcGxhdGVgIGVsZW1lbnQuXG4gKiBEZXBlbmRpbmcgb24gdGhlIHN0YXRlIG9mIHRoZSBhY2NvcmRpb24sIHRoZSB0ZW1wbGF0ZSB3aWxsIGJlIGVpdGhlciBpbnNlcnRlZCBvciByZW1vdmVkIGZyb20gdGhlIERPTS5cbiAqXG4gKiBAc2luY2UgMTQuMS4wXG4gKi9cbkBEaXJlY3RpdmUoe1xuXHRzZWxlY3RvcjogJ1tuZ2JBY2NvcmRpb25Cb2R5XScsXG5cdHN0YW5kYWxvbmU6IHRydWUsXG5cdGhvc3Q6IHsgJ1tjbGFzcy5hY2NvcmRpb24tYm9keV0nOiAndHJ1ZScgfSxcbn0pXG5leHBvcnQgY2xhc3MgTmdiQWNjb3JkaW9uQm9keSBpbXBsZW1lbnRzIEFmdGVyQ29udGVudENoZWNrZWQsIE9uRGVzdHJveSB7XG5cdHByaXZhdGUgX3ZjciA9IGluamVjdChWaWV3Q29udGFpbmVyUmVmKTtcblx0cHJpdmF0ZSBfZWxlbWVudCA9IGluamVjdChFbGVtZW50UmVmPEhUTUxFbGVtZW50PikubmF0aXZlRWxlbWVudDtcblx0cHJpdmF0ZSBfaXRlbSA9IGluamVjdChOZ2JBY2NvcmRpb25JdGVtKTtcblxuXHRwcml2YXRlIF92aWV3UmVmOiBFbWJlZGRlZFZpZXdSZWY8YW55PiB8IG51bGwgPSBudWxsO1xuXG5cdEBDb250ZW50Q2hpbGQoVGVtcGxhdGVSZWYsIHsgc3RhdGljOiB0cnVlIH0pIHByaXZhdGUgX2JvZHlUcGw6IFRlbXBsYXRlUmVmPGFueT47XG5cblx0bmdBZnRlckNvbnRlbnRDaGVja2VkKCk6IHZvaWQge1xuXHRcdGlmICh0aGlzLl9ib2R5VHBsKSB7XG5cdFx0XHRpZiAodGhpcy5faXRlbS5fc2hvdWxkQmVJbkRPTSkge1xuXHRcdFx0XHR0aGlzLl9jcmVhdGVWaWV3SWZOb3RFeGlzdHMoKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMuX2Rlc3Ryb3lWaWV3SWZFeGlzdHMoKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRuZ09uRGVzdHJveSgpOiB2b2lkIHtcblx0XHR0aGlzLl9kZXN0cm95Vmlld0lmRXhpc3RzKCk7XG5cdH1cblxuXHRwcml2YXRlIF9kZXN0cm95Vmlld0lmRXhpc3RzKCk6IHZvaWQge1xuXHRcdGlmICh0aGlzLl92aWV3UmVmKSB7XG5cdFx0XHR0aGlzLl92aWV3UmVmLmRlc3Ryb3koKTtcblx0XHRcdHRoaXMuX3ZpZXdSZWYgPSBudWxsO1xuXHRcdH1cblx0fVxuXG5cdHByaXZhdGUgX2NyZWF0ZVZpZXdJZk5vdEV4aXN0cygpOiB2b2lkIHtcblx0XHRpZiAoIXRoaXMuX3ZpZXdSZWYpIHtcblx0XHRcdHRoaXMuX3ZpZXdSZWYgPSB0aGlzLl92Y3IuY3JlYXRlRW1iZWRkZWRWaWV3KHRoaXMuX2JvZHlUcGwpO1xuXHRcdFx0dGhpcy5fdmlld1JlZi5kZXRlY3RDaGFuZ2VzKCk7XG5cdFx0XHRmb3IgKGNvbnN0IG5vZGUgb2YgdGhpcy5fdmlld1JlZi5yb290Tm9kZXMpIHtcblx0XHRcdFx0dGhpcy5fZWxlbWVudC5hcHBlbmRDaGlsZChub2RlKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cbn1cblxuLyoqXG4gKiBBIGRpcmVjdGl2ZSB0aGF0IHdyYXBzIHRoZSBjb2xsYXBzaWJsZSBpdGVtJ3MgY29udGVudCBvZiB0aGUgYWNjb3JkaW9uLlxuICpcbiAqIEludGVybmFsbHkgaXQgcmV1c2VzIHRoZSBbYE5nYkNvbGxhcHNlYCBkaXJlY3RpdmVdKCMvY29tcG9uZW50cy9jb2xsYXBzZSlcbiAqXG4gKiBAc2luY2UgMTQuMS4wXG4gKi9cbkBEaXJlY3RpdmUoe1xuXHRleHBvcnRBczogJ25nYkFjY29yZGlvbkNvbGxhcHNlJyxcblx0c3RhbmRhbG9uZTogdHJ1ZSxcblx0c2VsZWN0b3I6ICdbbmdiQWNjb3JkaW9uQ29sbGFwc2VdJyxcblx0aG9zdDoge1xuXHRcdHJvbGU6ICdyZWdpb24nLFxuXHRcdCdbY2xhc3MuYWNjb3JkaW9uLWNvbGxhcHNlXSc6ICd0cnVlJyxcblx0XHQnW2lkXSc6ICdpdGVtLmNvbGxhcHNlSWQnLFxuXHRcdCdbYXR0ci5hcmlhLWxhYmVsbGVkYnldJzogJ2l0ZW0udG9nZ2xlSWQnLFxuXHR9LFxuXHRob3N0RGlyZWN0aXZlczogW05nYkNvbGxhcHNlXSxcbn0pXG5leHBvcnQgY2xhc3MgTmdiQWNjb3JkaW9uQ29sbGFwc2Uge1xuXHRpdGVtID0gaW5qZWN0KE5nYkFjY29yZGlvbkl0ZW0pO1xuXHRuZ2JDb2xsYXBzZSA9IGluamVjdChOZ2JDb2xsYXBzZSk7XG59XG5cbi8qKlxuICogQSBkaXJlY3RpdmUgdG8gcHV0IG9uIGEgdG9nZ2xpbmcgZWxlbWVudCBpbnNpZGUgdGhlIGFjY29yZGlvbiBpdGVtJ3MgaGVhZGVyLlxuICogSXQgd2lsbCByZWdpc3RlciBjbGljayBoYW5kbGVycyB0aGF0IHRvZ2dsZSB0aGUgYXNzb2NpYXRlZCBwYW5lbCBhbmQgd2lsbCBoYW5kbGUgYWNjZXNzaWJpbGl0eSBhdHRyaWJ1dGVzLlxuICpcbiAqIFRoaXMgZGlyZWN0aXZlIGlzIHVzZWQgaW50ZXJuYWxseSBieSB0aGUgW2BOZ2JBY2NvcmRpb25CdXR0b25gIGRpcmVjdGl2ZV0oIy9jb21wb25lbnRzL2FjY29yZGlvbi9hcGkjTmdiQWNjb3JkaW9uQnV0dG9uKS5cbiAqXG4gKiBAc2luY2UgMTQuMS4wXG4gKi9cbkBEaXJlY3RpdmUoe1xuXHRzZWxlY3RvcjogJ1tuZ2JBY2NvcmRpb25Ub2dnbGVdJyxcblx0c3RhbmRhbG9uZTogdHJ1ZSxcblx0aG9zdDoge1xuXHRcdCdbaWRdJzogJ2l0ZW0udG9nZ2xlSWQnLFxuXHRcdCdbY2xhc3MuY29sbGFwc2VkXSc6ICdpdGVtLmNvbGxhcHNlZCcsXG5cdFx0J1thdHRyLmFyaWEtY29udHJvbHNdJzogJ2l0ZW0uY29sbGFwc2VJZCcsXG5cdFx0J1thdHRyLmFyaWEtZXhwYW5kZWRdJzogJyFpdGVtLmNvbGxhcHNlZCcsXG5cdFx0JyhjbGljayknOiAnIWl0ZW0uZGlzYWJsZWQgJiYgYWNjb3JkaW9uLnRvZ2dsZShpdGVtLmlkKScsXG5cdH0sXG59KVxuZXhwb3J0IGNsYXNzIE5nYkFjY29yZGlvblRvZ2dsZSB7XG5cdGl0ZW0gPSBpbmplY3QoTmdiQWNjb3JkaW9uSXRlbSk7XG5cdGFjY29yZGlvbiA9IGluamVjdChOZ2JBY2NvcmRpb25EaXJlY3RpdmUpO1xufVxuXG4vKipcbiAqIEEgZGlyZWN0aXZlIHRvIHB1dCBvbiBhIGJ1dHRvbiBlbGVtZW50IGluc2lkZSBhbiBhY2NvcmRpb24gaXRlbSdzIGhlYWRlci5cbiAqXG4gKiBJZiB5b3Ugd2FudCBhIGN1c3RvbSBtYXJrdXAgZm9yIHRoZSBoZWFkZXIsIHlvdSBjYW4gYWxzbyB1c2UgdGhlIFtgTmdiQWNjb3JkaW9uVG9nZ2xlYCBkaXJlY3RpdmVdKCMvY29tcG9uZW50cy9hY2NvcmRpb24vYXBpI05nYkFjY29yZGlvblRvZ2dsZSkuXG4gKlxuICogQHNpbmNlIDE0LjEuMFxuICovXG5ARGlyZWN0aXZlKHtcblx0c2VsZWN0b3I6ICdidXR0b25bbmdiQWNjb3JkaW9uQnV0dG9uXScsXG5cdHN0YW5kYWxvbmU6IHRydWUsXG5cdGhvc3Q6IHtcblx0XHQnW2Rpc2FibGVkXSc6ICdpdGVtLmRpc2FibGVkJyxcblx0XHQnW2NsYXNzLmFjY29yZGlvbi1idXR0b25dJzogJ3RydWUnLFxuXHRcdHR5cGU6ICdidXR0b24nLFxuXHR9LFxuXHRob3N0RGlyZWN0aXZlczogW05nYkFjY29yZGlvblRvZ2dsZV0sXG59KVxuZXhwb3J0IGNsYXNzIE5nYkFjY29yZGlvbkJ1dHRvbiB7XG5cdGl0ZW0gPSBpbmplY3QoTmdiQWNjb3JkaW9uSXRlbSk7XG59XG5cbi8qKlxuICogQSBkaXJlY3RpdmUgdGhhdCB3cmFwcyBhbiBhY2NvcmRpb24gaXRlbSdzIGhlYWRlci5cbiAqXG4gKiBAc2luY2UgMTQuMS4wXG4gKi9cbkBEaXJlY3RpdmUoe1xuXHRzZWxlY3RvcjogJ1tuZ2JBY2NvcmRpb25IZWFkZXJdJyxcblx0c3RhbmRhbG9uZTogdHJ1ZSxcblx0aG9zdDoge1xuXHRcdHJvbGU6ICdoZWFkaW5nJyxcblx0XHQnW2NsYXNzLmFjY29yZGlvbi1oZWFkZXJdJzogJ3RydWUnLFxuXHRcdCdbY2xhc3MuY29sbGFwc2VkXSc6ICdpdGVtLmNvbGxhcHNlZCcsXG5cdH0sXG59KVxuZXhwb3J0IGNsYXNzIE5nYkFjY29yZGlvbkhlYWRlciB7XG5cdGl0ZW0gPSBpbmplY3QoTmdiQWNjb3JkaW9uSXRlbSk7XG59XG5cbi8qKlxuICogQSBkaXJlY3RpdmUgdGhhdCB3cmFwcyBhbiBhY2NvcmRpb24gaXRlbTogYSB0b2dnbGVhYmxlIGhlYWRlciArIGJvZHkgdGhhdCBjb2xsYXBzZXMuXG4gKlxuICogWW91IGNhbiBnZXQgaG9sZCBvZiB0aGUgYE5nYkFjY29yZGlvbkl0ZW1gIGluc3RhbmNlIGluIHRoZSB0ZW1wbGF0ZSB3aXRoIGAjaXRlbT1cIm5nYkFjY29yZGlvbkl0ZW1cImAuXG4gKiBJdCBhbGxvd3MgdG8gY2hlY2sgaWYgdGhlIGl0ZW0gaXMgY29sbGFwc2VkIG9yIG5vdCwgdG9nZ2xlIHRoZSBjb2xsYXBzZSBzdGF0ZSwgZXRjLlxuICpcbiAqIEV2ZXJ5IGFjY29yZGlvbiBpdGVtIGhhcyBhIHN0cmluZyBJRCB0aGF0IGlzIGF1dG9tYXRpY2FsbHkgZ2VuZXJhdGVkIGluIHRoZSBgbmdiLWFjY29yZGlvbi1pdGVtLVhYYCBmb3JtYXQsIHVubGVzcyBwcm92aWRlZCBleHBsaWNpdGx5LlxuICpcbiAqIEBzaW5jZSAxNC4xLjBcbiAqL1xuQERpcmVjdGl2ZSh7XG5cdHNlbGVjdG9yOiAnW25nYkFjY29yZGlvbkl0ZW1dJyxcblx0ZXhwb3J0QXM6ICduZ2JBY2NvcmRpb25JdGVtJyxcblx0c3RhbmRhbG9uZTogdHJ1ZSxcblx0aG9zdDoge1xuXHRcdCdbY2xhc3MuYWNjb3JkaW9uLWl0ZW1dJzogJ3RydWUnLFxuXHRcdCdbaWRdJzogJ2lkJyxcblx0fSxcbn0pXG5leHBvcnQgY2xhc3MgTmdiQWNjb3JkaW9uSXRlbSBpbXBsZW1lbnRzIEFmdGVyQ29udGVudEluaXQge1xuXHRwcml2YXRlIF9hY2NvcmRpb24gPSBpbmplY3QoTmdiQWNjb3JkaW9uRGlyZWN0aXZlKTtcblx0cHJpdmF0ZSBfY2QgPSBpbmplY3QoQ2hhbmdlRGV0ZWN0b3JSZWYpO1xuXHRwcml2YXRlIF9kZXN0cm95UmVmID0gaW5qZWN0KERlc3Ryb3lSZWYpO1xuXG5cdHByaXZhdGUgX2NvbGxhcHNlZCA9IHRydWU7XG5cdHByaXZhdGUgX2lkID0gYG5nYi1hY2NvcmRpb24taXRlbS0ke25leHRJZCsrfWA7XG5cdHByaXZhdGUgX2Rlc3Ryb3lPbkhpZGU6IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG5cblx0cHJpdmF0ZSBfY29sbGFwc2VBbmltYXRpb25SdW5uaW5nID0gZmFsc2U7XG5cblx0QENvbnRlbnRDaGlsZChOZ2JBY2NvcmRpb25Db2xsYXBzZSwgeyBzdGF0aWM6IHRydWUgfSkgcHJpdmF0ZSBfY29sbGFwc2U6IE5nYkFjY29yZGlvbkNvbGxhcHNlO1xuXG5cdC8qKlxuXHQgKiBTZXRzIHRoZSBjdXN0b20gSUQgb2YgdGhlIGFjY29yZGlvbiBpdGVtLiBJdCBtdXN0IGJlIHVuaXF1ZSBmb3IgdGhlIGRvY3VtZW50LlxuXHQgKlxuXHQgKiBAcGFyYW0gaWQgVGhlIElEIG9mIHRoZSBhY2NvcmRpb24gaXRlbSwgbXVzdCBiZSBhIG5vbi1lbXB0eSBzdHJpbmdcblx0ICovXG5cdEBJbnB1dCgnbmdiQWNjb3JkaW9uSXRlbScpIHNldCBpZChpZDogc3RyaW5nKSB7XG5cdFx0aWYgKGlzU3RyaW5nKGlkKSAmJiBpZCAhPT0gJycpIHtcblx0XHRcdHRoaXMuX2lkID0gaWQ7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIElmIGB0cnVlYCwgdGhlIGNvbnRlbnQgb2YgdGhlIGFjY29yZGlvbiBpdGVtJ3MgYm9keSB3aWxsIGJlIHJlbW92ZWQgZnJvbSB0aGUgRE9NLiBJdCB3aWxsIGJlIGp1c3QgaGlkZGVuIG90aGVyd2lzZS5cblx0ICpcblx0ICogVGhpcyBwcm9wZXJ0eSBjYW4gYWxzbyBiZSBzZXQgdXAgb24gdGhlIHBhcmVudCBbYE5nYkFjY29yZGlvbmAgZGlyZWN0aXZlXSgjL2NvbXBvbmVudHMvYWNjb3JkaW9uL2FwaSNOZ2JBY2NvcmRpb25EaXJlY3RpdmUpLlxuXHQgKi9cblx0QElucHV0KCkgc2V0IGRlc3Ryb3lPbkhpZGUoZGVzdHJveU9uSGlkZTogYm9vbGVhbikge1xuXHRcdHRoaXMuX2Rlc3Ryb3lPbkhpZGUgPSBkZXN0cm95T25IaWRlO1xuXHR9XG5cblx0Z2V0IGRlc3Ryb3lPbkhpZGUoKTogYm9vbGVhbiB7XG5cdFx0cmV0dXJuIHRoaXMuX2Rlc3Ryb3lPbkhpZGUgPT09IHVuZGVmaW5lZCA/IHRoaXMuX2FjY29yZGlvbi5kZXN0cm95T25IaWRlIDogdGhpcy5fZGVzdHJveU9uSGlkZSE7XG5cdH1cblxuXHQvKipcblx0ICogSWYgYHRydWVgLCB0aGUgYWNjb3JkaW9uIGl0ZW0gd2lsbCBiZSBkaXNhYmxlZC5cblx0ICogSXQgd29uJ3QgcmVhY3QgdG8gdXNlcidzIGNsaWNrcywgYnV0IHN0aWxsIHdpbGwgYmUgdG9nZ2VsYWJsZSBwcm9ncmFtbWF0aWNhbGx5LlxuXHQgKi9cblx0QElucHV0KCkgZGlzYWJsZWQgPSBmYWxzZTtcblxuXHQvKipcblx0ICpcdElmIGB0cnVlYCwgdGhlIGFjY29yZGlvbiBpdGVtIHdpbGwgYmUgY29sbGFwc2VkLiBPdGhlcndpc2UsIGl0IHdpbGwgYmUgZXhwYW5kZWQuXG5cdCAqXG5cdCAqIEBwYXJhbSBjb2xsYXBzZWQgTmV3IHN0YXRlIG9mIHRoZSBhY2NvcmRpb24gaXRlbS5cblx0ICovXG5cdEBJbnB1dCgpIHNldCBjb2xsYXBzZWQoY29sbGFwc2VkOiBib29sZWFuKSB7XG5cdFx0aWYgKGNvbGxhcHNlZCkge1xuXHRcdFx0dGhpcy5jb2xsYXBzZSgpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmV4cGFuZCgpO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBFdmVudCBlbWl0dGVkIGJlZm9yZSB0aGUgZXhwYW5kaW5nIGFuaW1hdGlvbiBzdGFydHMuIEl0IGhhcyBubyBwYXlsb2FkLlxuXHQgKlxuXHQgKiBAc2luY2UgMTUuMS4wXG5cdCAqL1xuXHRAT3V0cHV0KCkgc2hvdyA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcblxuXHQvKipcblx0ICogRXZlbnQgZW1pdHRlZCB3aGVuIHRoZSBleHBhbmRpbmcgYW5pbWF0aW9uIGlzIGZpbmlzaGVkLiBJdCBoYXMgbm8gcGF5bG9hZC5cblx0ICovXG5cdEBPdXRwdXQoKSBzaG93biA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcblxuXHQvKipcblx0ICogRXZlbnQgZW1pdHRlZCBiZWZvcmUgdGhlIGNvbGxhcHNpbmcgYW5pbWF0aW9uIHN0YXJ0cy4gSXQgaGFzIG5vIHBheWxvYWQuXG5cdCAqXG5cdCAqIEBzaW5jZSAxNS4xLjBcblx0ICovXG5cdEBPdXRwdXQoKSBoaWRlID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xuXG5cdC8qKlxuXHQgKiBFdmVudCBlbWl0dGVkIHdoZW4gdGhlIGNvbGxhcHNpbmcgYW5pbWF0aW9uIGlzIGZpbmlzaGVkIGFuZCBiZWZvcmUgdGhlIGNvbnRlbnQgaXMgcmVtb3ZlZCBmcm9tIERPTS5cblx0ICogSXQgaGFzIG5vIHBheWxvYWQuXG5cdCAqL1xuXHRAT3V0cHV0KCkgaGlkZGVuID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xuXG5cdGdldCBjb2xsYXBzZWQoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX2NvbGxhcHNlZDtcblx0fVxuXG5cdGdldCBpZCgpIHtcblx0XHRyZXR1cm4gYCR7dGhpcy5faWR9YDtcblx0fVxuXG5cdGdldCB0b2dnbGVJZCgpIHtcblx0XHRyZXR1cm4gYCR7dGhpcy5pZH0tdG9nZ2xlYDtcblx0fVxuXG5cdGdldCBjb2xsYXBzZUlkKCkge1xuXHRcdHJldHVybiBgJHt0aGlzLmlkfS1jb2xsYXBzZWA7XG5cdH1cblxuXHRnZXQgX3Nob3VsZEJlSW5ET00oKSB7XG5cdFx0cmV0dXJuICF0aGlzLmNvbGxhcHNlZCB8fCB0aGlzLl9jb2xsYXBzZUFuaW1hdGlvblJ1bm5pbmcgfHwgIXRoaXMuZGVzdHJveU9uSGlkZTtcblx0fVxuXG5cdG5nQWZ0ZXJDb250ZW50SW5pdCgpIHtcblx0XHRjb25zdCB7IG5nYkNvbGxhcHNlIH0gPSB0aGlzLl9jb2xsYXBzZTtcblx0XHQvLyB3ZSBuZWVkIHRvIGRpc2FibGUgdGhlIGFuaW1hdGlvbiBmb3IgdGhlIGZpcnN0IGluaXRcblx0XHRuZ2JDb2xsYXBzZS5hbmltYXRpb24gPSBmYWxzZTtcblx0XHRuZ2JDb2xsYXBzZS5jb2xsYXBzZWQgPSB0aGlzLmNvbGxhcHNlZDtcblx0XHQvLyB3ZSBzZXQgdGhlIGFuaW1hdGlvbiB0byB0aGUgZGVmYXVsdCBvZiB0aGUgYWNjb3JkaW9uXG5cdFx0bmdiQ29sbGFwc2UuYW5pbWF0aW9uID0gdGhpcy5fYWNjb3JkaW9uLmFuaW1hdGlvbjtcblx0XHQvLyBldmVudCBmb3J3YXJkaW5nIGZyb20gJ25nYkNvbGxhcHNlJyB0byAnbmdiQWNjb3JkaW9uJ1xuXHRcdG5nYkNvbGxhcHNlLmhpZGRlbi5waXBlKHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSkuc3Vic2NyaWJlKCgpID0+IHtcblx0XHRcdC8vIHdoZW4gdGhlIGFuaW1hdGlvbiBmaW5pc2hlcyB3ZSBjYW4gcmVtb3ZlIHRoZSB0ZW1wbGF0ZSBmcm9tIERPTVxuXHRcdFx0dGhpcy5fY29sbGFwc2VBbmltYXRpb25SdW5uaW5nID0gZmFsc2U7XG5cdFx0XHR0aGlzLmhpZGRlbi5lbWl0KCk7XG5cdFx0XHR0aGlzLl9hY2NvcmRpb24uaGlkZGVuLmVtaXQodGhpcy5pZCk7XG5cdFx0fSk7XG5cdFx0bmdiQ29sbGFwc2Uuc2hvd24ucGlwZSh0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZikpLnN1YnNjcmliZSgoKSA9PiB7XG5cdFx0XHR0aGlzLnNob3duLmVtaXQoKTtcblx0XHRcdHRoaXMuX2FjY29yZGlvbi5zaG93bi5lbWl0KHRoaXMuaWQpO1xuXHRcdH0pO1xuXHR9XG5cblx0LyoqXG5cdCAqIFRvZ2dsZXMgYW4gYWNjb3JkaW9uIGl0ZW0uXG5cdCAqL1xuXHR0b2dnbGUoKSB7XG5cdFx0dGhpcy5jb2xsYXBzZWQgPSAhdGhpcy5jb2xsYXBzZWQ7XG5cdH1cblxuXHQvKipcblx0ICogRXhwYW5kcyBhbiBhY2NvcmRpb24gaXRlbS5cblx0ICovXG5cdGV4cGFuZCgpIHtcblx0XHRpZiAodGhpcy5jb2xsYXBzZWQpIHtcblx0XHRcdC8vIGNoZWNraW5nIGlmIGFjY29yZGlvbiBhbGxvd3MgdG8gZXhwYW5kIHRoZSBwYW5lbCBpbiByZXNwZWN0IHRvICdjbG9zZU90aGVycycgZmxhZ1xuXHRcdFx0aWYgKCF0aGlzLl9hY2NvcmRpb24uX2Vuc3VyZUNhbkV4cGFuZCh0aGlzKSkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2NvbGxhcHNlZCA9IGZhbHNlO1xuXG5cdFx0XHQvLyBuZWVkIGlmIHRoZSBhY2NvcmRpb24gaXMgdXNlZCBpbnNpZGUgYSBjb21wb25lbnQgaGF2aW5nIE9uUHVzaCBjaGFuZ2UgZGV0ZWN0aW9uIHN0cmF0ZWd5XG5cdFx0XHR0aGlzLl9jZC5tYXJrRm9yQ2hlY2soKTtcblxuXHRcdFx0Ly8gd2UgbmVlZCBmb3JjZSBDRCB0byBnZXQgdGVtcGxhdGUgaW50byBET00gYmVmb3JlIHN0YXJ0aW5nIGFuaW1hdGlvbiB0byBjYWxjdWxhdGUgaXRzIGhlaWdodCBjb3JyZWN0bHlcblx0XHRcdC8vIHRoaXMgd2lsbCBzeW5jaHJvbm91c2x5IHB1dCB0aGUgaXRlbSBib2R5IGludG8gRE9NLCBiZWNhdXNlIGB0aGlzLl9jb2xsYXBzZWRgIHdhcyBmbGlwcGVkIHRvIGBmYWxzZWBcblx0XHRcdHRoaXMuX2NkLmRldGVjdENoYW5nZXMoKTtcblxuXHRcdFx0Ly8gZmlyaW5nIGV2ZW50cyBiZWZvcmUgc3RhcnRpbmcgYW5pbWF0aW9uc1xuXHRcdFx0dGhpcy5zaG93LmVtaXQoKTtcblx0XHRcdHRoaXMuX2FjY29yZGlvbi5zaG93LmVtaXQodGhpcy5pZCk7XG5cblx0XHRcdC8vIHdlIGFsc28gbmVlZCB0byBtYWtlIHN1cmUgJ2FuaW1hdGlvbicgZmxhZyBpcyB1cC10by0gZGF0ZVxuXHRcdFx0dGhpcy5fY29sbGFwc2UubmdiQ29sbGFwc2UuYW5pbWF0aW9uID0gdGhpcy5fYWNjb3JkaW9uLmFuaW1hdGlvbjtcblx0XHRcdHRoaXMuX2NvbGxhcHNlLm5nYkNvbGxhcHNlLmNvbGxhcHNlZCA9IGZhbHNlO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBDb2xsYXBzZXMgYW4gYWNjb3JkaW9uIGl0ZW0uXG5cdCAqL1xuXHRjb2xsYXBzZSgpIHtcblx0XHRpZiAoIXRoaXMuY29sbGFwc2VkKSB7XG5cdFx0XHR0aGlzLl9jb2xsYXBzZWQgPSB0cnVlO1xuXHRcdFx0dGhpcy5fY29sbGFwc2VBbmltYXRpb25SdW5uaW5nID0gdHJ1ZTtcblxuXHRcdFx0Ly8gbmVlZCBpZiB0aGUgYWNjb3JkaW9uIGlzIHVzZWQgaW5zaWRlIGEgY29tcG9uZW50IGhhdmluZyBPblB1c2ggY2hhbmdlIGRldGVjdGlvbiBzdHJhdGVneVxuXHRcdFx0dGhpcy5fY2QubWFya0ZvckNoZWNrKCk7XG5cblx0XHRcdC8vIGZpcmluZyBldmVudHMgYmVmb3JlIHN0YXJ0aW5nIGFuaW1hdGlvbnNcblx0XHRcdHRoaXMuaGlkZS5lbWl0KCk7XG5cdFx0XHR0aGlzLl9hY2NvcmRpb24uaGlkZS5lbWl0KHRoaXMuaWQpO1xuXG5cdFx0XHQvLyB3ZSBhbHNvIG5lZWQgdG8gbWFrZSBzdXJlICdhbmltYXRpb24nIGZsYWcgaXMgdXAtdG8tIGRhdGVcblx0XHRcdHRoaXMuX2NvbGxhcHNlLm5nYkNvbGxhcHNlLmFuaW1hdGlvbiA9IHRoaXMuX2FjY29yZGlvbi5hbmltYXRpb247XG5cdFx0XHR0aGlzLl9jb2xsYXBzZS5uZ2JDb2xsYXBzZS5jb2xsYXBzZWQgPSB0cnVlO1xuXHRcdH1cblx0fVxufVxuXG4vKipcbiAqIEFjY29yZGlvbiBpcyBhIHN0YWNrIG9mIGNhcmRzIHRoYXQgaGF2ZSBhIGhlYWRlciBhbmQgY29sbGFwc2libGUgYm9keS5cb