UNPKG

@ng-bootstrap/ng-bootstrap

Version:
493 lines 61.1 kB
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChildren, DestroyRef, Directive, ElementRef, EventEmitter, inject, Input, NgZone, Output, PLATFORM_ID, TemplateRef, ViewEncapsulation, } from '@angular/core'; import { isPlatformBrowser, NgTemplateOutlet } from '@angular/common'; import { NgbCarouselConfig } from './carousel-config'; import { BehaviorSubject, combineLatest, NEVER, timer, zip } from 'rxjs'; import { distinctUntilChanged, map, startWith, switchMap, take } from 'rxjs/operators'; import { ngbCompleteTransition, ngbRunTransition } from '../util/transition/ngbTransition'; import { ngbCarouselTransitionIn, ngbCarouselTransitionOut, NgbSlideEventDirection, } from './carousel-transition'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import * as i0 from "@angular/core"; let nextId = 0; let carouselId = 0; /** * A directive that wraps the individual carousel slide. */ export class NgbSlide { constructor() { this.templateRef = inject(TemplateRef); /** * Slide id that must be unique for the entire document. * * If not provided, will be generated in the `ngb-slide-xx` format. */ this.id = `ngb-slide-${nextId++}`; /** * An event emitted when the slide transition is finished * * @since 8.0.0 */ this.slid = new EventEmitter(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbSlide, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.0", type: NgbSlide, isStandalone: true, selector: "ng-template[ngbSlide]", inputs: { id: "id" }, outputs: { slid: "slid" }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbSlide, decorators: [{ type: Directive, args: [{ selector: 'ng-template[ngbSlide]', standalone: true }] }], propDecorators: { id: [{ type: Input }], slid: [{ type: Output }] } }); /** * Carousel is a component to easily create and control slideshows. * * Allows to set intervals, change the way user interacts with the slides and provides a programmatic API. */ export class NgbCarousel { constructor() { this.NgbSlideEventSource = NgbSlideEventSource; this._config = inject(NgbCarouselConfig); this._platformId = inject(PLATFORM_ID); this._ngZone = inject(NgZone); this._cd = inject(ChangeDetectorRef); this._container = inject(ElementRef); this._destroyRef = inject(DestroyRef); this._interval$ = new BehaviorSubject(this._config.interval); this._mouseHover$ = new BehaviorSubject(false); this._focused$ = new BehaviorSubject(false); this._pauseOnHover$ = new BehaviorSubject(this._config.pauseOnHover); this._pauseOnFocus$ = new BehaviorSubject(this._config.pauseOnFocus); this._pause$ = new BehaviorSubject(false); this._wrap$ = new BehaviorSubject(this._config.wrap); this.id = `ngb-carousel-${carouselId++}`; /** * A flag to enable/disable the animations. * * @since 8.0.0 */ this.animation = this._config.animation; /** * If `true`, allows to interact with carousel using keyboard 'arrow left' and 'arrow right'. */ this.keyboard = this._config.keyboard; /** * If `true`, 'previous' and 'next' navigation arrows will be visible on the slide. * * @since 2.2.0 */ this.showNavigationArrows = this._config.showNavigationArrows; /** * If `true`, navigation indicators at the bottom of the slide will be visible. * * @since 2.2.0 */ this.showNavigationIndicators = this._config.showNavigationIndicators; /** * An event emitted just before the slide transition starts. * * See [`NgbSlideEvent`](#/components/carousel/api#NgbSlideEvent) for payload details. */ this.slide = new EventEmitter(); /** * An event emitted right after the slide transition is completed. * * See [`NgbSlideEvent`](#/components/carousel/api#NgbSlideEvent) for payload details. * * @since 8.0.0 */ this.slid = new EventEmitter(); /* * Keep the ids of the panels currently transitionning * in order to allow only the transition revertion */ this._transitionIds = null; } /** * Time in milliseconds before the next slide is shown. */ set interval(value) { this._interval$.next(value); } get interval() { return this._interval$.value; } /** * If `true`, will 'wrap' the carousel by switching from the last slide back to the first. */ set wrap(value) { this._wrap$.next(value); } get wrap() { return this._wrap$.value; } /** * If `true`, will pause slide switching when mouse cursor hovers the slide. * * @since 2.2.0 */ set pauseOnHover(value) { this._pauseOnHover$.next(value); } get pauseOnHover() { return this._pauseOnHover$.value; } /** * If `true`, will pause slide switching when the focus is inside the carousel. */ set pauseOnFocus(value) { this._pauseOnFocus$.next(value); } get pauseOnFocus() { return this._pauseOnFocus$.value; } set mouseHover(value) { this._mouseHover$.next(value); } get mouseHover() { return this._mouseHover$.value; } set focused(value) { this._focused$.next(value); } get focused() { return this._focused$.value; } arrowLeft() { this.focus(); this.prev(NgbSlideEventSource.ARROW_LEFT); } arrowRight() { this.focus(); this.next(NgbSlideEventSource.ARROW_RIGHT); } ngAfterContentInit() { // setInterval() doesn't play well with SSR and protractor, // so we should run it in the browser and outside Angular if (isPlatformBrowser(this._platformId)) { this._ngZone.runOutsideAngular(() => { const hasNextSlide$ = combineLatest([ this.slide.pipe(map((slideEvent) => slideEvent.current), startWith(this.activeId)), this._wrap$, this.slides.changes.pipe(startWith(null)), ]).pipe(map(([currentSlideId, wrap]) => { const slideArr = this.slides.toArray(); const currentSlideIdx = this._getSlideIdxById(currentSlideId); return wrap ? slideArr.length > 1 : currentSlideIdx < slideArr.length - 1; }), distinctUntilChanged()); combineLatest([ this._pause$, this._pauseOnHover$, this._mouseHover$, this._pauseOnFocus$, this._focused$, this._interval$, hasNextSlide$, ]) .pipe(map(([pause, pauseOnHover, mouseHover, pauseOnFocus, focused, interval, hasNextSlide]) => pause || (pauseOnHover && mouseHover) || (pauseOnFocus && focused) || !hasNextSlide ? 0 : interval), distinctUntilChanged(), switchMap((interval) => (interval > 0 ? timer(interval, interval) : NEVER)), takeUntilDestroyed(this._destroyRef)) .subscribe(() => this._ngZone.run(() => this.next(NgbSlideEventSource.TIMER))); }); } this.slides.changes.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(() => { this._transitionIds?.forEach((id) => ngbCompleteTransition(this._getSlideElement(id))); this._transitionIds = null; this._cd.markForCheck(); // The following code need to be done asynchronously, after the dom becomes stable, // otherwise all changes will be undone. this._ngZone.onStable.pipe(take(1)).subscribe(() => { for (const { id } of this.slides) { const element = this._getSlideElement(id); if (id === this.activeId) { element.classList.add('active'); } else { element.classList.remove('active'); } } }); }); } ngAfterContentChecked() { let activeSlide = this._getSlideById(this.activeId); this.activeId = activeSlide ? activeSlide.id : this.slides.length ? this.slides.first.id : ''; } ngAfterViewInit() { // Initialize the 'active' class (not managed by the template) if (this.activeId) { const element = this._getSlideElement(this.activeId); if (element) { element.classList.add('active'); } } } /** * Navigates to a slide with the specified identifier. */ select(slideId, source) { this._cycleToSelected(slideId, this._getSlideEventDirection(this.activeId, slideId), source); } /** * Navigates to the previous slide. */ prev(source) { this._cycleToSelected(this._getPrevSlide(this.activeId), NgbSlideEventDirection.END, source); } /** * Navigates to the next slide. */ next(source) { this._cycleToSelected(this._getNextSlide(this.activeId), NgbSlideEventDirection.START, source); } /** * Pauses cycling through the slides. */ pause() { this._pause$.next(true); } /** * Restarts cycling through the slides from start to end. */ cycle() { this._pause$.next(false); } /** * Set the focus on the carousel. */ focus() { this._container.nativeElement.focus(); } _cycleToSelected(slideIdx, direction, source) { const transitionIds = this._transitionIds; if (transitionIds && (transitionIds[0] !== slideIdx || transitionIds[1] !== this.activeId)) { // Revert prevented return; } let selectedSlide = this._getSlideById(slideIdx); if (selectedSlide && selectedSlide.id !== this.activeId) { this._transitionIds = [this.activeId, slideIdx]; this.slide.emit({ prev: this.activeId, current: selectedSlide.id, direction: direction, paused: this._pause$.value, source, }); const options = { animation: this.animation, runningTransition: 'stop', context: { direction }, }; const transitions = []; const activeSlide = this._getSlideById(this.activeId); if (activeSlide) { const activeSlideTransition = ngbRunTransition(this._ngZone, this._getSlideElement(activeSlide.id), ngbCarouselTransitionOut, options); activeSlideTransition.subscribe(() => { activeSlide.slid.emit({ isShown: false, direction, source }); }); transitions.push(activeSlideTransition); } const previousId = this.activeId; this.activeId = selectedSlide.id; const nextSlide = this._getSlideById(this.activeId); const transition = ngbRunTransition(this._ngZone, this._getSlideElement(selectedSlide.id), ngbCarouselTransitionIn, options); transition.subscribe(() => { nextSlide?.slid.emit({ isShown: true, direction, source }); }); transitions.push(transition); zip(...transitions) .pipe(take(1)) .subscribe(() => { this._transitionIds = null; this.slid.emit({ prev: previousId, current: selectedSlide.id, direction: direction, paused: this._pause$.value, source, }); }); } // we get here after the interval fires or any external API call like next(), prev() or select() this._cd.markForCheck(); } _getSlideEventDirection(currentActiveSlideId, nextActiveSlideId) { const currentActiveSlideIdx = this._getSlideIdxById(currentActiveSlideId); const nextActiveSlideIdx = this._getSlideIdxById(nextActiveSlideId); return currentActiveSlideIdx > nextActiveSlideIdx ? NgbSlideEventDirection.END : NgbSlideEventDirection.START; } _getSlideById(slideId) { return this.slides.find((slide) => slide.id === slideId) || null; } _getSlideIdxById(slideId) { const slide = this._getSlideById(slideId); return slide != null ? this.slides.toArray().indexOf(slide) : -1; } _getNextSlide(currentSlideId) { const slideArr = this.slides.toArray(); const currentSlideIdx = this._getSlideIdxById(currentSlideId); const isLastSlide = currentSlideIdx === slideArr.length - 1; return isLastSlide ? this.wrap ? slideArr[0].id : slideArr[slideArr.length - 1].id : slideArr[currentSlideIdx + 1].id; } _getPrevSlide(currentSlideId) { const slideArr = this.slides.toArray(); const currentSlideIdx = this._getSlideIdxById(currentSlideId); const isFirstSlide = currentSlideIdx === 0; return isFirstSlide ? this.wrap ? slideArr[slideArr.length - 1].id : slideArr[0].id : slideArr[currentSlideIdx - 1].id; } _getSlideElement(slideId) { return this._container.nativeElement.querySelector(`#slide-${slideId}`); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbCarousel, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.0.0", type: NgbCarousel, isStandalone: true, selector: "ngb-carousel", inputs: { animation: "animation", activeId: "activeId", interval: "interval", wrap: "wrap", keyboard: "keyboard", pauseOnHover: "pauseOnHover", pauseOnFocus: "pauseOnFocus", showNavigationArrows: "showNavigationArrows", showNavigationIndicators: "showNavigationIndicators" }, outputs: { slide: "slide", slid: "slid" }, host: { attributes: { "tabIndex": "0" }, listeners: { "keydown.arrowLeft": "keyboard && arrowLeft()", "keydown.arrowRight": "keyboard && arrowRight()", "mouseenter": "mouseHover = true", "mouseleave": "mouseHover = false", "focusin": "focused = true", "focusout": "focused = false" }, properties: { "style.display": "\"block\"", "attr.aria-activedescendant": "'slide-' + activeId" }, classAttribute: "carousel slide" }, queries: [{ propertyName: "slides", predicate: NgbSlide }], exportAs: ["ngbCarousel"], ngImport: i0, template: ` <div class="carousel-indicators" [class.visually-hidden]="!showNavigationIndicators" role="tablist"> @for (slide of slides; track slide) { <button type="button" data-bs-target [class.active]="slide.id === activeId" role="tab" [attr.aria-labelledby]="'slide-' + slide.id" [attr.aria-controls]="'slide-' + slide.id" [attr.aria-selected]="slide.id === activeId" (click)="focus(); select(slide.id, NgbSlideEventSource.INDICATOR)" ></button> } </div> <div class="carousel-inner"> @for (slide of slides; track slide; let i = $index; let c = $count) { <div class="carousel-item" [id]="'slide-' + slide.id" role="tabpanel"> <span class="visually-hidden" i18n="Currently selected slide number read by screen reader@@ngb.carousel.slide-number" > Slide {{ i + 1 }} of {{ c }} </span> <ng-template [ngTemplateOutlet]="slide.templateRef" /> </div> } </div> @if (showNavigationArrows) { <button class="carousel-control-prev" type="button" (click)="arrowLeft()" [attr.aria-labelledby]="id + '-previous'" > <span class="carousel-control-prev-icon" aria-hidden="true"></span> <span class="visually-hidden" i18n="@@ngb.carousel.previous" [id]="id + '-previous'">Previous</span> </button> <button class="carousel-control-next" type="button" (click)="arrowRight()" [attr.aria-labelledby]="id + '-next'"> <span class="carousel-control-next-icon" aria-hidden="true"></span> <span class="visually-hidden" i18n="@@ngb.carousel.next" [id]="id + '-next'">Next</span> </button> } `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: NgbCarousel, decorators: [{ type: Component, args: [{ selector: 'ngb-carousel', exportAs: 'ngbCarousel', standalone: true, imports: [NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'carousel slide', '[style.display]': '"block"', tabIndex: '0', '(keydown.arrowLeft)': 'keyboard && arrowLeft()', '(keydown.arrowRight)': 'keyboard && arrowRight()', '(mouseenter)': 'mouseHover = true', '(mouseleave)': 'mouseHover = false', '(focusin)': 'focused = true', '(focusout)': 'focused = false', '[attr.aria-activedescendant]': `'slide-' + activeId`, }, template: ` <div class="carousel-indicators" [class.visually-hidden]="!showNavigationIndicators" role="tablist"> @for (slide of slides; track slide) { <button type="button" data-bs-target [class.active]="slide.id === activeId" role="tab" [attr.aria-labelledby]="'slide-' + slide.id" [attr.aria-controls]="'slide-' + slide.id" [attr.aria-selected]="slide.id === activeId" (click)="focus(); select(slide.id, NgbSlideEventSource.INDICATOR)" ></button> } </div> <div class="carousel-inner"> @for (slide of slides; track slide; let i = $index; let c = $count) { <div class="carousel-item" [id]="'slide-' + slide.id" role="tabpanel"> <span class="visually-hidden" i18n="Currently selected slide number read by screen reader@@ngb.carousel.slide-number" > Slide {{ i + 1 }} of {{ c }} </span> <ng-template [ngTemplateOutlet]="slide.templateRef" /> </div> } </div> @if (showNavigationArrows) { <button class="carousel-control-prev" type="button" (click)="arrowLeft()" [attr.aria-labelledby]="id + '-previous'" > <span class="carousel-control-prev-icon" aria-hidden="true"></span> <span class="visually-hidden" i18n="@@ngb.carousel.previous" [id]="id + '-previous'">Previous</span> </button> <button class="carousel-control-next" type="button" (click)="arrowRight()" [attr.aria-labelledby]="id + '-next'"> <span class="carousel-control-next-icon" aria-hidden="true"></span> <span class="visually-hidden" i18n="@@ngb.carousel.next" [id]="id + '-next'">Next</span> </button> } `, }] }], propDecorators: { slides: [{ type: ContentChildren, args: [NgbSlide] }], animation: [{ type: Input }], activeId: [{ type: Input }], interval: [{ type: Input }], wrap: [{ type: Input }], keyboard: [{ type: Input }], pauseOnHover: [{ type: Input }], pauseOnFocus: [{ type: Input }], showNavigationArrows: [{ type: Input }], showNavigationIndicators: [{ type: Input }], slide: [{ type: Output }], slid: [{ type: Output }] } }); export var NgbSlideEventSource; (function (NgbSlideEventSource) { NgbSlideEventSource["TIMER"] = "timer"; NgbSlideEventSource["ARROW_LEFT"] = "arrowLeft"; NgbSlideEventSource["ARROW_RIGHT"] = "arrowRight"; NgbSlideEventSource["INDICATOR"] = "indicator"; })(NgbSlideEventSource || (NgbSlideEventSource = {})); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2Fyb3VzZWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY2Fyb3VzZWwvY2Fyb3VzZWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUlOLHVCQUF1QixFQUN2QixpQkFBaUIsRUFDakIsU0FBUyxFQUNULGVBQWUsRUFDZixVQUFVLEVBQ1YsU0FBUyxFQUNULFVBQVUsRUFDVixZQUFZLEVBQ1osTUFBTSxFQUNOLEtBQUssRUFDTCxNQUFNLEVBQ04sTUFBTSxFQUNOLFdBQVcsRUFFWCxXQUFXLEVBQ1gsaUJBQWlCLEdBQ2pCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRXRFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRXRELE9BQU8sRUFBRSxlQUFlLEVBQUUsYUFBYSxFQUFFLEtBQUssRUFBYyxLQUFLLEVBQUUsR0FBRyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3JGLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN2RixPQUFPLEVBQUUscUJBQXFCLEVBQUUsZ0JBQWdCLEVBQXdCLE1BQU0sa0NBQWtDLENBQUM7QUFDakgsT0FBTyxFQUVOLHVCQUF1QixFQUN2Qix3QkFBd0IsRUFDeEIsc0JBQXNCLEdBQ3RCLE1BQU0sdUJBQXVCLENBQUM7QUFDL0IsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7O0FBRWhFLElBQUksTUFBTSxHQUFHLENBQUMsQ0FBQztBQUNmLElBQUksVUFBVSxHQUFHLENBQUMsQ0FBQztBQUVuQjs7R0FFRztBQUVILE1BQU0sT0FBTyxRQUFRO0lBRHJCO1FBRUMsZ0JBQVcsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7UUFF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bnRlbnRDaGVja2VkLFxuXHRBZnRlckNvbnRlbnRJbml0LFxuXHRBZnRlclZpZXdJbml0LFxuXHRDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcblx0Q2hhbmdlRGV0ZWN0b3JSZWYsXG5cdENvbXBvbmVudCxcblx0Q29udGVudENoaWxkcmVuLFxuXHREZXN0cm95UmVmLFxuXHREaXJlY3RpdmUsXG5cdEVsZW1lbnRSZWYsXG5cdEV2ZW50RW1pdHRlcixcblx0aW5qZWN0LFxuXHRJbnB1dCxcblx0Tmdab25lLFxuXHRPdXRwdXQsXG5cdFBMQVRGT1JNX0lELFxuXHRRdWVyeUxpc3QsXG5cdFRlbXBsYXRlUmVmLFxuXHRWaWV3RW5jYXBzdWxhdGlvbixcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBpc1BsYXRmb3JtQnJvd3NlciwgTmdUZW1wbGF0ZU91dGxldCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5cbmltcG9ydCB7IE5nYkNhcm91c2VsQ29uZmlnIH0gZnJvbSAnLi9jYXJvdXNlbC1jb25maWcnO1xuXG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIGNvbWJpbmVMYXRlc3QsIE5FVkVSLCBPYnNlcnZhYmxlLCB0aW1lciwgemlwIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBkaXN0aW5jdFVudGlsQ2hhbmdlZCwgbWFwLCBzdGFydFdpdGgsIHN3aXRjaE1hcCwgdGFrZSB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IG5nYkNvbXBsZXRlVHJhbnNpdGlvbiwgbmdiUnVuVHJhbnNpdGlvbiwgTmdiVHJhbnNpdGlvbk9wdGlvbnMgfSBmcm9tICcuLi91dGlsL3RyYW5zaXRpb24vbmdiVHJhbnNpdGlvbic7XG5pbXBvcnQge1xuXHROZ2JDYXJvdXNlbEN0eCxcblx0bmdiQ2Fyb3VzZWxUcmFuc2l0aW9uSW4sXG5cdG5nYkNhcm91c2VsVHJhbnNpdGlvbk91dCxcblx0TmdiU2xpZGVFdmVudERpcmVjdGlvbixcbn0gZnJvbSAnLi9jYXJvdXNlbC10cmFuc2l0aW9uJztcbmltcG9ydCB7IHRha2VVbnRpbERlc3Ryb3llZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUvcnhqcy1pbnRlcm9wJztcblxubGV0IG5leHRJZCA9IDA7XG5sZXQgY2Fyb3VzZWxJZCA9IDA7XG5cbi8qKlxuICogQSBkaXJlY3RpdmUgdGhhdCB3cmFwcyB0aGUgaW5kaXZpZHVhbCBjYXJvdXNlbCBzbGlkZS5cbiAqL1xuQERpcmVjdGl2ZSh7IHNlbGVjdG9yOiAnbmctdGVtcGxhdGVbbmdiU2xpZGVdJywgc3RhbmRhbG9uZTogdHJ1ZSB9KVxuZXhwb3J0IGNsYXNzIE5nYlNsaWRlIHtcblx0dGVtcGxhdGVSZWYgPSBpbmplY3QoVGVtcGxhdGVSZWYpO1xuXG5cdC8qKlxuXHQgKiBTbGlkZSBpZCB0aGF0IG11c3QgYmUgdW5pcXVlIGZvciB0aGUgZW50aXJlIGRvY3VtZW50LlxuXHQgKlxuXHQgKiBJZiBub3QgcHJvdmlkZWQsIHdpbGwgYmUgZ2VuZXJhdGVkIGluIHRoZSBgbmdiLXNsaWRlLXh4YCBmb3JtYXQuXG5cdCAqL1xuXHRASW5wdXQoKSBpZCA9IGBuZ2Itc2xpZGUtJHtuZXh0SWQrK31gO1xuXG5cdC8qKlxuXHQgKiBBbiBldmVudCBlbWl0dGVkIHdoZW4gdGhlIHNsaWRlIHRyYW5zaXRpb24gaXMgZmluaXNoZWRcblx0ICpcblx0ICogQHNpbmNlIDguMC4wXG5cdCAqL1xuXHRAT3V0cHV0KCkgc2xpZCA9IG5ldyBFdmVudEVtaXR0ZXI8TmdiU2luZ2xlU2xpZGVFdmVudD4oKTtcbn1cblxuLyoqXG4gKiBDYXJvdXNlbCBpcyBhIGNvbXBvbmVudCB0byBlYXNpbHkgY3JlYXRlIGFuZCBjb250cm9sIHNsaWRlc2hvd3MuXG4gKlxuICogQWxsb3dzIHRvIHNldCBpbnRlcnZhbHMsIGNoYW5nZSB0aGUgd2F5IHVzZXIgaW50ZXJhY3RzIHdpdGggdGhlIHNsaWRlcyBhbmQgcHJvdmlkZXMgYSBwcm9ncmFtbWF0aWMgQVBJLlxuICovXG5AQ29tcG9uZW50KHtcblx0c2VsZWN0b3I6ICduZ2ItY2Fyb3VzZWwnLFxuXHRleHBvcnRBczogJ25nYkNhcm91c2VsJyxcblx0c3RhbmRhbG9uZTogdHJ1ZSxcblx0aW1wb3J0czogW05nVGVtcGxhdGVPdXRsZXRdLFxuXHRjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcblx0ZW5jYXBzdWxhdGlvbjogVmlld0VuY2Fwc3VsYXRpb24uTm9uZSxcblx0aG9zdDoge1xuXHRcdGNsYXNzOiAnY2Fyb3VzZWwgc2xpZGUnLFxuXHRcdCdbc3R5bGUuZGlzcGxheV0nOiAnXCJibG9ja1wiJyxcblx0XHR0YWJJbmRleDogJzAnLFxuXHRcdCcoa2V5ZG93bi5hcnJvd0xlZnQpJzogJ2tleWJvYXJkICYmIGFycm93TGVmdCgpJyxcblx0XHQnKGtleWRvd24uYXJyb3dSaWdodCknOiAna2V5Ym9hcmQgJiYgYXJyb3dSaWdodCgpJyxcblx0XHQnKG1vdXNlZW50ZXIpJzogJ21vdXNlSG92ZXIgPSB0cnVlJyxcblx0XHQnKG1vdXNlbGVhdmUpJzogJ21vdXNlSG92ZXIgPSBmYWxzZScsXG5cdFx0Jyhmb2N1c2luKSc6ICdmb2N1c2VkID0gdHJ1ZScsXG5cdFx0Jyhmb2N1c291dCknOiAnZm9jdXNlZCA9IGZhbHNlJyxcblx0XHQnW2F0dHIuYXJpYS1hY3RpdmVkZXNjZW5kYW50XSc6IGAnc2xpZGUtJyArIGFjdGl2ZUlkYCxcblx0fSxcblx0dGVtcGxhdGU6IGBcblx0XHQ8ZGl2IGNsYXNzPVwiY2Fyb3VzZWwtaW5kaWNhdG9yc1wiIFtjbGFzcy52aXN1YWxseS1oaWRkZW5dPVwiIXNob3dOYXZpZ2F0aW9uSW5kaWNhdG9yc1wiIHJvbGU9XCJ0YWJsaXN0XCI+XG5cdFx0XHRAZm9yIChzbGlkZSBvZiBzbGlkZXM7IHRyYWNrIHNsaWRlKSB7XG5cdFx0XHRcdDxidXR0b25cblx0XHRcdFx0XHR0eXBlPVwiYnV0dG9uXCJcblx0XHRcdFx0XHRkYXRhLWJzLXRhcmdldFxuXHRcdFx0XHRcdFtjbGFzcy5hY3RpdmVdPVwic2xpZGUuaWQgPT09IGFjdGl2ZUlkXCJcblx0XHRcdFx0XHRyb2xlPVwidGFiXCJcblx0XHRcdFx0XHRbYXR0ci5hcmlhLWxhYmVsbGVkYnldPVwiJ3NsaWRlLScgKyBzbGlkZS5pZFwiXG5cdFx0XHRcdFx0W2F0dHIuYXJpYS1jb250cm9sc109XCInc2xpZGUtJyArIHNsaWRlLmlkXCJcblx0XHRcdFx0XHRbYXR0ci5hcmlhLXNlbGVjdGVkXT1cInNsaWRlLmlkID09PSBhY3RpdmVJZFwiXG5cdFx0XHRcdFx0KGNsaWNrKT1cImZvY3VzKCk7IHNlbGVjdChzbGlkZS5pZCwgTmdiU2xpZGVFdmVudFNvdXJjZS5JTkRJQ0FUT1IpXCJcblx0XHRcdFx0PjwvYnV0dG9uPlxuXHRcdFx0fVxuXHRcdDwvZGl2PlxuXHRcdDxkaXYgY2xhc3M9XCJjYXJvdXNlbC1pbm5lclwiPlxuXHRcdFx0QGZvciAoc2xpZGUgb2Ygc2xpZGVzOyB0cmFjayBzbGlkZTsgbGV0IGkgPSAkaW5kZXg7IGxldCBjID0gJGNvdW50KSB7XG5cdFx0XHRcdDxkaXYgY2xhc3M9XCJjYXJvdXNlbC1pdGVtXCIgW2lkXT1cIidzbGlkZS0nICsgc2xpZGUuaWRcIiByb2xlPVwidGFicGFuZWxcIj5cblx0XHRcdFx0XHQ8c3BhblxuXHRcdFx0XHRcdFx0Y2xhc3M9XCJ2aXN1YWxseS1oaWRkZW5cIlxuXHRcdFx0XHRcdFx0aTE4bj1cIkN1cnJlbnRseSBzZWxlY3RlZCBzbGlkZSBudW1iZXIgcmVhZCBieSBzY3JlZW4gcmVhZGVyQEBuZ2IuY2Fyb3VzZWwuc2xpZGUtbnVtYmVyXCJcblx0XHRcdFx0XHQ+XG5cdFx0XHRcdFx0XHRTbGlkZSB7eyBpICsgMSB9fSBvZiB7eyBjIH19XG5cdFx0XHRcdFx0PC9zcGFuPlxuXHRcdFx0XHRcdDxuZy10ZW1wbGF0ZSBbbmdUZW1wbGF0ZU91dGxldF09XCJzbGlkZS50ZW1wbGF0ZVJlZlwiIC8+XG5cdFx0XHRcdDwvZGl2PlxuXHRcdFx0fVxuXHRcdDwvZGl2PlxuXHRcdEBpZiAoc2hvd05hdmlnYXRpb25BcnJvd3MpIHtcblx0XHRcdDxidXR0b25cblx0XHRcdFx0Y2xhc3M9XCJjYXJvdXNlbC1jb250cm9sLXByZXZcIlxuXHRcdFx0XHR0eXBlPVwiYnV0dG9uXCJcblx0XHRcdFx0KGNsaWNrKT1cImFycm93TGVmdCgpXCJcblx0XHRcdFx0W2F0dHIuYXJpYS1sYWJlbGxlZGJ5XT1cImlkICsgJy1wcmV2aW91cydcIlxuXHRcdFx0PlxuXHRcdFx0XHQ8c3BhbiBjbGFzcz1cImNhcm91c2VsLWNvbnRyb2wtcHJldi1pY29uXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCI+PC9zcGFuPlxuXHRcdFx0XHQ8c3BhbiBjbGFzcz1cInZpc3VhbGx5LWhpZGRlblwiIGkxOG49XCJAQG5nYi5jYXJvdXNlbC5wcmV2aW91c1wiIFtpZF09XCJpZCArICctcHJldmlvdXMnXCI+UHJldmlvdXM8L3NwYW4+XG5cdFx0XHQ8L2J1dHRvbj5cblx0XHRcdDxidXR0b24gY2xhc3M9XCJjYXJvdXNlbC1jb250cm9sLW5leHRcIiB0eXBlPVwiYnV0dG9uXCIgKGNsaWNrKT1cImFycm93UmlnaHQoKVwiIFthdHRyLmFyaWEtbGFiZWxsZWRieV09XCJpZCArICctbmV4dCdcIj5cblx0XHRcdFx0PHNwYW4gY2xhc3M9XCJjYXJvdXNlbC1jb250cm9sLW5leHQtaWNvblwiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPjwvc3Bhbj5cblx0XHRcdFx0PHNwYW4gY2xhc3M9XCJ2aXN1YWxseS1oaWRkZW5cIiBpMThuPVwiQEBuZ2IuY2Fyb3VzZWwubmV4dFwiIFtpZF09XCJpZCArICctbmV4dCdcIj5OZXh0PC9zcGFuPlxuXHRcdFx0PC9idXR0b24+XG5cdFx0fVxuXHRgLFxufSlcbmV4cG9ydCBjbGFzcyBOZ2JDYXJvdXNlbCBpbXBsZW1lbnRzIEFmdGVyQ29udGVudENoZWNrZWQsIEFmdGVyQ29udGVudEluaXQsIEFmdGVyVmlld0luaXQge1xuXHRAQ29udGVudENoaWxkcmVuKE5nYlNsaWRlKSBzbGlkZXM6IFF1ZXJ5TGlzdDxOZ2JTbGlkZT47XG5cblx0cHVibGljIE5nYlNsaWRlRXZlbnRTb3VyY2UgPSBOZ2JTbGlkZUV2ZW50U291cmNlO1xuXG5cdHByaXZhdGUgX2NvbmZpZyA9IGluamVjdChOZ2JDYXJvdXNlbENvbmZpZyk7XG5cdHByaXZhdGUgX3BsYXRmb3JtSWQgPSBpbmplY3QoUExBVEZPUk1fSUQpO1xuXHRwcml2YXRlIF9uZ1pvbmUgPSBpbmplY3QoTmdab25lKTtcblx0cHJpdmF0ZSBfY2QgPSBpbmplY3QoQ2hhbmdlRGV0ZWN0b3JSZWYpO1xuXHRwcml2YXRlIF9jb250YWluZXIgPSBpbmplY3QoRWxlbWVudFJlZik7XG5cdHByaXZhdGUgX2Rlc3Ryb3lSZWYgPSBpbmplY3QoRGVzdHJveVJlZik7XG5cblx0cHJpdmF0ZSBfaW50ZXJ2YWwkID0gbmV3IEJlaGF2aW9yU3ViamVjdCh0aGlzLl9jb25maWcuaW50ZXJ2YWwpO1xuXHRwcml2YXRlIF9tb3VzZUhvdmVyJCA9IG5ldyBCZWhhdmlvclN1YmplY3QoZmFsc2UpO1xuXHRwcml2YXRlIF9mb2N1c2VkJCA9IG5ldyBCZWhhdmlvclN1YmplY3QoZmFsc2UpO1xuXHRwcml2YXRlIF9wYXVzZU9uSG92ZXIkID0gbmV3IEJlaGF2aW9yU3ViamVjdCh0aGlzLl9jb25maWcucGF1c2VPbkhvdmVyKTtcblx0cHJpdmF0ZSBfcGF1c2VPbkZvY3VzJCA9IG5ldyBCZWhhdmlvclN1YmplY3QodGhpcy5fY29uZmlnLnBhdXNlT25Gb2N1cyk7XG5cdHByaXZhdGUgX3BhdXNlJCA9IG5ldyBCZWhhdmlvclN1YmplY3QoZmFsc2UpO1xuXHRwcml2YXRlIF93cmFwJCA9IG5ldyBCZWhhdmlvclN1YmplY3QodGhpcy5fY29uZmlnLndyYXApO1xuXG5cdGlkID0gYG5nYi1jYXJvdXNlbC0ke2Nhcm91c2VsSWQrK31gO1xuXG5cdC8qKlxuXHQgKiBBIGZsYWcgdG8gZW5hYmxlL2Rpc2FibGUgdGhlIGFuaW1hdGlvbnMuXG5cdCAqXG5cdCAqIEBzaW5jZSA4LjAuMFxuXHQgKi9cblx0QElucHV0KCkgYW5pbWF0aW9uID0gdGhpcy5fY29uZmlnLmFuaW1hdGlvbjtcblxuXHQvKipcblx0ICogVGhlIHNsaWRlIGlkIHRoYXQgc2hvdWxkIGJlIGRpc3BsYXllZCAqKmluaXRpYWxseSoqLlxuXHQgKlxuXHQgKiBGb3Igc3Vic2VxdWVudCBpbnRlcmFjdGlvbnMgdXNlIG1ldGhvZHMgYHNlbGVjdCgpYCwgYG5leHQoKWAsIGV0Yy4gYW5kIHRoZSBgKHNsaWRlKWAgb3V0cHV0LlxuXHQgKi9cblx0QElucHV0KCkgYWN0aXZlSWQ6IHN0cmluZztcblxuXHQvKipcblx0ICogVGltZSBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIHRoZSBuZXh0IHNsaWRlIGlzIHNob3duLlxuXHQgKi9cblx0QElucHV0KClcblx0c2V0IGludGVydmFsKHZhbHVlOiBudW1iZXIpIHtcblx0XHR0aGlzLl9pbnRlcnZhbCQubmV4dCh2YWx1ZSk7XG5cdH1cblxuXHRnZXQgaW50ZXJ2YWwoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX2ludGVydmFsJC52YWx1ZTtcblx0fVxuXG5cdC8qKlxuXHQgKiBJZiBgdHJ1ZWAsIHdpbGwgJ3dyYXAnIHRoZSBjYXJvdXNlbCBieSBzd2l0Y2hpbmcgZnJvbSB0aGUgbGFzdCBzbGlkZSBiYWNrIHRvIHRoZSBmaXJzdC5cblx0ICovXG5cdEBJbnB1dCgpXG5cdHNldCB3cmFwKHZhbHVlOiBib29sZWFuKSB7XG5cdFx0dGhpcy5fd3JhcCQubmV4dCh2YWx1ZSk7XG5cdH1cblxuXHRnZXQgd3JhcCgpIHtcblx0XHRyZXR1cm4gdGhpcy5fd3JhcCQudmFsdWU7XG5cdH1cblxuXHQvKipcblx0ICogSWYgYHRydWVgLCBhbGxvd3MgdG8gaW50ZXJhY3Qgd2l0aCBjYXJvdXNlbCB1c2luZyBrZXlib2FyZCAnYXJyb3cgbGVmdCcgYW5kICdhcnJvdyByaWdodCcuXG5cdCAqL1xuXHRASW5wdXQoKSBrZXlib2FyZCA9IHRoaXMuX2NvbmZpZy5rZXlib2FyZDtcblxuXHQvKipcblx0ICogSWYgYHRydWVgLCB3aWxsIHBhdXNlIHNsaWRlIHN3aXRjaGluZyB3aGVuIG1vdXNlIGN1cnNvciBob3ZlcnMgdGhlIHNsaWRlLlxuXHQgKlxuXHQgKiBAc2luY2UgMi4yLjBcblx0ICovXG5cdEBJbnB1dCgpXG5cdHNldCBwYXVzZU9uSG92ZXIodmFsdWU6IGJvb2xlYW4pIHtcblx0XHR0aGlzLl9wYXVzZU9uSG92ZXIkLm5leHQodmFsdWUpO1xuXHR9XG5cblx0Z2V0IHBhdXNlT25Ib3ZlcigpIHtcblx0XHRyZXR1cm4gdGhpcy5fcGF1c2VPbkhvdmVyJC52YWx1ZTtcblx0fVxuXG5cdC8qKlxuXHQgKiBJZiBgdHJ1ZWAsIHdpbGwgcGF1c2Ugc2xpZGUgc3dpdGNoaW5nIHdoZW4gdGhlIGZvY3VzIGlzIGluc2lkZSB0aGUgY2Fyb3VzZWwuXG5cdCAqL1xuXHRASW5wdXQoKVxuXHRzZXQgcGF1c2VPbkZvY3VzKHZhbHVlOiBib29sZWFuKSB7XG5cdFx0dGhpcy5fcGF1c2VPbkZvY3VzJC5uZXh0KHZhbHVlKTtcblx0fVxuXG5cdGdldCBwYXVzZU9uRm9jdXMoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX3BhdXNlT25Gb2N1cyQudmFsdWU7XG5cdH1cblxuXHQvKipcblx0ICogSWYgYHRydWVgLCAncHJldmlvdXMnIGFuZCAnbmV4dCcgbmF2aWdhdGlvbiBhcnJvd3Mgd2lsbCBiZSB2aXNpYmxlIG9uIHRoZSBzbGlkZS5cblx0ICpcblx0ICogQHNpbmNlIDIuMi4wXG5cdCAqL1xuXHRASW5wdXQoKSBzaG93TmF2aWdhdGlvbkFycm93cyA9IHRoaXMuX2NvbmZpZy5zaG93TmF2aWdhdGlvbkFycm93cztcblxuXHQvKipcblx0ICogSWYgYHRydWVgLCBuYXZpZ2F0aW9uIGluZGljYXRvcnMgYXQgdGhlIGJvdHRvbSBvZiB0aGUgc2xpZGUgd2lsbCBiZSB2aXNpYmxlLlxuXHQgKlxuXHQgKiBAc2luY2UgMi4yLjBcblx0ICovXG5cdEBJbnB1dCgpIHNob3dOYXZpZ2F0aW9uSW5kaWNhdG9ycyA9IHRoaXMuX2NvbmZpZy5zaG93TmF2aWdhdGlvbkluZGljYXRvcnM7XG5cblx0LyoqXG5cdCAqIEFuIGV2ZW50IGVtaXR0ZWQganVzdCBiZWZvcmUgdGhlIHNsaWRlIHRyYW5zaXRpb24gc3RhcnRzLlxuXHQgKlxuXHQgKiBTZWUgW2BOZ2JTbGlkZUV2ZW50YF0oIy9jb21wb25lbnRzL2Nhcm91c2VsL2FwaSNOZ2JTbGlkZUV2ZW50KSBmb3IgcGF5bG9hZCBkZXRhaWxzLlxuXHQgKi9cblx0QE91dHB1dCgpIHNsaWRlID0gbmV3IEV2ZW50RW1pdHRlcjxOZ2JTbGlkZUV2ZW50PigpO1xuXG5cdC8qKlxuXHQgKiBBbiBldmVudCBlbWl0dGVkIHJpZ2h0IGFmdGVyIHRoZSBzbGlkZSB0cmFuc2l0aW9uIGlzIGNvbXBsZXRlZC5cblx0ICpcblx0ICogU2VlIFtgTmdiU2xpZGVFdmVudGBdKCMvY29tcG9uZW50cy9jYXJvdXNlbC9hcGkjTmdiU2xpZGVFdmVudCkgZm9yIHBheWxvYWQgZGV0YWlscy5cblx0ICpcblx0ICogQHNpbmNlIDguMC4wXG5cdCAqL1xuXHRAT3V0cHV0KCkgc2xpZCA9IG5ldyBFdmVudEVtaXR0ZXI8TmdiU2xpZGVFdmVudD4oKTtcblxuXHQvKlxuXHQgKiBLZWVwIHRoZSBpZHMgb2YgdGhlIHBhbmVscyBjdXJyZW50bHkgdHJhbnNpdGlvbm5pbmdcblx0ICogaW4gb3JkZXIgdG8gYWxsb3cgb25seSB0aGUgdHJhbnNpdGlvbiByZXZlcnRpb25cblx0ICovXG5cdHByaXZhdGUgX3RyYW5zaXRpb25JZHM6IFtzdHJpbmcsIHN0cmluZ10gfCBudWxsID0gbnVsbDtcblxuXHRzZXQgbW91c2VIb3Zlcih2YWx1ZTogYm9vbGVhbikge1xuXHRcdHRoaXMuX21vdXNlSG92ZXIkLm5leHQodmFsdWUpO1xuXHR9XG5cblx0Z2V0IG1vdXNlSG92ZXIoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX21vdXNlSG92ZXIkLnZhbHVlO1xuXHR9XG5cblx0c2V0IGZvY3VzZWQodmFsdWU6IGJvb2xlYW4pIHtcblx0XHR0aGlzLl9mb2N1c2VkJC5uZXh0KHZhbHVlKTtcblx0fVxuXG5cdGdldCBmb2N1c2VkKCkge1xuXHRcdHJldHVybiB0aGlzLl9mb2N1c2VkJC52YWx1ZTtcblx0fVxuXG5cdGFycm93TGVmdCgpIHtcblx0XHR0aGlzLmZvY3VzKCk7XG5cdFx0dGhpcy5wcmV2KE5nYlNsaWRlRXZlbnRTb3VyY2UuQVJST1dfTEVGVCk7XG5cdH1cblxuXHRhcnJvd1JpZ2h0KCkge1xuXHRcdHRoaXMuZm9jdXMoKTtcblx0XHR0aGlzLm5leHQoTmdiU2xpZGVFdmVudFNvdXJjZS5BUlJPV19SSUdIVCk7XG5cdH1cblxuXHRuZ0FmdGVyQ29udGVudEluaXQoKSB7XG5cdFx0Ly8gc2V0SW50ZXJ2YWwoKSBkb2Vzbid0IHBsYXkgd2VsbCB3aXRoIFNTUiBhbmQgcHJvdHJhY3Rvcixcblx0XHQvLyBzbyB3ZSBzaG91bGQgcnVuIGl0IGluIHRoZSBicm93c2VyIGFuZCBvdXRzaWRlIEFuZ3VsYXJcblx0XHRpZiAoaXNQbGF0Zm9ybUJyb3dzZXIodGhpcy5fcGxhdGZvcm1JZCkpIHtcblx0XHRcdHRoaXMuX25nWm9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PiB7XG5cdFx0XHRcdGNvbnN0IGhhc05leHRTbGlkZSQgPSBjb21iaW5lTGF0ZXN0KFtcblx0XHRcdFx0XHR0aGlzLnNsaWRlLnBpcGUoXG5cdFx0XHRcdFx0XHRtYXAoKHNsaWRlRXZlbnQpID0+IHNsaWRlRXZlbnQuY3VycmVudCksXG5cdFx0XHRcdFx0XHRzdGFydFdpdGgodGhpcy5hY3RpdmVJZCksXG5cdFx0XHRcdFx0KSxcblx0XHRcdFx0XHR0aGlzLl93cmFwJCxcblx0XHRcdFx0XHR0aGlzLnNsaWRlcy5jaGFuZ2VzLnBpcGUoc3RhcnRXaXRoKG51bGwpKSxcblx0XHRcdFx0XSkucGlwZShcblx0XHRcdFx0XHRtYXAoKFtjdXJyZW50U2xpZGVJZCwgd3JhcF0pID0+IHtcblx0XHRcdFx0XHRcdGNvbnN0IHNsaWRlQXJyID0gdGhpcy5zbGlkZXMudG9BcnJheSgpO1xuXHRcdFx0XHRcdFx0Y29uc3QgY3VycmVudFNsaWRlSWR4ID0gdGhpcy5fZ2V0U2xpZGVJZHhCeUlkKGN1cnJlbnRTbGlkZUlkKTtcblx0XHRcdFx0XHRcdHJldHVybiB3cmFwID8gc2xpZGVBcnIubGVuZ3RoID4gMSA6IGN1cnJlbnRTbGlkZUlkeCA8IHNsaWRlQXJyLmxlbmd0aCAtIDE7XG5cdFx0XHRcdFx0fSksXG5cdFx0XHRcdFx0ZGlzdGluY3RVbnRpbENoYW5nZWQoKSxcblx0XHRcdFx0KTtcblx0XHRcdFx0Y29tYmluZUxhdGVzdChbXG5cdFx0XHRcdFx0dGhpcy5fcGF1c2UkLFxuXHRcdFx0XHRcdHRoaXMuX3BhdXNlT25Ib3ZlciQsXG5cdFx0XHRcdFx0dGhpcy5fbW91c2VIb3ZlciQsXG5cdFx0XHRcdFx0dGhpcy5fcGF1c2VPbkZvY3VzJCxcblx0XHRcdFx0XHR0aGlzLl9mb2N1c2VkJCxcblx0XHRcdFx0XHR0aGlzLl9pbnRlcnZhbCQsXG5cdFx0XHRcdFx0aGFzTmV4dFNsaWRlJCxcblx0XHRcdFx0XSlcblx0XHRcdFx0XHQucGlwZShcblx0XHRcdFx0XHRcdG1hcChcblx0XHRcdFx0XHRcdFx0KFtwYXVzZSwgcGF1c2VPbkhvdmVyLCBtb3VzZUhvdmVyLCBwYXVzZU9uRm9jdXMsIGZvY3VzZWQsIGludGVydmFsLCBoYXNOZXh0U2xpZGVdOiBbXG5cdFx0XHRcdFx0XHRcdFx0Ym9vbGVhbixcblx0XHRcdFx0XHRcdFx0XHRib29sZWFuLFxuXHRcdFx0XHRcdFx0XHRcdGJvb2xlYW4sXG5cdFx0XHRcdFx0XHRcdFx0Ym9vbGVhbixcblx0XHRcdFx0XHRcdFx0XHRib29sZWFuLFxuXHRcdFx0XHRcdFx0XHRcdG51bWJlcixcblx0XHRcdFx0XHRcdFx0XHRib29sZWFuLFxuXHRcdFx0XHRcdFx0XHRdKSA9PlxuXHRcdFx0XHRcdFx0XHRcdHBhdXNlIHx8IChwYXVzZU9uSG92ZXIgJiYgbW91c2VIb3ZlcikgfHwgKHBhdXNlT25Gb2N1cyAmJiBmb2N1c2VkKSB8fCAhaGFzTmV4dFNsaWRlID8gMCA6IGludGVydmFsLFxuXHRcdFx0XHRcdFx0KSxcblxuXHRcdFx0XHRcdFx0ZG