@cradokski/fullscreen
Version:
An Angular service and **directives** that provide **fullscreen control**, **reactive state**, and **template-friendly utilities**.
142 lines • 19.9 kB
JavaScript
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import * as i0 from "@angular/core";
export class FullScreenService {
constructor(zone) {
this.zone = zone;
/** Internal flag for synchronous API compatibility */
this.isFullscreenFlag = false;
/** Timestamp for double-tap detection */
this.lastTapTime = null;
/** For testing: allows mocking time */
this.nowFn = () => Date.now();
/** RxJS state observable for template bindings */
this.fullscreen$ = new BehaviorSubject({
active: false,
element: null
});
// ---------------------------------------------------------------------
// DOM fullscreen event handler
// ---------------------------------------------------------------------
this.handleFullscreenEvent = () => {
const el = this.getFullscreenElement();
const isFs = !!el;
this.isFullscreenFlag = isFs;
this.zone.run(() => {
this.fullscreen$.next({ active: isFs, element: el });
});
};
[
'fullscreenchange',
'webkitfullscreenchange',
'mozfullscreenchange',
'MSFullscreenChange'
].forEach(event => document.addEventListener(event, this.handleFullscreenEvent));
}
// ---------------------------------------------------------------------
// Internal helpers
// ---------------------------------------------------------------------
/** Returns the currently fullscreen element (cross-browser) */
getFullscreenElement() {
return (document.fullscreenElement ||
document.webkitFullscreenElement ||
document.mozFullScreenElement ||
document.msFullscreenElement ||
null);
}
/** Request fullscreen on a specific element (default: <html>) */
async enterFullscreenElement(element = document.documentElement) {
const request = element.requestFullscreen ??
element.webkitRequestFullscreen ??
element.mozRequestFullScreen ??
element.msRequestFullscreen;
if (!request) {
throw new Error('Fullscreen API not supported');
}
await request.call(element);
return 'entered';
}
/** Exit fullscreen (cross-browser) */
async exitFullscreenElement() {
const exit = document.exitFullscreen ??
document.webkitExitFullscreen ??
document.mozCancelFullScreen ??
document.msExitFullscreen;
if (!exit) {
throw new Error('Fullscreen API not supported');
}
await exit.call(document);
return 'exited';
}
/** Sync check used by directives and consumers */
isFullscreenActive() {
const active = !!this.getFullscreenElement();
this.isFullscreenFlag = active;
return active;
}
// ---------------------------------------------------------------------
// Public API (backwards compatible)
// ---------------------------------------------------------------------
enterFullscreen(element) {
this.enterFullscreenElement(element)
.then(() => (this.isFullscreenFlag = true))
.catch(() => { });
}
exitFullscreen() {
this.exitFullscreenElement()
.then(() => (this.isFullscreenFlag = false))
.catch(() => { });
}
toggleFullscreen(element) {
return this.isFullscreenActive()
? this.exitFullscreenElement()
: this.enterFullscreenElement(element);
}
ensureFullscreen(element) {
return this.isFullscreenActive()
? Promise.resolve('entered')
: this.enterFullscreenElement(element);
}
ensureExitedFullscreen() {
return this.isFullscreenActive()
? this.exitFullscreenElement()
: Promise.resolve('exited');
}
// ---------------------------------------------------------------------
// Double-tap browser toggle
// ---------------------------------------------------------------------
browserFsToggle(options) {
this.browserFsToggleAsync(options);
return this.isFullscreenFlag;
}
async browserFsToggleAsync(options) {
const delayMs = options?.delayMs ?? 300;
if (options?.requireDoubleTap) {
const now = this.nowFn();
if (this.lastTapTime && now - this.lastTapTime < delayMs) {
this.lastTapTime = 0;
const status = await this.toggleFullscreen();
return status === 'entered';
}
this.lastTapTime = now;
return false;
}
const status = await this.toggleFullscreen();
return status === 'entered';
}
// ---------------------------------------------------------------------
// Watch API (unified)
// ---------------------------------------------------------------------
/** Subscribe to fullscreen changes; returns unwatch() */
watchFullscreen(callback) {
const sub = this.fullscreen$.subscribe(({ active, element }) => callback(active, element));
return () => sub.unsubscribe();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FullScreenService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FullScreenService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FullScreenService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [{ type: i0.NgZone }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnVsbHNjcmVlbi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvZnVsbHNjcmVlbi9zcmMvbGliL2Z1bGxzY3JlZW4uc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFVLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxNQUFNLENBQUM7O0FBY3ZDLE1BQU0sT0FBTyxpQkFBaUI7SUFnQjVCLFlBQW9CLElBQVk7UUFBWixTQUFJLEdBQUosSUFBSSxDQUFRO1FBZmhDLHNEQUFzRDtRQUM5QyxxQkFBZ0IsR0FBRyxLQUFLLENBQUM7UUFFakMseUNBQXlDO1FBQ2pDLGdCQUFXLEdBQWtCLElBQUksQ0FBQztRQUUxQyx1Q0FBdUM7UUFDL0IsVUFBSyxHQUFpQixHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFFL0Msa0RBQWtEO1FBQ3pDLGdCQUFXLEdBQUcsSUFBSSxlQUFlLENBQWtCO1lBQzFELE1BQU0sRUFBRSxLQUFLO1lBQ2IsT0FBTyxFQUFFLElBQUk7U0FDZCxDQUFDLENBQUM7UUFrSkgsd0VBQXdFO1FBQ3hFLCtCQUErQjtRQUMvQix3RUFBd0U7UUFFaEUsMEJBQXFCLEdBQUcsR0FBRyxFQUFFO1lBQ25DLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO1lBQ3ZDLE1BQU0sSUFBSSxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFFbEIsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksQ0FBQztZQUU3QixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUU7Z0JBQ2pCLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUN2RCxD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QUUsQ0FBQztRQUM3QyxPQUFPLE1BQU0sS0FBSyxTQUFTLENBQUM7SUFDOUIsQ0FBQztJQUVELHdFQUF3RTtJQUN4RSxzQkFBc0I7SUFDdEIsd0VBQXdFO0lBRXhFLHlEQUF5RDtJQUN6RCxlQUFlLENBQUMsUUFBNEI7UUFDMUMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsRUFBRSxFQUFFLENBQzdELFFBQVEsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQzFCLENBQUM7UUFDRixPQUFPLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNqQyxDQUFDOytHQTlKVSxpQkFBaUI7bUhBQWpCLGlCQUFpQixjQURKLE1BQU07OzRGQUNuQixpQkFBaUI7a0JBRDdCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgTmdab25lIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCB9IGZyb20gJ3J4anMnO1xyXG5cclxuZXhwb3J0IHR5cGUgRnVsbHNjcmVlblN0YXR1cyA9ICdlbnRlcmVkJyB8ICdleGl0ZWQnO1xyXG5leHBvcnQgdHlwZSBGdWxsc2NyZWVuQ2FsbGJhY2sgPSAoaXNGdWxsc2NyZWVuOiBib29sZWFuLCBlbGVtZW50OiBFbGVtZW50IHwgbnVsbCkgPT4gdm9pZDtcclxuXHJcbi8qKiBSZWFjdGl2ZSBmdWxsc2NyZWVuIHN0YXRlIGZvciB0ZW1wbGF0ZXMgYW5kIGRpcmVjdGl2ZXMgKi9cclxuZXhwb3J0IGludGVyZmFjZSBGdWxsc2NyZWVuU3RhdGUge1xyXG4gIC8qKiBXaGV0aGVyIGFueSBlbGVtZW50IGlzIGN1cnJlbnRseSBmdWxsc2NyZWVuICovXHJcbiAgYWN0aXZlOiBib29sZWFuO1xyXG4gIC8qKiBXaGljaCBlbGVtZW50IGlzIGZ1bGxzY3JlZW4gKGlmIGFueSkgKi9cclxuICBlbGVtZW50OiBFbGVtZW50IHwgbnVsbDtcclxufVxyXG5cclxuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcclxuZXhwb3J0IGNsYXNzIEZ1bGxTY3JlZW5TZXJ2aWNlIHtcclxuICAvKiogSW50ZXJuYWwgZmxhZyBmb3Igc3luY2hyb25vdXMgQVBJIGNvbXBhdGliaWxpdHkgKi9cclxuICBwcml2YXRlIGlzRnVsbHNjcmVlbkZsYWcgPSBmYWxzZTtcclxuXHJcbiAgLyoqIFRpbWVzdGFtcCBmb3IgZG91YmxlLXRhcCBkZXRlY3Rpb24gKi9cclxuICBwcml2YXRlIGxhc3RUYXBUaW1lOiBudW1iZXIgfCBudWxsID0gbnVsbDtcclxuXHJcbiAgLyoqIEZvciB0ZXN0aW5nOiBhbGxvd3MgbW9ja2luZyB0aW1lICovXHJcbiAgcHJpdmF0ZSBub3dGbjogKCkgPT4gbnVtYmVyID0gKCkgPT4gRGF0ZS5ub3coKTtcclxuXHJcbiAgLyoqIFJ4SlMgc3RhdGUgb2JzZXJ2YWJsZSBmb3IgdGVtcGxhdGUgYmluZGluZ3MgKi9cclxuICByZWFkb25seSBmdWxsc2NyZWVuJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8RnVsbHNjcmVlblN0YXRlPih7XHJcbiAgICBhY3RpdmU6IGZhbHNlLFxyXG4gICAgZWxlbWVudDogbnVsbFxyXG4gIH0pO1xyXG5cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHpvbmU6IE5nWm9uZSkge1xyXG4gICAgW1xyXG4gICAgICAnZnVsbHNjcmVlbmNoYW5nZScsXHJcbiAgICAgICd3ZWJraXRmdWxsc2NyZWVuY2hhbmdlJyxcclxuICAgICAgJ21vemZ1bGxzY3JlZW5jaGFuZ2UnLFxyXG4gICAgICAnTVNGdWxsc2NyZWVuQ2hhbmdlJ1xyXG4gICAgXS5mb3JFYWNoKGV2ZW50ID0+XHJcbiAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoZXZlbnQsIHRoaXMuaGFuZGxlRnVsbHNjcmVlbkV2ZW50KVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4gIC8vIEludGVybmFsIGhlbHBlcnNcclxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcbiAgLyoqIFJldHVybnMgdGhlIGN1cnJlbnRseSBmdWxsc2NyZWVuIGVsZW1lbnQgKGNyb3NzLWJyb3dzZXIpICovXHJcbiAgcHJpdmF0ZSBnZXRGdWxsc2NyZWVuRWxlbWVudCgpOiBFbGVtZW50IHwgbnVsbCB7XHJcbiAgICByZXR1cm4gKFxyXG4gICAgICBkb2N1bWVudC5mdWxsc2NyZWVuRWxlbWVudCB8fFxyXG4gICAgICAoZG9jdW1lbnQgYXMgYW55KS53ZWJraXRGdWxsc2NyZWVuRWxlbWVudCB8fFxyXG4gICAgICAoZG9jdW1lbnQgYXMgYW55KS5tb3pGdWxsU2NyZWVuRWxlbWVudCB8fFxyXG4gICAgICAoZG9jdW1lbnQgYXMgYW55KS5tc0Z1bGxzY3JlZW5FbGVtZW50IHx8XHJcbiAgICAgIG51bGxcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvKiogUmVxdWVzdCBmdWxsc2NyZWVuIG9uIGEgc3BlY2lmaWMgZWxlbWVudCAoZGVmYXVsdDogPGh0bWw+KSAqL1xyXG4gIHByaXZhdGUgYXN5bmMgZW50ZXJGdWxsc2NyZWVuRWxlbWVudChcclxuICAgIGVsZW1lbnQ6IEhUTUxFbGVtZW50ID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50XHJcbiAgKTogUHJvbWlzZTxGdWxsc2NyZWVuU3RhdHVzPiB7XHJcbiAgICBjb25zdCByZXF1ZXN0ID1cclxuICAgICAgZWxlbWVudC5yZXF1ZXN0RnVsbHNjcmVlbiA/P1xyXG4gICAgICAoZWxlbWVudCBhcyBhbnkpLndlYmtpdFJlcXVlc3RGdWxsc2NyZWVuID8/XHJcbiAgICAgIChlbGVtZW50IGFzIGFueSkubW96UmVxdWVzdEZ1bGxTY3JlZW4gPz9cclxuICAgICAgKGVsZW1lbnQgYXMgYW55KS5tc1JlcXVlc3RGdWxsc2NyZWVuO1xyXG5cclxuICAgIGlmICghcmVxdWVzdCkge1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Z1bGxzY3JlZW4gQVBJIG5vdCBzdXBwb3J0ZWQnKTtcclxuICAgIH1cclxuXHJcbiAgICBhd2FpdCByZXF1ZXN0LmNhbGwoZWxlbWVudCk7XHJcbiAgICByZXR1cm4gJ2VudGVyZWQnO1xyXG4gIH1cclxuXHJcbiAgLyoqIEV4aXQgZnVsbHNjcmVlbiAoY3Jvc3MtYnJvd3NlcikgKi9cclxuICBwcml2YXRlIGFzeW5jIGV4aXRGdWxsc2NyZWVuRWxlbWVudCgpOiBQcm9taXNlPEZ1bGxzY3JlZW5TdGF0dXM+IHtcclxuICAgIGNvbnN0IGV4aXQgPVxyXG4gICAgICBkb2N1bWVudC5leGl0RnVsbHNjcmVlbiA/P1xyXG4gICAgICAoZG9jdW1lbnQgYXMgYW55KS53ZWJraXRFeGl0RnVsbHNjcmVlbiA/P1xyXG4gICAgICAoZG9jdW1lbnQgYXMgYW55KS5tb3pDYW5jZWxGdWxsU2NyZWVuID8/XHJcbiAgICAgIChkb2N1bWVudCBhcyBhbnkpLm1zRXhpdEZ1bGxzY3JlZW47XHJcblxyXG4gICAgaWYgKCFleGl0KSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcignRnVsbHNjcmVlbiBBUEkgbm90IHN1cHBvcnRlZCcpO1xyXG4gICAgfVxyXG5cclxuICAgIGF3YWl0IGV4aXQuY2FsbChkb2N1bWVudCk7XHJcbiAgICByZXR1cm4gJ2V4aXRlZCc7XHJcbiAgfVxyXG5cclxuICAvKiogU3luYyBjaGVjayB1c2VkIGJ5IGRpcmVjdGl2ZXMgYW5kIGNvbnN1bWVycyAqL1xyXG4gIGlzRnVsbHNjcmVlbkFjdGl2ZSgpOiBib29sZWFuIHtcclxuICAgIGNvbnN0IGFjdGl2ZSA9ICEhdGhpcy5nZXRGdWxsc2NyZWVuRWxlbWVudCgpO1xyXG4gICAgdGhpcy5pc0Z1bGxzY3JlZW5GbGFnID0gYWN0aXZlO1xyXG4gICAgcmV0dXJuIGFjdGl2ZTtcclxuICB9XHJcblxyXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4gIC8vIFB1YmxpYyBBUEkgKGJhY2t3YXJkcyBjb21wYXRpYmxlKVxyXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuICBlbnRlckZ1bGxzY3JlZW4oZWxlbWVudD86IEhUTUxFbGVtZW50KTogdm9pZCB7XHJcbiAgICB0aGlzLmVudGVyRnVsbHNjcmVlbkVsZW1lbnQoZWxlbWVudClcclxuICAgICAgLnRoZW4oKCkgPT4gKHRoaXMuaXNGdWxsc2NyZWVuRmxhZyA9IHRydWUpKVxyXG4gICAgICAuY2F0Y2goKCkgPT4geyB9KTtcclxuICB9XHJcblxyXG4gIGV4aXRGdWxsc2NyZWVuKCk6IHZvaWQge1xyXG4gICAgdGhpcy5leGl0RnVsbHNjcmVlbkVsZW1lbnQoKVxyXG4gICAgICAudGhlbigoKSA9PiAodGhpcy5pc0Z1bGxzY3JlZW5GbGFnID0gZmFsc2UpKVxyXG4gICAgICAuY2F0Y2goKCkgPT4geyB9KTtcclxuICB9XHJcblxyXG4gIHRvZ2dsZUZ1bGxzY3JlZW4oZWxlbWVudD86IEhUTUxFbGVtZW50KTogUHJvbWlzZTxGdWxsc2NyZWVuU3RhdHVzPiB7XHJcbiAgICByZXR1cm4gdGhpcy5pc0Z1bGxzY3JlZW5BY3RpdmUoKVxyXG4gICAgICA/IHRoaXMuZXhpdEZ1bGxzY3JlZW5FbGVtZW50KClcclxuICAgICAgOiB0aGlzLmVudGVyRnVsbHNjcmVlbkVsZW1lbnQoZWxlbWVudCk7XHJcbiAgfVxyXG5cclxuICBlbnN1cmVGdWxsc2NyZWVuKGVsZW1lbnQ/OiBIVE1MRWxlbWVudCk6IFByb21pc2U8RnVsbHNjcmVlblN0YXR1cz4ge1xyXG4gICAgcmV0dXJuIHRoaXMuaXNGdWxsc2NyZWVuQWN0aXZlKClcclxuICAgICAgPyBQcm9taXNlLnJlc29sdmUoJ2VudGVyZWQnKVxyXG4gICAgICA6IHRoaXMuZW50ZXJGdWxsc2NyZWVuRWxlbWVudChlbGVtZW50KTtcclxuICB9XHJcblxyXG4gIGVuc3VyZUV4aXRlZEZ1bGxzY3JlZW4oKTogUHJvbWlzZTxGdWxsc2NyZWVuU3RhdHVzPiB7XHJcbiAgICByZXR1cm4gdGhpcy5pc0Z1bGxzY3JlZW5BY3RpdmUoKVxyXG4gICAgICA/IHRoaXMuZXhpdEZ1bGxzY3JlZW5FbGVtZW50KClcclxuICAgICAgOiBQcm9taXNlLnJlc29sdmUoJ2V4aXRlZCcpO1xyXG4gIH1cclxuXHJcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcbiAgLy8gRG91YmxlLXRhcCBicm93c2VyIHRvZ2dsZVxyXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuICBicm93c2VyRnNUb2dnbGUob3B0aW9ucz86IHsgcmVxdWlyZURvdWJsZVRhcD86IGJvb2xlYW47IGRlbGF5TXM/OiBudW1iZXIgfSk6IGJvb2xlYW4ge1xyXG4gICAgdGhpcy5icm93c2VyRnNUb2dnbGVBc3luYyhvcHRpb25zKTtcclxuICAgIHJldHVybiB0aGlzLmlzRnVsbHNjcmVlbkZsYWc7XHJcbiAgfVxyXG5cclxuICBhc3luYyBicm93c2VyRnNUb2dnbGVBc3luYyhcclxuICAgIG9wdGlvbnM/OiB7IHJlcXVpcmVEb3VibGVUYXA/OiBib29sZWFuOyBkZWxheU1zPzogbnVtYmVyIH1cclxuICApOiBQcm9taXNlPGJvb2xlYW4+IHtcclxuICAgIGNvbnN0IGRlbGF5TXMgPSBvcHRpb25zPy5kZWxheU1zID8/IDMwMDtcclxuXHJcbiAgICBpZiAob3B0aW9ucz8ucmVxdWlyZURvdWJsZVRhcCkge1xyXG4gICAgICBjb25zdCBub3cgPSB0aGlzLm5vd0ZuKCk7XHJcblxyXG4gICAgICBpZiAodGhpcy5sYXN0VGFwVGltZSAmJiBub3cgLSB0aGlzLmxhc3RUYXBUaW1lIDwgZGVsYXlNcykge1xyXG4gICAgICAgIHRoaXMubGFzdFRhcFRpbWUgPSAwO1xyXG4gICAgICAgIGNvbnN0IHN0YXR1cyA9IGF3YWl0IHRoaXMudG9nZ2xlRnVsbHNjcmVlbigpO1xyXG4gICAgICAgIHJldHVybiBzdGF0dXMgPT09ICdlbnRlcmVkJztcclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy5sYXN0VGFwVGltZSA9IG5vdztcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHN0YXR1cyA9IGF3YWl0IHRoaXMudG9nZ2xlRnVsbHNjcmVlbigpO1xyXG4gICAgcmV0dXJuIHN0YXR1cyA9PT0gJ2VudGVyZWQnO1xyXG4gIH1cclxuXHJcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcbiAgLy8gV2F0Y2ggQVBJICh1bmlmaWVkKVxyXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuICAvKiogU3Vic2NyaWJlIHRvIGZ1bGxzY3JlZW4gY2hhbmdlczsgcmV0dXJucyB1bndhdGNoKCkgKi9cclxuICB3YXRjaEZ1bGxzY3JlZW4oY2FsbGJhY2s6IEZ1bGxzY3JlZW5DYWxsYmFjayk6ICgpID0+IHZvaWQge1xyXG4gICAgY29uc3Qgc3ViID0gdGhpcy5mdWxsc2NyZWVuJC5zdWJzY3JpYmUoKHsgYWN0aXZlLCBlbGVtZW50IH0pID0+XHJcbiAgICAgIGNhbGxiYWNrKGFjdGl2ZSwgZWxlbWVudClcclxuICAgICk7XHJcbiAgICByZXR1cm4gKCkgPT4gc3ViLnVuc3Vic2NyaWJlKCk7XHJcbiAgfVxyXG5cclxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuICAvLyBET00gZnVsbHNjcmVlbiBldmVudCBoYW5kbGVyXHJcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG4gIHByaXZhdGUgaGFuZGxlRnVsbHNjcmVlbkV2ZW50ID0gKCkgPT4ge1xyXG4gICAgY29uc3QgZWwgPSB0aGlzLmdldEZ1bGxzY3JlZW5FbGVtZW50KCk7XHJcbiAgICBjb25zdCBpc0ZzID0gISFlbDtcclxuXHJcbiAgICB0aGlzLmlzRnVsbHNjcmVlbkZsYWcgPSBpc0ZzO1xyXG5cclxuICAgIHRoaXMuem9uZS5ydW4oKCkgPT4ge1xyXG4gICAgICB0aGlzLmZ1bGxzY3JlZW4kLm5leHQoeyBhY3RpdmU6IGlzRnMsIGVsZW1lbnQ6IGVsIH0pO1xyXG4gICAgfSk7XHJcbiAgfTtcclxufVxyXG4iXX0=