@wizdm/animate
Version:
On Scroll Animation for Angular
165 lines • 28 kB
JavaScript
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