dpgraham-webdriveragent
Version:
Package bundling WebDriverAgent
329 lines (246 loc) • 44.2 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.updateProjectFile = updateProjectFile;
exports.resetProjectFile = resetProjectFile;
exports.setRealDeviceSecurity = setRealDeviceSecurity;
exports.getAdditionalRunContent = getAdditionalRunContent;
exports.getXctestrunFileName = getXctestrunFileName;
exports.generateXcodeConfigFile = generateXcodeConfigFile;
exports.setXctestrunFile = setXctestrunFile;
exports.getXctestrunFilePath = getXctestrunFilePath;
exports.killProcess = killProcess;
exports.randomInt = randomInt;
exports.getWDAUpgradeTimestamp = getWDAUpgradeTimestamp;
exports.areFilesEqual = areFilesEqual;
exports.resetTestProcesses = resetTestProcesses;
exports.getPIDsListeningOnPort = getPIDsListeningOnPort;
exports.killAppUsingPattern = killAppUsingPattern;
exports.isTvOS = isTvOS;
require("source-map-support/register");
var _appiumSupport = require("appium-support");
var _teen_process = require("teen_process");
var _path = _interopRequireDefault(require("path"));
var _logger = _interopRequireDefault(require("./logger"));
var _lodash = _interopRequireDefault(require("lodash"));
var _constants = require("./constants");
var _bluebird = _interopRequireDefault(require("bluebird"));
var _asyncbox = require("asyncbox");
const PROJECT_FILE = 'project.pbxproj';
async function getPIDsUsingPattern(pattern) {
const args = ['-if', pattern];
try {
const {
stdout
} = await (0, _teen_process.exec)('pgrep', args);
return stdout.split(/\s+/).map(x => parseInt(x, 10)).filter(_lodash.default.isInteger).map(x => `${x}`);
} catch (err) {
_logger.default.debug(`'pgrep ${args.join(' ')}' didn't detect any matching processes. Return code: ${err.code}`);
return [];
}
}
async function killAppUsingPattern(pgrepPattern) {
const signals = [2, 15, 9];
for (const signal of signals) {
const matchedPids = await getPIDsUsingPattern(pgrepPattern);
if (_lodash.default.isEmpty(matchedPids)) {
return;
}
const args = [`-${signal}`, ...matchedPids];
try {
await (0, _teen_process.exec)('kill', args);
} catch (err) {
_logger.default.debug(`kill ${args.join(' ')} -> ${err.message}`);
}
if (signal === _lodash.default.last(signals)) {
return;
}
try {
await (0, _asyncbox.waitForCondition)(async () => {
const pidCheckPromises = matchedPids.map(pid => (0, _teen_process.exec)('kill', ['-0', pid]).then(() => false).catch(() => true));
return (await _bluebird.default.all(pidCheckPromises)).every(x => x === true);
}, {
waitMs: 1000,
intervalMs: 100
});
return;
} catch (ign) {}
}
}
function isTvOS(platformName) {
return _lodash.default.toLower(platformName) === _lodash.default.toLower(_constants.PLATFORM_NAME_TVOS);
}
async function areFilesEqual(file1, file2) {
const files = [file1, file2];
if (!_lodash.default.every(await _bluebird.default.all(files.map(f => _appiumSupport.fs.exists(f))))) {
return false;
}
const [hash1, hash2] = await _bluebird.default.all(files.map(f => _appiumSupport.fs.hash(f, 'sha1')));
return hash1 === hash2;
}
async function replaceInFile(file, find, replace) {
let contents = await _appiumSupport.fs.readFile(file, 'utf8');
let newContents = contents.replace(find, replace);
if (newContents !== contents) {
await _appiumSupport.fs.writeFile(file, newContents, 'utf8');
}
}
async function updateProjectFile(agentPath, newBundleId) {
let projectFilePath = _path.default.resolve(agentPath, PROJECT_FILE);
try {
await _appiumSupport.fs.copyFile(projectFilePath, `${projectFilePath}.old`);
await replaceInFile(projectFilePath, new RegExp(_lodash.default.escapeRegExp(_constants.WDA_RUNNER_BUNDLE_ID), 'g'), newBundleId);
_logger.default.debug(`Successfully updated '${projectFilePath}' with bundle id '${newBundleId}'`);
} catch (err) {
_logger.default.debug(`Error updating project file: ${err.message}`);
_logger.default.warn(`Unable to update project file '${projectFilePath}' with ` + `bundle id '${newBundleId}'. WebDriverAgent may not start`);
}
}
async function resetProjectFile(agentPath) {
const projectFilePath = _path.default.join(agentPath, PROJECT_FILE);
try {
if (!(await _appiumSupport.fs.exists(`${projectFilePath}.old`))) {
return;
}
await _appiumSupport.fs.mv(`${projectFilePath}.old`, projectFilePath);
_logger.default.debug(`Successfully reset '${projectFilePath}' with bundle id '${_constants.WDA_RUNNER_BUNDLE_ID}'`);
} catch (err) {
_logger.default.debug(`Error resetting project file: ${err.message}`);
_logger.default.warn(`Unable to reset project file '${projectFilePath}' with ` + `bundle id '${_constants.WDA_RUNNER_BUNDLE_ID}'. WebDriverAgent has been ` + `modified and not returned to the original state.`);
}
}
async function setRealDeviceSecurity(keychainPath, keychainPassword) {
_logger.default.debug('Setting security for iOS device');
await (0, _teen_process.exec)('security', ['-v', 'list-keychains', '-s', keychainPath]);
await (0, _teen_process.exec)('security', ['-v', 'unlock-keychain', '-p', keychainPassword, keychainPath]);
await (0, _teen_process.exec)('security', ['set-keychain-settings', '-t', '3600', '-l', keychainPath]);
}
async function generateXcodeConfigFile(orgId, signingId) {
_logger.default.debug(`Generating xcode config file for orgId '${orgId}' and signingId ` + `'${signingId}'`);
const contents = `DEVELOPMENT_TEAM = ${orgId}
CODE_SIGN_IDENTITY = ${signingId}
`;
const xcconfigPath = await _appiumSupport.tempDir.path('appium-temp.xcconfig');
_logger.default.debug(`Writing xcode config file to ${xcconfigPath}`);
await _appiumSupport.fs.writeFile(xcconfigPath, contents, 'utf8');
return xcconfigPath;
}
async function setXctestrunFile(deviceInfo, sdkVersion, bootstrapPath, wdaRemotePort) {
const xctestrunFilePath = await getXctestrunFilePath(deviceInfo, sdkVersion, bootstrapPath);
const xctestRunContent = await _appiumSupport.plist.parsePlistFile(xctestrunFilePath);
const updateWDAPort = getAdditionalRunContent(deviceInfo.platformName, wdaRemotePort);
const newXctestRunContent = _lodash.default.merge(xctestRunContent, updateWDAPort);
await _appiumSupport.plist.updatePlistFile(xctestrunFilePath, newXctestRunContent, true);
return xctestrunFilePath;
}
function getAdditionalRunContent(platformName, wdaRemotePort) {
const runner = `WebDriverAgentRunner${isTvOS(platformName) ? '_tvOS' : ''}`;
return {
[runner]: {
EnvironmentVariables: {
USE_PORT: wdaRemotePort
}
}
};
}
async function getXctestrunFilePath(deviceInfo, sdkVersion, bootstrapPath) {
const sdkBased = [_path.default.resolve(bootstrapPath, `${deviceInfo.udid}_${sdkVersion}.xctestrun`), sdkVersion];
const platformBased = [_path.default.resolve(bootstrapPath, `${deviceInfo.udid}_${deviceInfo.platformVersion}.xctestrun`), deviceInfo.platformVersion];
for (const [filePath, version] of [sdkBased, platformBased]) {
if (await _appiumSupport.fs.exists(filePath)) {
_logger.default.info(`Using '${filePath}' as xctestrun file`);
return filePath;
}
const originalXctestrunFile = _path.default.resolve(bootstrapPath, getXctestrunFileName(deviceInfo, version));
if (await _appiumSupport.fs.exists(originalXctestrunFile)) {
await _appiumSupport.fs.copyFile(originalXctestrunFile, filePath);
_logger.default.info(`Using '${filePath}' as xctestrun file copied by '${originalXctestrunFile}'`);
return filePath;
}
}
_logger.default.errorAndThrow(`If you are using 'useXctestrunFile' capability then you ` + `need to have a xctestrun file (expected: ` + `'${_path.default.resolve(bootstrapPath, getXctestrunFileName(deviceInfo, sdkVersion))}')`);
}
function getXctestrunFileName(deviceInfo, version) {
return isTvOS(deviceInfo.platformName) ? `WebDriverAgentRunner_tvOS_appletv${deviceInfo.isRealDevice ? `os${version}-arm64` : `simulator${version}-x86_64`}.xctestrun` : `WebDriverAgentRunner_iphone${deviceInfo.isRealDevice ? `os${version}-arm64` : `simulator${version}-x86_64`}.xctestrun`;
}
async function killProcess(name, proc) {
if (!proc || !proc.isRunning) {
return;
}
_logger.default.info(`Shutting down '${name}' process (pid '${proc.proc.pid}')`);
_logger.default.info(`Sending 'SIGTERM'...`);
try {
await proc.stop('SIGTERM', 1000);
return;
} catch (err) {
if (!err.message.includes(`Process didn't end after`)) {
throw err;
}
_logger.default.debug(`${name} process did not end in a timely fashion: '${err.message}'.`);
}
_logger.default.info(`Sending 'SIGKILL'...`);
try {
await proc.stop('SIGKILL');
} catch (err) {
if (err.message.includes('not currently running')) {
return;
}
throw err;
}
}
function randomInt(low, high) {
return Math.floor(Math.random() * (high - low) + low);
}
async function getWDAUpgradeTimestamp(bootstrapPath) {
const carthageRootPath = _path.default.resolve(bootstrapPath, _constants.CARTHAGE_ROOT);
if (await _appiumSupport.fs.exists(carthageRootPath)) {
const {
mtime
} = await _appiumSupport.fs.stat(carthageRootPath);
return mtime.getTime();
}
return null;
}
async function resetTestProcesses(udid, isSimulator) {
const processPatterns = [`xcodebuild.*${udid}`];
if (isSimulator) {
processPatterns.push(`${udid}.*XCTRunner`);
processPatterns.push(`xctest.*${udid}`);
}
_logger.default.debug(`Killing running processes '${processPatterns.join(', ')}' for the device ${udid}...`);
await _bluebird.default.all(processPatterns.map(killAppUsingPattern));
}
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) {
if (e.code !== 1) {
_logger.default.debug(`Error getting processes listening on port '${port}': ${e.stderr || e.message}`);
}
return result;
}
if (!_lodash.default.isFunction(filteringFunc)) {
return result;
}
return await _bluebird.default.filter(result, async pid => {
let stdout;
try {
({
stdout
} = await (0, _teen_process.exec)('ps', ['-p', pid, '-o', 'command']));
} catch (e) {
if (e.code === 1) {
return false;
}
throw e;
}
return await filteringFunc(stdout);
});
}require('source-map-support').install();
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi91dGlscy5qcyJdLCJuYW1lcyI6WyJQUk9KRUNUX0ZJTEUiLCJnZXRQSURzVXNpbmdQYXR0ZXJuIiwicGF0dGVybiIsImFyZ3MiLCJzdGRvdXQiLCJzcGxpdCIsIm1hcCIsIngiLCJwYXJzZUludCIsImZpbHRlciIsIl8iLCJpc0ludGVnZXIiLCJlcnIiLCJsb2ciLCJkZWJ1ZyIsImpvaW4iLCJjb2RlIiwia2lsbEFwcFVzaW5nUGF0dGVybiIsInBncmVwUGF0dGVybiIsInNpZ25hbHMiLCJzaWduYWwiLCJtYXRjaGVkUGlkcyIsImlzRW1wdHkiLCJtZXNzYWdlIiwibGFzdCIsInBpZENoZWNrUHJvbWlzZXMiLCJwaWQiLCJ0aGVuIiwiY2F0Y2giLCJCIiwiYWxsIiwiZXZlcnkiLCJ3YWl0TXMiLCJpbnRlcnZhbE1zIiwiaWduIiwiaXNUdk9TIiwicGxhdGZvcm1OYW1lIiwidG9Mb3dlciIsIlBMQVRGT1JNX05BTUVfVFZPUyIsImFyZUZpbGVzRXF1YWwiLCJmaWxlMSIsImZpbGUyIiwiZmlsZXMiLCJmIiwiZnMiLCJleGlzdHMiLCJoYXNoMSIsImhhc2gyIiwiaGFzaCIsInJlcGxhY2VJbkZpbGUiLCJmaWxlIiwiZmluZCIsInJlcGxhY2UiLCJjb250ZW50cyIsInJlYWRGaWxlIiwibmV3Q29udGVudHMiLCJ3cml0ZUZpbGUiLCJ1cGRhdGVQcm9qZWN0RmlsZSIsImFnZW50UGF0aCIsIm5ld0J1bmRsZUlkIiwicHJvamVjdEZpbGVQYXRoIiwicGF0aCIsInJlc29sdmUiLCJjb3B5RmlsZSIsIlJlZ0V4cCIsImVzY2FwZVJlZ0V4cCIsIldEQV9SVU5ORVJfQlVORExFX0lEIiwid2FybiIsInJlc2V0UHJvamVjdEZpbGUiLCJtdiIsInNldFJlYWxEZXZpY2VTZWN1cml0eSIsImtleWNoYWluUGF0aCIsImtleWNoYWluUGFzc3dvcmQiLCJnZW5lcmF0ZVhjb2RlQ29uZmlnRmlsZSIsIm9yZ0lkIiwic2lnbmluZ0lkIiwieGNjb25maWdQYXRoIiwidGVtcERpciIsInNldFhjdGVzdHJ1bkZpbGUiLCJkZXZpY2VJbmZvIiwic2RrVmVyc2lvbiIsImJvb3RzdHJhcFBhdGgiLCJ3ZGFSZW1vdGVQb3J0IiwieGN0ZXN0cnVuRmlsZVBhdGgiLCJnZXRYY3Rlc3RydW5GaWxlUGF0aCIsInhjdGVzdFJ1bkNvbnRlbnQiLCJwbGlzdCIsInBhcnNlUGxpc3RGaWxlIiwidXBkYXRlV0RBUG9ydCIsImdldEFkZGl0aW9uYWxSdW5Db250ZW50IiwibmV3WGN0ZXN0UnVuQ29udGVudCIsIm1lcmdlIiwidXBkYXRlUGxpc3RGaWxlIiwicnVubmVyIiwiRW52aXJvbm1lbnRWYXJpYWJsZXMiLCJVU0VfUE9SVCIsInNka0Jhc2VkIiwidWRpZCIsInBsYXRmb3JtQmFzZWQiLCJwbGF0Zm9ybVZlcnNpb24iLCJmaWxlUGF0aCIsInZlcnNpb24iLCJpbmZvIiwib3JpZ2luYWxYY3Rlc3RydW5GaWxlIiwiZ2V0WGN0ZXN0cnVuRmlsZU5hbWUiLCJlcnJvckFuZFRocm93IiwiaXNSZWFsRGV2aWNlIiwia2lsbFByb2Nlc3MiLCJuYW1lIiwicHJvYyIsImlzUnVubmluZyIsInN0b3AiLCJpbmNsdWRlcyIsInJhbmRvbUludCIsImxvdyIsImhpZ2giLCJNYXRoIiwiZmxvb3IiLCJyYW5kb20iLCJnZXRXREFVcGdyYWRlVGltZXN0YW1wIiwiY2FydGhhZ2VSb290UGF0aCIsIkNBUlRIQUdFX1JPT1QiLCJtdGltZSIsInN0YXQiLCJnZXRUaW1lIiwicmVzZXRUZXN0UHJvY2Vzc2VzIiwiaXNTaW11bGF0b3IiLCJwcm9jZXNzUGF0dGVybnMiLCJwdXNoIiwiZ2V0UElEc0xpc3RlbmluZ09uUG9ydCIsInBvcnQiLCJmaWx0ZXJpbmdGdW5jIiwicmVzdWx0IiwidHJpbSIsImUiLCJzdGRlcnIiLCJpc0Z1bmN0aW9uIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUdBLE1BQU1B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SSxDQUFDMUgsZ0JBQUU4SCxVQUFGLENBQWFMLGFBQWIsQ0FBTCxFQUFrQztBQUNoQyxXQUFPQyxNQUFQO0FBQ0Q7O0FBQ0QsU0FBTyxNQUFNdkcsa0JBQUVwQixNQUFGLENBQVMySCxNQUFULEVBQWlCLE1BQU8xRyxHQUFQLElBQWU7QUFDM0MsUUFBSXRCLE1BQUo7O0FBQ0EsUUFBSTtBQUNGLE9BQUM7QUFBQ0EsUUFBQUE7QUFBRCxVQUFXLE1BQU0sd0JBQUssSUFBTCxFQUFXLENBQUMsSUFBRCxFQUFPc0IsR0FBUCxFQUFZLElBQVosRUFBa0IsU0FBbEIsQ0FBWCxDQUFsQjtBQUNELEtBRkQsQ0FFRSxPQUFPNEcsQ0FBUCxFQUFVO0FBQ1YsVUFBSUEsQ0FBQyxDQUFDdEgsSUFBRixLQUFXLENBQWYsRUFBa0I7QUFFaEIsZUFBTyxLQUFQO0FBQ0Q7O0FBQ0QsWUFBTXNILENBQU47QUFDRDs7QUFDRCxXQUFPLE1BQU1ILGFBQWEsQ0FBQy9ILE1BQUQsQ0FBMUI7QUFDRCxHQVpZLENBQWI7QUFhRCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGZzLCB0ZW1wRGlyLCBwbGlzdCB9IGZyb20gJ2FwcGl1bS1zdXBwb3J0JztcbmltcG9ydCB7IGV4ZWMgfSBmcm9tICd0ZWVuX3Byb2Nlc3MnO1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgbG9nIGZyb20gJy4vbG9nZ2VyJztcbmltcG9ydCBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgeyBXREFfUlVOTkVSX0JVTkRMRV9JRCwgUExBVEZPUk1fTkFNRV9UVk9TLCBDQVJUSEFHRV9ST09UIH0gZnJvbSAnLi9jb25zdGFudHMnO1xuaW1wb3J0IEIgZnJvbSAnYmx1ZWJpcmQnO1xuaW1wb3J0IHsgd2FpdEZvckNvbmRpdGlvbiB9IGZyb20gJ2FzeW5jYm94JztcblxuXG5jb25zdCBQUk9KRUNUX0ZJTEUgPSAncHJvamVjdC5wYnhwcm9qJztcblxuYXN5bmMgZnVuY3Rpb24gZ2V0UElEc1VzaW5nUGF0dGVybiAocGF0dGVybikge1xuICBjb25zdCBhcmdzID0gW1xuICAgICctaWYnLCAvLyBjYXNlIGluc2Vuc2l0aXZlLCBmdWxsIGNtZGxpbmUgbWF0Y2hcbiAgICBwYXR0ZXJuLFxuICBdO1xuICB0cnkge1xuICAgIGNvbnN0IHtzdGRvdXR9ID0gYXdhaXQgZXhlYygncGdyZXAnLCBhcmdzKTtcbiAgICByZXR1cm4gc3Rkb3V0LnNwbGl0KC9cXHMrLylcbiAgICAgIC5tYXAoKHgpID0+IHBhcnNlSW50KHgsIDEwKSlcbiAgICAgIC5maWx0ZXIoXy5pc0ludGVnZXIpXG4gICAgICAubWFwKCh4KSA9PiBgJHt4fWApO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBsb2cuZGVidWcoYCdwZ3JlcCAke2FyZ3Muam9pbignICcpfScgZGlkbid0IGRldGVjdCBhbnkgbWF0Y2hpbmcgcHJvY2Vzc2VzLiBSZXR1cm4gY29kZTogJHtlcnIuY29kZX1gKTtcbiAgICByZXR1cm4gW107XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24ga2lsbEFwcFVzaW5nUGF0dGVybiAocGdyZXBQYXR0ZXJuKSB7XG4gIGNvbnN0IHNpZ25hbHMgPSBbMiwgMTUsIDldO1xuICBmb3IgKGNvbnN0IHNpZ25hbCBvZiBzaWduYWxzKSB7XG4gICAgY29uc3QgbWF0Y2hlZFBpZHMgPSBhd2FpdCBnZXRQSURzVXNpbmdQYXR0ZXJuKHBncmVwUGF0dGVybik7XG4gICAgaWYgKF8uaXNFbXB0eShtYXRjaGVkUGlkcykpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgYXJncyA9IFtgLSR7c2lnbmFsfWAsIC4uLm1hdGNoZWRQaWRzXTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgZXhlYygna2lsbCcsIGFyZ3MpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgbG9nLmRlYnVnKGBraWxsICR7YXJncy5qb2luKCcgJyl9IC0+ICR7ZXJyLm1lc3NhZ2V9YCk7XG4gICAgfVxuICAgIGlmIChzaWduYWwgPT09IF8ubGFzdChzaWduYWxzKSkge1xuICAgICAgLy8gdGhlcmUgaXMgbm8gbmVlZCB0byB3YWl0IGFmdGVyIFNJR0tJTExcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHdhaXRGb3JDb25kaXRpb24oYXN5bmMgKCkgPT4ge1xuICAgICAgICBjb25zdCBwaWRDaGVja1Byb21pc2VzID0gbWF0Y2hlZFBpZHNcbiAgICAgICAgICAubWFwKChwaWQpID0+IGV4ZWMoJ2tpbGwnLCBbJy0wJywgcGlkXSlcbiAgICAgICAgICAgIC8vIHRoZSBwcm9jZXNzIGlzIHN0aWxsIGFsaXZlXG4gICAgICAgICAgICAudGhlbigoKSA9PiBmYWxzZSlcbiAgICAgICAgICAgIC8vIHRoZSBwcm9jZXNzIGlzIGRlYWRcbiAgICAgICAgICAgIC5jYXRjaCgoKSA9PiB0cnVlKVxuICAgICAgICAgICk7XG4gICAgICAgIHJldHVybiAoYXdhaXQgQi5hbGwocGlkQ2hlY2tQcm9taXNlcykpXG4gICAgICAgICAgLmV2ZXJ5KCh4KSA9PiB4ID09PSB0cnVlKTtcbiAgICAgIH0sIHtcbiAgICAgICAgd2FpdE1zOiAxMDAwLFxuICAgICAgICBpbnRlcnZhbE1zOiAxMDAsXG4gICAgICB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9IGNhdGNoIChpZ24pIHtcbiAgICAgIC8vIHRyeSB0aGUgbmV4dCBzaWduYWxcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm4gdHJ1ZSBpZiB0aGUgcGxhdGZvcm1OYW1lIGlzIHR2T1NcbiAqIEBwYXJhbSB7c3RyaW5nfSBwbGF0Zm9ybU5hbWUgVGhlIG5hbWUgb2YgdGhlIHBsYXRvcm1cbiAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm4gdHJ1ZSBpZiB0aGUgcGxhdGZvcm1OYW1lIGlzIHR2T1NcbiAqL1xuZnVuY3Rpb24gaXNUdk9TIChwbGF0Zm9ybU5hbWUpIHtcbiAgcmV0dXJuIF8udG9Mb3dlcihwbGF0Zm9ybU5hbWUpID09PSBfLnRvTG93ZXIoUExBVEZPUk1fTkFNRV9UVk9TKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gYXJlRmlsZXNFcXVhbCAoZmlsZTEsIGZpbGUyKSB7XG4gIGNvbnN0IGZpbGVzID0gW2ZpbGUxLCBmaWxlMl07XG4gIGlmICghXy5ldmVyeShhd2FpdCBCLmFsbChmaWxlcy5tYXAoKGYpID0+IGZzLmV4aXN0cyhmKSkpKSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBjb25zdCBbaGFzaDEsIGhhc2gyXSA9IGF3YWl0IEIuYWxsKGZpbGVzLm1hcCgoZikgPT4gZnMuaGFzaChmLCAnc2hhMScpKSk7XG4gIHJldHVybiBoYXNoMSA9PT0gaGFzaDI7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJlcGxhY2VJbkZpbGUgKGZpbGUsIGZpbmQsIHJlcGxhY2UpIHtcbiAgbGV0IGNvbnRlbnRzID0gYXdhaXQgZnMucmVhZEZpbGUoZmlsZSwgJ3V0ZjgnKTtcblxuICBsZXQgbmV3Q29udGVudHMgPSBjb250ZW50cy5yZXBsYWNlKGZpbmQsIHJlcGxhY2UpO1xuICBpZiAobmV3Q29udGVudHMgIT09IGNvbnRlbnRzKSB7XG4gICAgYXdhaXQgZnMud3JpdGVGaWxlKGZpbGUsIG5ld0NvbnRlbnRzLCAndXRmOCcpO1xuICB9XG59XG5cbi8qKlxuICogVXBkYXRlIFdlYkRyaXZlckFnZW50UnVubmVyIHByb2plY3QgYnVuZGxlIElEIHdpdGggbmV3QnVuZGxlSWQuXG4gKiBUaGlzIG1ldGhvZCBhc3N1bWVzIHByb2plY3QgZmlsZSBpcyBpbiB0aGUgY29ycmVjdCBzdGF0ZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBhZ2VudFBhdGggLSBQYXRoIHRvIHRoZSAueGNvZGVwcm9qIGRpcmVjdG9yeS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdCdW5kbGVJZCB0aGUgbmV3IGJ1bmRsZSBJRCB1c2VkIHRvIHVwZGF0ZS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gdXBkYXRlUHJvamVjdEZpbGUgKGFnZW50UGF0aCwgbmV3QnVuZGxlSWQpIHtcbiAgbGV0IHByb2plY3RGaWxlUGF0aCA9IHBhdGgucmVzb2x2ZShhZ2VudFBhdGgsIFBST0pFQ1RfRklMRSk7XG4gIHRyeSB7XG4gICAgLy8gQXNzdW1pbmcgcHJvamVjdEZpbGVQYXRoIGlzIGluIHRoZSBjb3JyZWN0IHN0YXRlLCBjcmVhdGUgLm9sZCBmcm9tIHByb2plY3RGaWxlUGF0aFxuICAgIGF3YWl0IGZzLmNvcHlGaWxlKHByb2plY3RGaWxlUGF0aCwgYCR7cHJvamVjdEZpbGVQYXRofS5vbGRgKTtcbiAgICBhd2FpdCByZXBsYWNlSW5GaWxlKHByb2plY3RGaWxlUGF0aCwgbmV3IFJlZ0V4cChfLmVzY2FwZVJlZ0V4cChXREFfUlVOTkVSX0JVTkRMRV9JRCksICdnJyksIG5ld0J1bmRsZUlkKTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11c2VsZXNzLWVzY2FwZVxuICAgIGxvZy5kZWJ1ZyhgU3VjY2Vzc2Z1bGx5IHVwZGF0ZWQgJyR7cHJvamVjdEZpbGVQYXRofScgd2l0aCBidW5kbGUgaWQgJyR7bmV3QnVuZGxlSWR9J2ApO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBsb2cuZGVidWcoYEVycm9yIHVwZGF0aW5nIHByb2plY3QgZmlsZTogJHtlcnIubWVzc2FnZX1gKTtcbiAgICBsb2cud2FybihgVW5hYmxlIHRvIHVwZGF0ZSBwcm9qZWN0IGZpbGUgJyR7cHJvamVjdEZpbGVQYXRofScgd2l0aCBgICtcbiAgICAgIGBidW5kbGUgaWQgJyR7bmV3QnVuZGxlSWR9Jy4gV2ViRHJpdmVyQWdlbnQgbWF5IG5vdCBzdGFydGApO1xuICB9XG59XG5cbi8qKlxuICogUmVzZXQgV2ViRHJpdmVyQWdlbnRSdW5uZXIgcHJvamVjdCBidW5kbGUgSUQgdG8gY29ycmVjdCBzdGF0ZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBhZ2VudFBhdGggLSBQYXRoIHRvIHRoZSAueGNvZGVwcm9qIGRpcmVjdG9yeS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVzZXRQcm9qZWN0RmlsZSAoYWdlbnRQYXRoKSB7XG4gIGNvbnN0IHByb2plY3RGaWxlUGF0aCA9IHBhdGguam9pbihhZ2VudFBhdGgsIFBST0pFQ1RfRklMRSk7XG4gIHRyeSB7XG4gICAgLy8gcmVzdG9yZSBwcm9qZWN0RmlsZVBhdGggZnJvbSAub2xkIGZpbGVcbiAgICBpZiAoIWF3YWl0IGZzLmV4aXN0cyhgJHtwcm9qZWN0RmlsZVBhdGh9Lm9sZGApKSB7XG4gICAgICByZXR1cm47IC8vIG5vIG5lZWQgdG8gcmVzZXRcbiAgICB9XG4gICAgYXdhaXQgZnMubXYoYCR7cHJvamVjdEZpbGVQYXRofS5vbGRgLCBwcm9qZWN0RmlsZVBhdGgpO1xuICAgIGxvZy5kZWJ1ZyhgU3VjY2Vzc2Z1bGx5IHJlc2V0ICcke3Byb2plY3RGaWxlUGF0aH0nIHdpdGggYnVuZGxlIGlkICcke1dEQV9SVU5ORVJfQlVORExFX0lEfSdgKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nLmRlYnVnKGBFcnJvciByZXNldHRpbmcgcHJvamVjdCBmaWxlOiAke2Vyci5tZXNzYWdlfWApO1xuICAgIGxvZy53YXJuKGBVbmFibGUgdG8gcmVzZXQgcHJvamVjdCBmaWxlICcke3Byb2plY3RGaWxlUGF0aH0nIHdpdGggYCArXG4gICAgICBgYnVuZGxlIGlkICcke1dEQV9SVU5ORVJfQlVORExFX0lEfScuIFdlYkRyaXZlckFnZW50IGhhcyBiZWVuIGAgK1xuICAgICAgYG1vZGlmaWVkIGFuZCBub3QgcmV0dXJuZWQgdG8gdGhlIG9yaWdpbmFsIHN0YXRlLmApO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNldFJlYWxEZXZpY2VTZWN1cml0eSAoa2V5Y2hhaW5QYXRoLCBrZXljaGFpblBhc3N3b3JkKSB7XG4gIGxvZy5kZWJ1ZygnU2V0dGluZyBzZWN1cml0eSBmb3IgaU9TIGRldmljZScpO1xuICBhd2FpdCBleGVjKCdzZWN1cml0eScsIFsnLXYnLCAnbGlzdC1rZXljaGFpbnMnLCAnLXMnLCBrZXljaGFpblBhdGhdKTtcbiAgYXdhaXQgZXhlYygnc2VjdXJpdHknLCBbJy12JywgJ3VubG9jay1rZXljaGFpbicsICctcCcsIGtleWNoYWluUGFzc3dvcmQsIGtleWNoYWluUGF0aF0pO1xuICBhd2FpdCBleGVjKCdzZWN1cml0eScsIFsnc2V0LWtleWNoYWluLXNldHRpbmdzJywgJy10JywgJzM2MDAnLCAnLWwnLCBrZXljaGFpblBhdGhdKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2VuZXJhdGVYY29kZUNvbmZpZ0ZpbGUgKG9yZ0lkLCBzaWduaW5nSWQpIHtcbiAgbG9nLmRlYnVnKGBHZW5lcmF0aW5nIHhjb2RlIGNvbmZpZyBmaWxlIGZvciBvcmdJZCAnJHtvcmdJZH0nIGFuZCBzaWduaW5nSWQgYCArXG4gICAgICAgICAgICBgJyR7c2lnbmluZ0lkfSdgKTtcbiAgY29uc3QgY29udGVudHMgPSBgREVWRUxPUE1FTlRfVEVBTSA9ICR7b3JnSWR9XG5DT0RFX1NJR05fSURFTlRJVFkgPSAke3NpZ25pbmdJZH1cbmA7XG4gIGNvbnN0IHhjY29uZmlnUGF0aCA9IGF3YWl0IHRlbXBEaXIucGF0aCgnYXBwaXVtLXRlbXAueGNjb25maWcnKTtcbiAgbG9nLmRlYnVnKGBXcml0aW5nIHhjb2RlIGNvbmZpZyBmaWxlIHRvICR7eGNjb25maWdQYXRofWApO1xuICBhd2FpdCBmcy53cml0ZUZpbGUoeGNjb25maWdQYXRoLCBjb250ZW50cywgJ3V0ZjgnKTtcbiAgcmV0dXJuIHhjY29uZmlnUGF0aDtcbn1cblxuLyoqXG4gKiBJbmZvcm1hdGlvbiBvZiB0aGUgZGV2aWNlIHVuZGVyIHRlc3RcbiAqIEB0eXBlZGVmIHtPYmplY3R9IERldmljZUluZm9cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBpc1JlYWxEZXZpY2UgLSBFcXVhbHMgdG8gdHJ1ZSBpZiB0aGUgY3VycmVudCBkZXZpY2UgaXMgYSByZWFsIGRldmljZVxuICogQHByb3BlcnR5IHtzdHJpbmd9IHVkaWQgLSBUaGUgZGV2aWNlIFVESUQuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gcGxhdGZvcm1WZXJzaW9uIC0gVGhlIHBsYXRmb3JtIHZlcnNpb24gb2YgT1MuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gcGxhdGZvcm1OYW1lIC0gVGhlIHBsYXRmb3JtIG5hbWUgb2YgaU9TLCB0dk9TXG4qL1xuLyoqXG4gKiBDcmVhdGVzIHhjdGVzdHJ1biBmaWxlIHBlciBkZXZpY2UgJiBwbGF0Zm9ybSB2ZXJzaW9uLlxuICogV2UgZXhwZWN0cyB0byBoYXZlIFdlYkRyaXZlckFnZW50UnVubmVyX2lwaG9uZW9zJHtzZGtWZXJzaW9ufHBsYXRmb3JtVmVyc2lvbn0tYXJtNjQueGN0ZXN0cnVuIGZvciByZWFsIGRldmljZVxuICogYW5kIFdlYkRyaXZlckFnZW50UnVubmVyX2lwaG9uZXNpbXVsYXRvciR7c2RrVmVyc2lvbnxwbGF0Zm9ybVZlcnNpb259LXg4Nl82NC54Y3Rlc3RydW4gZm9yIHNpbXVsYXRvciBsb2NhdGVkIEBib290c3RyYXBQYXRoXG4gKiBOZXdlciBYY29kZSAoWGNvZGUgMTAuMCBhdCBsZWFzdCkgZ2VuZXJhdGUgeGN0ZXN0cnVuIGZpbGUgZm9sbG93aW5nIHNka1ZlcnNpb24uXG4gKiBlLmcuIFhjb2RlIHdoaWNoIGhhcyBpT1MgU0RLIFZlcnNpb24gMTIuMiBnZW5lcmF0ZSBXZWJEcml2ZXJBZ2VudFJ1bm5lcl9pcGhvbmVzaW11bGF0b3IuMi14ODZfNjQueGN0ZXN0cnVuXG4gKiAgICAgIGV2ZW4gaWYgdGhlIGNhcCBoYXMgcGxhdGZvcm0gdmVyc2lvbiAxMS40XG4gKlxuICogQHBhcmFtIHtEZXZpY2VJbmZvfSBkZXZpY2VJbmZvXG4gKiBAcGFyYW0ge3N0cmluZ30gc2RrVmVyc2lvbiAtIFRoZSBYY29kZSBTREsgdmVyc2lvbiBvZiBPUy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBib290c3RyYXBQYXRoIC0gVGhlIGZvbGRlciBwYXRoIGNvbnRhaW5pbmcgeGN0ZXN0cnVuIGZpbGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gd2RhUmVtb3RlUG9ydCAtIFRoZSByZW1vdGUgcG9ydCBXREEgaXMgbGlzdGVuaW5nIG9uLlxuICogQHJldHVybiB7c3RyaW5nfSByZXR1cm5zIHhjdGVzdHJ1bkZpbGVQYXRoIGZvciBnaXZlbiBkZXZpY2VcbiAqIEB0aHJvd3MgaWYgV2ViRHJpdmVyQWdlbnRSdW5uZXJfaXBob25lb3Mke3Nka1ZlcnNpb258cGxhdGZvcm1WZXJzaW9ufS1hcm02NC54Y3Rlc3RydW4gZm9yIHJlYWwgZGV2aWNlXG4gKiBvciBXZWJEcml2ZXJBZ2VudFJ1bm5lcl9pcGhvbmVzaW11bGF0b3Ike3Nka1ZlcnNpb258cGxhdGZvcm1WZXJzaW9ufS14ODZfNjQueGN0ZXN0cnVuIGZvciBzaW11bGF0b3IgaXMgbm90IGZvdW5kIEBib290c3RyYXBQYXRoLFxuICogdGhlbiBpdCB3aWxsIHRocm93IGZpbGUgbm90IGZvdW5kIGV4Y2VwdGlvblxuICovXG5hc3luYyBmdW5jdGlvbiBzZXRYY3Rlc3RydW5GaWxlIChkZXZpY2VJbmZvLCBzZGtWZXJzaW9uLCBib290c3RyYXBQYXRoLCB3ZGFSZW1vdGVQb3J0KSB7XG4gIGNvbnN0IHhjdGVzdHJ1bkZpbGVQYXRoID0gYXdhaXQgZ2V0WGN0ZXN0cnVuRmlsZVBhdGgoZGV2aWNlSW5mbywgc2RrVmVyc2lvbiwgYm9vdHN0cmFwUGF0aCk7XG4gIGNvbnN0IHhjdGVzdFJ1bkNvbnRlbnQgPSBhd2FpdCBwbGlzdC5wYXJzZVBsaXN0RmlsZSh4Y3Rlc3RydW5GaWxlUGF0aCk7XG4gIGNvbnN0IHVwZGF0ZVdEQVBvcnQgPSBnZXRBZGRpdGlvbmFsUnVuQ29udGVudChkZXZpY2VJbmZvLnBsYXRmb3JtTmFtZSwgd2RhUmVtb3RlUG9ydCk7XG4gIGNvbnN0IG5ld1hjdGVzdFJ1bkNvbnRlbnQgPSBfLm1lcmdlKHhjdGVzdFJ1bkNvbnRlbnQsIHVwZGF0ZVdEQVBvcnQpO1xuICBhd2FpdCBwbGlzdC51cGRhdGVQbGlzdEZpbGUoeGN0ZXN0cnVuRmlsZVBhdGgsIG5ld1hjdGVzdFJ1bkNvbnRlbnQsIHRydWUpO1xuXG4gIHJldHVybiB4Y3Rlc3RydW5GaWxlUGF0aDtcbn1cblxuLyoqXG4gKiBSZXR1cm4gdGhlIFdEQSBvYmplY3Qgd2hpY2ggYXBwZW5kcyBleGlzdGluZyB4Y3Rlc3QgcnVubmVyIGNvbnRlbnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBwbGF0Zm9ybU5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgcGxhdGZvcm1cbiAqIEBwYXJhbSB7c3RyaW5nfSB2ZXJzaW9uIC0gVGhlIFhjb2RlIFNESyB2ZXJzaW9uIG9mIE9TLlxuICogQHJldHVybiB7b2JqZWN0fSByZXR1cm5zIGEgcnVubmVyIG9iamVjdCB3aGljaCBoYXMgVVNFX1BPUlRcbiAqL1xuZnVuY3Rpb24gZ2V0QWRkaXRpb25hbFJ1bkNvbnRlbnQgKHBsYXRmb3JtTmFtZSwgd2RhUmVtb3RlUG9ydCkge1xuICBjb25zdCBydW5uZXIgPSBgV2ViRHJpdmVyQWdlbnRSdW5uZXIke2lzVHZPUyhwbGF0Zm9ybU5hbWUpID8gJ190dk9TJyA6ICcnfWA7XG5cbiAgcmV0dXJuIHtcbiAgICBbcnVubmVyXToge1xuICAgICAgRW52aXJvbm1lbnRWYXJpYWJsZXM6IHtcbiAgICAgICAgVVNFX1BPUlQ6IHdkYVJlbW90ZVBvcnRcbiAgICAgIH1cbiAgICB9XG4gIH07XG59XG5cbi8qKlxuICogUmV0dXJuIHRoZSBwYXRoIG9mIHhjdGVzdHJ1biBpZiBpdCBleGlzdHNcbiAqIEBwYXJhbSB7RGV2aWNlSW5mb30gZGV2aWNlSW5mb1xuICogQHBhcmFtIHtzdHJpbmd9IHNka1ZlcnNpb24gLSBUaGUgWGNvZGUgU0RLIHZlcnNpb24gb2YgT1MuXG4gKiBAcGFyYW0ge3N0cmluZ30gYm9vdHN0cmFwUGF0aCAtIFRoZSBmb2xkZXIgcGF0aCBjb250YWluaW5nIHhjdGVzdHJ1biBmaWxlLlxuICovXG5hc3luYyBmdW5jdGlvbiBnZXRYY3Rlc3RydW5GaWxlUGF0aCAoZGV2aWNlSW5mbywgc2RrVmVyc2lvbiwgYm9vdHN0cmFwUGF0aCkge1xuICAvLyBGaXJzdCB0cnkgdGhlIFNESyBwYXRoLCBmb3IgWGNvZGUgMTAgKGF0IGxlYXN0KVxuICBjb25zdCBzZGtCYXNlZCA9IFtcbiAgICBwYXRoLnJlc29sdmUoYm9vdHN0cmFwUGF0aCwgYCR7ZGV2aWNlSW5mby51ZGlkfV8ke3Nka1ZlcnNpb259LnhjdGVzdHJ1bmApLFxuICAgIHNka1ZlcnNpb24sXG4gIF07XG4gIC8vIE5leHQgdHJ5IFBsYXRmb3JtIHBhdGgsIGZvciBlYXJsaWVyIFhjb2RlIHZlcnNpb25zXG4gIGNvbnN0IHBsYXRmb3JtQmFzZWQgPSBbXG4gICAgcGF0aC5yZXNvbHZlKGJvb3RzdHJhcFBhdGgsIGAke2RldmljZUluZm8udWRpZH1fJHtkZXZpY2VJbmZvLnBsYXRmb3JtVmVyc2lvbn0ueGN0ZXN0cnVuYCksXG4gICAgZGV2aWNlSW5mby5wbGF0Zm9ybVZlcnNpb24sXG4gIF07XG5cbiAgZm9yIChjb25zdCBbZmlsZVBhdGgsIHZlcnNpb25dIG9mIFtzZGtCYXNlZCwgcGxhdGZvcm1CYXNlZF0pIHtcbiAgICBpZiAoYXdhaXQgZnMuZXhpc3RzKGZpbGVQYXRoKSkge1xuICAgICAgbG9nLmluZm8oYFVzaW5nICcke2ZpbGVQYXRofScgYXMgeGN0ZXN0cnVuIGZpbGVgKTtcbiAgICAgIHJldHVybiBmaWxlUGF0aDtcbiAgICB9XG4gICAgY29uc3Qgb3JpZ2luYWxYY3Rlc3RydW5GaWxlID0gcGF0aC5yZXNvbHZlKGJvb3RzdHJhcFBhdGgsIGdldFhjdGVzdHJ1bkZpbGVOYW1lKGRldmljZUluZm8sIHZlcnNpb24pKTtcbiAgICBpZiAoYXdhaXQgZnMuZXhpc3RzKG9yaWdpbmFsWGN0ZXN0cnVuRmlsZSkpIHtcbiAgICAgIC8vIElmIHRoaXMgaXMgZmlyc3QgdGltZSBydW4gZm9yIGdpdmVuIGRldmljZSwgdGhlbiBmaXJzdCBnZW5lcmF0ZSB4Y3Rlc3RydW4gZmlsZSBmb3IgZGV2aWNlLlxuICAgICAgLy8gV2UgbmVlZCB0byBoYXZlIGEgeGN0ZXN0cnVuIGZpbGUgKipwZXIgZGV2aWNlKiogYmVjYXVzZSB3ZSBjYW50IG5vdCBoYXZlIHNhbWUgd2RhIHBvcnQgZm9yIGFsbCBkZXZpY2VzLlxuICAgICAgYXdhaXQgZnMuY29weUZpbGUob3JpZ2luYWxYY3Rlc3RydW5GaWxlLCBmaWxlUGF0aCk7XG4gICAgICBsb2cuaW5mbyhgVXNpbmcgJyR7ZmlsZVBhdGh9JyBhcyB4Y3Rlc3RydW4gZmlsZSBjb3BpZWQgYnkgJyR7b3JpZ2luYWxYY3Rlc3RydW5GaWxlfSdgKTtcbiAgICAgIHJldHVybiBmaWxlUGF0aDtcbiAgICB9XG4gIH1cblxuICBsb2cuZXJyb3JBbmRUaHJvdyhgSWYgeW91IGFyZSB1c2luZyAndXNlWGN0ZXN0cnVuRmlsZScgY2FwYWJpbGl0eSB0aGVuIHlvdSBgICtcbiAgICBgbmVlZCB0byBoYXZlIGEgeGN0ZXN0cnVuIGZpbGUgKGV4cGVjdGVkOiBgICtcbiAgICBgJyR7cGF0aC5yZXNvbHZlKGJvb3RzdHJhcFBhdGgsIGdldFhjdGVzdHJ1bkZpbGVOYW1lKGRldmljZUluZm8sIHNka1ZlcnNpb24pKX0nKWApO1xufVxuXG5cbi8qKlxuICogUmV0dXJuIHRoZSBuYW1lIG9mIHhjdGVzdHJ1biBmaWxlXG4gKiBAcGFyYW0ge0RldmljZUluZm99IGRldmljZUluZm9cbiAqIEBwYXJhbSB7c3RyaW5nfSB2ZXJzaW9uIC0gVGhlIFhjb2RlIFNESyB2ZXJzaW9uIG9mIE9TLlxuICogQHJldHVybiB7c3RyaW5nfSByZXR1cm5zIHhjdGVzdHJ1bkZpbGVQYXRoIGZvciBnaXZlbiBkZXZpY2VcbiAqL1xuZnVuY3Rpb24gZ2V0WGN0ZXN0cnVuRmlsZU5hbWUgKGRldmljZUluZm8sIHZlcnNpb24pIHtcbiAgcmV0dXJuIGlzVHZPUyhkZXZpY2VJbmZvLnBsYXRmb3JtTmFtZSlcbiAgICA/IGBXZWJEcml2ZXJBZ2VudFJ1bm5lcl90dk9TX2FwcGxldHYke2RldmljZUluZm8uaXNSZWFsRGV2aWNlID8gYG9zJHt2ZXJzaW9ufS1hcm02NGAgOiBgc2ltdWxhdG9yJHt2ZXJzaW9ufS14ODZfNjRgfS54Y3Rlc3RydW5gXG4gICAgOiBgV2ViRHJpdmVyQWdlbnRSdW5uZXJfaXBob25lJHtkZXZpY2VJbmZvLmlzUmVhbERldmljZSA/IGBvcyR7dmVyc2lvbn0tYXJtNjRgIDogYHNpbXVsYXRvciR7dmVyc2lvbn0teDg2XzY0YH0ueGN0ZXN0cnVuYDtcbn1cblxuYXN5bmMgZnVuY3Rpb24ga2lsbFByb2Nlc3MgKG5hbWUsIHByb2MpIHtcbiAgaWYgKCFwcm9jIHx8ICFwcm9jLmlzUnVubmluZykge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGxvZy5pbmZvKGBTaHV0dGluZyBkb3duICcke25hbWV9JyBwcm9jZXNzIChwaWQgJyR7cHJvYy5wcm9jLnBpZH0nKWApO1xuXG4gIGxvZy5pbmZvKGBTZW5kaW5nICdTSUdURVJNJy4uLmApO1xuICB0cnkge1xuICAgIGF3YWl0IHByb2Muc3RvcCgnU0lHVEVSTScsIDEwMDApO1xuICAgIHJldHVybjtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgaWYgKCFlcnIubWVzc2FnZS5pbmNsdWRlcyhgUHJvY2VzcyBkaWRuJ3QgZW5kIGFmdGVyYCkpIHtcbiAgICAgIHRocm93IGVycjtcbiAgICB9XG4gICAgbG9nLmRlYnVnKGAke25hbWV9IHByb2Nlc3MgZGlkIG5vdCBlbmQgaW4gYSB0aW1lbHkgZmFzaGlvbjogJyR7ZXJyLm1lc3NhZ2V9Jy5gKTtcbiAgfVxuXG4gIGxvZy5pbmZvKGBTZW5kaW5nICdTSUdLSUxMJy4uLmApO1xuICB0cnkge1xuICAgIGF3YWl0IHByb2Muc3RvcCgnU0lHS0lMTCcpO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBpZiAoZXJyLm1lc3NhZ2UuaW5jbHVkZXMoJ25vdCBjdXJyZW50bHkgcnVubmluZycpKSB7XG4gICAgICAvLyB0aGUgcHJvY2VzcyBlbmRlZCBidXQgZm9yIHNvbWUgcmVhc29uIHdlIHdlcmUgbm90IGluZm9ybWVkXG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRocm93IGVycjtcbiAgfVxufVxuXG4vKipcbiAqIEdlbmVyYXRlIGEgcmFuZG9tIGludGVnZXIuXG4gKlxuICogQHJldHVybiB7bnVtYmVyfSBBIHJhbmRvbSBpbnRlZ2VyIG51bWJlciBpbiByYW5nZSBbbG93LCBoaWdodCkuIGBsb3dgYCBpcyBpbmNsdXNpdmUgYW5kIGBoaWdoYCBpcyBleGNsdXNpdmUuXG4gKi9cbmZ1bmN0aW9uIHJhbmRvbUludCAobG93LCBoaWdoKSB7XG4gIHJldHVybiBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAoaGlnaCAtIGxvdykgKyBsb3cpO1xufVxuXG4vKipcbiAqIFJldHJpZXZlcyBXREEgdXBncmFkZSB0aW1lc3RhbXBcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gYm9vdHN0cmFwUGF0aCBUaGUgZnVsbCBwYXRoIHRvIHRoZSBmb2xkZXIgd2hlcmUgV0RBIHNvdXJjZSBpcyBsb2NhdGVkXG4gKiBAcmV0dXJuIHs/bnVtYmVyfSBUaGUgVU5JWCB0aW1lc3RhbXAgb2YgdGhlIGNhcnRoYWdlIHJvb3QgZm9sZGVyLCB3aGVyZSBkZXBlbmRlbmNpZXMgYXJlIGRvd25sb2FkZWQuXG4gKiBUaGlzIGZvbGRlciBpcyBjcmVhdGVkIG9ubHkgb25jZSBvbiBtb2R1bGUgdXBncmFkZS9maXJzdCBpbnN0YWxsLlxuICovXG5hc3luYyBmdW5jdGlvbiBnZXRXREFVcGdyYWRlVGltZXN0YW1wIChib290c3RyYXBQYXRoKSB7XG4gIGNvbnN0IGNhcnRoYWdlUm9vdFBhdGggPSBwYXRoLnJlc29sdmUoYm9vdHN0cmFwUGF0aCwgQ0FSVEhBR0VfUk9PVCk7XG4gIGlmIChhd2FpdCBmcy5leGlzdHMoY2FydGhhZ2VSb290UGF0aCkpIHtcbiAgICBjb25zdCB7bXRpbWV9ID0gYXdhaXQgZnMuc3RhdChjYXJ0aGFnZVJvb3RQYXRoKTtcbiAgICByZXR1cm4gbXRpbWUuZ2V0VGltZSgpO1xuICB9XG4gIHJldHVybiBudWxsO1xufVxuXG4vKipcbiAqIEtpbGxzIHJ1bm5pbmcgWENUZXN0IHByb2Nlc3NlcyBmb3IgdGhlIHBhcnRpY3VsYXIgZGV2aWNlLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB1ZGlkIC0gVGhlIGRldmljZSBVRElELlxuICogQHBhcmFtIHtib29sZWFufSBpc1NpbXVsYXRvciAtIEVxdWFscyB0byB0cnVlIGlmIHRoZSBjdXJyZW50IGRldmljZSBpcyBhIFNpbXVsYXRvclxuICovXG5hc3luYyBmdW5jdGlvbiByZXNldFRlc3RQcm9jZXNzZXMgKHVkaWQsIGlzU2ltdWxhdG9yKSB7XG4gIGNvbnN0IHByb2Nlc3NQYXR0ZXJucyA9IFtgeGNvZGVidWlsZC4qJHt1ZGlkfWBdO1xuICBpZiAoaXNTaW11bGF0b3IpIHtcbiAgICBwcm9jZXNzUGF0dGVybnMucHVzaChgJHt1ZGlkfS4qWENUUnVubmVyYCk7XG4gICAgLy8gVGhlIHBhdHRlcm4gdG8gZmluZCBpbiBjYXNlIGlkYiB3YXMgdXNlZFxuICAgIHByb2Nlc3NQYXR0ZXJucy5wdXNoKGB4Y3Rlc3QuKiR7dWRpZH1gKTtcbiAgfVxuICBsb2cuZGVidWcoYEtpbGxpbmcgcnVubmluZyBwcm9jZXNzZXMgJyR7cHJvY2Vzc1BhdHRlcm5zLmpvaW4oJywgJyl9JyBmb3IgdGhlIGRldmljZSAke3VkaWR9Li4uYCk7XG4gIGF3YWl0IEIuYWxsKHByb2Nlc3NQYXR0ZXJucy5tYXAoa2lsbEFwcFVzaW5nUGF0dGVybikpO1xufVxuXG4vKipcbiAqIEdldCB0aGUgSURzIG9mIHByb2Nlc3NlcyBsaXN0ZW5pbmcgb24gdGhlIHBhcnRpY3VsYXIgc3lzdGVtIHBvcnQuXG4gKiBJdCBpcyBhbHNvIHBvc3NpYmxlIHRvIGFwcGx5IGFkZGl0aW9uYWwgZmlsdGVyaW5nIGJhc2VkIG9uIHRoZVxuICogcHJvY2VzcyBjb21tYW5kIGxpbmUuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd8bnVtYmVyfSBwb3J0IC0gVGhlIHBvcnQgbnVtYmVyLlxuICogQHBhcmFtIHs/RnVuY3Rpb259IGZpbHRlcmluZ0Z1bmMgLSBPcHRpb25hbCBsYW1iZGEgZnVuY3Rpb24sIHdoaWNoXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlY2VpdmVzIGNvbW1hbmQgbGluZSBzdHJpbmcgb2YgdGhlIHBhcnRpY3VsYXIgcHJvY2Vzc1xuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0ZW5pbmcgb24gZ2l2ZW4gcG9ydCwgYW5kIGlzIGV4cGVjdGVkIHRvIHJldHVyblxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlaXRoZXIgdHJ1ZSBvciBmYWxzZSB0byBpbmNsdWRlL2V4Y2x1ZGUgdGhlIGNvcnJlc3BvbmRpbmcgUElEXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZyb20gdGhlIHJlc3VsdGluZyBhcnJheS5cbiAqIEByZXR1cm5zIHtBcnJheTxzdHJpbmc+fSAtIHRoZSBsaXN0IG9mIG1hdGNoZWQgcHJvY2VzcyBpZHMuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGdldFBJRHNMaXN0ZW5pbmdPblBvcnQgKHBvcnQsIGZpbHRlcmluZ0Z1bmMgPSBudWxsKSB7XG4gIGNvbnN0IHJlc3VsdCA9IFtdO1xuICB0cnkge1xuICAgIC8vIFRoaXMgb25seSB3b3JrcyBzaW5jZSBNYWMgT1MgWCBFbCBDYXBpdGFuXG4gICAgY29uc3Qge3N0ZG91dH0gPSBhd2FpdCBleGVjKCdsc29mJywgWyctdGknLCBgdGNwOiR7cG9ydH1gXSk7XG4gICAgcmVzdWx0LnB1c2goLi4uKHN0ZG91dC50cmltKCkuc3BsaXQoL1xcbisvKSkpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgaWYgKGUuY29kZSAhPT0gMSkge1xuICAgICAgLy8gY29kZSAxIG1lYW5zIG5vIHByb2Nlc3Nlcy4gT3RoZXIgZXJyb3JzIG5lZWQgcmVwb3J0aW5nXG4gICAgICBsb2cuZGVidWcoYEVycm9yIGdldHRpbmcgcHJvY2Vzc2VzIGxpc3RlbmluZyBvbiBwb3J0ICcke3BvcnR9JzogJHtlLnN0ZGVyciB8fCBlLm1lc3NhZ2V9YCk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICBpZiAoIV8uaXNGdW5jdGlvbihmaWx0ZXJpbmdGdW5jKSkge1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbiAgcmV0dXJuIGF3YWl0IEIuZmlsdGVyKHJlc3VsdCwgYXN5bmMgKHBpZCkgPT4ge1xuICAgIGxldCBzdGRvdXQ7XG4gICAgdHJ5IHtcbiAgICAgICh7c3Rkb3V0fSA9IGF3YWl0IGV4ZWMoJ3BzJywgWyctcCcsIHBpZCwgJy1vJywgJ2NvbW1hbmQnXSkpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGlmIChlLmNvZGUgPT09IDEpIHtcbiAgICAgICAgLy8gVGhlIHByb2Nlc3MgZG9lcyBub3QgZXhpc3QgYW55bW9yZSwgdGhlcmUncyBub3RoaW5nIHRvIGZpbHRlclxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgICByZXR1cm4gYXdhaXQgZmlsdGVyaW5nRnVuYyhzdGRvdXQpO1xuICB9KTtcbn1cblxuZXhwb3J0IHsgdXBkYXRlUHJvamVjdEZpbGUsIHJlc2V0UHJvamVjdEZpbGUsIHNldFJlYWxEZXZpY2VTZWN1cml0eSxcbiAgZ2V0QWRkaXRpb25hbFJ1bkNvbnRlbnQsIGdldFhjdGVzdHJ1bkZpbGVOYW1lLCBnZW5lcmF0ZVhjb2RlQ29uZmlnRmlsZSxcbiAgc2V0WGN0ZXN0cnVuRmlsZSwgZ2V0WGN0ZXN0cnVuRmlsZVBhdGgsIGtpbGxQcm9jZXNzLCByYW5kb21JbnQsXG4gIGdldFdEQVVwZ3JhZGVUaW1lc3RhbXAsIGFyZUZpbGVzRXF1YWwsIHJlc2V0VGVzdFByb2Nlc3NlcyxcbiAgZ2V0UElEc0xpc3RlbmluZ09uUG9ydCwga2lsbEFwcFVzaW5nUGF0dGVybiwgaXNUdk9TLFxufTtcbiJdLCJmaWxlIjoibGliL3V0aWxzLmpzIiwic291cmNlUm9vdCI6Ii4uLy4uIn0=