UNPKG

verdaccio

Version:

A lightweight private npm proxy registry

567 lines (465 loc) 58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _lodash = _interopRequireDefault(require("lodash")); var _pluginLoader = _interopRequireDefault(require("../lib/plugin-loader")); var _constants = require("./constants"); var _cryptoUtils = require("./crypto-utils"); var _authUtils = require("./auth-utils"); var _utils = require("./utils"); var _configUtils = require("./config-utils"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } /* eslint-disable @typescript-eslint/no-var-requires */ const LoggerApi = require('./logger'); class Auth { constructor(config) { _defineProperty(this, "config", void 0); _defineProperty(this, "logger", void 0); _defineProperty(this, "secret", void 0); _defineProperty(this, "plugins", void 0); this.config = config; this.logger = LoggerApi.logger.child({ sub: 'auth' }); this.secret = config.secret; this.plugins = this._loadPlugin(config); this._applyDefaultPlugins(); } _loadPlugin(config) { const pluginOptions = { config, logger: this.logger }; return (0, _pluginLoader.default)(config, config.auth, pluginOptions, plugin => { const { authenticate, allow_access, allow_publish } = plugin; // @ts-ignore return authenticate || allow_access || allow_publish; }); } _applyDefaultPlugins() { this.plugins.push((0, _authUtils.getDefaultPlugins)()); } changePassword(username, password, newPassword, cb) { const validPlugins = _lodash.default.filter(this.plugins, plugin => _lodash.default.isFunction(plugin.changePassword)); if (_lodash.default.isEmpty(validPlugins)) { return cb(_utils.ErrorCode.getInternalError(_constants.SUPPORT_ERRORS.PLUGIN_MISSING_INTERFACE)); } for (const plugin of validPlugins) { if (_lodash.default.isNil(plugin) || _lodash.default.isFunction(plugin.changePassword) === false) { this.logger.trace('auth plugin does not implement changePassword, trying next one'); continue; } else { this.logger.trace({ username }, 'updating password for @{username}'); plugin.changePassword(username, password, newPassword, (err, profile) => { if (err) { this.logger.error({ username, err }, `An error has been produced updating the password for @{username}. Error: @{err.message}`); return cb(err); } this.logger.trace({ username }, 'updated password for @{username} was successful'); return cb(null, profile); }); } } } authenticate(username, password, cb) { const plugins = this.plugins.slice(0); const self = this; (function next() { const plugin = plugins.shift(); if (_lodash.default.isFunction(plugin.authenticate) === false) { return next(); } self.logger.trace({ username }, 'authenticating @{username}'); plugin.authenticate(username, password, function (err, groups) { if (err) { self.logger.trace({ username, err }, 'authenticating for user @{username} failed. Error: @{err.message}'); return cb(err); } // Expect: SKIP if groups is falsey and not an array // with at least one item (truthy length) // Expect: CONTINUE otherwise (will error if groups is not // an array, but this is current behavior) // Caveat: STRING (if valid) will pass successfully // bug give unexpected results // Info: Cannot use `== false to check falsey values` if (!!groups && groups.length !== 0) { // TODO: create a better understanding of expectations if (_lodash.default.isString(groups)) { throw new TypeError('plugin group error: invalid type for function'); } const isGroupValid = _lodash.default.isArray(groups); if (!isGroupValid) { throw new TypeError(_constants.API_ERROR.BAD_FORMAT_USER_GROUP); } self.logger.trace({ username, groups }, 'authentication for user @{username} was successfully. Groups: @{groups}'); return cb(err, (0, _authUtils.createRemoteUser)(username, groups)); } next(); }); })(); } add_user(user, password, cb) { const self = this; const plugins = this.plugins.slice(0); this.logger.trace({ user }, 'add user @{user}'); (function next() { const plugin = plugins.shift(); let method = 'adduser'; if (_lodash.default.isFunction(plugin[method]) === false) { method = 'add_user'; self.logger.warn('the plugin method add_user in the auth plugin is deprecated and will be removed in next major release, notify to the plugin author'); } if (_lodash.default.isFunction(plugin[method]) === false) { next(); } else { // p.add_user() execution plugin[method](user, password, function (err, ok) { if (err) { self.logger.trace({ user, err: err.message }, 'the user @{user} could not being added. Error: @{err}'); return cb(err); } if (ok) { self.logger.trace({ user }, 'the user @{user} has been added'); return self.authenticate(user, password, cb); } next(); }); } })(); } /** * Allow user to access a package. */ allow_access({ packageName, packageVersion }, user, callback) { const plugins = this.plugins.slice(0); const pkgAllowAcces = { name: packageName, version: packageVersion }; const pkg = Object.assign({}, pkgAllowAcces, (0, _configUtils.getMatchedPackagesSpec)(packageName, this.config.packages)); const self = this; this.logger.trace({ packageName }, 'allow access for @{packageName}'); (function next() { const plugin = plugins.shift(); if (_lodash.default.isNil(plugin) || _lodash.default.isFunction(plugin.allow_access) === false) { return next(); } plugin.allow_access(user, pkg, function (err, ok) { if (err) { self.logger.trace({ packageName, err }, 'forbidden access for @{packageName}. Error: @{err.message}'); return callback(err); } if (ok) { self.logger.trace({ packageName }, 'allowed access for @{packageName}'); return callback(null, ok); } next(); // cb(null, false) causes next plugin to roll }); })(); } allow_unpublish({ packageName, packageVersion }, user, callback) { const pkg = Object.assign({ name: packageName, version: packageVersion }, (0, _configUtils.getMatchedPackagesSpec)(packageName, this.config.packages)); this.logger.trace({ packageName }, 'allow unpublish for @{packageName}'); for (const plugin of this.plugins) { if (_lodash.default.isNil(plugin) || _lodash.default.isFunction(plugin.allow_unpublish) === false) { this.logger.trace({ packageName }, 'allow unpublish for @{packageName} plugin does not implement allow_unpublish'); continue; } else { plugin.allow_unpublish(user, pkg, (err, ok) => { if (err) { this.logger.trace({ packageName }, 'forbidden publish for @{packageName}, it will fallback on unpublish permissions'); return callback(err); } if (_lodash.default.isNil(ok) === true) { this.logger.trace({ packageName }, 'we bypass unpublish for @{packageName}, publish will handle the access'); // @ts-ignore // eslint-disable-next-line return this.allow_publish(...arguments); } if (ok) { this.logger.trace({ packageName }, 'allowed unpublish for @{packageName}'); return callback(null, ok); } }); } } } /** * Allow user to publish a package. */ allow_publish({ packageName, packageVersion }, user, callback) { const plugins = this.plugins.slice(0); const self = this; const pkg = Object.assign({ name: packageName, version: packageVersion }, (0, _configUtils.getMatchedPackagesSpec)(packageName, this.config.packages)); this.logger.trace({ packageName, plugins: this.plugins.length }, 'allow publish for @{packageName} init | plugins: @{plugins}'); (function next() { const plugin = plugins.shift(); if (_lodash.default.isNil(plugin) || _lodash.default.isFunction(plugin.allow_publish) === false) { self.logger.trace({ packageName }, 'allow publish for @{packageName} plugin does not implement allow_publish'); return next(); } // @ts-ignore plugin.allow_publish(user, pkg, (err, ok) => { if (_lodash.default.isNil(err) === false && _lodash.default.isError(err)) { self.logger.trace({ packageName }, 'forbidden publish for @{packageName}'); return callback(err); } if (ok) { self.logger.trace({ packageName }, 'allowed publish for @{packageName}'); return callback(null, ok); } self.logger.trace({ packageName }, 'allow publish skip validation for @{packageName}'); next(); // cb(null, false) causes next plugin to roll }); })(); } apiJWTmiddleware() { const plugins = this.plugins.slice(0); const helpers = { createAnonymousRemoteUser: _authUtils.createAnonymousRemoteUser, createRemoteUser: _authUtils.createRemoteUser }; for (const plugin of plugins) { if (plugin.apiJWTmiddleware) { return plugin.apiJWTmiddleware(helpers); } } return (req, res, _next) => { req.pause(); const next = function (err) { req.resume(); // uncomment this to reject users with bad auth headers // return _next.apply(null, arguments) // swallow error, user remains unauthorized // set remoteUserError to indicate that user was attempting authentication if (err) { req.remote_user.error = err.message; } return _next(); }; if (this._isRemoteUserValid(req.remote_user)) { return next(); } // in case auth header does not exist we return anonymous function req.remote_user = (0, _authUtils.createAnonymousRemoteUser)(); const { authorization } = req.headers; if (_lodash.default.isNil(authorization)) { return next(); } if (!(0, _authUtils.isAuthHeaderValid)(authorization)) { this.logger.trace('api middleware auth heather is not valid'); return next(_utils.ErrorCode.getBadRequest(_constants.API_ERROR.BAD_AUTH_HEADER)); } const security = (0, _authUtils.getSecurity)(this.config); const { secret } = this.config; if ((0, _authUtils.isAESLegacy)(security)) { this.logger.trace('api middleware using legacy auth token'); this._handleAESMiddleware(req, security, secret, authorization, next); } else { this.logger.trace('api middleware using JWT auth token'); this._handleJWTAPIMiddleware(req, security, secret, authorization, next); } }; } _handleJWTAPIMiddleware(req, security, secret, authorization, next) { const { scheme, token } = (0, _authUtils.parseAuthTokenHeader)(authorization); if (scheme.toUpperCase() === _constants.TOKEN_BASIC.toUpperCase()) { // this should happen when client tries to login with an existing user const credentials = (0, _utils.convertPayloadToBase64)(token).toString(); const { user, password } = (0, _authUtils.parseBasicPayload)(credentials); this.authenticate(user, password, (err, user) => { if (!err) { req.remote_user = user; next(); } else { req.remote_user = (0, _authUtils.createAnonymousRemoteUser)(); next(err); } }); } else { // jwt handler const credentials = (0, _authUtils.getMiddlewareCredentials)(security, secret, authorization); if (credentials) { // if the signature is valid we rely on it req.remote_user = credentials; next(); } else { // with JWT throw 401 next(_utils.ErrorCode.getForbidden(_constants.API_ERROR.BAD_USERNAME_PASSWORD)); } } } _handleAESMiddleware(req, security, secret, authorization, next) { const credentials = (0, _authUtils.getMiddlewareCredentials)(security, secret, authorization); if (credentials) { const { user, password } = credentials; this.authenticate(user, password, (err, user) => { if (!err) { req.remote_user = user; next(); } else { req.remote_user = (0, _authUtils.createAnonymousRemoteUser)(); next(err); } }); } else { // we force npm client to ask again with basic authentication return next(_utils.ErrorCode.getBadRequest(_constants.API_ERROR.BAD_AUTH_HEADER)); } } _isRemoteUserValid(remote_user) { return _lodash.default.isUndefined(remote_user) === false && _lodash.default.isUndefined(remote_user.name) === false; } /** * JWT middleware for WebUI */ webUIJWTmiddleware() { return (req, res, _next) => { if (this._isRemoteUserValid(req.remote_user)) { return _next(); } req.pause(); const next = err => { req.resume(); if (err) { // req.remote_user.error = err.message; res.status(err.statusCode).send(err.message); } return _next(); }; const { authorization } = req.headers; if (_lodash.default.isNil(authorization)) { return next(); } if (!(0, _authUtils.isAuthHeaderValid)(authorization)) { return next(_utils.ErrorCode.getBadRequest(_constants.API_ERROR.BAD_AUTH_HEADER)); } const token = (authorization || '').replace(`${_constants.TOKEN_BEARER} `, ''); if (!token) { return next(); } let credentials; try { credentials = (0, _authUtils.verifyJWTPayload)(token, this.config.secret); } catch (err) {// FIXME: intended behaviour, do we want it? } if (this._isRemoteUserValid(credentials)) { const { name, groups } = credentials; // $FlowFixMe req.remote_user = (0, _authUtils.createRemoteUser)(name, groups); } else { req.remote_user = (0, _authUtils.createAnonymousRemoteUser)(); } next(); }; } async jwtEncrypt(user, signOptions) { const { real_groups, name, groups } = user; const realGroupsValidated = _lodash.default.isNil(real_groups) ? [] : real_groups; const groupedGroups = _lodash.default.isNil(groups) ? real_groups : groups.concat(realGroupsValidated); const payload = { real_groups: realGroupsValidated, name, groups: groupedGroups }; const token = await (0, _cryptoUtils.signPayload)(payload, this.secret, signOptions); return token; } /** * Encrypt a string. */ aesEncrypt(buf) { return (0, _cryptoUtils.aesEncrypt)(buf, this.secret); } } var _default = Auth; exports.default = _default; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvYXV0aC50cyJdLCJuYW1lcyI6WyJMb2dnZXJBcGkiLCJyZXF1aXJlIiwiQXV0aCIsImNvbnN0cnVjdG9yIiwiY29uZmlnIiwibG9nZ2VyIiwiY2hpbGQiLCJzdWIiLCJzZWNyZXQiLCJwbHVnaW5zIiwiX2xvYWRQbHVnaW4iLCJfYXBwbHlEZWZhdWx0UGx1Z2lucyIsInBsdWdpbk9wdGlvbnMiLCJhdXRoIiwicGx1Z2luIiwiYXV0aGVudGljYXRlIiwiYWxsb3dfYWNjZXNzIiwiYWxsb3dfcHVibGlzaCIsInB1c2giLCJjaGFuZ2VQYXNzd29yZCIsInVzZXJuYW1lIiwicGFzc3dvcmQiLCJuZXdQYXNzd29yZCIsImNiIiwidmFsaWRQbHVnaW5zIiwiXyIsImZpbHRlciIsImlzRnVuY3Rpb24iLCJpc0VtcHR5IiwiRXJyb3JDb2RlIiwiZ2V0SW50ZXJuYWxFcnJvciIsIlNVUFBPUlRfRVJST1JTIiwiUExVR0lOX01JU1NJTkdfSU5URVJGQUNFIiwiaXNOaWwiLCJ0cmFjZSIsImVyciIsInByb2ZpbGUiLCJlcnJvciIsInNsaWNlIiwic2VsZiIsIm5leHQiLCJzaGlmdCIsImdyb3VwcyIsImxlbmd0aCIsImlzU3RyaW5nIiwiVHlwZUVycm9yIiwiaXNHcm91cFZhbGlkIiwiaXNBcnJheSIsIkFQSV9FUlJPUiIsIkJBRF9GT1JNQVRfVVNFUl9HUk9VUCIsImFkZF91c2VyIiwidXNlciIsIm1ldGhvZCIsIndhcm4iLCJvayIsIm1lc3NhZ2UiLCJwYWNrYWdlTmFtZSIsInBhY2thZ2VWZXJzaW9uIiwiY2FsbGJhY2siLCJwa2dBbGxvd0FjY2VzIiwibmFtZSIsInZlcnNpb24iLCJwa2ciLCJPYmplY3QiLCJhc3NpZ24iLCJwYWNrYWdlcyIsImFsbG93X3VucHVibGlzaCIsImFyZ3VtZW50cyIsImlzRXJyb3IiLCJhcGlKV1RtaWRkbGV3YXJlIiwiaGVscGVycyIsImNyZWF0ZUFub255bW91c1JlbW90ZVVzZXIiLCJjcmVhdGVSZW1vdGVVc2VyIiwicmVxIiwicmVzIiwiX25leHQiLCJwYXVzZSIsInJlc3VtZSIsInJlbW90ZV91c2VyIiwiX2lzUmVtb3RlVXNlclZhbGlkIiwiYXV0aG9yaXphdGlvbiIsImhlYWRlcnMiLCJnZXRCYWRSZXF1ZXN0IiwiQkFEX0FVVEhfSEVBREVSIiwic2VjdXJpdHkiLCJfaGFuZGxlQUVTTWlkZGxld2FyZSIsIl9oYW5kbGVKV1RBUElNaWRkbGV3YXJlIiwic2NoZW1lIiwidG9rZW4iLCJ0b1VwcGVyQ2FzZSIsIlRPS0VOX0JBU0lDIiwiY3JlZGVudGlhbHMiLCJ0b1N0cmluZyIsImdldEZvcmJpZGRlbiIsIkJBRF9VU0VSTkFNRV9QQVNTV09SRCIsImlzVW5kZWZpbmVkIiwid2ViVUlKV1RtaWRkbGV3YXJlIiwic3RhdHVzIiwic3RhdHVzQ29kZSIsInNlbmQiLCJyZXBsYWNlIiwiVE9LRU5fQkVBUkVSIiwiand0RW5jcnlwdCIsInNpZ25PcHRpb25zIiwicmVhbF9ncm91cHMiLCJyZWFsR3JvdXBzVmFsaWRhdGVkIiwiZ3JvdXBlZEdyb3VwcyIsImNvbmNhdCIsInBheWxvYWQiLCJhZXNFbmNyeXB0IiwiYnVmIl0sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBQUE7O0FBZ0JBOztBQUVBOztBQUNBOztBQUNBOztBQVlBOztBQUNBOzs7Ozs7QUFFQTtBQUNBLE1BQU1BLFNBQVMsR0FBR0MsT0FBTyxDQUFDLFVBQUQsQ0FBekI7O0FBRUEsTUFBTUMsSUFBTixDQUE0QjtBQU1uQkMsRUFBQUEsV0FBVyxDQUFDQyxNQUFELEVBQWlCO0FBQUE7O0FBQUE7O0FBQUE7O0FBQUE7O0FBQ2pDLFNBQUtBLE1BQUwsR0FBY0EsTUFBZDtBQUNBLFNBQUtDLE1BQUwsR0FBY0wsU0FBUyxDQUFDSyxNQUFWLENBQWlCQyxLQUFqQixDQUF1QjtBQUFFQyxNQUFBQSxHQUFHLEVBQUU7QUFBUCxLQUF2QixDQUFkO0FBQ0EsU0FBS0MsTUFBTCxHQUFjSixNQUFNLENBQUNJLE1BQXJCO0FBQ0EsU0FBS0MsT0FBTCxHQUFlLEtBQUtDLFdB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Q0FsQixRQUFBQSxHQUFHLENBQUNLLFdBQUosR0FBa0IsaUNBQWlCbEIsSUFBakIsRUFBdUJsQixNQUF2QixDQUFsQjtBQUNELE9BSkQsTUFJTztBQUNMK0IsUUFBQUEsR0FBRyxDQUFDSyxXQUFKLEdBQWtCLDJDQUFsQjtBQUNEOztBQUVEdEMsTUFBQUEsSUFBSTtBQUNMLEtBOUNEO0FBK0NEOztBQUVzQixRQUFWOEQsVUFBVSxDQUFDbkQsSUFBRCxFQUFtQm9ELFdBQW5CLEVBQWlFO0FBQ3RGLFVBQU07QUFBRUMsTUFBQUEsV0FBRjtBQUFlNUMsTUFBQUEsSUFBZjtBQUFxQmxCLE1BQUFBO0FBQXJCLFFBQWdDUyxJQUF0QztBQUNBLFVBQU1zRCxtQkFBbUIsR0FBR2hGLGdCQUFFUSxLQUFGLENBQVF1RSxXQUFSLElBQXVCLEVBQXZCLEdBQTRCQSxXQUF4RDtBQUNBLFVBQU1FLGFBQWEsR0FBR2pGLGdCQUFFUSxLQUFGLENBQVFTLE1BQVIsSUFBa0I4RCxXQUFsQixHQUFnQzlELE1BQU0sQ0FBQ2lFLE1BQVAsQ0FBY0YsbUJBQWQsQ0FBdEQ7QUFDQSxVQUFNRyxPQUFtQixHQUFHO0FBQzFCSixNQUFBQSxXQUFXLEVBQUVDLG1CQURhO0FBRTFCN0MsTUFBQUEsSUFGMEI7QUFHMUJsQixNQUFBQSxNQUFNLEVBQUVnRTtBQUhrQixLQUE1QjtBQU1BLFVBQU1sQixLQUFhLEdBQUcsTUFBTSw4QkFBWW9CLE9BQVosRUFBcUIsS0FBS3BHLE1BQTFCLEVBQWtDK0YsV0FBbEMsQ0FBNUI7QUFFQSxXQUFPZixLQUFQO0FBQ0Q7QUFFRDtBQUNGO0FBQ0E7OztBQUNTcUIsRUFBQUEsVUFBVSxDQUFDQyxHQUFELEVBQXNCO0FBQ3JDLFdBQU8sNkJBQVdBLEdBQVgsRUFBZ0IsS0FBS3RHLE1BQXJCLENBQVA7QUFDRDs7QUF2ZXlCOztlQTBlYk4sSSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgeyBWZXJkYWNjaW9FcnJvciB9IGZyb20gJ0B2ZXJkYWNjaW8vY29tbW9ucy1hcGknO1xuXG5pbXBvcnQge1xuICBDb25maWcsXG4gIExvZ2dlcixcbiAgQ2FsbGJhY2ssXG4gIElQbHVnaW5BdXRoLFxuICBSZW1vdGVVc2VyLFxuICBKV1RTaWduT3B0aW9ucyxcbiAgU2VjdXJpdHksXG4gIEF1dGhQbHVnaW5QYWNrYWdlLFxuICBBbGxvd0FjY2VzcyxcbiAgUGFja2FnZUFjY2Vzc1xufSBmcm9tICdAdmVyZGFjY2lvL3R5cGVzJztcbmltcG9ydCB7IE5leHRGdW5jdGlvbiB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IGxvYWRQbHVnaW4gZnJvbSAnLi4vbGliL3BsdWdpbi1sb2FkZXInO1xuaW1wb3J0IHsgJFJlcXVlc3RFeHRlbmQsICRSZXNwb25zZUV4dGVuZCwgSUF1dGgsIEFFU1BheWxvYWQgfSBmcm9tICcuLi8uLi90eXBlcyc7XG5pbXBvcnQgeyBBUElfRVJST1IsIFNVUFBPUlRfRVJST1JTLCBUT0tFTl9CQVNJQywgVE9LRU5fQkVBUkVSIH0gZnJvbSAnLi9jb25zdGFudHMnO1xuaW1wb3J0IHsgYWVzRW5jcnlwdCwgc2lnblBheWxvYWQgfSBmcm9tICcuL2NyeXB0by11dGlscyc7XG5pbXBvcnQge1xuICBnZXREZWZhdWx0UGx1Z2lucyxcbiAgZ2V0TWlkZGxld2FyZUNyZWRlbnRpYWxzLFxuICB2ZXJpZnlKV1RQYXlsb2FkLFxuICBjcmVhdGVBbm9ueW1vdXNSZW1vdGVVc2VyLFxuICBpc0F1dGhIZWFkZXJWYWxpZCxcbiAgZ2V0U2VjdXJpdHksXG4gIGlzQUVTTGVnYWN5LFxuICBwYXJzZUF1dGhUb2tlbkhlYWRlcixcbiAgcGFyc2VCYXNpY1BheWxvYWQsXG4gIGNyZWF0ZVJlbW90ZVVzZXJcbn0gZnJvbSAnLi9hdXRoLXV0aWxzJztcbmltcG9ydCB7IGNvbnZlcnRQYXlsb2FkVG9CYXNlNjQsIEVycm9yQ29kZSB9IGZyb20gJy4vdXRpbHMnO1xuaW1wb3J0IHsgZ2V0TWF0Y2hlZFBhY2thZ2VzU3BlYyB9IGZyb20gJy4vY29uZmlnLXV0aWxzJztcblxuLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXZhci1yZXF1aXJlcyAqL1xuY29uc3QgTG9nZ2VyQXBpID0gcmVxdWlyZSgnLi9sb2dnZXInKTtcblxuY2xhc3MgQXV0aCBpbXBsZW1lbnRzIElBdXRoIHtcbiAgcHVibGljIGNvbmZpZzogQ29uZmlnO1xuICBwdWJsaWMgbG9nZ2VyOiBMb2dnZXI7XG4gIHB1YmxpYyBzZWNyZXQ6IHN0cmluZztcbiAgcHVibGljIHBsdWdpbnM6IElQbHVnaW5BdXRoPENvbmZpZz5bXTtcblxuICBwdWJsaWMgY29uc3RydWN0b3IoY29uZmlnOiBDb25maWcpIHtcbiAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICB0aGlzLmxvZ2dlciA9IExvZ2dlckFwaS5sb2dnZXIuY2hpbGQoeyBzdWI6ICdhdXRoJyB9KTtcbiAgICB0aGlzLnNlY3JldCA9IGNvbmZpZy5zZWNyZXQ7XG4gICAgdGhpcy5wbHVnaW5zID0gdGhpcy5fbG9hZFBsdWdpbihjb25maWcpO1xuICAgIHRoaXMuX2FwcGx5RGVmYXVsdFBsdWdpbnMoKTtcbiAgfVxuXG4gIHByaXZhdGUgX2xvYWRQbHVnaW4oY29uZmlnOiBDb25maWcpOiBJUGx1Z2luQXV0aDxDb25maWc+W10ge1xuICAgIGNvbnN0IHBsdWdpbk9wdGlvbnMgPSB7XG4gICAgICBjb25maWcsXG4gICAgICBsb2dnZXI6IHRoaXMubG9nZ2VyXG4gICAgfTtcblxuICAgIHJldHVybiBsb2FkUGx1Z2luPElQbHVnaW5BdXRoPENvbmZpZz4+KFxuICAgICAgY29uZmlnLFxuICAgICAgY29uZmlnLmF1dGgsXG4gICAgICBwbHVnaW5PcHRpb25zLFxuICAgICAgKHBsdWdpbjogSVBsdWdpbkF1dGg8Q29uZmlnPik6IGJvb2xlYW4gPT4ge1xuICAgICAgICBjb25zdCB7IGF1dGhlbnRpY2F0ZSwgYWxsb3dfYWNjZXNzLCBhbGxvd19wdWJsaXNoIH0gPSBwbHVnaW47XG5cbiAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICByZXR1cm4gYXV0aGVudGljYXRlIHx8IGFsbG93X2FjY2VzcyB8fCBhbGxvd19wdWJsaXNoO1xuICAgICAgfVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIF9hcHBseURlZmF1bHRQbHVnaW5zKCk6IHZvaWQge1xuICAgIHRoaXMucGx1Z2lucy5wdXNoKGdldERlZmF1bHRQbHVnaW5zKCkpO1xuICB9XG5cbiAgcHVibGljIGNoYW5nZVBhc3N3b3JkKFxuICAgIHVzZXJuYW1lOiBzdHJpbmcsXG4gICAgcGFzc3dvcmQ6IHN0cmluZyxcbiAgICBuZXdQYXNzd29yZDogc3RyaW5nLFxuICAgIGNiOiBDYWxsYmFja1xuICApOiB2b2lkIHtcbiAgICBjb25zdCB2YWxpZFBsdWdpbnMgPSBfLmZpbHRlcih0aGlzLnBsdWdpbnMsIChwbHVnaW4pID0+IF8uaXNGdW5jdGlvbihwbHVnaW4uY2hhbmdlUGFzc3dvcmQpKTtcblxuICAgIGlmIChfLmlzRW1wdHkodmFsaWRQbHVnaW5zKSkge1xuICAgICAgcmV0dXJuIGNiKEVycm9yQ29kZS5nZXRJbnRlcm5hbEVycm9yKFNVUFBPUlRfRVJST1JTLlBMVUdJTl9NSVNTSU5HX0lOVEVSRkFDRSkpO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgcGx1Z2luIG9mIHZhbGlkUGx1Z2lucykge1xuICAgICAgaWYgKF8uaXNOaWwocGx1Z2luKSB8fCBfLmlzRnVuY3Rpb24ocGx1Z2luLmNoYW5nZVBhc3N3b3JkKSA9PT0gZmFsc2UpIHtcbiAgICAgICAgdGhpcy5sb2dnZXIudHJhY2UoJ2F1dGggcGx1Z2luIGRvZXMgbm90IGltcGxlbWVudCBjaGFuZ2VQYXNzd29yZCwgdHJ5aW5nIG5leHQgb25lJyk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5sb2dnZXIudHJhY2UoeyB1c2VybmFtZSB9LCAndXBkYXRpbmcgcGFzc3dvcmQgZm9yIEB7dXNlcm5hbWV9Jyk7XG4gICAgICAgIHBsdWdpbi5jaGFuZ2VQYXNzd29yZCEodXNlcm5hbWUsIHBhc3N3b3JkLCBuZXdQYXNzd29yZCwgKGVyciwgcHJvZmlsZSk6IHZvaWQgPT4ge1xuICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgIHRoaXMubG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgICB7IHVzZXJuYW1lLCBlcnIgfSxcbiAgICAgICAgICAgICAgYEFuIGVycm9yIGhhcyBiZWVuIHByb2R1Y2VkXG4gICAgICAgICAgICB1cGRhdGluZyB0aGUgcGFzc3dvcmQgZm9yIEB7dXNlcm5hbWV9LiBFcnJvcjogQHtlcnIubWVzc2FnZX1gXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuIGNiKGVycik7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy5sb2dnZXIudHJhY2UoeyB1c2VybmFtZSB9LCAndXBkYXRlZCBwYXNzd29yZCBmb3IgQHt1c2VybmFtZX0gd2FzIHN1Y2Nlc3NmdWwnKTtcbiAgICAgICAgICByZXR1cm4gY2IobnVsbCwgcHJvZmlsZSk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBhdXRoZW50aWNhdGUodXNlcm5hbWU6IHN0cmluZywgcGFzc3dvcmQ6IHN0cmluZywgY2I6IENhbGxiYWNrKTogdm9pZCB7XG4gICAgY29uc3QgcGx1Z2lucyA9IHRoaXMucGx1Z2lucy5zbGljZSgwKTtcbiAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAoZnVuY3Rpb24gbmV4dCgpOiB2b2lkIHtcbiAgICAgIGNvbnN0IHBsdWdpbiA9IHBsdWdpbnMuc2hpZnQoKSBhcyBJUGx1Z2luQXV0aDxDb25maWc+O1xuXG4gICAgICBpZiAoXy5pc0Z1bmN0aW9uKHBsdWdpbi5hdXRoZW50aWNhdGUpID09PSBmYWxzZSkge1xuICAgICAgICByZXR1cm4gbmV4dCgpO1xuICAgICAgfVxuXG4gICAgICBzZWxmLmxvZ2dlci50cmFjZSh7IHVzZXJuYW1lIH0sICdhdXRoZW50aWNhdGluZyBAe3VzZXJuYW1lfScpO1xuICAgICAgcGx1Z2luLmF1dGhlbnRpY2F0ZSh1c2VybmFtZSwgcGFzc3dvcmQsIGZ1bmN0aW9uIChlcnIsIGdyb3Vwcyk6IHZvaWQge1xuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgc2VsZi5sb2dnZXIudHJhY2UoXG4gICAgICAgICAgICB7IHVzZXJuYW1lLCBlcnIgfSxcbiAgICAgICAgICAgICdhdXRoZW50aWNhdGluZyBmb3IgdXNlciBAe3VzZXJuYW1lfSBmYWlsZWQuIEVycm9yOiBAe2Vyci5tZXNzYWdlfSdcbiAgICAgICAgICApO1xuICAgICAgICAgIHJldHVybiBjYihlcnIpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRXhwZWN0OiBTS0lQIGlmIGdyb3VwcyBpcyBmYWxzZXkgYW5kIG5vdCBhbiBhcnJheVxuICAgICAgICAvLyAgICAgICAgIHdpdGggYXQgbGVhc3Qgb25lIGl0ZW0gKHRydXRoeSBsZW5ndGgpXG4gICAgICAgIC8vIEV4cGVjdDogQ09OVElOVUUgb3RoZXJ3aXNlICh3aWxsIGVycm9yIGlmIGdyb3VwcyBpcyBub3RcbiAgICAgICAgLy8gICAgICAgICBhbiBhcnJheSwgYnV0IHRoaXMgaXMgY3VycmVudCBiZWhhdmlvcilcbiAgICAgICAgLy8gQ2F2ZWF0OiBTVFJJTkcgKGlmIHZhbGlkKSB3aWxsIHBhc3Mgc3VjY2Vzc2Z1bGx5XG4gICAgICAgIC8vICAgICAgICAgYnVnIGdpdmUgdW5leHBlY3RlZCByZXN1bHRzXG4gICAgICAgIC8vIEluZm86IENhbm5vdCB1c2UgYD09IGZhbHNlIHRvIGNoZWNrIGZhbHNleSB2YWx1ZXNgXG4gICAgICAgIGlmICghIWdyb3VwcyAmJiBncm91cHMubGVuZ3RoICE9PSAwKSB7XG4gICAgICAgICAgLy8gVE9ETzogY3JlYXRlIGEgYmV0dGVyIHVuZGVyc3RhbmRpbmcgb2YgZXhwZWN0YXRpb25zXG4gICAgICAgICAgaWYgKF8uaXNTdHJpbmcoZ3JvdXBzKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcigncGx1Z2luIGdyb3VwIGVycm9yOiBpbnZhbGlkIHR5cGUgZm9yIGZ1bmN0aW9uJyk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IGlzR3JvdXBWYWxpZDogYm9vbGVhbiA9IF8uaXNBcnJheShncm91cHMpO1xuICAgICAgICAgIGlmICghaXNHcm91cFZhbGlkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKEFQSV9FUlJPUi5CQURfRk9STUFUX1VTRVJfR1JPVVApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHNlbGYubG9nZ2VyLnRyYWNlKFxuICAgICAgICAgICAgeyB1c2VybmFtZSwgZ3JvdXBzIH0sXG4gICAgICAgICAgICAnYXV0aGVudGljYXRpb24gZm9yIHVzZXIgQHt1c2VybmFtZX0gd2FzIHN1Y2Nlc3NmdWxseS4gR3JvdXBzOiBAe2dyb3Vwc30nXG4gICAgICAgICAgKTtcbiAgICAgICAgICByZXR1cm4gY2IoZXJyLCBjcmVhdGVSZW1vdGVVc2VyKHVzZXJuYW1lLCBncm91cHMpKTtcbiAgICAgICAgfVxuICAgICAgICBuZXh0KCk7XG4gICAgICB9KTtcbiAgICB9KSgpO1xuICB9XG5cbiAgcHVibGljIGFkZF91c2VyKHVzZXI6IHN0cmluZywgcGFzc3dvcmQ6IHN0cmluZywgY2I6IENhbGxiYWNrKTogdm9pZCB7XG4gICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgY29uc3QgcGx1Z2lucyA9IHRoaXMucGx1Z2lucy5zbGljZSgwKTtcbiAgICB0aGlzLmxvZ2dlci50cmFjZSh7IHVzZXIgfSwgJ2FkZCB1c2VyIEB7dXNlcn0nKTtcblxuICAgIChmdW5jdGlvbiBuZXh0KCk6IHZvaWQge1xuICAgICAgY29uc3QgcGx1Z2luID0gcGx1Z2lucy5zaGlmdCgpIGFzIElQbHVnaW5BdXRoPENvbmZpZz47XG4gICAgICBsZXQgbWV0aG9kID0gJ2FkZHVzZXInO1xuICAgICAgaWYgKF8uaXNGdW5jdGlvbihwbHVnaW5bbWV0aG9kXSkgPT09IGZhbHNlKSB7XG4gICAgICAgIG1ldGhvZCA9ICdhZGRfdXNlcic7XG4gICAgICAgIHNlbGYubG9nZ2VyLndhcm4oXG4gICAgICAgICAgJ3RoZSBwbHVnaW4gbWV0aG9kIGFkZF91c2VyIGluIHRoZSBhdXRoIHBsdWdpbiBpcyBkZXByZWNhdGVkIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gbmV4dCBtYWpvciByZWxlYXNlLCBub3RpZnkgdG8gdGhlIHBsdWdpbiBhdXRob3InXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIGlmIChfLmlzRnVuY3Rpb24ocGx1Z2luW21ldGhvZF0pID09PSBmYWxzZSkge1xuICAgICAgICBuZXh0KCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBwLmFkZF91c2VyKCkgZXhlY3V0aW9uXG4gICAgICAgIHBsdWdpblttZXRob2RdKHVzZXIsIHBhc3N3b3JkLCBmdW5jdGlvbiAoZXJyLCBvayk6IHZvaWQge1xuICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgIHNlbGYubG9nZ2VyLnRyYWNlKFxuICAgICAgICAgICAgICB7IHVzZXIsIGVycjogZXJyLm1lc3NhZ2UgfSxcbiAgICAgICAgICAgICAgJ3RoZSB1c2VyIEB7dXNlcn0gY291bGQgbm90IGJlaW5nIGFkZGVkLiBFcnJvcjogQHtlcnJ9J1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiBjYihlcnIpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAob2spIHtcbiAgICAgICAgICAgIHNlbGYubG9nZ2VyLnRyYWNlKHsgdXNlciB9LCAndGhlIHVzZXIgQHt1c2VyfSBoYXMgYmVlbiBhZGRlZCcpO1xuICAgICAgICAgICAgcmV0dXJuIHNlbGYuYXV0aGVudGljYXRlKHVzZXIsIHBhc3N3b3JkLCBjYik7XG4gICAgICAgICAgfVxuICAgICAgICAgIG5leHQoKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSkoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbGxvdyB1c2VyIHRvIGFjY2VzcyBhIHBhY2thZ2UuXG4gICAqL1xuICBwdWJsaWMgYWxsb3dfYWNjZXNzKFxuICAgIHsgcGFja2FnZU5hbWUsIHBhY2thZ2VWZXJzaW9uIH06IEF1dGhQbHVnaW5QYWNrYWdlLFxuICAgIHVzZXI6IFJlbW90ZVVzZXIsXG4gICAgY2FsbGJhY2s6IENhbGxiYWNrXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IHBsdWdpbnMgPSB0aGlzLnBsdWdpbnMuc2xpY2UoMCk7XG4gICAgY29uc3QgcGtnQWxsb3dBY2NlczogQWxsb3dBY2Nlc3MgPSB7IG5hbWU6IHBhY2thZ2VOYW1lLCB2ZXJzaW9uOiBwYWNrYWdlVmVyc2lvbiB9O1xuICAgIGNvbnN0IHBrZyA9IE9iamVjdC5hc3NpZ24oXG4gICAgICB7fSxcbiAgICAgIHBrZ0FsbG93QWNjZXMsXG4gICAgICBnZXRNYXRjaGVkUGFja2FnZXNTcGVjKHBhY2thZ2VOYW1lLCB0aGlzLmNvbmZpZy5wYWNrYWdlcylcbiAgICApIGFzIEFsbG93QWNjZXNzICYgUGFja2FnZUFjY2VzcztcbiAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICB0aGlzLmxvZ2dlci50cmFjZSh7IHBhY2thZ2VOYW1lIH0sICdhbGxvdyBhY2Nlc3MgZm9yIEB7cGFja2FnZU5hbWV9Jyk7XG5cbiAgICAoZnVuY3Rpb24gbmV4dCgpOiB2b2lkIHtcbiAgICAgIGNvbnN0IHBsdWdpbjogSVBsdWdpbkF1dGg8Q29uZmlnPiA9IHBsdWdpbnMuc2hpZnQoKSBhcyBJUGx1Z2luQXV0aDxDb25maWc+O1xuXG4gICAgICBpZiAoXy5pc05pbChwbHVnaW4pIHx8IF8uaXNGdW5jdGlvbihwbHVnaW4uYWxsb3dfYWNjZXNzKSA9PT0gZmFsc2UpIHtcbiAgICAgICAgcmV0dXJuIG5leHQoKTtcbiAgICAgIH1cblxuICAgICAgcGx1Z2luLmFsbG93X2FjY2VzcyEodXNlciwgcGtnLCBmdW5jdGlvbiAoZXJyLCBvazogYm9vbGVhbik6IHZvaWQge1xuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgc2VsZi5sb2dnZXIudHJhY2UoXG4gICAgICAgICAgICB7IHBhY2thZ2VOYW1lLCBlcnIgfSxcbiAgICAgICAgICAgICdmb3JiaWRkZW4gYWNjZXNzIGZvciBAe3BhY2thZ2VOYW1lfS4gRXJyb3I6IEB7ZXJyLm1lc3NhZ2V9J1xuICAgICAgICAgICk7XG4gICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKGVycik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAob2spIHtcbiAgICAgICAgICBzZWxmLmxvZ2dlci50cmFjZSh7IHBhY2thZ2VOYW1lIH0sICdhbGxvd2VkIGFjY2VzcyBmb3IgQHtwYWNrYWdlTmFtZX0nKTtcbiAgICAgICAgICByZXR1cm4gY2FsbGJhY2sobnVsbCwgb2spO1xuICAgICAgICB9XG5cbiAgICAgICAgbmV4dCgpOyAvLyBjYihudWxsLCBmYWxzZSkgY2F1c2VzIG5leHQgcGx1Z2luIHRvIHJvbGxcbiAgICAgIH0pO1xuICAgIH0pKCk7XG4gIH1cblxuICBwdWJsaWMgYWxsb3dfdW5wdWJsaXNoKFxuICAgIHsgcGFja2FnZU5hbWUsIHBhY2thZ2VWZXJzaW9uIH06IEF1dGhQbHVnaW5QYWNrYWdlLFxuICAgIHVzZXI6IFJlbW90ZVVzZXIsXG4gICAgY2FsbGJhY2s6IENhbGxiYWNrXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IHBrZyA9IE9iamVjdC5hc3NpZ24oXG4gICAgICB7IG5hbWU6IHBhY2thZ2VOYW1lLCB2ZXJzaW9uOiBwYWNrYWdlVmVyc2lvbiB9LFxuICAgICAgZ2V0TWF0Y2hlZFBhY2thZ2VzU3BlYyhwYWNrYWdlTmFtZSwgdGhpcy5jb25maWcucGFja2FnZXMpXG4gICAgKTtcbiAgICB0aGlzLmxvZ2dlci50cmFjZSh7IHBhY2thZ2VOYW1lIH0sICdhbGxvdyB1bnB1Ymxpc2ggZm9yIEB7cGFja2FnZU5hbWV9Jyk7XG5cbiAgICBmb3IgKGNvbnN0IHBsdWdpbiBvZiB0aGlzLnBsdWdpbnMpIHtcbiAgICAgIGlmIChfLmlzTmlsKHBsdWdpbikgfHwgXy5pc0Z1bmN0aW9uKHBsdWdpbi5hbGxvd191bnB1Ymxpc2gpID09PSBmYWxzZSkge1xuICAgICAgICB0aGlzLmxvZ2dlci50cmFjZShcbiAgICAgICAgICB7IHBhY2thZ2VOYW1lIH0sXG4gICAgICAgICAgJ2FsbG93IHVucHVibGlzaCBmb3IgQHtwYWNrYWdlTmFtZX0gcGx1Z2luIGRvZXMgbm90IGltcGxlbWVudCBhbGxvd191bnB1Ymxpc2gnXG4gICAgICAgICk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcGx1Z2luLmFsbG93X3VucHVibGlzaCEodXNlciwgcGtnLCAoZXJyLCBvazogYm9vbGVhbik6IHZvaWQgPT4ge1xuICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgIHRoaXMubG9nZ2VyLnRyYWNlKFxuICAgICAgICAgICAgICB7IHBhY2thZ2VOYW1lIH0sXG4gICAgICAgICAgICAgICdmb3JiaWRkZW4gcHVibGlzaCBmb3IgQHtwYWNrYWdlTmFtZX0sIGl0IHdpbGwgZmFsbGJhY2sgb24gdW5wdWJsaXNoIHBlcm1pc3Npb25zJ1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhlcnIpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChfLmlzTmlsKG9rKSA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgdGhpcy5sb2dnZXIudHJhY2UoXG4gICAgICAgICAgICAgIHsgcGFja2FnZU5hbWUgfSxcbiAgICAgICAgICAgICAgJ3dlIGJ5cGFzcyB1bnB1Ymxpc2ggZm9yIEB7cGFja2FnZU5hbWV9LCBwdWJsaXNoIHdpbGwgaGFuZGxlIHRoZSBhY2Nlc3MnXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5hbGxvd19wdWJsaXNoKC4uLmFyZ3VtZW50cyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKG9rKSB7XG4gICAgICAgICAgICB0aGlzLmxvZ2dlci50cmFjZSh7IHBhY2thZ2VOYW1lIH0sICdhbGxvd2VkIHVucHVibGlzaCBmb3IgQHtwYWNrYWdlTmFtZX0nKTtcbiAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhudWxsLCBvayk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQWxsb3cgdXNlciB0byBwdWJsaXNoIGEgcGFja2FnZS5cbiAgICovXG4gIHB1YmxpYyBhbGxvd19wdWJsaXNoKFxuICAgIHsgcGFja2FnZU5hbWUsIHBhY2thZ2VWZXJzaW9uIH06IEF1dGhQbHVnaW5QYWNrYWdlLFxuICAgIHVzZXI6IFJlbW90ZVVzZXIsXG4gICAgY2FsbGJhY2s6IENhbGxiYWNrXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IHBsdWdpbnMgPSB0aGlzLnBsdWdpbnMuc2xpY2UoMCk7XG4gICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgY29uc3QgcGtnID0gT2JqZWN0LmFzc2lnbihcbiAgICAgIHsgbmFtZTogcGFja2FnZU5hbWUsIHZlcnNpb246IHBhY2thZ2VWZXJzaW9uIH0sXG4gICAgICBnZXRNYXRjaGVkUGFja2FnZXNTcGVjKHBhY2thZ2VOYW1lLCB0aGlzLmNvbmZpZy5wYWNrYWdlcylcbiAgICApO1xuICAgIHRoaXMubG9nZ2VyLnRyYWNlKFxuICAgICAgeyBwYWNrYWdlTmFtZSwgcGx1Z2luczogdGhpcy5wbHVnaW5zLmxlbmd0aCB9LFxuICAgICAgJ2FsbG93IHB1Ymxpc2ggZm9yIEB7cGFja2FnZU5hbWV9IGluaXQgfCBwbHVnaW5zOiBAe3BsdWdpbnN9J1xuICAgICk7XG5cbiAgICAoZnVuY3Rpb24gbmV4dCgpOiB2b2lkIHtcbiAgICAgIGNvbnN0IHBsdWdpbiA9IHBsdWdpbnMuc2hpZnQoKTtcblxuICAgICAgaWYgKF8uaXNOaWwocGx1Z2luKSB8fCBfLmlzRnVuY3Rpb24ocGx1Z2luLmFsbG93X3B1Ymxpc2gpID09PSBmYWxzZSkge1xuICAgICAgICBzZWxmLmxvZ2dlci50cmFjZShcbiAgICAgICAgICB7IHBhY2thZ2VOYW1lIH0sXG4gICAgICAgICAgJ2FsbG93IHB1Ymxpc2ggZm9yIEB7cGFja2FnZU5hbWV9IHBsdWdpbiBkb2VzIG5vdCBpbXBsZW1lbnQgYWxsb3dfcHVibGlzaCdcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIG5leHQoKTtcbiAgICAgIH1cblxuICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgcGx1Z2luLmFsbG93X3B1Ymxpc2godXNlciwgcGtnLCAoZXJyOiBWZXJkYWNjaW9FcnJvciwgb2s6IGJvb2xlYW4pOiB2b2lkID0+IHtcbiAgICAgICAgaWYgKF8uaXNOaWwoZXJyKSA9PT0gZmFsc2UgJiYgXy5pc0Vycm9yKGVycikpIHtcbiAgICAgICAgICBzZWxmLmxvZ2dlci50cmFjZSh7IHBhY2thZ2VOYW1lIH0sICdmb3JiaWRkZW4gcHVibGlzaCBmb3IgQHtwYWNrYWdlTmFtZX0nKTtcbiAgICAgICAgICByZXR1cm4gY2FsbGJhY2soZXJyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChvaykge1xuICAgICAgICAgIHNlbGYubG9nZ2VyLnRyYWNlKHsgcGFja2FnZU5hbWUgfSwgJ2FsbG93ZWQgcHVibGlzaCBmb3IgQHtwYWNrYWdlTmFtZX0nKTtcbiAgICAgICAgICByZXR1cm4gY2FsbGJhY2sobnVsbCwgb2spO1xuICAgICAgICB9XG5cbiAgICAgICAgc2VsZi5sb2dnZXIudHJhY2UoeyBwYWNrYWdlTmFtZSB9LCAnYWxsb3cgcHVibGlzaCBza2lwIHZhbGlkYXRpb24gZm9yIEB7cGFja2FnZU5hbWV9Jyk7XG4gICAgICAgIG5leHQoKTsgLy8gY2IobnVsbCwgZmFsc2UpIGNhdXNlcyBuZXh0IHBsdWdpbiB0byByb2xsXG4gICAgICB9KTtcbiAgICB9KSgpO1xuICB9XG5cbiAgcHVibGljIGFwaUpXVG1pZGRsZXdhcmUoKTogRnVuY3Rpb24ge1xuICAgIGNvbnN0IHBsdWdpbnMgPSB0aGlzLnBsdWdpbnMuc2xpY2UoMCk7XG4gICAgY29uc3QgaGVscGVycyA9IHsgY3JlYXRlQW5vbnltb3VzUmVtb3RlVXNlci