UNPKG

filestack-js

Version:

Official JavaScript library for Filestack

329 lines (327 loc) 44.9 kB
"use strict"; /* * 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) { 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' && [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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvcmVxdWVzdC9hZGFwdGVycy9odHRwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7Ozs7QUFFSCwrQ0FBMkI7QUFDM0IsaURBQTZCO0FBQzdCLHdEQUEwQjtBQUcxQixxQ0FBeUM7QUFDekMscURBQWlDO0FBRWpDLHNEQUFrQztBQUNsQyx3Q0FBMEc7QUFDMUcsa0NBQThEO0FBQzlELG9DQUEwQztBQUUxQyxJQUFNLFlBQVksR0FBRyxTQUFTLENBQUM7QUFDL0IsSUFBTSxlQUFlLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUNsQyxJQUFNLGFBQWEsR0FBRyxFQUFFLENBQUM7QUFDekIsSUFBTSxZQUFZLEdBQUcsZUFBZSxDQUFDO0FBQ3JDLElBQU0sS0FBSyxHQUFHLElBQUEsZUFBSyxFQUFDLGlCQUFpQixDQUFDLENBQUM7QUFFdkM7Ozs7O0dBS0c7QUFDSDtJQUFpQyw4Q0FBZTtJQUc5Qyw0QkFBWSxHQUFHLEVBQUUsSUFBUztRQUFULHFCQUFBLEVBQUEsU0FBUztRQUExQixZQUNFLGtCQUFNLElBQUksQ0FBQyxTQUlaO1FBRkMsS0FBSSxDQUFDLE9BQU8sR0FBRyxHQUFHLENBQUM7UUFDbkIsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsY0FBTSxPQUFBLEtBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQWxCLENBQWtCLENBQUMsQ0FBQzs7SUFDOUMsQ0FBQztJQUVELG1DQUFNLEdBQU4sVUFBTyxLQUFVLEVBQUUsUUFBaUIsRUFBRSxFQUE4QztRQUNsRixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFFRCxnQ0FBRyxHQUFILFVBQUksS0FBSztRQUNQLElBQUksS0FBSyxFQUFFO1lBQ1QsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENB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QUFDO0FBQUQsQ0FsVEEsQUFrVEMsSUFBQTtBQWxUWSxrQ0FBVyIsImZpbGUiOiJsaWIvcmVxdWVzdC9hZGFwdGVycy9odHRwLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIENvcHlyaWdodCAoYykgMjAxOCBieSBGaWxlc3RhY2tcbiAqIFNvbWUgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqL1xuXG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcbmltcG9ydCAqIGFzIHpsaWIgZnJvbSAnemxpYic7XG5pbXBvcnQgRGVidWcgZnJvbSAnZGVidWcnO1xuXG5pbXBvcnQgeyBBZGFwdGVySW50ZXJmYWNlIH0gZnJvbSAnLi9pbnRlcmZhY2UnO1xuaW1wb3J0IHsgZ2V0VmVyc2lvbiB9IGZyb20gJy4uLy4uL3V0aWxzJztcbmltcG9ydCAqIGFzIFN0cmVhbSBmcm9tICdzdHJlYW0nO1xuaW1wb3J0IHsgRnNSZXF1ZXN0T3B0aW9ucywgRnNSZXNwb25zZSB9IGZyb20gJy4uL3R5cGVzJztcbmltcG9ydCAqIGFzIHV0aWxzIGZyb20gJy4uL3V0aWxzJztcbmltcG9ydCB7IHByZXBhcmVEYXRhLCBwYXJzZVJlc3BvbnNlLCBjb21iaW5lVVJMLCBzZXQgYXMgc2V0SGVhZGVyLCBub3JtYWxpemVIZWFkZXJzIH0gZnJvbSAnLi8uLi9oZWxwZXJzJztcbmltcG9ydCB7IEZzUmVxdWVzdEVycm9yQ29kZSwgRnNSZXF1ZXN0RXJyb3IgfSBmcm9tICcuLi9lcnJvcic7XG5pbXBvcnQgeyBGc0h0dHBNZXRob2QgfSBmcm9tICcuLy4uL3R5cGVzJztcblxuY29uc3QgSFRUUFNfUkVHRVhQID0gL2h0dHBzOj8vO1xuY29uc3QgSFRUUF9DSFVOS19TSVpFID0gMTYgKiAxMDI0O1xuY29uc3QgTUFYX1JFRElSRUNUUyA9IDEwO1xuY29uc3QgQ0FOQ0VMX0NMRUFSID0gYEZzQ2xlYW5NZW1vcnlgO1xuY29uc3QgZGVidWcgPSBEZWJ1ZygnZnM6cmVxdWVzdDpodHRwJyk7XG5cbi8qKlxuICogV3JpdGFibGUgc3RyZWFtIHRoYXRzIG92ZXJ3cmFwIGh0dHAgcmVxdWVzdCBmb3IgcHJvZ3Jlc3MgZXZlbnRcbiAqXG4gKiBAY2xhc3MgSHR0cFdyaXRhYmxlU3RyZWFtXG4gKiBAZXh0ZW5kcyB7U3RyZWFtLldyaXRhYmxlfVxuICovXG5jbGFzcyBIdHRwV3JpdGFibGVTdHJlYW0gZXh0ZW5kcyBTdHJlYW0uV3JpdGFibGUge1xuICBwcml2YXRlIHJlcXVlc3Q7XG5cbiAgY29uc3RydWN0b3IocmVxLCBvcHRzID0ge30pIHtcbiAgICBzdXBlcihvcHRzKTtcblxuICAgIHRoaXMucmVxdWVzdCA9IHJlcTtcbiAgICByZXEub25jZSgnZHJhaW4nLCAoKSA9PiB0aGlzLmVtaXQoJ2RyYWluJykpO1xuICB9XG5cbiAgX3dyaXRlKGNodW5rOiBhbnksIGVuY29kaW5nPzogc3RyaW5nLCBjYj86IChlcnJvcjogRXJyb3IgfCBudWxsIHwgdW5kZWZpbmVkKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgdGhpcy5yZXF1ZXN0LndyaXRlKGNodW5rLCBlbmNvZGluZywgY2IpO1xuICB9XG5cbiAgZW5kKGNodW5rKSB7XG4gICAgaWYgKGNodW5rKSB7XG4gICAgICB0aGlzLnJlcXVlc3Qud3JpdGUoY2h1bmspO1xuICAgIH1cblxuICAgIHRoaXMucmVxdWVzdC5lbmQoKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxufVxuXG4vKipcbiAqIE5vZGUgaHR0cCByZXF1ZXN0IGNsYXNzXG4gKlxuICogQGV4cG9ydFxuICogQGNsYXNzIEh0dHBBZGFwdGVyXG4gKiBAaW1wbGVtZW50cyB7QWRhcHRlckludGVyZmFjZX1cbiAqL1xuZXhwb3J0IGNsYXNzIEh0dHBBZGFwdGVyIGltcGxlbWVudHMgQWRhcHRlckludGVyZmFjZSB7XG4gIHByaXZhdGUgcmVkaXJlY3RIb29wcyA9IDA7XG4gIHByaXZhdGUgcmVkaXJlY3RQYXRocyA9IFtdO1xuXG4gIC8qKlxuICAgKiBkbyByZXF1ZXN0IGJhc2VkIG9uIGNvbmZpZ3VyYXRpb25cbiAgICpcbiAgICogQHBhcmFtIHtGc1JlcXVlc3RPcHRpb25zfSBjb25maWdcbiAgICogQHJldHVybnNcbiAgICogQG1lbWJlcm9mIEh0dHBBZGFwdGVyXG4gICAqL1xuICByZXF1ZXN0KGNvbmZpZzogRnNSZXF1ZXN0T3B0aW9ucykge1xuICAgIC8vIGlmIHRoaXMgb3B0aW9uIGlzIHVuc3BlY2lmaWVkIHNldCBpdCBieSBkZWZhdWx0XG4gICAgaWYgKHR5cGVvZiBjb25maWcuZmlsZXN0YWNrSGVhZGVycyA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIGNvbmZpZy5maWxlc3RhY2tIZWFkZXJzID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBjb25maWcuaGVhZGVycyA9IG5vcm1hbGl6ZUhlYWRlcnMoY29uZmlnLmhlYWRlcnMpO1xuXG4gICAgbGV0IHsgZGF0YSwgaGVhZGVycyB9ID0gcHJlcGFyZURhdGEoY29uZmlnKTtcblxuICAgIGhlYWRlcnMgPSBzZXRIZWFkZXIoaGVhZGVycywgJ3VzZXItYWdlbnQnLCBgZmlsZXN0YWNrLXJlcXVlc3QvJHtnZXRWZXJzaW9uKCl9YCk7XG5cbiAgICAvLyBmb3Igbm93IHdlIGFyZSBub3QgdXNpbmcgc3RyZWFtc1xuICAgIGlmIChkYXRhKSB7XG4gICAgICBkZWJ1ZygnUmVxdWVzdCBkYXRhICVPJywgZGF0YSk7XG5cbiAgICAgIGlmICghQnVmZmVyLmlzQnVmZmVyKGRhdGEpKSB7XG4gICAgICAgIGlmICghdXRpbHMuaXNTdHJpbmcoZGF0YSkpIHtcbiAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QobmV3IEZzUmVxdWVzdEVycm9yKCdEYXRhIG11c3QgYmUgYSBzdHJpbmcsIEpTT04gb3IgYSBCdWZmZXInLCBjb25maWcpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGRhdGEgPSBCdWZmZXIuZnJvbShkYXRhLCAndXRmLTgnKTtcbiAgICAgIH1cblxuICAgICAgaGVhZGVycyA9IHNldEhlYWRlcihoZWFkZXJzLCAnY29udGVudC1sZW5ndGgnLCBkYXRhLmxlbmd0aCwgdHJ1ZSk7XG4gICAgfVxuXG4gICAgLy8gSFRUUCBiYXNpYyBhdXRoZW50aWNhdGlvblxuICAgIGxldCBhdXRoO1xuICAgIGlmIChjb25maWcuYXV0aCkge1xuICAgICAgaWYgKCFjb25maWcuYXV0aC51c2VybmFtZSB8fCBjb25maWcuYXV0aC51c2VybmFtZS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcihgQmFzaWMgYXV0aDogdXNlcm5hbWUgaXMgcmVxdWlyZWQgJHtjb25maWcuYXV0aH1gLCBjb25maWcpKTtcbiAgICAgIH1cblxuICAgICAgYXV0aCA9IGAke2NvbmZpZy5hdXRoLnVzZXJuYW1lfToke2NvbmZpZy5hdXRoLnBhc3N3b3JkfWA7XG4gICAgfVxuXG4gICAgLy8gUGFyc2UgdXJsXG4gICAgbGV0IHBhcnNlZCA9IHVybC5wYXJzZShjb25maWcudXJsKTtcblxuICAgIC8vIHRyeSB0byBhZGQgZGVmYXVsdCBodHRwcyBwcm90b2NvbFxuICAgIGlmICghcGFyc2VkLnByb3RvY29sKSB7XG4gICAgICBwYXJzZWQgPSB1cmwucGFyc2UoYGh0dHBzOi8vJHtjb25maWcudXJsfWApO1xuICAgIH1cblxuICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBqdXN0IGJlIHN1cmUgdGhhdCB0aGUgaG9zdCBpcyBwYXJzZWQgY29ycmVjdGx5LCBub3QgbmVlZGVkIHRvIHRlc3QgKi9cbiAgICBpZiAoIXBhcnNlZC5ob3N0KSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QobmV3IEZzUmVxdWVzdEVycm9yKGBDYW5ub3QgcGFyc2UgcHJvdmlkZWQgdXJsICR7Y29uZmlnLnVybH1gLCBjb25maWcpKTtcbiAgICB9XG5cbiAgICAvLyBub3JtYWxpemUgYXV0aCBoZWFkZXJcbiAgICBpZiAoYXV0aCAmJiBoZWFkZXJzLkF1dGhvcml6YXRpb24pIHtcbiAgICAgIGRlbGV0ZSBoZWFkZXJzLkF1dGhvcml6YXRpb247XG4gICAgfVxuXG4gICAgY29uc3QgaXNIdHRwc1JlcXVlc3QgPSBIVFRQU19SRUdFWFAudGVzdChwYXJzZWQucHJvdG9jb2wpO1xuICAgIGNvbnN0IGFnZW50ID0gaXNIdHRwc1JlcXVlc3QgPyByZXF1aXJlKCdodHRwcycpIDogcmVxdWlyZSgnaHR0cCcpO1xuXG4gICAgY29uc3Qgb3B0aW9ucyA9IHtcbiAgICAgIHBhdGg6IGNvbWJpbmVVUkwocGFyc2VkLnBhdGgsIGNvbmZpZy5wYXJhbXMpLFxuICAgICAgaG9zdDogcGFyc2VkLmhvc3QsXG4gICAgICBwb3J0OiBwYXJzZWQucG9ydCxcbiAgICAgIHByb3RvY29sOiBwYXJzZWQucHJvdG9jb2wsXG4gICAgICBtZXRob2Q6IGNvbmZpZy5tZXRob2QudG9VcHBlckNhc2UoKSxcbiAgICAgIGhlYWRlcnM6IGhlYWRlcnMsXG4gICAgICBhZ2VudDogbmV3IGFnZW50LkFnZW50KCksXG4gICAgICBhdXRoOiBhdXRoLFxuICAgIH07XG5cbiAgICBkZWJ1ZygnU3RhcnRpbmcgJXMgcmVxdWVzdCB3aXRoIG9wdGlvbnMgJU8nLCBpc0h0dHBzUmVxdWVzdCA/ICdodHRwcycgOiAnaHR0cCcsIG9wdGlvbnMpO1xuXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlPEZzUmVzcG9uc2U+KChyZXNvbHZlLCByZWplY3QpOiBhbnkgPT4ge1xuICAgICAgbGV0IHJlcTtcbiAgICAgIGxldCBjYW5jZWxMaXN0ZW5lcjtcblxuICAgICAgaWYgKGNvbmZpZy5jYW5jZWxUb2tlbikge1xuICAgICAgICBjYW5jZWxMaXN0ZW5lciA9IGNvbmZpZy5jYW5jZWxUb2tlbi5vbignY2FuY2VsJywgKHJlYXNvbikgPT4ge1xuICAgICAgICAgIC8vIGNsZWFudXAgaGFuZGxlclxuICAgICAgICAgIGNhbmNlbExpc3RlbmVyID0gbnVsbDtcblxuICAgICAgICAgIC8vIGRvIG5vdGhpbmcgaWYgcHJvbWlzZSBpcyByZXNvbHZlZCBieSBzeXN0ZW1cbiAgICAgICAgICBpZiAocmVhc29uICYmIHJlYXNvbi5tZXNzYWdlID09PSBDQU5DRUxfQ0xFQVIpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dDogaWYgcmVxdWVzdCBpcyBkb25lIGNhbmNlbCB0b2tlbiBzaG91bGQgbm90IHRocm93IGFueSBlcnJvciAqL1xuICAgICAgICAgIGlmIChyZXEpIHtcbiAgICAgICAgICAgIHJlcS5hYm9ydCgpO1xuICAgICAgICAgICAgcmVxID0gbnVsbDtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBkZWJ1ZygnUmVxdWVzdCBjYW5jZWxlZCBieSB1c2VyICVzLCBjb25maWc6ICVPJywgcmVhc29uLCBjb25maWcpO1xuICAgICAgICAgIHJldHVybiByZWplY3QobmV3IEZzUmVxdWVzdEVycm9yKGBSZXF1ZXN0IGFib3J0ZWQuIFJlYXNvbjogJHtyZWFzb259YCwgY29uZmlnLCBudWxsLCBGc1JlcXVlc3RFcnJvckNvZGUuQUJPUlRFRCkpO1xuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgcmVxID0gYWdlbnQucmVxdWVzdChvcHRpb25zLCByZXMgPT4ge1xuICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dDoganVzdCBiZSBzdXJlIHRoYXQgcmVzcG9uc2Ugd2lsbCBub3QgYmUgY2FsbGVkIGFmdGVyIHJlcXVlc3QgaXMgYWJvcnRlZCAqL1xuICAgICAgICBpZiAoIXJlcSB8fCByZXEuYWJvcnRlZCkge1xuICAgICAgICAgIHJldHVybiByZWplY3QobmV3IEZzUmVxdWVzdEVycm9yKCdSZXF1ZXN0IGFib3J0ZWQnLCBjb25maWcpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBzdHJlYW0gPSByZXM7XG4gICAgICAgIGRlYnVnKCdSZXNwb25zZSBzdGF0dXNDb2RlOiAlZCwgUmVzcG9uc2UgSGVhZGVyczogJU8nLCByZXMuc3RhdHVzQ29kZSwgcmVzLmhlYWRlcnMpO1xuXG4gICAgICAgIGNvbnN0IGNvbXByZXNzSGVhZGVycyA9IHJlcy5oZWFkZXJzWydjb250ZW50LWVuY29kaW5nJ107XG5cbiAgICAgICAgaWYgKGNvbXByZXNzSGVhZGVycyAmJiBjb21wcmVzc0hlYWRlcnMubGVuZ3RoICYmIFsnZ3ppcCcsICdjb21wcmVzcycsICdkZWZsYXRlJ10uc29tZSgodikgPT4gY29tcHJlc3NIZWFkZXJzLmluZGV4T2YodikgPiAtMSkpIHtcbiAgICAgICAgICAvLyBhZGQgdGhlIHVuemlwcGVyIHRvIHRoZSBib2R5IHN0cmVhbSBwcm9jZXNzaW5nIHBpcGVsaW5lXG4gICAgICAgICAgc3RyZWFtID0gcmVzLnN0YXR1c0NvZGUgPT09IDIwNCA/IHN0cmVhbSA6IHN0cmVhbS5waXBlKHpsaWIuY3JlYXRlVW56aXAoKSk7XG4gICAgICAgICAgLy8gcmVtb3ZlIHRoZSBjb250ZW50LWVuY29kaW5nIGluIG9yZGVyIHRvIG5vdCBjb25mdXNlIGRvd25zdHJlYW0gb3BlcmF0aW9uc1xuICAgICAgICAgIGRlbGV0ZSByZXMuaGVhZGVyc1snY29udGVudC1lbmNvZGluZyddO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHJlc3BvbnNlOiBGc1Jlc3BvbnNlID0ge1xuICAgICAgICAgIHN0YXR1czogcmVzLnN0YXR1c0NvZGUsXG4gICAgICAgICAgc3RhdHVzVGV4dDogcmVzLnN0YXR1c01lc3NhZ2UsXG4gICAgICAgICAgaGVhZGVyczogcmVzLmhlYWRlcnMsXG4gICAgICAgICAgY29uZmlnLFxuICAgICAgICAgIGRhdGE6IHt9LFxuICAgICAgICB9O1xuXG4gICAgICAgIC8vIHdlIG5lZWQgdG8gZm9sbG93IHJlZGlyZWN0IHNvIG1ha2Ugc2FtZSByZXF1ZXN0IHdpdGggbmV3IGxvY2F0aW9uXG4gICAgICAgIGlmIChbMzAxLCAzMDJdLmluZGV4T2YocmVzLnN0YXR1c0NvZGUpID4gLTEpIHtcbiAgICAgICAgICBkZWJ1ZygnUmVkaXJlY3QgcmVjZWl2ZWQgJXMnLCByZXMuc3RhdHVzQ29kZSk7XG5cbiAgICAgICAgICBpZiAodGhpcy5yZWRpcmVjdEhvb3BzID49IE1BWF9SRURJUkVDVFMpIHtcbiAgICAgICAgICAgIHJldHVybiByZWplY3QobmV3IEZzUmVxdWVzdEVycm9yKGBNYXggcmVkaXJlY3RzICgke3RoaXMucmVkaXJlY3RIb29wc30pIHJlYWNoZWQuIEV4aXRpbmdgLCBjb25maWcsIHJlc3BvbnNlLCBGc1JlcXVlc3RFcnJvckNvZGUuUkVESVJFQ1QpKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCB1cmwgPSByZXMuaGVhZGVyc1snbG9jYXRpb24nXTtcblxuICAgICAgICAgIGlmICghdXJsIHx8IHVybC5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybiByZWplY3QobmV3IEZzUmVxdWVzdEVycm9yKGBSZWRpcmVjdCBoZWFkZXIgbG9jYXRpb24gbm90IGZvdW5kYCwgY29uZmlnLCByZXNwb25zZSwgRnNSZXF1ZXN0RXJyb3JDb2RlLlJFRElSRUNUKSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHRoaXMucmVkaXJlY3RQYXRocy5pbmRleE9mKHVybCkgPiAtMSkge1xuICAgICAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoYFJlZGlyZWN0IGxvb3AgZGV0ZWN0ZWQgYXQgdXJsICR7dXJsfWAsIGNvbmZpZywgcmVzcG9uc2UsIEZzUmVxdWVzdEVycm9yQ29kZS5SRURJUkVDVCkpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMucmVkaXJlY3RQYXRocy5wdXNoKHVybCk7XG4gICAgICAgICAgdGhpcy5yZWRpcmVjdEhvb3BzKys7XG5cbiAgICAgICAgICAvLyBmcmVlIHJlc291cmNlc1xuICAgICAgICAgIHJlcyA9IHVuZGVmaW5lZDtcbiAgICAgICAgICByZXEgPSB1bmRlZmluZWQ7XG5cbiAgICAgICAgICBkZWJ1ZygnUmVkaXJlY3RpbmcgcmVxdWVzdCB0byAlcyAoaG9vcC1jb3VudDogJWQpJywgdXJsLCB0aGlzLnJlZGlyZWN0SG9vcHMpO1xuXG4gICAgICAgICAgcmV0dXJuIHJlc29sdmUodGhpcy5yZXF1ZXN0KE9iamVjdC5hc3NpZ24oe30sIGNvbmZpZywgeyB1cmwgfSkpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCByZXNwb25zZUJ1ZmZlciA9IFtdO1xuICAgICAgICBzdHJlYW0ub24oJ2RhdGEnLCBjaHVuayA9PiByZXNwb25zZUJ1ZmZlci5wdXNoKGNodW5rKSk7XG5cbiAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQ6IGl0cyBoYXJkIHRvIHRlc3Qgc29ja2V0IGV2ZW50cyB3aXRoIGplc3QgYW5kIG5vY2sgLSB0ZXN0ZWQgbWFudWFsbHkgKi9cbiAgICAgICAgc3RyZWFtLm9uKCdlcnJvcicsIGVyciA9PiB7XG4gICAgICAgICAgcmVzID0gdW5kZWZpbmVkO1xuICAgICAgICAgIHJlcSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICByZXNwb25zZUJ1ZmZlciA9IHVuZGVmaW5lZDtcbiAgICAgICAgICBkZWJ1ZygnUmVxdWVzdCBlcnJvcjogQWJvcnRlZCAlTycsIGVycik7XG5cbiAgICAgICAgICBpZiAocmVxLmFib3J0ZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBjbGVhciBjYW5jZWwgdG9rZW4gdG8gYXZvaWQgbWVtb3J5IGxlYWtcbiAgICAgICAgICBpZiAoY2FuY2VsTGlzdGVuZXIpIHtcbiAgICAgICAgICAgIGNvbmZpZy5jYW5jZWxUb2tlbi5yZW1vdmVMaXN0ZW5lcihjYW5jZWxMaXN0ZW5lcik7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoZXJyLm1lc3NhZ2UsIGNvbmZpZywgbnVsbCwgRnNSZXF1ZXN0RXJyb3JDb2RlLk5FVFdPUkspKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgc3RyZWFtLm9uKCdlbmQnLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgLy8gY2xlYXIgY2FuY2VsIHRva2VuIHRvIGF2b2lkIG1lbW9yeSBsZWFrXG4gICAgICAgICAgaWYgKGNhbmNlbExpc3RlbmVyKSB7XG4gICAgICAgICAgICBjb25maWcuY2FuY2VsVG9rZW4ucmVtb3ZlTGlzdGVuZXIoY2FuY2VsTGlzdGVuZXIpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIGNoZWNrIGlmIHRoZXJlIGlzIGFueSByZXNwb25zZSBkYXRhIGluc2lkZVxuICAgICAgICAgIGlmIChyZXMuc3RhdHVzQ29kZSAhPT0gMjA0KSB7XG4gICAgICAgICAgICAvLyBwcmVwYXJlIHJlc3BvbnNlXG4gICAgICAgICAgICByZXNwb25zZS5kYXRhID0gQnVmZmVyLmNvbmNhdChyZXNwb25zZUJ1ZmZlcik7XG4gICAgICAgICAgICByZXNwb25zZSA9IGF3YWl0IHBhcnNlUmVzcG9uc2UocmVzcG9uc2UpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXNwb25zZS5kYXRhID0gbnVsbDtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBmcmVlIHJlc291cmNlc1xuICAgICAgICAgIHJlcyA9IHVuZGVmaW5lZDtcbiAgICAgICAgICByZXEgPSB1bmRlZmluZWQ7XG5cbiAgICAgICAgICByZXNwb25zZUJ1ZmZlciA9IHVuZGVmaW5lZDtcblxuICAgICAgICAgIGlmICg1MDAgPD0gcmVzcG9uc2Uuc3RhdHVzICYmIHJlc3BvbnNlLnN0YXR1cyA8PSA1OTkpIHtcbiAgICAgICAgICAgIC8vIHNlcnZlciBlcnJvciB0aHJvd1xuICAgICAgICAgICAgZGVidWcoJ1NlcnZlciBlcnJvcig1eHgpIC0gJU8nLCByZXNwb25zZSk7XG4gICAgICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBGc1JlcXVlc3RFcnJvcihgU2VydmVyIGVycm9yICR7dXJsfWAsIGNvbmZpZywgcmVzcG9uc2UsIEZzUmVxdWVzdEVycm9yQ29kZS5TRVJWRVIpKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKDQwMCA8PSByZXNwb25zZS5zdGF0dXMgJiYgcmVzcG9uc2Uuc3RhdHVzIDw9IDQ5OSkge1xuICAgICAgICAgICAgZGVidWcoJ1JlcXVlc3QgZXJyb3IoNHh4KSAtICVPJywgcmVzcG9uc2UpO1xuICAgICAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoYFJlcXVlc3QgZXJyb3IgJHt1cmx9YCwgY29uZmlnLCByZXNwb25zZSwgRnNSZXF1ZXN0RXJyb3JDb2RlLlJFUVVFU1QpKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBkZWJ1ZygnUmVxdWVzdCBlbmRzOiAlTycsIHJlc3BvbnNlKTtcbiAgICAgICAgICByZXR1cm4gcmVzb2x2ZShyZXNwb25zZSk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGlmIChjb25maWcudGltZW91dCkge1xuICAgICAgICByZXEuc2V0VGltZW91dChjb25maWcudGltZW91dCwgKCkgPT4ge1xuICAgICAgICAgIHJlcS5hYm9ydCgpO1xuXG4gICAgICAgICAgaWYgKGNhbmNlbExpc3RlbmVyKSB7XG4gICAgICAgICAgICBjb25maWcuY2FuY2VsVG9rZW4ucmVtb3ZlTGlzdGVuZXIoY2FuY2VsTGlzdGVuZXIpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiByZWplY3QobmV3IEZzUmVxdWVzdEVycm9yKCdSZXF1ZXN0IHRpbWVvdXQnLCBjb25maWcsIG51bGwsIEZzUmVxdWVzdEVycm9yQ29kZS5USU1FT1VUKSk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICByZXEub24oJ2Vycm9yJywgZXJyID0+IHtcbiAgICAgICAgaWYgKGNhbmNlbExpc3RlbmVyKSB7XG4gICAgICAgICAgY29uZmlnLmNhbmNlbFRva2VuLnJlbW92ZUxpc3RlbmVyKGNhbmNlbExpc3RlbmVyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghcmVxIHx8IHJlcS5hYm9ydGVkKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgZGVidWcoJ1JlcXVlc3QgZXJyb3I6ICVzIC0gJU8nLCBlcnIsIGVyci5jb2RlKTtcbiAgICAgICAgcmV0dXJuIHJlamVjdChuZXcgRnNSZXF1ZXN0RXJyb3IoYFJlcXVlc3QgZXJyb3I6ICR7ZXJyLmNvZGV9YCwgY29uZmlnLCBudWxsLCBGc1JlcXVlc3RFcnJvckNvZGUuTkVUV09SSykpO1xuICAgICAgfSk7XG5cbiAgICAgIGlmIChCdWZmZXIuaXNCdWZmZXIoZGF0YSkgJiYgWydQT1NUJywgJ1BVVCddLmluZGV4T2YoY29uZmlnLm1ldGhvZCkgPiAtMSkge1xuICAgICAgICByZXR1cm4gdGhpcy5idWZmZXJUb0NodW5rcyhkYXRhKS5waXBlKHRoaXMuZ2V0UHJvZ3Jlc3NNb25pdG9yKGNvbmZpZywgZGF0YS5sZW5ndGgpKS5waXBlKG5ldyBIdHRwV3JpdGFibGVTdHJlYW0ocmVxKSk7XG4gICAgICB9XG5cbiAgICAgIHJlcS5lbmQoZGF0YSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogTW9uaXRvciBhbmQgZW1pdCBwcm9ncmVzcyBldmVudCBpZiBuZWVkZWRcbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQG1lbWJlcm9mIEh0dHBBZGFwdGVyXG4gICAqL1xuICBwcml2YXRlIGdldFByb2dyZXNzTW9uaXRvciA9IChjb25maWcsIHRvdGFsKSA9PiB7XG4gICAgbGV0IGxvYWRlZCA9IDA7XG5cbiAgICBjb25zdCBwcm9ncmVzcyA9IG5ldyBTdHJlYW0uVHJhbnNmb3JtKCk7XG4gICAgcHJvZ3Jlc3MuX3RyYW5zZm9ybSA9IChjaHVuaywgZW5jb2RpbmcsIGNiKSA9PiB7XG4gICAgICBpZiAodHlwZW9mIGNvbmZpZy5vblByb2dyZXNzID09PSAnZnVuY3Rpb24nICYmIFtGc0h0dHBNZXRob2QuUE9TVCwgRnNIdHRwTWV0aG9kLlBVVF0uaW5kZXhPZihjb25maWcubWV0aG9kKSA+IC0xKSB7XG4gICAgICAgIGxvYWRlZCArPSBjaHVuay5sZW5ndGg7XG4gICAgICAgIGNvbmZpZy5vblByb2dyZXNzKHtcbiAgICAgICAgICBsZW5ndGhDb21wdXRhYmxlOiB0cnVlLFxuICAgICAgICAgIGxvYWRlZCxcbiAgICAgICAgICB0b3RhbCxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICBjYihudWxsLCBjaHVuayk7XG4gICAgfTtcblxuICAgIHJldHVybiBwcm9ncmVzcztcbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0IGJ1ZmZlciB0byBzdHJlYW1cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHsqfSBidWZmZXJcbiAgICogQHJldHVybnMge1N0cmVhbS5SZWFkYWJsZX1cbiAgICogQG1lbWJlcm9mIEh0dHBBZGFwdGVyXG4gICAqL1xuICBwcml2YXRlIGJ1ZmZlclRvQ2h1bmtzKGJ1ZmZlcik6IFN0cmVhbS5SZWFkYWJsZSB7XG4gICAgY29uc3QgY2h1bmtpbmcgPSBuZXcgU3RyZWFtLlJlYWRhYmxlKCk7XG4gICAgY29uc3QgdG90YWxMZW5ndGggPSBidWZmZXIubGVuZ3RoO1xuICAgIGNvbnN0IHJlbWFpbmRlciA9IHRvdGFsTGVuZ3RoICUgSFRUUF9DSFVOS19TSVpFO1xuICAgIGNvbnN0IGN1dG9mZiA9IHRvdGFsTGVuZ3RoIC0gcmVtYWluZGVyO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjdXRvZmY7IGkgKz0gSFRUUF9DSFVOS19TSVpFKSB7XG4gICAgICBjb25zdCBjaHVuayA9IGJ1ZmZlci5zbGljZShpLCBpICsgSFRUUF9DSFVOS19TSVpFKTtcbiAgICAgIGNodW5raW5nLnB1c2goY2h1bmspO1xuICAgIH1cblxuICAgIGlmIChyZW1haW5kZXIgPiAwKSB7XG4gICAgICBjb25zdCByZW1haW5kZXJCdWZmZXIgPSBidWZmZXIuc2xpY2UoLXJlbWFpbmRlcik7XG4gICAgICBjaHVua2luZy5wdXNoKHJlbWFpbmRlckJ1ZmZlcik7XG4gICAgfVxuXG4gICAgY2h1bmtpbmcucHVzaChudWxsKTtcblxuICAgIHJldHVybiBjaHVua2luZztcbiAgfVxufVxuIl19