UNPKG

gst-atom-xcuitest-driver

Version:

ATOM driver for iOS using XCUITest for backend

450 lines (335 loc) 50.8 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.detectUdid = detectUdid; exports.getAndCheckXcodeVersion = getAndCheckXcodeVersion; exports.getAndCheckIosSdkVersion = getAndCheckIosSdkVersion; exports.getGenericSimulatorForIosVersion = getGenericSimulatorForIosVersion; exports.checkAppPresent = checkAppPresent; exports.getDriverInfo = getDriverInfo; exports.clearSystemFiles = clearSystemFiles; exports.translateDeviceName = translateDeviceName; exports.normalizeCommandTimeouts = normalizeCommandTimeouts; exports.markSystemFilesForCleanup = markSystemFilesForCleanup; exports.printUser = printUser; exports.getPIDsListeningOnPort = getPIDsListeningOnPort; exports.encodeBase64OrUpload = encodeBase64OrUpload; exports.removeAllSessionWebSocketHandlers = removeAllSessionWebSocketHandlers; exports.verifyApplicationPlatform = verifyApplicationPlatform; exports.isLocalHost = isLocalHost; exports.normalizePlatformVersion = normalizePlatformVersion; exports.DEFAULT_TIMEOUT_KEY = void 0; require("source-map-support/register"); var _bluebird = _interopRequireDefault(require("bluebird")); var _gstAtomIosDevice = require("gst-atom-ios-device"); var _appiumSupport = require("appium-support"); var _path = _interopRequireDefault(require("path")); var _gstAtomIosDriver = require("gst-atom-ios-driver"); var _teen_process = require("teen_process"); var _appiumXcode = _interopRequireDefault(require("appium-xcode")); var _lodash = _interopRequireDefault(require("lodash")); var _logger = _interopRequireDefault(require("./logger")); var _iosGenericSimulators = _interopRequireDefault(require("./ios-generic-simulators")); var _url = _interopRequireDefault(require("url")); var _os = _interopRequireDefault(require("os")); var _semver = _interopRequireDefault(require("semver")); const DEFAULT_TIMEOUT_KEY = 'default'; exports.DEFAULT_TIMEOUT_KEY = DEFAULT_TIMEOUT_KEY; const XCTEST_LOG_FILES_PATTERNS = [/^Session-WebDriverAgentRunner.*\.log$/i, /^StandardOutputAndStandardError\.txt$/i]; const XCTEST_LOGS_CACHE_FOLDER_PREFIX = 'com.apple.dt.XCTest'; async function detectUdid(usbmuxdRemoteHost, usbmuxdRemotePort) { _logger.default.debug('Auto-detecting real device udid...'); var options = { usbmuxdRemoteHost: usbmuxdRemoteHost, usbmuxdRemotePort: usbmuxdRemotePort }; const udids = await _gstAtomIosDevice.utilities.getConnectedDevices(null, options); if (_lodash.default.isEmpty(udids)) { throw new Error('No device is connected to the host'); } const udid = _lodash.default.last(udids); if (udids.length > 1) { _logger.default.warn(`Multiple devices found: ${udids.join(', ')}`); _logger.default.warn(`Choosing '${udid}'. If this is wrong, manually set with 'udid' desired capability`); } _logger.default.debug(`Detected real device udid: '${udid}'`); return udid; } async function getAndCheckXcodeVersion() { let version; try { version = await _appiumXcode.default.getVersion(true); } catch (err) { _logger.default.debug(err); _logger.default.errorAndThrow(`Could not determine Xcode version: ${err.message}`); } if (version.versionFloat < 7.3) { _logger.default.errorAndThrow(`Xcode version '${version.versionString}'. Support for ` + `Xcode ${version.versionString} is not supported. ` + `Please upgrade to version 7.3 or higher`); } return version; } async function getAndCheckIosSdkVersion() { try { return await _appiumXcode.default.getMaxIOSSDK(); } catch (err) { _logger.default.errorAndThrow(`Could not determine iOS SDK version: ${err.message}`); } } function getGenericSimulatorForIosVersion(platformVersion, deviceName) { let genericSimulators = _iosGenericSimulators.default[deviceName]; if (genericSimulators) { genericSimulators = genericSimulators.sort(([simOne], [simTwo]) => _appiumSupport.util.compareVersions(simOne, '<', simTwo) ? -1 : 1); let genericIosSimulator; for (const [platformVersionFromList, iosSimulator] of genericSimulators) { if (_appiumSupport.util.compareVersions(platformVersionFromList, '>', platformVersion)) { break; } genericIosSimulator = iosSimulator; } return genericIosSimulator; } } function translateDeviceName(platformVersion, deviceName = '') { const deviceNameTranslated = getGenericSimulatorForIosVersion(platformVersion, deviceName.toLowerCase().trim()); if (deviceNameTranslated) { _logger.default.debug(`Changing deviceName from '${deviceName}' to '${deviceNameTranslated}'`); return deviceNameTranslated; } return deviceName; } const derivedDataCleanupMarkers = new Map(); async function markSystemFilesForCleanup(wda) { if (!wda || !(await wda.retrieveDerivedDataPath())) { _logger.default.warn('No WebDriverAgent derived data available, so unable to mark system files for cleanup'); return; } const logsRoot = _path.default.resolve(await wda.retrieveDerivedDataPath(), 'Logs'); let markersCount = 0; if (derivedDataCleanupMarkers.has(logsRoot)) { markersCount = derivedDataCleanupMarkers.get(logsRoot); } derivedDataCleanupMarkers.set(logsRoot, ++markersCount); } async function clearSystemFiles(wda) { if (!wda || !(await wda.retrieveDerivedDataPath())) { _logger.default.warn('No WebDriverAgent derived data available, so unable to clear system files'); return; } const logsRoot = _path.default.resolve(await wda.retrieveDerivedDataPath(), 'Logs'); if (derivedDataCleanupMarkers.has(logsRoot)) { let markersCount = derivedDataCleanupMarkers.get(logsRoot); derivedDataCleanupMarkers.set(logsRoot, --markersCount); if (markersCount > 0) { _logger.default.info(`Not cleaning '${logsRoot}' folder, because the other session does not expect it to be cleaned`); return; } } derivedDataCleanupMarkers.set(logsRoot, 0); const globPattern = `${_os.default.tmpdir()}/${XCTEST_LOGS_CACHE_FOLDER_PREFIX}*/`; const dstFolders = await _appiumSupport.fs.glob(globPattern); if (_lodash.default.isEmpty(dstFolders)) { _logger.default.debug(`Did not find the temporary XCTest logs root at '${globPattern}'`); } else { for (const dstFolder of dstFolders) { let scheduledFilesCount = 0; _bluebird.default.resolve(_appiumSupport.fs.walkDir(dstFolder, true, (itemPath, isDir) => { if (isDir) { return; } const fileName = _path.default.basename(itemPath); if (!XCTEST_LOG_FILES_PATTERNS.some(p => p.test(fileName))) { return; } _appiumSupport.fs.unlink(itemPath).catch(e => { _logger.default.info(e.message); }); scheduledFilesCount++; })).finally(() => { if (scheduledFilesCount > 0) { _logger.default.info(`Scheduled ${scheduledFilesCount} temporary XCTest log ` + `${_appiumSupport.util.pluralize('file', scheduledFilesCount)} for cleanup in '${dstFolder}'`); } }).catch(e => { _logger.default.info(e.message); }); } _logger.default.debug(`Started background XCTest logs cleanup in '${dstFolders}'`); } if (await _appiumSupport.fs.exists(logsRoot)) { _logger.default.info(`Cleaning test logs in '${logsRoot}' folder`); await _gstAtomIosDriver.utils.clearLogs([logsRoot]); return; } _logger.default.info(`There is no ${logsRoot} folder, so not cleaning files`); } async function checkAppPresent(app) { _logger.default.debug(`Checking whether app '${app}' is actually present on file system`); if (!(await _appiumSupport.fs.exists(app))) { _logger.default.errorAndThrow(`Could not find app at '${app}'`); } _logger.default.debug('App is present'); } async function getDriverInfo() { const stat = await _appiumSupport.fs.stat(_path.default.resolve(__dirname, '..')); const built = stat.mtime.getTime(); const pkg = require(__filename.includes('build/lib/utils') ? '../../package.json' : '../package.json'); const version = pkg.version; return { built, version }; } function normalizeCommandTimeouts(value) { if (typeof value !== 'string') { return value; } let result = {}; if (!isNaN(value)) { result[DEFAULT_TIMEOUT_KEY] = _lodash.default.toInteger(value); return result; } try { result = JSON.parse(value); if (!_lodash.default.isPlainObject(result)) { throw new Error(); } } catch (err) { _logger.default.errorAndThrow(`"commandTimeouts" capability should be a valid JSON object. "${value}" was given instead`); } for (let [cmd, timeout] of _lodash.default.toPairs(result)) { if (!_lodash.default.isInteger(timeout) || timeout <= 0) { _logger.default.errorAndThrow(`The timeout for "${cmd}" should be a valid natural number of milliseconds. "${timeout}" was given instead`); } } return result; } async function printUser() { try { let { stdout } = await (0, _teen_process.exec)('whoami'); _logger.default.debug(`Current user: '${stdout.trim()}'`); } catch (err) { _logger.default.debug(`Unable to get username running server: ${err.message}`); } } async function getPIDsListeningOnPort(port, filteringFunc = null) { const result = []; try { const { stdout } = await (0, _teen_process.exec)('lsof', ['-ti', `tcp:${port}`]); result.push(...stdout.trim().split(/\n+/)); } catch (e) { return result; } if (!_lodash.default.isFunction(filteringFunc)) { return result; } return await _bluebird.default.filter(result, async x => { const { stdout } = await (0, _teen_process.exec)('ps', ['-p', x, '-o', 'command']); return await filteringFunc(stdout); }); } async function encodeBase64OrUpload(localPath, remotePath = null, uploadOptions = {}) { if (!(await _appiumSupport.fs.exists(localPath))) { _logger.default.errorAndThrow(`The file at '${localPath}' does not exist or is not accessible`); } const { size } = await _appiumSupport.fs.stat(localPath); _logger.default.debug(`The size of the file is ${_appiumSupport.util.toReadableSizeString(size)}`); if (_lodash.default.isEmpty(remotePath)) { return (await _appiumSupport.util.toInMemoryBase64(localPath)).toString(); } const { user, pass, method } = uploadOptions; const remoteUrl = _url.default.parse(remotePath); let options = {}; if (remoteUrl.protocol.startsWith('http')) { options = { url: remoteUrl.href, method: method || 'PUT', multipart: [{ body: _appiumSupport.fs.createReadStream(localPath) }] }; if (user && pass) { options.auth = { user, pass }; } } else if (remoteUrl.protocol === 'ftp:') { options = { host: remoteUrl.hostname, port: remoteUrl.port || 21 }; if (user && pass) { options.user = user; options.pass = pass; } } await _appiumSupport.net.uploadFile(localPath, remotePath, options); return ''; } async function removeAllSessionWebSocketHandlers(server, sessionId) { if (!server || !_lodash.default.isFunction(server.getWebSocketHandlers)) { return; } const activeHandlers = await server.getWebSocketHandlers(sessionId); for (const pathname of _lodash.default.keys(activeHandlers)) { await server.removeWebSocketHandler(pathname); } } async function verifyApplicationPlatform(app, expectedPlatform) { _logger.default.debug('Verifying application platform'); const infoPlist = _path.default.resolve(app, 'Info.plist'); if (!(await _appiumSupport.fs.exists(infoPlist))) { _logger.default.debug(`'${infoPlist}' does not exist`); return; } const { CFBundleSupportedPlatforms } = await _appiumSupport.plist.parsePlistFile(infoPlist); _logger.default.debug(`CFBundleSupportedPlatforms: ${JSON.stringify(CFBundleSupportedPlatforms)}`); if (!_lodash.default.isArray(CFBundleSupportedPlatforms)) { _logger.default.debug(`CFBundleSupportedPlatforms key does not exist in '${infoPlist}'`); return; } const { isSimulator, isTvOS } = expectedPlatform; const prefix = isTvOS ? 'AppleTV' : 'iPhone'; const suffix = isSimulator ? 'Simulator' : 'OS'; const dstPlatform = `${prefix}${suffix}`; if (!CFBundleSupportedPlatforms.includes(dstPlatform)) { throw new Error(`${isSimulator ? 'Simulator' : 'Real device'} architecture is unsupported by the '${app}' application. ` + `Make sure the correct deployment target has been selected for its compilation in Xcode.`); } } function isLocalHost(urlString) { try { const { hostname } = _url.default.parse(urlString); return ['localhost', '127.0.0.1', '::1', '::ffff:127.0.0.1'].includes(hostname); } catch (ign) { _logger.default.warn(`'${urlString}' cannot be parsed as a valid URL`); } return false; } function normalizePlatformVersion(originalVersion) { const normalizedVersion = _semver.default.coerce(originalVersion); if (!normalizedVersion) { throw new Error(`The platform version '${originalVersion}' should be a valid version number`); } return `${normalizedVersion.major}.${normalizedVersion.minor}`; }require('source-map-support').install(); //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi91dGlscy5qcyJdLCJuYW1lcyI6WyJERUZBVUxUX1RJTUVPVVRfS0VZIiwiWENURVNUX0xPR19GSUxFU19QQVRURVJOUyIsIlhDVEVTVF9MT0dTX0NBQ0hFX0ZPTERFUl9QUkVGSVgiLCJkZXRlY3RVZGlkIiwidXNibXV4ZFJlbW90ZUhvc3QiLCJ1c2JtdXhkUmVtb3RlUG9ydCIsImxvZyIsImRlYnVnIiwib3B0aW9ucyIsInVkaWRzIiwidXRpbGl0aWVzIiwiZ2V0Q29ubmVjdGVkRGV2aWNlcyIsIl8iLCJpc0VtcHR5IiwiRXJyb3IiLCJ1ZGlkIiwibGFzdCIsImxlbmd0aCIsIndhcm4iLCJqb2luIiwiZ2V0QW5kQ2hlY2tYY29kZVZlcnNpb24iLCJ2ZXJzaW9uIiwieGNvZGUiLCJnZXRWZXJzaW9uIiwiZXJyIiwiZXJyb3JBbmRUaHJvdyIsIm1lc3NhZ2UiLCJ2ZXJzaW9uRmxvYXQiLCJ2ZXJzaW9uU3RyaW5nIiwiZ2V0QW5kQ2hlY2tJb3NTZGtWZXJzaW9uIiwiZ2V0TWF4SU9TU0RLIiwiZ2V0R2VuZXJpY1NpbXVsYXRvckZvcklvc1ZlcnNpb24iLCJwbGF0Zm9ybVZlcnNpb24iLCJkZXZpY2VOYW1lIiwiZ2VuZXJpY1NpbXVsYXRvcnMiLCJpb3NHZW5lcmljU2ltdWxhdG9ycyIsInNvcnQiLCJzaW1PbmUiLCJzaW1Ud28iLCJ1dGlsIiwiY29tcGFyZVZlcnNpb25zIiwiZ2VuZXJpY0lvc1NpbXVsYXRvciIsInBsYXRmb3JtVmVyc2lvbkZyb21MaXN0IiwiaW9zU2ltdWxhdG9yIiwidHJhbnNsYXRlRGV2aWNlTmFtZSIsImRldmljZU5hbWVUcmFuc2xhdGVkIiwidG9Mb3dlckNhc2UiLCJ0cmltIiwiZGVyaXZlZERhdGFDbGVhbnVwTWFya2VycyIsIk1hcCIsIm1hcmtTeXN0ZW1GaWxlc0ZvckNsZWFudXAiLCJ3ZGEiLCJyZXRyaWV2ZURlcml2ZWREYXRhUGF0aCIsImxvZ3NSb290IiwicGF0aCIsInJlc29sdmUiLCJtYXJrZXJzQ291bnQiLCJoYXMiLCJnZXQiLCJzZXQiLCJjbGVhclN5c3RlbUZpbGVzIiwiaW5mbyIsImdsb2JQYXR0ZXJuIiwib3MiLCJ0bXBkaXIiLCJkc3RGb2xkZXJzIiwiZnMiLCJnbG9iIiwiZHN0Rm9sZGVyIiwic2NoZWR1bGVkRmlsZXNDb3VudCIsIkIiLCJ3YWxrRGlyIiwiaXRlbVBhdGgiLCJpc0RpciIsImZpbGVOYW1lIiwiYmFzZW5hbWUiLCJzb21lIiwicCIsInRlc3QiLCJ1bmxpbmsiLCJjYXRjaCIsImUiLCJmaW5hbGx5IiwicGx1cmFsaXplIiwiZXhpc3RzIiwiaW9zVXRpbHMiLCJjbGVhckxvZ3MiLCJjaGVja0FwcFByZXNlbnQiLCJhcHAiLCJnZXREcml2ZXJJbmZvIiwic3RhdCIsIl9fZGlybmFtZSIsImJ1aWx0IiwibXRpbWUiLCJnZXRUaW1lIiwicGtnIiwicmVxdWlyZSIsIl9fZmlsZW5hbWUiLCJpbmNsdWRlcyIsIm5vcm1hbGl6ZUNvbW1hbmRUaW1lb3V0cyIsInZhbHVlIiwicmVzdWx0IiwiaXNOYU4iLCJ0b0ludGVnZXIiLCJKU09OIiwicGFyc2UiLCJpc1BsYWluT2JqZWN0IiwiY21kIiwidGltZW91dCIsInRvUGFpcnMiLCJpc0ludGVnZXIiLCJwcmludFVzZXIiLCJzdGRvdXQiLCJnZXRQSURzTGlzdGVuaW5nT25Qb3J0IiwicG9ydCIsImZpbHRlcmluZ0Z1bmMiLCJwdXNoIiwic3BsaXQiLCJpc0Z1bmN0aW9uIiwiZmlsdGVyIiwieCIsImVuY29kZUJhc2U2NE9yVXBsb2FkIiwibG9jYWxQYXRoIiwicmVtb3RlUGF0aCIsInVwbG9hZE9wdGlvbnMiLCJzaXplIiwidG9SZWFkYWJsZVNpemVTdHJpbmciLCJ0b0luTWVtb3J5QmFzZTY0IiwidG9TdHJpbmciLCJ1c2VyIiwicGFzcyIsIm1ldGhvZCIsInJlbW90ZVVybCIsInVybCIsInByb3RvY29sIiwic3RhcnRzV2l0aCIsImhyZWYiLCJtdWx0aXBhcnQiLCJib2R5IiwiY3JlYXRlUmVhZFN0cmVhbSIsImF1dGgiLCJob3N0IiwiaG9zdG5hbWUiLCJuZXQiLCJ1cGxvYWRGaWxlIiwicmVtb3ZlQWxsU2Vzc2lvbldlYlNvY2tldEhhbmRsZXJzIiwic2VydmVyIiwic2Vzc2lvbklkIiwiZ2V0V2ViU29ja2V0SGFuZGxlcnMiLCJhY3RpdmVIYW5kbGVycyIsInBhdGhuYW1lIiwia2V5cyIsInJlbW92ZVdlYlNvY2tldEhhbmRsZXIiLCJ2ZXJpZnlBcHBsaWNhdGlvblBsYXRmb3JtIiwiZXhwZWN0ZWRQbGF0Zm9ybSIsImluZm9QbGlzdCIsIkNGQnVuZGxlU3VwcG9ydGVkUGxhdGZvcm1zIiwicGxpc3QiLCJwYXJzZVBsaXN0RmlsZSIsInN0cmluZ2lmeSIsImlzQXJyYXkiLCJpc1NpbXVsYXRvciIsImlzVHZPUyIsInByZWZpeCIsInN1ZmZpeCIsImRzdFBsYXRmb3JtIiwiaXNMb2NhbEhvc3QiLCJ1cmxTdHJpbmciLCJpZ24iLCJub3JtYWxpemVQbGF0Zm9ybVZlcnNpb24iLCJvcmlnaW5hbFZlcnNpb24iLCJub3JtYWxpemVkVmVyc2lvbiIsInNlbXZlciIsImNvZXJjZSIsIm1ham9yIiwibWlub3IiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFHQSxNQUFNQSxtQkFBbUIsR0FBRyxTQUE1Qjs7QUFDQSxNQUFNQyx5QkFBeUIsR0FBRyxDQUNoQyx3Q0FEZ0MsRUFFaEMsd0NBRmdDLENBQWxDO0FBSUEsTUFBTUMsK0JBQStCLEdBQUcscUJBQXhDOztBQUdBLGVBQWVDLFVBQWYsQ0FBMkJDLGlCQUEzQixFQUE4Q0MsaUJBQTlDLEVBQWlFO0FBQy9EQyxrQkFBSUMsS0FBSixDQUFVLG9DQUFWOztBQUNBLE1BQUlDLE9BQU8sR0FBRztBQUNaSixJQUFBQSxpQkFBaUIsRUFBRUEsaUJBRFA7QUFFWkMsSUFBQUEsaUJBQWlCLEVBQUVBO0FBRlAsR0FBZDtBQUlBLFFBQU1JLEtB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ekUsR0FBSSxpQkFBeEYsR0FDYix5RkFERyxDQUFOO0FBRUQ7QUFDRjs7QUFPRCxTQUFTOEUsV0FBVCxDQUFzQkMsU0FBdEIsRUFBaUM7QUFDL0IsTUFBSTtBQUNGLFVBQU07QUFBQ3pCLE1BQUFBO0FBQUQsUUFBYVQsYUFBSTVCLEtBQUosQ0FBVThELFNBQVYsQ0FBbkI7O0FBQ0EsV0FBTyxDQUFDLFdBQUQsRUFBYyxXQUFkLEVBQTJCLEtBQTNCLEVBQWtDLGtCQUFsQyxFQUFzRHJFLFFBQXRELENBQStENEMsUUFBL0QsQ0FBUDtBQUNELEdBSEQsQ0FHRSxPQUFPMEIsR0FBUCxFQUFZO0FBQ1psSyxvQkFBSVksSUFBSixDQUFVLElBQUdxSixTQUFVLG1DQUF2QjtBQUNEOztBQUNELFNBQU8sS0FBUDtBQUNEOztBQVNELFNBQVNFLHdCQUFULENBQW1DQyxlQUFuQyxFQUFvRDtBQUNsRCxRQUFNQyxpQkFBaUIsR0FBR0MsZ0JBQU9DLE1BQVAsQ0FBY0gsZUFBZCxDQUExQjs7QUFDQSxNQUFJLENBQUNDLGlCQUFMLEVBQXdCO0FBQ3RCLFVBQU0sSUFBSTdKLEtBQUosQ0FBVyx5QkFBd0I0SixlQUFnQixvQ0FBbkQsQ0FBTjtBQUNEOztBQUNELFNBQVEsR0FBRUMsaUJBQWlCLENBQUNHLEtBQU0sSUFBR0gsaUJBQWlCLENBQUNJLEtBQU0sRUFBN0Q7QUFDRCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBCIGZyb20gJ2JsdWViaXJkJztcbmltcG9ydCB7IHV0aWxpdGllcyB9IGZyb20gJ2dzdC1hdG9tLWlvcy1kZXZpY2UnO1xuaW1wb3J0IHsgZnMsIHV0aWwsIG5ldCwgcGxpc3QgfSBmcm9tICdhcHBpdW0tc3VwcG9ydCc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IHV0aWxzIGFzIGlvc1V0aWxzIH0gZnJvbSAnZ3N0LWF0b20taW9zLWRyaXZlcic7XG5pbXBvcnQgeyBleGVjIH0gZnJvbSAndGVlbl9wcm9jZXNzJztcbmltcG9ydCB4Y29kZSBmcm9tICdhcHBpdW0teGNvZGUnO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCBsb2cgZnJvbSAnLi9sb2dnZXInO1xuaW1wb3J0IGlvc0dlbmVyaWNTaW11bGF0b3JzIGZyb20gJy4vaW9zLWdlbmVyaWMtc2ltdWxhdG9ycyc7XG5pbXBvcnQgdXJsIGZyb20gJ3VybCc7XG5pbXBvcnQgb3MgZnJvbSAnb3MnO1xuaW1wb3J0IHNlbXZlciBmcm9tICdzZW12ZXInO1xuXG5cbmNvbnN0IERFRkFVTFRfVElNRU9VVF9LRVkgPSAnZGVmYXVsdCc7XG5jb25zdCBYQ1RFU1RfTE9HX0ZJTEVTX1BBVFRFUk5TID0gW1xuICAvXlNlc3Npb24tV2ViRHJpdmVyQWdlbnRSdW5uZXIuKlxcLmxvZyQvaSxcbiAgL15TdGFuZGFyZE91dHB1dEFuZFN0YW5kYXJkRXJyb3JcXC50eHQkL2ksXG5dO1xuY29uc3QgWENURVNUX0xPR1NfQ0FDSEVfRk9MREVSX1BSRUZJWCA9ICdjb20uYXBwbGUuZHQuWENUZXN0JztcblxuXG5hc3luYyBmdW5jdGlvbiBkZXRlY3RVZGlkICh1c2JtdXhkUmVtb3RlSG9zdCwgdXNibXV4ZFJlbW90ZVBvcnQpIHtcbiAgbG9nLmRlYnVnKCdBdXRvLWRldGVjdGluZyByZWFsIGRldmljZSB1ZGlkLi4uJyk7XG4gIHZhciBvcHRpb25zID0ge1xuICAgIHVzYm11eGRSZW1vdGVIb3N0OiB1c2JtdXhkUmVtb3RlSG9zdCxcbiAgICB1c2JtdXhkUmVtb3RlUG9ydDogdXNibXV4ZFJlbW90ZVBvcnRcbiAgfTtcbiAgY29uc3QgdWRpZHMgPSBhd2FpdCB1dGlsaXRpZXMuZ2V0Q29ubmVjdGVkRGV2aWNlcyhudWxsLCBvcHRpb25zKTtcbiAgaWYgKF8uaXNFbXB0eSh1ZGlkcykpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGRldmljZSBpcyBjb25uZWN0ZWQgdG8gdGhlIGhvc3QnKTtcbiAgfVxuICBjb25zdCB1ZGlkID0gXy5sYXN0KHVkaWRzKTtcbiAgaWYgKHVkaWRzLmxlbmd0aCA+IDEpIHtcbiAgICBsb2cud2FybihgTXVsdGlwbGUgZGV2aWNlcyBmb3VuZDogJHt1ZGlkcy5qb2luKCcsICcpfWApO1xuICAgIGxvZy53YXJuKGBDaG9vc2luZyAnJHt1ZGlkfScuIElmIHRoaXMgaXMgd3JvbmcsIG1hbnVhbGx5IHNldCB3aXRoICd1ZGlkJyBkZXNpcmVkIGNhcGFiaWxpdHlgKTtcbiAgfVxuICBsb2cuZGVidWcoYERldGVjdGVkIHJlYWwgZGV2aWNlIHVkaWQ6ICcke3VkaWR9J2ApO1xuICByZXR1cm4gdWRpZDtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0QW5kQ2hlY2tYY29kZVZlcnNpb24gKCkge1xuICBsZXQgdmVyc2lvbjtcbiAgdHJ5IHtcbiAgICB2ZXJzaW9uID0gYXdhaXQgeGNvZGUuZ2V0VmVyc2lvbih0cnVlKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nLmRlYnVnKGVycik7XG4gICAgbG9nLmVycm9yQW5kVGhyb3coYENvdWxkIG5vdCBkZXRlcm1pbmUgWGNvZGUgdmVyc2lvbjogJHtlcnIubWVzc2FnZX1gKTtcbiAgfVxuXG4gIC8vIHdlIGRvIG5vdCBzdXBwb3J0IFhjb2RlcyA8IDcuMyxcbiAgaWYgKHZlcnNpb24udmVyc2lvbkZsb2F0IDwgNy4zKSB7XG4gICAgbG9nLmVycm9yQW5kVGhyb3coYFhjb2RlIHZlcnNpb24gJyR7dmVyc2lvbi52ZXJzaW9uU3RyaW5nfScuIFN1cHBvcnQgZm9yIGAgK1xuICAgICAgICAgICAgICAgICAgICAgIGBYY29kZSAke3ZlcnNpb24udmVyc2lvblN0cmluZ30gaXMgbm90IHN1cHBvcnRlZC4gYCArXG4gICAgICAgICAgICAgICAgICAgICAgYFBsZWFzZSB1cGdyYWRlIHRvIHZlcnNpb24gNy4zIG9yIGhpZ2hlcmApO1xuICB9XG4gIHJldHVybiB2ZXJzaW9uO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRBbmRDaGVja0lvc1Nka1ZlcnNpb24gKCkge1xuICB0cnkge1xuICAgIHJldHVybiBhd2FpdCB4Y29kZS5nZXRNYXhJT1NTREsoKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nLmVycm9yQW5kVGhyb3coYENvdWxkIG5vdCBkZXRlcm1pbmUgaU9TIFNESyB2ZXJzaW9uOiAke2Vyci5tZXNzYWdlfWApO1xuICB9XG59XG5cbi8qKlxuICogR2V0IHRoZSBnZW5lcmljIHNpbXVsYXRvciBmb3IgYSBnaXZlbiBJT1MgdmVyc2lvbiBhbmQgZGV2aWNlIHR5cGUgKGlQaG9uZSwgaVBhZClcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ3xudW1iZXJ9IHBsYXRmb3JtVmVyc2lvbiBJT1MgdmVyc2lvbi4gZS5nLikgMTMuMFxuICogQHBhcmFtIHtzdHJpbmd9IGRldmljZU5hbWUgVHlwZSBvZiBJT1MgZGV2aWNlLiBDYW4gYmUgaVBob25lLCBpUGFkIChwb3NzaWJseSBtb3JlIGluIHRoZSBmdXR1cmUpXG4gKlxuICogQHJldHVybnMge3N0cmluZ30gR2VuZXJpYyBpUGhvbmUgb3IgaVBhZCBzaW11bGF0b3IgKGlmIGFwcGxpY2FibGUpXG4gKi9cbmZ1bmN0aW9uIGdldEdlbmVyaWNTaW11bGF0b3JGb3JJb3NWZXJzaW9uIChwbGF0Zm9ybVZlcnNpb24sIGRldmljZU5hbWUpIHtcbiAgbGV0IGdlbmVyaWNTaW11bGF0b3JzID0gaW9zR2VuZXJpY1NpbXVsYXRvcnNbZGV2aWNlTmFtZV07XG5cbiAgaWYgKGdlbmVyaWNTaW11bGF0b3JzKSB7XG4gICAgZ2VuZXJpY1NpbXVsYXRvcnMgPSBnZW5lcmljU2ltdWxhdG9ycy5zb3J0KChbc2ltT25lXSwgW3NpbVR3b10pID0+IHV0aWwuY29tcGFyZVZlcnNpb25zKHNpbU9uZSwgJzwnLCBzaW1Ud28pID8gLTEgOiAxKTtcblxuICAgIC8vIEZpbmQgdGhlIGhpZ2hlc3QgaU9TIHZlcnNpb24gaW4gdGhlIGxpc3QgdGhhdCBpcyBiZWxvdyB0aGUgcHJvdmlkZWQgdmVyc2lvblxuICAgIGxldCBnZW5lcmljSW9zU2ltdWxhdG9yO1xuICAgIGZvciAoY29uc3QgW3BsYXRmb3JtVmVyc2lvbkZyb21MaXN0LCBpb3NTaW11bGF0b3JdIG9mIGdlbmVyaWNTaW11bGF0b3JzKSB7XG4gICAgICBpZiAodXRpbC5jb21wYXJlVmVyc2lvbnMocGxhdGZvcm1WZXJzaW9uRnJvbUxpc3QsICc+JywgcGxhdGZvcm1WZXJzaW9uKSkge1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGdlbmVyaWNJb3NTaW11bGF0b3IgPSBpb3NTaW11bGF0b3I7XG4gICAgfVxuICAgIHJldHVybiBnZW5lcmljSW9zU2ltdWxhdG9yO1xuICB9XG59XG5cbmZ1bmN0aW9uIHRyYW5zbGF0ZURldmljZU5hbWUgKHBsYXRmb3JtVmVyc2lvbiwgZGV2aWNlTmFtZSA9ICcnKSB7XG4gIGNvbnN0IGRldmljZU5hbWVUcmFuc2xhdGVkID0gZ2V0R2VuZXJpY1NpbXVsYXRvckZvcklvc1ZlcnNpb24ocGxhdGZvcm1WZXJzaW9uLCBkZXZpY2VOYW1lLnRvTG93ZXJDYXNlKCkudHJpbSgpKTtcbiAgaWYgKGRldmljZU5hbWVUcmFuc2xhdGVkKSB7XG4gICAgbG9nLmRlYnVnKGBDaGFuZ2luZyBkZXZpY2VOYW1lIGZyb20gJyR7ZGV2aWNlTmFtZX0nIHRvICcke2RldmljZU5hbWVUcmFuc2xhdGVkfSdgKTtcbiAgICByZXR1cm4gZGV2aWNlTmFtZVRyYW5zbGF0ZWQ7XG4gIH1cbiAgcmV0dXJuIGRldmljZU5hbWU7XG59XG5cbi8vIFRoaXMgbWFwIGNvbnRhaW5zIGRlcml2ZWQgZGF0YSBsb2dzIGZvbGRlcnMgYXMga2V5c1xuLy8gYW5kIHZhbHVlcyBhcmUgdGhlIGNvdW50IG9mIHRpbWVzIHRoZSBwYXJ0aWN1bGFyXG4vLyBmb2xkZXIgaGFzIGJlZW4gc2NoZWR1bGVkIGZvciByZW1vdmFsXG5jb25zdCBkZXJpdmVkRGF0YUNsZWFudXBNYXJrZXJzID0gbmV3IE1hcCgpO1xuXG5hc3luYyBmdW5jdGlvbiBtYXJrU3lzdGVtRmlsZXNGb3JDbGVhbnVwICh3ZGEpIHtcbiAgaWYgKCF3ZGEgfHwgIWF3YWl0IHdkYS5yZXRyaWV2ZURlcml2ZWREYXRhUGF0aCgpKSB7XG4gICAgbG9nLndhcm4oJ05vIFdlYkRyaXZlckFnZW50IGRlcml2ZWQgZGF0YSBhdmFpbGFibGUsIHNvIHVuYWJsZSB0byBtYXJrIHN5c3RlbSBmaWxlcyBmb3IgY2xlYW51cCcpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IGxvZ3NSb290ID0gcGF0aC5yZXNvbHZlKGF3YWl0IHdkYS5yZXRyaWV2ZURlcml2ZWREYXRhUGF0aCgpLCAnTG9ncycpO1xuICBsZXQgbWFya2Vyc0NvdW50ID0gMDtcbiAgaWYgKGRlcml2ZWREYXRhQ2xlYW51cE1hcmtlcnMuaGFzKGxvZ3NSb290KSkge1xuICAgIG1hcmtlcnNDb3VudCA9IGRlcml2ZWREYXRhQ2xlYW51cE1hcmtlcnMuZ2V0KGxvZ3NSb290KTtcbiAgfVxuICBkZXJpdmVkRGF0YUNsZWFudXBNYXJrZXJzLnNldChsb2dzUm9vdCwgKyttYXJrZXJzQ291bnQpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBjbGVhclN5c3RlbUZpbGVzICh3ZGEpIHtcbiAgLy8gb25seSB3YW50IHRvIGNsZWFyIHRoZSBzeXN0ZW0gZmlsZXMgZm9yIHRoZSBwYXJ0aWN1bGFyIFdEQSB4Y29kZSBydW5cbiAgaWYgKCF3ZGEgfHwgIWF3YWl0IHdkYS5yZXRyaWV2ZURlcml2ZWREYXRhUGF0aCgpKSB7XG4gICAgbG9nLndhcm4oJ05vIFdlYkRyaXZlckFnZW50IGRlcml2ZWQgZGF0YSBhdmFpbGFibGUsIHNvIHVuYWJsZSB0byBjbGVhciBzeXN0ZW0gZmlsZXMnKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCBsb2dzUm9vdCA9IHBhdGgucmVzb2x2ZShhd2FpdCB3ZGEucmV0cmlldmVEZXJpdmVkRGF0YVBhdGgoKSwgJ0xvZ3MnKTtcbiAgaWYgKGRlcml2ZWREYXRhQ2xlYW51cE1hcmtlcnMuaGFzKGxvZ3NSb290KSkge1xuICAgIGxldCBtYXJrZXJzQ291bnQgPSBkZXJpdmVkRGF0YUNsZWFudXBNYXJrZXJzLmdldChsb2dzUm9vdCk7XG4gICAgZGVyaXZlZERhdGFDbGVhbnVwTWFya2Vycy5zZXQobG9nc1Jvb3QsIC0tbWFya2Vyc0NvdW50KTtcbiAgICBpZiAobWFya2Vyc0NvdW50ID4gMCkge1xuICAgICAgbG9nLmluZm8oYE5vdCBjbGVhbmluZyAnJHtsb2dzUm9vdH0nIGZvbGRlciwgYmVjYXVzZSB0aGUgb3RoZXIgc2Vzc2lvbiBkb2VzIG5vdCBleHBlY3QgaXQgdG8gYmUgY2xlYW5lZGApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgfVxuICBkZXJpdmVkRGF0YUNsZWFudXBNYXJrZXJzLnNldChsb2dzUm9vdCwgMCk7XG5cbiAgLy8gQ2xlYW5pbmcgdXAgYmlnIHRlbXBvcmFyeSBmaWxlcyBjcmVhdGVkIGJ5IFhDVGVzdDogaHR0cHM6Ly9naXRodWIuY29tL2FwcGl1bS9hcHBpdW0vaXNzdWVzLzk0MTBcbiAgY29uc3QgZ2xvYlBhdHRlcm4gPSBgJHtvcy50bXBkaXIoKX0vJHtYQ1RFU1RfTE9HU19DQUNIRV9GT0xERVJfUFJFRklYfSovYDtcbiAgY29uc3QgZHN0Rm9sZGVycyA9IGF3YWl0IGZzLmdsb2IoZ2xvYlBhdHRlcm4pO1xuICBpZiAoXy5pc0VtcHR5KGRzdEZvbGRlcnMpKSB7XG4gICAgbG9nLmRlYnVnKGBEaWQgbm90IGZpbmQgdGhlIHRlbXBvcmFyeSBYQ1Rlc3QgbG9ncyByb290IGF0ICcke2dsb2JQYXR0ZXJufSdgKTtcbiAgfSBlbHNlIHtcbiAgICAvLyBwZXJmb3JtIHRoZSBjbGVhbnVwIGFzeW5jaHJvbm91c2x5XG4gICAgZm9yIChjb25zdCBkc3RGb2xkZXIgb2YgZHN0Rm9sZGVycykge1xuICAgICAgbGV0IHNjaGVkdWxlZEZpbGVzQ291bnQgPSAwO1xuICAgICAgQi5yZXNvbHZlKGZzLndhbGtEaXIoZHN0Rm9sZGVyLCB0cnVlLCAoaXRlbVBhdGgsIGlzRGlyKSA9PiB7XG4gICAgICAgIGlmIChpc0Rpcikge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBmaWxlTmFtZSA9IHBhdGguYmFzZW5hbWUoaXRlbVBhdGgpO1xuICAgICAgICBpZiAoIVhDVEVTVF9MT0dfRklMRVNfUEFUVEVSTlMuc29tZSgocCkgPT4gcC50ZXN0KGZpbGVOYW1lKSkpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkZWxldGUgdGhlIGZpbGUgYXN5bmNocm9ub3VzbHlcbiAgICAgICAgZnMudW5saW5rKGl0ZW1QYXRoKS5jYXRjaCgoZSkgPT4ge1xuICAgICAgICAgIGxvZy5pbmZvKGUubWVzc2FnZSk7XG4gICAgICAgIH0pO1xuICAgICAgICBzY2hlZHVsZWRGaWxlc0NvdW50Kys7XG4gICAgICB9KSkuZmluYWxseSgoKSA9PiB7XG4gICAgICAgIGlmIChzY2hlZHVsZWRGaWxlc0NvdW50ID4gMCkge1xuICAgICAgICAgIGxvZy5pbmZvKGBTY2hlZHVsZWQgJHtzY2hlZHVsZWRGaWxlc0NvdW50fSB0ZW1wb3JhcnkgWENUZXN0IGxvZyBgICtcbiAgICAgICAgICAgIGAke3V0aWwucGx1cmFsaXplKCdmaWxlJywgc2NoZWR1bGVkRmlsZXNDb3VudCl9IGZvciBjbGVhbnVwIGluICcke2RzdEZvbGRlcn0nYCk7XG4gICAgICAgIH1cbiAgICAgIH0pLmNhdGNoKChlKSA9PiB7XG4gICAgICAgIGxvZy5pbmZvKGUubWVzc2FnZSk7XG4gICAgICB9KTtcbiAgICB9XG4gICAgbG9nLmRlYnVnKGBTdGFydGVkIGJhY2tncm91bmQgWENUZXN0IGxvZ3MgY2xlYW51cCBpbiAnJHtkc3RGb2xkZXJzfSdgKTtcbiAgfVxuXG4gIGlmIChhd2FpdCBmcy5leGlzdHMobG9nc1Jvb3QpKSB7XG4gICAgbG9nLmluZm8oYENsZWFuaW5nIHRlc3QgbG9ncyBpbiAnJHtsb2dzUm9vdH0nIGZvbGRlcmApO1xuICAgIGF3YWl0IGlvc1V0aWxzLmNsZWFyTG9ncyhbbG9nc1Jvb3RdKTtcbiAgICByZXR1cm47XG4gIH1cbiAgbG9nLmluZm8oYFRoZXJlIGlzIG5vICR7bG9nc1Jvb3R9IGZvbGRlciwgc28gbm90IGNsZWFuaW5nIGZpbGVzYCk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNoZWNrQXBwUHJlc2VudCAoYXBwKSB7XG4gIGxvZy5kZWJ1ZyhgQ2hlY2tpbmcgd2hldGhlciBhcHAgJyR7YXBwfScgaXMgYWN0dWFsbHkgcHJlc2VudCBvbiBmaWxlIHN5c3RlbWApO1xuICBpZiAoIShhd2FpdCBmcy5leGlzdHMoYXBwKSkpIHtcbiAgICBsb2cuZXJyb3JBbmRUaHJvdyhgQ291bGQgbm90IGZpbmQgYXBwIGF0ICcke2FwcH0nYCk7XG4gIH1cbiAgbG9nLmRlYnVnKCdBcHAgaXMgcHJlc2VudCcpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXREcml2ZXJJbmZvICgpIHtcbiAgY29uc3Qgc3RhdCA9IGF3YWl0IGZzLnN0YXQocGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4uJykpO1xuICBjb25zdCBidWlsdCA9IHN0YXQubXRpbWUuZ2V0VGltZSgpO1xuXG4gIC8vIGdldCB0aGUgcGFja2FnZS5qc29uIGFuZCB0aGUgdmVyc2lvbiBmcm9tIGl0XG4gIGNvbnN0IHBrZyA9IHJlcXVpcmUoX19maWxlbmFtZS5pbmNsdWRlcygnYnVpbGQvbGliL3V0aWxzJykgPyAnLi4vLi4vcGFja2FnZS5qc29uJyA6ICcuLi9wYWNrYWdlLmpzb24nKTtcbiAgY29uc3QgdmVyc2lvbiA9IHBrZy52ZXJzaW9uO1xuXG4gIHJldHVybiB7XG4gICAgYnVpbHQsXG4gICAgdmVyc2lvbixcbiAgfTtcbn1cblxuZnVuY3Rpb24gbm9ybWFsaXplQ29tbWFuZFRpbWVvdXRzICh2YWx1ZSkge1xuICAvLyBUaGUgdmFsdWUgaXMgbm9ybWFsaXplZCBhbHJlYWR5XG4gIGlmICh0eXBlb2YgdmFsdWUgIT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIHZhbHVlO1xuICB9XG5cbiAgbGV0IHJlc3VsdCA9IHt9O1xuICAvLyBVc2UgYXMgZGVmYXVsdCB0aW1lb3V0IGZvciBhbGwgY29tbWFuZHMgaWYgYSBzaW5nbGUgaW50ZWdlciB2YWx1ZSBpcyBwcm92aWRlZFxuICBpZiAoIWlzTmFOKHZhbHVlKSkge1xuICAgIHJlc3VsdFtERUZBVUxUX1RJTUVPVVRfS0VZXSA9IF8udG9JbnRlZ2VyKHZhbHVlKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLy8gSlNPTiBvYmplY3QgaGFzIGJlZW4gcHJvdmlkZWQuIExldCdzIHBhcnNlIGl0XG4gIHRyeSB7XG4gICAgcmVzdWx0ID0gSlNPTi5wYXJzZSh2YWx1ZSk7XG4gICAgaWYgKCFfLmlzUGxhaW5PYmplY3QocmVzdWx0KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCk7XG4gICAgfVxuICB9IGNhdGNoIChlcnIpIHtcbiAgICBsb2cuZXJyb3JBbmRUaHJvdyhgXCJjb21tYW5kVGltZW91dHNcIiBjYXBhYmlsaXR5IHNob3VsZCBiZSBhIHZhbGlkIEpTT04gb2JqZWN0LiBcIiR7dmFsdWV9XCIgd2FzIGdpdmVuIGluc3RlYWRgKTtcbiAgfVxuICBmb3IgKGxldCBbY21kLCB0aW1lb3V0XSBvZiBfLnRvUGFpcnMocmVzdWx0KSkge1xuICAgIGlmICghXy5pc0ludGVnZXIodGltZW91dCkgfHwgdGltZW91dCA8PSAwKSB7XG4gICAgICBsb2cuZXJyb3JBbmRUaHJvdyhgVGhlIHRpbWVvdXQgZm9yIFwiJHtjbWR9XCIgc2hvdWxkIGJlIGEgdmFsaWQgbmF0dXJhbCBudW1iZXIgb2YgbWlsbGlzZWNvbmRzLiBcIiR7dGltZW91dH1cIiB3YXMgZ2l2ZW4gaW5zdGVhZGApO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufVxuXG5hc3luYyBmdW5jdGlvbiBwcmludFVzZXIgKCkge1xuICB0cnkge1xuICAgIGxldCB7c3Rkb3V0fSA9IGF3YWl0IGV4ZWMoJ3dob2FtaScpO1xuICAgIGxvZy5kZWJ1ZyhgQ3VycmVudCB1c2VyOiAnJHtzdGRvdXQudHJpbSgpfSdgKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nLmRlYnVnKGBVbmFibGUgdG8gZ2V0IHVzZXJuYW1lIHJ1bm5pbmcgc2VydmVyOiAke2Vyci5tZXNzYWdlfWApO1xuICB9XG59XG5cbi8qKlxuICogR2V0IHRoZSBJRHMgb2YgcHJvY2Vzc2VzIGxpc3RlbmluZyBvbiB0aGUgcGFydGljdWxhciBzeXN0ZW0gcG9ydC5cbiAqIEl0IGlzIGFsc28gcG9zc2libGUgdG8gYXBwbHkgYWRkaXRpb25hbCBmaWx0ZXJpbmcgYmFzZWQgb24gdGhlXG4gKiBwcm9jZXNzIGNvbW1hbmQgbGluZS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ3xudW1iZXJ9IHBvcnQgLSBUaGUgcG9ydCBudW1iZXIuXG4gKiBAcGFyYW0gez9GdW5jdGlvbn0gZmlsdGVyaW5nRnVuYyAtIE9wdGlvbmFsIGxhbWJkYSBmdW5jdGlvbiwgd2hpY2hcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2ZXMgY29tbWFuZCBsaW5lIHN0cmluZyBvZiB0aGUgcGFydGljdWxhciBwcm9jZXNzXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3RlbmluZyBvbiBnaXZlbiBwb3J0LCBhbmQgaXMgZXhwZWN0ZWQgdG8gcmV0dXJuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVpdGhlciB0cnVlIG9yIGZhbHNlIHRvIGluY2x1ZGUvZXhjbHVkZSB0aGUgY29ycmVzcG9uZGluZyBQSURcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnJvbSB0aGUgcmVzdWx0aW5nIGFycmF5LlxuICogQHJldHVybnMge0FycmF5PHN0cmluZz59IC0gdGhlIGxpc3Qgb2YgbWF0Y2hlZCBwcm9jZXNzIGlkcy5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gZ2V0UElEc0xpc3RlbmluZ09uUG9ydCAocG9ydCwgZmlsdGVyaW5nRnVuYyA9IG51bGwpIHtcbiAgY29uc3QgcmVzdWx0ID0gW107XG4gIHRyeSB7XG4gICAgLy8gVGhpcyBvbmx5IHdvcmtzIHNpbmNlIE1hYyBPUyBYIEVsIENhcGl0YW5cbiAgICBjb25zdCB7c3Rkb3V0fSA9IGF3YWl0IGV4ZWMoJ2xzb2YnLCBbJy10aScsIGB0Y3A6JHtwb3J0fWBdKTtcbiAgICByZXN1bHQucHVzaCguLi4oc3Rkb3V0LnRyaW0oKS5zcGxpdCgvXFxuKy8pKSk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgaWYgKCFfLmlzRnVuY3Rpb24oZmlsdGVyaW5nRnVuYykpIHtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG4gIHJldHVybiBhd2FpdCBCLmZpbHRlcihyZXN1bHQsIGFzeW5jICh4KSA9PiB7XG4gICAgY29uc3Qge3N0ZG91dH0gPSBhd2FpdCBleGVjKCdwcycsIFsnLXAnLCB4LCAnLW8nLCAnY29tbWFuZCddKTtcbiAgICByZXR1cm4gYXdhaXQgZmlsdGVyaW5nRnVuYyhzdGRvdXQpO1xuICB9KTtcbn1cblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBVcGxvYWRPcHRpb25zXG4gKlxuICogQHByb3BlcnR5IHs/c3RyaW5nfSB1c2VyIC0gVGhlIG5hbWUgb2YgdGhlIHVzZXIgZm9yIHRoZSByZW1vdGUgYXV0aGVudGljYXRpb24uIE9ubHkgd29ya3MgaWYgYHJlbW90ZVBhdGhgIGlzIHByb3ZpZGVkLlxuICogQHByb3BlcnR5IHs/c3RyaW5nfSBwYXNzIC0gVGhlIHBhc3N3b3JkIGZvciB0aGUgcmVtb3RlIGF1dGhlbnRpY2F0aW9uLiBPbmx5IHdvcmtzIGlmIGByZW1vdGVQYXRoYCBpcyBwcm92aWRlZC5cbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gbWV0aG9kIC0gVGhlIGh0dHAgbXVsdGlwYXJ0IHVwbG9hZCBtZXRob2QgbmFtZS4gVGhlICdQVVQnIG9uZSBpcyB1c2VkIGJ5IGRlZmF1bHQuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9ubHkgd29ya3MgaWYgYHJlbW90ZVBhdGhgIGlzIHByb3ZpZGVkLlxuICovXG5cblxuLyoqXG4gKiBFbmNvZGVzIHRoZSBnaXZlbiBsb2NhbCBmaWxlIHRvIGJhc2U2NCBhbmQgcmV0dXJucyB0aGUgcmVzdWx0aW5nIHN0cmluZ1xuICogb3IgdXBsb2FkcyBpdCB0byBhIHJlbW90ZSBzZXJ2ZXIgdXNpbmcgaHR0cC9odHRwcyBvciBmdHAgcHJvdG9jb2xzXG4gKiBpZiBgcmVtb3RlUGF0aGAgaXMgc2V0XG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGxvY2FsUGF0aCAtIFRoZSBwYXRoIHRvIGFuIGV4aXN0aW5nIGxvY2FsIGZpbGVcbiAqIEBwYXJhbSB7P3N0cmluZ30gcmVtb3RlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSByZW1vdGUgbG9jYXRpb24sIHdoZXJlXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzIGZpbGUgc2hvdWxkIGJlIHVwbG9hZGVkXG4gKiBAcGFyYW0gez9VcGxvYWRPcHRpb25zfSB1cGxvYWRPcHRpb25zIC0gU2V0IG9mIHVwbG9hZCBvcHRpb25zXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBFaXRoZXIgYW4gZW1wdHkgc3RyaW5nIGlmIHRoZSB1cGxvYWQgd2FzIHN1Y2Nlc3NmdWwgb3JcbiAqIGJhc2U2NC1lbmNvZGVkIGZpbGUgcmVwcmVzZW50YXRpb24gaWYgYHJlbW90ZVBhdGhgIGlzIGZhbHN5XG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGVuY29kZUJhc2U2NE9yVXBsb2FkIChsb2NhbFBhdGgsIHJlbW90ZVBhdGggPSBudWxsLCB1cGxvYWRPcHRpb25zID0ge30pIHtcbiAgaWYgKCFhd2FpdCBmcy5leGlzdHMobG9jYWxQYXRoKSkge1xuICAgIGxvZy5lcnJvckFuZFRocm93KGBUaGUgZmlsZSBhdCAnJHtsb2NhbFBhdGh9JyBkb2VzIG5vdCBleGlzdCBvciBpcyBub3QgYWNjZXNzaWJsZWApO1xuICB9XG5cbiAgY29uc3Qge3NpemV9ID0gYXdhaXQgZnMuc3RhdChsb2NhbFBhdGgpO1xuICBsb2cuZGVidWcoYFRoZSBzaXplIG9mIHRoZSBmaWxlIGlzICR7dXRpbC50b1JlYWRhYmxlU2l6ZVN0cmluZyhzaXplKX1gKTtcbiAgaWYgKF8uaXNFbXB0eShyZW1vdGVQYXRoKSkge1xuICAgIHJldHVybiAoYXdhaXQgdXRpbC50b0luTWVtb3J5QmFzZTY0KGxvY2FsUGF0aCkpLnRvU3RyaW5nKCk7XG4gIH1cblxuICBjb25zdCB7XG4gICAgdXNlcixcbiAgICBwYXNzLFxuICAgIG1ldGhvZCxcbiAgfSA9IHVwbG9hZE9wdGlvbnM7XG4gIGNvbnN0IHJlbW90ZVVybCA9IHVybC5wYXJzZShyZW1vdGVQYXRoKTtcbiAgbGV0IG9wdGlvbnMgPSB7fTtcbiAgaWYgKHJlbW90ZVVybC5wcm90b2NvbC5zdGFydHNXaXRoKCdodHRwJykpIHtcbiAgICBvcHRpb25zID0ge1xuICAgICAgdXJsOiByZW1vdGVVcmwuaHJlZixcbiAgICAgIG1ldGhvZDogbWV0aG9kIHx8ICdQVVQnLFxuICAgICAgbXVsdGlwYXJ0OiBbeyBib2R5OiBmcy5jcmVhdGVSZWFkU3RyZWFtKGxvY2FsUGF0aCkgfV0sXG4gICAgfTtcbiAgICBpZiAodXNlciAmJiBwYXNzKSB7XG4gICAgICBvcHRpb25zLmF1dGggPSB7dXNlciwgcGFzc307XG4gICAgfVxuICB9IGVsc2UgaWYgKHJlbW90ZVVybC5wcm90b2NvbCA9PT0gJ2Z0cDonKSB7XG4gICAgb3B0aW9ucyA9IHtcbiAgICAgIGhvc3Q6IHJlbW90ZVVybC5ob3N0bmFtZSxcbiAgICAgIHBvcnQ6IHJlbW90ZVVybC5wb3J0IHx8IDIxLFxuICAgIH07XG4gICAgaWYgKHVzZXIgJiYgcGFzcykge1xuICAgICAgb3B0aW9ucy51c2VyID0gdXNlcjtcbiAgICAgIG9wdGlvbnMucGFzcyA9IHBhc3M7XG4gICAgfVxuICB9XG4gIGF3YWl0IG5ldC51cGxvYWRGaWxlKGxvY2FsUGF0aCwgcmVtb3RlUGF0aCwgb3B0aW9ucyk7XG4gIHJldHVybiAnJztcbn1cblxuLyoqXG4gKiBTdG9wcyBhbmQgcmVtb3ZlcyBhbGwgd2ViIHNvY2tldCBoYW5kbGVycyB0aGF0IGFyZSBsaXN0ZW5pbmdcbiAqIGluIHNjb3BlIG9mIHRoZSBjdXJyZWN0IHNlc3Npb24uXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlciAtIFRoZSBpbnN0YW5jZSBvZiBOb2RlSnMgSFRUUCBzZXJ2ZXIsXG4gKiB3aGljaCBob3N0cyBBcHBpdW1cbiAqIEBwYXJhbSB7c3RyaW5nfSBzZXNzaW9uSWQgLSBUaGUgaWQgb2YgdGhlIGN1cnJlbnQgc2Vzc2lvblxuICovXG5hc3luYyBmdW5jdGlvbiByZW1vdmVBbGxTZXNzaW9uV2ViU29ja2V0SGFuZGxlcnMgKHNlcnZlciwgc2Vzc2lvbklkKSB7XG4gIGlmICghc2VydmVyIHx8ICFfLmlzRnVuY3Rpb24oc2VydmVyLmdldFdlYlNvY2tldEhhbmRsZXJzKSkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IGFjdGl2ZUhhbmRsZXJzID0gYXdhaXQgc2VydmVyLmdldFdlYlNvY2tldEhhbmRsZXJzKHNlc3Npb25JZCk7XG4gIGZvciAoY29uc3QgcGF0aG5hbWUgb2YgXy5rZXlzKGFjdGl2ZUhhbmRsZXJzKSkge1xuICAgIGF3YWl0IHNlcnZlci5yZW1vdmVXZWJTb2NrZXRIYW5kbGVyKHBhdGhuYW1lKTtcbiAgfVxufVxuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IFBsYXRmb3JtT3B0c1xuICpcbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gaXNTaW11bGF0b3IgLSBXaGV0aGVyIHRoZSBkZXN0aW5hdGlvbiBwbGF0Zm9ybSBpcyBhIFNpbXVsYXRvclxuICogQHByb3BlcnR5IHtib29sZWFufSBpc1R2T1MgLSBXaGV0aGVyIHRoZSBkZXN0aW5hdGlvbiBwbGF0Zm9ybSBpcyBhIFNpbXVsYXRvclxuICovXG5cbi8qKlxuICogVmVyaWZ5IHdoZXRoZXIgdGhlIGdpdmVuIGFwcGxpY2F0aW9uIGlzIGNvbXBhdGlibGUgdG8gdGhlXG4gKiBwbGF0Zm9ybSB3aGVyZSBpdCBpcyBnb2luZyB0byBiZSBpbnN0YWxsZWQgYW5kIHRlc3RlZC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gYXBwIC0gVGhlIGFjdHVhbCBwYXRoIHRvIHRoZSBhcHBsaWNhdGlvbiBidW5kbGVcbiAqIEBwYXJhbSB7UGxhdGZvcm1PcHRzfSBleHBlY3RlZFBsYXRmb3JtXG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgYnVuZGxlIGFyY2hpdGVjdHVyZSBkb2VzIG5vdCBtYXRjaCB0aGUgZXhwZWN0ZWQgZGV2aWNlIGFyY2hpdGVjdHVyZS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gdmVyaWZ5QXBwbGljYXRpb25QbGF0Zm9ybSAoYXBwLCBleHBlY3RlZFBsYXRmb3JtKSB7XG4gIGxvZy5kZWJ1ZygnVmVyaWZ5aW5nIGFwcGxpY2F0aW9uIHBsYXRmb3JtJyk7XG5cbiAgY29uc3QgaW5mb1BsaXN0ID0gcGF0aC5yZXNvbHZlKGFwcCwgJ0luZm8ucGxpc3QnKTtcbiAgaWYgKCFhd2FpdCBmcy5leGlzdHMoaW5mb1BsaXN0KSkge1xuICAgIGxvZy5kZWJ1ZyhgJyR7aW5mb1BsaXN0fScgZG9lcyBub3QgZXhpc3RgKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCB7Q0ZCdW5kbGVTdXBwb3J0ZWRQbGF0Zm9ybXN9ID0gYXdhaXQgcGxpc3QucGFyc2VQbGlzdEZpbGUoaW5mb1BsaXN0KTtcbiAgbG9nLmRlYnVnKGBDRkJ1bmRsZVN1cHBvcnRlZFBsYXRmb3JtczogJHtKU09OLnN0cmluZ2lmeShDRkJ1bmRsZVN1cHBvcnRlZFBsYXRmb3Jtcyl9YCk7XG4gIGlmICghXy5pc0FycmF5KENGQnVuZGxlU3VwcG9ydGVkUGxhdGZvcm1zKSkge1xuICAgIGxvZy5kZWJ1ZyhgQ0ZCdW5kbGVTdXBwb3J0ZWRQbGF0Zm9ybXMga2V5IGRvZXMgbm90IGV4aXN0IGluICcke2luZm9QbGlzdH0nYCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3Qge1xuICAgIGlzU2ltdWxhdG9yLFxuICAgIGlzVHZPUyxcbiAgfSA9IGV4cGVjdGVkUGxhdGZvcm07XG4gIGNvbnN0IHByZWZpeCA9IGlzVHZPUyA/ICdBcHBsZVRWJyA6ICdpUGhvbmUnO1xuICBjb25zdCBzdWZmaXggPSBpc1NpbXVsYXRvciA/ICdTaW11bGF0b3InIDogJ09TJztcbiAgY29uc3QgZHN0UGxhdGZvcm0gPSBgJHtwcmVmaXh9JHtzdWZmaXh9YDtcbiAgaWYgKCFDRkJ1bmRsZVN1cHBvcnRlZFBsYXRmb3Jtcy5pbmNsdWRlcyhkc3RQbGF0Zm9ybSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCR7aXNTaW11bGF0b3IgPyAnU2ltdWxhdG9yJyA6ICdSZWFsIGRldmljZSd9IGFyY2hpdGVjdHVyZSBpcyB1bnN1cHBvcnRlZCBieSB0aGUgJyR7YXBwfScgYXBwbGljYXRpb24uIGAgK1xuICAgICAgYE1ha2Ugc3VyZSB0aGUgY29ycmVjdCBkZXBsb3ltZW50IHRhcmdldCBoYXMgYmVlbiBzZWxlY3RlZCBmb3IgaXRzIGNvbXBpbGF0aW9uIGluIFhjb2RlLmApO1xuICB9XG59XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIHRoZSB1cmxTdHJpbmcgaXMgbG9jYWxob3N0XG4gKiBAcGFyYW0gez9zdHJpbmd9IHVybFN0cmluZ1xuICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybiB0cnVlIGlmIHRoZSB1cmxTdHJpbmcgaXMgbG9jYWxob3N0XG4gKi9cbmZ1bmN0aW9uIGlzTG9jYWxIb3N0ICh1cmxTdHJpbmcpIHtcbiAgdHJ5IHtcbiAgICBjb25zdCB7aG9zdG5hbWV9ID0gdXJsLnBhcnNlKHVybFN0cmluZyk7XG4gICAgcmV0dXJuIFsnbG9jYWxob3N0JywgJzEyNy4wLjAuMScsICc6OjEnLCAnOjpmZmZmOjEyNy4wLjAuMSddLmluY2x1ZGVzKGhvc3RuYW1lKTtcbiAgfSBjYXRjaCAoaWduKSB7XG4gICAgbG9nLndhcm4oYCcke3VybFN0cmluZ30nIGNhbm5vdCBiZSBwYXJzZWQgYXMgYSB2YWxpZCBVUkxgKTtcbiAgfVxuICByZXR1cm4gZmFsc2U7XG59XG5cbi8qKlxuICogTm9ybWFsaXplcyBwbGF0Zm9ybVZlcnNpb24gdG8gYSB2YWxpZCBpT1MgdmVyc2lvbiBzdHJpbmdcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gb3JpZ2luYWxWZXJzaW9uIC0gTG9vc2UgdmVyc2lvbiBudW1iZXIsIHRoYXQgY2FuIGJlIHBhcnNlZCBieSBzZW12ZXJcbiAqIEByZXR1cm4ge3N0cmluZ30gaU9TIHZlcnNpb24gbnVtYmVyIGluIDxtYWpvcj4uPG1pbm9yPiBmb3JtYXRcbiAqIEB0aHJvd3Mge0Vycm9yfSBpZiB0aGUgdmVyc2lvbiBudW1iZXIgY2Fubm90IGJlIHBhcnNlZFxuICovXG5mdW5jdGlvbiBub3JtYWxpemVQbGF0Zm9ybVZlcnNpb24gKG9yaWdpbmFsVmVyc2lvbikge1xuICBjb25zdCBub3JtYWxpemVkVmVyc2lvbiA9IHNlbXZlci5jb2VyY2Uob3JpZ2luYWxWZXJzaW9uKTtcbiAgaWYgKCFub3JtYWxpemVkVmVyc2lvbikge1xuICAgIHRocm93IG5ldyBFcnJvcihgVGhlIHBsYXRmb3JtIHZlcnNpb24gJyR7b3JpZ2luYWxWZXJzaW9ufScgc2