UNPKG

@decaf-ts/utils

Version:

module management utils for decaf-ts

300 lines 36.4 kB
"use strict"; 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