vibetunnel
Version:
Terminal sharing server with web interface - supports macOS, Linux, and headless environments
376 lines • 40.5 kB
JavaScript
"use strict";
/**
* Client for connecting to VibeTunnel Unix sockets
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.VibeTunnelSocketClient = void 0;
const events_1 = require("events");
const net = __importStar(require("net"));
const logger_js_1 = require("../utils/logger.js");
const socket_protocol_js_1 = require("./socket-protocol.js");
const logger = (0, logger_js_1.createLogger)('socket-client');
/**
* Unix socket client for communication between VibeTunnel web server and terminal processes.
*
* This class provides a robust client for connecting to Unix domain sockets with automatic
* reconnection, heartbeat support, and message parsing using the VibeTunnel socket protocol.
* It handles terminal control operations like stdin input, resizing, and process management.
*
* Key features:
* - Automatic reconnection with configurable delay
* - Heartbeat mechanism to detect connection health
* - Binary message protocol with length-prefixed framing
* - Event-based API for handling connection state and messages
* - macOS socket path length validation (104 char limit)
*
* @example
* ```typescript
* // Create a client for a terminal session
* const client = new VibeTunnelSocketClient('/tmp/vibetunnel/session-123.sock', {
* autoReconnect: true,
* heartbeatInterval: 30000
* });
*
* // Listen for events
* client.on('connect', () => console.log('Connected to terminal'));
* client.on('status', (status) => console.log('Terminal status:', status));
* client.on('error', (error) => console.error('Socket error:', error));
*
* // Connect and send commands
* await client.connect();
* client.sendStdin('ls -la\n');
* client.resize(80, 24);
* ```
*
* @extends EventEmitter
*/
class VibeTunnelSocketClient extends events_1.EventEmitter {
constructor(socketPath, options = {}) {
super();
this.socketPath = socketPath;
this.options = options;
this.parser = new socket_protocol_js_1.MessageParser();
this.connected = false;
this.reconnectDelay = 1000;
this.lastHeartbeat = Date.now();
// IMPORTANT: macOS has a 104 character limit for Unix socket paths
// If you get EINVAL errors when connecting, the path is likely too long
if (socketPath.length > 103) {
logger.warn(`Socket path may be too long (${socketPath.length} chars): ${socketPath}`);
}
}
/**
* Connect to the socket
*/
connect() {
return new Promise((resolve, reject) => {
if (this.connected) {
resolve();
return;
}
this.socket = net.createConnection(this.socketPath);
this.socket.setNoDelay(true);
this.socket.setKeepAlive(true, 0);
const onConnect = () => {
this.connected = true;
this.setupSocketHandlers();
this.emit('connect');
this.startHeartbeat();
cleanup();
resolve();
};
const onError = (error) => {
cleanup();
// Destroy the socket to prevent further errors
this.socket?.destroy();
this.socket = undefined;
reject(error);
};
const cleanup = () => {
this.socket?.off('connect', onConnect);
this.socket?.off('error', onError);
};
this.socket.once('connect', onConnect);
this.socket.once('error', onError);
});
}
/**
* Setup socket event handlers
*/
setupSocketHandlers() {
if (!this.socket)
return;
this.socket.on('data', (chunk) => {
this.parser.addData(chunk);
for (const { type, payload } of this.parser.parseMessages()) {
this.handleMessage(type, payload);
}
});
this.socket.on('close', () => {
this.handleDisconnect();
});
this.socket.on('error', (error) => {
logger.error(`Socket error on ${this.socketPath}:`, error);
this.emit('error', error);
});
}
/**
* Handle incoming messages
*/
handleMessage(type, payload) {
try {
const data = (0, socket_protocol_js_1.parsePayload)(type, payload);
// Emit event with message type enum name
this.emit(socket_protocol_js_1.MessageType[type], data);
// Handle heartbeat
if (type === socket_protocol_js_1.MessageType.HEARTBEAT) {
this.lastHeartbeat = Date.now();
// Echo heartbeat back
this.sendHeartbeat();
}
}
catch (error) {
logger.error('Failed to parse message:', error);
}
}
/**
* Handle disconnection
*/
handleDisconnect(error) {
this.connected = false;
this.stopHeartbeat();
this.emit('disconnect', error);
if (this.options.autoReconnect && !this.reconnectTimer) {
this.reconnectTimer = setTimeout(() => {
this.reconnectTimer = undefined;
this.connect().catch((err) => {
logger.debug(`Reconnection failed: ${err.message}`);
this.handleDisconnect(err);
});
}, this.reconnectDelay);
}
}
/**
* Start heartbeat
*/
startHeartbeat() {
if (this.options.heartbeatInterval) {
this.heartbeatInterval = setInterval(() => {
this.sendHeartbeat();
}, this.options.heartbeatInterval);
}
}
/**
* Stop heartbeat
*/
stopHeartbeat() {
if (this.heartbeatInterval) {
clearInterval(this.heartbeatInterval);
this.heartbeatInterval = undefined;
}
}
/**
* Send data to stdin
*/
sendStdin(data) {
return this.send(socket_protocol_js_1.MessageBuilder.stdin(data));
}
/**
* Send resize command
*/
resize(cols, rows) {
return this.send(socket_protocol_js_1.MessageBuilder.resize(cols, rows));
}
/**
* Send kill command
*/
kill(signal) {
return this.send(socket_protocol_js_1.MessageBuilder.kill(signal));
}
/**
* Send reset size command
*/
resetSize() {
return this.send(socket_protocol_js_1.MessageBuilder.resetSize());
}
/**
* Send update title command
*/
updateTitle(title) {
return this.send(socket_protocol_js_1.MessageBuilder.updateTitle(title));
}
/**
* Send status update
*/
sendStatus(app, status, extra) {
return this.send(socket_protocol_js_1.MessageBuilder.status(app, status, extra));
}
/**
* Send a message with type-safe payload
*/
sendMessage(type, payload) {
const message = this.buildMessage(type, payload);
return this.send(message);
}
/**
* Send a message and wait for a response
*/
async sendMessageWithResponse(requestType, payload, responseType, timeout = 5000) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
this.off(socket_protocol_js_1.MessageType[responseType], handleResponse);
this.off('error', handleError);
reject(new Error(`Request timeout waiting for ${socket_protocol_js_1.MessageType[responseType]}`));
}, timeout);
const handleResponse = (data) => {
clearTimeout(timer);
this.off('error', handleError);
resolve(data);
};
const handleError = (error) => {
clearTimeout(timer);
this.off(socket_protocol_js_1.MessageType[responseType], handleResponse);
if ('message' in error) {
reject(new Error(error.message));
}
else {
reject(error);
}
};
// Listen for response
this.once(socket_protocol_js_1.MessageType[responseType], handleResponse);
this.once('error', handleError);
const sent = this.sendMessage(requestType, payload);
if (!sent) {
clearTimeout(timer);
this.off(socket_protocol_js_1.MessageType[responseType], handleResponse);
this.off('error', handleError);
reject(new Error('Failed to send message'));
}
});
}
/**
* Build a message buffer from type and payload
*/
buildMessage(type, payload) {
switch (type) {
case socket_protocol_js_1.MessageType.STDIN_DATA:
return socket_protocol_js_1.MessageBuilder.stdin(payload);
case socket_protocol_js_1.MessageType.CONTROL_CMD: {
const cmd = payload;
switch (cmd.cmd) {
case 'resize':
return socket_protocol_js_1.MessageBuilder.resize(cmd.cols, cmd.rows);
case 'kill':
return socket_protocol_js_1.MessageBuilder.kill(cmd.signal);
case 'reset-size':
return socket_protocol_js_1.MessageBuilder.resetSize();
case 'update-title':
return socket_protocol_js_1.MessageBuilder.updateTitle(cmd.title);
default:
// For generic control commands, use frameMessage directly
return (0, socket_protocol_js_1.frameMessage)(socket_protocol_js_1.MessageType.CONTROL_CMD, cmd);
}
}
case socket_protocol_js_1.MessageType.STATUS_UPDATE: {
const statusPayload = payload;
return socket_protocol_js_1.MessageBuilder.status(statusPayload.app, statusPayload.status, statusPayload.extra);
}
case socket_protocol_js_1.MessageType.HEARTBEAT:
return socket_protocol_js_1.MessageBuilder.heartbeat();
case socket_protocol_js_1.MessageType.STATUS_REQUEST:
return socket_protocol_js_1.MessageBuilder.statusRequest();
case socket_protocol_js_1.MessageType.GIT_FOLLOW_REQUEST:
return socket_protocol_js_1.MessageBuilder.gitFollowRequest(payload);
case socket_protocol_js_1.MessageType.GIT_EVENT_NOTIFY:
return socket_protocol_js_1.MessageBuilder.gitEventNotify(payload);
default:
throw new Error(`Unsupported message type: ${type}`);
}
}
/**
* Send heartbeat
*/
sendHeartbeat() {
return this.send(socket_protocol_js_1.MessageBuilder.heartbeat());
}
/**
* Send raw message
*/
send(message) {
if (!this.connected || !this.socket) {
logger.debug('Cannot send message: not connected');
return false;
}
try {
return this.socket.write(message);
}
catch (error) {
logger.error('Failed to send message:', error);
return false;
}
}
/**
* Disconnect from the socket
*/
disconnect() {
this.options.autoReconnect = false;
this.connected = false;
this.stopHeartbeat();
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
this.reconnectTimer = undefined;
}
if (this.socket) {
this.socket.destroy();
this.socket = undefined;
}
}
/**
* Check if connected
*/
isConnected() {
return this.connected;
}
/**
* Get time since last heartbeat
*/
getTimeSinceLastHeartbeat() {
return Date.now() - this.lastHeartbeat;
}
}
exports.VibeTunnelSocketClient = VibeTunnelSocketClient;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic29ja2V0LWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zZXJ2ZXIvcHR5L3NvY2tldC1jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOztHQUVHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFSCxtQ0FBc0M7QUFDdEMseUNBQTJCO0FBQzNCLGtEQUFrRDtBQUNsRCw2REFlOEI7QUFFOUIsTUFBTSxNQUFNLEdBQUcsSUFBQSx3QkFBWSxFQUFDLGVBQWUsQ0FBQyxDQUFDO0FBVTdDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0NHO0FBQ0gsTUFBYSxzQkFBdUIsU0FBUSxxQkFBWTtJQVN0RCxZQUNtQixVQUFrQixFQUNsQixVQUdiLEVBQUU7UUFFTixLQUFLLEVBQUUsQ0FBQztRQU5TLGVBQVUsR0FBVixVQUFVLENBQVE7UUFDbEIsWUFBTyxHQUFQLE9BQU8sQ0FHbEI7UUFaQSxXQUFNLEdBQUcsSUFBSSxrQ0FBYSxFQUFFLENBQUM7UUFDN0IsY0FBUyxHQUFHLEtBQUssQ0FBQztRQUVULG1CQUFjLEdBQUcsSUFBSSxDQUFDO1FBRS9CLGtCQUFhLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBV2pDLG1FQUFtRTtRQUNuRSx3RUFBd0U7UUFDeEUsSUFBSSxVQUFVLENBQUMsTUFBTSxHQUFHLEdBQUcsRUFBRSxDQUFDO1lBQzVCLE1BQU0sQ0FBQyxJQUFJLENBQUMsZ0NBQWdDLFVBQVUsQ0FBQyxNQUFNLFlBQVksVUFBVSxFQUFFLENBQUMsQ0FBQztRQUN6RixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0gsT0FBTztRQUNMLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDckMsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7Z0JBQ25CLE9BQU8sRUFBRSxDQUFDO2dCQUNWLE9B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QUMsY0FBYyxDQUFDLENBQUM7WUFDbEMsSUFBSSxDQUFDLGNBQWMsR0FBRyxTQUFTLENBQUM7UUFDbEMsQ0FBQztRQUVELElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2hCLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDdEIsSUFBSSxDQUFDLE1BQU0sR0FBRyxTQUFTLENBQUM7UUFDMUIsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNILFdBQVc7UUFDVCxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUM7SUFDeEIsQ0FBQztJQUVEOztPQUVHO0lBQ0gseUJBQXlCO1FBQ3ZCLE9BQU8sSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUM7SUFDekMsQ0FBQztDQUNGO0FBM1ZELHdEQTJWQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ2xpZW50IGZvciBjb25uZWN0aW5nIHRvIFZpYmVUdW5uZWwgVW5peCBzb2NrZXRzXG4gKi9cblxuaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSAnZXZlbnRzJztcbmltcG9ydCAqIGFzIG5ldCBmcm9tICduZXQnO1xuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB7XG4gIHR5cGUgQ29udHJvbENvbW1hbmQsXG4gIHR5cGUgRXJyb3JNZXNzYWdlLFxuICBmcmFtZU1lc3NhZ2UsXG4gIHR5cGUgR2l0RXZlbnROb3RpZnksXG4gIHR5cGUgR2l0Rm9sbG93UmVxdWVzdCxcbiAgdHlwZSBLaWxsQ29tbWFuZCxcbiAgTWVzc2FnZUJ1aWxkZXIsXG4gIE1lc3NhZ2VQYXJzZXIsXG4gIHR5cGUgTWVzc2FnZVBheWxvYWQsXG4gIE1lc3NhZ2VUeXBlLFxuICBwYXJzZVBheWxvYWQsXG4gIHR5cGUgUmVzaXplQ29tbWFuZCxcbiAgdHlwZSBTdGF0dXNVcGRhdGUsXG4gIHR5cGUgVXBkYXRlVGl0bGVDb21tYW5kLFxufSBmcm9tICcuL3NvY2tldC1wcm90b2NvbC5qcyc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignc29ja2V0LWNsaWVudCcpO1xuXG5leHBvcnQgaW50ZXJmYWNlIFNvY2tldENsaWVudEV2ZW50cyB7XG4gIGNvbm5lY3Q6ICgpID0+IHZvaWQ7XG4gIGRpc2Nvbm5lY3Q6IChlcnJvcj86IEVycm9yKSA9PiB2b2lkO1xuICBlcnJvcjogKGVycm9yOiBFcnJvcikgPT4gdm9pZDtcbiAgLy8gTWVzc2FnZS1zcGVjaWZpYyBldmVudHMgYXJlIGVtaXR0ZWQgdXNpbmcgTWVzc2FnZVR5cGUgZW51bSBuYW1lc1xuICAvLyBlLmcuLCAnU1RBVFVTX1VQREFURScsICdFUlJPUicsICdIRUFSVEJFQVQnLCBldGMuXG59XG5cbi8qKlxuICogVW5peCBzb2NrZXQgY2xpZW50IGZvciBjb21tdW5pY2F0aW9uIGJldHdlZW4gVmliZVR1bm5lbCB3ZWIgc2VydmVyIGFuZCB0ZXJtaW5hbCBwcm9jZXNzZXMuXG4gKlxuICogVGhpcyBjbGFzcyBwcm92aWRlcyBhIHJvYnVzdCBjbGllbnQgZm9yIGNvbm5lY3RpbmcgdG8gVW5peCBkb21haW4gc29ja2V0cyB3aXRoIGF1dG9tYXRpY1xuICogcmVjb25uZWN0aW9uLCBoZWFydGJlYXQgc3VwcG9ydCwgYW5kIG1lc3NhZ2UgcGFyc2luZyB1c2luZyB0aGUgVmliZVR1bm5lbCBzb2NrZXQgcHJvdG9jb2wuXG4gKiBJdCBoYW5kbGVzIHRlcm1pbmFsIGNvbnRyb2wgb3BlcmF0aW9ucyBsaWtlIHN0ZGluIGlucHV0LCByZXNpemluZywgYW5kIHByb2Nlc3MgbWFuYWdlbWVudC5cbiAqXG4gKiBLZXkgZmVhdHVyZXM6XG4gKiAtIEF1dG9tYXRpYyByZWNvbm5lY3Rpb24gd2l0aCBjb25maWd1cmFibGUgZGVsYXlcbiAqIC0gSGVhcnRiZWF0IG1lY2hhbmlzbSB0byBkZXRlY3QgY29ubmVjdGlvbiBoZWFsdGhcbiAqIC0gQmluYXJ5IG1lc3NhZ2UgcHJvdG9jb2wgd2l0aCBsZW5ndGgtcHJlZml4ZWQgZnJhbWluZ1xuICogLSBFdmVudC1iYXNlZCBBUEkgZm9yIGhhbmRsaW5nIGNvbm5lY3Rpb24gc3RhdGUgYW5kIG1lc3NhZ2VzXG4gKiAtIG1hY09TIHNvY2tldCBwYXRoIGxlbmd0aCB2YWxpZGF0aW9uICgxMDQgY2hhciBsaW1pdClcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gQ3JlYXRlIGEgY2xpZW50IGZvciBhIHRlcm1pbmFsIHNlc3Npb25cbiAqIGNvbnN0IGNsaWVudCA9IG5ldyBWaWJlVHVubmVsU29ja2V0Q2xpZW50KCcvdG1wL3ZpYmV0dW5uZWwvc2Vzc2lvbi0xMjMuc29jaycsIHtcbiAqICAgYXV0b1JlY29ubmVjdDogdHJ1ZSxcbiAqICAgaGVhcnRiZWF0SW50ZXJ2YWw6IDMwMDAwXG4gKiB9KTtcbiAqXG4gKiAvLyBMaXN0ZW4gZm9yIGV2ZW50c1xuICogY2xpZW50Lm9uKCdjb25uZWN0JywgKCkgPT4gY29uc29sZS5sb2coJ0Nvbm5lY3RlZCB0byB0ZXJtaW5hbCcpKTtcbiAqIGNsaWVudC5vbignc3RhdHVzJywgKHN0YXR1cykgPT4gY29uc29sZS5sb2coJ1Rlcm1pbmFsIHN0YXR1czonLCBzdGF0dXMpKTtcbiAqIGNsaWVudC5vbignZXJyb3InLCAoZXJyb3IpID0+IGNvbnNvbGUuZXJyb3IoJ1NvY2tldCBlcnJvcjonLCBlcnJvcikpO1xuICpcbiAqIC8vIENvbm5lY3QgYW5kIHNlbmQgY29tbWFuZHNcbiAqIGF3YWl0IGNsaWVudC5jb25uZWN0KCk7XG4gKiBjbGllbnQuc2VuZFN0ZGluKCdscyAtbGFcXG4nKTtcbiAqIGNsaWVudC5yZXNpemUoODAsIDI0KTtcbiAqIGBgYFxuICpcbiAqIEBleHRlbmRzIEV2ZW50RW1pdHRlclxuICovXG5leHBvcnQgY2xhc3MgVmliZVR1bm5lbFNvY2tldENsaWVudCBleHRlbmRzIEV2ZW50RW1pdHRlciB7XG4gIHByaXZhdGUgc29ja2V0PzogbmV0LlNvY2tldDtcbiAgcHJpdmF0ZSBwYXJzZXIgPSBuZXcgTWVzc2FnZVBhcnNlcigpO1xuICBwcml2YXRlIGNvbm5lY3RlZCA9IGZhbHNlO1xuICBwcml2YXRlIHJlY29ubmVjdFRpbWVyPzogTm9kZUpTLlRpbWVvdXQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgcmVjb25uZWN0RGVsYXkgPSAxMDAwO1xuICBwcml2YXRlIGhlYXJ0YmVhdEludGVydmFsPzogTm9kZUpTLlRpbWVvdXQ7XG4gIHByaXZhdGUgbGFzdEhlYXJ0YmVhdCA9IERhdGUubm93KCk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBzb2NrZXRQYXRoOiBzdHJpbmcsXG4gICAgcHJpdmF0ZSByZWFkb25seSBvcHRpb25zOiB7XG4gICAgICBhdXRvUmVjb25uZWN0PzogYm9vbGVhbjtcbiAgICAgIGhlYXJ0YmVhdEludGVydmFsPzogbnVtYmVyO1xuICAgIH0gPSB7fVxuICApIHtcbiAgICBzdXBlcigpO1xuXG4gICAgLy8gSU1QT1JUQU5UOiBtYWNPUyBoYXMgYSAxMDQgY2hhcmFjdGVyIGxpbWl0IGZvciBVbml4IHNvY2tldCBwYXRoc1xuICAgIC8vIElmIHlvdSBnZXQgRUlOVkFMIGVycm9ycyB3aGVuIGNvbm5lY3RpbmcsIHRoZSBwYXRoIGlzIGxpa2VseSB0b28gbG9uZ1xuICAgIGlmIChzb2NrZXRQYXRoLmxlbmd0aCA+IDEwMykge1xuICAgICAgbG9nZ2VyLndhcm4oYFNvY2tldCBwYXRoIG1heSBiZSB0b28gbG9uZyAoJHtzb2NrZXRQYXRoLmxlbmd0aH0gY2hhcnMpOiAke3NvY2tldFBhdGh9YCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENvbm5lY3QgdG8gdGhlIHNvY2tldFxuICAgKi9cbiAgY29ubmVjdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgaWYgKHRoaXMuY29ubmVjdGVkKSB7XG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNvY2tldCA9IG5ldC5jcmVhdGVDb25uZWN0aW9uKHRoaXMuc29ja2V0UGF0aCk7XG4gICAgICB0aGlzLnNvY2tldC5zZXROb0RlbGF5KHRydWUpO1xuICAgICAgdGhpcy5zb2NrZXQuc2V0S2VlcEFsaXZlKHRydWUsIDApO1xuXG4gICAgICBjb25zdCBvbkNvbm5lY3QgPSAoKSA9PiB7XG4gICAgICAgIHRoaXMuY29ubmVjdGVkID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5zZXR1cFNvY2tldEhhbmRsZXJzKCk7XG4gICAgICAgIHRoaXMuZW1pdCgnY29ubmVjdCcpO1xuICAgICAgICB0aGlzLnN0YXJ0SGVhcnRiZWF0KCk7XG4gICAgICAgIGNsZWFudXAoKTtcbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgfTtcblxuICAgICAgY29uc3Qgb25FcnJvciA9IChlcnJvcjogRXJyb3IpID0+IHtcbiAgICAgICAgY2xlYW51cCgpO1xuICAgICAgICAvLyBEZXN0cm95IHRoZSBzb2NrZXQgdG8gcHJldmVudCBmdXJ0aGVyIGVycm9yc1xuICAgICAgICB0aGlzLnNvY2tldD8uZGVzdHJveSgpO1xuICAgICAgICB0aGlzLnNvY2tldCA9IHVuZGVmaW5lZDtcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IGNsZWFudXAgPSAoKSA9PiB7XG4gICAgICAgIHRoaXMuc29ja2V0Py5vZmYoJ2Nvbm5lY3QnLCBvbkNvbm5lY3QpO1xuICAgICAgICB0aGlzLnNvY2tldD8ub2ZmKCdlcnJvcicsIG9uRXJyb3IpO1xuICAgICAgfTtcblxuICAgICAgdGhpcy5zb2NrZXQub25jZSgnY29ubmVjdCcsIG9uQ29ubmVjdCk7XG4gICAgICB0aGlzLnNvY2tldC5vbmNlKCdlcnJvcicsIG9uRXJyb3IpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHVwIHNvY2tldCBldmVudCBoYW5kbGVyc1xuICAgKi9cbiAgcHJpdmF0ZSBzZXR1cFNvY2tldEhhbmRsZXJzKCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5zb2NrZXQpIHJldHVybjtcblxuICAgIHRoaXMuc29ja2V0Lm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XG4gICAgICB0aGlzLnBhcnNlci5hZGREYXRhKGNodW5rKTtcblxuICAgICAgZm9yIChjb25zdCB7IHR5cGUsIHBheWxvYWQgfSBvZiB0aGlzLnBhcnNlci5wYXJzZU1lc3NhZ2VzKCkpIHtcbiAgICAgICAgdGhpcy5oYW5kbGVNZXNzYWdlKHR5cGUsIHBheWxvYWQpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5zb2NrZXQub24oJ2Nsb3NlJywgKCkgPT4ge1xuICAgICAgdGhpcy5oYW5kbGVEaXNjb25uZWN0KCk7XG4gICAgfSk7XG5cbiAgICB0aGlzLnNvY2tldC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICAgIGxvZ2dlci5lcnJvcihgU29ja2V0IGVycm9yIG9uICR7dGhpcy5zb2NrZXRQYXRofTpgLCBlcnJvcik7XG4gICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgZXJyb3IpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEhhbmRsZSBpbmNvbWluZyBtZXNzYWdlc1xuICAgKi9cbiAgcHJpdmF0ZSBoYW5kbGVNZXNzYWdlKHR5cGU6IE1lc3NhZ2VUeXBlLCBwYXlsb2FkOiBCdWZmZXIpOiB2b2lkIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgZGF0YSA9IHBhcnNlUGF5bG9hZCh0eXBlLCBwYXlsb2FkKTtcblxuICAgICAgLy8gRW1pdCBldmVudCB3aXRoIG1lc3NhZ2UgdHlwZSBlbnVtIG5hbWVcbiAgICAgIHRoaXMuZW1pdChNZXNzYWdlVHlwZVt0eXBlXSwgZGF0YSk7XG5cbiAgICAgIC8vIEhhbmRsZSBoZWFydGJlYXRcbiAgICAgIGlmICh0eXBlID09PSBNZXNzYWdlVHlwZS5IRUFSVEJFQVQpIHtcbiAgICAgICAgdGhpcy5sYXN0SGVhcnRiZWF0ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgLy8gRWNobyBoZWFydGJlYXQgYmFja1xuICAgICAgICB0aGlzLnNlbmRIZWFydGJlYXQoKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdGYWlsZWQgdG8gcGFyc2UgbWVzc2FnZTonLCBlcnJvcik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEhhbmRsZSBkaXNjb25uZWN0aW9uXG4gICAqL1xuICBwcml2YXRlIGhhbmRsZURpc2Nvbm5lY3QoZXJyb3I/OiBFcnJvcik6IHZvaWQge1xuICAgIHRoaXMuY29ubmVjdGVkID0gZmFsc2U7XG4gICAgdGhpcy5zdG9wSGVhcnRiZWF0KCk7XG4gICAgdGhpcy5lbWl0KCdkaXNjb25uZWN0JywgZXJyb3IpO1xuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5hdXRvUmVjb25uZWN0ICYmICF0aGlzLnJlY29ubmVjdFRpbWVyKSB7XG4gICAgICB0aGlzLnJlY29ubmVjdFRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHRoaXMucmVjb25uZWN0VGltZXIgPSB1bmRlZmluZWQ7XG4gICAgICAgIHRoaXMuY29ubmVjdCgpLmNhdGNoKChlcnIpID0+IHtcbiAgICAgICAgICBsb2dnZXIuZGVidWcoYFJlY29ubmVjdGlvbiBmYWlsZWQ6ICR7ZXJyLm1lc3NhZ2V9YCk7XG4gICAgICAgICAgdGhpcy5oYW5kbGVEaXNjb25uZWN0KGVycik7XG4gICAgICAgIH0pO1xuICAgICAgfSwgdGhpcy5yZWNvbm5lY3REZWxheSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFN0YXJ0IGhlYXJ0YmVhdFxuICAgKi9cbiAgcHJpdmF0ZSBzdGFydEhlYXJ0YmVhdCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5vcHRpb25zLmhlYXJ0YmVhdEludGVydmFsKSB7XG4gICAgICB0aGlzLmhlYXJ0YmVhdEludGVydmFsID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgICAgICB0aGlzLnNlbmRIZWFydGJlYXQoKTtcbiAgICAgIH0sIHRoaXMub3B0aW9ucy5oZWFydGJlYXRJbnRlcnZhbCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFN0b3AgaGVhcnRiZWF0XG4gICAqL1xuICBwcml2YXRlIHN0b3BIZWFydGJlYXQoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaGVhcnRiZWF0SW50ZXJ2YWwpIHtcbiAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy5oZWFydGJlYXRJbnRlcnZhbCk7XG4gICAgICB0aGlzLmhlYXJ0YmVhdEludGVydmFsID0gdW5kZWZpbmVkO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTZW5kIGRhdGEgdG8gc3RkaW5cbiAgICovXG4gIHNlbmRTdGRpbihkYXRhOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5zZW5kKE1lc3NhZ2VCdWlsZGVyLnN0ZGluKGRhdGEpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZW5kIHJlc2l6ZSBjb21tYW5kXG4gICAqL1xuICByZXNpemUoY29sczogbnVtYmVyLCByb3dzOiBudW1iZXIpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5zZW5kKE1lc3NhZ2VCdWlsZGVyLnJlc2l6ZShjb2xzLCByb3dzKSk7XG4gIH1cblxuICAvKipcbiAgICogU2VuZCBraWxsIGNvbW1hbmRcbiAgICovXG4gIGtpbGwoc2lnbmFsPzogc3RyaW5nIHwgbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc2VuZChNZXNzYWdlQnVpbGRlci5raWxsKHNpZ25hbCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNlbmQgcmVzZXQgc2l6ZSBjb21tYW5kXG4gICAqL1xuICByZXNldFNpemUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc2VuZChNZXNzYWdlQnVpbGRlci5yZXNldFNpemUoKSk7XG4gIH1cblxuICAvKipcbiAgICogU2VuZCB1cGRhdGUgdGl0bGUgY29tbWFuZFxuICAgKi9cbiAgdXBkYXRlVGl0bGUodGl0bGU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnNlbmQoTWVzc2FnZUJ1aWxkZXIudXBkYXRlVGl0bGUodGl0bGUpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZW5kIHN0YXR1cyB1cGRhdGVcbiAgICovXG4gIHNlbmRTdGF0dXMoYXBwOiBzdHJpbmcsIHN0YXR1czogc3RyaW5nLCBleHRyYT86IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc2VuZChNZXNzYWdlQnVpbGRlci5zdGF0dXMoYXBwLCBzdGF0dXMsIGV4dHJhKSk7XG4gIH1cblxuICAvKipcbiAgICogU2VuZCBhIG1lc3NhZ2Ugd2l0aCB0eXBlLXNhZmUgcGF5bG9hZFxuICAgKi9cbiAgcHVibGljIHNlbmRNZXNzYWdlPFQgZXh0ZW5kcyBNZXNzYWdlVHlwZT4odHlwZTogVCwgcGF5bG9hZDogTWVzc2FnZVBheWxvYWQ8VD4pOiBib29sZWFuIHtcbiAgICBjb25zdCBtZXNzYWdlID0gdGhpcy5idWlsZE1lc3NhZ2UodHlwZSwgcGF5bG9hZCk7XG4gICAgcmV0dXJuIHRoaXMuc2VuZChtZXNzYWdlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZW5kIGEgbWVzc2FnZSBhbmQgd2FpdCBmb3IgYSByZXNwb25zZVxuICAgKi9cbiAgcHVibGljIGFzeW5jIHNlbmRNZXNzYWdlV2l0aFJlc3BvbnNlPFRSZXF1ZXN0IGV4dGVuZHMgTWVzc2FnZVR5cGUsIFRSZXNwb25zZSBleHRlbmRzIE1lc3NhZ2VUeXBlPihcbiAgICByZXF1ZXN0VHlwZTogVFJlcXVlc3QsXG4gICAgcGF5bG9hZDogTWVzc2FnZVBheWxvYWQ8VFJlcXVlc3Q+LFxuICAgIHJlc3BvbnNlVHlwZTogVFJlc3BvbnNlLFxuICAgIHRpbWVvdXQgPSA1MDAwXG4gICk6IFByb21pc2U8TWVzc2FnZVBheWxvYWQ8VFJlc3BvbnNlPj4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCB0aW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICB0aGlzLm9mZihNZXNzYWdlVHlwZVtyZXNwb25zZVR5cGVdLCBoYW5kbGVSZXNwb25zZSk7XG4gICAgICAgIHRoaXMub2ZmKCdlcnJvcicsIGhhbmRsZUVycm9yKTtcbiAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihgUmVxdWVzdCB0aW1lb3V0IHdhaXRpbmcgZm9yICR7TWVzc2FnZVR5cGVbcmVzcG9uc2VUeXBlXX1gKSk7XG4gICAgICB9LCB0aW1lb3V0KTtcblxuICAgICAgY29uc3QgaGFuZGxlUmVzcG9uc2UgPSAoZGF0YTogTWVzc2FnZVBheWxvYWQ8VFJlc3BvbnNlPikgPT4ge1xuICAgICAgICBjbGVhclRpbWVvdXQodGltZXIpO1xuICAgICAgICB0aGlzLm9mZignZXJyb3InLCBoYW5kbGVFcnJvcik7XG4gICAgICAgIHJlc29sdmUoZGF0YSk7XG4gICAgICB9O1xuXG4gICAgICBjb25zdCBoYW5kbGVFcnJvciA9IChlcnJvcjogRXJyb3IgfCBFcnJvck1lc3NhZ2UpID0+IHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVyKTtcbiAgICAgICAgdGhpcy5vZmYoTWVzc2FnZVR5cGVbcmVzcG9uc2VUeXBlXSwgaGFuZGxlUmVzcG9uc2UpO1xuICAgICAgICBpZiAoJ21lc3NhZ2UnIGluIGVycm9yKSB7XG4gICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihlcnJvci5tZXNzYWdlKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgLy8gTGlzdGVuIGZvciByZXNwb25zZVxuICAgICAgdGhpcy5vbmNlKE1lc3NhZ2VUeXBlW3Jlc3BvbnNlVHlwZV0sIGhhbmRsZVJlc3BvbnNlKTtcbiAgICAgIHRoaXMub25jZSgnZXJyb3InLCBoYW5kbGVFcnJvcik7XG5cbiAgICAgIGNvbnN0IHNlbnQgPSB0aGlzLnNlbmRNZXNzYWdlKHJlcXVlc3RUeXBlLCBwYXlsb2FkKTtcbiAgICAgIGlmICghc2VudCkge1xuICAgICAgICBjbGVhclRpbWVvdXQodGltZXIpO1xuICAgICAgICB0aGlzLm9mZihNZXNzYWdlVHlwZVtyZXNwb25zZVR5cGVdLCBoYW5kbGVSZXNwb25zZSk7XG4gICAgICAgIHRoaXMub2ZmKCdlcnJvcicsIGhhbmRsZUVycm9yKTtcbiAgICAgICAgcmVqZWN0KG5ldyBFcnJvcignRmFpbGVkIHRvIHNlbmQgbWVzc2FnZScpKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZCBhIG1lc3NhZ2UgYnVmZmVyIGZyb20gdHlwZSBhbmQgcGF5bG9hZFxuICAgKi9cbiAgcHJpdmF0ZSBidWlsZE1lc3NhZ2U8VCBleHRlbmRzIE1lc3NhZ2VUeXBlPih0eXBlOiBULCBwYXlsb2FkOiBNZXNzYWdlUGF5bG9hZDxUPik6IEJ1ZmZlciB7XG4gICAgc3dpdGNoICh0eXBlKSB7XG4gICAgICBjYXNlIE1lc3NhZ2VUeXBlLlNURElOX0RBVEE6XG4gICAgICAgIHJldHVybiBNZXNzYWdlQnVpbGRlci5zdGRpbihwYXlsb2FkIGFzIHN0cmluZyk7XG4gICAgICBjYXNlIE1lc3NhZ2VUeXBlLkNPTlRST0xfQ01EOiB7XG4gICAgICAgIGNvbnN0IGNtZCA9IHBheWxvYWQgYXMgQ29udHJvbENvbW1hbmQ7XG4gICAgICAgIHN3aXRjaCAoY21kLmNtZCkge1xuICAgICAgICAgIGNhc2UgJ3Jlc2l6ZSc6XG4gICAgICAgICAgICByZXR1cm4gTWVzc2FnZUJ1aWxkZXIucmVzaXplKChjbWQgYXMgUmVzaXplQ29tbWFuZCkuY29scywgKGNtZCBhcyBSZXNpemVDb21tYW5kKS5yb3dzKTtcbiAgICAgICAgICBjYXNlICdraWxsJzpcbiAgICAgICAgICAgIHJldHVybiBNZXNzYWdlQnVpbGRlci5raWxsKChjbWQgYXMgS2lsbENvbW1hbmQpLnNpZ25hbCk7XG4gICAgICAgICAgY2FzZSAncmVzZXQtc2l6ZSc6XG4gICAgICAgICAgICByZXR1cm4gTWVzc2FnZUJ1aWxkZXIucmVzZXRTaXplKCk7XG4gICAgICAgICAgY2FzZSAndXBkYXRlLXRpdGxlJzpcbiAgICAgICAgICAgIHJldHVybiBNZXNzYWdlQnVpbGRlci51cGRhdGVUaXRsZSgoY21kIGFzIFVwZGF0ZVRpdGxlQ29tbWFuZCkudGl0bGUpO1xuICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAvLyBGb3IgZ2VuZXJpYyBjb250cm9sIGNvbW1hbmRzLCB1c2UgZnJhbWVNZXNzYWdlIGRpcmVjdGx5XG4gICAgICAgICAgICByZXR1cm4gZnJhbWVNZXNzYWdlKE1lc3NhZ2VUeXBlLkNPTlRST0xfQ01ELCBjbWQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBjYXNlIE1lc3NhZ2VUeXBlLlNUQVRVU19VUERBVEU6IHtcbiAgICAgICAgY29uc3Qgc3RhdHVzUGF5bG9hZCA9IHBheWxvYWQgYXMgU3RhdHVzVXBkYXRlO1xuICAgICAgICByZXR1cm4gTWVzc2FnZUJ1aWxkZXIuc3RhdHVzKFxuICAgICAgICAgIHN0YXR1c1BheWxvYWQuYXBwLFxuICAgICAgICAgIHN0YXR1c1BheWxvYWQuc3RhdHVzLFxuICAgICAgICAgIHN0YXR1c1BheWxvYWQuZXh0cmEgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWRcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGNhc2UgTWVzc2FnZVR5cGUuSEVBUlRCRUFUOlxuICAgICAgICByZXR1cm4gTWVzc2FnZUJ1aWxkZXIuaGVhcnRiZWF0KCk7XG4gICAgICBjYXNlIE1lc3NhZ2VUeXBlLlNUQVRVU19SRVFVRVNUOlxuICAgICAgICByZXR1cm4gTWVzc2FnZUJ1aWxkZXIuc3RhdHVzUmVxdWVzdCgpO1xuICAgICAgY2FzZSBNZXNzYWdlVHlwZS5HSVRfRk9MTE9XX1JFUVVFU1Q6XG4gICAgICAgIHJldHVybiBNZXNzYWdlQnVpbGRlci5naXRGb2xsb3dSZXF1ZXN0KHBheWxvYWQgYXMgR2l0Rm9sbG93UmVxdWVzdCk7XG4gICAgICBjYXNlIE1lc3NhZ2VUeXBlLkdJVF9FVkVOVF9OT1RJRlk6XG4gICAgICAgIHJldHVybiBNZXNzYWdlQnVpbGRlci5naXRFdmVudE5vdGlmeShwYXlsb2FkIGFzIEdpdEV2ZW50Tm90aWZ5KTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5zdXBwb3J0ZWQgbWVzc2FnZSB0eXBlOiAke3R5cGV9YCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNlbmQgaGVhcnRiZWF0XG4gICAqL1xuICBwcml2YXRlIHNlbmRIZWFydGJlYXQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc2VuZChNZXNzYWdlQnVpbGRlci5oZWFydGJlYXQoKSk7XG4gIH1cblxuICAvKipcbiAgICogU2VuZCByYXcgbWVzc2FnZVxuICAgKi9cbiAgcHJpdmF0ZSBzZW5kKG1lc3NhZ2U6IEJ1ZmZlcik6IGJvb2xlYW4ge1xuICAgIGlmICghdGhpcy5jb25uZWN0ZWQgfHwgIXRoaXMuc29ja2V0KSB7XG4gICAgICBsb2dnZXIuZGVidWcoJ0Nhbm5vdCBzZW5kIG1lc3NhZ2U6IG5vdCBjb25uZWN0ZWQnKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHRoaXMuc29ja2V0LndyaXRlKG1lc3NhZ2UpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ0ZhaWxlZCB0byBzZW5kIG1lc3NhZ2U6JywgZXJyb3IpO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEaXNjb25uZWN0IGZyb20gdGhlIHNvY2tldFxuICAgKi9cbiAgZGlzY29ubmVjdCgpOiB2b2lkIHtcbiAgICB0aGlzLm9wdGlvbnMuYXV0b1JlY29ubmVjdCA9IGZhbHNlO1xuICAgIHRoaXMuY29ubmVjdGVkID0gZmFsc2U7XG4gICAgdGhpcy5zdG9wSGVhcnRiZWF0KCk7XG5cbiAgICBpZiAodGhpcy5yZWNvbm5lY3RUaW1lcikge1xuICAgICAgY2xlYXJUaW1lb3V0KHRoaXMucmVjb25uZWN0VGltZXIpO1xuICAgICAgdGhpcy5yZWNvbm5lY3RUaW1lciA9IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5zb2NrZXQpIHtcbiAgICAgIHRoaXMuc29ja2V0LmRlc3Ryb3koKTtcbiAgICAgIHRoaXMuc29ja2V0ID0gdW5kZWZpbmVkO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiBjb25uZWN0ZWRcbiAgICovXG4gIGlzQ29ubmVjdGVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmNvbm5lY3RlZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGltZSBzaW5jZSBsYXN0IGhlYXJ0YmVhdFxuICAgKi9cbiAgZ2V0VGltZVNpbmNlTGFzdEhlYXJ0YmVhdCgpOiBudW1iZXIge1xuICAgIHJldHVybiBEYXRlLm5vdygpIC0gdGhpcy5sYXN0SGVhcnRiZWF0O1xuICB9XG59XG4iXX0=