UNPKG

@wizdm/animate

Version:

On Scroll Animation for Angular

165 lines 28 kB
import { map, startWith, distinctUntilChanged, take, scan, switchMap, debounceTime, shareReplay } from 'rxjs/operators'; import { ANIMATE_CONFIG, animateConfigFactory } from './animate.config'; import { Injectable, NgZone, Inject, Optional } from '@angular/core'; import { ScrollDispatcher, ViewportRuler } from '@angular/cdk/scrolling'; import { Observable, BehaviorSubject, of } from 'rxjs'; import * as i0 from "@angular/core"; import * as i1 from "@angular/cdk/scrolling"; import * as i2 from "./animate.config"; export class AnimateService { constructor(scroll, viewPort, zone, config) { this.scroll = scroll; this.viewPort = viewPort; this.zone = zone; this.config = config; this.options$ = new BehaviorSubject({}); // Gets the module configuration this.config = animateConfigFactory(config); // Computes a common view observable to support the 'scrolling' triggering method this.view$ = this.options$.pipe( // Tracks for viewport changes giving it 100ms time to accurately update for orientation changes switchMap(options => viewPort.change(100).pipe( // Starts with a value startWith(null), // Gets the viewport map(() => { // Picks the ClientRect of the relevant container const rt = (options.root instanceof Element) ? options.root.getBoundingClientRect() : this.viewPort.getViewportRect(); // Combines the various options to build the final container const left = rt.left + (options.left || this.config.offsetLeft || 0); const top = rt.top + (options.top || this.config.offsetTop || 0); const right = rt.right + (options.right || this.config.offsetRight || 0); const bottom = rt.bottom + (options.bottom || this.config.offsetBottom || 0); // Returns the reultins client rect return { top, left, bottom, right, height: bottom - top, width: right - left }; }), // Debounces to aggregate fast changes (like during orientation changes) debounceTime(20))), // Makes all the component to share the same viewport values shareReplay(1)); } /** True when the trigger is provided using the IntersectionObserver API */ get useIntersectionObserver() { return this.config.triggerMode === 'intersectionObserver'; } /** True when the trigger is provided using cdk/scrolling package */ get useScrolling() { return this.config.triggerMode === 'scrolling'; } /** Applies the given options to the triggering service */ setup(options) { this.options$.next(options); } // Triggers the animation trigger(elm, threshold) { // Waits until the zone is stable once, aka the render is complete so the element to measure is there return source => this.zone.onStable.pipe( // Waits just once take(1), // Triggers the play and replay requests switchMap(() => source), // Triggers upon the most suitable method switchMap(trigger => // Simply return the sourced trigger when threshold is 0 (threshold <= 0) ? of(trigger) : ( // Check upon the configured method otherwise this.useIntersectionObserver ? // Triggers upon element intersection (IntersectionObserver API) this.intersecting(elm, threshold) : // Triggers upon cdk/scrolling this.scrolling(elm, threshold)))); } // Triggers the animation on intersection (using the IntersectionObserver API) intersecting(elm, threshold) { return this.options$.pipe( // Turns the options into a suitable configuration for the IntersectionObserver AnimateOptions map(options => { // Identifies an optional element to be used as the container const root = options.root || null; // Merges the margins from both the global config and the local options const top = options.top || this.config.offsetTop || 0; const right = options.right || this.config.offsetRight || 0; const bottom = options.bottom || this.config.offsetBottom || 0; const left = options.left || this.config.offsetLeft || 0; // Computes the rootMargin string acordingly const rootMargin = `${-top}px ${-right}px ${-bottom}px ${-left}px`; // Returns the proper initialization object return { root, rootMargin }; }), // Observes the element switchMap(options => this.observe(elm, threshold, options))); } /** Builds an Obsevable out of the IntersectionObserver API */ observe(elm, threshold, options) { return new Observable(subscriber => { // Creates a single entry observer const observer = new IntersectionObserver(entries => { // Monitors the only enry intesection ratio const ratio = entries[0].intersectionRatio; // Emits true whenever the intersection cross the threashold (making sure to run in the angular zone) if (ratio >= threshold) { this.zone.run(() => subscriber.next(true)); } // Emits false whenever the intersection cross back to full invisibility (making sure to run in the angular zone) if (ratio <= 0) { this.zone.run(() => subscriber.next(false)); } // Initializes the observer with the given parameters }, Object.assign(Object.assign({}, options), { threshold: [0, threshold] })); // Starts observing the target element observer.observe(elm.nativeElement); // Disconnects when unsubscribed return () => observer.disconnect(); }); } // Triggers the animation on scroll scrolling(elm, threshold) { // Returns an AOS observable using cdk/scrollilng return this.scroll.ancestorScrolled(elm, 0).pipe( // Makes sure triggering the start no matter there's no scroll event hits yet startWith(0), // Maps the scrolling to the element visibility value switchMap(() => this.visibility(elm)), // Applies an hysteresys, so, to trigger the animation on based on the treshold while off on full invisibility scan((result, visiblility) => (visiblility >= threshold) || (result && visiblility > 0), false), // Distincts the resulting triggers distinctUntilChanged(), // Runs within the angular zone to trigger change detection back on source => new Observable(subscriber => source.subscribe(value => this.zone.run(() => subscriber.next(value))))); } // Computes the element's visibility ratio against the container visibility(elm) { // Resolves from the latest viewport return this.view$.pipe(map(view => { // Gets the element's bounding rect const rect = elm && elm.nativeElement && elm.nativeElement.getBoundingClientRect(); if (!rect) { return 0; } // Return 1.0 when the element is fully within the viewport if (rect.left > view.left - 1 && rect.top > view.top - 1 && rect.right < view.right + 1 && rect.bottom < view.bottom + 1) { return 1; } // Computes the intersection area otherwise const a = Math.round(rect.width * rect.height); const b = Math.max(0, Math.min(rect.right, view.right) - Math.max(rect.left, view.left)); const c = Math.max(0, Math.min(rect.bottom, view.bottom) - Math.max(rect.top, view.top)); // Returns the amount of visible area return Math.round(b * c / a * 10) / 10; })); } } /** @nocollapse */ AnimateService.ɵprov = i0.ɵɵdefineInjectable({ factory: function AnimateService_Factory() { return new AnimateService(i0.ɵɵinject(i1.ScrollDispatcher), i0.ɵɵinject(i1.ViewportRuler), i0.ɵɵinject(i0.NgZone), i0.ɵɵinject(i2.ANIMATE_CONFIG, 8)); }, token: AnimateService, providedIn: "root" }); AnimateService.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] } ]; /** @nocollapse */ AnimateService.ctorParameters = () => [ { type: ScrollDispatcher }, { type: ViewportRuler }, { type: NgZone }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [ANIMATE_CONFIG,] }] } ]; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5pbWF0ZS5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vYW5pbWF0ZS9zcmMvbGliL2FuaW1hdGUuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxvQkFBb0IsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEgsT0FBTyxFQUFpQixjQUFjLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQUN0RixPQUFPLEVBQUUsVUFBVSxFQUFjLE1BQU0sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2pGLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxhQUFhLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN6RSxPQUFPLEVBQUUsVUFBVSxFQUFFLGVBQWUsRUFBRSxFQUFFLEVBQW9CLE1BQU0sTUFBTSxDQUFDOzs7O0FBZXpFLE1BQU0sT0FBTyxjQUFjO0lBb0J6QixZQUFvQixNQUF3QixFQUFVLFFBQXVCLEVBQVUsSUFBWSxFQUN2RCxNQUFzQjtRQUQ5QyxXQUFNLEdBQU4sTUFBTSxDQUFrQjtRQUFVLGFBQVEsR0FBUixRQUFRLENBQWU7UUFBVSxTQUFJLEdBQUosSUFBSSxDQUFRO1FBQ3ZELFdBQU0sR0FBTixNQUFNLENBQWdCO1FBbkIxRCxhQUFRLEdBQUcsSUFBSSxlQUFlLENBQWlCLEVBQUUsQ0FBQyxDQUFDO1FBcUJ6RCxnQ0FBZ0M7UUFDaEMsSUFBSSxDQUFDLE1BQU0sR0FBRyxvQkFBb0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUUzQyxrRkFBa0Y7UUFDbEYsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUk7UUFDN0Isa0dBQWtHO1FBQ2xHLFNBQVMsQ0FBRSxPQUFPLENBQUMsRUFB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QUFDLEtBQUssR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtnQkFDdkgsT0FBTyxDQUFDLENBQUM7YUFDVjtZQUVELDJDQUEyQztZQUMzQyxNQUFNLENBQUMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQy9DLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQ3pGLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBRXpGLHNDQUFzQztZQUN0QyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ3pDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDTixDQUFDOzs7O1lBcEtGLFVBQVUsU0FBQztnQkFDVixVQUFVLEVBQUUsTUFBTTthQUNuQjs7OztZQWZRLGdCQUFnQjtZQUFFLGFBQWE7WUFEUCxNQUFNOzRDQXNDcEMsUUFBUSxZQUFJLE1BQU0sU0FBQyxjQUFjIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgbWFwLCBzdGFydFdpdGgsIGRpc3RpbmN0VW50aWxDaGFuZ2VkLCB0YWtlLCBzY2FuLCBzd2l0Y2hNYXAsIGRlYm91bmNlVGltZSwgc2hhcmVSZXBsYXkgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBBbmltYXRlQ29uZmlnLCBBTklNQVRFX0NPTkZJRywgYW5pbWF0ZUNvbmZpZ0ZhY3RvcnkgfSBmcm9tICcuL2FuaW1hdGUuY29uZmlnJ1xuaW1wb3J0IHsgSW5qZWN0YWJsZSwgRWxlbWVudFJlZiwgTmdab25lLCBJbmplY3QsIE9wdGlvbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBTY3JvbGxEaXNwYXRjaGVyLCBWaWV3cG9ydFJ1bGVyIH0gZnJvbSAnQGFuZ3VsYXIvY2RrL3Njcm9sbGluZyc7XG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBCZWhhdmlvclN1YmplY3QsIG9mLCBPcGVyYXRvckZ1bmN0aW9uIH0gZnJvbSAncnhqcyc7XG5cbi8qKiBDb25maWd1cmVzIGFsdGVybmF0aXZlIGNvbnRhaW5lcnMgZm9yIEFPUyB0cmlnZ2VyaW5nICovXG5leHBvcnQgaW50ZXJmYWNlIEFuaW1hdGVPcHRpb25zIHtcbiAgXG4gIHJvb3Q/OiBFbGVtZW50O1xuICBsZWZ0PzogbnVtYmVyO1xuICB0b3A/OiBudW1iZXI7XG4gIHJpZ2h0PzogbnVtYmVyO1xuICBib3R0b20/OiBudW1iZXI7XG59XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIEFuaW1hdGVTZXJ2aWNlIHtcblxuICBwcml2YXRlIG9wdGlvbnMkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxBbmltYXRlT3B0aW9ucz4oe30pO1xuICBwcml2YXRlIHZpZXckOiBPYnNlcnZhYmxlPENsaWVudFJlY3Q+O1xuXG4gIC8qKiBUcnVlIHdoZW4gdGhlIHRyaWdnZXIgaXMgcHJvdmlkZWQgdXNpbmcgdGhlIEludGVyc2VjdGlvbk9ic2VydmVyIEFQSSAqL1xuICBwdWJsaWMgZ2V0IHVzZUludGVyc2VjdGlvbk9ic2VydmVyKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmNvbmZpZy50cmlnZ2VyTW9kZSA9PT0gJ2ludGVyc2VjdGlvbk9ic2VydmVyJztcbiAgfVxuXG4gIC8qKiBUcnVlIHdoZW4gdGhlIHRyaWdnZXIgaXMgcHJvdmlkZWQgdXNpbmcgY2RrL3Njcm9sbGluZyBwYWNrYWdlICovXG4gIHB1YmxpYyBnZXQgdXNlU2Nyb2xsaW5nKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmNvbmZpZy50cmlnZ2VyTW9kZSA9PT0gJ3Njcm9sbGluZyc7XG4gIH1cblxuICAvKiogQXBwbGllcyB0aGUgZ2l2ZW4gb3B0aW9ucyB0byB0aGUgdHJpZ2dlcmluZyBzZXJ2aWNlICovXG4gIHB1YmxpYyBzZXR1cChvcHRpb25zOiBBbmltYXRlT3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyQubmV4dChvcHRpb25zKTtcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgc2Nyb2xsOiBTY3JvbGxEaXNwYXRjaGVyLCBwcml2YXRlIHZpZXdQb3J0OiBWaWV3cG9ydFJ1bGVyLCBwcml2YXRlIHpvbmU6IE5nWm9uZSxcbiAgQE9wdGlvbmFsKCkgQEluamVjdChBTklNQVRFX0NPTkZJRykgcHJpdmF0ZSBjb25maWc/OiBBbmltYXRlQ29uZmlnKSB7XG5cbiAgICAvLyBHZXRzIHRoZSBtb2R1bGUgY29uZmlndXJhdGlvblxuICAgIHRoaXMuY29uZmlnID0gYW5pbWF0ZUNvbmZpZ0ZhY3RvcnkoY29uZmlnKTtcblxuICAgIC8vIENvbXB1dGVzIGEgY29tbW9uIHZpZXcgb2JzZXJ2YWJsZSB0byBzdXBwb3J0IHRoZSAnc2Nyb2xsaW5nJyB0cmlnZ2VyaW5nIG1ldGhvZCBcbiAgICB0aGlzLnZpZXckID0gdGhpcy5vcHRpb25zJC5waXBlKCBcbiAgICAgIC8vIFRyYWNrcyBmb3Igdmlld3BvcnQgY2hhbmdlcyBnaXZpbmcgaXQgMTAwbXMgdGltZSB0byBhY2N1cmF0ZWx5IHVwZGF0ZSBmb3Igb3JpZW50YXRpb24gY2hhbmdlcyAgXG4gICAgICBzd2l0Y2hNYXAoIG9wdGlvbnMgPT4gdmlld1BvcnQuY2hhbmdlKDEwMCkucGlwZSggXG4gICAgICAgIC8vIFN0YXJ0cyB3aXRoIGEgdmFsdWVcbiAgICAgICAgc3RhcnRXaXRoKCBudWxsICksIFxuICAgICAgICAvLyBHZXRzIHRoZSB2aWV3cG9ydFxuICAgICAgICBtYXAoICgpID0+IHtcbiAgICAgICAgICAvLyBQaWNrcyB0aGUgQ2xpZW50UmVjdCBvZiB0aGUgcmVsZXZhbnQgY29udGFpbmVyIFxuICAgICAgICAgIGNvbnN0IHJ0ID0gKG9wdGlvbnMucm9vdCBpbnN0YW5jZW9mIEVsZW1lbnQpID8gb3B0aW9ucy5yb290LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpIDogdGhpcy52aWV3UG9ydC5nZXRWaWV3cG9ydFJlY3QoKTsgXG4gICAgICAgICAgLy8gQ29tYmluZXMgdGhlIHZhcmlvdXMgb3B0aW9ucyB0byBidWlsZCB0aGUgZmluYWwgY29udGFpbmVyXG4gICAgICAgICAgY29uc3QgbGVmdCA9IHJ0LmxlZnQgKyAob3B0aW9ucy5sZWZ0IHx8IHRoaXMuY29uZmlnLm9mZnNldExlZnQgfHwgMCk7XG4gICAgICAgICAgY29uc3QgdG9wID0gcnQudG9wICsgKG9wdGlvbnMudG9wIHx8IHRoaXMuY29uZmlnLm9mZnNldFRvcCB8fCAwKTtcbiAgICAgICAgICBjb25zdCByaWdodCA9IHJ0LnJpZ2h0ICsgKG9wdGlvbnMucmlnaHQgfHwgdGhpcy5jb25maWcub2Zmc2V0UmlnaHQgfHwgMCk7XG4gICAgICAgICAgY29uc3QgYm90dG9tID0gcnQuYm90dG9tICsgKG9wdGlvbnMuYm90dG9tIHx8IHRoaXMuY29uZmlnLm9mZnNldEJvdHRvbSB8fCAwKTtcbiAgICAgICAgICAvLyBSZXR1cm5zIHRoZSByZXVsdGlucyBjbGllbnQgcmVjdCBcbiAgICAgICAgICByZXR1cm4geyB0b3AsIGxlZnQsIGJvdHRvbSwgcmlnaHQsIGhlaWdodDogYm90dG9tIC0gdG9wLCB3aWR0aDogcmlnaHQgLSBsZWZ0IH07XG4gICAgICAgIH0pLFxuICAgICAgICAvLyBEZWJvdW5jZXMgdG8gYWdncmVnYXRlIGZhc3QgY2hhbmdlcyAobGlrZSBkdXJpbmcgb3JpZW50YXRpb24gY2hhbmdlcylcbiAgICAgICAgZGVib3VuY2VUaW1lKDIwKSwgXG4gICAgICApKSxcbiAgICAgIC8vIE1ha2VzIGFsbCB0aGUgY29tcG9uZW50IHRvIHNoYXJlIHRoZSBzYW1lIHZpZXdwb3J0IHZhbHVlc1xuICAgICAgc2hhcmVSZXBsYXkoMSlcbiAgICApO1xuICB9XG5cbiAgLy8gVHJpZ2dlcnMgdGhlIGFuaW1hdGlvblxuICBwdWJsaWMgdHJpZ2dlcihlbG06IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+LCB0aHJlc2hvbGQ6IG51bWJlcik6IE9wZXJhdG9yRnVuY3Rpb248Ym9vbGVhbiwgYm9vbGVhbj4ge1xuXG4gICAgLy8gV2FpdHMgdW50aWwgdGhlIHpvbmUgaXMgc3RhYmxlIG9uY2UsIGFrYSB0aGUgcmVuZGVyIGlzIGNvbXBsZXRlIHNvIHRoZSBlbGVtZW50IHRvIG1lYXN1cmUgaXMgdGhlcmUgXG4gICAgcmV0dXJuIHNvdXJjZSA9PiB0aGlzLnpvbmUub25TdGFibGUucGlwZSggXG4gICAgICAvLyBXYWl0cyBqdXN0IG9uY2VcbiAgICAgIHRha2UoMSksXG4gICAgICAvLyBUcmlnZ2VycyB0aGUgcGxheSBhbmQgcmVwbGF5IHJlcXVlc3RzXG4gICAgICBzd2l0Y2hNYXAoICgpID0+IHNvdXJjZSApLFxuICAgICAgLy8gVHJpZ2dlcnMgdXBvbiB0aGUgbW9zdCBzdWl0YWJsZSBtZXRob2RcbiAgICAgIHN3aXRjaE1hcCggdHJpZ2dlciA9PiBcbiAgICAgICAgLy8gU2ltcGx5IHJldHVybiB0aGUgc291cmNlZCB0cmlnZ2VyIHdoZW4gdGhyZXNob2xkIGlzIDBcbiAgICAgICAgKHRocmVzaG9sZCA8PSAwKSA/IG9mKHRyaWdnZXIpIDogKFxuICAgICAgICAgIC8vIENoZWNrIHVwb24gdGhlIGNvbmZpZ3VyZWQgbWV0aG9kIG90aGVyd2lzZVxuICAgICAgICAgIHRoaXMudXNlSW50ZXJzZWN0aW9uT2JzZXJ2ZXIgPyBcbiAgICAgICAgICAvLyBUcmlnZ2VycyB1cG9uIGVsZW1lbnQgaW50ZXJzZWN0aW9uIChJbnRlcnNlY3Rpb25PYnNlcnZlciBBUEkpXG4gICAgICAgICAgdGhpcy5pbnRlcnNlY3RpbmcoZWxtLCB0aHJlc2hvbGQpIDogXG4gICAgICAgICAgLy8gVHJpZ2dlcnMgdXBvbiBjZGsvc2Nyb2xsaW5nXG4gICAgICAgICAgdGhpcy5zY3JvbGxpbmcoZWxtICx0aHJlc2hvbGQpXG4gICAgICAgIClcbiAgICAgIClcbiAgICApO1xuICB9XG5cbiAgLy8gVHJpZ2dlcnMgdGhlIGFuaW1hdGlvbiBvbiBpbnRlcnNlY3Rpb24gKHVzaW5nIHRoZSBJbnRlcnNlY3Rpb25PYnNlcnZlciBBUEkpXG4gIHByaXZhdGUgaW50ZXJzZWN0aW5nKGVsbTogRWxlbWVudFJlZjxIVE1MRWxlbWVudD4sIHRocmVzaG9sZDogbnVtYmVyKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG5cbiAgICByZXR1cm4gdGhpcy5vcHRpb25zJC5waXBlKFxuICAgICAgLy8gVHVybnMgdGhlIG9wdGlvbnMgaW50byBhIHN1aXRhYmxlIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBJbnRlcnNlY3Rpb25PYnNlcnZlciBBbmltYXRlT3B0aW9uc1xuICAgICAgbWFwKCBvcHRpb25zID0+IHtcbiAgICAgICAgLy8gSWRlbnRpZmllcyBhbiBvcHRpb25hbCBlbGVtZW50IHRvIGJlIHVzZWQgYXMgdGhlIGNvbnRhaW5lclxuICAgICAgICBjb25zdCByb290ID0gb3B0aW9ucy5yb290IHx8IG51bGw7XG4gICAgICAgIC8vIE1lcmdlcyB0aGUgbWFyZ2lucyBmcm9tIGJvdGggdGhlIGdsb2JhbCBjb25maWcgYW5kIHRoZSBsb2NhbCBvcHRpb25zIFxuICAgICAgICBjb25zdCB0b3AgPSBvcHRpb25zLnRvcCB8fCB0aGlzLmNvbmZpZy5vZmZzZXRUb3AgfHwgMDtcbiAgICAgICAgY29uc3QgcmlnaHQgPSBvcHRpb25zLnJpZ2h0IHx8IHRoaXMuY29uZmlnLm9mZnNldFJpZ2h0IHx8IDA7XG4gICAgICAgIGNvbnN0IGJvdHRvbSA9IG9wdGlvbnMuYm90dG9tIHx8IHRoaXMuY29uZmlnLm9mZnNldEJvdHRvbSB8fCAwO1xuICAgICAgICBjb25zdCBsZWZ0ID0gb3B0aW9ucy5sZWZ0IHx8IHRoaXMuY29uZmlnLm9mZnNldExlZnQgfHwgMDtcbiAgICAgICAgLy8gQ29tcHV0ZXMgdGhlIHJvb3RNYXJnaW4gc3RyaW5nIGFjb3JkaW5nbHlcbiAgICAgICAgY29uc3Qgcm9vdE1hcmdpbiA9IGAkey10b3B9cHggJHstcmlnaHR9cHggJHstYm90dG9tfXB4ICR7LWxlZnR9cHhgO1xuICAgICAgICAvLyBSZXR1cm5zIHRoZSBwcm9wZXIgaW5pdGlhbGl6YXRpb24gb2JqZWN0XG4gICAgICAgIHJldHVybiB7IHJvb3QsIHJvb3RNYXJnaW4gfSBhcyBJbnRlcnNlY3Rpb25PYnNlcnZlckluaXQ7XG4gICAgICB9KSxcbiAgICAgIC8vIE9ic2VydmVzIHRoZSBlbGVtZW50XG4gICAgICBzd2l0Y2hNYXAoIG9wdGlvbnMgPT4gdGhpcy5vYnNlcnZlKGVsbSwgdGhyZXNob2xkLCBvcHRpb25zKSApXG4gICAgKTtcbiAgfVxuXG4gIC8qKiBCdWlsZHMgYW4gT2JzZXZhYmxlIG91dCBvZiB0aGUgSW50ZXJzZWN0aW9uT2JzZXJ2ZXIgQVBJICovXG4gIHByaXZhdGUgb2JzZXJ2ZShlbG06IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+LCB0aHJlc2hvbGQ6IG51bWJlciwgb3B0aW9uczogSW50ZXJzZWN0aW9uT2JzZXJ2ZXJJbml0KTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG5cbiAgICByZXR1cm4gbmV3IE9ic2VydmFibGU8Ym9vbGVhbj4oIHN1YnNjcmliZXIgPT4ge1xuICAgICAgLy8gQ3JlYXRlcyBhIHNpbmdsZSBlbnRyeSBvYnNlcnZlclxuICAgICAgY29uc3Qgb2JzZXJ2ZXIgPSBuZXcgSW50ZXJzZWN0aW9uT2JzZXJ2ZXIoIGVudHJpZXMgPT4ge1xuICAgICAgICAvLyBNb25pdG9ycyB0aGUgb25seSBlbnJ5IGludGVzZWN0aW9uIHJhdGlvIFxuICAgICAgICBjb25zdCByYXRpbyA9IGVudHJpZXNbMF0uaW50ZXJzZWN0aW9uUmF0aW87XG4gICAgICAgIC8vIEVtaXRzIHRydWUgd2hlbmV2ZXIgdGhlIGludGVyc2VjdGlvbiBjcm9zcyB0aGUgdGhyZWFzaG9sZCAobWFraW5nIHN1cmUgdG8gcnVuIGluIHRoZSBhbmd1bGFyIHpvbmUpXG4gICAgICAgIGlmKHJhdGlvID49IHRocmVzaG9sZCkgeyB0aGlzLnpvbmUucnVuKCAoKSA9PiBzdWJzY3JpYmVyLm5leHQodHJ1ZSkgKTsgfVxuICAgICAgICAvLyBFbWl0cyBmYWxzZSB3aGVuZXZlciB0aGUgaW50ZXJzZWN0aW9uIGNyb3NzIGJhY2sgdG8gZnVsbCBpbnZpc2liaWxpdHkgKG1ha2luZyBzdXJlIHRvIHJ1biBpbiB0aGUgYW5ndWxhciB6b25lKVxuICAgICAgICBpZihyYXRpbyA8PSAwKSB7IHRoaXMuem9uZS5ydW4oICgpID0+IHN1YnNjcmliZXIubmV4dChmYWxzZSkgKTsgfVxuICAgICAgLy8gSW5pdGlhbGl6ZXMgdGhlIG9ic2VydmVyIHdpdGggdGhlIGdpdmVuIHBhcmFtZXRlcnNcbiAgICAgIH0sIHsgLi4ub3B0aW9ucywgdGhyZXNob2xkOiBbIDAsIHRocmVzaG9sZCBdIH0pO1xuXG4gICAgICAvLyBTdGFydHMgb2JzZXJ2aW5nIHRoZSB0YXJnZXQgZWxlbWVudCBcbiAgICAgIG9ic2VydmVyLm9ic2VydmUoZWxtLm5hdGl2ZUVsZW1lbnQpO1xuICAgICAgLy8gRGlzY29ubmVjdHMgd2hlbiB1bnN1YnNjcmliZWRcbiAgICAgIHJldHVybiAoKSA9PiBvYnNlcnZlci5kaXNjb25uZWN0KCk7XG4gICAgfSk7XG4gIH1cblxuICAvLyBUcmlnZ2VycyB0aGUgYW5pbWF0aW9uIG9uIHNjcm9sbFxuICBwcml2YXRlIHNjcm9sbGluZyhlbG06IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+LCB0aHJlc2hvbGQ6IG51bWJlcik6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgIC8vIFJldHVybnMgYW4gQU9TIG9ic2VydmFibGUgdXNpbmcgY2RrL3Njcm9sbGlsbmdcbiAgICByZXR1cm4gdGhpcy5zY3JvbGwuYW5jZXN0b3JTY3JvbGxlZChlbG0sIDApLnBpcGUoXG4gICAgICAvLyBNYWtlcyBzdXJlIHRyaWdnZXJpbmcgdGhlIHN0YXJ0IG5vIG1hdHRlciB0aGVyZSdzIG5vIHNjcm9sbCBldmVudCBoaXRzIHlldFxuICAgICAgc3RhcnRXaXRoKDApLFxuICAgICAgLy8gTWFwcyB0aGUgc2Nyb2xsaW5nIHRvIHRoZSBlbGVtZW50IHZpc2liaWxpdHkgdmFsdWVcbiAgICAgIHN3aXRjaE1hcCggKCkgPT4gdGhpcy52aXNpYmlsaXR5KGVsbSkgKSxcbiAgICAgIC8vIEFwcGxpZXMgYW4gaHlzdGVyZXN5cywgc28sIHRvIHRyaWdnZXIgdGhlIGFuaW1hdGlvbiBvbiBiYXNlZCBvbiB0aGUgdHJlc2hvbGQgd2hpbGUgb2ZmIG9uIGZ1bGwgaW52aXNpYmlsaXR5XG4gICAgICBzY2FuKChyZXN1bHQsIHZpc2libGlsaXR5KSA9PiAodmlzaWJsaWxpdHkgPj0gdGhyZXNob2xkKSB8fCAocmVzdWx0ICYmIHZpc2libGlsaXR5ID4gMCksIGZhbHNlKSxcbiAgICAgIC8vIERpc3RpbmN0cyB0aGUgcmVzdWx0aW5nIHRyaWdnZXJzIFxuICAgICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKSxcbiAgICAgIC8vIFJ1bnMgd2l0aGluIHRoZSBhbmd1bGFyIHpvbmUgdG8gdHJpZ2dlciBjaGFuZ2UgZGV0ZWN0aW9uIGJhY2sgb25cbiAgICAgIHNvdXJjZSA9PiBuZXcgT2JzZXJ2YWJsZSggc3Vic2NyaWJlciA9PiBzb3VyY2Uuc3Vic2NyaWJlKCB2YWx1ZSA9PiB0aGlzLnpvbmUucnVuKCAoKSA9PiBzdWJzY3JpYmVyLm5leHQodmFsdWUpICkgKSApXG4gICAgKTtcbiAgfVxuXG4gIC8vIENvbXB1dGVzIHRoZSBlbGVtZW50J3MgdmlzaWJpbGl0eSByYXRpbyBhZ2FpbnN0IHRoZSBjb250YWluZXJcbiAgcHJpdmF0ZSB2aXNpYmlsaXR5KGVsbTogRWxlbWVudFJlZjxIVE1MRWxlbWVudD4pOiBPYnNlcnZhYmxlPG51bWJlcj4ge1xuXG4gICAgLy8gUmVzb2x2ZXMgZnJvbSB0aGUgbGF0ZXN0IHZpZXdwb3J0XG4gICAgcmV0dXJuIHRoaXMudmlldyQucGlwZSggbWFwKCB2aWV3ID0+IHtcblxuICAgICAgLy8gR2V0cyB0aGUgZWxlbWVudCdzIGJvdW5kaW5nIHJlY3RcbiAgICAgIGNvbnN0IHJlY3QgPSBlbG0gJiYgZWxtLm5hdGl2ZUVsZW1lbnQgJiYgZWxtLm5hdGl2ZUVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICBpZighcmVjdCkgeyByZXR1cm4gMDsgfVxuXG4gICAgICAvLyBSZXR1cm4gMS4wIHdoZW4gdGhlIGVsZW1lbnQgaXMgZnVsbHkgd2l0aGluIHRoZSB2aWV3cG9ydFxuICAgICAgaWYocmVjdC5sZWZ0ID4gdmlldy5sZWZ0IC0gMSAmJiByZWN0LnRvcCA+IHZpZXcudG9wIC0gMSAmJiByZWN0LnJpZ2h0IDwgdmlldy5yaWdodCArIDEgJiYgcmVjdC5ib3R0b20gPCB2aWV3LmJvdHRvbSArIDEpIHsgXG4gICAgICAgIHJldHVybiAxOyBcbiAgICAgIH1cblxuICAgICAgLy8gQ29tcHV0ZXMgdGhlIGludGVyc2VjdGlvbiBhcmVhIG90aGVyd2lzZVxuICAgICAgY29uc3QgYSA9IE1hdGgucm91bmQocmVjdC53aWR0aCAqIHJlY3QuaGVpZ2h0KTtcbiAgICAgIGNvbnN0IGIgPSBNYXRoLm1heCgwLCBNYXRoLm1pbihyZWN0LnJpZ2h0LCB2aWV3LnJpZ2h0KSAtIE1hdGgubWF4KHJlY3QubGVmdCwgdmlldy5sZWZ0KSk7XG4gICAgICBjb25zdCBjID0gTWF0aC5tYXgoMCwgTWF0aC5taW4ocmVjdC5ib3R0b20sIHZpZXcuYm90dG9tKSAtIE1hdGgubWF4KHJlY3QudG9wLCB2aWV3LnRvcCkpO1xuXG4gICAgICAvLyBSZXR1cm5zIHRoZSBhbW91bnQgb2YgdmlzaWJsZSBhcmVhIFxuICAgICAgcmV0dXJuIE1hdGgucm91bmQoYiAqIGMgLyBhICogMTApIC8gMTA7XG4gICAgfSkpO1xuICB9XG59Il19