UNPKG

rfx-parallax

Version:
276 lines 43.7 kB
import { Component, Inject, Input, PLATFORM_ID } from '@angular/core'; import { visibilityAnimation } from '../../animations'; import { isPlatformBrowser } from '@angular/common'; import * as i0 from "@angular/core"; import * as i1 from "../../services"; import * as i2 from "../../directives/will-change.directive"; export class RfxParallaxComponent { constructor(htmlElement, renderer, scrollEventService, resizeEventService, platformId) { this.htmlElement = htmlElement; this.renderer = renderer; this.scrollEventService = scrollEventService; this.resizeEventService = resizeEventService; this.platformId = platformId; this.parallaxPercentage = 40; this.positionPercentage = 50; this.imageZIndex = -1; this.isDisabled = false; this.visibleOverflow = false; this.imageLeftPx = 0; this.isLoaded = false; this.forceFullWidth = false; this.isBrowser = isPlatformBrowser(this.platformId); } /** * Set container position and overflow. * If parallax is not disabled, create listeners. */ ngOnInit() { if (this.isBrowser) { this.setContainerPosition(this.htmlElement.nativeElement); this.setContainerOverflow(this.htmlElement.nativeElement, this.visibleOverflow); if (!this.isDisabled) { this.createListeners(); } } } /** * Update parallax values when some properies changed. * - isDisabled change, enable or disable parallax and refresh image properties. * - visibleOverflow change, show or hide image overflow on container without refresh. * - imagerUrl, parallaxPercentage or positionPercentage change, refresh image properties. * @param {SimpleChanges} changes - SimpleChanges object. */ ngOnChanges(changes) { if (this.isBrowser) { if (this.hasValueChanged(changes['isDisabled'], true)) { this.destroyListeners(); } else if (this.hasValueChanged(changes['isDisabled'], false)) { this.createListeners(); } if (this.hasValueChanged(changes['visibleOverflow'])) { this.setContainerOverflow(this.htmlElement.nativeElement, changes['visibleOverflow'].currentValue); } if (this.image && ((this.hasValueChanged(changes['imageUrl']) || this.hasValueChanged(changes['parallaxPercentage']) || this.hasValueChanged(changes['positionPercentage'])) || this.hasValueChanged(changes['isDisabled']) || this.hasValueChanged(changes['forceFullWidth']))) { this.setImageProperties(this.image); } } } ngOnDestroy() { this.destroyListeners(); } /** * Check if SimpleChange value has changed. * Eventually check if value corresponds to a new value. * @param {SimpleChange} change - SimpleChange object. * @param {any} newValue - New value. * @returns {boolean} - true if value has changed. */ hasValueChanged(change, newValue = change?.currentValue) { return change?.firstChange === false && change?.currentValue !== undefined && change?.currentValue === newValue; } /** * Destroy all listeners. */ destroyListeners() { this.scrollEventListener?.unsubscribe(); this.resizeEventListener?.unsubscribe(); } /** * Listen to scroll and resize events. * Destroy alreay existing listeners. */ createListeners() { this.destroyListeners(); this.scrollEventListener = this.scrollEventService.getMouseScroll().subscribe((scroll) => this.onMouseScroll(scroll)); this.resizeEventListener = this.resizeEventService.getResize().subscribe(() => this.onResize()); } /** * On mouse scroll event recalculate and change * parallaxed image position. * @param {number} scroll - Scroll value. */ onMouseScroll(scroll) { if (this.parallaxBoundaries && this.image) { const topPx = this.getImageTop(scroll, this.parallaxBoundaries); this.setImageTransform(this.image, this.imageLeftPx, topPx); } } /** * On window resize event reload parallax properties. */ onResize() { if (this.image) { this.setImageProperties(this.image); } } /** * Set image object and loading status. * Set image properties after image is fully loaded * but only if platform is browser. * @param {Event} event - Image loaded event. */ onImageLoaded(event) { this.image = event.target; if (this.isBrowser) { this.setImageProperties(this.image); } this.isLoaded = true; } /** * Set image properties needed for parallax effect. * @param {HTMLImageElement} image - Image to be parallaxed. */ setImageProperties(image) { const scrollTop = this.scrollEventService.getMouseScrollValue(); this.setImageSize(image, this.htmlElement.nativeElement.clientWidth, this.htmlElement.nativeElement.clientHeight, this.parallaxPercentage, this.isDisabled, this.forceFullWidth); this.parallaxBoundaries = this.getParallaxBoundaries(scrollTop, this.htmlElement.nativeElement, image.height, this.parallaxPercentage); this.imageLeftPx = this.getImageLeft(this.htmlElement.nativeElement.clientWidth, image.width, this.positionPercentage); const topPx = this.isDisabled ? this.getDisabledImageTop(this.parallaxBoundaries) : this.getImageTop(scrollTop, this.parallaxBoundaries); this.setImageTransform(image, this.imageLeftPx, topPx); } /** * Set container position to relative * if image is not already in relative or absolute position. * @param {HTMLElement} container */ setContainerPosition(container) { const position = getComputedStyle(container).position; if (position !== 'relative' && position !== 'absolute') { this.renderer.setStyle(container, 'position', 'relative'); } } /** * Set container overflow. * @param {HTMLElement} container - Container element. * @param {boolean} isOverflowVisible - true to show container overflow. */ setContainerOverflow(container, isOverflowVisible) { this.renderer.setStyle(container, 'overflow', isOverflowVisible ? 'visible' : 'hidden'); } /** * Set image size based on container size, * parallax percentage and disabled state. * @param {HTMLImageElement} image - Image element. * @param {number} containerWidth - Container width. * @param {number} containerHeight - Container height. * @param {number} parallaxPercentage - Parallax percentage. * @param {boolean} isDisabled - true to disable parallax effect. * @param {boolean} forceFullWidth - true to force image size to container width. */ setImageSize(image, containerWidth, containerHeight, parallaxPercentage, isDisabled, forceFullWidth) { if (forceFullWidth) { this.renderer.setAttribute(image, 'width', `${containerWidth}px`); this.renderer.setAttribute(image, 'height', `auto`); } else { const minimumHeight = (containerHeight * (100 + (isDisabled ? 0 : parallaxPercentage))) / 100; const ratio = image.naturalHeight / image.naturalWidth; const minimumRatio = minimumHeight / containerWidth; if (ratio > minimumRatio) { this.renderer.setAttribute(image, 'width', `${containerWidth}px`); this.renderer.setAttribute(image, 'height', `auto`); } else { this.renderer.setAttribute(image, 'width', `auto`); this.renderer.setAttribute(image, 'height', `${minimumHeight}px`); } } } /** * Get parallax boundaries. This data is used * to calculate parallax movement. * @param {number} scrollTop - Scroll top. * @param {HTMLElement} container - Container element. * @param {number} imageHeight - Image height. * @param {number} parallaxPercentage - Parallax percentage. * @return {ParallaxBoundariesModel} - Parallax boundaries. */ getParallaxBoundaries(scrollTop, container, imageHeight, parallaxPercentage) { const elementTop = container.getBoundingClientRect().top + scrollTop; const usablePixels = container.clientHeight / 100 * parallaxPercentage; const unusablePixels = imageHeight - container.clientHeight - usablePixels; const startPoint = elementTop - usablePixels - window.innerHeight; const endPoint = elementTop + container.clientHeight + usablePixels; const totalPixels = endPoint - startPoint; return { startPoint, endPoint, totalPixels, usablePixels, unusablePixels }; } /** * Get image left position. * @param {number} containerWidth - Container width. * @param {number} imageWidth - Image width. * @param {number} positionPercentage - Position percentage. * @return {number} - Image left position. */ getImageLeft(containerWidth, imageWidth, positionPercentage) { return (containerWidth - imageWidth) / 100 * positionPercentage; } /** * Get image top position. * @param {number} scrollTop - Scroll top. * @param {ParallaxBoundariesModel} boundaries - Parallax boundaries. * @return {number} - Image top position. */ getImageTop(scrollTop, boundaries) { const area = Math.max(0, Math.min(scrollTop - boundaries.startPoint, boundaries.totalPixels)); const areaPercentage = 100 / boundaries.totalPixels * area; return -boundaries.usablePixels * (1 - areaPercentage / 100) - boundaries.unusablePixels / 2; } /** * Get disabled image top position. * @param {number} boundaries - Parallax boundaries. * @return {number} - Image top position. */ getDisabledImageTop(boundaries) { return (-boundaries.usablePixels - boundaries.unusablePixels) / 2; } /** * Set image transform properties. * @param {HTMLImageElement} image - Image element. * @param {number} leftPx - Image left position. * @param {number} topPx - Image top position. */ setImageTransform(image, leftPx, topPx) { const newTranslate = `translate(${leftPx.toFixed(1)}px, ${topPx.toFixed(1)}px)`; if (image.style.transform !== newTranslate) { this.renderer.setStyle(image, 'transform', newTranslate); } } } RfxParallaxComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: RfxParallaxComponent, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i1.ScrollEventService }, { token: i1.ResizeEventService }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component }); RfxParallaxComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.0.2", type: RfxParallaxComponent, selector: "[libRfxParallax]", inputs: { imageUrl: "imageUrl", imageAlt: "imageAlt", parallaxPercentage: "parallaxPercentage", positionPercentage: "positionPercentage", imageZIndex: "imageZIndex", visibleOverflow: "visibleOverflow", isDisabled: "isDisabled", forceFullWidth: "forceFullWidth" }, usesOnChanges: true, ngImport: i0, template: "<img\r\n [alt]=\"imageAlt ?? ''\"\r\n [@visibility]=\"isLoaded\"\r\n libWillChange\r\n [isDisabled]=\"isDisabled || !isBrowser\"\r\n class=\"rfx-image\"\r\n [src]=\"imageUrl\"\r\n [style.zIndex]=\"imageZIndex\"\r\n (load)=\"onImageLoaded($event)\" />\r\n\r\n<ng-content></ng-content>\r\n", styles: [".rfx-image{position:absolute;left:0;top:0;will-change:transform;opacity:0}\n"], directives: [{ type: i2.WillChangeDirective, selector: "[libWillChange]", inputs: ["triggerArea", "isDisabled"] }], animations: [ visibilityAnimation ] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: RfxParallaxComponent, decorators: [{ type: Component, args: [{ selector: '[libRfxParallax]', animations: [ visibilityAnimation ], template: "<img\r\n [alt]=\"imageAlt ?? ''\"\r\n [@visibility]=\"isLoaded\"\r\n libWillChange\r\n [isDisabled]=\"isDisabled || !isBrowser\"\r\n class=\"rfx-image\"\r\n [src]=\"imageUrl\"\r\n [style.zIndex]=\"imageZIndex\"\r\n (load)=\"onImageLoaded($event)\" />\r\n\r\n<ng-content></ng-content>\r\n", styles: [".rfx-image{position:absolute;left:0;top:0;will-change:transform;opacity:0}\n"] }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i1.ScrollEventService }, { type: i1.ResizeEventService }, { type: Object, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }]; }, propDecorators: { imageUrl: [{ type: Input }], imageAlt: [{ type: Input }], parallaxPercentage: [{ type: Input }], positionPercentage: [{ type: Input }], imageZIndex: [{ type: Input }], visibleOverflow: [{ type: Input }], isDisabled: [{ type: Input }], forceFullWidth: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmZ4LXBhcmFsbGF4LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3JmeC1wYXJhbGxheC9zcmMvbGliL2NvbXBvbmVudHMvcmZ4LXBhcmFsbGF4L3JmeC1wYXJhbGxheC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9yZngtcGFyYWxsYXgvc3JjL2xpYi9jb21wb25lbnRzL3JmeC1wYXJhbGxheC9yZngtcGFyYWxsYXguY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBYyxNQUFNLEVBQUUsS0FBSyxFQUFxQixXQUFXLEVBQTBDLE1BQU0sZUFBZSxDQUFDO0FBSTdJLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGlCQUFpQixDQUFDOzs7O0FBVXBELE1BQU0sT0FBTyxvQkFBb0I7SUFpSC9CLFlBQ1UsV0FBdUIsRUFDdkIsUUFBbUIsRUFDbkIsa0JBQXNDLEVBQ3RDLGtCQUFzQyxFQUNqQixVQUFrQjtRQUp2QyxnQkFBVyxHQUFYLFdBQVcsQ0FBWTtRQUN2QixhQUFRLEdBQVIsUUFBUSxDQUFXO1FBQ25CLHVCQUFrQixHQUFsQixrQkFBa0IsQ0FBb0I7UUFDdEMsdUJBQWtCLEdBQWxCLGtCQUFrQixDQUFvQjtRQUNqQixlQUFVLEdBQVYsVUFBVSxDQUFRO1FBRS9DLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxFQUFFLENBQUM7UUFDN0IsSUFBSSxDQUFDLGtCQUFrQixHQUFHLEVBQUUsQ0FBQztRQUM3QixJQUFJLENBQUMsV0FBVyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ3RCLElBQUksQ0FBQyxVQUFVLEdBQUcsS0FBSyxDQUFDO1FBQ3hCLElBQUksQ0FBQyxlQUFlLEdBQUcsS0FBSyxDQUFDO1FBQzdCLElBQUksQ0FBQyxXQUFXLEdBQUcsQ0FBQyxDQUFDO1FBQ3JCLElBQUksQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDO1FBQ3RCLElBQUksQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDO1FBQzVCLElBQUksQ0FBQyxTQUFTLEdBQUcsaUJBQWlCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3RELENBQUM7SUFFRDs7O09BR0c7SUFDSSxRQUFRO1FBQ2IsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFO1lBQ2xCLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBQzFELElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLGFBQWEsRUFBRSxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUM7WUFFaEYsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUU7Z0JBQ3BCLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQzthQUN4QjtTQUNGO0lBQ0gsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNJLFdBQVcsQ0FBQyxPQUFzQjtRQUN2QyxJQUFJLElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDbEIsSUFBSSxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsRUFBRSxJQUFJLENBQUMsRUFBRTtnQkFDckQsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7YUFDekI7aUJBQU0sSUFBSSxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRTtnQkFDN0QsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO2FBQ3hCO1lBRUQsSUFBSSxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLEVBQUU7Z0JBQ3BELElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLGFBQWEsRUFBRSxPQUFPLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQzthQUNwRztZQUVELElBQUksSUFBSSxDQUFDLEtBQUssSUFBSSxDQUFDLENBQ2pCLElBQUksQ0FBQyxlQUFlLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO2dCQUN6QyxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO2dCQUNuRCxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLENBQUM7Z0JBQ3BELElBQUksQ0FBQyxlQUFlLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFDO2dCQUMzQyxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsRUFBRTtnQkFDbEQsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQzthQUNyQztTQUNGO0lBQ0gsQ0FBQztJQUVNLFdBQVc7UUFDaEIsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7SUFDMUIsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNLLGVBQWUsQ0FBQyxNQUFvQixFQUFFLFdBQWdCLE1BQU0sRUFBRSxZQUFZO1FBQ2hGLE9BQU8sTUFBTSxFQUFFLFdBQVcsS0FBSyxLQUFLLElBQUksTUFBTSxFQUFFLFlBQVksS0FBSyxTQUFTLElBQUksTUFBTSxFQUFFLFlBQVksS0FBSyxRQUFRLENBQUM7SUFDbEgsQ0FBQztJQUVEOztPQUVHO0lBQ0ssZ0JBQWdCO1FBQ3RCLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxXQUFXLEVBQUUsQ0FBQztRQUN4QyxJQUFJLENBQUMsbUJBQW1CLEVBQUUsV0FBVyxFQUFFLENBQUM7SUFDMUMsQ0FBQztJQUVEOzs7T0FHRztJQUNLLGVBQWU7UUFDckIsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFFeEIsSUFBSSxDQUFDLG1CQUFtQixHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxjQUFjLEVBQUUsQ0FBQyxTQUFTLENBQzNFLENBQUMsTUFBYyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUMvQyxDQUFDO1FBRUYsSUFBSSxDQUFDLG1CQUFtQixHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxTQUFTLENBQ3RFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FDdEIsQ0FBQztJQUNKLENBQUM7SUFFRDs7OztPQUlHO0lBQ0ssYUFBYSxDQUFDLE1BQWM7UUFDbEMsSUFBSSxJQUFJLENBQUMsa0JBQWtCLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRTtZQUN6QyxNQUFNLEtBQUssR0FBVyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsa0JBQWtCLENBQUMsQ0FBQztZQUN4RSxJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsV0FBVyxFQUFFLEtBQUssQ0FBQyxDQUFDO1NBQzdEO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssUUFBUTtRQUNkLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRTtZQUNkLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7U0FDckM7SUFDSCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxhQUFhLENBQUMsS0FBWTtRQUMvQixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQyxNQUEwQixDQUFDO1FBRTlDLElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRTtZQUNsQixJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1NBQ3JDO1FBRUQsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7SUFDdkIsQ0FBQztJQUVEOzs7T0FHRztJQUNLLGtCQUFrQixDQUFDLEtBQXVCO1FBQ2hELE1BQU0sU0FBUyxHQUFXLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBRXhFLElBQUksQ0FBQyxZQUFZLENBQ2YsS0FBSyxFQUNMLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLFdBQVcsRUFDMUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsWUFBWSxFQUMzQyxJQUFJLENBQUMsa0JBQWtCLEVBQ3ZCLElBQUksQ0FBQyxVQUFVLEVBQ2YsSUFBSSxDQUFDLGNBQWMsQ0FDcEIsQ0FBQztRQUVGLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQ2xELFNBQVMsRUFDVCxJQUFJLENBQUMsV0FBVyxDQUFDLGFBQWEsRUFDOUIsS0FBSyxDQUFDLE1BQU0sRUFDWixJQUFJLENBQUMsa0JBQWtCLENBQ3hCLENBQUM7UUFFRixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQ2xDLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLFdBQVcsRUFDMUMsS0FBSyxDQUFDLEtBQUssRUFDWCxJQUFJLENBQUMsa0JBQWtCLENBQ3hCLENBQUM7UUFFRixNQUFNLEtBQUssR0FBVyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7WUFDckMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUM7WUFDbkQsSUFBSSxDQUFDLFdBQVcsQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFFdkQsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsV0FBVyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFFRDs7OztPQUlHO0lBQ0ssb0JBQW9CLENBQUMsU0FBc0I7UUFDakQsTUFBTSxRQUFRLEdBQVcsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLENBQUMsUUFBUSxDQUFDO1FBQzlELElBQUksUUFBUSxLQUFLLFVBQVUsSUFBSSxRQUFRLEtBQUssVUFBVSxFQUFFO1lBQ3RELElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFBRSxVQUFVLEVBQUUsVUFBVSxDQUFDLENBQUM7U0FDM0Q7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLG9CQUFvQixDQUFDLFNBQXNCLEVBQUUsaUJBQTBCO1FBQzdFLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFBRSxVQUFVLEVBQUUsaUJBQWlCLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDMUYsQ0FBQztJQUVEOzs7Ozs7Ozs7T0FTRztJQUNLLFlBQVksQ0FDbEIsS0FBdUIsRUFDdkIsY0FBc0IsRUFDdEIsZUFBdUIsRUFDdkIsa0JBQTBCLEVBQzFCLFVBQW1CLEVBQ25CLGNBQXVCO1FBRXZCLElBQUksY0FBYyxFQUFFO1lBQ2xCLElBQUksQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsR0FBRyxjQUFjLElBQUksQ0FBQyxDQUFDO1lBQ2xFLElBQUksQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLENBQUM7U0FDckQ7YUFBTTtZQUNMLE1BQU0sYUFBYSxHQUFXLENBQUMsZUFBZSxHQUFHLENBQUMsR0FBRyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLGtCQUFrQixDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQztZQUN0RyxNQUFNLEtBQUssR0FBVyxLQUFLLENBQUMsYUFBYSxHQUFHLEtBQUssQ0FBQyxZQUFZLENBQUM7WUFDL0QsTUFBTSxZQUFZLEdBQVcsYUFBYSxHQUFHLGNBQWMsQ0FBQztZQUU1RCxJQUFJLEtBQUssR0FBRyxZQUFZLEVBQUU7Z0JBQ3hCLElBQUksQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsR0FBRyxjQUFjLElBQUksQ0FBQyxDQUFDO2dCQUNsRSxJQUFJLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLE1BQU0sQ0FBQyxDQUFDO2FBQ3JEO2lCQUFNO2dCQUNMLElBQUksQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUM7Z0JBQ25ELElBQUksQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsR0FBRyxhQUFhLElBQUksQ0FBQyxDQUFDO2FBQ25FO1NBQ0Y7SUFDSCxDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSyxxQkFBcUIsQ0FBQyxTQUFpQixFQUFFLFNBQXNCLEVBQUUsV0FBbUIsRUFBRSxrQkFBMEI7UUFDdEgsTUFBTSxVQUFVLEdBQVcsU0FBUyxDQUFDLHFCQUFxQixFQUFFLENBQUMsR0FBRyxHQUFHLFNBQVMsQ0FBQztRQUM3RSxNQUFNLFlBQVksR0FBVyxTQUFTLENBQUMsWUFBWSxHQUFHLEdBQUcsR0FBRyxrQkFBa0IsQ0FBQztRQUMvRSxNQUFNLGNBQWMsR0FBVyxXQUFXLEdBQUcsU0FBUyxDQUFDLFlBQVksR0FBRyxZQUFZLENBQUM7UUFDbkYsTUFBTSxVQUFVLEdBQVcsVUFBVSxHQUFHLFlBQVksR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDO1FBQzFFLE1BQU0sUUFBUSxHQUFHLFVBQVUsR0FBRyxTQUFTLENBQUMsWUFBWSxHQUFHLFlBQVksQ0FBQztRQUNwRSxNQUFNLFdBQVcsR0FBRyxRQUFRLEdBQUcsVUFBVSxDQUFDO1FBQzFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsY0FBYyxFQUFFLENBQUM7SUFDN0UsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNLLFlBQVksQ0FBQyxjQUFzQixFQUFFLFVBQWtCLEVBQUUsa0JBQTBCO1FBQ3pGLE9BQU8sQ0FBQyxjQUFjLEdBQUcsVUFBVSxDQUFDLEdBQUcsR0FBRyxHQUFHLGtCQUFrQixDQUFDO0lBQ2xFLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNLLFdBQVcsQ0FBQyxTQUFpQixFQUFFLFVBQW1DO1FBQ3hFLE1BQU0sSUFBSSxHQUFXLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxHQUFHLFVBQVUsQ0FBQyxVQUFVLEVBQUUsVUFBVSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7UUFDdEcsTUFBTSxjQUFjLEdBQVcsR0FBRyxHQUFHLFVBQVUsQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO1FBQ25FLE9BQU8sQ0FBQyxVQUFVLENBQUMsWUFBWSxHQUFHLENBQUMsQ0FBQyxHQUFHLGNBQWMsR0FBRyxHQUFHLENBQUMsR0FBRyxVQUFVLENBQUMsY0FBYyxHQUFHLENBQUMsQ0FBQztJQUMvRixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLG1CQUFtQixDQUFDLFVBQW1DO1FBQzdELE9BQU8sQ0FBQyxDQUFDLFVBQVUsQ0FBQyxZQUFZLEdBQUcsVUFBVSxDQUFDLGNBQWMsQ0FBQyxHQUFHLENBQUMsQ0FBQTtJQUNuRSxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSyxpQkFBaUIsQ0FBQyxLQUF1QixFQUFFLE1BQWMsRUFBRSxLQUFhO1FBQzlFLE1BQU0sWUFBWSxHQUFXLGFBQWEsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7UUFFeEYsSUFBSSxLQUFLLENBQUMsS0FBSyxDQUFDLFNBQVMsS0FBSyxZQUFZLEVBQUU7WUFDMUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLFdBQVcsRUFBRSxZQUFZLENBQUMsQ0FBQztTQUMxRDtJQUNILENBQUM7O2lIQXhaVSxvQkFBb0IseUlBc0hyQixXQUFXO3FHQXRIVixvQkFBb0IscVZDZmpDLHlTQVdBLDROREFjO1FBQ1YsbUJBQW1CO0tBQ3BCOzJGQUVVLG9CQUFvQjtrQkFSaEMsU0FBUzsrQkFDRSxrQkFBa0IsY0FHaEI7d0JBQ1YsbUJBQW1CO3FCQUNwQjs2S0F3SDBDLE1BQU07MEJBQTlDLE1BQU07MkJBQUMsV0FBVzs0Q0E5R2QsUUFBUTtzQkFEZCxLQUFLO2dCQVFDLFFBQVE7c0JBRGQsS0FBSztnQkFVQyxrQkFBa0I7c0JBRHhCLEtBQUs7Z0JBVUMsa0JBQWtCO3NCQUR4QixLQUFLO2dCQVNDLFdBQVc7c0JBRGpCLEtBQUs7Z0JBU0MsZUFBZTtzQkFEckIsS0FBSztnQkFVQyxVQUFVO3NCQURoQixLQUFLO2dCQVFDLGNBQWM7c0JBRHBCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEVsZW1lbnRSZWYsIEluamVjdCwgSW5wdXQsIE9uQ2hhbmdlcywgT25Jbml0LCBQTEFURk9STV9JRCwgUmVuZGVyZXIyLCBTaW1wbGVDaGFuZ2UsIFNpbXBsZUNoYW5nZXMgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IFJlc2l6ZUV2ZW50U2VydmljZSwgU2Nyb2xsRXZlbnRTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vc2VydmljZXMnO1xyXG5pbXBvcnQgeyBQYXJhbGxheEJvdW5kYXJpZXNNb2RlbCB9IGZyb20gJy4uLy4uL21vZGVscyc7XHJcbmltcG9ydCB7IHZpc2liaWxpdHlBbmltYXRpb24gfSBmcm9tICcuLi8uLi9hbmltYXRpb25zJztcclxuaW1wb3J0IHsgaXNQbGF0Zm9ybUJyb3dzZXIgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdbbGliUmZ4UGFyYWxsYXhdJyxcclxuICB0ZW1wbGF0ZVVybDogJy4vcmZ4LXBhcmFsbGF4LmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybHM6IFsnLi9yZngtcGFyYWxsYXguY29tcG9uZW50Lmxlc3MnXSxcclxuICBhbmltYXRpb25zOiBbXHJcbiAgICB2aXNpYmlsaXR5QW5pbWF0aW9uXHJcbiAgXVxyXG59KVxyXG5leHBvcnQgY2xhc3MgUmZ4UGFyYWxsYXhDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uQ2hhbmdlcyB7XHJcbiAgLyoqXHJcbiAgICogSW1hZ2UgdXJsLlxyXG4gICAqIENhbiBiZSBodHRwKHMpIG9yIHJlbGF0aXZlIHBhdGguXHJcbiAgICogVE9ETzogQWRkIHN1cHBvcnQgZm9yIGZhbGxiYWNrLlxyXG4gICAqIEB0eXBlIHtzdHJpbmd9XHJcbiAgICovXHJcbiAgQElucHV0KClcclxuICBwdWJsaWMgaW1hZ2VVcmw6IHN0cmluZyB8IHVuZGVmaW5lZDtcclxuXHJcbiAgLyoqXHJcbiAgICogSW1hZ2UgYWx0IGF0dHJpYnV0ZS5cclxuICAgKiBAdHlwZSB7c3RyaW5nfVxyXG4gICAqL1xyXG4gIEBJbnB1dCgpXHJcbiAgcHVibGljIGltYWdlQWx0OiBzdHJpbmcgfCB1bmRlZmluZWQ7XHJcblxyXG4gIC8qKlxyXG4gICAqIFBlcmNlbnRhZ2Ugb2YgaW1hZ2Ugc2Nyb2xsaW5nLlxyXG4gICAqIGUuZy4gNDAlIHdpbGwgc2Nyb2xsIDQwJSBvZiB0aGUgaW1hZ2UuXHJcbiAgICogRGVmYXVsdCBpcyA0MC5cclxuICAgKiBAdHlwZSB7bnVtYmVyfVxyXG4gICAqL1xyXG4gIEBJbnB1dCgpXHJcbiAgcHVibGljIHBhcmFsbGF4UGVyY2VudGFnZTogbnVtYmVyO1xyXG5cclxuICAvKipcclxuICAgKiBJbWFnZSB2aWV3IHBvc2l0aW9uIGluIHBlcmNlbnRhZ2UuXHJcbiAgICogZS5nLiA1MCUgd2lsbCBzaG93IGNlbnRlcmVkIGltYWdlIGluIGNvbnRhaW5lci5cclxuICAgKiBEZWZhdWx0IGlzIDUwLlxyXG4gICAqIEB0eXBlIHtudW1iZXJ9XHJcbiAgICovXHJcbiAgQElucHV0KClcclxuICBwdWJsaWMgcG9zaXRpb25QZXJjZW50YWdlOiBudW1iZXI7XHJcblxyXG4gIC8qKlxyXG4gICAqIEltYWdlIHotaW5kZXggcHJvcGVydHkuXHJcbiAgICogRGVmYXVsdCBpcyAtMS5cclxuICAgKiBAdHlwZSB7bnVtYmVyfVxyXG4gICAqL1xyXG4gIEBJbnB1dCgpXHJcbiAgcHVibGljIGltYWdlWkluZGV4OiBudW1iZXI7XHJcblxyXG4gIC8qKlxyXG4gICAqIFNob3cgb3IgaGlkZSBpbWFnZSBvdmVyZmxvdyBvbiBjb250YWluZXIuXHJcbiAgICogRGVmYXVsdCBpcyBmYWxzZSAoaGlkZSkuXHJcbiAgICogQHR5cGUge2Jvb2xlYW59XHJcbiAgICovXHJcbiAgQElucHV0KClcclxuICBwdWJsaWMgdmlzaWJsZU92ZXJmbG93OiBib29sZWFuO1xyXG5cclxuICAvKipcclxuICAgKiBEaXNhYmxlIGltYWdlIHBhcmFsbGF4IGVmZmVjdCBhbmRcclxuICAgKiByZXN0b3JlIGRlZmF1bHQgaW1hZ2UgcG9zaXRpb24uXHJcbiAgICogVXNlZnVsIG9uIGxvdyBwZXJmb3JtYW5jZSBkZXZpY2VzLlxyXG4gICAqIEB0eXBlIHtib29sZWFufVxyXG4gICAqL1xyXG4gIEBJbnB1dCgpXHJcbiAgcHVibGljIGlzRGlzYWJsZWQ6IGJvb2xlYW47XHJcblxyXG4gIC8qKlxyXG4gICAqIEZvcmNlIGltYWdlIHRvIGJlIDEwMCUgb2YgY29udGFpbmVyIHdpZHRoLlxyXG4gICAqIEB0eXBlIHtib29sZWFufVxyXG4gICAqL1xyXG4gIEBJbnB1dCgpXHJcbiAgcHVibGljIGZvcmNlRnVsbFdpZHRoOiBib29sZWFuO1xyXG5cclxuICAvKipcclxuICAgKiBTdWJzY3JpcHRpb24gdG8gc2Nyb2xsIGV2ZW50LlxyXG4gICAqIEB0eXBlIHtTdWJzY3JpcHRpb24gfCB1bmRlZmluZWR9XHJcbiAgICovXHJcbiAgcHJpdmF0ZSBzY3JvbGxFdmVudExpc3RlbmVyOiBTdWJzY3JpcHRpb24gfCB1bmRlZmluZWQ7XHJcblxyXG4gIC8qKlxyXG4gICAqIFN1YnNjcmlwdGlvbiB0byByZXNpemUgZXZlbnQuXHJcbiAgICogQHR5cGUge1N1YnNjcmlwdGlvbiB8IHVuZGVmaW5lZH1cclxuICAgKi9cclxuICBwcml2YXRlIHJlc2l6ZUV2ZW50TGlzdGVuZXI6IFN1YnNjcmlwdGlvbiB8IHVuZGVmaW5lZDtcclxuXHJcbiAgLyoqXHJcbiAgICogUGFyYWxsYXhlZCBpbWFnZSBib3VuZGFyaWVzLlxyXG4gICAqIEB0eXBlIHtQYXJhbGxheEJvdW5kYXJpZXNNb2RlbCB8IHVuZGVmaW5lZH1cclxuICAgKi9cclxuICBwcml2YXRlIHBhcmFsbGF4Qm91bmRhcmllczogUGFyYWxsYXhCb3VuZGFyaWVzTW9kZWwgfCB1bmRlZmluZWQ7XHJcblxyXG4gIC8qKlxyXG4gICAqIEltYWdlIHRvIGJlIHBhcmFsbGF4ZWQuXHJcbiAgICogQHR5cGUge0hUTUxJbWFnZUVsZW1lbnQgfCB1bmRlZmluZWR9XHJcbiAgICovXHJcbiAgcHJpdmF0ZSBpbWFnZTogSFRNTEltYWdlRWxlbWVudCB8IHVuZGVmaW5lZDtcclxuXHJcbiAgLyoqXHJcbiAgICogSW1hZ2UgbGVmdCBwb3NpdGlvbi5cclxuICAgKiBXZSBzYXZlIHRoaXMgdmFsdWUgYW5kIHJlZHVjZSBvdmVyaGVhZCBvZlxyXG4gICAqIGNhbGN1bGF0aW5nIGl0IGV2ZXJ5IHRpbWUgb24gc2Nyb2xsLlxyXG4gICAqIEB0eXBlIHtudW1iZXJ9XHJcbiAgICovXHJcbiAgcHJpdmF0ZSBpbWFnZUxlZnRQeDogbnVtYmVyO1xyXG5cclxuICAvKipcclxuICAgKiBJcyBpbWFnZSBsb2FkZWQuXHJcbiAgICogQHR5cGUge2Jvb2xlYW59XHJcbiAgICovXHJcbiAgcHVibGljIGlzTG9hZGVkOiBib29sZWFuO1xyXG5cclxuICAvKipcclxuICAgKiBJcyBwbGF0Zm9ybSBicm93c2VyLlxyXG4gICAqIEZhbHNlIGZvciBleGFtcGxlIHdoZW4gdXNpbmcgU1NSLlxyXG4gICAqIEB0eXBlIHtib29sZWFufVxyXG4gICAqL1xyXG4gIHB1YmxpYyBpc0Jyb3dzZXI6IGJvb2xlYW47XHJcblxyXG5cclxuICBjb25zdHJ1Y3RvcihcclxuICAgIHByaXZhdGUgaHRtbEVsZW1lbnQ6IEVsZW1lbnRSZWYsXHJcbiAgICBwcml2YXRlIHJlbmRlcmVyOiBSZW5kZXJlcjIsXHJcbiAgICBwcml2YXRlIHNjcm9sbEV2ZW50U2VydmljZTogU2Nyb2xsRXZlbnRTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSByZXNpemVFdmVudFNlcnZpY2U6IFJlc2l6ZUV2ZW50U2VydmljZSxcclxuICAgIEBJbmplY3QoUExBVEZPUk1fSUQpIHByaXZhdGUgcGxhdGZvcm1JZDogT2JqZWN0XHJcbiAgKSB7XHJcbiAgICB0aGlzLnBhcmFsbGF4UGVyY2VudGFnZSA9IDQwO1xyXG4gICAgdGhpcy5wb3NpdGlvblBlcmNlbnRhZ2UgPSA1MDtcclxuICAgIHRoaXMuaW1hZ2VaSW5kZXggPSAtMTtcclxuICAgIHRoaXMuaXNEaXNhYmxlZCA9IGZhbHNlO1xyXG4gICAgdGhpcy52aXNpYmxlT3ZlcmZsb3cgPSBmYWxzZTtcclxuICAgIHRoaXMuaW1hZ2VMZWZ0UHggPSAwO1xyXG4gICAgdGhpcy5pc0xvYWRlZCA9IGZhbHNlO1xyXG4gICAgdGhpcy5mb3JjZUZ1bGxXaWR0aCA9IGZhbHNlO1xyXG4gICAgdGhpcy5pc0Jyb3dzZXIgPSBpc1BsYXRmb3JtQnJvd3Nlcih0aGlzLnBsYXRmb3JtSWQpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU2V0IGNvbnRhaW5lciBwb3NpdGlvbiBhbmQgb3ZlcmZsb3cuXHJcbiAgICogSWYgcGFyYWxsYXggaXMgbm90IGRpc2FibGVkLCBjcmVhdGUgbGlzdGVuZXJzLlxyXG4gICAqL1xyXG4gIHB1YmxpYyBuZ09uSW5pdCgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLmlzQnJvd3Nlcikge1xyXG4gICAgICB0aGlzLnNldENvbnRhaW5lclBvc2l0aW9uKHRoaXMuaHRtbEVsZW1lbnQubmF0aXZlRWxlbWVudCk7XHJcbiAgICAgIHRoaXMuc2V0Q29udGFpbmVyT3ZlcmZsb3codGhpcy5odG1sRWxlbWVudC5uYXRpdmVFbGVtZW50LCB0aGlzLnZpc2libGVPdmVyZmxvdyk7XHJcblxyXG4gICAgICBpZiAoIXRoaXMuaXNEaXNhYmxlZCkge1xyXG4gICAgICAgIHRoaXMuY3JlYXRlTGlzdGVuZXJzKCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFVwZGF0ZSBwYXJhbGxheCB2YWx1ZXMgd2hlbiBzb21lIHByb3BlcmllcyBjaGFuZ2VkLlxyXG4gICAqIC0gaXNEaXNhYmxlZCBjaGFuZ2UsIGVuYWJsZSBvciBkaXNhYmxlIHBhcmFsbGF4IGFuZCByZWZyZXNoIGltYWdlIHByb3BlcnRpZXMuXHJcbiAgICogLSB2aXNpYmxlT3ZlcmZsb3cgY2hhbmdlLCBzaG93IG9yIGhpZGUgaW1hZ2Ugb3ZlcmZsb3cgb24gY29udGFpbmVyIHdpdGhvdXQgcmVmcmVzaC5cclxuICAgKiAtIGltYWdlclVybCwgcGFyYWxsYXhQZXJjZW50YWdlIG9yIHBvc2l0aW9uUGVyY2VudGFnZSBjaGFuZ2UsIHJlZnJlc2ggaW1hZ2UgcHJvcGVydGllcy5cclxuICAgKiBAcGFyYW0ge1NpbXBsZUNoYW5nZXN9IGNoYW5nZXMgLSBTaW1wbGVDaGFuZ2VzIG9iamVjdC5cclxuICAgKi9cclxuICBwdWJsaWMgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuaXNCcm93c2VyKSB7XHJcbiAgICAgIGlmICh0aGlzLmhhc1ZhbHVlQ2hhbmdlZChjaGFuZ2VzWydpc0Rpc2FibGVkJ10sIHRydWUpKSB7XHJcbiAgICAgICAgdGhpcy5kZXN0cm95TGlzdGVuZXJzKCk7XHJcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5oYXNWYWx1ZUNoYW5nZWQoY2hhbmdlc1snaXNEaXNhYmxlZCddLCBmYWxzZSkpIHtcclxuICAgICAgICB0aGlzLmNyZWF0ZUxpc3RlbmVycygpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodGhpcy5oYXNWYWx1ZUNoYW5nZWQoY2hhbmdlc1sndmlzaWJsZU92ZXJmbG93J10pKSB7XHJcbiAgICAgICAgdGhpcy5zZXRDb250YWluZXJPdmVyZmxvdyh0aGlzLmh0bWxFbGVtZW50Lm5hdGl2ZUVsZW1lbnQsIGNoYW5nZXNbJ3Zpc2libGVPdmVyZmxvdyddLmN1cnJlbnRWYWx1ZSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICh0aGlzLmltYWdlICYmICgoXHJcbiAgICAgICAgdGhpcy5oYXNWYWx1ZUNoYW5nZWQoY2hhbmdlc1snaW1hZ2VVcmwnXSkgfHxcclxuICAgICAgICB0aGlzLmhhc1ZhbHVlQ2hhbmdlZChjaGFuZ2VzWydwYXJhbGxheFBlcmNlbnRhZ2UnXSkgfHxcclxuICAgICAgICB0aGlzLmhhc1ZhbHVlQ2hhbmdlZChjaGFuZ2VzWydwb3NpdGlvblBlcmNlbnRhZ2UnXSkpIHx8XHJcbiAgICAgICAgdGhpcy5oYXNWYWx1ZUNoYW5nZWQoY2hhbmdlc1snaXNEaXNhYmxlZCddKSB8fFxyXG4gICAgICAgIHRoaXMuaGFzVmFsdWVDaGFuZ2VkKGNoYW5nZXNbJ2ZvcmNlRnVsbFdpZHRoJ10pKSkge1xyXG4gICAgICAgIHRoaXMuc2V0SW1hZ2VQcm9wZXJ0aWVzKHRoaXMuaW1hZ2UpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgbmdPbkRlc3Ryb3koKTogdm9pZCB7XHJcbiAgICB0aGlzLmRlc3Ryb3lMaXN0ZW5lcnMoKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENoZWNrIGlmIFNpbXBsZUNoYW5nZSB2YWx1ZSBoYXMgY2hhbmdlZC5cclxuICAgKiBFdmVudHVhbGx5IGNoZWNrIGlmIHZhbHVlIGNvcnJlc3BvbmRzIHRvIGEgbmV3IHZhbHVlLlxyXG4gICAqIEBwYXJhbSB7U2ltcGxlQ2hhbmdlfSBjaGFuZ2UgLSBTaW1wbGVDaGFuZ2Ugb2JqZWN0LlxyXG4gICAqIEBwYXJhbSB7YW55fSBuZXdWYWx1ZSAtIE5ldyB2YWx1ZS5cclxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSB0cnVlIGlmIHZhbHVlIGhhcyBjaGFuZ2VkLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgaGFzVmFsdWVDaGFuZ2VkKGNoYW5nZTogU2ltcGxlQ2hhbmdlLCBuZXdWYWx1ZTogYW55ID0gY2hhbmdlPy5jdXJyZW50VmFsdWUpOiBib29sZWFuIHtcclxuICAgIHJldHVybiBjaGFuZ2U/LmZpcnN0Q2hhbmdlID09PSBmYWxzZSAmJiBjaGFuZ2U/LmN1cnJlbnRWYWx1ZSAhPT0gdW5kZWZpbmVkICYmIGNoYW5nZT8uY3VycmVudFZhbHVlID09PSBuZXdWYWx1ZTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIERlc3Ryb3kgYWxsIGxpc3RlbmVycy5cclxuICAgKi9cclxuICBwcml2YXRlIGRlc3Ryb3lMaXN0ZW5lcnMoKTogdm9pZCB7XHJcbiAgICB0aGlzLnNjcm9sbEV2ZW50TGlzdGVuZXI/LnVuc3Vic2NyaWJlKCk7XHJcbiAgICB0aGlzLnJlc2l6ZUV2ZW50TGlzdGVuZXI/LnVuc3Vic2NyaWJlKCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBMaXN0ZW4gdG8gc2Nyb2xsIGFuZCByZXNpemUgZXZlbnRzLlxyXG4gICAqIERlc3Ryb3kgYWxyZWF5IGV4aXN0aW5nIGxpc3RlbmVycy5cclxuICAgKi9cclxuICBwcml2YXRlIGNyZWF0ZUxpc3RlbmVycygpOiB2b2lkIHtcclxuICAgIHRoaXMuZGVzdHJveUxpc3RlbmVycygpO1xyXG5cclxuICAgIHRoaXMuc2Nyb2xsRXZlbnRMaXN0ZW5lciA9IHRoaXMuc2Nyb2xsRXZlbnRTZXJ2aWNlLmdldE1vdXNlU2Nyb2xsKCkuc3Vic2NyaWJlKFxyXG4gICAgICAoc2Nyb2xsOiBudW1iZXIpID0+IHRoaXMub25Nb3VzZVNjcm9sbChzY3JvbGwpXHJcbiAgICApO1xyXG5cclxuICAgIHRoaXMucmVzaXplRXZlbnRMaXN0ZW5lciA9IHRoaXMucmVzaXplRXZlbnRTZXJ2aWNlLmdldFJlc2l6ZSgpLnN1YnNjcmliZShcclxuICAgICAgKCkgPT4gdGhpcy5vblJlc2l6ZSgpXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogT24gbW91c2Ugc2Nyb2xsIGV2ZW50IHJlY2FsY3VsYXRlIGFuZCBjaGFuZ2VcclxuICAgKiBwYXJhbGxheGVkIGltYWdlIHBvc2l0aW9uLlxyXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzY3JvbGwgLSBTY3JvbGwgdmFsdWUuXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBvbk1vdXNlU2Nyb2xsKHNjcm9sbDogbnVtYmVyKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5wYXJhbGxheEJvdW5kYXJpZXMgJiYgdGhpcy5pbWFnZSkge1xyXG4gICAgICBjb25zdCB0b3BQeDogbnVtYmVyID0gdGhpcy5nZXRJbWFnZVRvcChzY3JvbGwsIHRoaXMucGFyYWxsYXhCb3VuZGFyaWVzKTtcclxuICAgICAgdGhpcy5zZXRJbWFnZVRyYW5zZm9ybSh0aGlzLmltYWdlLCB0aGlzLmltYWdlTGVmdFB4LCB0b3BQeCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBPbiB3aW5kb3cgcmVzaXplIGV2ZW50IHJlbG9hZCBwYXJhbGxheCBwcm9wZXJ0aWVzLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgb25SZXNpemUoKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5pbWFnZSkge1xyXG4gICAgICB0aGlzLnNldEltYWdlUHJvcGVydGllcyh0aGlzLmltYWdlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNldCBpbWFnZSBvYmplY3QgYW5kIGxvYWRpbmcgc3RhdHVzLlxyXG4gICAqIFNldCBpbWFnZSBwcm9wZXJ0aWVzIGFmdGVyIGltYWdlIGlzIGZ1bGx5IGxvYWRlZFxyXG4gICAqIGJ1dCBvbmx5IGlmIHBsYXRmb3JtIGlzIGJyb3dzZXIuXHJcbiAgICogQHBhcmFtIHtFdmVudH0gZXZlbnQgLSBJbWFnZSBsb2FkZWQgZXZlbnQuXHJcbiAgICovXHJcbiAgcHVibGljIG9uSW1hZ2VMb2FkZWQoZXZlbnQ6IEV2ZW50KTogdm9pZCB7XHJcbiAgICB0aGlzLmltYWdlID0gZXZlbnQudGFyZ2V0IGFzIEhUTUxJbWFnZUVsZW1lbnQ7XHJcblxyXG4gICAgaWYgKHRoaXMuaXNCcm93c2VyKSB7XHJcbiAgICAgIHRoaXMuc2V0SW1hZ2VQcm9wZXJ0aWVzKHRoaXMuaW1hZ2UpO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuaXNMb2FkZWQgPSB0cnVlO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU2V0IGltYWdlIHByb3BlcnRpZXMgbmVlZGVkIGZvciBwYXJhbGxheCBlZmZlY3QuXHJcbiAgICogQHBhcmFtIHtIVE1MSW1hZ2VFbGVtZW50fSBpbWFnZSAtIEltYWdlIHRvIGJlIHBhcmFsbGF4ZWQuXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBzZXRJbWFnZVByb3BlcnRpZXMoaW1hZ2U6IEhUTUxJbWFnZUVsZW1lbnQpOiB2b2lkIHtcclxuICAgIGNvbnN0IHNjcm9sbFRvcDogbnVtYmVyID0gdGhpcy5zY3JvbGxFdmVudFNlcnZpY2UuZ2V0TW91c2VTY3JvbGxWYWx1ZSgpO1xyXG5cclxuICAgIHRoaXMuc2V0SW1hZ2VTaXplKFxyXG4gICAgICBpbWFnZSxcclxuICAgICAgdGhpcy5odG1sRWxlbWVudC5uYXRpdmVFbGVtZW50LmNsaWVudFdpZHRoLFxyXG4gICAgICB0aGlzLmh0bWxFbGVtZW50Lm5hdGl2ZUVsZW1lbnQuY2xpZW50SGVpZ2h0LFxyXG4gICAgICB0aGlzLnBhcmFsbGF4UGVyY2VudGFnZSxcclxuICAgICAgdGhpcy5pc0Rpc2FibGVkLFxyXG4gICAgICB0aGlzLmZvcmNlRnVsbFdpZHRoXHJcbiAgICApO1xyXG5cclxuICAgIHRoaXMucGFyYWxsYXhCb3VuZGFyaWVzID0gdGhpcy5nZXRQYXJhbGxheEJvdW5kYXJpZXMoXHJcbiAgICAgIHNjcm9sbFRvcCxcclxuICAgICAgdGhpcy5odG1sRWxlbWVudC5uYXRpdmVFbGVtZW50LFxyXG4gICAgICBpbWFnZS5oZWlnaHQsXHJcbiAgICAgIHRoaXMucGFyYWxsYXhQZXJjZW50YWdlXHJcbiAgICApO1xyXG5cclxuICAgIHRoaXMuaW1hZ2VMZWZ0UHggPSB0aGlzLmdldEltYWdlTGVmdChcclxuICAgICAgdGhpcy5odG1sRWxlbWVudC5uYXRpdmVFbGVtZW50LmNsaWVudFdpZHRoLFxyXG4gICAgICBpbWFnZS53aWR0aCxcclxuICAgICAgdGhpcy5wb3NpdGlvblBlcmNlbnRhZ2VcclxuICAgICk7XHJcblxyXG4gICAgY29uc3QgdG9wUHg6IG51bWJlciA9IHRoaXMuaXNEaXNhYmxlZCA/XHJcbiAgICAgIHRoaXMuZ2V0RGlzYWJsZWRJbWFnZVRvcCh0aGlzLnBhcmFsbGF4Qm91bmRhcmllcykgOlxyXG4gICAgICB0aGlzLmdldEltYWdlVG9wKHNjcm9sbFRvcCwgdGhpcy5wYXJhbGxheEJvdW5kYXJpZXMpO1xyXG5cclxuICAgIHRoaXMuc2V0SW1hZ2VUcmFuc2Zvcm0oaW1hZ2UsIHRoaXMuaW1hZ2VMZWZ0UHgsIHRvcFB4KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNldCBjb250YWluZXIgcG9zaXRpb24gdG8gcmVsYXRpdmVcclxuICAgKiBpZiBpbWFnZSBpcyBub3QgYWxyZWFkeSBpbiByZWxhdGl2ZSBvciBhYnNvbHV0ZSBwb3NpdGlvbi5cclxuICAgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBjb250YWluZXJcclxuICAgKi9cclxuICBwcml2YXRlIHNldENvbnRhaW5lclBvc2l0aW9uKGNvbnRhaW5lcjogSFRNTEVsZW1lbnQpOiB2b2lkIHtcclxuICAgIGNvbnN0IHBvc2l0aW9uOiBzdHJpbmcgPSBnZXRDb21wdXRlZFN0eWxlKGNvbnRhaW5lcikucG9zaXRpb247XHJcbiAgICBpZiAocG9zaXRpb24gIT09ICdyZWxhdGl2ZScgJiYgcG9zaXRpb24gIT09ICdhYnNvbHV0ZScpIHtcclxuICAgICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZShjb250YWluZXIsICdwb3NpdGlvbicsICdyZWxhdGl2ZScpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU2V0IGNvbnRhaW5lciBvdmVyZmxvdy5cclxuICAgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBjb250YWluZXIgLSBDb250YWluZXIgZWxlbWVudC5cclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGlzT3ZlcmZsb3dWaXNpYmxlIC0gdHJ1ZSB0byBzaG93IGNvbnRhaW5lciBvdmVyZmxvdy5cclxuICAgKi9cclxuICBwcml2YXRlIHNldENvbnRhaW5lck92ZXJmbG93KGNvbnRhaW5lcjogSFRNTEVsZW1lbnQsIGlzT3ZlcmZsb3dWaXNpYmxlOiBib29sZWFuKTogdm9pZCB7XHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKGNvbnRhaW5lciwgJ292ZXJmbG93JywgaXNPdmVyZmxvd1Zpc2libGUgPyAndmlzaWJsZScgOiAnaGlkZGVuJyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXQgaW1hZ2Ugc2l6ZSBiYXNlZCBvbiBjb250YWluZXIgc2l6ZSxcclxuICAgKiBwYXJhbGxheCBwZXJjZW50YWdlIGFuZCBkaXNhYmxlZCBzdGF0ZS5cclxuICAgKiBAcGFyYW0ge0hUTUxJbWFnZUVsZW1lbnR9IGltYWdlIC0gSW1hZ2UgZWxlbWVudC5cclxuICAgKiBAcGFyYW0ge251bWJlcn0gY29udGFpbmVyV2lkdGggLSBDb250YWluZXIgd2lkdGguXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IGNvbnRhaW5lckhlaWdodCAtIENvbnRhaW5lciBoZWlnaHQuXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IHBhcmFsbGF4UGVyY2VudGFnZSAtIFBhcmFsbGF4IHBlcmNlbnRhZ2UuXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBpc0Rpc2FibGVkIC0gdHJ1ZSB0byBkaXNhYmxlIHBhcmFsbGF4IGVmZmVjdC5cclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGZvcmNlRnVsbFdpZHRoIC0gdHJ1ZSB0byBmb3JjZSBpbWFnZSBzaXplIHRvIGNvbnRhaW5lciB3aWR0aC5cclxuICAgKi9cclxuICBwcml2YXRlIHNldEltYWdlU2l6ZShcclxuICAgIGltYWdlOiBIVE1MSW1hZ2VFbGVtZW50LFxyXG4gICAgY29udGFpbmVyV2lkdGg6IG51bWJlcixcclxuICAgIGNvbnRhaW5lckhlaWdodDogbnVtYmVyLFxyXG4gICAgcGFyYWxsYXhQZXJjZW50YWdlOiBudW1iZXIsXHJcbiAgICBpc0Rpc2FibGVkOiBib29sZWFuLFxyXG4gICAgZm9yY2VGdWxsV2lkdGg6IGJvb2xlYW5cclxuICApOiB2b2lkIHtcclxuICAgIGlmIChmb3JjZUZ1bGxXaWR0aCkge1xyXG4gICAgICB0aGlzLnJlbmRlcmVyLnNldEF0dHJpYnV0ZShpbWFnZSwgJ3dpZHRoJywgYCR7Y29udGFpbmVyV2lkdGh9cHhgKTtcclxuICAgICAgdGhpcy5yZW5kZXJlci5zZXRBdHRyaWJ1dGUoaW1hZ2UsICdoZWlnaHQnLCBgYXV0b2ApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgY29uc3QgbWluaW11bUhlaWdodDogbnVtYmVyID0gKGNvbnRhaW5lckhlaWdodCAqICgxMDAgKyAoaXNEaXNhYmxlZCA/IDAgOiBwYXJhbGxheFBlcmNlbnRhZ2UpKSkgLyAxMDA7XHJcbiAgICAgIGNvbnN0IHJhdGlvOiBudW1iZXIgPSBpbWFnZS5uYXR1cmFsSGVpZ2h0IC8gaW1hZ2UubmF0dXJhbFdpZHRoO1xyXG4gICAgICBjb25zdCBtaW5pbXVtUmF0aW86IG51bWJlciA9IG1pbmltdW1IZWlnaHQgLyBjb250YWluZXJXaWR0aDtcclxuXHJcbiAgICAgIGlmIChyYXRpbyA+IG1pbmltdW1SYXRpbykge1xyXG4gICAgICAgIHRoaXMucmVuZGVyZXIuc2V0QXR0cmlidXRlKGltYWdlLCAnd2lkdGgnLCBgJHtjb250YWluZXJXaWR0aH1weGApO1xyXG4gICAgICAgIHRoaXMucmVuZGVyZXIuc2V0QXR0cmlidXRlKGltYWdlLCAnaGVpZ2h0JywgYGF1dG9gKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLnJlbmRlcmVyLnNldEF0dHJpYnV0ZShpbWFnZSwgJ3dpZHRoJywgYGF1dG9gKTtcclxuICAgICAgICB0aGlzLnJlbmRlcmVyLnNldEF0dHJpYnV0ZShpbWFnZSwgJ2hlaWdodCcsIGAke21pbmltdW1IZWlnaHR9cHhgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogR2V0IHBhcmFsbGF4IGJvdW5kYXJpZXMuIFRoaXMgZGF0YSBpcyB1c2VkXHJcbiAgICogdG8gY2FsY3VsYXRlIHBhcmFsbGF4IG1vdmVtZW50LlxyXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzY3JvbGxUb3AgLSBTY3JvbGwgdG9wLlxyXG4gICAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGNvbnRhaW5lciAtIENvbnRhaW5lciBlbGVtZW50LlxyXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBpbWFnZUhlaWdodCAtIEltYWdlIGhlaWdodC5cclxuICAgKiBAcGFyYW0ge251bWJlcn0gcGFyYWxsYXhQZXJjZW50YWdlIC0gUGFyYWxsYXggcGVyY2VudGFnZS5cclxuICAgKiBAcmV0dXJuIHtQYXJhbGxheEJvdW5kYXJpZXNNb2RlbH0gLSBQYXJhbGxheCBib3VuZGFyaWVzLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgZ2V0UGFyYWxsYXhCb3VuZGFyaWVzKHNjcm9sbFRvcDogbnVtYmVyLCBjb250YWluZXI6IEhUTUxFbGVtZW50LCBpbWFnZUhlaWdodDogbnVtYmVyLCBwYXJhbGxheFBlcmNlbnRhZ2U6IG51bWJlcik6IFBhcmFsbGF4Qm91bmRhcmllc01vZGVsIHtcclxuICAgIGNvbnN0IGVsZW1lbnRUb3A6IG51bWJlciA9IGNvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS50b3AgKyBzY3JvbGxUb3A7XHJcbiAgICBjb25zdCB1c2FibGVQaXhlbHM6IG51bWJlciA9IGNvbnRhaW5lci5jbGllbnRIZWlnaHQgLyAxMDAgKiBwYXJhbGxheFBlcmNlbnRhZ2U7XHJcbiAgICBjb25zdCB1bnVzYWJsZVBpeGVsczogbnVtYmVyID0gaW1hZ2VIZWlnaHQgLSBjb250YWluZXIuY2xpZW50SGVpZ2h0IC0gdXNhYmxlUGl4ZWxzO1xyXG4gICAgY29uc3Qgc3RhcnRQb2ludDogbnVtYmVyID0gZWxlbWVudFRvcCAtIHVzYWJsZVBpeGVscyAtIHdpbmRvdy5pbm5lckhlaWdodDtcclxuICAgIGNvbnN0IGVuZFBvaW50ID0gZWxlbWVudFRvcCArIGNvbnRhaW5lci5jbGllbnRIZWlnaHQgKyB1c2FibGVQaXhlbHM7XHJcbiAgICBjb25zdCB0b3RhbFBpeGVscyA9IGVuZFBvaW50IC0gc3RhcnRQb2ludDtcclxuICAgIHJldHVybiB7IHN0YXJ0UG9pbnQsIGVuZFBvaW50LCB0b3RhbFBpeGVscywgdXNhYmxlUGl4ZWxzLCB1bnVzYWJsZVBpeGVscyB9O1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogR2V0IGltYWdlIGxlZnQgcG9zaXRpb24uXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IGNvbnRhaW5lcldpZHRoIC0gQ29udGFpbmVyIHdpZHRoLlxyXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBpbWFnZVdpZHRoIC0gSW1hZ2Ugd2lkdGguXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IHBvc2l0aW9uUGVyY2VudGFnZSAtIFBvc2l0aW9uIHBlcmNlbnRhZ2UuXHJcbiAgICogQHJldHVybiB7bnVtYmVyfSAtIEltYWdlIGxlZnQgcG9zaXRpb24uXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBnZXRJbWFnZUxlZnQoY29udGFpbmVyV2lkdGg6IG51bWJlciwgaW1hZ2VXaWR0aDogbnVtYmVyLCBwb3NpdGlvblBlcmNlbnRhZ2U6IG51bWJlcik6IG51bWJlciB7XHJcbiAgICByZXR1cm4gKGNvbnRhaW5lcldpZHRoIC0gaW1hZ2VXaWR0aCkgLyAxMDAgKiBwb3NpdGlvblBlcmNlbnRhZ2U7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBHZXQgaW1hZ2UgdG9wIHBvc2l0aW9uLlxyXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzY3JvbGxUb3AgLSBTY3JvbGwgdG9wLlxyXG4gICAqIEBwYXJhbSB7UGFyYWxsYXhCb3VuZGFyaWVzTW9kZWx9IGJvdW5kYXJpZXMgLSBQYXJhbGxheCBib3VuZGFyaWVzLlxyXG4gICAqIEByZXR1cm4ge251bWJlcn0gLSBJbWFnZSB0b3AgcG9zaXRpb24uXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBnZXRJbWFnZVRvcChzY3JvbGxUb3A6IG51bWJlciwgYm91bmRhcmllczogUGFyYWxsYXhCb3VuZGFyaWVzTW9kZWwpOiBudW1iZXIge1xyXG4gICAgY29uc3QgYXJlYTogbnVtYmVyID0gTWF0aC5tYXgoMCwgTWF0aC5taW4oc2Nyb2xsVG9wIC0gYm91bmRhcmllcy5zdGFydFBvaW50LCBib3VuZGFyaWVzLnRvdGFsUGl4ZWxzKSk7XHJcbiAgICBjb25zdCBhcmVhUGVyY2VudGFnZTogbnVtYmVyID0gMTAwIC8gYm91bmRhcmllcy50b3RhbFBpeGVscyAqIGFyZWE7XHJcbiAgICByZXR1cm4gLWJvdW5kYXJpZXMudXNhYmxlUGl4ZWxzICogKDEgLSBhcmVhUGVyY2VudGFnZSAvIDEwMCkgLSBib3VuZGFyaWVzLnVudXNhYmxlUGl4ZWxzIC8gMjtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldCBkaXNhYmxlZCBpbWFnZSB0b3AgcG9zaXRpb24uXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IGJvdW5kYXJpZXMgLSBQYXJhbGxheCBib3VuZGFyaWVzLlxyXG4gICAqIEByZXR1cm4ge251bWJlcn0gLSBJbWFnZSB0b3AgcG9zaXRpb24uXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBnZXREaXNhYmxlZEltYWdlVG9wKGJvdW5kYXJpZXM6IFBhcmFsbGF4Qm91bmRhcmllc01vZGVsKTogbnVtYmVyIHtcclxuICAgIHJldHVybiAoLWJvdW5kYXJpZXMudXNhYmxlUGl4ZWxzIC0gYm91bmRhcmllcy51bnVzYWJsZVBpeGVscykgLyAyXHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXQgaW1hZ2UgdHJhbnNmb3JtIHByb3BlcnRpZXMuXHJcbiAgICogQHBhcmFtIHtIVE1MSW1hZ2VFbGVtZW50fSBpbWFnZSAtIEltYWdlIGVsZW1lbnQuXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IGxlZnRQeCAtIEltYWdlIGxlZnQgcG9zaXRpb24uXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IHRvcFB4IC0gSW1hZ2UgdG9wIHBvc2l0aW9uLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgc2V0SW1hZ2VUcmFuc2Zvcm0oaW1hZ2U6IEhUTUxJbWFnZUVsZW1lbnQsIGxlZnRQeDogbnVtYmVyLCB0b3BQeDogbnVtYmVyKTogdm9pZCB7XHJcbiAgICBjb25zdCBuZXdUcmFuc2xhdGU6IHN0cmluZyA9IGB0cmFuc2xhdGUoJHtsZWZ0UHgudG9GaXhlZCgxKX1weCwgJHt0b3BQeC50b0ZpeGVkKDEpfXB4KWA7XHJcblxyXG4gICAgaWYgKGltYWdlLnN0eWxlLnRyYW5zZm9ybSAhPT0gbmV3VHJhbnNsYXRlKSB7XHJcbiAgICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUoaW1hZ2UsICd0cmFuc2Zvcm0nLCBuZXdUcmFuc2xhdGUpO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iLCI8aW1nXHJcbiAgW2FsdF09XCJpbWFnZUFsdCA/PyAnJ1wiXHJcbiAgW0B2aXNpYmlsaXR5XT1cImlzTG9hZGVkXCJcclxuICBsaWJXaWxsQ2hhbmdlXHJcbiAgW2lzRGlzYWJsZWRdPVwiaXNEaXNhYmxlZCB8fCAhaXNCcm93c2VyXCJcclxuICBjbGFzcz1cInJmeC1pbWFnZVwiXHJcbiAgW3NyY109XCJpbWFnZVVybFwiXHJcbiAgW3N0eWxlLnpJbmRleF09XCJpbWFnZVpJbmRleFwiXHJcbiAgKGxvYWQpPVwib25JbWFnZUxvYWRlZCgkZXZlbnQpXCIgLz5cclxuXHJcbjxuZy1jb250ZW50PjwvbmctY29udGVudD5cclxuIl19