UNPKG

specmatic

Version:
353 lines (352 loc) 69.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.testWithApiCoverage = exports.test = exports.stopStub = exports.startStub = exports.startApiCoverageServer = exports.showTestResults = exports.setExpectations = exports.setExpectationJson = exports.printJarVersion = exports.Stub = void 0; var _axios = _interopRequireDefault(require("axios")); var _path = _interopRequireDefault(require("path")); var _fastXmlParser = require("fast-xml-parser"); var _fs = _interopRequireDefault(require("fs")); var _logger = _interopRequireDefault(require("../common/logger")); var _runner = require("../common/runner"); var _expressListEndpoints = _interopRequireDefault(require("../lib/express-list-endpoints")); var _http = _interopRequireDefault(require("http")); var _shutdownUtils = require("./shutdownUtils"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i["return"]) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); } function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { function o(r, n) { _regeneratorDefine2(e, r, function (e) { return this._invoke(r, n, e); }); } r ? i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2)); }, _regeneratorDefine2(e, r, n, t); } function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); } function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } var freePortMessage = 'Free port found'; var stubServingMessage = 'serving endpoints from specs'; var Stub = exports.Stub = /*#__PURE__*/_createClass(function Stub(host, port, url, process) { _classCallCheck(this, Stub); _defineProperty(this, "host", void 0); _defineProperty(this, "port", void 0); _defineProperty(this, "url", void 0); _defineProperty(this, "process", void 0); this.host = host; this.port = port; this.url = url; this.process = process; }); var startStub = exports.startStub = function startStub(host, port, args) { var cmd = ["stub"]; if (host) cmd.push("--host=".concat(host)); if (port) cmd.push("--port=".concat(port)); if (args) cmd.push.apply(cmd, _toConsumableArray(args.map(function (arg) { return String(arg); }))); _logger["default"].info('Stub: Starting server'); _logger["default"].debug("Stub: Executing \"".concat(cmd, "\"")); var parsedPort = port == null || port === 0 ? null : String(port); return new Promise(function (resolve, reject) { var javaProcess = (0, _runner.callCore)(cmd, function (err) { if (err) { _logger["default"].error("Stub: Exited with error ".concat(err)); } }, function (message, error) { if (!error) { if (message.indexOf(freePortMessage) > -1) { _logger["default"].info("Stub: ".concat(message)); parsedPort = parsedPort !== null && parsedPort !== void 0 ? parsedPort : message.split("".concat(freePortMessage, ":"))[1].trim(); } else if (message.indexOf(stubServingMessage) > -1) { _logger["default"].info("Stub: ".concat(message)); var stubInfo = message.split(stubServingMessage); if (stubInfo.length < 2) reject('Cannot determine url from stub output');else try { var stub = parseStubOutput(stubInfo, parsedPort, javaProcess); resolve(stub); } catch (e) { reject(extractErrorMessage(e)); } } else if (message.indexOf('Address already in use') > -1) { _logger["default"].error("Stub: ".concat(message)); reject('Address already in use'); } else { _logger["default"].debug("Stub: ".concat(message)); } } else { _logger["default"].error("Stub: ".concat(message)); } }); }); }; function extractErrorMessage(error) { if (typeof error === 'string') { return error; } if (error instanceof Error) { return error.message; } return String(error); } function parseStubOutput(stubInfo, parsedPort, javaProcess) { var _ref; var url = stubInfo[0].trim(); var urlInfo = /\b(.*?):\/\/(.*?):?([0-9]+)?(\/.*)?$/.exec(url); if (urlInfo === null || !urlInfo[1] || !urlInfo[2]) { throw new Error('Cannot determine host and port from stub output'); } var protocol = urlInfo[1]; var host = urlInfo[2]; var regexPort = urlInfo[3]; var path = urlInfo[4] || ""; var defaultPort = protocol === 'http' ? '80' : protocol === 'https' ? '443' : undefined; var finalPort = (_ref = parsedPort !== null && parsedPort !== void 0 ? parsedPort : regexPort) !== null && _ref !== void 0 ? _ref : defaultPort; if (!finalPort) { throw new Error('Cannot determine port from stub output'); } var portNumber = Number.parseInt(finalPort, 10); if (Number.isNaN(portNumber) || portNumber <= 0 || portNumber > 65535) { throw new Error("Invalid port: ".concat(finalPort)); } var finalUrl = "".concat(protocol, "://").concat(host, ":").concat(finalPort).concat(path); return new Stub(host, Number.parseInt(finalPort), finalUrl, javaProcess); } var stopStub = exports.stopStub = /*#__PURE__*/function () { var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(stub) { var _javaProcess$stdout, _javaProcess$stderr; var javaProcess; return _regenerator().w(function (_context) { while (1) switch (_context.n) { case 0: _logger["default"].debug("Stub: Stopping server at ".concat(stub.url)); javaProcess = stub.process; (_javaProcess$stdout = javaProcess.stdout) === null || _javaProcess$stdout === void 0 || _javaProcess$stdout.removeAllListeners(); (_javaProcess$stderr = javaProcess.stderr) === null || _javaProcess$stderr === void 0 || _javaProcess$stderr.removeAllListeners(); javaProcess.removeAllListeners('close'); _logger["default"].debug('Trying to stop stub process gracefully ...'); _context.n = 1; return (0, _shutdownUtils.gracefulShutdown)(javaProcess); case 1: _logger["default"].debug('Completed graceful termination of the stub process'); _logger["default"].info("Stub: Stopped server at ".concat(stub.url)); case 2: return _context.a(2); } }, _callee); })); return function stopStub(_x) { return _ref2.apply(this, arguments); }; }(); var testWithApiCoverage = exports.testWithApiCoverage = /*#__PURE__*/function () { var _ref3 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(expressApp, host, port, contractPath, args) { return _regenerator().w(function (_context3) { while (1) switch (_context3.n) { case 0: return _context3.a(2, new Promise(/*#__PURE__*/function () { var _ref4 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(resolve, _reject) { var apiCoverageServer, results; return _regenerator().w(function (_context2) { while (1) switch (_context2.n) { case 0: _context2.n = 1; return startApiCoverageServer(expressApp); case 1: apiCoverageServer = _context2.v; _context2.n = 2; return test(host, port, contractPath, args); case 2: results = _context2.v; apiCoverageServer.close(function () { resolve(results); }); case 3: return _context2.a(2); } }, _callee2); })); return function (_x7, _x8) { return _ref4.apply(this, arguments); }; }())); } }, _callee3); })); return function testWithApiCoverage(_x2, _x3, _x4, _x5, _x6) { return _ref3.apply(this, arguments); }; }(); var test = exports.test = function test(host, port, contractPath, args) { var specsPath = _path["default"].resolve(contractPath + ''); var cmd = ["test"]; if (contractPath) cmd.push(specsPath); cmd.push('--junitReportDir=dist/test-report'); if (host) cmd.push("--host=".concat(host)); if (port) cmd.push("--port=".concat(port)); if (args) cmd.push.apply(cmd, _toConsumableArray(args.map(function (arg) { return String(arg); }))); _logger["default"].info('Test: Running'); _logger["default"].debug("Test: Executing \"".concat(cmd, "\"")); var reportDir = _path["default"].resolve('dist/test-report'); _fs["default"].rmSync(reportDir, { recursive: true, force: true }); return new Promise(function (resolve, _reject) { (0, _runner.callCore)(cmd, function (err) { if (err) _logger["default"].error("Test: Failed with error ".concat(err)); var testCases = parseJunitXML(); var total = testCases.length; var failure = testCases.filter(function (testcase) { return testcase['failure'] || testcase['skipped']; }).length; var success = total - failure; var result = { total: total, success: success, failure: failure }; resolve(result); }, function (message, error) { if (message.indexOf('API COVERAGE SUMMARY') > -1) { console.log(message); //Log always for all log levels } else { _logger["default"][error ? 'error' : 'debug']("Test: ".concat(message)); } }); }); }; var showTestResults = exports.showTestResults = function showTestResults(testFn) { var testCases = parseJunitXML(); testCases.map(function (testcase) { var name = 'No Name'; if (testcase['system-out']) { var nameTempArr = testcase['system-out'].trim().replace(/\n/g, '').split(/display-name:.*Scenario: /); if (nameTempArr.length > 1) name = nameTempArr[1].trim(); } testFn(name, function () { if (testcase.failure || testcase.skipped) throw new Error('Did not pass'); }); }); }; var setExpectations = exports.setExpectations = function setExpectations(stubPath, stubServerBaseUrl) { var stubResponse = require(_path["default"].resolve(stubPath)); return setExpectationJson(stubResponse, stubServerBaseUrl); }; var setExpectationJson = exports.setExpectationJson = function setExpectationJson(stubResponse, stubServerBaseUrl) { stubServerBaseUrl = stubServerBaseUrl || 'http://localhost:9000'; _logger["default"].info("Set Expectations: Stub url is ".concat(stubServerBaseUrl)); return new Promise(function (resolve, reject) { _axios["default"].post("".concat(stubServerBaseUrl, "/_specmatic/expectations"), stubResponse).then(function (response) { _logger["default"].debug("Set Expectations: ".concat(response.data)); _logger["default"].info('Set Expectations: Finished'); resolve(); })["catch"](function (err) { var _err$response; var setExpectationsErrorMessage = "Set Expectations: Failed with error ".concat(err); // Check if the response data is in text format if (err && ((_err$response = err.response) === null || _err$response === void 0 ? void 0 : _err$response.headers['content-type']) === 'text/plain') { try { // Use a check to handle text content var errorText = typeof err.response.data === 'string' ? err.response.data : "Error text not available"; setExpectationsErrorMessage += " - ".concat(errorText); } catch (e) { _logger["default"].error("Failed to retrieve text error message."); } } _logger["default"].error(setExpectationsErrorMessage); reject(setExpectationsErrorMessage); }); }); }; var printJarVersion = exports.printJarVersion = function printJarVersion() { var cmd = ["--version"]; _logger["default"].info('Print Jar Version: Running'); _logger["default"].debug("Print Jar Version: Executing \"".concat(cmd, "\"")); (0, _runner.callCore)(cmd, function (err) { if (err) _logger["default"].error("Print Jar Version: Failed with error ".concat(err)); }, function (message, error) { if (error) _logger["default"].error("Print Jar Version: ".concat(message));else console.log("".concat(message)); }); }; var startApiCoverageServer = exports.startApiCoverageServer = function startApiCoverageServer(expressApp) { _logger["default"].debug("Registering API endpoint for coverage"); var app = _http["default"].createServer(function (_req, res) { res.writeHead(200, { 'Content-Type': 'application/json' }); var endPoints = JSON.stringify(extractEndPoints(expressApp)); _logger["default"].debug("Endpoints: ".concat(endPoints)); res.end(endPoints); }); return new Promise(function (resolve, reject) { app.on('error', function (err) { _logger["default"].error('Error while starting end points server for api coverage', err); reject('Error while starting end points server for api coverage'); }); app.listen({ host: '127.0.0.1', port: 0 }, function () { var address = app.address(); process.env['endpointsAPI'] = "http://".concat(address === null || address === void 0 ? void 0 : address.address, ":").concat(address === null || address === void 0 ? void 0 : address.port); _logger["default"].info("Endpoints API registered at ".concat(process.env['endpointsAPI'])); resolve(app); }); }); }; var parseJunitXML = function parseJunitXML() { var reportPath = _path["default"].resolve('dist/test-report/TEST-junit-jupiter.xml'); var data = _fs["default"].readFileSync(reportPath); var parser = new _fastXmlParser.XMLParser(); var resultXml = parser.parse(data); resultXml.testsuite.testcase = Array.isArray(resultXml.testsuite.testcase) ? resultXml.testsuite.testcase : [resultXml.testsuite.testcase]; return resultXml.testsuite.testcase; }; var listEndPoints = function listEndPoints(expressApp) { var details = (0, _expressListEndpoints["default"])(expressApp); var endPoints = {}; details.map(function (apiDetail) { endPoints[apiDetail.path] = apiDetail.methods; }); delete endPoints['*']; return endPoints; }; function extractEndPoints(expressApp) { var endPoints = listEndPoints(expressApp); var springActuatorPayload = { contexts: { application: { mappings: { dispatcherServlets: { dispatcherServlet: [] } } } } }; Object.keys(endPoints).sort().map(function (path) { springActuatorPayload.contexts.application.mappings.dispatcherServlets.dispatcherServlet.push({ details: { requestMappingConditions: { methods: endPoints[path].sort(), patterns: [convertEndpointToSpringSyntax(path)].map(removeRegexFromPath) } } }); }); return springActuatorPayload; } var convertEndpointToSpringSyntax = function convertEndpointToSpringSyntax(path) { return path.replace(/:([^/]+)/g, '{$1}').replace(/\\/g, ''); }; var removeRegexFromPath = function removeRegexFromPath(path) { return path.replace(/\([^()]*\)/g, ''); }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXhpb3MiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9wYXRoIiwiX2Zhc3RYbWxQYXJzZXIiLCJfZnMiLCJfbG9nZ2VyIiwiX3J1bm5lciIsIl9leHByZXNzTGlzdEVuZHBvaW50cyIsIl9odHRwIiwiX3NodXRkb3duVXRpbHMiLCJlIiwiX19lc01vZHVsZSIsIl90eXBlb2YiLCJvIiwiU3ltYm9sIiwiaXRlcmF0b3IiLCJjb25zdHJ1Y3RvciIsInByb3RvdHlwZSIsIl9yZWdlbmVyYXRvciIsInQiLCJyIiwibiIsInRvU3RyaW5nVGFnIiwiaSIsImMiLCJHZW5lcmF0b3IiLCJ1IiwiT2JqZWN0IiwiY3JlYXRlIiwiX3JlZ2VuZXJhdG9yRGVmaW5lMiIsImYiLCJwIiwieSIsIkciLCJ2IiwiYSIsImQiLCJiaW5kIiwibGVuZ3RoIiwibCIsIlR5cGVFcnJvciIsImNhbGwiLCJkb25lIiwidmFsdWUiLCJHZW5lcmF0b3JGdW5jdGlvbiIsIkdlbmVyYXRvckZ1bmN0aW9uUHJvdG90eXBlIiwiZ2V0UHJvdG90eXBlT2YiLCJzZXRQcm90b3R5cGVPZiIsIl9fcHJvdG9fXyIsImRpc3BsYXlOYW1lIiwidyIsIm0iLCJkZWZpbmVQcm9wZXJ0eSIsIl9yZWdlbmVyYXRvckRlZmluZSIsIl9pbnZva2UiLCJlbnVtZXJhYmxlIiwiY29uZmlndXJhYmxlIiwid3JpdGFibGUiLCJhc3luY0dlbmVyYXRvclN0ZXAiLCJQcm9taXNlIiwicmVzb2x2ZSIsInRoZW4iLCJfYXN5bmNUb0dlbmVyYXRvciIsImFyZ3VtZW50cyIsImFwcGx5IiwiX25leHQiLCJfdGhyb3ciLCJfdG9Db25zdW1hYmxlQXJyYXkiLCJfYXJyYXlXaXRob3V0SG9sZXMiLCJfaXRlcmFibGVUb0FycmF5IiwiX3Vuc3VwcG9ydGVkSXRlcmFibGVUb0FycmF5IiwiX25vbkl0ZXJhYmxlU3ByZWFkIiwiX2FycmF5TGlrZVRvQXJyYXkiLCJ0b1N0cmluZyIsInNsaWNlIiwibmFtZSIsIkFycmF5IiwiZnJvbSIsInRlc3QiLCJpc0FycmF5IiwiX2RlZmluZVByb3BlcnRpZXMiLCJfdG9Qcm9wZXJ0eUtleSIsImtleSIsIl9jcmVhdGVDbGFzcyIsIl9jbGFzc0NhbGxDaGVjayIsIl9kZWZpbmVQcm9wZXJ0eSIsIl90b1ByaW1pdGl2ZSIsInRvUHJpbWl0aXZlIiwiU3RyaW5nIiwiTnVtYmVyIiwiZnJlZVBvcnRNZXNzYWdlIiwic3R1YlNlcnZpbmdNZXNzYWdlIiwiU3R1YiIsImV4cG9ydHMiLCJob3N0IiwicG9ydCIsInVybCIsInByb2Nlc3MiLCJzdGFydFN0dWIiLCJhcmdzIiwiY21kIiwicHVzaCIsImNvbmNhdCIsIm1hcCIsImFyZyIsImxvZ2dlciIsImluZm8iLCJkZWJ1ZyIsInBhcnNlZFBvcnQiLCJyZWplY3QiLCJqYXZhUHJvY2VzcyIsImNhbGxDb3JlIiwiZXJyIiwiZXJyb3IiLCJtZXNzYWdlIiwiaW5kZXhPZiIsInNwbGl0IiwidHJpbSIsInN0dWJJbmZvIiwic3R1YiIsInBhcnNlU3R1Yk91dHB1dCIsImV4dHJhY3RFcnJvck1lc3NhZ2UiLCJFcnJvciIsIl9yZWYiLCJ1cmxJbmZvIiwiZXhlYyIsInByb3RvY29sIiwicmVnZXhQb3J0IiwicGF0aCIsImRlZmF1bHRQb3J0IiwidW5kZWZpbmVkIiwiZmluYWxQb3J0IiwicG9ydE51bWJlciIsInBhcnNlSW50IiwiaXNOYU4iLCJmaW5hbFVybCIsInN0b3BTdHViIiwiX3JlZjIiLCJfY2FsbGVlIiwiX2phdmFQcm9jZXNzJHN0ZG91dCIsIl9qYXZhUHJvY2VzcyRzdGRlcnIiLCJfY29udGV4dCIsInN0ZG91dCIsInJlbW92ZUFsbExpc3RlbmVycyIsInN0ZGVyciIsImdyYWNlZnVsU2h1dGRvd24iLCJfeCIsInRlc3RXaXRoQXBpQ292ZXJhZ2UiLCJfcmVmMyIsIl9jYWxsZWUzIiwiZXhwcmVzc0FwcCIsImNvbnRyYWN0UGF0aCIsIl9jb250ZXh0MyIsIl9yZWY0IiwiX2NhbGxlZTIiLCJfcmVqZWN0IiwiYXBpQ292ZXJhZ2VTZXJ2ZXIiLCJyZXN1bHRzIiwiX2NvbnRleHQyIiwic3RhcnRBcGlDb3ZlcmFnZVNlcnZlciIsImNsb3NlIiwiX3g3IiwiX3g4IiwiX3gyIiwiX3gzIiwiX3g0IiwiX3g1IiwiX3g2Iiwic3BlY3NQYXRoIiwicmVwb3J0RGlyIiwiZnMiLCJybVN5bmMiLCJyZWN1cnNpdmUiLCJmb3JjZSIsInRlc3RDYXNlcyIsInBhcnNlSnVuaXRYTUwiLCJ0b3RhbCIsImZhaWx1cmUiLCJmaWx0ZXIiLCJ0ZXN0Y2FzZSIsInN1Y2Nlc3MiLCJyZXN1bHQiLCJjb25zb2xlIiwibG9nIiwic2hvd1Rlc3RSZXN1bHRzIiwidGVzdEZuIiwibmFtZVRlbXBBcnIiLCJyZXBsYWNlIiwic2tpcHBlZCIsInNldEV4cGVjdGF0aW9ucyIsInN0dWJQYXRoIiwic3R1YlNlcnZlckJhc2VVcmwiLCJzdHViUmVzcG9uc2UiLCJzZXRFeHBlY3RhdGlvbkpzb24iLCJheGlvcyIsInBvc3QiLCJyZXNwb25zZSIsImRhdGEiLCJfZXJyJHJlc3BvbnNlIiwic2V0RXhwZWN0YXRpb25zRXJyb3JNZXNzYWdlIiwiaGVhZGVycyIsImVycm9yVGV4dCIsInByaW50SmFyVmVyc2lvbiIsImFwcCIsImh0dHAiLCJjcmVhdGVTZXJ2ZXIiLCJfcmVxIiwicmVzIiwid3JpdGVIZWFkIiwiZW5kUG9pbnRzIiwiSlNPTiIsInN0cmluZ2lmeSIsImV4dHJhY3RFbmRQb2ludHMiLCJlbmQiLCJvbiIsImxpc3RlbiIsImFkZHJlc3MiLCJlbnYiLCJyZXBvcnRQYXRoIiwicmVhZEZpbGVTeW5jIiwicGFyc2VyIiwiWE1MUGFyc2VyIiwicmVzdWx0WG1sIiwicGFyc2UiLCJ0ZXN0c3VpdGUiLCJsaXN0RW5kUG9pbnRzIiwiZGV0YWlscyIsImxpc3RFeHByZXNzRW5kcG9pbnRzIiwiYXBpRGV0YWlsIiwibWV0aG9kcyIsInNwcmluZ0FjdHVhdG9yUGF5bG9hZCIsImNvbnRleHRzIiwiYXBwbGljYXRpb24iLCJtYXBwaW5ncyIsImRpc3BhdGNoZXJTZXJ2bGV0cyIsImRpc3BhdGNoZXJTZXJ2bGV0Iiwia2V5cyIsInNvcnQiLCJyZXF1ZXN0TWFwcGluZ0NvbmRpdGlvbnMiLCJwYXR0ZXJucyIsImNvbnZlcnRFbmRwb2ludFRvU3ByaW5nU3ludGF4IiwicmVtb3ZlUmVnZXhGcm9tUGF0aCJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb3JlL2luZGV4LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBheGlvcyBmcm9tICdheGlvcydcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnXG5pbXBvcnQgeyBDaGlsZFByb2Nlc3MgfSBmcm9tICdjaGlsZF9wcm9jZXNzJ1xuaW1wb3J0IHsgWE1MUGFyc2VyIH0gZnJvbSAnZmFzdC14bWwtcGFyc2VyJ1xuaW1wb3J0IGZzIGZyb20gJ2ZzJ1xuaW1wb3J0IGxvZ2dlciBmcm9tICcuLi9jb21tb24vbG9nZ2VyJ1xuaW1wb3J0IHsgY2FsbENvcmUgfSBmcm9tICcuLi9jb21tb24vcnVubmVyJ1xuaW1wb3J0IGxpc3RFeHByZXNzRW5kcG9pbnRzIGZyb20gJy4uL2xpYi9leHByZXNzLWxpc3QtZW5kcG9pbnRzJztcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnXG5pbXBvcnQgeyBBZGRyZXNzSW5mbyB9IGZyb20gJ25ldCdcbmltcG9ydCB7IGdyYWNlZnVsU2h1dGRvd24gfSBmcm9tICcuL3NodXRkb3duVXRpbHMnXG5cbmNvbnN0IGZyZWVQb3J0TWVzc2FnZSA9ICdGcmVlIHBvcnQgZm91bmQnXG5jb25zdCBzdHViU2VydmluZ01lc3NhZ2UgPSAnc2VydmluZyBlbmRwb2ludHMgZnJvbSBzcGVjcydcblxuZXhwb3J0IGNsYXNzIFN0dWIge1xuICAgIGhvc3Q6IHN0cmluZ1xuICAgIHBvcnQ6IG51bWJlclxuICAgIHVybDogc3RyaW5nXG4gICAgcHJvY2VzczogQ2hpbGRQcm9jZXNzXG4gICAgY29uc3RydWN0b3IoaG9zdDogc3RyaW5nLCBwb3J0OiBudW1iZXIsIHVybDogc3RyaW5nLCBwcm9jZXNzOiBDaGlsZFByb2Nlc3MpIHtcbiAgICAgICAgdGhpcy5ob3N0ID0gaG9zdFxuICAgICAgICB0aGlzLnBvcnQgPSBwb3J0XG4gICAgICAgIHRoaXMudXJsID0gdXJsXG4gICAgICAgIHRoaXMucHJvY2VzcyA9IHByb2Nlc3NcbiAgICB9XG59XG5cbmNvbnN0IHN0YXJ0U3R1YiA9IChob3N0Pzogc3RyaW5nLCBwb3J0PzogbnVtYmVyLCBhcmdzPzogKHN0cmluZyB8IG51bWJlcilbXSk6IFByb21pc2U8U3R1Yj4gPT4ge1xuICAgIHZhciBjbWQgPSBbYHN0dWJgXVxuICAgIGlmIChob3N0KSBjbWQgLnB1c2goYC0taG9zdD0ke2hvc3R9YClcbiAgICBpZiAocG9ydCkgY21kIC5wdXNoKGAtLXBvcnQ9JHtwb3J0fWApXG4gICAgaWYgKGFyZ3MpIGNtZCAucHVzaCguLi5hcmdzLm1hcChhcmcgPT4gU3RyaW5nKGFyZykpKVxuXG4gICAgbG9nZ2VyLmluZm8oJ1N0dWI6IFN0YXJ0aW5nIHNlcnZlcicpXG4gICAgbG9nZ2VyLmRlYnVnKGBTdHViOiBFeGVjdXRpbmcgXCIke2NtZH1cImApXG4gICAgbGV0IHBhcnNlZFBvcnQ6IHN0cmluZyB8IG51bGwgPSBwb3J0ID09IG51bGwgfHwgcG9ydCA9PT0gMCA/IG51bGwgOiBTdHJpbmcocG9ydCk7XG5cbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBjb25zdCBqYXZhUHJvY2VzcyA9IGNhbGxDb3JlKFxuICAgICAgICAgICAgY21kLFxuICAgICAgICAgICAgKGVycjogYW55KSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgICAgICBsb2dnZXIuZXJyb3IoYFN0dWI6IEV4aXRlZCB3aXRoIGVycm9yICR7ZXJyfWApXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIChtZXNzYWdlLCBlcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgIGlmICghZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKG1lc3NhZ2UuaW5kZXhPZihmcmVlUG9ydE1lc3NhZ2UpID4gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2dlci5pbmZvKGBTdHViOiAke21lc3NhZ2V9YClcbiAgICAgICAgICAgICAgICAgICAgICAgIHBhcnNlZFBvcnQgPSBwYXJzZWRQb3J0ID8/IG1lc3NhZ2Uuc3BsaXQoYCR7ZnJlZVBvcnRNZXNzYWdlfTpgKVsxXS50cmltKClcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChtZXNzYWdlLmluZGV4T2Yoc3R1YlNlcnZpbmdNZXNzYWdlKSA+IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBsb2dnZXIuaW5mbyhgU3R1YjogJHttZXNzYWdlfWApXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBzdHViSW5mbyA9IG1lc3NhZ2Uuc3BsaXQoc3R1YlNlcnZpbmdNZXNzYWdlKVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHN0dWJJbmZvLmxlbmd0aCA8IDIpIHJlamVjdCgnQ2Fubm90IGRldGVybWluZSB1cmwgZnJvbSBzdHViIG91dHB1dCcpXG4gICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3R1YiA9IHBhcnNlU3R1Yk91dHB1dChzdHViSW5mbywgcGFyc2VkUG9ydCwgamF2YVByb2Nlc3MpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdmUoc3R1Yik7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7IHJlamVjdChleHRyYWN0RXJyb3JNZXNzYWdlKGUpKTsgfVxuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG1lc3NhZ2UuaW5kZXhPZignQWRkcmVzcyBhbHJlYWR5IGluIHVzZScpID4gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2dlci5lcnJvcihgU3R1YjogJHttZXNzYWdlfWApXG4gICAgICAgICAgICAgICAgICAgICAgICByZWplY3QoJ0FkZHJlc3MgYWxyZWFkeSBpbiB1c2UnKVxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKGBTdHViOiAke21lc3NhZ2V9YClcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGxvZ2dlci5lcnJvcihgU3R1YjogJHttZXNzYWdlfWApXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApXG4gICAgfSlcbn1cblxuZnVuY3Rpb24gZXh0cmFjdEVycm9yTWVzc2FnZShlcnJvcjogYW55KTogc3RyaW5nIHtcbiAgICBpZiAodHlwZW9mIGVycm9yID09PSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuIGVycm9yO1xuICAgIH1cblxuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICByZXR1cm4gZXJyb3IubWVzc2FnZTtcbiAgICB9XG5cbiAgICByZXR1cm4gU3RyaW5nKGVycm9yKTtcbn1cblxuZnVuY3Rpb24gcGFyc2VTdHViT3V0cHV0KFxuICAgIHN0dWJJbmZvOiBzdHJpbmdbXSxcbiAgICBwYXJzZWRQb3J0OiBzdHJpbmcgfCBudWxsLFxuICAgIGphdmFQcm9jZXNzOiBDaGlsZFByb2Nlc3Ncbik6IFN0dWIge1xuICAgIGNvbnN0IHVybCA9IHN0dWJJbmZvWzBdLnRyaW0oKTtcbiAgICBjb25zdCB1cmxJbmZvID0gL1xcYiguKj8pOlxcL1xcLyguKj8pOj8oWzAtOV0rKT8oXFwvLiopPyQvLmV4ZWModXJsKTtcblxuICAgIGlmICh1cmxJbmZvID09PSBudWxsIHx8ICF1cmxJbmZvWzFdIHx8ICF1cmxJbmZvWzJdKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBkZXRlcm1pbmUgaG9zdCBhbmQgcG9ydCBmcm9tIHN0dWIgb3V0cHV0Jyk7XG4gICAgfVxuXG4gICAgY29uc3QgcHJvdG9jb2wgPSB1cmxJbmZvWzFdO1xuICAgIGNvbnN0IGhvc3QgPSB1cmxJbmZvWzJdO1xuICAgIGNvbnN0IHJlZ2V4UG9ydCA9IHVybEluZm9bM107XG4gICAgY29uc3QgcGF0aCA9IHVybEluZm9bNF0gfHwgXCJcIjtcbiAgICBjb25zdCBkZWZhdWx0UG9ydCA9IHByb3RvY29sID09PSAnaHR0cCcgPyAnODAnIDogcHJvdG9jb2wgPT09ICdodHRwcycgPyAnNDQzJyA6IHVuZGVmaW5lZDtcbiAgICBjb25zdCBmaW5hbFBvcnQgPSBwYXJzZWRQb3J0ID8/IHJlZ2V4UG9ydCA/PyBkZWZhdWx0UG9ydDtcblxuICAgIGlmICghZmluYWxQb3J0KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBkZXRlcm1pbmUgcG9ydCBmcm9tIHN0dWIgb3V0cHV0Jyk7XG4gICAgfVxuXG4gICAgY29uc3QgcG9ydE51bWJlciA9IE51bWJlci5wYXJzZUludChmaW5hbFBvcnQsIDEwKTtcbiAgICBpZiAoTnVtYmVyLmlzTmFOKHBvcnROdW1iZXIpIHx8IHBvcnROdW1iZXIgPD0gMCB8fCBwb3J0TnVtYmVyID4gNjU1MzUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBwb3J0OiAke2ZpbmFsUG9ydH1gKTtcbiAgICB9XG5cbiAgICBjb25zdCBmaW5hbFVybCA9IGAke3Byb3RvY29sfTovLyR7aG9zdH06JHtmaW5hbFBvcnR9JHtwYXRofWA7XG4gICAgcmV0dXJuIG5ldyBTdHViKGhvc3QsIE51bWJlci5wYXJzZUludChmaW5hbFBvcnQpLCBmaW5hbFVybCwgamF2YVByb2Nlc3MpO1xufVxuXG5jb25zdCBzdG9wU3R1YiA9IGFzeW5jIChzdHViOiBTdHViKSA9PiB7XG4gICAgbG9nZ2VyLmRlYnVnKGBTdHViOiBTdG9wcGluZyBzZXJ2ZXIgYXQgJHtzdHViLnVybH1gKVxuICAgIGNvbnN0IGphdmFQcm9jZXNzID0gc3R1Yi5wcm9jZXNzXG4gICAgamF2YVByb2Nlc3Muc3Rkb3V0Py5yZW1vdmVBbGxMaXN0ZW5lcnMoKVxuICAgIGphdmFQcm9jZXNzLnN0ZGVycj8ucmVtb3ZlQWxsTGlzdGVuZXJzKClcbiAgICBqYXZhUHJvY2Vzcy5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Nsb3NlJylcbiAgICBsb2dnZXIuZGVidWcoJ1RyeWluZyB0byBzdG9wIHN0dWIgcHJvY2VzcyBncmFjZWZ1bGx5IC4uLicpXG4gICAgYXdhaXQgZ3JhY2VmdWxTaHV0ZG93bihqYXZhUHJvY2VzcylcbiAgICBsb2dnZXIuZGVidWcoJ0NvbXBsZXRlZCBncmFjZWZ1bCB0ZXJtaW5hdGlvbiBvZiB0aGUgc3R1YiBwcm9jZXNzJylcbiAgICBsb2dnZXIuaW5mbyhgU3R1YjogU3RvcHBlZCBzZXJ2ZXIgYXQgJHtzdHViLnVybH1gKVxufVxuXG5jb25zdCB0ZXN0V2l0aEFwaUNvdmVyYWdlID0gYXN5bmMgKFxuICAgIGV4cHJlc3NBcHA6IGFueSxcbiAgICBob3N0Pzogc3RyaW5nLFxuICAgIHBvcnQ/OiBudW1iZXIsXG4gICAgY29udHJhY3RQYXRoPzogc3RyaW5nLFxuICAgIGFyZ3M/OiAoc3RyaW5nIHwgbnVtYmVyKVtdXG4pOiBQcm9taXNlPHsgW2s6IHN0cmluZ106IG51bWJlciB9IHwgdW5kZWZpbmVkPiA9PiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGFzeW5jIChyZXNvbHZlLCBfcmVqZWN0KSA9PiB7XG4gICAgICAgIGxldCBhcGlDb3ZlcmFnZVNlcnZlciA9IGF3YWl0IHN0YXJ0QXBpQ292ZXJhZ2VTZXJ2ZXIoZXhwcmVzc0FwcClcbiAgICAgICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IHRlc3QoaG9zdCwgcG9ydCwgY29udHJhY3RQYXRoLCBhcmdzKVxuICAgICAgICBhcGlDb3ZlcmFnZVNlcnZlci5jbG9zZSgoKSA9PiB7XG4gICAgICAgICAgICByZXNvbHZlKHJlc3VsdHMpXG4gICAgICAgIH0pXG4gICAgfSlcbn1cblxuY29uc3QgdGVzdCA9IChob3N0Pzogc3RyaW5nLCBwb3J0PzogbnVtYmVyLCBjb250cmFjdFBhdGg/OiBzdHJpbmcsIGFyZ3M/OiAoc3RyaW5nIHwgbnVtYmVyKVtdKTogUHJvbWlzZTx7IFtrOiBzdHJpbmddOiBudW1iZXIgfSB8IHVuZGVmaW5lZD4gPT4ge1xuICAgIGNvbnN0IHNwZWNzUGF0aCA9IHBhdGgucmVzb2x2ZShjb250cmFjdFBhdGggKyAnJylcblxuICAgIGNvbnN0IGNtZCA9IFtgdGVzdGBdXG4gICAgaWYgKGNvbnRyYWN0UGF0aCkgY21kLnB1c2goc3BlY3NQYXRoKVxuICAgIGNtZC5wdXNoKCctLWp1bml0UmVwb3J0RGlyPWRpc3QvdGVzdC1yZXBvcnQnKVxuICAgIGlmIChob3N0KSBjbWQucHVzaChgLS1ob3N0PSR7aG9zdH1gKVxuICAgIGlmIChwb3J0KSBjbWQucHVzaChgLS1wb3J0PSR7cG9ydH1gKVxuICAgIGlmIChhcmdzKSBjbWQucHVzaCguLi5hcmdzLm1hcChhcmcgPT4gU3RyaW5nKGFyZykpKVxuXG4gICAgbG9nZ2VyLmluZm8oJ1Rlc3Q6IFJ1bm5pbmcnKVxuICAgIGxvZ2dlci5kZWJ1ZyhgVGVzdDogRXhlY3V0aW5nIFwiJHtjbWR9XCJgKVxuXG4gICAgY29uc3QgcmVwb3J0RGlyID0gcGF0aC5yZXNvbHZlKCdkaXN0L3Rlc3QtcmVwb3J0JylcbiAgICBmcy5ybVN5bmMocmVwb3J0RGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSlcblxuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgX3JlamVjdCkgPT4ge1xuICAgICAgICBjYWxsQ29yZShcbiAgICAgICAgICAgIGNtZCxcbiAgICAgICAgICAgIChlcnI6IGFueSkgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChlcnIpIGxvZ2dlci5lcnJvcihgVGVzdDogRmFpbGVkIHdpdGggZXJyb3IgJHtlcnJ9YClcbiAgICAgICAgICAgICAgICB2YXIgdGVzdENhc2VzID0gcGFyc2VKdW5pdFhNTCgpXG4gICAgICAgICAgICAgICAgY29uc3QgdG90YWwgPSB0ZXN0Q2FzZXMubGVuZ3RoXG4gICAgICAgICAgICAgICAgY29uc3QgZmFpbHVyZSA9IHRlc3RDYXNlcy5maWx0ZXIoKHRlc3RjYXNlOiB7IFtpZDogc3RyaW5nXTogYW55IH0pID0+IHRlc3RjYXNlWydmYWlsdXJlJ10gfHwgdGVzdGNhc2VbJ3NraXBwZWQnXSkubGVuZ3RoXG4gICAgICAgICAgICAgICAgY29uc3Qgc3VjY2VzcyA9IHRvdGFsIC0gZmFpbHVyZVxuICAgICAgICAgICAgICAgIHZhciByZXN1bHQgPSB7IHRvdGFsLCBzdWNjZXNzLCBmYWlsdXJlIH1cbiAgICAgICAgICAgICAgICByZXNvbHZlKHJlc3VsdClcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAobWVzc2FnZSwgZXJyb3IpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAobWVzc2FnZS5pbmRleE9mKCdBUEkgQ09WRVJBR0UgU1VNTUFSWScpID4gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2cobWVzc2FnZSkgLy9Mb2cgYWx3YXlzIGZvciBhbGwgbG9nIGxldmVsc1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGxvZ2dlcltlcnJvciA/ICdlcnJvcicgOiAnZGVidWcnXShgVGVzdDogJHttZXNzYWdlfWApXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApXG4gICAgfSlcbn1cblxuY29uc3Qgc2hvd1Rlc3RSZXN1bHRzID0gKHRlc3RGbjogKG5hbWU6IHN0cmluZywgY2I6ICgpID0+IHZvaWQpID0+IHZvaWQpID0+IHtcbiAgICB2YXIgdGVzdENhc2VzID0gcGFyc2VKdW5pdFhNTCgpXG4gICAgdGVzdENhc2VzLm1hcChmdW5jdGlvbiAodGVzdGNhc2U6IHsgW2lkOiBzdHJpbmddOiBhbnkgfSkge1xuICAgICAgICB2YXIgbmFtZSA9ICdObyBOYW1lJ1xuICAgICAgICBpZiAodGVzdGNhc2VbJ3N5c3RlbS1vdXQnXSkge1xuICAgICAgICAgICAgY29uc3QgbmFtZVRlbXBBcnIgPSB0ZXN0Y2FzZVsnc3lzdGVtLW91dCddXG4gICAgICAgICAgICAgICAgLnRyaW0oKVxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cXG4vZywgJycpXG4gICAgICAgICAgICAgICAgLnNwbGl0KC9kaXNwbGF5LW5hbWU6LipTY2VuYXJpbzogLylcbiAgICAgICAgICAgIGlmIChuYW1lVGVtcEFyci5sZW5ndGggPiAxKSBuYW1lID0gbmFtZVRlbXBBcnJbMV0udHJpbSgpXG4gICAgICAgIH1cbiAgICAgICAgdGVzdEZuKG5hbWUsICgpID0+IHtcbiAgICAgICAgICAgIGlmICh0ZXN0Y2FzZS5mYWlsdXJlIHx8IHRlc3RjYXNlLnNraXBwZWQpIHRocm93IG5ldyBFcnJvcignRGlkIG5vdCBwYXNzJylcbiAgICAgICAgfSlcbiAgICB9KVxufVxuXG5jb25zdCBzZXRFeHBlY3RhdGlvbnMgPSAoc3R1YlBhdGg6IHN0cmluZywgc3R1YlNlcnZlckJhc2VVcmw/OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICBjb25zdCBzdHViUmVzcG9uc2UgPSByZXF1aXJlKHBhdGgucmVzb2x2ZShzdHViUGF0aCkpXG4gICAgcmV0dXJuIHNldEV4cGVjdGF0aW9uSnNvbihzdHViUmVzcG9uc2UsIHN0dWJTZXJ2ZXJCYXNlVXJsKVxufVxuXG5jb25zdCBzZXRFeHBlY3RhdGlvbkpzb24gPSAoc3R1YlJlc3BvbnNlOiBhbnksIHN0dWJTZXJ2ZXJCYXNlVXJsPzogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgc3R1YlNlcnZlckJhc2VVcmwgPSBzdHViU2VydmVyQmFzZVVybCB8fCAnaHR0cDovL2xvY2FsaG9zdDo5MDAwJ1xuXG4gICAgbG9nZ2VyLmluZm8oYFNldCBFeHBlY3RhdGlvbnM6IFN0dWIgdXJsIGlzICR7c3R1YlNlcnZlckJhc2VVcmx9YClcblxuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGF4aW9zXG4gICAgICAgICAgICAucG9zdChgJHtzdHViU2VydmVyQmFzZVVybH0vX3NwZWNtYXRpYy9leHBlY3RhdGlvbnNgLCBzdHViUmVzcG9uc2UpXG4gICAgICAgICAgICAudGhlbihyZXNwb25zZSA9PiB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKGBTZXQgRXhwZWN0YXRpb25zOiAke3Jlc3BvbnNlLmRhdGF9YClcbiAgICAgICAgICAgICAgICBsb2dnZXIuaW5mbygnU2V0IEV4cGVjdGF0aW9uczogRmluaXNoZWQnKVxuICAgICAgICAgICAgICAgIHJlc29sdmUoKVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5jYXRjaChlcnIgPT4ge1xuICAgICAgICAgICAgICAgIHZhciBzZXRFeHBlY3RhdGlvbnNFcnJvck1lc3NhZ2UgPSBgU2V0IEV4cGVjdGF0aW9uczogRmFpbGVkIHdpdGggZXJyb3IgJHtlcnJ9YFxuICAgICAgICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSByZXNwb25zZSBkYXRhIGlzIGluIHRleHQgZm9ybWF0XG4gICAgICAgICAgICAgICAgaWYgKGVyciAmJiBlcnIucmVzcG9uc2U/LmhlYWRlcnNbJ2NvbnRlbnQtdHlwZSddID09PSAndGV4dC9wbGFpbicpIHtcbiAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVzZSBhIGNoZWNrIHRvIGhhbmRsZSB0ZXh0IGNvbnRlbnRcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGVycm9yVGV4dCA9IHR5cGVvZiBlcnIucmVzcG9uc2UuZGF0YSA9PT0gJ3N0cmluZycgPyBlcnIucmVzcG9uc2UuZGF0YSA6IFwiRXJyb3IgdGV4dCBub3QgYXZhaWxhYmxlXCI7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRFeHBlY3RhdGlvbnNFcnJvck1lc3NhZ2UgKz0gYCAtICR7ZXJyb3JUZXh0fWA7XG4gICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2dlci5lcnJvcihcIkZhaWxlZCB0byByZXRyaWV2ZSB0ZXh0IGVycm9yIG1lc3NhZ2UuXCIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGxvZ2dlci5lcnJvcihzZXRFeHBlY3RhdGlvbnNFcnJvck1lc3NhZ2UpXG4gICAgICAgICAgICAgICAgcmVqZWN0KHNldEV4cGVjdGF0aW9uc0Vycm9yTWVzc2FnZSlcbiAgICAgICAgICAgIH0pXG4gICAgfSlcbn1cblxuY29uc3QgcHJpbnRKYXJWZXJzaW9uID0gKCkgPT4ge1xuICAgIGNvbnN0IGNtZCA9IFtgLS12ZXJzaW9uYF1cbiAgICBsb2dnZXIuaW5mbygnUHJpbnQgSmFyIFZlcnNpb246IFJ1bm5pbmcnKVxuICAgIGxvZ2dlci5kZWJ1ZyhgUHJpbnQgSmFyIFZlcnNpb246IEV4ZWN1dGluZyBcIiR7Y21kfVwiYClcblxuICAgIGNhbGxDb3JlKFxuICAgICAgICBjbWQsXG4gICAgICAgIChlcnI6IGFueSkgPT4ge1xuICAgICAgICAgICAgaWYgKGVycikgbG9nZ2VyLmVycm9yKGBQcmludCBKYXIgVmVyc2lvbjogRmFpbGVkIHdpdGggZXJyb3IgJHtlcnJ9YClcbiAgICAgICAgfSxcbiAgICAgICAgKG1lc3NhZ2UsIGVycm9yKSA9PiB7XG4gICAgICAgICAgICBpZiAoZXJyb3IpIGxvZ2dlci5lcnJvcihgUHJpbnQgSmFyIFZlcnNpb246ICR7bWVzc2FnZX1gKVxuICAgICAgICAgICAgZWxzZSBjb25zb2xlLmxvZyhgJHttZXNzYWdlfWApXG4gICAgICAgIH1cbiAgICApXG59XG5cbmNvbnN0IHN0YXJ0QXBpQ292ZXJhZ2VTZXJ2ZXIgPSAoZXhwcmVzc0FwcDogYW55KTogUHJvbWlzZTxodHRwLlNlcnZlcj4gPT4ge1xuICAgIGxvZ2dlci5kZWJ1ZyhgUmVnaXN0ZXJpbmcgQVBJIGVuZHBvaW50IGZvciBjb3ZlcmFnZWApXG4gICAgbGV0IGFwcCA9IGh0dHAuY3JlYXRlU2VydmVyKChfcmVxLCByZXMpID0+IHtcbiAgICAgICAgcmVzLndyaXRlSGVhZCgyMDAsIHsgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyB9KVxuICAgICAgICBjb25zdCBlbmRQb2ludHMgPSBKU09OLnN0cmluZ2lmeShleHRyYWN0RW5kUG9pbnRzKGV4cHJlc3NBcHApKVxuICAgICAgICBsb2dnZXIuZGVidWcoYEVuZHBvaW50czogJHtlbmRQb2ludHN9YClcbiAgICAgICAgcmVzLmVuZChlbmRQb2ludHMpXG4gICAgfSlcbiAgICByZXR1cm4gbmV3IFByb21pc2U8aHR0cC5TZXJ2ZXI+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgYXBwLm9uKCdlcnJvcicsIGVyciA9PiB7XG4gICAgICAgICAgICBsb2dnZXIuZXJyb3IoJ0Vycm9yIHdoaWxlIHN0YXJ0aW5nIGVuZCBwb2ludHMgc2VydmVyIGZvciBhcGkgY292ZXJhZ2UnLCBlcnIpXG4gICAgICAgICAgICByZWplY3QoJ0Vycm9yIHdoaWxlIHN0YXJ0aW5nIGVuZCBwb2ludHMgc2VydmVyIGZvciBhcGkgY292ZXJhZ2UnKVxuICAgICAgICB9KVxuICAgICAgICBhcHAubGlzdGVuKHsgaG9zdDogJzEyNy4wLjAuMScsIHBvcnQ6IDAgfSwgKCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgYWRkcmVzcyA9IGFwcC5hZGRyZXNzKCkgYXMgQWRkcmVzc0luZm8gfCBudWxsXG4gICAgICAgICAgICBwcm9jZXNzLmVudlsnZW5kcG9pbnRzQVBJJ10gPSBgaHR0cDovLyR7YWRkcmVzcz8uYWRkcmVzc306JHthZGRyZXNzPy5wb3J0fWBcbiAgICAgICAgICAgIGxvZ2dlci5pbmZvKGBFbmRwb2ludHMgQVBJIHJlZ2lzdGVyZWQgYXQgJHtwcm9jZXNzLmVudlsnZW5kcG9pbnRzQVBJJ119YClcbiAgICAgICAgICAgIHJlc29sdmUoYXBwKVxuICAgICAgICB9KVxuICAgIH0pXG59XG5cbmNvbnN0IHBhcnNlSnVuaXRYTUwgPSAoKSA9PiB7XG4gICAgY29uc3QgcmVwb3J0UGF0aCA9IHBhdGgucmVzb2x2ZSgnZGlzdC90ZXN0LXJlcG9ydC9URVNULWp1bml0LWp1cGl0ZXIueG1sJylcbiAgICB2YXIgZGF0YSA9IGZzLnJlYWRGaWxlU3luYyhyZXBvcnRQYXRoKVxuICAgIGNvbnN0IHBhcnNlciA9IG5ldyBYTUxQYXJzZXIoKVxuICAgIHZhciByZXN1bHRYbWwgPSBwYXJzZXIucGFyc2UoZGF0YSlcbiAgICByZXN1bHRYbWwudGVzdHN1aXRlLnRlc3RjYXNlID0gQXJyYXkuaXNBcnJheShyZXN1bHRYbWwudGVzdHN1aXRlLnRlc3RjYXNlKSA/IHJlc3VsdFhtbC50ZXN0c3VpdGUudGVzdGNhc2UgOiBbcmVzdWx0WG1sLnRlc3RzdWl0ZS50ZXN0Y2FzZV1cbiAgICByZXR1cm4gcmVzdWx0WG1sLnRlc3RzdWl0ZS50ZXN0Y2FzZVxufVxuXG5jb25zdCBsaXN0RW5kUG9pbnRzID0gKGV4cHJlc3NBcHA6IGFueSk6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nW10gfSA9PiB7XG4gICAgY29uc3QgZGV0YWlscyA9IGxpc3RFeHByZXNzRW5kcG9pbnRzKGV4cHJlc3NBcHApXG4gICAgbGV0IGVuZFBvaW50czogeyBba2V5OiBzdHJpbmddOiBzdHJpbmdbXSB9ID0ge31cbiAgICBkZXRhaWxzLm1hcChhcGlEZXRhaWwgPT4ge1xuICAgICAgICBlbmRQb2ludHNbYXBpRGV0YWlsLnBhdGhdID0gYXBpRGV0YWlsLm1ldGhvZHNcbiAgICB9KVxuICAgIGRlbGV0ZSBlbmRQb2ludHNbJyonXVxuICAgIHJldHVybiBlbmRQb2ludHNcbn1cblxuZnVuY3Rpb24gZXh0cmFjdEVuZFBvaW50cyhleHByZXNzQXBwOiBhbnkpIHtcbiAgICBsZXQgZW5kUG9pbnRzID0gbGlzdEVuZFBvaW50cyhleHByZXNzQXBwKVxuICAgIGxldCBzcHJpbmdBY3R1YXRvclBheWxvYWQgPSB7XG4gICAgICAgIGNvbnRleHRzOiB7XG4gICAgICAgICAgICBhcHBsaWNhdGlvbjoge1xuICAgICAgICAgICAgICAgIG1hcHBpbmdzOiB7XG4gICAgICAgICAgICAgICAgICAgIGRpc3BhdGNoZXJTZXJ2bGV0czoge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGF0Y2hlclNlcnZsZXQ6IFtdLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgIH1cbiAgICBPYmplY3Qua2V5cyhlbmRQb2ludHMpXG4gICAgICAgIC5zb3J0KClcbiAgICAgICAgLm1hcChwYXRoID0+IHtcbiAgICAgICAgICAgIHNwcmluZ0FjdHVhdG9yUGF5bG9hZC5jb250ZXh0cy5hcHBsaWNhdGlvbi5tYXBwaW5ncy5kaXNwYXRjaGVyU2VydmxldHMuZGlzcGF0Y2hlclNlcnZsZXQucHVzaCh7XG4gICAgICAgICAgICAgICAgZGV0YWlsczoge1xuICAgICAgICAgICAgICAgICAgICByZXF1ZXN0TWFwcGluZ0NvbmRpdGlvbnM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZHM6IGVuZFBvaW50c1twYXRoXS5zb3J0KCksXG4gICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuczogW2NvbnZlcnRFbmRwb2ludFRvU3ByaW5nU3ludGF4KHBhdGgpXS5tYXAocmVtb3ZlUmVnZXhGcm9tUGF0aClcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSBhcyBuZXZlcilcbiAgICAgICAgfSlcbiAgICByZXR1cm4gc3ByaW5nQWN0dWF0b3JQYXlsb2FkXG59XG5cbmNvbnN0IGNvbnZlcnRFbmRwb2ludFRvU3ByaW5nU3ludGF4ID0gKHBhdGg6IHN0cmluZykgPT4ge1xuICAgIHJldHVybiBwYXRoLnJlcGxhY2UoLzooW14vXSspL2csICd7JDF9JykucmVwbGFjZSgvXFxcXC9nLCAnJylcbn1cblxuY29uc3QgcmVtb3ZlUmVnZXhGcm9tUGF0aCA9IChwYXRoOiBzdHJpbmcpID0+IHtcbiAgICByZXR1cm4gcGF0aC5yZXBsYWNlKC9cXChbXigpXSpcXCkvZywgJycpXG59XG5cbmV4cG9ydCB7IHN0YXJ0U3R1Yiwgc3RvcFN0dWIsIHRlc3QsIHRlc3RXaXRoQXBpQ292ZXJhZ2UsIHNldEV4cGVjdGF0aW9ucywgc2V0RXhwZWN0YXRpb25Kc29uLCBwcmludEphclZlcnNpb24sIHNob3dUZXN0UmVzdWx0cyB9XG5leHBvcnQgeyBzdGFydEFwaUNvdmVyYWdlU2VydmVyIH1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsSUFBQUEsTUFBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsS0FBQSxHQUFBRixzQkFBQSxDQUFBQyxPQUFBO0FBRUEsSUFBQUUsY0FBQSxHQUFBRixPQUFBO0FBQ0EsSUFBQUcsR0FBQSxHQUFBSixzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUksT0FBQSxHQUFBTCxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUssT0FBQSxHQUFBTCxPQUFBO0FBQ0EsSUFBQU0scUJBQUEsR0FBQVAsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFPLEtBQUEsR0FBQVIsc0JBQUEsQ0FBQUMsT0FBQTtBQUVBLElBQUFRLGNBQUEsR0FBQVIsT0FBQTtBQUFrRCxTQUFBRCx1QkFBQVUsQ0FBQSxXQUFBQSxDQUFBLElBQUFBLENBQUEsQ0FBQUMsVUFBQSxHQUFBRCxDQUFBLGdCQUFBQSxDQUFBO0FBQUEsU0FBQUUsUUFBQUMsQ0FBQSxzQ0FBQUQsT0FBQSx3QkFBQUUsTUFBQSx1QkFBQUEsTUFBQSxDQUFBQyxRQUFBLGFBQUFGLENBQUEsa0JBQUFBLENBQUEsZ0JBQUFBLENBQUEsV0FBQUEsQ0FBQSx5QkFBQUMsTUFBQSxJQUFBRCxDQUFBLENBQUFHLFdBQUEsS0FBQUYsTUFBQSxJQUFBRCxDQUFBLEtBQUFDLE1B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