UNPKG

gst-atom-xcuitest-driver

Version:

ATOM driver for iOS using XCUITest for backend

348 lines (277 loc) 40 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; require("source-map-support/register"); var _appiumSupport = require("appium-support"); var _path = _interopRequireDefault(require("path")); var _gstAtomIosDevice = require("gst-atom-ios-device"); var _bluebird = _interopRequireDefault(require("bluebird")); var _logger = _interopRequireDefault(require("./logger")); var _lodash = _interopRequireDefault(require("lodash")); var _teen_process = require("teen_process"); var _nodeFetch = _interopRequireDefault(require("node-fetch")); const APPLICATION_INSTALLED_NOTIFICATION = 'com.apple.mobile.application_installed'; const INSTALLATION_STAGING_DIR = 'PublicStaging'; const DEFAULT_ITEM_PUSH_TIMEOUT = 30 * 1000; const APPLICATION_NOTIFICATION_TIMEOUT = 30 * 1000; const IOS_DEPLOY = 'ios-deploy'; class IOSDeploy { constructor(opts) { this.udid = opts.udid; this.opts = opts; } async remove(bundleId) { if (this.opts.webDriverAgentUrl) { const body = { serial: this.opts.udid, bundleId: bundleId }; _logger.default.info(`[${this.opts.udid}] Calling Device Farm to uninstall ${bundleId}`); let response = await (0, _nodeFetch.default)(this.opts.dfIOSUninstallApi, { method: 'post', body: JSON.stringify(body), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + this.opts.dfToken }, timeout: 3600000 }).catch(err => { _logger.default.error(`[${this.opts.udid}] ${err.message}`); _logger.default.errorAndThrow(err); }); let data = await response.json(); if (!data.success) { _logger.default.errorAndThrow(`[${this.opts.udid}] ${data.description}`); } _logger.default.info(`[${this.opts.udid}][${bundleId}] Uninstallation successfully`); return; } var options = { udid: this.udid, usbmuxdRemoteHost: this.opts.usbmuxdRemoteHost, usbmuxdRemotePort: this.opts.usbmuxdRemotePort }; const service = await _gstAtomIosDevice.services.startInstallationProxyService(options); try { await service.uninstallApplication(bundleId); } finally { service.close(); } } async removeApp(bundleId) { await this.remove(bundleId); } async installToDeviceFarm() { const body = { type: 'iOS', serial: this.opts.udid, url: this.opts.appUrl }; _logger.default.info(`[${this.opts.udid}] Calling Device Farm to install iOS application at ${this.opts.appUrl}`); let response = await (0, _nodeFetch.default)(this.opts.dfIOSInstallApi, { method: 'post', body: JSON.stringify(body), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + this.opts.dfToken }, timeout: 3600000 }).catch(err => { _logger.default.error(`[${this.opts.udid}] ${err.message}`); _logger.default.errorAndThrow(err); }); let data = await response.json(); if (!data.success) { _logger.default.errorAndThrow(`[${this.opts.udid}] ${data.description}`); } _logger.default.info(`[${this.opts.udid}] Installation successfully (${this.opts.appUrl}) `); } async install(app, timeout) { if (this.opts.webDriverAgentUrl) { await this.installToDeviceFarm(); return; } const timer = new _appiumSupport.timing.Timer().start(); try { const bundlePathOnPhone = await this.pushAppBundle(app, timeout); await this.installApplication(bundlePathOnPhone); } catch (err) { _logger.default.warn(`Error installing app: ${err.message}`); _logger.default.warn(`Falling back to '${IOS_DEPLOY}' usage`); try { await _appiumSupport.fs.which(IOS_DEPLOY); } catch (err1) { throw new Error(`Could not install '${app}':\n` + ` - ${err.message}\n` + ` - '${IOS_DEPLOY}' utility has not been found in PATH. Is it installed?`); } try { await (0, _teen_process.exec)(IOS_DEPLOY, ['--id', this.udid, '--bundle', app]); } catch (err1) { throw new Error(`Could not install '${app}':\n` + ` - ${err.message}\n` + ` - ${err1.stderr || err1.stdout || err1.message}`); } } _logger.default.info(`App installation succeeded after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`); } async installApplication(bundlePathOnPhone) { var options = { udid: this.udid, usbmuxdRemoteHost: this.opts.usbmuxdRemoteHost, usbmuxdRemotePort: this.opts.usbmuxdRemotePort }; const notificationService = await _gstAtomIosDevice.services.startNotificationProxyService(options); const installationService = await _gstAtomIosDevice.services.startInstallationProxyService(options); const appInstalledNotification = new _bluebird.default(resolve => { notificationService.observeNotification(APPLICATION_INSTALLED_NOTIFICATION, { notification: resolve }); }); try { await installationService.installApplication(bundlePathOnPhone, { PackageType: 'Developer' }); try { await appInstalledNotification.timeout(APPLICATION_NOTIFICATION_TIMEOUT, `Could not get the application installed notification within ${APPLICATION_NOTIFICATION_TIMEOUT}ms but we will continue`); } catch (e) { _logger.default.warn(`Failed to receive the notification. Error: ${e.message}`); } } finally { installationService.close(); notificationService.close(); } } async pushAppBundle(app, timeout = DEFAULT_ITEM_PUSH_TIMEOUT) { const timer = new _appiumSupport.timing.Timer().start(); var options = { udid: this.udid, usbmuxdRemoteHost: this.opts.usbmuxdRemoteHost, usbmuxdRemotePort: this.opts.usbmuxdRemotePort }; const afcService = await _gstAtomIosDevice.services.startAfcService(options); try { const bundlePathOnPhone = await this.createAppPath(afcService, app); await _appiumSupport.fs.walkDir(app, true, async (itemPath, isDir) => { const pathOnPhone = _path.default.join(bundlePathOnPhone, _path.default.relative(app, itemPath)); if (isDir) { await afcService.createDirectory(pathOnPhone); } else { const readStream = _appiumSupport.fs.createReadStream(itemPath, { autoClose: true }); const writeStream = await afcService.createWriteStream(pathOnPhone, { autoDestroy: true }); writeStream.on('finish', writeStream.destroy); let pushError = null; const itemPushWait = new _bluebird.default((resolve, reject) => { writeStream.on('close', () => { if (pushError) { reject(pushError); } else { resolve(); } }); const onStreamError = e => { readStream.unpipe(writeStream); _logger.default.debug(e); pushError = e; }; writeStream.on('error', onStreamError); readStream.on('error', onStreamError); }); readStream.pipe(writeStream); await itemPushWait.timeout(timeout, `Could not push '${itemPath}' within the timeout of ${timeout}ms. ` + `Consider increasing the value of 'appPushTimeout' capability.`); } }); _logger.default.debug(`Pushed the app files successfully after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`); return bundlePathOnPhone; } finally { afcService.close(); } } async createAppPath(afcService, localAppPath) { const basename = _path.default.basename(localAppPath); const relativePath = _path.default.join(INSTALLATION_STAGING_DIR, basename); try { await afcService.deleteDirectory(relativePath); } catch (ign) {} await afcService.createDirectory(relativePath); return relativePath; } async installApp(app, timeout) { await this.install(app, timeout); } async isAppInstalled(bundleId) { if (this.opts.webDriverAgentUrl) { const body = { serial: this.opts.udid, bundleId: bundleId }; _logger.default.info(`[${this.opts.udid}] Calling Device Farm to check the application with bundle id ${this.opts.appUrl} is installed`); let response = await (0, _nodeFetch.default)(this.opts.dfAppInstalledApi, { method: 'post', body: JSON.stringify(body), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + this.opts.dfToken }, timeout: 60000 }).catch(err => { _logger.default.error(`[${this.opts.udid}] ${err.message}`); _logger.default.errorAndThrow(err); }); let data = await response.json(); _logger.default.info(`[${this.opts.udid}] Application ${bundleId} is installed: ${data.isInstalled}`); return data.isInstalled; } var options = { udid: this.udid, usbmuxdRemoteHost: this.opts.usbmuxdRemoteHost, usbmuxdRemotePort: this.opts.usbmuxdRemotePort }; const service = await _gstAtomIosDevice.services.startInstallationProxyService(options); try { const applications = await service.lookupApplications({ bundleIds: bundleId }); return !!applications[bundleId]; } finally { service.close(); } } async getUserInstalledBundleIdsByBundleName(bundleName) { var options = { udid: this.udid, usbmuxdRemoteHost: this.opts.usbmuxdRemoteHost, usbmuxdRemotePort: this.opts.usbmuxdRemotePort }; const service = await _gstAtomIosDevice.services.startInstallationProxyService(options); try { const applications = await service.listApplications({ applicationType: 'User' }); return _lodash.default.reduce(applications, (acc, { CFBundleName }, key) => { if (CFBundleName === bundleName) { acc.push(key); } return acc; }, []); } finally { service.close(); } } async getPlatformVersion() { var options = { udid: this.udid, usbmuxdRemoteHost: this.opts.usbmuxdRemoteHost, usbmuxdRemotePort: this.opts.usbmuxdRemotePort }; return await _gstAtomIosDevice.utilities.getOSVersion(null, options); } } var _default = IOSDeploy; exports.default = _default;require('source-map-support').install(); //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi9pb3MtZGVwbG95LmpzIl0sIm5hbWVzIjpbIkFQUExJQ0FUSU9OX0lOU1RBTExFRF9OT1RJRklDQVRJT04iLCJJTlNUQUxMQVRJT05fU1RBR0lOR19ESVIiLCJERUZBVUxUX0lURU1fUFVTSF9USU1FT1VUIiwiQVBQTElDQVRJT05fTk9USUZJQ0FUSU9OX1RJTUVPVVQiLCJJT1NfREVQTE9ZIiwiSU9TRGVwbG95IiwiY29uc3RydWN0b3IiLCJvcHRzIiwidWRpZCIsInJlbW92ZSIsImJ1bmRsZUlkIiwid2ViRHJpdmVyQWdlbnRVcmwiLCJib2R5Iiwic2VyaWFsIiwibG9nIiwiaW5mbyIsInJlc3BvbnNlIiwiZGZJT1NVbmluc3RhbGxBcGkiLCJtZXRob2QiLCJKU09OIiwic3RyaW5naWZ5IiwiaGVhZGVycyIsImRmVG9rZW4iLCJ0aW1lb3V0IiwiY2F0Y2giLCJlcnIiLCJlcnJvciIsIm1lc3NhZ2UiLCJlcnJvckFuZFRocm93IiwiZGF0YSIsImpzb24iLCJzdWNjZXNzIiwiZGVzY3JpcHRpb24iLCJvcHRpb25zIiwidXNibXV4ZFJlbW90ZUhvc3QiLCJ1c2JtdXhkUmVtb3RlUG9ydCIsInNlcnZpY2UiLCJzZXJ2aWNlcyIsInN0YXJ0SW5zdGFsbGF0aW9uUHJveHlTZXJ2aWNlIiwidW5pbnN0YWxsQXBwbGljYXRpb24iLCJjbG9zZSIsInJlbW92ZUFwcCIsImluc3RhbGxUb0RldmljZUZhcm0iLCJ0eXBlIiwidXJsIiwiYXBwVXJsIiwiZGZJT1NJbnN0YWxsQXBpIiwiaW5zdGFsbCIsImFwcCIsInRpbWVyIiwidGltaW5nIiwiVGltZXIiLCJzdGFydCIsImJ1bmRsZVBhdGhPblBob25lIiwicHVzaEFwcEJ1bmRsZSIsImluc3RhbGxBcHBsaWNhdGlvbiIsIndhcm4iLCJmcyIsIndoaWNoIiwiZXJyMSIsIkVycm9yIiwic3RkZXJyIiwic3Rkb3V0IiwiZ2V0RHVyYXRpb24iLCJhc01pbGxpU2Vjb25kcyIsInRvRml4ZWQiLCJub3RpZmljYXRpb25TZXJ2aWNlIiwic3RhcnROb3RpZmljYXRpb25Qcm94eVNlcnZpY2UiLCJpbnN0YWxsYXRpb25TZXJ2aWNlIiwiYXBwSW5zdGFsbGVkTm90aWZpY2F0aW9uIiwiQiIsInJlc29sdmUiLCJvYnNlcnZlTm90aWZpY2F0aW9uIiwibm90aWZpY2F0aW9uIiwiUGFja2FnZVR5cGUiLCJlIiwiYWZjU2VydmljZSIsInN0YXJ0QWZjU2VydmljZSIsImNyZWF0ZUFwcFBhdGgiLCJ3YWxrRGlyIiwiaXRlbVBhdGgiLCJpc0RpciIsInBhdGhPblBob25lIiwicGF0aCIsImpvaW4iLCJyZWxhdGl2ZSIsImNyZWF0ZURpcmVjdG9yeSIsInJlYWRTdHJlYW0iLCJjcmVhdGVSZWFkU3RyZWFtIiwiYXV0b0Nsb3NlIiwid3JpdGVTdHJlYW0iLCJjcmVhdGVXcml0ZVN0cmVhbSIsImF1dG9EZXN0cm95Iiwib24iLCJkZXN0cm95IiwicHVzaEVycm9yIiwiaXRlbVB1c2hXYWl0IiwicmVqZWN0Iiwib25TdHJlYW1FcnJvciIsInVucGlwZSIsImRlYnVnIiwicGlwZSIsImxvY2FsQXBwUGF0aCIsImJhc2VuYW1lIiwicmVsYXRpdmVQYXRoIiwiZGVsZXRlRGlyZWN0b3J5IiwiaWduIiwiaW5zdGFsbEFwcCIsImlzQXBwSW5zdGFsbGVkIiwiZGZBcHBJbnN0YWxsZWRBcGkiLCJpc0luc3RhbGxlZCIsImFwcGxpY2F0aW9ucyIsImxvb2t1cEFwcGxpY2F0aW9ucyIsImJ1bmRsZUlkcyIsImdldFVzZXJJbnN0YWxsZWRCdW5kbGVJZHNCeUJ1bmRsZU5hbWUiLCJidW5kbGVOYW1lIiwibGlzdEFwcGxpY2F0aW9ucyIsImFwcGxpY2F0aW9uVHlwZSIsIl8iLCJyZWR1Y2UiLCJhY2MiLCJDRkJ1bmRsZU5hbWUiLCJrZXkiLCJwdXNoIiwiZ2V0UGxhdGZvcm1WZXJzaW9uIiwidXRpbGl0aWVzIiwiZ2V0T1NWZXJzaW9uIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNB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IjpbIi8qIGVzbGludC1kaXNhYmxlIHByb21pc2UvcHJlZmVyLWF3YWl0LXRvLWNhbGxiYWNrcyAqL1xuaW1wb3J0IHsgZnMsIHRpbWluZyB9IGZyb20gJ2FwcGl1bS1zdXBwb3J0JztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgc2VydmljZXMsIHV0aWxpdGllcyB9IGZyb20gJ2dzdC1hdG9tLWlvcy1kZXZpY2UnO1xuaW1wb3J0IEIgZnJvbSAnYmx1ZWJpcmQnO1xuaW1wb3J0IGxvZyBmcm9tICcuL2xvZ2dlcic7XG5pbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHsgZXhlYyB9IGZyb20gJ3RlZW5fcHJvY2Vzcyc7XG5pbXBvcnQgZmV0Y2ggZnJvbSAnbm9kZS1mZXRjaCc7XG5cbmNvbnN0IEFQUExJQ0FUSU9OX0lOU1RBTExFRF9OT1RJRklDQVRJT04gPSAnY29tLmFwcGxlLm1vYmlsZS5hcHBsaWNhdGlvbl9pbnN0YWxsZWQnO1xuY29uc3QgSU5TVEFMTEFUSU9OX1NUQUdJTkdfRElSID0gJ1B1YmxpY1N0YWdpbmcnO1xuY29uc3QgREVGQVVMVF9JVEVNX1BVU0hfVElNRU9VVCA9IDMwICogMTAwMDtcbmNvbnN0IEFQUExJQ0FUSU9OX05PVElGSUNBVElPTl9USU1FT1VUID0gMzAgKiAxMDAwO1xuY29uc3QgSU9TX0RFUExPWSA9ICdpb3MtZGVwbG95JztcblxuY2xhc3MgSU9TRGVwbG95IHtcblxuICBjb25zdHJ1Y3RvciAob3B0cykge1xuICAgIHRoaXMudWRpZCA9IG9wdHMudWRpZDtcbiAgICB0aGlzLm9wdHMgPSBvcHRzO1xuICB9XG5cbiAgYXN5bmMgcmVtb3ZlIChidW5kbGVJZCkge1xuICAgIC8vIElmIHdlIGFyZSB1c2luZyByZW1vdGUgZGV2aWNlIGluIGRldmljZSBmYXJtXG4gICAgLy8gQ2FsbCBBUEkgdG8gcmVtb3ZlIGFwcGxpY2F0aW9uXG4gICAgaWYodGhpcy5vcHRzLndlYkRyaXZlckFnZW50VXJsKXtcbiAgICAgIGNvbnN0IGJvZHkgPSB7XG4gICAgICAgIHNlcmlhbDogdGhpcy5vcHRzLnVkaWQsXG4gICAgICAgIGJ1bmRsZUlkOiBidW5kbGVJZFxuICAgICAgfTtcblxuICAgICAgbG9nLmluZm8oYFske3RoaXMub3B0cy51ZGlkfV0gQ2FsbGluZyBEZXZpY2UgRmFybSB0byB1bmluc3RhbGwgJHtidW5kbGVJZH1gKTtcblxuICAgICAgbGV0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godGhpcy5vcHRzLmRmSU9TVW5pbnN0YWxsQXBpLCB7XG4gICAgICAgIG1ldGhvZDogJ3Bvc3QnLFxuICAgICAgICBib2R5OiAgICBKU09OLnN0cmluZ2lmeShib2R5KSxcbiAgICAgICAgaGVhZGVyczogeyAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgdGhpcy5vcHRzLmRmVG9rZW5cbiAgICAgICAgfSxcbiAgICAgICAgdGltZW91dDogMzYwMDAwMFxuICAgICAgfSkuY2F0Y2goZXJyID0+IHtcbiAgICAgICAgbG9nLmVycm9yKGBbJHt0aGlzLm9wdHMudWRpZH1dICR7ZXJyLm1lc3NhZ2V9YCk7XG4gICAgICAgIGxvZy5lcnJvckFuZFRocm93KGVycik7XG4gICAgICB9KTtcblxuICAgICAgbGV0IGRhdGEgPSBhd2FpdCByZXNwb25zZS5qc29uKCk7XG5cbiAgICAgIGlmKCFkYXRhLnN1Y2Nlc3MpIHtcbiAgICAgICAgbG9nLmVycm9yQW5kVGhyb3coYFske3RoaXMub3B0cy51ZGlkfV0gJHtkYXRhLmRlc2NyaXB0aW9ufWApO1xuICAgICAgfVxuXG4gICAgICBsb2cuaW5mbyhgWyR7dGhpcy5vcHRzLnVkaWR9XVske2J1bmRsZUlkfV0gVW5pbnN0YWxsYXRpb24gc3VjY2Vzc2Z1bGx5YCk7XG5cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgb3B0aW9ucyA9IHtcbiAgICAgIHVkaWQ6IHRoaXMudWRpZCxcbiAgICAgIHVzYm11eGRSZW1vdGVIb3N0OiB0aGlzLm9wdHMudXNibXV4ZFJlbW90ZUhvc3QsXG4gICAgICB1c2JtdXhkUmVtb3RlUG9ydDogdGhpcy5vcHRzLnVzYm11eGRSZW1vdGVQb3J0XG4gICAgfTtcbiAgICBjb25zdCBzZXJ2aWNlID0gYXdhaXQgc2VydmljZXMuc3RhcnRJbnN0YWxsYXRpb25Qcm94eVNlcnZpY2Uob3B0aW9ucyk7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHNlcnZpY2UudW5pbnN0YWxsQXBwbGljYXRpb24oYnVuZGxlSWQpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBzZXJ2aWNlLmNsb3NlKCk7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgcmVtb3ZlQXBwIChidW5kbGVJZCkge1xuICAgIGF3YWl0IHRoaXMucmVtb3ZlKGJ1bmRsZUlkKTtcbiAgfVxuXG4gIC8vIE5odU5IIC0gaW5zdGFsbCBhcHBsaWNhdGlvbiB0aHJvdWdoIERGXG4gIGFzeW5jIGluc3RhbGxUb0RldmljZUZhcm0oKXtcbiAgICBjb25zdCBib2R5ID0geyB0eXBlOiAnaU9TJywgXG4gICAgICBzZXJpYWw6IHRoaXMub3B0cy51ZGlkLFxuICAgICAgdXJsOiB0aGlzLm9wdHMuYXBwVXJsXG4gICAgfTtcblxuICAgIGxvZy5pbmZvKGBbJHt0aGlzLm9wdHMudWRpZH1dIENhbGxpbmcgRGV2aWNlIEZhcm0gdG8gaW5zdGFsbCBpT1MgYXBwbGljYXRpb24gYXQgJHt0aGlzLm9wdHMuYXBwVXJsfWApO1xuXG4gICAgbGV0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godGhpcy5vcHRzLmRmSU9TSW5zdGFsbEFwaSwge1xuICAgICAgbWV0aG9kOiAncG9zdCcsXG4gICAgICBib2R5OiAgICBKU09OLnN0cmluZ2lmeShib2R5KSxcbiAgICAgIGhlYWRlcnM6IHsgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyB0aGlzLm9wdHMuZGZUb2tlblxuICAgICAgfSxcbiAgICAgIHRpbWVvdXQ6IDM2MDAwMDBcbiAgICB9KS5jYXRjaChlcnIgPT4ge1xuICAgICAgbG9nLmVycm9yKGBbJHt0aGlzLm9wdHMudWRpZH1dICR7ZXJyLm1lc3NhZ2V9YCk7XG4gICAgICBsb2cuZXJyb3JBbmRUaHJvdyhlcnIpO1xuICAgIH0pO1xuXG4gICAgbGV0IGRhdGEgPSBhd2FpdCByZXNwb25zZS5qc29uKCk7XG5cbiAgICBpZighZGF0YS5zdWNjZXNzKSB7XG4gICAgICBsb2cuZXJyb3JBbmRUaHJvdyhgWyR7dGhpcy5vcHRzLnVkaWR9XSAke2RhdGEuZGVzY3JpcHRpb259YCk7XG4gICAgfVxuXG4gICAgbG9nLmluZm8oYFske3RoaXMub3B0cy51ZGlkfV0gSW5zdGFsbGF0aW9uIHN1Y2Nlc3NmdWxseSAoJHt0aGlzLm9wdHMuYXBwVXJsfSkgYCk7XG4gIH1cblxuICBhc3luYyBpbnN0YWxsIChhcHAsIHRpbWVvdXQpIHtcbiAgICBpZiAodGhpcy5vcHRzLndlYkRyaXZlckFnZW50VXJsKXtcbiAgICAgIGF3YWl0IHRoaXMuaW5zdGFsbFRvRGV2aWNlRmFybSgpXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgdGltZXIgPSBuZXcgdGltaW5nLlRpbWVyKCkuc3RhcnQoKTtcbiAgICB0cnkge1xuICAgICAgY29uc3QgYnVuZGxlUGF0aE9uUGhvbmUgPSBhd2FpdCB0aGlzLnB1c2hBcHBCdW5kbGUoYXBwLCB0aW1lb3V0KTtcbiAgICAgIGF3YWl0IHRoaXMuaW5zdGFsbEFwcGxpY2F0aW9uKGJ1bmRsZVBhdGhPblBob25lKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGxvZy53YXJuKGBFcnJvciBpbnN0YWxsaW5nIGFwcDogJHtlcnIubWVzc2FnZX1gKTtcbiAgICAgIGxvZy53YXJuKGBGYWxsaW5nIGJhY2sgdG8gJyR7SU9TX0RFUExPWX0nIHVzYWdlYCk7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBmcy53aGljaChJT1NfREVQTE9ZKTtcbiAgICAgIH0gY2F0Y2ggKGVycjEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDb3VsZCBub3QgaW5zdGFsbCAnJHthcHB9JzpcXG5gICtcbiAgICAgICAgICBgICAtICR7ZXJyLm1lc3NhZ2V9XFxuYCArXG4gICAgICAgICAgYCAgLSAnJHtJT1NfREVQTE9ZfScgdXRpbGl0eSBoYXMgbm90IGJlZW4gZm91bmQgaW4gUEFUSC4gSXMgaXQgaW5zdGFsbGVkP2ApO1xuICAgICAgfVxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgZXhlYyhJT1NfREVQTE9ZLCBbXG4gICAgICAgICAgJy0taWQnLCB0aGlzLnVkaWQsXG4gICAgICAgICAgJy0tYnVuZGxlJywgYXBwLFxuICAgICAgICBdKTtcbiAgICAgIH0gY2F0Y2ggKGVycjEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDb3VsZCBub3QgaW5zdGFsbCAnJHthcHB9JzpcXG5gICtcbiAgICAgICAgICBgICAtICR7ZXJyLm1lc3NhZ2V9XFxuYCArXG4gICAgICAgICAgYCAgLSAke2VycjEuc3RkZXJyIHx8IGVycjEuc3Rkb3V0IHx8IGVycjEubWVzc2FnZX1gKTtcbiAgICAgIH1cbiAgICB9XG4gICAgbG9nLmluZm8oYEFwcCBpbnN0YWxsYXRpb24gc3VjY2VlZGVkIGFmdGVyICR7dGltZXIuZ2V0RHVyYXRpb24oKS5hc01pbGxpU2Vjb25kcy50b0ZpeGVkKDApfW1zYCk7XG4gIH1cblxuICBhc3luYyBpbnN0YWxsQXBwbGljYXRpb24gKGJ1bmRsZVBhdGhPblBob25lKSB7XG4gICAgdmFyIG9wdGlvbnMgPSB7XG4gICAgICB1ZGlkOiB0aGlzLnVkaWQsXG4gICAgICB1c2JtdXhkUmVtb3RlSG9zdDogdGhpcy5vcHRzLnVzYm11eGRSZW1vdGVIb3N0LFxuICAgICAgdXNibXV4ZFJlbW90ZVBvcnQ6IHRoaXMub3B0cy51c2JtdXhkUmVtb3RlUG9ydFxuICAgIH07XG4gICAgY29uc3Qgbm90aWZpY2F0aW9uU2VydmljZSA9IGF3YWl0IHNlcnZpY2VzLnN0YXJ0Tm90aWZpY2F0aW9uUHJveHlTZXJ2aWNlKG9wdGlvbnMpO1xuICAgIGNvbnN0IGluc3RhbGxhdGlvblNlcnZpY2UgPSBhd2FpdCBzZXJ2aWNlcy5zdGFydEluc3RhbGxhdGlvblByb3h5U2VydmljZShvcHRpb25zKTtcbiAgICBjb25zdCBhcHBJbnN0YWxsZWROb3RpZmljYXRpb24gPSBuZXcgQigocmVzb2x2ZSkgPT4ge1xuICAgICAgbm90aWZpY2F0aW9uU2VydmljZS5vYnNlcnZlTm90aWZpY2F0aW9uKEFQUExJQ0FUSU9OX0lOU1RBTExFRF9OT1RJRklDQVRJT04sIHtub3RpZmljYXRpb246IHJlc29sdmV9KTtcbiAgICB9KTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgaW5zdGFsbGF0aW9uU2VydmljZS5pbnN0YWxsQXBwbGljYXRpb24oYnVuZGxlUGF0aE9uUGhvbmUsIHtQYWNrYWdlVHlwZTogJ0RldmVsb3Blcid9KTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGFwcEluc3RhbGxlZE5vdGlmaWNhdGlvbi50aW1lb3V0KEFQUExJQ0FUSU9OX05PVElGSUNBVElPTl9USU1FT1VULCBgQ291bGQgbm90IGdldCB0aGUgYXBwbGljYXRpb24gaW5zdGFsbGVkIG5vdGlmaWNhdGlvbiB3aXRoaW4gJHtBUFBMSUNBVElPTl9OT1RJRklDQVRJT05fVElNRU9VVH1tcyBidXQgd2Ugd2lsbCBjb250aW51ZWApO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBsb2cud2FybihgRmFpbGVkIHRvIHJlY2VpdmUgdGhlIG5vdGlmaWNhdGlvbi4gRXJyb3I6ICR7ZS5tZXNzYWdlfWApO1xuICAgICAgfVxuICAgIH0gZmluYWxseSB7XG4gICAgICBpbnN0YWxsYXRpb25TZXJ2aWNlLmNsb3NlKCk7XG4gICAgICBub3RpZmljYXRpb25TZXJ2aWNlLmNsb3NlKCk7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgcHVzaEFwcEJ1bmRsZSAoYXBwLCB0aW1lb3V0ID0gREVGQVVMVF9JVEVNX1BVU0hfVElNRU9VVCkge1xuICAgIGNvbnN0IHRpbWVyID0gbmV3IHRpbWluZy5UaW1lcigpLnN0YXJ0KCk7XG4gICAgdmFyIG9wdGlvbnMgPSB7XG4gICAgICB1ZGlkOiB0aGlzLnVkaWQsXG4gICAgICB1c2JtdXhkUmVtb3RlSG9zdDogdGhpcy5vcHRzLnVzYm11eGRSZW1vdGVIb3N0LFxuICAgICAgdXNibXV4ZFJlbW90ZVBvcnQ6IHRoaXMub3B0cy51c2JtdXhkUmVtb3RlUG9ydFxuICAgIH07XG4gICAgY29uc3QgYWZjU2VydmljZSA9IGF3YWl0IHNlcnZpY2VzLnN0YXJ0QWZjU2VydmljZShvcHRpb25zKTtcbiAgICAvLyBXZSBhcmUgcHVzaGluZyBzZXJpYWxseSBkdWUgdG8gdGhpcyBodHRwczovL2dpdGh1Yi5jb20vYXBwaXVtL2FwcGl1bS9pc3N1ZXMvMTMxMTUuIFRoZXJlIGlzIG5vdGhpbmcgZWxzZSB3ZSBjYW4gZG8gYmVzaWRlcyB0aGlzXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGJ1bmRsZVBhdGhPblBob25lID0gYXdhaXQgdGhpcy5jcmVhdGVBcHBQYXRoKGFmY1NlcnZpY2UsIGFwcCk7XG4gICAgICBhd2FpdCBmcy53YWxrRGlyKGFwcCwgdHJ1ZSwgYXN5bmMgKGl0ZW1QYXRoLCBpc0RpcikgPT4ge1xuICAgICAgICBjb25zdCBwYXRoT25QaG9uZSA9IHBhdGguam9pbihidW5kbGVQYXRoT25QaG9uZSwgcGF0aC5yZWxhdGl2ZShhcHAsIGl0ZW1QYXRoKSk7XG4gICAgICAgIGlmIChpc0Rpcikge1xuICAgICAgICAgIGF3YWl0IGFmY1NlcnZpY2UuY3JlYXRlRGlyZWN0b3J5KHBhdGhPblBob25lKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCByZWFkU3RyZWFtID0gZnMuY3JlYXRlUmVhZFN0cmVhbShpdGVtUGF0aCwge2F1dG9DbG9zZTogdHJ1ZX0pO1xuICAgICAgICAgIGNvbnN0IHdyaXRlU3RyZWFtID0gYXdhaXQgYWZjU2VydmljZS5jcmVhdGVXcml0ZVN0cmVhbShwYXRoT25QaG9uZSwge2F1dG9EZXN0cm95OiB0cnVlfSk7XG4gICAgICAgICAgd3JpdGVTdHJlYW0ub24oJ2ZpbmlzaCcsIHdyaXRlU3RyZWFtLmRlc3Ryb3kpO1xuICAgICAgICAgIGxldCBwdXNoRXJyb3IgPSBudWxsO1xuICAgICAgICAgIGNvbnN0IGl0ZW1QdXNoV2FpdCA9IG5ldyBCKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIHdyaXRlU3RyZWFtLm9uKCdjbG9zZScsICgpID0+IHtcbiAgICAgICAgICAgICAgaWYgKHB1c2hFcnJvcikge1xuICAgICAgICAgICAgICAgIHJlamVjdChwdXNoRXJyb3IpO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBjb25zdCBvblN0cmVhbUVycm9yID0gKGUpID0+IHtcbiAgICAgICAgICAgICAgcmVhZFN0cmVhbS51bnBpcGUod3JpdGVTdHJlYW0pO1xuICAgICAgICAgICAgICBsb2cuZGVidWcoZSk7XG4gICAgICAgICAgICAgIHB1c2hFcnJvciA9IGU7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgd3JpdGVTdHJlYW0ub24oJ2Vycm9yJywgb25TdHJlYW1FcnJvcik7XG4gICAgICAgICAgICByZWFkU3RyZWFtLm9uKCdlcnJvcicsIG9uU3RyZWFtRXJyb3IpO1xuICAgICAgICAgIH0pO1xuICAgICAgICAgIHJlYWRTdHJlYW0ucGlwZSh3cml0ZVN0cmVhbSk7XG4gICAgICAgICAgYXdhaXQgaXRlbVB1c2hXYWl0LnRpbWVvdXQodGltZW91dCxcbiAgICAgICAgICAgIGBDb3VsZCBub3QgcHVzaCAnJHtpdGVtUGF0aH0nIHdpdGhpbiB0aGUgdGltZW91dCBvZiAke3RpbWVvdXR9bXMuIGAgK1xuICAgICAgICAgICAgYENvbnNpZGVyIGluY3JlYXNpbmcgdGhlIHZhbHVlIG9mICdhcHBQdXNoVGltZW91dCcgY2FwYWJpbGl0eS5gKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICBsb2cuZGVidWcoYFB1c2hlZCB0aGUgYXBwIGZpbGVzIHN1Y2Nlc3NmdWxseSBhZnRlciAke3RpbWVyLmdldER1cmF0aW9uKCkuYXNNaWxsaVNlY29uZHMudG9GaXhlZCgwKX1tc2ApO1xuICAgICAgcmV0dXJuIGJ1bmRsZVBhdGhPblBob25lO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBhZmNTZXJ2aWNlLmNsb3NlKCk7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgY3JlYXRlQXBwUGF0aCAoYWZjU2VydmljZSwgbG9jYWxBcHBQYXRoKSB7XG4gICAgY29uc3QgYmFzZW5hbWUgPSBwYXRoLmJhc2VuYW1lKGxvY2FsQXBwUGF0aCk7XG4gICAgY29uc3QgcmVsYXRpdmVQYXRoID0gcGF0aC5qb2luKElOU1RBTExBVElPTl9TVEFHSU5HX0RJUiwgYmFzZW5hbWUpO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBhZmNTZXJ2aWNlLmRlbGV0ZURpcmVjdG9yeShyZWxhdGl2ZVBhdGgpO1xuICAgIH0gY2F0Y2ggKGlnbikge31cbiAgICBhd2FpdCBhZmNTZXJ2aWNlLmNyZWF0ZURpcmVjdG9yeShyZWxhdGl2ZVBhdGgpO1xuICAgIHJldHVybiByZWxhdGl2ZVBhdGg7XG4gIH1cblxuICBhc3luYyBpbnN0YWxsQXBwIChhcHAsIHRpbWVvdXQpIHtcbiAgICBhd2FpdCB0aGlzLmluc3RhbGwoYXBwLCB0aW1lb3V0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYW4gYXBwbGljYXRpb24gb2JqZWN0IGlmIHRlc3QgYXBwIGhhcyAnYnVuZGxlaWQnLlxuICAgKiBUaGUgdGFyZ2V0IGJ1bmRsZWlkIGNhbiBiZSBVc2VyIGFuZCBTeXN0ZW0gYXBwcy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGJ1bmRsZUlkIFRoZSBidW5kbGVJZCB0byBlbnN1cmUgaXQgaXMgaW5zdGFsbGVkXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IFJldHVybnMgVHJ1ZSBpZiB0aGUgYnVuZGxlaWQgZXhpc3RzIGluIHRoZSByZXN1bHQgb2YgJ2xpc3RBcHBsaWNhdGlvbnMnIGxpa2U6XG4gICAqIHsgXCJjb20uYXBwbGUuUHJlZmVyZW5jZXNcIjp7XG4gICAqICAgXCJVSVJlcXVpcmVkRGV2aWNlQ2FwYWJpbGl0aWVzXCI6W1wiYXJtNjRcIl0sXG4gICAqICAgXCJVSVJlcXVpcmVzRnVsbFNjcmVlblwiOnRydWUsXG4gICAqICAgXCJDRkJ1bmRsZUluZm9EaWN0aW9uYXJ5VmVyc2lvblwiOlwiNi4wXCIsXG4gICAqICAgXCJFbnRpdGxlbWVudHNcIjpcbiAgICogICAgIHtcImNvbS5hcHBsZS5mcm9udGJvYXJkLmRlbGV0ZS1hcHBsaWNhdGlvbi1zbmFwc2hvdHNcIjp0cnVlLC4uXG4gICAqL1xuICBhc3luYyBpc0FwcEluc3RhbGxlZCAoYnVuZGxlSWQpIHtcbiAgICAvLyBJZiB1c2luZyByZW1vdGUgZGV2aWNlIG9uIGRldmljZSBmYXJtLFxuICAgIC8vIGNhbGwgZGV2aWNlIGZhcm0gYXBpIHRvIGNoZWNrIGFuIGFwcGxpY2F0aW9uIGlzIGluc3RhbGxlZFxuICAgIGlmKHRoaXMub3B0cy53ZWJEcml2ZXJBZ2VudFVybCkge1xuICAgICAgY29uc3QgYm9keSA9IHtcbiAgICAgICAgc2VyaWFsOiB0aGlzLm9wdHMudWRpZCxcbiAgICAgICAgYnVuZGxlSWQ6IGJ1bmRsZUlkXG4gICAgICB9O1xuXG4gICAgICBsb2cuaW5mbyhgWyR7dGhpcy5vcHRzLnVkaWR9XSBDYWxsaW5nIERldmljZSBGYXJtIHRvIGNoZWNrIHRoZSBhcHBsaWNhdGlvbiB3aXRoIGJ1bmRsZSBpZCAke3RoaXMub3B0cy5hcHBVcmx9IGlzIGluc3RhbGxlZGApO1xuXG4gICAgICBsZXQgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCh0aGlzLm9wdHMuZGZBcHBJbnN0YWxsZWRBcGksIHtcbiAgICAgICAgbWV0aG9kOiAncG9zdCcsXG4gICAgICAgIGJvZHk6ICAgIEpTT04uc3RyaW5naWZ5KGJvZHkpLFxuICAgICAgICBoZWFkZXJzOiB7ICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyB0aGlzLm9wdHMuZGZUb2tlblxuICAgICAgICB9LFxuICAgICAgICB0aW1lb3V0OiA2MDAwMFxuICAgICAgfSkuY2F0Y2goZXJyID0+IHtcbiAgICAgICAgbG9nLmVycm9yKGBbJHt0aGlzLm9wdHMudWRpZH1dICR7ZXJyLm1lc3NhZ2V9YCk7XG4gICAgICAgIGxvZy5lcnJvckFuZFRocm93KGVycik7XG4gICAgICB9KTtcblxuICAgICAgbGV0IGRhdGEgPSBhd2FpdCByZXNwb25zZS5qc29uKCk7XG5cbiAgICAgIGxvZy5pbmZvKGBbJHt0aGlzLm9wdHMudWRpZH1dIEFwcGxpY2F0aW9uICR7YnVuZGxlSWR9IGlzIGluc3RhbGxlZDogJHtkYXRhLmlzSW5zdGFsbGVkfWApO1xuICAgICAgcmV0dXJuIGRhdGEuaXNJbnN0YWxsZWQ7XG4gICAgfVxuXG4gICAgdmFyIG9wdGlvbnMgPSB7XG4gICAgICB1ZGlkOiB0aGlzLnVkaWQsXG4gICAgICB1c2JtdXhkUmVtb3RlSG9zdDogdGhpcy5vcHRzLnVzYm11eGRSZW1vdGVIb3N0LFxuICAgICAgdXNibXV4ZFJlbW90ZVBvcnQ6IHRoaXMub3B0cy51c2JtdXhkUmVtb3RlUG9ydFxuICAgIH07XG4gICAgY29uc3Qgc2VydmljZSA9IGF3YWl0IHNlcnZpY2VzLnN0YXJ0SW5zdGFsbGF0aW9uUHJveHlTZXJ2aWNlKG9wdGlvbnMpO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBhcHBsaWNhdGlvbnMgPSBhd2FpdCBzZXJ2aWNlLmxvb2t1cEFwcGxpY2F0aW9ucyh7IGJ1bmRsZUlkczogYnVuZGxlSWQgfSk7XG4gICAgICByZXR1cm4gISFhcHBsaWNhdGlvbnNbYnVuZGxlSWRdO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBzZXJ2aWNlLmNsb3NlKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBidW5kbGVOYW1lIFRoZSBuYW1lIG9mIENGQnVuZGxlTmFtZSBpbiBJbmZvLnBsaXN0XG4gICAqXG4gICAqIEByZXR1cm5zIHtBcnJheTxzdHJpbmc+fSBBIGxpc3Qgb2YgVXNlciBsZXZlbCBhcHBzJyBidW5kbGUgaWRzIHdoaWNoIGhhc1xuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgJ0NGQnVuZGxlTmFtZScgYXR0cmlidXRlIGFzICdidW5kbGVOYW1lJy5cbiAgICovXG4gIGFzeW5jIGdldFVzZXJJbnN0YWxsZWRCdW5kbGVJZHNCeUJ1bmRsZU5hbWUgKGJ1bmRsZU5hbWUpIHtcbiAgICB2YXIgb3B0aW9ucyA9IHtcbiAgICAgIHVkaWQ6IHRoaXMudWRpZCxcbiAgICAgIHVzYm11eGRSZW1vdGVIb3N0OiB0aGlzLm9wdHMudXNibXV4ZFJlbW90ZUhvc3QsXG4gICAgICB1c2JtdXhkUmVtb3RlUG9ydDogdGhpcy5vcHRzLnVzYm11eGRSZW1vdGVQb3J0XG4gICAgfTtcbiAgICBjb25zdCBzZXJ2aWNlID0gYXdhaXQgc2VydmljZXMuc3RhcnRJbnN0YWxsYXRpb25Qcm94eVNlcnZpY2Uob3B0aW9ucyk7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGFwcGxpY2F0aW9ucyA9IGF3YWl0IHNlcnZpY2UubGlzdEFwcGxpY2F0aW9ucyh7YXBwbGljYXRpb25UeXBlOiAnVXNlcid9KTtcbiAgICAgIHJldHVybiBfLnJlZHVjZShhcHBsaWNhdGlvbnMsIChhY2MsIHtDRkJ1bmRsZU5hbWV9LCBrZXkpID0+IHtcbiAgICAgICAgaWYgKENGQnVuZGxlTmFtZSA9PT0gYnVuZGxlTmFtZSkge1xuICAgICAgICAgIGFjYy5wdXNoKGtleSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgIH0sIFtdKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgc2VydmljZS5jbG9zZSgpO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGdldFBsYXRmb3JtVmVyc2lvbiAoKSB7XG4gICAgdmFyIG9wdGlvbnMgPSB7XG4gICAgICB1ZGlkOiB0aGlzLnVkaWQsXG4gICAgICB1c2JtdXhkUmVtb3RlSG9zdDogdGhpcy5vcHRzLnVzYm11eGRSZW1vdGVIb3N0LFxuICAgICAgdXNibXV4ZFJlbW90ZVBvcnQ6IHRoaXMub3B0cy51c2JtdXhkUmVtb3RlUG9ydFxuICAgIH07XG4gICAgcmV0dXJuIGF3YWl0IHV0aWxpdGllcy5nZXRPU1ZlcnNpb24obnVsbCwgb3B0aW9ucyk7XG4gIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgSU9TRGVwbG95O1xuIl0sImZpbGUiOiJsaWIvaW9zLWRlcGxveS5qcyIsInNvdXJjZVJvb3QiOiIuLi8uLiJ9