UNPKG

gst-atom-xcuitest-driver

Version:

ATOM driver for iOS using XCUITest for backend

304 lines (230 loc) 38.4 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.commands = void 0; require("source-map-support/register"); var _lodash = _interopRequireDefault(require("lodash")); var _path = _interopRequireDefault(require("path")); var _appiumSupport = require("appium-support"); var _teen_process = require("teen_process"); var _logger = _interopRequireDefault(require("../logger")); var _utils = require("../utils"); var _asyncbox = require("asyncbox"); var _os = _interopRequireDefault(require("os")); let commands = {}; exports.commands = commands; const PERF_RECORD_FEAT_NAME = 'perf_record'; const PERF_RECORD_SECURITY_MESSAGE = 'Performance measurement requires relaxing security for simulator. ' + `Please set '--relaxed-security' or '--allow-insecure' with '${PERF_RECORD_FEAT_NAME}' ` + 'referencing https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/security.md for more details.'; const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; const STOP_TIMEOUT_MS = 3 * 60 * 1000; const STARTUP_TIMEOUT_MS = 15 * 1000; const DEFAULT_PROFILE_NAME = 'Activity Monitor'; const DEFAULT_EXT = 'trace'; const DEFAULT_PID = 'current'; const INSTRUMENTS_BINARY = 'instruments'; async function requireInstruments() { try { return await _appiumSupport.fs.which(INSTRUMENTS_BINARY); } catch (e) { _logger.default.errorAndThrow(`${INSTRUMENTS_BINARY} has not been found in PATH. ` + `Please make sure Xcode development tools are installed`); } } class PerfRecorder { constructor(reportPath, udid, opts = {}) { this._process = null; this._reportPath = reportPath; this._zippedReportPath = ''; this._timeout = opts.timeout && opts.timeout > 0 ? opts.timeout : DEFAULT_TIMEOUT_MS; this._profileName = opts.profileName || DEFAULT_PROFILE_NAME; this._pid = opts.pid; this._udid = udid; this._logger = _appiumSupport.logger.getLogger(`${_lodash.default.truncate(this._profileName, { length: 10 })}@${this._udid.substring(0, 8)}`); this._archivePromise = null; } get profileName() { return this._profileName; } async getOriginalReportPath() { return (await _appiumSupport.fs.exists(this._reportPath)) ? this._reportPath : ''; } async getZippedReportPath() { if (await _appiumSupport.fs.exists(this._zippedReportPath)) { return this._zippedReportPath; } const originalReportPath = await this.getOriginalReportPath(); if (!originalReportPath) { return ''; } const zippedReportPath = originalReportPath.replace(`.${DEFAULT_EXT}`, '.zip'); if (!this._archivePromise) { this._archivePromise = _appiumSupport.zip.toArchive(zippedReportPath, { cwd: originalReportPath }); } await this._archivePromise; this._zippedReportPath = zippedReportPath; return this._zippedReportPath; } isRunning() { var _this$_process; return !!((_this$_process = this._process) !== null && _this$_process !== void 0 && _this$_process.isRunning); } async _enforceTermination() { if (this._process && this.isRunning()) { this._logger.debug('Force-stopping the currently running perf recording'); try { await this._process.stop('SIGKILL'); } catch (ign) {} } this._process = null; if (this._archivePromise) { this._archivePromise.then(() => _appiumSupport.fs.rimraf(this._zippedReportPath)).finally(() => { this._archivePromise = null; }).catch(() => {}); } else { await _appiumSupport.fs.rimraf(this._zippedReportPath); } await _appiumSupport.fs.rimraf(this._reportPath); return ''; } async start() { const instruments = await requireInstruments(); const args = ['-w', this._udid, '-t', this._profileName, '-D', this._reportPath, '-l', `${this._timeout}`]; if (this._pid) { args.push('-p', `${this._pid}`); } const fullCmd = [instruments, ...args]; this._process = new _teen_process.SubProcess(fullCmd[0], fullCmd.slice(1)); this._archivePromise = null; this._logger.debug(`Starting ${INSTRUMENTS_BINARY}: ${_appiumSupport.util.quote(fullCmd)}`); this._process.on('output', (stdout, stderr) => { if (_lodash.default.trim(stdout || stderr)) { this._logger.debug(`[${INSTRUMENTS_BINARY}] ${stdout || stderr}`); } }); this._process.once('exit', async (code, signal) => { this._process = null; if (code === 0) { this._logger.debug('Performance recording exited without errors'); try { await this.getZippedReportPath(); } catch (e) { this._logger.warn(e); } } else { await this._enforceTermination(); this._logger.warn(`Performance recording exited with error code ${code}, signal ${signal}`); } }); await this._process.start(0); try { await (0, _asyncbox.waitForCondition)(async () => { if (await this.getOriginalReportPath()) { return true; } if (!this._process) { throw new Error(`${INSTRUMENTS_BINARY} process died unexpectedly`); } return false; }, { waitMs: STARTUP_TIMEOUT_MS, intervalMs: 500 }); } catch (e) { await this._enforceTermination(); this._logger.errorAndThrow(`There is no .${DEFAULT_EXT} file found for performance profile ` + `'${this._profileName}'. Make sure the profile is supported on this device. ` + `You could use 'instruments -s' command to see the list of all available profiles. ` + `Check the server log for more details`); } this._logger.info(`The performance recording has started. Will timeout in ${this._timeout}ms`); } async stop(force = false) { if (force) { return await this._enforceTermination(); } if (!this.isRunning()) { this._logger.debug('Performance recording is not running. Returning the recent result'); return await this.getZippedReportPath(); } try { await this._process.stop('SIGINT', STOP_TIMEOUT_MS); } catch (e) { this._logger.errorAndThrow(`Performance recording has failed to exit after ${STOP_TIMEOUT_MS}ms`); } return await this.getZippedReportPath(); } } commands.mobileStartPerfRecord = async function mobileStartPerfRecord(opts = {}) { if (!this.isFeatureEnabled(PERF_RECORD_FEAT_NAME) && !this.isRealDevice()) { _logger.default.errorAndThrow(PERF_RECORD_SECURITY_MESSAGE); } const { timeout = DEFAULT_TIMEOUT_MS, profileName = DEFAULT_PROFILE_NAME, pid } = opts; if (!_lodash.default.isEmpty(this._perfRecorders)) { const recorders = this._perfRecorders.filter(x => x.profileName === profileName); if (!_lodash.default.isEmpty(recorders)) { for (const recorder of recorders) { if (recorder.isRunning()) { _logger.default.debug(`Performance recorder for '${profileName}' on device '${this.opts.device.udid}' ` + ` is already running. Doing nothing`); return; } _lodash.default.pull(this._perfRecorders, recorder); await recorder.stop(true); } } } const reportPath = _path.default.resolve(_os.default.tmpdir(), `appium_perf_${profileName.replace(/\W/g, '_')}_${_appiumSupport.util.uuidV4().substring(0, 8)}.${DEFAULT_EXT}`); let realPid; if (pid) { if (_lodash.default.toLower(pid) === DEFAULT_PID) { const appInfo = await this.proxyCommand('/wda/activeAppInfo', 'GET'); realPid = appInfo.pid; } else { realPid = pid; } } const recorder = new PerfRecorder(reportPath, this.opts.device.udid, { timeout: parseInt(timeout, 10), profileName, pid: parseInt(realPid, 10) }); await recorder.start(); this._perfRecorders = [...(this._perfRecorders || []), recorder]; }; commands.mobileStopPerfRecord = async function mobileStopPerfRecord(opts = {}) { if (!this.isFeatureEnabled(PERF_RECORD_FEAT_NAME) && !this.isRealDevice()) { _logger.default.errorAndThrow(PERF_RECORD_SECURITY_MESSAGE); } if (_lodash.default.isEmpty(this._perfRecorders)) { _logger.default.info('No performance recorders have been started. Doing nothing'); return ''; } const { remotePath, user, pass, method, profileName = DEFAULT_PROFILE_NAME } = opts; const recorders = this._perfRecorders.filter(x => x.profileName === profileName); if (_lodash.default.isEmpty(recorders)) { _logger.default.errorAndThrow(`There are no records for performance profile '${profileName}' ` + `and device ${this.opts.device.udid}. Have you started the profiling before?`); } const resultPath = await recorders[0].stop(); if (!(await _appiumSupport.fs.exists(resultPath))) { _logger.default.errorAndThrow(`There is no .${DEFAULT_EXT} file found for performance profile '${profileName}' ` + `and device ${this.opts.device.udid}. Make sure the profile is supported on this device. ` + `You could use 'instruments -s' command to see the list of all available profiles.`); } return await (0, _utils.encodeBase64OrUpload)(resultPath, remotePath, { user, pass, method }); }; var _default = commands; exports.default = _default;require('source-map-support').install(); //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi9jb21tYW5kcy9wZXJmb3JtYW5jZS5qcyJdLCJuYW1lcyI6WyJjb21tYW5kcyIsIlBFUkZfUkVDT1JEX0ZFQVRfTkFNRSIsIlBFUkZfUkVDT1JEX1NFQ1VSSVRZX01FU1NBR0UiLCJERUZBVUxUX1RJTUVPVVRfTVMiLCJTVE9QX1RJTUVPVVRfTVMiLCJTVEFSVFVQX1RJTUVPVVRfTVMiLCJERUZBVUxUX1BST0ZJTEVfTkFNRSIsIkRFRkFVTFRfRVhUIiwiREVGQVVMVF9QSUQiLCJJTlNUUlVNRU5UU19CSU5BUlkiLCJyZXF1aXJlSW5zdHJ1bWVudHMiLCJmcyIsIndoaWNoIiwiZSIsImxvZyIsImVycm9yQW5kVGhyb3ciLCJQZXJmUmVjb3JkZXIiLCJjb25zdHJ1Y3RvciIsInJlcG9ydFBhdGgiLCJ1ZGlkIiwib3B0cyIsIl9wcm9jZXNzIiwiX3JlcG9ydFBhdGgiLCJfemlwcGVkUmVwb3J0UGF0aCIsIl90aW1lb3V0IiwidGltZW91dCIsIl9wcm9maWxlTmFtZSIsInByb2ZpbGVOYW1lIiwiX3BpZCIsInBpZCIsIl91ZGlkIiwiX2xvZ2dlciIsImxvZ2dlciIsImdldExvZ2dlciIsIl8iLCJ0cnVuY2F0ZSIsImxlbmd0aCIsInN1YnN0cmluZyIsIl9hcmNoaXZlUHJvbWlzZSIsImdldE9yaWdpbmFsUmVwb3J0UGF0aCIsImV4aXN0cyIsImdldFppcHBlZFJlcG9ydFBhdGgiLCJvcmlnaW5hbFJlcG9ydFBhdGgiLCJ6aXBwZWRSZXBvcnRQYXRoIiwicmVwbGFjZSIsInppcCIsInRvQXJjaGl2ZSIsImN3ZCIsImlzUnVubmluZyIsIl9lbmZvcmNlVGVybWluYXRpb24iLCJkZWJ1ZyIsInN0b3AiLCJpZ24iLCJ0aGVuIiwicmltcmFmIiwiZmluYWxseSIsImNhdGNoIiwic3RhcnQiLCJpbnN0cnVtZW50cyIsImFyZ3MiLCJwdXNoIiwiZnVsbENtZCIsIlN1YlByb2Nlc3MiLCJzbGljZSIsInV0aWwiLCJxdW90ZSIsIm9uIiwic3Rkb3V0Iiwic3RkZXJyIiwidHJpbSIsIm9uY2UiLCJjb2RlIiwic2lnbmFsIiwid2FybiIsIkVycm9yIiwid2FpdE1zIiwiaW50ZXJ2YWxNcyIsImluZm8iLCJmb3JjZSIsIm1vYmlsZVN0YXJ0UGVyZlJlY29yZCIsImlzRmVhdHVyZUVuYWJsZWQiLCJpc1JlYWxEZXZpY2UiLCJpc0VtcHR5IiwiX3BlcmZSZWNvcmRlcnMiLCJyZWNvcmRlcnMiLCJmaWx0ZXIiLCJ4IiwicmVjb3JkZXIiLCJkZXZpY2UiLCJwdWxsIiwicGF0aCIsInJlc29sdmUiLCJvcyIsInRtcGRpciIsInV1aWRWNCIsInJlYWxQaWQiLCJ0b0xvd2VyIiwiYXBwSW5mbyIsInByb3h5Q29tbWFuZCIsInBhcnNlSW50IiwibW9iaWxlU3RvcFBlcmZSZWNvcmQiLCJyZW1vdGVQYXRoIiwidXNlciIsInBhc3MiLCJtZXRob2QiLCJyZXN1bHRQYXRoIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQUFBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUdBLElBQUlBLFFBQVEsR0FBRyxFQUFmOztBQUVBLE1BQU1DLHFCQUFxQixHQUFHLGFBQTlCO0FBQ0EsTUFBTUMsNEJBQTRCLEdBQUcsdUVBQ2xDLCtEQUE4REQscUJBQXNCLElBRGxELEdBRW5DLHVIQUZGO0FBR0EsTUFBTUUsa0JBQWtCLEdBQUcsSUFBSSxFQUFKLEdBQVMsSUFBcEM7QUFDQSxNQUFNQyxlQUFlLEdBQUcsSUFBSSxFQUFKLEdBQVMsSUFBakM7QUFDQSxNQUFNQyxrQkFBa0IsR0FBRyxLQUFLLElBQWhDO0FBQ0EsTUFBTUMsb0JBQW9CLEdBQUcsa0JBQTdCO0FBQ0EsTUFBTUMsV0FBVyxHQUFHLE9BQXBCO0FBQ0EsTUFBTUMsV0FBVyxHQUFHLFNBQXBCO0FBQ0EsTUFBTUMsa0JBQWtCLEdBQUcsYUFBM0I7O0FBR0EsZUFBZUMsa0JBQWYsR0FBcUM7QUFDbkMsTUFBSTtBQUNGLFdBQU8sTUFBTUMsa0JBQUdDLEtBQUgsQ0FBU0gsa0JBQVQsQ0FBYjtBQUNELEdB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QU07QUFDSndCLElBQUFBLFVBREk7QUFFSkMsSUFBQUEsSUFGSTtBQUdKQyxJQUFBQSxJQUhJO0FBSUpDLElBQUFBLE1BSkk7QUFLSjdFLElBQUFBLFdBQVcsR0FBR3JCO0FBTFYsTUFNRmMsSUFOSjs7QUFRQSxRQUFNZ0UsU0FBUyxHQUFHLEtBQUtELGNBQUwsQ0FDZkUsTUFEZSxDQUNQQyxDQUFELElBQU9BLENBQUMsQ0FBQzNELFdBQUYsS0FBa0JBLFdBRGpCLENBQWxCOztBQUVBLE1BQUlPLGdCQUFFZ0QsT0FBRixDQUFVRSxTQUFWLENBQUosRUFBMEI7QUFDeEJ0RSxvQkFBSUMsYUFBSixDQUFtQixpREFBZ0RZLFdBQVksSUFBN0QsR0FDZixjQUFhLEtBQUtQLElBQUwsQ0FBVW9FLE1BQVYsQ0FBaUJyRSxJQUFLLDBDQUR0QztBQUVEOztBQUNELFFBQU1zRixVQUFVLEdBQUcsTUFBTXJCLFNBQVMsQ0FBQyxDQUFELENBQVQsQ0FBYWpDLElBQWIsRUFBekI7O0FBQ0EsTUFBSSxFQUFDLE1BQU14QyxrQkFBRzZCLE1BQUgsQ0FBVWlFLFVBQVYsQ0FBUCxDQUFKLEVBQWtDO0FBQ2hDM0Ysb0JBQUlDLGFBQUosQ0FBbUIsZ0JBQWVSLFdBQVksd0NBQXVDb0IsV0FBWSxJQUEvRSxHQUNmLGNBQWEsS0FBS1AsSUFBTCxDQUFVb0UsTUFBVixDQUFpQnJFLElBQUssdURBRHBCLEdBRWYsbUZBRkg7QUFHRDs7QUFFRCxTQUFPLE1BQU0saUNBQXFCc0YsVUFBckIsRUFBaUNKLFVBQWpDLEVBQTZDO0FBQUVDLElBQUFBLElBQUY7QUFBUUMsSUFBQUEsSUFBUjtBQUFjQyxJQUFBQTtBQUFkLEdBQTdDLENBQWI7QUFDRCxDQWhDRDs7ZUFvQ2V4RyxRIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgZnMsIHppcCwgbG9nZ2VyLCB1dGlsIH0gZnJvbSAnYXBwaXVtLXN1cHBvcnQnO1xuaW1wb3J0IHsgU3ViUHJvY2VzcyB9IGZyb20gJ3RlZW5fcHJvY2Vzcyc7XG5pbXBvcnQgbG9nIGZyb20gJy4uL2xvZ2dlcic7XG5pbXBvcnQgeyBlbmNvZGVCYXNlNjRPclVwbG9hZCB9IGZyb20gJy4uL3V0aWxzJztcbmltcG9ydCB7IHdhaXRGb3JDb25kaXRpb24gfSBmcm9tICdhc3luY2JveCc7XG5pbXBvcnQgb3MgZnJvbSAnb3MnO1xuXG5cbmxldCBjb21tYW5kcyA9IHt9O1xuXG5jb25zdCBQRVJGX1JFQ09SRF9GRUFUX05BTUUgPSAncGVyZl9yZWNvcmQnO1xuY29uc3QgUEVSRl9SRUNPUkRfU0VDVVJJVFlfTUVTU0FHRSA9ICdQZXJmb3JtYW5jZSBtZWFzdXJlbWVudCByZXF1aXJlcyByZWxheGluZyBzZWN1cml0eSBmb3Igc2ltdWxhdG9yLiAnICtcbiAgYFBsZWFzZSBzZXQgJy0tcmVsYXhlZC1zZWN1cml0eScgb3IgJy0tYWxsb3ctaW5zZWN1cmUnIHdpdGggJyR7UEVSRl9SRUNPUkRfRkVBVF9OQU1FfScgYCArXG4gICdyZWZlcmVuY2luZyBodHRwczovL2dpdGh1Yi5jb20vYXBwaXVtL2FwcGl1bS9ibG9iL21hc3Rlci9kb2NzL2VuL3dyaXRpbmctcnVubmluZy1hcHBpdW0vc2VjdXJpdHkubWQgZm9yIG1vcmUgZGV0YWlscy4nO1xuY29uc3QgREVGQVVMVF9USU1FT1VUX01TID0gNSAqIDYwICogMTAwMDtcbmNvbnN0IFNUT1BfVElNRU9VVF9NUyA9IDMgKiA2MCAqIDEwMDA7XG5jb25zdCBTVEFSVFVQX1RJTUVPVVRfTVMgPSAxNSAqIDEwMDA7XG5jb25zdCBERUZBVUxUX1BST0ZJTEVfTkFNRSA9ICdBY3Rpdml0eSBNb25pdG9yJztcbmNvbnN0IERFRkFVTFRfRVhUID0gJ3RyYWNlJztcbmNvbnN0IERFRkFVTFRfUElEID0gJ2N1cnJlbnQnO1xuY29uc3QgSU5TVFJVTUVOVFNfQklOQVJZID0gJ2luc3RydW1lbnRzJztcblxuXG5hc3luYyBmdW5jdGlvbiByZXF1aXJlSW5zdHJ1bWVudHMgKCkge1xuICB0cnkge1xuICAgIHJldHVybiBhd2FpdCBmcy53aGljaChJTlNUUlVNRU5UU19CSU5BUlkpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgbG9nLmVycm9yQW5kVGhyb3coYCR7SU5TVFJVTUVOVFNfQklOQVJZfSBoYXMgbm90IGJlZW4gZm91bmQgaW4gUEFUSC4gYCArXG4gICAgICBgUGxlYXNlIG1ha2Ugc3VyZSBYY29kZSBkZXZlbG9wbWVudCB0b29scyBhcmUgaW5zdGFsbGVkYCk7XG4gIH1cbn1cblxuXG5jbGFzcyBQZXJmUmVjb3JkZXIge1xuICBjb25zdHJ1Y3RvciAocmVwb3J0UGF0aCwgdWRpZCwgb3B0cyA9IHt9KSB7XG4gICAgdGhpcy5fcHJvY2VzcyA9IG51bGw7XG4gICAgdGhpcy5fcmVwb3J0UGF0aCA9IHJlcG9ydFBhdGg7XG4gICAgdGhpcy5femlwcGVkUmVwb3J0UGF0aCA9ICcnO1xuICAgIHRoaXMuX3RpbWVvdXQgPSAob3B0cy50aW1lb3V0ICYmIG9wdHMudGltZW91dCA+IDApID8gb3B0cy50aW1lb3V0IDogREVGQVVMVF9USU1FT1VUX01TO1xuICAgIHRoaXMuX3Byb2ZpbGVOYW1lID0gb3B0cy5wcm9maWxlTmFtZSB8fCBERUZBVUxUX1BST0ZJTEVfTkFNRTtcbiAgICB0aGlzLl9waWQgPSBvcHRzLnBpZDtcbiAgICB0aGlzLl91ZGlkID0gdWRpZDtcbiAgICB0aGlzLl9sb2dnZXIgPSBsb2dnZXIuZ2V0TG9nZ2VyKFxuICAgICAgYCR7Xy50cnVuY2F0ZSh0aGlzLl9wcm9maWxlTmFtZSwge2xlbmd0aDogMTB9KX1AJHt0aGlzLl91ZGlkLnN1YnN0cmluZygwLCA4KX1gKTtcbiAgICB0aGlzLl9hcmNoaXZlUHJvbWlzZSA9IG51bGw7XG4gIH1cblxuICBnZXQgcHJvZmlsZU5hbWUgKCkge1xuICAgIHJldHVybiB0aGlzLl9wcm9maWxlTmFtZTtcbiAgfVxuXG4gIGFzeW5jIGdldE9yaWdpbmFsUmVwb3J0UGF0aCAoKSB7XG4gICAgcmV0dXJuIChhd2FpdCBmcy5leGlzdHModGhpcy5fcmVwb3J0UGF0aCkpID8gdGhpcy5fcmVwb3J0UGF0aCA6ICcnO1xuICB9XG5cbiAgYXN5bmMgZ2V0WmlwcGVkUmVwb3J0UGF0aCAoKSB7XG4gICAgaWYgKGF3YWl0IGZzLmV4aXN0cyh0aGlzLl96aXBwZWRSZXBvcnRQYXRoKSkge1xuICAgICAgcmV0dXJuIHRoaXMuX3ppcHBlZFJlcG9ydFBhdGg7XG4gICAgfVxuICAgIGNvbnN0IG9yaWdpbmFsUmVwb3J0UGF0aCA9IGF3YWl0IHRoaXMuZ2V0T3JpZ2luYWxSZXBvcnRQYXRoKCk7XG4gICAgaWYgKCFvcmlnaW5hbFJlcG9ydFBhdGgpIHtcbiAgICAgIHJldHVybiAnJztcbiAgICB9XG4gICAgY29uc3QgemlwcGVkUmVwb3J0UGF0aCA9IG9yaWdpbmFsUmVwb3J0UGF0aC5yZXBsYWNlKGAuJHtERUZBVUxUX0VYVH1gLCAnLnppcCcpO1xuICAgIC8vIFRoaXMgaXMgdG8gcHJldmVudCBwb3NzaWJsZSByYWNlIGNvbmRpdGlvbnMsIGJlY2F1c2UgdGhlIGFyY2hpdmUgb3BlcmF0aW9uXG4gICAgLy8gY291bGQgYmUgcHJldHR5IHRpbWUtaW50ZW5zaXZlXG4gICAgaWYgKCF0aGlzLl9hcmNoaXZlUHJvbWlzZSkge1xuICAgICAgdGhpcy5fYXJjaGl2ZVByb21pc2UgPSB6aXAudG9BcmNoaXZlKHppcHBlZFJlcG9ydFBhdGgsIHtcbiAgICAgICAgY3dkOiBvcmlnaW5hbFJlcG9ydFBhdGgsXG4gICAgICB9KTtcbiAgICB9XG4gICAgYXdhaXQgdGhpcy5fYXJjaGl2ZVByb21pc2U7XG4gICAgdGhpcy5femlwcGVkUmVwb3J0UGF0aCA9IHppcHBlZFJlcG9ydFBhdGg7XG4gICAgcmV0dXJuIHRoaXMuX3ppcHBlZFJlcG9ydFBhdGg7XG4gIH1cblxuICBpc1J1bm5pbmcgKCkge1xuICAgIHJldHVybiAhISh0aGlzLl9wcm9jZXNzPy5pc1J1bm5pbmcpO1xuICB9XG5cbiAgYXN5bmMgX2VuZm9yY2VUZXJtaW5hdGlvbiAoKSB7XG4gICAgaWYgKHRoaXMuX3Byb2Nlc3MgJiYgdGhpcy5pc1J1bm5pbmcoKSkge1xuICAgICAgdGhpcy5fbG9nZ2VyLmRlYnVnKCdGb3JjZS1zdG9wcGluZyB0aGUgY3VycmVudGx5IHJ1bm5pbmcgcGVyZiByZWNvcmRpbmcnKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuX3Byb2Nlc3Muc3RvcCgnU0lHS0lMTCcpO1xuICAgICAgfSBjYXRjaCAoaWduKSB7fVxuICAgIH1cbiAgICB0aGlzLl9wcm9jZXNzID0gbnVsbDtcbiAgICBpZiAodGhpcy5fYXJjaGl2ZVByb21pc2UpIHtcbiAgICAgIHRoaXMuX2FyY2hpdmVQcm9taXNlXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBwcm9taXNlL3ByZWZlci1hd2FpdC10by10aGVuXG4gICAgICAgIC50aGVuKCgpID0+IGZzLnJpbXJhZih0aGlzLl96aXBwZWRSZXBvcnRQYXRoKSlcbiAgICAgICAgLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgICAgIHRoaXMuX2FyY2hpdmVQcm9taXNlID0gbnVsbDtcbiAgICAgICAgfSlcbiAgICAgICAgLmNhdGNoKCgpID0+IHt9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgYXdhaXQgZnMucmltcmFmKHRoaXMuX3ppcHBlZFJlcG9ydFBhdGgpO1xuICAgIH1cbiAgICBhd2FpdCBmcy5yaW1yYWYodGhpcy5fcmVwb3J0UGF0aCk7XG4gICAgcmV0dXJuICcnO1xuICB9XG5cbiAgYXN5bmMgc3RhcnQgKCkge1xuICAgIGNvbnN0IGluc3RydW1lbnRzID0gYXdhaXQgcmVxdWlyZUluc3RydW1lbnRzKCk7XG5cbiAgICAvLyBodHRwczovL2hlbHAuYXBwbGUuY29tL2luc3RydW1lbnRzL21hYy9jdXJyZW50LyMvZGV2YjE0ZmZhYTVcbiAgICBjb25zdCBhcmdzID0gW1xuICAgICAgJy13JywgdGhpcy5fdWRpZCxcbiAgICAgICctdCcsIHRoaXMuX3Byb2ZpbGVOYW1lLFxuICAgICAgJy1EJywgdGhpcy5fcmVwb3J0UGF0aCxcbiAgICAgICctbCcsIGAke3RoaXMuX3RpbWVvdXR9YCxcbiAgICBdO1xuICAgIGlmICh0aGlzLl9waWQpIHtcbiAgICAgIGFyZ3MucHVzaCgnLXAnLCBgJHt0aGlzLl9waWR9YCk7XG4gICAgfVxuICAgIGNvbnN0IGZ1bGxDbWQgPSBbXG4gICAgICBpbnN0cnVtZW50cyxcbiAgICAgIC4uLmFyZ3MsXG4gICAgXTtcbiAgICB0aGlzLl9wcm9jZXNzID0gbmV3IFN1YlByb2Nlc3MoZnVsbENtZFswXSwgZnVsbENtZC5zbGljZSgxKSk7XG4gICAgdGhpcy5fYXJjaGl2ZVByb21pc2UgPSBudWxsO1xuICAgIHRoaXMuX2xvZ2dlci5kZWJ1ZyhgU3RhcnRpbmcgJHtJTlNUUlVNRU5UU19CSU5BUll9OiAke3V0aWwucXVvdGUoZnVsbENtZCl9YCk7XG4gICAgdGhpcy5fcHJvY2Vzcy5vbignb3V0cHV0JywgKHN0ZG91dCwgc3RkZXJyKSA9PiB7XG4gICAgICBpZiAoXy50cmltKHN0ZG91dCB8fCBzdGRlcnIpKSB7XG4gICAgICAgIHRoaXMuX2xvZ2dlci5kZWJ1ZyhgWyR7SU5TVFJVTUVOVFNfQklOQVJZfV0gJHtzdGRvdXQgfHwgc3RkZXJyfWApO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHRoaXMuX3Byb2Nlc3Mub25jZSgnZXhpdCcsIGFzeW5jIChjb2RlLCBzaWduYWwpID0+IHtcbiAgICAgIHRoaXMuX3Byb2Nlc3MgPSBudWxsO1xuICAgICAgaWYgKGNvZGUgPT09IDApIHtcbiAgICAgICAgdGhpcy5fbG9nZ2VyLmRlYnVnKCdQZXJmb3JtYW5jZSByZWNvcmRpbmcgZXhpdGVkIHdpdGhvdXQgZXJyb3JzJyk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gY2FjaGUgemlwcGVkIHJlcG9ydFxuICAgICAgICAgIGF3YWl0IHRoaXMuZ2V0WmlwcGVkUmVwb3J0UGF0aCgpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgdGhpcy5fbG9nZ2VyLndhcm4oZSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGF3YWl0IHRoaXMuX2VuZm9yY2VUZXJtaW5hdGlvbigpO1xuICAgICAgICB0aGlzLl9sb2dnZXIud2FybihgUGVyZm9ybWFuY2UgcmVjb3JkaW5nIGV4aXRlZCB3aXRoIGVycm9yIGNvZGUgJHtjb2RlfSwgc2lnbmFsICR7c2lnbmFsfWApO1xuICAgICAgfVxuICAgIH0pO1xuICAgIGF3YWl0IHRoaXMuX3Byb2Nlc3Muc3RhcnQoMCk7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHdhaXRGb3JDb25kaXRpb24oYXN5bmMgKCkgPT4ge1xuICAgICAgICBpZiAoYXdhaXQgdGhpcy5nZXRPcmlnaW5hbFJlcG9ydFBhdGgoKSkge1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIGlmICghdGhpcy5fcHJvY2Vzcykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgJHtJTlNUUlVNRU5UU19CSU5BUll9IHByb2Nlc3MgZGllZCB1bmV4cGVjdGVkbHlgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9LCB7XG4gICAgICAgIHdhaXRNczogU1RBUlRVUF9USU1FT1VUX01TLFxuICAgICAgICBpbnRlcnZhbE1zOiA1MDAsXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBhd2FpdCB0aGlzLl9lbmZvcmNlVGVybWluYXRpb24oKTtcbiAgICAgIHRoaXMuX2xvZ2dlci5lcnJvckFuZFRocm93KGBUaGVyZSBpcyBubyAuJHtERUZBVUxUX0VYVH0gZmlsZSBmb3VuZCBmb3IgcGVyZm9ybWFuY2UgcHJvZmlsZSBgICtcbiAgICAgICAgYCcke3RoaXMuX3Byb2ZpbGVOYW1lfScuIE1ha2Ugc3VyZSB0aGUgcHJvZmlsZSBpcyBzdXBwb3J0ZWQgb24gdGhpcyBkZXZpY2UuIGAgK1xuICAgICAgICBgWW91IGNvdWxkIHVzZSAnaW5zdHJ1bWVudHMgLXMnIGNvbW1hbmQgdG8gc2VlIHRoZSBsaXN0IG9mIGFsbCBhdmFpbGFibGUgcHJvZmlsZXMuIGAgK1xuICAgICAgICBgQ2hlY2sgdGhlIHNlcnZlciBsb2cgZm9yIG1vcmUgZGV0YWlsc2ApO1xuICAgIH1cbiAgICB0aGlzLl9sb2dnZXIuaW5mbyhgVGhlIHBlcmZvcm1hbmNlIHJlY29yZGluZyBoYXMgc3RhcnRlZC4gV2lsbCB0aW1lb3V0IGluICR7dGhpcy5fdGltZW91dH1tc2ApO1xuICB9XG5cbiAgYXN5bmMgc3RvcCAoZm9yY2UgPSBmYWxzZSkge1xuICAgIGlmIChmb3JjZSkge1xuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuX2VuZm9yY2VUZXJtaW5hdGlvbigpO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5pc1J1bm5pbmcoKSkge1xuICAgICAgdGhpcy5fbG9nZ2VyLmRlYnVnKCdQZXJmb3JtYW5jZSByZWNvcmRpbmcgaXMgbm90IHJ1bm5pbmcuIFJldHVybmluZyB0aGUgcmVjZW50IHJlc3VsdCcpO1xuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuZ2V0WmlwcGVkUmVwb3J0UGF0aCgpO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLl9wcm9jZXNzLnN0b3AoJ1NJR0lOVCcsIFNUT1BfVElNRU9VVF9NUyk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhpcy5fbG9nZ2VyLmVycm9yQW5kVGhyb3coYFBlcmZvcm1hbmNlIHJlY29yZGluZyBoYXMgZmFpbGVkIHRvIGV4aXQgYWZ0ZXIgJHtTVE9QX1RJTUVPVVRfTVN9bXNgKTtcbiAgICB9XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMuZ2V0WmlwcGVkUmVwb3J0UGF0aCgpO1xuICB9XG59XG5cblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBTdGFydFBlcmZSZWNvcmRPcHRpb25zXG4gKlxuICogQHByb3BlcnR5IHs/bnVtYmVyfHN0cmluZ30gdGltZW91dCBbMzAwMDAwXSAtIFRoZSBtYXhpbXVtIGNvdW50IG9mIG1pbGxpc2Vjb25kcyB0byByZWNvcmQgdGhlIHByb2ZpbGluZyBpbmZvcm1hdGlvbi5cbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gcHJvZmlsZU5hbWUgW0FjdGl2aXR5IE1vbml0b3JdIC0gVGhlIG5hbWUgb2YgZXhpc3RpbmcgcGVyZm9ybWFuY2UgcHJvZmlsZSB0byBhcHBseS5cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRXhlY3V0ZSBgaW5zdHJ1bWVudHMgLXNgIHRvIHNob3cgdGhlIGxpc3Qgb2YgYXZhaWxhYmxlIHByb2ZpbGVzLlxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDYW4gYWxzbyBjb250YWluIHRoZSBmdWxsIHBhdGggdG8gdGhlIGNob3NlbiB0ZW1wbGF0ZSBvbiB0aGUgc2VydmVyIGZpbGUgc3lzdGVtLlxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOb3RlLCB0aGF0IG5vdCBhbGwgcHJvZmlsZXMgYXJlIHN1cHBvcnRlZCBvbiBtb2JpbGUgZGV2aWNlcy5cbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ3xudW1iZXJ9IHBpZCAtIFRoZSBJRCBvZiB0aGUgcHJvY2VzcyB0byBtZWFzdXJlIHRoZSBwZXJmb3JtYW5jZSBmb3IuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTZXQgaXQgdG8gYGN1cnJlbnRgIGluIG9yZGVyIHRvIG1lYXN1cmUgdGhlIHBlcmZvcm1hbmNlIG9mXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgcHJvY2Vzcywgd2hpY2ggYmVsb25ncyB0byB0aGUgY3VycmVudGx5IGFjdGl2ZSBhcHBsaWNhdGlvbi5cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFsbCBwcm9jZXNzZXMgcnVubmluZyBvbiB0aGUgZGV2aWNlIGFyZSBtZWFzdXJlZCBpZlxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGlkIGlzIHVuc2V0ICh0aGUgZGVmYXVsdCBzZXR0aW5nKS5cbiAqL1xuXG4vKipcbiAqIFN0YXJ0cyBwZXJmb3JtYW5jZSBwcm9maWxpbmcgZm9yIHRoZSBkZXZpY2UgdW5kZXIgdGVzdC5cbiAqIFJlbGF4aW5nIHNlY3VyaXR5IGlzIG1hbmRhdG9yeSBmb3Igc2ltdWxhdG9ycy4gSXQgY2FuIGFsd2F5cyB3b3JrIGZvciByZWFsIGRldmljZXMuXG4gKlxuICogVGhlIGBpbnN0cnVtZW50c2AgZGV2ZWxvcGVyIHV0aWxpdHkgaXMgdXNlZCBmb3IgdGhpcyBwdXJwb3NlIHVuZGVyIHRoZSBob29kLlxuICogSXQgaXMgcG9zc2libGUgdG8gcmVjb3JkIG11bHRpcGxlIHByb2ZpbGVzIGF0IHRoZSBzYW1lIHRpbWUuXG4gKiBSZWFkIGh0dHBzOi8vZGV2ZWxvcGVyLmFwcGxlLmNvbS9saWJyYXJ5L2NvbnRlbnQvZG9jdW1lbnRhdGlvbi9EZXZlbG9wZXJUb29scy9Db25jZXB0dWFsL0luc3RydW1lbnRzVXNlckd1aWRlL1JlY29yZGluZyxQYXVzaW5nLGFuZFN0b3BwaW5nVHJhY2VzLmh0bWxcbiAqIGZvciBtb3JlIGRldGFpbHMuXG4gKlxuICogQHBhcmFtIHs/U3RhcnRQZXJmUmVjb3JkT3B0aW9uc30gb3B0cyAtIFRoZSBzZXQgb2YgcG9zc2libGUgc3RhcnQgcmVjb3JkIG9wdGlvbnNcbiAqL1xuY29tbWFuZHMubW9iaWxlU3RhcnRQZXJmUmVjb3JkID0gYXN5bmMgZnVuY3Rpb24gbW9iaWxlU3RhcnRQZXJmUmVjb3JkIChvcHRzID0ge30pIHtcbiAgaWYgKCF0aGlzLmlzRmVhdHVyZUVuYWJsZWQoUEVSRl9SRUNPUkRfRkVBVF9OQU1FKSAmJiAhdGhpcy5pc1JlYWxEZXZpY2UoKSkge1xuICAgIGxvZy5lcnJvckFuZFRocm93KFBFUkZfUkVDT1JEX1NFQ1VSSVRZX01FU1NBR0UpO1xuICB9XG5cbiAgY29uc3Qge1xuICAgIHRpbWVvdXQgPSBERUZBVUxUX1RJTUVPVVRfTVMsXG4gICAgcHJvZmlsZU5hbWUgPSBERUZBVUxUX1BST0ZJTEVfTkFNRSxcbiAgICBwaWQsXG4gIH0gPSBvcHRzO1xuXG4gIGlmICghXy5pc0VtcHR5KHRoaXMuX3BlcmZSZWNvcmRlcnMpKSB7XG4gICAgY29uc3QgcmVjb3JkZXJzID0gdGhpcy5fcGVyZlJlY29yZGVyc1xuICAgICAgLmZpbHRlcigoeCkgPT4geC5wcm9maWxlTmFtZSA9PT0gcHJvZmlsZU5hbWUpO1xuICAgIGlmICghXy5pc0VtcHR5KHJlY29yZGVycykpIHtcbiAgICAgIGZvciAoY29uc3QgcmVjb3JkZXIgb2YgcmVjb3JkZXJzKSB7XG4gICAgICAgIGlmIChyZWNvcmRlci5pc1J1bm5pbmcoKSkge1xuICAgICAgICAgIGxvZy5kZWJ1ZyhgUGVyZm9ybWFuY2UgcmVjb3JkZXIgZm9yICcke3Byb2ZpbGVOYW1lfScgb24gZGV2aWNlICcke3RoaXMub3B0cy5kZXZpY2UudWRpZH0nIGAgK1xuICAgICAgICAgICAgYCBpcyBhbHJlYWR5IHJ1bm5pbmcuIERvaW5nIG5vdGhpbmdgKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgXy5wdWxsKHRoaXMuX3BlcmZSZWNvcmRlcnMsIHJlY29yZGVyKTtcbiAgICAgICAgYXdhaXQgcmVjb3JkZXIuc3RvcCh0cnVlKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBjb25zdCByZXBvcnRQYXRoID0gcGF0aC5yZXNvbHZlKG9zLnRtcGRpcigpLFxuICAgIGBhcHBpdW1fcGVyZl8ke3Byb2ZpbGVOYW1lLnJlcGxhY2UoL1xcVy9nLCAnXycpfV8ke3V0aWwudXVpZFY0KCkuc3Vic3RyaW5nKDAsIDgpfS4ke0RFRkFVTFRfRVhUfWApO1xuICBsZXQgcmVhbFBpZDtcbiAgaWYgKHBpZCkge1xuICAgIGlmIChfLnRvTG93ZXIocGlkKSA9PT0gREVGQVVMVF9QSUQpIHtcbiAgICAgIGNvbnN0IGFwcEluZm8gPSBhd2FpdCB0aGlzLnByb3h5Q29tbWFuZCgnL3dkYS9hY3RpdmVBcHBJbmZvJywgJ0dFVCcpO1xuICAgICAgcmVhbFBpZCA9IGFwcEluZm8ucGlkO1xuICAgIH0gZWxzZSB7XG4gICAgICByZWFsUGlkID0gcGlkO1xuICAgIH1cbiAgfVxuICBjb25zdCByZWNvcmRlciA9IG5ldyBQZXJmUmVjb3JkZXIocmVwb3J0UGF0aCwgdGhpcy5vcHRzLmRldmljZS51ZGlkLCB7XG4gICAgdGltZW91dDogcGFyc2VJbnQodGltZW91dCwgMTApLFxuICAgIHByb2ZpbGVOYW1lLFxuICAgIHBpZDogcGFyc2VJbnQocmVhbFBpZCwgMTApLFxuICB9KTtcbiAgYXdhaXQgcmVjb3JkZXIuc3RhcnQoKTtcbiAgdGhpcy5fcGVyZlJlY29yZGVycyA9IFsuLi4odGhpcy5fcGVyZlJlY29yZGVycyB8fCBbXSksIHJlY29yZGVyXTtcbn07XG5cbi8qKlxuICogQHR5cGVkZWYge09iamVjdH0gU3RvcFJlY29yZGluZ09wdGlvbnNcbiAqXG4gKiBAcHJvcGVydHkgez9zdHJpbmd9IHJlbW90ZVBhdGggLSBUaGUgcGF0aCB0byB0aGUgcmVtb3RlIGxvY2F0aW9uLCB3aGVyZSB0aGUgcmVzdWx0aW5nIHppcHBlZCAudHJhY2UgZmlsZSBzaG91bGQgYmUgdXBsb2FkZWQuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaGUgZm9sbG93aW5nIHByb3RvY29scyBhcmUgc3VwcG9ydGVkOiBodHRwL2h0dHBzLCBmdHAuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOdWxsIG9yIGVtcHR5IHN0cmluZyB2YWx1ZSAodGhlIGRlZmF1bHQgc2V0dGluZykgbWVhbnMgdGhlIGNvbnRlbnQgb2YgcmVzdWx0aW5nXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlIHNob3VsZCBiZSB6aXBwZWQsIGVuY29kZWQgYXMgQmFzZTY0IGFuZCBwYXNzZWQgYXMgdGhlIGVuZHBvaW50IHJlc3BvbnNlIHZhbHVlLlxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQW4gZXhjZXB0aW9uIHdpbGwgYmUgdGhyb3duIGlmIHRoZSBnZW5lcmF0ZWQgZmlsZSBpcyB0b28gYmlnIHRvXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaXQgaW50byB0aGUgYXZhaWxhYmxlIHByb2Nlc3MgbWVtb3J5LlxuICogQHByb3BlcnR5IHs/c3RyaW5nfSB1c2VyIC0gVGhlIG5hbWUgb2YgdGhlIHVzZXIgZm9yIHRoZSByZW1vdGUgYXV0aGVudGljYXRpb24uIE9ubHkgd29ya3MgaWYgYHJlbW90ZVBhdGhgIGlzIHByb3ZpZGVkLlxuICogQHByb3BlcnR5IHs/c3RyaW5nfSBwYXNzIC0gVGhlIHBhc3N3b3JkIGZvciB0aGUgcmVtb3RlIGF1dGhlbnRpY2F0aW9uLiBPbmx5IHdvcmtzIGlmIGByZW1vdGVQYXRoYCBpcyBwcm92aWRlZC5cbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gbWV0aG9kIFtQVVRdIC0gVGhlIGh0dHAgbXVsdGlwYXJ0IHVwbG9hZCBtZXRob2QgbmFtZS4gT25seSB3b3JrcyBpZiBgcmVtb3RlUGF0aGAgaXMgcHJvdmlkZWQuXG4gKiBAcHJvcGVydHkgez9zdHJpbmd9IHByb2ZpbGVOYW1lIFtBY3Rpdml0eSBNb25pdG9yXSAtIFRoZSBuYW1lIG9mIGFuIGV4aXN0aW5nIHBlcmZvcm1hbmNlIHByb2ZpbGUgZm9yIHdoaWNoIHRoZSByZWNvcmRpbmcgaGFzIGJlZW4gbWFkZS5cbiAqL1xuXG4vKipcbiAqIFN0b3BzIHBlcmZvcm1hbmNlIHByb2ZpbGluZyBmb3IgdGhlIGRldmljZSB1bmRlciB0ZXN0LlxuICogVGhlIHJlc3VsdGluZyBmaWxlIGluIC50cmFjZSBmb3JtYXQgY2FuIGJlIGVpdGhlciByZXR1cm5lZFxuICogZGlyZWN0bHkgYXMgYmFzZTY0LWVuY29kZWQgemlwIGFyY2hpdmUgb3IgdXBsb2FkZWQgdG8gYSByZW1vdGUgbG9jYXRpb25cbiAqIChzdWNoIGZpbGVzIGNhbiBiZSBwcmV0dHkgbGFyZ2UpLiBBZnRlcndhcmRzIGl0IGlzIHBvc3NpYmxlIHRvIHVuYXJjaGl2ZSBhbmRcbiAqIG9wZW4gc3VjaCBmaWxlIHdpdGggWGNvZGUgRGV2IFRvb2xzLlxuICpcbiAqIEBwYXJhbSB7P1N0b3BSZWNvcmRpbmdPcHRpb25zfSBvcHRzIC0gVGhlIHNldCBvZiBwb3NzaWJsZSBzdG9wIHJlY29yZCBvcHRpb25zXG4gKiBAcmV0dXJuIHtzdHJpbmd9IEVpdGhlciBhbiBlbXB0eSBzdHJpbmcgaWYgdGhlIHVwbG9hZCB3YXMgc3VjY2Vzc2Z1bCBvciBiYXNlLTY0IGVuY29kZWRcbiAqIGNvbnRlbnQgb2YgemlwcGVkIC50cmFjZSBmaWxlLlxuICogQHRocm93cyB7RXJyb3J9IElmIG5vIHBlcmZvcm1hbmNlIHJlY29yZGluZyB3aXRoIGdpdmVuIHByb2ZpbGUgbmFtZS9kZXZpY2UgdWRpZCBjb21iaW5hdGlvblxuICogaGFzIGJlZW4gc3RhcnRlZCBiZWZvcmUgb3IgdGhlIHJlc3VsdGluZyAudHJhY2UgZmlsZSBoYXMgbm90IGJlZW4gZ2VuZXJhdGVkIHByb3Blcmx5LlxuICovXG5jb21tYW5kcy5tb2JpbGVTdG9wUGVyZlJlY29yZCA9IGFzeW5jIGZ1bmN0aW9uIG1vYmlsZVN0b3BQZXJmUmVjb3JkIChvcHRzID0ge30pIHtcbiAgaWYgKCF0aGlzLmlzRmVhdHVyZUVuYWJsZWQoUEVSRl9SRUNPUkRfRkVBVF9OQU1FKSAmJiAhdGhpcy5pc1JlYWxEZXZpY2UoKSkge1xuICAgIGxvZy5lcnJvckFuZFRocm93KFBFUkZfUkVDT1JEX1NFQ1VSSVRZX01FU1NBR0UpO1xuICB9XG5cbiAgaWYgKF8uaXNFbXB0eSh0aGlzLl9wZXJmUmVjb3JkZXJzKSkge1xuICAgIGxvZy5pbmZvKCdObyBwZXJmb3JtYW5jZSByZWNvcmRlcnMgaGF2ZSBiZWVuIHN0YXJ0ZWQuIERvaW5nIG5vdGhpbmcnKTtcbiAgICByZXR1cm4gJyc7XG4gIH1cblxuICBjb25zdCB7XG4gICAgcmVtb3RlUGF0aCxcbiAgICB1c2VyLFxuICAgIHBhc3MsXG4gICAgbWV0aG9kLFxuICAgIHByb2ZpbGVOYW1lID0gREVGQVVMVF9QUk9GSUxFX05BTUUsXG4gIH0gPSBvcHRzO1xuXG4gIGNvbnN0IHJlY29yZGVycyA9IHRoaXMuX3BlcmZSZWNvcmRlcnNcbiAgICAuZmlsdGVyKCh4KSA9PiB4LnByb2ZpbGVOYW1lID09PSBwcm9maWxlTmFtZSk7XG4gIGlmIChfLmlzRW1wdHkocmVjb3JkZXJzKSkge1xuICAgIGxvZy5lcnJvckFuZFRocm93KGBUaGVyZSBhcmUgbm8gcmVjb3JkcyBmb3IgcGVyZm9ybWFuY2UgcHJvZmlsZSAnJHtwcm9maWxlTmFtZX0nIGAgK1xuICAgICAgYGFuZCBkZXZpY2UgJHt0aGlzLm9wdHMuZGV2aWNlLnVkaWR9LiBIYXZlIHlvdSBzdGFydGVkIHRoZSBwcm9maWxpbmcgYmVmb3JlP2ApO1xuICB9XG4gIGNvbnN0IHJlc3VsdFBhdGggPSBhd2FpdCByZWNvcmRlcnNbMF0uc3RvcCgpO1xuICBpZiAoIWF3YWl0IGZzLmV4aXN0cyhyZXN1bHRQYXRoKSkge1xuICAgIGxvZy5lcnJvckFuZFRocm93KGBUaGVyZSBpcyBubyAuJHtERUZBVUxUX0VYVH0gZmlsZSBmb3VuZCBmb3IgcGVyZm9ybWFuY2UgcHJvZmlsZSAnJHtwcm9maWxlTmFtZX0nIGAgK1xuICAgICAgYGFuZCBkZXZpY2UgJHt0aGlzLm9wdHMuZGV2aWNlLnVkaWR9LiBNYWtlIHN1cmUgdGhlIHByb2ZpbGUgaXMgc3VwcG9ydGVkIG9uIHRoaXMgZGV2aWNlLiBgICtcbiAgICAgIGBZb3UgY291bGQgdXNlICdpbnN0cnVtZW50cyAtcycgY29tbWFuZCB0byBzZWUgdGhlIGxpc3Qgb2YgYWxsIGF2YWlsYWJsZSBwcm9maWxlcy5gKTtcbiAgfVxuXG4gIHJldHVybiBhd2FpdCBlbmNvZGVCYXNlNjRPclVwbG9hZChyZXN1bHRQYXRoLCByZW1vdGVQYXRoLCB7IHVzZXIsIHBhc3MsIG1ldGhvZCB9KTtcbn07XG5cblxuZXhwb3J0IHsgY29tbWFuZHMgfTtcbmV4cG9ydCBkZWZhdWx0IGNvbW1hbmRzO1xuIl0sImZpbGUiOiJsaWIvY29tbWFuZHMvcGVyZm9ybWFuY2UuanMiLCJzb3VyY2VSb290IjoiLi4vLi4vLi4ifQ==