gst-atom-xcuitest-driver
Version:
ATOM driver for iOS using XCUITest for backend
348 lines (277 loc) • 40 kB
JavaScript
;
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