astra / web /server.js
Lorenzob's picture
Upload folder using huggingface_hub
19605ab verified
raw
history blame
35.9 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;
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==