UNPKG

@omostan/ngx-idle

Version:

A module for responding to idle users in Angular applications. this is a forked version of the original @ng-Idle

380 lines 39.9 kB
import { EventEmitter, Inject, Injectable, Optional, PLATFORM_ID } from '@angular/core'; import { Interrupt } from './interrupt'; import { LocalStorageExpiry } from './localstorageexpiry'; import * as i0 from "@angular/core"; import * as i1 from "./idleexpiry"; import * as i2 from "./keepalivesvc"; /* * Indicates the desired auto resume behavior. */ export var AutoResume; (function (AutoResume) { /* * Auto resume functionality will be disabled. */ AutoResume[AutoResume["disabled"] = 0] = "disabled"; /* * Can resume automatically even if they are idle. */ AutoResume[AutoResume["idle"] = 1] = "idle"; /* * Can only resume automatically if they are not yet idle. */ AutoResume[AutoResume["notIdle"] = 2] = "notIdle"; })(AutoResume || (AutoResume = {})); /** * A service for detecting and responding to user idleness. */ export class Idle { constructor(expiry, zone, keepaliveSvc, // eslint-disable-next-line @typescript-eslint/ban-types platformId) { this.expiry = expiry; this.zone = zone; this.platformId = platformId; this.idle = 20 * 60; // in seconds this.timeoutVal = 30; // in seconds this.autoResume = AutoResume.idle; this.interrupts = new Array(); this.running = false; this.keepaliveEnabled = false; this.onIdleStart = new EventEmitter(); this.onIdleEnd = new EventEmitter(); this.onTimeoutWarning = new EventEmitter(); this.onTimeout = new EventEmitter(); this.onInterrupt = new EventEmitter(); if (keepaliveSvc) { this.keepaliveSvc = keepaliveSvc; this.keepaliveEnabled = true; } this.setIdling(false); } /* * Sets the idle name for localStorage. * Important to set if multiple instances of Idle with LocalStorageExpiry * @param The name of the idle. */ setIdleName(key) { if (this.expiry instanceof LocalStorageExpiry) { this.expiry.setIdleName(key); } else { throw new Error('Cannot set expiry key name because no LocalStorageExpiry has been provided.'); } } /* * Returns whether or not keepalive integration is enabled. * @return True if integration is enabled; otherwise, false. */ getKeepaliveEnabled() { return this.keepaliveEnabled; } /* * Sets and returns whether or not keepalive integration is enabled. * @param True if the integration is enabled; otherwise, false. * @return The current value. */ setKeepaliveEnabled(value) { if (!this.keepaliveSvc) { throw new Error('Cannot enable keepalive integration because no KeepaliveSvc has been provided.'); } return (this.keepaliveEnabled = value); } /* * Returns the current timeout value. * @return The timeout value in seconds. */ getTimeout() { return this.timeoutVal; } /* * Sets the timeout value. * @param seconds - The timeout value in seconds. 0 or false to disable timeout feature. * @return The current value. If disabled, the value will be 0. */ setTimeout(seconds) { if (seconds === false) { this.timeoutVal = 0; } else if (typeof seconds === 'number' && seconds >= 0) { this.timeoutVal = seconds; } else { throw new Error("'seconds' can only be 'false' or a positive number."); } return this.timeoutVal; } /* * Returns the current idle value. * @return The idle value in seconds. */ getIdle() { return this.idle; } /* * Sets the idle value. * @param seconds - The idle value in seconds. * @return The idle value in seconds. */ setIdle(seconds) { if (seconds <= 0) { throw new Error("'seconds' must be greater zero"); } return (this.idle = seconds); } /* * Returns the current autoresume value. * @return The current value. */ getAutoResume() { return this.autoResume; } setAutoResume(value) { return (this.autoResume = value); } /* * Sets interrupts from the specified sources. * @param sources - Interrupt sources. * @return The resulting interrupts. */ setInterrupts(sources) { this.clearInterrupts(); const self = this; for (const source of sources) { const options = { platformId: this.platformId }; const sub = new Interrupt(source, options); sub.subscribe((args) => { self.interrupt(args.force, args.innerArgs); }); this.interrupts.push(sub); } return this.interrupts; } /* * Returns the current interrupts. * @return The current interrupts. */ getInterrupts() { return this.interrupts; } /* * Pauses, unsubscribes, and clears the current interrupt subscriptions. */ clearInterrupts() { for (const sub of this.interrupts) { sub.pause(); sub.unsubscribe(); } this.interrupts.length = 0; } /* * Returns whether or not the service is running i.e. watching for idleness. * @return True if service is watching; otherwise, false. */ isRunning() { return this.running; } /* * Returns whether or not the user is considered idle. * @return True if the user is in the idle state; otherwise, false. */ isIdling() { return this.idling; } /* * Starts watching for inactivity. */ watch(skipExpiry) { this.safeClearInterval('idleHandle'); this.safeClearInterval('timeoutHandle'); const timeout = !this.timeoutVal ? 0 : this.timeoutVal; if (!skipExpiry) { const value = new Date(this.expiry.now().getTime() + (this.idle + timeout) * 1000); this.expiry.last(value); } if (this.idling) { this.toggleState(); } if (!this.running) { this.startKeepalive(); this.toggleInterrupts(true); } this.running = true; const watchFn = () => { this.zone.run(() => { const diff = this.getExpiryDiff(timeout); if (diff > 0) { this.safeClearInterval('idleHandle'); this.setIdleIntervalOutsideOfZone(watchFn, diff); } else { this.toggleState(); } }); }; this.setIdleIntervalOutsideOfZone(watchFn, this.idle * 1000); } /* * Allows protractor tests to call waitForAngular without hanging */ setIdleIntervalOutsideOfZone(watchFn, frequency) { this.zone.runOutsideAngular(() => { this.idleHandle = setInterval(watchFn, frequency); }); } /* * Stops watching for inactivity. */ stop() { this.stopKeepalive(); this.toggleInterrupts(false); this.safeClearInterval('idleHandle'); this.safeClearInterval('timeoutHandle'); this.setIdling(false); this.running = false; this.expiry.last(null); } /* * Forces a timeout event and state. */ timeout() { this.stopKeepalive(); this.toggleInterrupts(false); this.safeClearInterval('idleHandle'); this.safeClearInterval('timeoutHandle'); this.setIdling(true); this.running = false; this.countdown = 0; this.onTimeout.emit(null); } /* * Signals that user activity has occurred. * @param force - Forces watch to be called, unless they are timed out. * @param eventArgs - Optional source event arguments. */ interrupt(force, eventArgs) { if (!this.running) { return; } if (this.timeoutVal && this.expiry.isExpired()) { this.timeout(); return; } this.onInterrupt.emit(eventArgs); if (force === true || this.autoResume === AutoResume.idle || (this.autoResume === AutoResume.notIdle && !this.expiry.idling())) { this.watch(force); } } setIdling(value) { this.idling = value; this.expiry.idling(value); } toggleState() { this.setIdling(!this.idling); if (this.idling) { this.onIdleStart.emit(null); this.stopKeepalive(); if (this.timeoutVal > 0) { this.countdown = this.timeoutVal; this.doCountdown(); this.setTimoutIntervalOutsideZone(() => { this.doCountdownInZone(); }, 1000); } } else { this.toggleInterrupts(true); this.onIdleEnd.emit(null); this.startKeepalive(); } this.safeClearInterval('idleHandle'); } setTimoutIntervalOutsideZone(intervalFn, frequency) { this.zone.runOutsideAngular(() => { this.timeoutHandle = setInterval(() => { intervalFn(); }, frequency); }); } toggleInterrupts(resume) { for (const interrupt of this.interrupts) { if (resume) { interrupt.resume(); } else { interrupt.pause(); } } } getExpiryDiff(timeout) { const now = this.expiry.now(); const last = this.expiry.last() || now; return last.getTime() - now.getTime() - timeout * 1000; } doCountdownInZone() { this.zone.run(() => { this.doCountdown(); }); } doCountdown() { const diff = this.getExpiryDiff(this.timeoutVal); if (diff > 0) { this.safeClearInterval('timeoutHandle'); this.interrupt(true); return; } if (!this.idling) { return; } if (this.countdown <= 0) { this.timeout(); return; } this.onTimeoutWarning.emit(this.countdown); this.countdown--; } safeClearInterval(handleName) { const handle = this[handleName]; if (handle !== null && typeof handle !== 'undefined') { clearInterval(this[handleName]); this[handleName] = null; } } startKeepalive() { if (!this.keepaliveSvc || !this.keepaliveEnabled) { return; } if (this.running) { this.keepaliveSvc.ping(); } this.keepaliveSvc.start(); } stopKeepalive() { if (!this.keepaliveSvc || !this.keepaliveEnabled) { return; } this.keepaliveSvc.stop(); } /* * Called by Angular when destroying the instance. */ ngOnDestroy() { this.stop(); this.clearInterrupts(); } } Idle.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: Idle, deps: [{ token: i1.IdleExpiry }, { token: i0.NgZone }, { token: i2.KeepaliveSvc, optional: true }, { token: PLATFORM_ID, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); Idle.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: Idle }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: Idle, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i1.IdleExpiry }, { type: i0.NgZone }, { type: i2.KeepaliveSvc, decorators: [{ type: Optional }] }, { type: Object, decorators: [{ type: Optional }, { type: Inject, args: [PLATFORM_ID] }] }]; } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaWRsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL2NvcmUvc3JjL2xpYi9pZGxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxZQUFZLEVBQ1osTUFBTSxFQUNOLFVBQVUsRUFHVixRQUFRLEVBQ1IsV0FBVyxFQUNaLE1BQU0sZUFBZSxDQUFDO0FBR3ZCLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFJeEMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7Ozs7QUFFMUQ7O0dBRUc7QUFDSCxNQUFNLENBQU4sSUFBWSxVQWFYO0FBYkQsV0FBWSxVQUFVO0lBQ3BCOztPQUVHO0lBQ0gsbURBQVEsQ0FBQTtJQUNSOztPQUVHO0lBQ0gsMkNBQUksQ0FBQTtJQUNKOztPQUVHO0lBQ0gsaURBQU8sQ0FBQTtBQUNULENBQUMsRUFiVyxVQUFVLEtBQVYsVUFBVSxRQWFyQjtBQUVEOztHQUVHO0FBRUgsTUFBTSxPQUFPLElBQUk7SUFxQmYsWUFDVSxNQUFrQixFQUNsQixJQUFZLEVBQ1IsWUFBMkI7SUFDdkMsd0RBQXdEO0lBQ2YsVUFBbUI7UUFKcEQsV0FBTSxHQUFOLE1BQU0sQ0FBWTtRQUNsQixTQUFJLEdBQUosSUFBSSxDQUFRO1FBR3FCLGVBQVUsR0FBVixVQUFVLENBQVM7UUF6QnRELFNBQUksR0FBVyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsYUFBYTtRQUNyQyxlQUFVLEdBQUcsRUFBRSxDQUFDLENBQUMsYUFBYTtRQUM5QixlQUFVLEdBQWUsVUFBVSxDQUFDLElBQUksQ0FBQztRQUN6QyxlQUFVLEdBQXFCLElBQUksS0FBSyxFQUFFLENBQUM7UUFDM0MsWUFBTyxHQUFHLEtBQUssQ0FBQztRQUtoQixxQkFBZ0IsR0FBRyxLQUFLLENBQUM7UUFHMUIsZ0JBQVcsR0FBc0IsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUNwRCxjQUFTLEdBQXNC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RTtZQUNoRCxPQUFPO1NBQ1I7UUFFRCxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQzNCLENBQUM7SUFFRDs7T0FFRztJQUNILFdBQVc7UUFDVCxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDWixJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7SUFDekIsQ0FBQzs7aUdBL1pVLElBQUksOEdBMEJPLFdBQVc7cUdBMUJ0QixJQUFJOzJGQUFKLElBQUk7a0JBRGhCLFVBQVU7OzBCQXlCTixRQUFROzhCQUU2QyxNQUFNOzBCQUEzRCxRQUFROzswQkFBSSxNQUFNOzJCQUFDLFdBQVciLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xyXG4gIEV2ZW50RW1pdHRlcixcclxuICBJbmplY3QsXHJcbiAgSW5qZWN0YWJsZSxcclxuICBOZ1pvbmUsXHJcbiAgT25EZXN0cm95LFxyXG4gIE9wdGlvbmFsLFxyXG4gIFBMQVRGT1JNX0lEXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcblxyXG5pbXBvcnQgeyBJZGxlRXhwaXJ5IH0gZnJvbSAnLi9pZGxlZXhwaXJ5JztcclxuaW1wb3J0IHsgSW50ZXJydXB0IH0gZnJvbSAnLi9pbnRlcnJ1cHQnO1xyXG5pbXBvcnQgeyBJbnRlcnJ1cHRBcmdzIH0gZnJvbSAnLi9pbnRlcnJ1cHRhcmdzJztcclxuaW1wb3J0IHsgSW50ZXJydXB0U291cmNlIH0gZnJvbSAnLi9pbnRlcnJ1cHRzb3VyY2UnO1xyXG5pbXBvcnQgeyBLZWVwYWxpdmVTdmMgfSBmcm9tICcuL2tlZXBhbGl2ZXN2Yyc7XHJcbmltcG9ydCB7IExvY2FsU3RvcmFnZUV4cGlyeSB9IGZyb20gJy4vbG9jYWxzdG9yYWdlZXhwaXJ5JztcclxuXHJcbi8qXHJcbiAqIEluZGljYXRlcyB0aGUgZGVzaXJlZCBhdXRvIHJlc3VtZSBiZWhhdmlvci5cclxuICovXHJcbmV4cG9ydCBlbnVtIEF1dG9SZXN1bWUge1xyXG4gIC8qXHJcbiAgICogQXV0byByZXN1bWUgZnVuY3Rpb25hbGl0eSB3aWxsIGJlIGRpc2FibGVkLlxyXG4gICAqL1xyXG4gIGRpc2FibGVkLFxyXG4gIC8qXHJcbiAgICogQ2FuIHJlc3VtZSBhdXRvbWF0aWNhbGx5IGV2ZW4gaWYgdGhleSBhcmUgaWRsZS5cclxuICAgKi9cclxuICBpZGxlLFxyXG4gIC8qXHJcbiAgICogQ2FuIG9ubHkgcmVzdW1lIGF1dG9tYXRpY2FsbHkgaWYgdGhleSBhcmUgbm90IHlldCBpZGxlLlxyXG4gICAqL1xyXG4gIG5vdElkbGVcclxufVxyXG5cclxuLyoqXHJcbiAqIEEgc2VydmljZSBmb3IgZGV0ZWN0aW5nIGFuZCByZXNwb25kaW5nIHRvIHVzZXIgaWRsZW5lc3MuXHJcbiAqL1xyXG5ASW5qZWN0YWJsZSgpXHJcbmV4cG9ydCBjbGFzcyBJZGxlIGltcGxlbWVudHMgT25EZXN0cm95IHtcclxuICBwcml2YXRlIGlkbGU6IG51bWJlciA9IDIwICogNjA7IC8vIGluIHNlY29uZHNcclxuICBwcml2YXRlIHRpbWVvdXRWYWwgPSAzMDsgLy8gaW4gc2Vjb25kc1xyXG4gIHByaXZhdGUgYXV0b1Jlc3VtZTogQXV0b1Jlc3VtZSA9IEF1dG9SZXN1bWUuaWRsZTtcclxuICBwcml2YXRlIGludGVycnVwdHM6IEFycmF5PEludGVycnVwdD4gPSBuZXcgQXJyYXkoKTtcclxuICBwcml2YXRlIHJ1bm5pbmcgPSBmYWxzZTtcclxuICBwcml2YXRlIGlkbGluZzogYm9vbGVhbjtcclxuICBwcml2YXRlIGlkbGVIYW5kbGU6IGFueTtcclxuICBwcml2YXRlIHRpbWVvdXRIYW5kbGU6IGFueTtcclxuICBwcml2YXRlIGNvdW50ZG93bjogbnVtYmVyO1xyXG4gIHByaXZhdGUga2VlcGFsaXZlRW5hYmxlZCA9IGZhbHNlO1xyXG4gIHByaXZhdGUga2VlcGFsaXZlU3ZjOiBLZWVwYWxpdmVTdmM7XHJcblxyXG4gIHB1YmxpYyBvbklkbGVTdGFydDogRXZlbnRFbWl0dGVyPGFueT4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XHJcbiAgcHVibGljIG9uSWRsZUVuZDogRXZlbnRFbWl0dGVyPGFueT4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XHJcbiAgcHVibGljIG9uVGltZW91dFdhcm5pbmc6IEV2ZW50RW1pdHRlcjxudW1iZXI+ID0gbmV3IEV2ZW50RW1pdHRlcjxudW1iZXI+KCk7XHJcbiAgcHVibGljIG9uVGltZW91dDogRXZlbnRFbWl0dGVyPG51bWJlcj4gPSBuZXcgRXZlbnRFbWl0dGVyPG51bWJlcj4oKTtcclxuICBwdWJsaWMgb25JbnRlcnJ1cHQ6IEV2ZW50RW1pdHRlcjxhbnk+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xyXG5cclxuICBba2V5OiBzdHJpbmddOiBhbnk7XHJcblxyXG4gIGNvbnN0cnVjdG9yKFxyXG4gICAgcHJpdmF0ZSBleHBpcnk6IElkbGVFeHBpcnksXHJcbiAgICBwcml2YXRlIHpvbmU6IE5nWm9uZSxcclxuICAgIEBPcHRpb25hbCgpIGtlZXBhbGl2ZVN2Yz86IEtlZXBhbGl2ZVN2YyxcclxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvYmFuLXR5cGVzXHJcbiAgICBAT3B0aW9uYWwoKSBASW5qZWN0KFBMQVRGT1JNX0lEKSBwcml2YXRlIHBsYXRmb3JtSWQ/OiBPYmplY3RcclxuICApIHtcclxuICAgIGlmIChrZWVwYWxpdmVTdmMpIHtcclxuICAgICAgdGhpcy5rZWVwYWxpdmVTdmMgPSBrZWVwYWxpdmVTdmM7XHJcbiAgICAgIHRoaXMua2VlcGFsaXZlRW5hYmxlZCA9IHRydWU7XHJcbiAgICB9XHJcbiAgICB0aGlzLnNldElkbGluZyhmYWxzZSk7XHJcbiAgfVxyXG5cclxuICAvKlxyXG4gICAqIFNldHMgdGhlIGlkbGUgbmFtZSBmb3IgbG9jYWxTdG9yYWdlLlxyXG4gICAqIEltcG9ydGFudCB0byBzZXQgaWYgbXVsdGlwbGUgaW5zdGFuY2VzIG9mIElkbGUgd2l0aCBMb2NhbFN0b3JhZ2VFeHBpcnlcclxuICAgKiBAcGFyYW0gVGhlIG5hbWUgb2YgdGhlIGlkbGUuXHJcbiAgICovXHJcbiAgc2V0SWRsZU5hbWUoa2V5OiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLmV4cGlyeSBpbnN0YW5jZW9mIExvY2FsU3RvcmFnZUV4cGlyeSkge1xyXG4gICAgICB0aGlzLmV4cGlyeS5zZXRJZGxlTmFtZShrZXkpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFxyXG4gICAgICAgICdDYW5ub3Qgc2V0IGV4cGlyeSBrZXkgbmFtZSBiZWNhdXNlIG5vIExvY2FsU3RvcmFnZUV4cGlyeSBoYXMgYmVlbiBwcm92aWRlZC4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKlxyXG4gICAqIFJldHVybnMgd2hldGhlciBvciBub3Qga2VlcGFsaXZlIGludGVncmF0aW9uIGlzIGVuYWJsZWQuXHJcbiAgICogQHJldHVybiBUcnVlIGlmIGludGVncmF0aW9uIGlzIGVuYWJsZWQ7IG90aGVyd2lzZSwgZmFsc2UuXHJcbiAgICovXHJcbiAgZ2V0S2VlcGFsaXZlRW5hYmxlZCgpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLmtlZXBhbGl2ZUVuYWJsZWQ7XHJcbiAgfVxyXG5cclxuICAvKlxyXG4gICAqIFNldHMgYW5kIHJldHVybnMgd2hldGhlciBvciBub3Qga2VlcGFsaXZlIGludGVncmF0aW9uIGlzIGVuYWJsZWQuXHJcbiAgICogQHBhcmFtIFRydWUgaWYgdGhlIGludGVncmF0aW9uIGlzIGVuYWJsZWQ7IG90aGVyd2lzZSwgZmFsc2UuXHJcbiAgICogQHJldHVybiBUaGUgY3VycmVudCB2YWx1ZS5cclxuICAgKi9cclxuICBzZXRLZWVwYWxpdmVFbmFibGVkKHZhbHVlOiBib29sZWFuKTogYm9vbGVhbiB7XHJcbiAgICBpZiAoIXRoaXMua2VlcGFsaXZlU3ZjKSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcihcclxuICAgICAgICAnQ2Fubm90IGVuYWJsZSBrZWVwYWxpdmUgaW50ZWdyYXRpb24gYmVjYXVzZSBubyBLZWVwYWxpdmVTdmMgaGFzIGJlZW4gcHJvdmlkZWQuJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiAodGhpcy5rZWVwYWxpdmVFbmFibGVkID0gdmFsdWUpO1xyXG4gIH1cclxuXHJcbiAgLypcclxuICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHRpbWVvdXQgdmFsdWUuXHJcbiAgICogQHJldHVybiBUaGUgdGltZW91dCB2YWx1ZSBpbiBzZWNvbmRzLlxyXG4gICAqL1xyXG4gIGdldFRpbWVvdXQoKTogbnVtYmVyIHtcclxuICAgIHJldHVybiB0aGlzLnRpbWVvdXRWYWw7XHJcbiAgfVxyXG5cclxuICAvKlxyXG4gICAqIFNldHMgdGhlIHRpbWVvdXQgdmFsdWUuXHJcbiAgICogQHBhcmFtIHNlY29uZHMgLSBUaGUgdGltZW91dCB2YWx1ZSBpbiBzZWNvbmRzLiAwIG9yIGZhbHNlIHRvIGRpc2FibGUgdGltZW91dCBmZWF0dXJlLlxyXG4gICAqIEByZXR1cm4gVGhlIGN1cnJlbnQgdmFsdWUuIElmIGRpc2FibGVkLCB0aGUgdmFsdWUgd2lsbCBiZSAwLlxyXG4gICAqL1xyXG4gIHNldFRpbWVvdXQoc2Vjb25kczogbnVtYmVyIHwgYm9vbGVhbik6IG51bWJlciB7XHJcbiAgICBpZiAoc2Vjb25kcyA9PT0gZmFsc2UpIHtcclxuICAgICAgdGhpcy50aW1lb3V0VmFsID0gMDtcclxuICAgIH0gZWxzZSBpZiAodHlwZW9mIHNlY29uZHMgPT09ICdudW1iZXInICYmIHNlY29uZHMgPj0gMCkge1xyXG4gICAgICB0aGlzLnRpbWVvdXRWYWwgPSBzZWNvbmRzO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiJ3NlY29uZHMnIGNhbiBvbmx5IGJlICdmYWxzZScgb3IgYSBwb3NpdGl2ZSBudW1iZXIuXCIpO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0aGlzLnRpbWVvdXRWYWw7XHJcbiAgfVxyXG5cclxuICAvKlxyXG4gICAqIFJldHVybnMgdGhlIGN1cnJlbnQgaWRsZSB2YWx1ZS5cclxuICAgKiBAcmV0dXJuIFRoZSBpZGxlIHZhbHVlIGluIHNlY29uZHMuXHJcbiAgICovXHJcbiAgZ2V0SWRsZSgpOiBudW1iZXIge1xyXG4gICAgcmV0dXJuIHRoaXMuaWRsZTtcclxuICB9XHJcblxyXG4gIC8qXHJcbiAgICogU2V0cyB0aGUgaWRsZSB2YWx1ZS5cclxuICAgKiBAcGFyYW0gc2Vjb25kcyAtIFRoZSBpZGxlIHZhbHVlIGluIHNlY29uZHMuXHJcbiAgICogQHJldHVybiBUaGUgaWRsZSB2YWx1ZSBpbiBzZWNvbmRzLlxyXG4gICAqL1xyXG4gIHNldElkbGUoc2Vjb25kczogbnVtYmVyKTogbnVtYmVyIHtcclxuICAgIGlmIChzZWNvbmRzIDw9IDApIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiJ3NlY29uZHMnIG11c3QgYmUgZ3JlYXRlciB6ZXJvXCIpO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiAodGhpcy5pZGxlID0gc2Vjb25kcyk7XHJcbiAgfVxyXG5cclxuICAvKlxyXG4gICAqIFJldHVybnMgdGhlIGN1cnJlbnQgYXV0b3Jlc3VtZSB2YWx1ZS5cclxuICAgKiBAcmV0dXJuIFRoZSBjdXJyZW50IHZhbHVlLlxyXG4gICAqL1xyXG4gIGdldEF1dG9SZXN1bWUoKTogQXV0b1Jlc3VtZSB7XHJcbiAgICByZXR1cm4gdGhpcy5hdXRvUmVzdW1lO1xyXG4gIH1cclxuXHJcbiAgc2V0QXV0b1Jlc3VtZSh2YWx1ZTogQXV0b1Jlc3VtZSk6IEF1dG9SZXN1bWUge1xyXG4gICAgcmV0dXJuICh0aGlzLmF1dG9SZXN1bWUgPSB2YWx1ZSk7XHJcbiAgfVxyXG5cclxuICAvKlxyXG4gICAqIFNldHMgaW50ZXJydXB0cyBmcm9tIHRoZSBzcGVjaWZpZWQgc291cmNlcy5cclxuICAgKiBAcGFyYW0gc291cmNlcyAtIEludGVycnVwdCBzb3VyY2VzLlxyXG4gICAqIEByZXR1cm4gVGhlIHJlc3VsdGluZyBpbnRlcnJ1cHRzLlxyXG4gICAqL1xyXG4gIHNldEludGVycnVwdHMoc291cmNlczogQXJyYXk8SW50ZXJydXB0U291cmNlPik6IEFycmF5PEludGVycnVwdD4ge1xyXG4gICAgdGhpcy5jbGVhckludGVycnVwdHMoKTtcclxuXHJcbiAgICBjb25zdCBzZWxmID0gdGhpcztcclxuXHJcbiAgICBmb3IgKGNvbnN0IHNvdXJjZSBvZiBzb3VyY2VzKSB7XHJcbiAgICAgIGNvbnN0IG9wdGlvbnMgPSB7IHBsYXRmb3JtSWQ6IHRoaXMucGxhdGZvcm1JZCB9O1xyXG4gICAgICBjb25zdCBzdWIgPSBuZXcgSW50ZXJydXB0KHNvdXJjZSwgb3B0aW9ucyk7XHJcbiAgICAgIHN1Yi5zdWJzY3JpYmUoKGFyZ3M6IEludGVycnVwdEFyZ3MpID0+IHtcclxuICAgICAgICBzZWxmLmludGVycnVwdChhcmdzLmZvcmNlLCBhcmdzLmlubmVyQXJncyk7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgdGhpcy5pbnRlcnJ1cHRzLnB1c2goc3ViKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdGhpcy5pbnRlcnJ1cHRzO1xyXG4gIH1cclxuXHJcbiAgLypcclxuICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IGludGVycnVwdHMuXHJcbiAgICogQHJldHVybiBUaGUgY3VycmVudCBpbnRlcnJ1cHRzLlxyXG4gICAqL1xyXG4gIGdldEludGVycnVwdHMoKTogQXJyYXk8SW50ZXJydXB0PiB7XHJcbiAgICByZXR1cm4gdGhpcy5pbnRlcnJ1cHRzO1xyXG4gIH1cclxuXHJcbiAgLypcclxuICAgKiBQYXVzZXMsIHVuc3Vic2NyaWJlcywgYW5kIGNsZWFycyB0aGUgY3VycmVudCBpbnRlcnJ1cHQgc3Vic2NyaXB0aW9ucy5cclxuICAgKi9cclxuICBjbGVhckludGVycnVwdHMoKTogdm9pZCB7XHJcbiAgICBmb3IgKGNvbnN0IHN1YiBvZiB0aGlzLmludGVycnVwdHMpIHtcclxuICAgICAgc3ViLnBhdXNlKCk7XHJcbiAgICAgIHN1Yi51bnN1YnNjcmliZSgpO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuaW50ZXJydXB0cy5sZW5ndGggPSAwO1xyXG4gIH1cclxuXHJcbiAgLypcclxuICAgKiBSZXR1cm5zIHdoZXRoZXIgb3Igbm90IHRoZSBzZXJ2aWNlIGlzIHJ1bm5pbmcgaS5lLiB3YXRjaGluZyBmb3IgaWRsZW5lc3MuXHJcbiAgICogQHJldHVybiBUcnVlIGlmIHNlcnZpY2UgaXMgd2F0Y2hpbmc7IG90aGVyd2lzZSwgZmFsc2UuXHJcbiAgICovXHJcbiAgaXNSdW5uaW5nKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMucnVubmluZztcclxuICB9XHJcblxyXG4gIC8qXHJcbiAgICogUmV0dXJucyB3aGV0aGVyIG9yIG5vdCB0aGUgdXNlciBpcyBjb25zaWRlcmVkIGlkbGUuXHJcbiAgICogQHJldHVybiBUcnVlIGlmIHRoZSB1c2VyIGlzIGluIHRoZSBpZGxlIHN0YXRlOyBvdGhlcndpc2UsIGZhbHNlLlxyXG4gICAqL1xyXG4gIGlzSWRsaW5nKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMuaWRsaW5nO1xyXG4gIH1cclxuXHJcbiAgLypcclxuICAgKiBTdGFydHMgd2F0Y2hpbmcgZm9yIGluYWN0aXZpdHkuXHJcbiAgICovXHJcbiAgd2F0Y2goc2tpcEV4cGlyeT86IGJvb2xlYW4pOiB2b2lkIHtcclxuICAgIHRoaXMuc2FmZUNsZWFySW50ZXJ2YWwoJ2lkbGVIYW5kbGUnKTtcclxuICAgIHRoaXMuc2FmZUNsZWFySW50ZXJ2YWwoJ3RpbWVvdXRIYW5kbGUnKTtcclxuXHJcbiAgICBjb25zdCB0aW1lb3V0ID0gIXRoaXMudGltZW91dFZhbCA/IDAgOiB0aGlzLnRpbWVvdXRWYWw7XHJcbiAgICBpZiAoIXNraXBFeHBpcnkpIHtcclxuICAgICAgY29uc3QgdmFsdWUgPSBuZXcgRGF0ZShcclxuICAgICAgICB0aGlzLmV4cGlyeS5ub3coKS5nZXRUaW1lKCkgKyAodGhpcy5pZGxlICsgdGltZW91dCkgKiAxMDAwXHJcbiAgICAgICk7XHJcbiAgICAgIHRoaXMuZXhwaXJ5Lmxhc3QodmFsdWUpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLmlkbGluZykge1xyXG4gICAgICB0aGlzLnRvZ2dsZVN0YXRlKCk7XHJcbiAgICB9XHJcbiAgICBpZiAoIXRoaXMucnVubmluZykge1xyXG4gICAgICB0aGlzLnN0YXJ0S2VlcGFsaXZlKCk7XHJcbiAgICAgIHRoaXMudG9nZ2xlSW50ZXJydXB0cyh0cnVlKTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLnJ1bm5pbmcgPSB0cnVlO1xyXG5cclxuICAgIGNvbnN0IHdhdGNoRm4gPSAoKSA9PiB7XHJcbiAgICAgIHRoaXMuem9uZS5ydW4oKCkgPT4ge1xyXG4gICAgICAgIGNvbnN0IGRpZmYgPSB0aGlzLmdldEV4cGlyeURpZmYodGltZW91dCk7XHJcbiAgICAgICAgaWYgKGRpZmYgPiAwKSB7XHJcbiAgICAgICAgICB0aGlzLnNhZmVDbGVhckludGVydmFsKCdpZGxlSGFuZGxlJyk7XHJcbiAgICAgICAgICB0aGlzLnNldElkbGVJbnRlcnZhbE91dHNpZGVPZlpvbmUod2F0Y2hGbiwgZGlmZik7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHRoaXMudG9nZ2xlU3RhdGUoKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfTtcclxuXHJcbiAgICB0aGlzLnNldElkbGVJbnRlcnZhbE91dHNpZGVPZlpvbmUod2F0Y2hGbiwgdGhpcy5pZGxlICogMTAwMCk7XHJcbiAgfVxyXG5cclxuICAvKlxyXG4gICAqIEFsbG93cyBwcm90cmFjdG9yIHRlc3RzIHRvIGNhbGwgd2FpdEZvckFuZ3VsYXIgd2l0aG91dCBoYW5naW5nXHJcbiAgICovXHJcbiAgc2V0SWRsZUludGVydmFsT3V0c2lkZU9mWm9uZSh3YXRjaEZuOiAoKSA9PiB2b2lkLCBmcmVxdWVuY3k6IG51bWJlcik6IHZvaWQge1xyXG4gICAgdGhpcy56b25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+IHtcclxuICAgICAgdGhpcy5pZGxlSGFuZGxlID0gc2V0SW50ZXJ2YWwod2F0Y2hGbiwgZnJlcXVlbmN5KTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLypcclxuICAgKiBTdG9wcyB3YXRjaGluZyBmb3IgaW5hY3Rpdml0eS5cclxuICAgKi9cclxuICBzdG9wKCk6IHZvaWQge1xyXG4gICAgdGhpcy5zdG9wS2VlcGFsaXZlKCk7XHJcblxyXG4gICAgdGhpcy50b2dnbGVJbnRlcnJ1cHRzKGZhbHNlKTtcclxuXHJcbiAgICB0aGlzLnNhZmVDbGVhckludGVydmFsKCdpZGxlSGFuZGxlJyk7XHJcbiAgICB0aGlzLnNhZmVDbGVhckludGVydmFsKCd0aW1lb3V0SGFuZGxlJyk7XHJcblxyXG4gICAgdGhpcy5zZXRJZGxpbmcoZmFsc2UpO1xyXG4gICAgdGhpcy5ydW5uaW5nID0gZmFsc2U7XHJcblxyXG4gICAgdGhpcy5leHBpcnkubGFzdChudWxsKTtcclxuICB9XHJcblxyXG4gIC8qXHJcbiAgICogRm9yY2VzIGEgdGltZW91dCBldmVudCBhbmQgc3RhdGUuXHJcbiAgICovXHJcbiAgdGltZW91dCgpOiB2b2lkIHtcclxuICAgIHRoaXMuc3RvcEtlZXBhbGl2ZSgpO1xyXG5cclxuICAgIHRoaXMudG9nZ2xlSW50ZXJydXB0cyhmYWxzZSk7XHJcblxyXG4gICAgdGhpcy5zYWZlQ2xlYXJJbnRlcnZhbCgnaWRsZUhhbmRsZScpO1xyXG4gICAgdGhpcy5zYWZlQ2xlYXJJbnRlcnZhbCgndGltZW91dEhhbmRsZScpO1xyXG5cclxuICAgIHRoaXMuc2V0SWRsaW5nKHRydWUpO1xyXG4gICAgdGhpcy5ydW5uaW5nID0gZmFsc2U7XHJcbiAgICB0aGlzLmNvdW50ZG93biA9IDA7XHJcblxyXG4gICAgdGhpcy5vblRpbWVvdXQuZW1pdChudWxsKTtcclxuICB9XHJcblxyXG4gIC8qXHJcbiAgICogU2lnbmFscyB0aGF0IHVzZXIgYWN0aXZpdHkgaGFzIG9jY3VycmVkLlxyXG4gICAqIEBwYXJhbSBmb3JjZSAtIEZvcmNlcyB3YXRjaCB0byBiZSBjYWxsZWQsIHVubGVzcyB0aGV5IGFyZSB0aW1lZCBvdXQuXHJcbiAgICogQHBhcmFtIGV2ZW50QXJncyAtIE9wdGlvbmFsIHNvdXJjZSBldmVudCBhcmd1bWVudHMuXHJcbiAgICovXHJcbiAgaW50ZXJydXB0KGZvcmNlPzogYm9vbGVhbiwgZXZlbnRBcmdzPzogYW55KTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMucnVubmluZykge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMudGltZW91dFZhbCAmJiB0aGlzLmV4cGlyeS5pc0V4cGlyZWQoKSkge1xyXG4gICAgICB0aGlzLnRpbWVvdXQoKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgdGhpcy5vbkludGVycnVwdC5lbWl0KGV2ZW50QXJncyk7XHJcblxyXG4gICAgaWYgKFxyXG4gICAgICBmb3JjZSA9PT0gdHJ1ZSB8fFxyXG4gICAgICB0aGlzLmF1dG9SZXN1bWUgPT09IEF1dG9SZXN1bWUuaWRsZSB8fFxyXG4gICAgICAodGhpcy5hdXRvUmVzdW1lID09PSBBdXRvUmVzdW1lLm5vdElkbGUgJiYgIXRoaXMuZXhwaXJ5LmlkbGluZygpKVxyXG4gICAgKSB7XHJcbiAgICAgIHRoaXMud2F0Y2goZm9yY2UpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzZXRJZGxpbmcodmFsdWU6IGJvb2xlYW4pOiB2b2lkIHtcclxuICAgIHRoaXMuaWRsaW5nID0gdmFsdWU7XHJcbiAgICB0aGlzLmV4cGlyeS5pZGxpbmcodmFsdWUpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSB0b2dnbGVTdGF0ZSgpOiB2b2lkIHtcclxuICAgIHRoaXMuc2V0SWRsaW5nKCF0aGlzLmlkbGluZyk7XHJcblxyXG4gICAgaWYgKHRoaXMuaWRsaW5nKSB7XHJcbiAgICAgIHRoaXMub25JZGxlU3RhcnQuZW1pdChudWxsKTtcclxuICAgICAgdGhpcy5zdG9wS2VlcGFsaXZlKCk7XHJcblxyXG4gICAgICBpZiAodGhpcy50aW1lb3V0VmFsID4gMCkge1xyXG4gICAgICAgIHRoaXMuY291bnRkb3duID0gdGhpcy50aW1lb3V0VmFsO1xyXG4gICAgICAgIHRoaXMuZG9Db3VudGRvd24oKTtcclxuICAgICAgICB0aGlzLnNldFRpbW91dEludGVydmFsT3V0c2lkZVpvbmUoKCkgPT4ge1xyXG4gICAgICAgICAgdGhpcy5kb0NvdW50ZG93bkluWm9uZSgpO1xyXG4gICAgICAgIH0sIDEwMDApO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLnRvZ2dsZUludGVycnVwdHModHJ1ZSk7XHJcbiAgICAgIHRoaXMub25JZGxlRW5kLmVtaXQobnVsbCk7XHJcbiAgICAgIHRoaXMuc3RhcnRLZWVwYWxpdmUoKTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLnNhZmVDbGVhckludGVydmFsKCdpZGxlSGFuZGxlJyk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHNldFRpbW91dEludGVydmFsT3V0c2lkZVpvbmUoXHJcbiAgICBpbnRlcnZhbEZuOiAoKSA9PiB2b2lkLFxyXG4gICAgZnJlcXVlbmN5OiBudW1iZXJcclxuICApIHtcclxuICAgIHRoaXMuem9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PiB7XHJcbiAgICAgIHRoaXMudGltZW91dEhhbmRsZSA9IHNldEludGVydmFsKCgpID0+IHtcclxuICAgICAgICBpbnRlcnZhbEZuKCk7XHJcbiAgICAgIH0sIGZyZXF1ZW5jeSk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdG9nZ2xlSW50ZXJydXB0cyhyZXN1bWU6IGJvb2xlYW4pOiB2b2lkIHtcclxuICAgIGZvciAoY29uc3QgaW50ZXJydXB0IG9mIHRoaXMuaW50ZXJydXB0cykge1xyXG4gICAgICBpZiAocmVzdW1lKSB7XHJcbiAgICAgICAgaW50ZXJydXB0LnJlc3VtZSgpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGludGVycnVwdC5wYXVzZSgpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGdldEV4cGlyeURpZmYodGltZW91dDogbnVtYmVyKTogbnVtYmVyIHtcclxuICAgIGNvbnN0IG5vdzogRGF0ZSA9IHRoaXMuZXhwaXJ5Lm5vdygpO1xyXG4gICAgY29uc3QgbGFzdDogRGF0ZSA9IHRoaXMuZXhwaXJ5Lmxhc3QoKSB8fCBub3c7XHJcbiAgICByZXR1cm4gbGFzdC5nZXRUaW1lKCkgLSBub3cuZ2V0VGltZSgpIC0gdGltZW91dCAqIDEwMDA7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGRvQ291bnRkb3duSW5ab25lKCk6IHZvaWQge1xyXG4gICAgdGhpcy56b25lLnJ1bigoKSA9PiB7XHJcbiAgICAgIHRoaXMuZG9Db3VudGRvd24oKTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBkb0NvdW50ZG93bigpOiB2b2lkIHtcclxuICAgIGNvbnN0IGRpZmYgPSB0aGlzLmdldEV4cGlyeURpZmYodGhpcy50aW1lb3V0VmFsKTtcclxuICAgIGlmIChkaWZmID4gMCkge1xyXG4gICAgICB0aGlzLnNhZmVDbGVhckludGVydmFsKCd0aW1lb3V0SGFuZGxlJyk7XHJcbiAgICAgIHRoaXMuaW50ZXJydXB0KHRydWUpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCF0aGlzLmlkbGluZykge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMuY291bnRkb3duIDw9IDApIHtcclxuICAgICAgdGhpcy50aW1lb3V0KCk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLm9uVGltZW91dFdhcm5pbmcuZW1pdCh0aGlzLmNvdW50ZG93bik7XHJcbiAgICB0aGlzLmNvdW50ZG93bi0tO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzYWZlQ2xlYXJJbnRlcnZhbChoYW5kbGVOYW1lOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGNvbnN0IGhhbmRsZSA9IHRoaXNbaGFuZGxlTmFtZV07XHJcbiAgICBpZiAoaGFuZGxlICE9PSBudWxsICYmIHR5cGVvZiBoYW5kbGUgIT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIGNsZWFySW50ZXJ2YWwodGhpc1toYW5kbGVOYW1lXSk7XHJcbiAgICAgIHRoaXNbaGFuZGxlTmFtZV0gPSBudWxsO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzdGFydEtlZXBhbGl2ZSgpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5rZWVwYWxpdmVTdmMgfHwgIXRoaXMua2VlcGFsaXZlRW5hYmxlZCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMucnVubmluZykge1xyXG4gICAgICB0aGlzLmtlZXBhbGl2ZVN2Yy5waW5nKCk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5rZWVwYWxpdmVTdmMuc3RhcnQoKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgc3RvcEtlZXBhbGl2ZSgpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5rZWVwYWxpdmVTdmMgfHwgIXRoaXMua2VlcGFsaXZlRW5hYmxlZCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5rZWVwYWxpdmVTdmMuc3RvcCgpO1xyXG4gIH1cclxuXHJcbiAgLypcclxuICAgKiBDYWxsZWQgYnkgQW5ndWxhciB3aGVuIGRlc3Ryb3lpbmcgdGhlIGluc3RhbmNlLlxyXG4gICAqL1xyXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xyXG4gICAgdGhpcy5zdG9wKCk7XHJcbiAgICB0aGlzLmNsZWFySW50ZXJydXB0cygpO1xyXG4gIH1cclxufVxyXG4iXX0=