@decaf-ts/utils
Version:
module management utils for decaf-ts
300 lines • 36.4 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TestReporter = exports.JestReportersTempPathEnvKey = void 0;
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const fs_2 = require("./fs.cjs");
/**
* @description Environment variable key for Jest HTML reporters temporary directory path
* @summary Constant defining the environment variable key for Jest HTML reporters
* @const JestReportersTempPathEnvKey
* @memberOf module:utils
*/
exports.JestReportersTempPathEnvKey = "JEST_HTML_REPORTERS_TEMP_DIR_PATH";
/**
* @description Array of dependencies required by the test reporter
* @summary List of npm packages needed for reporting functionality
* @const dependencies
* @memberOf module:utils
*/
const dependencies = ["jest-html-reporters", "json2md", "chartjs-node-canvas"];
/**
* @description Normalizes imports to handle both CommonJS and ESModule formats
* @summary Utility function to handle module import differences between formats
* @template T - Type of the imported module
* @param {Promise<T>} importPromise - Promise returned by dynamic import
* @return {Promise<T>} Normalized module
* @function normalizeImport
* @memberOf module:utils
*/
async function normalizeImport(importPromise) {
// CommonJS's `module.exports` is wrapped as `default` in ESModule.
return importPromise.then((m) => (m.default || m));
}
/**
* @description Test reporting utility class for managing test results and evidence
* @summary A comprehensive test reporter that handles various types of test artifacts including messages,
* attachments, data, images, tables, and graphs. It provides methods to report and store test evidence
* in different formats and manages dependencies for reporting functionality.
*
* @template T - Type of data being reported
* @param {string} [testCase="tests"] - Name of the test case
* @param {string} [basePath] - Base path for storing test reports
* @class
*
* @example
* ```typescript
* const reporter = new TestReporter('login-test');
*
* // Report test messages
* await reporter.reportMessage('Test Started', 'Login flow initiated');
*
* // Report test data
* await reporter.reportData('user-credentials', { username: 'test' }, 'json');
*
* // Report test results table
* await reporter.reportTable('test-results', {
* headers: ['Step', 'Status'],
* rows: [
* { Step: 'Login', Status: 'Pass' },
* { Step: 'Validation', Status: 'Pass' }
* ]
* });
*
* // Report test evidence
* await reporter.reportAttachment('Screenshot', screenshotBuffer);
* ```
*
* @mermaid
* sequenceDiagram
* participant Client
* participant TestReporter
* participant FileSystem
* participant Dependencies
*
* Client->>TestReporter: new TestReporter(testCase, basePath)
* TestReporter->>FileSystem: Create report directory
*
* alt Report Message
* Client->>TestReporter: reportMessage(title, message)
* TestReporter->>Dependencies: Import helpers
* TestReporter->>FileSystem: Store message
* else Report Data
* Client->>TestReporter: reportData(reference, data, type)
* TestReporter->>Dependencies: Process data
* TestReporter->>FileSystem: Store formatted data
* else Report Table
* Client->>TestReporter: reportTable(reference, tableDef)
* TestReporter->>Dependencies: Convert to MD format
* TestReporter->>FileSystem: Store table
* end
*/
class TestReporter {
constructor(testCase = "tests", basePath = path_1.default.join(process.cwd(), "workdocs", "reports", "evidences")) {
this.testCase = testCase;
this.basePath = basePath;
this.basePath = path_1.default.join(basePath, this.testCase);
if (!fs_1.default.existsSync(this.basePath)) {
fs_1.default.mkdirSync(basePath, { recursive: true });
}
}
/**
* @description Imports required helper functions
* @summary Ensures all necessary dependencies are available and imports helper functions
* @return {Promise<void>} Promise that resolves when helpers are imported
*/
async importHelpers() {
this.deps = await (0, fs_2.installIfNotAvailable)([dependencies[0]], this.deps);
// if (!process.env[JestReportersTempPathEnvKey])
// process.env[JestReportersTempPathEnvKey] = './workdocs/reports';
const { addMsg, addAttach } = await normalizeImport(Promise.resolve(`${`${dependencies[0]}/helper`}`).then(s => __importStar(require(s))));
TestReporter.addMsgFunction = addMsg;
TestReporter.addAttachFunction = addAttach;
}
/**
* @description Reports a message to the test report
* @summary Adds a formatted message to the test report with an optional title
* @param {string} title - Title of the message
* @param {string | object} message - Content of the message
* @return {Promise<void>} Promise that resolves when the message is reported
*/
async reportMessage(title, message) {
if (!TestReporter.addMsgFunction)
await this.importHelpers();
const msg = `${title}${message ? `\n${message}` : ""}`;
await TestReporter.addMsgFunction({ message: msg });
}
/**
* @description Reports an attachment to the test report
* @summary Adds a formatted message to the test report with an optional title
* @param {string} title - Title of the message
* @param {string | Buffer} attachment - Content of the message
* @return {Promise<void>} Promise that resolves when the message is reported
*/
async reportAttachment(title, attachment) {
if (!TestReporter.addAttachFunction)
await this.importHelpers();
await TestReporter.addAttachFunction({
attach: attachment,
description: title,
});
}
/**
* @description Reports data with specified type
* @summary Processes and stores data in the test report with formatting
* @param {string} reference - Reference identifier for the data
* @param {string | number | object} data - Data to be reported
* @param {PayloadType} type - Type of the payload
* @param {boolean} [trim=false] - Whether to trim the data
* @return {Promise<void>} Promise that resolves when data is reported
*/
async report(reference, data, type, trim = false) {
try {
let attachFunction = this.reportMessage.bind(this);
let extension = ".txt";
switch (type) {
case "image":
data = Buffer.from(data);
extension = ".png";
attachFunction = this.reportAttachment.bind(this);
break;
case "json":
if (trim) {
if (data.request)
delete data["request"];
if (data.config)
delete data["config"];
}
data = JSON.stringify(data, null, 2);
extension = ".json";
break;
case "md":
extension = ".md";
break;
case "text":
extension = ".txt";
break;
default:
console.log(`Unsupported type ${type}. assuming text`);
}
reference = reference.includes("\n")
? reference
: `${reference}${extension}`;
await attachFunction(reference, data);
}
catch (e) {
throw new Error(`Could not store attach artifact ${reference} under to test report ${this.testCase} - ${e}`);
}
}
/**
* @description Reports data with a specified type
* @summary Wrapper method for reporting various types of data
* @param {string} reference - Reference identifier for the data
* @param {string | number | object} data - Data to be reported
* @param {PayloadType} [type="json"] - Type of the payload
* @param {boolean} [trim=false] - Whether to trim the data
* @return {Promise<void>} Promise that resolves when data is reported
*/
async reportData(reference, data, type = "json", trim = false) {
return this.report(reference, data, type, trim);
}
/**
* @description Reports a JSON object
* @summary Convenience method for reporting JSON objects
* @param {string} reference - Reference identifier for the object
* @param {object} json - JSON object to be reported
* @param {boolean} [trim=false] - Whether to trim the object
* @return {Promise<void>} Promise that resolves when object is reported
*/
async reportObject(reference, json, trim = false) {
return this.report(reference, json, "json", trim);
}
/**
* @description Reports a table in markdown format
* @summary Converts and stores a table definition in markdown format
* @param {string} reference - Reference identifier for the table
* @param {MdTableDefinition} tableDef - Table definition object
* @return {Promise<void>} Promise that resolves when table is reported
*/
async reportTable(reference, tableDef) {
this.deps = await (0, fs_2.installIfNotAvailable)([dependencies[1]], this.deps);
let txt;
try {
const json2md = await normalizeImport(Promise.resolve(`${`${dependencies[1]}`}`).then(s => __importStar(require(s))));
txt = json2md(tableDef);
}
catch (e) {
throw new Error(`Could not convert JSON to Markdown - ${e}`);
}
return this.report(reference, txt, "md");
}
/**
* @description Reports a graph using Chart.js
* @summary Generates and stores a graph visualization
* @param {string} reference - Reference identifier for the graph
* @param {any} config - Chart.js configuration object
* @return {Promise<void>} Promise that resolves when graph is reported
*/
async reportGraph(reference, config) {
this.deps = await (0, fs_2.installIfNotAvailable)([dependencies[2]], this.deps);
const { ChartJSNodeCanvas } = await normalizeImport(Promise.resolve(`${dependencies[2]}`).then(s => __importStar(require(s))));
const width = 600; //px
const height = 800; //px
const backgroundColour = "white"; // Uses https://www.w3schools.com/tags/canvas_fillstyle.asp
const chartJSNodeCanvas = new ChartJSNodeCanvas({
width,
height,
backgroundColour,
});
const image = await chartJSNodeCanvas.renderToBuffer(config);
return await this.reportImage(reference, image);
}
/**
* @description Reports an image to the test report
* @summary Stores an image buffer in the test report
* @param {string} reference - Reference identifier for the image
* @param {Buffer} buffer - Image data buffer
* @return {Promise<void>} Promise that resolves when image is reported
*/
async reportImage(reference, buffer) {
return this.report(reference, buffer, "image");
}
}
exports.TestReporter = TestReporter;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvdGVzdHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsZ0RBQXdCO0FBQ3hCLDRDQUFvQjtBQUVwQixpQ0FBNkM7QUFtQzdDOzs7OztHQUtHO0FBQ1UsUUFBQSwyQkFBMkIsR0FBRyxtQ0FBbUMsQ0FBQztBQUUvRTs7Ozs7R0FLRztBQUNILE1BQU0sWUFBWSxHQUFHLENBQUMscUJBQXFCLEVBQUUsU0FBUyxFQUFFLHFCQUFxQixDQUFDLENBQUM7QUFFL0U7Ozs7Ozs7O0dBUUc7QUFDSCxLQUFLLFVBQVUsZUFBZSxDQUFJLGFBQXlCO0lBQ3pELG1FQUFtRTtJQUNuRSxPQUFPLGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sSUFBSSxDQUFDLENBQU0sQ0FBQyxDQUFDO0FBQy9ELENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBeURHO0FBQ0gsTUFBYSxZQUFZO0lBd0J2QixZQUNZLFdBQW1CLE9BQU8sRUFDMUIsV0FBVyxjQUFJLENBQUMsSUFBSSxDQUM1QixPQUFPLENBQUMsR0FBRyxFQUFFLEVBQ2IsVUFBVSxFQUNWLFNBQVMsRUFDVCxXQUFXLENBQ1o7UUFOUyxhQUFRLEdBQVIsUUFBUSxDQUFrQjtRQUMxQixhQUFRLEdBQVIsUUFBUSxDQUtqQjtRQUVELElBQUksQ0FBQyxRQUFRLEdBQUcsY0FBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ25ELElBQUksQ0FBQyxZQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQ2xDLFlBQUUsQ0FBQyxTQUFT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VyxDQUFDLFNBQWlCLEVBQUUsTUFBYztRQUNqRCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNqRCxDQUFDO0NBQ0Y7QUFwT0Qsb0NBb09DIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCBmcyBmcm9tIFwiZnNcIjtcbmltcG9ydCB7IE1kVGFibGVEZWZpbml0aW9uIH0gZnJvbSBcIi4vbWRcIjtcbmltcG9ydCB7IGluc3RhbGxJZk5vdEF2YWlsYWJsZSB9IGZyb20gXCIuL2ZzXCI7XG5pbXBvcnQgeyBTaW1wbGVEZXBlbmRlbmN5TWFwIH0gZnJvbSBcIi4vdHlwZXNcIjtcblxuLyoqXG4gKiBAaW50ZXJmYWNlIEFkZEF0dGFjaFBhcmFtc1xuICogQGRlc2NyaXB0aW9uIFBhcmFtZXRlcnMgZm9yIGFkZGluZyBhbiBhdHRhY2htZW50IHRvIGEgcmVwb3J0XG4gKiBAc3VtbWFyeSBJbnRlcmZhY2UgZm9yIGF0dGFjaG1lbnQgcGFyYW1ldGVyc1xuICogQG1lbWJlck9mIG1vZHVsZTp1dGlsc1xuICovXG5leHBvcnQgaW50ZXJmYWNlIEFkZEF0dGFjaFBhcmFtcyB7XG4gIGF0dGFjaDogc3RyaW5nIHwgQnVmZmVyO1xuICBkZXNjcmlwdGlvbjogc3RyaW5nIHwgb2JqZWN0O1xuICBjb250ZXh0PzogYW55O1xuICBidWZmZXJGb3JtYXQ/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogQGludGVyZmFjZSBBZGRNc2dQYXJhbXNcbiAqIEBkZXNjcmlwdGlvbiBQYXJhbWV0ZXJzIGZvciBhZGRpbmcgYSBtZXNzYWdlIHRvIGEgcmVwb3J0XG4gKiBAc3VtbWFyeSBJbnRlcmZhY2UgZm9yIG1lc3NhZ2UgcGFyYW1ldGVyc1xuICogQG1lbWJlck9mIG1vZHVsZTp1dGlsc1xuICovXG5leHBvcnQgaW50ZXJmYWNlIEFkZE1zZ1BhcmFtcyB7XG4gIG1lc3NhZ2U6IHN0cmluZyB8IG9iamVjdDtcbiAgY29udGV4dD86IGFueTtcbn1cblxuLyoqXG4gKiBAdHlwZWRlZiB7KFwianNvblwifFwiaW1hZ2VcInxcInRleHRcInxcIm1kXCIpfSBQYXlsb2FkVHlwZVxuICogQGRlc2NyaXB0aW9uIFR5cGVzIG9mIHBheWxvYWRzIHRoYXQgY2FuIGJlIGhhbmRsZWRcbiAqIEBzdW1tYXJ5IFVuaW9uIHR5cGUgZm9yIHBheWxvYWQgdHlwZXNcbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuZXhwb3J0IHR5cGUgUGF5bG9hZFR5cGUgPSBcImpzb25cIiB8IFwiaW1hZ2VcIiB8IFwidGV4dFwiIHwgXCJtZFwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBFbnZpcm9ubWVudCB2YXJpYWJsZSBrZXkgZm9yIEplc3QgSFRNTCByZXBvcnRlcnMgdGVtcG9yYXJ5IGRpcmVjdG9yeSBwYXRoXG4gKiBAc3VtbWFyeSBDb25zdGFudCBkZWZpbmluZyB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGUga2V5IGZvciBKZXN0IEhUTUwgcmVwb3J0ZXJzXG4gKiBAY29uc3QgSmVzdFJlcG9ydGVyc1RlbXBQYXRoRW52S2V5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOnV0aWxzXG4gKi9cbmV4cG9ydCBjb25zdCBKZXN0UmVwb3J0ZXJzVGVtcFBhdGhFbnZLZXkgPSBcIkpFU1RfSFRNTF9SRVBPUlRFUlNfVEVNUF9ESVJfUEFUSFwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBBcnJheSBvZiBkZXBlbmRlbmNpZXMgcmVxdWlyZWQgYnkgdGhlIHRlc3QgcmVwb3J0ZXJcbiAqIEBzdW1tYXJ5IExpc3Qgb2YgbnBtIHBhY2thZ2VzIG5lZWRlZCBmb3IgcmVwb3J0aW5nIGZ1bmN0aW9uYWxpdHlcbiAqIEBjb25zdCBkZXBlbmRlbmNpZXNcbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuY29uc3QgZGVwZW5kZW5jaWVzID0gW1wiamVzdC1odG1sLXJlcG9ydGVyc1wiLCBcImpzb24ybWRcIiwgXCJjaGFydGpzLW5vZGUtY2FudmFzXCJdO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBOb3JtYWxpemVzIGltcG9ydHMgdG8gaGFuZGxlIGJvdGggQ29tbW9uSlMgYW5kIEVTTW9kdWxlIGZvcm1hdHNcbiAqIEBzdW1tYXJ5IFV0aWxpdHkgZnVuY3Rpb24gdG8gaGFuZGxlIG1vZHVsZSBpbXBvcnQgZGlmZmVyZW5jZXMgYmV0d2VlbiBmb3JtYXRzXG4gKiBAdGVtcGxhdGUgVCAtIFR5cGUgb2YgdGhlIGltcG9ydGVkIG1vZHVsZVxuICogQHBhcmFtIHtQcm9taXNlPFQ+fSBpbXBvcnRQcm9taXNlIC0gUHJvbWlzZSByZXR1cm5lZCBieSBkeW5hbWljIGltcG9ydFxuICogQHJldHVybiB7UHJvbWlzZTxUPn0gTm9ybWFsaXplZCBtb2R1bGVcbiAqIEBmdW5jdGlvbiBub3JtYWxpemVJbXBvcnRcbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuYXN5bmMgZnVuY3Rpb24gbm9ybWFsaXplSW1wb3J0PFQ+KGltcG9ydFByb21pc2U6IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+IHtcbiAgLy8gQ29tbW9uSlMncyBgbW9kdWxlLmV4cG9ydHNgIGlzIHdyYXBwZWQgYXMgYGRlZmF1bHRgIGluIEVTTW9kdWxlLlxuICByZXR1cm4gaW1wb3J0UHJvbWlzZS50aGVuKChtOiBhbnkpID0+IChtLmRlZmF1bHQgfHwgbSkgYXMgVCk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFRlc3QgcmVwb3J0aW5nIHV0aWxpdHkgY2xhc3MgZm9yIG1hbmFnaW5nIHRlc3QgcmVzdWx0cyBhbmQgZXZpZGVuY2VcbiAqIEBzdW1tYXJ5IEEgY29tcHJlaGVuc2l2ZSB0ZXN0IHJlcG9ydGVyIHRoYXQgaGFuZGxlcyB2YXJpb3VzIHR5cGVzIG9mIHRlc3QgYXJ0aWZhY3RzIGluY2x1ZGluZyBtZXNzYWdlcyxcbiAqIGF0dGFjaG1lbnRzLCBkYXRhLCBpbWFnZXMsIHRhYmxlcywgYW5kIGdyYXBocy4gSXQgcHJvdmlkZXMgbWV0aG9kcyB0byByZXBvcnQgYW5kIHN0b3JlIHRlc3QgZXZpZGVuY2VcbiAqIGluIGRpZmZlcmVudCBmb3JtYXRzIGFuZCBtYW5hZ2VzIGRlcGVuZGVuY2llcyBmb3IgcmVwb3J0aW5nIGZ1bmN0aW9uYWxpdHkuXG4gKlxuICogQHRlbXBsYXRlIFQgLSBUeXBlIG9mIGRhdGEgYmVpbmcgcmVwb3J0ZWRcbiAqIEBwYXJhbSB7c3RyaW5nfSBbdGVzdENhc2U9XCJ0ZXN0c1wiXSAtIE5hbWUgb2YgdGhlIHRlc3QgY2FzZVxuICogQHBhcmFtIHtzdHJpbmd9IFtiYXNlUGF0aF0gLSBCYXNlIHBhdGggZm9yIHN0b3JpbmcgdGVzdCByZXBvcnRzXG4gKiBAY2xhc3NcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3QgcmVwb3J0ZXIgPSBuZXcgVGVzdFJlcG9ydGVyKCdsb2dpbi10ZXN0Jyk7XG4gKlxuICogLy8gUmVwb3J0IHRlc3QgbWVzc2FnZXNcbiAqIGF3YWl0IHJlcG9ydGVyLnJlcG9ydE1lc3NhZ2UoJ1Rlc3QgU3RhcnRlZCcsICdMb2dpbiBmbG93IGluaXRpYXRlZCcpO1xuICpcbiAqIC8vIFJlcG9ydCB0ZXN0IGRhdGFcbiAqIGF3YWl0IHJlcG9ydGVyLnJlcG9ydERhdGEoJ3VzZXItY3JlZGVudGlhbHMnLCB7IHVzZXJuYW1lOiAndGVzdCcgfSwgJ2pzb24nKTtcbiAqXG4gKiAvLyBSZXBvcnQgdGVzdCByZXN1bHRzIHRhYmxlXG4gKiBhd2FpdCByZXBvcnRlci5yZXBvcnRUYWJsZSgndGVzdC1yZXN1bHRzJywge1xuICogICBoZWFkZXJzOiBbJ1N0ZXAnLCAnU3RhdHVzJ10sXG4gKiAgIHJvd3M6IFtcbiAqICAgICB7IFN0ZXA6ICdMb2dpbicsIFN0YXR1czogJ1Bhc3MnIH0sXG4gKiAgICAgeyBTdGVwOiAnVmFsaWRhdGlvbicsIFN0YXR1czogJ1Bhc3MnIH1cbiAqICAgXVxuICogfSk7XG4gKlxuICogLy8gUmVwb3J0IHRlc3QgZXZpZGVuY2VcbiAqIGF3YWl0IHJlcG9ydGVyLnJlcG9ydEF0dGFjaG1lbnQoJ1NjcmVlbnNob3QnLCBzY3JlZW5zaG90QnVmZmVyKTtcbiAqIGBgYFxuICpcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2xpZW50XG4gKiAgIHBhcnRpY2lwYW50IFRlc3RSZXBvcnRlclxuICogICBwYXJ0aWNpcGFudCBGaWxlU3lzdGVtXG4gKiAgIHBhcnRpY2lwYW50IERlcGVuZGVuY2llc1xuICpcbiAqICAgQ2xpZW50LT4+VGVzdFJlcG9ydGVyOiBuZXcgVGVzdFJlcG9ydGVyKHRlc3RDYXNlLCBiYXNlUGF0aClcbiAqICAgVGVzdFJlcG9ydGVyLT4+RmlsZVN5c3RlbTogQ3JlYXRlIHJlcG9ydCBkaXJlY3RvcnlcbiAqXG4gKiAgIGFsdCBSZXBvcnQgTWVzc2FnZVxuICogICAgIENsaWVudC0+PlRlc3RSZXBvcnRlcjogcmVwb3J0TWVzc2FnZSh0aXRsZSwgbWVzc2FnZSlcbiAqICAgICBUZXN0UmVwb3J0ZXItPj5EZXBlbmRlbmNpZXM6IEltcG9ydCBoZWxwZXJzXG4gKiAgICAgVGVzdFJlcG9ydGVyLT4+RmlsZVN5c3RlbTogU3RvcmUgbWVzc2FnZVxuICogICBlbHNlIFJlcG9ydCBEYXRhXG4gKiAgICAgQ2xpZW50LT4+VGVzdFJlcG9ydGVyOiByZXBvcnREYXRhKHJlZmVyZW5jZSwgZGF0YSwgdHlwZSlcbiAqICAgICBUZXN0UmVwb3J0ZXItPj5EZXBlbmRlbmNpZXM6IFByb2Nlc3MgZGF0YVxuICogICAgIFRlc3RSZXBvcnRlci0+PkZpbGVTeXN0ZW06IFN0b3JlIGZvcm1hdHRlZCBkYXRhXG4gKiAgIGVsc2UgUmVwb3J0IFRhYmxlXG4gKiAgICAgQ2xpZW50LT4+VGVzdFJlcG9ydGVyOiByZXBvcnRUYWJsZShyZWZlcmVuY2UsIHRhYmxlRGVmKVxuICogICAgIFRlc3RSZXBvcnRlci0+PkRlcGVuZGVuY2llczogQ29udmVydCB0byBNRCBmb3JtYXRcbiAqICAgICBUZXN0UmVwb3J0ZXItPj5GaWxlU3lzdGVtOiBTdG9yZSB0YWJsZVxuICogICBlbmRcbiAqL1xuZXhwb3J0IGNsYXNzIFRlc3RSZXBvcnRlciB7XG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRnVuY3Rpb24gZm9yIGFkZGluZyBtZXNzYWdlcyB0byB0aGUgdGVzdCByZXBvcnRcbiAgICogQHN1bW1hcnkgU3RhdGljIGhhbmRsZXIgZm9yIHByb2Nlc3NpbmcgYW5kIHN0b3JpbmcgdGVzdCBtZXNzYWdlc1xuICAgKiBAdHlwZSB7ZnVuY3Rpb24oQWRkTXNnUGFyYW1zKTogUHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIHByb3RlY3RlZCBzdGF0aWMgYWRkTXNnRnVuY3Rpb246IChwYXJhbXM6IEFkZE1zZ1BhcmFtcykgPT4gUHJvbWlzZTx2b2lkPjtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEZ1bmN0aW9uIGZvciBhZGRpbmcgYXR0YWNobWVudHMgdG8gdGhlIHRlc3QgcmVwb3J0XG4gICAqIEBzdW1tYXJ5IFN0YXRpYyBoYW5kbGVyIGZvciBwcm9jZXNzaW5nIGFuZCBzdG9yaW5nIHRlc3QgYXR0YWNobWVudHNcbiAgICogQHR5cGUge2Z1bmN0aW9uKEFkZEF0dGFjaFBhcmFtcyk6IFByb21pc2U8dm9pZD59XG4gICAqL1xuICBwcm90ZWN0ZWQgc3RhdGljIGFkZEF0dGFjaEZ1bmN0aW9uOiAoXG4gICAgcGFyYW1zOiBBZGRBdHRhY2hQYXJhbXNcbiAgKSA9PiBQcm9taXNlPHZvaWQ+O1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gTWFwIG9mIGRlcGVuZGVuY2llcyByZXF1aXJlZCBieSB0aGUgcmVwb3J0ZXJcbiAgICogQHN1bW1hcnkgU3RvcmVzIHRoZSBjdXJyZW50IHN0YXRlIG9mIGRlcGVuZGVuY2llc1xuICAgKiBAdHlwZSB7U2ltcGxlRGVwZW5kZW5jeU1hcH1cbiAgICovXG4gIHByaXZhdGUgZGVwcz86IFNpbXBsZURlcGVuZGVuY3lNYXA7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJvdGVjdGVkIHRlc3RDYXNlOiBzdHJpbmcgPSBcInRlc3RzXCIsXG4gICAgcHJvdGVjdGVkIGJhc2VQYXRoID0gcGF0aC5qb2luKFxuICAgICAgcHJvY2Vzcy5jd2QoKSxcbiAgICAgIFwid29ya2RvY3NcIixcbiAgICAgIFwicmVwb3J0c1wiLFxuICAgICAgXCJldmlkZW5jZXNcIlxuICAgIClcbiAgKSB7XG4gICAgdGhpcy5iYXNlUGF0aCA9IHBhdGguam9pbihiYXNlUGF0aCwgdGhpcy50ZXN0Q2FzZSk7XG4gICAgaWYgKCFmcy5leGlzdHNTeW5jKHRoaXMuYmFzZVBhdGgpKSB7XG4gICAgICBmcy5ta2RpclN5bmMoYmFzZVBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gSW1wb3J0cyByZXF1aXJlZCBoZWxwZXIgZnVuY3Rpb25zXG4gICAqIEBzdW1tYXJ5IEVuc3VyZXMgYWxsIG5lY2Vzc2FyeSBkZXBlbmRlbmNpZXMgYXJlIGF2YWlsYWJsZSBhbmQgaW1wb3J0cyBoZWxwZXIgZnVuY3Rpb25zXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGhlbHBlcnMgYXJlIGltcG9ydGVkXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGltcG9ydEhlbHBlcnMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5kZXBzID0gYXdhaXQgaW5zdGFsbElmTm90QXZhaWxhYmxlKFtkZXBlbmRlbmNpZXNbMF1dLCB0aGlzLmRlcHMpO1xuICAgIC8vIGlmICghcHJvY2Vzcy5lbnZbSmVzdFJlcG9ydGVyc1RlbXBQYXRoRW52S2V5XSlcbiAgICAvLyAgIHByb2Nlc3MuZW52W0plc3RSZXBvcnRlcnNUZW1wUGF0aEVudktleV0gPSAnLi93b3JrZG9jcy9yZXBvcnRzJztcbiAgICBjb25zdCB7IGFkZE1zZywgYWRkQXR0YWNoIH0gPSBhd2FpdCBub3JtYWxpemVJbXBvcnQoXG4gICAgICBpbXBvcnQoYCR7ZGVwZW5kZW5jaWVzWzBdfS9oZWxwZXJgKVxuICAgICk7XG4gICAgVGVzdFJlcG9ydGVyLmFkZE1zZ0Z1bmN0aW9uID0gYWRkTXNnO1xuICAgIFRlc3RSZXBvcnRlci5hZGRBdHRhY2hGdW5jdGlvbiA9IGFkZEF0dGFjaDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVwb3J0cyBhIG1lc3NhZ2UgdG8gdGhlIHRlc3QgcmVwb3J0XG4gICAqIEBzdW1tYXJ5IEFkZHMgYSBmb3JtYXR0ZWQgbWVzc2FnZSB0byB0aGUgdGVzdCByZXBvcnQgd2l0aCBhbiBvcHRpb25hbCB0aXRsZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGl0bGUgLSBUaXRsZSBvZiB0aGUgbWVzc2FnZVxuICAgKiBAcGFyYW0ge3N0cmluZyB8IG9iamVjdH0gbWVzc2FnZSAtIENvbnRlbnQgb2YgdGhlIG1lc3NhZ2VcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIG1lc3NhZ2UgaXMgcmVwb3J0ZWRcbiAgICovXG4gIGFzeW5jIHJlcG9ydE1lc3NhZ2UodGl0bGU6IHN0cmluZywgbWVzc2FnZTogc3RyaW5nIHwgb2JqZWN0KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKCFUZXN0UmVwb3J0ZXIuYWRkTXNnRnVuY3Rpb24pIGF3YWl0IHRoaXMuaW1wb3J0SGVscGVycygpO1xuICAgIGNvbnN0IG1zZyA9IGAke3RpdGxlfSR7bWVzc2FnZSA/IGBcXG4ke21lc3NhZ2V9YCA6IFwiXCJ9YDtcbiAgICBhd2FpdCBUZXN0UmVwb3J0ZXIuYWRkTXNnRnVuY3Rpb24oeyBtZXNzYWdlOiBtc2cgfSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlcG9ydHMgYW4gYXR0YWNobWVudCB0byB0aGUgdGVzdCByZXBvcnRcbiAgICogQHN1bW1hcnkgQWRkcyBhIGZvcm1hdHRlZCBtZXNzYWdlIHRvIHRoZSB0ZXN0IHJlcG9ydCB3aXRoIGFuIG9wdGlvbmFsIHRpdGxlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0aXRsZSAtIFRpdGxlIG9mIHRoZSBtZXNzYWdlXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgQnVmZmVyfSBhdHRhY2htZW50IC0gQ29udGVudCBvZiB0aGUgbWVzc2FnZVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgbWVzc2FnZSBpcyByZXBvcnRlZFxuICAgKi9cbiAgYXN5bmMgcmVwb3J0QXR0YWNobWVudChcbiAgICB0aXRsZTogc3RyaW5nLFxuICAgIGF0dGFjaG1lbnQ6IHN0cmluZyB8IEJ1ZmZlclxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIVRlc3RSZXBvcnRlci5hZGRBdHRhY2hGdW5jdGlvbikgYXdhaXQgdGhpcy5pbXBvcnRIZWxwZXJzKCk7XG4gICAgYXdhaXQgVGVzdFJlcG9ydGVyLmFkZEF0dGFjaEZ1bmN0aW9uKHtcbiAgICAgIGF0dGFjaDogYXR0YWNobWVudCxcbiAgICAgIGRlc2NyaXB0aW9uOiB0aXRsZSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVwb3J0cyBkYXRhIHdpdGggc3BlY2lmaWVkIHR5cGVcbiAgICogQHN1bW1hcnkgUHJvY2Vzc2VzIGFuZCBzdG9yZXMgZGF0YSBpbiB0aGUgdGVzdCByZXBvcnQgd2l0aCBmb3JtYXR0aW5nXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByZWZlcmVuY2UgLSBSZWZlcmVuY2UgaWRlbnRpZmllciBmb3IgdGhlIGRhdGFcbiAgICogQHBhcmFtIHtzdHJpbmcgfCBudW1iZXIgfCBvYmplY3R9IGRhdGEgLSBEYXRhIHRvIGJlIHJlcG9ydGVkXG4gICAqIEBwYXJhbSB7UGF5bG9hZFR5cGV9IHR5cGUgLSBUeXBlIG9mIHRoZSBwYXlsb2FkXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3RyaW09ZmFsc2VdIC0gV2hldGhlciB0byB0cmltIHRoZSBkYXRhXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGRhdGEgaXMgcmVwb3J0ZWRcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyByZXBvcnQoXG4gICAgcmVmZXJlbmNlOiBzdHJpbmcsXG4gICAgZGF0YTogc3RyaW5nIHwgbnVtYmVyIHwgb2JqZWN0IHwgQnVmZmVyLFxuICAgIHR5cGU6IFBheWxvYWRUeXBlLFxuICAgIHRyaW06IGJvb2xlYW4gPSBmYWxzZVxuICApIHtcbiAgICB0cnkge1xuICAgICAgbGV0IGF0dGFjaEZ1bmN0aW9uOlxuICAgICAgICB8IHR5cGVvZiB0aGlzLnJlcG9ydE1lc3NhZ2VcbiAgICAgICAgfCB0eXBlb2YgdGhpcy5yZXBvcnRBdHRhY2htZW50ID0gdGhpcy5yZXBvcnRNZXNzYWdlLmJpbmQodGhpcyk7XG4gICAgICBsZXQgZXh0ZW5zaW9uOiBcIi5wbmdcIiB8IFwiLnR4dFwiIHwgXCIubWRcIiB8IFwiLmpzb25cIiA9IFwiLnR4dFwiO1xuXG4gICAgICBzd2l0Y2ggKHR5cGUpIHtcbiAgICAgICAgY2FzZSBcImltYWdlXCI6XG4gICAgICAgICAgZGF0YSA9IEJ1ZmZlci5mcm9tKGRhdGEgYXMgQnVmZmVyKTtcbiAgICAgICAgICBleHRlbnNpb24gPSBcIi5wbmdcIjtcbiAgICAgICAgICBhdHRhY2hGdW5jdGlvbiA9IHRoaXMucmVwb3J0QXR0YWNobWVudC5iaW5kKHRoaXMpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwianNvblwiOlxuICAgICAgICAgIGlmICh0cmltKSB7XG4gICAgICAgICAgICBpZiAoKGRhdGEgYXMgeyByZXF1ZXN0PzogdW5rbm93biB9KS5yZXF1ZXN0KVxuICAgICAgICAgICAgICBkZWxldGUgKGRhdGEgYXMgeyByZXF1ZXN0PzogdW5rbm93biB9KVtcInJlcXVlc3RcIl07XG4gICAgICAgICAgICBpZiAoKGRhdGEgYXMgeyBjb25maWc/OiB1bmtub3duIH0pLmNvbmZpZylcbiAgICAgICAgICAgICAgZGVsZXRlIChkYXRhIGFzIHsgY29uZmlnPzogdW5rbm93biB9KVtcImNvbmZpZ1wiXTtcbiAgICAgICAgICB9XG4gICAgICAgICAgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGRhdGEsIG51bGwsIDIpO1xuICAgICAgICAgIGV4dGVuc2lvbiA9IFwiLmpzb25cIjtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcIm1kXCI6XG4gICAgICAgICAgZXh0ZW5zaW9uID0gXCIubWRcIjtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcInRleHRcIjpcbiAgICAgICAgICBleHRlbnNpb24gPSBcIi50eHRcIjtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICBjb25zb2xlLmxvZyhgVW5zdXBwb3J0ZWQgdHlwZSAke3R5cGV9LiBhc3N1bWluZyB0ZXh0YCk7XG4gICAgICB9XG4gICAgICByZWZlcmVuY2UgPSByZWZlcmVuY2UuaW5jbHVkZXMoXCJcXG5cIilcbiAgICAgICAgPyByZWZlcmVuY2VcbiAgICAgICAgOiBgJHtyZWZlcmVuY2V9JHtleHRlbnNpb259YDtcbiAgICAgIGF3YWl0IGF0dGFjaEZ1bmN0aW9uKHJlZmVyZW5jZSwgZGF0YSBhcyBCdWZmZXIgfCBzdHJpbmcpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYENvdWxkIG5vdCBzdG9yZSBhdHRhY2ggYXJ0aWZhY3QgJHtyZWZlcmVuY2V9IHVuZGVyIHRvIHRlc3QgcmVwb3J0ICR7dGhpcy50ZXN0Q2FzZX0gLSAke2V9YFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlcG9ydHMgZGF0YSB3aXRoIGEgc3BlY2lmaWVkIHR5cGVcbiAgICogQHN1bW1hcnkgV3JhcHBlciBtZXRob2QgZm9yIHJlcG9ydGluZyB2YXJpb3VzIHR5cGVzIG9mIGRhdGFcbiAgICogQHBhcmFtIHtzdHJpbmd9IHJlZmVyZW5jZSAtIFJlZmVyZW5jZSBpZGVudGlmaWVyIGZvciB0aGUgZGF0YVxuICAgKiBAcGFyYW0ge3N0cmluZyB8IG51bWJlciB8IG9iamVjdH0gZGF0YSAtIERhdGEgdG8gYmUgcmVwb3J0ZWRcbiAgICogQHBhcmFtIHtQYXlsb2FkVHlwZX0gW3R5cGU9XCJqc29uXCJdIC0gVHlwZSBvZiB0aGUgcGF5bG9hZFxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFt0cmltPWZhbHNlXSAtIFdoZXRoZXIgdG8gdHJpbSB0aGUgZGF0YVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiBkYXRhIGlzIHJlcG9ydGVkXG4gICAqL1xuICBhc3luYyByZXBvcnREYXRhKFxuICAgIHJlZmVyZW5jZTogc3RyaW5nLFxuICAgIGRhdGE6IHN0cmluZyB8IG51bWJlciB8IG9iamVjdCxcbiAgICB0eXBlOiBQYXlsb2FkVHlwZSA9IFwianNvblwiLFxuICAgIHRyaW0gPSBmYWxzZVxuICApIHtcbiAgICByZXR1cm4gdGhpcy5yZXBvcnQocmVmZXJlbmNlLCBkYXRhLCB0eXBlLCB0cmltKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVwb3J0cyBhIEpTT04gb2JqZWN0XG4gICAqIEBzdW1tYXJ5IENvbnZlbmllbmNlIG1ldGhvZCBmb3IgcmVwb3J0aW5nIEpTT04gb2JqZWN0c1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVmZXJlbmNlIC0gUmVmZXJlbmNlIGlkZW50aWZpZXIgZm9yIHRoZSBvYmplY3RcbiAgICogQHBhcmFtIHtvYmplY3R9IGpzb24gLSBKU09OIG9iamVjdCB0byBiZSByZXBvcnRlZFxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFt0cmltPWZhbHNlXSAtIFdoZXRoZXIgdG8gdHJpbSB0aGUgb2JqZWN0XG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIG9iamVjdCBpcyByZXBvcnRlZFxuICAgKi9cbiAgYXN5bmMgcmVwb3J0T2JqZWN0KHJlZmVyZW5jZTogc3RyaW5nLCBqc29uOiBvYmplY3QsIHRyaW0gPSBmYWxzZSkge1xuICAgIHJldHVybiB0aGlzLnJlcG9ydChyZWZlcmVuY2UsIGpzb24sIFwianNvblwiLCB0cmltKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVwb3J0cyBhIHRhYmxlIGluIG1hcmtkb3duIGZvcm1hdFxuICAgKiBAc3VtbWFyeSBDb252ZXJ0cyBhbmQgc3RvcmVzIGEgdGFibGUgZGVmaW5pdGlvbiBpbiBtYXJrZG93biBmb3JtYXRcbiAgICogQHBhcmFtIHtzdHJpbmd9IHJlZmVyZW5jZSAtIFJlZmVyZW5jZSBpZGVudGlmaWVyIGZvciB0aGUgdGFibGVcbiAgICogQHBhcmFtIHtNZFRhYmxlRGVmaW5pdGlvbn0gdGFibGVEZWYgLSBUYWJsZSBkZWZpbml0aW9uIG9iamVjdFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0YWJsZSBpcyByZXBvcnRlZFxuICAgKi9cbiAgYXN5bmMgcmVwb3J0VGFibGUocmVmZXJlbmNlOiBzdHJpbmcsIHRhYmxlRGVmOiBNZFRhYmxlRGVmaW5pdGlvbikge1xuICAgIHRoaXMuZGVwcyA9IGF3YWl0IGluc3RhbGxJZk5vdEF2YWlsYWJsZShbZGVwZW5kZW5jaWVzWzFdXSwgdGhpcy5kZXBzKTtcbiAgICBsZXQgdHh0OiBzdHJpbmc7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGpzb24ybWQgPSBhd2FpdCBub3JtYWxpemVJbXBvcnQoaW1wb3J0KGAke2RlcGVuZGVuY2llc1sxXX1gKSk7XG4gICAgICB0eHQgPSBqc29uMm1kKHRhYmxlRGVmKTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENvdWxkIG5vdCBjb252ZXJ0IEpTT04gdG8gTWFya2Rvd24gLSAke2V9YCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMucmVwb3J0KHJlZmVyZW5jZSwgdHh0LCBcIm1kXCIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZXBvcnRzIGEgZ3JhcGggdXNpbmcgQ2hhcnQuanNcbiAgICogQHN1bW1hcnkgR2VuZXJhdGVzIGFuZCBzdG9yZXMgYSBncmFwaCB2aXN1YWxpemF0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByZWZlcmVuY2UgLSBSZWZlcmVuY2UgaWRlbnRpZmllciBmb3IgdGhlIGdyYXBoXG4gICAqIEBwYXJhbSB7YW55fSBjb25maWcgLSBDaGFydC5qcyBjb25maWd1cmF0aW9uIG9iamVjdFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiBncmFwaCBpcyByZXBvcnRlZFxuICAgKi9cbiAgYXN5bmMgcmVwb3J0R3JhcGgocmVmZXJlbmNlOiBzdHJpbmcsIGNvbmZpZzogYW55KSB7XG4gICAgdGhpcy5kZXBzID0gYXdhaXQgaW5zdGFsbElmTm90QXZhaWxhYmxlKFtkZXBlbmRlbmNpZXNbMl1dLCB0aGlzLmRlcHMpO1xuICAgIGNvbnN0IHsgQ2hhcnRKU05vZGVDYW52YXMgfSA9IGF3YWl0IG5vcm1hbGl6ZUltcG9ydChcbiAgICAgIGltcG9ydChkZXBlbmRlbmNpZXNbMl0pXG4gICAgKTtcblxuICAgIGNvbnN0IHdpZHRoID0gNjAwOyAvL3B4XG4gICAgY29uc3QgaGVpZ2h0ID0gODAwOyAvL3B4XG4gICAgY29uc3QgYmFja2dyb3VuZENvbG91ciA9IFwid2hpdGVcIjsgLy8gVXNlcyBodHRwczovL3d3dy53M3NjaG9vbHMuY29tL3RhZ3MvY2FudmFzX2ZpbGxzdHlsZS5hc3BcbiAgICBjb25zdCBjaGFydEpTTm9kZUNhbnZhcyA9IG5ldyBDaGFydEpTTm9kZUNhbnZhcyh7XG4gICAgICB3aWR0aCxcbiAgICAgIGhlaWdodCxcbiAgICAgIGJhY2tncm91bmRDb2xvdXIsXG4gICAgfSk7XG5cbiAgICBjb25zdCBpbWFnZSA9IGF3YWl0IGNoYXJ0SlNOb2RlQ2FudmFzLnJlbmRlclRvQnVmZmVyKGNvbmZpZyk7XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMucmVwb3J0SW1hZ2UocmVmZXJlbmNlLCBpbWFnZSk7XG4gIH1cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZXBvcnRzIGFuIGltYWdlIHRvIHRoZSB0ZXN0IHJlcG9ydFxuICAgKiBAc3VtbWFyeSBTdG9yZXMgYW4gaW1hZ2UgYnVmZmVyIGluIHRoZSB0ZXN0IHJlcG9ydFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVmZXJlbmNlIC0gUmVmZXJlbmNlIGlkZW50aWZpZXIgZm9yIHRoZSBpbWFnZVxuICAgKiBAcGFyYW0ge0J1ZmZlcn0gYnVmZmVyIC0gSW1hZ2UgZGF0YSBidWZmZXJcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gaW1hZ2UgaXMgcmVwb3J0ZWRcbiAgICovXG4gIGFzeW5jIHJlcG9ydEltYWdlKHJlZmVyZW5jZTogc3RyaW5nLCBidWZmZXI6IEJ1ZmZlcikge1xuICAgIHJldHVybiB0aGlzLnJlcG9ydChyZWZlcmVuY2UsIGJ1ZmZlciwgXCJpbWFnZVwiKTtcbiAgfVxufVxuIl19