filestack-js
Version:
Official JavaScript library for Filestack
330 lines (328 loc) • 45.2 kB
JavaScript
/*
* Copyright (c) 2018 by Filestack
* Some rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.HttpAdapter = void 0;
var tslib_1 = require("tslib");
var url = tslib_1.__importStar(require("url"));
var zlib = tslib_1.__importStar(require("zlib"));
var debug_1 = tslib_1.__importDefault(require("debug"));
var utils_1 = require("../../utils");
var Stream = tslib_1.__importStar(require("stream"));
var utils = tslib_1.__importStar(require("../utils"));
var helpers_1 = require("./../helpers");
var error_1 = require("../error");
var types_1 = require("./../types");
var HTTPS_REGEXP = /https:?/;
var HTTP_CHUNK_SIZE = 16 * 1024;
var MAX_REDIRECTS = 10;
var CANCEL_CLEAR = "FsCleanMemory";
var debug = (0, debug_1.default)('fs:request:http');
/**
* Writable stream thats overwrap http request for progress event
*
* @class HttpWritableStream
* @extends {Stream.Writable}
*/
var HttpWritableStream = /** @class */ (function (_super) {
tslib_1.__extends(HttpWritableStream, _super);
function HttpWritableStream(req, opts) {
if (opts === void 0) { opts = {}; }
var _this = _super.call(this, opts) || this;
_this.request = req;
req.once('drain', function () { return _this.emit('drain'); });
return _this;
}
HttpWritableStream.prototype._write = function (chunk, encoding, cb) {
this.request.write(chunk, encoding, cb);
};
HttpWritableStream.prototype.end = function (chunk, encoding, cb) {
_super.prototype.end.call(this, chunk, encoding, cb);
return this;
};
HttpWritableStream.prototype._final = function (cb) {
this.request.end();
cb();
};
return HttpWritableStream;
}(Stream.Writable));
/**
* Node http request class
*
* @export
* @class HttpAdapter
* @implements {AdapterInterface}
*/
var HttpAdapter = /** @class */ (function () {
function HttpAdapter() {
this.redirectHoops = 0;
this.redirectPaths = [];
/**
* Monitor and emit progress event if needed
*
* @private
* @memberof HttpAdapter
*/
this.getProgressMonitor = function (config, total) {
var loaded = 0;
var progress = new Stream.Transform();
progress._transform = function (chunk, encoding, cb) {
if (typeof config.onProgress === 'function' && [types_1.FsHttpMethod.POST, types_1.FsHttpMethod.PUT].indexOf(config.method) > -1) {
loaded += chunk.length;
config.onProgress({
lengthComputable: true,
loaded: loaded,
total: total,
});
}
cb(null, chunk);
};
return progress;
};
}
/**
* do request based on configuration
*
* @param {FsRequestOptions} config
* @returns
* @memberof HttpAdapter
*/
HttpAdapter.prototype.request = function (config) {
var _this = this;
// if this option is unspecified set it by default
if (typeof config.filestackHeaders === 'undefined') {
config.filestackHeaders = true;
}
config.headers = (0, helpers_1.normalizeHeaders)(config.headers);
var _a = (0, helpers_1.prepareData)(config), data = _a.data, headers = _a.headers;
headers = (0, helpers_1.set)(headers, 'user-agent', "filestack-request/".concat((0, utils_1.getVersion)()));
// for now we are not using streams
if (data) {
debug('Request data %O', data);
if (!Buffer.isBuffer(data)) {
if (!utils.isString(data)) {
return Promise.reject(new error_1.FsRequestError('Data must be a string, JSON or a Buffer', config));
}
data = Buffer.from(data, 'utf-8');
}
headers = (0, helpers_1.set)(headers, 'content-length', data.length, true);
}
// HTTP basic authentication
var auth;
if (config.auth) {
if (!config.auth.username || config.auth.username.length === 0) {
return Promise.reject(new error_1.FsRequestError("Basic auth: username is required ".concat(config.auth), config));
}
auth = "".concat(config.auth.username, ":").concat(config.auth.password);
}
// Parse url
var parsed = url.parse(config.url);
// try to add default https protocol
if (!parsed.protocol) {
parsed = url.parse("https://".concat(config.url));
}
/* istanbul ignore next: just be sure that the host is parsed correctly, not needed to test */
if (!parsed.host) {
return Promise.reject(new error_1.FsRequestError("Cannot parse provided url ".concat(config.url), config));
}
// normalize auth header
if (auth && headers.Authorization) {
delete headers.Authorization;
}
var isHttpsRequest = HTTPS_REGEXP.test(parsed.protocol);
var agent = isHttpsRequest ? require('https') : require('http');
var options = {
path: (0, helpers_1.combineURL)(parsed.path, config.params),
host: parsed.host,
port: parsed.port,
protocol: parsed.protocol,
method: config.method.toUpperCase(),
headers: headers,
agent: new agent.Agent(),
auth: auth,
};
debug('Starting %s request with options %O', isHttpsRequest ? 'https' : 'http', options);
return new Promise(function (resolve, reject) {
var req;
var cancelListener;
if (config.cancelToken) {
cancelListener = config.cancelToken.on('cancel', function (reason) {
// cleanup handler
cancelListener = null;
// do nothing if promise is resolved by system
if (reason && reason.message === CANCEL_CLEAR) {
return;
}
/* istanbul ignore next: if request is done cancel token should not throw any error */
if (req) {
req.abort();
req = null;
}
debug('Request canceled by user %s, config: %O', reason, config);
return reject(new error_1.FsRequestError("Request aborted. Reason: ".concat(reason), config, null, error_1.FsRequestErrorCode.ABORTED));
});
}
req = agent.request(options, function (res) {
/* istanbul ignore next: just be sure that response will not be called after request is aborted */
if (!req || req.aborted) {
return reject(new error_1.FsRequestError('Request aborted', config));
}
var stream = res;
debug('Response statusCode: %d, Response Headers: %O', res.statusCode, res.headers);
var compressHeaders = res.headers['content-encoding'];
if (compressHeaders && compressHeaders.length && ['gzip', 'compress', 'deflate'].some(function (v) { return compressHeaders.indexOf(v) > -1; })) {
// add the unzipper to the body stream processing pipeline
stream = res.statusCode === 204 ? stream : stream.pipe(zlib.createUnzip());
// remove the content-encoding in order to not confuse downstream operations
delete res.headers['content-encoding'];
}
var response = {
status: res.statusCode,
statusText: res.statusMessage,
headers: res.headers,
config: config,
data: {},
};
// we need to follow redirect so make same request with new location
if ([301, 302].indexOf(res.statusCode) > -1) {
debug('Redirect received %s', res.statusCode);
if (_this.redirectHoops >= MAX_REDIRECTS) {
return reject(new error_1.FsRequestError("Max redirects (".concat(_this.redirectHoops, ") reached. Exiting"), config, response, error_1.FsRequestErrorCode.REDIRECT));
}
var url_1 = res.headers['location'];
if (!url_1 || url_1.length === 0) {
return reject(new error_1.FsRequestError("Redirect header location not found", config, response, error_1.FsRequestErrorCode.REDIRECT));
}
if (_this.redirectPaths.indexOf(url_1) > -1) {
return reject(new error_1.FsRequestError("Redirect loop detected at url ".concat(url_1), config, response, error_1.FsRequestErrorCode.REDIRECT));
}
_this.redirectPaths.push(url_1);
_this.redirectHoops++;
// free resources
res = undefined;
req = undefined;
debug('Redirecting request to %s (hoop-count: %d)', url_1, _this.redirectHoops);
return resolve(_this.request(Object.assign({}, config, { url: url_1 })));
}
var responseBuffer = [];
stream.on('data', function (chunk) { return responseBuffer.push(chunk); });
/* istanbul ignore next: its hard to test socket events with jest and nock - tested manually */
stream.on('error', function (err) {
res = undefined;
req = undefined;
responseBuffer = undefined;
debug('Request error: Aborted %O', err);
if (req.aborted) {
return;
}
// clear cancel token to avoid memory leak
if (cancelListener) {
config.cancelToken.removeListener(cancelListener);
}
return reject(new error_1.FsRequestError(err.message, config, null, error_1.FsRequestErrorCode.NETWORK));
});
stream.on('end', function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
// clear cancel token to avoid memory leak
if (cancelListener) {
config.cancelToken.removeListener(cancelListener);
}
if (!(res.statusCode !== 204)) return [3 /*break*/, 2];
// prepare response
response.data = Buffer.concat(responseBuffer);
return [4 /*yield*/, (0, helpers_1.parseResponse)(response)];
case 1:
response = _a.sent();
return [3 /*break*/, 3];
case 2:
response.data = null;
_a.label = 3;
case 3:
// free resources
res = undefined;
req = undefined;
responseBuffer = undefined;
if (500 <= response.status && response.status <= 599) {
// server error throw
debug('Server error(5xx) - %O', response);
return [2 /*return*/, reject(new error_1.FsRequestError("Server error ".concat(url), config, response, error_1.FsRequestErrorCode.SERVER))];
}
else if (400 <= response.status && response.status <= 499) {
debug('Request error(4xx) - %O', response);
return [2 /*return*/, reject(new error_1.FsRequestError("Request error ".concat(url), config, response, error_1.FsRequestErrorCode.REQUEST))];
}
debug('Request ends: %O', response);
return [2 /*return*/, resolve(response)];
}
});
}); });
});
if (config.timeout) {
req.setTimeout(config.timeout, function () {
req.abort();
if (cancelListener) {
config.cancelToken.removeListener(cancelListener);
}
return reject(new error_1.FsRequestError('Request timeout', config, null, error_1.FsRequestErrorCode.TIMEOUT));
});
}
req.on('error', function (err) {
if (cancelListener) {
config.cancelToken.removeListener(cancelListener);
}
if (!req || req.aborted) {
return;
}
debug('Request error: %s - %O', err, err.code);
return reject(new error_1.FsRequestError("Request error: ".concat(err.code), config, null, error_1.FsRequestErrorCode.NETWORK));
});
if (Buffer.isBuffer(data) && ['POST', 'PUT'].indexOf(config.method) > -1) {
return _this.bufferToChunks(data).pipe(_this.getProgressMonitor(config, data.length)).pipe(new HttpWritableStream(req));
}
req.end(data);
});
};
/**
* Convert buffer to stream
*
* @private
* @param {*} buffer
* @returns {Stream.Readable}
* @memberof HttpAdapter
*/
HttpAdapter.prototype.bufferToChunks = function (buffer) {
var chunking = new Stream.Readable();
var totalLength = buffer.length;
var remainder = totalLength % HTTP_CHUNK_SIZE;
var cutoff = totalLength - remainder;
for (var i = 0; i < cutoff; i += HTTP_CHUNK_SIZE) {
var chunk = buffer.slice(i, i + HTTP_CHUNK_SIZE);
chunking.push(chunk);
}
if (remainder > 0) {
var remainderBuffer = buffer.slice(-remainder);
chunking.push(remainderBuffer);
}
chunking.push(null);
return chunking;
};
return HttpAdapter;
}());
exports.HttpAdapter = HttpAdapter;
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvcmVxdWVzdC9hZGFwdGVycy9odHRwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7Ozs7QUFFSCwrQ0FBMkI7QUFDM0IsaURBQTZCO0FBQzdCLHdEQUEwQjtBQUcxQixxQ0FBeUM7QUFDekMscURBQWlDO0FBRWpDLHNEQUFrQztBQUNsQyx3Q0FBMEc7QUFDMUcsa0NBQThEO0FBQzlELG9DQUEwQztBQUUxQyxJQUFNLFlBQVksR0FBRyxTQUFTLENBQUM7QUFDL0IsSUFBTSxlQUFlLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUNsQyxJQUFNLGFBQWEsR0FBRyxFQUFFLENBQUM7QUFDekIsSUFBTSxZQUFZLEdBQUcsZUFBZSxDQUFDO0FBQ3JDLElBQU0sS0FBSyxHQUFHLElBQUEsZUFBSyxFQUFDLGlCQUFpQixDQUFDLENBQUM7QUFFdkM7Ozs7O0dBS0c7QUFDSDtJQUFpQyw4Q0FBZTtJQUc5Qyw0QkFBWSxHQUFHLEVBQUUsSUFBUztRQUFULHFCQUFBLEVBQUEsU0FBUztRQUExQixZQUNFLGtCQUFNLElBQUksQ0FBQyxTQUlaO1FBRkMsS0FBSSxDQUFDLE9BQU8sR0FBRyxHQUFHLENBQUM7UUFDbkIsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsY0FBTSxPQUFBLEtBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQWxCLENBQWtCLENBQUMsQ0FBQzs7SUFDOUMsQ0FBQztJQUVELG1DQUFNLEdBQU4sVUFBTyxLQUFVLEVBQUUsUUFBaUIsRUFBRSxFQUE4QztRQUNsRixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFFRCxnQ0FBRyxHQUFILFVBQUksS0FBVyxFQUFFLFFBQWMsRUFBRSxFQUFRO1FBQ3ZDLGlCQUFNLEdBQUcsWUFBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEVBQUUs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LENBQUMsSUFBSSxDQUFDLENBQUM7UUFFcEIsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztJQUNILGtCQUFDO0FBQUQsQ0FsVEEsQUFrVEMsSUFBQTtBQWxUWSxrQ0FBVyIsImZpbGUiOiJsaWIvcmVxdWVzdC9hZGFwdGVycy9odHRwLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIENvcHlyaWdodCAoYykgMjAxOCBieSBGaWxlc3RhY2tcbiAqIFNvbWUgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqL1xuXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcbmltcG9ydCAqIGFzIHpsaWIgZnJvbSAnemxpYic7XG5pbXBvcnQgRGVidWcgZnJvbSAnZGVidWcnO1xuXG5pbXBvcnQgeyBBZGFwdGVySW50ZXJmYWNlIH0gZnJvbSAnLi9pbnRlcmZhY2UnO1xuaW1wb3J0IHsgZ2V0VmVyc2lvbiB9IGZyb20gJy4uLy4uL3V0aWxzJztcbmltcG9ydCAqIGFzIFN0cmVhbSBmcm9tICdzdHJlYW0nO1xuaW1wb3J0IHsgRnNSZXF1ZXN0T3B0aW9ucywgRnNSZXNwb25zZSB9IGZyb20gJy4uL3R5cGVzJztcbmltcG9ydCAqIGFzIHV0aWxzIGZyb20gJy4uL3V0aWxzJztcbmltcG9ydCB7IHByZXBhcmVEYXRhLCBwYXJzZVJlc3BvbnNlLCBjb21iaW5lVVJMLCBzZXQgYXMgc2V0SGVhZGVyLCBub3JtYWxpemVIZWFkZXJzIH0gZnJvbSAnLi8uLi9oZWxwZXJzJztcbmltcG9ydCB7IEZzUmVxdWVzdEVycm9yQ29kZSwgRnNSZXF1ZXN0RXJyb3IgfSBmcm9tICcuLi9lcnJvcic7XG5pbXBvcnQgeyBGc0h0dHBNZXRob2QgfSBmcm9tICcuLy4uL3R5cGVzJztcblxuY29uc3QgSFRUUFNfUkVHRVhQID0gL2h0dHBzOj8vO1xuY29uc3QgSFRUUF9DSFVOS19TSVpFID0gMTYgKiAxMDI0O1xuY29uc3QgTUFYX1JFRElSRUNUUyA9IDEwO1xuY29uc3QgQ0FOQ0VMX0NMRUFSID0gYEZzQ2xlYW5NZW1vcnlgO1xuY29uc3QgZGVidWcgPSBEZWJ1ZygnZnM6cmVxdWVzdDpodHRwJyk7XG5cbi8qKlxuICogV3JpdGFibGUgc3RyZWFtIHRoYXRzIG92ZXJ3cmFwIGh0dHAgcmVxdWVzdCBmb3IgcHJvZ3Jlc3MgZXZlbnRcbiAqXG4gKiBAY2xhc3MgSHR0cFdyaXRhYmxlU3RyZWFtXG4gKiBAZXh0ZW5kcyB7U3RyZWFtLldyaXRhYmxlfVxuICovXG5jbGFzcyBIdHRwV3JpdGFibGVTdHJlYW0gZXh0ZW5kcyBTdHJlYW0uV3JpdGFibGUge1xuICBwcml2YXRlIHJlcXVlc3Q7XG5cbiAgY29uc3RydWN0b3IocmVxLCBvcHRzID0ge30pIHtcbiAgICBzdXBlcihvcHRzKTtcblxuICAgIHRoaXMucmVxdWVzdCA9IHJlcTtcbiAgICByZXEub25jZSgnZHJhaW4nLCAoKSA9PiB0aGlzLmVtaXQoJ2RyYWluJykpO1xuICB9XG5cbiAgX3dyaXRlKGNodW5rOiBhbnksIGVuY29kaW5nPzogc3RyaW5nLCBjYj86IChlcnJvcjogRXJyb3IgfCBudWxsIHwgdW5kZWZpbmVkKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgdGhpcy5yZXF1ZXN0LndyaXRlKGNodW5rLCBlbmNvZGluZywgY2IpO1xuICB9XG5cbiAgZW5kKGNodW5rPzogYW55LCBlbmNvZGluZz86IGFueSwgY2I/OiBhbnkpOiB0aGlzIHtcbiAgICBzdXBlci5lbmQoY2h1bmssIGVuY29kaW5nLCBjYik7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBfZmluYWwoY2I6IChlcnJvcj86IEVycm9yIHwgbnVsbCB8IHVuZGVmaW5lZCkgPT4gdm9pZCk6IHZvaWQge1xuICAgIHRoaXMucmVxdWVzdC5lbmQoKTtcbiAgICBjYigpO1xuICB9XG59XG5cbi8qKlxuICogTm9kZSBodHRwIHJlcXVlc3QgY2xhc3NcbiAqXG4gKiBAZXhwb3J0XG4gKiBAY2xhc3MgSHR0cEFkYXB0ZXJcbiAqIEBpbXBsZW1lbnRzIHtBZGFwdGVySW50ZXJmYWNlfVxuICovXG5leHBvcnQgY2xhc3MgSHR0cEFkYXB0ZXIgaW1wbGVtZW50cyBBZGFwdGVySW50ZXJmYWNlIHtcbiAgcHJpdmF0ZSByZWRpcmVjdEhvb3BzID0gMDtcbiAgcHJpdmF0ZSByZWRpcmVjdFBhdGhzID0gW107XG5cbiAgLyoqXG4gICAqIGRvIHJlcXVlc3QgYmFzZWQgb24gY29uZmlndXJhdGlvblxuICAgKlxuICAgKiBAcGFyYW0ge0ZzUmVxdWVzdE9wdGlvbnN9IGNvbmZpZ1xuICAgKiBAcmV0dXJuc1xuICAgKiBAbWVtYmVyb2YgSHR0cEFkYXB0ZXJcbiAgICovXG4gIHJlcXVlc3QoY29uZmlnOiBGc1JlcXVlc3RPcHRpb25zKSB7XG4gICAgLy8gaWYgdGhpcyBvcHRpb24gaXMgdW5zcGVjaWZpZWQgc2V0IGl0IGJ5IGRlZmF1bHRcbiAgICBpZiAodHlwZW9mIGNvbmZpZy5maWxlc3RhY2tIZWFkZXJzID09PSAndW5kZWZpbmVkJykge1xuICAgICAgY29uZmlnLmZpbGVzdGFja0hlYWRlcnMgPSB0cnVlO1xuICAgIH1cblxuICAgIGNvbmZpZy5oZWFkZXJzID0gbm9ybWFsaXplSGVhZGVycyhjb25maWcuaGVhZGVycyk7XG5cbiAgICBsZXQgeyBkYXRhLCBoZWFkZXJzIH0gPSBwcmVwYXJlRGF0YShjb25maWcpO1xuXG4gICAgaGVhZGVycyA9IHNldEhlYWRlcihoZWFkZXJzLCAndXNlci1hZ2VudCcsIGBmaWxlc3RhY2stcmVxdWVzdC8ke2dldFZlcnNpb24oKX1gKTtcblxuICAgIC8vIGZvciBub3cgd2UgYXJlIG5vdCB1c2luZyBzdHJlYW1zXG4gICAgaWYgKGRhdGEpIHtcbiAgICAgIGRlYnVnKCdSZXF1ZXN0IGRhdGEgJU8nLCBkYXRhKTtcblxuICAgICAgaWYgKCFCdWZmZXIuaXNCdWZmZXIoZGF0YSkpIHtcbiAgICAgICAgaWYgKCF1dGlscy5pc1N0cmluZyhkYXRhKSkge1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoJ0RhdGEgbXVzdCBiZSBhIHN0cmluZywgSlNPTiBvciBhIEJ1ZmZlcicsIGNvbmZpZykpO1xuICAgICAgICB9XG5cbiAgICAgICAgZGF0YSA9IEJ1ZmZlci5mcm9tKGRhdGEsICd1dGYtOCcpO1xuICAgICAgfVxuXG4gICAgICBoZWFkZXJzID0gc2V0SGVhZGVyKGhlYWRlcnMsICdjb250ZW50LWxlbmd0aCcsIGRhdGEubGVuZ3RoLCB0cnVlKTtcbiAgICB9XG5cbiAgICAvLyBIVFRQIGJhc2ljIGF1dGhlbnRpY2F0aW9uXG4gICAgbGV0IGF1dGg7XG4gICAgaWYgKGNvbmZpZy5hdXRoKSB7XG4gICAgICBpZiAoIWNvbmZpZy5hdXRoLnVzZXJuYW1lIHx8IGNvbmZpZy5hdXRoLnVzZXJuYW1lLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QobmV3IEZzUmVxdWVzdEVycm9yKGBCYXNpYyBhdXRoOiB1c2VybmFtZSBpcyByZXF1aXJlZCAke2NvbmZpZy5hdXRofWAsIGNvbmZpZykpO1xuICAgICAgfVxuXG4gICAgICBhdXRoID0gYCR7Y29uZmlnLmF1dGgudXNlcm5hbWV9OiR7Y29uZmlnLmF1dGgucGFzc3dvcmR9YDtcbiAgICB9XG5cbiAgICAvLyBQYXJzZSB1cmxcbiAgICBsZXQgcGFyc2VkID0gdXJsLnBhcnNlKGNvbmZpZy51cmwpO1xuXG4gICAgLy8gdHJ5IHRvIGFkZCBkZWZhdWx0IGh0dHBzIHByb3RvY29sXG4gICAgaWYgKCFwYXJzZWQucHJvdG9jb2wpIHtcbiAgICAgIHBhcnNlZCA9IHVybC5wYXJzZShgaHR0cHM6Ly8ke2NvbmZpZy51cmx9YCk7XG4gICAgfVxuXG4gICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQ6IGp1c3QgYmUgc3VyZSB0aGF0IHRoZSBob3N0IGlzIHBhcnNlZCBjb3JyZWN0bHksIG5vdCBuZWVkZWQgdG8gdGVzdCAqL1xuICAgIGlmICghcGFyc2VkLmhvc3QpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoYENhbm5vdCBwYXJzZSBwcm92aWRlZCB1cmwgJHtjb25maWcudXJsfWAsIGNvbmZpZykpO1xuICAgIH1cblxuICAgIC8vIG5vcm1hbGl6ZSBhdXRoIGhlYWRlclxuICAgIGlmIChhdXRoICYmIGhlYWRlcnMuQXV0aG9yaXphdGlvbikge1xuICAgICAgZGVsZXRlIGhlYWRlcnMuQXV0aG9yaXphdGlvbjtcbiAgICB9XG5cbiAgICBjb25zdCBpc0h0dHBzUmVxdWVzdCA9IEhUVFBTX1JFR0VYUC50ZXN0KHBhcnNlZC5wcm90b2NvbCk7XG4gICAgY29uc3QgYWdlbnQgPSBpc0h0dHBzUmVxdWVzdCA/IHJlcXVpcmUoJ2h0dHBzJykgOiByZXF1aXJlKCdodHRwJyk7XG5cbiAgICBjb25zdCBvcHRpb25zID0ge1xuICAgICAgcGF0aDogY29tYmluZVVSTChwYXJzZWQucGF0aCwgY29uZmlnLnBhcmFtcyksXG4gICAgICBob3N0OiBwYXJzZWQuaG9zdCxcbiAgICAgIHBvcnQ6IHBhcnNlZC5wb3J0LFxuICAgICAgcHJvdG9jb2w6IHBhcnNlZC5wcm90b2NvbCxcbiAgICAgIG1ldGhvZDogY29uZmlnLm1ldGhvZC50b1VwcGVyQ2FzZSgpLFxuICAgICAgaGVhZGVyczogaGVhZGVycyxcbiAgICAgIGFnZW50OiBuZXcgYWdlbnQuQWdlbnQoKSxcbiAgICAgIGF1dGg6IGF1dGgsXG4gICAgfTtcblxuICAgIGRlYnVnKCdTdGFydGluZyAlcyByZXF1ZXN0IHdpdGggb3B0aW9ucyAlTycsIGlzSHR0cHNSZXF1ZXN0ID8gJ2h0dHBzJyA6ICdodHRwJywgb3B0aW9ucyk7XG5cbiAgICByZXR1cm4gbmV3IFByb21pc2U8RnNSZXNwb25zZT4oKHJlc29sdmUsIHJlamVjdCk6IGFueSA9PiB7XG4gICAgICBsZXQgcmVxO1xuICAgICAgbGV0IGNhbmNlbExpc3RlbmVyO1xuXG4gICAgICBpZiAoY29uZmlnLmNhbmNlbFRva2VuKSB7XG4gICAgICAgIGNhbmNlbExpc3RlbmVyID0gY29uZmlnLmNhbmNlbFRva2VuLm9uKCdjYW5jZWwnLCAocmVhc29uKSA9PiB7XG4gICAgICAgICAgLy8gY2xlYW51cCBoYW5kbGVyXG4gICAgICAgICAgY2FuY2VsTGlzdGVuZXIgPSBudWxsO1xuXG4gICAgICAgICAgLy8gZG8gbm90aGluZyBpZiBwcm9taXNlIGlzIHJlc29sdmVkIGJ5IHN5c3RlbVxuICAgICAgICAgIGlmIChyZWFzb24gJiYgcmVhc29uLm1lc3NhZ2UgPT09IENBTkNFTF9DTEVBUikge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBpZiByZXF1ZXN0IGlzIGRvbmUgY2FuY2VsIHRva2VuIHNob3VsZCBub3QgdGhyb3cgYW55IGVycm9yICovXG4gICAgICAgICAgaWYgKHJlcSkge1xuICAgICAgICAgICAgcmVxLmFib3J0KCk7XG4gICAgICAgICAgICByZXEgPSBudWxsO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGRlYnVnKCdSZXF1ZXN0IGNhbmNlbGVkIGJ5IHVzZXIgJXMsIGNvbmZpZzogJU8nLCByZWFzb24sIGNvbmZpZyk7XG4gICAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoYFJlcXVlc3QgYWJvcnRlZC4gUmVhc29uOiAke3JlYXNvbn1gLCBjb25maWcsIG51bGwsIEZzUmVxdWVzdEVycm9yQ29kZS5BQk9SVEVEKSk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICByZXEgPSBhZ2VudC5yZXF1ZXN0KG9wdGlvbnMsIHJlcyA9PiB7XG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBqdXN0IGJlIHN1cmUgdGhhdCByZXNwb25zZSB3aWxsIG5vdCBiZSBjYWxsZWQgYWZ0ZXIgcmVxdWVzdCBpcyBhYm9ydGVkICovXG4gICAgICAgIGlmICghcmVxIHx8IHJlcS5hYm9ydGVkKSB7XG4gICAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoJ1JlcXVlc3QgYWJvcnRlZCcsIGNvbmZpZykpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHN0cmVhbSA9IHJlcztcbiAgICAgICAgZGVidWcoJ1Jlc3BvbnNlIHN0YXR1c0NvZGU6ICVkLCBSZXNwb25zZSBIZWFkZXJzOiAlTycsIHJlcy5zdGF0dXNDb2RlLCByZXMuaGVhZGVycyk7XG5cbiAgICAgICAgY29uc3QgY29tcHJlc3NIZWFkZXJzID0gcmVzLmhlYWRlcnNbJ2NvbnRlbnQtZW5jb2RpbmcnXTtcblxuICAgICAgICBpZiAoY29tcHJlc3NIZWFkZXJzICYmIGNvbXByZXNzSGVhZGVycy5sZW5ndGggJiYgWydnemlwJywgJ2NvbXByZXNzJywgJ2RlZmxhdGUnXS5zb21lKCh2KSA9PiBjb21wcmVzc0hlYWRlcnMuaW5kZXhPZih2KSA+IC0xKSkge1xuICAgICAgICAgIC8vIGFkZCB0aGUgdW56aXBwZXIgdG8gdGhlIGJvZHkgc3RyZWFtIHByb2Nlc3NpbmcgcGlwZWxpbmVcbiAgICAgICAgICBzdHJlYW0gPSByZXMuc3RhdHVzQ29kZSA9PT0gMjA0ID8gc3RyZWFtIDogc3RyZWFtLnBpcGUoemxpYi5jcmVhdGVVbnppcCgpKTtcbiAgICAgICAgICAvLyByZW1vdmUgdGhlIGNvbnRlbnQtZW5jb2RpbmcgaW4gb3JkZXIgdG8gbm90IGNvbmZ1c2UgZG93bnN0cmVhbSBvcGVyYXRpb25zXG4gICAgICAgICAgZGVsZXRlIHJlcy5oZWFkZXJzWydjb250ZW50LWVuY29kaW5nJ107XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgcmVzcG9uc2U6IEZzUmVzcG9uc2UgPSB7XG4gICAgICAgICAgc3RhdHVzOiByZXMuc3RhdHVzQ29kZSxcbiAgICAgICAgICBzdGF0dXNUZXh0OiByZXMuc3RhdHVzTWVzc2FnZSxcbiAgICAgICAgICBoZWFkZXJzOiByZXMuaGVhZGVycyxcbiAgICAgICAgICBjb25maWcsXG4gICAgICAgICAgZGF0YToge30sXG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gd2UgbmVlZCB0byBmb2xsb3cgcmVkaXJlY3Qgc28gbWFrZSBzYW1lIHJlcXVlc3Qgd2l0aCBuZXcgbG9jYXRpb25cbiAgICAgICAgaWYgKFszMDEsIDMwMl0uaW5kZXhPZihyZXMuc3RhdHVzQ29kZSkgPiAtMSkge1xuICAgICAgICAgIGRlYnVnKCdSZWRpcmVjdCByZWNlaXZlZCAlcycsIHJlcy5zdGF0dXNDb2RlKTtcblxuICAgICAgICAgIGlmICh0aGlzLnJlZGlyZWN0SG9vcHMgPj0gTUFYX1JFRElSRUNUUykge1xuICAgICAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoYE1heCByZWRpcmVjdHMgKCR7dGhpcy5yZWRpcmVjdEhvb3BzfSkgcmVhY2hlZC4gRXhpdGluZ2AsIGNvbmZpZywgcmVzcG9uc2UsIEZzUmVxdWVzdEVycm9yQ29kZS5SRURJUkVDVCkpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IHVybCA9IHJlcy5oZWFkZXJzWydsb2NhdGlvbiddO1xuXG4gICAgICAgICAgaWYgKCF1cmwgfHwgdXJsLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoYFJlZGlyZWN0IGhlYWRlciBsb2NhdGlvbiBub3QgZm91bmRgLCBjb25maWcsIHJlc3BvbnNlLCBGc1JlcXVlc3RFcnJvckNvZGUuUkVESVJFQ1QpKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAodGhpcy5yZWRpcmVjdFBhdGhzLmluZGV4T2YodXJsKSA+IC0xKSB7XG4gICAgICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcihgUmVkaXJlY3QgbG9vcCBkZXRlY3RlZCBhdCB1cmwgJHt1cmx9YCwgY29uZmlnLCByZXNwb25zZSwgRnNSZXF1ZXN0RXJyb3JDb2RlLlJFRElSRUNUKSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy5yZWRpcmVjdFBhdGhzLnB1c2godXJsKTtcbiAgICAgICAgICB0aGlzLnJlZGlyZWN0SG9vcHMrKztcblxuICAgICAgICAgIC8vIGZyZWUgcmVzb3VyY2VzXG4gICAgICAgICAgcmVzID0gdW5kZWZpbmVkO1xuICAgICAgICAgIHJlcSA9IHVuZGVmaW5lZDtcblxuICAgICAgICAgIGRlYnVnKCdSZWRpcmVjdGluZyByZXF1ZXN0IHRvICVzIChob29wLWNvdW50OiAlZCknLCB1cmwsIHRoaXMucmVkaXJlY3RIb29wcyk7XG5cbiAgICAgICAgICByZXR1cm4gcmVzb2x2ZSh0aGlzLnJlcXVlc3QoT2JqZWN0LmFzc2lnbih7fSwgY29uZmlnLCB7IHVybCB9KSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHJlc3BvbnNlQnVmZmVyID0gW107XG4gICAgICAgIHN0cmVhbS5vbignZGF0YScsIGNodW5rID0+IHJlc3BvbnNlQnVmZmVyLnB1c2goY2h1bmspKTtcblxuICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dDogaXRzIGhhcmQgdG8gdGVzdCBzb2NrZXQgZXZlbnRzIHdpdGggamVzdCBhbmQgbm9jayAtIHRlc3RlZCBtYW51YWxseSAqL1xuICAgICAgICBzdHJlYW0ub24oJ2Vycm9yJywgZXJyID0+IHtcbiAgICAgICAgICByZXMgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgcmVxID0gdW5kZWZpbmVkO1xuICAgICAgICAgIHJlc3BvbnNlQnVmZmVyID0gdW5kZWZpbmVkO1xuICAgICAgICAgIGRlYnVnKCdSZXF1ZXN0IGVycm9yOiBBYm9ydGVkICVPJywgZXJyKTtcblxuICAgICAgICAgIGlmIChyZXEuYWJvcnRlZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIGNsZWFyIGNhbmNlbCB0b2tlbiB0byBhdm9pZCBtZW1vcnkgbGVha1xuICAgICAgICAgIGlmIChjYW5jZWxMaXN0ZW5lcikge1xuICAgICAgICAgICAgY29uZmlnLmNhbmNlbFRva2VuLnJlbW92ZUxpc3RlbmVyKGNhbmNlbExpc3RlbmVyKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcihlcnIubWVzc2FnZSwgY29uZmlnLCBudWxsLCBGc1JlcXVlc3RFcnJvckNvZGUuTkVUV09SSykpO1xuICAgICAgICB9KTtcblxuICAgICAgICBzdHJlYW0ub24oJ2VuZCcsIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAvLyBjbGVhciBjYW5jZWwgdG9rZW4gdG8gYXZvaWQgbWVtb3J5IGxlYWtcbiAgICAgICAgICBpZiAoY2FuY2VsTGlzdGVuZXIpIHtcbiAgICAgICAgICAgIGNvbmZpZy5jYW5jZWxUb2tlbi5yZW1vdmVMaXN0ZW5lcihjYW5jZWxMaXN0ZW5lcik7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gY2hlY2sgaWYgdGhlcmUgaXMgYW55IHJlc3BvbnNlIGRhdGEgaW5zaWRlXG4gICAgICAgICAgaWYgKHJlcy5zdGF0dXNDb2RlICE9PSAyMDQpIHtcbiAgICAgICAgICAgIC8vIHByZXBhcmUgcmVzcG9uc2VcbiAgICAgICAgICAgIHJlc3BvbnNlLmRhdGEgPSBCdWZmZXIuY29uY2F0KHJlc3BvbnNlQnVmZmVyKTtcbiAgICAgICAgICAgIHJlc3BvbnNlID0gYXdhaXQgcGFyc2VSZXNwb25zZShyZXNwb25zZSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJlc3BvbnNlLmRhdGEgPSBudWxsO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIGZyZWUgcmVzb3VyY2VzXG4gICAgICAgICAgcmVzID0gdW5kZWZpbmVkO1xuICAgICAgICAgIHJlcSA9IHVuZGVmaW5lZDtcblxuICAgICAgICAgIHJlc3BvbnNlQnVmZmVyID0gdW5kZWZpbmVkO1xuXG4gICAgICAgICAgaWYgKDUwMCA8PSByZXNwb25zZS5zdGF0dXMgJiYgcmVzcG9uc2Uuc3RhdHVzIDw9IDU5OSkge1xuICAgICAgICAgICAgLy8gc2VydmVyIGVycm9yIHRocm93XG4gICAgICAgICAgICBkZWJ1ZygnU2VydmVyIGVycm9yKDV4eCkgLSAlTycsIHJlc3BvbnNlKTtcbiAgICAgICAgICAgIHJldHVybiByZWplY3QobmV3IEZzUmVxdWVzdEVycm9yKGBTZXJ2ZXIgZXJyb3IgJHt1cmx9YCwgY29uZmlnLCByZXNwb25zZSwgRnNSZXF1ZXN0RXJyb3JDb2RlLlNFUlZFUikpO1xuICAgICAgICAgIH0gZWxzZSBpZiAoNDAwIDw9IHJlc3BvbnNlLnN0YXR1cyAmJiByZXNwb25zZS5zdGF0dXMgPD0gNDk5KSB7XG4gICAgICAgICAgICBkZWJ1ZygnUmVxdWVzdCBlcnJvcig0eHgpIC0gJU8nLCByZXNwb25zZSk7XG4gICAgICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcihgUmVxdWVzdCBlcnJvciAke3VybH1gLCBjb25maWcsIHJlc3BvbnNlLCBGc1JlcXVlc3RFcnJvckNvZGUuUkVRVUVTVCkpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGRlYnVnKCdSZXF1ZXN0IGVuZHM6ICVPJywgcmVzcG9uc2UpO1xuICAgICAgICAgIHJldHVybiByZXNvbHZlKHJlc3BvbnNlKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgaWYgKGNvbmZpZy50aW1lb3V0KSB7XG4gICAgICAgIHJlcS5zZXRUaW1lb3V0KGNvbmZpZy50aW1lb3V0LCAoKSA9PiB7XG4gICAgICAgICAgcmVxLmFib3J0KCk7XG5cbiAgICAgICAgICBpZiAoY2FuY2VsTGlzdGVuZXIpIHtcbiAgICAgICAgICAgIGNvbmZpZy5jYW5jZWxUb2tlbi5yZW1vdmVMaXN0ZW5lcihjYW5jZWxMaXN0ZW5lcik7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoJ1JlcXVlc3QgdGltZW91dCcsIGNvbmZpZywgbnVsbCwgRnNSZXF1ZXN0RXJyb3JDb2RlLlRJTUVPVVQpKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHJlcS5vbignZXJyb3InLCBlcnIgPT4ge1xuICAgICAgICBpZiAoY2FuY2VsTGlzdGVuZXIpIHtcbiAgICAgICAgICBjb25maWcuY2FuY2VsVG9rZW4ucmVtb3ZlTGlzdGVuZXIoY2FuY2VsTGlzdGVuZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFyZXEgfHwgcmVxLmFib3J0ZWQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBkZWJ1ZygnUmVxdWVzdCBlcnJvcjogJXMgLSAlTycsIGVyciwgZXJyLmNvZGUpO1xuICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcihgUmVxdWVzdCBlcnJvcjogJHtlcnIuY29kZX1gLCBjb25maWcsIG51bGwsIEZzUmVxdWVzdEVycm9yQ29kZS5ORVRXT1JLKSk7XG4gICAgICB9KTtcblxuICAgICAgaWYgKEJ1ZmZlci5pc0J1ZmZlcihkYXRhKSAmJiBbJ1BPU1QnLCAnUFVUJ10uaW5kZXhPZihjb25maWcubWV0aG9kKSA+IC0xKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmJ1ZmZlclRvQ2h1bmtzKGRhdGEpLnBpcGUodGhpcy5nZXRQcm9ncmVzc01vbml0b3IoY29uZmlnLCBkYXRhLmxlbmd0aCkpLnBpcGUobmV3IEh0dHBXcml0YWJsZVN0cmVhbShyZXEpKTtcbiAgICAgIH1cblxuICAgICAgcmVxLmVuZChkYXRhKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNb25pdG9yIGFuZCBlbWl0IHByb2dyZXNzIGV2ZW50IGlmIG5lZWRlZFxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAbWVtYmVyb2YgSHR0cEFkYXB0ZXJcbiAgICovXG4gIHByaXZhdGUgZ2V0UHJvZ3Jlc3NNb25pdG9yID0gKGNvbmZpZywgdG90YWwpID0+IHtcbiAgICBsZXQgbG9hZGVkID0gMDtcblxuICAgIGNvbnN0IHByb2dyZXNzID0gbmV3IFN0cmVhbS5UcmFuc2Zvcm0oKTtcbiAgICBwcm9ncmVzcy5fdHJhbnNmb3JtID0gKGNodW5rLCBlbmNvZGluZywgY2IpID0+IHtcbiAgICAgIGlmICh0eXBlb2YgY29uZmlnLm9uUHJvZ3Jlc3MgPT09ICdmdW5jdGlvbicgJiYgW0ZzSHR0cE1ldGhvZC5QT1NULCBGc0h0dHBNZXRob2QuUFVUXS5pbmRleE9mKGNvbmZpZy5tZXRob2QpID4gLTEpIHtcbiAgICAgICAgbG9hZGVkICs9IGNodW5rLmxlbmd0aDtcbiAgICAgICAgY29uZmlnLm9uUHJvZ3Jlc3Moe1xuICAgICAgICAgIGxlbmd0aENvbXB1dGFibGU6IHRydWUsXG4gICAgICAgICAgbG9hZGVkLFxuICAgICAgICAgIHRvdGFsLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIGNiKG51bGwsIGNodW5rKTtcbiAgICB9O1xuXG4gICAgcmV0dXJuIHByb2dyZXNzO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgYnVmZmVyIHRvIHN0cmVhbVxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0geyp9IGJ1ZmZlclxuICAgKiBAcmV0dXJucyB7U3RyZWFtLlJlYWRhYmxlfVxuICAgKiBAbWVtYmVyb2YgSHR0cEFkYXB0ZXJcbiAgICovXG4gIHByaXZhdGUgYnVmZmVyVG9DaHVua3MoYnVmZmVyKTogU3RyZWFtLlJlYWRhYmxlIHtcbiAgICBjb25zdCBjaHVua2luZyA9IG5ldyBTdHJlYW0uUmVhZGFibGUoKTtcbiAgICBjb25zdCB0b3RhbExlbmd0aCA9IGJ1ZmZlci5sZW5ndGg7XG4gICAgY29uc3QgcmVtYWluZGVyID0gdG90YWxMZW5ndGggJSBIVFRQX0NIVU5LX1NJWkU7XG4gICAgY29uc3QgY3V0b2ZmID0gdG90YWxMZW5ndGggLSByZW1haW5kZXI7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGN1dG9mZjsgaSArPSBIVFRQX0NIVU5LX1NJWkUpIHtcbiAgICAgIGNvbnN0IGNodW5rID0gYnVmZmVyLnNsaWNlKGksIGkgKyBIVFRQX0NIVU5LX1NJWkUpO1xuICAgICAgY2h1bmtpbmcucHVzaChjaHVuayk7XG4gICAgfVxuXG4gICAgaWYgKHJlbWFpbmRlciA+IDApIHtcbiAgICAgIGNvbnN0IHJlbWFpbmRlckJ1ZmZlciA9IGJ1ZmZlci5zbGljZSgtcmVtYWluZGVyKTtcbiAgICAgIGNodW5raW5nLnB1c2gocmVtYWluZGVyQnVmZmVyKTtcbiAgICB9XG5cbiAgICBjaHVua2luZy5wdXNoKG51bGwpO1xuXG4gICAgcmV0dXJuIGNodW5raW5nO1xuICB9XG59XG4iXX0=
;