513 lines
52 KiB
JavaScript
513 lines
52 KiB
JavaScript
import _Reflect$construct from "@babel/runtime-corejs3/core-js-stable/reflect/construct";
|
|
import _wrapNativeSuper from "@babel/runtime-corejs3/helpers/wrapNativeSuper";
|
|
import _typeof from "@babel/runtime-corejs3/helpers/typeof";
|
|
import _classCallCheck from "@babel/runtime-corejs3/helpers/classCallCheck";
|
|
import _createClass from "@babel/runtime-corejs3/helpers/createClass";
|
|
import _possibleConstructorReturn from "@babel/runtime-corejs3/helpers/possibleConstructorReturn";
|
|
import _getPrototypeOf from "@babel/runtime-corejs3/helpers/getPrototypeOf";
|
|
import _inherits from "@babel/runtime-corejs3/helpers/inherits";
|
|
import _defineProperty from "@babel/runtime-corejs3/helpers/defineProperty";
|
|
import _asyncToGenerator from "@babel/runtime-corejs3/helpers/asyncToGenerator";
|
|
import _regeneratorRuntime from "@babel/runtime-corejs3/regenerator";
|
|
import _concatInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/concat";
|
|
import _Date$now from "@babel/runtime-corejs3/core-js-stable/date/now";
|
|
import _Object$keys2 from "@babel/runtime-corejs3/core-js-stable/object/keys";
|
|
import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";
|
|
import _globalThis from "@babel/runtime-corejs3/core-js/global-this";
|
|
import _Array$isArray from "@babel/runtime-corejs3/core-js-stable/array/is-array";
|
|
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? _Reflect$construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
|
|
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
|
|
import "core-js/modules/es.error.cause.js";
|
|
import "core-js/modules/es.array.join.js";
|
|
import "core-js/modules/es.array.push.js";
|
|
import "core-js/modules/es.function.name.js";
|
|
import "core-js/modules/es.object.keys.js";
|
|
import "core-js/modules/es.regexp.exec.js";
|
|
import "core-js/modules/es.regexp.test.js";
|
|
import "core-js/modules/web.self.js";
|
|
/**
|
|
*
|
|
*/
|
|
import { EventEmitter } from 'events';
|
|
import xml2js from 'xml2js';
|
|
import { getLogger } from './util/logger';
|
|
import { StreamPromise } from './util/promise';
|
|
import { parseCSV } from './csv';
|
|
import { createLazyStream } from './util/stream';
|
|
import { getBodySize } from './util/get-body-size';
|
|
|
|
/** @private */
|
|
function parseJSON(str) {
|
|
return JSON.parse(str);
|
|
}
|
|
|
|
/** @private */
|
|
function parseXML(_x) {
|
|
return _parseXML.apply(this, arguments);
|
|
}
|
|
/** @private */
|
|
function _parseXML() {
|
|
_parseXML = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5(str) {
|
|
return _regeneratorRuntime.wrap(function _callee5$(_context11) {
|
|
while (1) switch (_context11.prev = _context11.next) {
|
|
case 0:
|
|
return _context11.abrupt("return", xml2js.parseStringPromise(str, {
|
|
explicitArray: false
|
|
}));
|
|
case 1:
|
|
case "end":
|
|
return _context11.stop();
|
|
}
|
|
}, _callee5);
|
|
}));
|
|
return _parseXML.apply(this, arguments);
|
|
}
|
|
function parseText(str) {
|
|
return str;
|
|
}
|
|
|
|
/**
|
|
* HTTP based API class with authorization hook
|
|
*/
|
|
export var HttpApi = /*#__PURE__*/function (_EventEmitter) {
|
|
function HttpApi(conn, options) {
|
|
var _this;
|
|
_classCallCheck(this, HttpApi);
|
|
_this = _callSuper(this, HttpApi);
|
|
_this._conn = conn;
|
|
_this._logger = conn._logLevel ? HttpApi._logger.createInstance(conn._logLevel) : HttpApi._logger;
|
|
_this._responseType = options.responseType;
|
|
_this._transport = options.transport || conn._transport;
|
|
_this._noContentResponse = options.noContentResponse;
|
|
_this._options = options;
|
|
return _this;
|
|
}
|
|
|
|
/**
|
|
* Callout to API endpoint using http
|
|
*/
|
|
_inherits(HttpApi, _EventEmitter);
|
|
return _createClass(HttpApi, [{
|
|
key: "request",
|
|
value: function request(_request) {
|
|
var _this2 = this;
|
|
return StreamPromise.create(function () {
|
|
var _createLazyStream = createLazyStream(),
|
|
stream = _createLazyStream.stream,
|
|
setStream = _createLazyStream.setStream;
|
|
var promise = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
var _context, _context2;
|
|
var refreshDelegate, bodyPromise, _body2, requestTime, requestPromise, response, responseTime, err, body;
|
|
return _regeneratorRuntime.wrap(function _callee$(_context3) {
|
|
while (1) switch (_context3.prev = _context3.next) {
|
|
case 0:
|
|
refreshDelegate = _this2.getRefreshDelegate();
|
|
/* TODO decide remove or not this section */
|
|
/*
|
|
// remember previous instance url in case it changes after a refresh
|
|
const lastInstanceUrl = conn.instanceUrl;
|
|
// check to see if the token refresh has changed the instance url
|
|
if(lastInstanceUrl !== conn.instanceUrl){
|
|
// if the instance url has changed
|
|
// then replace the current request urls instance url fragment
|
|
// with the updated instance url
|
|
request.url = request.url.replace(lastInstanceUrl,conn.instanceUrl);
|
|
}
|
|
*/
|
|
if (!(refreshDelegate && refreshDelegate.isRefreshing())) {
|
|
_context3.next = 10;
|
|
break;
|
|
}
|
|
_context3.next = 4;
|
|
return refreshDelegate.waitRefresh();
|
|
case 4:
|
|
bodyPromise = _this2.request(_request);
|
|
setStream(bodyPromise.stream());
|
|
_context3.next = 8;
|
|
return bodyPromise;
|
|
case 8:
|
|
_body2 = _context3.sent;
|
|
return _context3.abrupt("return", _body2);
|
|
case 10:
|
|
// hook before sending
|
|
_this2.beforeSend(_request);
|
|
_this2.emit('request', _request);
|
|
_this2._logger.debug(_concatInstanceProperty(_context = "<request> method=".concat(_request.method, ", url=")).call(_context, _request.url));
|
|
requestTime = _Date$now();
|
|
requestPromise = _this2._transport.httpRequest(_request, _this2._options);
|
|
setStream(requestPromise.stream());
|
|
_context3.prev = 16;
|
|
_context3.next = 19;
|
|
return requestPromise;
|
|
case 19:
|
|
response = _context3.sent;
|
|
_context3.next = 26;
|
|
break;
|
|
case 22:
|
|
_context3.prev = 22;
|
|
_context3.t0 = _context3["catch"](16);
|
|
_this2._logger.error(_context3.t0);
|
|
throw _context3.t0;
|
|
case 26:
|
|
_context3.prev = 26;
|
|
responseTime = _Date$now();
|
|
_this2._logger.debug("elapsed time: ".concat(responseTime - requestTime, " msec"));
|
|
return _context3.finish(26);
|
|
case 30:
|
|
if (response) {
|
|
_context3.next = 32;
|
|
break;
|
|
}
|
|
return _context3.abrupt("return");
|
|
case 32:
|
|
_this2._logger.debug(_concatInstanceProperty(_context2 = "<response> status=".concat(String(response.statusCode), ", url=")).call(_context2, _request.url));
|
|
_this2.emit('response', response);
|
|
// Refresh token if session has been expired and requires authentication
|
|
// when session refresh delegate is available
|
|
if (!(_this2.isSessionExpired(response) && refreshDelegate)) {
|
|
_context3.next = 39;
|
|
break;
|
|
}
|
|
_context3.next = 37;
|
|
return refreshDelegate.refresh(requestTime);
|
|
case 37:
|
|
/* remove the `content-length` header after token refresh
|
|
*
|
|
* SOAP requests include the access token their the body,
|
|
* if the first req had an invalid token and jsforce successfully
|
|
* refreshed it we need to remove the `content-length` header
|
|
* so that it get's re-calculated again with the new body.
|
|
*
|
|
* REST request aren't affected by this because the access token
|
|
* is sent via HTTP headers
|
|
*
|
|
* `_message` is only present in SOAP requests
|
|
*/
|
|
if ('_message' in _request && _request.headers && 'content-length' in _request.headers) {
|
|
delete _request.headers['content-length'];
|
|
}
|
|
return _context3.abrupt("return", _this2.request(_request));
|
|
case 39:
|
|
if (!_this2.isErrorResponse(response)) {
|
|
_context3.next = 44;
|
|
break;
|
|
}
|
|
_context3.next = 42;
|
|
return _this2.getError(response);
|
|
case 42:
|
|
err = _context3.sent;
|
|
throw err;
|
|
case 44:
|
|
_context3.next = 46;
|
|
return _this2.getResponseBody(response);
|
|
case 46:
|
|
body = _context3.sent;
|
|
return _context3.abrupt("return", body);
|
|
case 48:
|
|
case "end":
|
|
return _context3.stop();
|
|
}
|
|
}, _callee, null, [[16, 22, 26, 30]]);
|
|
}))();
|
|
return {
|
|
stream: stream,
|
|
promise: promise
|
|
};
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @protected
|
|
*/
|
|
}, {
|
|
key: "getRefreshDelegate",
|
|
value: function getRefreshDelegate() {
|
|
return this._conn._refreshDelegate;
|
|
}
|
|
|
|
/**
|
|
* @protected
|
|
*/
|
|
}, {
|
|
key: "beforeSend",
|
|
value: function beforeSend(request) {
|
|
var _context5;
|
|
/* eslint-disable no-param-reassign */
|
|
var headers = request.headers || {};
|
|
if (this._conn.accessToken) {
|
|
headers.Authorization = "Bearer ".concat(this._conn.accessToken);
|
|
}
|
|
if (this._conn._callOptions) {
|
|
var callOptions = [];
|
|
for (var _i = 0, _Object$keys = _Object$keys2(this._conn._callOptions); _i < _Object$keys.length; _i++) {
|
|
var _context4;
|
|
var name = _Object$keys[_i];
|
|
callOptions.push(_concatInstanceProperty(_context4 = "".concat(name, "=")).call(_context4, this._conn._callOptions[name]));
|
|
}
|
|
headers['Sforce-Call-Options'] = callOptions.join(', ');
|
|
}
|
|
var bodySize = getBodySize(request.body, headers);
|
|
var cannotHaveBody = _includesInstanceProperty(_context5 = ['GET', 'HEAD', 'OPTIONS']).call(_context5, request.method);
|
|
|
|
// Don't set content-length in browsers as it's not allowed
|
|
var isBrowser = 'window' in _globalThis || 'self' in _globalThis;
|
|
if (!isBrowser &&
|
|
// Don't set content-length in browsers as it's not allowed
|
|
!cannotHaveBody && !!request.body && !('transfer-encoding' in headers) && !('content-length' in headers) && !!bodySize) {
|
|
this._logger.debug("missing 'content-length' header, setting it to: ".concat(bodySize));
|
|
headers['content-length'] = String(bodySize);
|
|
}
|
|
request.headers = headers;
|
|
}
|
|
|
|
/**
|
|
* Detect response content mime-type
|
|
* @protected
|
|
*/
|
|
}, {
|
|
key: "getResponseContentType",
|
|
value: function getResponseContentType(response) {
|
|
return this._responseType || response.headers && response.headers['content-type'];
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
}, {
|
|
key: "parseResponseBody",
|
|
value: (function () {
|
|
var _parseResponseBody = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(response) {
|
|
var contentType, parseBody, _context6;
|
|
return _regeneratorRuntime.wrap(function _callee2$(_context7) {
|
|
while (1) switch (_context7.prev = _context7.next) {
|
|
case 0:
|
|
contentType = this.getResponseContentType(response) || '';
|
|
parseBody = /^(text|application)\/xml(;|$)/.test(contentType) ? parseXML : /^application\/json(;|$)/.test(contentType) ? parseJSON : /^text\/csv(;|$)/.test(contentType) ? parseCSV : parseText;
|
|
_context7.prev = 2;
|
|
return _context7.abrupt("return", parseBody(response.body));
|
|
case 6:
|
|
_context7.prev = 6;
|
|
_context7.t0 = _context7["catch"](2);
|
|
// TODO(next major): we could throw a new "invalid response body" error instead.
|
|
this._logger.debug(_concatInstanceProperty(_context6 = "Failed to parse body of content-type: ".concat(contentType, ". Error: ")).call(_context6, _context7.t0.message));
|
|
return _context7.abrupt("return", response.body);
|
|
case 10:
|
|
case "end":
|
|
return _context7.stop();
|
|
}
|
|
}, _callee2, this, [[2, 6]]);
|
|
}));
|
|
function parseResponseBody(_x2) {
|
|
return _parseResponseBody.apply(this, arguments);
|
|
}
|
|
return parseResponseBody;
|
|
}()
|
|
/**
|
|
* Get response body
|
|
* @protected
|
|
*/
|
|
)
|
|
}, {
|
|
key: "getResponseBody",
|
|
value: (function () {
|
|
var _getResponseBody = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3(response) {
|
|
var body, err;
|
|
return _regeneratorRuntime.wrap(function _callee3$(_context8) {
|
|
while (1) switch (_context8.prev = _context8.next) {
|
|
case 0:
|
|
if (!(response.statusCode === 204)) {
|
|
_context8.next = 2;
|
|
break;
|
|
}
|
|
return _context8.abrupt("return", this._noContentResponse);
|
|
case 2:
|
|
_context8.next = 4;
|
|
return this.parseResponseBody(response);
|
|
case 4:
|
|
body = _context8.sent;
|
|
if (!this.hasErrorInResponseBody(body)) {
|
|
_context8.next = 10;
|
|
break;
|
|
}
|
|
_context8.next = 8;
|
|
return this.getError(response, body);
|
|
case 8:
|
|
err = _context8.sent;
|
|
throw err;
|
|
case 10:
|
|
if (!(response.statusCode === 300)) {
|
|
_context8.next = 12;
|
|
break;
|
|
}
|
|
throw new HttpApiError('Multiple records found', 'MULTIPLE_CHOICES', body);
|
|
case 12:
|
|
return _context8.abrupt("return", body);
|
|
case 13:
|
|
case "end":
|
|
return _context8.stop();
|
|
}
|
|
}, _callee3, this);
|
|
}));
|
|
function getResponseBody(_x3) {
|
|
return _getResponseBody.apply(this, arguments);
|
|
}
|
|
return getResponseBody;
|
|
}()
|
|
/**
|
|
* Detect session expiry
|
|
* @protected
|
|
*/
|
|
)
|
|
}, {
|
|
key: "isSessionExpired",
|
|
value: function isSessionExpired(response) {
|
|
var _context9;
|
|
// TODO:
|
|
// The connected app msg only applies to Agent API requests, we should move this to a separate SFAP/Agent API class later.
|
|
return response.statusCode === 401 && !_includesInstanceProperty(_context9 = response.body).call(_context9, 'Connected app is not attached to Agent');
|
|
}
|
|
|
|
/**
|
|
* Detect error response
|
|
* @protected
|
|
*/
|
|
}, {
|
|
key: "isErrorResponse",
|
|
value: function isErrorResponse(response) {
|
|
return response.statusCode >= 400;
|
|
}
|
|
|
|
/**
|
|
* Detect error in response body
|
|
* @protected
|
|
*/
|
|
}, {
|
|
key: "hasErrorInResponseBody",
|
|
value: function hasErrorInResponseBody(_body) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Parsing error message in response
|
|
* @protected
|
|
*/
|
|
}, {
|
|
key: "parseError",
|
|
value: function parseError(body) {
|
|
var errors = body;
|
|
|
|
// XML response
|
|
if (errors.Errors) {
|
|
return errors.Errors.Error;
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
/**
|
|
* Get error message in response
|
|
* @protected
|
|
*/
|
|
}, {
|
|
key: "getError",
|
|
value: (function () {
|
|
var _getError = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4(response, body) {
|
|
var error;
|
|
return _regeneratorRuntime.wrap(function _callee4$(_context10) {
|
|
while (1) switch (_context10.prev = _context10.next) {
|
|
case 0:
|
|
_context10.prev = 0;
|
|
_context10.t0 = this;
|
|
_context10.t1 = body;
|
|
if (_context10.t1) {
|
|
_context10.next = 7;
|
|
break;
|
|
}
|
|
_context10.next = 6;
|
|
return this.parseResponseBody(response);
|
|
case 6:
|
|
_context10.t1 = _context10.sent;
|
|
case 7:
|
|
_context10.t2 = _context10.t1;
|
|
error = _context10.t0.parseError.call(_context10.t0, _context10.t2);
|
|
_context10.next = 13;
|
|
break;
|
|
case 11:
|
|
_context10.prev = 11;
|
|
_context10.t3 = _context10["catch"](0);
|
|
case 13:
|
|
if (!_Array$isArray(error)) {
|
|
_context10.next = 19;
|
|
break;
|
|
}
|
|
if (!(error.length === 1)) {
|
|
_context10.next = 18;
|
|
break;
|
|
}
|
|
error = error[0];
|
|
_context10.next = 19;
|
|
break;
|
|
case 18:
|
|
return _context10.abrupt("return", new HttpApiError("Multiple errors returned.\n Check `error.data` for the error details", 'MULTIPLE_API_ERRORS', error));
|
|
case 19:
|
|
error = _typeof(error) === 'object' && error !== null && typeof error.message === 'string' ? error : {
|
|
errorCode: "ERROR_HTTP_".concat(response.statusCode),
|
|
message: response.body
|
|
};
|
|
if (!(response.headers['content-type'] === 'text/html')) {
|
|
_context10.next = 23;
|
|
break;
|
|
}
|
|
this._logger.debug("html response.body: ".concat(response.body));
|
|
return _context10.abrupt("return", new HttpApiError("HTTP response contains html content.\nCheck that the org exists and can be reached.\nSee `error.data` for the full html response.", error.errorCode, error.message));
|
|
case 23:
|
|
return _context10.abrupt("return", error instanceof HttpApiError ? error : new HttpApiError(error.message, error.errorCode, error));
|
|
case 24:
|
|
case "end":
|
|
return _context10.stop();
|
|
}
|
|
}, _callee4, this, [[0, 11]]);
|
|
}));
|
|
function getError(_x4, _x5) {
|
|
return _getError.apply(this, arguments);
|
|
}
|
|
return getError;
|
|
}())
|
|
}]);
|
|
}(EventEmitter);
|
|
|
|
/**
|
|
*
|
|
*/
|
|
_defineProperty(HttpApi, "_logger", getLogger('http-api'));
|
|
var HttpApiError = /*#__PURE__*/function (_Error) {
|
|
/**
|
|
* This contains error-specific details, usually returned from the API.
|
|
*/
|
|
|
|
function HttpApiError(message, errorCode, data) {
|
|
var _this3;
|
|
_classCallCheck(this, HttpApiError);
|
|
_this3 = _callSuper(this, HttpApiError, [message]);
|
|
_this3.name = errorCode || _this3.name;
|
|
_this3.errorCode = _this3.name;
|
|
_this3.data = data;
|
|
return _this3;
|
|
}
|
|
|
|
/**
|
|
* This will be removed in the next major (v4)
|
|
*
|
|
* @deprecated use `error.data` instead
|
|
*/
|
|
_inherits(HttpApiError, _Error);
|
|
return _createClass(HttpApiError, [{
|
|
key: "content",
|
|
get: function get() {
|
|
return this.data;
|
|
}
|
|
}]);
|
|
}(/*#__PURE__*/_wrapNativeSuper(Error));
|
|
export default HttpApi;
|
|
export var isBrowser = 'window' in _globalThis || 'self' in _globalThis;
|
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJFdmVudEVtaXR0ZXIiLCJ4bWwyanMiLCJnZXRMb2dnZXIiLCJTdHJlYW1Qcm9taXNlIiwicGFyc2VDU1YiLCJjcmVhdGVMYXp5U3RyZWFtIiwiZ2V0Qm9keVNpemUiLCJwYXJzZUpTT04iLCJzdHIiLCJKU09OIiwicGFyc2UiLCJwYXJzZVhNTCIsIl94IiwiX3BhcnNlWE1MIiwiYXBwbHkiLCJhcmd1bWVudHMiLCJfYXN5bmNUb0dlbmVyYXRvciIsIl9yZWdlbmVyYXRvclJ1bnRpbWUiLCJtYXJrIiwiX2NhbGxlZTUiLCJ3cmFwIiwiX2NhbGxlZTUkIiwiX2NvbnRleHQxMSIsInByZXYiLCJuZXh0IiwiYWJydXB0IiwicGFyc2VTdHJpbmdQcm9taXNlIiwiZXhwbGljaXRBcnJheSIsInN0b3AiLCJwYXJzZVRleHQiLCJIdHRwQXBpIiwiX0V2ZW50RW1pdHRlciIsImNvbm4iLCJvcHRpb25zIiwiX3RoaXMiLCJfY2xhc3NDYWxsQ2hlY2siLCJfY2FsbFN1cGVyIiwiX2Nvbm4iLCJfbG9nZ2VyIiwiX2xvZ0xldmVsIiwiY3JlYXRlSW5zdGFuY2UiLCJfcmVzcG9uc2VUeXBlIiwicmVzcG9uc2VUeXBlIiwiX3RyYW5zcG9ydCIsInRyYW5zcG9ydCIsIl9ub0NvbnRlbnRSZXNwb25zZSIsIm5vQ29udGVudFJlc3BvbnNlIiwiX29wdGlvbnMiLCJfaW5oZXJpdHMiLCJfY3JlYXRlQ2xhc3MiLCJrZXkiLCJ2YWx1ZSIsInJlcXVlc3QiLCJfdGhpczIiLCJjcmVhdGUiLCJfY3JlYXRlTGF6eVN0cmVhbSIsInN0cmVhbSIsInNldFN0cmVhbSIsInByb21pc2UiLCJfY2FsbGVlIiwiX2NvbnRleHQiLCJfY29udGV4dDIiLCJyZWZyZXNoRGVsZWdhdGUiLCJib2R5UHJvbWlzZSIsIl9ib2R5MiIsInJlcXVlc3RUaW1lIiwicmVxdWVzdFByb21pc2UiLCJyZXNwb25zZSIsInJlc3BvbnNlVGltZSIsImVyciIsImJvZHkiLCJfY2FsbGVlJCIsIl9jb250ZXh0MyIsImdldFJlZnJlc2hEZWxlZ2F0ZSIsImlzUmVmcmVzaGluZyIsIndhaXRSZWZyZXNoIiwic2VudCIsImJlZm9yZVNlbmQiLCJlbWl0IiwiZGVidWciLCJfY29uY2F0SW5zdGFuY2VQcm9wZXJ0eSIsImNvbmNhdCIsIm1ldGhvZCIsImNhbGwiLCJ1cmwiLCJfRGF0ZSRub3ciLCJodHRwUmVxdWVzdCIsInQwIiwiZXJyb3IiLCJmaW5pc2giLCJTdHJpbmciLCJzdGF0dXNDb2RlIiwiaXNTZXNzaW9uRXhwaXJlZCIsInJlZnJlc2giLCJoZWFkZXJzIiwiaXNFcnJvclJlc3BvbnNlIiwiZ2V0RXJyb3IiLCJnZXRSZXNwb25zZUJvZHkiLCJfcmVmcmVzaERlbGVnYXRlIiwiX2NvbnRleHQ1IiwiYWNjZXNzVG9rZW4iLCJBdXRob3JpemF0aW9uIiwiX2NhbGxPcHRpb25zIiwiY2FsbE9wdGlvbnMiLCJfaSIsIl9PYmplY3Qka2V5cyIsIl9PYmplY3Qka2V5czIiLCJsZW5ndGgiLCJfY29udGV4dDQiLCJuYW1lIiwicHVzaCIsImpvaW4iLCJib2R5U2l6ZSIsImNhbm5vdEhhdmVCb2R5IiwiX2luY2x1ZGVzSW5zdGFuY2VQcm9wZXJ0eSIsImlzQnJvd3NlciIsIl9nbG9iYWxUaGlzIiwiZ2V0UmVzcG9uc2VDb250ZW50VHlwZSIsIl9wYXJzZVJlc3BvbnNlQm9keSIsIl9jYWxsZWUyIiwiY29udGVudFR5cGUiLCJwYXJzZUJvZHkiLCJfY29udGV4dDYiLCJfY2FsbGVlMiQiLCJfY29udGV4dDciLCJ0ZXN0IiwibWVzc2FnZSIsInBhcnNlUmVzcG9uc2VCb2R5IiwiX3gyIiwiX2dldFJlc3BvbnNlQm9keSIsIl9jYWxsZWUzIiwiX2NhbGxlZTMkIiwiX2NvbnRleHQ4IiwiaGFzRXJyb3JJblJlc3BvbnNlQm9keSIsIkh0dHBBcGlFcnJvciIsIl94MyIsIl9jb250ZXh0OSIsIl9ib2R5IiwicGFyc2VFcnJvciIsImVycm9ycyIsIkVycm9ycyIsIkVycm9yIiwiX2dldEVycm9yIiwiX2NhbGxlZTQiLCJfY2FsbGVlNCQiLCJfY29udGV4dDEwIiwidDEiLCJ0MiIsInQzIiwiX0FycmF5JGlzQXJyYXkiLCJfdHlwZW9mIiwiZXJyb3JDb2RlIiwiX3g0IiwiX3g1IiwiX2RlZmluZVByb3BlcnR5IiwiX0Vycm9yIiwiZGF0YSIsIl90aGlzMyIsImdldCIsIl93cmFwTmF0aXZlU3VwZXIiXSwic291cmNlcyI6WyIuLi9zcmMvaHR0cC1hcGkudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKlxuICovXG5pbXBvcnQgeyBFdmVudEVtaXR0ZXIgfSBmcm9tICdldmVudHMnO1xuaW1wb3J0IHhtbDJqcyBmcm9tICd4bWwyanMnO1xuaW1wb3J0IHsgTG9nZ2VyLCBnZXRMb2dnZXIgfSBmcm9tICcuL3V0aWwvbG9nZ2VyJztcbmltcG9ydCB7IFN0cmVhbVByb21pc2UgfSBmcm9tICcuL3V0aWwvcHJvbWlzZSc7XG5pbXBvcnQgQ29ubmVjdGlvbiBmcm9tICcuL2Nvbm5lY3Rpb24nO1xuaW1wb3J0IFRyYW5zcG9ydCBmcm9tICcuL3RyYW5zcG9ydCc7XG5pbXBvcnQgeyBwYXJzZUNTViB9IGZyb20gJy4vY3N2JztcbmltcG9ydCB7XG4gIEh0dHBSZXF1ZXN0LFxuICBIdHRwUmVxdWVzdE9wdGlvbnMsXG4gIEh0dHBSZXNwb25zZSxcbiAgT3B0aW9uYWwsXG4gIFNjaGVtYSxcbn0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBjcmVhdGVMYXp5U3RyZWFtIH0gZnJvbSAnLi91dGlsL3N0cmVhbSc7XG5pbXBvcnQgeyBnZXRCb2R5U2l6ZSB9IGZyb20gJy4vdXRpbC9nZXQtYm9keS1zaXplJztcblxuLyoqIEBwcml2YXRlICovXG5mdW5jdGlvbiBwYXJzZUpTT04oc3RyOiBzdHJpbmcpIHtcbiAgcmV0dXJuIEpTT04ucGFyc2Uoc3RyKTtcbn1cblxuLyoqIEBwcml2YXRlICovXG5hc3luYyBmdW5jdGlvbiBwYXJzZVhNTChzdHI6IHN0cmluZykge1xuICByZXR1cm4geG1sMmpzLnBhcnNlU3RyaW5nUHJvbWlzZShzdHIsIHsgZXhwbGljaXRBcnJheTogZmFsc2UgfSk7XG59XG5cbi8qKiBAcHJpdmF0ZSAqL1xuZnVuY3Rpb24gcGFyc2VUZXh0KHN0cjogc3RyaW5nKSB7XG4gIHJldHVybiBzdHI7XG59XG5cbi8qKlxuICogSFRUUCBiYXNlZCBBUEkgY2xhc3Mgd2l0aCBhdXRob3JpemF0aW9uIGhvb2tcbiAqL1xuZXhwb3J0IGNsYXNzIEh0dHBBcGk8UyBleHRlbmRzIFNjaGVtYT4gZXh0ZW5kcyBFdmVudEVtaXR0ZXIge1xuICBzdGF0aWMgX2xvZ2dlciA9IGdldExvZ2dlcignaHR0cC1hcGknKTtcblxuICBfY29ubjogQ29ubmVjdGlvbjxTPjtcbiAgX2xvZ2dlcjogTG9nZ2VyO1xuICBfdHJhbnNwb3J0OiBUcmFuc3BvcnQ7XG4gIF9yZXNwb25zZVR5cGU6IHN0cmluZyB8IHZvaWQ7XG4gIF9ub0NvbnRlbnRSZXNwb25zZTogc3RyaW5nIHwgdm9pZDtcbiAgX29wdGlvbnM6IEh0dHBSZXF1ZXN0T3B0aW9ucztcblxuICBjb25zdHJ1Y3Rvcihjb25uOiBDb25uZWN0aW9uPFM+LCBvcHRpb25zOiBhbnkpIHtcbiAgICBzdXBlcigpO1xuICAgIHRoaXMuX2Nvbm4gPSBjb25uO1xuICAgIHRoaXMuX2xvZ2dlciA9IGNvbm4uX2xvZ0xldmVsXG4gICAgICA/IEh0dHBBcGkuX2xvZ2dlci5jcmVhdGVJbnN0YW5jZShjb25uLl9sb2dMZXZlbClcbiAgICAgIDogSHR0cEFwaS5fbG9nZ2VyO1xuICAgIHRoaXMuX3Jlc3BvbnNlVHlwZSA9IG9wdGlvbnMucmVzcG9uc2VUeXBlO1xuICAgIHRoaXMuX3RyYW5zcG9ydCA9IG9wdGlvbnMudHJhbnNwb3J0IHx8IGNvbm4uX3RyYW5zcG9ydDtcbiAgICB0aGlzLl9ub0NvbnRlbnRSZXNwb25zZSA9IG9wdGlvbnMubm9Db250ZW50UmVzcG9uc2U7XG4gICAgdGhpcy5fb3B0aW9ucyA9IG9wdGlvbnM7XG4gIH1cblxuICAvKipcbiAgICogQ2FsbG91dCB0byBBUEkgZW5kcG9pbnQgdXNpbmcgaHR0cFxuICAgKi9cbiAgcmVxdWVzdDxSID0gdW5rbm93bj4ocmVxdWVzdDogSHR0cFJlcXVlc3QpOiBTdHJlYW1Qcm9taXNlPFI+IHtcbiAgICByZXR1cm4gU3RyZWFtUHJvbWlzZS5jcmVhdGU8Uj4oKCkgPT4ge1xuICAgICAgY29uc3QgeyBzdHJlYW0sIHNldFN0cmVhbSB9ID0gY3JlYXRlTGF6eVN0cmVhbSgpO1xuICAgICAgY29uc3QgcHJvbWlzZSA9IChhc3luYyAoKSA9PiB7XG4gICAgICAgIGNvbnN0IHJlZnJlc2hEZWxlZ2F0ZSA9IHRoaXMuZ2V0UmVmcmVzaERlbGVnYXRlKCk7XG4gICAgICAgIC8qIFRPRE8gZGVjaWRlIHJlbW92ZSBvciBub3QgdGhpcyBzZWN0aW9uICovXG4gICAgICAgIC8qXG4gICAgICAgIC8vIHJlbWVtYmVyIHByZXZpb3VzIGluc3RhbmNlIHVybCBpbiBjYXNlIGl0IGNoYW5nZXMgYWZ0ZXIgYSByZWZyZXNoXG4gICAgICAgIGNvbnN0IGxhc3RJbnN0YW5jZVVybCA9IGNvbm4uaW5zdGFuY2VVcmw7XG5cbiAgICAgICAgLy8gY2hlY2sgdG8gc2VlIGlmIHRoZSB0b2tlbiByZWZyZXNoIGhhcyBjaGFuZ2VkIHRoZSBpbnN0YW5jZSB1cmxcbiAgICAgICAgaWYobGFzdEluc3RhbmNlVXJsICE9PSBjb25uLmluc3RhbmNlVXJsKXtcbiAgICAgICAgICAvLyBpZiB0aGUgaW5zdGFuY2UgdXJsIGhhcyBjaGFuZ2VkXG4gICAgICAgICAgLy8gdGhlbiByZXBsYWNlIHRoZSBjdXJyZW50IHJlcXVlc3QgdXJscyBpbnN0YW5jZSB1cmwgZnJhZ21lbnRcbiAgICAgICAgICAvLyB3aXRoIHRoZSB1cGRhdGVkIGluc3RhbmNlIHVybFxuICAgICAgICAgIHJlcXVlc3QudXJsID0gcmVxdWVzdC51cmwucmVwbGFjZShsYXN0SW5zdGFuY2VVcmwsY29ubi5pbnN0YW5jZVVybCk7XG4gICAgICAgIH1cbiAgICAgICAgKi9cbiAgICAgICAgaWYgKHJlZnJlc2hEZWxlZ2F0ZSAmJiByZWZyZXNoRGVsZWdhdGUuaXNSZWZyZXNoaW5nKCkpIHtcbiAgICAgICAgICBhd2FpdCByZWZyZXNoRGVsZWdhdGUud2FpdFJlZnJlc2goKTtcbiAgICAgICAgICBjb25zdCBib2R5UHJvbWlzZSA9IHRoaXMucmVxdWVzdChyZXF1ZXN0KTtcbiAgICAgICAgICBzZXRTdHJlYW0oYm9keVByb21pc2Uuc3RyZWFtKCkpO1xuICAgICAgICAgIGNvbnN0IGJvZHkgPSBhd2FpdCBib2R5UHJvbWlzZTtcbiAgICAgICAgICByZXR1cm4gYm9keTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGhvb2sgYmVmb3JlIHNlbmRpbmdcbiAgICAgICAgdGhpcy5iZWZvcmVTZW5kKHJlcXVlc3QpO1xuXG4gICAgICAgIHRoaXMuZW1pdCgncmVxdWVzdCcsIHJlcXVlc3QpO1xuICAgICAgICB0aGlzLl9sb2dnZXIuZGVidWcoXG4gICAgICAgICAgYDxyZXF1ZXN0PiBtZXRob2Q9JHtyZXF1ZXN0Lm1ldGhvZH0sIHVybD0ke3JlcXVlc3QudXJsfWAsXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHJlcXVlc3RUaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgICAgY29uc3QgcmVxdWVzdFByb21pc2UgPSB0aGlzLl90cmFuc3BvcnQuaHR0cFJlcXVlc3QoXG4gICAgICAgICAgcmVxdWVzdCxcbiAgICAgICAgICB0aGlzLl9vcHRpb25zLFxuICAgICAgICApO1xuXG4gICAgICAgIHNldFN0cmVhbShyZXF1ZXN0UHJvbWlzZS5zdHJlYW0oKSk7XG5cbiAgICAgICAgbGV0IHJlc3BvbnNlOiBIdHRwUmVzcG9uc2UgfCB2b2lkO1xuICAgICAgICB0cnkge1xuICAgICAgICAgIHJlc3BvbnNlID0gYXdhaXQgcmVxdWVzdFByb21pc2U7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIHRoaXMuX2xvZ2dlci5lcnJvcihlcnIpO1xuICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICBjb25zdCByZXNwb25zZVRpbWUgPSBEYXRlLm5vdygpO1xuICAgICAgICAgIHRoaXMuX2xvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICAgIGBlbGFwc2VkIHRpbWU6ICR7cmVzcG9uc2VUaW1lIC0gcmVxdWVzdFRpbWV9IG1zZWNgLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFyZXNwb25zZSkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLl9sb2dnZXIuZGVidWcoXG4gICAgICAgICAgYDxyZXNwb25zZT4gc3RhdHVzPSR7U3RyaW5nKHJlc3BvbnNlLnN0YXR1c0NvZGUpfSwgdXJsPSR7XG4gICAgICAgICAgICByZXF1ZXN0LnVybFxuICAgICAgICAgIH1gLFxuICAgICAgICApO1xuICAgICAgICB0aGlzLmVtaXQoJ3Jlc3BvbnNlJywgcmVzcG9uc2UpO1xuICAgICAgICAvLyBSZWZyZXNoIHRva2VuIGlmIHNlc3Npb24gaGFzIGJlZW4gZXhwaXJlZCBhbmQgcmVxdWlyZXMgYXV0aGVudGljYXRpb25cbiAgICAgICAgLy8gd2hlbiBzZXNzaW9uIHJlZnJlc2ggZGVsZWdhdGUgaXMgYXZhaWxhYmxlXG4gICAgICAgIGlmICh0aGlzLmlzU2Vzc2lvbkV4cGlyZWQocmVzcG9uc2UpICYmIHJlZnJlc2hEZWxlZ2F0ZSkge1xuICAgICAgICAgIGF3YWl0IHJlZnJlc2hEZWxlZ2F0ZS5yZWZyZXNoKHJlcXVlc3RUaW1lKTtcbiAgICAgICAgICAvKiByZW1vdmUgdGhlIGBjb250ZW50LWxlbmd0aGAgaGVhZGVyIGFmdGVyIHRva2VuIHJlZnJlc2hcbiAgICAgICAgICAgKlxuICAgICAgICAgICAqIFNPQVAgcmVxdWVzdHMgaW5jbHVkZSB0aGUgYWNjZXNzIHRva2VuIHRoZWlyIHRoZSBib2R5LFxuICAgICAgICAgICAqIGlmIHRoZSBmaXJzdCByZXEgaGFkIGFuIGludmFsaWQgdG9rZW4gYW5kIGpzZm9yY2Ugc3VjY2Vzc2Z1bGx5XG4gICAgICAgICAgICogcmVmcmVzaGVkIGl0IHdlIG5lZWQgdG8gcmVtb3ZlIHRoZSBgY29udGVudC1sZW5ndGhgIGhlYWRlclxuICAgICAgICAgICAqIHNvIHRoYXQgaXQgZ2V0J3MgcmUtY2FsY3VsYXRlZCBhZ2FpbiB3aXRoIHRoZSBuZXcgYm9keS5cbiAgICAgICAgICAgKlxuICAgICAgICAgICAqIFJFU1QgcmVxdWVzdCBhcmVuJ3QgYWZmZWN0ZWQgYnkgdGhpcyBiZWNhdXNlIHRoZSBhY2Nlc3MgdG9rZW5cbiAgICAgICAgICAgKiBpcyBzZW50IHZpYSBIVFRQIGhlYWRlcnNcbiAgICAgICAgICAgKlxuICAgICAgICAgICAqIGBfbWVzc2FnZWAgaXMgb25seSBwcmVzZW50IGluIFNPQVAgcmVxdWVzdHNcbiAgICAgICAgICAgKi9cbiAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAnX21lc3NhZ2UnIGluIHJlcXVlc3QgJiZcbiAgICAgICAgICAgIHJlcXVlc3QuaGVhZGVycyAmJlxuICAgICAgICAgICAgJ2NvbnRlbnQtbGVuZ3RoJyBpbiByZXF1ZXN0LmhlYWRlcnNcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIGRlbGV0ZSByZXF1ZXN0LmhlYWRlcnNbJ2NvbnRlbnQtbGVuZ3RoJ107XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB0aGlzLnJlcXVlc3QocmVxdWVzdCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuaXNFcnJvclJlc3BvbnNlKHJlc3BvbnNlKSkge1xuICAgICAgICAgIGNvbnN0IGVyciA9IGF3YWl0IHRoaXMuZ2V0RXJyb3IocmVzcG9uc2UpO1xuICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBib2R5ID0gYXdhaXQgdGhpcy5nZXRSZXNwb25zZUJvZHkocmVzcG9uc2UpO1xuICAgICAgICByZXR1cm4gYm9keTtcbiAgICAgIH0pKCk7XG4gICAgICByZXR1cm4geyBzdHJlYW0sIHByb21pc2UgfTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJvdGVjdGVkXG4gICAqL1xuICBnZXRSZWZyZXNoRGVsZWdhdGUoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2Nvbm4uX3JlZnJlc2hEZWxlZ2F0ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJvdGVjdGVkXG4gICAqL1xuICBiZWZvcmVTZW5kKHJlcXVlc3Q6IEh0dHBSZXF1ZXN0KSB7XG4gICAgLyogZXNsaW50LWRpc2FibGUgbm8tcGFyYW0tcmVhc3NpZ24gKi9cbiAgICBjb25zdCBoZWFkZXJzID0gcmVxdWVzdC5oZWFkZXJzIHx8IHt9O1xuICAgIGlmICh0aGlzLl9jb25uLmFjY2Vzc1Rva2VuKSB7XG4gICAgICBoZWFkZXJzLkF1dGhvcml6YXRpb24gPSBgQmVhcmVyICR7dGhpcy5fY29ubi5hY2Nlc3NUb2tlbn1gO1xuICAgIH1cbiAgICBpZiAodGhpcy5fY29ubi5fY2FsbE9wdGlvbnMpIHtcbiAgICAgIGNvbnN0IGNhbGxPcHRpb25zID0gW107XG4gICAgICBmb3IgKGNvbnN0IG5hbWUgb2YgT2JqZWN0LmtleXModGhpcy5fY29ubi5fY2FsbE9wdGlvbnMpKSB7XG4gICAgICAgIGNhbGxPcHRpb25zLnB1c2goYCR7bmFtZX09JHt0aGlzLl9jb25uLl9jYWxsT3B0aW9uc1tuYW1lXX1gKTtcbiAgICAgIH1cbiAgICAgIGhlYWRlcnNbJ1Nmb3JjZS1DYWxsLU9wdGlvbnMnXSA9IGNhbGxPcHRpb25zLmpvaW4oJywgJyk7XG4gICAgfVxuXG4gICAgY29uc3QgYm9keVNpemUgPSBnZXRCb2R5U2l6ZShyZXF1ZXN0LmJvZHksIGhlYWRlcnMpO1xuXG4gICAgY29uc3QgY2Fubm90SGF2ZUJvZHkgPSBbJ0dFVCcsICdIRUFEJywgJ09QVElPTlMnXS5pbmNsdWRlcyhyZXF1ZXN0Lm1ldGhvZCk7XG5cbiAgICAvLyBEb24ndCBzZXQgY29udGVudC1sZW5ndGggaW4gYnJvd3NlcnMgYXMgaXQncyBub3QgYWxsb3dlZFxuICAgIGNvbnN0IGlzQnJvd3NlciA9ICd3aW5kb3cnIGluIGdsb2JhbFRoaXMgfHwgJ3NlbGYnIGluIGdsb2JhbFRoaXM7XG5cbiAgICBpZiAoXG4gICAgICAhaXNCcm93c2VyICYmIC8vIERvbid0IHNldCBjb250ZW50LWxlbmd0aCBpbiBicm93c2VycyBhcyBpdCdzIG5vdCBhbGxvd2VkXG4gICAgICAhY2Fubm90SGF2ZUJvZHkgJiZcbiAgICAgICEhcmVxdWVzdC5ib2R5ICYmXG4gICAgICAhKCd0cmFuc2Zlci1lbmNvZGluZycgaW4gaGVhZGVycykgJiZcbiAgICAgICEoJ2NvbnRlbnQtbGVuZ3RoJyBpbiBoZWFkZXJzKSAmJlxuICAgICAgISFib2R5U2l6ZVxuICAgICkge1xuICAgICAgdGhpcy5fbG9nZ2VyLmRlYnVnKFxuICAgICAgICBgbWlzc2luZyAnY29udGVudC1sZW5ndGgnIGhlYWRlciwgc2V0dGluZyBpdCB0bzogJHtib2R5U2l6ZX1gLFxuICAgICAgKTtcbiAgICAgIGhlYWRlcnNbJ2NvbnRlbnQtbGVuZ3RoJ10gPSBTdHJpbmcoYm9keVNpemUpO1xuICAgIH1cbiAgICByZXF1ZXN0LmhlYWRlcnMgPSBoZWFkZXJzO1xuICB9XG5cbiAgLyoqXG4gICAqIERldGVjdCByZXNwb25zZSBjb250ZW50IG1pbWUtdHlwZVxuICAgKiBAcHJvdGVjdGVkXG4gICAqL1xuICBnZXRSZXNwb25zZUNvbnRlbnRUeXBlKHJlc3BvbnNlOiBIdHRwUmVzcG9uc2UpOiBPcHRpb25hbDxzdHJpbmc+IHtcbiAgICByZXR1cm4gKFxuICAgICAgdGhpcy5fcmVzcG9uc2VUeXBlIHx8XG4gICAgICAocmVzcG9uc2UuaGVhZGVycyAmJiByZXNwb25zZS5oZWFkZXJzWydjb250ZW50LXR5cGUnXSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L3JlcXVpcmUtYXdhaXRcbiAgYXN5bmMgcGFyc2VSZXNwb25zZUJvZHkocmVzcG9uc2U6IEh0dHBSZXNwb25zZSkge1xuICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gdGhpcy5nZXRSZXNwb25zZUNvbnRlbnRUeXBlKHJlc3BvbnNlKSB8fCAnJztcbiAgICBjb25zdCBwYXJzZUJvZHkgPSAvXih0ZXh0fGFwcGxpY2F0aW9uKVxcL3htbCg7fCQpLy50ZXN0KGNvbnRlbnRUeXBlKVxuICAgICAgPyBwYXJzZVhNTFxuICAgICAgOiAvXmFwcGxpY2F0aW9uXFwvanNvbig7fCQpLy50ZXN0KGNvbnRlbnRUeXBlKVxuICAgICAgPyBwYXJzZUpTT05cbiAgICAgIDogL150ZXh0XFwvY3N2KDt8JCkvLnRlc3QoY29udGVudFR5cGUpXG4gICAgICA/IHBhcnNlQ1NWXG4gICAgICA6IHBhcnNlVGV4dDtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHBhcnNlQm9keShyZXNwb25zZS5ib2R5KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvLyBUT0RPKG5leHQgbWFqb3IpOiB3ZSBjb3VsZCB0aHJvdyBhIG5ldyBcImludmFsaWQgcmVzcG9uc2UgYm9keVwiIGVycm9yIGluc3RlYWQuXG4gICAgICB0aGlzLl9sb2dnZXIuZGVidWcoXG4gICAgICAgIGBGYWlsZWQgdG8gcGFyc2UgYm9keSBvZiBjb250ZW50LXR5cGU6ICR7Y29udGVudFR5cGV9LiBFcnJvcjogJHtcbiAgICAgICAgICAoZSBhcyBFcnJvcikubWVzc2FnZVxuICAgICAgICB9YCxcbiAgICAgICk7XG4gICAgICByZXR1cm4gcmVzcG9uc2UuYm9keTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0IHJlc3BvbnNlIGJvZHlcbiAgICogQHByb3RlY3RlZFxuICAgKi9cbiAgYXN5bmMgZ2V0UmVzcG9uc2VCb2R5KHJlc3BvbnNlOiBIdHRwUmVzcG9uc2UpIHtcbiAgICBpZiAocmVzcG9uc2Uuc3RhdHVzQ29kZSA9PT0gMjA0KSB7XG4gICAgICAvLyBObyBDb250ZW50XG4gICAgICByZXR1cm4gdGhpcy5fbm9Db250ZW50UmVzcG9uc2U7XG4gICAgfVxuICAgIGNvbnN0IGJvZHkgPSBhd2FpdCB0aGlzLnBhcnNlUmVzcG9uc2VCb2R5KHJlc3BvbnNlKTtcbiAgICBsZXQgZXJyO1xuICAgIGlmICh0aGlzLmhhc0Vycm9ySW5SZXNwb25zZUJvZHkoYm9keSkpIHtcbiAgICAgIGVyciA9IGF3YWl0IHRoaXMuZ2V0RXJyb3IocmVzcG9uc2UsIGJvZHkpO1xuICAgICAgdGhyb3cgZXJyO1xuICAgIH1cbiAgICBpZiAocmVzcG9uc2Uuc3RhdHVzQ29kZSA9PT0gMzAwKSB7XG4gICAgICAvLyBNdWx0aXBsZSBDaG9pY2VzXG4gICAgICB0aHJvdyBuZXcgSHR0cEFwaUVycm9yKFxuICAgICAgICAnTXVsdGlwbGUgcmVjb3JkcyBmb3VuZCcsXG4gICAgICAgICdNVUxUSVBMRV9DSE9JQ0VTJyxcbiAgICAgICAgYm9keSxcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBib2R5O1xuICB9XG5cbiAgLyoqXG4gICAqIERldGVjdCBzZXNzaW9uIGV4cGlyeVxuICAgKiBAcHJvdGVjdGVkXG4gICAqL1xuICBpc1Nlc3Npb25FeHBpcmVkKHJlc3BvbnNlOiBIdHRwUmVzcG9uc2UpIHtcbiAgICAvLyBUT0RPOlxuICAgIC8vIFRoZSBjb25uZWN0ZWQgYXBwIG1zZyBvbmx5IGFwcGxpZXMgdG8gQWdlbnQgQVBJIHJlcXVlc3RzLCB3ZSBzaG91bGQgbW92ZSB0aGlzIHRvIGEgc2VwYXJhdGUgU0ZBUC9BZ2VudCBBUEkgY2xhc3MgbGF0ZXIuXG4gICAgcmV0dXJuIChcbiAgICAgIHJlc3BvbnNlLnN0YXR1c0NvZGUgPT09IDQwMSAmJlxuICAgICAgIXJlc3BvbnNlLmJvZHkuaW5jbHVkZXMoJ0Nvbm5lY3RlZCBhcHAgaXMgbm90IGF0dGFjaGVkIHRvIEFnZW50JylcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIERldGVjdCBlcnJvciByZXNwb25zZVxuICAgKiBAcHJvdGVjdGVkXG4gICAqL1xuICBpc0Vycm9yUmVzcG9uc2UocmVzcG9uc2U6IEh0dHBSZXNwb25zZSkge1xuICAgIHJldHVybiByZXNwb25zZS5zdGF0dXNDb2RlID49IDQwMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlY3QgZXJyb3IgaW4gcmVzcG9uc2UgYm9keVxuICAgKiBAcHJvdGVjdGVkXG4gICAqL1xuICBoYXNFcnJvckluUmVzcG9uc2VCb2R5KF9ib2R5OiBPcHRpb25hbDxzdHJpbmc+KSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIFBhcnNpbmcgZXJyb3IgbWVzc2FnZSBpbiByZXNwb25zZVxuICAgKiBAcHJvdGVjdGVkXG4gICAqL1xuICBwYXJzZUVycm9yKGJvZHk6IGFueSkge1xuICAgIGNvbnN0IGVycm9ycyA9IGJvZHk7XG5cbiAgICAvLyBYTUwgcmVzcG9uc2VcbiAgICBpZiAoZXJyb3JzLkVycm9ycykge1xuICAgICAgcmV0dXJuIGVycm9ycy5FcnJvcnMuRXJyb3I7XG4gICAgfVxuXG4gICAgcmV0dXJuIGVycm9ycztcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgZXJyb3IgbWVzc2FnZSBpbiByZXNwb25zZVxuICAgKiBAcHJvdGVjdGVkXG4gICAqL1xuICBhc3luYyBnZXRFcnJvcihyZXNwb25zZTogSHR0cFJlc3BvbnNlLCBib2R5PzogYW55KTogUHJvbWlzZTxFcnJvcj4ge1xuICAgIGxldCBlcnJvcjtcbiAgICB0cnkge1xuICAgICAgZXJyb3IgPSB0aGlzLnBhcnNlRXJyb3IoYm9keSB8fCAoYXdhaXQgdGhpcy5wYXJzZVJlc3BvbnNlQm9keShyZXNwb25zZSkpKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZSBuby1lbXB0eVxuICAgIH1cblxuICAgIGlmIChBcnJheS5pc0FycmF5KGVycm9yKSkge1xuICAgICAgaWYgKGVycm9yLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICBlcnJvciA9IGVycm9yWzBdO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIG5ldyBIdHRwQXBpRXJyb3IoXG4gICAgICAgICAgYE11bHRpcGxlIGVycm9ycyByZXR1cm5lZC5cbiAgQ2hlY2sgXFxgZXJyb3IuZGF0YVxcYCBmb3IgdGhlIGVycm9yIGRldGFpbHNgLFxuICAgICAgICAgICdNVUxUSVBMRV9BUElfRVJST1JTJyxcbiAgICAgICAgICBlcnJvcixcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBlcnJvciA9XG4gICAgICB0eXBlb2YgZXJyb3IgPT09ICdvYmplY3QnICYmXG4gICAgICBlcnJvciAhPT0gbnVsbCAmJlxuICAgICAgdHlwZW9mIGVycm9yLm1lc3NhZ2UgPT09ICdzdHJpbmcnXG4gICAgICAgID8gZXJyb3JcbiAgICAgICAgOiB7XG4gICAgICAgICAgICBlcnJvckNvZGU6IGBFUlJPUl9IVFRQXyR7cmVzcG9uc2Uuc3RhdHVzQ29kZX1gLFxuICAgICAgICAgICAgbWVzc2FnZTogcmVzcG9uc2UuYm9keSxcbiAgICAgICAgICB9O1xuXG4gICAgaWYgKHJlc3BvbnNlLmhlYWRlcnNbJ2NvbnRlbnQtdHlwZSddID09PSAndGV4dC9odG1sJykge1xuICAgICAgdGhpcy5fbG9nZ2VyLmRlYnVnKGBodG1sIHJlc3BvbnNlLmJvZHk6ICR7cmVzcG9uc2UuYm9keX1gKTtcbiAgICAgIHJldHVybiBuZXcgSHR0cEFwaUVycm9yKFxuICAgICAgICBgSFRUUCByZXNwb25zZSBjb250YWlucyBodG1sIGNvbnRlbnQuXG5DaGVjayB0aGF0IHRoZSBvcmcgZXhpc3RzIGFuZCBjYW4gYmUgcmVhY2hlZC5cblNlZSBcXGBlcnJvci5kYXRhXFxgIGZvciB0aGUgZnVsbCBodG1sIHJlc3BvbnNlLmAsXG4gICAgICAgIGVycm9yLmVycm9yQ29kZSxcbiAgICAgICAgZXJyb3IubWVzc2FnZSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGVycm9yIGluc3RhbmNlb2YgSHR0cEFwaUVycm9yXG4gICAgICA/IGVycm9yXG4gICAgICA6IG5ldyBIdHRwQXBpRXJyb3IoZXJyb3IubWVzc2FnZSwgZXJyb3IuZXJyb3JDb2RlLCBlcnJvcik7XG4gIH1cbn1cblxuLyoqXG4gKlxuICovXG5jbGFzcyBIdHRwQXBpRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIC8qKlxuICAgKiBUaGlzIGNvbnRhaW5zIGVycm9yLXNwZWNpZmljIGRldGFpbHMsIHVzdWFsbHkgcmV0dXJuZWQgZnJvbSB0aGUgQVBJLlxuICAgKi9cbiAgZGF0YTogYW55O1xuICBlcnJvckNvZGU6IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcihtZXNzYWdlOiBzdHJpbmcsIGVycm9yQ29kZT86IHN0cmluZyB8IHVuZGVmaW5lZCwgZGF0YT86IGFueSkge1xuICAgIHN1cGVyKG1lc3NhZ2UpO1xuICAgIHRoaXMubmFtZSA9IGVycm9yQ29kZSB8fCB0aGlzLm5hbWU7XG4gICAgdGhpcy5lcnJvckNvZGUgPSB0aGlzLm5hbWU7XG4gICAgdGhpcy5kYXRhID0gZGF0YTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGlzIHdpbGwgYmUgcmVtb3ZlZCBpbiB0aGUgbmV4dCBtYWpvciAodjQpXG4gICAqXG4gICAqIEBkZXByZWNhdGVkIHVzZSBgZXJyb3IuZGF0YWAgaW5zdGVhZFxuICAgKi9cbiAgZ2V0IGNvbnRlbnQoKSB7XG4gICAgcmV0dXJuIHRoaXMuZGF0YTtcbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBIdHRwQXBpO1xuZXhwb3J0IGNvbnN0IGlzQnJvd3NlciA9ICd3aW5kb3cnIGluIGdsb2JhbFRoaXMgfHwgJ3NlbGYnIGluIGdsb2JhbFRoaXM7XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBO0FBQ0E7QUFDQTtBQUNBLFNBQVNBLFlBQVksUUFBUSxRQUFRO0FBQ3JDLE9BQU9DLE1BQU0sTUFBTSxRQUFRO0FBQzNCLFNBQWlCQyxTQUFTLFFBQVEsZUFBZTtBQUNqRCxTQUFTQyxhQUFhLFFBQVEsZ0JBQWdCO0FBRzlDLFNBQVNDLFFBQVEsUUFBUSxPQUFPO0FBUWhDLFNBQVNDLGdCQUFnQixRQUFRLGVBQWU7QUFDaEQs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
|