serverless-spy
Version:
CDK-based library for writing elegant integration tests on AWS serverless architecture and an additional web console to monitor events in real time.
217 lines • 31.2 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const http = require("http");
const path = require("path");
const util_1 = require("util");
const progam = require("caporal");
const open = require("open");
const ws_1 = require("ws");
// @ts-ignore
const iot_connection_1 = require("../listener/iot-connection");
const topic_1 = require("../listener/topic");
const readFileAsync = (0, util_1.promisify)(fs.readFile);
//resolve issue with module import
let opener = open;
if (open.default) {
opener = open.default;
}
async function run() {
let stackList;
let cdkOutput;
let options;
progam
.description('ServerlessSpy web console')
.option('--ws <ws>', 'Websocket link')
.option('--cdkoutput <cdkoutput>', 'CDK output file that contains IoT Endpoint link in a property ServerlessSpyWsUrl')
.option('--cdkstack <cdkstack>', 'CDK stack in cdk output file. If not specified the first one is picked.')
.option('--open <open>', 'Open browser', progam.BOOL, true)
.option('--port <p>', `A port on localhost where ServerlessSpy web console is accessible.`, progam.INT, '3456')
.option('--wsport <wsp>', `A port on localhost where ServerlessSpy websocket is accessible.`, progam.INT, '3457')
.action((_args, opt, _logger) => {
options = opt;
});
progam.parse(process.argv);
if (!options.ws && !options.cdkoutput) {
throw new Error('--ws or --cdkoutput parameter not specified');
}
if (options.cdkoutput) {
const rawdata = fs.readFileSync(options.cdkoutput);
cdkOutput = JSON.parse(rawdata.toString());
stackList = Object.keys(cdkOutput);
}
const wss = new ws_1.WebSocketServer({ port: options.wsport });
let connection = undefined;
wss.on('close', async () => {
if (connection)
connection.end(true);
});
wss.on('connection', async function connect(ws) {
console.log('Connection');
ws.on('message', function message(data) {
console.log('received: %s', data);
});
let wsUrl;
if (options.ws) {
wsUrl = options.ws;
}
else if (cdkOutput) {
if (cdkOutput[options.cdkstack]) {
wsUrl = cdkOutput[options.cdkstack].ServerlessSpyWsUrl;
}
else if (cdkOutput[Object.keys(cdkOutput)[0]]) {
wsUrl = cdkOutput[Object.keys(cdkOutput)[0]].ServerlessSpyWsUrl;
}
}
if (!wsUrl) {
throw new Error('Missing IoT endpoint url');
}
const wsUrlWithoutScope = wsUrl.split('/')[0];
connection = await (0, iot_connection_1.getConnection)(true, wsUrlWithoutScope);
const topic = (0, topic_1.getTopic)('#');
console.log(`Subscribing to ${topic}`);
connection.on('connect', () => {
console.log('Connection opened');
if (connection) {
connection.subscribe(topic);
}
});
connection.on('message', (topic, data) => {
ws.send(JSON.stringify({
...JSON.parse(JSON.parse(data.toString()).data),
topic,
}));
});
});
http
.createServer((request, response) => {
void (async () => {
try {
//console.log('request ', request.url);
let filePath = `.${request.url}`;
//remove query parameters
filePath = filePath.split('?')[0];
let rootFolder = __dirname;
if (request.url?.startsWith('/webServerlessSpy.js')) {
//get transpiled TS to JS files
rootFolder = getCompiledJsPath();
}
else if (request.url?.startsWith('/bootstrap/')) {
filePath = filePath.substring('/bootstrap/'.length);
const bootstrapFolder = await getNpmModuleInstalledPath('bootstrap');
rootFolder = bootstrapFolder;
}
else if (request.url?.startsWith('/bootstrap-icons/')) {
filePath = filePath.substring('/bootstrap-icons/'.length);
const bootstrapFolder = await getNpmModuleInstalledPath('bootstrap-icons');
rootFolder = bootstrapFolder;
}
else {
if (filePath === './') {
filePath = './index.html';
}
}
filePath = path.join(rootFolder, filePath);
//console.log(`${request.url} --> ${filePath}`);
const extname = String(path.extname(filePath)).toLowerCase();
const mimeTypes = {
'.html': 'text/html',
'.js': 'text/javascript',
'.css': 'text/css',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpg',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.wav': 'audio/wav',
'.mp4': 'video/mp4',
'.woff': 'application/font-woff',
'.ttf': 'application/font-ttf',
'.eot': 'application/vnd.ms-fontobject',
'.otf': 'application/font-otf',
'.wasm': 'application/wasm',
};
const contentType = mimeTypes[extname] || 'application/octet-stream';
if (request.url === '/stackList') {
response.writeHead(200, { 'Content-Type': 'application/json' });
response.end(JSON.stringify(stackList), 'utf-8');
}
else if (request.url === '/stackTopicMappings') {
response.writeHead(200, { 'Content-Type': 'application/json' });
const mappings = {};
if (cdkOutput) {
for (const [stackName, stack] of Object.entries(cdkOutput)) {
if (stack.ServerlessSpyWsUrl) {
const [_, scope] = stack.ServerlessSpyWsUrl.split('/');
if (scope) {
mappings[stackName] = scope;
}
}
}
}
response.end(JSON.stringify(mappings), 'utf-8');
}
else if (request.url?.match('^/wsUrl')) {
response.writeHead(200, { 'Content-Type': 'text/html' });
response.end(`ws:localhost:${options.wsport}`, 'utf-8');
}
else {
try {
const content = await readFileAsync(filePath);
response.writeHead(200, { 'Content-Type': contentType });
response.end(content, 'utf-8');
}
catch (error) {
if (error.code === 'ENOENT') {
response.writeHead(404, { 'Content-Type': 'text/html' });
response.end(`No such file or directory ${request.url}`, 'utf-8');
}
else {
response.writeHead(500);
response.end(`Error: ${error.code} ..\n`);
}
}
}
}
catch (err) {
response.writeHead(500, { 'Content-Type': 'text/html' });
response.end(err.message, 'utf-8');
}
})();
})
.listen(options.port);
console.log(`ServerlessSpy console runing at http://localhost:${options.port}`);
if (options.open) {
await opener(`http://localhost:${options.port}`);
}
}
run().catch(console.error);
function getNpmModuleInstalledPath(npm) {
let folder = path.join(__dirname, '../', 'node_modules', npm);
if (fs.existsSync(folder)) {
return folder;
}
let folderAsPackage = path.join(__dirname, '../../', 'node_modules', npm);
if (fs.existsSync(folderAsPackage)) {
return folderAsPackage;
}
// When boostrap ends up in importing projects root node_modules and not in serverless-spys node_modules
folderAsPackage = path.join(__dirname, '../../../../', 'node_modules', npm);
if (fs.existsSync(folderAsPackage)) {
return folderAsPackage;
}
throw new Error(`Can not find package in folder ${folder} and ${folderAsPackage}`);
}
function getCompiledJsPath() {
let folder = path.join(__dirname, '../', 'lib/cli');
if (fs.existsSync(folder)) {
return folder;
}
let folderAsPackage = path.join(__dirname, '../../', 'lib/cli');
if (fs.existsSync(folderAsPackage)) {
return folderAsPackage;
}
throw new Error(`Can not find compiled files in folder ${folder} and ${folderAsPackage}`);
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vY2xpL2NsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFDQSx5QkFBeUI7QUFDekIsNkJBQTZCO0FBQzdCLDZCQUE2QjtBQUM3QiwrQkFBaUM7QUFFakMsa0NBQWtDO0FBQ2xDLDZCQUE2QjtBQUM3QiwyQkFBcUM7QUFDckMsYUFBYTtBQUNiLCtEQUEyRDtBQUMzRCw2Q0FBNkM7QUFFN0MsTUFBTSxhQUFhLEdBQUcsSUFBQSxnQkFBUyxFQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUU3QyxrQ0FBa0M7QUFDbEMsSUFBSSxNQUFNLEdBQUcsSUFBSSxDQUFDO0FBQ2xCLElBQUssSUFBWSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQzFCLE1BQU0sR0FBSSxJQUFZLENBQUMsT0FBTyxDQUFDO0FBQ2pDLENBQUM7QUFFRCxLQUFLLFVBQVUsR0FBRztJQUNoQixJQUFJLFNBQStCLENBQUM7SUFDcEMsSUFBSSxTQUFpRCxDQUFDO0lBRXRELElBQUksT0FBWSxDQUFDO0lBRWpCLE1BQU07U0FDSCxXQUFXLENBQUMsMkJBQTJCLENBQUM7U0FDeEMsTUFBTSxDQUFDLFdBQVcsRUFBRSxnQkFBZ0IsQ0FBQztTQUNyQyxNQUFNLENBQ0wseUJBQXlCLEVBQ3pCLGtGQUFrRixDQUNuRjtTQUNBLE1BQU0sQ0FDTCx1QkFBdUIsRUFDdkIseUVBQXlFLENBQzFFO1NBQ0EsTUFBTSxDQUFDLGVBQWUsRUFBRSxjQUFjLEVBQUUsTUFBTSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUM7U0FDMUQsTUFBTSxDQUNMLFlBQVksRUFDWixvRUFBb0UsRUFDcEUsTUFBTSxDQUFDLEdBQUcsRUFDVixNQUFNLENBQ1A7U0FDQSxNQUFNLENBQ0wsZ0JBQWdCLEVBQ2hCLGtFQUFrRSxFQUNsRSxNQUFNLENBQUMsR0FBRyxFQUNWLE1BQU0sQ0FDUDtTQUNBLE1BQU0sQ0FBQyxDQUFDLEtBQUssRUFBRSxHQUFH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VUFBVSxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUM7UUFDbkMsT0FBTyxlQUFlLENBQUM7SUFDekIsQ0FBQztJQUVELE1BQU0sSUFBSSxLQUFLLENBQ2Isa0NBQWtDLE1BQU0sUUFBUSxlQUFlLEVBQUUsQ0FDbEUsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFTLGlCQUFpQjtJQUN4QixJQUFJLE1BQU0sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxLQUFLLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDcEQsSUFBSSxFQUFFLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7UUFDMUIsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVELElBQUksZUFBZSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLFFBQVEsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUVoRSxJQUFJLEVBQUUsQ0FBQyxVQUFVLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQztRQUNuQyxPQUFPLGVBQWUsQ0FBQztJQUN6QixDQUFDO0lBRUQsTUFBTSxJQUFJLEtBQUssQ0FDYix5Q0FBeUMsTUFBTSxRQUFRLGVBQWUsRUFBRSxDQUN6RSxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIiMhL3Vzci9iaW4vZW52IG5vZGVcbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIGh0dHAgZnJvbSAnaHR0cCc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgcHJvbWlzaWZ5IH0gZnJvbSAndXRpbCc7XG5pbXBvcnQgeyBkZXZpY2UgfSBmcm9tICdhd3MtaW90LWRldmljZS1zZGsnO1xuaW1wb3J0ICogYXMgcHJvZ2FtIGZyb20gJ2NhcG9yYWwnO1xuaW1wb3J0ICogYXMgb3BlbiBmcm9tICdvcGVuJztcbmltcG9ydCB7IFdlYlNvY2tldFNlcnZlciB9IGZyb20gJ3dzJztcbi8vIEB0cy1pZ25vcmVcbmltcG9ydCB7IGdldENvbm5lY3Rpb24gfSBmcm9tICcuLi9saXN0ZW5lci9pb3QtY29ubmVjdGlvbic7XG5pbXBvcnQgeyBnZXRUb3BpYyB9IGZyb20gJy4uL2xpc3RlbmVyL3RvcGljJztcblxuY29uc3QgcmVhZEZpbGVBc3luYyA9IHByb21pc2lmeShmcy5yZWFkRmlsZSk7XG5cbi8vcmVzb2x2ZSBpc3N1ZSB3aXRoIG1vZHVsZSBpbXBvcnRcbmxldCBvcGVuZXIgPSBvcGVuO1xuaWYgKChvcGVuIGFzIGFueSkuZGVmYXVsdCkge1xuICBvcGVuZXIgPSAob3BlbiBhcyBhbnkpLmRlZmF1bHQ7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJ1bigpIHtcbiAgbGV0IHN0YWNrTGlzdDogc3RyaW5nW10gfCB1bmRlZmluZWQ7XG4gIGxldCBjZGtPdXRwdXQ6IFJlY29yZDxzdHJpbmcsIFJlY29yZDxzdHJpbmcsIHN0cmluZz4+O1xuXG4gIGxldCBvcHRpb25zOiBhbnk7XG5cbiAgcHJvZ2FtXG4gICAgLmRlc2NyaXB0aW9uKCdTZXJ2ZXJsZXNzU3B5IHdlYiBjb25zb2xlJylcbiAgICAub3B0aW9uKCctLXdzIDx3cz4nLCAnV2Vic29ja2V0IGxpbmsnKVxuICAgIC5vcHRpb24oXG4gICAgICAnLS1jZGtvdXRwdXQgPGNka291dHB1dD4nLFxuICAgICAgJ0NESyBvdXRwdXQgZmlsZSB0aGF0IGNvbnRhaW5zIElvVCBFbmRwb2ludCBsaW5rIGluIGEgcHJvcGVydHkgU2VydmVybGVzc1NweVdzVXJsJ1xuICAgIClcbiAgICAub3B0aW9uKFxuICAgICAgJy0tY2Rrc3RhY2sgPGNka3N0YWNrPicsXG4gICAgICAnQ0RLIHN0YWNrIGluIGNkayBvdXRwdXQgZmlsZS4gSWYgbm90IHNwZWNpZmllZCB0aGUgZmlyc3Qgb25lIGlzIHBpY2tlZC4nXG4gICAgKVxuICAgIC5vcHRpb24oJy0tb3BlbiA8b3Blbj4nLCAnT3BlbiBicm93c2VyJywgcHJvZ2FtLkJPT0wsIHRydWUpXG4gICAgLm9wdGlvbihcbiAgICAgICctLXBvcnQgPHA+JyxcbiAgICAgIGBBIHBvcnQgb24gbG9jYWxob3N0IHdoZXJlIFNlcnZlcmxlc3NTcHkgd2ViIGNvbnNvbGUgaXMgYWNjZXNzaWJsZS5gLFxuICAgICAgcHJvZ2FtLklOVCxcbiAgICAgICczNDU2J1xuICAgIClcbiAgICAub3B0aW9uKFxuICAgICAgJy0td3Nwb3J0IDx3c3A+JyxcbiAgICAgIGBBIHBvcnQgb24gbG9jYWxob3N0IHdoZXJlIFNlcnZlcmxlc3NTcHkgd2Vic29ja2V0IGlzIGFjY2Vzc2libGUuYCxcbiAgICAgIHByb2dhbS5JTlQsXG4gICAgICAnMzQ1NydcbiAgICApXG4gICAgLmFjdGlvbigoX2FyZ3MsIG9wdCwgX2xvZ2dlcikgPT4ge1xuICAgICAgb3B0aW9ucyA9IG9wdDtcbiAgICB9KTtcblxuICBwcm9nYW0ucGFyc2UocHJvY2Vzcy5hcmd2KTtcblxuICBpZiAoIW9wdGlvbnMud3MgJiYgIW9wdGlvbnMuY2Rrb3V0cHV0KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCctLXdzIG9yIC0tY2Rrb3V0cHV0IHBhcmFtZXRlciBub3Qgc3BlY2lmaWVkJyk7XG4gIH1cblxuICBpZiAob3B0aW9ucy5jZGtvdXRwdXQpIHtcbiAgICBjb25zdCByYXdkYXRhID0gZnMucmVhZEZpbGVTeW5jKG9wdGlvbnMuY2Rrb3V0cHV0KTtcbiAgICBjZGtPdXRwdXQgPSBKU09OLnBhcnNlKHJhd2RhdGEudG9TdHJpbmcoKSk7XG4gICAgc3RhY2tMaXN0ID0gT2JqZWN0LmtleXMoY2RrT3V0cHV0KTtcbiAgfVxuXG4gIGNvbnN0IHdzcyA9IG5ldyBXZWJTb2NrZXRTZXJ2ZXIoeyBwb3J0OiBvcHRpb25zLndzcG9ydCB9KTtcbiAgbGV0IGNvbm5lY3Rpb246IGRldmljZSB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcblxuICB3c3Mub24oJ2Nsb3NlJywgYXN5bmMgKCkgPT4ge1xuICAgIGlmIChjb25uZWN0aW9uKSBjb25uZWN0aW9uLmVuZCh0cnVlKTtcbiAgfSk7XG5cbiAgd3NzLm9uKCdjb25uZWN0aW9uJywgYXN5bmMgZnVuY3Rpb24gY29ubmVjdCh3cykge1xuICAgIGNvbnNvbGUubG9nKCdDb25uZWN0aW9uJyk7XG4gICAgd3Mub24oJ21lc3NhZ2UnLCBmdW5jdGlvbiBtZXNzYWdlKGRhdGEpIHtcbiAgICAgIGNvbnNvbGUubG9nKCdyZWNlaXZlZDogJXMnLCBkYXRhKTtcbiAgICB9KTtcblxuICAgIGxldCB3c1VybDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIGlmIChvcHRpb25zLndzKSB7XG4gICAgICB3c1VybCA9IG9wdGlvbnMud3M7XG4gICAgfSBlbHNlIGlmIChjZGtPdXRwdXQpIHtcbiAgICAgIGlmIChjZGtPdXRwdXRbb3B0aW9ucy5jZGtzdGFja10pIHtcbiAgICAgICAgd3NVcmwgPSBjZGtPdXRwdXRbb3B0aW9ucy5jZGtzdGFja10uU2VydmVybGVzc1NweVdzVXJsO1xuICAgICAgfSBlbHNlIGlmIChjZGtPdXRwdXRbT2JqZWN0LmtleXMoY2RrT3V0cHV0KVswXV0pIHtcbiAgICAgICAgd3NVcmwgPSBjZGtPdXRwdXRbT2JqZWN0LmtleXMoY2RrT3V0cHV0KVswXV0uU2VydmVybGVzc1NweVdzVXJsO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICghd3NVcmwpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBJb1QgZW5kcG9pbnQgdXJsJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgd3NVcmxXaXRob3V0U2NvcGUgPSB3c1VybC5zcGxpdCgnLycpWzBdO1xuXG4gICAgY29ubmVjdGlvbiA9IGF3YWl0IGdldENvbm5lY3Rpb24odHJ1ZSwgd3NVcmxXaXRob3V0U2NvcGUpO1xuXG4gICAgY29uc3QgdG9waWMgPSBnZXRUb3BpYygnIycpO1xuICAgIGNvbnNvbGUubG9nKGBTdWJzY3JpYmluZyB0byAke3RvcGljfWApO1xuXG4gICAgY29ubmVjdGlvbi5vbignY29ubmVjdCcsICgpID0+IHtcbiAgICAgIGNvbnNvbGUubG9nKCdDb25uZWN0aW9uIG9wZW5lZCcpO1xuICAgICAgaWYgKGNvbm5lY3Rpb24pIHtcbiAgICAgICAgY29ubmVjdGlvbi5zdWJzY3JpYmUodG9waWMpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgY29ubmVjdGlvbi5vbignbWVzc2FnZScsICh0b3BpYzogc3RyaW5nLCBkYXRhOiBCdWZmZXIpID0+IHtcbiAgICAgIHdzLnNlbmQoXG4gICAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAuLi5KU09OLnBhcnNlKEpTT04ucGFyc2UoZGF0YS50b1N0cmluZygpKS5kYXRhKSxcbiAgICAgICAgICB0b3BpYyxcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGh0dHBcbiAgICAuY3JlYXRlU2VydmVyKChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xuICAgICAgdm9pZCAoYXN5bmMgKCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIC8vY29uc29sZS5sb2coJ3JlcXVlc3QgJywgcmVxdWVzdC51cmwpO1xuICAgICAgICAgIGxldCBmaWxlUGF0aDogc3RyaW5nID0gYC4ke3JlcXVlc3QudXJsfWA7XG4gICAgICAgICAgLy9yZW1vdmUgcXVlcnkgcGFyYW1ldGVyc1xuICAgICAgICAgIGZpbGVQYXRoID0gZmlsZVBhdGguc3BsaXQoJz8nKVswXTtcbiAgICAgICAgICBsZXQgcm9vdEZvbGRlciA9IF9fZGlybmFtZTtcblxuICAgICAgICAgIGlmIChyZXF1ZXN0LnVybD8uc3RhcnRzV2l0aCgnL3dlYlNlcnZlcmxlc3NTcHkuanMnKSkge1xuICAgICAgICAgICAgLy9nZXQgdHJhbnNwaWxlZCBUUyB0byBKUyBmaWxlc1xuICAgICAgICAgICAgcm9vdEZvbGRlciA9IGdldENvbXBpbGVkSnNQYXRoKCk7XG4gICAgICAgICAgfSBlbHNlIGlmIChyZXF1ZXN0LnVybD8uc3RhcnRzV2l0aCgnL2Jvb3RzdHJhcC8nKSkge1xuICAgICAgICAgICAgZmlsZVBhdGggPSBmaWxlUGF0aC5zdWJzdHJpbmcoJy9ib290c3RyYXAvJy5sZW5ndGgpO1xuICAgICAgICAgICAgY29uc3QgYm9vdHN0cmFwRm9sZGVyID0gYXdhaXQgZ2V0TnBtTW9kdWxlSW5zdGFsbGVkUGF0aChcbiAgICAgICAgICAgICAgJ2Jvb3RzdHJhcCdcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJvb3RGb2xkZXIgPSBib290c3RyYXBGb2xkZXI7XG4gICAgICAgICAgfSBlbHNlIGlmIChyZXF1ZXN0LnVybD8uc3RhcnRzV2l0aCgnL2Jvb3RzdHJhcC1pY29ucy8nKSkge1xuICAgICAgICAgICAgZmlsZVBhdGggPSBmaWxlUGF0aC5zdWJzdHJpbmcoJy9ib290c3RyYXAtaWNvbnMvJy5sZW5ndGgpO1xuICAgICAgICAgICAgY29uc3QgYm9vdHN0cmFwRm9sZGVyID0gYXdhaXQgZ2V0TnBtTW9kdWxlSW5zdGFsbGVkUGF0aChcbiAgICAgICAgICAgICAgJ2Jvb3RzdHJhcC1pY29ucydcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJvb3RGb2xkZXIgPSBib290c3RyYXBGb2xkZXI7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmIChmaWxlUGF0aCA9PT0gJy4vJykge1xuICAgICAgICAgICAgICBmaWxlUGF0aCA9ICcuL2luZGV4Lmh0bWwnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGZpbGVQYXRoID0gcGF0aC5qb2luKHJvb3RGb2xkZXIsIGZpbGVQYXRoKTtcbiAgICAgICAgICAvL2NvbnNvbGUubG9nKGAke3JlcXVlc3QudXJsfSAtLT4gJHtmaWxlUGF0aH1gKTtcblxuICAgICAgICAgIGNvbnN0IGV4dG5hbWUgPSBTdHJpbmcocGF0aC5leHRuYW1lKGZpbGVQYXRoKSkudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgICBjb25zdCBtaW1lVHlwZXM6IGFueSA9IHtcbiAgICAgICAgICAgICcuaHRtbCc6ICd0ZXh0L2h0bWwnLFxuICAgICAgICAgICAgJy5qcyc6ICd0ZXh0L2phdmFzY3JpcHQnLFxuICAgICAgICAgICAgJy5jc3MnOiAndGV4dC9jc3MnLFxuICAgICAgICAgICAgJy5qc29uJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICAgJy5wbmcnOiAnaW1hZ2UvcG5nJyxcbiAgICAgICAgICAgICcuanBnJzogJ2ltYWdlL2pwZycsXG4gICAgICAgICAgICAnLmdpZic6ICdpbWFnZS9naWYnLFxuICAgICAgICAgICAgJy5zdmcnOiAnaW1hZ2Uvc3ZnK3htbCcsXG4gICAgICAgICAgICAnLndhdic6ICdhdWRpby93YXYnLFxuICAgICAgICAgICAgJy5tcDQnOiAndmlkZW8vbXA0JyxcbiAgICAgICAgICAgICcud29mZic6ICdhcHBsaWNhdGlvbi9mb250LXdvZmYnLFxuICAgICAgICAgICAgJy50dGYnOiAnYXBwbGljYXRpb24vZm9udC10dGYnLFxuICAgICAgICAgICAgJy5lb3QnOiAnYXBwbGljYXRpb24vdm5kLm1zLWZvbnRvYmplY3QnLFxuICAgICAgICAgICAgJy5vdGYnOiAnYXBwbGljYXRpb24vZm9udC1vdGYnLFxuICAgICAgICAgICAgJy53YXNtJzogJ2FwcGxpY2F0aW9uL3dhc20nLFxuICAgICAgICAgIH07XG5cbiAgICAgICAgICBjb25zdCBjb250ZW50VHlwZSA9IG1pbWVUeXBlc1tleHRuYW1lXSB8fCAnYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtJztcblxuICAgICAgICAgIGlmIChyZXF1ZXN0LnVybCA9PT0gJy9zdGFja0xpc3QnKSB7XG4gICAgICAgICAgICByZXNwb25zZS53cml0ZUhlYWQoMjAwLCB7ICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicgfSk7XG4gICAgICAgICAgICByZXNwb25zZS5lbmQoSlNPTi5zdHJpbmdpZnkoc3RhY2tMaXN0KSwgJ3V0Zi04Jyk7XG4gICAgICAgICAgfSBlbHNlIGlmIChyZXF1ZXN0LnVybCA9PT0gJy9zdGFja1RvcGljTWFwcGluZ3MnKSB7XG4gICAgICAgICAgICByZXNwb25zZS53cml0ZUhlYWQoMjAwLCB7ICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicgfSk7XG4gICAgICAgICAgICBjb25zdCBtYXBwaW5nczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICAgICAgICAgICAgaWYgKGNka091dHB1dCkge1xuICAgICAgICAgICAgICBmb3IgKGNvbnN0IFtzdGFja05hbWUsIHN0YWNrXSBvZiBPYmplY3QuZW50cmllcyhjZGtPdXRwdXQpKSB7XG4gICAgICAgICAgICAgICAgaWYgKHN0YWNrLlNlcnZlcmxlc3NTcHlXc1VybCkge1xuICAgICAgICAgICAgICAgICAgY29uc3QgW18sIHNjb3BlXSA9IHN0YWNrLlNlcnZlcmxlc3NTcHlXc1VybC5zcGxpdCgnLycpO1xuICAgICAgICAgICAgICAgICAgaWYgKHNjb3BlKSB7XG4gICAgICAgICAgICAgICAgICAgIG1hcHBpbmdzW3N0YWNrTmFtZV0gPSBzY29wZTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJlc3BvbnNlLmVuZChKU09OLnN0cmluZ2lmeShtYXBwaW5ncyksICd1dGYtOCcpO1xuICAgICAgICAgIH0gZWxzZSBpZiAocmVxdWVzdC51cmw/Lm1hdGNoKCdeL3dzVXJsJykpIHtcbiAgICAgICAgICAgIHJlc3BvbnNlLndyaXRlSGVhZCgyMDAsIHsgJ0NvbnRlbnQtVHlwZSc6ICd0ZXh0L2h0bWwnIH0pO1xuICAgICAgICAgICAgcmVzcG9uc2UuZW5kKGB3czpsb2NhbGhvc3Q6JHtvcHRpb25zLndzcG9ydH1gLCAndXRmLTgnKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgY29uc3QgY29udGVudCA9IGF3YWl0IHJlYWRGaWxlQXN5bmMoZmlsZVBhdGgpO1xuXG4gICAgICAgICAgICAgIHJlc3BvbnNlLndyaXRlSGVhZCgyMDAsIHsgJ0NvbnRlbnQtVHlwZSc6IGNvbnRlbnRUeXBlIH0pO1xuICAgICAgICAgICAgICByZXNwb25zZS5lbmQoY29udGVudCwgJ3V0Zi04Jyk7XG4gICAgICAgICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICAgICAgICAgIGlmIChlcnJvci5jb2RlID09PSAnRU5PRU5UJykge1xuICAgICAgICAgICAgICAgIHJlc3BvbnNlLndyaXRlSGVhZCg0MDQsIHsgJ0NvbnRlbnQtVHlwZSc6ICd0ZXh0L2h0bWwnIH0pO1xuICAgICAgICAgICAgICAgIHJlc3BvbnNlLmVuZChcbiAgICAgICAgICAgICAgICAgIGBObyBzdWNoIGZpbGUgb3IgZGlyZWN0b3J5ICR7cmVxdWVzdC51cmx9YCxcbiAgICAgICAgICAgICAgICAgICd1dGYtOCdcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJlc3BvbnNlLndyaXRlSGVhZCg1MDApO1xuICAgICAgICAgICAgICAgIHJlc3BvbnNlLmVuZChgRXJyb3I6ICR7ZXJyb3IuY29kZX0gLi5cXG5gKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICByZXNwb25zZS53cml0ZUhlYWQoNTAwLCB7ICdDb250ZW50LVR5cGUnOiAndGV4dC9odG1sJyB9KTtcbiAgICAgICAgICByZXNwb25zZS5lbmQoZXJyLm1lc3NhZ2UsICd1dGYtOCcpO1xuICAgICAgICB9XG4gICAgICB9KSgpO1xuICAgIH0pXG4gICAgLmxpc3RlbihvcHRpb25zLnBvcnQpO1xuXG4gIGNvbnNvbGUubG9nKFxuICAgIGBTZXJ2ZXJsZXNzU3B5IGNvbnNvbGUgcnVuaW5nIGF0IGh0dHA6Ly9sb2NhbGhvc3Q6JHtvcHRpb25zLnBvcnR9YFxuICApO1xuICBpZiAob3B0aW9ucy5vcGVuKSB7XG4gICAgYXdhaXQgb3BlbmVyKGBodHRwOi8vbG9jYWxob3N0OiR7b3B0aW9ucy5wb3J0fWApO1xuICB9XG59XG5cbnJ1bigpLmNhdGNoKGNvbnNvbGUuZXJyb3IpO1xuXG5mdW5jdGlvbiBnZXROcG1Nb2R1bGVJbnN0YWxsZWRQYXRoKG5wbTogc3RyaW5nKSB7XG4gIGxldCBmb2xkZXIgPSBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vJywgJ25vZGVfbW9kdWxlcycsIG5wbSk7XG4gIGlmIChmcy5leGlzdHNTeW5jKGZvbGRlcikpIHtcbiAgICByZXR1cm4gZm9sZGVyO1xuICB9XG5cbiAgbGV0IGZvbGRlckFzUGFja2FnZSA9IHBhdGguam9pbihfX2Rpcm5hbWUsICcuLi8uLi8nLCAnbm9kZV9tb2R1bGVzJywgbnBtKTtcblxuICBpZiAoZnMuZXhpc3RzU3luYyhmb2xkZXJBc1BhY2thZ2UpKSB7XG4gICAgcmV0dXJuIGZvbGRlckFzUGFja2FnZTtcbiAgfVxuXG4gIC8vIFdoZW4gYm9vc3RyYXAgZW5kcyB1cCBpbiBpbXBvcnRpbmcgcHJvamVjdHMgcm9vdCBub2RlX21vZHVsZXMgYW5kIG5vdCBpbiBzZXJ2ZXJsZXNzLXNweXMgbm9kZV9tb2R1bGVzXG4gIGZvbGRlckFzUGFja2FnZSA9IHBhdGguam9pbihfX2Rpcm5hbWUsICcuLi8uLi8uLi8uLi8nLCAnbm9kZV9tb2R1bGVzJywgbnBtKTtcblxuICBpZiAoZnMuZXhpc3RzU3luYyhmb2xkZXJBc1BhY2thZ2UpKSB7XG4gICAgcmV0dXJuIGZvbGRlckFzUGFja2FnZTtcbiAgfVxuXG4gIHRocm93IG5ldyBFcnJvcihcbiAgICBgQ2FuIG5vdCBmaW5kIHBhY2thZ2UgaW4gZm9sZGVyICR7Zm9sZGVyfSBhbmQgJHtmb2xkZXJBc1BhY2thZ2V9YFxuICApO1xufVxuXG5mdW5jdGlvbiBnZXRDb21waWxlZEpzUGF0aCgpIHtcbiAgbGV0IGZvbGRlciA9IHBhdGguam9pbihfX2Rpcm5hbWUsICcuLi8nLCAnbGliL2NsaScpO1xuICBpZiAoZnMuZXhpc3RzU3luYyhmb2xkZXIpKSB7XG4gICAgcmV0dXJuIGZvbGRlcjtcbiAgfVxuXG4gIGxldCBmb2xkZXJBc1BhY2thZ2UgPSBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vLi4vJywgJ2xpYi9jbGknKTtcblxuICBpZiAoZnMuZXhpc3RzU3luYyhmb2xkZXJBc1BhY2thZ2UpKSB7XG4gICAgcmV0dXJuIGZvbGRlckFzUGFja2FnZTtcbiAgfVxuXG4gIHRocm93IG5ldyBFcnJvcihcbiAgICBgQ2FuIG5vdCBmaW5kIGNvbXBpbGVkIGZpbGVzIGluIGZvbGRlciAke2ZvbGRlcn0gYW5kICR7Zm9sZGVyQXNQYWNrYWdlfWBcbiAgKTtcbn1cbiJdfQ==
;