UNPKG

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.

215 lines 31.4 kB
#!/usr/bin/env node import * as fs from 'fs'; import * as http from 'http'; import * as path from 'path'; import { promisify } from 'util'; import * as progam from 'caporal'; import * as open from 'open'; import { WebSocketServer } from 'ws'; // @ts-ignore import { getConnection } from '../listener/iot-connection'; import { getTopic } from '../listener/topic'; const readFileAsync = 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 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 getConnection(true, wsUrlWithoutScope); const topic = 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vY2xpL2NsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQ0EsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDekIsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUVqQyxPQUFPLEtBQUssTUFBTSxNQUFNLFNBQVMsQ0FBQztBQUNsQyxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUM3QixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQ3JDLGFBQWE7QUFDYixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDM0QsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRTdDLE1BQU0sYUFBYSxHQUFHLFNBQVMsQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUM7QUFFN0Msa0NBQWtDO0FBQ2xDLElBQUksTUFBTSxHQUFHLElBQUksQ0FBQztBQUNsQixJQUFLLElBQVksQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUMxQixNQUFNLEdBQUksSUFBWSxDQUFDLE9BQU8sQ0FBQztBQUNqQyxDQUFDO0FBRUQsS0FBSyxVQUFVLEdBQUc7SUFDaEIsSUFBSSxTQUErQixDQUFDO0lBQ3BDLElBQUksU0FBaUQsQ0FBQztJQUV0RCxJQUFJLE9BQVksQ0FBQztJQUVqQixNQUFNO1NBQ0gsV0FBVyxDQUFDLDJCQUEyQixDQUFDO1NBQ3hDLE1BQU0sQ0FBQyxXQUFXLEVBQUUsZ0JBQWdCLENBQUM7U0FDckMsTUFBTSxDQUNMLHlCQUF5QixFQUN6QixrRkFBa0YsQ0FDbkY7U0FDQSxNQUFNLENBQ0wsdUJBQXVCLEVBQ3ZCLHlFQUF5RSxDQUMxRTtTQUNBLE1BQU0sQ0FBQyxl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QUcsQ0FBQyxDQUFDO0lBRTFFLElBQUksRUFBRSxDQUFDLFVBQVUsQ0FBQyxlQUFlLENBQUMsRUFBRSxDQUFDO1FBQ25DLE9BQU8sZUFBZSxDQUFDO0lBQ3pCLENBQUM7SUFFRCx3R0FBd0c7SUFDeEcsZUFBZSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLGNBQWMsRUFBRSxjQUFjLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFFNUUsSUFBSSxFQUFFLENBQUMsVUFBVSxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUM7UUFDbkMsT0FBTyxlQUFlLENBQUM7SUFDekIsQ0FBQztJQUVELE1BQU0sSUFBSSxLQUFLLENBQ2Isa0NBQWtDLE1BQU0sUUFBUSxlQUFlLEVBQUUsQ0FDbEUsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFTLGlCQUFpQjtJQUN4QixJQUFJLE1BQU0sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxLQUFLLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDcEQsSUFBSSxFQUFFLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7UUFDMUIsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVELElBQUksZUFBZSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLFFBQVEsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUVoRSxJQUFJLEVBQUUsQ0FBQyxVQUFVLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQztRQUNuQyxPQUFPLGVBQWUsQ0FBQztJQUN6QixDQUFDO0lBRUQsTUFBTSxJQUFJLEtBQUssQ0FDYix5Q0FBeUMsTUFBTSxRQUFRLGVBQWUsRUFBRSxDQUN6RSxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIiMhL3Vzci9iaW4vZW52IG5vZGVcbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIGh0dHAgZnJvbSAnaHR0cCc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgcHJvbWlzaWZ5IH0gZnJvbSAndXRpbCc7XG5pbXBvcnQgeyBkZXZpY2UgfSBmcm9tICdhd3MtaW90LWRldmljZS1zZGsnO1xuaW1wb3J0ICogYXMgcHJvZ2FtIGZyb20gJ2NhcG9yYWwnO1xuaW1wb3J0ICogYXMgb3BlbiBmcm9tICdvcGVuJztcbmltcG9ydCB7IFdlYlNvY2tldFNlcnZlciB9IGZyb20gJ3dzJztcbi8vIEB0cy1pZ25vcmVcbmltcG9ydCB7IGdldENvbm5lY3Rpb24gfSBmcm9tICcuLi9saXN0ZW5lci9pb3QtY29ubmVjdGlvbic7XG5pbXBvcnQgeyBnZXRUb3BpYyB9IGZyb20gJy4uL2xpc3RlbmVyL3RvcGljJztcblxuY29uc3QgcmVhZEZpbGVBc3luYyA9IHByb21pc2lmeShmcy5yZWFkRmlsZSk7XG5cbi8vcmVzb2x2ZSBpc3N1ZSB3aXRoIG1vZHVsZSBpbXBvcnRcbmxldCBvcGVuZXIgPSBvcGVuO1xuaWYgKChvcGVuIGFzIGFueSkuZGVmYXVsdCkge1xuICBvcGVuZXIgPSAob3BlbiBhcyBhbnkpLmRlZmF1bHQ7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJ1bigpIHtcbiAgbGV0IHN0YWNrTGlzdDogc3RyaW5nW10gfCB1bmRlZmluZWQ7XG4gIGxldCBjZGtPdXRwdXQ6IFJlY29yZDxzdHJpbmcsIFJlY29yZDxzdHJpbmcsIHN0cmluZz4+O1xuXG4gIGxldCBvcHRpb25zOiBhbnk7XG5cbiAgcHJvZ2FtXG4gICAgLmRlc2NyaXB0aW9uKCdTZXJ2ZXJsZXNzU3B5IHdlYiBjb25zb2xlJylcbiAgICAub3B0aW9uKCctLXdzIDx3cz4nLCAnV2Vic29ja2V0IGxpbmsnKVxuICAgIC5vcHRpb24oXG4gICAgICAnLS1jZGtvdXRwdXQgPGNka291dHB1dD4nLFxuICAgICAgJ0NESyBvdXRwdXQgZmlsZSB0aGF0IGNvbnRhaW5zIElvVCBFbmRwb2ludCBsaW5rIGluIGEgcHJvcGVydHkgU2VydmVybGVzc1NweVdzVXJsJ1xuICAgIClcbiAgICAub3B0aW9uKFxuICAgICAgJy0tY2Rrc3RhY2sgPGNka3N0YWNrPicsXG4gICAgICAnQ0RLIHN0YWNrIGluIGNkayBvdXRwdXQgZmlsZS4gSWYgbm90IHNwZWNpZmllZCB0aGUgZmlyc3Qgb25lIGlzIHBpY2tlZC4nXG4gICAgKVxuICAgIC5vcHRpb24oJy0tb3BlbiA8b3Blbj4nLCAnT3BlbiBicm93c2VyJywgcHJvZ2FtLkJPT0wsIHRydWUpXG4gICAgLm9wdGlvbihcbiAgICAgICctLXBvcnQgPHA+JyxcbiAgICAgIGBBIHBvcnQgb24gbG9jYWxob3N0IHdoZXJlIFNlcnZlcmxlc3NTcHkgd2ViIGNvbnNvbGUgaXMgYWNjZXNzaWJsZS5gLFxuICAgICAgcHJvZ2FtLklOVCxcbiAgICAgICczNDU2J1xuICAgIClcbiAgICAub3B0aW9uKFxuICAgICAgJy0td3Nwb3J0IDx3c3A+JyxcbiAgICAgIGBBIHBvcnQgb24gbG9jYWxob3N0IHdoZXJlIFNlcnZlcmxlc3NTcHkgd2Vic29ja2V0IGlzIGFjY2Vzc2libGUuYCxcbiAgICAgIHByb2dhbS5JTlQsXG4gICAgICAnMzQ1NydcbiAgICApXG4gICAgLmFjdGlvbigoX2FyZ3MsIG9wdCwgX2xvZ2dlcikgPT4ge1xuICAgICAgb3B0aW9ucyA9IG9wdDtcbiAgICB9KTtcblxuICBwcm9nYW0ucGFyc2UocHJvY2Vzcy5hcmd2KTtcblxuICBpZiAoIW9wdGlvbnMud3MgJiYgIW9wdGlvbnMuY2Rrb3V0cHV0KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCctLXdzIG9yIC0tY2Rrb3V0cHV0IHBhcmFtZXRlciBub3Qgc3BlY2lmaWVkJyk7XG4gIH1cblxuICBpZiAob3B0aW9ucy5jZGtvdXRwdXQpIHtcbiAgICBjb25zdCByYXdkYXRhID0gZnMucmVhZEZpbGVTeW5jKG9wdGlvbnMuY2Rrb3V0cHV0KTtcbiAgICBjZGtPdXRwdXQgPSBKU09OLnBhcnNlKHJhd2RhdGEudG9TdHJpbmcoKSk7XG4gICAgc3RhY2tMaXN0ID0gT2JqZWN0LmtleXMoY2RrT3V0cHV0KTtcbiAgfVxuXG4gIGNvbnN0IHdzcyA9IG5ldyBXZWJTb2NrZXRTZXJ2ZXIoeyBwb3J0OiBvcHRpb25zLndzcG9ydCB9KTtcbiAgbGV0IGNvbm5lY3Rpb246IGRldmljZSB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcblxuICB3c3Mub24oJ2Nsb3NlJywgYXN5bmMgKCkgPT4ge1xuICAgIGlmIChjb25uZWN0aW9uKSBjb25uZWN0aW9uLmVuZCh0cnVlKTtcbiAgfSk7XG5cbiAgd3NzLm9uKCdjb25uZWN0aW9uJywgYXN5bmMgZnVuY3Rpb24gY29ubmVjdCh3cykge1xuICAgIGNvbnNvbGUubG9nKCdDb25uZWN0aW9uJyk7XG4gICAgd3Mub24oJ21lc3NhZ2UnLCBmdW5jdGlvbiBtZXNzYWdlKGRhdGEpIHtcbiAgICAgIGNvbnNvbGUubG9nKCdyZWNlaXZlZDogJXMnLCBkYXRhKTtcbiAgICB9KTtcblxuICAgIGxldCB3c1VybDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIGlmIChvcHRpb25zLndzKSB7XG4gICAgICB3c1VybCA9IG9wdGlvbnMud3M7XG4gICAgfSBlbHNlIGlmIChjZGtPdXRwdXQpIHtcbiAgICAgIGlmIChjZGtPdXRwdXRbb3B0aW9ucy5jZGtzdGFja10pIHtcbiAgICAgICAgd3NVcmwgPSBjZGtPdXRwdXRbb3B0aW9ucy5jZGtzdGFja10uU2VydmVybGVzc1NweVdzVXJsO1xuICAgICAgfSBlbHNlIGlmIChjZGtPdXRwdXRbT2JqZWN0LmtleXMoY2RrT3V0cHV0KVswXV0pIHtcbiAgICAgICAgd3NVcmwgPSBjZGtPdXRwdXRbT2JqZWN0LmtleXMoY2RrT3V0cHV0KVswXV0uU2VydmVybGVzc1NweVdzVXJsO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICghd3NVcmwpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBJb1QgZW5kcG9pbnQgdXJsJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgd3NVcmxXaXRob3V0U2NvcGUgPSB3c1VybC5zcGxpdCgnLycpWzBdO1xuXG4gICAgY29ubmVjdGlvbiA9IGF3YWl0IGdldENvbm5lY3Rpb24odHJ1ZSwgd3NVcmxXaXRob3V0U2NvcGUpO1xuXG4gICAgY29uc3QgdG9waWMgPSBnZXRUb3BpYygnIycpO1xuICAgIGNvbnNvbGUubG9nKGBTdWJzY3JpYmluZyB0byAke3RvcGljfWApO1xuXG4gICAgY29ubmVjdGlvbi5vbignY29ubmVjdCcsICgpID0+IHtcbiAgICAgIGNvbnNvbGUubG9nKCdDb25uZWN0aW9uIG9wZW5lZCcpO1xuICAgICAgaWYgKGNvbm5lY3Rpb24pIHtcbiAgICAgICAgY29ubmVjdGlvbi5zdWJzY3JpYmUodG9waWMpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgY29ubmVjdGlvbi5vbignbWVzc2FnZScsICh0b3BpYzogc3RyaW5nLCBkYXRhOiBCdWZmZXIpID0+IHtcbiAgICAgIHdzLnNlbmQoXG4gICAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAuLi5KU09OLnBhcnNlKEpTT04ucGFyc2UoZGF0YS50b1N0cmluZygpKS5kYXRhKSxcbiAgICAgICAgICB0b3BpYyxcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGh0dHBcbiAgICAuY3JlYXRlU2VydmVyKChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xuICAgICAgdm9pZCAoYXN5bmMgKCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIC8vY29uc29sZS5sb2coJ3JlcXVlc3QgJywgcmVxdWVzdC51cmwpO1xuICAgICAgICAgIGxldCBmaWxlUGF0aDogc3RyaW5nID0gYC4ke3JlcXVlc3QudXJsfWA7XG4gICAgICAgICAgLy9yZW1vdmUgcXVlcnkgcGFyYW1ldGVyc1xuICAgICAgICAgIGZpbGVQYXRoID0gZmlsZVBhdGguc3BsaXQoJz8nKVswXTtcbiAgICAgICAgICBsZXQgcm9vdEZvbGRlciA9IF9fZGlybmFtZTtcblxuICAgICAgICAgIGlmIChyZXF1ZXN0LnVybD8uc3RhcnRzV2l0aCgnL3dlYlNlcnZlcmxlc3NTcHkuanMnKSkge1xuICAgICAgICAgICAgLy9nZXQgdHJhbnNwaWxlZCBUUyB0byBKUyBmaWxlc1xuICAgICAgICAgICAgcm9vdEZvbGRlciA9IGdldENvbXBpbGVkSnNQYXRoKCk7XG4gICAgICAgICAgfSBlbHNlIGlmIChyZXF1ZXN0LnVybD8uc3RhcnRzV2l0aCgnL2Jvb3RzdHJhcC8nKSkge1xuICAgICAgICAgICAgZmlsZVBhdGggPSBmaWxlUGF0aC5zdWJzdHJpbmcoJy9ib290c3RyYXAvJy5sZW5ndGgpO1xuICAgICAgICAgICAgY29uc3QgYm9vdHN0cmFwRm9sZGVyID0gYXdhaXQgZ2V0TnBtTW9kdWxlSW5zdGFsbGVkUGF0aChcbiAgICAgICAgICAgICAgJ2Jvb3RzdHJhcCdcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJvb3RGb2xkZXIgPSBib290c3RyYXBGb2xkZXI7XG4gICAgICAgICAgfSBlbHNlIGlmIChyZXF1ZXN0LnVybD8uc3RhcnRzV2l0aCgnL2Jvb3RzdHJhcC1pY29ucy8nKSkge1xuICAgICAgICAgICAgZmlsZVBhdGggPSBmaWxlUGF0aC5zdWJzdHJpbmcoJy9ib290c3RyYXAtaWNvbnMvJy5sZW5ndGgpO1xuICAgICAgICAgICAgY29uc3QgYm9vdHN0cmFwRm9sZGVyID0gYXdhaXQgZ2V0TnBtTW9kdWxlSW5zdGFsbGVkUGF0aChcbiAgICAgICAgICAgICAgJ2Jvb3RzdHJhcC1pY29ucydcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJvb3RGb2xkZXIgPSBib290c3RyYXBGb2xkZXI7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmIChmaWxlUGF0aCA9PT0gJy4vJykge1xuICAgICAgICAgICAgICBmaWxlUGF0aCA9ICcuL2luZGV4Lmh0bWwnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGZpbGVQYXRoID0gcGF0aC5qb2luKHJvb3RGb2xkZXIsIGZpbGVQYXRoKTtcbiAgICAgICAgICAvL2NvbnNvbGUubG9nKGAke3JlcXVlc3QudXJsfSAtLT4gJHtmaWxlUGF0aH1gKTtcblxuICAgICAgICAgIGNvbnN0IGV4dG5hbWUgPSBTdHJpbmcocGF0aC5leHRuYW1lKGZpbGVQYXRoKSkudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgICBjb25zdCBtaW1lVHlwZXM6IGFueSA9IHtcbiAgICAgICAgICAgICcuaHRtbCc6ICd0ZXh0L2h0bWwnLFxuICAgICAgICAgICAgJy5qcyc6ICd0ZXh0L2phdmFzY3JpcHQnLFxuICAgICAgICAgICAgJy5jc3MnOiAndGV4dC9jc3MnLFxuICAgICAgICAgICAgJy5qc29uJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICAgJy5wbmcnOiAnaW1hZ2UvcG5nJyxcbiAgICAgICAgICAgICcuanBnJzogJ2ltYWdlL2pwZycsXG4gICAgICAgICAgICAnLmdpZic6ICdpbWFnZS9naWYnLFxuICAgICAgICAgICAgJy5zdmcnOiAnaW1hZ2Uvc3ZnK3htbCcsXG4gICAgICAgICAgICAnLndhdic6ICdhdWRpby93YXYnLFxuICAgICAgICAgICAgJy5tcDQnOiAndmlkZW8vbXA0JyxcbiAgICAgICAgICAgICcud29mZic6ICdhcHBsaWNhdGlvbi9mb250LXdvZmYnLFxuICAgICAgICAgICAgJy50dGYnOiAnYXBwbGljYXRpb24vZm9udC10dGYnLFxuICAgICAgICAgICAgJy5lb3QnOiAnYXBwbGljYXRpb24vdm5kLm1zLWZvbnRvYmplY3QnLFxuICAgICAgICAgICAgJy5vdGYnOiAnYXBwbGljYXRpb24vZm9udC1vdGYnLFxuICAgICAgICAgICAgJy53YXNtJzogJ2FwcGxpY2F0aW9uL3dhc20nLFxuICAgICAgICAgIH07XG5cbiAgICAgICAgICBjb25zdCBjb250ZW50VHlwZSA9IG1pbWVUeXBlc1tleHRuYW1lXSB8fCAnYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtJztcblxuICAgICAgICAgIGlmIChyZXF1ZXN0LnVybCA9PT0gJy9zdGFja0xpc3QnKSB7XG4gICAgICAgICAgICByZXNwb25zZS53cml0ZUhlYWQoMjAwLCB7ICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicgfSk7XG4gICAgICAgICAgICByZXNwb25zZS5lbmQoSlNPTi5zdHJpbmdpZnkoc3RhY2tMaXN0KSwgJ3V0Zi04Jyk7XG4gICAgICAgICAgfSBlbHNlIGlmIChyZXF1ZXN0LnVybCA9PT0gJy9zdGFja1RvcGljTWFwcGluZ3MnKSB7XG4gICAgICAgICAgICByZXNwb25zZS53cml0ZUhlYWQoMjAwLCB7ICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicgfSk7XG4gICAgICAgICAgICBjb25zdCBtYXBwaW5nczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICAgICAgICAgICAgaWYgKGNka091dHB1dCkge1xuICAgICAgICAgICAgICBmb3IgKGNvbnN0IFtzdGFja05hbWUsIHN0YWNrXSBvZiBPYmplY3QuZW50cmllcyhjZGtPdXRwdXQpKSB7XG4gICAgICAgICAgICAgICAgaWYgKHN0YWNrLlNlcnZlcmxlc3NTcHlXc1VybCkge1xuICAgICAgICAgICAgICAgICAgY29uc3QgW18sIHNjb3BlXSA9IHN0YWNrLlNlcnZlcmxlc3NTcHlXc1VybC5zcGxpdCgnLycpO1xuICAgICAgICAgICAgICAgICAgaWYgKHNjb3BlKSB7XG4gICAgICAgICAgICAgICAgICAgIG1hcHBpbmdzW3N0YWNrTmFtZV0gPSBzY29wZTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJlc3BvbnNlLmVuZChKU09OLnN0cmluZ2lmeShtYXBwaW5ncyksICd1dGYtOCcpO1xuICAgICAgICAgIH0gZWxzZSBpZiAocmVxdWVzdC51cmw/Lm1hdGNoKCdeL3dzVXJsJykpIHtcbiAgICAgICAgICAgIHJlc3BvbnNlLndyaXRlSGVhZCgyMDAsIHsgJ0NvbnRlbnQtVHlwZSc6ICd0ZXh0L2h0bWwnIH0pO1xuICAgICAgICAgICAgcmVzcG9uc2UuZW5kKGB3czpsb2NhbGhvc3Q6JHtvcHRpb25zLndzcG9ydH1gLCAndXRmLTgnKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgY29uc3QgY29udGVudCA9IGF3YWl0IHJlYWRGaWxlQXN5bmMoZmlsZVBhdGgpO1xuXG4gICAgICAgICAgICAgIHJlc3BvbnNlLndyaXRlSGVhZCgyMDAsIHsgJ0NvbnRlbnQtVHlwZSc6IGNvbnRlbnRUeXBlIH0pO1xuICAgICAgICAgICAgICByZXNwb25zZS5lbmQoY29udGVudCwgJ3V0Zi04Jyk7XG4gICAgICAgICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICAgICAgICAgIGlmIChlcnJvci5jb2RlID09PSAnRU5PRU5UJykge1xuICAgICAgICAgICAgICAgIHJlc3BvbnNlLndyaXRlSGVhZCg0MDQsIHsgJ0NvbnRlbnQtVHlwZSc6ICd0ZXh0L2h0bWwnIH0pO1xuICAgICAgICAgICAgICAgIHJlc3BvbnNlLmVuZChcbiAgICAgICAgICAgICAgICAgIGBObyBzdWNoIGZpbGUgb3IgZGlyZWN0b3J5ICR7cmVxdWVzdC51cmx9YCxcbiAgICAgICAgICAgICAgICAgICd1dGYtOCdcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJlc3BvbnNlLndyaXRlSGVhZCg1MDApO1xuICAgICAgICAgICAgICAgIHJlc3BvbnNlLmVuZChgRXJyb3I6ICR7ZXJyb3IuY29kZX0gLi5cXG5gKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICByZXNwb25zZS53cml0ZUhlYWQoNTAwLCB7ICdDb250ZW50LVR5cGUnOiAndGV4dC9odG1sJyB9KTtcbiAgICAgICAgICByZXNwb25zZS5lbmQoZXJyLm1lc3NhZ2UsICd1dGYtOCcpO1xuICAgICAgICB9XG4gICAgICB9KSgpO1xuICAgIH0pXG4gICAgLmxpc3RlbihvcHRpb25zLnBvcnQpO1xuXG4gIGNvbnNvbGUubG9nKFxuICAgIGBTZXJ2ZXJsZXNzU3B5IGNvbnNvbGUgcnVuaW5nIGF0IGh0dHA6Ly9sb2NhbGhvc3Q6JHtvcHRpb25zLnBvcnR9YFxuICApO1xuICBpZiAob3B0aW9ucy5vcGVuKSB7XG4gICAgYXdhaXQgb3BlbmVyKGBodHRwOi8vbG9jYWxob3N0OiR7b3B0aW9ucy5wb3J0fWApO1xuICB9XG59XG5cbnJ1bigpLmNhdGNoKGNvbnNvbGUuZXJyb3IpO1xuXG5mdW5jdGlvbiBnZXROcG1Nb2R1bGVJbnN0YWxsZWRQYXRoKG5wbTogc3RyaW5nKSB7XG4gIGxldCBmb2xkZXIgPSBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vJywgJ25vZGVfbW9kdWxlcycsIG5wbSk7XG4gIGlmIChmcy5leGlzdHNTeW5jKGZvbGRlcikpIHtcbiAgICByZXR1cm4gZm9sZGVyO1xuICB9XG5cbiAgbGV0IGZvbGRlckFzUGFja2FnZSA9IHBhdGguam9pbihfX2Rpcm5hbWUsICcuLi8uLi8nLCAnbm9kZV9tb2R1bGVzJywgbnBtKTtcblxuICBpZiAoZnMuZXhpc3RzU3luYyhmb2xkZXJBc1BhY2thZ2UpKSB7XG4gICAgcmV0dXJuIGZvbGRlckFzUGFja2FnZTtcbiAgfVxuXG4gIC8vIFdoZW4gYm9vc3RyYXAgZW5kcyB1cCBpbiBpbXBvcnRpbmcgcHJvamVjdHMgcm9vdCBub2RlX21vZHVsZXMgYW5kIG5vdCBpbiBzZXJ2ZXJsZXNzLXNweXMgbm9kZV9tb2R1bGVzXG4gIGZvbGRlckFzUGFja2FnZSA9IHBhdGguam9pbihfX2Rpcm5hbWUsICcuLi8uLi8uLi8uLi8nLCAnbm9kZV9tb2R1bGVzJywgbnBtKTtcblxuICBpZiAoZnMuZXhpc3RzU3luYyhmb2xkZXJBc1BhY2thZ2UpKSB7XG4gICAgcmV0dXJuIGZvbGRlckFzUGFja2FnZTtcbiAgfVxuXG4gIHRocm93IG5ldyBFcnJvcihcbiAgICBgQ2FuIG5vdCBmaW5kIHBhY2thZ2UgaW4gZm9sZGVyICR7Zm9sZGVyfSBhbmQgJHtmb2xkZXJBc1BhY2thZ2V9YFxuICApO1xufVxuXG5mdW5jdGlvbiBnZXRDb21waWxlZEpzUGF0aCgpIHtcbiAgbGV0IGZvbGRlciA9IHBhdGguam9pbihfX2Rpcm5hbWUsICcuLi8nLCAnbGliL2NsaScpO1xuICBpZiAoZnMuZXhpc3RzU3luYyhmb2xkZXIpKSB7XG4gICAgcmV0dXJuIGZvbGRlcjtcbiAgfVxuXG4gIGxldCBmb2xkZXJBc1BhY2thZ2UgPSBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vLi4vJywgJ2xpYi9jbGknKTtcblxuICBpZiAoZnMuZXhpc3RzU3luYyhmb2xkZXJBc1BhY2thZ2UpKSB7XG4gICAgcmV0dXJuIGZvbGRlckFzUGFja2FnZTtcbiAgfVxuXG4gIHRocm93IG5ldyBFcnJvcihcbiAgICBgQ2FuIG5vdCBmaW5kIGNvbXBpbGVkIGZpbGVzIGluIGZvbGRlciAke2ZvbGRlcn0gYW5kICR7Zm9sZGVyQXNQYWNrYWdlfWBcbiAgKTtcbn1cbiJdfQ==