filestack-js
Version:
Official JavaScript library for Filestack
326 lines (324 loc) • 44.8 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.
*/
import { __awaiter, __extends, __generator } from "tslib";
import * as url from 'url';
import * as zlib from 'zlib';
import Debug from 'debug';
import { getVersion } from '../../utils';
import * as Stream from 'stream';
import * as utils from '../utils';
import { prepareData, parseResponse, combineURL, set as setHeader, normalizeHeaders } from './../helpers';
import { FsRequestErrorCode, FsRequestError } from '../error';
import { FsHttpMethod } from './../types';
var HTTPS_REGEXP = /https:?/;
var HTTP_CHUNK_SIZE = 16 * 1024;
var MAX_REDIRECTS = 10;
var CANCEL_CLEAR = "FsCleanMemory";
var debug = Debug('fs:request:http');
/**
* Writable stream thats overwrap http request for progress event
*
* @class HttpWritableStream
* @extends {Stream.Writable}
*/
var HttpWritableStream = /** @class */ (function (_super) {
__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) {
if (chunk) {
this.request.write(chunk);
}
this.request.end();
return this;
};
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' && [FsHttpMethod.POST, 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 = normalizeHeaders(config.headers);
var _a = prepareData(config), data = _a.data, headers = _a.headers;
headers = setHeader(headers, 'user-agent', "filestack-request/".concat(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 FsRequestError('Data must be a string, JSON or a Buffer', config));
}
data = Buffer.from(data, 'utf-8');
}
headers = setHeader(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 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 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: 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 FsRequestError("Request aborted. Reason: ".concat(reason), config, null, 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 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 FsRequestError("Max redirects (".concat(_this.redirectHoops, ") reached. Exiting"), config, response, FsRequestErrorCode.REDIRECT));
}
var url_1 = res.headers['location'];
if (!url_1 || url_1.length === 0) {
return reject(new FsRequestError("Redirect header location not found", config, response, FsRequestErrorCode.REDIRECT));
}
if (_this.redirectPaths.indexOf(url_1) > -1) {
return reject(new FsRequestError("Redirect loop detected at url ".concat(url_1), config, response, 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 FsRequestError(err.message, config, null, FsRequestErrorCode.NETWORK));
});
stream.on('end', function () { return __awaiter(_this, void 0, void 0, function () {
return __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*/, 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 FsRequestError("Server error ".concat(url), config, response, FsRequestErrorCode.SERVER))];
}
else if (400 <= response.status && response.status <= 499) {
debug('Request error(4xx) - %O', response);
return [2 /*return*/, reject(new FsRequestError("Request error ".concat(url), config, response, 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 FsRequestError('Request timeout', config, null, 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 FsRequestError("Request error: ".concat(err.code), config, null, 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;
}());
export { HttpAdapter };
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvcmVxdWVzdC9hZGFwdGVycy9odHRwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRzs7QUFFSCxPQUFPLEtBQUssR0FBRyxNQUFNLEtBQUssQ0FBQztBQUMzQixPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUM3QixPQUFPLEtBQUssTUFBTSxPQUFPLENBQUM7QUFHMUIsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN6QyxPQUFPLEtBQUssTUFBTSxNQUFNLFFBQVEsQ0FBQztBQUVqQyxPQUFPLEtBQUssS0FBSyxNQUFNLFVBQVUsQ0FBQztBQUNsQyxPQUFPLEVBQUUsV0FBVyxFQUFFLGFBQWEsRUFBRSxVQUFVLEVBQUUsR0FBRyxJQUFJLFNBQVMsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUMxRyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsY0FBYyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQzlELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFMUMsSUFBTSxZQUFZLEdBQUcsU0FBUyxDQUFDO0FBQy9CLElBQU0sZUFBZSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFDbEMsSUFBTSxhQUFhLEdBQUcsRUFBRSxDQUFDO0FBQ3pCLElBQU0sWUFBWSxHQUFHLGVBQWUsQ0FBQztBQUNyQyxJQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsaUJBQWlCLENBQUMsQ0FBQztBQUV2Qzs7Ozs7R0FLRztBQUNIO0lBQWlDLHNDQUFlO0lBRzlDLDRCQUFZLEdBQUcsRUFBRSxJQUFTO1FBQVQscUJBQUEsRUFBQSxTQUFTO1FBQTFCLFlBQ0Usa0JBQU0sSUFBSSxDQUFDLFNBSVo7UUFGQyxLQUFJLENBQUMsT0FBTyxHQUFHLEdBQUcsQ0FBQztRQUNuQixHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxjQUFNLE9BQUEsS0FBSSxDQUFD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O1NBQ3RCO1FBRUQsSUFBSSxTQUFTLEdBQUcsQ0FBQyxFQUFFO1lBQ2pCLElBQU0sZUFBZSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUNqRCxRQUFRLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1NBQ2hDO1FBRUQsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUVwQixPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBQ0gsa0JBQUM7QUFBRCxDQWxUQSxBQWtUQyxJQUFBIiwiZmlsZSI6ImxpYi9yZXF1ZXN0L2FkYXB0ZXJzL2h0dHAuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogQ29weXJpZ2h0IChjKSAyMDE4IGJ5IEZpbGVzdGFja1xuICogU29tZSByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICovXG5cbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xuaW1wb3J0ICogYXMgemxpYiBmcm9tICd6bGliJztcbmltcG9ydCBEZWJ1ZyBmcm9tICdkZWJ1Zyc7XG5cbmltcG9ydCB7IEFkYXB0ZXJJbnRlcmZhY2UgfSBmcm9tICcuL2ludGVyZmFjZSc7XG5pbXBvcnQgeyBnZXRWZXJzaW9uIH0gZnJvbSAnLi4vLi4vdXRpbHMnO1xuaW1wb3J0ICogYXMgU3RyZWFtIGZyb20gJ3N0cmVhbSc7XG5pbXBvcnQgeyBGc1JlcXVlc3RPcHRpb25zLCBGc1Jlc3BvbnNlIH0gZnJvbSAnLi4vdHlwZXMnO1xuaW1wb3J0ICogYXMgdXRpbHMgZnJvbSAnLi4vdXRpbHMnO1xuaW1wb3J0IHsgcHJlcGFyZURhdGEsIHBhcnNlUmVzcG9uc2UsIGNvbWJpbmVVUkwsIHNldCBhcyBzZXRIZWFkZXIsIG5vcm1hbGl6ZUhlYWRlcnMgfSBmcm9tICcuLy4uL2hlbHBlcnMnO1xuaW1wb3J0IHsgRnNSZXF1ZXN0RXJyb3JDb2RlLCBGc1JlcXVlc3RFcnJvciB9IGZyb20gJy4uL2Vycm9yJztcbmltcG9ydCB7IEZzSHR0cE1ldGhvZCB9IGZyb20gJy4vLi4vdHlwZXMnO1xuXG5jb25zdCBIVFRQU19SRUdFWFAgPSAvaHR0cHM6Py87XG5jb25zdCBIVFRQX0NIVU5LX1NJWkUgPSAxNiAqIDEwMjQ7XG5jb25zdCBNQVhfUkVESVJFQ1RTID0gMTA7XG5jb25zdCBDQU5DRUxfQ0xFQVIgPSBgRnNDbGVhbk1lbW9yeWA7XG5jb25zdCBkZWJ1ZyA9IERlYnVnKCdmczpyZXF1ZXN0Omh0dHAnKTtcblxuLyoqXG4gKiBXcml0YWJsZSBzdHJlYW0gdGhhdHMgb3ZlcndyYXAgaHR0cCByZXF1ZXN0IGZvciBwcm9ncmVzcyBldmVudFxuICpcbiAqIEBjbGFzcyBIdHRwV3JpdGFibGVTdHJlYW1cbiAqIEBleHRlbmRzIHtTdHJlYW0uV3JpdGFibGV9XG4gKi9cbmNsYXNzIEh0dHBXcml0YWJsZVN0cmVhbSBleHRlbmRzIFN0cmVhbS5Xcml0YWJsZSB7XG4gIHByaXZhdGUgcmVxdWVzdDtcblxuICBjb25zdHJ1Y3RvcihyZXEsIG9wdHMgPSB7fSkge1xuICAgIHN1cGVyKG9wdHMpO1xuXG4gICAgdGhpcy5yZXF1ZXN0ID0gcmVxO1xuICAgIHJlcS5vbmNlKCdkcmFpbicsICgpID0+IHRoaXMuZW1pdCgnZHJhaW4nKSk7XG4gIH1cblxuICBfd3JpdGUoY2h1bms6IGFueSwgZW5jb2Rpbmc/OiBzdHJpbmcsIGNiPzogKGVycm9yOiBFcnJvciB8IG51bGwgfCB1bmRlZmluZWQpID0+IHZvaWQpOiB2b2lkIHtcbiAgICB0aGlzLnJlcXVlc3Qud3JpdGUoY2h1bmssIGVuY29kaW5nLCBjYik7XG4gIH1cblxuICBlbmQoY2h1bmspIHtcbiAgICBpZiAoY2h1bmspIHtcbiAgICAgIHRoaXMucmVxdWVzdC53cml0ZShjaHVuayk7XG4gICAgfVxuXG4gICAgdGhpcy5yZXF1ZXN0LmVuZCgpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG5cbi8qKlxuICogTm9kZSBodHRwIHJlcXVlc3QgY2xhc3NcbiAqXG4gKiBAZXhwb3J0XG4gKiBAY2xhc3MgSHR0cEFkYXB0ZXJcbiAqIEBpbXBsZW1lbnRzIHtBZGFwdGVySW50ZXJmYWNlfVxuICovXG5leHBvcnQgY2xhc3MgSHR0cEFkYXB0ZXIgaW1wbGVtZW50cyBBZGFwdGVySW50ZXJmYWNlIHtcbiAgcHJpdmF0ZSByZWRpcmVjdEhvb3BzID0gMDtcbiAgcHJpdmF0ZSByZWRpcmVjdFBhdGhzID0gW107XG5cbiAgLyoqXG4gICAqIGRvIHJlcXVlc3QgYmFzZWQgb24gY29uZmlndXJhdGlvblxuICAgKlxuICAgKiBAcGFyYW0ge0ZzUmVxdWVzdE9wdGlvbnN9IGNvbmZpZ1xuICAgKiBAcmV0dXJuc1xuICAgKiBAbWVtYmVyb2YgSHR0cEFkYXB0ZXJcbiAgICovXG4gIHJlcXVlc3QoY29uZmlnOiBGc1JlcXVlc3RPcHRpb25zKSB7XG4gICAgLy8gaWYgdGhpcyBvcHRpb24gaXMgdW5zcGVjaWZpZWQgc2V0IGl0IGJ5IGRlZmF1bHRcbiAgICBpZiAodHlwZW9mIGNvbmZpZy5maWxlc3RhY2tIZWFkZXJzID09PSAndW5kZWZpbmVkJykge1xuICAgICAgY29uZmlnLmZpbGVzdGFja0hlYWRlcnMgPSB0cnVlO1xuICAgIH1cblxuICAgIGNvbmZpZy5oZWFkZXJzID0gbm9ybWFsaXplSGVhZGVycyhjb25maWcuaGVhZGVycyk7XG5cbiAgICBsZXQgeyBkYXRhLCBoZWFkZXJzIH0gPSBwcmVwYXJlRGF0YShjb25maWcpO1xuXG4gICAgaGVhZGVycyA9IHNldEhlYWRlcihoZWFkZXJzLCAndXNlci1hZ2VudCcsIGBmaWxlc3RhY2stcmVxdWVzdC8ke2dldFZlcnNpb24oKX1gKTtcblxuICAgIC8vIGZvciBub3cgd2UgYXJlIG5vdCB1c2luZyBzdHJlYW1zXG4gICAgaWYgKGRhdGEpIHtcbiAgICAgIGRlYnVnKCdSZXF1ZXN0IGRhdGEgJU8nLCBkYXRhKTtcblxuICAgICAgaWYgKCFCdWZmZXIuaXNCdWZmZXIoZGF0YSkpIHtcbiAgICAgICAgaWYgKCF1dGlscy5pc1N0cmluZyhkYXRhKSkge1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoJ0RhdGEgbXVzdCBiZSBhIHN0cmluZywgSlNPTiBvciBhIEJ1ZmZlcicsIGNvbmZpZykpO1xuICAgICAgICB9XG5cbiAgICAgICAgZGF0YSA9IEJ1ZmZlci5mcm9tKGRhdGEsICd1dGYtOCcpO1xuICAgICAgfVxuXG4gICAgICBoZWFkZXJzID0gc2V0SGVhZGVyKGhlYWRlcnMsICdjb250ZW50LWxlbmd0aCcsIGRhdGEubGVuZ3RoLCB0cnVlKTtcbiAgICB9XG5cbiAgICAvLyBIVFRQIGJhc2ljIGF1dGhlbnRpY2F0aW9uXG4gICAgbGV0IGF1dGg7XG4gICAgaWYgKGNvbmZpZy5hdXRoKSB7XG4gICAgICBpZiAoIWNvbmZpZy5hdXRoLnVzZXJuYW1lIHx8IGNvbmZpZy5hdXRoLnVzZXJuYW1lLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QobmV3IEZzUmVxdWVzdEVycm9yKGBCYXNpYyBhdXRoOiB1c2VybmFtZSBpcyByZXF1aXJlZCAke2NvbmZpZy5hdXRofWAsIGNvbmZpZykpO1xuICAgICAgfVxuXG4gICAgICBhdXRoID0gYCR7Y29uZmlnLmF1dGgudXNlcm5hbWV9OiR7Y29uZmlnLmF1dGgucGFzc3dvcmR9YDtcbiAgICB9XG5cbiAgICAvLyBQYXJzZSB1cmxcbiAgICBsZXQgcGFyc2VkID0gdXJsLnBhcnNlKGNvbmZpZy51cmwpO1xuXG4gICAgLy8gdHJ5IHRvIGFkZCBkZWZhdWx0IGh0dHBzIHByb3RvY29sXG4gICAgaWYgKCFwYXJzZWQucHJvdG9jb2wpIHtcbiAgICAgIHBhcnNlZCA9IHVybC5wYXJzZShgaHR0cHM6Ly8ke2NvbmZpZy51cmx9YCk7XG4gICAgfVxuXG4gICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQ6IGp1c3QgYmUgc3VyZSB0aGF0IHRoZSBob3N0IGlzIHBhcnNlZCBjb3JyZWN0bHksIG5vdCBuZWVkZWQgdG8gdGVzdCAqL1xuICAgIGlmICghcGFyc2VkLmhvc3QpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoYENhbm5vdCBwYXJzZSBwcm92aWRlZCB1cmwgJHtjb25maWcudXJsfWAsIGNvbmZpZykpO1xuICAgIH1cblxuICAgIC8vIG5vcm1hbGl6ZSBhdXRoIGhlYWRlclxuICAgIGlmIChhdXRoICYmIGhlYWRlcnMuQXV0aG9yaXphdGlvbikge1xuICAgICAgZGVsZXRlIGhlYWRlcnMuQXV0aG9yaXphdGlvbjtcbiAgICB9XG5cbiAgICBjb25zdCBpc0h0dHBzUmVxdWVzdCA9IEhUVFBTX1JFR0VYUC50ZXN0KHBhcnNlZC5wcm90b2NvbCk7XG4gICAgY29uc3QgYWdlbnQgPSBpc0h0dHBzUmVxdWVzdCA/IHJlcXVpcmUoJ2h0dHBzJykgOiByZXF1aXJlKCdodHRwJyk7XG5cbiAgICBjb25zdCBvcHRpb25zID0ge1xuICAgICAgcGF0aDogY29tYmluZVVSTChwYXJzZWQucGF0aCwgY29uZmlnLnBhcmFtcyksXG4gICAgICBob3N0OiBwYXJzZWQuaG9zdCxcbiAgICAgIHBvcnQ6IHBhcnNlZC5wb3J0LFxuICAgICAgcHJvdG9jb2w6IHBhcnNlZC5wcm90b2NvbCxcbiAgICAgIG1ldGhvZDogY29uZmlnLm1ldGhvZC50b1VwcGVyQ2FzZSgpLFxuICAgICAgaGVhZGVyczogaGVhZGVycyxcbiAgICAgIGFnZW50OiBuZXcgYWdlbnQuQWdlbnQoKSxcbiAgICAgIGF1dGg6IGF1dGgsXG4gICAgfTtcblxuICAgIGRlYnVnKCdTdGFydGluZyAlcyByZXF1ZXN0IHdpdGggb3B0aW9ucyAlTycsIGlzSHR0cHNSZXF1ZXN0ID8gJ2h0dHBzJyA6ICdodHRwJywgb3B0aW9ucyk7XG5cbiAgICByZXR1cm4gbmV3IFByb21pc2U8RnNSZXNwb25zZT4oKHJlc29sdmUsIHJlamVjdCk6IGFueSA9PiB7XG4gICAgICBsZXQgcmVxO1xuICAgICAgbGV0IGNhbmNlbExpc3RlbmVyO1xuXG4gICAgICBpZiAoY29uZmlnLmNhbmNlbFRva2VuKSB7XG4gICAgICAgIGNhbmNlbExpc3RlbmVyID0gY29uZmlnLmNhbmNlbFRva2VuLm9uKCdjYW5jZWwnLCAocmVhc29uKSA9PiB7XG4gICAgICAgICAgLy8gY2xlYW51cCBoYW5kbGVyXG4gICAgICAgICAgY2FuY2VsTGlzdGVuZXIgPSBudWxsO1xuXG4gICAgICAgICAgLy8gZG8gbm90aGluZyBpZiBwcm9taXNlIGlzIHJlc29sdmVkIGJ5IHN5c3RlbVxuICAgICAgICAgIGlmIChyZWFzb24gJiYgcmVhc29uLm1lc3NhZ2UgPT09IENBTkNFTF9DTEVBUikge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBpZiByZXF1ZXN0IGlzIGRvbmUgY2FuY2VsIHRva2VuIHNob3VsZCBub3QgdGhyb3cgYW55IGVycm9yICovXG4gICAgICAgICAgaWYgKHJlcSkge1xuICAgICAgICAgICAgcmVxLmFib3J0KCk7XG4gICAgICAgICAgICByZXEgPSBudWxsO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGRlYnVnKCdSZXF1ZXN0IGNhbmNlbGVkIGJ5IHVzZXIgJXMsIGNvbmZpZzogJU8nLCByZWFzb24sIGNvbmZpZyk7XG4gICAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoYFJlcXVlc3QgYWJvcnRlZC4gUmVhc29uOiAke3JlYXNvbn1gLCBjb25maWcsIG51bGwsIEZzUmVxdWVzdEVycm9yQ29kZS5BQk9SVEVEKSk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICByZXEgPSBhZ2VudC5yZXF1ZXN0KG9wdGlvbnMsIHJlcyA9PiB7XG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBqdXN0IGJlIHN1cmUgdGhhdCByZXNwb25zZSB3aWxsIG5vdCBiZSBjYWxsZWQgYWZ0ZXIgcmVxdWVzdCBpcyBhYm9ydGVkICovXG4gICAgICAgIGlmICghcmVxIHx8IHJlcS5hYm9ydGVkKSB7XG4gICAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoJ1JlcXVlc3QgYWJvcnRlZCcsIGNvbmZpZykpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHN0cmVhbSA9IHJlcztcbiAgICAgICAgZGVidWcoJ1Jlc3BvbnNlIHN0YXR1c0NvZGU6ICVkLCBSZXNwb25zZSBIZWFkZXJzOiAlTycsIHJlcy5zdGF0dXNDb2RlLCByZXMuaGVhZGVycyk7XG5cbiAgICAgICAgY29uc3QgY29tcHJlc3NIZWFkZXJzID0gcmVzLmhlYWRlcnNbJ2NvbnRlbnQtZW5jb2RpbmcnXTtcblxuICAgICAgICBpZiAoY29tcHJlc3NIZWFkZXJzICYmIGNvbXByZXNzSGVhZGVycy5sZW5ndGggJiYgWydnemlwJywgJ2NvbXByZXNzJywgJ2RlZmxhdGUnXS5zb21lKCh2KSA9PiBjb21wcmVzc0hlYWRlcnMuaW5kZXhPZih2KSA+IC0xKSkge1xuICAgICAgICAgIC8vIGFkZCB0aGUgdW56aXBwZXIgdG8gdGhlIGJvZHkgc3RyZWFtIHByb2Nlc3NpbmcgcGlwZWxpbmVcbiAgICAgICAgICBzdHJlYW0gPSByZXMuc3RhdHVzQ29kZSA9PT0gMjA0ID8gc3RyZWFtIDogc3RyZWFtLnBpcGUoemxpYi5jcmVhdGVVbnppcCgpKTtcbiAgICAgICAgICAvLyByZW1vdmUgdGhlIGNvbnRlbnQtZW5jb2RpbmcgaW4gb3JkZXIgdG8gbm90IGNvbmZ1c2UgZG93bnN0cmVhbSBvcGVyYXRpb25zXG4gICAgICAgICAgZGVsZXRlIHJlcy5oZWFkZXJzWydjb250ZW50LWVuY29kaW5nJ107XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgcmVzcG9uc2U6IEZzUmVzcG9uc2UgPSB7XG4gICAgICAgICAgc3RhdHVzOiByZXMuc3RhdHVzQ29kZSxcbiAgICAgICAgICBzdGF0dXNUZXh0OiByZXMuc3RhdHVzTWVzc2FnZSxcbiAgICAgICAgICBoZWFkZXJzOiByZXMuaGVhZGVycyxcbiAgICAgICAgICBjb25maWcsXG4gICAgICAgICAgZGF0YToge30sXG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gd2UgbmVlZCB0byBmb2xsb3cgcmVkaXJlY3Qgc28gbWFrZSBzYW1lIHJlcXVlc3Qgd2l0aCBuZXcgbG9jYXRpb25cbiAgICAgICAgaWYgKFszMDEsIDMwMl0uaW5kZXhPZihyZXMuc3RhdHVzQ29kZSkgPiAtMSkge1xuICAgICAgICAgIGRlYnVnKCdSZWRpcmVjdCByZWNlaXZlZCAlcycsIHJlcy5zdGF0dXNDb2RlKTtcblxuICAgICAgICAgIGlmICh0aGlzLnJlZGlyZWN0SG9vcHMgPj0gTUFYX1JFRElSRUNUUykge1xuICAgICAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoYE1heCByZWRpcmVjdHMgKCR7dGhpcy5yZWRpcmVjdEhvb3BzfSkgcmVhY2hlZC4gRXhpdGluZ2AsIGNvbmZpZywgcmVzcG9uc2UsIEZzUmVxdWVzdEVycm9yQ29kZS5SRURJUkVDVCkpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IHVybCA9IHJlcy5oZWFkZXJzWydsb2NhdGlvbiddO1xuXG4gICAgICAgICAgaWYgKCF1cmwgfHwgdXJsLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoYFJlZGlyZWN0IGhlYWRlciBsb2NhdGlvbiBub3QgZm91bmRgLCBjb25maWcsIHJlc3BvbnNlLCBGc1JlcXVlc3RFcnJvckNvZGUuUkVESVJFQ1QpKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAodGhpcy5yZWRpcmVjdFBhdGhzLmluZGV4T2YodXJsKSA+IC0xKSB7XG4gICAgICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcihgUmVkaXJlY3QgbG9vcCBkZXRlY3RlZCBhdCB1cmwgJHt1cmx9YCwgY29uZmlnLCByZXNwb25zZSwgRnNSZXF1ZXN0RXJyb3JDb2RlLlJFRElSRUNUKSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy5yZWRpcmVjdFBhdGhzLnB1c2godXJsKTtcbiAgICAgICAgICB0aGlzLnJlZGlyZWN0SG9vcHMrKztcblxuICAgICAgICAgIC8vIGZyZWUgcmVzb3VyY2VzXG4gICAgICAgICAgcmVzID0gdW5kZWZpbmVkO1xuICAgICAgICAgIHJlcSA9IHVuZGVmaW5lZDtcblxuICAgICAgICAgIGRlYnVnKCdSZWRpcmVjdGluZyByZXF1ZXN0IHRvICVzIChob29wLWNvdW50OiAlZCknLCB1cmwsIHRoaXMucmVkaXJlY3RIb29wcyk7XG5cbiAgICAgICAgICByZXR1cm4gcmVzb2x2ZSh0aGlzLnJlcXVlc3QoT2JqZWN0LmFzc2lnbih7fSwgY29uZmlnLCB7IHVybCB9KSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHJlc3BvbnNlQnVmZmVyID0gW107XG4gICAgICAgIHN0cmVhbS5vbignZGF0YScsIGNodW5rID0+IHJlc3BvbnNlQnVmZmVyLnB1c2goY2h1bmspKTtcblxuICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dDogaXRzIGhhcmQgdG8gdGVzdCBzb2NrZXQgZXZlbnRzIHdpdGggamVzdCBhbmQgbm9jayAtIHRlc3RlZCBtYW51YWxseSAqL1xuICAgICAgICBzdHJlYW0ub24oJ2Vycm9yJywgZXJyID0+IHtcbiAgICAgICAgICByZXMgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgcmVxID0gdW5kZWZpbmVkO1xuICAgICAgICAgIHJlc3BvbnNlQnVmZmVyID0gdW5kZWZpbmVkO1xuICAgICAgICAgIGRlYnVnKCdSZXF1ZXN0IGVycm9yOiBBYm9ydGVkICVPJywgZXJyKTtcblxuICAgICAgICAgIGlmIChyZXEuYWJvcnRlZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIGNsZWFyIGNhbmNlbCB0b2tlbiB0byBhdm9pZCBtZW1vcnkgbGVha1xuICAgICAgICAgIGlmIChjYW5jZWxMaXN0ZW5lcikge1xuICAgICAgICAgICAgY29uZmlnLmNhbmNlbFRva2VuLnJlbW92ZUxpc3RlbmVyKGNhbmNlbExpc3RlbmVyKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcihlcnIubWVzc2FnZSwgY29uZmlnLCBudWxsLCBGc1JlcXVlc3RFcnJvckNvZGUuTkVUV09SSykpO1xuICAgICAgICB9KTtcblxuICAgICAgICBzdHJlYW0ub24oJ2VuZCcsIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAvLyBjbGVhciBjYW5jZWwgdG9rZW4gdG8gYXZvaWQgbWVtb3J5IGxlYWtcbiAgICAgICAgICBpZiAoY2FuY2VsTGlzdGVuZXIpIHtcbiAgICAgICAgICAgIGNvbmZpZy5jYW5jZWxUb2tlbi5yZW1vdmVMaXN0ZW5lcihjYW5jZWxMaXN0ZW5lcik7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gY2hlY2sgaWYgdGhlcmUgaXMgYW55IHJlc3BvbnNlIGRhdGEgaW5zaWRlXG4gICAgICAgICAgaWYgKHJlcy5zdGF0dXNDb2RlICE9PSAyMDQpIHtcbiAgICAgICAgICAgIC8vIHByZXBhcmUgcmVzcG9uc2VcbiAgICAgICAgICAgIHJlc3BvbnNlLmRhdGEgPSBCdWZmZXIuY29uY2F0KHJlc3BvbnNlQnVmZmVyKTtcbiAgICAgICAgICAgIHJlc3BvbnNlID0gYXdhaXQgcGFyc2VSZXNwb25zZShyZXNwb25zZSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJlc3BvbnNlLmRhdGEgPSBudWxsO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIGZyZWUgcmVzb3VyY2VzXG4gICAgICAgICAgcmVzID0gdW5kZWZpbmVkO1xuICAgICAgICAgIHJlcSA9IHVuZGVmaW5lZDtcblxuICAgICAgICAgIHJlc3BvbnNlQnVmZmVyID0gdW5kZWZpbmVkO1xuXG4gICAgICAgICAgaWYgKDUwMCA8PSByZXNwb25zZS5zdGF0dXMgJiYgcmVzcG9uc2Uuc3RhdHVzIDw9IDU5OSkge1xuICAgICAgICAgICAgLy8gc2VydmVyIGVycm9yIHRocm93XG4gICAgICAgICAgICBkZWJ1ZygnU2VydmVyIGVycm9yKDV4eCkgLSAlTycsIHJlc3BvbnNlKTtcbiAgICAgICAgICAgIHJldHVybiByZWplY3QobmV3IEZzUmVxdWVzdEVycm9yKGBTZXJ2ZXIgZXJyb3IgJHt1cmx9YCwgY29uZmlnLCByZXNwb25zZSwgRnNSZXF1ZXN0RXJyb3JDb2RlLlNFUlZFUikpO1xuICAgICAgICAgIH0gZWxzZSBpZiAoNDAwIDw9IHJlc3BvbnNlLnN0YXR1cyAmJiByZXNwb25zZS5zdGF0dXMgPD0gNDk5KSB7XG4gICAgICAgICAgICBkZWJ1ZygnUmVxdWVzdCBlcnJvcig0eHgpIC0gJU8nLCByZXNwb25zZSk7XG4gICAgICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcihgUmVxdWVzdCBlcnJvciAke3VybH1gLCBjb25maWcsIHJlc3BvbnNlLCBGc1JlcXVlc3RFcnJvckNvZGUuUkVRVUVTVCkpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGRlYnVnKCdSZXF1ZXN0IGVuZHM6ICVPJywgcmVzcG9uc2UpO1xuICAgICAgICAgIHJldHVybiByZXNvbHZlKHJlc3BvbnNlKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgaWYgKGNvbmZpZy50aW1lb3V0KSB7XG4gICAgICAgIHJlcS5zZXRUaW1lb3V0KGNvbmZpZy50aW1lb3V0LCAoKSA9PiB7XG4gICAgICAgICAgcmVxLmFib3J0KCk7XG5cbiAgICAgICAgICBpZiAoY2FuY2VsTGlzdGVuZXIpIHtcbiAgICAgICAgICAgIGNvbmZpZy5jYW5jZWxUb2tlbi5yZW1vdmVMaXN0ZW5lcihjYW5jZWxMaXN0ZW5lcik7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoJ1JlcXVlc3QgdGltZW91dCcsIGNvbmZpZywgbnVsbCwgRnNSZXF1ZXN0RXJyb3JDb2RlLlRJTUVPVVQpKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHJlcS5vbignZXJyb3InLCBlcnIgPT4ge1xuICAgICAgICBpZiAoY2FuY2VsTGlzdGVuZXIpIHtcbiAgICAgICAgICBjb25maWcuY2FuY2VsVG9rZW4ucmVtb3ZlTGlzdGVuZXIoY2FuY2VsTGlzdGVuZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFyZXEgfHwgcmVxLmFib3J0ZWQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBkZWJ1ZygnUmVxdWVzdCBlcnJvcjogJXMgLSAlTycsIGVyciwgZXJyLmNvZGUpO1xuICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcihgUmVxdWVzdCBlcnJvcjogJHtlcnIuY29kZX1gLCBjb25maWcsIG51bGwsIEZzUmVxdWVzdEVycm9yQ29kZS5ORVRXT1JLKSk7XG4gICAgICB9KTtcblxuICAgICAgaWYgKEJ1ZmZlci5pc0J1ZmZlcihkYXRhKSAmJiBbJ1BPU1QnLCAnUFVUJ10uaW5kZXhPZihjb25maWcubWV0aG9kKSA+IC0xKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmJ1ZmZlclRvQ2h1bmtzKGRhdGEpLnBpcGUodGhpcy5nZXRQcm9ncmVzc01vbml0b3IoY29uZmlnLCBkYXRhLmxlbmd0aCkpLnBpcGUobmV3IEh0dHBXcml0YWJsZVN0cmVhbShyZXEpKTtcbiAgICAgIH1cblxuICAgICAgcmVxLmVuZChkYXRhKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNb25pdG9yIGFuZCBlbWl0IHByb2dyZXNzIGV2ZW50IGlmIG5lZWRlZFxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAbWVtYmVyb2YgSHR0cEFkYXB0ZXJcbiAgICovXG4gIHByaXZhdGUgZ2V0UHJvZ3Jlc3NNb25pdG9yID0gKGNvbmZpZywgdG90YWwpID0+IHtcbiAgICBsZXQgbG9hZGVkID0gMDtcblxuICAgIGNvbnN0IHByb2dyZXNzID0gbmV3IFN0cmVhbS5UcmFuc2Zvcm0oKTtcbiAgICBwcm9ncmVzcy5fdHJhbnNmb3JtID0gKGNodW5rLCBlbmNvZGluZywgY2IpID0+IHtcbiAgICAgIGlmICh0eXBlb2YgY29uZmlnLm9uUHJvZ3Jlc3MgPT09ICdmdW5jdGlvbicgJiYgW0ZzSHR0cE1ldGhvZC5QT1NULCBGc0h0dHBNZXRob2QuUFVUXS5pbmRleE9mKGNvbmZpZy5tZXRob2QpID4gLTEpIHtcbiAgICAgICAgbG9hZGVkICs9IGNodW5rLmxlbmd0aDtcbiAgICAgICAgY29uZmlnLm9uUHJvZ3Jlc3Moe1xuICAgICAgICAgIGxlbmd0aENvbXB1dGFibGU6IHRydWUsXG4gICAgICAgICAgbG9hZGVkLFxuICAgICAgICAgIHRvdGFsLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIGNiKG51bGwsIGNodW5rKTtcbiAgICB9O1xuXG4gICAgcmV0dXJuIHByb2dyZXNzO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgYnVmZmVyIHRvIHN0cmVhbVxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0geyp9IGJ1ZmZlclxuICAgKiBAcmV0dXJucyB7U3RyZWFtLlJlYWRhYmxlfVxuICAgKiBAbWVtYmVyb2YgSHR0cEFkYXB0ZXJcbiAgICovXG4gIHByaXZhdGUgYnVmZmVyVG9DaHVua3MoYnVmZmVyKTogU3RyZWFtLlJlYWRhYmxlIHtcbiAgICBjb25zdCBjaHVua2luZyA9IG5ldyBTdHJlYW0uUmVhZGFibGUoKTtcbiAgICBjb25zdCB0b3RhbExlbmd0aCA9IGJ1ZmZlci5sZW5ndGg7XG4gICAgY29uc3QgcmVtYWluZGVyID0gdG90YWxMZW5ndGggJSBIVFRQX0NIVU5LX1NJWkU7XG4gICAgY29uc3QgY3V0b2ZmID0gdG90YWxMZW5ndGggLSByZW1haW5kZXI7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGN1dG9mZjsgaSArPSBIVFRQX0NIVU5LX1NJWkUpIHtcbiAgICAgIGNvbnN0IGNodW5rID0gYnVmZmVyLnNsaWNlKGksIGkgKyBIVFRQX0NIVU5LX1NJWkUpO1xuICAgICAgY2h1bmtpbmcucHVzaChjaHVuayk7XG4gICAgfVxuXG4gICAgaWYgKHJlbWFpbmRlciA+IDApIHtcbiAgICAgIGNvbnN0IHJlbWFpbmRlckJ1ZmZlciA9IGJ1ZmZlci5zbGljZSgtcmVtYWluZGVyKTtcbiAgICAgIGNodW5raW5nLnB1c2gocmVtYWluZGVyQnVmZmVyKTtcbiAgICB9XG5cbiAgICBjaHVua2luZy5wdXNoKG51bGwpO1xuXG4gICAgcmV0dXJuIGNodW5raW5nO1xuICB9XG59XG4iXX0=