UNPKG

lzy-load

Version:

LzyLoad is an Angular Lib for loading content on demand

265 lines 37.1 kB
/* * Important note: Is required that the items marked as lazy-load-items using the "LazyLoadItemDirective" * are present in the template at the moment of the initialization of the component because the * ContentChildren query is evaluated just before the AfterContentInit life circle, * if the items are being added dynamically later to the template then is possible that the parent of this component needs to run manualy * change detection to notify this component that the template has changed. Example of this case is in the cases-table in * gallery-management */ import { Component, ContentChildren, ElementRef, HostListener, Input, Renderer2 } from '@angular/core'; import { Subject, Subscription } from 'rxjs'; import { debounceTime } from 'rxjs/internal/operators'; import { LzyLoadItemDirective, LL_PRO_NAME } from '../../directives/lzy-load-item.directive'; import { LoadStrategy, UnloadStrategy } from '../../models/settings'; export class LzyLoadContComponent { constructor(renderer, hostElement) { this.renderer = renderer; this.hostElement = hostElement; // Component fields this.init = false; this.loadingRangeAmount = 0; this.preloadAmo = 0; this.scrollEvent = new Subject(); this.onResizeEvent = new Subject(); // new properties this.numOfVisiElem = 0; this.loadedRange = []; this.settings = { loadStrategy: LoadStrategy.PctOfVisibleElem, unloadStrategy: UnloadStrategy.KeepLoaded, percent: 2 }; // Subscription that is gonna handle the unsubscribe to all the other subscriptions this.subscription = new Subscription(); } ngOnInit() { this.registerIO(); this.initScroll(); this.initScreenResizing(); } registerIO() { // Initializing the IO options this.IOOptions = { root: null, rootMargin: '0px', threshold: [0.1] }; // If the container was passed then use it as a root for the IO if (this.container) { this.IOOptions.root = this.container; } else { // If the container input was not provided then use the self component as a container this.container = this.hostElement.nativeElement; this.IOOptions.root = this.container; } } initScroll() { // Listening for scroll event in the container this.renderer.listen(this.container, 'scroll', () => { this.scrollEvent.next(); }); // subscribing to scroll events to preload the items that need to be // preload in both directions up and down of the current position // including 100 mil of debounce time this.subscription.add(this.scrollEvent.pipe(debounceTime(100)).subscribe(() => { this.updateLoadedElements(); })); } initScreenResizing() { // Subscribing to the resize event and giving it a 300 miliseconds delay to prevent trigger this code too offten this.subscription.add(this.onResizeEvent.pipe(debounceTime(300)).subscribe(() => { // Updating the settings after changing the viewport this.calSettings(); // resetting the component after the change in the layout this.updateLoadedElements(); })); } // Used for initialize the component settings initialize() { this.initializeIntersectionObs(); } resetAndRecalculateSettings() { // Resetting the isReady variable to false that will trigger the initial calculations for the first // execution of the IO callback this.init = false; // Disconnecting from the observer and its targets if (this.observer) { this.observer.disconnect(); } // Initializing again the observer with the current elements this.initializeIntersectionObs(); } ngAfterContentInit() { // Listening for changes in the elements this.subscription.add(this.itemsIO.changes.subscribe(() => { this.resetAndRecalculateSettings(); })); // Initializing if are items to observe for if (this.itemsIO.length > 0) { this.initialize(); } } // Calculate preload amounts calSettings() { switch (this.settings.loadStrategy) { case LoadStrategy.AheadOfVisElem: { this.loadingRangeAmount = Math.ceil(this.settings.number + this.numOfVisiElem); // Calculating the amount of items to be load in both directions this.preloadAmo = this.settings.number; break; } case LoadStrategy.PctOfVisibleElem: { // Calculating the amount of preload elements depending of the amount of visible items in the view this.loadingRangeAmount = Math.ceil(this.settings.factor * this.numOfVisiElem); // Calculating the amount of items to be load in both directions this.preloadAmo = Math.ceil((this.loadingRangeAmount - this.numOfVisiElem) / 2); break; } case LoadStrategy.OnVisible: { this.loadingRangeAmount = this.numOfVisiElem; this.preloadAmo = 0; break; } case LoadStrategy.PctOfTotElem: { // Calculating the amount of preload elements depending of the amount of visible items in the view this.loadingRangeAmount = Math.ceil(this.settings.percent * this.itemsIO.length); // Calculating the amount of items to be load in both directions this.preloadAmo = Math.ceil((this.loadingRangeAmount - this.numOfVisiElem) / 2); break; } } } // loading the content inLoadingRange(element) { element.loadContent = true; } // unloading the content outOfLoadingRange(element) { if (this.settings.unloadStrategy === UnloadStrategy.LeavLoadedRange) { element.loadContent = false; } } // Calculate the amount of visible elements that are in the exact moment and update the property in the component getVisibleItems() { this.numOfVisiElem = this.itemsIO.filter((item) => { return item.isVisible; }).length; return this.numOfVisiElem; } // Initialize the IO and the targets to observe initializeIntersectionObs() { // callback provided to the IO const ioCallBack = (entries) => { const updEntriesVisibility = () => { entries.forEach((entry) => { // when an element is intersecting the view const itemElement = this.itemsIO.toArray()[entry.target[LL_PRO_NAME]]; if (itemElement) { itemElement.isVisible = entry.isIntersecting; } }); }; // differentiating between the first call to the function and the rest. The first is always gonna be // the initialization of all the targets if (!this.init) { // Updating the visibility of each element updEntriesVisibility(); // Calculating the amount of visible items and updating the property "visibleItemsAmo" for first time this.getVisibleItems(); // calculating amount of visible items depending if the selected model for the component needs it this.calSettings(); // Preloading the items this.updateLoadedElements(); this.init = true; } else { // This code will be executed always after the first time // Updating the visibility of each element updEntriesVisibility(); } }; // Creating the observer this.observer = new IntersectionObserver(ioCallBack, this.IOOptions); // Registering the items with the observer this.itemsIO.forEach((item) => { this.observer.observe(item.hostElement.nativeElement); }); } // calculate the new range of elements in the list that should be preload calLoadedRange(visibleItems) { const newRange = [0, 0]; // getting the range of current visible items const firstVisibleItem = visibleItems[0]; const lastVisibleItem = visibleItems[visibleItems.length - 1]; // Last item position in the array of items const lastItemPosInArray = (this.itemsIO.length - 1); // Setting the new start position to the current position menus the preload amount divided by two // in order to preload forward and in backward newRange[0] = Math.max(0, (firstVisibleItem.pos - this.preloadAmo)); if (newRange[0] === 0) { // prefetching the elements ahead of the last visible item newRange[1] = Math.min(this.loadingRangeAmount, lastItemPosInArray); } else if ((lastVisibleItem.pos + this.preloadAmo) >= lastItemPosInArray) { // pre-fetching the elements ahead and backward of the range of visible items newRange[1] = lastItemPosInArray; newRange[0] = Math.max(0, lastItemPosInArray - this.loadingRangeAmount); } else { newRange[1] = (lastVisibleItem.pos + this.preloadAmo); } return newRange; } // Function that calculate the current visible items and the ones that need to be preload updateLoadedElements() { // Getting the current visible elements in the container const visibleItems = this.itemsIO.filter((item) => { return item.isVisible; }); // if are not visible items, then do nothing if (visibleItems.length > 0) { // Calculating the elements should be preload this.loadedRange = this.calLoadedRange(visibleItems); this.itemsIO.forEach((item, index) => { if (index >= this.loadedRange[0] && index <= this.loadedRange[1]) { // element within the loading range this.inLoadingRange(item); } else { // element out the loading range this.outOfLoadingRange(item); } }); } } // Listening to the resize event so we can recalculate the amount of visible items in the list and other // important properties that are use for the component onResize() { this.onResizeEvent.next(); } ngOnDestroy() { if (this.observer) { this.observer.disconnect(); } this.subscription.unsubscribe(); } } LzyLoadContComponent.decorators = [ { type: Component, args: [{ selector: 'lzy-load-cont', template: "<ng-content></ng-content>", styles: [":host{background:transparent;border:inherit;color:inherit;display:flex;margin:0;padding:0}"] },] } ]; LzyLoadContComponent.ctorParameters = () => [ { type: Renderer2 }, { type: ElementRef } ]; LzyLoadContComponent.propDecorators = { settings: [{ type: Input }], container: [{ type: Input }], itemsIO: [{ type: ContentChildren, args: [LzyLoadItemDirective, { descendants: true },] }], onResize: [{ type: HostListener, args: ['window:resize', [],] }] }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibHp5LWxvYWQtY29udGVudC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9senktbG9hZC9zcmMvbGliL2NvbXBvbmVudHMvbHp5LWxvYWQtY29udGVudC9senktbG9hZC1jb250ZW50LmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7OztJQU9JO0FBQ0gsT0FBTyxFQUFvQixTQUFTLEVBQUUsZUFBZSxFQUNwRCxVQUFVLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBZ0MsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2pHLE9BQU8sRUFBRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzdDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsV0FBVyxFQUFFLE1BQU0sMENBQTBDLENBQUM7QUFDN0YsT0FBTyxFQUFZLFlBQVksRUFBRSxjQUFjLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQU9oRixNQUFNLE9BQU8sb0JBQW9CO0lBNEIvQixZQUFvQixRQUFtQixFQUFVLFdBQXVCO1FBQXBELGFBQVEsR0FBUixRQUFRLENBQVc7UUFBVSxnQkFBVyxHQUFYLFdBQVcsQ0FBWTtRQXZCeEUsbUJBQW1CO1FBQ1gsU0FBSSxHQUFHLEtBQUssQ0FBQztRQUNiLHVCQUFrQixHQUFHLENBQUMsQ0FBQztRQUN2QixlQUFVLEdBQUcsQ0FBQyxDQUFDO1FBQ2YsZ0JBQVcsR0FBRyxJQUFJLE9BQU8sRUFBUSxDQUFDO1FBQ2xDLGtCQUFhLEdBQUcsSUFBSSxPQUFPLEVBQVEsQ0FBQztRQUU1QyxpQkFBaUI7UUFDVCxrQkFBYSxHQUFHLENBQUMsQ0FBQztRQUNsQixnQkFBVyxHQUFHLEVBQUUsQ0FBQztRQUVoQixhQUFRLEdBQWE7WUFDNUIsWUFBWSxFQUFFLFlBQVksQ0FBQyxnQkFBZ0I7WUFDM0MsY0FBYyxFQUFFLGNBQWMsQ0FBQyxVQUFVO1lBQ3pDLE9BQU8sRUFBRSxDQUFDO1NBQ1gsQ0FBQztRQUdGLG1GQUFtRjtRQUNuRixpQkFBWSxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7SUFJeUMsQ0FBQztJQUc1RSxRQUFRO1FBRU4sSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBRWxCLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUVsQixJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztJQUM1QixDQUFDO0lBRU8sVUFBVTtRQUNoQiwrQkFBK0I7UUFDL0IsSUFBSSxDQUFDLFNBQVMsR0FBRztZQUNmLElBQUksRUFBRSxJQUFJO1lBQ1YsVUFBVSxFQUFFLEtBQUs7WUFDakIsU0FBUyxFQUFFLENBQUMsR0FBRyxDQUFDO1NBQ2pCLENBQUM7UUFDRiwrREFBK0Q7UUFDL0QsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFO1lBQ2xCLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUM7U0FDdEM7YUFBTTtZQUNMLHFGQUFxRjtZQUNyRixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDO1lBQ2hELElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUM7U0FDdEM7SUFDSCxDQUFDO0lBRU8sVUFBVTtRQUNoQiw4Q0FBOEM7UUFDOUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxRQUFRLEVBQUUsR0FBRyxFQUFFO1lBQ2xELElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDMUIsQ0FBQyxDQUFDLENBQUM7UUFFSCxvRUFBb0U7UUFDcEUsaUVBQWlFO1FBQ2pFLHFDQUFxQztRQUNyQyxJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFO1lBQzlFLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO1FBQzVCLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDTixDQUFDO0lBRU8sa0JBQWtCO1FBQ3hCLGdIQUFnSDtRQUNoSCxJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFO1lBQzlFLG9EQUFvRDtZQUNwRCxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDbkIseURBQXlEO1lBQ3pELElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO1FBQzlCLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDTixDQUFDO0lBRUQsNkNBQTZDO0lBQzdDLFVBQVU7UUFDUixJQUFJLENBQUMseUJBQXlCLEVBQUUsQ0FBQztJQUNuQyxDQUFDO0lBRUQsMkJBQTJCO1FBQ3pCLG1HQUFtRztRQUNuRywrQkFBK0I7UUFDL0IsSUFBSSxDQUFDLElBQUksR0FBSSxLQUFLLENBQUM7UUFDbkIsa0RBQWtEO1FBQ2xELElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRTtZQUNqQixJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRSxDQUFDO1NBQzVCO1FBQ0QsNERBQTREO1FBQzVELElBQUksQ0FBQyx5QkFBeUIsRUFBRSxDQUFDO0lBQ25DLENBQUM7SUFFRCxrQkFBa0I7UUFDaEIsd0NBQXdDO1FBQ3hDLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUU7WUFDdEQsSUFBSSxDQUFDLDJCQUEyQixFQUFFLENBQUM7UUFDdkMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNKLDJDQUEyQztRQUMzQyxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtZQUM1QixJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7U0FDbEI7SUFDSCxDQUFDO0lBRUQsNEJBQTRCO0lBQ3BCLFdBQVc7UUFDakIsUUFBUSxJQUFJLENBQUMsUUFBUSxDQUFDLFlBQVksRUFBRTtZQUNoQyxLQUFLLFlBQVksQ0FBQyxjQUFjLENBQUMsQ0FBQztnQkFDaEMsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUMvRSxnRUFBZ0U7Z0JBQ2hFLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUM7Z0JBQ3ZDLE1BQU07YUFDUDtZQUNELEtBQUssWUFBWSxDQUFDLGdCQUFnQixDQUFDLENBQUM7Z0JBQ2xDLGtHQUFrRztnQkFDbEcsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUMvRSxnRUFBZ0U7Z0JBQ2hFLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7Z0JBQ2hGLE1BQU07YUFDUDtZQUNELEtBQUssWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUMzQixJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQztnQkFDN0MsSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUM7Z0JBQ3BCLE1BQU07YUFDUDtZQUNELEtBQUssWUFBWSxDQUFDLFlBQVksQ0FBQyxDQUFDO2dCQUM5QixrR0FBa0c7Z0JBQ2xHLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQ2pGLGdFQUFnRTtnQkFDaEUsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztnQkFDaEYsTUFBTTthQUNQO1NBQ0Y7SUFDTCxDQUFDO0lBRUQsc0JBQXNCO0lBQ2QsY0FBYyxDQUFDLE9BQTZCO1FBQ2hELE9BQU8sQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO0lBQy9CLENBQUM7SUFFRCx3QkFBd0I7SUFDaEIsaUJBQWlCLENBQUMsT0FBNkI7UUFDckQsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLGNBQWMsS0FBSyxjQUFjLENBQUMsZUFBZSxFQUFFO1lBQ2pFLE9BQU8sQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFDO1NBQy9CO0lBQ0gsQ0FBQztJQUVELGtIQUFrSDtJQUMxRyxlQUFlO1FBQ3JCLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUEwQixFQUFFLEVBQUU7WUFDdEUsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDO1FBQ3hCLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztRQUNWLE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQztJQUM1QixDQUFDO0lBRUQsK0NBQStDO0lBQ3ZDLHlCQUF5QjtRQUUvQiw4QkFBOEI7UUFDOUIsTUFBTSxVQUFVLEdBQUcsQ0FBQyxPQUFvQyxFQUFFLEVBQUU7WUFDMUQsTUFBTSxvQkFBb0IsR0FBRyxHQUFHLEVBQUU7Z0JBQ2hDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxLQUFnQyxFQUFFLEVBQUU7b0JBQ25ELDJDQUEyQztvQkFDM0MsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7b0JBQ3RFLElBQUksV0FBVyxFQUFFO3dCQUNmLFdBQVcsQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDLGNBQWMsQ0FBQztxQkFDOUM7Z0JBQ0gsQ0FBQyxDQUFDLENBQUM7WUFDTCxDQUFDLENBQUM7WUFDRixvR0FBb0c7WUFDcEcsd0NBQXdDO1lBQ3hDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFO2dCQUNkLDBDQUEwQztnQkFDMUMsb0JBQW9CLEVBQUUsQ0FBQztnQkFDdkIscUdBQXFHO2dCQUNyRyxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7Z0JBQ3ZCLGlHQUFpRztnQkFDakcsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO2dCQUNuQix1QkFBdUI7Z0JBQ3ZCLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO2dCQUM1QixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQzthQUNsQjtpQkFBTTtnQkFDTCx5REFBeUQ7Z0JBQ3pELDBDQUEwQztnQkFDMUMsb0JBQW9CLEVBQUUsQ0FBQzthQUN4QjtRQUNILENBQUMsQ0FBQztRQUNGLHdCQUF3QjtRQUN4QixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksb0JBQW9CLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNyRSwwQ0FBMEM7UUFDMUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUEwQixFQUFFLEVBQUU7WUFDbEQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUN4RCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCx5RUFBeUU7SUFDekUsY0FBYyxDQUFDLFlBQW9DO1FBQ2pELE1BQU0sUUFBUSxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ3hCLDZDQUE2QztRQUM3QyxNQUFNLGdCQUFnQixHQUFHLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN6QyxNQUFNLGVBQWUsR0FBRyxZQUFZLENBQUMsWUFBWSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztRQUM5RCwyQ0FBMkM7UUFDM0MsTUFBTSxrQkFBa0IsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ3JELGlHQUFpRztRQUNqRyw4Q0FBOEM7UUFDOUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO1FBQ3BFLElBQUksUUFBUSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsRUFBRTtZQUNyQiwwREFBMEQ7WUFDMUQsUUFBUSxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLGtCQUFrQixFQUFFLGtCQUFrQixDQUFDLENBQUM7U0FDckU7YUFBTSxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksa0JBQWtCLEVBQUU7WUFDeEUsNkVBQTZFO1lBQzdFLFFBQVEsQ0FBQyxDQUFDLENBQUMsR0FBRyxrQkFBa0IsQ0FBQztZQUNqQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEdBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsa0JBQWtCLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLENBQUM7U0FDMUU7YUFBTTtZQUNMLFFBQVEsQ0FBQyxDQUFDLENBQUMsR0FBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1NBQ3hEO1FBQ0QsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztJQUVELHlGQUF5RjtJQUN6RixvQkFBb0I7UUFDakIseURBQXlEO1FBQ3pELE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBMEIsRUFBRSxFQUFFO1lBQ3ZFLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQztRQUN4QixDQUFDLENBQUMsQ0FBQztRQUVILDRDQUE0QztRQUMzQyxJQUFJLFlBQVksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1lBQzVCLDZDQUE2QztZQUM3QyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDckQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUEwQixFQUFFLEtBQUssRUFBRSxFQUFFO2dCQUN6RCxJQUFJLEtBQUssSUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssSUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFFO29CQUNoRSxtQ0FBbUM7b0JBQ25DLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7aUJBQzNCO3FCQUFNO29CQUNMLGdDQUFnQztvQkFDaEMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxDQUFDO2lCQUM5QjtZQUNILENBQUMsQ0FBQyxDQUFDO1NBQ0o7SUFDSCxDQUFDO0lBRUQsd0dBQXdHO0lBQ3hHLHNEQUFzRDtJQUNuQixRQUFRO1FBQ3pDLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDNUIsQ0FBQztJQUVELFdBQVc7UUFDVCxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUU7WUFDakIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLEVBQUUsQ0FBQztTQUM1QjtRQUNELElBQUksQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDbEMsQ0FBQzs7O1lBdlFELFNBQVMsU0FBQztnQkFDVixRQUFRLEVBQUUsZUFBZTtnQkFDekIscUNBQWdEOzthQUVqRDs7O1lBVmdFLFNBQVM7WUFBeEUsVUFBVTs7O3VCQTJCVCxLQUFLO3dCQU1MLEtBQUs7c0JBSUwsZUFBZSxTQUFDLG9CQUFvQixFQUFFLEVBQUMsV0FBVyxFQUFFLElBQUksRUFBQzt1QkErTnpELFlBQVksU0FBQyxlQUFlLEVBQUUsRUFBRSIsInNvdXJjZXNDb250ZW50IjpbIi8qXHJcbiAgKiBJbXBvcnRhbnQgbm90ZTogSXMgcmVxdWlyZWQgdGhhdCB0aGUgaXRlbXMgbWFya2VkIGFzIGxhenktbG9hZC1pdGVtcyB1c2luZyB0aGUgXCJMYXp5TG9hZEl0ZW1EaXJlY3RpdmVcIlxyXG4gICogYXJlIHByZXNlbnQgaW4gdGhlIHRlbXBsYXRlIGF0IHRoZSBtb21lbnQgb2YgdGhlIGluaXRpYWxpemF0aW9uIG9mIHRoZSBjb21wb25lbnQgYmVjYXVzZSB0aGVcclxuICAqIENvbnRlbnRDaGlsZHJlbiBxdWVyeSBpcyBldmFsdWF0ZWQganVzdCBiZWZvcmUgdGhlIEFmdGVyQ29udGVudEluaXQgbGlmZSBjaXJjbGUsXHJcbiAgKiBpZiB0aGUgaXRlbXMgYXJlIGJlaW5nIGFkZGVkIGR5bmFtaWNhbGx5IGxhdGVyIHRvIHRoZSB0ZW1wbGF0ZSB0aGVuIGlzIHBvc3NpYmxlIHRoYXQgdGhlIHBhcmVudCBvZiB0aGlzIGNvbXBvbmVudCBuZWVkcyB0byBydW4gbWFudWFseVxyXG4gICogY2hhbmdlIGRldGVjdGlvbiB0byBub3RpZnkgdGhpcyBjb21wb25lbnQgdGhhdCB0aGUgdGVtcGxhdGUgaGFzIGNoYW5nZWQuIEV4YW1wbGUgb2YgdGhpcyBjYXNlIGlzIGluIHRoZSBjYXNlcy10YWJsZSBpblxyXG4gICogZ2FsbGVyeS1tYW5hZ2VtZW50XHJcbiAgKi9cclxuIGltcG9ydCB7IEFmdGVyQ29udGVudEluaXQsIENvbXBvbmVudCwgQ29udGVudENoaWxkcmVuLFxyXG4gIEVsZW1lbnRSZWYsIEhvc3RMaXN0ZW5lciwgSW5wdXQsIE9uRGVzdHJveSwgT25Jbml0LCBRdWVyeUxpc3QsIFJlbmRlcmVyMiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG4gaW1wb3J0IHsgU3ViamVjdCwgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XHJcbiBpbXBvcnQgeyBkZWJvdW5jZVRpbWUgfSBmcm9tICdyeGpzL2ludGVybmFsL29wZXJhdG9ycyc7XHJcbiBpbXBvcnQgeyBMenlMb2FkSXRlbURpcmVjdGl2ZSwgTExfUFJPX05BTUUgfSBmcm9tICcuLi8uLi9kaXJlY3RpdmVzL2x6eS1sb2FkLWl0ZW0uZGlyZWN0aXZlJztcclxuIGltcG9ydCB7IFNldHRpbmdzLCBMb2FkU3RyYXRlZ3ksIFVubG9hZFN0cmF0ZWd5IH0gZnJvbSAnLi4vLi4vbW9kZWxzL3NldHRpbmdzJztcclxuXHJcbiBAQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ2x6eS1sb2FkLWNvbnQnLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9senktbG9hZC1jb250ZW50LmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybHM6IFsnLi9senktbG9hZC1jb250ZW50LmNvbXBvbmVudC5jc3MnXVxyXG59KVxyXG5leHBvcnQgY2xhc3MgTHp5TG9hZENvbnRDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIEFmdGVyQ29udGVudEluaXQsIE9uRGVzdHJveSB7XHJcbiAgLy8gSW50ZXJzZWN0aW9uT2JzZXJ2ZXIgc2V0dGluZ3NcclxuICBwcml2YXRlIG9ic2VydmVyOiBJbnRlcnNlY3Rpb25PYnNlcnZlcjtcclxuICBwcml2YXRlIElPT3B0aW9uczogeyByb290OiBhbnksIHJvb3RNYXJnaW46ICcwcHgnLCB0aHJlc2hvbGQ6IFswLjFdfTtcclxuXHJcbiAgLy8gQ29tcG9uZW50IGZpZWxkc1xyXG4gIHByaXZhdGUgaW5pdCA9IGZhbHNlO1xyXG4gIHByaXZhdGUgbG9hZGluZ1JhbmdlQW1vdW50ID0gMDtcclxuICBwcml2YXRlIHByZWxvYWRBbW8gPSAwO1xyXG4gIHByaXZhdGUgc2Nyb2xsRXZlbnQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xyXG4gIHByaXZhdGUgb25SZXNpemVFdmVudCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XHJcblxyXG4gIC8vIG5ldyBwcm9wZXJ0aWVzXHJcbiAgcHJpdmF0ZSBudW1PZlZpc2lFbGVtID0gMDtcclxuICBwcml2YXRlIGxvYWRlZFJhbmdlID0gW107XHJcblxyXG4gIEBJbnB1dCgpIHNldHRpbmdzOiBTZXR0aW5ncyA9IHtcclxuICAgIGxvYWRTdHJhdGVneTogTG9hZFN0cmF0ZWd5LlBjdE9mVmlzaWJsZUVsZW0sXHJcbiAgICB1bmxvYWRTdHJhdGVneTogVW5sb2FkU3RyYXRlZ3kuS2VlcExvYWRlZCxcclxuICAgIHBlcmNlbnQ6IDJcclxuICB9O1xyXG5cclxuICBASW5wdXQoKSBjb250YWluZXI6IEhUTUxFbGVtZW50O1xyXG4gIC8vIFN1YnNjcmlwdGlvbiB0aGF0IGlzIGdvbm5hIGhhbmRsZSB0aGUgdW5zdWJzY3JpYmUgdG8gYWxsIHRoZSBvdGhlciBzdWJzY3JpcHRpb25zXHJcbiAgc3Vic2NyaXB0aW9uID0gbmV3IFN1YnNjcmlwdGlvbigpO1xyXG5cclxuICBAQ29udGVudENoaWxkcmVuKEx6eUxvYWRJdGVtRGlyZWN0aXZlLCB7ZGVzY2VuZGFudHM6IHRydWV9KSBpdGVtc0lPOiBRdWVyeUxpc3Q8THp5TG9hZEl0ZW1EaXJlY3RpdmU+O1xyXG5cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlbmRlcmVyOiBSZW5kZXJlcjIsIHByaXZhdGUgaG9zdEVsZW1lbnQ6IEVsZW1lbnRSZWYpIHt9XHJcblxyXG5cclxuICBuZ09uSW5pdCgpIHtcclxuXHJcbiAgICB0aGlzLnJlZ2lzdGVySU8oKTtcclxuXHJcbiAgICB0aGlzLmluaXRTY3JvbGwoKTtcclxuXHJcbiAgICB0aGlzLmluaXRTY3JlZW5SZXNpemluZygpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSByZWdpc3RlcklPKCkge1xyXG4gICAgLy8gIEluaXRpYWxpemluZyB0aGUgSU8gb3B0aW9uc1xyXG4gICAgdGhpcy5JT09wdGlvbnMgPSB7XHJcbiAgICAgIHJvb3Q6IG51bGwsXHJcbiAgICAgIHJvb3RNYXJnaW46ICcwcHgnLFxyXG4gICAgICB0aHJlc2hvbGQ6IFswLjFdXHJcbiAgICB9O1xyXG4gICAgLy8gSWYgdGhlIGNvbnRhaW5lciB3YXMgcGFzc2VkIHRoZW4gdXNlIGl0IGFzIGEgcm9vdCBmb3IgdGhlIElPXHJcbiAgICBpZiAodGhpcy5jb250YWluZXIpIHtcclxuICAgICAgdGhpcy5JT09wdGlvbnMucm9vdCA9IHRoaXMuY29udGFpbmVyO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSWYgdGhlIGNvbnRhaW5lciBpbnB1dCB3YXMgbm90IHByb3ZpZGVkIHRoZW4gdXNlIHRoZSBzZWxmIGNvbXBvbmVudCBhcyBhIGNvbnRhaW5lclxyXG4gICAgICB0aGlzLmNvbnRhaW5lciA9IHRoaXMuaG9zdEVsZW1lbnQubmF0aXZlRWxlbWVudDtcclxuICAgICAgdGhpcy5JT09wdGlvbnMucm9vdCA9IHRoaXMuY29udGFpbmVyO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBpbml0U2Nyb2xsKCkge1xyXG4gICAgLy8gTGlzdGVuaW5nIGZvciBzY3JvbGwgZXZlbnQgaW4gdGhlIGNvbnRhaW5lclxyXG4gICAgdGhpcy5yZW5kZXJlci5saXN0ZW4odGhpcy5jb250YWluZXIsICdzY3JvbGwnLCAoKSA9PiB7XHJcbiAgICAgIHRoaXMuc2Nyb2xsRXZlbnQubmV4dCgpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gc3Vic2NyaWJpbmcgdG8gc2Nyb2xsIGV2ZW50cyB0byBwcmVsb2FkIHRoZSBpdGVtcyB0aGF0IG5lZWQgdG8gYmVcclxuICAgIC8vIHByZWxvYWQgaW4gYm90aCBkaXJlY3Rpb25zIHVwIGFuZCBkb3duIG9mIHRoZSBjdXJyZW50IHBvc2l0aW9uXHJcbiAgICAvLyBpbmNsdWRpbmcgMTAwIG1pbCBvZiBkZWJvdW5jZSB0aW1lXHJcbiAgICB0aGlzLnN1YnNjcmlwdGlvbi5hZGQodGhpcy5zY3JvbGxFdmVudC5waXBlKGRlYm91bmNlVGltZSgxMDApKS5zdWJzY3JpYmUoKCkgPT4ge1xyXG4gICAgdGhpcy51cGRhdGVMb2FkZWRFbGVtZW50cygpO1xyXG4gICAgfSkpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBpbml0U2NyZWVuUmVzaXppbmcoKSB7XHJcbiAgICAvLyBTdWJzY3JpYmluZyB0byB0aGUgcmVzaXplIGV2ZW50IGFuZCBnaXZpbmcgaXQgYSAzMDAgbWlsaXNlY29uZHMgZGVsYXkgdG8gcHJldmVudCB0cmlnZ2VyIHRoaXMgY29kZSB0b28gb2ZmdGVuXHJcbiAgICB0aGlzLnN1YnNjcmlwdGlvbi5hZGQodGhpcy5vblJlc2l6ZUV2ZW50LnBpcGUoZGVib3VuY2VUaW1lKDMwMCkpLnN1YnNjcmliZSgoKSA9PiB7XHJcbiAgICAgIC8vIFVwZGF0aW5nIHRoZSBzZXR0aW5ncyBhZnRlciBjaGFuZ2luZyB0aGUgdmlld3BvcnRcclxuICAgICAgdGhpcy5jYWxTZXR0aW5ncygpO1xyXG4gICAgICAvLyByZXNldHRpbmcgdGhlIGNvbXBvbmVudCBhZnRlciB0aGUgY2hhbmdlIGluIHRoZSBsYXlvdXRcclxuICAgICAgdGhpcy51cGRhdGVMb2FkZWRFbGVtZW50cygpO1xyXG4gICAgfSkpO1xyXG4gIH1cclxuXHJcbiAgLy8gVXNlZCBmb3IgaW5pdGlhbGl6ZSB0aGUgY29tcG9uZW50IHNldHRpbmdzXHJcbiAgaW5pdGlhbGl6ZSgpOiB2b2lkIHtcclxuICAgIHRoaXMuaW5pdGlhbGl6ZUludGVyc2VjdGlvbk9icygpO1xyXG4gIH1cclxuXHJcbiAgcmVzZXRBbmRSZWNhbGN1bGF0ZVNldHRpbmdzKCk6IHZvaWQge1xyXG4gICAgLy8gUmVzZXR0aW5nIHRoZSBpc1JlYWR5IHZhcmlhYmxlIHRvIGZhbHNlIHRoYXQgd2lsbCB0cmlnZ2VyIHRoZSBpbml0aWFsIGNhbGN1bGF0aW9ucyBmb3IgdGhlIGZpcnN0XHJcbiAgICAvLyBleGVjdXRpb24gb2YgdGhlIElPIGNhbGxiYWNrXHJcbiAgICB0aGlzLmluaXQgPSAgZmFsc2U7XHJcbiAgICAvLyBEaXNjb25uZWN0aW5nIGZyb20gdGhlIG9ic2VydmVyIGFuZCBpdHMgdGFyZ2V0c1xyXG4gICAgaWYgKHRoaXMub2JzZXJ2ZXIpIHtcclxuICAgICAgdGhpcy5vYnNlcnZlci5kaXNjb25uZWN0KCk7XHJcbiAgICB9XHJcbiAgICAvLyBJbml0aWFsaXppbmcgYWdhaW4gdGhlIG9ic2VydmVyIHdpdGggdGhlIGN1cnJlbnQgZWxlbWVudHNcclxuICAgIHRoaXMuaW5pdGlhbGl6ZUludGVyc2VjdGlvbk9icygpO1xyXG4gIH1cclxuXHJcbiAgbmdBZnRlckNvbnRlbnRJbml0KCk6IHZvaWQge1xyXG4gICAgLy8gTGlzdGVuaW5nIGZvciBjaGFuZ2VzIGluIHRoZSBlbGVtZW50c1xyXG4gICAgdGhpcy5zdWJzY3JpcHRpb24uYWRkKHRoaXMuaXRlbXNJTy5jaGFuZ2VzLnN1YnNjcmliZSgoKSA9PiB7XHJcbiAgICAgICAgdGhpcy5yZXNldEFuZFJlY2FsY3VsYXRlU2V0dGluZ3MoKTtcclxuICAgIH0pKTtcclxuICAgIC8vIEluaXRpYWxpemluZyBpZiBhcmUgaXRlbXMgdG8gb2JzZXJ2ZSBmb3JcclxuICAgIGlmICh0aGlzLml0ZW1zSU8ubGVuZ3RoID4gMCkge1xyXG4gICAgIHRoaXMuaW5pdGlhbGl6ZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2FsY3VsYXRlIHByZWxvYWQgYW1vdW50c1xyXG4gIHByaXZhdGUgY2FsU2V0dGluZ3MoKSB7XHJcbiAgICBzd2l0Y2ggKHRoaXMuc2V0dGluZ3MubG9hZFN0cmF0ZWd5KSB7XHJcbiAgICAgICAgY2FzZSBMb2FkU3RyYXRlZ3kuQWhlYWRPZlZpc0VsZW06IHtcclxuICAgICAgICAgIHRoaXMubG9hZGluZ1JhbmdlQW1vdW50ID0gTWF0aC5jZWlsKHRoaXMuc2V0dGluZ3MubnVtYmVyICsgdGhpcy5udW1PZlZpc2lFbGVtKTtcclxuICAgICAgICAgIC8vIENhbGN1bGF0aW5nIHRoZSBhbW91bnQgb2YgaXRlbXMgdG8gYmUgbG9hZCBpbiBib3RoIGRpcmVjdGlvbnNcclxuICAgICAgICAgIHRoaXMucHJlbG9hZEFtbyA9IHRoaXMuc2V0dGluZ3MubnVtYmVyO1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNhc2UgTG9hZFN0cmF0ZWd5LlBjdE9mVmlzaWJsZUVsZW06IHtcclxuICAgICAgICAgIC8vIENhbGN1bGF0aW5nIHRoZSBhbW91bnQgb2YgcHJlbG9hZCBlbGVtZW50cyBkZXBlbmRpbmcgb2YgdGhlIGFtb3VudCBvZiB2aXNpYmxlIGl0ZW1zIGluIHRoZSB2aWV3XHJcbiAgICAgICAgICB0aGlzLmxvYWRpbmdSYW5nZUFtb3VudCA9IE1hdGguY2VpbCh0aGlzLnNldHRpbmdzLmZhY3RvciAqIHRoaXMubnVtT2ZWaXNpRWxlbSk7XHJcbiAgICAgICAgICAvLyBDYWxjdWxhdGluZyB0aGUgYW1vdW50IG9mIGl0ZW1zIHRvIGJlIGxvYWQgaW4gYm90aCBkaXJlY3Rpb25zXHJcbiAgICAgICAgICB0aGlzLnByZWxvYWRBbW8gPSBNYXRoLmNlaWwoKHRoaXMubG9hZGluZ1JhbmdlQW1vdW50IC0gdGhpcy5udW1PZlZpc2lFbGVtKSAvIDIpO1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNhc2UgTG9hZFN0cmF0ZWd5Lk9uVmlzaWJsZToge1xyXG4gICAgICAgICAgdGhpcy5sb2FkaW5nUmFuZ2VBbW91bnQgPSB0aGlzLm51bU9mVmlzaUVsZW07XHJcbiAgICAgICAgICB0aGlzLnByZWxvYWRBbW8gPSAwO1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNhc2UgTG9hZFN0cmF0ZWd5LlBjdE9mVG90RWxlbToge1xyXG4gICAgICAgICAgLy8gQ2FsY3VsYXRpbmcgdGhlIGFtb3VudCBvZiBwcmVsb2FkIGVsZW1lbnRzIGRlcGVuZGluZyBvZiB0aGUgYW1vdW50IG9mIHZpc2libGUgaXRlbXMgaW4gdGhlIHZpZXdcclxuICAgICAgICAgIHRoaXMubG9hZGluZ1JhbmdlQW1vdW50ID0gTWF0aC5jZWlsKHRoaXMuc2V0dGluZ3MucGVyY2VudCAqIHRoaXMuaXRlbXNJTy5sZW5ndGgpO1xyXG4gICAgICAgICAgLy8gQ2FsY3VsYXRpbmcgdGhlIGFtb3VudCBvZiBpdGVtcyB0byBiZSBsb2FkIGluIGJvdGggZGlyZWN0aW9uc1xyXG4gICAgICAgICAgdGhpcy5wcmVsb2FkQW1vID0gTWF0aC5jZWlsKCh0aGlzLmxvYWRpbmdSYW5nZUFtb3VudCAtIHRoaXMubnVtT2ZWaXNpRWxlbSkgLyAyKTtcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gbG9hZGluZyB0aGUgY29udGVudFxyXG4gIHByaXZhdGUgaW5Mb2FkaW5nUmFuZ2UoZWxlbWVudDogTHp5TG9hZEl0ZW1EaXJlY3RpdmUpIHtcclxuICAgICAgZWxlbWVudC5sb2FkQ29udGVudCA9IHRydWU7XHJcbiAgfVxyXG5cclxuICAvLyB1bmxvYWRpbmcgdGhlIGNvbnRlbnRcclxuICBwcml2YXRlIG91dE9mTG9hZGluZ1JhbmdlKGVsZW1lbnQ6IEx6eUxvYWRJdGVtRGlyZWN0aXZlKSB7XHJcbiAgICBpZiAodGhpcy5zZXR0aW5ncy51bmxvYWRTdHJhdGVneSA9PT0gVW5sb2FkU3RyYXRlZ3kuTGVhdkxvYWRlZFJhbmdlKSB7XHJcbiAgICAgICAgZWxlbWVudC5sb2FkQ29udGVudCA9IGZhbHNlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2FsY3VsYXRlIHRoZSBhbW91bnQgb2YgdmlzaWJsZSBlbGVtZW50cyAgdGhhdCBhcmUgaW4gdGhlIGV4YWN0IG1vbWVudCBhbmQgdXBkYXRlIHRoZSBwcm9wZXJ0eSBpbiB0aGUgY29tcG9uZW50XHJcbiAgcHJpdmF0ZSBnZXRWaXNpYmxlSXRlbXMoKSB7XHJcbiAgICB0aGlzLm51bU9mVmlzaUVsZW0gPSB0aGlzLml0ZW1zSU8uZmlsdGVyKChpdGVtOiBMenlMb2FkSXRlbURpcmVjdGl2ZSkgPT4ge1xyXG4gICAgICByZXR1cm4gaXRlbS5pc1Zpc2libGU7XHJcbiAgICB9KS5sZW5ndGg7XHJcbiAgICByZXR1cm4gdGhpcy5udW1PZlZpc2lFbGVtO1xyXG4gIH1cclxuXHJcbiAgLy8gSW5pdGlhbGl6ZSB0aGUgSU8gYW5kIHRoZSB0YXJnZXRzIHRvIG9ic2VydmVcclxuICBwcml2YXRlIGluaXRpYWxpemVJbnRlcnNlY3Rpb25PYnMoKSB7XHJcblxyXG4gICAgLy8gY2FsbGJhY2sgcHJvdmlkZWQgdG8gdGhlIElPXHJcbiAgICBjb25zdCBpb0NhbGxCYWNrID0gKGVudHJpZXM6IEludGVyc2VjdGlvbk9ic2VydmVyRW50cnlbXSkgPT4ge1xyXG4gICAgICBjb25zdCB1cGRFbnRyaWVzVmlzaWJpbGl0eSA9ICgpID0+IHtcclxuICAgICAgICBlbnRyaWVzLmZvckVhY2goKGVudHJ5OiBJbnRlcnNlY3Rpb25PYnNlcnZlckVudHJ5KSA9PiB7XHJcbiAgICAgICAgICAvLyB3aGVuIGFuIGVsZW1lbnQgaXMgaW50ZXJzZWN0aW5nIHRoZSB2aWV3XHJcbiAgICAgICAgICBjb25zdCBpdGVtRWxlbWVudCA9IHRoaXMuaXRlbXNJTy50b0FycmF5KClbZW50cnkudGFyZ2V0W0xMX1BST19OQU1FXV07XHJcbiAgICAgICAgICBpZiAoaXRlbUVsZW1lbnQpIHtcclxuICAgICAgICAgICAgaXRlbUVsZW1lbnQuaXNWaXNpYmxlID0gZW50cnkuaXNJbnRlcnNlY3Rpbmc7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH07XHJcbiAgICAgIC8vIGRpZmZlcmVudGlhdGluZyBiZXR3ZWVuIHRoZSBmaXJzdCBjYWxsIHRvIHRoZSBmdW5jdGlvbiBhbmQgdGhlIHJlc3QuIFRoZSBmaXJzdCBpcyBhbHdheXMgZ29ubmEgYmVcclxuICAgICAgLy8gdGhlIGluaXRpYWxpemF0aW9uIG9mIGFsbCB0aGUgdGFyZ2V0c1xyXG4gICAgICBpZiAoIXRoaXMuaW5pdCkge1xyXG4gICAgICAgIC8vIFVwZGF0aW5nIHRoZSB2aXNpYmlsaXR5IG9mIGVhY2ggZWxlbWVudFxyXG4gICAgICAgIHVwZEVudHJpZXNWaXNpYmlsaXR5KCk7XHJcbiAgICAgICAgLy8gQ2FsY3VsYXRpbmcgdGhlIGFtb3VudCBvZiB2aXNpYmxlIGl0ZW1zIGFuZCB1cGRhdGluZyB0aGUgcHJvcGVydHkgXCJ2aXNpYmxlSXRlbXNBbW9cIiBmb3IgZmlyc3QgdGltZVxyXG4gICAgICAgIHRoaXMuZ2V0VmlzaWJsZUl0ZW1zKCk7XHJcbiAgICAgICAgLy8gY2FsY3VsYXRpbmcgYW1vdW50IG9mIHZpc2libGUgaXRlbXMgZGVwZW5kaW5nIGlmIHRoZSBzZWxlY3RlZCBtb2RlbCBmb3IgdGhlIGNvbXBvbmVudCBuZWVkcyBpdFxyXG4gICAgICAgIHRoaXMuY2FsU2V0dGluZ3MoKTtcclxuICAgICAgICAvLyBQcmVsb2FkaW5nIHRoZSBpdGVtc1xyXG4gICAgICAgIHRoaXMudXBkYXRlTG9hZGVkRWxlbWVudHMoKTtcclxuICAgICAgICB0aGlzLmluaXQgPSB0cnVlO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIFRoaXMgY29kZSB3aWxsIGJlIGV4ZWN1dGVkIGFsd2F5cyBhZnRlciB0aGUgZmlyc3QgdGltZVxyXG4gICAgICAgIC8vIFVwZGF0aW5nIHRoZSB2aXNpYmlsaXR5IG9mIGVhY2ggZWxlbWVudFxyXG4gICAgICAgIHVwZEVudHJpZXNWaXNpYmlsaXR5KCk7XHJcbiAgICAgIH1cclxuICAgIH07XHJcbiAgICAvLyBDcmVhdGluZyB0aGUgb2JzZXJ2ZXJcclxuICAgIHRoaXMub2JzZXJ2ZXIgPSBuZXcgSW50ZXJzZWN0aW9uT2JzZXJ2ZXIoaW9DYWxsQmFjaywgdGhpcy5JT09wdGlvbnMpO1xyXG4gICAgLy8gUmVnaXN0ZXJpbmcgdGhlIGl0ZW1zIHdpdGggdGhlIG9ic2VydmVyXHJcbiAgICB0aGlzLml0ZW1zSU8uZm9yRWFjaCgoaXRlbTogTHp5TG9hZEl0ZW1EaXJlY3RpdmUpID0+IHtcclxuICAgICAgdGhpcy5vYnNlcnZlci5vYnNlcnZlKGl0ZW0uaG9zdEVsZW1lbnQubmF0aXZlRWxlbWVudCk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8vIGNhbGN1bGF0ZSB0aGUgbmV3IHJhbmdlIG9mIGVsZW1lbnRzIGluIHRoZSBsaXN0IHRoYXQgc2hvdWxkIGJlIHByZWxvYWRcclxuICBjYWxMb2FkZWRSYW5nZSh2aXNpYmxlSXRlbXM6IEx6eUxvYWRJdGVtRGlyZWN0aXZlW10pOiBudW1iZXJbXSB7XHJcbiAgICBjb25zdCBuZXdSYW5nZSA9IFswLCAwXTtcclxuICAgIC8vIGdldHRpbmcgdGhlIHJhbmdlIG9mIGN1cnJlbnQgdmlzaWJsZSBpdGVtc1xyXG4gICAgY29uc3QgZmlyc3RWaXNpYmxlSXRlbSA9IHZpc2libGVJdGVtc1swXTtcclxuICAgIGNvbnN0IGxhc3RWaXNpYmxlSXRlbSA9IHZpc2libGVJdGVtc1t2aXNpYmxlSXRlbXMubGVuZ3RoIC0gMV07XHJcbiAgICAvLyBMYXN0IGl0ZW0gcG9zaXRpb24gaW4gdGhlIGFycmF5IG9mIGl0ZW1zXHJcbiAgICBjb25zdCBsYXN0SXRlbVBvc0luQXJyYXkgPSAodGhpcy5pdGVtc0lPLmxlbmd0aCAtIDEpO1xyXG4gICAgLy8gU2V0dGluZyB0aGUgbmV3IHN0YXJ0IHBvc2l0aW9uIHRvIHRoZSBjdXJyZW50IHBvc2l0aW9uIG1lbnVzIHRoZSBwcmVsb2FkIGFtb3VudCBkaXZpZGVkIGJ5IHR3b1xyXG4gICAgLy8gaW4gb3JkZXIgdG8gcHJlbG9hZCBmb3J3YXJkIGFuZCBpbiBiYWNrd2FyZFxyXG4gICAgbmV3UmFuZ2VbMF0gPSBNYXRoLm1heCgwLCAoZmlyc3RWaXNpYmxlSXRlbS5wb3MgLSB0aGlzLnByZWxvYWRBbW8pKTtcclxuICAgIGlmIChuZXdSYW5nZVswXSA9PT0gMCkge1xyXG4gICAgICAvLyBwcmVmZXRjaGluZyB0aGUgZWxlbWVudHMgYWhlYWQgb2YgdGhlIGxhc3QgdmlzaWJsZSBpdGVtXHJcbiAgICAgIG5ld1JhbmdlWzFdID0gTWF0aC5taW4odGhpcy5sb2FkaW5nUmFuZ2VBbW91bnQsIGxhc3RJdGVtUG9zSW5BcnJheSk7XHJcbiAgICB9IGVsc2UgaWYgKChsYXN0VmlzaWJsZUl0ZW0ucG9zICsgdGhpcy5wcmVsb2FkQW1vKSA+PSBsYXN0SXRlbVBvc0luQXJyYXkpIHtcclxuICAgICAgLy8gcHJlLWZldGNoaW5nIHRoZSBlbGVtZW50cyBhaGVhZCBhbmQgYmFja3dhcmQgb2YgdGhlIHJhbmdlIG9mIHZpc2libGUgaXRlbXNcclxuICAgICAgbmV3UmFuZ2VbMV0gPSBsYXN0SXRlbVBvc0luQXJyYXk7XHJcbiAgICAgIG5ld1JhbmdlWzBdID0gIE1hdGgubWF4KDAsIGxhc3RJdGVtUG9zSW5BcnJheSAtIHRoaXMubG9hZGluZ1JhbmdlQW1vdW50KTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIG5ld1JhbmdlWzFdID0gIChsYXN0VmlzaWJsZUl0ZW0ucG9zICsgdGhpcy5wcmVsb2FkQW1vKTtcclxuICAgIH1cclxuICAgIHJldHVybiBuZXdSYW5nZTtcclxuICB9XHJcblxyXG4gIC8vIEZ1bmN0aW9uIHRoYXQgY2FsY3VsYXRlIHRoZSBjdXJyZW50IHZpc2libGUgaXRlbXMgYW5kIHRoZSBvbmVzIHRoYXQgbmVlZCB0byBiZSBwcmVsb2FkXHJcbiAgdXBkYXRlTG9hZGVkRWxlbWVudHMoKSB7XHJcbiAgICAgLy8gIEdldHRpbmcgdGhlIGN1cnJlbnQgdmlzaWJsZSBlbGVtZW50cyBpbiB0aGUgY29udGFpbmVyXHJcbiAgICAgY29uc3QgdmlzaWJsZUl0ZW1zID0gdGhpcy5pdGVtc0lPLmZpbHRlcigoaXRlbTogTHp5TG9hZEl0ZW1EaXJlY3RpdmUpID0+IHtcclxuICAgICAgcmV0dXJuIGl0ZW0uaXNWaXNpYmxlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gaWYgYXJlIG5vdCB2aXNpYmxlIGl0ZW1zLCB0aGVuIGRvIG5vdGhpbmdcclxuICAgICBpZiAodmlzaWJsZUl0ZW1zLmxlbmd0aCA+IDApIHtcclxuICAgICAgLy8gQ2FsY3VsYXRpbmcgdGhlIGVsZW1lbnRzIHNob3VsZCBiZSBwcmVsb2FkXHJcbiAgICAgIHRoaXMubG9hZGVkUmFuZ2UgPSB0aGlzLmNhbExvYWRlZFJhbmdlKHZpc2libGVJdGVtcyk7XHJcbiAgICAgIHRoaXMuaXRlbXNJTy5mb3JFYWNoKChpdGVtOiBMenlMb2FkSXRlbURpcmVjdGl2ZSwgaW5kZXgpID0+IHtcclxuICAgICAgICBpZiAoaW5kZXggPj0gdGhpcy5sb2FkZWRSYW5nZVswXSAmJiBpbmRleCA8PSB0aGlzLmxvYWRlZFJhbmdlWzFdKSB7XHJcbiAgICAgICAgICAvLyBlbGVtZW50IHdpdGhpbiB0aGUgbG9hZGluZyByYW5nZVxyXG4gICAgICAgICAgdGhpcy5pbkxvYWRpbmdSYW5nZShpdGVtKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgLy8gZWxlbWVudCBvdXQgdGhlIGxvYWRpbmcgcmFuZ2VcclxuICAgICAgICAgIHRoaXMub3V0T2ZMb2FkaW5nUmFuZ2UoaXRlbSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIExpc3RlbmluZyB0byB0aGUgcmVzaXplIGV2ZW50IHNvIHdlIGNhbiByZWNhbGN1bGF0ZSB0aGUgYW1vdW50IG9mIHZpc2libGUgaXRlbXMgaW4gdGhlIGxpc3QgYW5kIG90aGVyXHJcbiAgLy8gaW1wb3J0YW50IHByb3BlcnRpZXMgdGhhdCBhcmUgdXNlIGZvciB0aGUgY29tcG9uZW50XHJcbiAgQEhvc3RMaXN0ZW5lcignd2luZG93OnJlc2l6ZScsIFtdKSBvblJlc2l6ZSgpIHtcclxuICAgIHRoaXMub25SZXNpemVFdmVudC5uZXh0KCk7XHJcbiAgfVxyXG5cclxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLm9ic2VydmVyKSB7XHJcbiAgICAgIHRoaXMub2JzZXJ2ZXIuZGlzY29ubmVjdCgpO1xyXG4gICAgfVxyXG4gICAgdGhpcy5zdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcclxuICB9XHJcbn1cclxuIl19