@rudderstack/integrations-lib
Version:
A comprehensive TypeScript library providing shared utilities, SDKs, and tools for RudderStack integrations and destinations.
281 lines • 36.2 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AxiosClient = void 0;
/* eslint-disable require-await */
const axios_1 = __importDefault(require("axios"));
const http_1 = __importDefault(require("http"));
const https_1 = __importDefault(require("https"));
const constants_1 = require("../../constants");
const utils_1 = require("../../utils");
// Allowed labels for timing metrics
const TIMING_METRIC_LABELS = [
'feature',
'destType',
'endpointPath',
'requestMethod',
'module',
'workspaceId',
'destinationId',
'implementation',
'sourceId',
];
// Allowed labels for counter metrics
const COUNTER_METRIC_LABELS = [
'feature',
'destType',
'endpointPath',
'success',
'statusCode',
'requestMethod',
'module',
'workspaceId',
'destinationId',
'implementation',
'sourceId',
];
/**
* Filters labels to only include allowed keys
* @param allLabels - The complete set of labels
* @param allowedLabels - Array of allowed label keys
* @returns Filtered labels object
*/
function filterMetricLabels(allLabels, allowedLabels) {
return allowedLabels.reduce((filteredLabels, key) => {
if (allLabels[key] !== undefined) {
return { ...filteredLabels, [key]: allLabels[key] };
}
return filteredLabels;
}, {});
}
/**
* A wrapper around axios to make http requests
*
* @class AxiosClient
* @classdesc
* The `AxiosClient` class is a wrapper around the axios library that provides a simplified interface for making HTTP requests. It handles various types of errors and provides a consistent response format.
*
* @param {AxiosRequestConfig} options - The default options for the http client
*
* @example
* const axiosClient = new AxiosClient({ timeout: 1000 * 10 });
* const response = await axiosClient.post("https://example.com", { foo: "bar" });
* if (response.type === "success") {
* console.log(response.statusCode);
* console.log(response.responseBody);
* } else if (response.type === "application-error") {
* console.log(response.statusCode);
* console.log(response.message);
* console.log(response.responseBody);
* } else if (response.type === "client-error") {
* console.log(response.statusCode);
* console.log(response.message);
* }
*/
class AxiosClient {
constructor(options, observabilityConfig) {
const defaultOptions = {
timeout: 1000 * 10,
// `withCredentials` indicates whether or not cross-site Access-Control requests should be made using credentials
withCredentials: false,
// `responseEncoding` indicates encoding to use for decoding responses (Node.js only),
responseEncoding: 'utf8',
// `maxBodyLength` (Node only option) defines the max size of the http request content in bytes allowed,
maxBodyLength: 1000 * 1000 * 10,
// `maxRedirects` defines the maximum number of redirects to follow in node.js,
maxRedirects: 5,
// `httpAgent` and `httpsAgent` define a custom agent to be used when performing http
httpAgent: new http_1.default.Agent({ keepAlive: true }),
// and https requests, respectively, in node.js. This allows options to be added like `keepAlive` that are not enabled by default.
httpsAgent: new https_1.default.Agent({ keepAlive: true }),
};
this.options = { ...defaultOptions, ...options };
this.instance = axios_1.default.create(this.options);
// Merge with default config to eliminate null checks
const defaultObservabilityConfig = {
logger: undefined,
statsClient: undefined,
defaultStatTags: {},
};
this.observabilityConfig = { ...defaultObservabilityConfig, ...observabilityConfig };
}
async makeRequest(config, responseParser) {
const startTimestamp = new Date();
// Extract metadata for logging/metrics
const method = config.method?.toUpperCase() || 'UNKNOWN';
const url = config.url || 'unknown';
const body = config.data || undefined;
const statTags = {
...this.observabilityConfig.defaultStatTags,
requestMethod: method,
endpointPath: 'default',
...config.statTags,
};
const metadataMetricTags = {
...(this.observabilityConfig.defaultStatTags?.metadata || {}),
...(config.statTags?.metadata || {}),
};
// Optional request logging
const requestLogParams = {
requestDetails: {
method: method || 'undefined',
url: url || 'undefined',
body: body || 'undefined',
},
metadata: statTags.metadata || {},
};
this.observabilityConfig.logger?.requestLog(`[HTTP] ${method} ${url} request`, requestLogParams);
try {
const requestConfig = config;
const response = await this.instance.request(requestConfig);
const { status, data, headers } = response;
// Optional response logging
const responseLogParams = {
responseDetails: {
status: status || 0,
body: data || 'undefined',
headers: headers || 'undefined',
},
metadata: statTags.metadata || {},
};
this.observabilityConfig.logger?.responseLog(`[HTTP] ${method} ${url} response`, responseLogParams);
// Optional success metrics
const allLabels = { ...metadataMetricTags, ...statTags, statusCode: status };
const timingLabels = filterMetricLabels(allLabels, TIMING_METRIC_LABELS);
this.observabilityConfig.statsClient?.timing('outgoing_request_latency', startTimestamp, timingLabels);
const counterLabels = filterMetricLabels(allLabels, COUNTER_METRIC_LABELS);
this.observabilityConfig.statsClient?.counter('outgoing_request_count', 1, counterLabels);
if (responseParser) {
try {
const parsedData = responseParser(data);
return {
type: 'success',
statusCode: status,
responseBody: parsedData,
headers,
};
}
catch (error) {
const unknownError = error;
return {
type: 'client-error',
// @ts-expect-error: Error has status
statusCode: unknownError.status || 500,
message: `Failed to parse response data: ${unknownError.message}`,
};
}
}
return { type: 'success', statusCode: status, responseBody: data, headers };
}
catch (error) {
// Determine status code for error metrics
let errorStatusCode = 500; // Default to 500 for network/unknown errors
if (axios_1.default.isAxiosError(error)) {
const axiosError = error;
if (axiosError.response) {
errorStatusCode = axiosError.response.status;
}
}
// Optional error logging
this.observabilityConfig.logger?.error?.(`[HTTP] ${method} ${url} error`, {
error: error.message,
statTags: { ...statTags, statusCode: errorStatusCode },
});
// Optional error metrics
const allErrorLabels = { ...metadataMetricTags, ...statTags, statusCode: errorStatusCode };
const timingLabels = filterMetricLabels(allErrorLabels, TIMING_METRIC_LABELS);
this.observabilityConfig.statsClient?.timing('outgoing_request_latency', startTimestamp, timingLabels);
const counterLabels = filterMetricLabels(allErrorLabels, COUNTER_METRIC_LABELS);
this.observabilityConfig.statsClient?.counter('outgoing_request_count', 1, counterLabels);
if (axios_1.default.isAxiosError(error)) {
const axiosError = error;
if (axiosError.response) {
const { response } = axiosError;
return {
type: 'application-error',
statusCode: response.status,
message: response.statusText,
responseBody: response.data,
headers: response.headers,
};
}
if (axiosError.code) {
const resp = constants_1.NETWORK_STATUS_ERR_MAP[axiosError.code];
if (!resp) {
return {
type: 'client-error',
statusCode: 500,
message: `Unknown Error:${axiosError.message}`,
};
}
return {
type: 'client-error',
statusCode: resp.status,
message: resp.message,
};
}
}
const unknownError = error;
const status = 500;
const message = unknownError.message || 'Unknown Error';
return { type: 'client-error', statusCode: status, message };
}
}
async get(url, options, responseParser) {
let config = {
method: 'get',
url,
};
if ((0, utils_1.isNotEmpty)(options)) {
config = { ...config, ...options };
}
return this.makeRequest(config, responseParser);
}
async post(url, data, options, responseParser) {
let config = {
method: 'post',
url,
data,
};
if ((0, utils_1.isNotEmpty)(options)) {
config = { ...config, ...options };
}
return this.makeRequest(config, responseParser);
}
async put(url, data, options, responseParser) {
let config = {
method: 'put',
url,
data,
};
if ((0, utils_1.isNotEmpty)(options)) {
config = { ...config, ...options };
}
return this.makeRequest(config, responseParser);
}
async patch(url, data, options, responseParser) {
let config = {
method: 'patch',
url,
data,
};
if ((0, utils_1.isNotEmpty)(options)) {
config = { ...config, ...options };
}
return this.makeRequest(config, responseParser);
}
async delete(url, options, responseParser) {
let config = {
method: 'delete',
url,
};
if ((0, utils_1.isNotEmpty)(options)) {
config = { ...config, ...options };
}
return this.makeRequest(config, responseParser);
}
}
exports.AxiosClient = AxiosClient;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXhpb3NfY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL25ldHdvcmsvY2xpZW50cy9heGlvc19jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsa0NBQWtDO0FBQ2xDLGtEQUF5RDtBQUN6RCxnREFBd0I7QUFDeEIsa0RBQTBCO0FBQzFCLCtDQUF5RDtBQVd6RCx1Q0FBeUM7QUFFekMsb0NBQW9DO0FBQ3BDLE1BQU0sb0JBQW9CLEdBQUc7SUFDM0IsU0FBUztJQUNULFVBQVU7SUFDVixjQUFjO0lBQ2QsZUFBZTtJQUNmLFFBQVE7SUFDUixhQUFhO0lBQ2IsZUFBZTtJQUNmLGdCQUFnQjtJQUNoQixVQUFVO0NBQ1gsQ0FBQztBQUVGLHFDQUFxQztBQUNyQyxNQUFNLHFCQUFxQixHQUFHO0lBQzVCLFNBQVM7SUFDVCxVQUFVO0lBQ1YsY0FBYztJQUNkLFNBQVM7SUFDVCxZQUFZO0lBQ1osZUFBZTtJQUNmLFFBQVE7SUFDUixhQUFhO0lBQ2IsZUFBZTtJQUNmLGdCQUFnQjtJQUNoQixVQUFVO0NBQ1gsQ0FBQztBQUVGOzs7OztHQUtHO0FBQ0gsU0FBUyxrQkFBa0IsQ0FDekIsU0FBa0MsRUFDbEMsYUFBdUI7SUFFdkIsT0FBTyxhQUFhLENBQUMsTUFBTSxDQUFDLENBQUMsY0FBdUMsRUFBRSxHQUFXLEVBQUUsRUFBRTtRQUNuRixJQUFJLFNBQVMsQ0FBQyxHQUFHLENBQUMsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNqQyxPQUFPLEVBQUUsR0FBRyxjQUFjLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxTQUFTLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN0RCxDQUFDO1FBQ0QsT0FBTyxjQUFjLENBQUM7SUFDeEIsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0FBQ1QsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXVCRztBQUNILE1BQWEsV0FBVztJQU90QixZQUFZLE9BQXVCLEVBQUUsbUJBQW9EO1FBQ3ZGLE1BQU0sY0FBYyxHQUFHO1lBQ3JCLE9BQU8sRUFBRSxJQUFJLEdBQUcsRUFBRTtZQUNsQixpSEFBaUg7WUFDakgsZUFBZSxFQUFFLEtBQUs7WUFDdEIsc0ZBQXNGO1lBQ3RGLGdCQUFnQixFQUFFLE1BQU07WUFDeEIsd0dBQXdHO1lBQ3hHLGFBQWEsRUFBRSxJQUFJLEdBQUcsSUFBSSxHQUFHLEVBQUU7WUFDL0IsK0VBQStFO1lBQy9FLFlBQVksRUFBRSxDQUFDO1lBQ2YscUZBQXFGO1lBQ3JGLFNBQVMsRUFBRSxJQUFJLGNBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUM7WUFDOUMsa0lBQWtJO1lBQ2xJLFVBQVUsRUFBRSxJQUFJLGVBQUssQ0FBQyxLQUFLLENBQUMsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUM7U0FDakQsQ0FBQztRQUNGLElBQUksQ0FBQyxPQUFPLEdBQUcsRUFBRSxHQUFHLGNBQWMsRUFBRSxHQUFHLE9BQU8sRUFBRSxDQUFDO1FBQ2pELElBQUksQ0FBQyxRQUFRLEdBQUcsZUFBSyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFM0MscURBQXFEO1FBQ3JELE1BQU0sMEJBQTBCLEdBQW1DO1lBQ2pFLE1BQU0sRUFBRSxTQUFTO1lBQ2pCLFdBQVcsRUFBRSxTQUFTO1lBQ3RCLGVBQWUsRUFBRSxFQUFFO1NBQ3BCLENBQUM7UUFDRixJQUFJLENBQUMsbUJBQW1CLEdBQUcsRUFBRSxHQUFHLDBCQUEwQixFQUFFLEdBQUcsbUJBQW1CLEVBQUUsQ0FBQztJQUN2RixDQUFDO0lBRU8sS0FBSyxDQUFDLFdBQVcsQ0FDdkIsTUFBcUIsRUFDckIsY0FBa0M7UUFFbEMsTUFBTSxjQUFjLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUNsQyx1Q0FBdUM7UUFDdkMsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLE1BQU0sRUFBRSxXQUFXLEVBQUUsSUFBSSxTQUFTLENBQUM7UUFDekQsTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDLEdBQUcsSUFBSSxTQUFTLENBQUM7UUFDcEMsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksSUFBSSxTQUFTLENBQUM7UUFDdEMsTUFBTSxRQUFRLEdBQWE7WUFDekIsR0FBRyxJQUFJLENBQUMsbUJBQW1CLENBQUMsZUFBZTtZQUMzQyxhQUFhLEVBQUUsTUFBTTtZQUNyQixZQUFZLEVBQUUsU0FBUztZQUN2QixHQUFHLE1BQU0sQ0FBQyxRQUFRO1NBQ25CLENBQUM7UUFFRixNQUFNLGtCQUFrQixHQUFHO1lBQ3pCLEdBQUcsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsZUFBZSxFQUFFLFFBQVEsSUFBSSxFQUFFLENBQUM7WUFDN0QsR0FBRyxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsUUFBUSxJQUFJLEVBQUUsQ0FBQztTQUNyQyxDQUFDO1FBRUYsMkJBQTJCO1FBQzNCLE1BQU0sZ0JBQWdCLEdBQXFCO1lBQ3pDLGNBQWMsRUFBRTtnQkFDZCxNQUFNLEVBQUUsTUFBTSxJQUFJLFdBQVc7Z0JBQzdCLEdBQUcsRUFBRSxHQUFHLElBQUksV0FBVztnQkFDdkIsSUFBSSxFQUFFLElBQUksSUFBSSxXQUFXO2FBQzFCO1lBQ0QsUUFBUSxFQUFFLFFBQVEsQ0FBQyxRQUFRLElBQUksRUFBRTtTQUNsQyxDQUFDO1FBQ0YsSUFBSSxDQUFDLG1CQUFtQixDQUFDLE1BQU0sRUFBRSxVQUFVLENBQ3pDLFVBQVUsTUFBTSxJQUFJLEdBQUcsVUFBVSxFQUNqQyxnQkFBZ0IsQ0FDakIsQ0FBQztRQUVGLElBQUksQ0FBQztZQUNILE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQztZQUM3QixNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBQzVELE1BQU0sRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxHQUFHLFFBQVEsQ0FBQztZQUUzQyw0QkFBNEI7WUFDNUIsTUFBTSxpQkFBaUIsR0FBc0I7Z0JBQzNDLGVBQWUsRUFBRTtvQkFDZixNQUFNLEVBQUUsTUFBTSxJQUFJLENBQUM7b0JBQ25CLElBQUksRUFBRSxJQUFJLElBQUksV0FBVztvQkFDekIsT0FBTyxFQUFFLE9BQU8sSUFBSSxXQUFXO2lCQUNoQztnQkFDRCxRQUFRLEVBQUUsUUFBUSxDQUFDLFFBQVEsSUFBSSxFQUFFO2FBQ2xDLENBQUM7WUFDRixJQUFJLENBQUMsbUJBQW1CLENBQUMsTUFBTSxFQUFFLFdBQVcsQ0FDMUMsVUFBVSxNQUFNLElBQUksR0FBRyxXQUFXLEVBQ2xDLGlCQUFpQixDQUNsQixDQUFDO1lBRUYsMkJBQTJCO1lBQzNCLE1BQU0sU0FBUyxHQUFHLEVBQUUsR0FBRyxrQkFBa0IsRUFBRSxHQUFHLFFBQVEsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLENBQUM7WUFFN0UsTUFBTSxZQUFZLEdBQUcsa0JBQWtCLENBQUMsU0FBUyxFQUFFLG9CQUFvQixDQUFDLENBQUM7WUFDekUsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFdBQVcsRUFBRSxNQUFNLENBQzFDLDBCQUEwQixFQUMxQixjQUFjLEVBQ2QsWUFBWSxDQUNiLENBQUM7WUFFRixNQUFNLGFBQWEsR0FBRyxrQkFBa0IsQ0FBQyxTQUFTLEVBQUUscUJBQXFCLENBQUMsQ0FBQztZQUMzRSxJQUFJLENBQUMsbUJBQW1CLENBQUMsV0FBVyxFQUFFLE9BQU8sQ0FBQyx3QkFBd0IsRUFBRSxDQUFDLEVBQUUsYUFBYSxDQUFDLENBQUM7WUFFMUYsSUFBSSxjQUFjLEVBQUUsQ0FBQztnQkFDbkIsSUFBSSxDQUFDO29CQUNILE1BQU0sVUFBVSxHQUFHLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDeEMsT0FBTzt3QkFDTCxJQUFJLEVBQUUsU0FBUzt3QkFDZixVQUFVLEVBQUUsTUFBTTt3QkFDbEIsWUFBWSxFQUFFLFVBQVU7d0JBQ3hCLE9BQU87cUJBQ1IsQ0FBQztnQkFDSixDQUFDO2dCQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7b0JBQ2YsTUFBTSxZQUFZLEdBQUcsS0FBYyxDQUFDO29CQUNwQyxPQUFPO3dCQUNMLElBQUksRUFBRSxjQUFjO3dCQUNwQixxQ0FBcUM7d0JBQ3JDLFVBQVUsRUFBRSxZQUFZLENBQUMsTUFBTSxJQUFJLEdBQUc7d0JBQ3RDLE9BQU8sRUFBRSxrQ0FBa0MsWUFBWSxDQUFDLE9BQU8sRUFBRTtxQkFDbEUsQ0FBQztnQkFDSixDQUFDO1lBQ0gsQ0FBQztZQUNELE9BQU8sRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQztRQUM5RSxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLDBDQUEwQztZQUMxQyxJQUFJLGVBQWUsR0FBRyxHQUFHLENBQUMsQ0FBQyw0Q0FBNEM7WUFDdkUsSUFBSSxlQUFLLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQzlCLE1BQU0sVUFBVSxHQUFHLEtBQW1CLENBQUM7Z0JBQ3ZDLElBQUksVUFBVSxDQUFDLFFBQVEsRUFBRSxDQUFDO29CQUN4QixlQUFlLEdBQUcsVUFBVSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUM7Z0JBQy9DLENBQUM7WUFDSCxDQUFDO1lBRUQseUJBQXlCO1lBQ3pCLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLENBQUMsVUFBVSxNQUFNLElBQUksR0FBRyxRQUFRLEVBQUU7Z0JBQ3hFLEtBQUssRUFBRyxLQUFlLENBQUMsT0FBTztnQkFDL0IsUUFBUSxFQUFFLEVBQUUsR0FBRyxRQUFRLEVBQUUsVUFBVSxFQUFFLGVBQWUsRUFBRTthQUN2RCxDQUFDLENBQUM7WUFFSCx5QkFBeUI7WUFDekIsTUFBTSxjQUFjLEdBQUcsRUFBRSxHQUFHLGtCQUFrQixFQUFFLEdBQUcsUUFBUSxFQUFFLFVBQVUsRUFBRSxlQUFlLEVBQUUsQ0FBQztZQUUzRixNQUFNLFlBQVksR0FBRyxrQkFBa0IsQ0FBQyxjQUFjLEVBQUUsb0JBQW9CLENBQUMsQ0FBQztZQUM5RSxJQUFJLENBQUMsbUJBQW1CLENBQUMsV0FBVyxFQUFFLE1BQU0sQ0FDMUMsMEJBQTBCLEVBQzFCLGNBQWMsRUFDZCxZQUFZLENBQ2IsQ0FBQztZQUVGLE1BQU0sYUFBYSxHQUFHLGtCQUFrQixDQUFDLGNBQWMsRUFBRSxxQkFBcUIsQ0FBQyxDQUFDO1lBQ2hGLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxXQUFXLEVBQUUsT0FBTyxDQUFDLHdCQUF3QixFQUFFLENBQUMsRUFBRSxhQUFhLENBQUMsQ0FBQztZQUUxRixJQUFJLGVBQUssQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDOUIsTUFBTSxVQUFVLEdBQUcsS0FBbUIsQ0FBQztnQkFDdkMsSUFBSSxVQUFVLENBQUMsUUFBUSxFQUFFLENBQUM7b0JBQ3hCLE1BQU0sRUFBRSxRQUFRLEVBQUUsR0FBRyxVQUFVLENBQUM7b0JBQ2hDLE9BQU87d0JBQ0wsSUFBSSxFQUFFLG1CQUFtQjt3QkFDekIsVUFBVSxFQUFFLFFBQVEsQ0FBQyxNQUFNO3dCQUMzQixPQUFPLEVBQUUsUUFBUSxDQUFDLFVBQVU7d0JBQzVCLFlBQVksRUFBRSxRQUFRLENBQUMsSUFBSTt3QkFDM0IsT0FBTyxFQUFFLFFBQVEsQ0FBQyxPQUFPO3FCQUMxQixDQUFDO2dCQUNKLENBQUM7Z0JBQ0QsSUFBSSxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUM7b0JBQ3BCLE1BQU0sSUFBSSxHQUFHLGtDQUFzQixDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDckQsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO3dCQUNWLE9BQU87NEJBQ0wsSUFBSSxFQUFFLGNBQWM7NEJBQ3BCLFVBQVUsRUFBRSxHQUFHOzRCQUNmLE9BQU8sRUFBRSxpQkFBaUIsVUFBVSxDQUFDLE9BQU8sRUFBRTt5QkFDL0MsQ0FBQztvQkFDSixDQUFDO29CQUNELE9BQU87d0JBQ0wsSUFBSSxFQUFFLGNBQWM7d0JBQ3BCLFVBQVUsRUFBRSxJQUFJLENBQUMsTUFBTTt3QkFDdkIsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPO3FCQUN0QixDQUFDO2dCQUNKLENBQUM7WUFDSCxDQUFDO1lBRUQsTUFBTSxZQUFZLEdBQUcsS0FBYyxDQUFDO1lBQ3BDLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQztZQUNuQixNQUFNLE9BQU8sR0FBRyxZQUFZLENBQUMsT0FBTyxJQUFJLGVBQWUsQ0FBQztZQUV4RCxPQUFPLEVBQUUsSUFBSSxFQUFFLGNBQWMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxDQUFDO1FBQy9ELENBQUM7SUFDSCxDQUFDO0lBRU0sS0FBSyxDQUFDLEdBQUcsQ0FDZCxHQUFXLEVBQ1gsT0FBdUIsRUFDdkIsY0FBa0M7UUFFbEMsSUFBSSxNQUFNLEdBQWtCO1lBQzFCLE1BQU0sRUFBRSxLQUFLO1lBQ2IsR0FBRztTQUNKLENBQUM7UUFDRixJQUFJLElBQUEsa0JBQVUsRUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQ3hCLE1BQU0sR0FBRyxFQUFFLEdBQUcsTUFBTSxFQUFFLEdBQUcsT0FBTyxFQUFFLENBQUM7UUFDckMsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBSSxNQUFNLEVBQUUsY0FBYyxDQUFDLENBQUM7SUFDckQsQ0FBQztJQUVNLEtBQUssQ0FBQyxJQUFJLENBQ2YsR0FBVyxFQUNYLElBQWMsRUFDZCxPQUF1QixFQUN2QixjQUFrQztRQUVsQyxJQUFJLE1BQU0sR0FBa0I7WUFDMUIsTUFBTSxFQUFFLE1BQU07WUFDZCxHQUFHO1lBQ0gsSUFBSTtTQUNMLENBQUM7UUFDRixJQUFJLElBQUEsa0JBQVUsRUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQ3hCLE1BQU0sR0FBRyxFQUFFLEdBQUcsTUFBTSxFQUFFLEdBQUcsT0FBTyxFQUFFLENBQUM7UUFDckMsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBSSxNQUFNLEVBQUUsY0FBYyxDQUFDLENBQUM7SUFDckQsQ0FBQztJQUVNLEtBQUssQ0FBQyxHQUFHLENBQ2QsR0FBVyxFQUNYLElBQWMsRUFDZCxPQUF1QixFQUN2QixjQUFrQztRQUVsQyxJQUFJLE1BQU0sR0FBa0I7WUFDMUIsTUFBTSxFQUFFLEtBQUs7WUFDYixHQUFHO1lBQ0gsSUFBSTtTQUNMLENBQUM7UUFDRixJQUFJLElBQUEsa0JBQVUsRUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQ3hCLE1BQU0sR0FBRyxFQUFFLEdBQUcsTUFBTSxFQUFFLEdBQUcsT0FBTyxFQUFFLENBQUM7UUFDckMsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBSSxNQUFNLEVBQUUsY0FBYyxDQUFDLENBQUM7SUFDckQsQ0FBQztJQUVNLEtBQUssQ0FBQyxLQUFLLENBQ2hCLEdBQVcsRUFDWCxJQUFjLEVBQ2QsT0FBdUIsRUFDdkIsY0FBa0M7UUFFbEMsSUFBSSxNQUFNLEdBQWtCO1lBQzFCLE1BQU0sRUFBRSxPQUFPO1lBQ2YsR0FBRztZQUNILElBQUk7U0FDTCxDQUFDO1FBQ0YsSUFBSSxJQUFBLGtCQUFVLEVBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUN4QixNQUFNLEdBQUcsRUFBRSxHQUFHLE1BQU0sRUFBRSxHQUFHLE9BQU8sRUFBRSxDQUFDO1FBQ3JDLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUksTUFBTSxFQUFFLGNBQWMsQ0FBQyxDQUFDO0lBQ3JELENBQUM7SUFFTSxLQUFLLENBQUMsTUFBTSxDQUNqQixHQUFXLEVBQ1gsT0FBdUIsRUFDdkIsY0FBa0M7UUFFbEMsSUFBSSxNQUFNLEdBQWtCO1lBQzFCLE1BQU0sRUFBRSxRQUFRO1lBQ2hCLEdBQUc7U0FDSixDQUFDO1FBQ0YsSUFBSSxJQUFBLGtCQUFVLEVBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUN4QixNQUFNLEdBQUcsRUFBRSxHQUFHLE1BQU0sRUFBRSxHQUFHLE9BQU8sRUFBRSxDQUFDO1FBQ3JDLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUksTUFBTSxFQUFFLGNBQWMsQ0FBQyxDQUFDO0lBQ3JELENBQUM7Q0FHRjtBQTlRRCxrQ0E4UUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSByZXF1aXJlLWF3YWl0ICovXG5pbXBvcnQgYXhpb3MsIHsgQXhpb3NFcnJvciwgQXhpb3NJbnN0YW5jZSB9IGZyb20gJ2F4aW9zJztcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcbmltcG9ydCB7IE5FVFdPUktfU1RBVFVTX0VSUl9NQVAgfSBmcm9tICcuLi8uLi9jb25zdGFudHMnO1xuaW1wb3J0IHtcbiAgQXBpUmVzcG9uc2UsXG4gIEh0dHBDbGllbnQsXG4gIFJlc3BvbnNlUGFyc2VyLFxuICBBeGlvc0NsaWVudE9ic2VydmFiaWxpdHlDb25maWcsXG4gIFN0YXRUYWdzLFxuICBSZXF1ZXN0TG9nUGFyYW1zLFxuICBSZXNwb25zZUxvZ1BhcmFtcyxcbiAgUmVxdWVzdENvbmZpZyxcbn0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBpc05vdEVtcHR5IH0gZnJvbSAnLi4vLi4vdXRpbHMnO1xuXG4vLyBBbGxvd2VkIGxhYmVscyBmb3IgdGltaW5nIG1ldHJpY3NcbmNvbnN0IFRJTUlOR19NRVRSSUNfTEFCRUxTID0gW1xuICAnZmVhdHVyZScsXG4gICdkZXN0VHlwZScsXG4gICdlbmRwb2ludFBhdGgnLFxuICAncmVxdWVzdE1ldGhvZCcsXG4gICdtb2R1bGUnLFxuICAnd29ya3NwYWNlSWQnLFxuICAnZGVzdGluYXRpb25JZCcsXG4gICdpbXBsZW1lbnRhdGlvbicsXG4gICdzb3VyY2VJZCcsXG5dO1xuXG4vLyBBbGxvd2VkIGxhYmVscyBmb3IgY291bnRlciBtZXRyaWNzXG5jb25zdCBDT1VOVEVSX01FVFJJQ19MQUJFTFMgPSBbXG4gICdmZWF0dXJlJyxcbiAgJ2Rlc3RUeXBlJyxcbiAgJ2VuZHBvaW50UGF0aCcsXG4gICdzdWNjZXNzJyxcbiAgJ3N0YXR1c0NvZGUnLFxuICAncmVxdWVzdE1ldGhvZCcsXG4gICdtb2R1bGUnLFxuICAnd29ya3NwYWNlSWQnLFxuICAnZGVzdGluYXRpb25JZCcsXG4gICdpbXBsZW1lbnRhdGlvbicsXG4gICdzb3VyY2VJZCcsXG5dO1xuXG4vKipcbiAqIEZpbHRlcnMgbGFiZWxzIHRvIG9ubHkgaW5jbHVkZSBhbGxvd2VkIGtleXNcbiAqIEBwYXJhbSBhbGxMYWJlbHMgLSBUaGUgY29tcGxldGUgc2V0IG9mIGxhYmVsc1xuICogQHBhcmFtIGFsbG93ZWRMYWJlbHMgLSBBcnJheSBvZiBhbGxvd2VkIGxhYmVsIGtleXNcbiAqIEByZXR1cm5zIEZpbHRlcmVkIGxhYmVscyBvYmplY3RcbiAqL1xuZnVuY3Rpb24gZmlsdGVyTWV0cmljTGFiZWxzKFxuICBhbGxMYWJlbHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICBhbGxvd2VkTGFiZWxzOiBzdHJpbmdbXSxcbik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgcmV0dXJuIGFsbG93ZWRMYWJlbHMucmVkdWNlKChmaWx0ZXJlZExhYmVsczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIGtleTogc3RyaW5nKSA9PiB7XG4gICAgaWYgKGFsbExhYmVsc1trZXldICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiB7IC4uLmZpbHRlcmVkTGFiZWxzLCBba2V5XTogYWxsTGFiZWxzW2tleV0gfTtcbiAgICB9XG4gICAgcmV0dXJuIGZpbHRlcmVkTGFiZWxzO1xuICB9LCB7fSk7XG59XG5cbi8qKlxuICogQSB3cmFwcGVyIGFyb3VuZCBheGlvcyB0byBtYWtlIGh0dHAgcmVxdWVzdHNcbiAqXG4gKiBAY2xhc3MgQXhpb3NDbGllbnRcbiAqIEBjbGFzc2Rlc2NcbiAqIFRoZSBgQXhpb3NDbGllbnRgIGNsYXNzIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIGF4aW9zIGxpYnJhcnkgdGhhdCBwcm92aWRlcyBhIHNpbXBsaWZpZWQgaW50ZXJmYWNlIGZvciBtYWtpbmcgSFRUUCByZXF1ZXN0cy4gSXQgaGFuZGxlcyB2YXJpb3VzIHR5cGVzIG9mIGVycm9ycyBhbmQgcHJvdmlkZXMgYSBjb25zaXN0ZW50IHJlc3BvbnNlIGZvcm1hdC5cbiAqXG4gKiBAcGFyYW0ge0F4aW9zUmVxdWVzdENvbmZpZ30gb3B0aW9ucyAtIFRoZSBkZWZhdWx0IG9wdGlvbnMgZm9yIHRoZSBodHRwIGNsaWVudFxuICpcbiAqIEBleGFtcGxlXG4gKiBjb25zdCBheGlvc0NsaWVudCA9IG5ldyBBeGlvc0NsaWVudCh7IHRpbWVvdXQ6IDEwMDAgKiAxMCB9KTtcbiAqIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgYXhpb3NDbGllbnQucG9zdChcImh0dHBzOi8vZXhhbXBsZS5jb21cIiwgeyBmb286IFwiYmFyXCIgfSk7XG4gKiBpZiAocmVzcG9uc2UudHlwZSA9PT0gXCJzdWNjZXNzXCIpIHtcbiAqICAgY29uc29sZS5sb2cocmVzcG9uc2Uuc3RhdHVzQ29kZSk7XG4gKiAgIGNvbnNvbGUubG9nKHJlc3BvbnNlLnJlc3BvbnNlQm9keSk7XG4gKiB9IGVsc2UgaWYgKHJlc3BvbnNlLnR5cGUgPT09IFwiYXBwbGljYXRpb24tZXJyb3JcIikge1xuICogICBjb25zb2xlLmxvZyhyZXNwb25zZS5zdGF0dXNDb2RlKTtcbiAqICAgY29uc29sZS5sb2cocmVzcG9uc2UubWVzc2FnZSk7XG4gKiAgIGNvbnNvbGUubG9nKHJlc3BvbnNlLnJlc3BvbnNlQm9keSk7XG4gKiB9IGVsc2UgaWYgKHJlc3BvbnNlLnR5cGUgPT09IFwiY2xpZW50LWVycm9yXCIpIHtcbiAqICAgY29uc29sZS5sb2cocmVzcG9uc2Uuc3RhdHVzQ29kZSk7XG4gKiAgIGNvbnNvbGUubG9nKHJlc3BvbnNlLm1lc3NhZ2UpO1xuICogfVxuICovXG5leHBvcnQgY2xhc3MgQXhpb3NDbGllbnQgaW1wbGVtZW50cyBIdHRwQ2xpZW50IHtcbiAgcHJpdmF0ZSBvcHRpb25zOiBSZXF1ZXN0Q29uZmlnO1xuXG4gIHByaXZhdGUgaW5zdGFuY2U6IEF4aW9zSW5zdGFuY2U7XG5cbiAgcHJpdmF0ZSBvYnNlcnZhYmlsaXR5Q29uZmlnOiBBeGlvc0NsaWVudE9ic2VydmFiaWxpdHlDb25maWc7XG5cbiAgY29uc3RydWN0b3Iob3B0aW9ucz86IFJlcXVlc3RDb25maWcsIG9ic2VydmFiaWxpdHlDb25maWc/OiBBeGlvc0NsaWVudE9ic2VydmFiaWxpdHlDb25maWcpIHtcbiAgICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IHtcbiAgICAgIHRpbWVvdXQ6IDEwMDAgKiAxMCxcbiAgICAgIC8vIGB3aXRoQ3JlZGVudGlhbHNgIGluZGljYXRlcyB3aGV0aGVyIG9yIG5vdCBjcm9zcy1zaXRlIEFjY2Vzcy1Db250cm9sIHJlcXVlc3RzIHNob3VsZCBiZSBtYWRlIHVzaW5nIGNyZWRlbnRpYWxzXG4gICAgICB3aXRoQ3JlZGVudGlhbHM6IGZhbHNlLFxuICAgICAgLy8gYHJlc3BvbnNlRW5jb2RpbmdgIGluZGljYXRlcyBlbmNvZGluZyB0byB1c2UgZm9yIGRlY29kaW5nIHJlc3BvbnNlcyAoTm9kZS5qcyBvbmx5KSxcbiAgICAgIHJlc3BvbnNlRW5jb2Rpbmc6ICd1dGY4JyxcbiAgICAgIC8vIGBtYXhCb2R5TGVuZ3RoYCAoTm9kZSBvbmx5IG9wdGlvbikgZGVmaW5lcyB0aGUgbWF4IHNpemUgb2YgdGhlIGh0dHAgcmVxdWVzdCBjb250ZW50IGluIGJ5dGVzIGFsbG93ZWQsXG4gICAgICBtYXhCb2R5TGVuZ3RoOiAxMDAwICogMTAwMCAqIDEwLFxuICAgICAgLy8gYG1heFJlZGlyZWN0c2AgZGVmaW5lcyB0aGUgbWF4aW11bSBudW1iZXIgb2YgcmVkaXJlY3RzIHRvIGZvbGxvdyBpbiBub2RlLmpzLFxuICAgICAgbWF4UmVkaXJlY3RzOiA1LFxuICAgICAgLy8gYGh0dHBBZ2VudGAgYW5kIGBodHRwc0FnZW50YCBkZWZpbmUgYSBjdXN0b20gYWdlbnQgdG8gYmUgdXNlZCB3aGVuIHBlcmZvcm1pbmcgaHR0cFxuICAgICAgaHR0cEFnZW50OiBuZXcgaHR0cC5BZ2VudCh7IGtlZXBBbGl2ZTogdHJ1ZSB9KSxcbiAgICAgIC8vIGFuZCBodHRwcyByZXF1ZXN0cywgcmVzcGVjdGl2ZWx5LCBpbiBub2RlLmpzLiBUaGlzIGFsbG93cyBvcHRpb25zIHRvIGJlIGFkZGVkIGxpa2UgYGtlZXBBbGl2ZWAgdGhhdCBhcmUgbm90IGVuYWJsZWQgYnkgZGVmYXVsdC5cbiAgICAgIGh0dHBzQWdlbnQ6IG5ldyBodHRwcy5BZ2VudCh7IGtlZXBBbGl2ZTogdHJ1ZSB9KSxcbiAgICB9O1xuICAgIHRoaXMub3B0aW9ucyA9IHsgLi4uZGVmYXVsdE9wdGlvbnMsIC4uLm9wdGlvbnMgfTtcbiAgICB0aGlzLmluc3RhbmNlID0gYXhpb3MuY3JlYXRlKHRoaXMub3B0aW9ucyk7XG5cbiAgICAvLyBNZXJnZSB3aXRoIGRlZmF1bHQgY29uZmlnIHRvIGVsaW1pbmF0ZSBudWxsIGNoZWNrc1xuICAgIGNvbnN0IGRlZmF1bHRPYnNlcnZhYmlsaXR5Q29uZmlnOiBBeGlvc0NsaWVudE9ic2VydmFiaWxpdHlDb25maWcgPSB7XG4gICAgICBsb2dnZXI6IHVuZGVmaW5lZCxcbiAgICAgIHN0YXRzQ2xpZW50OiB1bmRlZmluZWQsXG4gICAgICBkZWZhdWx0U3RhdFRhZ3M6IHt9LFxuICAgIH07XG4gICAgdGhpcy5vYnNlcnZhYmlsaXR5Q29uZmlnID0geyAuLi5kZWZhdWx0T2JzZXJ2YWJpbGl0eUNvbmZpZywgLi4ub2JzZXJ2YWJpbGl0eUNvbmZpZyB9O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBtYWtlUmVxdWVzdDxUPihcbiAgICBjb25maWc6IFJlcXVlc3RDb25maWcsXG4gICAgcmVzcG9uc2VQYXJzZXI/OiBSZXNwb25zZVBhcnNlcjxUPixcbiAgKTogUHJvbWlzZTxBcGlSZXNwb25zZTxUPj4ge1xuICAgIGNvbnN0IHN0YXJ0VGltZXN0YW1wID0gbmV3IERhdGUoKTtcbiAgICAvLyBFeHRyYWN0IG1ldGFkYXRhIGZvciBsb2dnaW5nL21ldHJpY3NcbiAgICBjb25zdCBtZXRob2QgPSBjb25maWcubWV0aG9kPy50b1VwcGVyQ2FzZSgpIHx8ICdVTktOT1dOJztcbiAgICBjb25zdCB1cmwgPSBjb25maWcudXJsIHx8ICd1bmtub3duJztcbiAgICBjb25zdCBib2R5ID0gY29uZmlnLmRhdGEgfHwgdW5kZWZpbmVkO1xuICAgIGNvbnN0IHN0YXRUYWdzOiBTdGF0VGFncyA9IHtcbiAgICAgIC4uLnRoaXMub2JzZXJ2YWJpbGl0eUNvbmZpZy5kZWZhdWx0U3RhdFRhZ3MsXG4gICAgICByZXF1ZXN0TWV0aG9kOiBtZXRob2QsXG4gICAgICBlbmRwb2ludFBhdGg6ICdkZWZhdWx0JyxcbiAgICAgIC4uLmNvbmZpZy5zdGF0VGFncyxcbiAgICB9O1xuXG4gICAgY29uc3QgbWV0YWRhdGFNZXRyaWNUYWdzID0ge1xuICAgICAgLi4uKHRoaXMub2JzZXJ2YWJpbGl0eUNvbmZpZy5kZWZhdWx0U3RhdFRhZ3M/Lm1ldGFkYXRhIHx8IHt9KSxcbiAgICAgIC4uLihjb25maWcuc3RhdFRhZ3M/Lm1ldGFkYXRhIHx8IHt9KSxcbiAgICB9O1xuXG4gICAgLy8gT3B0aW9uYWwgcmVxdWVzdCBsb2dnaW5nXG4gICAgY29uc3QgcmVxdWVzdExvZ1BhcmFtczogUmVxdWVzdExvZ1BhcmFtcyA9IHtcbiAgICAgIHJlcXVlc3REZXRhaWxzOiB7XG4gICAgICAgIG1ldGhvZDogbWV0aG9kIHx8ICd1bmRlZmluZWQnLFxuICAgICAgICB1cmw6IHVybCB8fCAndW5kZWZpbmVkJyxcbiAgICAgICAgYm9keTogYm9keSB8fCAndW5kZWZpbmVkJyxcbiAgICAgIH0sXG4gICAgICBtZXRhZGF0YTogc3RhdFRhZ3MubWV0YWRhdGEgfHwge30sXG4gICAgfTtcbiAgICB0aGlzLm9ic2VydmFiaWxpdHlDb25maWcubG9nZ2VyPy5yZXF1ZXN0TG9nKFxuICAgICAgYFtIVFRQXSAke21ldGhvZH0gJHt1cmx9IHJlcXVlc3RgLFxuICAgICAgcmVxdWVzdExvZ1BhcmFtcyxcbiAgICApO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlcXVlc3RDb25maWcgPSBjb25maWc7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuaW5zdGFuY2UucmVxdWVzdChyZXF1ZXN0Q29uZmlnKTtcbiAgICAgIGNvbnN0IHsgc3RhdHVzLCBkYXRhLCBoZWFkZXJzIH0gPSByZXNwb25zZTtcblxuICAgICAgLy8gT3B0aW9uYWwgcmVzcG9uc2UgbG9nZ2luZ1xuICAgICAgY29uc3QgcmVzcG9uc2VMb2dQYXJhbXM6IFJlc3BvbnNlTG9nUGFyYW1zID0ge1xuICAgICAgICByZXNwb25zZURldGFpbHM6IHtcbiAgICAgICAgICBzdGF0dXM6IHN0YXR1cyB8fCAwLFxuICAgICAgICAgIGJvZHk6IGRhdGEgfHwgJ3VuZGVmaW5lZCcsXG4gICAgICAgICAgaGVhZGVyczogaGVhZGVycyB8fCAndW5kZWZpbmVkJyxcbiAgICAgICAgfSxcbiAgICAgICAgbWV0YWRhdGE6IHN0YXRUYWdzLm1ldGFkYXRhIHx8IHt9LFxuICAgICAgfTtcbiAgICAgIHRoaXMub2JzZXJ2YWJpbGl0eUNvbmZpZy5sb2dnZXI/LnJlc3BvbnNlTG9nKFxuICAgICAgICBgW0hUVFBdICR7bWV0aG9kfSAke3VybH0gcmVzcG9uc2VgLFxuICAgICAgICByZXNwb25zZUxvZ1BhcmFtcyxcbiAgICAgICk7XG5cbiAgICAgIC8vIE9wdGlvbmFsIHN1Y2Nlc3MgbWV0cmljc1xuICAgICAgY29uc3QgYWxsTGFiZWxzID0geyAuLi5tZXRhZGF0YU1ldHJpY1RhZ3MsIC4uLnN0YXRUYWdzLCBzdGF0dXNDb2RlOiBzdGF0dXMgfTtcblxuICAgICAgY29uc3QgdGltaW5nTGFiZWxzID0gZmlsdGVyTWV0cmljTGFiZWxzKGFsbExhYmVscywgVElNSU5HX01FVFJJQ19MQUJFTFMpO1xuICAgICAgdGhpcy5vYnNlcnZhYmlsaXR5Q29uZmlnLnN0YXRzQ2xpZW50Py50aW1pbmcoXG4gICAgICAgICdvdXRnb2luZ19yZXF1ZXN0X2xhdGVuY3knLFxuICAgICAgICBzdGFydFRpbWVzdGFtcCxcbiAgICAgICAgdGltaW5nTGFiZWxzLFxuICAgICAgKTtcblxuICAgICAgY29uc3QgY291bnRlckxhYmVscyA9IGZpbHRlck1ldHJpY0xhYmVscyhhbGxMYWJlbHMsIENPVU5URVJfTUVUUklDX0xBQkVMUyk7XG4gICAgICB0aGlzLm9ic2VydmFiaWxpdHlDb25maWcuc3RhdHNDbGllbnQ/LmNvdW50ZXIoJ291dGdvaW5nX3JlcXVlc3RfY291bnQnLCAxLCBjb3VudGVyTGFiZWxzKTtcblxuICAgICAgaWYgKHJlc3BvbnNlUGFyc2VyKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgcGFyc2VkRGF0YSA9IHJlc3BvbnNlUGFyc2VyKGRhdGEpO1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB0eXBlOiAnc3VjY2VzcycsXG4gICAgICAgICAgICBzdGF0dXNDb2RlOiBzdGF0dXMsXG4gICAgICAgICAgICByZXNwb25zZUJvZHk6IHBhcnNlZERhdGEsXG4gICAgICAgICAgICBoZWFkZXJzLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc3QgdW5rbm93bkVycm9yID0gZXJyb3IgYXMgRXJyb3I7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHR5cGU6ICdjbGllbnQtZXJyb3InLFxuICAgICAgICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvcjogRXJyb3IgaGFzIHN0YXR1c1xuICAgICAgICAgICAgc3RhdHVzQ29kZTogdW5rbm93bkVycm9yLnN0YXR1cyB8fCA1MDAsXG4gICAgICAgICAgICBtZXNzYWdlOiBgRmFpbGVkIHRvIHBhcnNlIHJlc3BvbnNlIGRhdGE6ICR7dW5rbm93bkVycm9yLm1lc3NhZ2V9YCxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4geyB0eXBlOiAnc3VjY2VzcycsIHN0YXR1c0NvZGU6IHN0YXR1cywgcmVzcG9uc2VCb2R5OiBkYXRhLCBoZWFkZXJzIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIC8vIERldGVybWluZSBzdGF0dXMgY29kZSBmb3IgZXJyb3IgbWV0cmljc1xuICAgICAgbGV0IGVycm9yU3RhdHVzQ29kZSA9IDUwMDsgLy8gRGVmYXVsdCB0byA1MDAgZm9yIG5ldHdvcmsvdW5rbm93biBlcnJvcnNcbiAgICAgIGlmIChheGlvcy5pc0F4aW9zRXJyb3IoZXJyb3IpKSB7XG4gICAgICAgIGNvbnN0IGF4aW9zRXJyb3IgPSBlcnJvciBhcyBBeGlvc0Vycm9yO1xuICAgICAgICBpZiAoYXhpb3NFcnJvci5yZXNwb25zZSkge1xuICAgICAgICAgIGVycm9yU3RhdHVzQ29kZSA9IGF4aW9zRXJyb3IucmVzcG9uc2Uuc3RhdHVzO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIE9wdGlvbmFsIGVycm9yIGxvZ2dpbmdcbiAgICAgIHRoaXMub2JzZXJ2YWJpbGl0eUNvbmZpZy5sb2dnZXI/LmVycm9yPy4oYFtIVFRQXSAke21ldGhvZH0gJHt1cmx9IGVycm9yYCwge1xuICAgICAgICBlcnJvcjogKGVycm9yIGFzIEVycm9yKS5tZXNzYWdlLFxuICAgICAgICBzdGF0VGFnczogeyAuLi5zdGF0VGFncywgc3RhdHVzQ29kZTogZXJyb3JTdGF0dXNDb2RlIH0sXG4gICAgICB9KTtcblxuICAgICAgLy8gT3B0aW9uYWwgZXJyb3IgbWV0cmljc1xuICAgICAgY29uc3QgYWxsRXJyb3JMYWJlbHMgPSB7IC4uLm1ldGFkYXRhTWV0cmljVGFncywgLi4uc3RhdFRhZ3MsIHN0YXR1c0NvZGU6IGVycm9yU3RhdHVzQ29kZSB9O1xuXG4gICAgICBjb25zdCB0aW1pbmdMYWJlbHMgPSBmaWx0ZXJNZXRyaWNMYWJlbHMoYWxsRXJyb3JMYWJlbHMsIFRJTUlOR19NRVRSSUNfTEFCRUxTKTtcbiAgICAgIHRoaXMub2JzZXJ2YWJpbGl0eUNvbmZpZy5zdGF0c0NsaWVudD8udGltaW5nKFxuICAgICAgICAnb3V0Z29pbmdfcmVxdWVzdF9sYXRlbmN5JyxcbiAgICAgICAgc3RhcnRUaW1lc3RhbXAsXG4gICAgICAgIHRpbWluZ0xhYmVscyxcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IGNvdW50ZXJMYWJlbHMgPSBmaWx0ZXJNZXRyaWNMYWJlbHMoYWxsRXJyb3JMYWJlbHMsIENPVU5URVJfTUVUUklDX0xBQkVMUyk7XG4gICAgICB0aGlzLm9ic2VydmFiaWxpdHlDb25maWcuc3RhdHNDbGllbnQ/LmNvdW50ZXIoJ291dGdvaW5nX3JlcXVlc3RfY291bnQnLCAxLCBjb3VudGVyTGFiZWxzKTtcblxuICAgICAgaWYgKGF4aW9zLmlzQXhpb3NFcnJvcihlcnJvcikpIHtcbiAgICAgICAgY29uc3QgYXhpb3NFcnJvciA9IGVycm9yIGFzIEF4aW9zRXJyb3I7XG4gICAgICAgIGlmIChheGlvc0Vycm9yLnJlc3BvbnNlKSB7XG4gICAgICAgICAgY29uc3QgeyByZXNwb25zZSB9ID0gYXhpb3NFcnJvcjtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgdHlwZTogJ2FwcGxpY2F0aW9uLWVycm9yJyxcbiAgICAgICAgICAgIHN0YXR1c0NvZGU6IHJlc3BvbnNlLnN0YXR1cyxcbiAgICAgICAgICAgIG1lc3NhZ2U6IHJlc3BvbnNlLnN0YXR1c1RleHQsXG4gICAgICAgICAgICByZXNwb25zZUJvZHk6IHJlc3BvbnNlLmRhdGEsXG4gICAgICAgICAgICBoZWFkZXJzOiByZXNwb25zZS5oZWFkZXJzLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGF4aW9zRXJyb3IuY29kZSkge1xuICAgICAgICAgIGNvbnN0IHJlc3AgPSBORVRXT1JLX1NUQVRVU19FUlJfTUFQW2F4aW9zRXJyb3IuY29kZV07XG4gICAgICAgICAgaWYgKCFyZXNwKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICB0eXBlOiAnY2xpZW50LWVycm9yJyxcbiAgICAgICAgICAgICAgc3RhdHVzQ29kZTogNTAwLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBgVW5rbm93biBFcnJvcjoke2F4aW9zRXJyb3IubWVzc2FnZX1gLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHR5cGU6ICdjbGllbnQtZXJyb3InLFxuICAgICAgICAgICAgc3RhdHVzQ29kZTogcmVzcC5zdGF0dXMsXG4gICAgICAgICAgICBtZXNzYWdlOiByZXNwLm1lc3NhZ2UsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCB1bmtub3duRXJyb3IgPSBlcnJvciBhcyBFcnJvcjtcbiAgICAgIGNvbnN0IHN0YXR1cyA9IDUwMDtcbiAgICAgIGNvbnN0IG1lc3NhZ2UgPSB1bmtub3duRXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBFcnJvcic7XG5cbiAgICAgIHJldHVybiB7IHR5cGU6ICdjbGllbnQtZXJyb3InLCBzdGF0dXNDb2RlOiBzdGF0dXMsIG1lc3NhZ2UgfTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgZ2V0PFQ+KFxuICAgIHVybDogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiBSZXF1ZXN0Q29uZmlnLFxuICAgIHJlc3BvbnNlUGFyc2VyPzogUmVzcG9uc2VQYXJzZXI8VD4sXG4gICk6IFByb21pc2U8QXBpUmVzcG9uc2U8VD4+IHtcbiAgICBsZXQgY29uZmlnOiBSZXF1ZXN0Q29uZmlnID0ge1xuICAgICAgbWV0aG9kOiAnZ2V0JyxcbiAgICAgIHVybCxcbiAgICB9O1xuICAgIGlmIChpc05vdEVtcHR5KG9wdGlvbnMpKSB7XG4gICAgICBjb25maWcgPSB7IC4uLmNvbmZpZywgLi4ub3B0aW9ucyB9O1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5tYWtlUmVxdWVzdDxUPihjb25maWcsIHJlc3BvbnNlUGFyc2VyKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBwb3N0PFQ+KFxuICAgIHVybDogc3RyaW5nLFxuICAgIGRhdGE/OiB1bmtub3duLFxuICAgIG9wdGlvbnM/OiBSZXF1ZXN0Q29uZmlnLFxuICAgIHJlc3BvbnNlUGFyc2VyPzogUmVzcG9uc2VQYXJzZXI8VD4sXG4gICk6IFByb21pc2U8QXBpUmVzcG9uc2U8VD4+IHtcbiAgICBsZXQgY29uZmlnOiBSZXF1ZXN0Q29uZmlnID0ge1xuICAgICAgbWV0aG9kOiAncG9zdCcsXG4gICAgICB1cmwsXG4gICAgICBkYXRhLFxuICAgIH07XG4gICAgaWYgKGlzTm90RW1wdHkob3B0aW9ucykpIHtcbiAgICAgIGNvbmZpZyA9IHsgLi4uY29uZmlnLCAuLi5vcHRpb25zIH07XG4gICAgfVxuICAgIHJldHVybiB0aGlzLm1ha2VSZXF1ZXN0PFQ+KGNvbmZpZywgcmVzcG9uc2VQYXJzZXIpO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIHB1dDxUPihcbiAgICB1cmw6IHN0cmluZyxcbiAgICBkYXRhPzogdW5rbm93bixcbiAgICBvcHRpb25zPzogUmVxdWVzdENvbmZpZyxcbiAgICByZXNwb25zZVBhcnNlcj86IFJlc3BvbnNlUGFyc2VyPFQ+LFxuICApOiBQcm9taXNlPEFwaVJlc3BvbnNlPFQ+PiB7XG4gICAgbGV0IGNvbmZpZzogUmVxdWVzdENvbmZpZyA9IHtcbiAgICAgIG1ldGhvZDogJ3B1dCcsXG4gICAgICB1cmwsXG4gICAgICBkYXRhLFxuICAgIH07XG4gICAgaWYgKGlzTm90RW1wdHkob3B0aW9ucykpIHtcbiAgICAgIGNvbmZpZyA9IHsgLi4uY29uZmlnLCAuLi5vcHRpb25zIH07XG4gICAgfVxuICAgIHJldHVybiB0aGlzLm1ha2VSZXF1ZXN0PFQ+KGNvbmZpZywgcmVzcG9uc2VQYXJzZXIpO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIHBhdGNoPFQ+KFxuICAgIHVybDogc3RyaW5nLFxuICAgIGRhdGE/OiB1bmtub3duLFxuICAgIG9wdGlvbnM/OiBSZXF1ZXN0Q29uZmlnLFxuICAgIHJlc3BvbnNlUGFyc2VyPzogUmVzcG9uc2VQYXJzZXI8VD4sXG4gICk6IFByb21pc2U8QXBpUmVzcG9uc2U8VD4+IHtcbiAgICBsZXQgY29uZmlnOiBSZXF1ZXN0Q29uZmlnID0ge1xuICAgICAgbWV0aG9kOiAncGF0Y2gnLFxuICAgICAgdXJsLFxuICAgICAgZGF0YSxcbiAgICB9O1xuICAgIGlmIChpc05vdEVtcHR5KG9wdGlvbnMpKSB7XG4gICAgICBjb25maWcgPSB7IC4uLmNvbmZpZywgLi4ub3B0aW9ucyB9O1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5tYWtlUmVxdWVzdDxUPihjb25maWcsIHJlc3BvbnNlUGFyc2VyKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBkZWxldGU8VD4oXG4gICAgdXJsOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IFJlcXVlc3RDb25maWcsXG4gICAgcmVzcG9uc2VQYXJzZXI/OiBSZXNwb25zZVBhcnNlcjxUPixcbiAgKTogUHJvbWlzZTxBcGlSZXNwb25zZTxUPj4ge1xuICAgIGxldCBjb25maWc6IFJlcXVlc3RDb25maWcgPSB7XG4gICAgICBtZXRob2Q6ICdkZWxldGUnLFxuICAgICAgdXJsLFxuICAgIH07XG4gICAgaWYgKGlzTm90RW1wdHkob3B0aW9ucykpIHtcbiAgICAgIGNvbmZpZyA9IHsgLi4uY29uZmlnLCAuLi5vcHRpb25zIH07XG4gICAgfVxuICAgIHJldHVybiB0aGlzLm1ha2VSZXF1ZXN0PFQ+KGNvbmZpZywgcmVzcG9uc2VQYXJzZXIpO1xuICB9XG5cbiAgLy8gQWRkIG90aGVyIEhUVFAgbWV0aG9kcyBhcyBuZWVkZWRcbn1cbiJdfQ==