filestack-js
Version:
Official JavaScript library for Filestack
327 lines (325 loc) • 45 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, 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' && [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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R0FBRyxlQUFlLENBQUMsQ0FBQztZQUNuRCxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1NBQ3RCO1FBRUQsSUFBSSxTQUFTLEdBQUcsQ0FBQyxFQUFFO1lBQ2pCLElBQU0sZUFBZSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUNqRCxRQUFRLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1NBQ2hDO1FBRUQsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUVwQixPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBQ0gsa0JBQUM7QUFBRCxDQWxUQSxBQWtUQyxJQUFBIiwiZmlsZSI6ImxpYi9yZXF1ZXN0L2FkYXB0ZXJzL2h0dHAuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogQ29weXJpZ2h0IChjKSAyMDE4IGJ5IEZpbGVzdGFja1xuICogU29tZSByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICovXG5cbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xuaW1wb3J0ICogYXMgemxpYiBmcm9tICd6bGliJztcbmltcG9ydCBEZWJ1ZyBmcm9tICdkZWJ1Zyc7XG5cbmltcG9ydCB7IEFkYXB0ZXJJbnRlcmZhY2UgfSBmcm9tICcuL2ludGVyZmFjZSc7XG5pbXBvcnQgeyBnZXRWZXJzaW9uIH0gZnJvbSAnLi4vLi4vdXRpbHMnO1xuaW1wb3J0ICogYXMgU3RyZWFtIGZyb20gJ3N0cmVhbSc7XG5pbXBvcnQgeyBGc1JlcXVlc3RPcHRpb25zLCBGc1Jlc3BvbnNlIH0gZnJvbSAnLi4vdHlwZXMnO1xuaW1wb3J0ICogYXMgdXRpbHMgZnJvbSAnLi4vdXRpbHMnO1xuaW1wb3J0IHsgcHJlcGFyZURhdGEsIHBhcnNlUmVzcG9uc2UsIGNvbWJpbmVVUkwsIHNldCBhcyBzZXRIZWFkZXIsIG5vcm1hbGl6ZUhlYWRlcnMgfSBmcm9tICcuLy4uL2hlbHBlcnMnO1xuaW1wb3J0IHsgRnNSZXF1ZXN0RXJyb3JDb2RlLCBGc1JlcXVlc3RFcnJvciB9IGZyb20gJy4uL2Vycm9yJztcbmltcG9ydCB7IEZzSHR0cE1ldGhvZCB9IGZyb20gJy4vLi4vdHlwZXMnO1xuXG5jb25zdCBIVFRQU19SRUdFWFAgPSAvaHR0cHM6Py87XG5jb25zdCBIVFRQX0NIVU5LX1NJWkUgPSAxNiAqIDEwMjQ7XG5jb25zdCBNQVhfUkVESVJFQ1RTID0gMTA7XG5jb25zdCBDQU5DRUxfQ0xFQVIgPSBgRnNDbGVhbk1lbW9yeWA7XG5jb25zdCBkZWJ1ZyA9IERlYnVnKCdmczpyZXF1ZXN0Omh0dHAnKTtcblxuLyoqXG4gKiBXcml0YWJsZSBzdHJlYW0gdGhhdHMgb3ZlcndyYXAgaHR0cCByZXF1ZXN0IGZvciBwcm9ncmVzcyBldmVudFxuICpcbiAqIEBjbGFzcyBIdHRwV3JpdGFibGVTdHJlYW1cbiAqIEBleHRlbmRzIHtTdHJlYW0uV3JpdGFibGV9XG4gKi9cbmNsYXNzIEh0dHBXcml0YWJsZVN0cmVhbSBleHRlbmRzIFN0cmVhbS5Xcml0YWJsZSB7XG4gIHByaXZhdGUgcmVxdWVzdDtcblxuICBjb25zdHJ1Y3RvcihyZXEsIG9wdHMgPSB7fSkge1xuICAgIHN1cGVyKG9wdHMpO1xuXG4gICAgdGhpcy5yZXF1ZXN0ID0gcmVxO1xuICAgIHJlcS5vbmNlKCdkcmFpbicsICgpID0+IHRoaXMuZW1pdCgnZHJhaW4nKSk7XG4gIH1cblxuICBfd3JpdGUoY2h1bms6IGFueSwgZW5jb2Rpbmc/OiBzdHJpbmcsIGNiPzogKGVycm9yOiBFcnJvciB8IG51bGwgfCB1bmRlZmluZWQpID0+IHZvaWQpOiB2b2lkIHtcbiAgICB0aGlzLnJlcXVlc3Qud3JpdGUoY2h1bmssIGVuY29kaW5nLCBjYik7XG4gIH1cblxuICBlbmQoY2h1bms/OiBhbnksIGVuY29kaW5nPzogYW55LCBjYj86IGFueSk6IHRoaXMge1xuICAgIHN1cGVyLmVuZChjaHVuaywgZW5jb2RpbmcsIGNiKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIF9maW5hbChjYjogKGVycm9yPzogRXJyb3IgfCBudWxsIHwgdW5kZWZpbmVkKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgdGhpcy5yZXF1ZXN0LmVuZCgpO1xuICAgIGNiKCk7XG4gIH1cbn1cblxuLyoqXG4gKiBOb2RlIGh0dHAgcmVxdWVzdCBjbGFzc1xuICpcbiAqIEBleHBvcnRcbiAqIEBjbGFzcyBIdHRwQWRhcHRlclxuICogQGltcGxlbWVudHMge0FkYXB0ZXJJbnRlcmZhY2V9XG4gKi9cbmV4cG9ydCBjbGFzcyBIdHRwQWRhcHRlciBpbXBsZW1lbnRzIEFkYXB0ZXJJbnRlcmZhY2Uge1xuICBwcml2YXRlIHJlZGlyZWN0SG9vcHMgPSAwO1xuICBwcml2YXRlIHJlZGlyZWN0UGF0aHMgPSBbXTtcblxuICAvKipcbiAgICogZG8gcmVxdWVzdCBiYXNlZCBvbiBjb25maWd1cmF0aW9uXG4gICAqXG4gICAqIEBwYXJhbSB7RnNSZXF1ZXN0T3B0aW9uc30gY29uZmlnXG4gICAqIEByZXR1cm5zXG4gICAqIEBtZW1iZXJvZiBIdHRwQWRhcHRlclxuICAgKi9cbiAgcmVxdWVzdChjb25maWc6IEZzUmVxdWVzdE9wdGlvbnMpIHtcbiAgICAvLyBpZiB0aGlzIG9wdGlvbiBpcyB1bnNwZWNpZmllZCBzZXQgaXQgYnkgZGVmYXVsdFxuICAgIGlmICh0eXBlb2YgY29uZmlnLmZpbGVzdGFja0hlYWRlcnMgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICBjb25maWcuZmlsZXN0YWNrSGVhZGVycyA9IHRydWU7XG4gICAgfVxuXG4gICAgY29uZmlnLmhlYWRlcnMgPSBub3JtYWxpemVIZWFkZXJzKGNvbmZpZy5oZWFkZXJzKTtcblxuICAgIGxldCB7IGRhdGEsIGhlYWRlcnMgfSA9IHByZXBhcmVEYXRhKGNvbmZpZyk7XG5cbiAgICBoZWFkZXJzID0gc2V0SGVhZGVyKGhlYWRlcnMsICd1c2VyLWFnZW50JywgYGZpbGVzdGFjay1yZXF1ZXN0LyR7Z2V0VmVyc2lvbigpfWApO1xuXG4gICAgLy8gZm9yIG5vdyB3ZSBhcmUgbm90IHVzaW5nIHN0cmVhbXNcbiAgICBpZiAoZGF0YSkge1xuICAgICAgZGVidWcoJ1JlcXVlc3QgZGF0YSAlTycsIGRhdGEpO1xuXG4gICAgICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihkYXRhKSkge1xuICAgICAgICBpZiAoIXV0aWxzLmlzU3RyaW5nKGRhdGEpKSB7XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcignRGF0YSBtdXN0IGJlIGEgc3RyaW5nLCBKU09OIG9yIGEgQnVmZmVyJywgY29uZmlnKSk7XG4gICAgICAgIH1cblxuICAgICAgICBkYXRhID0gQnVmZmVyLmZyb20oZGF0YSwgJ3V0Zi04Jyk7XG4gICAgICB9XG5cbiAgICAgIGhlYWRlcnMgPSBzZXRIZWFkZXIoaGVhZGVycywgJ2NvbnRlbnQtbGVuZ3RoJywgZGF0YS5sZW5ndGgsIHRydWUpO1xuICAgIH1cblxuICAgIC8vIEhUVFAgYmFzaWMgYXV0aGVudGljYXRpb25cbiAgICBsZXQgYXV0aDtcbiAgICBpZiAoY29uZmlnLmF1dGgpIHtcbiAgICAgIGlmICghY29uZmlnLmF1dGgudXNlcm5hbWUgfHwgY29uZmlnLmF1dGgudXNlcm5hbWUubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoYEJhc2ljIGF1dGg6IHVzZXJuYW1lIGlzIHJlcXVpcmVkICR7Y29uZmlnLmF1dGh9YCwgY29uZmlnKSk7XG4gICAgICB9XG5cbiAgICAgIGF1dGggPSBgJHtjb25maWcuYXV0aC51c2VybmFtZX06JHtjb25maWcuYXV0aC5wYXNzd29yZH1gO1xuICAgIH1cblxuICAgIC8vIFBhcnNlIHVybFxuICAgIGxldCBwYXJzZWQgPSB1cmwucGFyc2UoY29uZmlnLnVybCk7XG5cbiAgICAvLyB0cnkgdG8gYWRkIGRlZmF1bHQgaHR0cHMgcHJvdG9jb2xcbiAgICBpZiAoIXBhcnNlZC5wcm90b2NvbCkge1xuICAgICAgcGFyc2VkID0gdXJsLnBhcnNlKGBodHRwczovLyR7Y29uZmlnLnVybH1gKTtcbiAgICB9XG5cbiAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dDoganVzdCBiZSBzdXJlIHRoYXQgdGhlIGhvc3QgaXMgcGFyc2VkIGNvcnJlY3RseSwgbm90IG5lZWRlZCB0byB0ZXN0ICovXG4gICAgaWYgKCFwYXJzZWQuaG9zdCkge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcihgQ2Fubm90IHBhcnNlIHByb3ZpZGVkIHVybCAke2NvbmZpZy51cmx9YCwgY29uZmlnKSk7XG4gICAgfVxuXG4gICAgLy8gbm9ybWFsaXplIGF1dGggaGVhZGVyXG4gICAgaWYgKGF1dGggJiYgaGVhZGVycy5BdXRob3JpemF0aW9uKSB7XG4gICAgICBkZWxldGUgaGVhZGVycy5BdXRob3JpemF0aW9uO1xuICAgIH1cblxuICAgIGNvbnN0IGlzSHR0cHNSZXF1ZXN0ID0gSFRUUFNfUkVHRVhQLnRlc3QocGFyc2VkLnByb3RvY29sKTtcbiAgICBjb25zdCBhZ2VudCA9IGlzSHR0cHNSZXF1ZXN0ID8gcmVxdWlyZSgnaHR0cHMnKSA6IHJlcXVpcmUoJ2h0dHAnKTtcblxuICAgIGNvbnN0IG9wdGlvbnMgPSB7XG4gICAgICBwYXRoOiBjb21iaW5lVVJMKHBhcnNlZC5wYXRoLCBjb25maWcucGFyYW1zKSxcbiAgICAgIGhvc3Q6IHBhcnNlZC5ob3N0LFxuICAgICAgcG9ydDogcGFyc2VkLnBvcnQsXG4gICAgICBwcm90b2NvbDogcGFyc2VkLnByb3RvY29sLFxuICAgICAgbWV0aG9kOiBjb25maWcubWV0aG9kLnRvVXBwZXJDYXNlKCksXG4gICAgICBoZWFkZXJzOiBoZWFkZXJzLFxuICAgICAgYWdlbnQ6IG5ldyBhZ2VudC5BZ2VudCgpLFxuICAgICAgYXV0aDogYXV0aCxcbiAgICB9O1xuXG4gICAgZGVidWcoJ1N0YXJ0aW5nICVzIHJlcXVlc3Qgd2l0aCBvcHRpb25zICVPJywgaXNIdHRwc1JlcXVlc3QgPyAnaHR0cHMnIDogJ2h0dHAnLCBvcHRpb25zKTtcblxuICAgIHJldHVybiBuZXcgUHJvbWlzZTxGc1Jlc3BvbnNlPigocmVzb2x2ZSwgcmVqZWN0KTogYW55ID0+IHtcbiAgICAgIGxldCByZXE7XG4gICAgICBsZXQgY2FuY2VsTGlzdGVuZXI7XG5cbiAgICAgIGlmIChjb25maWcuY2FuY2VsVG9rZW4pIHtcbiAgICAgICAgY2FuY2VsTGlzdGVuZXIgPSBjb25maWcuY2FuY2VsVG9rZW4ub24oJ2NhbmNlbCcsIChyZWFzb24pID0+IHtcbiAgICAgICAgICAvLyBjbGVhbnVwIGhhbmRsZXJcbiAgICAgICAgICBjYW5jZWxMaXN0ZW5lciA9IG51bGw7XG5cbiAgICAgICAgICAvLyBkbyBub3RoaW5nIGlmIHByb21pc2UgaXMgcmVzb2x2ZWQgYnkgc3lzdGVtXG4gICAgICAgICAgaWYgKHJlYXNvbiAmJiByZWFzb24ubWVzc2FnZSA9PT0gQ0FOQ0VMX0NMRUFSKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQ6IGlmIHJlcXVlc3QgaXMgZG9uZSBjYW5jZWwgdG9rZW4gc2hvdWxkIG5vdCB0aHJvdyBhbnkgZXJyb3IgKi9cbiAgICAgICAgICBpZiAocmVxKSB7XG4gICAgICAgICAgICByZXEuYWJvcnQoKTtcbiAgICAgICAgICAgIHJlcSA9IG51bGw7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgZGVidWcoJ1JlcXVlc3QgY2FuY2VsZWQgYnkgdXNlciAlcywgY29uZmlnOiAlTycsIHJlYXNvbiwgY29uZmlnKTtcbiAgICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcihgUmVxdWVzdCBhYm9ydGVkLiBSZWFzb246ICR7cmVhc29ufWAsIGNvbmZpZywgbnVsbCwgRnNSZXF1ZXN0RXJyb3JDb2RlLkFCT1JURUQpKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHJlcSA9IGFnZW50LnJlcXVlc3Qob3B0aW9ucywgcmVzID0+IHtcbiAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQ6IGp1c3QgYmUgc3VyZSB0aGF0IHJlc3BvbnNlIHdpbGwgbm90IGJlIGNhbGxlZCBhZnRlciByZXF1ZXN0IGlzIGFib3J0ZWQgKi9cbiAgICAgICAgaWYgKCFyZXEgfHwgcmVxLmFib3J0ZWQpIHtcbiAgICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcignUmVxdWVzdCBhYm9ydGVkJywgY29uZmlnKSk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgc3RyZWFtID0gcmVzO1xuICAgICAgICBkZWJ1ZygnUmVzcG9uc2Ugc3RhdHVzQ29kZTogJWQsIFJlc3BvbnNlIEhlYWRlcnM6ICVPJywgcmVzLnN0YXR1c0NvZGUsIHJlcy5oZWFkZXJzKTtcblxuICAgICAgICBjb25zdCBjb21wcmVzc0hlYWRlcnMgPSByZXMuaGVhZGVyc1snY29udGVudC1lbmNvZGluZyddO1xuXG4gICAgICAgIGlmIChjb21wcmVzc0hlYWRlcnMgJiYgY29tcHJlc3NIZWFkZXJzLmxlbmd0aCAmJiBbJ2d6aXAnLCAnY29tcHJlc3MnLCAnZGVmbGF0ZSddLnNvbWUoKHYpID0+IGNvbXByZXNzSGVhZGVycy5pbmRleE9mKHYpID4gLTEpKSB7XG4gICAgICAgICAgLy8gYWRkIHRoZSB1bnppcHBlciB0byB0aGUgYm9keSBzdHJlYW0gcHJvY2Vzc2luZyBwaXBlbGluZVxuICAgICAgICAgIHN0cmVhbSA9IHJlcy5zdGF0dXNDb2RlID09PSAyMDQgPyBzdHJlYW0gOiBzdHJlYW0ucGlwZSh6bGliLmNyZWF0ZVVuemlwKCkpO1xuICAgICAgICAgIC8vIHJlbW92ZSB0aGUgY29udGVudC1lbmNvZGluZyBpbiBvcmRlciB0byBub3QgY29uZnVzZSBkb3duc3RyZWFtIG9wZXJhdGlvbnNcbiAgICAgICAgICBkZWxldGUgcmVzLmhlYWRlcnNbJ2NvbnRlbnQtZW5jb2RpbmcnXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCByZXNwb25zZTogRnNSZXNwb25zZSA9IHtcbiAgICAgICAgICBzdGF0dXM6IHJlcy5zdGF0dXNDb2RlLFxuICAgICAgICAgIHN0YXR1c1RleHQ6IHJlcy5zdGF0dXNNZXNzYWdlLFxuICAgICAgICAgIGhlYWRlcnM6IHJlcy5oZWFkZXJzLFxuICAgICAgICAgIGNvbmZpZyxcbiAgICAgICAgICBkYXRhOiB7fSxcbiAgICAgICAgfTtcblxuICAgICAgICAvLyB3ZSBuZWVkIHRvIGZvbGxvdyByZWRpcmVjdCBzbyBtYWtlIHNhbWUgcmVxdWVzdCB3aXRoIG5ldyBsb2NhdGlvblxuICAgICAgICBpZiAoWzMwMSwgMzAyXS5pbmRleE9mKHJlcy5zdGF0dXNDb2RlKSA+IC0xKSB7XG4gICAgICAgICAgZGVidWcoJ1JlZGlyZWN0IHJlY2VpdmVkICVzJywgcmVzLnN0YXR1c0NvZGUpO1xuXG4gICAgICAgICAgaWYgKHRoaXMucmVkaXJlY3RIb29wcyA+PSBNQVhfUkVESVJFQ1RTKSB7XG4gICAgICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcihgTWF4IHJlZGlyZWN0cyAoJHt0aGlzLnJlZGlyZWN0SG9vcHN9KSByZWFjaGVkLiBFeGl0aW5nYCwgY29uZmlnLCByZXNwb25zZSwgRnNSZXF1ZXN0RXJyb3JDb2RlLlJFRElSRUNUKSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgdXJsID0gcmVzLmhlYWRlcnNbJ2xvY2F0aW9uJ107XG5cbiAgICAgICAgICBpZiAoIXVybCB8fCB1cmwubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcihgUmVkaXJlY3QgaGVhZGVyIGxvY2F0aW9uIG5vdCBmb3VuZGAsIGNvbmZpZywgcmVzcG9uc2UsIEZzUmVxdWVzdEVycm9yQ29kZS5SRURJUkVDVCkpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICh0aGlzLnJlZGlyZWN0UGF0aHMuaW5kZXhPZih1cmwpID4gLTEpIHtcbiAgICAgICAgICAgIHJldHVybiByZWplY3QobmV3IEZzUmVxdWVzdEVycm9yKGBSZWRpcmVjdCBsb29wIGRldGVjdGVkIGF0IHVybCAke3VybH1gLCBjb25maWcsIHJlc3BvbnNlLCBGc1JlcXVlc3RFcnJvckNvZGUuUkVESVJFQ1QpKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aGlzLnJlZGlyZWN0UGF0aHMucHVzaCh1cmwpO1xuICAgICAgICAgIHRoaXMucmVkaXJlY3RIb29wcysrO1xuXG4gICAgICAgICAgLy8gZnJlZSByZXNvdXJjZXNcbiAgICAgICAgICByZXMgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgcmVxID0gdW5kZWZpbmVkO1xuXG4gICAgICAgICAgZGVidWcoJ1JlZGlyZWN0aW5nIHJlcXVlc3QgdG8gJXMgKGhvb3AtY291bnQ6ICVkKScsIHVybCwgdGhpcy5yZWRpcmVjdEhvb3BzKTtcblxuICAgICAgICAgIHJldHVybiByZXNvbHZlKHRoaXMucmVxdWVzdChPYmplY3QuYXNzaWduKHt9LCBjb25maWcsIHsgdXJsIH0pKSk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgcmVzcG9uc2VCdWZmZXIgPSBbXTtcbiAgICAgICAgc3RyZWFtLm9uKCdkYXRhJywgY2h1bmsgPT4gcmVzcG9uc2VCdWZmZXIucHVzaChjaHVuaykpO1xuXG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBpdHMgaGFyZCB0byB0ZXN0IHNvY2tldCBldmVudHMgd2l0aCBqZXN0IGFuZCBub2NrIC0gdGVzdGVkIG1hbnVhbGx5ICovXG4gICAgICAgIHN0cmVhbS5vbignZXJyb3InLCBlcnIgPT4ge1xuICAgICAgICAgIHJlcyA9IHVuZGVmaW5lZDtcbiAgICAgICAgICByZXEgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgcmVzcG9uc2VCdWZmZXIgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgZGVidWcoJ1JlcXVlc3QgZXJyb3I6IEFib3J0ZWQgJU8nLCBlcnIpO1xuXG4gICAgICAgICAgaWYgKHJlcS5hYm9ydGVkKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gY2xlYXIgY2FuY2VsIHRva2VuIHRvIGF2b2lkIG1lbW9yeSBsZWFrXG4gICAgICAgICAgaWYgKGNhbmNlbExpc3RlbmVyKSB7XG4gICAgICAgICAgICBjb25maWcuY2FuY2VsVG9rZW4ucmVtb3ZlTGlzdGVuZXIoY2FuY2VsTGlzdGVuZXIpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiByZWplY3QobmV3IEZzUmVxdWVzdEVycm9yKGVyci5tZXNzYWdlLCBjb25maWcsIG51bGwsIEZzUmVxdWVzdEVycm9yQ29kZS5ORVRXT1JLKSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHN0cmVhbS5vbignZW5kJywgYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIC8vIGNsZWFyIGNhbmNlbCB0b2tlbiB0byBhdm9pZCBtZW1vcnkgbGVha1xuICAgICAgICAgIGlmIChjYW5jZWxMaXN0ZW5lcikge1xuICAgICAgICAgICAgY29uZmlnLmNhbmNlbFRva2VuLnJlbW92ZUxpc3RlbmVyKGNhbmNlbExpc3RlbmVyKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBjaGVjayBpZiB0aGVyZSBpcyBhbnkgcmVzcG9uc2UgZGF0YSBpbnNpZGVcbiAgICAgICAgICBpZiAocmVzLnN0YXR1c0NvZGUgIT09IDIwNCkge1xuICAgICAgICAgICAgLy8gcHJlcGFyZSByZXNwb25zZVxuICAgICAgICAgICAgcmVzcG9uc2UuZGF0YSA9IEJ1ZmZlci5jb25jYXQocmVzcG9uc2VCdWZmZXIpO1xuICAgICAgICAgICAgcmVzcG9uc2UgPSBhd2FpdCBwYXJzZVJlc3BvbnNlKHJlc3BvbnNlKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmVzcG9uc2UuZGF0YSA9IG51bGw7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gZnJlZSByZXNvdXJjZXNcbiAgICAgICAgICByZXMgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgcmVxID0gdW5kZWZpbmVkO1xuXG4gICAgICAgICAgcmVzcG9uc2VCdWZmZXIgPSB1bmRlZmluZWQ7XG5cbiAgICAgICAgICBpZiAoNTAwIDw9IHJlc3BvbnNlLnN0YXR1cyAmJiByZXNwb25zZS5zdGF0dXMgPD0gNTk5KSB7XG4gICAgICAgICAgICAvLyBzZXJ2ZXIgZXJyb3IgdGhyb3dcbiAgICAgICAgICAgIGRlYnVnKCdTZXJ2ZXIgZXJyb3IoNXh4KSAtICVPJywgcmVzcG9uc2UpO1xuICAgICAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoYFNlcnZlciBlcnJvciAke3VybH1gLCBjb25maWcsIHJlc3BvbnNlLCBGc1JlcXVlc3RFcnJvckNvZGUuU0VSVkVSKSk7XG4gICAgICAgICAgfSBlbHNlIGlmICg0MDAgPD0gcmVzcG9uc2Uuc3RhdHVzICYmIHJlc3BvbnNlLnN0YXR1cyA8PSA0OTkpIHtcbiAgICAgICAgICAgIGRlYnVnKCdSZXF1ZXN0IGVycm9yKDR4eCkgLSAlTycsIHJlc3BvbnNlKTtcbiAgICAgICAgICAgIHJldHVybiByZWplY3QobmV3IEZzUmVxdWVzdEVycm9yKGBSZXF1ZXN0IGVycm9yICR7dXJsfWAsIGNvbmZpZywgcmVzcG9uc2UsIEZzUmVxdWVzdEVycm9yQ29kZS5SRVFVRVNUKSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgZGVidWcoJ1JlcXVlc3QgZW5kczogJU8nLCByZXNwb25zZSk7XG4gICAgICAgICAgcmV0dXJuIHJlc29sdmUocmVzcG9uc2UpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoY29uZmlnLnRpbWVvdXQpIHtcbiAgICAgICAgcmVxLnNldFRpbWVvdXQoY29uZmlnLnRpbWVvdXQsICgpID0+IHtcbiAgICAgICAgICByZXEuYWJvcnQoKTtcblxuICAgICAgICAgIGlmIChjYW5jZWxMaXN0ZW5lcikge1xuICAgICAgICAgICAgY29uZmlnLmNhbmNlbFRva2VuLnJlbW92ZUxpc3RlbmVyKGNhbmNlbExpc3RlbmVyKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcignUmVxdWVzdCB0aW1lb3V0JywgY29uZmlnLCBudWxsLCBGc1JlcXVlc3RFcnJvckNvZGUuVElNRU9VVCkpO1xuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgcmVxLm9uKCdlcnJvcicsIGVyciA9PiB7XG4gICAgICAgIGlmIChjYW5jZWxMaXN0ZW5lcikge1xuICAgICAgICAgIGNvbmZpZy5jYW5jZWxUb2tlbi5yZW1vdmVMaXN0ZW5lcihjYW5jZWxMaXN0ZW5lcik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIXJlcSB8fCByZXEuYWJvcnRlZCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGRlYnVnKCdSZXF1ZXN0IGVycm9yOiAlcyAtICVPJywgZXJyLCBlcnIuY29kZSk7XG4gICAgICAgIHJldHVybiByZWplY3QobmV3IEZzUmVxdWVzdEVycm9yKGBSZXF1ZXN0IGVycm9yOiAke2Vyci5jb2RlfWAsIGNvbmZpZywgbnVsbCwgRnNSZXF1ZXN0RXJyb3JDb2RlLk5FVFdPUkspKTtcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoQnVmZmVyLmlzQnVmZmVyKGRhdGEpICYmIFsnUE9TVCcsICdQVVQnXS5pbmRleE9mKGNvbmZpZy5tZXRob2QpID4gLTEpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYnVmZmVyVG9DaHVua3MoZGF0YSkucGlwZSh0aGlzLmdldFByb2dyZXNzTW9uaXRvcihjb25maWcsIGRhdGEubGVuZ3RoKSkucGlwZShuZXcgSHR0cFdyaXRhYmxlU3RyZWFtKHJlcSkpO1xuICAgICAgfVxuXG4gICAgICByZXEuZW5kKGRhdGEpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIE1vbml0b3IgYW5kIGVtaXQgcHJvZ3Jlc3MgZXZlbnQgaWYgbmVlZGVkXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBtZW1iZXJvZiBIdHRwQWRhcHRlclxuICAgKi9cbiAgcHJpdmF0ZSBnZXRQcm9ncmVzc01vbml0b3IgPSAoY29uZmlnLCB0b3RhbCkgPT4ge1xuICAgIGxldCBsb2FkZWQgPSAwO1xuXG4gICAgY29uc3QgcHJvZ3Jlc3MgPSBuZXcgU3RyZWFtLlRyYW5zZm9ybSgpO1xuICAgIHByb2dyZXNzLl90cmFuc2Zvcm0gPSAoY2h1bmssIGVuY29kaW5nLCBjYikgPT4ge1xuICAgICAgaWYgKHR5cGVvZiBjb25maWcub25Qcm9ncmVzcyA9PT0gJ2Z1bmN0aW9uJyAmJiBbRnNIdHRwTWV0aG9kLlBPU1QsIEZzSHR0cE1ldGhvZC5QVVRdLmluZGV4T2YoY29uZmlnLm1ldGhvZCkgPiAtMSkge1xuICAgICAgICBsb2FkZWQgKz0gY2h1bmsubGVuZ3RoO1xuICAgICAgICBjb25maWcub25Qcm9ncmVzcyh7XG4gICAgICAgICAgbGVuZ3RoQ29tcHV0YWJsZTogdHJ1ZSxcbiAgICAgICAgICBsb2FkZWQsXG4gICAgICAgICAgdG90YWwsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgY2IobnVsbCwgY2h1bmspO1xuICAgIH07XG5cbiAgICByZXR1cm4gcHJvZ3Jlc3M7XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydCBidWZmZXIgdG8gc3RyZWFtXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7Kn0gYnVmZmVyXG4gICAqIEByZXR1cm5zIHtTdHJlYW0uUmVhZGFibGV9XG4gICAqIEBtZW1iZXJvZiBIdHRwQWRhcHRlclxuICAgKi9cbiAgcHJpdmF0ZSBidWZmZXJUb0NodW5rcyhidWZmZXIpOiBTdHJlYW0uUmVhZGFibGUge1xuICAgIGNvbnN0IGNodW5raW5nID0gbmV3IFN0cmVhbS5SZWFkYWJsZSgpO1xuICAgIGNvbnN0IHRvdGFsTGVuZ3RoID0gYnVmZmVyLmxlbmd0aDtcbiAgICBjb25zdCByZW1haW5kZXIgPSB0b3RhbExlbmd0aCAlIEhUVFBfQ0hVTktfU0laRTtcbiAgICBjb25zdCBjdXRvZmYgPSB0b3RhbExlbmd0aCAtIHJlbWFpbmRlcjtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY3V0b2ZmOyBpICs9IEhUVFBfQ0hVTktfU0laRSkge1xuICAgICAgY29uc3QgY2h1bmsgPSBidWZmZXIuc2xpY2UoaSwgaSArIEhUVFBfQ0hVTktfU0laRSk7XG4gICAgICBjaHVua2luZy5wdXNoKGNodW5rKTtcbiAgICB9XG5cbiAgICBpZiAocmVtYWluZGVyID4gMCkge1xuICAgICAgY29uc3QgcmVtYWluZGVyQnVmZmVyID0gYnVmZmVyLnNsaWNlKC1yZW1haW5kZXIpO1xuICAgICAgY2h1bmtpbmcucHVzaChyZW1haW5kZXJCdWZmZXIpO1xuICAgIH1cblxuICAgIGNodW5raW5nLnB1c2gobnVsbCk7XG5cbiAgICByZXR1cm4gY2h1bmtpbmc7XG4gIH1cbn1cbiJdfQ==