@akaustav/ngx-scroll-to
Version:
A simple Angular 12 plugin enabling you to smooth scroll to any element on your page and enhance scroll-based features in your app. This is a fork from @nicky-lenaers/ngx-scroll-to that adds support for Angular 12.
270 lines • 34.1 kB
JavaScript
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 = Object.assign(Object.assign({}, 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: "12.2.17", ngImport: i0, type: ScrollToService, deps: [{ token: DOCUMENT }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable });
ScrollToService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: ScrollToService });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", 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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VUFBVTs7MEJBeUJOLE1BQU07MkJBQUMsUUFBUTs7MEJBQ2YsTUFBTTsyQkFBQyxXQUFXIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0LCBJbmplY3RhYmxlLCBQTEFURk9STV9JRCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBET0NVTUVOVCwgaXNQbGF0Zm9ybUJyb3dzZXIgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xyXG5cclxuaW1wb3J0IHtcclxuICBTY3JvbGxUb0NvbmZpZ09wdGlvbnMsXHJcbiAgU2Nyb2xsVG9Db25maWdPcHRpb25zVGFyZ2V0LFxyXG4gIFNjcm9sbFRvTGlzdGVuZXJUYXJnZXQsXHJcbiAgU2Nyb2xsVG9UYXJnZXRcclxufSBmcm9tICcuL3Njcm9sbC10by1jb25maWcuaW50ZXJmYWNlJztcclxuaW1wb3J0IHsgU2Nyb2xsVG9BbmltYXRpb24gfSBmcm9tICcuL3Njcm9sbC10by1hbmltYXRpb24nO1xyXG5pbXBvcnQgeyBERUZBVUxUUywgaXNFbGVtZW50UmVmLCBpc05hdGl2ZUVsZW1lbnQsIGlzTnVtYmVyLCBpc1N0cmluZywgaXNXaW5kb3csIHN0cmlwSGFzaCB9IGZyb20gJy4vc2Nyb2xsLXRvLWhlbHBlcnMnO1xyXG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBSZXBsYXlTdWJqZWN0LCB0aHJvd0Vycm9yIH0gZnJvbSAncnhqcyc7XHJcblxyXG4vKipcclxuICogVGhlIFNjcm9sbCBUbyBTZXJ2aWNlIGhhbmRsZXMgc3RhcnRpbmcsIGludGVycnVwdGluZ1xyXG4gKiBhbmQgZW5kaW5nIHRoZSBhY3R1YWwgU2Nyb2xsIEFuaW1hdGlvbi4gSXQgcHJvdmlkZXNcclxuICogc29tZSB1dGlsaXRpZXMgdG8gZmluZCB0aGUgcHJvcGVyIEhUTUwgRWxlbWVudCBvbiBhXHJcbiAqIGdpdmVuIHBhZ2UgdG8gc2V0dXAgRXZlbnQgTGlzdGVuZXJzIGFuZCBjYWxjdWxhdGVcclxuICogZGlzdGFuY2VzIGZvciB0aGUgQW5pbWF0aW9uLlxyXG4gKi9cclxuQEluamVjdGFibGUoKVxyXG5leHBvcnQgY2xhc3MgU2Nyb2xsVG9TZXJ2aWNlIHtcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGFuaW1hdGlvbiB0aGF0IHByb3ZpZGVzIHRoZSBzY3JvbGxpbmdcclxuICAgKiB0byBoYXBwZW4gc21vb3RobHkgb3ZlciB0aW1lLiBEZWZpbmluZyBpdCBoZXJlXHJcbiAgICogYWxsb3dzIGZvciB1c2FnZSBvZiBlLmcuIGBzdGFydGAgYW5kIGBzdG9wYFxyXG4gICAqIG1ldGhvZHMgd2l0aGluIHRoaXMgQW5ndWxhciBTZXJ2aWNlLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgYW5pbWF0aW9uOiBTY3JvbGxUb0FuaW1hdGlvbjtcclxuXHJcbiAgLyoqXHJcbiAgICogSW50ZXJydXB0aXZlIEV2ZW50cyBhbGxvdyB0byBzY3JvbGxpbmcgYW5pbWF0aW9uXHJcbiAgICogdG8gYmUgaW50ZXJydXB0ZWQgYmVmb3JlIGl0IGlzIGZpbmlzaGVkLiBUaGUgbGlzdFxyXG4gICAqIG9mIEludGVycnVwdGl2ZSBFdmVudHMgcmVwcmVzZW50cyB0aG9zZS5cclxuICAgKi9cclxuICBwcml2YXRlIGludGVycnVwdGl2ZUV2ZW50czogc3RyaW5nW107XHJcblxyXG4gIC8qKlxyXG4gICAqIENvbnN0cnVjdCBhbmQgc2V0dXAgcmVxdWlyZWQgcGFyYXRlbWV0ZXJzLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIGRvY3VtZW50ICAgICAgICAgQSBSZWZlcmVuY2UgdG8gdGhlIERvY3VtZW50XHJcbiAgICogQHBhcmFtIHBsYXRmb3JtSWQgICAgICAgQW5ndWxhciBQbGF0Zm9ybSBJRFxyXG4gICAqL1xyXG4gIGNvbnN0cnVjdG9yKFxyXG4gICAgQEluamVjdChET0NVTUVOVCkgcHJpdmF0ZSBkb2N1bWVudDogYW55LFxyXG4gICAgQEluamVjdChQTEFURk9STV9JRCkgcHJpdmF0ZSBwbGF0Zm9ybUlkOiBhbnlcclxuICApIHtcclxuICAgIHRoaXMuaW50ZXJydXB0aXZlRXZlbnRzID0gWydtb3VzZXdoZWVsJywgJ0RPTU1vdXNlU2Nyb2xsJywgJ3RvdWNoc3RhcnQnXTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFRhcmdldCBhbiBFbGVtZW50IHRvIHNjcm9sbCB0by4gTm90aWNlIHRoYXQgdGhlIGBUaW1lT3V0YCBkZWNvcmF0b3JcclxuICAgKiBlbnN1cmVzIHRoZSBleGVjdXRpbmcgdG8gdGFrZSBwbGFjZSBpbiB0aGUgbmV4dCBBbmd1bGFyIGxpZmVjeWNsZS5cclxuICAgKiBUaGlzIGFsbG93cyBmb3Igc2Nyb2xsaW5nIHRvIGVsZW1lbnRzIHRoYXQgYXJlIGUuZy4gaW5pdGlhbGx5IGhpZGRlblxyXG4gICAqIGJ5IG1lYW5zIG9mIGAqbmdJZmAsIGJ1dCBvdWdodCB0byBiZSBzY3JvbGxlZCB0byBldmVudHVhbGx5LlxyXG4gICAqXHJcbiAgICogQHRvZG8gdHlwZSAnYW55JyBpbiBPYnNlcnZhYmxlIHNob3VsZCBiZWNvbWUgY3VzdG9tIHR5cGUgbGlrZSAnU2Nyb2xsVG9FdmVudCcgKGJhc2UgY2xhc3MpLCBzZWUgaXNzdWUgY29tbWVudDpcclxuICAgKiAgLSBodHRwczovL2dpdGh1Yi5jb20vbmlja3ktbGVuYWVycy9uZ3gtc2Nyb2xsLXRvL2lzc3Vlcy8xMCNpc3N1ZWNvbW1lbnQtMzE3MTk4NDgxXHJcbiAgICpcclxuICAgKiBAcGFyYW0gb3B0aW9ucyAgICAgICAgIENvbmZpZ3VyYXRpb24gT2JqZWN0XHJcbiAgICogQHJldHVybnMgICAgICAgICAgICAgICBPYnNlcnZhYmxlXHJcbiAgICovXHJcbiAgc2Nyb2xsVG8ob3B0aW9uczogU2Nyb2xsVG9Db25maWdPcHRpb25zKTogT2JzZXJ2YWJsZTxhbnk+IHtcclxuXHJcbiAgICBpZiAoIWlzUGxhdGZvcm1Ccm93c2VyKHRoaXMucGxhdGZvcm1JZCkpIHtcclxuICAgICAgcmV0dXJuIG5ldyBSZXBsYXlTdWJqZWN0KCkuYXNPYnNlcnZhYmxlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHRoaXMuc3RhcnQob3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTdGFydCBhIG5ldyBBbmltYXRpb24uXHJcbiAgICpcclxuICAgKiBAdG9kbyBFbWl0IHByb3BlciBldmVudHMgZnJvbSBzdWJzY3JpcHRpb25cclxuICAgKlxyXG4gICAqIEBwYXJhbSBvcHRpb25zICAgICAgICAgQ29uZmlndXJhdGlvbiBPYmplY3RcclxuICAgKiBAcmV0dXJucyAgICAgICAgICAgICAgIE9ic2VydmFibGVcclxuICAgKi9cclxuICBwcml2YXRlIHN0YXJ0KG9wdGlvbnM6IFNjcm9sbFRvQ29uZmlnT3B0aW9ucyk6IE9ic2VydmFibGU8bnVtYmVyPiB7XHJcblxyXG4gICAgLy8gTWVyZ2UgY29uZmlnIHdpdGggZGVmYXVsdCB2YWx1ZXNcclxuICAgIGNvbnN0IG1lcmdlZENvbmZpZ09wdGlvbnMgPSB7XHJcbiAgICAgIC4uLkRFRkFVTFRTIGFzIFNjcm9sbFRvQ29uZmlnT3B0aW9ucyxcclxuICAgICAgLi4ub3B0aW9uc1xyXG4gICAgfSBhcyBTY3JvbGxUb0NvbmZpZ09wdGlvbnNUYXJnZXQ7XHJcblxyXG4gICAgaWYgKHRoaXMuYW5pbWF0aW9uKSB7XHJcbiAgICAgIHRoaXMuYW5pbWF0aW9uLnN0b3AoKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB0YXJnZXROb2RlID0gdGhpcy5nZXROb2RlKG1lcmdlZENvbmZpZ09wdGlvbnMudGFyZ2V0KTtcclxuICAgIGlmIChtZXJnZWRDb25maWdPcHRpb25zLnRhcmdldCAmJiAhdGFyZ2V0Tm9kZSkge1xyXG4gICAgICByZXR1cm4gdGhyb3dFcnJvcigoKSA9PiBuZXcgRXJyb3IoJ1VuYWJsZSB0byBmaW5kIFRhcmdldCBFbGVtZW50JykpO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGNvbnRhaW5lcjogSFRNTEVsZW1lbnQgPSB0aGlzLmdldENvbnRhaW5lcihtZXJnZWRDb25maWdPcHRpb25zLCB0YXJnZXROb2RlKTtcclxuICAgIGlmIChtZXJnZWRDb25maWdPcHRpb25zLmNvbnRhaW5lciAmJiAhY29udGFpbmVyKSB7XHJcbiAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IG5ldyBFcnJvcignVW5hYmxlIHRvIGZpbmQgQ29udGFpbmVyIEVsZW1lbnQnKSk7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgbGlzdGVuZXJUYXJnZXQgPSB0aGlzLmdldExpc3RlbmVyVGFyZ2V0KGNvbnRhaW5lcikgfHwgd2luZG93O1xyXG5cclxuICAgIGxldCB0byA9IGNvbnRhaW5lciA/IGNvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS50b3AgOiAwO1xyXG5cclxuICAgIGlmICh0YXJnZXROb2RlKSB7XHJcbiAgICAgIHRvID0gaXNXaW5kb3cobGlzdGVuZXJUYXJnZXQpID9cclxuICAgICAgICB3aW5kb3cuc2Nyb2xsWSArIHRhcmdldE5vZGUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkudG9wIDpcclxuICAgICAgICB0YXJnZXROb2RlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDcmVhdGUgQW5pbWF0aW9uXHJcbiAgICB0aGlzLmFuaW1hdGlvbiA9IG5ldyBTY3JvbGxUb0FuaW1hdGlvbihcclxuICAgICAgY29udGFpbmVyLFxyXG4gICAgICBsaXN0ZW5lclRhcmdldCxcclxuICAgICAgaXNXaW5kb3cobGlzdGVuZXJUYXJnZXQpLFxyXG4gICAgICB0byxcclxuICAgICAgbWVyZ2VkQ29uZmlnT3B0aW9ucyxcclxuICAgICAgaXNQbGF0Zm9ybUJyb3dzZXIodGhpcy5wbGF0Zm9ybUlkKVxyXG4gICAgKTtcclxuICAgIGNvbnN0IG9uSW50ZXJydXB0ID0gKCkgPT4gdGhpcy5hbmltYXRpb24uc3RvcCgpO1xyXG4gICAgdGhpcy5hZGRJbnRlcnJ1cHRpdmVFdmVudExpc3RlbmVycyhsaXN0ZW5lclRhcmdldCwgb25JbnRlcnJ1cHQpO1xyXG5cclxuICAgIC8vIFN0YXJ0IEFuaW1hdGlvblxyXG4gICAgY29uc3QgYW5pbWF0aW9uJCA9IHRoaXMuYW5pbWF0aW9uLnN0YXJ0KCk7XHJcbiAgICB0aGlzLnN1YnNjcmliZVRvQW5pbWF0aW9uKGFuaW1hdGlvbiQsIGxpc3RlbmVyVGFyZ2V0LCBvbkludGVycnVwdCk7XHJcblxyXG4gICAgcmV0dXJuIGFuaW1hdGlvbiQ7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTdWJzY3JpYmUgdG8gdGhlIGV2ZW50cyBlbWl0dGVkIGZyb20gdGhlIFNjcm9sbGluZ1xyXG4gICAqIEFuaW1hdGlvbi4gRXZlbnRzIG1pZ2h0IGJlIHVzZWQgZm9yIGUuZy4gdW5zdWJzY3JpYmluZ1xyXG4gICAqIG9uY2UgZmluaXNoZWQuXHJcbiAgICpcclxuICAgKiBAcGFyYW0gYW5pbWF0aW9uJCAgICAgICAgICAgICAgVGhlIEFuaW1hdGlvbiBPYnNlcnZhYmxlXHJcbiAgICogQHBhcmFtIGxpc3RlbmVyVGFyZ2V0ICAgICAgICAgIFRoZSBMaXN0ZW5lciBUYXJnZXQgZm9yIGV2ZW50c1xyXG4gICAqIEBwYXJhbSBvbkludGVycnVwdCAgICAgICAgICAgICBUaGUgaGFuZGxlciBmb3IgSW50ZXJydXB0aXZlIEV2ZW50c1xyXG4gICAqIEByZXR1cm5zICAgICAgICAgICAgICAgICAgICAgICBWb2lkXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBzdWJzY3JpYmVUb0FuaW1hdGlvbihcclxuICAgIGFuaW1hdGlvbiQ6IE9ic2VydmFibGU8YW55PixcclxuICAgIGxpc3RlbmVyVGFyZ2V0OiBTY3JvbGxUb0xpc3RlbmVyVGFyZ2V0LFxyXG4gICAgb25JbnRlcnJ1cHQ6IEV2ZW50TGlzdGVuZXJPckV2ZW50TGlzdGVuZXJPYmplY3RcclxuICApIHtcclxuICAgIGNvbnN0IHN1YnNjcmlwdGlvbiA9IGFuaW1hdGlvbiRcclxuICAgICAgLnN1YnNjcmliZShcclxuICAgICAgICB7XHJcbiAgICAgICAgICBjb21wbGV0ZTogKCkgPT4ge1xyXG4gICAgICAgICAgICB0aGlzLnJlbW92ZUludGVycnVwdGl2ZUV2ZW50TGlzdGVuZXJzKHRoaXMuaW50ZXJydXB0aXZlRXZlbnRzLCBsaXN0ZW5lclRhcmdldCwgb25JbnRlcnJ1cHQpO1xyXG4gICAgICAgICAgICBzdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBHZXQgdGhlIGNvbnRhaW5lciBIVE1MIEVsZW1lbnQgaW4gd2hpY2hcclxuICAgKiB0aGUgc2Nyb2xsaW5nIHNob3VsZCBoYXBwZW4uXHJcbiAgICpcclxuICAgKiBAcGFyYW0gb3B0aW9ucyAgICAgICAgIFRoZSBNZXJnZWQgQ29uZmlndXJhdGlvbiBPYmplY3RcclxuICAgKiBAcGFyYW0gdGFyZ2V0Tm9kZSAgICB0aGUgdGFyZ2V0ZWQgSFRNTEVsZW1lbnRcclxuICAgKi9cclxuICBwcml2YXRlIGdldENvbnRhaW5lcihvcHRpb25zOiBTY3JvbGxUb0NvbmZpZ09wdGlvbnMsIHRhcmdldE5vZGU6IEhUTUxFbGVtZW50KTogSFRNTEVsZW1lbnQgfCBudWxsIHtcclxuXHJcbiAgICBsZXQgY29udGFpbmVyOiBIVE1MRWxlbWVudCB8IG51bGwgPSBudWxsO1xyXG5cclxuICAgIGlmIChvcHRpb25zLmNvbnRhaW5lcikge1xyXG4gICAgICBjb250YWluZXIgPSB0aGlzLmdldE5vZGUob3B0aW9ucy5jb250YWluZXIsIHRydWUpO1xyXG4gICAgfSBlbHNlIGlmICh0YXJnZXROb2RlKSB7XHJcbiAgICAgIGNvbnRhaW5lciA9IHRoaXMuZ2V0Rmlyc3RTY3JvbGxhYmxlUGFyZW50KHRhcmdldE5vZGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBjb250YWluZXI7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBBZGQgbGlzdGVuZXJzIGZvciB0aGUgQW5pbWF0aW9uIEludGVycnVwdGl2ZSBFdmVudHNcclxuICAgKiB0byB0aGUgTGlzdGVuZXIgVGFyZ2V0LlxyXG4gICAqXHJcbiAgICogQHBhcmFtIGV2ZW50cyAgICAgICAgICAgIExpc3Qgb2YgZXZlbnRzIHRvIGxpc3RlbiB0b1xyXG4gICAqIEBwYXJhbSBsaXN0ZW5lclRhcmdldCAgICBUYXJnZXQgdG8gYXR0YWNoIHRoZSBsaXN0ZW5lciBvblxyXG4gICAqIEBwYXJhbSBoYW5kbGVyICAgICAgICAgICBIYW5kbGVyIGZvciB3aGVuIHRoZSBsaXN0ZW5lciBmaXJlc1xyXG4gICAqIEByZXR1cm5zICAgICAgICAgICAgICAgICBWb2lkXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBhZGRJbnRlcnJ1cHRpdmVFdmVudExpc3RlbmVycyhcclxuICAgIGxpc3RlbmVyVGFyZ2V0OiBTY3JvbGxUb0xpc3RlbmVyVGFyZ2V0LFxyXG4gICAgaGFuZGxlcjogRXZlbnRMaXN0ZW5lck9yRXZlbnRMaXN0ZW5lck9iamVjdCk6IHZvaWQge1xyXG5cclxuICAgIGlmICghbGlzdGVuZXJUYXJnZXQpIHtcclxuICAgICAgbGlzdGVuZXJUYXJnZXQgPSB3aW5kb3c7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5pbnRlcnJ1cHRpdmVFdmVudHNcclxuICAgICAgLmZvckVhY2goZXZlbnQgPT4gbGlzdGVuZXJUYXJnZXRcclxuICAgICAgICAuYWRkRXZlbnRMaXN0ZW5lcihldmVudCwgaGFuZGxlciwgdGhpcy5zdXBwb3J0UGFzc2l2ZSgpID8ge3Bhc3NpdmU6IHRydWV9IDogZmFsc2UpKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEZlYXR1cmUtZGV0ZWN0IHN1cHBvcnQgZm9yIHBhc3NpdmUgZXZlbnQgbGlzdGVuZXJzLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMgICAgICAgV2hldGhlciBvciBub3QgcGFzc2l2ZSBldmVudCBsaXN0ZW5lcnMgYXJlIHN1cHBvcnRlZFxyXG4gICAqL1xyXG4gIHByaXZhdGUgc3VwcG9ydFBhc3NpdmUoKTogYm9vbGVhbiB7XHJcblxyXG4gICAgbGV0IHN1cHBvcnRzUGFzc2l2ZSA9IGZhbHNlO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIGNvbnN0IG9wdHMgPSBPYmplY3QuZGVmaW5lUHJvcGVydHkoe30sICdwYXNzaXZlJywge1xyXG4gICAgICAgIGdldDogKCkgPT4ge1xyXG4gICAgICAgICAgc3VwcG9ydHNQYXNzaXZlID0gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigndGVzdFBhc3NpdmUnLCBudWxsLCBvcHRzKTtcclxuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3Rlc3RQYXNzaXZlJywgbnVsbCwgb3B0cyk7XHJcbiAgICB9IGNhdGNoIChlKSB7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHN1cHBvcnRzUGFzc2l2ZTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlbW92ZSBsaXN0ZW5lcnMgZm9yIHRoZSBBbmltYXRpb24gSW50ZXJydXB0IEV2ZW50IGZyb21cclxuICAgKiB0aGUgTGlzdGVuZXIgVGFyZ2V0LiBTcGVjaWZ5aW5nIHRoZSBjb3JyZWN0IGhhbmRsZXIgcHJldmVudHNcclxuICAgKiBtZW1vcnkgbGVha3MgYW5kIG1ha2VzIHRoZSBhbGxvY2F0ZWQgbWVtb3J5IGF2YWlsYWJsZSBmb3JcclxuICAgKiBHYXJiYWdlIENvbGxlY3Rpb24uXHJcbiAgICpcclxuICAgKiBAcGFyYW0gZXZlbnRzICAgICAgICAgICAgTGlzdCBvZiBJbnRlcnJ1cHRpdmUgRXZlbnRzIHRvIHJlbW92ZVxyXG4gICAqIEBwYXJhbSBsaXN0ZW5lclRhcmdldCAgICBUYXJnZXQgdG8gYXR0YWNoIHRoZSBsaXN0ZW5lciBvblxyXG4gICAqIEBwYXJhbSBoYW5kbGVyICAgICAgICAgICBIYW5kbGVyIGZvciB3aGVuIHRoZSBsaXN0ZW5lciBmaXJlc1xyXG4gICAqIEByZXR1cm5zICAgICAgICAgICAgICAgICBWb2lkXHJcbiAgICovXHJcbiAgcHJpdmF0ZSByZW1vdmVJbnRlcnJ1cHRpdmVFdmVudExpc3RlbmVycyhcclxuICAgIGV2ZW50czogc3RyaW5nW10sXHJcbiAgICBsaXN0ZW5lclRhcmdldDogU2Nyb2xsVG9MaXN0ZW5lclRhcmdldCxcclxuICAgIGhhbmRsZXI6IEV2ZW50TGlzdGVuZXJPckV2ZW50TGlzdGVuZXJPYmplY3QpOiB2b2lkIHtcclxuXHJcbiAgICBpZiAoIWxpc3RlbmVyVGFyZ2V0KSB7XHJcbiAgICAgIGxpc3RlbmVyVGFyZ2V0ID0gd2luZG93O1xyXG4gICAgfVxyXG4gICAgZXZlbnRzLmZvckVhY2goZXZlbnQgPT4gbGlzdGVuZXJUYXJnZXQucmVtb3ZlRXZlbnRMaXN0ZW5lcihldmVudCwgaGFuZGxlcikpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRmluZCB0aGUgZmlyc3Qgc2Nyb2xsYWJsZSBwYXJlbnQgTm9kZSBvZiBhIGdpdmVuXHJcbiAgICogRWxlbWVudC4gVGhlIERPTSBUcmVlIGdldHMgc2VhcmNoZWQgdXB3YXJkc1xyXG4gICAqIHRvIGZpbmQgdGhpcyBmaXJzdCBzY3JvbGxhYmxlIHBhcmVudC4gUGFyZW50cyBtaWdodFxyXG4gICAqIGJlIGlnbm9yZWQgYnkgQ1NTIHN0eWxlcyBhcHBsaWVkIHRvIHRoZSBIVE1MIEVsZW1lbnQuXHJcbiAgICpcclxuICAgKiBAcGFyYW0gbmF0aXZlRWxlbWVudCAgICAgVGhlIEVsZW1lbnQgdG8gc2VhcmNoIHRoZSBET00gVHJlZSB1cHdhcmRzIGZyb21cclxuICAgKiBAcmV0dXJucyAgICAgICAgICAgICAgICAgVGhlIGZpcnN0IHNjcm9sbGFibGUgcGFyZW50IEhUTUwgRWxlbWVudFxyXG4gICAqL1xyXG4gIHByaXZhdGUgZ2V0Rmlyc3RTY3JvbGxhYmxlUGFyZW50KG5hdGl2ZUVsZW1lbnQ6IEhUTUxFbGVtZW50KTogSFRNTEVsZW1lbnQge1xyXG5cclxuICAgIGxldCBzdHlsZTogQ1NTU3R5bGVEZWNsYXJhdGlvbiA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKG5hdGl2ZUVsZW1lbnQpO1xyXG5cclxuICAgIGNvbnN0IG92ZXJmbG93UmVnZXg6IFJlZ0V4cCA9IC8oYXV0b3xzY3JvbGx8b3ZlcmxheSkvO1xyXG5cclxuICAgIGlmIChzdHlsZS5wb3NpdGlvbiA9PT0gJ2ZpeGVkJykge1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgcGFyZW50ID0gbmF0aXZlRWxlbWVudDtcclxuICAgIHdoaWxlIChwYXJlbnQucGFyZW50RWxlbWVudCkge1xyXG4gICAgICBwYXJlbnQgPSBwYXJlbnQucGFyZW50RWxlbWVudDtcclxuICAgICAgc3R5bGUgPSB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShwYXJlbnQpO1xyXG5cclxuICAgICAgaWYgKHN0eWxlLnBvc2l0aW9uID09PSAnYWJzb2x1dGUnXHJcbiAgICAgICAgfHwgc3R5bGUub3ZlcmZsb3cgPT09ICdoaWRkZW4nXHJcbiAgICAgICAgfHwgc3R5bGUub3ZlcmZsb3dZID09PSAnaGlkZGVuJykge1xyXG4gICAgICAgIGNvbnRpbnVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAob3ZlcmZsb3dSZWdleC50ZXN0KHN0eWxlLm92ZXJmbG93ICsgc3R5bGUub3ZlcmZsb3dZKVxyXG4gICAgICAgIHx8IHBhcmVudC50YWdOYW1lID09PSAnQk9EWScpIHtcclxuICAgICAgICByZXR1cm4gcGFyZW50O1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBHZXQgdGhlIFRhcmdldCBOb2RlIHRvIHNjcm9sbCB0by5cclxuICAgKlxyXG4gICAqIEBwYXJhbSBpZCAgICAgICAgICAgICAgVGhlIGdpdmVuIElEIG9mIHRoZSBub2RlLCBlaXRoZXIgYSBzdHJpbmcgb3JcclxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgIGFuIGVsZW1lbnQgcmVmZXJlbmNlXHJcbiAgICogQHBhcmFtIGFsbG93Qm9keVRhZyAgICBJbmRpY2F0ZSB3aGV0aGVyIG9yIG5vdCB0aGUgRG9jdW1lbnQgQm9keSBpc1xyXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgY29uc2lkZXJlZCBhIHZhbGlkIFRhcmdldCBOb2RlXHJcbiAgICogQHJldHVybnMgICAgICAgICAgICAgICBUaGUgVGFyZ2V0IE5vZGUgdG8gc2Nyb2xsIHRvXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBnZXROb2RlKGlkOiBTY3JvbGxUb1RhcmdldCwgYWxsb3dCb2R5VGFnOiBib29sZWFuID0gZmFsc2UpOiBIVE1MRWxlbWVudCB7XHJcblxyXG4gICAgbGV0IHRhcmdldE5vZGU6IEhUTUxFbGVtZW50O1xyXG5cclxuICAgIGlmIChpc1N0cmluZyhpZCkpIHtcclxuICAgICAgaWYgKGFsbG93Qm9keVRhZyAmJiAoaWQgPT09ICdib2R5JyB8fCBpZCA9PT0gJ0JPRFknKSkge1xyXG4gICAgICAgIHRhcmdldE5vZGUgPSB0aGlzLmRvY3VtZW50LmJvZHk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGFyZ2V0Tm9kZSA9IHRoaXMuZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoc3RyaXBIYXNoKGlkKSk7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSBpZiAoaXNOdW1iZXIoaWQpKSB7XHJcbiAgICAgIHRhcmdldE5vZGUgPSB0aGlzLmRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFN0cmluZyhpZCkpO1xyXG4gICAgfSBlbHNlIGlmIChpc0VsZW1lbnRSZWYoaWQpKSB7XHJcbiAgICAgIHRhcmdldE5vZGUgPSBpZC5uYXRpdmVFbGVtZW50O1xyXG4gICAgfSBlbHNlIGlmIChpc05hdGl2ZUVsZW1lbnQoaWQpKSB7XHJcbiAgICAgIHRhcmdldE5vZGUgPSBpZDtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdGFyZ2V0Tm9kZTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJldHJpZXZlIHRoZSBMaXN0ZW5lciB0YXJnZXQuIFRoaXMgTGlzdGVuZXIgVGFyZ2V0IGlzIHVzZWRcclxuICAgKiB0byBhdHRhY2ggRXZlbnQgTGlzdGVuZXJzIG9uLiBJbiBjYXNlIG9mIHRoZSB0YXJnZXQgYmVpbmdcclxuICAgKiB0aGUgRG9jdW1lbnQgQm9keSwgd2UgbmVlZCB0aGUgYWN0dWFsIGB3aW5kb3dgIHRvIGxpc3RlblxyXG4gICAqIGZvciBldmVudHMuXHJcbiAgICpcclxuICAgKiBAcGFyYW0gY29udGFpbmVyICAgICAgICAgICBUaGUgSFRNTCBDb250YWluZXIgZWxlbWVudFxyXG4gICAqIEByZXR1cm5zICAgICAgICAgICAgICAgICAgIFRoZSBMaXN0ZW5lciBUYXJnZXQgdG8gYXR0YWNoIGV2ZW50cyBvblxyXG4gICAqL1xyXG4gIHByaXZhdGUgZ2V0TGlzdGVuZXJUYXJnZXQoY29udGFpbmVyOiBIVE1MRWxlbWVudCk6IFNjcm9sbFRvTGlzdGVuZXJUYXJnZXQge1xyXG4gICAgaWYgKCFjb250YWluZXIpIHtcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcy5pc0RvY3VtZW50Qm9keShjb250YWluZXIpID8gd2luZG93IDogY29udGFpbmVyO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogVGVzdCBpZiBhIGdpdmVuIEhUTUwgRWxlbWVudCBpcyB0aGUgRG9jdW1lbnQgQm9keS5cclxuICAgKlxyXG4gICAqIEBwYXJhbSBlbGVtZW50ICAgICAgICAgICAgIFRoZSBnaXZlbiBIVE1MIEVsZW1lbnRcclxuICAgKiBAcmV0dXJucyAgICAgICAgICAgICAgICAgICBXaGV0aGVyIG9yIG5vdCB0aGUgRWxlbWVudCBpcyB0aGVcclxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICBEb2N1bWVudCBCb2R5IEVsZW1lbnRcclxuICAgKi9cclxuICBwcml2YXRlIGlzRG9jdW1lbnRCb2R5KGVsZW1lbnQ6IEhUTUxFbGVtZW50KTogZWxlbWVudCBpcyBIVE1MQm9keUVsZW1lbnQge1xyXG4gICAgcmV0dXJuIGVsZW1lbnQudGFnTmFtZS50b1VwcGVyQ2FzZSgpID09PSAnQk9EWSc7XHJcbiAgfVxyXG59XHJcbiJdfQ==