arshjaved's picture
normal Model Upload (teja)
f9f1a35 verified
raw
history blame
36 kB
"use strict";
/*
* 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 = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
return g.next = verb(0), g["throw"] = verb(1), g["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.run = run;
exports.stop = stop;
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);
}
/**
* Stops the server and associated Jupyter server.
*/
function stop() {
jupyter.close();
}
function readGceProjectId() {
return __awaiter(this, void 0, Promise, 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vdGhpcmRfcGFydHkvY29sYWIvc291cmNlcy9zZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7OztHQWNHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBZ0lILGtCQXNGQztBQUtELG9CQUVDO0FBM05ELDJCQUE2QjtBQUM3QixzQ0FBd0M7QUFFeEMsMkJBQTZCO0FBQzdCLHlCQUEyQjtBQUczQixtQ0FBcUM7QUFDckMsbUNBQXFDO0FBQ3JDLDJDQUEyRDtBQUMzRCw2Q0FBK0M7QUFDL0MscURBQTRDO0FBQzVDLHFEQUFnRTtBQUNoRSxtQ0FBcUM7QUFFckMsSUFBSSxNQUFtQixDQUFDO0FBQ3hCOztHQUVHO0FBQ0gsSUFBSSxXQUF3QixDQUFDO0FBRTdCLElBQUksUUFBK0IsQ0FBQztBQUdwQzs7Ozs7R0FLRztBQUNILFNBQWUsYUFBYSxDQUN4QixPQUE2QixFQUFFLFFBQTZCLEVBQzVELFdBQW1COzs7Ozs7b0JBQ3JCLGdEQUFnRDtvQkFFaEQsSUFBSSxRQUFRO3dCQUNSLENBQUMsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQzs0QkFDNUMsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQzt3QkFDNUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsUUFBUSxFQUFFLElBQUksQ0FBQyxDQUFDO3dCQUN0QyxzQkFBTztvQkFDVCxDQUFDO29CQUNELGlEQUFpRDtvQkFDakQsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO3dCQUNuQyxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FB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QUFDLEdBQUcsQ0FDQTtnQ0FDRSxRQUFRLEVBQUUsWUFBWTtnQ0FDdEIsSUFBSSxNQUFBO2dDQUNKLElBQUksRUFBRSx3Q0FBd0M7Z0NBQzlDLE9BQU8sRUFBRSxFQUFDLGlCQUFpQixFQUFFLFFBQVEsRUFBQzs2QkFDdkMsRUFDRCxVQUFDLFFBQVE7Z0NBQ1AsSUFBSSxJQUFJLEdBQUcsRUFBRSxDQUFDO2dDQUNkLFFBQVEsQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLFVBQUMsS0FBSztvQ0FDeEIsSUFBSSxJQUFJLEtBQUssQ0FBQztnQ0FDaEIsQ0FBQyxDQUFDLENBQUM7Z0NBQ0gsUUFBUSxDQUFDLEVBQUUsQ0FBQyxLQUFLLEVBQUU7b0NBQ2pCLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztnQ0FDaEIsQ0FBQyxDQUFDLENBQUM7NEJBQ0wsQ0FBQyxDQUFDO2lDQUNMLEVBQUUsQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDO2lDQUNuQixHQUFHLEVBQUUsQ0FBQzt3QkFDYixDQUFDLENBQUMsRUFBQTs7b0JBbkJJLFNBQVMsR0FBRyxTQW1CaEI7b0JBQ0Ysc0JBQU8sU0FBUyxDQUFDLElBQUksRUFBRSxFQUFDOzs7O0NBQ3pCIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIENvcHlyaWdodCAyMDE1IEdvb2dsZSBJbmMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTsgeW91IG1heSBub3RcbiAqIHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4gWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mXG4gKiB0aGUgTGljZW5zZSBhdFxuICpcbiAqIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUywgV0lUSE9VVFxuICogV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLiBTZWUgdGhlXG4gKiBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZCBsaW1pdGF0aW9ucyB1bmRlclxuICogdGhlIExpY2Vuc2UuXG4gKi9cblxuaW1wb3J0ICogYXMgaHR0cCBmcm9tICdodHRwJztcbmltcG9ydCAqIGFzIGh0dHBQcm94eSBmcm9tICdodHRwLXByb3h5JztcbmltcG9ydCAqIGFzIG5ldCBmcm9tICduZXQnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xuXG5pbXBvcnQge0FwcFNldHRpbmdzfSBmcm9tICcuL2FwcFNldHRpbmdzJztcbmltcG9ydCAqIGFzIGp1cHl0ZXIgZnJvbSAnLi9qdXB5dGVyJztcbmltcG9ydCAqIGFzIGxvZ2dpbmcgZnJvbSAnLi9sb2dnaW5nJztcbmltcG9ydCB7U29ja2V0SU9Ub0xzcCwgV2ViU29ja2V0VG9Mc3B9IGZyb20gJy4vcHl0aG9uX2xzcCc7XG5pbXBvcnQgKiBhcyByZXZlcnNlUHJveHkgZnJvbSAnLi9yZXZlcnNlUHJveHknO1xuaW1wb3J0IHtEYXBTZXJ2ZXJ9IGZyb20gJy4vc29ja2V0aW9fdG9fZGFwJztcbmltcG9ydCB7U29ja2V0SW9Ub1B0eSwgV2ViU29ja2V0VG9QdHl9IGZyb20gJy4vc29ja2V0aW9fdG9fcHR5JztcbmltcG9ydCAqIGFzIHNvY2tldHMgZnJvbSAnLi9zb2NrZXRzJztcblxubGV0IHNlcnZlcjogaHR0cC5TZXJ2ZXI7XG4vKipcbiAqIFRoZSBhcHBsaWNhdGlvbiBzZXR0aW5ncyBpbnN0YW5jZS5cbiAqL1xubGV0IGFwcFNldHRpbmdzOiBBcHBTZXR0aW5ncztcblxubGV0IGZpbGVzaGltOiBodHRwUHJveHkuUHJveHlTZXJ2ZXI7XG5cblxuLyoqXG4gKiBIYW5kbGVzIGFsbCByZXF1ZXN0cy5cbiAqIEBwYXJhbSByZXF1ZXN0IHRoZSBpbmNvbWluZyBIVFRQIHJlcXVlc3QuXG4gKiBAcGFyYW0gcmVzcG9uc2UgdGhlIG91dC1nb2luZyBIVFRQIHJlc3BvbnNlLlxuICogQHBhdGggdGhlIHBhcnNlZCBwYXRoIGluIHRoZSByZXF1ZXN0LlxuICovXG5hc3luYyBmdW5jdGlvbiBoYW5kbGVSZXF1ZXN0KFxuICAgIHJlcXVlc3Q6IGh0dHAuSW5jb21pbmdNZXNzYWdlLCByZXNwb25zZTogaHR0cC5TZXJ2ZXJSZXNwb25zZSxcbiAgICByZXF1ZXN0UGF0aDogc3RyaW5nKSB7XG4gIC8vIC9maWxlcyBhbmQgL3N0YXRpYyBhcmUgb25seSB1c2VkIGluIHJ1bmxvY2FsLlxuXG4gIGlmIChmaWxlc2hpbSAmJlxuICAgICAgKChyZXF1ZXN0UGF0aC5pbmRleE9mKCcvYXBpL2NvbnRlbnRzJykgPT09IDApIHx8XG4gICAgICAgKHJlcXVlc3RQYXRoLmluZGV4T2YoJy9maWxlcycpID09PSAwKSkpIHtcbiAgICBmaWxlc2hpbS53ZWIocmVxdWVzdCwgcmVzcG9uc2UsIG51bGwpO1xuICAgIHJldHVybjtcbiAgfVxuICAvLyBUaGUgZXhwbGljaXQgc2V0IG9mIHBhdGhzIHdlIHByb3h5IHRvIGp1cHl0ZXIuXG4gIGlmICgocmVxdWVzdFBhdGguaW5kZXhPZignL2FwaScpID09PSAwKSB8fFxuICAgICAgKHJlcXVlc3RQYXRoLmluZGV4T2YoJy9uYmV4dGVuc2lvbnMnKSA9PT0gMCkgfHxcbiAgICAgIChyZXF1ZXN0UGF0aC5pbmRleE9mKCcvZmlsZXMnKSA9PT0gMCkgfHxcbiAgICAgIChyZXF1ZXN0UGF0aC5pbmRleE9mKCcvc3RhdGljJykgPT09IDApKSB7XG4gICAganVweXRlci5oYW5kbGVSZXF1ZXN0KHJlcXVlc3QsIHJlc3BvbnNlKTtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKGFwcFNldHRpbmdzLmNvbGFiUmVkaXJlY3QgJiYgcmVxdWVzdFBhdGggPT09ICcvJykge1xuICAgIGNvbnN0IGhvc3QgPSBwcm9jZXNzLmVudlsnV0VCX0hPU1QnXSB8fCAnJztcbiAgICBsZXQgdXJsID0gYXBwU2V0dGluZ3MuY29sYWJSZWRpcmVjdC5yZXBsYWNlKCd7anVweXRlcl9ob3N0fScsIGhvc3QpO1xuICAgIGlmIChhcHBTZXR0aW5ncy5jb2xhYlJlZGlyZWN0LmluY2x1ZGVzKCd7cHJvamVjdF9pZH0nKSkge1xuICAgICAgY29uc3QgcHJvamVjdElkID0gYXdhaXQgcmVhZEdjZVByb2plY3RJZCgpO1xuICAgICAgdXJsID0gdXJsLnJlcGxhY2UoJ3twcm9qZWN0X2lkfScsIHByb2plY3RJZCk7XG4gICAgfVxuICAgIHJlc3BvbnNlLndyaXRlSGVhZCgzMDIsIHtcbiAgICAgICdMb2NhdGlvbic6IHVybCxcbiAgICB9KTtcbiAgICByZXNwb25zZS5lbmQoKTtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBOb3QgRm91bmRcbiAgcmVzcG9uc2Uuc3RhdHVzQ29kZSA9IDQwNDtcbiAgcmVzcG9uc2UuZW5kKCk7XG59XG5cbi8qKlxuICogQmFzZSBsb2dpYyBmb3IgaGFuZGxpbmcgYWxsIHJlcXVlc3RzIHNlbnQgdG8gdGhlIHByb3h5IHdlYiBzZXJ2ZXIuIFNvbWVcbiAqIHJlcXVlc3RzIGFyZSBoYW5kbGVkIHdpdGhpbiB0aGUgc2VydmVyLCB3aGlsZSBzb21lIGFyZSBwcm94aWVkIHRvIHRoZVxuICogSnVweXRlciBub3RlYm9vayBzZXJ2ZXIuXG4gKlxuICogRXJyb3IgaGFuZGxpbmcgaXMgbGVmdCB0byB0aGUgY2FsbGVyLlxuICpcbiAqIEBwYXJhbSByZXF1ZXN0IHRoZSBpbmNvbWluZyBIVFRQIHJlcXVlc3QuXG4gKiBAcGFyYW0gcmVzcG9uc2UgdGhlIG91dC1nb2luZyBIVFRQIHJlc3BvbnNlLlxuICovXG5mdW5jdGlvbiB1bmNoZWNrZWRSZXF1ZXN0SGFuZGxlcihcbiAgICByZXF1ZXN0OiBodHRwLkluY29taW5nTWVzc2FnZSwgcmVzcG9uc2U6IGh0dHAuU2VydmVyUmVzcG9uc2UpIHtcbiAgY29uc3QgcGFyc2VkVXJsID0gdXJsLnBhcnNlKHJlcXVlc3QudXJsIHx8ICcnLCB0cnVlKTtcbiAgY29uc3QgdXJscGF0aCA9IHBhcnNlZFVybC5wYXRobmFtZSB8fCAnJztcblxuICBsb2dnaW5nLmxvZ1JlcXVlc3QocmVxdWVzdCwgcmVzcG9uc2UpO1xuXG4gIGZvciAoY29uc3QgaGFuZGxlciBvZiBzb2NrZXRJb0hhbmRsZXJzKSB7XG4gICAgaWYgKGhhbmRsZXIuaXNQYXRoUHJveGllZCh1cmxwYXRoKSkge1xuICAgICAgLy8gV2lsbCBhdXRvbWF0aWNhbGx5IGJlIGhhbmRsZWQgYnkgc29ja2V0LmlvLlxuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IHByb3h5UG9ydCA9IHJldmVyc2VQcm94eS5nZXRSZXF1ZXN0UG9ydCh1cmxwYXRoKTtcbiAgaWYgKHNvY2tldHMuaXNTb2NrZXRJb1BhdGgodXJscGF0aCkpIHtcbiAgICAvLyBXaWxsIGF1dG9tYXRpY2FsbHkgYmUgaGFuZGxlZCBieSBzb2NrZXQuaW8uXG4gIH0gZWxzZSBpZiAocHJveHlQb3J0ICYmIHByb3h5UG9ydCAhPT0gcmVxdWVzdC5zb2NrZXQubG9jYWxQb3J0KSB7XG4gICAgLy8gRG8gbm90IGFsbG93IHByb3h5aW5nIHRvIHRoaXMgc2FtZSBwb3J0LCBhcyB0aGF0IGNhbiBiZSB1c2VkIHRvIG1hc2sgdGhlXG4gICAgLy8gdGFyZ2V0IHBhdGguXG4gICAgcmV2ZXJzZVByb3h5LmhhbmRsZVJlcXVlc3QocmVxdWVzdCwgcmVzcG9uc2UsIHByb3h5UG9ydCk7XG4gIH0gZWxzZSB7XG4gICAgaGFuZGxlUmVxdWVzdChyZXF1ZXN0LCByZXNwb25zZSwgdXJscGF0aCk7XG4gIH1cbn1cblxuLyoqXG4gKiBIYW5kbGVzIGFsbCByZXF1ZXN0cyBzZW50IHRvIHRoZSBwcm94eSB3ZWIgc2VydmVyLiBTb21lIHJlcXVlc3RzIGFyZSBoYW5kbGVkXG4gKiB3aXRoaW4gdGhlIHNlcnZlciwgd2hpbGUgc29tZSBhcmUgcHJveGllZCB0byB0aGUgSnVweXRlciBub3RlYm9vayBzZXJ2ZXIuXG4gKiBAcGFyYW0gcmVxdWVzdCB0aGUgaW5jb21pbmcgSFRUUCByZXF1ZXN0LlxuICogQHBhcmFtIHJlc3BvbnNlIHRoZSBvdXQtZ29pbmcgSFRUUCByZXNwb25zZS5cbiAqL1xuZnVuY3Rpb24gcmVxdWVzdEhhbmRsZXIoXG4gICAgcmVxdWVzdDogaHR0cC5JbmNvbWluZ01lc3NhZ2UsIHJlc3BvbnNlOiBodHRwLlNlcnZlclJlc3BvbnNlKSB7XG4gIHRyeSB7XG4gICAgdW5jaGVja2VkUmVxdWVzdEhhbmRsZXIocmVxdWVzdCwgcmVzcG9uc2UpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgbG9nZ2luZy5nZXRMb2dnZXIoKS5lcnJvcihcbiAgICAgICAgYFVuY2F1Z2h0IGVycm9yIGhhbmRsaW5nIGEgcmVxdWVzdCB0byBcIiR7cmVxdWVzdC51cmx9XCI6ICR7ZX1gKTtcbiAgfVxufVxuXG5jb25zdCBzb2NrZXRJb0hhbmRsZXJzOiBTb2NrZXRJb1RvUHR5W10gPSBbXTtcblxuLyoqXG4gKiBSdW5zIHRoZSBwcm94eSB3ZWIgc2VydmVyLlxuICogQHBhcmFtIHNldHRpbmdzIHRoZSBjb25maWd1cmF0aW9uIHNldHRpbmdzIHRvIHVzZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJ1bihzZXR0aW5nczogQXBwU2V0dGluZ3MpOiB2b2lkIHtcbiAganVweXRlci5pbml0KHNldHRpbmdzKTtcbiAgcmV2ZXJzZVByb3h5LmluaXQoc2V0dGluZ3MpO1xuICBhcHBTZXR0aW5ncyA9IHNldHRpbmdzO1xuXG4gIGlmIChzZXR0aW5ncy5maWxlSGFuZGxlckFkZHIpIHtcbiAgICBmaWxlc2hpbSA9IGh0dHBQcm94eS5jcmVhdGVQcm94eVNlcnZlcihcbiAgICAgICAge3RhcmdldDogYGh0dHA6Ly8ke2FwcFNldHRpbmdzLmZpbGVIYW5kbGVyQWRkcn1gfSk7XG4gICAgZmlsZXNoaW0ub24oJ2Vycm9yJywgKGVycm9yLCByZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xuICAgICAgbG9nZ2luZy5nZXRMb2dnZXIoKS5lcnJvcihlcnJvciwgYGZpbGVzaGltIGVycm9yIGZvciAke3JlcXVlc3QudXJsfWApO1xuICAgICAgcmVzcG9uc2Uud3JpdGVIZWFkKDUwMCwgJ0ludGVybmFsIFNlcnZlciBFcnJvcicpO1xuICAgICAgcmVzcG9uc2UuZW5kKCk7XG4gICAgfSk7XG4gIH1cblxuICBzZXJ2ZXIgPSBodHRwLmNyZWF0ZVNlcnZlcihyZXF1ZXN0SGFuZGxlcik7XG4gIC8vIERpc2FibGUgSFRUUCBrZWVwLWFsaXZlIGNvbm5lY3Rpb24gdGltZW91dHMgaW4gb3JkZXIgdG8gYXZvaWQgY29ubmVjdGlvblxuICAvLyBmbGFrZXMuIERldGFpbHM6IGIvMTEyMTUxMDY0XG4gIHNlcnZlci5rZWVwQWxpdmVUaW1lb3V0ID0gMDtcblxuICBjb25zdCBzb2NrZXRJb1NlcnZlciA9IHNvY2tldHMuaW5pdChzZXJ2ZXIsIHNldHRpbmdzKTtcblxuICBzb2NrZXRJb0hhbmRsZXJzLnB1c2gobmV3IFNvY2tldElvVG9QdHkoJy90dHknLCBzZXJ2ZXIpKTtcblxuICBsZXQgZGFwU2VydmVyOiBEYXBTZXJ2ZXI7XG4gIGlmIChzZXR0aW5ncy5kZWJ1Z0FkYXB0ZXJNdWx0aXBsZXhlclBhdGgpIHtcbiAgICBkYXBTZXJ2ZXIgPVxuICAgICAgICBuZXcgRGFwU2VydmVyKHNldHRpbmdzLmRlYnVnQWRhcHRlck11bHRpcGxleGVyUGF0aCwgc29ja2V0SW9TZXJ2ZXIpO1xuICB9XG5cbiAgY29uc3QgY29udGVudERpciA9IHBhdGguam9pbihzZXR0aW5ncy5kYXRhbGFiUm9vdCwgc2V0dGluZ3MuY29udGVudERpcik7XG4gIGNvbnN0IGxvZ3NEaXIgPSBwYXRoLmpvaW4oc2V0dGluZ3MuZGF0YWxhYlJvb3QsICcvdmFyL2NvbGFiLycpO1xuICBjb25zdCBwaXBMb2dzRGlyID0gcGF0aC5qb2luKHNldHRpbmdzLmRhdGFsYWJSb290LCAnL3Zhci9sb2cvJyk7XG5cbiAgLy8gSGFuZGxlciBtYW5hZ2VzIGl0cyBvd24gbGlmZXRpbWUuXG4gIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby11bnVzZWQtZXhwcmVzc2lvblxuICBuZXcgU29ja2V0SU9Ub0xzcChcbiAgICAgIHNvY2tldElvU2VydmVyLCBfX2Rpcm5hbWUsIGNvbnRlbnREaXIsIGxvZ3NEaXIsIHBpcExvZ3NEaXIsXG4gICAgICBzZXR0aW5ncy5sYW5ndWFnZVNlcnZlclByb3h5LCBzZXR0aW5ncy5sYW5ndWFnZVNlcnZlclByb3h5QXJncyk7XG5cbiAgc2VydmVyLm9uKFxuICAgICAgJ3VwZ3JhZGUnLFxuICAgICAgKHJlcXVlc3Q6IGh0dHAuSW5jb21pbmdNZXNzYWdlLCBzb2NrZXQ6IG5ldC5Tb2NrZXQsIGhlYWQ6IEJ1ZmZlcikgPT4ge1xuICAgICAgICBjb25zdCBwYXJzZWRVcmwgPSB1cmwucGFyc2UocmVxdWVzdC51cmwgfHwgJycsIHRydWUpO1xuICAgICAgICBjb25zdCB1cmxwYXRoID0gcGFyc2VkVXJsLnBhdGhuYW1lIHx8ICcnO1xuICAgICAgICBjb25zdCBwcm94eVBvcnQgPSByZXZlcnNlUHJveHkuZ2V0UmVxdWVzdFBvcnQodXJscGF0aCk7XG4gICAgICAgIGlmIChwcm94eVBvcnQgJiYgcHJveHlQb3J0ICE9PSByZXF1ZXN0LnNvY2tldC5sb2NhbFBvcnQpIHtcbiAgICAgICAgICByZXZlcnNlUHJveHkuaGFuZGxlVXBncmFkZShyZXF1ZXN0LCBzb2NrZXQsIGhlYWQsIHByb3h5UG9ydCk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmIChyZXF1ZXN0LnVybCA9PT0gJy9jb2xhYi90dHknKSB7XG4gICAgICAgICAgV2ViU29ja2V0VG9QdHkocmVxdWVzdCwgc29ja2V0LCBoZWFkKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHJlcXVlc3QudXJsID09PSAnL2NvbGFiL2RhcCcpIHtcbiAgICAgICAgICBkYXBTZXJ2ZXI/LmhhbmRsZVVwZ3JhZGUocmVxdWVzdCwgc29ja2V0LCBoZWFkKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHJlcXVlc3QudXJsID09PSAnL2NvbGFiL2xzcCcpIHtcbiAgICAgICAgICBXZWJTb2NrZXRUb0xzcChcbiAgICAgICAgICAgICAgcmVxdWVzdCwgc29ja2V0LCBoZWFkLCBfX2Rpcm5hbWUsIGNvbnRlbnREaXIsIGxvZ3NEaXIsIHBpcExvZ3NEaXIsXG4gICAgICAgICAgICAgIHNldHRpbmdzLmxhbmd1YWdlU2VydmVyUHJveHksIHNldHRpbmdzLmxhbmd1YWdlU2VydmVyUHJveHlBcmdzKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAganVweXRlci5oYW5kbGVTb2NrZXQocmVxdWVzdCwgc29ja2V0LCBoZWFkKTtcbiAgICAgIH0pO1xuXG5cbiAgbG9nZ2luZy5nZXRMb2dnZXIoKS5pbmZvKFxuICAgICAgJ1N0YXJ0aW5nIHNlcnZlciBhdCBodHRwOi8vbG9jYWxob3N0OiVkJywgc2V0dGluZ3Muc2VydmVyUG9ydCk7XG4gIHByb2Nlc3Mub24oJ1NJR0lOVCcsICgpID0+IHByb2Nlc3MuZXhpdCgpKTtcbiAgY29uc3Qgb3B0aW9ucyA9IHtcbiAgICBwb3J0OiBzZXR0aW5ncy5zZXJ2ZXJQb3J0LFxuICAgIGlwdjZPbmx5OiBmYWxzZSxcbiAgICBob3N0OiBzZXR0aW5ncy5zZXJ2ZXJIb3N0IHx8ICcnXG4gIH07XG4gIGlmICgnVEVTVF9UTVBESVInIGluIHByb2Nlc3MuZW52KSB7XG4gICAgLy8gUmVxdWlyZWQgdG8gYXZvaWQgXCJFQUZOT1NVUFBPUlQ6IGFkZHJlc3MgZmFtaWx5IG5vdCBzdXBwb3J0ZWRcIiBvblxuICAgIC8vIElQdjYtb25seSBlbnZpcm9ubWVudHMgKG5vdGFibHksIGV2ZW4gd2l0aCB0aGUgaG9zdCBvdmVycmlkZSBiZWxvdykuXG4gICAgb3B0aW9uc1snaXB2Nk9ubHknXSA9IHRydWU7XG4gICAgLy8gaXB2Nk9ubHkgYWxvbmUgaXNuJ3QgZW5vdWdoIHRvIGF2b2lkIGF0dGVtcHRpbmcgdG8gYmluZCB0byAwLjAuMC4wICh3aGljaFxuICAgIC8vIGZhaWxzIG9uIElQdjYtb25seSBlbnZpcm9ubWVudHMpLiAgTmVlZCB0byBzcGVjaWZ5IGFuIElQIGFkZHJlc3MgYmVjYXVzZVxuICAgIC8vIEROUyByZXNvbHV0aW9uIGV2ZW4gb2YgaXA2LWxvY2FsaG9zdCBmYWlscyBvbiBzb21lIHN1Y2ggZW52aXJvbm1lbnRzLlxuICAgIG9wdGlvbnNbJ2hvc3QnXSA9ICc6OjEnO1xuICB9XG4gIHNlcnZlci5saXN0ZW4ob3B0aW9ucyk7XG59XG5cbi8qKlxuICogU3RvcHMgdGhlIHNlcnZlciBhbmQgYXNzb2NpYXRlZCBKdXB5dGVyIHNlcnZlci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN0b3AoKTogdm9pZCB7XG4gIGp1cHl0ZXIuY2xvc2UoKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVhZEdjZVByb2plY3RJZCgpOiBQcm9taXNlPHN0cmluZz4ge1xuICBsZXQgbWV0YWRhdGFIb3N0ID0gJ21ldGFkYXRhLmdvb2dsZS5pbnRlcm5hbCc7XG4gIGxldCBwb3J0OiB1bmRlZmluZWR8bnVtYmVyID0gdW5kZWZpbmVkO1xuICBpZiAocHJvY2Vzcy5lbnZbJ0dDRV9NRVRBREFUQV9IT1NUJ10pIHtcbiAgICBtZXRhZGF0YUhvc3QgPSBwcm9jZXNzLmVudlsnR0NFX01FVEFEQVRBX0hPU1QnXTtcbiAgICBjb25zdCBwb3J0UGFydHMgPSBtZXRhZGF0YUhvc3QubWF0Y2goLyguKik6KFxcZCspLyk7XG4gICAgaWYgKHBvcnRQYXJ0cykge1xuICAgICAgbWV0YWRhdGFIb3N0ID0gcG9ydFBhcnRzWzFdO1xuICAgICAgaWYgKG1ldGFkYXRhSG9zdC5zdGFydHNXaXRoKCdbJykpIHtcbiAgICAgICAgbWV0YWRhdGFIb3N0ID0gbWV0YWRhdGFIb3N0LnN1YnN0cmluZygxLCBtZXRhZGF0YUhvc3QubGVuZ3RoIC0gMSk7XG4gICAgICB9XG4gICAgICBwb3J0ID0gTnVtYmVyKHBvcnRQYXJ0c1syXSk7XG4gICAgfVxuICB9XG4gIGNvbnN0IHByb2plY3RJZCA9IGF3YWl0IG5ldyBQcm9taXNlPHN0cmluZz4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGh0dHAuZ2V0KFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBob3N0bmFtZTogbWV0YWRhdGFIb3N0LFxuICAgICAgICAgICAgICBwb3J0LFxuICAgICAgICAgICAgICBwYXRoOiAnL2NvbXB1dGVNZXRhZGF0YS92MS9wcm9qZWN0L3Byb2plY3QtaWQnLFxuICAgICAgICAgICAgICBoZWFkZXJzOiB7J01ldGFkYXRhLUZsYXZvcic6ICdHb29nbGUnfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIChyZXNwb25zZSkgPT4ge1xuICAgICAgICAgICAgICBsZXQgZGF0YSA9ICcnO1xuICAgICAgICAgICAgICByZXNwb25zZS5vbignZGF0YScsIChjaHVuaykgPT4ge1xuICAgICAgICAgICAgICAgIGRhdGEgKz0gY2h1bms7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICByZXNwb25zZS5vbignZW5kJywgKCkgPT4ge1xuICAgICAgICAgICAgICAgIHJlc29sdmUoZGF0YSk7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgLm9uKCdlcnJvcicsIHJlamVjdClcbiAgICAgICAgLmVuZCgpO1xuICB9KTtcbiAgcmV0dXJuIHByb2plY3RJZC50cmltKCk7XG59XG4iXX0=