appium-webdriveragent 5.6.2 → 5.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,404 +1,515 @@
1
1
  "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
- Object.defineProperty(exports, "__esModule", {
5
- value: true
6
- });
7
- exports.default = exports.WebDriverAgent = void 0;
8
- require("source-map-support/register");
9
- var _lodash = _interopRequireDefault(require("lodash"));
10
- var _path = _interopRequireDefault(require("path"));
11
- var _url2 = _interopRequireDefault(require("url"));
12
- var _bluebird = _interopRequireDefault(require("bluebird"));
13
- var _baseDriver = require("@appium/base-driver");
14
- var _support = require("@appium/support");
15
- var _logger = _interopRequireDefault(require("./logger"));
16
- var _noSessionProxy = require("./no-session-proxy");
17
- var _utils = require("./utils");
18
- var _xcodebuild = _interopRequireDefault(require("./xcodebuild"));
19
- var _asyncLock = _interopRequireDefault(require("async-lock"));
20
- var _teen_process = require("teen_process");
21
- var _checkDependencies = require("./check-dependencies");
22
- var _constants = require("./constants");
23
- var _appiumIosDevice = require("appium-ios-device");
24
- var _strongbox = require("@appium/strongbox");
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.WebDriverAgent = void 0;
7
+ const lodash_1 = __importDefault(require("lodash"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const url_1 = __importDefault(require("url"));
10
+ const bluebird_1 = __importDefault(require("bluebird"));
11
+ const base_driver_1 = require("@appium/base-driver");
12
+ const support_1 = require("@appium/support");
13
+ const logger_1 = __importDefault(require("./logger"));
14
+ const no_session_proxy_1 = require("./no-session-proxy");
15
+ const utils_1 = require("./utils");
16
+ const xcodebuild_1 = __importDefault(require("./xcodebuild"));
17
+ const async_lock_1 = __importDefault(require("async-lock"));
18
+ const teen_process_1 = require("teen_process");
19
+ const check_dependencies_1 = require("./check-dependencies");
20
+ const constants_1 = require("./constants");
21
+ const appium_ios_device_1 = require("appium-ios-device");
22
+ const strongbox_1 = require("@appium/strongbox");
25
23
  const WDA_LAUNCH_TIMEOUT = 60 * 1000;
26
24
  const WDA_AGENT_PORT = 8100;
27
25
  const WDA_CF_BUNDLE_NAME = 'WebDriverAgentRunner-Runner';
28
- const SHARED_RESOURCES_GUARD = new _asyncLock.default();
26
+ const SHARED_RESOURCES_GUARD = new async_lock_1.default();
29
27
  const RECENT_MODULE_VERSION_ITEM_NAME = 'recentWdaModuleVersion';
30
28
  class WebDriverAgent {
31
- constructor(xcodeVersion, args = {}, log = null) {
32
- this.xcodeVersion = xcodeVersion;
33
- this.args = _lodash.default.clone(args);
34
- this.log = log ?? _logger.default;
35
- this.device = args.device;
36
- this.platformVersion = args.platformVersion;
37
- this.platformName = args.platformName;
38
- this.iosSdkVersion = args.iosSdkVersion;
39
- this.host = args.host;
40
- this.isRealDevice = !!args.realDevice;
41
- this.idb = (args.device || {}).idb;
42
- this.wdaBundlePath = args.wdaBundlePath;
43
- this.setWDAPaths(args.bootstrapPath, args.agentPath);
44
- this.wdaLocalPort = args.wdaLocalPort;
45
- this.wdaRemotePort = args.wdaLocalPort || WDA_AGENT_PORT;
46
- this.wdaBaseUrl = args.wdaBaseUrl || _constants.WDA_BASE_URL;
47
- this.prebuildWDA = args.prebuildWDA;
48
- this.webDriverAgentUrl = args.webDriverAgentUrl;
49
- this.started = false;
50
- this.wdaConnectionTimeout = args.wdaConnectionTimeout;
51
- this.useXctestrunFile = args.useXctestrunFile;
52
- this.usePrebuiltWDA = args.usePrebuiltWDA;
53
- this.derivedDataPath = args.derivedDataPath;
54
- this.mjpegServerPort = args.mjpegServerPort;
55
- this.updatedWDABundleId = args.updatedWDABundleId;
56
- this.usePreinstalledWDA = args.usePreinstalledWDA;
57
- this.xctestApiClient = null;
58
- this.xcodebuild = this.canSkipXcodebuild ? null : new _xcodebuild.default(this.xcodeVersion, this.device, {
59
- platformVersion: this.platformVersion,
60
- platformName: this.platformName,
61
- iosSdkVersion: this.iosSdkVersion,
62
- agentPath: this.agentPath,
63
- bootstrapPath: this.bootstrapPath,
64
- realDevice: this.isRealDevice,
65
- showXcodeLog: args.showXcodeLog,
66
- xcodeConfigFile: args.xcodeConfigFile,
67
- xcodeOrgId: args.xcodeOrgId,
68
- xcodeSigningId: args.xcodeSigningId,
69
- keychainPath: args.keychainPath,
70
- keychainPassword: args.keychainPassword,
71
- useSimpleBuildTest: args.useSimpleBuildTest,
72
- usePrebuiltWDA: args.usePrebuiltWDA,
73
- updatedWDABundleId: this.updatedWDABundleId,
74
- launchTimeout: args.wdaLaunchTimeout || WDA_LAUNCH_TIMEOUT,
75
- wdaRemotePort: this.wdaRemotePort,
76
- useXctestrunFile: this.useXctestrunFile,
77
- derivedDataPath: args.derivedDataPath,
78
- mjpegServerPort: this.mjpegServerPort,
79
- allowProvisioningDeviceRegistration: args.allowProvisioningDeviceRegistration,
80
- resultBundlePath: args.resultBundlePath,
81
- resultBundleVersion: args.resultBundleVersion
82
- }, this.log);
83
- }
84
- get canSkipXcodebuild() {
85
- return this.usePreinstalledWDA || this.args.webDriverAgentUrl;
86
- }
87
- get bundleIdForXctest() {
88
- return this.updatedWDABundleId ? `${this.updatedWDABundleId}.xctrunner` : _constants.WDA_RUNNER_BUNDLE_ID_FOR_XCTEST;
89
- }
90
- setWDAPaths(bootstrapPath, agentPath) {
91
- this.bootstrapPath = bootstrapPath || _utils.BOOTSTRAP_PATH;
92
- this.log.info(`Using WDA path: '${this.bootstrapPath}'`);
93
- this.agentPath = agentPath || _path.default.resolve(this.bootstrapPath, 'WebDriverAgent.xcodeproj');
94
- this.log.info(`Using WDA agent: '${this.agentPath}'`);
95
- }
96
- async cleanupObsoleteProcesses() {
97
- const obsoletePids = await (0, _utils.getPIDsListeningOnPort)(this.url.port, cmdLine => cmdLine.includes('/WebDriverAgentRunner') && !cmdLine.toLowerCase().includes(this.device.udid.toLowerCase()));
98
- if (_lodash.default.isEmpty(obsoletePids)) {
99
- this.log.debug(`No obsolete cached processes from previous WDA sessions ` + `listening on port ${this.url.port} have been found`);
100
- return;
101
- }
102
- this.log.info(`Detected ${obsoletePids.length} obsolete cached process${obsoletePids.length === 1 ? '' : 'es'} ` + `from previous WDA sessions. Cleaning them up`);
103
- try {
104
- await (0, _teen_process.exec)('kill', obsoletePids);
105
- } catch (e) {
106
- this.log.warn(`Failed to kill obsolete cached process${obsoletePids.length === 1 ? '' : 'es'} '${obsoletePids}'. ` + `Original error: ${e.message}`);
107
- }
108
- }
109
- async isRunning() {
110
- return !!(await this.getStatus());
111
- }
112
- get basePath() {
113
- if (this.url.path === '/') {
114
- return '';
29
+ constructor(xcodeVersion, args = {}, log = null) {
30
+ this.xcodeVersion = xcodeVersion;
31
+ this.args = lodash_1.default.clone(args);
32
+ this.log = log ?? logger_1.default;
33
+ this.device = args.device;
34
+ this.platformVersion = args.platformVersion;
35
+ this.platformName = args.platformName;
36
+ this.iosSdkVersion = args.iosSdkVersion;
37
+ this.host = args.host;
38
+ this.isRealDevice = !!args.realDevice;
39
+ this.idb = (args.device || {}).idb;
40
+ this.wdaBundlePath = args.wdaBundlePath;
41
+ this.setWDAPaths(args.bootstrapPath, args.agentPath);
42
+ this.wdaLocalPort = args.wdaLocalPort;
43
+ this.wdaRemotePort = args.wdaLocalPort || WDA_AGENT_PORT;
44
+ this.wdaBaseUrl = args.wdaBaseUrl || constants_1.WDA_BASE_URL;
45
+ this.prebuildWDA = args.prebuildWDA;
46
+ // this.args.webDriverAgentUrl guiarantees the capabilities acually
47
+ // gave 'appium:webDriverAgentUrl' but 'this.webDriverAgentUrl'
48
+ // could be used for caching WDA with xcodebuild.
49
+ this.webDriverAgentUrl = args.webDriverAgentUrl;
50
+ this.started = false;
51
+ this.wdaConnectionTimeout = args.wdaConnectionTimeout;
52
+ this.useXctestrunFile = args.useXctestrunFile;
53
+ this.usePrebuiltWDA = args.usePrebuiltWDA;
54
+ this.derivedDataPath = args.derivedDataPath;
55
+ this.mjpegServerPort = args.mjpegServerPort;
56
+ this.updatedWDABundleId = args.updatedWDABundleId;
57
+ this.usePreinstalledWDA = args.usePreinstalledWDA;
58
+ this.xctestApiClient = null;
59
+ this.xcodebuild = this.canSkipXcodebuild
60
+ ? null
61
+ : new xcodebuild_1.default(this.xcodeVersion, this.device, {
62
+ platformVersion: this.platformVersion,
63
+ platformName: this.platformName,
64
+ iosSdkVersion: this.iosSdkVersion,
65
+ agentPath: this.agentPath,
66
+ bootstrapPath: this.bootstrapPath,
67
+ realDevice: this.isRealDevice,
68
+ showXcodeLog: args.showXcodeLog,
69
+ xcodeConfigFile: args.xcodeConfigFile,
70
+ xcodeOrgId: args.xcodeOrgId,
71
+ xcodeSigningId: args.xcodeSigningId,
72
+ keychainPath: args.keychainPath,
73
+ keychainPassword: args.keychainPassword,
74
+ useSimpleBuildTest: args.useSimpleBuildTest,
75
+ usePrebuiltWDA: args.usePrebuiltWDA,
76
+ updatedWDABundleId: this.updatedWDABundleId,
77
+ launchTimeout: args.wdaLaunchTimeout || WDA_LAUNCH_TIMEOUT,
78
+ wdaRemotePort: this.wdaRemotePort,
79
+ useXctestrunFile: this.useXctestrunFile,
80
+ derivedDataPath: args.derivedDataPath,
81
+ mjpegServerPort: this.mjpegServerPort,
82
+ allowProvisioningDeviceRegistration: args.allowProvisioningDeviceRegistration,
83
+ resultBundlePath: args.resultBundlePath,
84
+ resultBundleVersion: args.resultBundleVersion,
85
+ }, this.log);
115
86
  }
116
- return this.url.path || '';
117
- }
118
- async getStatus() {
119
- const noSessionProxy = new _noSessionProxy.NoSessionProxy({
120
- server: this.url.hostname,
121
- port: this.url.port,
122
- base: this.basePath,
123
- timeout: 3000
124
- });
125
- try {
126
- return await noSessionProxy.command('/status', 'GET');
127
- } catch (err) {
128
- this.log.debug(`WDA is not listening at '${this.url.href}'`);
129
- return null;
87
+ /**
88
+ * Return true if the session does not need xcodebuild.
89
+ * @returns {boolean} Whether the session needs/has xcodebuild.
90
+ */
91
+ get canSkipXcodebuild() {
92
+ // Use this.args.webDriverAgentUrl to guarantee
93
+ // the capabilities set gave the `appium:webDriverAgentUrl`.
94
+ return this.usePreinstalledWDA || this.args.webDriverAgentUrl;
130
95
  }
131
- }
132
- async uninstall() {
133
- try {
134
- const bundleIds = await this.device.getUserInstalledBundleIdsByBundleName(WDA_CF_BUNDLE_NAME);
135
- if (_lodash.default.isEmpty(bundleIds)) {
136
- this.log.debug('No WDAs on the device.');
137
- return;
138
- }
139
- this.log.debug(`Uninstalling WDAs: '${bundleIds}'`);
140
- for (const bundleId of bundleIds) {
141
- await this.device.removeApp(bundleId);
142
- }
143
- } catch (e) {
144
- this.log.debug(e);
145
- this.log.warn(`WebDriverAgent uninstall failed. Perhaps, it is already uninstalled? ` + `Original error: ${e.message}`);
96
+ /**
97
+ *
98
+ * @returns {string} Bundle ID for Xctest.
99
+ */
100
+ get bundleIdForXctest() {
101
+ return this.updatedWDABundleId ? `${this.updatedWDABundleId}.xctrunner` : constants_1.WDA_RUNNER_BUNDLE_ID_FOR_XCTEST;
146
102
  }
147
- }
148
- async _cleanupProjectIfFresh() {
149
- if (this.canSkipXcodebuild) {
150
- return;
103
+ setWDAPaths(bootstrapPath, agentPath) {
104
+ // allow the user to specify a place for WDA. This is undocumented and
105
+ // only here for the purposes of testing development of WDA
106
+ this.bootstrapPath = bootstrapPath || utils_1.BOOTSTRAP_PATH;
107
+ this.log.info(`Using WDA path: '${this.bootstrapPath}'`);
108
+ // for backward compatibility we need to be able to specify agentPath too
109
+ this.agentPath = agentPath || path_1.default.resolve(this.bootstrapPath, 'WebDriverAgent.xcodeproj');
110
+ this.log.info(`Using WDA agent: '${this.agentPath}'`);
151
111
  }
152
- const packageInfo = JSON.parse(await _support.fs.readFile(_path.default.join(_utils.BOOTSTRAP_PATH, 'package.json'), 'utf8'));
153
- const box = (0, _strongbox.strongbox)(packageInfo.name);
154
- let boxItem = box.getItem(RECENT_MODULE_VERSION_ITEM_NAME);
155
- if (!boxItem) {
156
- const timestampPath = _path.default.resolve(process.env.HOME, _constants.WDA_UPGRADE_TIMESTAMP_PATH);
157
- if (await _support.fs.exists(timestampPath)) {
158
- try {
159
- boxItem = await box.createItemWithValue(RECENT_MODULE_VERSION_ITEM_NAME, '5.0.0');
160
- } catch (e) {
161
- this.log.warn(`The actual module version cannot be persisted: ${e.message}`);
162
- return;
112
+ async cleanupObsoleteProcesses() {
113
+ const obsoletePids = await (0, utils_1.getPIDsListeningOnPort)(this.url.port, (cmdLine) => cmdLine.includes('/WebDriverAgentRunner') &&
114
+ !cmdLine.toLowerCase().includes(this.device.udid.toLowerCase()));
115
+ if (lodash_1.default.isEmpty(obsoletePids)) {
116
+ this.log.debug(`No obsolete cached processes from previous WDA sessions ` +
117
+ `listening on port ${this.url.port} have been found`);
118
+ return;
163
119
  }
164
- } else {
165
- this.log.info('There is no need to perform the project cleanup. A fresh install has been detected');
120
+ this.log.info(`Detected ${obsoletePids.length} obsolete cached process${obsoletePids.length === 1 ? '' : 'es'} ` +
121
+ `from previous WDA sessions. Cleaning them up`);
166
122
  try {
167
- await box.createItemWithValue(RECENT_MODULE_VERSION_ITEM_NAME, packageInfo.version);
168
- } catch (e) {
169
- this.log.warn(`The actual module version cannot be persisted: ${e.message}`);
123
+ await (0, teen_process_1.exec)('kill', obsoletePids);
124
+ }
125
+ catch (e) {
126
+ this.log.warn(`Failed to kill obsolete cached process${obsoletePids.length === 1 ? '' : 'es'} '${obsoletePids}'. ` +
127
+ `Original error: ${e.message}`);
170
128
  }
171
- return;
172
- }
173
- }
174
- let recentModuleVersion = await boxItem.read();
175
- try {
176
- recentModuleVersion = _support.util.coerceVersion(recentModuleVersion, true);
177
- } catch (e) {
178
- this.log.warn(`The persisted module version string has been damaged: ${e.message}`);
179
- this.log.info(`Updating it to '${packageInfo.version}' assuming the project clenup is not needed`);
180
- await boxItem.write(packageInfo.version);
181
- return;
182
- }
183
- if (_support.util.compareVersions(recentModuleVersion, '>=', packageInfo.version)) {
184
- this.log.info(`WebDriverAgent does not need a cleanup. The project sources are up to date ` + `(${recentModuleVersion} >= ${packageInfo.version})`);
185
- return;
186
- }
187
- this.log.info(`Cleaning up the WebDriverAgent project after the module upgrade has happened ` + `(${recentModuleVersion} < ${packageInfo.version})`);
188
- try {
189
- await this.xcodebuild.cleanProject();
190
- await boxItem.write(packageInfo.version);
191
- } catch (e) {
192
- this.log.warn(`Cannot perform WebDriverAgent project cleanup. Original error: ${e.message}`);
193
129
  }
194
- }
195
- async launchWithPreinstalledWDA(sessionId) {
196
- const xctestEnv = {
197
- USE_PORT: this.wdaLocalPort || WDA_AGENT_PORT,
198
- WDA_PRODUCT_BUNDLE_IDENTIFIER: this.bundleIdForXctest
199
- };
200
- if (this.mjpegServerPort) {
201
- xctestEnv.MJPEG_SERVER_PORT = this.mjpegServerPort;
130
+ /**
131
+ * Return boolean if WDA is running or not
132
+ * @return {Promise<boolean>} True if WDA is running
133
+ * @throws {Error} If there was invalid response code or body
134
+ */
135
+ async isRunning() {
136
+ return !!(await this.getStatus());
202
137
  }
203
- this.log.info('Launching WebDriverAgent on the device without xcodebuild');
204
- this.xctestApiClient = new _appiumIosDevice.Xctest(this.device.udid, this.bundleIdForXctest, null, {
205
- env: xctestEnv
206
- });
207
- await this.xctestApiClient.start();
208
- this.setupProxies(sessionId);
209
- const status = await this.getStatus();
210
- this.started = true;
211
- return status;
212
- }
213
- async launch(sessionId) {
214
- if (this.webDriverAgentUrl) {
215
- this.log.info(`Using provided WebdriverAgent at '${this.webDriverAgentUrl}'`);
216
- this.url = this.webDriverAgentUrl;
217
- this.setupProxies(sessionId);
218
- return await this.getStatus();
138
+ get basePath() {
139
+ if (this.url.path === '/') {
140
+ return '';
141
+ }
142
+ return this.url.path || '';
219
143
  }
220
- if (this.usePreinstalledWDA) {
221
- if (this.isRealDevice) {
222
- return await this.launchWithPreinstalledWDA(sessionId);
223
- }
224
- throw new Error('usePreinstalledWDA is available only for a real device.');
144
+ /**
145
+ * Return current running WDA's status like below
146
+ * {
147
+ * "state": "success",
148
+ * "os": {
149
+ * "name": "iOS",
150
+ * "version": "11.4",
151
+ * "sdkVersion": "11.3"
152
+ * },
153
+ * "ios": {
154
+ * "simulatorVersion": "11.4",
155
+ * "ip": "172.254.99.34"
156
+ * },
157
+ * "build": {
158
+ * "time": "Jun 24 2018 17:08:21",
159
+ * "productBundleIdentifier": "com.facebook.WebDriverAgentRunner"
160
+ * }
161
+ * }
162
+ *
163
+ * @return {Promise<any?>} State Object
164
+ * @throws {Error} If there was invalid response code or body
165
+ */
166
+ async getStatus() {
167
+ const noSessionProxy = new no_session_proxy_1.NoSessionProxy({
168
+ server: this.url.hostname,
169
+ port: this.url.port,
170
+ base: this.basePath,
171
+ timeout: 3000,
172
+ });
173
+ try {
174
+ return await noSessionProxy.command('/status', 'GET');
175
+ }
176
+ catch (err) {
177
+ this.log.debug(`WDA is not listening at '${this.url.href}'`);
178
+ return null;
179
+ }
225
180
  }
226
- this.log.info('Launching WebDriverAgent on the device');
227
- this.setupProxies(sessionId);
228
- if (!this.useXctestrunFile && !(await _support.fs.exists(this.agentPath))) {
229
- throw new Error(`Trying to use WebDriverAgent project at '${this.agentPath}' but the ` + 'file does not exist');
181
+ /**
182
+ * Uninstall WDAs from the test device.
183
+ * Over Xcode 11, multiple WDA can be in the device since Xcode 11 generates different WDA.
184
+ * Appium does not expect multiple WDAs are running on a device.
185
+ */
186
+ async uninstall() {
187
+ try {
188
+ const bundleIds = await this.device.getUserInstalledBundleIdsByBundleName(WDA_CF_BUNDLE_NAME);
189
+ if (lodash_1.default.isEmpty(bundleIds)) {
190
+ this.log.debug('No WDAs on the device.');
191
+ return;
192
+ }
193
+ this.log.debug(`Uninstalling WDAs: '${bundleIds}'`);
194
+ for (const bundleId of bundleIds) {
195
+ await this.device.removeApp(bundleId);
196
+ }
197
+ }
198
+ catch (e) {
199
+ this.log.debug(e);
200
+ this.log.warn(`WebDriverAgent uninstall failed. Perhaps, it is already uninstalled? ` +
201
+ `Original error: ${e.message}`);
202
+ }
230
203
  }
231
- if (this.idb || this.useXctestrunFile || this.derivedDataPath && this.usePrebuiltWDA) {
232
- this.log.info('Skipped WDA project cleanup according to the provided capabilities');
233
- } else {
234
- const synchronizationKey = _path.default.normalize(this.bootstrapPath);
235
- await SHARED_RESOURCES_GUARD.acquire(synchronizationKey, async () => await this._cleanupProjectIfFresh());
204
+ async _cleanupProjectIfFresh() {
205
+ if (this.canSkipXcodebuild) {
206
+ return;
207
+ }
208
+ const packageInfo = JSON.parse(await support_1.fs.readFile(path_1.default.join(utils_1.BOOTSTRAP_PATH, 'package.json'), 'utf8'));
209
+ const box = (0, strongbox_1.strongbox)(packageInfo.name);
210
+ let boxItem = box.getItem(RECENT_MODULE_VERSION_ITEM_NAME);
211
+ if (!boxItem) {
212
+ const timestampPath = path_1.default.resolve(process.env.HOME ?? '', constants_1.WDA_UPGRADE_TIMESTAMP_PATH);
213
+ if (await support_1.fs.exists(timestampPath)) {
214
+ // TODO: It is probably a bit ugly to hardcode the recent version string,
215
+ // TODO: hovewer it should do the job as a temporary transition trick
216
+ // TODO: to switch from a hardcoded file path to the strongbox usage.
217
+ try {
218
+ boxItem = await box.createItemWithValue(RECENT_MODULE_VERSION_ITEM_NAME, '5.0.0');
219
+ }
220
+ catch (e) {
221
+ this.log.warn(`The actual module version cannot be persisted: ${e.message}`);
222
+ return;
223
+ }
224
+ }
225
+ else {
226
+ this.log.info('There is no need to perform the project cleanup. A fresh install has been detected');
227
+ try {
228
+ await box.createItemWithValue(RECENT_MODULE_VERSION_ITEM_NAME, packageInfo.version);
229
+ }
230
+ catch (e) {
231
+ this.log.warn(`The actual module version cannot be persisted: ${e.message}`);
232
+ }
233
+ return;
234
+ }
235
+ }
236
+ let recentModuleVersion = await boxItem.read();
237
+ try {
238
+ recentModuleVersion = support_1.util.coerceVersion(recentModuleVersion, true);
239
+ }
240
+ catch (e) {
241
+ this.log.warn(`The persisted module version string has been damaged: ${e.message}`);
242
+ this.log.info(`Updating it to '${packageInfo.version}' assuming the project clenup is not needed`);
243
+ await boxItem.write(packageInfo.version);
244
+ return;
245
+ }
246
+ if (support_1.util.compareVersions(recentModuleVersion, '>=', packageInfo.version)) {
247
+ this.log.info(`WebDriverAgent does not need a cleanup. The project sources are up to date ` +
248
+ `(${recentModuleVersion} >= ${packageInfo.version})`);
249
+ return;
250
+ }
251
+ this.log.info(`Cleaning up the WebDriverAgent project after the module upgrade has happened ` +
252
+ `(${recentModuleVersion} < ${packageInfo.version})`);
253
+ try {
254
+ // @ts-ignore xcodebuild should be set
255
+ await this.xcodebuild.cleanProject();
256
+ await boxItem.write(packageInfo.version);
257
+ }
258
+ catch (e) {
259
+ this.log.warn(`Cannot perform WebDriverAgent project cleanup. Original error: ${e.message}`);
260
+ }
236
261
  }
237
- await (0, _utils.resetTestProcesses)(this.device.udid, !this.isRealDevice);
238
- if (this.idb) {
239
- return await this.startWithIDB();
262
+ /**
263
+ * Launch WDA with preinstalled package without xcodebuild.
264
+ * @param {string} sessionId Launch WDA and establish the session with this sessionId
265
+ * @return {Promise<any?>} State Object
266
+ */
267
+ async launchWithPreinstalledWDA(sessionId) {
268
+ const xctestEnv = {
269
+ USE_PORT: this.wdaLocalPort || WDA_AGENT_PORT,
270
+ WDA_PRODUCT_BUNDLE_IDENTIFIER: this.bundleIdForXctest
271
+ };
272
+ if (this.mjpegServerPort) {
273
+ xctestEnv.MJPEG_SERVER_PORT = this.mjpegServerPort;
274
+ }
275
+ this.log.info('Launching WebDriverAgent on the device without xcodebuild');
276
+ this.xctestApiClient = new appium_ios_device_1.Xctest(this.device.udid, this.bundleIdForXctest, null, { env: xctestEnv });
277
+ await this.xctestApiClient.start();
278
+ this.setupProxies(sessionId);
279
+ const status = await this.getStatus();
280
+ this.started = true;
281
+ return status;
240
282
  }
241
- await this.xcodebuild.init(this.noSessionProxy);
242
- if (this.prebuildWDA) {
243
- await this.xcodebuild.prebuild();
283
+ /**
284
+ * Return current running WDA's status like below after launching WDA
285
+ * {
286
+ * "state": "success",
287
+ * "os": {
288
+ * "name": "iOS",
289
+ * "version": "11.4",
290
+ * "sdkVersion": "11.3"
291
+ * },
292
+ * "ios": {
293
+ * "simulatorVersion": "11.4",
294
+ * "ip": "172.254.99.34"
295
+ * },
296
+ * "build": {
297
+ * "time": "Jun 24 2018 17:08:21",
298
+ * "productBundleIdentifier": "com.facebook.WebDriverAgentRunner"
299
+ * }
300
+ * }
301
+ *
302
+ * @param {string} sessionId Launch WDA and establish the session with this sessionId
303
+ * @return {Promise<any?>} State Object
304
+ * @throws {Error} If there was invalid response code or body
305
+ */
306
+ async launch(sessionId) {
307
+ if (this.webDriverAgentUrl) {
308
+ this.log.info(`Using provided WebdriverAgent at '${this.webDriverAgentUrl}'`);
309
+ this.url = this.webDriverAgentUrl;
310
+ this.setupProxies(sessionId);
311
+ return await this.getStatus();
312
+ }
313
+ if (this.usePreinstalledWDA) {
314
+ if (this.isRealDevice) {
315
+ return await this.launchWithPreinstalledWDA(sessionId);
316
+ }
317
+ throw new Error('usePreinstalledWDA is available only for a real device.');
318
+ }
319
+ this.log.info('Launching WebDriverAgent on the device');
320
+ this.setupProxies(sessionId);
321
+ if (!this.useXctestrunFile && !await support_1.fs.exists(this.agentPath)) {
322
+ throw new Error(`Trying to use WebDriverAgent project at '${this.agentPath}' but the ` +
323
+ 'file does not exist');
324
+ }
325
+ // useXctestrunFile and usePrebuiltWDA use existing dependencies
326
+ // It depends on user side
327
+ if (this.idb || this.useXctestrunFile || (this.derivedDataPath && this.usePrebuiltWDA)) {
328
+ this.log.info('Skipped WDA project cleanup according to the provided capabilities');
329
+ }
330
+ else {
331
+ const synchronizationKey = path_1.default.normalize(this.bootstrapPath);
332
+ await SHARED_RESOURCES_GUARD.acquire(synchronizationKey, async () => await this._cleanupProjectIfFresh());
333
+ }
334
+ // We need to provide WDA local port, because it might be occupied
335
+ await (0, utils_1.resetTestProcesses)(this.device.udid, !this.isRealDevice);
336
+ if (this.idb) {
337
+ return await this.startWithIDB();
338
+ }
339
+ // @ts-ignore xcodebuild should be set
340
+ await this.xcodebuild.init(this.noSessionProxy);
341
+ // Start the xcodebuild process
342
+ if (this.prebuildWDA) {
343
+ // @ts-ignore xcodebuild should be set
344
+ await this.xcodebuild.prebuild();
345
+ }
346
+ // @ts-ignore xcodebuild should be set
347
+ return await this.xcodebuild.start();
244
348
  }
245
- return await this.xcodebuild.start();
246
- }
247
- async startWithIDB() {
248
- this.log.info('Will launch WDA with idb instead of xcodebuild since the corresponding flag is enabled');
249
- const {
250
- wdaBundleId,
251
- testBundleId
252
- } = await this.prepareWDA();
253
- const env = {
254
- USE_PORT: this.wdaRemotePort,
255
- WDA_PRODUCT_BUNDLE_IDENTIFIER: this.updatedWDABundleId
256
- };
257
- if (this.mjpegServerPort) {
258
- env.MJPEG_SERVER_PORT = this.mjpegServerPort;
349
+ async startWithIDB() {
350
+ this.log.info('Will launch WDA with idb instead of xcodebuild since the corresponding flag is enabled');
351
+ const { wdaBundleId, testBundleId } = await this.prepareWDA();
352
+ const env = {
353
+ USE_PORT: this.wdaRemotePort,
354
+ WDA_PRODUCT_BUNDLE_IDENTIFIER: this.updatedWDABundleId,
355
+ };
356
+ if (this.mjpegServerPort) {
357
+ env.MJPEG_SERVER_PORT = this.mjpegServerPort;
358
+ }
359
+ return await this.idb.runXCUITest(wdaBundleId, wdaBundleId, testBundleId, { env });
259
360
  }
260
- return await this.idb.runXCUITest(wdaBundleId, wdaBundleId, testBundleId, {
261
- env
262
- });
263
- }
264
- async parseBundleId(wdaBundlePath) {
265
- const infoPlistPath = _path.default.join(wdaBundlePath, 'Info.plist');
266
- const infoPlist = await _support.plist.parsePlist(await _support.fs.readFile(infoPlistPath));
267
- if (!infoPlist.CFBundleIdentifier) {
268
- throw new Error(`Could not find bundle id in '${infoPlistPath}'`);
361
+ async parseBundleId(wdaBundlePath) {
362
+ const infoPlistPath = path_1.default.join(wdaBundlePath, 'Info.plist');
363
+ const infoPlist = await support_1.plist.parsePlist(await support_1.fs.readFile(infoPlistPath));
364
+ if (!infoPlist.CFBundleIdentifier) {
365
+ throw new Error(`Could not find bundle id in '${infoPlistPath}'`);
366
+ }
367
+ return infoPlist.CFBundleIdentifier;
269
368
  }
270
- return infoPlist.CFBundleIdentifier;
271
- }
272
- async prepareWDA() {
273
- const wdaBundlePath = this.wdaBundlePath || (await this.fetchWDABundle());
274
- const wdaBundleId = await this.parseBundleId(wdaBundlePath);
275
- if (!(await this.device.isAppInstalled(wdaBundleId))) {
276
- await this.device.installApp(wdaBundlePath);
369
+ async prepareWDA() {
370
+ const wdaBundlePath = this.wdaBundlePath || await this.fetchWDABundle();
371
+ const wdaBundleId = await this.parseBundleId(wdaBundlePath);
372
+ if (!await this.device.isAppInstalled(wdaBundleId)) {
373
+ await this.device.installApp(wdaBundlePath);
374
+ }
375
+ const testBundleId = await this.idb.installXCTestBundle(path_1.default.join(wdaBundlePath, 'PlugIns', 'WebDriverAgentRunner.xctest'));
376
+ return { wdaBundleId, testBundleId, wdaBundlePath };
277
377
  }
278
- const testBundleId = await this.idb.installXCTestBundle(_path.default.join(wdaBundlePath, 'PlugIns', 'WebDriverAgentRunner.xctest'));
279
- return {
280
- wdaBundleId,
281
- testBundleId,
282
- wdaBundlePath
283
- };
284
- }
285
- async fetchWDABundle() {
286
- if (!this.derivedDataPath) {
287
- return await (0, _checkDependencies.bundleWDASim)(this.xcodebuild);
378
+ async fetchWDABundle() {
379
+ if (!this.derivedDataPath) {
380
+ return await (0, check_dependencies_1.bundleWDASim)(this.xcodebuild);
381
+ }
382
+ const wdaBundlePaths = await support_1.fs.glob(`${this.derivedDataPath}/**/*${constants_1.WDA_RUNNER_APP}/`, {
383
+ absolute: true,
384
+ });
385
+ if (lodash_1.default.isEmpty(wdaBundlePaths)) {
386
+ throw new Error(`Could not find the WDA bundle in '${this.derivedDataPath}'`);
387
+ }
388
+ return wdaBundlePaths[0];
288
389
  }
289
- const wdaBundlePaths = await _support.fs.glob(`${this.derivedDataPath}/**/*${_constants.WDA_RUNNER_APP}/`, {
290
- absolute: true
291
- });
292
- if (_lodash.default.isEmpty(wdaBundlePaths)) {
293
- throw new Error(`Could not find the WDA bundle in '${this.derivedDataPath}'`);
390
+ async isSourceFresh() {
391
+ const existsPromises = [
392
+ 'Resources',
393
+ `Resources${path_1.default.sep}WebDriverAgent.bundle`,
394
+ ].map((subPath) => support_1.fs.exists(path_1.default.resolve(this.bootstrapPath, subPath)));
395
+ return (await bluebird_1.default.all(existsPromises)).some((v) => v === false);
294
396
  }
295
- return wdaBundlePaths[0];
296
- }
297
- async isSourceFresh() {
298
- const existsPromises = ['Resources', `Resources${_path.default.sep}WebDriverAgent.bundle`].map(subPath => _support.fs.exists(_path.default.resolve(this.bootstrapPath, subPath)));
299
- return (await _bluebird.default.all(existsPromises)).some(v => v === false);
300
- }
301
- setupProxies(sessionId) {
302
- const proxyOpts = {
303
- log: this.log,
304
- server: this.url.hostname,
305
- port: this.url.port,
306
- base: this.basePath,
307
- timeout: this.wdaConnectionTimeout,
308
- keepAlive: true
309
- };
310
- this.jwproxy = new _baseDriver.JWProxy(proxyOpts);
311
- this.jwproxy.sessionId = sessionId;
312
- this.proxyReqRes = this.jwproxy.proxyReqRes.bind(this.jwproxy);
313
- this.noSessionProxy = new _noSessionProxy.NoSessionProxy(proxyOpts);
314
- }
315
- async quit() {
316
- if (this.usePreinstalledWDA) {
317
- if (this.xctestApiClient) {
318
- this.log.info('Stopping the XCTest session');
319
- this.xctestApiClient.stop();
320
- this.xctestApiClient = null;
321
- }
322
- } else if (!this.args.webDriverAgentUrl) {
323
- this.log.info('Shutting down sub-processes');
324
- await this.xcodebuild.quit();
325
- await this.xcodebuild.reset();
326
- } else {
327
- this.log.debug('Do not stop xcodebuild nor XCTest session ' + 'since the WDA session is managed by outside this driver.');
397
+ setupProxies(sessionId) {
398
+ const proxyOpts = {
399
+ log: this.log,
400
+ server: this.url.hostname,
401
+ port: this.url.port,
402
+ base: this.basePath,
403
+ timeout: this.wdaConnectionTimeout,
404
+ keepAlive: true,
405
+ };
406
+ this.jwproxy = new base_driver_1.JWProxy(proxyOpts);
407
+ this.jwproxy.sessionId = sessionId;
408
+ this.proxyReqRes = this.jwproxy.proxyReqRes.bind(this.jwproxy);
409
+ this.noSessionProxy = new no_session_proxy_1.NoSessionProxy(proxyOpts);
328
410
  }
329
- if (this.jwproxy) {
330
- this.jwproxy.sessionId = null;
411
+ async quit() {
412
+ if (this.usePreinstalledWDA) {
413
+ if (this.xctestApiClient) {
414
+ this.log.info('Stopping the XCTest session');
415
+ this.xctestApiClient.stop();
416
+ this.xctestApiClient = null;
417
+ }
418
+ }
419
+ else if (!this.args.webDriverAgentUrl) {
420
+ this.log.info('Shutting down sub-processes');
421
+ // @ts-ignore xcodebuild should be set
422
+ await this.xcodebuild.quit();
423
+ // @ts-ignore xcodebuild should be set
424
+ await this.xcodebuild.reset();
425
+ }
426
+ else {
427
+ this.log.debug('Do not stop xcodebuild nor XCTest session ' +
428
+ 'since the WDA session is managed by outside this driver.');
429
+ }
430
+ if (this.jwproxy) {
431
+ this.jwproxy.sessionId = null;
432
+ }
433
+ this.started = false;
434
+ if (!this.args.webDriverAgentUrl) {
435
+ // if we populated the url ourselves (during `setupCaching` call, for instance)
436
+ // then clean that up. If the url was supplied, we want to keep it
437
+ this.webDriverAgentUrl = null;
438
+ }
331
439
  }
332
- this.started = false;
333
- if (!this.args.webDriverAgentUrl) {
334
- this.webDriverAgentUrl = null;
440
+ get url() {
441
+ if (!this._url) {
442
+ if (this.webDriverAgentUrl) {
443
+ this._url = url_1.default.parse(this.webDriverAgentUrl);
444
+ }
445
+ else {
446
+ const port = this.wdaLocalPort || WDA_AGENT_PORT;
447
+ const { protocol, hostname } = url_1.default.parse(this.wdaBaseUrl || constants_1.WDA_BASE_URL);
448
+ this._url = url_1.default.parse(`${protocol}//${hostname}:${port}`);
449
+ }
450
+ }
451
+ return this._url;
335
452
  }
336
- }
337
- get url() {
338
- if (!this._url) {
339
- if (this.webDriverAgentUrl) {
340
- this._url = _url2.default.parse(this.webDriverAgentUrl);
341
- } else {
342
- const port = this.wdaLocalPort || WDA_AGENT_PORT;
343
- const {
344
- protocol,
345
- hostname
346
- } = _url2.default.parse(this.wdaBaseUrl || _constants.WDA_BASE_URL);
347
- this._url = _url2.default.parse(`${protocol}//${hostname}:${port}`);
348
- }
453
+ set url(_url) {
454
+ this._url = url_1.default.parse(_url);
349
455
  }
350
- return this._url;
351
- }
352
- set url(_url) {
353
- this._url = _url2.default.parse(_url);
354
- }
355
- get fullyStarted() {
356
- return this.started;
357
- }
358
- set fullyStarted(started = false) {
359
- this.started = started;
360
- }
361
- async retrieveDerivedDataPath() {
362
- if (this.canSkipXcodebuild) {
363
- return;
456
+ get fullyStarted() {
457
+ return this.started;
364
458
  }
365
- return await this.xcodebuild.retrieveDerivedDataPath();
366
- }
367
- async setupCaching() {
368
- const status = await this.getStatus();
369
- if (!status || !status.build) {
370
- this.log.debug('WDA is currently not running. There is nothing to cache');
371
- return;
459
+ set fullyStarted(started) {
460
+ this.started = started ?? false;
372
461
  }
373
- const {
374
- productBundleIdentifier,
375
- upgradedAt
376
- } = status.build;
377
- if (_support.util.hasValue(productBundleIdentifier) && _support.util.hasValue(this.updatedWDABundleId) && this.updatedWDABundleId !== productBundleIdentifier) {
378
- this.log.info(`Will uninstall running WDA since it has different bundle id. The actual value is '${productBundleIdentifier}'.`);
379
- return await this.uninstall();
462
+ async retrieveDerivedDataPath() {
463
+ if (this.canSkipXcodebuild) {
464
+ return;
465
+ }
466
+ // @ts-ignore xcodebuild should be set
467
+ return await this.xcodebuild.retrieveDerivedDataPath();
380
468
  }
381
- if (_support.util.hasValue(productBundleIdentifier) && !_support.util.hasValue(this.updatedWDABundleId) && _constants.WDA_RUNNER_BUNDLE_ID !== productBundleIdentifier) {
382
- this.log.info(`Will uninstall running WDA since its bundle id is not equal to the default value ${_constants.WDA_RUNNER_BUNDLE_ID}`);
383
- return await this.uninstall();
469
+ /**
470
+ * Reuse running WDA if it has the same bundle id with updatedWDABundleId.
471
+ * Or reuse it if it has the default id without updatedWDABundleId.
472
+ * Uninstall it if the method faces an exception for the above situation.
473
+ */
474
+ async setupCaching() {
475
+ const status = await this.getStatus();
476
+ if (!status || !status.build) {
477
+ this.log.debug('WDA is currently not running. There is nothing to cache');
478
+ return;
479
+ }
480
+ const { productBundleIdentifier, upgradedAt, } = status.build;
481
+ // for real device
482
+ if (support_1.util.hasValue(productBundleIdentifier) && support_1.util.hasValue(this.updatedWDABundleId) && this.updatedWDABundleId !== productBundleIdentifier) {
483
+ this.log.info(`Will uninstall running WDA since it has different bundle id. The actual value is '${productBundleIdentifier}'.`);
484
+ return await this.uninstall();
485
+ }
486
+ // for simulator
487
+ if (support_1.util.hasValue(productBundleIdentifier) && !support_1.util.hasValue(this.updatedWDABundleId) && constants_1.WDA_RUNNER_BUNDLE_ID !== productBundleIdentifier) {
488
+ this.log.info(`Will uninstall running WDA since its bundle id is not equal to the default value ${constants_1.WDA_RUNNER_BUNDLE_ID}`);
489
+ return await this.uninstall();
490
+ }
491
+ const actualUpgradeTimestamp = await (0, utils_1.getWDAUpgradeTimestamp)();
492
+ this.log.debug(`Upgrade timestamp of the currently bundled WDA: ${actualUpgradeTimestamp}`);
493
+ this.log.debug(`Upgrade timestamp of the WDA on the device: ${upgradedAt}`);
494
+ if (actualUpgradeTimestamp && upgradedAt && lodash_1.default.toLower(`${actualUpgradeTimestamp}`) !== lodash_1.default.toLower(`${upgradedAt}`)) {
495
+ this.log.info('Will uninstall running WDA since it has different version in comparison to the one ' +
496
+ `which is bundled with appium-xcuitest-driver module (${actualUpgradeTimestamp} != ${upgradedAt})`);
497
+ return await this.uninstall();
498
+ }
499
+ const message = support_1.util.hasValue(productBundleIdentifier)
500
+ ? `Will reuse previously cached WDA instance at '${this.url.href}' with '${productBundleIdentifier}'`
501
+ : `Will reuse previously cached WDA instance at '${this.url.href}'`;
502
+ this.log.info(`${message}. Set the wdaLocalPort capability to a value different from ${this.url.port} if this is an undesired behavior.`);
503
+ this.webDriverAgentUrl = this.url.href;
384
504
  }
385
- const actualUpgradeTimestamp = await (0, _utils.getWDAUpgradeTimestamp)();
386
- this.log.debug(`Upgrade timestamp of the currently bundled WDA: ${actualUpgradeTimestamp}`);
387
- this.log.debug(`Upgrade timestamp of the WDA on the device: ${upgradedAt}`);
388
- if (actualUpgradeTimestamp && upgradedAt && _lodash.default.toLower(`${actualUpgradeTimestamp}`) !== _lodash.default.toLower(`${upgradedAt}`)) {
389
- this.log.info('Will uninstall running WDA since it has different version in comparison to the one ' + `which is bundled with appium-xcuitest-driver module (${actualUpgradeTimestamp} != ${upgradedAt})`);
390
- return await this.uninstall();
505
+ /**
506
+ * Quit and uninstall running WDA.
507
+ */
508
+ async quitAndUninstall() {
509
+ await this.quit();
510
+ await this.uninstall();
391
511
  }
392
- const message = _support.util.hasValue(productBundleIdentifier) ? `Will reuse previously cached WDA instance at '${this.url.href}' with '${productBundleIdentifier}'` : `Will reuse previously cached WDA instance at '${this.url.href}'`;
393
- this.log.info(`${message}. Set the wdaLocalPort capability to a value different from ${this.url.port} if this is an undesired behavior.`);
394
- this.webDriverAgentUrl = this.url.href;
395
- }
396
- async quitAndUninstall() {
397
- await this.quit();
398
- await this.uninstall();
399
- }
400
512
  }
401
513
  exports.WebDriverAgent = WebDriverAgent;
402
- var _default = WebDriverAgent;
403
- exports.default = _default;
404
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9kYXNoIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfcGF0aCIsIl91cmwyIiwiX2JsdWViaXJkIiwiX2Jhc2VEcml2ZXIiLCJfc3VwcG9ydCIsIl9sb2dnZXIiLCJfbm9TZXNzaW9uUHJveHkiLCJfdXRpbHMiLCJfeGNvZGVidWlsZCIsIl9hc3luY0xvY2siLCJfdGVlbl9wcm9jZXNzIiwiX2NoZWNrRGVwZW5kZW5jaWVzIiwiX2NvbnN0YW50cyIsIl9hcHBpdW1Jb3NEZXZpY2UiLCJfc3Ryb25nYm94IiwiV0RBX0xBVU5DSF9USU1FT1VUIiwiV0RBX0FHRU5UX1BPUlQiLCJXREFfQ0ZfQlVORExFX05BTUUiLCJTSEFSRURfUkVTT1VSQ0VTX0dVQVJEIiwiQXN5bmNMb2NrIiwiUkVDRU5UX01PRFVMRV9WRVJTSU9OX0lURU1fTkFNRSIsIldlYkRyaXZlckFnZW50IiwiY29uc3RydWN0b3IiLCJ4Y29kZVZlcnNpb24iLCJhcmdzIiwibG9nIiwiXyIsImNsb25lIiwiZGVmYXVsdExvZ2dlciIsImRldmljZSIsInBsYXRmb3JtVmVyc2lvbiIsInBsYXRmb3JtTmFtZSIsImlvc1Nka1ZlcnNpb24iLCJob3N0IiwiaXNSZWFsRGV2aWNlIiwicmVhbERldmljZSIsImlkYiIsIndkYUJ1bmRsZVBhdGgiLCJzZXRXREFQYXRocyIsImJvb3RzdHJhcFBhdGgiLCJhZ2VudFBhdGgiLCJ3ZGFMb2NhbFBvcnQiLCJ3ZGFSZW1vdGVQb3J0Iiwid2RhQmFzZVVybCIsIldEQV9CQVNFX1VSTCIsInByZWJ1aWxkV0RBIiwid2ViRHJpdmVyQWdlbnRVcmwiLCJzdGFydGVkIiwid2RhQ29ubmVjdGlvblRpbWVvdXQiLCJ1c2VYY3Rlc3RydW5GaWxlIiwidXNlUHJlYnVpbHRXREEiLCJkZXJpdmVkRGF0YVBhdGgiLCJtanBlZ1NlcnZlclBvcnQiLCJ1cGRhdGVkV0RBQnVuZGxlSWQiLCJ1c2VQcmVpbnN0YWxsZWRXREEiLCJ4Y3Rlc3RBcGlDbGllbnQiLCJ4Y29kZWJ1aWxkIiwiY2FuU2tpcFhjb2RlYnVpbGQiLCJYY29kZUJ1aWxkIiwic2hvd1hjb2RlTG9nIiwieGNvZGVDb25maWdGaWxlIiwieGNvZGVPcmdJZCIsInhjb2RlU2lnbmluZ0lkIiwia2V5Y2hhaW5QYXRoIiwia2V5Y2hhaW5QYXNzd29yZCIsInVzZVNpbXBsZUJ1aWxkVGVzdCIsImxhdW5jaFRpbWVvdXQiLCJ3ZGFMYXVuY2hUaW1lb3V0IiwiYWxsb3dQcm92aXNpb25pbmdEZXZpY2VSZWdpc3RyYXRpb24iLCJyZXN1bHRCdW5kbGVQYXRoIiwicmVzdWx0QnVuZGxlVmVyc2lvbiIsImJ1bmRsZUlkRm9yWGN0ZXN0IiwiV0RBX1JVTk5FUl9CVU5ETEVfSURfRk9SX1hDVEVTVCIsIkJPT1RTVFJBUF9QQVRIIiwiaW5mbyIsInBhdGgiLCJyZXNvbHZlIiwiY2xlYW51cE9ic29sZXRlUHJvY2Vzc2VzIiwib2Jzb2xldGVQaWRzIiwiZ2V0UElEc0xpc3RlbmluZ09uUG9ydCIsInVybCIsInBvcnQiLCJjbWRMaW5lIiwiaW5jbHVkZXMiLCJ0b0xvd2VyQ2FzZSIsInVkaWQiLCJpc0VtcHR5IiwiZGVidWciLCJsZW5ndGgiLCJleGVjIiwiZSIsIndhcm4iLCJtZXNzYWdlIiwiaXNSdW5uaW5nIiwiZ2V0U3RhdHVzIiwiYmFzZVBhdGgiLCJub1Nlc3Npb25Qcm94eSIsIk5vU2Vzc2lvblByb3h5Iiwic2VydmVyIiwiaG9zdG5hbWUiLCJiYXNlIiwidGltZW91dCIsImNvbW1hbmQiLCJlcnIiLCJocmVmIiwidW5pbnN0YWxsIiwiYnVuZGxlSWRzIiwiZ2V0VXNlckluc3RhbGxlZEJ1bmRsZUlkc0J5QnVuZGxlTmFtZSIsImJ1bmRsZUlkIiwicmVtb3ZlQXBwIiwiX2NsZWFudXBQcm9qZWN0SWZGcmVzaCIsInBhY2thZ2VJbmZvIiwiSlNPTiIsInBhcnNlIiwiZnMiLCJyZWFkRmlsZSIsImpvaW4iLCJib3giLCJzdHJvbmdib3giLCJuYW1lIiwiYm94SXRlbSIsImdldEl0ZW0iLCJ0aW1lc3RhbXBQYXRoIiwicHJvY2VzcyIsImVudiIsIkhPTUUiLCJXREFfVVBHUkFERV9USU1FU1RBTVBfUEFUSCIsImV4aXN0cyIsImNyZWF0ZUl0ZW1XaXRoVmFsdWUiLCJ2ZXJzaW9uIiwicmVjZW50TW9kdWxlVmVyc2lvbiIsInJlYWQiLCJ1dGlsIiwiY29lcmNlVmVyc2lvbiIsIndyaXRlIiwiY29tcGFyZVZlcnNpb25zIiwiY2xlYW5Qcm9qZWN0IiwibGF1bmNoV2l0aFByZWluc3RhbGxlZFdEQSIsInNlc3Npb25JZCIsInhjdGVzdEVudiIsIlVTRV9QT1JUIiwiV0RBX1BST0RVQ1RfQlVORExFX0lERU5USUZJRVIiLCJNSlBFR19TRVJWRVJfUE9SVCIsIlhjdGVzdCIsInN0YXJ0Iiwic2V0dXBQcm94aWVzIiwic3RhdHVzIiwibGF1bmNoIiwiRXJyb3IiLCJzeW5jaHJvbml6YXRpb25LZXkiLCJub3JtYWxpemUiLCJhY3F1aXJlIiwicmVzZXRUZXN0UHJvY2Vzc2VzIiwic3RhcnRXaXRoSURCIiwiaW5pdCIsInByZWJ1aWxkIiwid2RhQnVuZGxlSWQiLCJ0ZXN0QnVuZGxlSWQiLCJwcmVwYXJlV0RBIiwicnVuWENVSVRlc3QiLCJwYXJzZUJ1bmRsZUlkIiwiaW5mb1BsaXN0UGF0aCIsImluZm9QbGlzdCIsInBsaXN0IiwicGFyc2VQbGlzdCIsIkNGQnVuZGxlSWRlbnRpZmllciIsImZldGNoV0RBQnVuZGxlIiwiaXNBcHBJbnN0YWxsZWQiLCJpbnN0YWxsQXBwIiwiaW5zdGFsbFhDVGVzdEJ1bmRsZSIsImJ1bmRsZVdEQVNpbSIsIndkYUJ1bmRsZVBhdGhzIiwiZ2xvYiIsIldEQV9SVU5ORVJfQVBQIiwiYWJzb2x1dGUiLCJpc1NvdXJjZUZyZXNoIiwiZXhpc3RzUHJvbWlzZXMiLCJzZXAiLCJtYXAiLCJzdWJQYXRoIiwiQiIsImFsbCIsInNvbWUiLCJ2IiwicHJveHlPcHRzIiwia2VlcEFsaXZlIiwiandwcm94eSIsIkpXUHJveHkiLCJwcm94eVJlcVJlcyIsImJpbmQiLCJxdWl0Iiwic3RvcCIsInJlc2V0IiwiX3VybCIsInByb3RvY29sIiwiZnVsbHlTdGFydGVkIiwicmV0cmlldmVEZXJpdmVkRGF0YVBhdGgiLCJzZXR1cENhY2hpbmciLCJidWlsZCIsInByb2R1Y3RCdW5kbGVJZGVudGlmaWVyIiwidXBncmFkZWRBdCIsImhhc1ZhbHVlIiwiV0RBX1JVTk5FUl9CVU5ETEVfSUQiLCJhY3R1YWxVcGdyYWRlVGltZXN0YW1wIiwiZ2V0V0RBVXBncmFkZVRpbWVzdGFtcCIsInRvTG93ZXIiLCJxdWl0QW5kVW5pbnN0YWxsIiwiZXhwb3J0cyIsIl9kZWZhdWx0IiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uL2xpYi93ZWJkcml2ZXJhZ2VudC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgdXJsIGZyb20gJ3VybCc7XG5pbXBvcnQgQiBmcm9tICdibHVlYmlyZCc7XG5pbXBvcnQgeyBKV1Byb3h5IH0gZnJvbSAnQGFwcGl1bS9iYXNlLWRyaXZlcic7XG5pbXBvcnQgeyBmcywgdXRpbCwgcGxpc3QgfSBmcm9tICdAYXBwaXVtL3N1cHBvcnQnO1xuaW1wb3J0IGRlZmF1bHRMb2dnZXIgZnJvbSAnLi9sb2dnZXInO1xuaW1wb3J0IHsgTm9TZXNzaW9uUHJveHkgfSBmcm9tICcuL25vLXNlc3Npb24tcHJveHknO1xuaW1wb3J0IHtcbiAgZ2V0V0RBVXBncmFkZVRpbWVzdGFtcCwgcmVzZXRUZXN0UHJvY2Vzc2VzLCBnZXRQSURzTGlzdGVuaW5nT25Qb3J0LCBCT09UU1RSQVBfUEFUSFxufSBmcm9tICcuL3V0aWxzJztcbmltcG9ydCBYY29kZUJ1aWxkIGZyb20gJy4veGNvZGVidWlsZCc7XG5pbXBvcnQgQXN5bmNMb2NrIGZyb20gJ2FzeW5jLWxvY2snO1xuaW1wb3J0IHsgZXhlYyB9IGZyb20gJ3RlZW5fcHJvY2Vzcyc7XG5pbXBvcnQgeyBidW5kbGVXREFTaW0gfSBmcm9tICcuL2NoZWNrLWRlcGVuZGVuY2llcyc7XG5pbXBvcnQge1xuICBXREFfUlVOTkVSX0JVTkRMRV9JRCwgV0RBX1JVTk5FUl9CVU5ETEVfSURfRk9SX1hDVEVTVCwgV0RBX1JVTk5FUl9BUFAsXG4gIFdEQV9CQVNFX1VSTCwgV0RBX1VQR1JBREVfVElNRVNUQU1QX1BBVEhcbn0gZnJvbSAnLi9jb25zdGFudHMnO1xuaW1wb3J0IHtYY3Rlc3R9IGZyb20gJ2FwcGl1bS1pb3MtZGV2aWNlJztcbmltcG9ydCB7c3Ryb25nYm94fSBmcm9tICdAYXBwaXVtL3N0cm9uZ2JveCc7XG5cbmNvbnN0IFdEQV9MQVVOQ0hfVElNRU9VVCA9IDYwICogMTAwMDtcbmNvbnN0IFdEQV9BR0VOVF9QT1JUID0gODEwMDtcbmNvbnN0IFdEQV9DRl9CVU5ETEVfTkFNRSA9ICdXZWJEcml2ZXJBZ2VudFJ1bm5lci1SdW5uZXInO1xuY29uc3QgU0hBUkVEX1JFU09VUkNFU19HVUFSRCA9IG5ldyBBc3luY0xvY2soKTtcbmNvbnN0IFJFQ0VOVF9NT0RVTEVfVkVSU0lPTl9JVEVNX05BTUUgPSAncmVjZW50V2RhTW9kdWxlVmVyc2lvbic7XG5cbmNsYXNzIFdlYkRyaXZlckFnZW50IHtcbiAgY29uc3RydWN0b3IgKHhjb2RlVmVyc2lvbiwgYXJncyA9IHt9LCBsb2cgPSBudWxsKSB7XG4gICAgdGhpcy54Y29kZVZlcnNpb24gPSB4Y29kZVZlcnNpb247XG5cbiAgICB0aGlzLmFyZ3MgPSBfLmNsb25lKGFyZ3MpO1xuICAgIHRoaXMubG9nID0gbG9nID8/IGRlZmF1bHRMb2dnZXI7XG5cbiAgICB0aGlzLmRldmljZSA9IGFyZ3MuZGV2aWNlO1xuICAgIHRoaXMucGxhdGZvcm1WZXJzaW9uID0gYXJncy5wbGF0Zm9ybVZlcnNpb247XG4gICAgdGhpcy5wbGF0Zm9ybU5hbWUgPSBhcmdzLnBsYXRmb3JtTmFtZTtcbiAgICB0aGlzLmlvc1Nka1ZlcnNpb24gPSBhcmdzLmlvc1Nka1ZlcnNpb247XG4gICAgdGhpcy5ob3N0ID0gYXJncy5ob3N0O1xuICAgIHRoaXMuaXNSZWFsRGV2aWNlID0gISFhcmdzLnJlYWxEZXZpY2U7XG4gICAgdGhpcy5pZGIgPSAoYXJncy5kZXZpY2UgfHwge30pLmlkYjtcbiAgICB0aGlzLndkYUJ1bmRsZVBhdGggPSBhcmdzLndkYUJ1bmRsZVBhdGg7XG5cbiAgICB0aGlzLnNldFdEQVBhdGhzKGFyZ3MuYm9vdHN0cmFwUGF0aCwgYXJncy5hZ2VudFBhdGgpO1xuXG4gICAgdGhpcy53ZGFMb2NhbFBvcnQgPSBhcmdzLndkYUxvY2FsUG9ydDtcbiAgICB0aGlzLndkYVJlbW90ZVBvcnQgPSBhcmdzLndkYUxvY2FsUG9ydCB8fCBXREFfQUdFTlRfUE9SVDtcbiAgICB0aGlzLndkYUJhc2VVcmwgPSBhcmdzLndkYUJhc2VVcmwgfHwgV0RBX0JBU0VfVVJMO1xuXG4gICAgdGhpcy5wcmVidWlsZFdEQSA9IGFyZ3MucHJlYnVpbGRXREE7XG5cbiAgICAvLyB0aGlzLmFyZ3Mud2ViRHJpdmVyQWdlbnRVcmwgZ3VpYXJhbnRlZXMgdGhlIGNhcGFiaWxpdGllcyBhY3VhbGx5XG4gICAgLy8gZ2F2ZSAnYXBwaXVtOndlYkRyaXZlckFnZW50VXJsJyBidXQgJ3RoaXMud2ViRHJpdmVyQWdlbnRVcmwnXG4gICAgLy8gY291bGQgYmUgdXNlZCBmb3IgY2FjaGluZyBXREEgd2l0aCB4Y29kZWJ1aWxkLlxuICAgIHRoaXMud2ViRHJpdmVyQWdlbnRVcmwgPSBhcmdzLndlYkRyaXZlckFnZW50VXJsO1xuXG4gICAgdGhpcy5zdGFydGVkID0gZmFsc2U7XG5cbiAgICB0aGlzLndkYUNvbm5lY3Rpb25UaW1lb3V0ID0gYXJncy53ZGFDb25uZWN0aW9uVGltZW91dDtcblxuICAgIHRoaXMudXNlWGN0ZXN0cnVuRmlsZSA9IGFyZ3MudXNlWGN0ZXN0cnVuRmlsZTtcbiAgICB0aGlzLnVzZVByZWJ1aWx0V0RBID0gYXJncy51c2VQcmVidWlsdFdEQTtcbiAgICB0aGlzLmRlcml2ZWREYXRhUGF0aCA9IGFyZ3MuZGVyaXZlZERhdGFQYXRoO1xuICAgIHRoaXMubWpwZWdTZXJ2ZXJQb3J0ID0gYXJncy5tanBlZ1NlcnZlclBvcnQ7XG5cbiAgICB0aGlzLnVwZGF0ZWRXREFCdW5kbGVJZCA9IGFyZ3MudXBkYXRlZFdEQUJ1bmRsZUlkO1xuXG4gICAgdGhpcy51c2VQcmVpbnN0YWxsZWRXREEgPSBhcmdzLnVzZVByZWluc3RhbGxlZFdEQTtcbiAgICB0aGlzLnhjdGVzdEFwaUNsaWVudCA9IG51bGw7XG5cbiAgICB0aGlzLnhjb2RlYnVpbGQgPSB0aGlzLmNhblNraXBYY29kZWJ1aWxkXG4gICAgPyBudWxsXG4gICAgOiBuZXcgWGNvZGVCdWlsZCh0aGlzLnhjb2RlVmVyc2lvbiwgdGhpcy5kZXZpY2UsIHtcbiAgICAgICAgcGxhdGZvcm1WZXJzaW9uOiB0aGlzLnBsYXRmb3JtVmVyc2lvbixcbiAgICAgICAgcGxhdGZvcm1OYW1lOiB0aGlzLnBsYXRmb3JtTmFtZSxcbiAgICAgICAgaW9zU2RrVmVyc2lvbjogdGhpcy5pb3NTZGtWZXJzaW9uLFxuICAgICAgICBhZ2VudFBhdGg6IHRoaXMuYWdlbnRQYXRoLFxuICAgICAgICBib290c3RyYXBQYXRoOiB0aGlzLmJvb3RzdHJhcFBhdGgsXG4gICAgICAgIHJlYWxEZXZpY2U6IHRoaXMuaXNSZWFsRGV2aWNlLFxuICAgICAgICBzaG93WGNvZGVMb2c6IGFyZ3Muc2hvd1hjb2RlTG9nLFxuICAgICAgICB4Y29kZUNvbmZpZ0ZpbGU6IGFyZ3MueGNvZGVDb25maWdGaWxlLFxuICAgICAgICB4Y29kZU9yZ0lkOiBhcmdzLnhjb2RlT3JnSWQsXG4gICAgICAgIHhjb2RlU2lnbmluZ0lkOiBhcmdzLnhjb2RlU2lnbmluZ0lkLFxuICAgICAgICBrZXljaGFpblBhdGg6IGFyZ3Mua2V5Y2hhaW5QYXRoLFxuICAgICAgICBrZXljaGFpblBhc3N3b3JkOiBhcmdzLmtleWNoYWluUGFzc3dvcmQsXG4gICAgICAgIHVzZVNpbXBsZUJ1aWxkVGVzdDogYXJncy51c2VTaW1wbGVCdWlsZFRlc3QsXG4gICAgICAgIHVzZVByZWJ1aWx0V0RBOiBhcmdzLnVzZVByZWJ1aWx0V0RBLFxuICAgICAgICB1cGRhdGVkV0RBQnVuZGxlSWQ6IHRoaXMudXBkYXRlZFdEQUJ1bmRsZUlkLFxuICAgICAgICBsYXVuY2hUaW1lb3V0OiBhcmdzLndkYUxhdW5jaFRpbWVvdXQgfHwgV0RBX0xBVU5DSF9USU1FT1VULFxuICAgICAgICB3ZGFSZW1vdGVQb3J0OiB0aGlzLndkYVJlbW90ZVBvcnQsXG4gICAgICAgIHVzZVhjdGVzdHJ1bkZpbGU6IHRoaXMudXNlWGN0ZXN0cnVuRmlsZSxcbiAgICAgICAgZGVyaXZlZERhdGFQYXRoOiBhcmdzLmRlcml2ZWREYXRhUGF0aCxcbiAgICAgICAgbWpwZWdTZXJ2ZXJQb3J0OiB0aGlzLm1qcGVnU2VydmVyUG9ydCxcbiAgICAgICAgYWxsb3dQcm92aXNpb25pbmdEZXZpY2VSZWdpc3RyYXRpb246IGFyZ3MuYWxsb3dQcm92aXNpb25pbmdEZXZpY2VSZWdpc3RyYXRpb24sXG4gICAgICAgIHJlc3VsdEJ1bmRsZVBhdGg6IGFyZ3MucmVzdWx0QnVuZGxlUGF0aCxcbiAgICAgICAgcmVzdWx0QnVuZGxlVmVyc2lvbjogYXJncy5yZXN1bHRCdW5kbGVWZXJzaW9uLFxuICAgICAgfSwgdGhpcy5sb2cpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiB0cnVlIGlmIHRoZSBzZXNzaW9uIGRvZXMgbm90IG5lZWQgeGNvZGVidWlsZC5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IFdoZXRoZXIgdGhlIHNlc3Npb24gbmVlZHMvaGFzIHhjb2RlYnVpbGQuXG4gICAqL1xuICBnZXQgY2FuU2tpcFhjb2RlYnVpbGQgKCkge1xuICAgIC8vIFVzZSB0aGlzLmFyZ3Mud2ViRHJpdmVyQWdlbnRVcmwgdG8gZ3VhcmFudGVlXG4gICAgLy8gdGhlIGNhcGFiaWxpdGllcyBzZXQgZ2F2ZSB0aGUgYGFwcGl1bTp3ZWJEcml2ZXJBZ2VudFVybGAuXG4gICAgcmV0dXJuIHRoaXMudXNlUHJlaW5zdGFsbGVkV0RBIHx8IHRoaXMuYXJncy53ZWJEcml2ZXJBZ2VudFVybDtcbiAgfVxuXG4gIC8qKlxuICAgKlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSBCdW5kbGUgSUQgZm9yIFhjdGVzdC5cbiAgICovXG4gIGdldCBidW5kbGVJZEZvclhjdGVzdCAoKSB7XG4gICAgcmV0dXJuIHRoaXMudXBkYXRlZFdEQUJ1bmRsZUlkID8gYCR7dGhpcy51cGRhdGVkV0RBQnVuZGxlSWR9LnhjdHJ1bm5lcmAgOiBXREFfUlVOTkVSX0JVTkRMRV9JRF9GT1JfWENURVNUO1xuICB9XG5cbiAgc2V0V0RBUGF0aHMgKGJvb3RzdHJhcFBhdGgsIGFnZW50UGF0aCkge1xuICAgIC8vIGFsbG93IHRoZSB1c2VyIHRvIHNwZWNpZnkgYSBwbGFjZSBmb3IgV0RBLiBUaGlzIGlzIHVuZG9jdW1lbnRlZCBhbmRcbiAgICAvLyBvbmx5IGhlcmUgZm9yIHRoZSBwdXJwb3NlcyBvZiB0ZXN0aW5nIGRldmVsb3BtZW50IG9mIFdEQVxuICAgIHRoaXMuYm9vdHN0cmFwUGF0aCA9IGJvb3RzdHJhcFBhdGggfHwgQk9PVFNUUkFQX1BBVEg7XG4gICAgdGhpcy5sb2cuaW5mbyhgVXNpbmcgV0RBIHBhdGg6ICcke3RoaXMuYm9vdHN0cmFwUGF0aH0nYCk7XG5cbiAgICAvLyBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eSB3ZSBuZWVkIHRvIGJlIGFibGUgdG8gc3BlY2lmeSBhZ2VudFBhdGggdG9vXG4gICAgdGhpcy5hZ2VudFBhdGggPSBhZ2VudFBhdGggfHwgcGF0aC5yZXNvbHZlKHRoaXMuYm9vdHN0cmFwUGF0aCwgJ1dlYkRyaXZlckFnZW50Lnhjb2RlcHJvaicpO1xuICAgIHRoaXMubG9nLmluZm8oYFVzaW5nIFdEQSBhZ2VudDogJyR7dGhpcy5hZ2VudFBhdGh9J2ApO1xuICB9XG5cbiAgYXN5bmMgY2xlYW51cE9ic29sZXRlUHJvY2Vzc2VzICgpIHtcbiAgICBjb25zdCBvYnNvbGV0ZVBpZHMgPSBhd2FpdCBnZXRQSURzTGlzdGVuaW5nT25Qb3J0KHRoaXMudXJsLnBvcnQsXG4gICAgICAoY21kTGluZSkgPT4gY21kTGluZS5pbmNsdWRlcygnL1dlYkRyaXZlckFnZW50UnVubmVyJykgJiZcbiAgICAgICAgIWNtZExpbmUudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyh0aGlzLmRldmljZS51ZGlkLnRvTG93ZXJDYXNlKCkpKTtcblxuICAgIGlmIChfLmlzRW1wdHkob2Jzb2xldGVQaWRzKSkge1xuICAgICAgdGhpcy5sb2cuZGVidWcoYE5vIG9ic29sZXRlIGNhY2hlZCBwcm9jZXNzZXMgZnJvbSBwcmV2aW91cyBXREEgc2Vzc2lvbnMgYCArXG4gICAgICAgIGBsaXN0ZW5pbmcgb24gcG9ydCAke3RoaXMudXJsLnBvcnR9IGhhdmUgYmVlbiBmb3VuZGApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMubG9nLmluZm8oYERldGVjdGVkICR7b2Jzb2xldGVQaWRzLmxlbmd0aH0gb2Jzb2xldGUgY2FjaGVkIHByb2Nlc3Mke29ic29sZXRlUGlkcy5sZW5ndGggPT09IDEgPyAnJyA6ICdlcyd9IGAgK1xuICAgICAgYGZyb20gcHJldmlvdXMgV0RBIHNlc3Npb25zLiBDbGVhbmluZyB0aGVtIHVwYCk7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGV4ZWMoJ2tpbGwnLCBvYnNvbGV0ZVBpZHMpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRoaXMubG9nLndhcm4oYEZhaWxlZCB0byBraWxsIG9ic29sZXRlIGNhY2hlZCBwcm9jZXNzJHtvYnNvbGV0ZVBpZHMubGVuZ3RoID09PSAxID8gJycgOiAnZXMnfSAnJHtvYnNvbGV0ZVBpZHN9Jy4gYCArXG4gICAgICAgIGBPcmlnaW5hbCBlcnJvcjogJHtlLm1lc3NhZ2V9YCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBib29sZWFuIGlmIFdEQSBpcyBydW5uaW5nIG9yIG5vdFxuICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIFdEQSBpcyBydW5uaW5nXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGVyZSB3YXMgaW52YWxpZCByZXNwb25zZSBjb2RlIG9yIGJvZHlcbiAgICovXG4gIGFzeW5jIGlzUnVubmluZyAoKSB7XG4gICAgcmV0dXJuICEhKGF3YWl0IHRoaXMuZ2V0U3RhdHVzKCkpO1xuICB9XG5cbiAgZ2V0IGJhc2VQYXRoICgpIHtcbiAgICBpZiAodGhpcy51cmwucGF0aCA9PT0gJy8nKSB7XG4gICAgICByZXR1cm4gJyc7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnVybC5wYXRoIHx8ICcnO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBjdXJyZW50IHJ1bm5pbmcgV0RBJ3Mgc3RhdHVzIGxpa2UgYmVsb3dcbiAgICoge1xuICAgKiAgIFwic3RhdGVcIjogXCJzdWNjZXNzXCIsXG4gICAqICAgXCJvc1wiOiB7XG4gICAqICAgICBcIm5hbWVcIjogXCJpT1NcIixcbiAgICogICAgIFwidmVyc2lvblwiOiBcIjExLjRcIixcbiAgICogICAgIFwic2RrVmVyc2lvblwiOiBcIjExLjNcIlxuICAgKiAgIH0sXG4gICAqICAgXCJpb3NcIjoge1xuICAgKiAgICAgXCJzaW11bGF0b3JWZXJzaW9uXCI6IFwiMTEuNFwiLFxuICAgKiAgICAgXCJpcFwiOiBcIjE3Mi4yNTQuOTkuMzRcIlxuICAgKiAgIH0sXG4gICAqICAgXCJidWlsZFwiOiB7XG4gICAqICAgICBcInRpbWVcIjogXCJKdW4gMjQgMjAxOCAxNzowODoyMVwiLFxuICAgKiAgICAgXCJwcm9kdWN0QnVuZGxlSWRlbnRpZmllclwiOiBcImNvbS5mYWNlYm9vay5XZWJEcml2ZXJBZ2VudFJ1bm5lclwiXG4gICAqICAgfVxuICAgKiB9XG4gICAqXG4gICAqIEByZXR1cm4gez9vYmplY3R9IFN0YXRlIE9iamVjdFxuICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlcmUgd2FzIGludmFsaWQgcmVzcG9uc2UgY29kZSBvciBib2R5XG4gICAqL1xuICBhc3luYyBnZXRTdGF0dXMgKCkge1xuICAgIGNvbnN0IG5vU2Vzc2lvblByb3h5ID0gbmV3IE5vU2Vzc2lvblByb3h5KHtcbiAgICAgIHNlcnZlcjogdGhpcy51cmwuaG9zdG5hbWUsXG4gICAgICBwb3J0OiB0aGlzLnVybC5wb3J0LFxuICAgICAgYmFzZTogdGhpcy5iYXNlUGF0aCxcbiAgICAgIHRpbWVvdXQ6IDMwMDAsXG4gICAgfSk7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCBub1Nlc3Npb25Qcm94eS5jb21tYW5kKCcvc3RhdHVzJywgJ0dFVCcpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgdGhpcy5sb2cuZGVidWcoYFdEQSBpcyBub3QgbGlzdGVuaW5nIGF0ICcke3RoaXMudXJsLmhyZWZ9J2ApO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFVuaW5zdGFsbCBXREFzIGZyb20gdGhlIHRlc3QgZGV2aWNlLlxuICAgKiBPdmVyIFhjb2RlIDExLCBtdWx0aXBsZSBXREEgY2FuIGJlIGluIHRoZSBkZXZpY2Ugc2luY2UgWGNvZGUgMTEgZ2VuZXJhdGVzIGRpZmZlcmVudCBXREEuXG4gICAqIEFwcGl1bSBkb2VzIG5vdCBleHBlY3QgbXVsdGlwbGUgV0RBcyBhcmUgcnVubmluZyBvbiBhIGRldmljZS5cbiAgICovXG4gIGFzeW5jIHVuaW5zdGFsbCAoKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGJ1bmRsZUlkcyA9IGF3YWl0IHRoaXMuZGV2aWNlLmdldFVzZXJJbnN0YWxsZWRCdW5kbGVJZHNCeUJ1bmRsZU5hbWUoV0RBX0NGX0JVTkRMRV9OQU1FKTtcbiAgICAgIGlmIChfLmlzRW1wdHkoYnVuZGxlSWRzKSkge1xuICAgICAgICB0aGlzLmxvZy5kZWJ1ZygnTm8gV0RBcyBvbiB0aGUgZGV2aWNlLicpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMubG9nLmRlYnVnKGBVbmluc3RhbGxpbmcgV0RBczogJyR7YnVuZGxlSWRzfSdgKTtcbiAgICAgIGZvciAoY29uc3QgYnVuZGxlSWQgb2YgYnVuZGxlSWRzKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuZGV2aWNlLnJlbW92ZUFwcChidW5kbGVJZCk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhpcy5sb2cuZGVidWcoZSk7XG4gICAgICB0aGlzLmxvZy53YXJuKGBXZWJEcml2ZXJBZ2VudCB1bmluc3RhbGwgZmFpbGVkLiBQZXJoYXBzLCBpdCBpcyBhbHJlYWR5IHVuaW5zdGFsbGVkPyBgICtcbiAgICAgICAgYE9yaWdpbmFsIGVycm9yOiAke2UubWVzc2FnZX1gKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBfY2xlYW51cFByb2plY3RJZkZyZXNoICgpIHtcbiAgICBpZiAodGhpcy5jYW5Ta2lwWGNvZGVidWlsZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHBhY2thZ2VJbmZvID0gSlNPTi5wYXJzZShhd2FpdCBmcy5yZWFkRmlsZShwYXRoLmpvaW4oQk9PVFNUUkFQX1BBVEgsICdwYWNrYWdlLmpzb24nKSwgJ3V0ZjgnKSk7XG4gICAgY29uc3QgYm94ID0gc3Ryb25nYm94KHBhY2thZ2VJbmZvLm5hbWUpO1xuICAgIGxldCBib3hJdGVtID0gYm94LmdldEl0ZW0oUkVDRU5UX01PRFVMRV9WRVJTSU9OX0lURU1fTkFNRSk7XG4gICAgaWYgKCFib3hJdGVtKSB7XG4gICAgICBjb25zdCB0aW1lc3RhbXBQYXRoID0gcGF0aC5yZXNvbHZlKHByb2Nlc3MuZW52LkhPTUUsIFdEQV9VUEdSQURFX1RJTUVTVEFNUF9QQVRIKTtcbiAgICAgIGlmIChhd2FpdCBmcy5leGlzdHModGltZXN0YW1wUGF0aCkpIHtcbiAgICAgICAgLy8gVE9ETzogSXQgaXMgcHJvYmFibHkgYSBiaXQgdWdseSB0byBoYXJkY29kZSB0aGUgcmVjZW50IHZlcnNpb24gc3RyaW5nLFxuICAgICAgICAvLyBUT0RPOiBob3Zld2VyIGl0IHNob3VsZCBkbyB0aGUgam9iIGFzIGEgdGVtcG9yYXJ5IHRyYW5zaXRpb24gdHJpY2tcbiAgICAgICAgLy8gVE9ETzogdG8gc3dpdGNoIGZyb20gYSBoYXJkY29kZWQgZmlsZSBwYXRoIHRvIHRoZSBzdHJvbmdib3ggdXNhZ2UuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYm94SXRlbSA9IGF3YWl0IGJveC5jcmVhdGVJdGVtV2l0aFZhbHVlKFJFQ0VOVF9NT0RVTEVfVkVSU0lPTl9JVEVNX05BTUUsICc1LjAuMCcpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgdGhpcy5sb2cud2FybihgVGhlIGFjdHVhbCBtb2R1bGUgdmVyc2lvbiBjYW5ub3QgYmUgcGVyc2lzdGVkOiAke2UubWVzc2FnZX1gKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMubG9nLmluZm8oJ1RoZXJlIGlzIG5vIG5lZWQgdG8gcGVyZm9ybSB0aGUgcHJvamVjdCBjbGVhbnVwLiBBIGZyZXNoIGluc3RhbGwgaGFzIGJlZW4gZGV0ZWN0ZWQnKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBhd2FpdCBib3guY3JlYXRlSXRlbVdpdGhWYWx1ZShSRUNFTlRfTU9EVUxFX1ZFUlNJT05fSVRFTV9OQU1FLCBwYWNrYWdlSW5mby52ZXJzaW9uKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgIHRoaXMubG9nLndhcm4oYFRoZSBhY3R1YWwgbW9kdWxlIHZlcnNpb24gY2Fubm90IGJlIHBlcnNpc3RlZDogJHtlLm1lc3NhZ2V9YCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cblxuICAgIGxldCByZWNlbnRNb2R1bGVWZXJzaW9uID0gYXdhaXQgYm94SXRlbS5yZWFkKCk7XG4gICAgdHJ5IHtcbiAgICAgIHJlY2VudE1vZHVsZVZlcnNpb24gPSB1dGlsLmNvZXJjZVZlcnNpb24ocmVjZW50TW9kdWxlVmVyc2lvbiwgdHJ1ZSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhpcy5sb2cud2FybihgVGhlIHBlcnNpc3RlZCBtb2R1bGUgdmVyc2lvbiBzdHJpbmcgaGFzIGJlZW4gZGFtYWdlZDogJHtlLm1lc3NhZ2V9YCk7XG4gICAgICB0aGlzLmxvZy5pbmZvKGBVcGRhdGluZyBpdCB0byAnJHtwYWNrYWdlSW5mby52ZXJzaW9ufScgYXNzdW1pbmcgdGhlIHByb2plY3QgY2xlbnVwIGlzIG5vdCBuZWVkZWRgKTtcbiAgICAgIGF3YWl0IGJveEl0ZW0ud3JpdGUocGFja2FnZUluZm8udmVyc2lvbik7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHV0aWwuY29tcGFyZVZlcnNpb25zKHJlY2VudE1vZHVsZVZlcnNpb24sICc+PScsIHBhY2thZ2VJbmZvLnZlcnNpb24pKSB7XG4gICAgICB0aGlzLmxvZy5pbmZvKFxuICAgICAgICBgV2ViRHJpdmVyQWdlbnQgZG9lcyBub3QgbmVlZCBhIGNsZWFudXAuIFRoZSBwcm9qZWN0IHNvdXJjZXMgYXJlIHVwIHRvIGRhdGUgYCArXG4gICAgICAgIGAoJHtyZWNlbnRNb2R1bGVWZXJzaW9ufSA+PSAke3BhY2thZ2VJbmZvLnZlcnNpb259KWBcbiAgICAgICk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5sb2cuaW5mbyhcbiAgICAgIGBDbGVhbmluZyB1cCB0aGUgV2ViRHJpdmVyQWdlbnQgcHJvamVjdCBhZnRlciB0aGUgbW9kdWxlIHVwZ3JhZGUgaGFzIGhhcHBlbmVkIGAgK1xuICAgICAgYCgke3JlY2VudE1vZHVsZVZlcnNpb259IDwgJHtwYWNrYWdlSW5mby52ZXJzaW9ufSlgXG4gICAgKTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy54Y29kZWJ1aWxkLmNsZWFuUHJvamVjdCgpO1xuICAgICAgYXdhaXQgYm94SXRlbS53cml0ZShwYWNrYWdlSW5mby52ZXJzaW9uKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aGlzLmxvZy53YXJuKGBDYW5ub3QgcGVyZm9ybSBXZWJEcml2ZXJBZ2VudCBwcm9qZWN0IGNsZWFudXAuIE9yaWdpbmFsIGVycm9yOiAke2UubWVzc2FnZX1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTGF1bmNoIFdEQSB3aXRoIHByZWluc3RhbGxlZCBwYWNrYWdlIHdpdGhvdXQgeGNvZGVidWlsZC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHNlc3Npb25JZCBMYXVuY2ggV0RBIGFuZCBlc3RhYmxpc2ggdGhlIHNlc3Npb24gd2l0aCB0aGlzIHNlc3Npb25JZFxuICAgKiBAcmV0dXJuIHs/b2JqZWN0fSBTdGF0ZSBPYmplY3RcbiAgICovXG4gIGFzeW5jIGxhdW5jaFdpdGhQcmVpbnN0YWxsZWRXREEoc2Vzc2lvbklkKSB7XG4gICAgY29uc3QgeGN0ZXN0RW52ID0ge1xuICAgICAgVVNFX1BPUlQ6IHRoaXMud2RhTG9jYWxQb3J0IHx8IFdEQV9BR0VOVF9QT1JULFxuICAgICAgV0RBX1BST0RVQ1RfQlVORExFX0lERU5USUZJRVI6IHRoaXMuYnVuZGxlSWRGb3JYY3Rlc3RcbiAgICB9O1xuICAgIGlmICh0aGlzLm1qcGVnU2VydmVyUG9ydCkge1xuICAgICAgeGN0ZXN0RW52Lk1KUEVHX1NFUlZFUl9QT1JUID0gdGhpcy5tanBlZ1NlcnZlclBvcnQ7XG4gICAgfVxuICAgIHRoaXMubG9nLmluZm8oJ0xhdW5jaGluZyBXZWJEcml2ZXJBZ2VudCBvbiB0aGUgZGV2aWNlIHdpdGhvdXQgeGNvZGVidWlsZCcpO1xuICAgIHRoaXMueGN0ZXN0QXBpQ2xpZW50ID0gbmV3IFhjdGVzdCh0aGlzLmRldmljZS51ZGlkLCB0aGlzLmJ1bmRsZUlkRm9yWGN0ZXN0LCBudWxsLCB7ZW52OiB4Y3Rlc3RFbnZ9KTtcblxuICAgIGF3YWl0IHRoaXMueGN0ZXN0QXBpQ2xpZW50LnN0YXJ0KCk7XG5cbiAgICB0aGlzLnNldHVwUHJveGllcyhzZXNzaW9uSWQpO1xuICAgIGNvbnN0IHN0YXR1cyA9IGF3YWl0IHRoaXMuZ2V0U3RhdHVzKCk7XG4gICAgdGhpcy5zdGFydGVkID0gdHJ1ZTtcbiAgICByZXR1cm4gc3RhdHVzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBjdXJyZW50IHJ1bm5pbmcgV0RBJ3Mgc3RhdHVzIGxpa2UgYmVsb3cgYWZ0ZXIgbGF1bmNoaW5nIFdEQVxuICAgKiB7XG4gICAqICAgXCJzdGF0ZVwiOiBcInN1Y2Nlc3NcIixcbiAgICogICBcIm9zXCI6IHtcbiAgICogICAgIFwibmFtZVwiOiBcImlPU1wiLFxuICAgKiAgICAgXCJ2ZXJzaW9uXCI6IFwiMTEuNFwiLFxuICAgKiAgICAgXCJzZGtWZXJzaW9uXCI6IFwiMTEuM1wiXG4gICAqICAgfSxcbiAgICogICBcImlvc1wiOiB7XG4gICAqICAgICBcInNpbXVsYXRvclZlcnNpb25cIjogXCIxMS40XCIsXG4gICAqICAgICBcImlwXCI6IFwiMTcyLjI1NC45OS4zNFwiXG4gICAqICAgfSxcbiAgICogICBcImJ1aWxkXCI6IHtcbiAgICogICAgIFwidGltZVwiOiBcIkp1biAyNCAyMDE4IDE3OjA4OjIxXCIsXG4gICAqICAgICBcInByb2R1Y3RCdW5kbGVJZGVudGlmaWVyXCI6IFwiY29tLmZhY2Vib29rLldlYkRyaXZlckFnZW50UnVubmVyXCJcbiAgICogICB9XG4gICAqIH1cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNlc3Npb25JZCBMYXVuY2ggV0RBIGFuZCBlc3RhYmxpc2ggdGhlIHNlc3Npb24gd2l0aCB0aGlzIHNlc3Npb25JZFxuICAgKiBAcmV0dXJuIHs/b2JqZWN0fSBTdGF0ZSBPYmplY3RcbiAgICogQHRocm93cyB7RXJyb3J9IElmIHRoZXJlIHdhcyBpbnZhbGlkIHJlc3BvbnNlIGNvZGUgb3IgYm9keVxuICAgKi9cbiAgYXN5bmMgbGF1bmNoIChzZXNzaW9uSWQpIHtcbiAgICBpZiAodGhpcy53ZWJEcml2ZXJBZ2VudFVybCkge1xuICAgICAgdGhpcy5sb2cuaW5mbyhgVXNpbmcgcHJvdmlkZWQgV2ViZHJpdmVyQWdlbnQgYXQgJyR7dGhpcy53ZWJEcml2ZXJBZ2VudFVybH0nYCk7XG4gICAgICB0aGlzLnVybCA9IHRoaXMud2ViRHJpdmVyQWdlbnRVcmw7XG4gICAgICB0aGlzLnNldHVwUHJveGllcyhzZXNzaW9uSWQpO1xuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuZ2V0U3RhdHVzKCk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMudXNlUHJlaW5zdGFsbGVkV0RBKSB7XG4gICAgICBpZiAodGhpcy5pc1JlYWxEZXZpY2UpIHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMubGF1bmNoV2l0aFByZWluc3RhbGxlZFdEQShzZXNzaW9uSWQpO1xuICAgICAgfVxuICAgICAgdGhyb3cgbmV3IEVycm9yKCd1c2VQcmVpbnN0YWxsZWRXREEgaXMgYXZhaWxhYmxlIG9ubHkgZm9yIGEgcmVhbCBkZXZpY2UuJyk7XG4gICAgfVxuXG4gICAgdGhpcy5sb2cuaW5mbygnTGF1bmNoaW5nIFdlYkRyaXZlckFnZW50IG9uIHRoZSBkZXZpY2UnKTtcblxuICAgIHRoaXMuc2V0dXBQcm94aWVzKHNlc3Npb25JZCk7XG5cbiAgICBpZiAoIXRoaXMudXNlWGN0ZXN0cnVuRmlsZSAmJiAhYXdhaXQgZnMuZXhpc3RzKHRoaXMuYWdlbnRQYXRoKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBUcnlpbmcgdG8gdXNlIFdlYkRyaXZlckFnZW50IHByb2plY3QgYXQgJyR7dGhpcy5hZ2VudFBhdGh9JyBidXQgdGhlIGAgK1xuICAgICAgICAgICAgICAgICAgICAgICdmaWxlIGRvZXMgbm90IGV4aXN0Jyk7XG4gICAgfVxuXG4gICAgLy8gdXNlWGN0ZXN0cnVuRmlsZSBhbmQgdXNlUHJlYnVpbHRXREEgdXNlIGV4aXN0aW5nIGRlcGVuZGVuY2llc1xuICAgIC8vIEl0IGRlcGVuZHMgb24gdXNlciBzaWRlXG4gICAgaWYgKHRoaXMuaWRiIHx8IHRoaXMudXNlWGN0ZXN0cnVuRmlsZSB8fCAodGhpcy5kZXJpdmVkRGF0YVBhdGggJiYgdGhpcy51c2VQcmVidWlsdFdEQSkpIHtcbiAgICAgIHRoaXMubG9nLmluZm8oJ1NraXBwZWQgV0RBIHByb2plY3QgY2xlYW51cCBhY2NvcmRpbmcgdG8gdGhlIHByb3ZpZGVkIGNhcGFiaWxpdGllcycpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBzeW5jaHJvbml6YXRpb25LZXkgPSBwYXRoLm5vcm1hbGl6ZSh0aGlzLmJvb3RzdHJhcFBhdGgpO1xuICAgICAgYXdhaXQgU0hBUkVEX1JFU09VUkNFU19HVUFSRC5hY3F1aXJlKHN5bmNocm9uaXphdGlvbktleSxcbiAgICAgICAgYXN5bmMgKCkgPT4gYXdhaXQgdGhpcy5fY2xlYW51cFByb2plY3RJZkZyZXNoKCkpO1xuICAgIH1cblxuICAgIC8vIFdlIG5lZWQgdG8gcHJvdmlkZSBXREEgbG9jYWwgcG9ydCwgYmVjYXVzZSBpdCBtaWdodCBiZSBvY2N1cGllZFxuICAgIGF3YWl0IHJlc2V0VGVzdFByb2Nlc3Nlcyh0aGlzLmRldmljZS51ZGlkLCAhdGhpcy5pc1JlYWxEZXZpY2UpO1xuXG4gICAgaWYgKHRoaXMuaWRiKSB7XG4gICAgICByZXR1cm4gYXdhaXQgdGhpcy5zdGFydFdpdGhJREIoKTtcbiAgICB9XG5cbiAgICBhd2FpdCB0aGlzLnhjb2RlYnVpbGQuaW5pdCh0aGlzLm5vU2Vzc2lvblByb3h5KTtcblxuICAgIC8vIFN0YXJ0IHRoZSB4Y29kZWJ1aWxkIHByb2Nlc3NcbiAgICBpZiAodGhpcy5wcmVidWlsZFdEQSkge1xuICAgICAgYXdhaXQgdGhpcy54Y29kZWJ1aWxkLnByZWJ1aWxkKCk7XG4gICAgfVxuICAgIHJldHVybiBhd2FpdCB0aGlzLnhjb2RlYnVpbGQuc3RhcnQoKTtcbiAgfVxuXG4gIGFzeW5jIHN0YXJ0V2l0aElEQiAoKSB7XG4gICAgdGhpcy5sb2cuaW5mbygnV2lsbCBsYXVuY2ggV0RBIHdpdGggaWRiIGluc3RlYWQgb2YgeGNvZGVidWlsZCBzaW5jZSB0aGUgY29ycmVzcG9uZGluZyBmbGFnIGlzIGVuYWJsZWQnKTtcbiAgICBjb25zdCB7d2RhQnVuZGxlSWQsIHRlc3RCdW5kbGVJZH0gPSBhd2FpdCB0aGlzLnByZXBhcmVXREEoKTtcbiAgICBjb25zdCBlbnYgPSB7XG4gICAgICBVU0VfUE9SVDogdGhpcy53ZGFSZW1vdGVQb3J0LFxuICAgICAgV0RBX1BST0RVQ1RfQlVORExFX0lERU5USUZJRVI6IHRoaXMudXBkYXRlZFdEQUJ1bmRsZUlkLFxuICAgIH07XG4gICAgaWYgKHRoaXMubWpwZWdTZXJ2ZXJQb3J0KSB7XG4gICAgICBlbnYuTUpQRUdfU0VSVkVSX1BPUlQgPSB0aGlzLm1qcGVnU2VydmVyUG9ydDtcbiAgICB9XG5cbiAgICByZXR1cm4gYXdhaXQgdGhpcy5pZGIucnVuWENVSVRlc3Qod2RhQnVuZGxlSWQsIHdkYUJ1bmRsZUlkLCB0ZXN0QnVuZGxlSWQsIHtlbnZ9KTtcbiAgfVxuXG4gIGFzeW5jIHBhcnNlQnVuZGxlSWQgKHdkYUJ1bmRsZVBhdGgpIHtcbiAgICBjb25zdCBpbmZvUGxpc3RQYXRoID0gcGF0aC5qb2luKHdkYUJ1bmRsZVBhdGgsICdJbmZvLnBsaXN0Jyk7XG4gICAgY29uc3QgaW5mb1BsaXN0ID0gYXdhaXQgcGxpc3QucGFyc2VQbGlzdChhd2FpdCBmcy5yZWFkRmlsZShpbmZvUGxpc3RQYXRoKSk7XG4gICAgaWYgKCFpbmZvUGxpc3QuQ0ZCdW5kbGVJZGVudGlmaWVyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENvdWxkIG5vdCBmaW5kIGJ1bmRsZSBpZCBpbiAnJHtpbmZvUGxpc3RQYXRofSdgKTtcbiAgICB9XG4gICAgcmV0dXJuIGluZm9QbGlzdC5DRkJ1bmRsZUlkZW50aWZpZXI7XG4gIH1cblxuICBhc3luYyBwcmVwYXJlV0RBICgpIHtcbiAgICBjb25zdCB3ZGFCdW5kbGVQYXRoID0gdGhpcy53ZGFCdW5kbGVQYXRoIHx8IGF3YWl0IHRoaXMuZmV0Y2hXREFCdW5kbGUoKTtcbiAgICBjb25zdCB3ZGFCdW5kbGVJZCA9IGF3YWl0IHRoaXMucGFyc2VCdW5kbGVJZCh3ZGFCdW5kbGVQYXRoKTtcbiAgICBpZiAoIWF3YWl0IHRoaXMuZGV2aWNlLmlzQXBwSW5zdGFsbGVkKHdkYUJ1bmRsZUlkKSkge1xuICAgICAgYXdhaXQgdGhpcy5kZXZpY2UuaW5zdGFsbEFwcCh3ZGFCdW5kbGVQYXRoKTtcbiAgICB9XG4gICAgY29uc3QgdGVzdEJ1bmRsZUlkID0gYXdhaXQgdGhpcy5pZGIuaW5zdGFsbFhDVGVzdEJ1bmRsZShwYXRoLmpvaW4od2RhQnVuZGxlUGF0aCwgJ1BsdWdJbnMnLCAnV2ViRHJpdmVyQWdlbnRSdW5uZXIueGN0ZXN0JykpO1xuICAgIHJldHVybiB7d2RhQnVuZGxlSWQsIHRlc3RCdW5kbGVJZCwgd2RhQnVuZGxlUGF0aH07XG4gIH1cblxuICBhc3luYyBmZXRjaFdEQUJ1bmRsZSAoKSB7XG4gICAgaWYgKCF0aGlzLmRlcml2ZWREYXRhUGF0aCkge1xuICAgICAgcmV0dXJuIGF3YWl0IGJ1bmRsZVdEQVNpbSh0aGlzLnhjb2RlYnVpbGQpO1xuICAgIH1cbiAgICBjb25zdCB3ZGFCdW5kbGVQYXRocyA9IGF3YWl0IGZzLmdsb2IoYCR7dGhpcy5kZXJpdmVkRGF0YVBhdGh9LyoqLyoke1dEQV9SVU5ORVJfQVBQfS9gLCB7XG4gICAgICBhYnNvbHV0ZTogdHJ1ZSxcbiAgICB9KTtcbiAgICBpZiAoXy5pc0VtcHR5KHdkYUJ1bmRsZVBhdGhzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBDb3VsZCBub3QgZmluZCB0aGUgV0RBIGJ1bmRsZSBpbiAnJHt0aGlzLmRlcml2ZWREYXRhUGF0aH0nYCk7XG4gICAgfVxuICAgIHJldHVybiB3ZGFCdW5kbGVQYXRoc1swXTtcbiAgfVxuXG4gIGFzeW5jIGlzU291cmNlRnJlc2ggKCkge1xuICAgIGNvbnN0IGV4aXN0c1Byb21pc2VzID0gW1xuICAgICAgJ1Jlc291cmNlcycsXG4gICAgICBgUmVzb3VyY2VzJHtwYXRoLnNlcH1XZWJEcml2ZXJBZ2VudC5idW5kbGVgLFxuICAgIF0ubWFwKChzdWJQYXRoKSA9PiBmcy5leGlzdHMocGF0aC5yZXNvbHZlKHRoaXMuYm9vdHN0cmFwUGF0aCwgc3ViUGF0aCkpKTtcbiAgICByZXR1cm4gKGF3YWl0IEIuYWxsKGV4aXN0c1Byb21pc2VzKSkuc29tZSgodikgPT4gdiA9PT0gZmFsc2UpO1xuICB9XG5cbiAgc2V0dXBQcm94aWVzIChzZXNzaW9uSWQpIHtcbiAgICBjb25zdCBwcm94eU9wdHMgPSB7XG4gICAgICBsb2c6IHRoaXMubG9nLFxuICAgICAgc2VydmVyOiB0aGlzLnVybC5ob3N0bmFtZSxcbiAgICAgIHBvcnQ6IHRoaXMudXJsLnBvcnQsXG4gICAgICBiYXNlOiB0aGlzLmJhc2VQYXRoLFxuICAgICAgdGltZW91dDogdGhpcy53ZGFDb25uZWN0aW9uVGltZW91dCxcbiAgICAgIGtlZXBBbGl2ZTogdHJ1ZSxcbiAgICB9O1xuXG4gICAgdGhpcy5qd3Byb3h5ID0gbmV3IEpXUHJveHkocHJveHlPcHRzKTtcbiAgICB0aGlzLmp3cHJveHkuc2Vzc2lvbklkID0gc2Vzc2lvbklkO1xuICAgIHRoaXMucHJveHlSZXFSZXMgPSB0aGlzLmp3cHJveHkucHJveHlSZXFSZXMuYmluZCh0aGlzLmp3cHJveHkpO1xuXG4gICAgdGhpcy5ub1Nlc3Npb25Qcm94eSA9IG5ldyBOb1Nlc3Npb25Qcm94eShwcm94eU9wdHMpO1xuICB9XG5cbiAgYXN5bmMgcXVpdCAoKSB7XG4gICAgaWYgKHRoaXMudXNlUHJlaW5zdGFsbGVkV0RBKSB7XG4gICAgICBpZiAodGhpcy54Y3Rlc3RBcGlDbGllbnQpIHtcbiAgICAgICAgdGhpcy5sb2cuaW5mbygnU3RvcHBpbmcgdGhlIFhDVGVzdCBzZXNzaW9uJyk7XG4gICAgICAgIHRoaXMueGN0ZXN0QXBpQ2xpZW50LnN0b3AoKTtcbiAgICAgICAgdGhpcy54Y3Rlc3RBcGlDbGllbnQgPSBudWxsO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoIXRoaXMuYXJncy53ZWJEcml2ZXJBZ2VudFVybCkge1xuICAgICAgdGhpcy5sb2cuaW5mbygnU2h1dHRpbmcgZG93biBzdWItcHJvY2Vzc2VzJyk7XG4gICAgICBhd2FpdCB0aGlzLnhjb2RlYnVpbGQucXVpdCgpO1xuICAgICAgYXdhaXQgdGhpcy54Y29kZWJ1aWxkLnJlc2V0KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMubG9nLmRlYnVnKCdEbyBub3Qgc3RvcCB4Y29kZWJ1aWxkIG5vciBYQ1Rlc3Qgc2Vzc2lvbiAnICtcbiAgICAgICAgJ3NpbmNlIHRoZSBXREEgc2Vzc2lvbiBpcyBtYW5hZ2VkIGJ5IG91dHNpZGUgdGhpcyBkcml2ZXIuJyk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuandwcm94eSkge1xuICAgICAgdGhpcy5qd3Byb3h5LnNlc3Npb25JZCA9IG51bGw7XG4gICAgfVxuXG4gICAgdGhpcy5zdGFydGVkID0gZmFsc2U7XG5cbiAgICBpZiAoIXRoaXMuYXJncy53ZWJEcml2ZXJBZ2VudFVybCkge1xuICAgICAgLy8gaWYgd2UgcG9wdWxhdGVkIHRoZSB1cmwgb3Vyc2VsdmVzIChkdXJpbmcgYHNldHVwQ2FjaGluZ2AgY2FsbCwgZm9yIGluc3RhbmNlKVxuICAgICAgLy8gdGhlbiBjbGVhbiB0aGF0IHVwLiBJZiB0aGUgdXJsIHdhcyBzdXBwbGllZCwgd2Ugd2FudCB0byBrZWVwIGl0XG4gICAgICB0aGlzLndlYkRyaXZlckFnZW50VXJsID0gbnVsbDtcbiAgICB9XG4gIH1cblxuICBnZXQgdXJsICgpIHtcbiAgICBpZiAoIXRoaXMuX3VybCkge1xuICAgICAgaWYgKHRoaXMud2ViRHJpdmVyQWdlbnRVcmwpIHtcbiAgICAgICAgdGhpcy5fdXJsID0gdXJsLnBhcnNlKHRoaXMud2ViRHJpdmVyQWdlbnRVcmwpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgcG9ydCA9IHRoaXMud2RhTG9jYWxQb3J0IHx8IFdEQV9BR0VOVF9QT1JUO1xuICAgICAgICBjb25zdCB7cHJvdG9jb2wsIGhvc3RuYW1lfSA9IHVybC5wYXJzZSh0aGlzLndkYUJhc2VVcmwgfHwgV0RBX0JBU0VfVVJMKTtcbiAgICAgICAgdGhpcy5fdXJsID0gdXJsLnBhcnNlKGAke3Byb3RvY29sfS8vJHtob3N0bmFtZX06JHtwb3J0fWApO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fdXJsO1xuICB9XG5cbiAgc2V0IHVybCAoX3VybCkge1xuICAgIHRoaXMuX3VybCA9IHVybC5wYXJzZShfdXJsKTtcbiAgfVxuXG4gIGdldCBmdWxseVN0YXJ0ZWQgKCkge1xuICAgIHJldHVybiB0aGlzLnN0YXJ0ZWQ7XG4gIH1cblxuICBzZXQgZnVsbHlTdGFydGVkIChzdGFydGVkID0gZmFsc2UpIHtcbiAgICB0aGlzLnN0YXJ0ZWQgPSBzdGFydGVkO1xuICB9XG5cbiAgYXN5bmMgcmV0cmlldmVEZXJpdmVkRGF0YVBhdGggKCkge1xuICAgIGlmICh0aGlzLmNhblNraXBYY29kZWJ1aWxkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHJldHVybiBhd2FpdCB0aGlzLnhjb2RlYnVpbGQucmV0cmlldmVEZXJpdmVkRGF0YVBhdGgoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXVzZSBydW5uaW5nIFdEQSBpZiBpdCBoYXMgdGhlIHNhbWUgYnVuZGxlIGlkIHdpdGggdXBkYXRlZFdEQUJ1bmRsZUlkLlxuICAgKiBPciByZXVzZSBpdCBpZiBpdCBoYXMgdGhlIGRlZmF1bHQgaWQgd2l0aG91dCB1cGRhdGVkV0RBQnVuZGxlSWQuXG4gICAqIFVuaW5zdGFsbCBpdCBpZiB0aGUgbWV0aG9kIGZhY2VzIGFuIGV4Y2VwdGlvbiBmb3IgdGhlIGFib3ZlIHNpdHVhdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVwZGF0ZWRXREFCdW5kbGVJZCBCdW5kbGVJZCB5b3UnZCBsaWtlIHRvIHVzZVxuICAgKi9cbiAgYXN5bmMgc2V0dXBDYWNoaW5nICgpIHtcbiAgICBjb25zdCBzdGF0dXMgPSBhd2FpdCB0aGlzLmdldFN0YXR1cygpO1xuICAgIGlmICghc3RhdHVzIHx8ICFzdGF0dXMuYnVpbGQpIHtcbiAgICAgIHRoaXMubG9nLmRlYnVnKCdXREEgaXMgY3VycmVudGx5IG5vdCBydW5uaW5nLiBUaGVyZSBpcyBub3RoaW5nIHRvIGNhY2hlJyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qge1xuICAgICAgcHJvZHVjdEJ1bmRsZUlkZW50aWZpZXIsXG4gICAgICB1cGdyYWRlZEF0LFxuICAgIH0gPSBzdGF0dXMuYnVpbGQ7XG4gICAgLy8gZm9yIHJlYWwgZGV2aWNlXG4gICAgaWYgKHV0aWwuaGFzVmFsdWUocHJvZHVjdEJ1bmRsZUlkZW50aWZpZXIpICYmIHV0aWwuaGFzVmFsdWUodGhpcy51cGRhdGVkV0RBQnVuZGxlSWQpICYmIHRoaXMudXBkYXRlZFdEQUJ1bmRsZUlkICE9PSBwcm9kdWN0QnVuZGxlSWRlbnRpZmllcikge1xuICAgICAgdGhpcy5sb2cuaW5mbyhgV2lsbCB1bmluc3RhbGwgcnVubmluZyBXREEgc2luY2UgaXQgaGFzIGRpZmZlcmVudCBidW5kbGUgaWQuIFRoZSBhY3R1YWwgdmFsdWUgaXMgJyR7cHJvZHVjdEJ1bmRsZUlkZW50aWZpZXJ9Jy5gKTtcbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLnVuaW5zdGFsbCgpO1xuICAgIH1cbiAgICAvLyBmb3Igc2ltdWxhdG9yXG4gICAgaWYgKHV0aWwuaGFzVmFsdWUocHJvZHVjdEJ1bmRsZUlkZW50aWZpZXIpICYmICF1dGlsLmhhc1ZhbHVlKHRoaXMudXBkYXRlZFdEQUJ1bmRsZUlkKSAmJiBXREFfUlVOTkVSX0JVTkRMRV9JRCAhPT0gcHJvZHVjdEJ1bmRsZUlkZW50aWZpZXIpIHtcbiAgICAgIHRoaXMubG9nLmluZm8oYFdpbGwgdW5pbnN0YWxsIHJ1bm5pbmcgV0RBIHNpbmNlIGl0cyBidW5kbGUgaWQgaXMgbm90IGVxdWFsIHRvIHRoZSBkZWZhdWx0IHZhbHVlICR7V0RBX1JVTk5FUl9CVU5ETEVfSUR9YCk7XG4gICAgICByZXR1cm4gYXdhaXQgdGhpcy51bmluc3RhbGwoKTtcbiAgICB9XG5cbiAgICBjb25zdCBhY3R1YWxVcGdyYWRlVGltZXN0YW1wID0gYXdhaXQgZ2V0V0RBVXBncmFkZVRpbWVzdGFtcCgpO1xuICAgIHRoaXMubG9nLmRlYnVnKGBVcGdyYWRlIHRpbWVzdGFtcCBvZiB0aGUgY3VycmVudGx5IGJ1bmRsZWQgV0RBOiAke2FjdHVhbFVwZ3JhZGVUaW1lc3RhbXB9YCk7XG4gICAgdGhpcy5sb2cuZGVidWcoYFVwZ3JhZGUgdGltZXN0YW1wIG9mIHRoZSBXREEgb24gdGhlIGRldmljZTogJHt1cGdyYWRlZEF0fWApO1xuICAgIGlmIChhY3R1YWxVcGdyYWRlVGltZXN0YW1wICYmIHVwZ3JhZGVkQXQgJiYgXy50b0xvd2VyKGAke2FjdHVhbFVwZ3JhZGVUaW1lc3RhbXB9YCkgIT09IF8udG9Mb3dlcihgJHt1cGdyYWRlZEF0fWApKSB7XG4gICAgICB0aGlzLmxvZy5pbmZvKCdXaWxsIHVuaW5zdGFsbCBydW5uaW5nIFdEQSBzaW5jZSBpdCBoYXMgZGlmZmVyZW50IHZlcnNpb24gaW4gY29tcGFyaXNvbiB0byB0aGUgb25lICcgK1xuICAgICAgICBgd2hpY2ggaXMgYnVuZGxlZCB3aXRoIGFwcGl1bS14Y3VpdGVzdC1kcml2ZXIgbW9kdWxlICgke2FjdHVhbFVwZ3JhZGVUaW1lc3RhbXB9ICE9ICR7dXBncmFkZWRBdH0pYCk7XG4gICAgICByZXR1cm4gYXdhaXQgdGhpcy51bmluc3RhbGwoKTtcbiAgICB9XG5cbiAgICBjb25zdCBtZXNzYWdlID0gdXRpbC5oYXNWYWx1ZShwcm9kdWN0QnVuZGxlSWRlbnRpZmllcilcbiAgICAgID8gYFdpbGwgcmV1c2UgcHJldmlvdXNseSBjYWNoZWQgV0RBIGluc3RhbmNlIGF0ICcke3RoaXMudXJsLmhyZWZ9JyB3aXRoICcke3Byb2R1Y3RCdW5kbGVJZGVudGlmaWVyfSdgXG4gICAgICA6IGBXaWxsIHJldXNlIHByZXZpb3VzbHkgY2FjaGVkIFdEQSBpbnN0YW5jZSBhdCAnJHt0aGlzLnVybC5ocmVmfSdgO1xuICAgIHRoaXMubG9nLmluZm8oYCR7bWVzc2FnZX0uIFNldCB0aGUgd2RhTG9jYWxQb3J0IGNhcGFiaWxpdHkgdG8gYSB2YWx1ZSBkaWZmZXJlbnQgZnJvbSAke3RoaXMudXJsLnBvcnR9IGlmIHRoaXMgaXMgYW4gdW5kZXNpcmVkIGJlaGF2aW9yLmApO1xuICAgIHRoaXMud2ViRHJpdmVyQWdlbnRVcmwgPSB0aGlzLnVybC5ocmVmO1xuICB9XG5cbiAgLyoqXG4gICAqIFF1aXQgYW5kIHVuaW5zdGFsbCBydW5uaW5nIFdEQS5cbiAgICovXG4gIGFzeW5jIHF1aXRBbmRVbmluc3RhbGwgKCkge1xuICAgIGF3YWl0IHRoaXMucXVpdCgpO1xuICAgIGF3YWl0IHRoaXMudW5pbnN0YWxsKCk7XG4gIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgV2ViRHJpdmVyQWdlbnQ7XG5leHBvcnQgeyBXZWJEcml2ZXJBZ2VudCB9O1xuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7OztBQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLEtBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFFLEtBQUEsR0FBQUgsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFHLFNBQUEsR0FBQUosc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFJLFdBQUEsR0FBQUosT0FBQTtBQUNBLElBQUFLLFFBQUEsR0FBQUwsT0FBQTtBQUNBLElBQUFNLE9BQUEsR0FBQVAsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFPLGVBQUEsR0FBQVAsT0FBQTtBQUNBLElBQUFRLE1BQUEsR0FBQVIsT0FBQTtBQUdBLElBQUFTLFdBQUEsR0FBQVYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFVLFVBQUEsR0FBQVgsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFXLGFBQUEsR0FBQVgsT0FBQTtBQUNBLElBQUFZLGtCQUFBLEdBQUFaLE9BQUE7QUFDQSxJQUFBYSxVQUFBLEdBQUFiLE9BQUE7QUFJQSxJQUFBYyxnQkFBQSxHQUFBZCxPQUFBO0FBQ0EsSUFBQWUsVUFBQSxHQUFBZixPQUFBO0FBRUEsTUFBTWdCLGtCQUFrQixHQUFHLEVBQUUsR0FBRyxJQUFJO0FBQ3BDLE1B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
514
+ exports.default = WebDriverAgent;
515
+ //# sourceMappingURL=webdriveragent.js.map