verdaccio
Version:
A lightweight private npm proxy registry
747 lines (591 loc) • 76.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _zlib = _interopRequireDefault(require("zlib"));
var _stream = _interopRequireDefault(require("stream"));
var _url = _interopRequireDefault(require("url"));
var _JSONStream = _interopRequireDefault(require("JSONStream"));
var _lodash = _interopRequireDefault(require("lodash"));
var _request = _interopRequireDefault(require("request"));
var _streams = require("@verdaccio/streams");
var _utils = require("./utils");
var _constants = require("./constants");
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; }
const LoggerApi = require('./logger');
const encode = function (thing) {
return encodeURIComponent(thing).replace(/^%40/, '@');
};
const jsonContentType = _constants.HEADERS.JSON;
const contentTypeAccept = `${jsonContentType};`;
/**
* Just a helper (`config[key] || default` doesn't work because of zeroes)
*/
const setConfig = (config, key, def) => {
return _lodash.default.isNil(config[key]) === false ? config[key] : def;
};
/**
* Implements Storage interface
* (same for storage.js, local-storage.js, up-storage.js)
*/
class ProxyStorage {
// FIXME: upname is assigned to each instance
// @ts-ignore
// FIXME: proxy can be boolean or object, something smells here
// @ts-ignore
// @ts-ignore
/**
* Constructor
* @param {*} config
* @param {*} mainConfig
*/
constructor(config, mainConfig) {
_defineProperty(this, "config", void 0);
_defineProperty(this, "failed_requests", void 0);
_defineProperty(this, "userAgent", void 0);
_defineProperty(this, "ca", void 0);
_defineProperty(this, "logger", void 0);
_defineProperty(this, "server_id", void 0);
_defineProperty(this, "url", void 0);
_defineProperty(this, "maxage", void 0);
_defineProperty(this, "timeout", void 0);
_defineProperty(this, "max_fails", void 0);
_defineProperty(this, "fail_timeout", void 0);
_defineProperty(this, "agent_options", void 0);
_defineProperty(this, "upname", void 0);
_defineProperty(this, "proxy", void 0);
_defineProperty(this, "last_request_time", void 0);
_defineProperty(this, "strict_ssl", void 0);
this.config = config;
this.failed_requests = 0;
this.userAgent = mainConfig.user_agent;
this.ca = config.ca;
this.logger = LoggerApi.logger.child({
sub: 'out'
});
this.server_id = mainConfig.server_id;
this.url = _url.default.parse(this.config.url); // $FlowFixMe
this._setupProxy(this.url.hostname, config, mainConfig, this.url.protocol === 'https:');
this.config.url = this.config.url.replace(/\/$/, '');
if (this.config.timeout && Number(this.config.timeout) >= 1000) {
this.logger.warn(['Too big timeout value: ' + this.config.timeout, 'We changed time format to nginx-like one', '(see http://nginx.org/en/docs/syntax.html)', 'so please update your config accordingly'].join('\n'));
} // a bunch of different configurable timers
this.maxage = (0, _utils.parseInterval)(setConfig(this.config, 'maxage', '2m'));
this.timeout = (0, _utils.parseInterval)(setConfig(this.config, 'timeout', '30s'));
this.max_fails = Number(setConfig(this.config, 'max_fails', 2));
this.fail_timeout = (0, _utils.parseInterval)(setConfig(this.config, 'fail_timeout', '5m'));
this.strict_ssl = Boolean(setConfig(this.config, 'strict_ssl', true));
this.agent_options = setConfig(this.config, 'agent_options', {
keepAlive: true,
maxSockets: 40,
maxFreeSockets: 10
});
}
/**
* Fetch an asset.
* @param {*} options
* @param {*} cb
* @return {Request}
*/
request(options, cb) {
let json;
if (this._statusCheck() === false) {
const streamRead = new _stream.default.Readable();
process.nextTick(function () {
if (cb) {
cb(_utils.ErrorCode.getInternalError(_constants.API_ERROR.UPLINK_OFFLINE));
}
streamRead.emit('error', _utils.ErrorCode.getInternalError(_constants.API_ERROR.UPLINK_OFFLINE));
}); // $FlowFixMe
streamRead._read = function () {}; // preventing 'Uncaught, unspecified "error" event'
streamRead.on('error', function () {});
return streamRead;
}
const self = this;
const headers = this._setHeaders(options);
this._addProxyHeaders(options.req, headers);
this._overrideWithUpLinkConfLocaligHeaders(headers);
const method = options.method || 'GET';
const uri = options.uri_full || this.config.url + options.uri;
self.logger.info({
method: method,
headers: headers,
uri: uri
}, "making request: '@{method} @{uri}'");
if ((0, _utils.isObject)(options.json)) {
json = JSON.stringify(options.json);
headers['Content-Type'] = headers['Content-Type'] || _constants.HEADERS.JSON;
}
const requestCallback = cb ? function (err, res, body) {
let error;
const responseLength = err ? 0 : body.length; // $FlowFixMe
processBody();
logActivity(); // $FlowFixMe
cb(err, res, body);
/**
* Perform a decode.
*/
function processBody() {
if (err) {
error = err.message;
return;
}
if (options.json && res.statusCode < 300) {
try {
// $FlowFixMe
body = JSON.parse(body.toString(_constants.CHARACTER_ENCODING.UTF8));
} catch (_err) {
body = {};
err = _err;
error = err.message;
}
}
if (!err && (0, _utils.isObject)(body)) {
if (_lodash.default.isString(body.error)) {
error = body.error;
}
}
}
/**
* Perform a log.
*/
function logActivity() {
let message = "@{!status}, req: '@{request.method} @{request.url}'";
message += error ? ', error: @{!error}' : ', bytes: @{bytes.in}/@{bytes.out}';
self.logger.warn({
err: err || undefined,
// if error is null/false change this to undefined so it wont log
request: {
method: method,
url: uri
},
level: 35,
// http
status: res != null ? res.statusCode : 'ERR',
error: error,
bytes: {
in: json ? json.length : 0,
out: responseLength || 0
}
}, message);
}
} : undefined;
let requestOptions = {
url: uri,
method: method,
headers: headers,
body: json,
proxy: this.proxy,
encoding: null,
gzip: true,
timeout: this.timeout,
strictSSL: this.strict_ssl,
agentOptions: this.agent_options
};
if (this.ca) {
requestOptions = Object.assign({}, requestOptions, {
ca: this.ca
});
}
const req = (0, _request.default)(requestOptions, requestCallback);
let statusCalled = false;
req.on('response', function (res) {
// FIXME: _verdaccio_aborted seems not used
// @ts-ignore
if (!req._verdaccio_aborted && !statusCalled) {
statusCalled = true;
self._statusCheck(true);
}
if (_lodash.default.isNil(requestCallback) === false) {
(function do_log() {
const message = "@{!status}, req: '@{request.method} @{request.url}' (streaming)";
self.logger.warn({
request: {
method: method,
url: uri
},
level: 35,
// http
status: _lodash.default.isNull(res) === false ? res.statusCode : 'ERR'
}, message);
})();
}
});
req.on('error', function (_err) {
// FIXME: _verdaccio_aborted seems not used
// @ts-ignore
if (!req._verdaccio_aborted && !statusCalled) {
statusCalled = true;
self._statusCheck(false);
}
}); // @ts-ignore
return req;
}
/**
* Set default headers.
* @param {Object} options
* @return {Object}
* @private
*/
_setHeaders(options) {
const headers = options.headers || {};
const accept = _constants.HEADERS.ACCEPT;
const acceptEncoding = _constants.HEADERS.ACCEPT_ENCODING;
const userAgent = _constants.HEADERS.USER_AGENT;
headers[accept] = headers[accept] || contentTypeAccept;
headers[acceptEncoding] = headers[acceptEncoding] || 'gzip'; // registry.npmjs.org will only return search result if user-agent include string 'npm'
headers[userAgent] = headers[userAgent] || `npm (${this.userAgent})`;
return this._setAuth(headers);
}
/**
* Validate configuration auth and assign Header authorization
* @param {Object} headers
* @return {Object}
* @private
*/
_setAuth(headers) {
const {
auth
} = this.config;
if (_lodash.default.isNil(auth) || headers[_constants.HEADERS.AUTHORIZATION]) {
return headers;
} // $FlowFixMe
if (_lodash.default.isObject(auth) === false && _lodash.default.isObject(auth.token) === false) {
this._throwErrorAuth('Auth invalid');
} // get NPM_TOKEN http://blog.npmjs.org/post/118393368555/deploying-with-npm-private-modules
// or get other variable export in env
// https://github.com/verdaccio/verdaccio/releases/tag/v2.5.0
let token;
const tokenConf = auth;
if (_lodash.default.isNil(tokenConf.token) === false && _lodash.default.isString(tokenConf.token)) {
token = tokenConf.token;
} else if (_lodash.default.isNil(tokenConf.token_env) === false) {
if (_lodash.default.isString(tokenConf.token_env)) {
token = process.env[tokenConf.token_env];
} else if (_lodash.default.isBoolean(tokenConf.token_env) && tokenConf.token_env) {
token = process.env.NPM_TOKEN;
} else {
this.logger.error(_constants.ERROR_CODE.token_required);
this._throwErrorAuth(_constants.ERROR_CODE.token_required);
}
} else {
token = process.env.NPM_TOKEN;
}
if (_lodash.default.isNil(token)) {
this._throwErrorAuth(_constants.ERROR_CODE.token_required);
} // define type Auth allow basic and bearer
const type = tokenConf.type || _constants.TOKEN_BASIC;
this._setHeaderAuthorization(headers, type, token);
return headers;
}
/**
* @param {string} message
* @throws {Error}
* @private
*/
_throwErrorAuth(message) {
this.logger.error(message);
throw new Error(message);
}
/**
* Assign Header authorization with type authentication
* @param {Object} headers
* @param {string} type
* @param {string} token
* @private
*/
_setHeaderAuthorization(headers, type, token) {
const _type = type.toLowerCase();
if (_type !== _constants.TOKEN_BEARER.toLowerCase() && _type !== _constants.TOKEN_BASIC.toLowerCase()) {
this._throwErrorAuth(`Auth type '${_type}' not allowed`);
}
type = _lodash.default.upperFirst(type);
headers[_constants.HEADERS.AUTHORIZATION] = (0, _utils.buildToken)(type, token);
}
/**
* It will add or override specified headers from config file.
*
* Eg:
*
* uplinks:
npmjs:
url: https://registry.npmjs.org/
headers:
Accept: "application/vnd.npm.install-v2+json; q=1.0"
verdaccio-staging:
url: https://mycompany.com/npm
headers:
Accept: "application/json"
authorization: "Basic YourBase64EncodedCredentials=="
* @param {Object} headers
* @private
*/
_overrideWithUpLinkConfLocaligHeaders(headers) {
if (!this.config.headers) {
return headers;
} // add/override headers specified in the config
/* eslint guard-for-in: 0 */
for (const key in this.config.headers) {
headers[key] = this.config.headers[key];
}
}
/**
* Determine whether can fetch from the provided URL
* @param {*} url
* @return {Boolean}
*/
isUplinkValid(url) {
// $FlowFixMe
const urlParsed = _url.default.parse(url);
const isHTTPS = urlDomainParsed => urlDomainParsed.protocol === 'https:' && (urlParsed.port === null || urlParsed.port === '443');
const getHost = urlDomainParsed => isHTTPS(urlDomainParsed) ? urlDomainParsed.hostname : urlDomainParsed.host;
const isMatchProtocol = urlParsed.protocol === this.url.protocol;
const isMatchHost = getHost(urlParsed) === getHost(this.url); // @ts-ignore
const isMatchPath = urlParsed.path.indexOf(this.url.path) === 0;
return isMatchProtocol && isMatchHost && isMatchPath;
}
/**
* Get a remote package metadata
* @param {*} name package name
* @param {*} options request options, eg: eTag.
* @param {*} callback
*/
getRemoteMetadata(name, options, callback) {
const headers = {};
if (_lodash.default.isNil(options.etag) === false) {
headers['If-None-Match'] = options.etag;
headers[_constants.HEADERS.ACCEPT] = contentTypeAccept;
}
this.request({
uri: `/${encode(name)}`,
json: true,
headers: headers,
req: options.req
}, (err, res, body) => {
if (err) {
return callback(err);
}
if (res.statusCode === _constants.HTTP_STATUS.NOT_FOUND) {
return callback(_utils.ErrorCode.getNotFound(_constants.API_ERROR.NOT_PACKAGE_UPLINK));
}
if (!(res.statusCode >= _constants.HTTP_STATUS.OK && res.statusCode < _constants.HTTP_STATUS.MULTIPLE_CHOICES)) {
const error = _utils.ErrorCode.getInternalError(`${_constants.API_ERROR.BAD_STATUS_CODE}: ${res.statusCode}`); // $FlowFixMe
error.remoteStatus = res.statusCode;
return callback(error);
}
callback(null, body, res.headers.etag);
});
}
/**
* Fetch a tarball from the uplink.
* @param {String} url
* @return {Stream}
*/
fetchTarball(url) {
const stream = new _streams.ReadTarball({});
let current_length = 0;
let expected_length;
stream.abort = () => {};
const readStream = this.request({
uri_full: url,
encoding: null,
headers: {
Accept: contentTypeAccept
}
});
readStream.on('response', function (res) {
if (res.statusCode === _constants.HTTP_STATUS.NOT_FOUND) {
return stream.emit('error', _utils.ErrorCode.getNotFound(_constants.API_ERROR.NOT_FILE_UPLINK));
}
if (!(res.statusCode >= _constants.HTTP_STATUS.OK && res.statusCode < _constants.HTTP_STATUS.MULTIPLE_CHOICES)) {
return stream.emit('error', _utils.ErrorCode.getInternalError(`bad uplink status code: ${res.statusCode}`));
}
if (res.headers[_constants.HEADER_TYPE.CONTENT_LENGTH]) {
expected_length = res.headers[_constants.HEADER_TYPE.CONTENT_LENGTH];
stream.emit(_constants.HEADER_TYPE.CONTENT_LENGTH, res.headers[_constants.HEADER_TYPE.CONTENT_LENGTH]);
}
readStream.pipe(stream);
});
readStream.on('error', function (err) {
stream.emit('error', err);
});
readStream.on('data', function (data) {
current_length += data.length;
});
readStream.on('end', function (data) {
if (data) {
current_length += data.length;
}
if (expected_length && current_length != expected_length) {
stream.emit('error', _utils.ErrorCode.getInternalError(_constants.API_ERROR.CONTENT_MISMATCH));
}
});
return stream;
}
/**
* Perform a stream search.
* @param {*} options request options
* @return {Stream}
*/
search(options) {
const transformStream = new _stream.default.PassThrough({
objectMode: true
});
const requestStream = this.request({
uri: options.req.url,
req: options.req,
headers: {
referer: options.req.headers.referer
}
});
const parsePackage = pkg => {
if ((0, _utils.isObject)(pkg)) {
transformStream.emit('data', pkg);
}
};
requestStream.on('response', res => {
if (!String(res.statusCode).match(/^2\d\d$/)) {
return transformStream.emit('error', _utils.ErrorCode.getInternalError(`bad status code ${res.statusCode} from uplink`));
} // See https://github.com/request/request#requestoptions-callback
// Request library will not decode gzip stream.
let jsonStream;
if (res.headers[_constants.HEADER_TYPE.CONTENT_ENCODING] === _constants.HEADERS.GZIP) {
jsonStream = res.pipe(_zlib.default.createUnzip());
} else {
jsonStream = res;
}
jsonStream.pipe(_JSONStream.default.parse('*')).on('data', parsePackage);
jsonStream.on('end', () => {
transformStream.emit('end');
});
});
requestStream.on('error', err => {
transformStream.emit('error', err);
});
transformStream.abort = () => {
// FIXME: this is clearly a potential issue
// there is no abort method on Stream.Readable
// @ts-ignore
requestStream.abort();
transformStream.emit('end');
};
return transformStream;
}
/**
* Add proxy headers.
* FIXME: object mutations, it should return an new object
* @param {*} req the http request
* @param {*} headers the request headers
*/
_addProxyHeaders(req, headers) {
if (req) {
// Only submit X-Forwarded-For field if we don't have a proxy selected
// in the config file.
//
// Otherwise misconfigured proxy could return 407:
// https://github.com/rlidwka/sinopia/issues/254
//
// FIXME: proxy logic is odd, something is wrong here.
// @ts-ignore
if (!this.proxy) {
headers['X-Forwarded-For'] = (req.headers['x-forwarded-for'] ? req.headers['x-forwarded-for'] + ', ' : '') + req.connection.remoteAddress;
}
} // always attach Via header to avoid loops, even if we're not proxying
headers['Via'] = req && req.headers['via'] ? req.headers['via'] + ', ' : '';
headers['Via'] += '1.1 ' + this.server_id + ' (Verdaccio)';
}
/**
* Check whether the remote host is available.
* @param {*} alive
* @return {Boolean}
*/
_statusCheck(alive) {
if (arguments.length === 0) {
return this._ifRequestFailure() === false;
}
if (alive) {
if (this.failed_requests >= this.max_fails) {
this.logger.warn({
host: this.url.host
}, 'host @{host} is back online');
}
this.failed_requests = 0;
} else {
this.failed_requests++;
if (this.failed_requests === this.max_fails) {
this.logger.warn({
host: this.url.host
}, 'host @{host} is now offline');
}
}
this.last_request_time = Date.now();
}
/**
* If the request failure.
* @return {boolean}
* @private
*/
_ifRequestFailure() {
return this.failed_requests >= this.max_fails && Math.abs(Date.now() - this.last_request_time) < this.fail_timeout;
}
/**
* Set up a proxy.
* @param {*} hostname
* @param {*} config
* @param {*} mainconfig
* @param {*} isHTTPS
*/
_setupProxy(hostname, config, mainconfig, isHTTPS) {
let noProxyList;
const proxy_key = isHTTPS ? 'https_proxy' : 'http_proxy'; // get http_proxy and no_proxy configs
if (proxy_key in config) {
this.proxy = config[proxy_key];
} else if (proxy_key in mainconfig) {
this.proxy = mainconfig[proxy_key];
}
if ('no_proxy' in config) {
// $FlowFixMe
noProxyList = config.no_proxy;
} else if ('no_proxy' in mainconfig) {
noProxyList = mainconfig.no_proxy;
} // use wget-like algorithm to determine if proxy shouldn't be used
if (hostname[0] !== '.') {
hostname = '.' + hostname;
}
if (_lodash.default.isString(noProxyList) && noProxyList.length) {
// $FlowFixMe
noProxyList = noProxyList.split(',');
}
if (_lodash.default.isArray(noProxyList)) {
for (let i = 0; i < noProxyList.length; i++) {
let noProxyItem = noProxyList[i];
if (noProxyItem[0] !== '.') {
noProxyItem = '.' + noProxyItem;
}
if (hostname.lastIndexOf(noProxyItem) === hostname.length - noProxyItem.length) {
if (this.proxy) {
this.logger.debug({
url: this.url.href,
rule: noProxyItem
}, 'not using proxy for @{url}, excluded by @{rule} rule'); // @ts-ignore
this.proxy = false;
}
break;
}
}
} // if it's non-string (i.e. "false"), don't use it
if (_lodash.default.isString(this.proxy) === false) {
delete this.proxy;
} else {
this.logger.debug({
url: this.url.href,
proxy: this.proxy
}, 'using proxy @{proxy} for @{url}');
}
}
}
var _default = ProxyStorage;
exports.default = _default;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvdXAtc3RvcmFnZS50cyJdLCJuYW1lcyI6WyJMb2dnZXJBcGkiLCJyZXF1aXJlIiwiZW5jb2RlIiwidGhpbmciLCJlbmNvZGVVUklDb21wb25lbnQiLCJyZXBsYWNlIiwianNvbkNvbnRlbnRUeXBlIiwiSEVBREVSUyIsIkpTT04iLCJjb250ZW50VHlwZUFjY2VwdCIsInNldENvbmZpZyIsImNvbmZpZyIsImtleSIsImRlZiIsIl8iLCJpc05pbCIsIlByb3h5U3RvcmFnZSIsImNvbnN0cnVjdG9yIiwibWFpbkNvbmZpZyIsImZhaWxlZF9yZXF1ZXN0cyIsInVzZXJBZ2VudCIsInVzZXJfYWdlbnQiLCJjYSIsImxvZ2dlciIsImNoaWxkIiwic3ViIiwic2VydmVyX2lkIiwidXJsIiwiVVJMIiwicGFyc2UiLCJfc2V0dXBQcm94eSIsImhvc3RuYW1lIiwicHJvdG9jb2wiLCJ0aW1lb3V0IiwiTnVtYmVyIiwid2FybiIsImpvaW4iLCJtYXhhZ2UiLCJtYXhfZmFpbHMiLCJmYWlsX3RpbWVvdXQiLCJzdHJpY3Rfc3NsIiwiQm9vbGVhbiIsImFnZW50X29wdGlvbnMiLCJrZWVwQWxpdmUiLCJtYXhTb2NrZXRzIiwibWF4RnJlZVNvY2tldHMiLCJyZXF1ZXN0Iiwib3B0aW9ucyIsImNiIiwianNvbiIsIl9zdGF0dXNDaGVjayIsInN0cmVhbVJlYWQiLCJTdHJlYW0iLCJSZWFkYWJsZSIsInByb2Nlc3MiLCJuZXh0VGljayIsIkVycm9yQ29kZSIsImdldEludGVybmFsRXJyb3IiLCJBUElfRVJST1IiLCJVUExJTktfT0ZGTElORSIsImVtaXQiLCJfcmVhZCIsIm9uIiwic2VsZiIsImhlYWRlcnMiLCJfc2V0SGVhZGVycyIsIl9hZGRQcm94eUhlYWRlcnMiLCJyZXEiLCJfb3ZlcnJpZGVXaXRoVXBMaW5rQ29uZkxvY2FsaWdIZWFkZXJzIiwibWV0aG9kIiwidXJpIiwidXJpX2Z1bGwiLCJpbmZvIiwic3RyaW5naWZ5IiwicmVxdWVzdENhbGxiYWNrIiwiZXJyIiwicmVzIiwiYm9keSIsImVycm9yIiwicmVzcG9uc2VMZW5ndGgiLCJsZW5ndGgiLCJwcm9jZXNzQm9keSIsImxvZ0FjdGl2aXR5IiwibWVzc2FnZSIsInN0YXR1c0NvZGUiLCJ0b1N0cmluZyIsIkNIQVJBQ1RFUl9FTkNPRElORyIsIlVURjgiLCJfZXJyIiwiaXNTdHJpbmciLCJ1bmRlZmluZWQiLCJsZXZlbCIsInN0YXR1cyIsImJ5dGVzIiwiaW4iLCJvdXQiLCJyZXF1ZXN0T3B0aW9ucyIsInByb3h5IiwiZW5jb2RpbmciLCJnemlwIiwic3RyaWN0U1NMIiwiYWdlbnRPcHRpb25zIiwiT2JqZWN0IiwiYXNzaWduIiwic3RhdHVzQ2FsbGVkIiwiX3ZlcmRhY2Npb19hYm9ydGVkIiwiZG9fbG9nIiwiaXNOdWxsIiwiYWNjZXB0IiwiQUNDRVBUIiwiYWNjZXB0RW5jb2RpbmciLCJBQ0NFUFRfRU5DT0RJTkciLCJVU0VSX0FHRU5UIiwiX3NldEF1dGgiLCJhdXRoIiwiQVVUSE9SSVpBVElPTiIsImlzT2JqZWN0IiwidG9rZW4iLCJfdGhyb3dFcnJvckF1dGgiLCJ0b2tlbkNvbmYiLCJ0b2tlbl9lbnYiLCJlbnYiLCJpc0Jvb2xlYW4iLCJOUE1fVE9LRU4iLCJFUlJPUl9DT0RFIiwidG9rZW5fcmVxdWlyZWQiLCJ0eXBlIiwiVE9LRU5fQkFTSUMiLCJfc2V0SGVhZGVyQXV0aG9yaXphdGlvbiIsIkVycm9yIiwiX3R5cGUiLCJ0b0xvd2VyQ2FzZSIsIlRPS0VOX0JFQVJFUiIsInVwcGVyRmlyc3QiLCJpc1VwbGlua1ZhbGlkIiwidXJsUGFyc2VkIiwiaXNIVFRQUyIsInVybERvbWFpblBhcnNlZCIsInBvcnQiLCJnZXRIb3N0IiwiaG9zdCIsImlzTWF0Y2hQcm90b2NvbCIsImlzTWF0Y2hIb3N0IiwiaXNNYXRjaFBhdGgiLCJwYXRoIiwiaW5kZXhPZiIsImdldFJlbW90ZU1ldGFkYXRhIiwibmFtZSIsImNhbGxiYWNrIiwiZXRhZyIsIkhUVFBfU1RBVFVTIiwiTk9UX0ZPVU5EIiwiZ2V0Tm90Rm91bmQiLCJOT1RfUEFDS0FHRV9VUExJTksiLCJPSyIsIk1VTFRJUExFX0NIT0lDRVMiLCJCQURfU1RBVFVTX0NPREUiLCJyZW1vdGVTdGF0dXMiLCJmZXRjaFRhcmJhbGwiLCJzdHJlYW0iLCJSZWFkVGFyYmFsbCIsImN1cnJlbnRfbGVuZ3RoIiwiZXhwZWN0ZWRfbGVuZ3RoIiwiYWJvcnQiLCJyZWFkU3RyZWFtIiwiQWNjZXB0IiwiTk9UX0ZJTEVfVVBMSU5LIiwiSEVBREVSX1RZUEUiLCJDT05URU5UX0xFTkdUSCIsInBpcGUiLCJkYXRhIiwiQ09OVEVOVF9NSVNNQVRDSCIsInNlYXJjaCIsInRyYW5zZm9ybVN0cmVhbSIsIlBhc3NUaHJvdWdoIiwib2JqZWN0TW9kZSIsInJlcXVlc3RTdHJlYW0iLCJyZWZlcmVyIiwicGFyc2VQYWNrYWdlIiwicGtnIiwiU3RyaW5nIiwibWF0Y2giLCJqc29uU3RyZWFtIiwiQ09OVEVOVF9FTkNPRElORyIsIkdaSVAiLCJ6bGliIiwiY3JlYXRlVW56aXAiLCJKU09OU3RyZWFtIiwiY29ubmVjdGlvbiIsInJlbW90ZUFkZHJlc3MiLCJhbGl2ZSIsImFyZ3VtZW50cyIsIl9pZlJlcXVlc3RGYWlsdXJlIiwibGFzdF9yZXF1ZXN0X3RpbWUiLCJEYXRlIiwibm93IiwiTWF0aCIsImFicyIsIm1haW5jb25maWciLCJub1Byb3h5TGlzdCIsInByb3h5X2tleSIsIm5vX3Byb3h5Iiwic3BsaXQiLCJpc0FycmF5IiwiaSIsIm5vUHJveHlJdGVtIiwibGFzdEluZGV4T2YiLCJkZWJ1ZyIsImhyZWYiLCJydWxlIl0sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBQUE7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBR0E7O0FBQ0E7Ozs7OztBQVVBLE1BQU1BLFNBQVMsR0FBR0MsT0FBTyxDQUFDLFVBQUQsQ0FBekI7O0FBRUEsTUFBTUMsTUFBTSxHQUFHLFVBQVVDLEtBQVYsRUFBeUI7QUFDdEMsU0FBT0Msa0JBQWtCLENBQUNELEtBQUQsQ0FBbEIsQ0FB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QyxHQUFHTCxXQUFXLENBQUN2SCxNQUFoQyxFQUF3QzRILENBQUMsRUFBekMsRUFBNkM7QUFDM0MsWUFBSUMsV0FBVyxHQUFHTixXQUFXLENBQUNLLENBQUQsQ0FBN0I7O0FBQ0EsWUFBSUMsV0FBVyxDQUFDLENBQUQsQ0FBWCxLQUFtQixHQUF2QixFQUE0QjtBQUMxQkEsVUFBQUEsV0FBVyxHQUFHLE1BQU1BLFdBQXBCO0FBQ0Q7O0FBQ0QsWUFBSTlLLFFBQVEsQ0FBQytLLFdBQVQsQ0FBcUJELFdBQXJCLE1BQXNDOUssUUFBUSxDQUFDaUQsTUFBVCxHQUFrQjZILFdBQVcsQ0FBQzdILE1BQXhFLEVBQWdGO0FBQzlFLGNBQUksS0FBS2lCLEtBQVQsRUFBZ0I7QUFDZCxpQkFBSzFFLE1BQUwsQ0FBWXdMLEtBQVosQ0FDRTtBQUFFcEwsY0FBQUEsR0FBRyxFQUFFLEtBQUtBLEdBQUwsQ0FBU3FMLElBQWhCO0FBQXNCQyxjQUFBQSxJQUFJLEVBQUVKO0FBQTVCLGFBREYsRUFFRSxzREFGRixFQURjLENBS2Q7O0FBQ0EsaUJBQUs1RyxLQUFMLEdBQWEsS0FBYjtBQUNEOztBQUNEO0FBQ0Q7QUFDRjtBQUNGLEtBN0NLLENBK0NOOzs7QUFDQSxRQUFJbkYsZ0JBQUUyRSxRQUFGLENBQVcsS0FBS1EsS0FBaEIsTUFBMkIsS0FBL0IsRUFBc0M7QUFDcEMsYUFBTyxLQUFLQSxLQUFaO0FBQ0QsS0FGRCxNQUVPO0FBQ0wsV0FBSzFFLE1BQUwsQ0FBWXdMLEtBQVosQ0FDRTtBQUFFcEwsUUFBQUEsR0FBRyxFQUFFLEtBQUtBLEdBQUwsQ0FBU3FMLElBQWhCO0FBQXNCL0csUUFBQUEsS0FBSyxFQUFFLEtBQUtBO0FBQWxDLE9BREYsRUFFRSxpQ0FGRjtBQUlEO0FBQ0Y7O0FBdHFCa0M7O2VBeXFCdEJqRixZIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHpsaWIgZnJvbSAnemxpYic7XG5pbXBvcnQgU3RyZWFtLCB7IFJlYWRhYmxlIH0gZnJvbSAnc3RyZWFtJztcbmltcG9ydCBVUkwsIHsgVXJsV2l0aFN0cmluZ1F1ZXJ5IH0gZnJvbSAndXJsJztcbmltcG9ydCBKU09OU3RyZWFtIGZyb20gJ0pTT05TdHJlYW0nO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCByZXF1ZXN0IGZyb20gJ3JlcXVlc3QnO1xuaW1wb3J0IHsgUmVhZFRhcmJhbGwgfSBmcm9tICdAdmVyZGFjY2lvL3N0cmVhbXMnO1xuaW1wb3J0IHsgQ29uZmlnLCBDYWxsYmFjaywgSGVhZGVycywgTG9nZ2VyLCBQYWNrYWdlIH0gZnJvbSAnQHZlcmRhY2Npby90eXBlcyc7XG5pbXBvcnQgeyBJUHJveHksIFVwTGlua0NvbmZMb2NhbCB9IGZyb20gJy4uLy4uL3R5cGVzJztcbmltcG9ydCB7IHBhcnNlSW50ZXJ2YWwsIGlzT2JqZWN0LCBFcnJvckNvZGUsIGJ1aWxkVG9rZW4gfSBmcm9tICcuL3V0aWxzJztcbmltcG9ydCB7XG4gIEVSUk9SX0NPREUsXG4gIFRPS0VOX0JBU0lDLFxuICBUT0tFTl9CRUFSRVIsXG4gIEhFQURFUlMsXG4gIEhUVFBfU1RBVFVTLFxuICBBUElfRVJST1IsXG4gIEhFQURFUl9UWVBFLFxuICBDSEFSQUNURVJfRU5DT0RJTkdcbn0gZnJvbSAnLi9jb25zdGFudHMnO1xuY29uc3QgTG9nZ2VyQXBpID0gcmVxdWlyZSgnLi9sb2dnZXInKTtcblxuY29uc3QgZW5jb2RlID0gZnVuY3Rpb24gKHRoaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudCh0aGluZykucmVwbGFjZSgvXiU0MC8sICdAJyk7XG59O1xuXG5jb25zdCBqc29uQ29udGVudFR5cGUgPSBIRUFERVJTLkpTT047XG5jb25zdCBjb250ZW50VHlwZUFjY2VwdCA9IGAke2pzb25Db250ZW50VHlwZX07YDtcblxuLyoqXG4gKiBKdXN0IGEgaGVscGVyIChgY29uZmlnW2tleV0gfHwgZGVmYXVsdGAgZG9lc24ndCB3b3JrIGJlY2F1c2Ugb2YgemVyb2VzKVxuICovXG5jb25zdCBzZXRDb25maWcgPSAoY29uZmlnLCBrZXksIGRlZik6IHN0cmluZyA9PiB7XG4gIHJldHVybiBfLmlzTmlsKGNvbmZpZ1trZXldKSA9PT0gZmFsc2UgPyBjb25maWdba2V5XSA6IGRlZjtcbn07XG5cbi8qKlxuICogSW1wbGVtZW50cyBTdG9yYWdlIGludGVyZmFjZVxuICogKHNhbWUgZm9yIHN0b3JhZ2UuanMsIGxvY2FsLXN0b3JhZ2UuanMsIHVwLXN0b3JhZ2UuanMpXG4gKi9cbmNsYXNzIFByb3h5U3RvcmFnZSBpbXBsZW1lbnRzIElQcm94eSB7XG4gIHB1YmxpYyBjb25maWc6IFVwTGlua0NvbmZMb2NhbDtcbiAgcHVibGljIGZhaWxlZF9yZXF1ZXN0czogbnVtYmVyO1xuICBwdWJsaWMgdXNlckFnZW50OiBzdHJpbmc7XG4gIHB1YmxpYyBjYTogc3RyaW5nIHwgdm9pZDtcbiAgcHVibGljIGxvZ2dlcjogTG9nZ2VyO1xuICBwdWJsaWMgc2VydmVyX2lkOiBzdHJpbmc7XG4gIHB1YmxpYyB1cmw6IGFueTtcbiAgcHVibGljIG1heGFnZTogbnVtYmVyO1xuICBwdWJsaWMgdGltZW91dDogbnVtYmVyO1xuICBwdWJsaWMgbWF4X2ZhaWxzOiBudW1iZXI7XG4gIHB1YmxpYyBmYWlsX3RpbWVvdXQ6IG51bWJlcjtcbiAgcHVibGljIGFnZW50X29wdGlvbnM6IGFueTtcbiAgLy8gRklYTUU6IHVwbmFtZSBpcyBhc3NpZ25lZCB0byBlYWNoIGluc3RhbmNlXG4gIC8vIEB0cy1pZ25vcmVcbiAgcHVibGljIHVwbmFtZTogc3RyaW5nO1xuICAvLyBGSVhNRTogcHJveHkgY2FuIGJlIGJvb2xlYW4gb3Igb2JqZWN0LCBzb21ldGhpbmcgc21lbGxzIGhlcmVcbiAgLy8gQHRzLWlnbm9yZVxuICBwdWJsaWMgcHJveHk6IHN0cmluZyB8IHZvaWQ7XG4gIC8vIEB0cy1pZ25vcmVcbiAgcHVibGljIGxhc3RfcmVxdWVzdF90aW1lOiBudW1iZXIgfCBudWxsO1xuICBwdWJsaWMgc3RyaWN0X3NzbDogYm9vbGVhbjtcblxuICAvKipcbiAgICogQ29uc3RydWN0b3JcbiAgICogQHBhcmFtIHsqfSBjb25maWdcbiAgICogQHBhcmFtIHsqfSBtYWluQ29uZmlnXG4gICAqL1xuICBwdWJsaW