ngx-parallax-scroll
Version:
This is a simple angular plugin, that allows us to implement parallax effect for some element in page
320 lines • 27.5 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { Directive, ElementRef, Renderer2, Input, Inject, PLATFORM_ID } from '@angular/core';
import { isDevMode } from '@angular/core';
import { isPlatformServer } from '@angular/common';
import { fromEvent } from 'rxjs';
import { throttleTime } from 'rxjs/operators';
export class ParallaxScrollDirective {
/**
* @param {?} elem
* @param {?} renderer
* @param {?} platformId
*/
constructor(elem, renderer, platformId) {
this.elem = elem;
this.renderer = renderer;
this.platformId = platformId;
this._parallaxTimingFunVal = 'linear';
this._parallaxThrottleTime = 0;
this.directiveName = this.constructor.name;
}
/**
* @return {?}
*/
ngOnInit() {
if (isPlatformServer(this.platformId))
return;
// Initing parallax effect and setting element styles
this.initParallax();
this.setParallaxElTransform();
this.setParallaxTransition();
}
/**
* @param {?} changes
* @return {?}
*/
ngOnChanges(changes) {
// Setting parallax options from config object or input props
/** @type {?} */
const prlxSpeed = (changes['parallaxSpeed'] && changes['parallaxSpeed'].currentValue) ||
(changes['config'] && changes['config'].currentValue.parallaxSpeed);
/** @type {?} */
const prlxSmoothness = (changes['parallaxSmoothness'] && changes['parallaxSmoothness'].currentValue) ||
(changes['config'] && changes['config'].currentValue.parallaxSmoothness);
/** @type {?} */
const prlxDirection = (changes['parallaxDirection'] && changes['parallaxDirection'].currentValue) ||
(changes['config'] && changes['config'].currentValue.parallaxDirection);
/** @type {?} */
const prlxTimingFunction = (changes['parallaxTimingFunction'] && changes['parallaxTimingFunction'].currentValue) ||
(changes['config'] && changes['config'].currentValue.parallaxTimingFunction);
/** @type {?} */
const prlxThrottleTime = (changes['parallaxThrottleTime'] && changes['parallaxThrottleTime'].currentValue) ||
(changes['config'] && changes['config'].currentValue.parallaxThrottleTime);
this.setParallaxSpeed(prlxSpeed);
this.setParallaxSmoothness(prlxSmoothness);
this.setParallaxDirection(prlxDirection);
this.setParallaxTimingFun(prlxTimingFunction);
this.setParallaxThrottleTime(prlxThrottleTime);
}
/**
* @return {?}
*/
ngAfterViewInit() { }
/**
* @return {?}
*/
ngOnDestroy() {
this.scrollSubscribtion && this.scrollSubscribtion.unsubscribe();
}
// Setting parallax effect and setting element styles
/**
* @return {?}
*/
initParallax() {
this.scrollSubscribtion = fromEvent(window, 'scroll')
.pipe(throttleTime(this.prlxThrottleTime))
.subscribe((/**
* @return {?}
*/
() => {
this.setParallaxElTransform();
}));
}
// Setting parallax speed effect styles
/**
* @return {?}
*/
setParallaxElTransform() {
/** @type {?} */
let scrolled = window.pageYOffset;
this.renderer.setStyle(this.elem.nativeElement, 'transform', `translateY(${scrolled * this.prlxSpeed}px) translateZ(0)`);
}
// Setting parallax smooth effect styles, based on CSS animation-timing-function
/**
* @return {?}
*/
setParallaxTransition() {
this.renderer.setStyle(this.elem.nativeElement, 'transition', `transform ${this.prlxSmoothness}s ${this.prlxTimingFun}`);
}
// Setting parallax properties
/**
* @param {?} speedVal
* @return {?}
*/
setParallaxSpeed(speedVal) {
/** @type {?} */
const propName = 'parallaxSpeed';
this.validateParallaxSpeed(speedVal, propName, 'number') && (this._parallaxSpeedVal = speedVal);
}
/**
* @param {?} smoothnessVal
* @return {?}
*/
setParallaxSmoothness(smoothnessVal) {
/** @type {?} */
const propName = 'parallaxSmoothness';
this.validateParallaxSmoothness(smoothnessVal, propName, 'number') &&
(this._parallaxSmoothnessVal = smoothnessVal);
}
/**
* @param {?} directionVal
* @return {?}
*/
setParallaxDirection(directionVal) {
/** @type {?} */
const propName = 'parallaxDirection';
directionVal &&
this.isTypeOf(directionVal, 'string', propName) &&
directionVal === 'reverse' &&
(this._parallaxSpeedVal *= -1);
}
/**
* @param {?} timingFun
* @return {?}
*/
setParallaxTimingFun(timingFun) {
/** @type {?} */
const propName = 'parallaxTimingFunction';
timingFun &&
this.isTypeOf(timingFun, 'string', propName) &&
(this._parallaxTimingFunVal = timingFun);
}
/**
* @param {?} throttleTime
* @return {?}
*/
setParallaxThrottleTime(throttleTime) {
/** @type {?} */
const propName = 'parallaxThrottleTime';
throttleTime &&
this.isTypeOf(throttleTime, 'number', propName) &&
(this._parallaxThrottleTime = throttleTime);
}
// Getters for parallax options
/**
* @return {?}
*/
get prlxSpeed() {
return this._parallaxSpeedVal;
}
/**
* @return {?}
*/
get prlxSmoothness() {
return this._parallaxSmoothnessVal;
}
/**
* @return {?}
*/
get prlxTimingFun() {
return this._parallaxTimingFunVal;
}
/**
* @return {?}
*/
get prlxThrottleTime() {
return this._parallaxThrottleTime;
}
// Validation functions
/**
* @param {?} value
* @param {?} propName
* @return {?}
*/
isProvided(value, propName) {
/** @type {?} */
const isNotProvided = value == null || value === '';
if (isNotProvided && isDevMode()) {
throw new Error(`${this.directiveName}: [${propName}] is required, but was not provided`);
}
return true;
}
/**
* @param {?} value
* @param {?} requiredType
* @param {?} propName
* @return {?}
*/
isTypeOf(value, requiredType, propName) {
/** @type {?} */
const isRequiredType = typeof value === requiredType;
if (!isRequiredType && isDevMode()) {
throw new Error(`${this.directiveName}: [${propName}] is expected to be of type '${requiredType}', but type '${typeof value}' was provided`);
}
return true;
}
/**
* @param {?} value
* @param {?} propName
* @return {?}
*/
isPositive(value, propName) {
/** @type {?} */
const isRequiredType = typeof value === 'number';
/** @type {?} */
const isValid = value >= 0;
if (isRequiredType && !isValid && isDevMode()) {
throw new Error(`${this.directiveName}: [${propName}] is expected to be positive value, but negative '${value}' value was provided`);
}
return true;
}
// Executing validation functions to validate parallax speed
/**
* @param {?} value
* @param {?} propName
* @param {?} requiredType
* @return {?}
*/
validateParallaxSpeed(value, propName, requiredType) {
return (this.isProvided(value, propName) &&
this.isTypeOf(value, requiredType, propName) &&
this.isPositive(value, propName));
}
// Executing validation functions to validate parallax smoothness
/**
* @param {?} value
* @param {?} propName
* @param {?} requiredType
* @return {?}
*/
validateParallaxSmoothness(value, propName, requiredType) {
return (this.isProvided(value, propName) &&
this.isTypeOf(value, requiredType, propName) &&
this.isPositive(value, propName));
}
}
ParallaxScrollDirective.decorators = [
{ type: Directive, args: [{
selector: '[ngxParallaxScroll]'
},] }
];
/** @nocollapse */
ParallaxScrollDirective.ctorParameters = () => [
{ type: ElementRef },
{ type: Renderer2 },
{ type: Object, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }
];
ParallaxScrollDirective.propDecorators = {
config: [{ type: Input }],
parallaxSpeed: [{ type: Input }],
parallaxSmoothness: [{ type: Input }],
parallaxDirection: [{ type: Input }],
parallaxTimingFunction: [{ type: Input }],
parallaxThrottleTime: [{ type: Input }]
};
if (false) {
/**
* @type {?}
* @private
*/
ParallaxScrollDirective.prototype.config;
/** @type {?} */
ParallaxScrollDirective.prototype.parallaxSpeed;
/** @type {?} */
ParallaxScrollDirective.prototype.parallaxSmoothness;
/** @type {?} */
ParallaxScrollDirective.prototype.parallaxDirection;
/** @type {?} */
ParallaxScrollDirective.prototype.parallaxTimingFunction;
/** @type {?} */
ParallaxScrollDirective.prototype.parallaxThrottleTime;
/**
* @type {?}
* @private
*/
ParallaxScrollDirective.prototype._parallaxSpeedVal;
/**
* @type {?}
* @private
*/
ParallaxScrollDirective.prototype._parallaxSmoothnessVal;
/**
* @type {?}
* @private
*/
ParallaxScrollDirective.prototype._parallaxTimingFunVal;
/**
* @type {?}
* @private
*/
ParallaxScrollDirective.prototype._parallaxThrottleTime;
/** @type {?} */
ParallaxScrollDirective.prototype.scrollSubscribtion;
/** @type {?} */
ParallaxScrollDirective.prototype.isPrxElInViewport;
/** @type {?} */
ParallaxScrollDirective.prototype.directiveName;
/** @type {?} */
ParallaxScrollDirective.prototype.elem;
/** @type {?} */
ParallaxScrollDirective.prototype.renderer;
/**
* @type {?}
* @private
*/
ParallaxScrollDirective.prototype.platformId;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LXBhcmFsbGF4LXNjcm9sbC5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9uZ3gtcGFyYWxsYXgtc2Nyb2xsLyIsInNvdXJjZXMiOlsibGliL25neC1wYXJhbGxheC1zY3JvbGwuZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULFVBQVUsRUFDVixTQUFTLEVBQ1QsS0FBSyxFQU1MLE1BQU0sRUFDTixXQUFXLEVBQ1osTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMxQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNuRCxPQUFPLEVBQUUsU0FBUyxFQUFnQixNQUFNLE1BQU0sQ0FBQztBQUMvQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFNOUMsTUFBTSxPQUFPLHVCQUF1Qjs7Ozs7O0lBNkJsQyxZQUNTLElBQWdCLEVBQ2hCLFFBQW1CLEVBQ0csVUFBa0I7UUFGeEMsU0FBSSxHQUFKLElBQUksQ0FBWTtRQUNoQixhQUFRLEdBQVIsUUFBUSxDQUFXO1FBQ0csZUFBVSxHQUFWLFVBQVUsQ0FBUTtRQVZ6QywwQkFBcUIsR0FBVyxRQUFRLENBQUM7UUFDekMsMEJBQXFCLEdBQVcsQ0FBQyxDQUFDO1FBSTFDLGtCQUFhLEdBQVcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUM7SUFNM0MsQ0FBQzs7OztJQUVKLFFBQVE7UUFDTixJQUFJLGdCQUFnQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUM7WUFBRSxPQUFPO1FBRTlDLHFEQUFxRDtRQUNyRCxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDcEIsSUFBSSxDQUFDLHNCQUFzQixFQUFFLENBQUM7UUFDOUIsSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUM7SUFDL0IsQ0FBQzs7Ozs7SUFFRCxXQUFXLENBQUMs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Qzs7SUFHNUMsdUNBQXVCOztJQUN2QiwyQ0FBMEI7Ozs7O0lBQzFCLDZDQUErQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIERpcmVjdGl2ZSxcbiAgRWxlbWVudFJlZixcbiAgUmVuZGVyZXIyLFxuICBJbnB1dCxcbiAgT25Jbml0LFxuICBBZnRlclZpZXdJbml0LFxuICBPbkNoYW5nZXMsXG4gIFNpbXBsZUNoYW5nZXMsXG4gIE9uRGVzdHJveSxcbiAgSW5qZWN0LFxuICBQTEFURk9STV9JRFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IGlzRGV2TW9kZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgaXNQbGF0Zm9ybVNlcnZlciB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBmcm9tRXZlbnQsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgdGhyb3R0bGVUaW1lIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgSVBhcmFsbGF4U2Nyb2xsQ29uZmlnLCBQYXJhbGxheERpcmVjdGlvbiB9IGZyb20gJy4vbmd4LXBhcmFsbGF4LmludGVyZmFjZXMnO1xuXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICdbbmd4UGFyYWxsYXhTY3JvbGxdJ1xufSlcbmV4cG9ydCBjbGFzcyBQYXJhbGxheFNjcm9sbERpcmVjdGl2ZSBpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzLCBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3kge1xuICAvLyBSZXF1aXJlZCBpbnB1dCBmcm9tIGNvbmZpZyBvYmplY3Qgb3IgaW5wdXQgcHJvcHNcbiAgQElucHV0KCkgcHJpdmF0ZSBjb25maWc/OiBJUGFyYWxsYXhTY3JvbGxDb25maWc7XG5cbiAgQElucHV0KClcbiAgcGFyYWxsYXhTcGVlZDogbnVtYmVyO1xuXG4gIEBJbnB1dCgpXG4gIHBhcmFsbGF4U21vb3RobmVzczogbnVtYmVyO1xuXG4gIEBJbnB1dCgpXG4gIHBhcmFsbGF4RGlyZWN0aW9uPzogUGFyYWxsYXhEaXJlY3Rpb247XG5cbiAgQElucHV0KClcbiAgcGFyYWxsYXhUaW1pbmdGdW5jdGlvbj86IHN0cmluZztcblxuICBASW5wdXQoKVxuICBwYXJhbGxheFRocm90dGxlVGltZT86IG51bWJlcjtcblxuICAvLyBTZXR0aW5nIHRoZSB2YWx1ZXMgYWZ0ZXIgdmFsaWRhdGlvblxuICBwcml2YXRlIF9wYXJhbGxheFNwZWVkVmFsOiBudW1iZXI7XG4gIHByaXZhdGUgX3BhcmFsbGF4U21vb3RobmVzc1ZhbDogbnVtYmVyO1xuICBwcml2YXRlIF9wYXJhbGxheFRpbWluZ0Z1blZhbDogc3RyaW5nID0gJ2xpbmVhcic7XG4gIHByaXZhdGUgX3BhcmFsbGF4VGhyb3R0bGVUaW1lOiBudW1iZXIgPSAwO1xuXG4gIHNjcm9sbFN1YnNjcmlidGlvbjogU3Vic2NyaXB0aW9uO1xuICBpc1ByeEVsSW5WaWV3cG9ydDogYm9vbGVhbjtcbiAgZGlyZWN0aXZlTmFtZTogc3RyaW5nID0gdGhpcy5jb25zdHJ1Y3Rvci5uYW1lO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHB1YmxpYyBlbGVtOiBFbGVtZW50UmVmLFxuICAgIHB1YmxpYyByZW5kZXJlcjogUmVuZGVyZXIyLFxuICAgIEBJbmplY3QoUExBVEZPUk1fSUQpIHByaXZhdGUgcGxhdGZvcm1JZDogT2JqZWN0XG4gICkge31cblxuICBuZ09uSW5pdCgpIHtcbiAgICBpZiAoaXNQbGF0Zm9ybVNlcnZlcih0aGlzLnBsYXRmb3JtSWQpKSByZXR1cm47XG5cbiAgICAvLyBJbml0aW5nIHBhcmFsbGF4IGVmZmVjdCBhbmQgc2V0dGluZyBlbGVtZW50IHN0eWxlc1xuICAgIHRoaXMuaW5pdFBhcmFsbGF4KCk7XG4gICAgdGhpcy5zZXRQYXJhbGxheEVsVHJhbnNmb3JtKCk7XG4gICAgdGhpcy5zZXRQYXJhbGxheFRyYW5zaXRpb24oKTtcbiAgfVxuXG4gIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpIHtcbiAgICAvLyBTZXR0aW5nIHBhcmFsbGF4IG9wdGlvbnMgZnJvbSBjb25maWcgb2JqZWN0IG9yIGlucHV0IHByb3BzXG4gICAgY29uc3QgcHJseFNwZWVkID1cbiAgICAgIChjaGFuZ2VzWydwYXJhbGxheFNwZWVkJ10gJiYgY2hhbmdlc1sncGFyYWxsYXhTcGVlZCddLmN1cnJlbnRWYWx1ZSkgfHxcbiAgICAgIChjaGFuZ2VzWydjb25maWcnXSAmJiBjaGFuZ2VzWydjb25maWcnXS5jdXJyZW50VmFsdWUucGFyYWxsYXhTcGVlZCk7XG5cbiAgICBjb25zdCBwcmx4U21vb3RobmVzcyA9XG4gICAgICAoY2hhbmdlc1sncGFyYWxsYXhTbW9vdGhuZXNzJ10gJiYgY2hhbmdlc1sncGFyYWxsYXhTbW9vdGhuZXNzJ10uY3VycmVudFZhbHVlKSB8fFxuICAgICAgKGNoYW5nZXNbJ2NvbmZpZyddICYmIGNoYW5nZXNbJ2NvbmZpZyddLmN1cnJlbnRWYWx1ZS5wYXJhbGxheFNtb290aG5lc3MpO1xuXG4gICAgY29uc3QgcHJseERpcmVjdGlvbiA9XG4gICAgICAoY2hhbmdlc1sncGFyYWxsYXhEaXJlY3Rpb24nXSAmJiBjaGFuZ2VzWydwYXJhbGxheERpcmVjdGlvbiddLmN1cnJlbnRWYWx1ZSkgfHxcbiAgICAgIChjaGFuZ2VzWydjb25maWcnXSAmJiBjaGFuZ2VzWydjb25maWcnXS5jdXJyZW50VmFsdWUucGFyYWxsYXhEaXJlY3Rpb24pO1xuXG4gICAgY29uc3QgcHJseFRpbWluZ0Z1bmN0aW9uID1cbiAgICAgIChjaGFuZ2VzWydwYXJhbGxheFRpbWluZ0Z1bmN0aW9uJ10gJiYgY2hhbmdlc1sncGFyYWxsYXhUaW1pbmdGdW5jdGlvbiddLmN1cnJlbnRWYWx1ZSkgfHxcbiAgICAgIChjaGFuZ2VzWydjb25maWcnXSAmJiBjaGFuZ2VzWydjb25maWcnXS5jdXJyZW50VmFsdWUucGFyYWxsYXhUaW1pbmdGdW5jdGlvbik7XG5cbiAgICBjb25zdCBwcmx4VGhyb3R0bGVUaW1lID1cbiAgICAgIChjaGFuZ2VzWydwYXJhbGxheFRocm90dGxlVGltZSddICYmIGNoYW5nZXNbJ3BhcmFsbGF4VGhyb3R0bGVUaW1lJ10uY3VycmVudFZhbHVlKSB8fFxuICAgICAgKGNoYW5nZXNbJ2NvbmZpZyddICYmIGNoYW5nZXNbJ2NvbmZpZyddLmN1cnJlbnRWYWx1ZS5wYXJhbGxheFRocm90dGxlVGltZSk7XG5cbiAgICB0aGlzLnNldFBhcmFsbGF4U3BlZWQocHJseFNwZWVkKTtcbiAgICB0aGlzLnNldFBhcmFsbGF4U21vb3RobmVzcyhwcmx4U21vb3RobmVzcyk7XG4gICAgdGhpcy5zZXRQYXJhbGxheERpcmVjdGlvbihwcmx4RGlyZWN0aW9uKTtcbiAgICB0aGlzLnNldFBhcmFsbGF4VGltaW5nRnVuKHBybHhUaW1pbmdGdW5jdGlvbik7XG4gICAgdGhpcy5zZXRQYXJhbGxheFRocm90dGxlVGltZShwcmx4VGhyb3R0bGVUaW1lKTtcbiAgfVxuXG4gIG5nQWZ0ZXJWaWV3SW5pdCgpIHt9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgdGhpcy5zY3JvbGxTdWJzY3JpYnRpb24gJiYgdGhpcy5zY3JvbGxTdWJzY3JpYnRpb24udW5zdWJzY3JpYmUoKTtcbiAgfVxuXG4gIC8vIFNldHRpbmcgcGFyYWxsYXggZWZmZWN0IGFuZCBzZXR0aW5nIGVsZW1lbnQgc3R5bGVzXG4gIGluaXRQYXJhbGxheCgpOiB2b2lkIHtcbiAgICB0aGlzLnNjcm9sbFN1YnNjcmlidGlvbiA9IGZyb21FdmVudCh3aW5kb3csICdzY3JvbGwnKVxuICAgICAgLnBpcGUodGhyb3R0bGVUaW1lKHRoaXMucHJseFRocm90dGxlVGltZSkpXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgICAgdGhpcy5zZXRQYXJhbGxheEVsVHJhbnNmb3JtKCk7XG4gICAgICB9KTtcbiAgfVxuXG4gIC8vIFNldHRpbmcgcGFyYWxsYXggc3BlZWQgZWZmZWN0IHN0eWxlc1xuICBzZXRQYXJhbGxheEVsVHJhbnNmb3JtKCk6IHZvaWQge1xuICAgIGxldCBzY3JvbGxlZCA9IHdpbmRvdy5wYWdlWU9mZnNldDtcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKFxuICAgICAgdGhpcy5lbGVtLm5hdGl2ZUVsZW1lbnQsXG4gICAgICAndHJhbnNmb3JtJyxcbiAgICAgIGB0cmFuc2xhdGVZKCR7c2Nyb2xsZWQgKiB0aGlzLnBybHhTcGVlZH1weCkgdHJhbnNsYXRlWigwKWBcbiAgICApO1xuICB9XG5cbiAgLy8gU2V0dGluZyBwYXJhbGxheCBzbW9vdGggZWZmZWN0IHN0eWxlcywgYmFzZWQgb24gQ1NTIGFuaW1hdGlvbi10aW1pbmctZnVuY3Rpb25cbiAgc2V0UGFyYWxsYXhUcmFuc2l0aW9uKCkge1xuICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUoXG4gICAgICB0aGlzLmVsZW0ubmF0aXZlRWxlbWVudCxcbiAgICAgICd0cmFuc2l0aW9uJyxcbiAgICAgIGB0cmFuc2Zvcm0gJHt0aGlzLnBybHhTbW9vdGhuZXNzfXMgJHt0aGlzLnBybHhUaW1pbmdGdW59YFxuICAgICk7XG4gIH1cblxuICAvLyBTZXR0aW5nIHBhcmFsbGF4IHByb3BlcnRpZXNcbiAgc2V0UGFyYWxsYXhTcGVlZChzcGVlZFZhbDogYW55KTogdm9pZCB7XG4gICAgY29uc3QgcHJvcE5hbWUgPSAncGFyYWxsYXhTcGVlZCc7XG4gICAgdGhpcy52YWxpZGF0ZVBhcmFsbGF4U3BlZWQoc3BlZWRWYWwsIHByb3BOYW1lLCAnbnVtYmVyJykgJiYgKHRoaXMuX3BhcmFsbGF4U3BlZWRWYWwgPSBzcGVlZFZhbCk7XG4gIH1cblxuICBzZXRQYXJhbGxheFNtb290aG5lc3Moc21vb3RobmVzc1ZhbDogYW55KTogdm9pZCB7XG4gICAgY29uc3QgcHJvcE5hbWUgPSAncGFyYWxsYXhTbW9vdGhuZXNzJztcbiAgICB0aGlzLnZhbGlkYXRlUGFyYWxsYXhTbW9vdGhuZXNzKHNtb290aG5lc3NWYWwsIHByb3BOYW1lLCAnbnVtYmVyJykgJiZcbiAgICAgICh0aGlzLl9wYXJhbGxheFNtb290aG5lc3NWYWwgPSBzbW9vdGhuZXNzVmFsKTtcbiAgfVxuXG4gIHNldFBhcmFsbGF4RGlyZWN0aW9uKGRpcmVjdGlvblZhbDogYW55KTogdm9pZCB7XG4gICAgY29uc3QgcHJvcE5hbWUgPSAncGFyYWxsYXhEaXJlY3Rpb24nO1xuICAgIGRpcmVjdGlvblZhbCAmJlxuICAgICAgdGhpcy5pc1R5cGVPZihkaXJlY3Rpb25WYWwsICdzdHJpbmcnLCBwcm9wTmFtZSkgJiZcbiAgICAgIGRpcmVjdGlvblZhbCA9PT0gJ3JldmVyc2UnICYmXG4gICAgICAodGhpcy5fcGFyYWxsYXhTcGVlZFZhbCAqPSAtMSk7XG4gIH1cblxuICBzZXRQYXJhbGxheFRpbWluZ0Z1bih0aW1pbmdGdW46IGFueSk6IHZvaWQge1xuICAgIGNvbnN0IHByb3BOYW1lID0gJ3BhcmFsbGF4VGltaW5nRnVuY3Rpb24nO1xuICAgIHRpbWluZ0Z1biAmJlxuICAgICAgdGhpcy5pc1R5cGVPZih0aW1pbmdGdW4sICdzdHJpbmcnLCBwcm9wTmFtZSkgJiZcbiAgICAgICh0aGlzLl9wYXJhbGxheFRpbWluZ0Z1blZhbCA9IHRpbWluZ0Z1bik7XG4gIH1cblxuICBzZXRQYXJhbGxheFRocm90dGxlVGltZSh0aHJvdHRsZVRpbWU6IGFueSk6IHZvaWQge1xuICAgIGNvbnN0IHByb3BOYW1lID0gJ3BhcmFsbGF4VGhyb3R0bGVUaW1lJztcbiAgICB0aHJvdHRsZVRpbWUgJiZcbiAgICAgIHRoaXMuaXNUeXBlT2YodGhyb3R0bGVUaW1lLCAnbnVtYmVyJywgcHJvcE5hbWUpICYmXG4gICAgICAodGhpcy5fcGFyYWxsYXhUaHJvdHRsZVRpbWUgPSB0aHJvdHRsZVRpbWUpO1xuICB9XG5cbiAgLy8gR2V0dGVycyBmb3IgcGFyYWxsYXggb3B0aW9uc1xuICBnZXQgcHJseFNwZWVkKCkge1xuICAgIHJldHVybiB0aGlzLl9wYXJhbGxheFNwZWVkVmFsO1xuICB9XG5cbiAgZ2V0IHBybHhTbW9vdGhuZXNzKCkge1xuICAgIHJldHVybiB0aGlzLl9wYXJhbGxheFNtb290aG5lc3NWYWw7XG4gIH1cblxuICBnZXQgcHJseFRpbWluZ0Z1bigpIHtcbiAgICByZXR1cm4gdGhpcy5fcGFyYWxsYXhUaW1pbmdGdW5WYWw7XG4gIH1cblxuICBnZXQgcHJseFRocm90dGxlVGltZSgpIHtcbiAgICByZXR1cm4gdGhpcy5fcGFyYWxsYXhUaHJvdHRsZVRpbWU7XG4gIH1cblxuICAvLyBWYWxpZGF0aW9uIGZ1bmN0aW9uc1xuICBpc1Byb3ZpZGVkKHZhbHVlOiBhbnksIHByb3BOYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICBjb25zdCBpc05vdFByb3ZpZGVkID0gdmFsdWUgPT0gbnVsbCB8fCB2YWx1ZSA9PT0gJyc7XG4gICAgaWYgKGlzTm90UHJvdmlkZWQgJiYgaXNEZXZNb2RlKCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYCR7dGhpcy5kaXJlY3RpdmVOYW1lfTogQElucHV0IFske3Byb3BOYW1lfV0gaXMgcmVxdWlyZWQsIGJ1dCB3YXMgbm90IHByb3ZpZGVkYFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBpc1R5cGVPZih2YWx1ZTogYW55LCByZXF1aXJlZFR5cGU6ICdzdHJpbmcnIHwgJ251bWJlcicgfCAnYm9vbGVhbicsIHByb3BOYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICBjb25zdCBpc1JlcXVpcmVkVHlwZSA9IHR5cGVvZiB2YWx1ZSA9PT0gcmVxdWlyZWRUeXBlO1xuICAgIGlmICghaXNSZXF1aXJlZFR5cGUgJiYgaXNEZXZNb2RlKCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYCR7XG4gICAgICAgICAgdGhpcy5kaXJlY3RpdmVOYW1lXG4gICAgICAgIH06IEBJbnB1dCBbJHtwcm9wTmFtZX1dIGlzIGV4cGVjdGVkIHRvIGJlIG9mIHR5cGUgJyR7cmVxdWlyZWRUeXBlfScsIGJ1dCB0eXBlICcke3R5cGVvZiB2YWx1ZX0nIHdhcyBwcm92aWRlZGBcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgaXNQb3NpdGl2ZSh2YWx1ZTogbnVtYmVyLCBwcm9wTmFtZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgY29uc3QgaXNSZXF1aXJlZFR5cGUgPSB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInO1xuICAgIGNvbnN0IGlzVmFsaWQgPSB2YWx1ZSA+PSAwO1xuXG4gICAgaWYgKGlzUmVxdWlyZWRUeXBlICYmICFpc1ZhbGlkICYmIGlzRGV2TW9kZSgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGAke1xuICAgICAgICAgIHRoaXMuZGlyZWN0aXZlTmFtZVxuICAgICAgICB9OiBASW5wdXQgWyR7cHJvcE5hbWV9XSBpcyBleHBlY3RlZCB0byBiZSBwb3NpdGl2ZSB2YWx1ZSwgYnV0IG5lZ2F0aXZlICcke3ZhbHVlfScgdmFsdWUgd2FzIHByb3ZpZGVkYFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvLyBFeGVjdXRpbmcgdmFsaWRhdGlvbiBmdW5jdGlvbnMgdG8gdmFsaWRhdGUgcGFyYWxsYXggc3BlZWRcbiAgdmFsaWRhdGVQYXJhbGxheFNwZWVkKFxuICAgIHZhbHVlOiBhbnksXG4gICAgcHJvcE5hbWU6IHN0cmluZyxcbiAgICByZXF1aXJlZFR5cGU6ICdzdHJpbmcnIHwgJ251bWJlcicgfCAnYm9vbGVhbidcbiAgKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIHRoaXMuaXNQcm92aWRlZCh2YWx1ZSwgcHJvcE5hbWUpICYmXG4gICAgICB0aGlzLmlzVHlwZU9mKHZhbHVlLCByZXF1aXJlZFR5cGUsIHByb3BOYW1lKSAmJlxuICAgICAgdGhpcy5pc1Bvc2l0aXZlKHZhbHVlLCBwcm9wTmFtZSlcbiAgICApO1xuICB9XG5cbiAgLy8gRXhlY3V0aW5nIHZhbGlkYXRpb24gZnVuY3Rpb25zIHRvIHZhbGlkYXRlIHBhcmFsbGF4IHNtb290aG5lc3NcbiAgdmFsaWRhdGVQYXJhbGxheFNtb290aG5lc3MoXG4gICAgdmFsdWU6IGFueSxcbiAgICBwcm9wTmFtZTogc3RyaW5nLFxuICAgIHJlcXVpcmVkVHlwZTogJ3N0cmluZycgfCAnbnVtYmVyJyB8ICdib29sZWFuJ1xuICApIHtcbiAgICByZXR1cm4gKFxuICAgICAgdGhpcy5pc1Byb3ZpZGVkKHZhbHVlLCBwcm9wTmFtZSkgJiZcbiAgICAgIHRoaXMuaXNUeXBlT2YodmFsdWUsIHJlcXVpcmVkVHlwZSwgcHJvcE5hbWUpICYmXG4gICAgICB0aGlzLmlzUG9zaXRpdmUodmFsdWUsIHByb3BOYW1lKVxuICAgICk7XG4gIH1cbn1cbiJdfQ==