UNPKG

@nicky-lenaers/ngx-scroll-to

Version:

A simple Angular 4+ plugin enabling you to smooth scroll to any element on your page and enhance scroll-based features in your app.

273 lines 32.9 kB
import { Inject, Injectable, PLATFORM_ID } from '@angular/core'; import { DOCUMENT, isPlatformBrowser } from '@angular/common'; import { ScrollToAnimation } from './scroll-to-animation'; import { DEFAULTS, isElementRef, isNativeElement, isNumber, isString, isWindow, stripHash } from './scroll-to-helpers'; import { ReplaySubject, throwError } from 'rxjs'; import * as i0 from "@angular/core"; /** * The Scroll To Service handles starting, interrupting * and ending the actual Scroll Animation. It provides * some utilities to find the proper HTML Element on a * given page to setup Event Listeners and calculate * distances for the Animation. */ export class ScrollToService { /** * Construct and setup required paratemeters. * * @param document A Reference to the Document * @param platformId Angular Platform ID */ constructor(document, platformId) { this.document = document; this.platformId = platformId; this.interruptiveEvents = ['mousewheel', 'DOMMouseScroll', 'touchstart']; } /** * Target an Element to scroll to. Notice that the `TimeOut` decorator * ensures the executing to take place in the next Angular lifecycle. * This allows for scrolling to elements that are e.g. initially hidden * by means of `*ngIf`, but ought to be scrolled to eventually. * * @todo type 'any' in Observable should become custom type like 'ScrollToEvent' (base class), see issue comment: * - https://github.com/nicky-lenaers/ngx-scroll-to/issues/10#issuecomment-317198481 * * @param options Configuration Object * @returns Observable */ scrollTo(options) { if (!isPlatformBrowser(this.platformId)) { return new ReplaySubject().asObservable(); } return this.start(options); } /** * Start a new Animation. * * @todo Emit proper events from subscription * * @param options Configuration Object * @returns Observable */ start(options) { // Merge config with default values const mergedConfigOptions = { ...DEFAULTS, ...options }; if (this.animation) { this.animation.stop(); } const targetNode = this.getNode(mergedConfigOptions.target); if (mergedConfigOptions.target && !targetNode) { return throwError(() => new Error('Unable to find Target Element')); } const container = this.getContainer(mergedConfigOptions, targetNode); if (mergedConfigOptions.container && !container) { return throwError(() => new Error('Unable to find Container Element')); } const listenerTarget = this.getListenerTarget(container) || window; let to = container ? container.getBoundingClientRect().top : 0; if (targetNode) { to = isWindow(listenerTarget) ? window.scrollY + targetNode.getBoundingClientRect().top : targetNode.getBoundingClientRect().top; } // Create Animation this.animation = new ScrollToAnimation(container, listenerTarget, isWindow(listenerTarget), to, mergedConfigOptions, isPlatformBrowser(this.platformId)); const onInterrupt = () => this.animation.stop(); this.addInterruptiveEventListeners(listenerTarget, onInterrupt); // Start Animation const animation$ = this.animation.start(); this.subscribeToAnimation(animation$, listenerTarget, onInterrupt); return animation$; } /** * Subscribe to the events emitted from the Scrolling * Animation. Events might be used for e.g. unsubscribing * once finished. * * @param animation$ The Animation Observable * @param listenerTarget The Listener Target for events * @param onInterrupt The handler for Interruptive Events * @returns Void */ subscribeToAnimation(animation$, listenerTarget, onInterrupt) { const subscription = animation$ .subscribe({ complete: () => { this.removeInterruptiveEventListeners(this.interruptiveEvents, listenerTarget, onInterrupt); subscription.unsubscribe(); } }); } /** * Get the container HTML Element in which * the scrolling should happen. * * @param options The Merged Configuration Object * @param targetNode the targeted HTMLElement */ getContainer(options, targetNode) { let container = null; if (options.container) { container = this.getNode(options.container, true); } else if (targetNode) { container = this.getFirstScrollableParent(targetNode); } return container; } /** * Add listeners for the Animation Interruptive Events * to the Listener Target. * * @param events List of events to listen to * @param listenerTarget Target to attach the listener on * @param handler Handler for when the listener fires * @returns Void */ addInterruptiveEventListeners(listenerTarget, handler) { if (!listenerTarget) { listenerTarget = window; } this.interruptiveEvents .forEach(event => listenerTarget .addEventListener(event, handler, this.supportPassive() ? { passive: true } : false)); } /** * Feature-detect support for passive event listeners. * * @returns Whether or not passive event listeners are supported */ supportPassive() { let supportsPassive = false; try { const opts = Object.defineProperty({}, 'passive', { get: () => { supportsPassive = true; } }); window.addEventListener('testPassive', null, opts); window.removeEventListener('testPassive', null, opts); } catch (e) { } return supportsPassive; } /** * Remove listeners for the Animation Interrupt Event from * the Listener Target. Specifying the correct handler prevents * memory leaks and makes the allocated memory available for * Garbage Collection. * * @param events List of Interruptive Events to remove * @param listenerTarget Target to attach the listener on * @param handler Handler for when the listener fires * @returns Void */ removeInterruptiveEventListeners(events, listenerTarget, handler) { if (!listenerTarget) { listenerTarget = window; } events.forEach(event => listenerTarget.removeEventListener(event, handler)); } /** * Find the first scrollable parent Node of a given * Element. The DOM Tree gets searched upwards * to find this first scrollable parent. Parents might * be ignored by CSS styles applied to the HTML Element. * * @param nativeElement The Element to search the DOM Tree upwards from * @returns The first scrollable parent HTML Element */ getFirstScrollableParent(nativeElement) { let style = window.getComputedStyle(nativeElement); const overflowRegex = /(auto|scroll|overlay)/; if (style.position === 'fixed') { return null; } let parent = nativeElement; while (parent.parentElement) { parent = parent.parentElement; style = window.getComputedStyle(parent); if (style.position === 'absolute' || style.overflow === 'hidden' || style.overflowY === 'hidden') { continue; } if (overflowRegex.test(style.overflow + style.overflowY) || parent.tagName === 'BODY') { return parent; } } return null; } /** * Get the Target Node to scroll to. * * @param id The given ID of the node, either a string or * an element reference * @param allowBodyTag Indicate whether or not the Document Body is * considered a valid Target Node * @returns The Target Node to scroll to */ getNode(id, allowBodyTag = false) { let targetNode; if (isString(id)) { if (allowBodyTag && (id === 'body' || id === 'BODY')) { targetNode = this.document.body; } else { targetNode = this.document.getElementById(stripHash(id)); } } else if (isNumber(id)) { targetNode = this.document.getElementById(String(id)); } else if (isElementRef(id)) { targetNode = id.nativeElement; } else if (isNativeElement(id)) { targetNode = id; } return targetNode; } /** * Retrieve the Listener target. This Listener Target is used * to attach Event Listeners on. In case of the target being * the Document Body, we need the actual `window` to listen * for events. * * @param container The HTML Container element * @returns The Listener Target to attach events on */ getListenerTarget(container) { if (!container) { return null; } return this.isDocumentBody(container) ? window : container; } /** * Test if a given HTML Element is the Document Body. * * @param element The given HTML Element * @returns Whether or not the Element is the * Document Body Element */ isDocumentBody(element) { return element.tagName.toUpperCase() === 'BODY'; } } ScrollToService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.7", ngImport: i0, type: ScrollToService, deps: [{ token: DOCUMENT }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); ScrollToService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.7", ngImport: i0, type: ScrollToService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.7", ngImport: i0, type: ScrollToService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }]; } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Nyb2xsLXRvLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtc2Nyb2xsLXRvL3NyYy9saWIvc2Nyb2xsLXRvLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2hFLE9BQU8sRUFBRSxRQUFRLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQVE5RCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsUUFBUSxFQUFFLFlBQVksRUFBRSxlQUFlLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdkgsT0FBTyxFQUFjLGFBQWEsRUFBRSxVQUFVLEVBQUUsTUFBTSxNQUFNLENBQUM7O0FBRTdEOzs7Ozs7R0FNRztBQUVILE1BQU0sT0FBTyxlQUFlO0lBaUIxQjs7Ozs7T0FLRztJQUNILFlBQzRCLFFBQWEsRUFDVixVQUFlO1FBRGxCLGFBQVEsR0FBUixRQUFRLENBQUs7UUFDVixlQUFVLEdBQVYsVUFBVSxDQUFLO1FBRTVDLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxDQUFDLFlBQVksRUFBRSxnQkFBZ0IsRUFBRSxZQUFZLENBQUMsQ0FBQztJQUMzRSxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7O09BV0c7SUFDSCxRQUFRLENBQUMsT0FBOEI7UUFFckMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRTtZQUN2QyxPQUFPLElBQUksYUFBYSxFQUFFLENBQUMsWUFBWSxFQUFFLENBQUM7U0FDM0M7UUFFRCxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDN0IsQ0FBQztJQUVEOzs7Ozs7O09B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ZTtrQkFEM0IsVUFBVTs7MEJBeUJOLE1BQU07MkJBQUMsUUFBUTs7MEJBQ2YsTUFBTTsyQkFBQyxXQUFXIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0LCBJbmplY3RhYmxlLCBQTEFURk9STV9JRCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRE9DVU1FTlQsIGlzUGxhdGZvcm1Ccm93c2VyIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcblxuaW1wb3J0IHtcbiAgU2Nyb2xsVG9Db25maWdPcHRpb25zLFxuICBTY3JvbGxUb0NvbmZpZ09wdGlvbnNUYXJnZXQsXG4gIFNjcm9sbFRvTGlzdGVuZXJUYXJnZXQsXG4gIFNjcm9sbFRvVGFyZ2V0XG59IGZyb20gJy4vc2Nyb2xsLXRvLWNvbmZpZy5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgU2Nyb2xsVG9BbmltYXRpb24gfSBmcm9tICcuL3Njcm9sbC10by1hbmltYXRpb24nO1xuaW1wb3J0IHsgREVGQVVMVFMsIGlzRWxlbWVudFJlZiwgaXNOYXRpdmVFbGVtZW50LCBpc051bWJlciwgaXNTdHJpbmcsIGlzV2luZG93LCBzdHJpcEhhc2ggfSBmcm9tICcuL3Njcm9sbC10by1oZWxwZXJzJztcbmltcG9ydCB7IE9ic2VydmFibGUsIFJlcGxheVN1YmplY3QsIHRocm93RXJyb3IgfSBmcm9tICdyeGpzJztcblxuLyoqXG4gKiBUaGUgU2Nyb2xsIFRvIFNlcnZpY2UgaGFuZGxlcyBzdGFydGluZywgaW50ZXJydXB0aW5nXG4gKiBhbmQgZW5kaW5nIHRoZSBhY3R1YWwgU2Nyb2xsIEFuaW1hdGlvbi4gSXQgcHJvdmlkZXNcbiAqIHNvbWUgdXRpbGl0aWVzIHRvIGZpbmQgdGhlIHByb3BlciBIVE1MIEVsZW1lbnQgb24gYVxuICogZ2l2ZW4gcGFnZSB0byBzZXR1cCBFdmVudCBMaXN0ZW5lcnMgYW5kIGNhbGN1bGF0ZVxuICogZGlzdGFuY2VzIGZvciB0aGUgQW5pbWF0aW9uLlxuICovXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgU2Nyb2xsVG9TZXJ2aWNlIHtcblxuICAvKipcbiAgICogVGhlIGFuaW1hdGlvbiB0aGF0IHByb3ZpZGVzIHRoZSBzY3JvbGxpbmdcbiAgICogdG8gaGFwcGVuIHNtb290aGx5IG92ZXIgdGltZS4gRGVmaW5pbmcgaXQgaGVyZVxuICAgKiBhbGxvd3MgZm9yIHVzYWdlIG9mIGUuZy4gYHN0YXJ0YCBhbmQgYHN0b3BgXG4gICAqIG1ldGhvZHMgd2l0aGluIHRoaXMgQW5ndWxhciBTZXJ2aWNlLlxuICAgKi9cbiAgcHJpdmF0ZSBhbmltYXRpb246IFNjcm9sbFRvQW5pbWF0aW9uO1xuXG4gIC8qKlxuICAgKiBJbnRlcnJ1cHRpdmUgRXZlbnRzIGFsbG93IHRvIHNjcm9sbGluZyBhbmltYXRpb25cbiAgICogdG8gYmUgaW50ZXJydXB0ZWQgYmVmb3JlIGl0IGlzIGZpbmlzaGVkLiBUaGUgbGlzdFxuICAgKiBvZiBJbnRlcnJ1cHRpdmUgRXZlbnRzIHJlcHJlc2VudHMgdGhvc2UuXG4gICAqL1xuICBwcml2YXRlIGludGVycnVwdGl2ZUV2ZW50czogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdCBhbmQgc2V0dXAgcmVxdWlyZWQgcGFyYXRlbWV0ZXJzLlxuICAgKlxuICAgKiBAcGFyYW0gZG9jdW1lbnQgICAgICAgICBBIFJlZmVyZW5jZSB0byB0aGUgRG9jdW1lbnRcbiAgICogQHBhcmFtIHBsYXRmb3JtSWQgICAgICAgQW5ndWxhciBQbGF0Zm9ybSBJRFxuICAgKi9cbiAgY29uc3RydWN0b3IoXG4gICAgQEluamVjdChET0NVTUVOVCkgcHJpdmF0ZSBkb2N1bWVudDogYW55LFxuICAgIEBJbmplY3QoUExBVEZPUk1fSUQpIHByaXZhdGUgcGxhdGZvcm1JZDogYW55XG4gICkge1xuICAgIHRoaXMuaW50ZXJydXB0aXZlRXZlbnRzID0gWydtb3VzZXdoZWVsJywgJ0RPTU1vdXNlU2Nyb2xsJywgJ3RvdWNoc3RhcnQnXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUYXJnZXQgYW4gRWxlbWVudCB0byBzY3JvbGwgdG8uIE5vdGljZSB0aGF0IHRoZSBgVGltZU91dGAgZGVjb3JhdG9yXG4gICAqIGVuc3VyZXMgdGhlIGV4ZWN1dGluZyB0byB0YWtlIHBsYWNlIGluIHRoZSBuZXh0IEFuZ3VsYXIgbGlmZWN5Y2xlLlxuICAgKiBUaGlzIGFsbG93cyBmb3Igc2Nyb2xsaW5nIHRvIGVsZW1lbnRzIHRoYXQgYXJlIGUuZy4gaW5pdGlhbGx5IGhpZGRlblxuICAgKiBieSBtZWFucyBvZiBgKm5nSWZgLCBidXQgb3VnaHQgdG8gYmUgc2Nyb2xsZWQgdG8gZXZlbnR1YWxseS5cbiAgICpcbiAgICogQHRvZG8gdHlwZSAnYW55JyBpbiBPYnNlcnZhYmxlIHNob3VsZCBiZWNvbWUgY3VzdG9tIHR5cGUgbGlrZSAnU2Nyb2xsVG9FdmVudCcgKGJhc2UgY2xhc3MpLCBzZWUgaXNzdWUgY29tbWVudDpcbiAgICogIC0gaHR0cHM6Ly9naXRodWIuY29tL25pY2t5LWxlbmFlcnMvbmd4LXNjcm9sbC10by9pc3N1ZXMvMTAjaXNzdWVjb21tZW50LTMxNzE5ODQ4MVxuICAgKlxuICAgKiBAcGFyYW0gb3B0aW9ucyAgICAgICAgIENvbmZpZ3VyYXRpb24gT2JqZWN0XG4gICAqIEByZXR1cm5zICAgICAgICAgICAgICAgT2JzZXJ2YWJsZVxuICAgKi9cbiAgc2Nyb2xsVG8ob3B0aW9uczogU2Nyb2xsVG9Db25maWdPcHRpb25zKTogT2JzZXJ2YWJsZTxhbnk+IHtcblxuICAgIGlmICghaXNQbGF0Zm9ybUJyb3dzZXIodGhpcy5wbGF0Zm9ybUlkKSkge1xuICAgICAgcmV0dXJuIG5ldyBSZXBsYXlTdWJqZWN0KCkuYXNPYnNlcnZhYmxlKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuc3RhcnQob3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogU3RhcnQgYSBuZXcgQW5pbWF0aW9uLlxuICAgKlxuICAgKiBAdG9kbyBFbWl0IHByb3BlciBldmVudHMgZnJvbSBzdWJzY3JpcHRpb25cbiAgICpcbiAgICogQHBhcmFtIG9wdGlvbnMgICAgICAgICBDb25maWd1cmF0aW9uIE9iamVjdFxuICAgKiBAcmV0dXJucyAgICAgICAgICAgICAgIE9ic2VydmFibGVcbiAgICovXG4gIHByaXZhdGUgc3RhcnQob3B0aW9uczogU2Nyb2xsVG9Db25maWdPcHRpb25zKTogT2JzZXJ2YWJsZTxudW1iZXI+IHtcblxuICAgIC8vIE1lcmdlIGNvbmZpZyB3aXRoIGRlZmF1bHQgdmFsdWVzXG4gICAgY29uc3QgbWVyZ2VkQ29uZmlnT3B0aW9ucyA9IHtcbiAgICAgIC4uLkRFRkFVTFRTIGFzIFNjcm9sbFRvQ29uZmlnT3B0aW9ucyxcbiAgICAgIC4uLm9wdGlvbnNcbiAgICB9IGFzIFNjcm9sbFRvQ29uZmlnT3B0aW9uc1RhcmdldDtcblxuICAgIGlmICh0aGlzLmFuaW1hdGlvbikge1xuICAgICAgdGhpcy5hbmltYXRpb24uc3RvcCgpO1xuICAgIH1cblxuICAgIGNvbnN0IHRhcmdldE5vZGUgPSB0aGlzLmdldE5vZGUobWVyZ2VkQ29uZmlnT3B0aW9ucy50YXJnZXQpO1xuICAgIGlmIChtZXJnZWRDb25maWdPcHRpb25zLnRhcmdldCAmJiAhdGFyZ2V0Tm9kZSkge1xuICAgICAgcmV0dXJuIHRocm93RXJyb3IoKCkgPT4gbmV3IEVycm9yKCdVbmFibGUgdG8gZmluZCBUYXJnZXQgRWxlbWVudCcpKTtcbiAgICB9XG5cbiAgICBjb25zdCBjb250YWluZXI6IEhUTUxFbGVtZW50ID0gdGhpcy5nZXRDb250YWluZXIobWVyZ2VkQ29uZmlnT3B0aW9ucywgdGFyZ2V0Tm9kZSk7XG4gICAgaWYgKG1lcmdlZENvbmZpZ09wdGlvbnMuY29udGFpbmVyICYmICFjb250YWluZXIpIHtcbiAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IG5ldyBFcnJvcignVW5hYmxlIHRvIGZpbmQgQ29udGFpbmVyIEVsZW1lbnQnKSk7XG4gICAgfVxuXG4gICAgY29uc3QgbGlzdGVuZXJUYXJnZXQgPSB0aGlzLmdldExpc3RlbmVyVGFyZ2V0KGNvbnRhaW5lcikgfHwgd2luZG93O1xuXG4gICAgbGV0IHRvID0gY29udGFpbmVyID8gY29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCA6IDA7XG5cbiAgICBpZiAodGFyZ2V0Tm9kZSkge1xuICAgICAgdG8gPSBpc1dpbmRvdyhsaXN0ZW5lclRhcmdldCkgP1xuICAgICAgICB3aW5kb3cuc2Nyb2xsWSArIHRhcmdldE5vZGUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkudG9wIDpcbiAgICAgICAgdGFyZ2V0Tm9kZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS50b3A7XG4gICAgfVxuXG4gICAgLy8gQ3JlYXRlIEFuaW1hdGlvblxuICAgIHRoaXMuYW5pbWF0aW9uID0gbmV3IFNjcm9sbFRvQW5pbWF0aW9uKFxuICAgICAgY29udGFpbmVyLFxuICAgICAgbGlzdGVuZXJUYXJnZXQsXG4gICAgICBpc1dpbmRvdyhsaXN0ZW5lclRhcmdldCksXG4gICAgICB0byxcbiAgICAgIG1lcmdlZENvbmZpZ09wdGlvbnMsXG4gICAgICBpc1BsYXRmb3JtQnJvd3Nlcih0aGlzLnBsYXRmb3JtSWQpXG4gICAgKTtcbiAgICBjb25zdCBvbkludGVycnVwdCA9ICgpID0+IHRoaXMuYW5pbWF0aW9uLnN0b3AoKTtcbiAgICB0aGlzLmFkZEludGVycnVwdGl2ZUV2ZW50TGlzdGVuZXJzKGxpc3RlbmVyVGFyZ2V0LCBvbkludGVycnVwdCk7XG5cbiAgICAvLyBTdGFydCBBbmltYXRpb25cbiAgICBjb25zdCBhbmltYXRpb24kID0gdGhpcy5hbmltYXRpb24uc3RhcnQoKTtcbiAgICB0aGlzLnN1YnNjcmliZVRvQW5pbWF0aW9uKGFuaW1hdGlvbiQsIGxpc3RlbmVyVGFyZ2V0LCBvbkludGVycnVwdCk7XG5cbiAgICByZXR1cm4gYW5pbWF0aW9uJDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdWJzY3JpYmUgdG8gdGhlIGV2ZW50cyBlbWl0dGVkIGZyb20gdGhlIFNjcm9sbGluZ1xuICAgKiBBbmltYXRpb24uIEV2ZW50cyBtaWdodCBiZSB1c2VkIGZvciBlLmcuIHVuc3Vic2NyaWJpbmdcbiAgICogb25jZSBmaW5pc2hlZC5cbiAgICpcbiAgICogQHBhcmFtIGFuaW1hdGlvbiQgICAgICAgICAgICAgIFRoZSBBbmltYXRpb24gT2JzZXJ2YWJsZVxuICAgKiBAcGFyYW0gbGlzdGVuZXJUYXJnZXQgICAgICAgICAgVGhlIExpc3RlbmVyIFRhcmdldCBmb3IgZXZlbnRzXG4gICAqIEBwYXJhbSBvbkludGVycnVwdCAgICAgICAgICAgICBUaGUgaGFuZGxlciBmb3IgSW50ZXJydXB0aXZlIEV2ZW50c1xuICAgKiBAcmV0dXJucyAgICAgICAgICAgICAgICAgICAgICAgVm9pZFxuICAgKi9cbiAgcHJpdmF0ZSBzdWJzY3JpYmVUb0FuaW1hdGlvbihcbiAgICBhbmltYXRpb24kOiBPYnNlcnZhYmxlPGFueT4sXG4gICAgbGlzdGVuZXJUYXJnZXQ6IFNjcm9sbFRvTGlzdGVuZXJUYXJnZXQsXG4gICAgb25JbnRlcnJ1cHQ6IEV2ZW50TGlzdGVuZXJPckV2ZW50TGlzdGVuZXJPYmplY3RcbiAgKSB7XG4gICAgY29uc3Qgc3Vic2NyaXB0aW9uID0gYW5pbWF0aW9uJFxuICAgICAgLnN1YnNjcmliZShcbiAgICAgICAge1xuICAgICAgICAgIGNvbXBsZXRlOiAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnJlbW92ZUludGVycnVwdGl2ZUV2ZW50TGlzdGVuZXJzKHRoaXMuaW50ZXJydXB0aXZlRXZlbnRzLCBsaXN0ZW5lclRhcmdldCwgb25JbnRlcnJ1cHQpO1xuICAgICAgICAgICAgc3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgY29udGFpbmVyIEhUTUwgRWxlbWVudCBpbiB3aGljaFxuICAgKiB0aGUgc2Nyb2xsaW5nIHNob3VsZCBoYXBwZW4uXG4gICAqXG4gICAqIEBwYXJhbSBvcHRpb25zICAgICAgICAgVGhlIE1lcmdlZCBDb25maWd1cmF0aW9uIE9iamVjdFxuICAgKiBAcGFyYW0gdGFyZ2V0Tm9kZSAgICB0aGUgdGFyZ2V0ZWQgSFRNTEVsZW1lbnRcbiAgICovXG4gIHByaXZhdGUgZ2V0Q29udGFpbmVyKG9wdGlvbnM6IFNjcm9sbFRvQ29uZmlnT3B0aW9ucywgdGFyZ2V0Tm9kZTogSFRNTEVsZW1lbnQpOiBIVE1MRWxlbWVudCB8IG51bGwge1xuXG4gICAgbGV0IGNvbnRhaW5lcjogSFRNTEVsZW1lbnQgfCBudWxsID0gbnVsbDtcblxuICAgIGlmIChvcHRpb25zLmNvbnRhaW5lcikge1xuICAgICAgY29udGFpbmVyID0gdGhpcy5nZXROb2RlKG9wdGlvbnMuY29udGFpbmVyLCB0cnVlKTtcbiAgICB9IGVsc2UgaWYgKHRhcmdldE5vZGUpIHtcbiAgICAgIGNvbnRhaW5lciA9IHRoaXMuZ2V0Rmlyc3RTY3JvbGxhYmxlUGFyZW50KHRhcmdldE5vZGUpO1xuICAgIH1cblxuICAgIHJldHVybiBjb250YWluZXI7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGxpc3RlbmVycyBmb3IgdGhlIEFuaW1hdGlvbiBJbnRlcnJ1cHRpdmUgRXZlbnRzXG4gICAqIHRvIHRoZSBMaXN0ZW5lciBUYXJnZXQuXG4gICAqXG4gICAqIEBwYXJhbSBldmVudHMgICAgICAgICAgICBMaXN0IG9mIGV2ZW50cyB0byBsaXN0ZW4gdG9cbiAgICogQHBhcmFtIGxpc3RlbmVyVGFyZ2V0ICAgIFRhcmdldCB0byBhdHRhY2ggdGhlIGxpc3RlbmVyIG9uXG4gICAqIEBwYXJhbSBoYW5kbGVyICAgICAgICAgICBIYW5kbGVyIGZvciB3aGVuIHRoZSBsaXN0ZW5lciBmaXJlc1xuICAgKiBAcmV0dXJucyAgICAgICAgICAgICAgICAgVm9pZFxuICAgKi9cbiAgcHJpdmF0ZSBhZGRJbnRlcnJ1cHRpdmVFdmVudExpc3RlbmVycyhcbiAgICBsaXN0ZW5lclRhcmdldDogU2Nyb2xsVG9MaXN0ZW5lclRhcmdldCxcbiAgICBoYW5kbGVyOiBFdmVudExpc3RlbmVyT3JFdmVudExpc3RlbmVyT2JqZWN0KTogdm9pZCB7XG5cbiAgICBpZiAoIWxpc3RlbmVyVGFyZ2V0KSB7XG4gICAgICBsaXN0ZW5lclRhcmdldCA9IHdpbmRvdztcbiAgICB9XG5cbiAgICB0aGlzLmludGVycnVwdGl2ZUV2ZW50c1xuICAgICAgLmZvckVhY2goZXZlbnQgPT4gbGlzdGVuZXJUYXJnZXRcbiAgICAgICAgLmFkZEV2ZW50TGlzdGVuZXIoZXZlbnQsIGhhbmRsZXIsIHRoaXMuc3VwcG9ydFBhc3NpdmUoKSA/IHtwYXNzaXZlOiB0cnVlfSA6IGZhbHNlKSk7XG4gIH1cblxuICAvKipcbiAgICogRmVhdHVyZS1kZXRlY3Qgc3VwcG9ydCBmb3IgcGFzc2l2ZSBldmVudCBsaXN0ZW5lcnMuXG4gICAqXG4gICAqIEByZXR1cm5zICAgICAgIFdoZXRoZXIgb3Igbm90IHBhc3NpdmUgZXZlbnQgbGlzdGVuZXJzIGFyZSBzdXBwb3J0ZWRcbiAgICovXG4gIHByaXZhdGUgc3VwcG9ydFBhc3NpdmUoKTogYm9vbGVhbiB7XG5cbiAgICBsZXQgc3VwcG9ydHNQYXNzaXZlID0gZmFsc2U7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3Qgb3B0cyA9IE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh7fSwgJ3Bhc3NpdmUnLCB7XG4gICAgICAgIGdldDogKCkgPT4ge1xuICAgICAgICAgIHN1cHBvcnRzUGFzc2l2ZSA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Rlc3RQYXNzaXZlJywgbnVsbCwgb3B0cyk7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcigndGVzdFBhc3NpdmUnLCBudWxsLCBvcHRzKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgfVxuXG4gICAgcmV0dXJuIHN1cHBvcnRzUGFzc2l2ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgbGlzdGVuZXJzIGZvciB0aGUgQW5pbWF0aW9uIEludGVycnVwdCBFdmVudCBmcm9tXG4gICAqIHRoZSBMaXN0ZW5lciBUYXJnZXQuIFNwZWNpZnlpbmcgdGhlIGNvcnJlY3QgaGFuZGxlciBwcmV2ZW50c1xuICAgKiBtZW1vcnkgbGVha3MgYW5kIG1ha2VzIHRoZSBhbGxvY2F0ZWQgbWVtb3J5IGF2YWlsYWJsZSBmb3JcbiAgICogR2FyYmFnZSBDb2xsZWN0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0gZXZlbnRzICAgICAgICAgICAgTGlzdCBvZiBJbnRlcnJ1cHRpdmUgRXZlbnRzIHRvIHJlbW92ZVxuICAgKiBAcGFyYW0gbGlzdGVuZXJUYXJnZXQgICAgVGFyZ2V0IHRvIGF0dGFjaCB0aGUgbGlzdGVuZXIgb25cbiAgICogQHBhcmFtIGhhbmRsZXIgICAgICAgICAgIEhhbmRsZXIgZm9yIHdoZW4gdGhlIGxpc3RlbmVyIGZpcmVzXG4gICAqIEByZXR1cm5zICAgICAgICAgICAgICAgICBWb2lkXG4gICAqL1xuICBwcml2YXRlIHJlbW92ZUludGVycnVwdGl2ZUV2ZW50TGlzdGVuZXJzKFxuICAgIGV2ZW50czogc3RyaW5nW10sXG4gICAgbGlzdGVuZXJUYXJnZXQ6IFNjcm9sbFRvTGlzdGVuZXJUYXJnZXQsXG4gICAgaGFuZGxlcjogRXZlbnRMaXN0ZW5lck9yRXZlbnRMaXN0ZW5lck9iamVjdCk6IHZvaWQge1xuXG4gICAgaWYgKCFsaXN0ZW5lclRhcmdldCkge1xuICAgICAgbGlzdGVuZXJUYXJnZXQgPSB3aW5kb3c7XG4gICAgfVxuICAgIGV2ZW50cy5mb3JFYWNoKGV2ZW50ID0+IGxpc3RlbmVyVGFyZ2V0LnJlbW92ZUV2ZW50TGlzdGVuZXIoZXZlbnQsIGhhbmRsZXIpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5kIHRoZSBmaXJzdCBzY3JvbGxhYmxlIHBhcmVudCBOb2RlIG9mIGEgZ2l2ZW5cbiAgICogRWxlbWVudC4gVGhlIERPTSBUcmVlIGdldHMgc2VhcmNoZWQgdXB3YXJkc1xuICAgKiB0byBmaW5kIHRoaXMgZmlyc3Qgc2Nyb2xsYWJsZSBwYXJlbnQuIFBhcmVudHMgbWlnaHRcbiAgICogYmUgaWdub3JlZCBieSBDU1Mgc3R5bGVzIGFwcGxpZWQgdG8gdGhlIEhUTUwgRWxlbWVudC5cbiAgICpcbiAgICogQHBhcmFtIG5hdGl2ZUVsZW1lbnQgICAgIFRoZSBFbGVtZW50IHRvIHNlYXJjaCB0aGUgRE9NIFRyZWUgdXB3YXJkcyBmcm9tXG4gICAqIEByZXR1cm5zICAgICAgICAgICAgICAgICBUaGUgZmlyc3Qgc2Nyb2xsYWJsZSBwYXJlbnQgSFRNTCBFbGVtZW50XG4gICAqL1xuICBwcml2YXRlIGdldEZpcnN0U2Nyb2xsYWJsZVBhcmVudChuYXRpdmVFbGVtZW50OiBIVE1MRWxlbWVudCk6IEhUTUxFbGVtZW50IHtcblxuICAgIGxldCBzdHlsZTogQ1NTU3R5bGVEZWNsYXJhdGlvbiA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKG5hdGl2ZUVsZW1lbnQpO1xuXG4gICAgY29uc3Qgb3ZlcmZsb3dSZWdleDogUmVnRXhwID0gLyhhdXRvfHNjcm9sbHxvdmVybGF5KS87XG5cbiAgICBpZiAoc3R5bGUucG9zaXRpb24gPT09ICdmaXhlZCcpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGxldCBwYXJlbnQgPSBuYXRpdmVFbGVtZW50O1xuICAgIHdoaWxlIChwYXJlbnQucGFyZW50RWxlbWVudCkge1xuICAgICAgcGFyZW50ID0gcGFyZW50LnBhcmVudEVsZW1lbnQ7XG4gICAgICBzdHlsZSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKHBhcmVudCk7XG5cbiAgICAgIGlmIChzdHlsZS5wb3NpdGlvbiA9PT0gJ2Fic29sdXRlJ1xuICAgICAgICB8fCBzdHlsZS5vdmVyZmxvdyA9PT0gJ2hpZGRlbidcbiAgICAgICAgfHwgc3R5bGUub3ZlcmZsb3dZID09PSAnaGlkZGVuJykge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKG92ZXJmbG93UmVnZXgudGVzdChzdHlsZS5vdmVyZmxvdyArIHN0eWxlLm92ZXJmbG93WSlcbiAgICAgICAgfHwgcGFyZW50LnRhZ05hbWUgPT09ICdCT0RZJykge1xuICAgICAgICByZXR1cm4gcGFyZW50O1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgVGFyZ2V0IE5vZGUgdG8gc2Nyb2xsIHRvLlxuICAgKlxuICAgKiBAcGFyYW0gaWQgICAgICAgICAgICAgIFRoZSBnaXZlbiBJRCBvZiB0aGUgbm9kZSwgZWl0aGVyIGEgc3RyaW5nIG9yXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgYW4gZWxlbWVudCByZWZlcmVuY2VcbiAgICogQHBhcmFtIGFsbG93Qm9keVRhZyAgICBJbmRpY2F0ZSB3aGV0aGVyIG9yIG5vdCB0aGUgRG9jdW1lbnQgQm9keSBpc1xuICAgKiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNpZGVyZWQgYSB2YWxpZCBUYXJnZXQgTm9kZVxuICAgKiBAcmV0dXJucyAgICAgICAgICAgICAgIFRoZSBUYXJnZXQgTm9kZSB0byBzY3JvbGwgdG9cbiAgICovXG4gIHByaXZhdGUgZ2V0Tm9kZShpZDogU2Nyb2xsVG9UYXJnZXQsIGFsbG93Qm9keVRhZzogYm9vbGVhbiA9IGZhbHNlKTogSFRNTEVsZW1lbnQge1xuXG4gICAgbGV0IHRhcmdldE5vZGU6IEhUTUxFbGVtZW50O1xuXG4gICAgaWYgKGlzU3RyaW5nKGlkKSkge1xuICAgICAgaWYgKGFsbG93Qm9keVRhZyAmJiAoaWQgPT09ICdib2R5JyB8fCBpZCA9PT0gJ0JPRFknKSkge1xuICAgICAgICB0YXJnZXROb2RlID0gdGhpcy5kb2N1bWVudC5ib2R5O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGFyZ2V0Tm9kZSA9IHRoaXMuZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoc3RyaXBIYXNoKGlkKSk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChpc051bWJlcihpZCkpIHtcbiAgICAgIHRhcmdldE5vZGUgPSB0aGlzLmRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFN0cmluZyhpZCkpO1xuICAgIH0gZWxzZSBpZiAoaXNFbGVtZW50UmVmKGlkKSkge1xuICAgICAgdGFyZ2V0Tm9kZSA9IGlkLm5hdGl2ZUVsZW1lbnQ7XG4gICAgfSBlbHNlIGlmIChpc05hdGl2ZUVsZW1lbnQoaWQpKSB7XG4gICAgICB0YXJnZXROb2RlID0gaWQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRhcmdldE5vZGU7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmUgdGhlIExpc3RlbmVyIHRhcmdldC4gVGhpcyBMaXN0ZW5lciBUYXJnZXQgaXMgdXNlZFxuICAgKiB0byBhdHRhY2ggRXZlbnQgTGlzdGVuZXJzIG9uLiBJbiBjYXNlIG9mIHRoZSB0YXJnZXQgYmVpbmdcbiAgICogdGhlIERvY3VtZW50IEJvZHksIHdlIG5lZWQgdGhlIGFjdHVhbCBgd2luZG93YCB0byBsaXN0ZW5cbiAgICogZm9yIGV2ZW50cy5cbiAgICpcbiAgICogQHBhcmFtIGNvbnRhaW5lciAgICAgICAgICAgVGhlIEhUTUwgQ29udGFpbmVyIGVsZW1lbnRcbiAgICogQHJldHVybnMgICAgICAgICAgICAgICAgICAgVGhlIExpc3RlbmVyIFRhcmdldCB0byBhdHRhY2ggZXZlbnRzIG9uXG4gICAqL1xuICBwcml2YXRlIGdldExpc3RlbmVyVGFyZ2V0KGNvbnRhaW5lcjogSFRNTEVsZW1lbnQpOiBTY3JvbGxUb0xpc3RlbmVyVGFyZ2V0IHtcbiAgICBpZiAoIWNvbnRhaW5lcikge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmlzRG9jdW1lbnRCb2R5KGNvbnRhaW5lcikgPyB3aW5kb3cgOiBjb250YWluZXI7XG4gIH1cblxuICAvKipcbiAgICogVGVzdCBpZiBhIGdpdmVuIEhUTUwgRWxlbWVudCBpcyB0aGUgRG9jdW1lbnQgQm9keS5cbiAgICpcbiAgICogQHBhcmFtIGVsZW1lbnQgICAgICAgICAgICAgVGhlIGdpdmVuIEhUTUwgRWxlbWVudFxuICAgKiBAcmV0dXJucyAgICAgICAgICAgICAgICAgICBXaGV0aGVyIG9yIG5vdCB0aGUgRWxlbWVudCBpcyB0aGVcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgRG9jdW1lbnQgQm9keSBFbGVtZW50XG4gICAqL1xuICBwcml2YXRlIGlzRG9jdW1lbnRCb2R5KGVsZW1lbnQ6IEhUTUxFbGVtZW50KTogZWxlbWVudCBpcyBIVE1MQm9keUVsZW1lbnQge1xuICAgIHJldHVybiBlbGVtZW50LnRhZ05hbWUudG9VcHBlckNhc2UoKSA9PT0gJ0JPRFknO1xuICB9XG59XG4iXX0=