; | |
/* | |
* Copyright 2020 Google Inc. All rights reserved. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |
* use this file except in compliance with the License. You may obtain a copy of | |
* the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
* License for the specific language governing permissions and limitations under | |
* the License. | |
*/ | |
Object.defineProperty(exports, "__esModule", { value: true }); | |
exports.WebSocketToPty = exports.SocketIoToPty = void 0; | |
var nodePty = require("node-pty"); | |
var socketio = require("socket.io"); | |
var ws_1 = require("ws"); | |
var logging = require("./logging"); | |
var sockets_1 = require("./sockets"); | |
var sessionCounter = 0; | |
// Inspired by | |
// https://xtermjs.org/docs/guides/flowcontrol/#ideas-for-a-better-mechanism. | |
var ACK_CALLBACK_EVERY_BYTES = 100000; | |
var UNACKED_HIGH_WATERMARK = 5; | |
var UNACKED_LOW_WATERMARK = 2; | |
/** Socket<->terminal adapter. */ | |
var Session = /** @class */ (function () { | |
function Session(socket) { | |
var _this = this; | |
this.socket = socket; | |
this.pendingAckCallbacks = 0; | |
this.writtenBytes = 0; | |
this.id = sessionCounter++; | |
this.socket.onClose(function (reason) { | |
logging.getLogger().debug('PTY socket disconnected for session %d reason: %s', _this.id, reason); | |
// Handle client disconnects to close sockets, so as to free up resources. | |
_this.close(); | |
}); | |
this.socket.onStringMessage(function (data) { | |
// Propagate the message over to the pty. | |
logging.getLogger().debug('Send data in session %d\n%s', _this.id, data); | |
var message = JSON.parse(data); | |
if (message.data) { | |
_this.pty.write(message.data); | |
} | |
if (message.cols && message.rows) { | |
_this.pty.resize(message.cols, message.rows); | |
} | |
if (message.ack) { | |
_this.pendingAckCallbacks--; | |
if (_this.pendingAckCallbacks < UNACKED_LOW_WATERMARK) { | |
_this.pty.resume(); | |
} | |
} | |
}); | |
this.pty = nodePty.spawn('tmux', ['new-session', '-A', '-D', '-s', '0'], { | |
name: 'xterm-color', | |
cwd: './content', // Which path should terminal start | |
// Pass environment variables | |
env: process.env, | |
}); | |
this.pty.onData(function (data) { | |
_this.writtenBytes += data.length; | |
if (_this.writtenBytes < ACK_CALLBACK_EVERY_BYTES) { | |
var message = { data: data }; | |
_this.socket.sendString(JSON.stringify(message)); | |
} | |
else { | |
var message = { data: data, ack: true }; | |
_this.socket.sendString(JSON.stringify(message)); | |
_this.pendingAckCallbacks++; | |
_this.writtenBytes = 0; | |
if (_this.pendingAckCallbacks > UNACKED_HIGH_WATERMARK) { | |
_this.pty.pause(); | |
} | |
} | |
}); | |
this.pty.onExit(function (_a) { | |
var exitCode = _a.exitCode, signal = _a.signal; | |
_this.socket.close(false); | |
}); | |
} | |
Session.prototype.close = function () { | |
this.socket.close(false); | |
this.pty.kill(); | |
}; | |
return Session; | |
}()); | |
/** SocketIO to node-pty adapter. */ | |
var SocketIoToPty = /** @class */ (function () { | |
function SocketIoToPty(path, server) { | |
this.path = path; | |
var io = socketio(server, { | |
path: path, | |
transports: ['polling'], | |
allowUpgrades: false, | |
// v2.10 changed default from 60s to 5s, prefer the longer timeout to | |
// avoid errant disconnects. | |
pingTimeout: 60000, | |
}); | |
io.of('/').on('connection', function (socket) { | |
// Session manages its own lifetime. | |
// tslint:disable-next-line:no-unused-expression | |
new Session(new sockets_1.SocketIOAdapter(socket)); | |
}); | |
} | |
/** Return true iff path is handled by socket.io. */ | |
SocketIoToPty.prototype.isPathProxied = function (path) { | |
return path.indexOf(this.path + '/') === 0; | |
}; | |
return SocketIoToPty; | |
}()); | |
exports.SocketIoToPty = SocketIoToPty; | |
/** WebSocket to pty adapter. */ | |
function WebSocketToPty(request, sock, head) { | |
new ws_1.Server({ noServer: true }).handleUpgrade(request, sock, head, function (ws) { | |
// Session manages its own lifetime. | |
// tslint:disable-next-line:no-unused-expression | |
new Session(new sockets_1.WebSocketAdapter(ws)); | |
}); | |
} | |
exports.WebSocketToPty = WebSocketToPty; | |
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic29ja2V0aW9fdG9fcHR5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vdGhpcmRfcGFydHkvY29sYWIvc291cmNlcy9zb2NrZXRpb190b19wdHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7OztHQWNHOzs7QUFJSCxrQ0FBb0M7QUFDcEMsb0NBQXNDO0FBQ3RDLHlCQUEwQjtBQUUxQixtQ0FBcUM7QUFDckMscUNBQW9FO0FBU3BFLElBQUksY0FBYyxHQUFHLENBQUMsQ0FBQztBQUV2QixjQUFjO0FBQ2QsNkVBQTZFO0FBQzdFLElBQU0sd0JBQXdCLEdBQUcsTUFBTSxDQUFDO0FBQ3hDLElBQU0sc0JBQXNCLEdBQUcsQ0FBQyxDQUFDO0FBQ2pDLElBQU0scUJBQXFCLEdBQUcsQ0FBQyxDQUFDO0FBRWhDLGlDQUFpQztBQUNqQztJQU1FLGlCQUE2QixNQUFjO1FBQTNDLGlCQTBEQztRQTFENEIsV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQUhuQyx3QkFBbUIsR0FBRyxDQUFDLENBQUM7UUFDeEIsaUJBQVksR0FBRyxDQUFDLENBQUM7UUFHdkIsSUFBSSxDQUFDLEVBQUUsR0FBRyxjQUFjLEVBQUUsQ0FBQztRQUUzQixJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxVQUFDLE1BQU07WUFDekIsT0FBTyxDQUFDLFNBQVMsRUFBRSxDQUFDLEtBQUssQ0FDckIsbURBQW1ELEVBQUUsS0FBSSxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUUxRSwwRUFBMEU7WUFDMUUsS0FBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2YsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxVQUFDLElBQVk7WUFDdkMseUNBQXlDO1lBQ3pDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsQ0FBQyxLQUFLLENBQUMsNkJBQTZCLEVBQUUsS0FBSSxDQUFDLEVBQUUsRUFB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QUFHLFFBQVEsQ0FBQyxNQUFNLEVBQUU7WUFDMUIsSUFBSSxNQUFBO1lBQ0osVUFBVSxFQUFFLENBQUMsU0FBUyxDQUFDO1lBQ3ZCLGFBQWEsRUFBRSxLQUFLO1lBQ3BCLHFFQUFxRTtZQUNyRSw0QkFBNEI7WUFDNUIsV0FBVyxFQUFFLEtBQUs7U0FDbkIsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsWUFBWSxFQUFFLFVBQUMsTUFBdUI7WUFDbEQsb0NBQW9DO1lBQ3BDLGdEQUFnRDtZQUNoRCxJQUFJLE9BQU8sQ0FBQyxJQUFJLHlCQUFlLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUMzQyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxvREFBb0Q7SUFDcEQscUNBQWEsR0FBYixVQUFjLElBQVk7UUFDeEIsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzdDLENBQUM7SUFDSCxvQkFBQztBQUFELENBQUMsQUF0QkQsSUFzQkM7QUF0Qlksc0NBQWE7QUF5QjFCLGdDQUFnQztBQUNoQyxTQUFnQixjQUFjLENBQzFCLE9BQTZCLEVBQUUsSUFBZ0IsRUFBRSxJQUFZO0lBQy9ELElBQUksV0FBTSxDQUFDLEVBQUMsUUFBUSxFQUFFLElBQUksRUFBQyxDQUFDLENBQUMsYUFBYSxDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLFVBQUMsRUFBRTtRQUNqRSxvQ0FBb0M7UUFDcEMsZ0RBQWdEO1FBQ2hELElBQUksT0FBTyxDQUFDLElBQUksMEJBQWdCLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUN4QyxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUM7QUFQRCx3Q0FPQyIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gKiBDb3B5cmlnaHQgMjAyMCBHb29nbGUgSW5jLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7IHlvdSBtYXkgbm90XG4gKiB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZlxuICogdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsIFdJVEhPVVRcbiAqIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4gU2VlIHRoZVxuICogTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQgbGltaXRhdGlvbnMgdW5kZXJcbiAqIHRoZSBMaWNlbnNlLlxuICovXG5cbmltcG9ydCAqIGFzIGh0dHAgZnJvbSAnaHR0cCc7XG5pbXBvcnQgKiBhcyBuZXQgZnJvbSAnbmV0JztcbmltcG9ydCAqIGFzIG5vZGVQdHkgZnJvbSAnbm9kZS1wdHknO1xuaW1wb3J0ICogYXMgc29ja2V0aW8gZnJvbSAnc29ja2V0LmlvJztcbmltcG9ydCB7U2VydmVyfSBmcm9tICd3cyc7XG5cbmltcG9ydCAqIGFzIGxvZ2dpbmcgZnJvbSAnLi9sb2dnaW5nJztcbmltcG9ydCB7U29ja2V0LCBTb2NrZXRJT0FkYXB0ZXIsIFdlYlNvY2tldEFkYXB0ZXJ9IGZyb20gJy4vc29ja2V0cyc7XG5cblxuLy8gUGF1c2UgYW5kIHJlc3VtZSBhcmUgbWlzc2luZyBmcm9tIHRoZSB0eXBpbmdzLlxuaW50ZXJmYWNlIFB0eSB7XG4gIHBhdXNlKCk6IHZvaWQ7XG4gIHJlc3VtZSgpOiB2b2lkO1xufVxuXG5sZXQgc2Vzc2lvbkNvdW50ZXIgPSAwO1xuXG4vLyBJbnNwaXJlZCBieVxuLy8gaHR0cHM6Ly94dGVybWpzLm9yZy9kb2NzL2d1aWRlcy9mbG93Y29udHJvbC8jaWRlYXMtZm9yLWEtYmV0dGVyLW1lY2hhbmlzbS5cbmNvbnN0IEFDS19DQUxMQkFDS19FVkVSWV9CWVRFUyA9IDEwMDAwMDtcbmNvbnN0IFVOQUNLRURfSElHSF9XQVRFUk1BUksgPSA1O1xuY29uc3QgVU5BQ0tFRF9MT1dfV0FURVJNQVJLID0gMjtcblxuLyoqIFNvY2tldDwtPnRlcm1pbmFsIGFkYXB0ZXIuICovXG5jbGFzcyBTZXNzaW9uIHtcbiAgcHJpdmF0ZSByZWFkb25seSBpZDogbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IHB0eTogbm9kZVB0eS5JUHR5O1xuICBwcml2YXRlIHBlbmRpbmdBY2tDYWxsYmFja3MgPSAwO1xuICBwcml2YXRlIHdyaXR0ZW5CeXRlcyA9IDA7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBzb2NrZXQ6IFNvY2tldCkge1xuICAgIHRoaXMuaWQgPSBzZXNzaW9uQ291bnRlcisrO1xuXG4gICAgdGhpcy5zb2NrZXQub25DbG9zZSgocmVhc29uKSA9PiB7XG4gICAgICBsb2dnaW5nLmdldExvZ2dlcigpLmRlYnVnKFxuICAgICAgICAgICdQVFkgc29ja2V0IGRpc2Nvbm5lY3RlZCBmb3Igc2Vzc2lvbiAlZCByZWFzb246ICVzJywgdGhpcy5pZCwgcmVhc29uKTtcblxuICAgICAgLy8gSGFuZGxlIGNsaWVudCBkaXNjb25uZWN0cyB0byBjbG9zZSBzb2NrZXRzLCBzbyBhcyB0byBmcmVlIHVwIHJlc291cmNlcy5cbiAgICAgIHRoaXMuY2xvc2UoKTtcbiAgICB9KTtcblxuICAgIHRoaXMuc29ja2V0Lm9uU3RyaW5nTWVzc2FnZSgoZGF0YTogc3RyaW5nKSA9PiB7XG4gICAgICAvLyBQcm9wYWdhdGUgdGhlIG1lc3NhZ2Ugb3ZlciB0byB0aGUgcHR5LlxuICAgICAgbG9nZ2luZy5nZXRMb2dnZXIoKS5kZWJ1ZygnU2VuZCBkYXRhIGluIHNlc3Npb24gJWRcXG4lcycsIHRoaXMuaWQsIGRhdGEpO1xuICAgICAgY29uc3QgbWVzc2FnZSA9IEpTT04ucGFyc2UoZGF0YSkgYXMgSW5jb21pbmdNZXNzYWdlO1xuICAgICAgaWYgKG1lc3NhZ2UuZGF0YSkge1xuICAgICAgICB0aGlzLnB0eS53cml0ZShtZXNzYWdlLmRhdGEpO1xuICAgICAgfVxuICAgICAgaWYgKG1lc3NhZ2UuY29scyAmJiBtZXNzYWdlLnJvd3MpIHtcbiAgICAgICAgdGhpcy5wdHkucmVzaXplKG1lc3NhZ2UuY29scywgbWVzc2FnZS5yb3dzKTtcbiAgICAgIH1cbiAgICAgIGlmIChtZXNzYWdlLmFjaykge1xuICAgICAgICB0aGlzLnBlbmRpbmdBY2tDYWxsYmFja3MtLTtcbiAgICAgICAgaWYgKHRoaXMucGVuZGluZ0Fja0NhbGxiYWNrcyA8IFVOQUNLRURfTE9XX1dBVEVSTUFSSykge1xuICAgICAgICAgICh0aGlzLnB0eSBhcyB1bmtub3duIGFzIFB0eSkucmVzdW1lKCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMucHR5ID0gbm9kZVB0eS5zcGF3bigndG11eCcsIFsnbmV3LXNlc3Npb24nLCAnLUEnLCAnLUQnLCAnLXMnLCAnMCddLCB7XG4gICAgICBuYW1lOiAneHRlcm0tY29sb3InLFxuICAgICAgY3dkOiAnLi9jb250ZW50JywgIC8vIFdoaWNoIHBhdGggc2hvdWxkIHRlcm1pbmFsIHN0YXJ0XG4gICAgICAvLyBQYXNzIGVudmlyb25tZW50IHZhcmlhYmxlc1xuICAgICAgZW52OiBwcm9jZXNzLmVudiBhcyB7XG4gICAgICAgIFtrZXk6IHN0cmluZ106IHN0cmluZztcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICB0aGlzLnB0eS5vbkRhdGEoKGRhdGE6IHN0cmluZykgPT4ge1xuICAgICAgdGhpcy53cml0dGVuQnl0ZXMgKz0gZGF0YS5sZW5ndGg7XG4gICAgICBpZiAodGhpcy53cml0dGVuQnl0ZXMgPCBBQ0tfQ0FMTEJBQ0tfRVZFUllfQllURVMpIHtcbiAgICAgICAgY29uc3QgbWVzc2FnZTogT3V0Z29pbmdNZXNzYWdlID0ge2RhdGF9O1xuICAgICAgICB0aGlzLnNvY2tldC5zZW5kU3RyaW5nKEpTT04uc3RyaW5naWZ5KG1lc3NhZ2UpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IG1lc3NhZ2U6IE91dGdvaW5nTWVzc2FnZSA9IHtkYXRhLCBhY2s6IHRydWV9O1xuICAgICAgICB0aGlzLnNvY2tldC5zZW5kU3RyaW5nKEpTT04uc3RyaW5naWZ5KG1lc3NhZ2UpKTtcbiAgICAgICAgdGhpcy5wZW5kaW5nQWNrQ2FsbGJhY2tzKys7XG4gICAgICAgIHRoaXMud3JpdHRlbkJ5dGVzID0gMDtcbiAgICAgICAgaWYgKHRoaXMucGVuZGluZ0Fja0NhbGxiYWNrcyA+IFVOQUNLRURfSElHSF9XQVRFUk1BUkspIHtcbiAgICAgICAgICAodGhpcy5wdHkgYXMgdW5rbm93biBhcyBQdHkpLnBhdXNlKCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMucHR5Lm9uRXhpdChcbiAgICAgICAgKHtleGl0Q29kZSwgc2lnbmFsfToge2V4aXRDb2RlOiBudW1iZXIsIHNpZ25hbD86IG51bWJlcn0pID0+IHtcbiAgICAgICAgICB0aGlzLnNvY2tldC5jbG9zZShmYWxzZSk7XG4gICAgICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBjbG9zZSgpIHtcbiAgICB0aGlzLnNvY2tldC5jbG9zZShmYWxzZSk7XG4gICAgdGhpcy5wdHkua2lsbCgpO1xuICB9XG59XG5cbi8qKiBTb2NrZXRJTyB0byBub2RlLXB0eSBhZGFwdGVyLiAqL1xuZXhwb3J0IGNsYXNzIFNvY2tldElvVG9QdHkge1xuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IHBhdGg6IHN0cmluZywgc2VydmVyOiBodHRwLlNlcnZlcikge1xuICAgIGNvbnN0IGlvID0gc29ja2V0aW8oc2VydmVyLCB7XG4gICAgICBwYXRoLFxuICAgICAgdHJhbnNwb3J0czogWydwb2xsaW5nJ10sXG4gICAgICBhbGxvd1VwZ3JhZGVzOiBmYWxzZSxcbiAgICAgIC8vIHYyLjEwIGNoYW5nZWQgZGVmYXVsdCBmcm9tIDYwcyB0byA1cywgcHJlZmVyIHRoZSBsb25nZXIgdGltZW91dCB0b1xuICAgICAgLy8gYXZvaWQgZXJyYW50IGRpc2Nvbm5lY3RzLlxuICAgICAgcGluZ1RpbWVvdXQ6IDYwMDAwLFxuICAgIH0pO1xuXG4gICAgaW8ub2YoJy8nKS5vbignY29ubmVjdGlvbicsIChzb2NrZXQ6IFNvY2tldElPLlNvY2tldCkgPT4ge1xuICAgICAgLy8gU2Vzc2lvbiBtYW5hZ2VzIGl0cyBvd24gbGlmZXRpbWUuXG4gICAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tdW51c2VkLWV4cHJlc3Npb25cbiAgICAgIG5ldyBTZXNzaW9uKG5ldyBTb2NrZXRJT0FkYXB0ZXIoc29ja2V0KSk7XG4gICAgfSk7XG4gIH1cblxuICAvKiogUmV0dXJuIHRydWUgaWZmIHBhdGggaXMgaGFuZGxlZCBieSBzb2NrZXQuaW8uICovXG4gIGlzUGF0aFByb3hpZWQocGF0aDogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHBhdGguaW5kZXhPZih0aGlzLnBhdGggKyAnLycpID09PSAwO1xuICB9XG59XG5cblxuLyoqIFdlYlNvY2tldCB0byBwdHkgYWRhcHRlci4gKi9cbmV4cG9ydCBmdW5jdGlvbiBXZWJTb2NrZXRUb1B0eShcbiAgICByZXF1ZXN0OiBodHRwLkluY29taW5nTWVzc2FnZSwgc29jazogbmV0LlNvY2tldCwgaGVhZDogQnVmZmVyKSB7XG4gIG5ldyBTZXJ2ZXIoe25vU2VydmVyOiB0cnVlfSkuaGFuZGxlVXBncmFkZShyZXF1ZXN0LCBzb2NrLCBoZWFkLCAod3MpID0+IHtcbiAgICAvLyBTZXNzaW9uIG1hbmFnZXMgaXRzIG93biBsaWZldGltZS5cbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tdW51c2VkLWV4cHJlc3Npb25cbiAgICBuZXcgU2Vzc2lvbihuZXcgV2ViU29ja2V0QWRhcHRlcih3cykpO1xuICB9KTtcbn1cblxuZGVjbGFyZSBpbnRlcmZhY2UgSW5jb21pbmdNZXNzYWdlIHtcbiAgcmVhZG9ubHkgZGF0YT86IHN0cmluZztcbiAgcmVhZG9ubHkgY29scz86IG51bWJlcjtcbiAgcmVhZG9ubHkgcm93cz86IG51bWJlcjtcbiAgcmVhZG9ubHkgYWNrPzogYm9vbGVhbjtcbn1cblxuZGVjbGFyZSBpbnRlcmZhY2UgT3V0Z29pbmdNZXNzYWdlIHtcbiAgcmVhZG9ubHkgZGF0YT86IHN0cmluZztcbiAgcmVhZG9ubHkgYWNrPzogYm9vbGVhbjtcbn1cbiJdfQ== |