verdaccio
Version:
A lightweight private npm proxy registry
363 lines (292 loc) • 39.9 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.match = match;
exports.setSecurityWebHeaders = setSecurityWebHeaders;
exports.validateName = validateName;
exports.validatePackage = validatePackage;
exports.media = media;
exports.encodeScopePackage = encodeScopePackage;
exports.expectJson = expectJson;
exports.antiLoop = antiLoop;
exports.allow = allow;
exports.final = final;
exports.log = log;
exports.errorReportingMiddleware = errorReportingMiddleware;
exports.LOG_VERDACCIO_BYTES = exports.LOG_VERDACCIO_ERROR = exports.LOG_STATUS_MESSAGE = void 0;
var _lodash = _interopRequireDefault(require("lodash"));
var _utils = require("../lib/utils");
var _constants = require("../lib/constants");
var _cryptoUtils = require("../lib/crypto-utils");
var _logger = require("../lib/logger");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function match(regexp) {
return function (req, res, next, value) {
if (regexp.exec(value)) {
next();
} else {
next('route');
}
};
}
function setSecurityWebHeaders(req, res, next) {
// disable loading in frames (clickjacking, etc.)
res.header(_constants.HEADERS.FRAMES_OPTIONS, 'deny'); // avoid stablish connections outside of domain
res.header(_constants.HEADERS.CSP, "connect-src 'self'"); // https://stackoverflow.com/questions/18337630/what-is-x-content-type-options-nosniff
res.header(_constants.HEADERS.CTO, 'nosniff'); // https://stackoverflow.com/questions/9090577/what-is-the-http-header-x-xss-protection
res.header(_constants.HEADERS.XSS, '1; mode=block');
next();
} // flow: express does not match properly
// flow info https://github.com/flowtype/flow-typed/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+express
function validateName(req, res, next, value, name) {
if (value === '-') {
// special case in couchdb usually
next('route');
} else if ((0, _utils.validateName)(value)) {
next();
} else {
next(_utils.ErrorCode.getForbidden('invalid ' + name));
}
} // flow: express does not match properly
// flow info https://github.com/flowtype/flow-typed/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+express
function validatePackage(req, res, next, value, name) {
if (value === '-') {
// special case in couchdb usually
next('route');
} else if ((0, _utils.validatePackage)(value)) {
next();
} else {
next(_utils.ErrorCode.getForbidden('invalid ' + name));
}
}
function media(expect) {
return function (req, res, next) {
if (req.headers[_constants.HEADER_TYPE.CONTENT_TYPE] !== expect) {
next(_utils.ErrorCode.getCode(_constants.HTTP_STATUS.UNSUPPORTED_MEDIA, 'wrong content-type, expect: ' + expect + ', got: ' + req.headers[_constants.HEADER_TYPE.CONTENT_TYPE]));
} else {
next();
}
};
}
function encodeScopePackage(req, res, next) {
if (req.url.indexOf('@') !== -1) {
// e.g.: /@org/pkg/1.2.3 -> /@org%2Fpkg/1.2.3, /@org%2Fpkg/1.2.3 -> /@org%2Fpkg/1.2.3
req.url = req.url.replace(/^(\/@[^\/%]+)\/(?!$)/, '$1%2F');
}
next();
}
function expectJson(req, res, next) {
if (!(0, _utils.isObject)(req.body)) {
return next(_utils.ErrorCode.getBadRequest("can't parse incoming json"));
}
next();
}
function antiLoop(config) {
return function (req, res, next) {
if (req.headers.via != null) {
const arr = req.headers.via.split(',');
for (let i = 0; i < arr.length; i++) {
const m = arr[i].match(/\s*(\S+)\s+(\S+)/);
if (m && m[2] === config.server_id) {
return next(_utils.ErrorCode.getCode(_constants.HTTP_STATUS.LOOP_DETECTED, 'loop detected'));
}
}
}
next();
};
}
function allow(auth) {
return function (action) {
return function (req, res, next) {
req.pause();
const packageName = req.params.scope ? `@${req.params.scope}/${req.params.package}` : req.params.package;
const packageVersion = req.params.filename ? (0, _utils.getVersionFromTarball)(req.params.filename) : undefined;
const remote = req.remote_user;
_logger.logger.trace({
action,
user: remote.name
}, `[middleware/allow][@{action}] allow for @{user}`);
auth['allow_' + action]({
packageName,
packageVersion
}, remote, function (error, allowed) {
req.resume();
if (error) {
next(error);
} else if (allowed) {
next();
} else {
// last plugin (that's our built-in one) returns either
// cb(err) or cb(null, true), so this should never happen
throw _utils.ErrorCode.getInternalError(_constants.API_ERROR.PLUGIN_ERROR);
}
});
};
};
}
function final(body, req, res, next) {
if (res.statusCode === _constants.HTTP_STATUS.UNAUTHORIZED && !res.getHeader(_constants.HEADERS.WWW_AUTH)) {
// they say it's required for 401, so...
res.header(_constants.HEADERS.WWW_AUTH, `${_constants.TOKEN_BASIC}, ${_constants.TOKEN_BEARER}`);
}
try {
if (_lodash.default.isString(body) || _lodash.default.isObject(body)) {
if (!res.getHeader(_constants.HEADERS.CONTENT_TYPE)) {
res.header(_constants.HEADERS.CONTENT_TYPE, _constants.HEADERS.JSON);
}
if (typeof body === 'object' && _lodash.default.isNil(body) === false) {
if (typeof body.error === 'string') {
res._verdaccio_error = body.error;
}
body = JSON.stringify(body, undefined, ' ') + '\n';
} // don't send etags with errors
if (!res.statusCode || res.statusCode >= _constants.HTTP_STATUS.OK && res.statusCode < _constants.HTTP_STATUS.MULTIPLE_CHOICES) {
res.header(_constants.HEADERS.ETAG, '"' + (0, _cryptoUtils.stringToMD5)(body) + '"');
}
} else {// send(null), send(204), etc.
}
} catch (err) {
// if verdaccio sends headers first, and then calls res.send()
// as an error handler, we can't report error properly,
// and should just close socket
if (err.message.match(/set headers after they are sent/)) {
if (_lodash.default.isNil(res.socket) === false) {
res.socket.destroy();
}
return;
}
throw err;
}
res.send(body);
}
const LOG_STATUS_MESSAGE = "@{status}, user: @{user}(@{remoteIP}), req: '@{request.method} @{request.url}'";
exports.LOG_STATUS_MESSAGE = LOG_STATUS_MESSAGE;
const LOG_VERDACCIO_ERROR = `${LOG_STATUS_MESSAGE}, error: @{!error}`;
exports.LOG_VERDACCIO_ERROR = LOG_VERDACCIO_ERROR;
const LOG_VERDACCIO_BYTES = `${LOG_STATUS_MESSAGE}, bytes: @{bytes.in}/@{bytes.out}`;
exports.LOG_VERDACCIO_BYTES = LOG_VERDACCIO_BYTES;
function log(config) {
return function (req, res, next) {
var _config$experiments;
// logger
req.log = _logger.logger.child({
sub: 'in'
});
const _auth = req.headers.authorization;
if (_lodash.default.isNil(_auth) === false) {
req.headers.authorization = '<Classified>';
}
const _cookie = req.headers.cookie;
if (_lodash.default.isNil(_cookie) === false) {
req.headers.cookie = '<Classified>';
}
req.url = req.originalUrl; // avoid log noise data from static content
if (req.originalUrl.match(/static/) === null) {
req.log.info({
req: req,
ip: req.ip
}, "@{ip} requested '@{req.method} @{req.url}'");
}
req.originalUrl = req.url;
if (_lodash.default.isNil(_auth) === false) {
req.headers.authorization = _auth;
}
if (_lodash.default.isNil(_cookie) === false) {
req.headers.cookie = _cookie;
}
let bytesin = 0;
if ((config === null || config === void 0 ? void 0 : (_config$experiments = config.experiments) === null || _config$experiments === void 0 ? void 0 : _config$experiments.bytesin_off) !== true) {
req.on('data', function (chunk) {
bytesin += chunk.length;
});
}
let bytesout = 0;
const _write = res.write; // FIXME: res.write should return boolean
// @ts-ignore
res.write = function (buf) {
bytesout += buf.length;
/* eslint prefer-rest-params: "off" */
// @ts-ignore
_write.apply(res, arguments);
};
let logHasBeenCalled = false;
const log = function () {
if (logHasBeenCalled) {
return;
}
logHasBeenCalled = true;
const forwardedFor = req.headers['x-forwarded-for'];
const remoteAddress = req.connection.remoteAddress;
const remoteIP = forwardedFor ? `${forwardedFor} via ${remoteAddress}` : remoteAddress;
let message;
if (res._verdaccio_error) {
message = LOG_VERDACCIO_ERROR;
} else {
message = LOG_VERDACCIO_BYTES;
}
req.url = req.originalUrl; // avoid log noise data from static content
if (req.url.match(/static/) === null) {
req.log.warn({
request: {
method: req.method,
url: req.url
},
level: 35,
// http
user: req.remote_user && req.remote_user.name || null,
remoteIP,
status: res.statusCode,
error: res._verdaccio_error,
bytes: {
in: bytesin,
out: bytesout
}
}, message);
req.originalUrl = req.url;
}
};
req.on('close', function () {
log();
});
const _end = res.end;
res.end = function (buf) {
if (buf) {
bytesout += buf.length;
}
/* eslint prefer-rest-params: "off" */
// @ts-ignore
_end.apply(res, arguments);
log();
};
next();
};
} // Middleware
function errorReportingMiddleware(req, res, next) {
res.report_error = res.report_error || function (err) {
if (err.status && err.status >= _constants.HTTP_STATUS.BAD_REQUEST && err.status < 600) {
if (!res.headersSent) {
res.status(err.status);
next({
error: err.message || _constants.API_ERROR.UNKNOWN_ERROR
});
}
} else {
_logger.logger.error({
err: err
}, 'unexpected error: @{!err.message}\n@{err.stack}');
if (!res.status || !res.send) {
_logger.logger.error('this is an error in express.js, please report this');
res.destroy();
} else if (!res.headersSent) {
res.status(_constants.HTTP_STATUS.INTERNAL_ERROR);
next({
error: _constants.API_ERROR.INTERNAL_SERVER_ERROR
});
} else {// socket should be already closed
}
}
};
next();
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcGkvbWlkZGxld2FyZS50cyJdLCJuYW1lcyI6WyJtYXRjaCIsInJlZ2V4cCIsInJlcSIsInJlcyIsIm5leHQiLCJ2YWx1ZSIsImV4ZWMiLCJzZXRTZWN1cml0eVdlYkhlYWRlcnMiLCJoZWFkZXIiLCJIRUFERVJTIiwiRlJBTUVTX09QVElPTlMiLCJDU1AiLCJDVE8iLCJYU1MiLCJ2YWxpZGF0ZU5hbWUiLCJuYW1lIiwiRXJyb3JDb2RlIiwiZ2V0Rm9yYmlkZGVuIiwidmFsaWRhdGVQYWNrYWdlIiwibWVkaWEiLCJleHBlY3QiLCJoZWFkZXJzIiwiSEVBREVSX1RZUEUiLCJDT05URU5UX1RZUEUiLCJnZXRDb2RlIiwiSFRUUF9TVEFUVVMiLCJVTlNVUFBPUlRFRF9NRURJQSIsImVuY29kZVNjb3BlUGFja2FnZSIsInVybCIsImluZGV4T2YiLCJyZXBsYWNlIiwiZXhwZWN0SnNvbiIsImJvZHkiLCJnZXRCYWRSZXF1ZXN0IiwiYW50aUxvb3AiLCJjb25maWciLCJ2aWEiLCJhcnIiLCJzcGxpdCIsImkiLCJsZW5ndGgiLCJtIiwic2VydmVyX2lkIiwiTE9PUF9ERVRFQ1RFRCIsImFsbG93IiwiYXV0aCIsImFjdGlvbiIsInBhdXNlIiwicGFja2FnZU5hbWUiLCJwYXJhbXMiLCJzY29wZSIsInBhY2thZ2UiLCJwYWNrYWdlVmVyc2lvbiIsImZpbGVuYW1lIiwidW5kZWZpbmVkIiwicmVtb3RlIiwicmVtb3RlX3VzZXIiLCJsb2dnZXIiLCJ0cmFjZSIsInVzZXIiLCJlcnJvciIsImFsbG93ZWQiLCJyZXN1bWUiLCJnZXRJbnRlcm5hbEVycm9yIiwiQVBJX0VSUk9SIiwiUExVR0lOX0VSUk9SIiwiZmluYWwiLCJzdGF0dXNDb2RlIiwiVU5BVVRIT1JJWkVEIiwiZ2V0SGVhZGVyIiwiV1dXX0FVVEgiLCJUT0tFTl9CQVNJQyIsIlRPS0VOX0JFQVJFUiIsIl8iLCJpc1N0cmluZyIsImlzT2JqZWN0IiwiSlNPTiIsImlzTmlsIiwiX3ZlcmRhY2Npb19lcnJvciIsInN0cmluZ2lmeSIsIk9LIiwiTVVMVElQTEVfQ0hPSUNFUyIsIkVUQUciLCJlcnIiLCJtZXNzYWdlIiwic29ja2V0IiwiZGVzdHJveSIsInNlbmQiLCJMT0dfU1RBVFVTX01FU1NBR0UiLCJMT0dfVkVSREFDQ0lPX0VSUk9SIiwiTE9HX1ZFUkRBQ0NJT19CWVRFUyIsImxvZyIsImNoaWxkIiwic3ViIiwiX2F1dGgiLCJhdXRob3JpemF0aW9uIiwiX2Nvb2tpZSIsImNvb2tpZSIsIm9yaWdpbmFsVXJsIiwiaW5mbyIsImlwIiwiYnl0ZXNpbiIsImV4cGVyaW1lbnRzIiwiYnl0ZXNpbl9vZmYiLCJvbiIsImNodW5rIiwiYnl0ZXNvdXQiLCJfd3JpdGUiLCJ3cml0ZSIsImJ1ZiIsImFwcGx5IiwiYXJndW1lbnRzIiwibG9nSGFzQmVlbkNhbGxlZCIsImZvcndhcmRlZEZvciIsInJlbW90ZUFkZHJlc3MiLCJjb25uZWN0aW9uIiwicmVtb3RlSVAiLCJ3YXJuIiwicmVxdWVzdCIsIm1ldGhvZCIsImxldmVsIiwic3RhdHVzIiwiYnl0ZXMiLCJpbiIsIm91dCIsIl9lbmQiLCJlbmQiLCJlcnJvclJlcG9ydGluZ01pZGRsZXdhcmUiLCJyZXBvcnRfZXJyb3IiLCJCQURfUkVRVUVTVCIsImhlYWRlcnNTZW50IiwiVU5LTk9XTl9FUlJPUiIsIklOVEVSTkFMX0VSUk9SIiwiSU5URVJOQUxfU0VSVkVSX0VSUk9SIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7O0FBSUE7O0FBT0E7O0FBUUE7O0FBRUE7Ozs7QUFFTyxTQUFTQSxLQUFULENBQWVDLE1BQWYsRUFBb0M7QUFDekMsU0FBTyxVQUNMQyxHQURLLEVBRUxDLEdBRkssRUFHTEMsSUFISyxFQUlMQyxLQUpLLEVBS0M7QUFDTixRQUFJSixNQUFNLENBQUNLLElBQVAsQ0FBWUQsS0FBWixDQUFKLEVBQXdCO0FBQ3RCRCxNQUFBQSxJQUFJO0FBQ0wsS0FGRCxNQUVPO0FBQ0xBLE1BQUFBLElBQUksQ0FBQyxPQUFELENBQUo7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QUFDNkgsWUFBSixJQUNBLFVBQVU3QyxHQUFWLEVBQXFDO0FBQ25DLFFBQUlBLEdBQUcsQ0FBQ3NDLE1BQUosSUFBY3RDLEdBQUcsQ0FBQ3NDLE1BQUosSUFBY2hHLHVCQUFZd0csV0FBeEMsSUFBdUQ5QyxHQUFHLENBQUNzQyxNQUFKLEdBQWEsR0FBeEUsRUFBNkU7QUFDM0UsVUFBSSxDQUFDdEgsR0FBRyxDQUFDK0gsV0FBVCxFQUFzQjtBQUNwQi9ILFFBQUFBLEdBQUcsQ0FBQ3NILE1BQUosQ0FBV3RDLEdBQUcsQ0FBQ3NDLE1BQWY7QUFDQXJILFFBQUFBLElBQUksQ0FBQztBQUFFd0QsVUFBQUEsS0FBSyxFQUFFdUIsR0FBRyxDQUFDQyxPQUFKLElBQWVwQixxQkFBVW1FO0FBQWxDLFNBQUQsQ0FBSjtBQUNEO0FBQ0YsS0FMRCxNQUtPO0FBQ0wxRSxxQkFBT0csS0FBUCxDQUFhO0FBQUV1QixRQUFBQSxHQUFHLEVBQUVBO0FBQVAsT0FBYixFQUEyQixpREFBM0I7O0FBQ0EsVUFBSSxDQUFDaEYsR0FBRyxDQUFDc0gsTUFBTCxJQUFlLENBQUN0SCxHQUFHLENBQUNvRixJQUF4QixFQUE4QjtBQUM1QjlCLHVCQUFPRyxLQUFQLENBQWEsb0RBQWI7O0FBQ0F6RCxRQUFBQSxHQUFHLENBQUNtRixPQUFKO0FBQ0QsT0FIRCxNQUdPLElBQUksQ0FBQ25GLEdBQUcsQ0FBQytILFdBQVQsRUFBc0I7QUFDM0IvSCxRQUFBQSxHQUFHLENBQUNzSCxNQUFKLENBQVdoRyx1QkFBWTJHLGNBQXZCO0FBQ0FoSSxRQUFBQSxJQUFJLENBQUM7QUFBRXdELFVBQUFBLEtBQUssRUFBRUkscUJBQVVxRTtBQUFuQixTQUFELENBQUo7QUFDRCxPQUhNLE1BR0EsQ0FDTDtBQUNEO0FBQ0Y7QUFDRixHQXBCSDs7QUFzQkFqSSxFQUFBQSxJQUFJO0FBQ0wiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuXG5pbXBvcnQgeyBDb25maWcsIFBhY2thZ2UsIFJlbW90ZVVzZXIgfSBmcm9tICdAdmVyZGFjY2lvL3R5cGVzJztcbmltcG9ydCB7IFZlcmRhY2Npb0Vycm9yIH0gZnJvbSAnQHZlcmRhY2Npby9jb21tb25zLWFwaSc7XG5pbXBvcnQge1xuICB2YWxpZGF0ZU5hbWUgYXMgdXRpbFZhbGlkYXRlTmFtZSxcbiAgdmFsaWRhdGVQYWNrYWdlIGFzIHV0aWxWYWxpZGF0ZVBhY2thZ2UsXG4gIGdldFZlcnNpb25Gcm9tVGFyYmFsbCxcbiAgaXNPYmplY3QsXG4gIEVycm9yQ29kZVxufSBmcm9tICcuLi9saWIvdXRpbHMnO1xuaW1wb3J0IHtcbiAgQVBJX0VSUk9SLFxuICBIRUFERVJfVFlQRSxcbiAgSEVBREVSUyxcbiAgSFRUUF9TVEFUVVMsXG4gIFRPS0VOX0JBU0lDLFxuICBUT0tFTl9CRUFSRVJcbn0gZnJvbSAnLi4vbGliL2NvbnN0YW50cyc7XG5pbXBvcnQgeyBzdHJpbmdUb01ENSB9IGZyb20gJy4uL2xpYi9jcnlwdG8tdXRpbHMnO1xuaW1wb3J0IHsgJFJlc3BvbnNlRXh0ZW5kLCAkUmVxdWVzdEV4dGVuZCwgJE5leHRGdW5jdGlvblZlciwgSUF1dGggfSBmcm9tICcuLi8uLi90eXBlcyc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi9saWIvbG9nZ2VyJztcblxuZXhwb3J0IGZ1bmN0aW9uIG1hdGNoKHJlZ2V4cDogUmVnRXhwKTogYW55IHtcbiAgcmV0dXJuIGZ1bmN0aW9uIChcbiAgICByZXE6ICRSZXF1ZXN0RXh0ZW5kLFxuICAgIHJlczogJFJlc3BvbnNlRXh0ZW5kLFxuICAgIG5leHQ6ICROZXh0RnVuY3Rpb25WZXIsXG4gICAgdmFsdWU6IHN0cmluZ1xuICApOiB2b2lkIHtcbiAgICBpZiAocmVnZXhwLmV4ZWModmFsdWUpKSB7XG4gICAgICBuZXh0KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIG5leHQoJ3JvdXRlJyk7XG4gICAgfVxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc2V0U2VjdXJpdHlXZWJIZWFkZXJzKFxuICByZXE6ICRSZXF1ZXN0RXh0ZW5kLFxuICByZXM6ICRSZXNwb25zZUV4dGVuZCxcbiAgbmV4dDogJE5leHRGdW5jdGlvblZlclxuKTogdm9pZCB7XG4gIC8vIGRpc2FibGUgbG9hZGluZyBpbiBmcmFtZXMgKGNsaWNramFja2luZywgZXRjLilcbiAgcmVzLmhlYWRlcihIRUFERVJTLkZSQU1FU19PUFRJT05TLCAnZGVueScpO1xuICAvLyBhdm9pZCBzdGFibGlzaCBjb25uZWN0aW9ucyBvdXRzaWRlIG9mIGRvbWFpblxuICByZXMuaGVhZGVyKEhFQURFUlMuQ1NQLCBcImNvbm5lY3Qtc3JjICdzZWxmJ1wiKTtcbiAgLy8gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTgzMzc2MzAvd2hhdC1pcy14LWNvbnRlbnQtdHlwZS1vcHRpb25zLW5vc25pZmZcbiAgcmVzLmhlYWRlcihIRUFERVJTLkNUTywgJ25vc25pZmYnKTtcbiAgLy8gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvOTA5MDU3Ny93aGF0LWlzLXRoZS1odHRwLWhlYWRlci14LXhzcy1wcm90ZWN0aW9uXG4gIHJlcy5oZWFkZXIoSEVBREVSUy5YU1MsICcxOyBtb2RlPWJsb2NrJyk7XG4gIG5leHQoKTtcbn1cblxuLy8gZmxvdzogZXhwcmVzcyBkb2VzIG5vdCBtYXRjaCBwcm9wZXJseVxuLy8gZmxvdyBpbmZvIGh0dHBzOi8vZ2l0aHViLmNvbS9mbG93dHlwZS9mbG93LXR5cGVkL2lzc3Vlcz91dGY4PSVFMiU5QyU5MyZxPWlzJTNBaXNzdWUraXMlM0FvcGVuK2V4cHJlc3NcbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZU5hbWUoXG4gIHJlcTogJFJlcXVlc3RFeHRlbmQsXG4gIHJlczogJFJlc3BvbnNlRXh0ZW5kLFxuICBuZXh0OiAkTmV4dEZ1bmN0aW9uVmVyLFxuICB2YWx1ZTogc3RyaW5nLFxuICBuYW1lOiBzdHJpbmdcbik6IHZvaWQge1xuICBpZiAodmFsdWUgPT09ICctJykge1xuICAgIC8vIHNwZWNpYWwgY2FzZSBpbiBjb3VjaGRiIHVzdWFsbHlcbiAgICBuZXh0KCdyb3V0ZScpO1xuICB9IGVsc2UgaWYgKHV0aWxWYWxpZGF0ZU5hbWUodmFsdWUpKSB7XG4gICAgbmV4dCgpO1xuICB9IGVsc2Uge1xuICAgIG5leHQoRXJyb3JDb2RlLmdldEZvcmJpZGRlbignaW52YWxpZCAnICsgbmFtZSkpO1xuICB9XG59XG5cbi8vIGZsb3c6IGV4cHJlc3MgZG9lcyBub3QgbWF0Y2ggcHJvcGVybHlcbi8vIGZsb3cgaW5mbyBodHRwczovL2dpdGh1Yi5jb20vZmxvd3R5cGUvZmxvdy10eXBlZC9pc3N1ZXM/dXRmOD0lRTIlOUMlOTMmcT1pcyUzQWlzc3VlK2lzJTNBb3BlbitleHByZXNzXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVQYWNrYWdlKFxuICByZXE6ICRSZXF1ZXN0RXh0ZW5kLFxuICByZXM6ICRSZXNwb25zZUV4dGVuZCxcbiAgbmV4dDogJE5leHRGdW5jdGlvblZlcixcbiAgdmFsdWU6IHN0cmluZyxcbiAgbmFtZTogc3RyaW5nXG4pOiB2b2lkIHtcbiAgaWYgKHZhbHVlID09PSAnLScpIHtcbiAgICAvLyBzcGVjaWFsIGNhc2UgaW4gY291Y2hkYiB1c3VhbGx5XG4gICAgbmV4dCgncm91dGUnKTtcbiAgfSBlbHNlIGlmICh1dGlsVmFsaWRhdGVQYWNrYWdlKHZhbHVlKSkge1xuICAgIG5leHQoKTtcbiAgfSBlbHNlIHtcbiAgICBuZXh0KEVycm9yQ29kZS5nZXRGb3JiaWRkZW4oJ2ludmFsaWQgJyArIG5hbWUpKTtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gbWVkaWEoZXhwZWN0OiBzdHJpbmcgfCBudWxsKTogYW55IHtcbiAgcmV0dXJuIGZ1bmN0aW9uIChyZXE6ICRSZXF1ZXN0RXh0ZW5kLCByZXM6ICRSZXNwb25zZUV4dGVuZCwgbmV4dDogJE5leHRGdW5jdGlvblZlcik6IHZvaWQge1xuICAgIGlmIChyZXEuaGVhZGVyc1tIRUFERVJfVFlQRS5DT05URU5UX1RZUEVdICE9PSBleHBlY3QpIHtcbiAgICAgIG5leHQoXG4gICAgICAgIEVycm9yQ29kZS5nZXRDb2RlKFxuICAgICAgICAgIEhUVFBfU1RBVFVTLlVOU1VQUE9SVEVEX01FRElBLFxuICAgICAgICAgICd3cm9uZyBjb250ZW50LXR5cGUsIGV4cGVjdDogJyArXG4gICAgICAgICAgICBleHBlY3QgK1xuICAgICAgICAgICAgJywgZ290OiAnICtcbiAgICAgICAgICAgIHJlcS5oZWFkZXJzW0hFQURFUl9UWVBFLkNPTlRFTlRfVFlQRV1cbiAgICAgICAgKVxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgbmV4dCgpO1xuICAgIH1cbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGVuY29kZVNjb3BlUGFja2FnZShcbiAgcmVxOiAkUmVxdWVzdEV4dGVuZCxcbiAgcmVzOiAkUmVzcG9uc2VFeHRlbmQsXG4gIG5leHQ6ICROZXh0RnVuY3Rpb25WZXJcbik6IHZvaWQge1xuICBpZiAocmVxLnVybC5pbmRleE9mKCdAJykgIT09IC0xKSB7XG4gICAgLy8gZS5nLjogL0BvcmcvcGtnLzEuMi4zIC0+IC9Ab3JnJTJGcGtnLzEuMi4zLCAvQG9yZyUyRnBrZy8xLjIuMyAtPiAvQG9yZyUyRnBrZy8xLjIuM1xuICAgIHJlcS51cmwgPSByZXEudXJsLnJlcGxhY2UoL14oXFwvQFteXFwvJV0rKVxcLyg/ISQpLywgJyQxJTJGJyk7XG4gIH1cbiAgbmV4dCgpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZXhwZWN0SnNvbihcbiAgcmVxOiAkUmVxdWVzdEV4dGVuZCxcbiAgcmVzOiAkUmVzcG9uc2VFeHRlbmQsXG4gIG5leHQ6ICROZXh0RnVuY3Rpb25WZXJcbik6IHZvaWQge1xuICBpZiAoIWlzT2JqZWN0KHJlcS5ib2R5KSkge1xuICAgIHJldHVybiBuZXh0KEVycm9yQ29kZS5nZXRCYWRSZXF1ZXN0KFwiY2FuJ3QgcGFyc2UgaW5jb21pbmcganNvblwiKSk7XG4gIH1cbiAgbmV4dCgpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gYW50aUxvb3AoY29uZmlnOiBDb25maWcpOiBGdW5jdGlvbiB7XG4gIHJldHVybiBmdW5jdGlvbiAocmVxOiAkUmVxdWVzdEV4dGVuZCwgcmVzOiAkUmVzcG9uc2VFeHRlbmQsIG5leHQ6ICROZXh0RnVuY3Rpb25WZXIpOiB2b2lkIHtcbiAgICBpZiAocmVxLmhlYWRlcnMudmlhICE9IG51bGwpIHtcbiAgICAgIGNvbnN0IGFyciA9IHJlcS5oZWFkZXJzLnZpYS5zcGxpdCgnLCcpO1xuXG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGFyci5sZW5ndGg7IGkrKykge1xuICAgICAgICBjb25zdCBtID0gYXJyW2ldLm1hdGNoKC9cXHMqKFxcUyspXFxzKyhcXFMrKS8pO1xuICAgICAgICBpZiAobSAmJiBtWzJdID09PSBjb25maWcuc2VydmVyX2lkKSB7XG4gICAgICAgICAgcmV0dXJuIG5leHQoRXJyb3JDb2RlLmdldENvZGUoSFRUUF9TVEFUVVMuTE9PUF9ERVRFQ1RFRCwgJ2xvb3AgZGV0ZWN0ZWQnKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgbmV4dCgpO1xuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gYWxsb3coYXV0aDogSUF1dGgpOiBGdW5jdGlvbiB7XG4gIHJldHVybiBmdW5jdGlvbiAoYWN0aW9uOiBzdHJpbmcpOiBGdW5jdGlvbiB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uIChyZXE6ICRSZXF1ZXN0RXh0ZW5kLCByZXM6ICRSZXNwb25zZUV4dGVuZCwgbmV4dDogJE5leHRGdW5jdGlvblZlcik6IHZvaWQge1xuICAgICAgcmVxLnBhdXNlKCk7XG4gICAgICBjb25zdCBwYWNrYWdlTmFtZSA9IHJlcS5wYXJhbXMuc2NvcGVcbiAgICAgICAgPyBgQCR7cmVxLnBhcmFtcy5zY29wZX0vJHtyZXEucGFyYW1zLnBhY2thZ2V9YFxuICAgICAgICA6IHJlcS5wYXJhbXMucGFja2FnZTtcbiAgICAgIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gcmVxLnBhcmFtcy5maWxlbmFtZVxuICAgICAgICA/IGdldFZlcnNpb25Gcm9tVGFyYmFsbChyZXEucGFyYW1zLmZpbGVuYW1lKVxuICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICAgIGNvbnN0IHJlbW90ZTogUmVtb3RlVXNlciA9IHJlcS5yZW1vdGVfdXNlcjtcbiAgICAgIGxvZ2dlci50cmFjZShcbiAgICAgICAgeyBhY3Rpb24sIHVzZXI6IHJlbW90ZS5uYW1lIH0sXG4gICAgICAgIGBbbWlkZGxld2FyZS9hbGxvd11bQHthY3Rpb259XSBhbGxvdyBmb3IgQHt1c2VyfWBcbiAgICAgICk7XG5cbiAgICAgIGF1dGhbJ2FsbG93XycgKyBhY3Rpb25dKFxuICAgICAgICB7IHBhY2thZ2VOYW1lLCBwYWNrYWdlVmVyc2lvbiB9LFxuICAgICAgICByZW1vdGUsXG4gICAgICAgIGZ1bmN0aW9uIChlcnJvciwgYWxsb3dlZCk6IHZvaWQge1xuICAgICAgICAgIHJlcS5yZXN1bWUoKTtcbiAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgIG5leHQoZXJyb3IpO1xuICAgICAgICAgIH0gZWxzZSBpZiAoYWxsb3dlZCkge1xuICAgICAgICAgICAgbmV4dCgpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBsYXN0IHBsdWdpbiAodGhhdCdzIG91ciBidWlsdC1pbiBvbmUpIHJldHVybnMgZWl0aGVyXG4gICAgICAgICAgICAvLyBjYihlcnIpIG9yIGNiKG51bGwsIHRydWUpLCBzbyB0aGlzIHNob3VsZCBuZXZlciBoYXBwZW5cbiAgICAgICAgICAgIHRocm93IEVycm9yQ29kZS5nZXRJbnRlcm5hbEVycm9yKEFQSV9FUlJPUi5QTFVHSU5fRVJST1IpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgKTtcbiAgICB9O1xuICB9O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE1pZGRsZXdhcmVFcnJvciB7XG4gIGVycm9yOiBzdHJpbmc7XG59XG5cbmV4cG9ydCB0eXBlIEZpbmFsQm9keSA9IFBhY2thZ2UgfCBNaWRkbGV3YXJlRXJyb3IgfCBzdHJpbmc7XG5cbmV4cG9ydCBmdW5jdGlvbiBmaW5hbChcbiAgYm9keTogRmluYWxCb2R5LFxuICByZXE6ICRSZXF1ZXN0RXh0ZW5kLFxuICByZXM6ICRSZXNwb25zZUV4dGVuZCxcbiAgbmV4dDogJE5leHRGdW5jdGlvblZlclxuKTogdm9pZCB7XG4gIGlmIChyZXMuc3RhdHVzQ29kZSA9PT0gSFRUUF9TVEFUVVMuVU5BVVRIT1JJWkVEICYmICFyZXMuZ2V0SGVhZGVyKEhFQURFUlMuV1dXX0FVVEgpKSB7XG4gICAgLy8gdGhleSBzYXkgaXQncyByZXF1aXJlZCBmb3IgNDAxLCBzby4uLlxuICAgIHJlcy5oZWFkZXIoSEVBREVSUy5XV1dfQVVUSCwgYCR7VE9LRU5fQkFTSUN9LCAke1RPS0VOX0JFQVJFUn1gKTtcbiAgfVxuXG4gIHRyeSB7XG4gICAgaWYgKF8uaXNTdHJpbmcoYm9keSkgfHwgXy5pc09iamVjdChib2R5KSkge1xuICAgICAgaWYgKCFyZXMuZ2V0SGVhZGVyKEhFQURFUlMuQ09OVEVOVF9UWVBFKSkge1xuICAgICAgICByZXMuaGVhZGVyKEhFQURFUlMuQ09OVEVOVF9UWVBFLCBIRUFERVJTLkpTT04pO1xuICAgICAgfVxuXG4gICAgICBpZiAodHlwZW9mIGJvZHkgPT09ICdvYmplY3QnICYmIF8uaXNOaWwoYm9keSkgPT09IGZhbHNlKSB7XG4gICAgICAgIGlmICh0eXBlb2YgKGJvZHkgYXMgTWlkZGxld2FyZUVycm9yKS5lcnJvciA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICByZXMuX3ZlcmRhY2Npb19lcnJvciA9IChib2R5IGFzIE1pZGRsZXdhcmVFcnJvcikuZXJyb3I7XG4gICAgICAgIH1cbiAgICAgICAgYm9keSA9IEpTT04uc3RyaW5naWZ5KGJvZHksIHVuZGVmaW5lZCwgJyAgJykgKyAnXFxuJztcbiAgICAgIH1cblxuICAgICAgLy8gZG9uJ3Qgc2VuZCBldGFncyB3aXRoIGVycm9yc1xuICAgICAgaWYgKFxuICAgICAgICAhcmVzLnN0YXR1c0NvZGUgfHxcbiAgICAgICAgKHJlcy5zdGF0dXNDb2RlID49IEhUVFBfU1RBVFVTLk9LICYmIHJlcy5zdGF0dXNDb2RlIDwgSFRUUF9TVEFUVVMuTVVMVElQTEVfQ0hPSUNFUylcbiAgICAgICkge1xuICAgICAgICByZXMuaGVhZGVyKEhFQURFUlMuRVRBRywgJ1wiJyArIHN0cmluZ1RvTUQ1KGJvZHkgYXMgc3RyaW5nKSArICdcIicpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBzZW5kKG51bGwpLCBzZW5kKDIwNCksIGV0Yy5cbiAgICB9XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIC8vIGlmIHZlcmRhY2NpbyBzZW5kcyBoZWFkZXJzIGZpcnN0LCBhbmQgdGhlbiBjYWxscyByZXMuc2VuZCgpXG4gICAgLy8gYXMgYW4gZXJyb3IgaGFuZGxlciwgd2UgY2FuJ3QgcmVwb3J0IGVycm9yIHByb3Blcmx5LFxuICAgIC8vIGFuZCBzaG91bGQganVzdCBjbG9zZSBzb2NrZXRcbiAgICBpZiAoZXJyLm1lc3NhZ2UubWF0Y2goL3NldCBoZWFkZXJzIGFmdGVyIHRoZXkgYXJlIHNlbnQvKSkge1xuICAgICAgaWYgKF8uaXNOaWwocmVzLnNvY2tldCkgPT09IGZhbHNlKSB7XG4gICAgICAgIHJlcy5zb2NrZXQuZGVzdHJveSgpO1xuICAgICAgfVxuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aHJvdyBlcnI7XG4gIH1cblxuICByZXMuc2VuZChib2R5KTtcbn1cblxuZXhwb3J0IGNvbnN0IExPR19TVEFUVVNfTUVTU0FHRSA9XG4gIFwiQHtzdGF0dXN9LCB1c2VyOiBAe3VzZXJ9KEB7cmVtb3RlSVB9KSwgcmVxOiAnQHtyZXF1ZXN0Lm1ldGhvZH0gQHtyZXF1ZXN0LnVybH0nXCI7XG5leHBvcnQgY29uc3QgTE9HX1ZFUkRBQ0NJT19FUlJPUiA9IGAke0xPR19TVEFUVVNfTUVTU0FHRX0sIGVycm9yOiBAeyFlcnJvcn1gO1xuZXhwb3J0IGNvbnN0IExPR19WRVJEQUNDSU9fQllURVMgPSBgJHtMT0dfU1RBVFVTX01FU1NBR0V9LCBieXRlczogQHtieXRlcy5pbn0vQHtieXRlcy5vdXR9YDtcblxuZXhwb3J0IGZ1bmN0aW9uIGxvZyhjb25maWc6IENvbmZpZykge1xuICByZXR1cm4gZnVuY3Rpb24gKHJlcTogJFJlcXVlc3RFeHRlbmQsIHJlczogJFJlc3BvbnNlRXh0ZW5kLCBuZXh0OiAkTmV4dEZ1bmN0aW9uVmVyKTogdm9pZCB7XG4gICAgLy8gbG9nZ2VyXG4gICAgcmVxLmxvZyA9IGxvZ2dlci5jaGlsZCh7IHN1YjogJ2luJyB9KTtcblxuICAgIGNvbnN0IF9hdXRoID0gcmVxLmhlYWRlcnMuYXV0aG9yaXphdGlvbjtcbiAgICBpZiAoXy5pc05pbChfYXV0aCkgPT09IGZhbHNlKSB7XG4gICAgICByZXEuaGVhZGVycy5hdXRob3JpemF0aW9uID0gJzxDbGFzc2lmaWVkPic7XG4gICAgfVxuXG4gICAgY29uc3QgX2Nvb2tpZSA9IHJlcS5oZWFkZXJzLmNvb2tpZTtcbiAgICBpZiAoXy5pc05pbChfY29va2llKSA9PT0gZmFsc2UpIHtcbiAgICAgIHJlcS5oZWFkZXJzLmNvb2tpZSA9ICc8Q2xhc3NpZmllZD4nO1xuICAgIH1cblxuICAgIHJlcS51cmwgPSByZXEub3JpZ2luYWxVcmw7XG4gICAgLy8gYXZvaWQgbG9nIG5vaXNlIGRhdGEgZnJvbSBzdGF0aWMgY29udGVudFxuICAgIGlmIChyZXEub3JpZ2luYWxVcmwubWF0Y2goL3N0YXRpYy8pID09PSBudWxsKSB7XG4gICAgICByZXEubG9nLmluZm8oeyByZXE6IHJlcSwgaXA6IHJlcS5pcCB9LCBcIkB7aXB9IHJlcXVlc3RlZCAnQHtyZXEubWV0aG9kfSBAe3JlcS51cmx9J1wiKTtcbiAgICB9XG4gICAgcmVxLm9yaWdpbmFsVXJsID0gcmVxLnVybDtcblxuICAgIGlmIChfLmlzTmlsKF9hdXRoKSA9PT0gZmFsc2UpIHtcbiAgICAgIHJlcS5oZWFkZXJzLmF1dGhvcml6YXRpb24gPSBfYXV0aDtcbiAgICB9XG5cbiAgICBpZiAoXy5pc05pbChfY29va2llKSA9PT0gZmFsc2UpIHtcbiAgICAgIHJlcS5oZWFkZXJzLmNvb2tpZSA9IF9jb29raWU7XG4gICAgfVxuXG4gICAgbGV0IGJ5dGVzaW4gPSAwO1xuICAgIGlmIChjb25maWc/LmV4cGVyaW1lbnRzPy5ieXRlc2luX29mZiAhPT0gdHJ1ZSkge1xuICAgICAgcmVxLm9uKCdkYXRhJywgZnVuY3Rpb24gKGNodW5rKTogdm9pZCB7XG4gICAgICAgIGJ5dGVzaW4gKz0gY2h1bmsubGVuZ3RoO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgbGV0IGJ5dGVzb3V0ID0gMDtcbiAgICBjb25zdCBfd3JpdGUgPSByZXMud3JpdGU7XG4gICAgLy8gRklYTUU6IHJlcy53cml0ZSBzaG91bGQgcmV0dXJuIGJvb2xlYW5cbiAgICAvLyBAdHMtaWdub3JlXG4gICAgcmVzLndyaXRlID0gZnVuY3Rpb24gKGJ1Zik6IGJvb2xlYW4ge1xuICAgICAgYnl0ZXNvdXQgKz0gYnVmLmxlbmd0aDtcbiAgICAgIC8qIGVzbGludCBwcmVmZXItcmVzdC1wYXJhbXM6IFwib2ZmXCIgKi9cbiAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgIF93cml0ZS5hcHBseShyZXMsIGFyZ3VtZW50cyk7XG4gICAgfTtcblxuICAgIGxldCBsb2dIYXNCZWVuQ2FsbGVkID0gZmFsc2U7XG4gICAgY29uc3QgbG9nID0gZnVuY3Rpb24gKCk6IHZvaWQge1xuICAgICAgaWYgKGxvZ0hhc0JlZW5DYWxsZWQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgbG9nSGFzQmVlbkNhbGxlZCA9IHRydWU7XG5cbiAgICAgIGNvbnN0IGZvcndhcmRlZEZvciA9IHJlcS5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXTtcbiAgICAgIGNvbnN0IHJlbW90ZUFkZHJlc3MgPSByZXEuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzO1xuICAgICAgY29uc3QgcmVtb3RlSVAgPSBmb3J3YXJkZWRGb3IgPyBgJHtmb3J3YXJkZWRGb3J9IHZpYSAke3JlbW90ZUFkZHJlc3N9YCA6IHJlbW90ZUFkZHJlc3M7XG4gICAgICBsZXQgbWVzc2FnZTtcbiAgICAgIGlmIChyZXMuX3ZlcmRhY2Npb19lcnJvcikge1xuICAgICAgICBtZXNzYWdlID0gTE9HX1ZFUkRBQ0NJT19FUlJPUjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG1lc3NhZ2UgPSBMT0dfVkVSREFDQ0lPX0JZVEVTO1xuICAgICAgfVxuXG4gICAgICByZXEudXJsID0gcmVxLm9yaWdpbmFsVXJsO1xuICAgICAgLy8gYXZvaWQgbG9nIG5vaXNlIGRhdGEgZnJvbSBzdGF0aWMgY29udGVudFxuICAgICAgaWYgKHJlcS51cmwubWF0Y2goL3N0YXRpYy8pID09PSBudWxsKSB7XG4gICAgICAgIHJlcS5sb2cud2FybihcbiAgICAgICAgICB7XG4gICAgICAgICAgICByZXF1ZXN0OiB7XG4gICAgICAgICAgICAgIG1ldGhvZDogcmVxLm1ldGhvZCxcbiAgICAgICAgICAgICAgdXJsOiByZXEudXJsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbGV2ZWw6IDM1LCAvLyBodHRwXG4gICAgICAgICAgICB1c2VyOiAocmVxLnJlbW90ZV91c2VyICYmIHJlcS5yZW1vdGVfdXNlci5uYW1lKSB8fCBudWxsLFxuICAgICAgICAgICAgcmVtb3RlSVAsXG4gICAgICAgICAgICBzdGF0dXM6IHJlcy5zdGF0dXNDb2RlLFxuICAgICAgICAgICAgZXJyb3I6IHJlcy5fdmVyZGFjY2lvX2Vycm9yLFxuICAgICAgICAgICAgYnl0ZXM6IHtcbiAgICAgICAgICAgICAgaW46IGJ5dGVzaW4sXG4gICAgICAgICAgICAgIG91dDogYnl0ZXNvdXRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIG1lc3NhZ2VcbiAgICAgICAgKTtcbiAgICAgICAgcmVxLm9yaWdpbmFsVXJsID0gcmVxLnVybDtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgcmVxLm9uKCdjbG9zZScsIGZ1bmN0aW9uICgpOiB2b2lkIHtcbiAgICAgIGxvZygpO1xuICAgIH0pO1xuXG4gICAgY29uc3QgX2VuZCA9IHJlcy5lbmQ7XG4gICAgcmVzLmVuZCA9IGZ1bmN0aW9uIChidWYpOiB2b2lkIHtcbiAgICAgIGlmIChidWYpIHtcbiAgICAgICAgYnl0ZXNvdXQgKz0gYnVmLmxlbmd0aDtcbiAgICAgIH1cbiAgICAgIC8qIGVzbGludCBwcmVmZXItcmVzdC1wYXJhbXM6IFwib2ZmXCIgKi9cbiAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgIF9lbmQuYXBwbHkocmVzLCBhcmd1bWVudHMpO1xuICAgICAgbG9nKCk7XG4gICAgfTtcbiAgICBuZXh0KCk7XG4gIH07XG59XG5cbi8vIE1pZGRsZXdhcmVcbmV4cG9ydCBmdW5jdGlvbiBlcnJvclJlcG9ydGluZ01pZGRsZXdhcmUoXG4gIHJlcTogJFJlcXVlc3RFeHRlbmQsXG4gIHJlczogJFJlc3BvbnNlRXh0ZW5kLFxuICBuZXh0OiAkTmV4dEZ1bmN0aW9uVmVyXG4pOiB2b2lkIHtcbiAgcmVzLnJlcG9ydF9lcnJvciA9XG4gICAgcmVzLnJlcG9ydF9lcnJvciB8fFxuICAgIGZ1bmN0aW9uIChlcnI6IFZlcmRhY2Npb0Vycm9yKTogdm9pZCB7XG4gICAgICBpZiAoZXJyLnN0YXR1cyAmJiBlcnIuc3RhdHVzID49IEhUVFBfU1RBVFVTLkJBRF9SRVFVRVNUICYmIGVyci5zdGF0dXMgPCA2MDApIHtcbiAgICAgICAgaWYgKCFyZXMuaGVhZGVyc1NlbnQpIHtcbiAgICAgICAgICByZXMuc3RhdHVzKGVyci5zdGF0dXMpO1xuICAgICAgICAgIG5leHQoeyBlcnJvcjogZXJyLm1lc3NhZ2UgfHwgQVBJX0VSUk9SLlVOS05PV05fRVJST1IgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxvZ2dlci5lcnJvcih7IGVycjogZXJyIH0sICd1bmV4cGVjdGVkIGVycm9yOiBAeyFlcnIubWVzc2FnZX1cXG5Ae2Vyci5zdGFja30nKTtcbiAgICAgICAgaWYgKCFyZXMuc3RhdHVzIHx8ICFyZXMuc2VuZCkge1xuICAgICAgICAgIGxvZ2dlci5lcnJvcigndGhpcyBpcyBhbiBlcnJvciBpbiBleHByZXNzLmpzLCBwbGVhc2UgcmVwb3J0IHRoaXMnKTtcbiAgICAgICAgICByZXMuZGVzdHJveSgpO1xuICAgICAgICB9IGVsc2UgaWYgKCFyZXMuaGVhZGVyc1NlbnQpIHtcbiAgICAgICAgICByZXMuc3RhdHVzKEhUVFBfU1RBVFVTLklOVEVSTkFMX0VSUk9SKTtcbiAgICAgICAgICBuZXh0KHsgZXJyb3I6IEFQSV9FUlJPUi5JTlRFUk5BTF9TRVJWRVJfRVJST1IgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gc29ja2V0IHNob3VsZCBiZSBhbHJlYWR5IGNsb3NlZFxuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICBuZXh0KCk7XG59XG4iXX0=
;