; | |
/* | |
* Copyright 2015 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 }; | |
} | |
}; | |
var __values = (this && this.__values) || function(o) { | |
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; | |
if (m) return m.call(o); | |
if (o && typeof o.length === "number") return { | |
next: function () { | |
if (o && i >= o.length) o = void 0; | |
return { value: o && o[i++], done: !o }; | |
} | |
}; | |
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); | |
}; | |
Object.defineProperty(exports, "__esModule", { value: true }); | |
exports.stop = exports.run = void 0; | |
var http = require("http"); | |
var httpProxy = require("http-proxy"); | |
var path = require("path"); | |
var url = require("url"); | |
var jupyter = require("./jupyter"); | |
var logging = require("./logging"); | |
var python_lsp_1 = require("./python_lsp"); | |
var reverseProxy = require("./reverseProxy"); | |
var socketio_to_dap_1 = require("./socketio_to_dap"); | |
var socketio_to_pty_1 = require("./socketio_to_pty"); | |
var sockets = require("./sockets"); | |
var server; | |
/** | |
* The application settings instance. | |
*/ | |
var appSettings; | |
var fileshim; | |
/** | |
* Handles all requests. | |
* @param request the incoming HTTP request. | |
* @param response the out-going HTTP response. | |
* @path the parsed path in the request. | |
*/ | |
function handleRequest(request, response, requestPath) { | |
return __awaiter(this, void 0, void 0, function () { | |
var host, url_1, projectId; | |
return __generator(this, function (_a) { | |
switch (_a.label) { | |
case 0: | |
// /files and /static are only used in runlocal. | |
if (fileshim && | |
((requestPath.indexOf('/api/contents') === 0) || | |
(requestPath.indexOf('/files') === 0))) { | |
fileshim.web(request, response, null); | |
return [2 /*return*/]; | |
} | |
// The explicit set of paths we proxy to jupyter. | |
if ((requestPath.indexOf('/api') === 0) || | |
(requestPath.indexOf('/nbextensions') === 0) || | |
(requestPath.indexOf('/files') === 0) || | |
(requestPath.indexOf('/static') === 0)) { | |
jupyter.handleRequest(request, response); | |
return [2 /*return*/]; | |
} | |
if (!(appSettings.colabRedirect && requestPath === '/')) return [3 /*break*/, 3]; | |
host = process.env['WEB_HOST'] || ''; | |
url_1 = appSettings.colabRedirect.replace('{jupyter_host}', host); | |
if (!appSettings.colabRedirect.includes('{project_id}')) return [3 /*break*/, 2]; | |
return [4 /*yield*/, readGceProjectId()]; | |
case 1: | |
projectId = _a.sent(); | |
url_1 = url_1.replace('{project_id}', projectId); | |
_a.label = 2; | |
case 2: | |
response.writeHead(302, { | |
'Location': url_1, | |
}); | |
response.end(); | |
return [2 /*return*/]; | |
case 3: | |
// Not Found | |
response.statusCode = 404; | |
response.end(); | |
return [2 /*return*/]; | |
} | |
}); | |
}); | |
} | |
/** | |
* Base logic for handling all requests sent to the proxy web server. Some | |
* requests are handled within the server, while some are proxied to the | |
* Jupyter notebook server. | |
* | |
* Error handling is left to the caller. | |
* | |
* @param request the incoming HTTP request. | |
* @param response the out-going HTTP response. | |
*/ | |
function uncheckedRequestHandler(request, response) { | |
var e_1, _a; | |
var parsedUrl = url.parse(request.url || '', true); | |
var urlpath = parsedUrl.pathname || ''; | |
logging.logRequest(request, response); | |
try { | |
for (var socketIoHandlers_1 = __values(socketIoHandlers), socketIoHandlers_1_1 = socketIoHandlers_1.next(); !socketIoHandlers_1_1.done; socketIoHandlers_1_1 = socketIoHandlers_1.next()) { | |
var handler = socketIoHandlers_1_1.value; | |
if (handler.isPathProxied(urlpath)) { | |
// Will automatically be handled by socket.io. | |
return; | |
} | |
} | |
} | |
catch (e_1_1) { e_1 = { error: e_1_1 }; } | |
finally { | |
try { | |
if (socketIoHandlers_1_1 && !socketIoHandlers_1_1.done && (_a = socketIoHandlers_1.return)) _a.call(socketIoHandlers_1); | |
} | |
finally { if (e_1) throw e_1.error; } | |
} | |
var proxyPort = reverseProxy.getRequestPort(urlpath); | |
if (sockets.isSocketIoPath(urlpath)) { | |
// Will automatically be handled by socket.io. | |
} | |
else if (proxyPort && proxyPort !== request.socket.localPort) { | |
// Do not allow proxying to this same port, as that can be used to mask the | |
// target path. | |
reverseProxy.handleRequest(request, response, proxyPort); | |
} | |
else { | |
handleRequest(request, response, urlpath); | |
} | |
} | |
/** | |
* Handles all requests sent to the proxy web server. Some requests are handled | |
* within the server, while some are proxied to the Jupyter notebook server. | |
* @param request the incoming HTTP request. | |
* @param response the out-going HTTP response. | |
*/ | |
function requestHandler(request, response) { | |
try { | |
uncheckedRequestHandler(request, response); | |
} | |
catch (e) { | |
logging.getLogger().error("Uncaught error handling a request to \"".concat(request.url, "\": ").concat(e)); | |
} | |
} | |
var socketIoHandlers = []; | |
/** | |
* Runs the proxy web server. | |
* @param settings the configuration settings to use. | |
*/ | |
function run(settings) { | |
jupyter.init(settings); | |
reverseProxy.init(settings); | |
appSettings = settings; | |
if (settings.fileHandlerAddr) { | |
fileshim = httpProxy.createProxyServer({ target: "http://".concat(appSettings.fileHandlerAddr) }); | |
fileshim.on('error', function (error, request, response) { | |
logging.getLogger().error(error, "fileshim error for ".concat(request.url)); | |
response.writeHead(500, 'Internal Server Error'); | |
response.end(); | |
}); | |
} | |
server = http.createServer(requestHandler); | |
// Disable HTTP keep-alive connection timeouts in order to avoid connection | |
// flakes. Details: b/112151064 | |
server.keepAliveTimeout = 0; | |
var socketIoServer = sockets.init(server, settings); | |
socketIoHandlers.push(new socketio_to_pty_1.SocketIoToPty('/tty', server)); | |
var dapServer; | |
if (settings.debugAdapterMultiplexerPath) { | |
dapServer = | |
new socketio_to_dap_1.DapServer(settings.debugAdapterMultiplexerPath, socketIoServer); | |
} | |
var contentDir = path.join(settings.datalabRoot, settings.contentDir); | |
var logsDir = path.join(settings.datalabRoot, '/var/colab/'); | |
var pipLogsDir = path.join(settings.datalabRoot, '/var/log/'); | |
// Handler manages its own lifetime. | |
// tslint:disable-next-line:no-unused-expression | |
new python_lsp_1.SocketIOToLsp(socketIoServer, __dirname, contentDir, logsDir, pipLogsDir, settings.languageServerProxy, settings.languageServerProxyArgs); | |
server.on('upgrade', function (request, socket, head) { | |
var parsedUrl = url.parse(request.url || '', true); | |
var urlpath = parsedUrl.pathname || ''; | |
var proxyPort = reverseProxy.getRequestPort(urlpath); | |
if (proxyPort && proxyPort !== request.socket.localPort) { | |
reverseProxy.handleUpgrade(request, socket, head, proxyPort); | |
return; | |
} | |
if (request.url === '/colab/tty') { | |
(0, socketio_to_pty_1.WebSocketToPty)(request, socket, head); | |
return; | |
} | |
if (request.url === '/colab/dap') { | |
dapServer === null || dapServer === void 0 ? void 0 : dapServer.handleUpgrade(request, socket, head); | |
return; | |
} | |
if (request.url === '/colab/lsp') { | |
(0, python_lsp_1.WebSocketToLsp)(request, socket, head, __dirname, contentDir, logsDir, pipLogsDir, settings.languageServerProxy, settings.languageServerProxyArgs); | |
return; | |
} | |
jupyter.handleSocket(request, socket, head); | |
}); | |
logging.getLogger().info('Starting server at http://localhost:%d', settings.serverPort); | |
process.on('SIGINT', function () { return process.exit(); }); | |
var options = { | |
port: settings.serverPort, | |
ipv6Only: false, | |
host: settings.serverHost || '' | |
}; | |
if ('TEST_TMPDIR' in process.env) { | |
// Required to avoid "EAFNOSUPPORT: address family not supported" on | |
// IPv6-only environments (notably, even with the host override below). | |
options['ipv6Only'] = true; | |
// ipv6Only alone isn't enough to avoid attempting to bind to 0.0.0.0 (which | |
// fails on IPv6-only environments). Need to specify an IP address because | |
// DNS resolution even of ip6-localhost fails on some such environments. | |
options['host'] = '::1'; | |
} | |
server.listen(options); | |
} | |
exports.run = run; | |
/** | |
* Stops the server and associated Jupyter server. | |
*/ | |
function stop() { | |
jupyter.close(); | |
} | |
exports.stop = stop; | |
function readGceProjectId() { | |
return __awaiter(this, void 0, void 0, function () { | |
var metadataHost, port, portParts, projectId; | |
return __generator(this, function (_a) { | |
switch (_a.label) { | |
case 0: | |
metadataHost = 'metadata.google.internal'; | |
port = undefined; | |
if (process.env['GCE_METADATA_HOST']) { | |
metadataHost = process.env['GCE_METADATA_HOST']; | |
portParts = metadataHost.match(/(.*):(\d+)/); | |
if (portParts) { | |
metadataHost = portParts[1]; | |
if (metadataHost.startsWith('[')) { | |
metadataHost = metadataHost.substring(1, metadataHost.length - 1); | |
} | |
port = Number(portParts[2]); | |
} | |
} | |
return [4 /*yield*/, new Promise(function (resolve, reject) { | |
http.get({ | |
hostname: metadataHost, | |
port: port, | |
path: '/computeMetadata/v1/project/project-id', | |
headers: { 'Metadata-Flavor': 'Google' } | |
}, function (response) { | |
var data = ''; | |
response.on('data', function (chunk) { | |
data += chunk; | |
}); | |
response.on('end', function () { | |
resolve(data); | |
}); | |
}) | |
.on('error', reject) | |
.end(); | |
})]; | |
case 1: | |
projectId = _a.sent(); | |
return [2 /*return*/, projectId.trim()]; | |
} | |
}); | |
}); | |
} | |
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vdGhpcmRfcGFydHkvY29sYWIvc291cmNlcy9zZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7OztHQWNHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUVILDJCQUE2QjtBQUM3QixzQ0FBd0M7QUFFeEMsMkJBQTZCO0FBQzdCLHlCQUEyQjtBQUczQixtQ0FBcUM7QUFDckMsbUNBQXFDO0FBQ3JDLDJDQUEyRDtBQUMzRCw2Q0FBK0M7QUFDL0MscURBQTRDO0FBQzVDLHFEQUFnRTtBQUNoRSxtQ0FBcUM7QUFFckMsSUFBSSxNQUFtQixDQUFDO0FBQ3hCOztHQUVHO0FBQ0gsSUFBSSxXQUF3QixDQUFDO0FBRTdCLElBQUksUUFBK0IsQ0FBQztBQUdwQzs7Ozs7R0FLRztBQUNILFNBQWUsYUFBYSxDQUN4QixPQUE2QixFQUFFLFFBQTZCLEVBQzVELFdBQW1COzs7Ozs7b0JBQ3JCLGdEQUFnRDtvQkFFaEQsSUFBSSxRQUFRO3dCQUNSLENBQUMsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQzs0QkFDNUMsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQzt3QkFDNUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsUUFBUSxFQUFFLElBQUksQ0FBQyxDQUFDO3dCQUN0QyxzQkFBTztvQkFDVCxDQUFDO29CQUNELGlEQUFpRDtvQkFDakQsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO3dCQUNuQyxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxDQUFDO3dCQUM1QyxDQUFDLFdBQVcs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QUNBO2dDQUNFLFFBQVEsRUFBRSxZQUFZO2dDQUN0QixJQUFJLE1BQUE7Z0NBQ0osSUFBSSxFQUFFLHdDQUF3QztnQ0FDOUMsT0FBTyxFQUFFLEVBQUMsaUJBQWlCLEVBQUUsUUFBUSxFQUFDOzZCQUN2QyxFQUNELFVBQUMsUUFBUTtnQ0FDUCxJQUFJLElBQUksR0FBRyxFQUFFLENBQUM7Z0NBQ2QsUUFBUSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsVUFBQyxLQUFLO29DQUN4QixJQUFJLElBQUksS0FBSyxDQUFDO2dDQUNoQixDQUFDLENBQUMsQ0FBQztnQ0FDSCxRQUFRLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRTtvQ0FDakIsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO2dDQUNoQixDQUFDLENBQUMsQ0FBQzs0QkFDTCxDQUFDLENBQUM7aUNBQ0wsRUFBRSxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUM7aUNBQ25CLEdBQUcsRUFBRSxDQUFDO3dCQUNiLENBQUMsQ0FBQyxFQUFBOztvQkFuQkksU0FBUyxHQUFHLFNBbUJoQjtvQkFDRixzQkFBTyxTQUFTLENBQUMsSUFBSSxFQUFFLEVBQUM7Ozs7Q0FDekIiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogQ29weXJpZ2h0IDIwMTUgR29vZ2xlIEluYy4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpOyB5b3UgbWF5IG5vdFxuICogdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2ZcbiAqIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLCBXSVRIT1VUXG4gKiBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuIFNlZSB0aGVcbiAqIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kIGxpbWl0YXRpb25zIHVuZGVyXG4gKiB0aGUgTGljZW5zZS5cbiAqL1xuXG5pbXBvcnQgKiBhcyBodHRwIGZyb20gJ2h0dHAnO1xuaW1wb3J0ICogYXMgaHR0cFByb3h5IGZyb20gJ2h0dHAtcHJveHknO1xuaW1wb3J0ICogYXMgbmV0IGZyb20gJ25ldCc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0ICogYXMgdXJsIGZyb20gJ3VybCc7XG5cbmltcG9ydCB7QXBwU2V0dGluZ3N9IGZyb20gJy4vYXBwU2V0dGluZ3MnO1xuaW1wb3J0ICogYXMganVweXRlciBmcm9tICcuL2p1cHl0ZXInO1xuaW1wb3J0ICogYXMgbG9nZ2luZyBmcm9tICcuL2xvZ2dpbmcnO1xuaW1wb3J0IHtTb2NrZXRJT1RvTHNwLCBXZWJTb2NrZXRUb0xzcH0gZnJvbSAnLi9weXRob25fbHNwJztcbmltcG9ydCAqIGFzIHJldmVyc2VQcm94eSBmcm9tICcuL3JldmVyc2VQcm94eSc7XG5pbXBvcnQge0RhcFNlcnZlcn0gZnJvbSAnLi9zb2NrZXRpb190b19kYXAnO1xuaW1wb3J0IHtTb2NrZXRJb1RvUHR5LCBXZWJTb2NrZXRUb1B0eX0gZnJvbSAnLi9zb2NrZXRpb190b19wdHknO1xuaW1wb3J0ICogYXMgc29ja2V0cyBmcm9tICcuL3NvY2tldHMnO1xuXG5sZXQgc2VydmVyOiBodHRwLlNlcnZlcjtcbi8qKlxuICogVGhlIGFwcGxpY2F0aW9uIHNldHRpbmdzIGluc3RhbmNlLlxuICovXG5sZXQgYXBwU2V0dGluZ3M6IEFwcFNldHRpbmdzO1xuXG5sZXQgZmlsZXNoaW06IGh0dHBQcm94eS5Qcm94eVNlcnZlcjtcblxuXG4vKipcbiAqIEhhbmRsZXMgYWxsIHJlcXVlc3RzLlxuICogQHBhcmFtIHJlcXVlc3QgdGhlIGluY29taW5nIEhUVFAgcmVxdWVzdC5cbiAqIEBwYXJhbSByZXNwb25zZSB0aGUgb3V0LWdvaW5nIEhUVFAgcmVzcG9uc2UuXG4gKiBAcGF0aCB0aGUgcGFyc2VkIHBhdGggaW4gdGhlIHJlcXVlc3QuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGhhbmRsZVJlcXVlc3QoXG4gICAgcmVxdWVzdDogaHR0cC5JbmNvbWluZ01lc3NhZ2UsIHJlc3BvbnNlOiBodHRwLlNlcnZlclJlc3BvbnNlLFxuICAgIHJlcXVlc3RQYXRoOiBzdHJpbmcpIHtcbiAgLy8gL2ZpbGVzIGFuZCAvc3RhdGljIGFyZSBvbmx5IHVzZWQgaW4gcnVubG9jYWwuXG5cbiAgaWYgKGZpbGVzaGltICYmXG4gICAgICAoKHJlcXVlc3RQYXRoLmluZGV4T2YoJy9hcGkvY29udGVudHMnKSA9PT0gMCkgfHxcbiAgICAgICAocmVxdWVzdFBhdGguaW5kZXhPZignL2ZpbGVzJykgPT09IDApKSkge1xuICAgIGZpbGVzaGltLndlYihyZXF1ZXN0LCByZXNwb25zZSwgbnVsbCk7XG4gICAgcmV0dXJuO1xuICB9XG4gIC8vIFRoZSBleHBsaWNpdCBzZXQgb2YgcGF0aHMgd2UgcHJveHkgdG8ganVweXRlci5cbiAgaWYgKChyZXF1ZXN0UGF0aC5pbmRleE9mKCcvYXBpJykgPT09IDApIHx8XG4gICAgICAocmVxdWVzdFBhdGguaW5kZXhPZignL25iZXh0ZW5zaW9ucycpID09PSAwKSB8fFxuICAgICAgKHJlcXVlc3RQYXRoLmluZGV4T2YoJy9maWxlcycpID09PSAwKSB8fFxuICAgICAgKHJlcXVlc3RQYXRoLmluZGV4T2YoJy9zdGF0aWMnKSA9PT0gMCkpIHtcbiAgICBqdXB5dGVyLmhhbmRsZVJlcXVlc3QocmVxdWVzdCwgcmVzcG9uc2UpO1xuICAgIHJldHVybjtcbiAgfVxuICBpZiAoYXBwU2V0dGluZ3MuY29sYWJSZWRpcmVjdCAmJiByZXF1ZXN0UGF0aCA9PT0gJy8nKSB7XG4gICAgY29uc3QgaG9zdCA9IHByb2Nlc3MuZW52WydXRUJfSE9TVCddIHx8ICcnO1xuICAgIGxldCB1cmwgPSBhcHBTZXR0aW5ncy5jb2xhYlJlZGlyZWN0LnJlcGxhY2UoJ3tqdXB5dGVyX2hvc3R9JywgaG9zdCk7XG4gICAgaWYgKGFwcFNldHRpbmdzLmNvbGFiUmVkaXJlY3QuaW5jbHVkZXMoJ3twcm9qZWN0X2lkfScpKSB7XG4gICAgICBjb25zdCBwcm9qZWN0SWQgPSBhd2FpdCByZWFkR2NlUHJvamVjdElkKCk7XG4gICAgICB1cmwgPSB1cmwucmVwbGFjZSgne3Byb2plY3RfaWR9JywgcHJvamVjdElkKTtcbiAgICB9XG4gICAgcmVzcG9uc2Uud3JpdGVIZWFkKDMwMiwge1xuICAgICAgJ0xvY2F0aW9uJzogdXJsLFxuICAgIH0pO1xuICAgIHJlc3BvbnNlLmVuZCgpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIE5vdCBGb3VuZFxuICByZXNwb25zZS5zdGF0dXNDb2RlID0gNDA0O1xuICByZXNwb25zZS5lbmQoKTtcbn1cblxuLyoqXG4gKiBCYXNlIGxvZ2ljIGZvciBoYW5kbGluZyBhbGwgcmVxdWVzdHMgc2VudCB0byB0aGUgcHJveHkgd2ViIHNlcnZlci4gU29tZVxuICogcmVxdWVzdHMgYXJlIGhhbmRsZWQgd2l0aGluIHRoZSBzZXJ2ZXIsIHdoaWxlIHNvbWUgYXJlIHByb3hpZWQgdG8gdGhlXG4gKiBKdXB5dGVyIG5vdGVib29rIHNlcnZlci5cbiAqXG4gKiBFcnJvciBoYW5kbGluZyBpcyBsZWZ0IHRvIHRoZSBjYWxsZXIuXG4gKlxuICogQHBhcmFtIHJlcXVlc3QgdGhlIGluY29taW5nIEhUVFAgcmVxdWVzdC5cbiAqIEBwYXJhbSByZXNwb25zZSB0aGUgb3V0LWdvaW5nIEhUVFAgcmVzcG9uc2UuXG4gKi9cbmZ1bmN0aW9uIHVuY2hlY2tlZFJlcXVlc3RIYW5kbGVyKFxuICAgIHJlcXVlc3Q6IGh0dHAuSW5jb21pbmdNZXNzYWdlLCByZXNwb25zZTogaHR0cC5TZXJ2ZXJSZXNwb25zZSkge1xuICBjb25zdCBwYXJzZWRVcmwgPSB1cmwucGFyc2UocmVxdWVzdC51cmwgfHwgJycsIHRydWUpO1xuICBjb25zdCB1cmxwYXRoID0gcGFyc2VkVXJsLnBhdGhuYW1lIHx8ICcnO1xuXG4gIGxvZ2dpbmcubG9nUmVxdWVzdChyZXF1ZXN0LCByZXNwb25zZSk7XG5cbiAgZm9yIChjb25zdCBoYW5kbGVyIG9mIHNvY2tldElvSGFuZGxlcnMpIHtcbiAgICBpZiAoaGFuZGxlci5pc1BhdGhQcm94aWVkKHVybHBhdGgpKSB7XG4gICAgICAvLyBXaWxsIGF1dG9tYXRpY2FsbHkgYmUgaGFuZGxlZCBieSBzb2NrZXQuaW8uXG4gICAgICByZXR1cm47XG4gICAgfVxuICB9XG5cbiAgY29uc3QgcHJveHlQb3J0ID0gcmV2ZXJzZVByb3h5LmdldFJlcXVlc3RQb3J0KHVybHBhdGgpO1xuICBpZiAoc29ja2V0cy5pc1NvY2tldElvUGF0aCh1cmxwYXRoKSkge1xuICAgIC8vIFdpbGwgYXV0b21hdGljYWxseSBiZSBoYW5kbGVkIGJ5IHNvY2tldC5pby5cbiAgfSBlbHNlIGlmIChwcm94eVBvcnQgJiYgcHJveHlQb3J0ICE9PSByZXF1ZXN0LnNvY2tldC5sb2NhbFBvcnQpIHtcbiAgICAvLyBEbyBub3QgYWxsb3cgcHJveHlpbmcgdG8gdGhpcyBzYW1lIHBvcnQsIGFzIHRoYXQgY2FuIGJlIHVzZWQgdG8gbWFzayB0aGVcbiAgICAvLyB0YXJnZXQgcGF0aC5cbiAgICByZXZlcnNlUHJveHkuaGFuZGxlUmVxdWVzdChyZXF1ZXN0LCByZXNwb25zZSwgcHJveHlQb3J0KTtcbiAgfSBlbHNlIHtcbiAgICBoYW5kbGVSZXF1ZXN0KHJlcXVlc3QsIHJlc3BvbnNlLCB1cmxwYXRoKTtcbiAgfVxufVxuXG4vKipcbiAqIEhhbmRsZXMgYWxsIHJlcXVlc3RzIHNlbnQgdG8gdGhlIHByb3h5IHdlYiBzZXJ2ZXIuIFNvbWUgcmVxdWVzdHMgYXJlIGhhbmRsZWRcbiAqIHdpdGhpbiB0aGUgc2VydmVyLCB3aGlsZSBzb21lIGFyZSBwcm94aWVkIHRvIHRoZSBKdXB5dGVyIG5vdGVib29rIHNlcnZlci5cbiAqIEBwYXJhbSByZXF1ZXN0IHRoZSBpbmNvbWluZyBIVFRQIHJlcXVlc3QuXG4gKiBAcGFyYW0gcmVzcG9uc2UgdGhlIG91dC1nb2luZyBIVFRQIHJlc3BvbnNlLlxuICovXG5mdW5jdGlvbiByZXF1ZXN0SGFuZGxlcihcbiAgICByZXF1ZXN0OiBodHRwLkluY29taW5nTWVzc2FnZSwgcmVzcG9uc2U6IGh0dHAuU2VydmVyUmVzcG9uc2UpIHtcbiAgdHJ5IHtcbiAgICB1bmNoZWNrZWRSZXF1ZXN0SGFuZGxlcihyZXF1ZXN0LCByZXNwb25zZSk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBsb2dnaW5nLmdldExvZ2dlcigpLmVycm9yKFxuICAgICAgICBgVW5jYXVnaHQgZXJyb3IgaGFuZGxpbmcgYSByZXF1ZXN0IHRvIFwiJHtyZXF1ZXN0LnVybH1cIjogJHtlfWApO1xuICB9XG59XG5cbmNvbnN0IHNvY2tldElvSGFuZGxlcnM6IFNvY2tldElvVG9QdHlbXSA9IFtdO1xuXG4vKipcbiAqIFJ1bnMgdGhlIHByb3h5IHdlYiBzZXJ2ZXIuXG4gKiBAcGFyYW0gc2V0dGluZ3MgdGhlIGNvbmZpZ3VyYXRpb24gc2V0dGluZ3MgdG8gdXNlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcnVuKHNldHRpbmdzOiBBcHBTZXR0aW5ncyk6IHZvaWQge1xuICBqdXB5dGVyLmluaXQoc2V0dGluZ3MpO1xuICByZXZlcnNlUHJveHkuaW5pdChzZXR0aW5ncyk7XG4gIGFwcFNldHRpbmdzID0gc2V0dGluZ3M7XG5cbiAgaWYgKHNldHRpbmdzLmZpbGVIYW5kbGVyQWRkcikge1xuICAgIGZpbGVzaGltID0gaHR0cFByb3h5LmNyZWF0ZVByb3h5U2VydmVyKFxuICAgICAgICB7dGFyZ2V0OiBgaHR0cDovLyR7YXBwU2V0dGluZ3MuZmlsZUhhbmRsZXJBZGRyfWB9KTtcbiAgICBmaWxlc2hpbS5vbignZXJyb3InLCAoZXJyb3IsIHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XG4gICAgICBsb2dnaW5nLmdldExvZ2dlcigpLmVycm9yKGVycm9yLCBgZmlsZXNoaW0gZXJyb3IgZm9yICR7cmVxdWVzdC51cmx9YCk7XG4gICAgICByZXNwb25zZS53cml0ZUhlYWQoNTAwLCAnSW50ZXJuYWwgU2VydmVyIEVycm9yJyk7XG4gICAgICByZXNwb25zZS5lbmQoKTtcbiAgICB9KTtcbiAgfVxuXG4gIHNlcnZlciA9IGh0dHAuY3JlYXRlU2VydmVyKHJlcXVlc3RIYW5kbGVyKTtcbiAgLy8gRGlzYWJsZSBIVFRQIGtlZXAtYWxpdmUgY29ubmVjdGlvbiB0aW1lb3V0cyBpbiBvcmRlciB0byBhdm9pZCBjb25uZWN0aW9uXG4gIC8vIGZsYWtlcy4gRGV0YWlsczogYi8xMTIxNTEwNjRcbiAgc2VydmVyLmtlZXBBbGl2ZVRpbWVvdXQgPSAwO1xuXG4gIGNvbnN0IHNvY2tldElvU2VydmVyID0gc29ja2V0cy5pbml0KHNlcnZlciwgc2V0dGluZ3MpO1xuXG4gIHNvY2tldElvSGFuZGxlcnMucHVzaChuZXcgU29ja2V0SW9Ub1B0eSgnL3R0eScsIHNlcnZlcikpO1xuXG4gIGxldCBkYXBTZXJ2ZXI6IERhcFNlcnZlcjtcbiAgaWYgKHNldHRpbmdzLmRlYnVnQWRhcHRlck11bHRpcGxleGVyUGF0aCkge1xuICAgIGRhcFNlcnZlciA9XG4gICAgICAgIG5ldyBEYXBTZXJ2ZXIoc2V0dGluZ3MuZGVidWdBZGFwdGVyTXVsdGlwbGV4ZXJQYXRoLCBzb2NrZXRJb1NlcnZlcik7XG4gIH1cblxuICBjb25zdCBjb250ZW50RGlyID0gcGF0aC5qb2luKHNldHRpbmdzLmRhdGFsYWJSb290LCBzZXR0aW5ncy5jb250ZW50RGlyKTtcbiAgY29uc3QgbG9nc0RpciA9IHBhdGguam9pbihzZXR0aW5ncy5kYXRhbGFiUm9vdCwgJy92YXIvY29sYWIvJyk7XG4gIGNvbnN0IHBpcExvZ3NEaXIgPSBwYXRoLmpvaW4oc2V0dGluZ3MuZGF0YWxhYlJvb3QsICcvdmFyL2xvZy8nKTtcblxuICAvLyBIYW5kbGVyIG1hbmFnZXMgaXRzIG93biBsaWZldGltZS5cbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLXVudXNlZC1leHByZXNzaW9uXG4gIG5ldyBTb2NrZXRJT1RvTHNwKFxuICAgICAgc29ja2V0SW9TZXJ2ZXIsIF9fZGlybmFtZSwgY29udGVudERpciwgbG9nc0RpciwgcGlwTG9nc0RpcixcbiAgICAgIHNldHRpbmdzLmxhbmd1YWdlU2VydmVyUHJveHksIHNldHRpbmdzLmxhbmd1YWdlU2VydmVyUHJveHlBcmdzKTtcblxuICBzZXJ2ZXIub24oXG4gICAgICAndXBncmFkZScsXG4gICAgICAocmVxdWVzdDogaHR0cC5JbmNvbWluZ01lc3NhZ2UsIHNvY2tldDogbmV0LlNvY2tldCwgaGVhZDogQnVmZmVyKSA9PiB7XG4gICAgICAgIGNvbnN0IHBhcnNlZFVybCA9IHVybC5wYXJzZShyZXF1ZXN0LnVybCB8fCAnJywgdHJ1ZSk7XG4gICAgICAgIGNvbnN0IHVybHBhdGggPSBwYXJzZWRVcmwucGF0aG5hbWUgfHwgJyc7XG4gICAgICAgIGNvbnN0IHByb3h5UG9ydCA9IHJldmVyc2VQcm94eS5nZXRSZXF1ZXN0UG9ydCh1cmxwYXRoKTtcbiAgICAgICAgaWYgKHByb3h5UG9ydCAmJiBwcm94eVBvcnQgIT09IHJlcXVlc3Quc29ja2V0LmxvY2FsUG9ydCkge1xuICAgICAgICAgIHJldmVyc2VQcm94eS5oYW5kbGVVcGdyYWRlKHJlcXVlc3QsIHNvY2tldCwgaGVhZCwgcHJveHlQb3J0KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHJlcXVlc3QudXJsID09PSAnL2NvbGFiL3R0eScpIHtcbiAgICAgICAgICBXZWJTb2NrZXRUb1B0eShyZXF1ZXN0LCBzb2NrZXQsIGhlYWQpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBpZiAocmVxdWVzdC51cmwgPT09ICcvY29sYWIvZGFwJykge1xuICAgICAgICAgIGRhcFNlcnZlcj8uaGFuZGxlVXBncmFkZShyZXF1ZXN0LCBzb2NrZXQsIGhlYWQpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBpZiAocmVxdWVzdC51cmwgPT09ICcvY29sYWIvbHNwJykge1xuICAgICAgICAgIFdlYlNvY2tldFRvTHNwKFxuICAgICAgICAgICAgICByZXF1ZXN0LCBzb2NrZXQsIGhlYWQsIF9fZGlybmFtZSwgY29udGVudERpciwgbG9nc0RpciwgcGlwTG9nc0RpcixcbiAgICAgICAgICAgICAgc2V0dGluZ3MubGFuZ3VhZ2VTZXJ2ZXJQcm94eSwgc2V0dGluZ3MubGFuZ3VhZ2VTZXJ2ZXJQcm94eUFyZ3MpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBqdXB5dGVyLmhhbmRsZVNvY2tldChyZXF1ZXN0LCBzb2NrZXQsIGhlYWQpO1xuICAgICAgfSk7XG5cblxuICBsb2dnaW5nLmdldExvZ2dlcigpLmluZm8oXG4gICAgICAnU3RhcnRpbmcgc2VydmVyIGF0IGh0dHA6Ly9sb2NhbGhvc3Q6JWQnLCBzZXR0aW5ncy5zZXJ2ZXJQb3J0KTtcbiAgcHJvY2Vzcy5vbignU0lHSU5UJywgKCkgPT4gcHJvY2Vzcy5leGl0KCkpO1xuICBjb25zdCBvcHRpb25zID0ge1xuICAgIHBvcnQ6IHNldHRpbmdzLnNlcnZlclBvcnQsXG4gICAgaXB2Nk9ubHk6IGZhbHNlLFxuICAgIGhvc3Q6IHNldHRpbmdzLnNlcnZlckhvc3QgfHwgJydcbiAgfTtcbiAgaWYgKCdURVNUX1RNUERJUicgaW4gcHJvY2Vzcy5lbnYpIHtcbiAgICAvLyBSZXF1aXJlZCB0byBhdm9pZCBcIkVBRk5PU1VQUE9SVDogYWRkcmVzcyBmYW1pbHkgbm90IHN1cHBvcnRlZFwiIG9uXG4gICAgLy8gSVB2Ni1vbmx5IGVudmlyb25tZW50cyAobm90YWJseSwgZXZlbiB3aXRoIHRoZSBob3N0IG92ZXJyaWRlIGJlbG93KS5cbiAgICBvcHRpb25zWydpcHY2T25seSddID0gdHJ1ZTtcbiAgICAvLyBpcHY2T25seSBhbG9uZSBpc24ndCBlbm91Z2ggdG8gYXZvaWQgYXR0ZW1wdGluZyB0byBiaW5kIHRvIDAuMC4wLjAgKHdoaWNoXG4gICAgLy8gZmFpbHMgb24gSVB2Ni1vbmx5IGVudmlyb25tZW50cykuICBOZWVkIHRvIHNwZWNpZnkgYW4gSVAgYWRkcmVzcyBiZWNhdXNlXG4gICAgLy8gRE5TIHJlc29sdXRpb24gZXZlbiBvZiBpcDYtbG9jYWxob3N0IGZhaWxzIG9uIHNvbWUgc3VjaCBlbnZpcm9ubWVudHMuXG4gICAgb3B0aW9uc1snaG9zdCddID0gJzo6MSc7XG4gIH1cbiAgc2VydmVyLmxpc3RlbihvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBTdG9wcyB0aGUgc2VydmVyIGFuZCBhc3NvY2lhdGVkIEp1cHl0ZXIgc2VydmVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc3RvcCgpOiB2b2lkIHtcbiAganVweXRlci5jbG9zZSgpO1xufVxuXG5hc3luYyBmdW5jdGlvbiByZWFkR2NlUHJvamVjdElkKCk6IFByb21pc2U8c3RyaW5nPiB7XG4gIGxldCBtZXRhZGF0YUhvc3QgPSAnbWV0YWRhdGEuZ29vZ2xlLmludGVybmFsJztcbiAgbGV0IHBvcnQ6IHVuZGVmaW5lZHxudW1iZXIgPSB1bmRlZmluZWQ7XG4gIGlmIChwcm9jZXNzLmVudlsnR0NFX01FVEFEQVRBX0hPU1QnXSkge1xuICAgIG1ldGFkYXRhSG9zdCA9IHByb2Nlc3MuZW52WydHQ0VfTUVUQURBVEFfSE9TVCddO1xuICAgIGNvbnN0IHBvcnRQYXJ0cyA9IG1ldGFkYXRhSG9zdC5tYXRjaCgvKC4qKTooXFxkKykvKTtcbiAgICBpZiAocG9ydFBhcnRzKSB7XG4gICAgICBtZXRhZGF0YUhvc3QgPSBwb3J0UGFydHNbMV07XG4gICAgICBpZiAobWV0YWRhdGFIb3N0LnN0YXJ0c1dpdGgoJ1snKSkge1xuICAgICAgICBtZXRhZGF0YUhvc3QgPSBtZXRhZGF0YUhvc3Quc3Vic3RyaW5nKDEsIG1ldGFkYXRhSG9zdC5sZW5ndGggLSAxKTtcbiAgICAgIH1cbiAgICAgIHBvcnQgPSBOdW1iZXIocG9ydFBhcnRzWzJdKTtcbiAgICB9XG4gIH1cbiAgY29uc3QgcHJvamVjdElkID0gYXdhaXQgbmV3IFByb21pc2U8c3RyaW5nPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgaHR0cC5nZXQoXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGhvc3RuYW1lOiBtZXRhZGF0YUhvc3QsXG4gICAgICAgICAgICAgIHBvcnQsXG4gICAgICAgICAgICAgIHBhdGg6ICcvY29tcHV0ZU1ldGFkYXRhL3YxL3Byb2plY3QvcHJvamVjdC1pZCcsXG4gICAgICAgICAgICAgIGhlYWRlcnM6IHsnTWV0YWRhdGEtRmxhdm9yJzogJ0dvb2dsZSd9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgKHJlc3BvbnNlKSA9PiB7XG4gICAgICAgICAgICAgIGxldCBkYXRhID0gJyc7XG4gICAgICAgICAgICAgIHJlc3BvbnNlLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XG4gICAgICAgICAgICAgICAgZGF0YSArPSBjaHVuaztcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIHJlc3BvbnNlLm9uKCdlbmQnLCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgcmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KVxuICAgICAgICAub24oJ2Vycm9yJywgcmVqZWN0KVxuICAgICAgICAuZW5kKCk7XG4gIH0pO1xuICByZXR1cm4gcHJvamVjdElkLnRyaW0oKTtcbn1cbiJdfQ== |