"use strict"; /* * 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. */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DapServer = void 0; var childProcess = require("child_process"); var crypto = require("crypto"); var net = require("net"); var ws_1 = require("ws"); var jsonRpc = require("./json_rpc"); var logging = require("./logging"); var sockets_1 = require("./sockets"); var sessionCounter = 0; /** Socket<->debug adapter. */ var Session = /** @class */ (function () { function Session(clientSocket, domainSocketPath) { var _this = this; this.clientSocket = clientSocket; this.id = sessionCounter++; this.clientSocket.onClose(function (reason) { logging.getLogger().debug('DAP 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.connect(domainSocketPath); } Session.prototype.close = function () { if (this.dapSocket) { this.dapSocket.destroy(); } this.clientSocket.close(true); }; Session.prototype.connect = function (domainSocketPath) { return __awaiter(this, void 0, void 0, function () { var rpc_1, dapSocket_1, message, error_1; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); logging.getLogger().info('DAP creating Socket to %s for session %d', domainSocketPath, this.id); rpc_1 = new jsonRpc.JsonRpcReader(function (dapMessage) { var message = { data: jsonRpc.encodeJsonRpc(dapMessage.content) }; _this.clientSocket.sendString(JSON.stringify(message)); }); dapSocket_1 = new net.Socket(); this.dapSocket = dapSocket_1; dapSocket_1.on('data', function (data) { rpc_1.append(data); }); dapSocket_1.on('close', function () { _this.close(); }); return [4 /*yield*/, new Promise(function (resolve, reject) { dapSocket_1.on('error', reject); dapSocket_1.connect(domainSocketPath, resolve); })]; case 1: _a.sent(); message = { open: true }; this.clientSocket.sendString(JSON.stringify(message)); this.clientSocket.onBinaryMessage(function (data) { dapSocket_1.write(Uint8Array.from(data)); }); this.clientSocket.onStringMessage(function (data) { dapSocket_1.write(data); }); return [3 /*break*/, 3]; case 2: error_1 = _a.sent(); logging.getLogger().error('Error connecting to Debug Adapter: %s', error_1); this.close(); return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }; return Session; }()); /** Debug Adapter Protocol server. */ var DapServer = /** @class */ (function () { function DapServer(muxBinary, server) { var _this = this; this.portPromise = this.spawnMultiplexer(muxBinary); server === null || server === void 0 ? void 0 : server.of('/debugger').on('connection', function (socket) { _this.portPromise.then(function (domainSocketPath) { // Session manages its own lifetime. // tslint:disable-next-line:no-unused-expression new Session(new sockets_1.SocketIOAdapter(socket), domainSocketPath); }); }); } DapServer.prototype.handleUpgrade = function (request, sock, head) { var _this = this; new ws_1.Server({ noServer: true }).handleUpgrade(request, sock, head, function (ws) { _this.portPromise.then(function (domainSocketPath) { // Session manages its own lifetime. // tslint:disable-next-line:no-unused-expression new Session(new sockets_1.WebSocketAdapter(ws), domainSocketPath); }); }); }; DapServer.prototype.spawnMultiplexer = function (muxBinary) { return __awaiter(this, void 0, void 0, function () { var filename, muxProcess, muxOutput; return __generator(this, function (_a) { switch (_a.label) { case 0: filename = "/tmp/debugger_".concat(crypto.randomBytes(6).readUIntLE(0, 6).toString(36)); muxProcess = childProcess.spawn(muxBinary, [ "--domain_socket_path=".concat(filename), ]); muxProcess.stdout.on('data', function (data) { logging.getLogger().info('%s: %s', muxBinary, data); }); muxProcess.stdout.on('error', function (data) { logging.getLogger().info('%s: %s', muxBinary, data); }); muxOutput = ''; return [4 /*yield*/, new Promise(function (resolve, reject) { var connectionHandler = function (data) { muxOutput += data; // Wait for the process to indicate that it is listening. if (muxOutput.match(/Listening on /)) { muxProcess.stdout.off('data', connectionHandler); resolve(); } }; muxProcess.stdout.on('data', connectionHandler); muxProcess.stdout.on('error', reject); })]; case 1: _a.sent(); return [2 /*return*/, filename]; } }); }); }; return DapServer; }()); exports.DapServer = DapServer; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic29ja2V0aW9fdG9fZGFwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vdGhpcmRfcGFydHkvY29sYWIvc291cmNlcy9zb2NrZXRpb190b19kYXAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7OztHQWNHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFSCw0Q0FBOEM7QUFDOUMsK0JBQWlDO0FBRWpDLHlCQUEyQjtBQUkzQix5QkFBMEI7QUFFMUIsb0NBQXNDO0FBQ3RDLG1DQUFxQztBQUNyQyxxQ0FBb0U7QUFFcEUsSUFBSSxjQUFjLEdBQUcsQ0FBQyxDQUFDO0FBRXZCLDhCQUE4QjtBQUM5QjtJQUlFLGlCQUE2QixZQUFvQixFQUFFLGdCQUF3QjtRQUEzRSxpQkFZQztRQVo0QixpQkFBWSxHQUFaLFlBQVksQ0FBUTtRQUMvQyxJQUFJLENBQUMsRUFBRSxHQUFHLGNBQWMsRUFBRSxDQUFDO1FBRTNCLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLFVBQUMsTUFBTTtZQUMvQixPQUFPLENBQUMsU0FBUyxFQUFFLENBQUMsS0FBSyxDQUNyQixtREFBbUQsRUFBRSxLQUFJLENBQUMsRUFBRSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBRTFFLDBFQUEwRTtZQUMxRSxLQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDZixDQUFDLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUNqQyxDQUFDO0lBRU8sdUJBQUssR0FBYjtRQUNFLElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ25CLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDM0IsQ0FBQztRQUNELElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2hDLENBQUM7SUFFYSx5QkFBTyxHQUFy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SSxPQUFPLENBQU8sVUFBQyxPQUFPLEVBQUUsTUFBTTtnQ0FDdEMsSUFBTSxpQkFBaUIsR0FBRyxVQUFDLElBQVk7b0NBQ3JDLFNBQVMsSUFBSSxJQUFJLENBQUM7b0NBQ2xCLHlEQUF5RDtvQ0FDekQsSUFBSSxTQUFTLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUM7d0NBQ3JDLFVBQVUsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxpQkFBaUIsQ0FBQyxDQUFDO3dDQUNqRCxPQUFPLEVBQUUsQ0FBQztvQ0FDWixDQUFDO2dDQUNILENBQUMsQ0FBQztnQ0FDRixVQUFVLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsaUJBQWlCLENBQUMsQ0FBQztnQ0FDaEQsVUFBVSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDOzRCQUN4QyxDQUFDLENBQUMsRUFBQTs7d0JBWEYsU0FXRSxDQUFDO3dCQUNILHNCQUFPLFFBQVEsRUFBQzs7OztLQUNqQjtJQUNILGdCQUFDO0FBQUQsQ0FBQyxBQXJERCxJQXFEQztBQXJEWSw4QkFBUyIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gKiBDb3B5cmlnaHQgMjAyMCBHb29nbGUgSW5jLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7IHlvdSBtYXkgbm90XG4gKiB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZlxuICogdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsIFdJVEhPVVRcbiAqIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4gU2VlIHRoZVxuICogTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQgbGltaXRhdGlvbnMgdW5kZXJcbiAqIHRoZSBMaWNlbnNlLlxuICovXG5cbmltcG9ydCAqIGFzIGNoaWxkUHJvY2VzcyBmcm9tICdjaGlsZF9wcm9jZXNzJztcbmltcG9ydCAqIGFzIGNyeXB0byBmcm9tICdjcnlwdG8nO1xuaW1wb3J0ICogYXMgaHR0cCBmcm9tICdodHRwJztcbmltcG9ydCAqIGFzIG5ldCBmcm9tICduZXQnO1xuLy8gVGhlIHVudXN1YWwgY2FzaW5nIGlzIGZyb20gdXBzdHJlYW0gU29ja2V0SU8uXG4vLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6ZW5mb3JjZS1uYW1lLWNhc2luZ1xuaW1wb3J0ICogYXMgU29ja2V0SU8gZnJvbSAnc29ja2V0LmlvJztcbmltcG9ydCB7U2VydmVyfSBmcm9tICd3cyc7XG5cbmltcG9ydCAqIGFzIGpzb25ScGMgZnJvbSAnLi9qc29uX3JwYyc7XG5pbXBvcnQgKiBhcyBsb2dnaW5nIGZyb20gJy4vbG9nZ2luZyc7XG5pbXBvcnQge1NvY2tldCwgU29ja2V0SU9BZGFwdGVyLCBXZWJTb2NrZXRBZGFwdGVyfSBmcm9tICcuL3NvY2tldHMnO1xuXG5sZXQgc2Vzc2lvbkNvdW50ZXIgPSAwO1xuXG4vKiogU29ja2V0PC0+ZGVidWcgYWRhcHRlci4gKi9cbmNsYXNzIFNlc3Npb24ge1xuICBwcml2YXRlIHJlYWRvbmx5IGlkOiBudW1iZXI7XG4gIHByaXZhdGUgZGFwU29ja2V0PzogbmV0LlNvY2tldDtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IGNsaWVudFNvY2tldDogU29ja2V0LCBkb21haW5Tb2NrZXRQYXRoOiBzdHJpbmcpIHtcbiAgICB0aGlzLmlkID0gc2Vzc2lvbkNvdW50ZXIrKztcblxuICAgIHRoaXMuY2xpZW50U29ja2V0Lm9uQ2xvc2UoKHJlYXNvbikgPT4ge1xuICAgICAgbG9nZ2luZy5nZXRMb2dnZXIoKS5kZWJ1ZyhcbiAgICAgICAgICAnREFQIHNvY2tldCBkaXNjb25uZWN0ZWQgZm9yIHNlc3Npb24gJWQgcmVhc29uOiAlcycsIHRoaXMuaWQsIHJlYXNvbik7XG5cbiAgICAgIC8vIEhhbmRsZSBjbGllbnQgZGlzY29ubmVjdHMgdG8gY2xvc2Ugc29ja2V0cywgc28gYXMgdG8gZnJlZSB1cCByZXNvdXJjZXMuXG4gICAgICB0aGlzLmNsb3NlKCk7XG4gICAgfSk7XG5cbiAgICB0aGlzLmNvbm5lY3QoZG9tYWluU29ja2V0UGF0aCk7XG4gIH1cblxuICBwcml2YXRlIGNsb3NlKCkge1xuICAgIGlmICh0aGlzLmRhcFNvY2tldCkge1xuICAgICAgdGhpcy5kYXBTb2NrZXQuZGVzdHJveSgpO1xuICAgIH1cbiAgICB0aGlzLmNsaWVudFNvY2tldC5jbG9zZSh0cnVlKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgY29ubmVjdChkb21haW5Tb2NrZXRQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgbG9nZ2luZy5nZXRMb2dnZXIoKS5pbmZvKFxuICAgICAgICAgICdEQVAgY3JlYXRpbmcgU29ja2V0IHRvICVzIGZvciBzZXNzaW9uICVkJywgZG9tYWluU29ja2V0UGF0aCxcbiAgICAgICAgICB0aGlzLmlkKTtcblxuICAgICAgY29uc3QgcnBjID0gbmV3IGpzb25ScGMuSnNvblJwY1JlYWRlcigoZGFwTWVzc2FnZSkgPT4ge1xuICAgICAgICBjb25zdCBtZXNzYWdlOlxuICAgICAgICAgICAgT3V0Z29pbmdNZXNzYWdlID0ge2RhdGE6IGpzb25ScGMuZW5jb2RlSnNvblJwYyhkYXBNZXNzYWdlLmNvbnRlbnQpfTtcbiAgICAgICAgdGhpcy5jbGllbnRTb2NrZXQuc2VuZFN0cmluZyhKU09OLnN0cmluZ2lmeShtZXNzYWdlKSk7XG4gICAgICB9KTtcblxuICAgICAgY29uc3QgZGFwU29ja2V0ID0gbmV3IG5ldC5Tb2NrZXQoKTtcbiAgICAgIHRoaXMuZGFwU29ja2V0ID0gZGFwU29ja2V0O1xuICAgICAgZGFwU29ja2V0Lm9uKCdkYXRhJywgKGRhdGE6IEJ1ZmZlcikgPT4ge1xuICAgICAgICBycGMuYXBwZW5kKGRhdGEpO1xuICAgICAgfSk7XG4gICAgICBkYXBTb2NrZXQub24oJ2Nsb3NlJywgKCkgPT4ge1xuICAgICAgICB0aGlzLmNsb3NlKCk7XG4gICAgICB9KTtcbiAgICAgIGF3YWl0IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgZGFwU29ja2V0Lm9uKCdlcnJvcicsIHJlamVjdCk7XG4gICAgICAgIGRhcFNvY2tldC5jb25uZWN0KGRvbWFpblNvY2tldFBhdGgsIHJlc29sdmUpO1xuICAgICAgfSk7XG5cbiAgICAgIC8vIE5vdGlmeSB0aGUgY2xpZW50IHRoYXQgdGhlIGNvbm5lY3Rpb24uaXMgbm93IG9wZW4uXG4gICAgICBjb25zdCBtZXNzYWdlOiBPdXRnb2luZ01lc3NhZ2UgPSB7b3BlbjogdHJ1ZX07XG4gICAgICB0aGlzLmNsaWVudFNvY2tldC5zZW5kU3RyaW5nKEpTT04uc3RyaW5naWZ5KG1lc3NhZ2UpKTtcbiAgICAgIHRoaXMuY2xpZW50U29ja2V0Lm9uQmluYXJ5TWVzc2FnZSgoZGF0YTogQnVmZmVyKSA9PiB7XG4gICAgICAgIGRhcFNvY2tldC53cml0ZShVaW50OEFycmF5LmZyb20oZGF0YSkpO1xuICAgICAgfSk7XG4gICAgICB0aGlzLmNsaWVudFNvY2tldC5vblN0cmluZ01lc3NhZ2UoKGRhdGE6IHN0cmluZykgPT4ge1xuICAgICAgICBkYXBTb2NrZXQud3JpdGUoZGF0YSk7XG4gICAgICB9KTtcbiAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby1hbnlcbiAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICBsb2dnaW5nLmdldExvZ2dlcigpLmVycm9yKCdFcnJvciBjb25uZWN0aW5nIHRvIERlYnVnIEFkYXB0ZXI6ICVzJywgZXJyb3IpO1xuICAgICAgdGhpcy5jbG9zZSgpO1xuICAgIH1cbiAgfVxufVxuXG4vKiogRGVidWcgQWRhcHRlciBQcm90b2NvbCBzZXJ2ZXIuICovXG5leHBvcnQgY2xhc3MgRGFwU2VydmVyIHtcbiAgcHJpdmF0ZSByZWFkb25seSBwb3J0UHJvbWlzZTogUHJvbWlzZTxzdHJpbmc+O1xuICBjb25zdHJ1Y3RvcihtdXhCaW5hcnk6IHN0cmluZywgc2VydmVyPzogU29ja2V0SU8uU2VydmVyKSB7XG4gICAgdGhpcy5wb3J0UHJvbWlzZSA9IHRoaXMuc3Bhd25NdWx0aXBsZXhlcihtdXhCaW5hcnkpO1xuXG4gICAgc2VydmVyPy5vZignL2RlYnVnZ2VyJykub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0OiBTb2NrZXRJTy5Tb2NrZXQpID0+IHtcbiAgICAgIHRoaXMucG9ydFByb21pc2UudGhlbigoZG9tYWluU29ja2V0UGF0aCkgPT4ge1xuICAgICAgICAvLyBTZXNzaW9uIG1hbmFnZXMgaXRzIG93biBsaWZldGltZS5cbiAgICAgICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLXVudXNlZC1leHByZXNzaW9uXG4gICAgICAgIG5ldyBTZXNzaW9uKG5ldyBTb2NrZXRJT0FkYXB0ZXIoc29ja2V0KSwgZG9tYWluU29ja2V0UGF0aCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIGhhbmRsZVVwZ3JhZGUocmVxdWVzdDogaHR0cC5JbmNvbWluZ01lc3NhZ2UsIHNvY2s6IG5ldC5Tb2NrZXQsIGhlYWQ6IEJ1ZmZlcikge1xuICAgIG5ldyBTZXJ2ZXIoe25vU2VydmVyOiB0cnVlfSkuaGFuZGxlVXBncmFkZShyZXF1ZXN0LCBzb2NrLCBoZWFkLCAod3MpID0+IHtcbiAgICAgIHRoaXMucG9ydFByb21pc2UudGhlbigoZG9tYWluU29ja2V0UGF0aCkgPT4ge1xuICAgICAgICAvLyBTZXNzaW9uIG1hbmFnZXMgaXRzIG93biBsaWZldGltZS5cbiAgICAgICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLXVudXNlZC1leHByZXNzaW9uXG4gICAgICAgIG5ldyBTZXNzaW9uKG5ldyBXZWJTb2NrZXRBZGFwdGVyKHdzKSwgZG9tYWluU29ja2V0UGF0aCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgc3Bhd25NdWx0aXBsZXhlcihtdXhCaW5hcnk6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgZmlsZW5hbWUgPVxuICAgICAgICBgL3RtcC9kZWJ1Z2dlcl8ke2NyeXB0by5yYW5kb21CeXRlcyg2KS5yZWFkVUludExFKDAsIDYpLnRvU3RyaW5nKDM2KX1gO1xuICAgIGNvbnN0IG11eFByb2Nlc3MgPSBjaGlsZFByb2Nlc3Muc3Bhd24obXV4QmluYXJ5LCBbXG4gICAgICBgLS1kb21haW5fc29ja2V0X3BhdGg9JHtmaWxlbmFtZX1gLFxuICAgIF0pO1xuXG4gICAgbXV4UHJvY2Vzcy5zdGRvdXQub24oJ2RhdGEnLCAoZGF0YTogc3RyaW5nKSA9PiB7XG4gICAgICBsb2dnaW5nLmdldExvZ2dlcigpLmluZm8oJyVzOiAlcycsIG11eEJpbmFyeSwgZGF0YSk7XG4gICAgfSk7XG4gICAgbXV4UHJvY2Vzcy5zdGRvdXQub24oJ2Vycm9yJywgKGRhdGE6IHN0cmluZykgPT4ge1xuICAgICAgbG9nZ2luZy5nZXRMb2dnZXIoKS5pbmZvKCclczogJXMnLCBtdXhCaW5hcnksIGRhdGEpO1xuICAgIH0pO1xuXG4gICAgbGV0IG11eE91dHB1dCA9ICcnO1xuICAgIGF3YWl0IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGNvbnN0IGNvbm5lY3Rpb25IYW5kbGVyID0gKGRhdGE6IHN0cmluZykgPT4ge1xuICAgICAgICBtdXhPdXRwdXQgKz0gZGF0YTtcbiAgICAgICAgLy8gV2FpdCBmb3IgdGhlIHByb2Nlc3MgdG8gaW5kaWNhdGUgdGhhdCBpdCBpcyBsaXN0ZW5pbmcuXG4gICAgICAgIGlmIChtdXhPdXRwdXQubWF0Y2goL0xpc3RlbmluZyBvbiAvKSkge1xuICAgICAgICAgIG11eFByb2Nlc3Muc3Rkb3V0Lm9mZignZGF0YScsIGNvbm5lY3Rpb25IYW5kbGVyKTtcbiAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgICBtdXhQcm9jZXNzLnN0ZG91dC5vbignZGF0YScsIGNvbm5lY3Rpb25IYW5kbGVyKTtcbiAgICAgIG11eFByb2Nlc3Muc3Rkb3V0Lm9uKCdlcnJvcicsIHJlamVjdCk7XG4gICAgfSk7XG4gICAgcmV0dXJuIGZpbGVuYW1lO1xuICB9XG59XG5cbmRlY2xhcmUgaW50ZXJmYWNlIE91dGdvaW5nTWVzc2FnZSB7XG4gIHJlYWRvbmx5IGRhdGE/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IG9wZW4/OiBib29sZWFuO1xufVxuIl19