verdaccio
Version:
A lightweight private npm proxy registry
567 lines (465 loc) • 58 kB
JavaScript
"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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvYXV0aC50cyJdLCJuYW1lcyI6WyJMb2dnZXJBcGkiLCJyZXF1aXJlIiwiQXV0aCIsImNvbnN0cnVjdG9yIiwiY29uZmlnIiwibG9nZ2VyIiwiY2hpbGQiLCJzdWIiLCJzZWNyZXQiLCJwbHVnaW5zIiwiX2xvYWRQbHVnaW4iLCJfYXBwbHlEZWZhdWx0UGx1Z2lucyIsInBsdWdpbk9wdGlvbnMiLCJhdXRoIiwicGx1Z2luIiwiYXV0aGVudGljYXRlIiwiYWxsb3dfYWNjZXNzIiwiYWxsb3dfcHVibGlzaCIsInB1c2giLCJjaGFuZ2VQYXNzd29yZCIsInVzZXJuYW1lIiwicGFzc3dvcmQiLCJuZXdQYXNzd29yZCIsImNiIiwidmFsaWRQbHVnaW5zIiwiXyIsImZpbHRlciIsImlzRnVuY3Rpb24iLCJpc0VtcHR5IiwiRXJyb3JDb2RlIiwiZ2V0SW50ZXJuYWxFcnJvciIsIlNVUFBPUlRfRVJST1JTIiwiUExVR0lOX01JU1NJTkdfSU5URVJGQUNFIiwiaXNOaWwiLCJ0cmFjZSIsImVyciIsInByb2ZpbGUiLCJlcnJvciIsInNsaWNlIiwic2VsZiIsIm5leHQiLCJzaGlmdCIsImdyb3VwcyIsImxlbmd0aCIsImlzU3RyaW5nIiwiVHlwZUVycm9yIiwiaXNHcm91cFZhbGlkIiwiaXNBcnJheSIsIkFQSV9FUlJPUiIsIkJBRF9GT1JNQVRfVVNFUl9HUk9VUCIsImFkZF91c2VyIiwidXNlciIsIm1ldGhvZCIsIndhcm4iLCJvayIsIm1lc3NhZ2UiLCJwYWNrYWdlTmFtZSIsInBhY2thZ2VWZXJzaW9uIiwiY2FsbGJhY2siLCJwa2dBbGxvd0FjY2VzIiwibmFtZSIsInZlcnNpb24iLCJwa2ciLCJPYmplY3QiLCJhc3NpZ24iLCJwYWNrYWdlcyIsImFsbG93X3VucHVibGlzaCIsImFyZ3VtZW50cyIsImlzRXJyb3IiLCJhcGlKV1RtaWRkbGV3YXJlIiwiaGVscGVycyIsImNyZWF0ZUFub255bW91c1JlbW90ZVVzZXIiLCJjcmVhdGVSZW1vdGVVc2VyIiwicmVxIiwicmVzIiwiX25leHQiLCJwYXVzZSIsInJlc3VtZSIsInJlbW90ZV91c2VyIiwiX2lzUmVtb3RlVXNlclZhbGlkIiwiYXV0aG9yaXphdGlvbiIsImhlYWRlcnMiLCJnZXRCYWRSZXF1ZXN0IiwiQkFEX0FVVEhfSEVBREVSIiwic2VjdXJpdHkiLCJfaGFuZGxlQUVTTWlkZGxld2FyZSIsIl9oYW5kbGVKV1RBUElNaWRkbGV3YXJlIiwic2NoZW1lIiwidG9rZW4iLCJ0b1VwcGVyQ2FzZSIsIlRPS0VOX0JBU0lDIiwiY3JlZGVudGlhbHMiLCJ0b1N0cmluZyIsImdldEZvcmJpZGRlbiIsIkJBRF9VU0VSTkFNRV9QQVNTV09SRCIsImlzVW5kZWZpbmVkIiwid2ViVUlKV1RtaWRkbGV3YXJlIiwic3RhdHVzIiwic3RhdHVzQ29kZSIsInNlbmQiLCJyZXBsYWNlIiwiVE9LRU5fQkVBUkVSIiwiand0RW5jcnlwdCIsInNpZ25PcHRpb25zIiwicmVhbF9ncm91cHMiLCJyZWFsR3JvdXBzVmFsaWRhdGVkIiwiZ3JvdXBlZEdyb3VwcyIsImNvbmNhdCIsInBheWxvYWQiLCJhZXNFbmNyeXB0IiwiYnVmIl0sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBQUE7O0FBZ0JBOztBQUVBOztBQUNBOztBQUNBOztBQVlBOztBQUNBOzs7Ozs7QUFFQTtBQUNBLE1BQU1BLFNBQVMsR0FBR0MsT0FBTyxDQUFDLFVBQUQsQ0FBekI7O0FBRUEsTUFBTUMsSUFBTixDQUE0QjtBQU1uQkMsRUFBQUEsV0FBVyxDQUFDQyxNQUFELEVBQWlCO0FBQUE7O0FBQUE7O0FBQUE7O0FBQUE7O0FBQ2pDLFNBQUtBLE1BQUwsR0FBY0EsTUFBZDtBQUNBLFNBQUtDLE1BQUwsR0FBY0wsU0FBUyxDQUFDSyxNQUFWLENBQWlCQyxLQUFqQixDQUF1QjtBQUFFQyxNQUFBQSxHQUFHLEVBQUU7QUFBUCxLQUF2QixDQUFkO0FBQ0EsU0FBS0MsTUFBTCxHQUFjSixNQUFNLENBQUNJLE1BQXJCO0FBQ0EsU0FBS0MsT0FBTCxHQUFlLEtBQUtDLFdBQUwsQ0FBaUJOLE1BQWpCLENBQWY7O0FBQ0EsU0FBS08sb0JBQUw7QUFDRDs7QUFFT0QsRUFBQUEsV0FBVyxDQUFDTixNQUFELEVBQXdDO0FBQ3pELFVBQU1RLGFBQWEsR0FBRztBQUNwQlIsTUFBQUEsTUFEb0I7QUFFcEJDLE1BQUFBLE1BQU0sRUFBRSxLQUFLQTtBQUZPLEtBQXRCO0FBS0EsV0FBTywyQkFDTEQsTUFESyxFQUVMQSxNQUFNLENBQUNTLElBRkYsRUFHTEQsYUFISyxFQUlKRSxNQUFELElBQTBDO0FBQ3hDLFlBQU07QUFBRUMsUUFBQUEsWUFBRjtBQUFnQkMsUUFBQUEsWUFBaEI7QUFBOEJDLFFBQUFBO0FBQTlCLFVBQWdESCxNQUF0RCxDQUR3QyxDQUd4Qzs7QUFDQSxhQUFPQyxZQUFZLElBQUlDLFlBQWhCLElBQWdDQyxhQUF2QztBQUNELEtBVEksQ0FBUDtBQVdEOztBQUVPTixFQUFBQSxvQkFBb0IsR0FBUztBQUNuQyxTQUFLRixPQUFMLENBQWFTLElBQWIsQ0FBa0IsbUNBQWxCO0FBQ0Q7O0FBRU1DLEVBQUFBLGNBQWMsQ0FDbkJDLFFBRG1CLEVBRW5CQyxRQUZtQixFQUduQkMsV0FIbUIsRUFJbkJDLEVBSm1CLEVBS2I7QUFDTixVQUFNQyxZQUFZLEdBQUdDLGdCQUFFQyxNQUFGLENBQVMsS0FBS2pCLE9BQWQsRUFBd0JLLE1BQUQsSUFBWVcsZ0JBQUVFLFVBQUYsQ0FBYWIsTUFBTSxDQUFDSyxjQUFwQixDQUFuQyxDQUFyQjs7QUFFQSxRQUFJTSxnQkFBRUcsT0FBRixDQUFVSixZQUFWLENBQUosRUFBNkI7QUFDM0IsYUFBT0QsRUFBRSxDQUFDTSxpQkFBVUMsZ0JBQVYsQ0FBMkJDLDBCQUFlQyx3QkFBMUMsQ0FBRCxDQUFUO0FBQ0Q7O0FBRUQsU0FBSyxNQUFNbEIsTUFBWCxJQUFxQlUsWUFBckIsRUFBbUM7QUFDakMsVUFBSUMsZ0JBQUVRLEtBQUYsQ0FBUW5CLE1BQVIsS0FBbUJXLGdCQUFFRSxVQUFGLENBQWFiLE1BQU0sQ0FBQ0ssY0FBcEIsTUFBd0MsS0FBL0QsRUFBc0U7QUFDcEUsYUFBS2QsTUFBTCxDQUFZNkIsS0FBWixDQUFrQixnRUFBbEI7QUFDQTtBQUNELE9BSEQsTUFHTztBQUNMLGFBQUs3QixNQUFMLENBQVk2QixLQUFaLENBQWtCO0FBQUVkLFVBQUFBO0FBQUYsU0FBbEIsRUFBZ0MsbUNBQWhDO0FBQ0FOLFFBQUFBLE1BQU0sQ0FBQ0ssY0FBUCxDQUF1QkMsUUFBdkIsRUFBaUNDLFFBQWpDLEVBQTJDQyxXQUEzQyxFQUF3RCxDQUFDYSxHQUFELEVBQU1DLE9BQU4sS0FBd0I7QUFDOUUsY0FBSUQsR0FBSixFQUFTO0FBQ1AsaUJBQUs5QixNQUFMLENBQVlnQyxLQUFaLENBQ0U7QUFBRWpCLGNBQUFBLFFBQUY7QUFBWWUsY0FBQUE7QUFBWixhQURGLEVBRUc7QUFDZix5RUFIWTtBQUtBLG1CQUFPWixFQUFFLENBQUNZLEdBQUQsQ0FBVDtBQUNEOztBQUVELGVBQUs5QixNQUFMLENBQVk2QixLQUFaLENBQWtCO0FBQUVkLFlBQUFBO0FBQUYsV0FBbEIsRUFBZ0MsaURBQWhDO0FBQ0EsaUJBQU9HLEVBQUUsQ0FBQyxJQUFELEVBQU9hLE9BQVAsQ0FBVDtBQUNELFNBWkQ7QUFhRDtBQUNGO0FBQ0Y7O0FBRU1yQixFQUFBQSxZQUFZLENBQUNLLFFBQUQsRUFBbUJDLFFBQW5CLEVBQXFDRSxFQUFyQyxFQUF5RDtBQUMxRSxVQUFNZCxPQUFPLEdBQUcsS0FBS0EsT0FBTCxDQUFhNkIsS0FBYixDQUFtQixDQUFuQixDQUFoQjtBQUNBLFVBQU1DLElBQUksR0FBRyxJQUFiOztBQUNBLEtBQUMsU0FBU0MsSUFBVCxHQUFzQjtBQUNyQixZQUFNMUIsTUFBTSxHQUFHTCxPQUFPLENBQUNnQyxLQUFSLEVBQWY7O0FBRUEsVUFBSWhCLGdCQUFFRSxVQUFGLENBQWFiLE1BQU0sQ0FBQ0MsWUFBcEIsTUFBc0MsS0FBMUMsRUFBaUQ7QUFDL0MsZUFBT3lCLElBQUksRUFBWDtBQUNEOztBQUVERCxNQUFBQSxJQUFJLENBQUNsQyxNQUFMLENBQVk2QixLQUFaLENBQWtCO0FBQUVkLFFBQUFBO0FBQUYsT0FBbEIsRUFBZ0MsNEJBQWhDO0FBQ0FOLE1BQUFBLE1BQU0sQ0FBQ0MsWUFBUCxDQUFvQkssUUFBcEIsRUFBOEJDLFFBQTlCLEVBQXdDLFVBQVVjLEdBQVYsRUFBZU8sTUFBZixFQUE2QjtBQUNuRSxZQUFJUCxHQUFKLEVBQVM7QUFDUEksVUFBQUEsSUFBSSxDQUFDbEMsTUFBTCxDQUFZNkIsS0FBWixDQUNFO0FBQUVkLFlBQUFBLFFBQUY7QUFBWWUsWUFBQUE7QUFBWixXQURGLEVBRUUsbUVBRkY7QUFJQSxpQkFBT1osRUFBRSxDQUFDWSxHQUFELENBQVQ7QUFDRCxTQVBrRSxDQVNuRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBQ0EsWUFBSSxDQUFDLENBQUNPLE1BQUYsSUFBWUEsTUFBTSxDQUFDQyxNQUFQLEtBQWtCLENBQWxDLEVBQXFDO0FBQ25DO0FBQ0EsY0FBSWxCLGdCQUFFbUIsUUFBRixDQUFXRixNQUFYLENBQUosRUFBd0I7QUFDdEIsa0JBQU0sSUFBSUcsU0FBSixDQUFjLCtDQUFkLENBQU47QUFDRDs7QUFDRCxnQkFBTUMsWUFBcUIsR0FBR3JCLGdCQUFFc0IsT0FBRixDQUFVTCxNQUFWLENBQTlCOztBQUNBLGNBQUksQ0FBQ0ksWUFBTCxFQUFtQjtBQUNqQixrQkFBTSxJQUFJRCxTQUFKLENBQWNHLHFCQUFVQyxxQkFBeEIsQ0FBTjtBQUNEOztBQUVEVixVQUFBQSxJQUFJLENBQUNsQyxNQUFMLENBQVk2QixLQUFaLENBQ0U7QUFBRWQsWUFBQUEsUUFBRjtBQUFZc0IsWUFBQUE7QUFBWixXQURGLEVBRUUseUVBRkY7QUFJQSxpQkFBT25CLEVBQUUsQ0FBQ1ksR0FBRCxFQUFNLGlDQUFpQmYsUUFBakIsRUFBMkJzQixNQUEzQixDQUFOLENBQVQ7QUFDRDs7QUFDREYsUUFBQUEsSUFBSTtBQUNMLE9BakNEO0FBa0NELEtBMUNEO0FBMkNEOztBQUVNVSxFQUFBQSxRQUFRLENBQUNDLElBQUQsRUFBZTlCLFFBQWYsRUFBaUNFLEVBQWpDLEVBQXFEO0FBQ2xFLFVBQU1nQixJQUFJLEdBQUcsSUFBYjtBQUNBLFVBQU05QixPQUFPLEdBQUcsS0FBS0EsT0FBTCxDQUFhNkIsS0FBYixDQUFtQixDQUFuQixDQUFoQjtBQUNBLFNBQUtqQyxNQUFMLENBQVk2QixLQUFaLENBQWtCO0FBQUVpQixNQUFBQTtBQUFGLEtBQWxCLEVBQTRCLGtCQUE1Qjs7QUFFQSxLQUFDLFNBQVNYLElBQVQsR0FBc0I7QUFDckIsWUFBTTFCLE1BQU0sR0FBR0wsT0FBTyxDQUFDZ0MsS0FBUixFQUFmO0FBQ0EsVUFBSVcsTUFBTSxHQUFHLFNBQWI7O0FBQ0EsVUFBSTNCLGdCQUFFRSxVQUFGLENBQWFiLE1BQU0sQ0FBQ3NDLE1BQUQsQ0FBbkIsTUFBaUMsS0FBckMsRUFBNEM7QUFDMUNBLFFBQUFBLE1BQU0sR0FBRyxVQUFUO0FBQ0FiLFFBQUFBLElBQUksQ0FBQ2xDLE1BQUwsQ0FBWWdELElBQVosQ0FDRSxvSUFERjtBQUdEOztBQUVELFVBQUk1QixnQkFBRUUsVUFBRixDQUFhYixNQUFNLENBQUNzQyxNQUFELENBQW5CLE1BQWlDLEtBQXJDLEVBQTRDO0FBQzFDWixRQUFBQSxJQUFJO0FBQ0wsT0FGRCxNQUVPO0FBQ0w7QUFDQTFCLFFBQUFBLE1BQU0sQ0FBQ3NDLE1BQUQsQ0FBTixDQUFlRCxJQUFmLEVBQXFCOUIsUUFBckIsRUFBK0IsVUFBVWMsR0FBVixFQUFlbUIsRUFBZixFQUF5QjtBQUN0RCxjQUFJbkIsR0FBSixFQUFTO0FBQ1BJLFlBQUFBLElBQUksQ0FBQ2xDLE1BQUwsQ0FBWTZCLEtBQVosQ0FDRTtBQUFFaUIsY0FBQUEsSUFBRjtBQUFRaEIsY0FBQUEsR0FBRyxFQUFFQSxHQUFHLENBQUNvQjtBQUFqQixhQURGLEVBRUUsdURBRkY7QUFJQSxtQkFBT2hDLEVBQUUsQ0FBQ1ksR0FBRCxDQUFUO0FBQ0Q7O0FBQ0QsY0FBSW1CLEVBQUosRUFBUTtBQUNOZixZQUFBQSxJQUFJLENBQUNsQyxNQUFMLENBQVk2QixLQUFaLENBQWtCO0FBQUVpQixjQUFBQTtBQUFGLGFBQWxCLEVBQTRCLGlDQUE1QjtBQUNBLG1CQUFPWixJQUFJLENBQUN4QixZQUFMLENBQWtCb0MsSUFBbEIsRUFBd0I5QixRQUF4QixFQUFrQ0UsRUFBbEMsQ0FBUDtBQUNEOztBQUNEaUIsVUFBQUEsSUFBSTtBQUNMLFNBYkQ7QUFjRDtBQUNGLEtBN0JEO0FBOEJEO0FBRUQ7QUFDRjtBQUNBOzs7QUFDU3hCLEVBQUFBLFlBQVksQ0FDakI7QUFBRXdDLElBQUFBLFdBQUY7QUFBZUMsSUFBQUE7QUFBZixHQURpQixFQUVqQk4sSUFGaUIsRUFHakJPLFFBSGlCLEVBSVg7QUFDTixVQUFNakQsT0FBTyxHQUFHLEtBQUtBLE9BQUwsQ0FBYTZCLEtBQWIsQ0FBbUIsQ0FBbkIsQ0FBaEI7QUFDQSxVQUFNcUIsYUFBMEIsR0FBRztBQUFFQyxNQUFBQSxJQUFJLEVBQUVKLFdBQVI7QUFBcUJLLE1BQUFBLE9BQU8sRUFBRUo7QUFBOUIsS0FBbkM7QUFDQSxVQUFNSyxHQUFHLEdBQUdDLE1BQU0sQ0FBQ0MsTUFBUCxDQUNWLEVBRFUsRUFFVkwsYUFGVSxFQUdWLHlDQUF1QkgsV0FBdkIsRUFBb0MsS0FBS3BELE1BQUwsQ0FBWTZELFFBQWhELENBSFUsQ0FBWjtBQUtBLFVBQU0xQixJQUFJLEdBQUcsSUFBYjtBQUNBLFNBQUtsQyxNQUFMLENBQVk2QixLQUFaLENBQWtCO0FBQUVzQixNQUFBQTtBQUFGLEtBQWxCLEVBQW1DLGlDQUFuQzs7QUFFQSxLQUFDLFNBQVNoQixJQUFULEdBQXNCO0FBQ3JCLFlBQU0xQixNQUEyQixHQUFHTCxPQUFPLENBQUNnQyxLQUFSLEVBQXBDOztBQUVBLFVBQUloQixnQkFBRVEsS0FBRixDQUFRbkIsTUFBUixLQUFtQlcsZ0JBQUVFLFVBQUYsQ0FBYWIsTUFBTSxDQUFDRSxZQUFwQixNQUFzQyxLQUE3RCxFQUFvRTtBQUNsRSxlQUFPd0IsSUFBSSxFQUFYO0FBQ0Q7O0FBRUQxQixNQUFBQSxNQUFNLENBQUNFLFlBQVAsQ0FBcUJtQyxJQUFyQixFQUEyQlcsR0FBM0IsRUFBZ0MsVUFBVTNCLEdBQVYsRUFBZW1CLEVBQWYsRUFBa0M7QUFDaEUsWUFBSW5CLEdBQUosRUFBUztBQUNQSSxVQUFBQSxJQUFJLENBQUNsQyxNQUFMLENBQVk2QixLQUFaLENBQ0U7QUFBRXNCLFlBQUFBLFdBQUY7QUFBZXJCLFlBQUFBO0FBQWYsV0FERixFQUVFLDREQUZGO0FBSUEsaUJBQU91QixRQUFRLENBQUN2QixHQUFELENBQWY7QUFDRDs7QUFFRCxZQUFJbUIsRUFBSixFQUFRO0FBQ05mLFVBQUFBLElBQUksQ0FBQ2xDLE1BQUwsQ0FBWTZCLEtBQVosQ0FBa0I7QUFBRXNCLFlBQUFBO0FBQUYsV0FBbEIsRUFBbUMsbUNBQW5DO0FBQ0EsaUJBQU9FLFFBQVEsQ0FBQyxJQUFELEVBQU9KLEVBQVAsQ0FBZjtBQUNEOztBQUVEZCxRQUFBQSxJQUFJLEdBZDRELENBY3hEO0FBQ1QsT0FmRDtBQWdCRCxLQXZCRDtBQXdCRDs7QUFFTTBCLEVBQUFBLGVBQWUsQ0FDcEI7QUFBRVYsSUFBQUEsV0FBRjtBQUFlQyxJQUFBQTtBQUFmLEdBRG9CLEVBRXBCTixJQUZvQixFQUdwQk8sUUFIb0IsRUFJZDtBQUNOLFVBQU1JLEdBQUcsR0FBR0MsTUFBTSxDQUFDQyxNQUFQLENBQ1Y7QUFBRUosTUFBQUEsSUFBSSxFQUFFSixXQUFSO0FBQXFCSyxNQUFBQSxPQUFPLEVBQUVKO0FBQTlCLEtBRFUsRUFFVix5Q0FBdUJELFdBQXZCLEVBQW9DLEtBQUtwRCxNQUFMLENBQVk2RCxRQUFoRCxDQUZVLENBQVo7QUFJQSxTQUFLNUQsTUFBTCxDQUFZNkIsS0FBWixDQUFrQjtBQUFFc0IsTUFBQUE7QUFBRixLQUFsQixFQUFtQyxvQ0FBbkM7O0FBRUEsU0FBSyxNQUFNMUMsTUFBWCxJQUFxQixLQUFLTCxPQUExQixFQUFtQztBQUNqQyxVQUFJZ0IsZ0JBQUVRLEtBQUYsQ0FBUW5CLE1BQVIsS0FBbUJXLGdCQUFFRSxVQUFGLENBQWFiLE1BQU0sQ0FBQ29ELGVBQXBCLE1BQXlDLEtBQWhFLEVBQXVFO0FBQ3JFLGFBQUs3RCxNQUFMLENBQVk2QixLQUFaLENBQ0U7QUFBRXNCLFVBQUFBO0FBQUYsU0FERixFQUVFLDhFQUZGO0FBSUE7QUFDRCxPQU5ELE1BTU87QUFDTDFDLFFBQUFBLE1BQU0sQ0FBQ29ELGVBQVAsQ0FBd0JmLElBQXhCLEVBQThCVyxHQUE5QixFQUFtQyxDQUFDM0IsR0FBRCxFQUFNbUIsRUFBTixLQUE0QjtBQUM3RCxjQUFJbkIsR0FBSixFQUFTO0FBQ1AsaUJBQUs5QixNQUFMLENBQVk2QixLQUFaLENBQ0U7QUFBRXNCLGNBQUFBO0FBQUYsYUFERixFQUVFLGlGQUZGO0FBSUEsbUJBQU9FLFFBQVEsQ0FBQ3ZCLEdBQUQsQ0FBZjtBQUNEOztBQUVELGNBQUlWLGdCQUFFUSxLQUFGLENBQVFxQixFQUFSLE1BQWdCLElBQXBCLEVBQTBCO0FBQ3hCLGlCQUFLakQsTUFBTCxDQUFZNkIsS0FBWixDQUNFO0FBQUVzQixjQUFBQTtBQUFGLGFBREYsRUFFRSx3RUFGRixFQUR3QixDQUt4QjtBQUNBOztBQUNBLG1CQUFPLEtBQUt2QyxhQUFMLENBQW1CLEdBQUdrRCxTQUF0QixDQUFQO0FBQ0Q7O0FBRUQsY0FBSWIsRUFBSixFQUFRO0FBQ04saUJBQUtqRCxNQUFMLENBQVk2QixLQUFaLENBQWtCO0FBQUVzQixjQUFBQTtBQUFGLGFBQWxCLEVBQW1DLHNDQUFuQztBQUNBLG1CQUFPRSxRQUFRLENBQUMsSUFBRCxFQUFPSixFQUFQLENBQWY7QUFDRDtBQUNGLFNBdkJEO0FBd0JEO0FBQ0Y7QUFDRjtBQUVEO0FBQ0Y7QUFDQTs7O0FBQ1NyQyxFQUFBQSxhQUFhLENBQ2xCO0FBQUV1QyxJQUFBQSxXQUFGO0FBQWVDLElBQUFBO0FBQWYsR0FEa0IsRUFFbEJOLElBRmtCLEVBR2xCTyxRQUhrQixFQUlaO0FBQ04sVUFBTWpELE9BQU8sR0FBRyxLQUFLQSxPQUFMLENBQWE2QixLQUFiLENBQW1CLENBQW5CLENBQWhCO0FBQ0EsVUFBTUMsSUFBSSxHQUFHLElBQWI7QUFDQSxVQUFNdUIsR0FBRyxHQUFHQyxNQUFNLENBQUNDLE1BQVAsQ0FDVjtBQUFFSixNQUFBQSxJQUFJLEVBQUVKLFdBQVI7QUFBcUJLLE1BQUFBLE9BQU8sRUFBRUo7QUFBOUIsS0FEVSxFQUVWLHlDQUF1QkQsV0FBdkIsRUFBb0MsS0FBS3BELE1BQUwsQ0FBWTZELFFBQWhELENBRlUsQ0FBWjtBQUlBLFNBQUs1RCxNQUFMLENBQVk2QixLQUFaLENBQ0U7QUFBRXNCLE1BQUFBLFdBQUY7QUFBZS9DLE1BQUFBLE9BQU8sRUFBRSxLQUFLQSxPQUFMLENBQWFrQztBQUFyQyxLQURGLEVBRUUsNkRBRkY7O0FBS0EsS0FBQyxTQUFTSCxJQUFULEdBQXNCO0FBQ3JCLFlBQU0xQixNQUFNLEdBQUdMLE9BQU8sQ0FBQ2dDLEtBQVIsRUFBZjs7QUFFQSxVQUFJaEIsZ0JBQUVRLEtBQUYsQ0FBUW5CLE1BQVIsS0FBbUJXLGdCQUFFRSxVQUFGLENBQWFiLE1BQU0sQ0FBQ0csYUFBcEIsTUFBdUMsS0FBOUQsRUFBcUU7QUFDbkVzQixRQUFBQSxJQUFJLENBQUNsQyxNQUFMLENBQVk2QixLQUFaLENBQ0U7QUFBRXNCLFVBQUFBO0FBQUYsU0FERixFQUVFLDBFQUZGO0FBSUEsZUFBT2hCLElBQUksRUFBWDtBQUNELE9BVG9CLENBV3JCOzs7QUFDQTFCLE1BQUFBLE1BQU0sQ0FBQ0csYUFBUCxDQUFxQmtDLElBQXJCLEVBQTJCVyxHQUEzQixFQUFnQyxDQUFDM0IsR0FBRCxFQUFzQm1CLEVBQXRCLEtBQTRDO0FBQzFFLFlBQUk3QixnQkFBRVEsS0FBRixDQUFRRSxHQUFSLE1BQWlCLEtBQWpCLElBQTBCVixnQkFBRTJDLE9BQUYsQ0FBVWpDLEdBQVYsQ0FBOUIsRUFBOEM7QUFDNUNJLFVBQUFBLElBQUksQ0FBQ2xDLE1BQUwsQ0FBWTZCLEtBQVosQ0FBa0I7QUFBRXNCLFlBQUFBO0FBQUYsV0FBbEIsRUFBbUMsc0NBQW5DO0FBQ0EsaUJBQU9FLFFBQVEsQ0FBQ3ZCLEdBQUQsQ0FBZjtBQUNEOztBQUVELFlBQUltQixFQUFKLEVBQVE7QUFDTmYsVUFBQUEsSUFBSSxDQUFDbEMsTUFBTCxDQUFZNkIsS0FBWixDQUFrQjtBQUFFc0IsWUFBQUE7QUFBRixXQUFsQixFQUFtQyxvQ0FBbkM7QUFDQSxpQkFBT0UsUUFBUSxDQUFDLElBQUQsRUFBT0osRUFBUCxDQUFmO0FBQ0Q7O0FBRURmLFFBQUFBLElBQUksQ0FBQ2xDLE1BQUwsQ0FBWTZCLEtBQVosQ0FBa0I7QUFBRXNCLFVBQUFBO0FBQUYsU0FBbEIsRUFBbUMsa0RBQW5DO0FBQ0FoQixRQUFBQSxJQUFJLEdBWnNFLENBWWxFO0FBQ1QsT0FiRDtBQWNELEtBMUJEO0FBMkJEOztBQUVNNkIsRUFBQUEsZ0JBQWdCLEdBQWE7QUFDbEMsVUFBTTVELE9BQU8sR0FBRyxLQUFLQSxPQUFMLENBQWE2QixLQUFiLENBQW1CLENBQW5CLENBQWhCO0FBQ0EsVUFBTWdDLE9BQU8sR0FBRztBQUFFQyxNQUFBQSx5QkFBeUIsRUFBekJBLG9DQUFGO0FBQTZCQyxNQUFBQSxnQkFBZ0IsRUFBaEJBO0FBQTdCLEtBQWhCOztBQUNBLFNBQUssTUFBTTFELE1BQVgsSUFBcUJMLE9BQXJCLEVBQThCO0FBQzVCLFVBQUlLLE1BQU0sQ0FBQ3VELGdCQUFYLEVBQTZCO0FBQzNCLGVBQU92RCxNQUFNLENBQUN1RCxnQkFBUCxDQUF3QkMsT0FBeEIsQ0FBUDtBQUNEO0FBQ0Y7O0FBRUQsV0FBTyxDQUFDRyxHQUFELEVBQXNCQyxHQUF0QixFQUE0Q0MsS0FBNUMsS0FBMEU7QUFDL0VGLE1BQUFBLEdBQUcsQ0FBQ0csS0FBSjs7QUFFQSxZQUFNcEMsSUFBSSxHQUFHLFVBQVVMLEdBQVYsRUFBNEM7QUFDdkRzQyxRQUFBQSxHQUFHLENBQUNJLE1BQUosR0FEdUQsQ0FFdkQ7QUFDQTtBQUNBO0FBQ0E7O0FBQ0EsWUFBSTFDLEdBQUosRUFBUztBQUNQc0MsVUFBQUEsR0FBRyxDQUFDSyxXQUFKLENBQWdCekMsS0FBaEIsR0FBd0JGLEdBQUcsQ0FBQ29CLE9BQTVCO0FBQ0Q7O0FBQ0QsZUFBT29CLEtBQUssRUFBWjtBQUNELE9BVkQ7O0FBWUEsVUFBSSxLQUFLSSxrQkFBTCxDQUF3Qk4sR0FBRyxDQUFDSyxXQUE1QixDQUFKLEVBQThDO0FBQzVDLGVBQU90QyxJQUFJLEVBQVg7QUFDRCxPQWpCOEUsQ0FtQi9FOzs7QUFDQWlDLE1BQUFBLEdBQUcsQ0FBQ0ssV0FBSixHQUFrQiwyQ0FBbEI7QUFFQSxZQUFNO0FBQUVFLFFBQUFBO0FBQUYsVUFBb0JQLEdBQUcsQ0FBQ1EsT0FBOUI7O0FBQ0EsVUFBSXhELGdCQUFFUSxLQUFGLENBQVErQyxhQUFSLENBQUosRUFBNEI7QUFDMUIsZUFBT3hDLElBQUksRUFBWDtBQUNEOztBQUVELFVBQUksQ0FBQyxrQ0FBa0J3QyxhQUFsQixDQUFMLEVBQXVDO0FBQ3JDLGFBQUszRSxNQUFMLENBQVk2QixLQUFaLENBQWtCLDBDQUFsQjtBQUNBLGVBQU9NLElBQUksQ0FBQ1gsaUJBQVVxRCxhQUFWLENBQXdCbEMscUJBQVVtQyxlQUFsQyxDQUFELENBQVg7QUFDRDs7QUFFRCxZQUFNQyxRQUFrQixHQUFHLDRCQUFZLEtBQUtoRixNQUFqQixDQUEzQjtBQUNBLFlBQU07QUFBRUksUUFBQUE7QUFBRixVQUFhLEtBQUtKLE1BQXhCOztBQUVBLFVBQUksNEJBQVlnRixRQUFaLENBQUosRUFBMkI7QUFDekIsYUFBSy9FLE1BQUwsQ0FBWTZCLEtBQVosQ0FBa0Isd0NBQWxCOztBQUNBLGFBQUttRCxvQkFBTCxDQUEwQlosR0FBMUIsRUFBK0JXLFFBQS9CLEVBQXlDNUUsTUFBekMsRUFBaUR3RSxhQUFqRCxFQUFnRXhDLElBQWhFO0FBQ0QsT0FIRCxNQUdPO0FBQ0wsYUFBS25DLE1BQUwsQ0FBWTZCLEtBQVosQ0FBa0IscUNBQWxCOztBQUNBLGFBQUtvRCx1QkFBTCxDQUE2QmIsR0FBN0IsRUFBa0NXLFFBQWxDLEVBQTRDNUUsTUFBNUMsRUFBb0R3RSxhQUFwRCxFQUFtRXhDLElBQW5FO0FBQ0Q7QUFDRixLQTFDRDtBQTJDRDs7QUFFTzhDLEVBQUFBLHVCQUF1QixDQUM3QmIsR0FENkIsRUFFN0JXLFFBRjZCLEVBRzdCNUUsTUFINkIsRUFJN0J3RSxhQUo2QixFQUs3QnhDLElBTDZCLEVBTXZCO0FBQ04sVUFBTTtBQUFFK0MsTUFBQUEsTUFBRjtBQUFVQyxNQUFBQTtBQUFWLFFBQW9CLHFDQUFxQlIsYUFBckIsQ0FBMUI7O0FBQ0EsUUFBSU8sTUFBTSxDQUFDRSxXQUFQLE9BQXlCQyx1QkFBWUQsV0FBWixFQUE3QixFQUF3RDtBQUN0RDtBQUNBLFlBQU1FLFdBQVcsR0FBRyxtQ0FBdUJILEtBQXZCLEVBQThCSSxRQUE5QixFQUFwQjtBQUNBLFlBQU07QUFBRXpDLFFBQUFBLElBQUY7QUFBUTlCLFFBQUFBO0FBQVIsVUFBcUIsa0NBQWtCc0UsV0FBbEIsQ0FBM0I7QUFDQSxXQUFLNUUsWUFBTCxDQUFrQm9DLElBQWxCLEVBQXdCOUIsUUFBeEIsRUFBa0MsQ0FBQ2MsR0FBRCxFQUFNZ0IsSUFBTixLQUFxQjtBQUNyRCxZQUFJLENBQUNoQixHQUFMLEVBQVU7QUFDUnNDLFVBQUFBLEdBQUcsQ0FBQ0ssV0FBSixHQUFrQjNCLElBQWxCO0FBQ0FYLFVBQUFBLElBQUk7QUFDTCxTQUhELE1BR087QUFDTGlDLFVBQUFBLEdBQUcsQ0FBQ0ssV0FBSixHQUFrQiwyQ0FBbEI7QUFDQXRDLFVBQUFBLElBQUksQ0FBQ0wsR0FBRCxDQUFKO0FBQ0Q7QUFDRixPQVJEO0FBU0QsS0FiRCxNQWFPO0FBQ0w7QUFDQSxZQUFNd0QsV0FBZ0IsR0FBRyx5Q0FBeUJQLFFBQXpCLEVBQW1DNUUsTUFBbkMsRUFBMkN3RSxhQUEzQyxDQUF6Qjs7QUFDQSxVQUFJVyxXQUFKLEVBQWlCO0FBQ2Y7QUFDQWxCLFFBQUFBLEdBQUcsQ0FBQ0ssV0FBSixHQUFrQmEsV0FBbEI7QUFDQW5ELFFBQUFBLElBQUk7QUFDTCxPQUpELE1BSU87QUFDTDtBQUNBQSxRQUFBQSxJQUFJLENBQUNYLGlCQUFVZ0UsWUFBVixDQUF1QjdDLHFCQUFVOEMscUJBQWpDLENBQUQsQ0FBSjtBQUNEO0FBQ0Y7QUFDRjs7QUFFT1QsRUFBQUEsb0JBQW9CLENBQzFCWixHQUQwQixFQUUxQlcsUUFGMEIsRUFHMUI1RSxNQUgwQixFQUkxQndFLGFBSjBCLEVBSzFCeEMsSUFMMEIsRUFNcEI7QUFDTixVQUFNbUQsV0FBZ0IsR0FBRyx5Q0FBeUJQLFFBQXpCLEVBQW1DNUUsTUFBbkMsRUFBMkN3RSxhQUEzQyxDQUF6Qjs7QUFDQSxRQUFJVyxXQUFKLEVBQWlCO0FBQ2YsWUFBTTtBQUFFeEMsUUFBQUEsSUFBRjtBQUFROUIsUUFBQUE7QUFBUixVQUFxQnNFLFdBQTNCO0FBQ0EsV0FBSzVFLFlBQUwsQ0FBa0JvQyxJQUFsQixFQUF3QjlCLFFBQXhCLEVBQWtDLENBQUNjLEdBQUQsRUFBTWdCLElBQU4sS0FBcUI7QUFDckQsWUFBSSxDQUFDaEIsR0FBTCxFQUFVO0FBQ1JzQyxVQUFBQSxHQUFHLENBQUNLLFdBQUosR0FBa0IzQixJQUFsQjtBQUNBWCxVQUFBQSxJQUFJO0FBQ0wsU0FIRCxNQUdPO0FBQ0xpQyxVQUFBQSxHQUFHLENBQUNLLFdBQUosR0FBa0IsMkNBQWxCO0FBQ0F0QyxVQUFBQSxJQUFJLENBQUNMLEdBQUQsQ0FBSjtBQUNEO0FBQ0YsT0FSRDtBQVNELEtBWEQsTUFXTztBQUNMO0FBQ0EsYUFBT0ssSUFBSSxDQUFDWCxpQkFBVXFELGFBQVYsQ0FBd0JsQyxxQkFBVW1DLGVBQWxDLENBQUQsQ0FBWDtBQUNEO0FBQ0Y7O0FBRU9KLEVBQUFBLGtCQUFrQixDQUFDRCxXQUFELEVBQW1DO0FBQzNELFdBQU9yRCxnQkFBRXNFLFdBQUYsQ0FBY2pCLFdBQWQsTUFBK0IsS0FBL0IsSUFBd0NyRCxnQkFBRXNFLFdBQUYsQ0FBY2pCLFdBQVcsQ0FBQ2xCLElBQTFCLE1BQW9DLEtBQW5GO0FBQ0Q7QUFFRDtBQUNGO0FBQ0E7OztBQUNTb0MsRUFBQUEsa0JBQWtCLEdBQWE7QUFDcEMsV0FBTyxDQUFDdkIsR0FBRCxFQUFzQkMsR0FBdEIsRUFBNENDLEtBQTVDLEtBQTBFO0FBQy9FLFVBQUksS0FBS0ksa0JBQUwsQ0FBd0JOLEdBQUcsQ0FBQ0ssV0FBNUIsQ0FBSixFQUE4QztBQUM1QyxlQUFPSCxLQUFLLEVBQVo7QUFDRDs7QUFFREYsTUFBQUEsR0FBRyxDQUFDRyxLQUFKOztBQUNBLFlBQU1wQyxJQUFJLEdBQUlMLEdBQUQsSUFBc0M7QUFDakRzQyxRQUFBQSxHQUFHLENBQUNJLE1BQUo7O0FBQ0EsWUFBSTFDLEdBQUosRUFBUztBQUNQO0FBQ0F1QyxVQUFBQSxHQUFHLENBQUN1QixNQUFKLENBQVc5RCxHQUFHLENBQUMrRCxVQUFmLEVBQTJCQyxJQUEzQixDQUFnQ2hFLEdBQUcsQ0FBQ29CLE9BQXBDO0FBQ0Q7O0FBRUQsZUFBT29CLEtBQUssRUFBWjtBQUNELE9BUkQ7O0FBVUEsWUFBTTtBQUFFSyxRQUFBQTtBQUFGLFVBQW9CUCxHQUFHLENBQUNRLE9BQTlCOztBQUNBLFVBQUl4RCxnQkFBRVEsS0FBRixDQUFRK0MsYUFBUixDQUFKLEVBQTRCO0FBQzFCLGVBQU94QyxJQUFJLEVBQVg7QUFDRDs7QUFFRCxVQUFJLENBQUMsa0NBQWtCd0MsYUFBbEIsQ0FBTCxFQUF1QztBQUNyQyxlQUFPeEMsSUFBSSxDQUFDWCxpQkFBVXFELGFBQVYsQ0FBd0JsQyxxQkFBVW1DLGVBQWxDLENBQUQsQ0FBWDtBQUNEOztBQUVELFlBQU1LLEtBQUssR0FBRyxDQUFDUixhQUFhLElBQUksRUFBbEIsRUFBc0JvQixPQUF0QixDQUErQixHQUFFQyx1QkFBYSxHQUE5QyxFQUFrRCxFQUFsRCxDQUFkOztBQUNBLFVBQUksQ0FBQ2IsS0FBTCxFQUFZO0FBQ1YsZUFBT2hELElBQUksRUFBWDtBQUNEOztBQUVELFVBQUltRCxXQUFKOztBQUNBLFVBQUk7QUFDRkEsUUFBQUEsV0FBVyxHQUFHLGlDQUFpQkgsS0FBakIsRUFBd0IsS0FBS3BGLE1BQUwsQ0FBWUksTUFBcEMsQ0FBZDtBQUNELE9BRkQsQ0FFRSxPQUFPMkIsR0FBUCxFQUFZLENBQ1o7QUFDRDs7QUFFRCxVQUFJLEtBQUs0QyxrQkFBTCxDQUF3QlksV0FBeEIsQ0FBSixFQUEwQztBQUN4QyxjQUFNO0FBQUUvQixVQUFBQSxJQUFGO0FBQVFsQixVQUFBQTtBQUFSLFlBQW1CaUQsV0FBekIsQ0FEd0MsQ0FFeEM7O0FBQ0FsQixRQUFBQSxHQUFHLENBQUNLLFdBQUosR0FBa0IsaUNBQWlCbEIsSUFBakIsRUFBdUJsQixNQUF2QixDQUFsQjtBQUNELE9BSkQsTUFJTztBQUNMK0IsUUFBQUEsR0FBRyxDQUFDSyxXQUFKLEdBQWtCLDJDQUFsQjtBQUNEOztBQUVEdEMsTUFBQUEsSUFBSTtBQUNMLEtBOUNEO0FBK0NEOztBQUVzQixRQUFWOEQsVUFBVSxDQUFDbkQsSUFBRCxFQUFtQm9ELFdBQW5CLEVBQWlFO0FBQ3RGLFVBQU07QUFBRUMsTUFBQUEsV0FBRjtBQUFlNUMsTUFBQUEsSUFBZjtBQUFxQmxCLE1BQUFBO0FBQXJCLFFBQWdDUyxJQUF0QztBQUNBLFVBQU1zRCxtQkFBbUIsR0FBR2hGLGdCQUFFUSxLQUFGLENBQVF1RSxXQUFSLElBQXVCLEVBQXZCLEdBQTRCQSxXQUF4RDtBQUNBLFVBQU1FLGFBQWEsR0FBR2pGLGdCQUFFUSxLQUFGLENBQVFTLE1BQVIsSUFBa0I4RCxXQUFsQixHQUFnQzlELE1BQU0sQ0FBQ2lFLE1BQVAsQ0FBY0YsbUJBQWQsQ0FBdEQ7QUFDQSxVQUFNRyxPQUFtQixHQUFHO0FBQzFCSixNQUFBQSxXQUFXLEVBQUVDLG1CQURhO0FBRTFCN0MsTUFBQUEsSUFGMEI7QUFHMUJsQixNQUFBQSxNQUFNLEVBQUVnRTtBQUhrQixLQUE1QjtBQU1BLFVBQU1sQixLQUFhLEdBQUcsTUFBTSw4QkFBWW9CLE9BQVosRUFBcUIsS0FBS3BHLE1BQTFCLEVBQWtDK0YsV0FBbEMsQ0FBNUI7QUFFQSxXQUFPZixLQUFQO0FBQ0Q7QUFFRDtBQUNGO0FBQ0E7OztBQUNTcUIsRUFBQUEsVUFBVSxDQUFDQyxHQUFELEVBQXNCO0FBQ3JDLFdBQU8sNkJBQVdBLEdBQVgsRUFBZ0IsS0FBS3RHLE1BQXJCLENBQVA7QUFDRDs7QUF2ZXlCOztlQTBlYk4sSSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgeyBWZXJkYWNjaW9FcnJvciB9IGZyb20gJ0B2ZXJkYWNjaW8vY29tbW9ucy1hcGknO1xuXG5pbXBvcnQge1xuICBDb25maWcsXG4gIExvZ2dlcixcbiAgQ2FsbGJhY2ssXG4gIElQbHVnaW5BdXRoLFxuICBSZW1vdGVVc2VyLFxuICBKV1RTaWduT3B0aW9ucyxcbiAgU2VjdXJpdHksXG4gIEF1dGhQbHVnaW5QYWNrYWdlLFxuICBBbGxvd0FjY2VzcyxcbiAgUGFja2FnZUFjY2Vzc1xufSBmcm9tICdAdmVyZGFjY2lvL3R5cGVzJztcbmltcG9ydCB7IE5leHRGdW5jdGlvbiB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IGxvYWRQbHVnaW4gZnJvbSAnLi4vbGliL3BsdWdpbi1sb2FkZXInO1xuaW1wb3J0IHsgJFJlcXVlc3RFeHRlbmQsICRSZXNwb25zZUV4dGVuZCwgSUF1dGgsIEFFU1BheWxvYWQgfSBmcm9tICcuLi8uLi90eXBlcyc7XG5pbXBvcnQgeyBBUElfRVJST1IsIFNVUFBPUlRfRVJST1JTLCBUT0tFTl9CQVNJQywgVE9LRU5fQkVBUkVSIH0gZnJvbSAnLi9jb25zdGFudHMnO1xuaW1wb3J0IHsgYWVzRW5jcnlwdCwgc2lnblBheWxvYWQgfSBmcm9tICcuL2NyeXB0by11dGlscyc7XG5pbXBvcnQge1xuICBnZXREZWZhdWx0UGx1Z2lucyxcbiAgZ2V0TWlkZGxld2FyZUNyZWRlbnRpYWxzLFxuICB2ZXJpZnlKV1RQYXlsb2FkLFxuICBjcmVhdGVBbm9ueW1vdXNSZW1vdGVVc2VyLFxuICBpc0F1dGhIZWFkZXJWYWxpZCxcbiAgZ2V0U2VjdXJpdHksXG4gIGlzQUVTTGVnYWN5LFxuICBwYXJzZUF1dGhUb2tlbkhlYWRlcixcbiAgcGFyc2VCYXNpY1BheWxvYWQsXG4gIGNyZWF0ZVJlbW90ZVVzZXJcbn0gZnJvbSAnLi9hdXRoLXV0aWxzJztcbmltcG9ydCB7IGNvbnZlcnRQYXlsb2FkVG9CYXNlNjQsIEVycm9yQ29kZSB9IGZyb20gJy4vdXRpbHMnO1xuaW1wb3J0IHsgZ2V0TWF0Y2hlZFBhY2thZ2VzU3BlYyB9IGZyb20gJy4vY29uZmlnLXV0aWxzJztcblxuLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXZhci1yZXF1aXJlcyAqL1xuY29uc3QgTG9nZ2VyQXBpID0gcmVxdWlyZSgnLi9sb2dnZXInKTtcblxuY2xhc3MgQXV0aCBpbXBsZW1lbnRzIElBdXRoIHtcbiAgcHVibGljIGNvbmZpZzogQ29uZmlnO1xuICBwdWJsaWMgbG9nZ2VyOiBMb2dnZXI7XG4gIHB1YmxpYyBzZWNyZXQ6IHN0cmluZztcbiAgcHVibGljIHBsdWdpbnM6IElQbHVnaW5BdXRoPENvbmZpZz5bXTtcblxuICBwdWJsaWMgY29uc3RydWN0b3IoY29uZmlnOiBDb25maWcpIHtcbiAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICB0aGlzLmxvZ2dlciA9IExvZ2dlckFwaS5sb2dnZXIuY2hpbGQoeyBzdWI6ICdhdXRoJyB9KTtcbiAgICB0aGlzLnNlY3JldCA9IGNvbmZpZy5zZWNyZXQ7XG4gICAgdGhpcy5wbHVnaW5zID0gdGhpcy5fbG9hZFBsdWdpbihjb25maWcpO1xuICAgIHRoaXMuX2FwcGx5RGVmYXVsdFBsdWdpbnMoKTtcbiAgfVxuXG4gIHByaXZhdGUgX2xvYWRQbHVnaW4oY29uZmlnOiBDb25maWcpOiBJUGx1Z2luQXV0aDxDb25maWc+W10ge1xuICAgIGNvbnN0IHBsdWdpbk9wdGlvbnMgPSB7XG4gICAgICBjb25maWcsXG4gICAgICBsb2dnZXI6IHRoaXMubG9nZ2VyXG4gICAgfTtcblxuICAgIHJldHVybiBsb2FkUGx1Z2luPElQbHVnaW5BdXRoPENvbmZpZz4+KFxuICAgICAgY29uZmlnLFxuICAgICAgY29uZmlnLmF1dGgsXG4gICAgICBwbHVnaW5PcHRpb25zLFxuICAgICAgKHBsdWdpbjogSVBsdWdpbkF1dGg8Q29uZmlnPik6IGJvb2xlYW4gPT4ge1xuICAgICAgICBjb25zdCB7IGF1dGhlbnRpY2F0ZSwgYWxsb3dfYWNjZXNzLCBhbGxvd19wdWJsaXNoIH0gPSBwbHVnaW47XG5cbiAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICByZXR1cm4gYXV0aGVudGljYXRlIHx8IGFsbG93X2FjY2VzcyB8fCBhbGxvd19wdWJsaXNoO1xuICAgICAgfVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIF9hcHBseURlZmF1bHRQbHVnaW5zKCk6IHZvaWQge1xuICAgIHRoaXMucGx1Z2lucy5wdXNoKGdldERlZmF1bHRQbHVnaW5zKCkpO1xuICB9XG5cbiAgcHVibGljIGNoYW5nZVBhc3N3b3JkKFxuICAgIHVzZXJuYW1lOiBzdHJpbmcsXG4gICAgcGFzc3dvcmQ6IHN0cmluZyxcbiAgICBuZXdQYXNzd29yZDogc3RyaW5nLFxuICAgIGNiOiBDYWxsYmFja1xuICApOiB2b2lkIHtcbiAgICBjb25zdCB2YWxpZFBsdWdpbnMgPSBfLmZpbHRlcih0aGlzLnBsdWdpbnMsIChwbHVnaW4pID0+IF8uaXNGdW5jdGlvbihwbHVnaW4uY2hhbmdlUGFzc3dvcmQpKTtcblxuICAgIGlmIChfLmlzRW1wdHkodmFsaWRQbHVnaW5zKSkge1xuICAgICAgcmV0dXJuIGNiKEVycm9yQ29kZS5nZXRJbnRlcm5hbEVycm9yKFNVUFBPUlRfRVJST1JTLlBMVUdJTl9NSVNTSU5HX0lOVEVSRkFDRSkpO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgcGx1Z2luIG9mIHZhbGlkUGx1Z2lucykge1xuICAgICAgaWYgKF8uaXNOaWwocGx1Z2luKSB8fCBfLmlzRnVuY3Rpb24ocGx1Z2luLmNoYW5nZVBhc3N3b3JkKSA9PT0gZmFsc2UpIHtcbiAgICAgICAgdGhpcy5sb2dnZXIudHJhY2UoJ2F1dGggcGx1Z2luIGRvZXMgbm90IGltcGxlbWVudCBjaGFuZ2VQYXNzd29yZCwgdHJ5aW5nIG5leHQgb25lJyk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5sb2dnZXIudHJhY2UoeyB1c2VybmFtZSB9LCAndXBkYXRpbmcgcGFzc3dvcmQgZm9yIEB7dXNlcm5hbWV9Jyk7XG4gICAgICAgIHBsdWdpbi5jaGFuZ2VQYXNzd29yZCEodXNlcm5hbWUsIHBhc3N3b3JkLCBuZXdQYXNzd29yZCwgKGVyciwgcHJvZmlsZSk6IHZvaWQgPT4ge1xuICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgIHRoaXMubG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgICB7IHVzZXJuYW1lLCBlcnIgfSxcbiAgICAgICAgICAgICAgYEFuIGVycm9yIGhhcyBiZWVuIHByb2R1Y2VkXG4gICAgICAgICAgICB1cGRhdGluZyB0aGUgcGFzc3dvcmQgZm9yIEB7dXNlcm5hbWV9LiBFcnJvcjogQHtlcnIubWVzc2FnZX1gXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuIGNiKGVycik7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy5sb2dnZXIudHJhY2UoeyB1c2VybmFtZSB9LCAndXBkYXRlZCBwYXNzd29yZCBmb3IgQHt1c2VybmFtZX0gd2FzIHN1Y2Nlc3NmdWwnKTtcbiAgICAgICAgICByZXR1cm4gY2IobnVsbCwgcHJvZmlsZSk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBhdXRoZW50aWNhdGUodXNlcm5hbWU6IHN0cmluZywgcGFzc3dvcmQ6IHN0cmluZywgY2I6IENhbGxiYWNrKTogdm9pZCB7XG4gICAgY29uc3QgcGx1Z2lucyA9IHRoaXMucGx1Z2lucy5zbGljZSgwKTtcbiAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAoZnVuY3Rpb24gbmV4dCgpOiB2b2lkIHtcbiAgICAgIGNvbnN0IHBsdWdpbiA9IHBsdWdpbnMuc2hpZnQoKSBhcyBJUGx1Z2luQXV0aDxDb25maWc+O1xuXG4gICAgICBpZiAoXy5pc0Z1bmN0aW9uKHBsdWdpbi5hdXRoZW50aWNhdGUpID09PSBmYWxzZSkge1xuICAgICAgICByZXR1cm4gbmV4dCgpO1xuICAgICAgfVxuXG4gICAgICBzZWxmLmxvZ2dlci50cmFjZSh7IHVzZXJuYW1lIH0sICdhdXRoZW50aWNhdGluZyBAe3VzZXJuYW1lfScpO1xuICAgICAgcGx1Z2luLmF1dGhlbnRpY2F0ZSh1c2VybmFtZSwgcGFzc3dvcmQsIGZ1bmN0aW9uIChlcnIsIGdyb3Vwcyk6IHZvaWQge1xuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgc2VsZi5sb2dnZXIudHJhY2UoXG4gICAgICAgICAgICB7IHVzZXJuYW1lLCBlcnIgfSxcbiAgICAgICAgICAgICdhdXRoZW50aWNhdGluZyBmb3IgdXNlciBAe3VzZXJuYW1lfSBmYWlsZWQuIEVycm9yOiBAe2Vyci5tZXNzYWdlfSdcbiAgICAgICAgICApO1xuICAgICAgICAgIHJldHVybiBjYihlcnIpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRXhwZWN0OiBTS0lQIGlmIGdyb3VwcyBpcyBmYWxzZXkgYW5kIG5vdCBhbiBhcnJheVxuICAgICAgICAvLyAgICAgICAgIHdpdGggYXQgbGVhc3Qgb25lIGl0ZW0gKHRydXRoeSBsZW5ndGgpXG4gICAgICAgIC8vIEV4cGVjdDogQ09OVElOVUUgb3RoZXJ3aXNlICh3aWxsIGVycm9yIGlmIGdyb3VwcyBpcyBub3RcbiAgICAgICAgLy8gICAgICAgICBhbiBhcnJheSwgYnV0IHRoaXMgaXMgY3VycmVudCBiZWhhdmlvcilcbiAgICAgICAgLy8gQ2F2ZWF0OiBTVFJJTkcgKGlmIHZhbGlkKSB3aWxsIHBhc3Mgc3VjY2Vzc2Z1bGx5XG4gICAgICAgIC8vICAgICAgICAgYnVnIGdpdmUgdW5leHBlY3RlZCByZXN1bHRzXG4gICAgICAgIC8vIEluZm86IENhbm5vdCB1c2UgYD09IGZhbHNlIHRvIGNoZWNrIGZhbHNleSB2YWx1ZXNgXG4gICAgICAgIGlmICghIWdyb3VwcyAmJiBncm91cHMubGVuZ3RoICE9PSAwKSB7XG4gICAgICAgICAgLy8gVE9ETzogY3JlYXRlIGEgYmV0dGVyIHVuZGVyc3RhbmRpbmcgb2YgZXhwZWN0YXRpb25zXG4gICAgICAgICAgaWYgKF8uaXNTdHJpbmcoZ3JvdXBzKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcigncGx1Z2luIGdyb3VwIGVycm9yOiBpbnZhbGlkIHR5cGUgZm9yIGZ1bmN0aW9uJyk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IGlzR3JvdXBWYWxpZDogYm9vbGVhbiA9IF8uaXNBcnJheShncm91cHMpO1xuICAgICAgICAgIGlmICghaXNHcm91cFZhbGlkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKEFQSV9FUlJPUi5CQURfRk9STUFUX1VTRVJfR1JPVVApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHNlbGYubG9nZ2VyLnRyYWNlKFxuICAgICAgICAgICAgeyB1c2VybmFtZSwgZ3JvdXBzIH0sXG4gICAgICAgICAgICAnYXV0aGVudGljYXRpb24gZm9yIHVzZXIgQHt1c2VybmFtZX0gd2FzIHN1Y2Nlc3NmdWxseS4gR3JvdXBzOiBAe2dyb3Vwc30nXG4gICAgICAgICAgKTtcbiAgICAgICAgICByZXR1cm4gY2IoZXJyLCBjcmVhdGVSZW1vdGVVc2VyKHVzZXJuYW1lLCBncm91cHMpKTtcbiAgICAgICAgfVxuICAgICAgICBuZXh0KCk7XG4gICAgICB9KTtcbiAgICB9KSgpO1xuICB9XG5cbiAgcHVibGljIGFkZF91c2VyKHVzZXI6IHN0cmluZywgcGFzc3dvcmQ6IHN0cmluZywgY2I6IENhbGxiYWNrKTogdm9pZCB7XG4gICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgY29uc3QgcGx1Z2lucyA9IHRoaXMucGx1Z2lucy5zbGljZSgwKTtcbiAgICB0aGlzLmxvZ2dlci50cmFjZSh7IHVzZXIgfSwgJ2FkZCB1c2VyIEB7dXNlcn0nKTtcblxuICAgIChmdW5jdGlvbiBuZXh0KCk6IHZvaWQge1xuICAgICAgY29uc3QgcGx1Z2luID0gcGx1Z2lucy5zaGlmdCgpIGFzIElQbHVnaW5BdXRoPENvbmZpZz47XG4gICAgICBsZXQgbWV0aG9kID0gJ2FkZHVzZXInO1xuICAgICAgaWYgKF8uaXNGdW5jdGlvbihwbHVnaW5bbWV0aG9kXSkgPT09IGZhbHNlKSB7XG4gICAgICAgIG1ldGhvZCA9ICdhZGRfdXNlcic7XG4gICAgICAgIHNlbGYubG9nZ2VyLndhcm4oXG4gICAgICAgICAgJ3RoZSBwbHVnaW4gbWV0aG9kIGFkZF91c2VyIGluIHRoZSBhdXRoIHBsdWdpbiBpcyBkZXByZWNhdGVkIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gbmV4dCBtYWpvciByZWxlYXNlLCBub3RpZnkgdG8gdGhlIHBsdWdpbiBhdXRob3InXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIGlmIChfLmlzRnVuY3Rpb24ocGx1Z2luW21ldGhvZF0pID09PSBmYWxzZSkge1xuICAgICAgICBuZXh0KCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBwLmFkZF91c2VyKCkgZXhlY3V0aW9uXG4gICAgICAgIHBsdWdpblttZXRob2RdKHVzZXIsIHBhc3N3b3JkLCBmdW5jdGlvbiAoZXJyLCBvayk6IHZvaWQge1xuICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgIHNlbGYubG9nZ2VyLnRyYWNlKFxuICAgICAgICAgICAgICB7IHVzZXIsIGVycjogZXJyLm1lc3NhZ2UgfSxcbiAgICAgICAgICAgICAgJ3RoZSB1c2VyIEB7dXNlcn0gY291bGQgbm90IGJlaW5nIGFkZGVkLiBFcnJvcjogQHtlcnJ9J1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiBjYihlcnIpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAob2spIHtcbiAgICAgICAgICAgIHNlbGYubG9nZ2VyLnRyYWNlKHsgdXNlciB9LCAndGhlIHVzZXIgQHt1c2VyfSBoYXMgYmVlbiBhZGRlZCcpO1xuICAgICAgICAgICAgcmV0dXJuIHNlbGYuYXV0aGVudGljYXRlKHVzZXIsIHBhc3N3b3JkLCBjYik7XG4gICAgICAgICAgfVxuICAgICAgICAgIG5leHQoKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSkoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbGxvdyB1c2VyIHRvIGFjY2VzcyBhIHBhY2thZ2UuXG4gICAqL1xuICBwdWJsaWMgYWxsb3dfYWNjZXNzKFxuICAgIHsgcGFja2FnZU5hbWUsIHBhY2thZ2VWZXJzaW9uIH06IEF1dGhQbHVnaW5QYWNrYWdlLFxuICAgIHVzZXI6IFJlbW90ZVVzZXIsXG4gICAgY2FsbGJhY2s6IENhbGxiYWNrXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IHBsdWdpbnMgPSB0aGlzLnBsdWdpbnMuc2xpY2UoMCk7XG4gICAgY29uc3QgcGtnQWxsb3dBY2NlczogQWxsb3dBY2Nlc3MgPSB7IG5hbWU6IHBhY2thZ2VOYW1lLCB2ZXJzaW9uOiBwYWNrYWdlVmVyc2lvbiB9O1xuICAgIGNvbnN0IHBrZyA9IE9iamVjdC5hc3NpZ24oXG4gICAgICB7fSxcbiAgICAgIHBrZ0FsbG93QWNjZXMsXG4gICAgICBnZXRNYXRjaGVkUGFja2FnZXNTcGVjKHBhY2thZ2VOYW1lLCB0aGlzLmNvbmZpZy5wYWNrYWdlcylcbiAgICApIGFzIEFsbG93QWNjZXNzICYgUGFja2FnZUFjY2VzcztcbiAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICB0aGlzLmxvZ2dlci50cmFjZSh7IHBhY2thZ2VOYW1lIH0sICdhbGxvdyBhY2Nlc3MgZm9yIEB7cGFja2FnZU5hbWV9Jyk7XG5cbiAgICAoZnVuY3Rpb24gbmV4dCgpOiB2b2lkIHtcbiAgICAgIGNvbnN0IHBsdWdpbjogSVBsdWdpbkF1dGg8Q29uZmlnPiA9IHBsdWdpbnMuc2hpZnQoKSBhcyBJUGx1Z2luQXV0aDxDb25maWc+O1xuXG4gICAgICBpZiAoXy5pc05pbChwbHVnaW4pIHx8IF8uaXNGdW5jdGlvbihwbHVnaW4uYWxsb3dfYWNjZXNzKSA9PT0gZmFsc2UpIHtcbiAgICAgICAgcmV0dXJuIG5leHQoKTtcbiAgICAgIH1cblxuICAgICAgcGx1Z2luLmFsbG93X2FjY2VzcyEodXNlciwgcGtnLCBmdW5jdGlvbiAoZXJyLCBvazogYm9vbGVhbik6IHZvaWQge1xuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgc2VsZi5sb2dnZXIudHJhY2UoXG4gICAgICAgICAgICB7IHBhY2thZ2VOYW1lLCBlcnIgfSxcbiAgICAgICAgICAgICdmb3JiaWRkZW4gYWNjZXNzIGZvciBAe3BhY2thZ2VOYW1lfS4gRXJyb3I6IEB7ZXJyLm1lc3NhZ2V9J1xuICAgICAgICAgICk7XG4gICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKGVycik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAob2spIHtcbiAgICAgICAgICBzZWxmLmxvZ2dlci50cmFjZSh7IHBhY2thZ2VOYW1lIH0sICdhbGxvd2VkIGFjY2VzcyBmb3IgQHtwYWNrYWdlTmFtZX0nKTtcbiAgICAgICAgICByZXR1cm4gY2FsbGJhY2sobnVsbCwgb2spO1xuICAgICAgICB9XG5cbiAgICAgICAgbmV4dCgpOyAvLyBjYihudWxsLCBmYWxzZSkgY2F1c2VzIG5leHQgcGx1Z2luIHRvIHJvbGxcbiAgICAgIH0pO1xuICAgIH0pKCk7XG4gIH1cblxuICBwdWJsaWMgYWxsb3dfdW5wdWJsaXNoKFxuICAgIHsgcGFja2FnZU5hbWUsIHBhY2thZ2VWZXJzaW9uIH06IEF1dGhQbHVnaW5QYWNrYWdlLFxuICAgIHVzZXI6IFJlbW90ZVVzZXIsXG4gICAgY2FsbGJhY2s6IENhbGxiYWNrXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IHBrZyA9IE9iamVjdC5hc3NpZ24oXG4gICAgICB7IG5hbWU6IHBhY2thZ2VOYW1lLCB2ZXJzaW9uOiBwYWNrYWdlVmVyc2lvbiB9LFxuICAgICAgZ2V0TWF0Y2hlZFBhY2thZ2VzU3BlYyhwYWNrYWdlTmFtZSwgdGhpcy5jb25maWcucGFja2FnZXMpXG4gICAgKTtcbiAgICB0aGlzLmxvZ2dlci50cmFjZSh7IHBhY2thZ2VOYW1lIH0sICdhbGxvdyB1bnB1Ymxpc2ggZm9yIEB7cGFja2FnZU5hbWV9Jyk7XG5cbiAgICBmb3IgKGNvbnN0IHBsdWdpbiBvZiB0aGlzLnBsdWdpbnMpIHtcbiAgICAgIGlmIChfLmlzTmlsKHBsdWdpbikgfHwgXy5pc0Z1bmN0aW9uKHBsdWdpbi5hbGxvd191bnB1Ymxpc2gpID09PSBmYWxzZSkge1xuICAgICAgICB0aGlzLmxvZ2dlci50cmFjZShcbiAgICAgICAgICB7IHBhY2thZ2VOYW1lIH0sXG4gICAgICAgICAgJ2FsbG93IHVucHVibGlzaCBmb3IgQHtwYWNrYWdlTmFtZX0gcGx1Z2luIGRvZXMgbm90IGltcGxlbWVudCBhbGxvd191bnB1Ymxpc2gnXG4gICAgICAgICk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcGx1Z2luLmFsbG93X3VucHVibGlzaCEodXNlciwgcGtnLCAoZXJyLCBvazogYm9vbGVhbik6IHZvaWQgPT4ge1xuICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgIHRoaXMubG9nZ2VyLnRyYWNlKFxuICAgICAgICAgICAgICB7IHBhY2thZ2VOYW1lIH0sXG4gICAgICAgICAgICAgICdmb3JiaWRkZW4gcHVibGlzaCBmb3IgQHtwYWNrYWdlTmFtZX0sIGl0IHdpbGwgZmFsbGJhY2sgb24gdW5wdWJsaXNoIHBlcm1pc3Npb25zJ1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhlcnIpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChfLmlzTmlsKG9rKSA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgdGhpcy5sb2dnZXIudHJhY2UoXG4gICAgICAgICAgICAgIHsgcGFja2FnZU5hbWUgfSxcbiAgICAgICAgICAgICAgJ3dlIGJ5cGFzcyB1bnB1Ymxpc2ggZm9yIEB7cGFja2FnZU5hbWV9LCBwdWJsaXNoIHdpbGwgaGFuZGxlIHRoZSBhY2Nlc3MnXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5hbGxvd19wdWJsaXNoKC4uLmFyZ3VtZW50cyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKG9rKSB7XG4gICAgICAgICAgICB0aGlzLmxvZ2dlci50cmFjZSh7IHBhY2thZ2VOYW1lIH0sICdhbGxvd2VkIHVucHVibGlzaCBmb3IgQHtwYWNrYWdlTmFtZX0nKTtcbiAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhudWxsLCBvayk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQWxsb3cgdXNlciB0byBwdWJsaXNoIGEgcGFja2FnZS5cbiAgICovXG4gIHB1YmxpYyBhbGxvd19wdWJsaXNoKFxuICAgIHsgcGFja2FnZU5hbWUsIHBhY2thZ2VWZXJzaW9uIH06IEF1dGhQbHVnaW5QYWNrYWdlLFxuICAgIHVzZXI6IFJlbW90ZVVzZXIsXG4gICAgY2FsbGJhY2s6IENhbGxiYWNrXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IHBsdWdpbnMgPSB0aGlzLnBsdWdpbnMuc2xpY2UoMCk7XG4gICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgY29uc3QgcGtnID0gT2JqZWN0LmFzc2lnbihcbiAgICAgIHsgbmFtZTogcGFja2FnZU5hbWUsIHZlcnNpb246IHBhY2thZ2VWZXJzaW9uIH0sXG4gICAgICBnZXRNYXRjaGVkUGFja2FnZXNTcGVjKHBhY2thZ2VOYW1lLCB0aGlzLmNvbmZpZy5wYWNrYWdlcylcbiAgICApO1xuICAgIHRoaXMubG9nZ2VyLnRyYWNlKFxuICAgICAgeyBwYWNrYWdlTmFtZSwgcGx1Z2luczogdGhpcy5wbHVnaW5zLmxlbmd0aCB9LFxuICAgICAgJ2FsbG93IHB1Ymxpc2ggZm9yIEB7cGFja2FnZU5hbWV9IGluaXQgfCBwbHVnaW5zOiBAe3BsdWdpbnN9J1xuICAgICk7XG5cbiAgICAoZnVuY3Rpb24gbmV4dCgpOiB2b2lkIHtcbiAgICAgIGNvbnN0IHBsdWdpbiA9IHBsdWdpbnMuc2hpZnQoKTtcblxuICAgICAgaWYgKF8uaXNOaWwocGx1Z2luKSB8fCBfLmlzRnVuY3Rpb24ocGx1Z2luLmFsbG93X3B1Ymxpc2gpID09PSBmYWxzZSkge1xuICAgICAgICBzZWxmLmxvZ2dlci50cmFjZShcbiAgICAgICAgICB7IHBhY2thZ2VOYW1lIH0sXG4gICAgICAgICAgJ2FsbG93IHB1Ymxpc2ggZm9yIEB7cGFja2FnZU5hbWV9IHBsdWdpbiBkb2VzIG5vdCBpbXBsZW1lbnQgYWxsb3dfcHVibGlzaCdcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIG5leHQoKTtcbiAgICAgIH1cblxuICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgcGx1Z2luLmFsbG93X3B1Ymxpc2godXNlciwgcGtnLCAoZXJyOiBWZXJkYWNjaW9FcnJvciwgb2s6IGJvb2xlYW4pOiB2b2lkID0+IHtcbiAgICAgICAgaWYgKF8uaXNOaWwoZXJyKSA9PT0gZmFsc2UgJiYgXy5pc0Vycm9yKGVycikpIHtcbiAgICAgICAgICBzZWxmLmxvZ2dlci50cmFjZSh7IHBhY2thZ2VOYW1lIH0sICdmb3JiaWRkZW4gcHVibGlzaCBmb3IgQHtwYWNrYWdlTmFtZX0nKTtcbiAgICAgICAgICByZXR1cm4gY2FsbGJhY2soZXJyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChvaykge1xuICAgICAgICAgIHNlbGYubG9nZ2VyLnRyYWNlKHsgcGFja2FnZU5hbWUgfSwgJ2FsbG93ZWQgcHVibGlzaCBmb3IgQHtwYWNrYWdlTmFtZX0nKTtcbiAgICAgICAgICByZXR1cm4gY2FsbGJhY2sobnVsbCwgb2spO1xuICAgICAgICB9XG5cbiAgICAgICAgc2VsZi5sb2dnZXIudHJhY2UoeyBwYWNrYWdlTmFtZSB9LCAnYWxsb3cgcHVibGlzaCBza2lwIHZhbGlkYXRpb24gZm9yIEB7cGFja2FnZU5hbWV9Jyk7XG4gICAgICAgIG5leHQoKTsgLy8gY2IobnVsbCwgZmFsc2UpIGNhdXNlcyBuZXh0IHBsdWdpbiB0byByb2xsXG4gICAgICB9KTtcbiAgICB9KSgpO1xuICB9XG5cbiAgcHVibGljIGFwaUpXVG1pZGRsZXdhcmUoKTogRnVuY3Rpb24ge1xuICAgIGNvbnN0IHBsdWdpbnMgPSB0aGlzLnBsdWdpbnMuc2xpY2UoMCk7XG4gICAgY29uc3QgaGVscGVycyA9IHsgY3JlYXRlQW5vbnltb3VzUmVtb3RlVXNlci