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.
- package/CHANGELOG.md +7 -0
- package/build/index.js +39 -36
- package/build/lib/check-dependencies.d.ts +3 -0
- package/build/lib/check-dependencies.d.ts.map +1 -0
- package/build/lib/check-dependencies.js +38 -32
- package/build/lib/check-dependencies.js.map +1 -1
- package/build/lib/constants.d.ts +12 -0
- package/build/lib/constants.d.ts.map +1 -0
- package/build/lib/constants.js +8 -10
- package/build/lib/constants.js.map +1 -1
- package/build/lib/logger.d.ts +3 -0
- package/build/lib/logger.d.ts.map +1 -0
- package/build/lib/logger.js +5 -11
- package/build/lib/logger.js.map +1 -1
- package/build/lib/no-session-proxy.d.ts +6 -0
- package/build/lib/no-session-proxy.d.ts.map +1 -0
- package/build/lib/no-session-proxy.js +22 -26
- package/build/lib/no-session-proxy.js.map +1 -1
- package/build/lib/utils.d.ts +127 -0
- package/build/lib/utils.d.ts.map +1 -0
- package/build/lib/utils.js +347 -211
- package/build/lib/utils.js.map +1 -1
- package/build/lib/webdriveragent.d.ts +145 -0
- package/build/lib/webdriveragent.d.ts.map +1 -0
- package/build/lib/webdriveragent.js +478 -367
- package/build/lib/webdriveragent.js.map +1 -1
- package/build/lib/xcodebuild.d.ts +58 -0
- package/build/lib/xcodebuild.d.ts.map +1 -0
- package/build/lib/xcodebuild.js +367 -289
- package/build/lib/xcodebuild.js.map +1 -1
- package/lib/check-dependencies.js +3 -4
- package/lib/utils.js +10 -7
- package/lib/webdriveragent.js +14 -9
- package/lib/xcodebuild.js +39 -7
- package/package.json +28 -18
package/build/lib/utils.js
CHANGED
|
@@ -1,257 +1,393 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
exports.killProcess = killProcess;
|
|
17
|
-
exports.randomInt = randomInt;
|
|
18
|
-
exports.resetProjectFile = resetProjectFile;
|
|
19
|
-
exports.resetTestProcesses = resetTestProcesses;
|
|
20
|
-
exports.setRealDeviceSecurity = setRealDeviceSecurity;
|
|
21
|
-
exports.setXctestrunFile = setXctestrunFile;
|
|
22
|
-
exports.updateProjectFile = updateProjectFile;
|
|
23
|
-
require("source-map-support/register");
|
|
24
|
-
var _support = require("@appium/support");
|
|
25
|
-
var _teen_process = require("teen_process");
|
|
26
|
-
var _path = _interopRequireDefault(require("path"));
|
|
27
|
-
var _logger = _interopRequireDefault(require("./logger"));
|
|
28
|
-
var _lodash = _interopRequireDefault(require("lodash"));
|
|
29
|
-
var _constants = require("./constants");
|
|
30
|
-
var _bluebird = _interopRequireDefault(require("bluebird"));
|
|
31
|
-
var _fs2 = _interopRequireDefault(require("fs"));
|
|
32
|
-
var _asyncbox = require("asyncbox");
|
|
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.isTvOS = exports.killAppUsingPattern = exports.getPIDsListeningOnPort = exports.resetTestProcesses = exports.getWDAUpgradeTimestamp = exports.randomInt = exports.killProcess = exports.getXctestrunFilePath = exports.setXctestrunFile = exports.generateXcodeConfigFile = exports.getXctestrunFileName = exports.getAdditionalRunContent = exports.setRealDeviceSecurity = exports.resetProjectFile = exports.updateProjectFile = exports.BOOTSTRAP_PATH = void 0;
|
|
7
|
+
const support_1 = require("@appium/support");
|
|
8
|
+
const teen_process_1 = require("teen_process");
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const logger_1 = __importDefault(require("./logger"));
|
|
11
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
12
|
+
const constants_1 = require("./constants");
|
|
13
|
+
const bluebird_1 = __importDefault(require("bluebird"));
|
|
14
|
+
const fs_1 = __importDefault(require("fs"));
|
|
15
|
+
const asyncbox_1 = require("asyncbox");
|
|
33
16
|
const PROJECT_FILE = 'project.pbxproj';
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Calculates the path to the current module's root folder
|
|
19
|
+
*
|
|
20
|
+
* @returns {string} The full path to module root
|
|
21
|
+
* @throws {Error} If the current module root folder cannot be determined
|
|
22
|
+
*/
|
|
23
|
+
const getModuleRoot = lodash_1.default.memoize(function getModuleRoot() {
|
|
24
|
+
let currentDir = path_1.default.dirname(path_1.default.resolve(__filename));
|
|
25
|
+
let isAtFsRoot = false;
|
|
26
|
+
while (!isAtFsRoot) {
|
|
27
|
+
const manifestPath = path_1.default.join(currentDir, 'package.json');
|
|
28
|
+
try {
|
|
29
|
+
if (fs_1.default.existsSync(manifestPath) &&
|
|
30
|
+
JSON.parse(fs_1.default.readFileSync(manifestPath, 'utf8')).name === 'appium-webdriveragent') {
|
|
31
|
+
return currentDir;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (ign) { }
|
|
35
|
+
currentDir = path_1.default.dirname(currentDir);
|
|
36
|
+
isAtFsRoot = currentDir.length <= path_1.default.dirname(currentDir).length;
|
|
37
|
+
}
|
|
38
|
+
throw new Error('Cannot find the root folder of the appium-webdriveragent Node.js module');
|
|
48
39
|
});
|
|
49
|
-
|
|
50
|
-
exports.BOOTSTRAP_PATH = BOOTSTRAP_PATH;
|
|
40
|
+
exports.BOOTSTRAP_PATH = getModuleRoot();
|
|
51
41
|
async function getPIDsUsingPattern(pattern) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
} = await (0, _teen_process.exec)('pgrep', args);
|
|
57
|
-
return stdout.split(/\s+/).map(x => parseInt(x, 10)).filter(_lodash.default.isInteger).map(x => `${x}`);
|
|
58
|
-
} catch (err) {
|
|
59
|
-
_logger.default.debug(`'pgrep ${args.join(' ')}' didn't detect any matching processes. Return code: ${err.code}`);
|
|
60
|
-
return [];
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
async function killAppUsingPattern(pgrepPattern) {
|
|
64
|
-
const signals = [2, 15, 9];
|
|
65
|
-
for (const signal of signals) {
|
|
66
|
-
const matchedPids = await getPIDsUsingPattern(pgrepPattern);
|
|
67
|
-
if (_lodash.default.isEmpty(matchedPids)) {
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
const args = [`-${signal}`, ...matchedPids];
|
|
42
|
+
const args = [
|
|
43
|
+
'-if',
|
|
44
|
+
pattern,
|
|
45
|
+
];
|
|
71
46
|
try {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
47
|
+
const { stdout } = await (0, teen_process_1.exec)('pgrep', args);
|
|
48
|
+
return stdout.split(/\s+/)
|
|
49
|
+
.map((x) => parseInt(x, 10))
|
|
50
|
+
.filter(lodash_1.default.isInteger)
|
|
51
|
+
.map((x) => `${x}`);
|
|
75
52
|
}
|
|
76
|
-
|
|
77
|
-
|
|
53
|
+
catch (err) {
|
|
54
|
+
logger_1.default.debug(`'pgrep ${args.join(' ')}' didn't detect any matching processes. Return code: ${err.code}`);
|
|
55
|
+
return [];
|
|
78
56
|
}
|
|
79
|
-
try {
|
|
80
|
-
await (0, _asyncbox.waitForCondition)(async () => {
|
|
81
|
-
const pidCheckPromises = matchedPids.map(pid => (0, _teen_process.exec)('kill', ['-0', pid]).then(() => false).catch(() => true));
|
|
82
|
-
return (await _bluebird.default.all(pidCheckPromises)).every(x => x === true);
|
|
83
|
-
}, {
|
|
84
|
-
waitMs: 1000,
|
|
85
|
-
intervalMs: 100
|
|
86
|
-
});
|
|
87
|
-
return;
|
|
88
|
-
} catch (ign) {}
|
|
89
|
-
}
|
|
90
57
|
}
|
|
58
|
+
async function killAppUsingPattern(pgrepPattern) {
|
|
59
|
+
const signals = [2, 15, 9];
|
|
60
|
+
for (const signal of signals) {
|
|
61
|
+
const matchedPids = await getPIDsUsingPattern(pgrepPattern);
|
|
62
|
+
if (lodash_1.default.isEmpty(matchedPids)) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const args = [`-${signal}`, ...matchedPids];
|
|
66
|
+
try {
|
|
67
|
+
await (0, teen_process_1.exec)('kill', args);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
logger_1.default.debug(`kill ${args.join(' ')} -> ${err.message}`);
|
|
71
|
+
}
|
|
72
|
+
if (signal === lodash_1.default.last(signals)) {
|
|
73
|
+
// there is no need to wait after SIGKILL
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
await (0, asyncbox_1.waitForCondition)(async () => {
|
|
78
|
+
const pidCheckPromises = matchedPids
|
|
79
|
+
.map((pid) => (0, teen_process_1.exec)('kill', ['-0', pid])
|
|
80
|
+
// the process is still alive
|
|
81
|
+
.then(() => false)
|
|
82
|
+
// the process is dead
|
|
83
|
+
.catch(() => true));
|
|
84
|
+
return (await bluebird_1.default.all(pidCheckPromises))
|
|
85
|
+
.every((x) => x === true);
|
|
86
|
+
}, {
|
|
87
|
+
waitMs: 1000,
|
|
88
|
+
intervalMs: 100,
|
|
89
|
+
});
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
catch (ign) {
|
|
93
|
+
// try the next signal
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
exports.killAppUsingPattern = killAppUsingPattern;
|
|
98
|
+
/**
|
|
99
|
+
* Return true if the platformName is tvOS
|
|
100
|
+
* @param {string} platformName The name of the platorm
|
|
101
|
+
* @returns {boolean} Return true if the platformName is tvOS
|
|
102
|
+
*/
|
|
91
103
|
function isTvOS(platformName) {
|
|
92
|
-
|
|
104
|
+
return lodash_1.default.toLower(platformName) === lodash_1.default.toLower(constants_1.PLATFORM_NAME_TVOS);
|
|
93
105
|
}
|
|
106
|
+
exports.isTvOS = isTvOS;
|
|
94
107
|
async function replaceInFile(file, find, replace) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
108
|
+
let contents = await support_1.fs.readFile(file, 'utf8');
|
|
109
|
+
let newContents = contents.replace(find, replace);
|
|
110
|
+
if (newContents !== contents) {
|
|
111
|
+
await support_1.fs.writeFile(file, newContents, 'utf8');
|
|
112
|
+
}
|
|
100
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Update WebDriverAgentRunner project bundle ID with newBundleId.
|
|
116
|
+
* This method assumes project file is in the correct state.
|
|
117
|
+
* @param {string} agentPath - Path to the .xcodeproj directory.
|
|
118
|
+
* @param {string} newBundleId the new bundle ID used to update.
|
|
119
|
+
*/
|
|
101
120
|
async function updateProjectFile(agentPath, newBundleId) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
121
|
+
let projectFilePath = path_1.default.resolve(agentPath, PROJECT_FILE);
|
|
122
|
+
try {
|
|
123
|
+
// Assuming projectFilePath is in the correct state, create .old from projectFilePath
|
|
124
|
+
await support_1.fs.copyFile(projectFilePath, `${projectFilePath}.old`);
|
|
125
|
+
await replaceInFile(projectFilePath, new RegExp(lodash_1.default.escapeRegExp(constants_1.WDA_RUNNER_BUNDLE_ID), 'g'), newBundleId); // eslint-disable-line no-useless-escape
|
|
126
|
+
logger_1.default.debug(`Successfully updated '${projectFilePath}' with bundle id '${newBundleId}'`);
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
logger_1.default.debug(`Error updating project file: ${err.message}`);
|
|
130
|
+
logger_1.default.warn(`Unable to update project file '${projectFilePath}' with ` +
|
|
131
|
+
`bundle id '${newBundleId}'. WebDriverAgent may not start`);
|
|
132
|
+
}
|
|
111
133
|
}
|
|
134
|
+
exports.updateProjectFile = updateProjectFile;
|
|
135
|
+
/**
|
|
136
|
+
* Reset WebDriverAgentRunner project bundle ID to correct state.
|
|
137
|
+
* @param {string} agentPath - Path to the .xcodeproj directory.
|
|
138
|
+
*/
|
|
112
139
|
async function resetProjectFile(agentPath) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
140
|
+
const projectFilePath = path_1.default.join(agentPath, PROJECT_FILE);
|
|
141
|
+
try {
|
|
142
|
+
// restore projectFilePath from .old file
|
|
143
|
+
if (!await support_1.fs.exists(`${projectFilePath}.old`)) {
|
|
144
|
+
return; // no need to reset
|
|
145
|
+
}
|
|
146
|
+
await support_1.fs.mv(`${projectFilePath}.old`, projectFilePath);
|
|
147
|
+
logger_1.default.debug(`Successfully reset '${projectFilePath}' with bundle id '${constants_1.WDA_RUNNER_BUNDLE_ID}'`);
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
logger_1.default.debug(`Error resetting project file: ${err.message}`);
|
|
151
|
+
logger_1.default.warn(`Unable to reset project file '${projectFilePath}' with ` +
|
|
152
|
+
`bundle id '${constants_1.WDA_RUNNER_BUNDLE_ID}'. WebDriverAgent has been ` +
|
|
153
|
+
`modified and not returned to the original state.`);
|
|
117
154
|
}
|
|
118
|
-
await _support.fs.mv(`${projectFilePath}.old`, projectFilePath);
|
|
119
|
-
_logger.default.debug(`Successfully reset '${projectFilePath}' with bundle id '${_constants.WDA_RUNNER_BUNDLE_ID}'`);
|
|
120
|
-
} catch (err) {
|
|
121
|
-
_logger.default.debug(`Error resetting project file: ${err.message}`);
|
|
122
|
-
_logger.default.warn(`Unable to reset project file '${projectFilePath}' with ` + `bundle id '${_constants.WDA_RUNNER_BUNDLE_ID}'. WebDriverAgent has been ` + `modified and not returned to the original state.`);
|
|
123
|
-
}
|
|
124
155
|
}
|
|
156
|
+
exports.resetProjectFile = resetProjectFile;
|
|
125
157
|
async function setRealDeviceSecurity(keychainPath, keychainPassword) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
158
|
+
logger_1.default.debug('Setting security for iOS device');
|
|
159
|
+
await (0, teen_process_1.exec)('security', ['-v', 'list-keychains', '-s', keychainPath]);
|
|
160
|
+
await (0, teen_process_1.exec)('security', ['-v', 'unlock-keychain', '-p', keychainPassword, keychainPath]);
|
|
161
|
+
await (0, teen_process_1.exec)('security', ['set-keychain-settings', '-t', '3600', '-l', keychainPath]);
|
|
130
162
|
}
|
|
163
|
+
exports.setRealDeviceSecurity = setRealDeviceSecurity;
|
|
131
164
|
async function generateXcodeConfigFile(orgId, signingId) {
|
|
132
|
-
|
|
133
|
-
|
|
165
|
+
logger_1.default.debug(`Generating xcode config file for orgId '${orgId}' and signingId ` +
|
|
166
|
+
`'${signingId}'`);
|
|
167
|
+
const contents = `DEVELOPMENT_TEAM = ${orgId}
|
|
134
168
|
CODE_SIGN_IDENTITY = ${signingId}
|
|
135
169
|
`;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
170
|
+
const xcconfigPath = await support_1.tempDir.path('appium-temp.xcconfig');
|
|
171
|
+
logger_1.default.debug(`Writing xcode config file to ${xcconfigPath}`);
|
|
172
|
+
await support_1.fs.writeFile(xcconfigPath, contents, 'utf8');
|
|
173
|
+
return xcconfigPath;
|
|
140
174
|
}
|
|
175
|
+
exports.generateXcodeConfigFile = generateXcodeConfigFile;
|
|
176
|
+
/**
|
|
177
|
+
* Information of the device under test
|
|
178
|
+
* @typedef {Object} DeviceInfo
|
|
179
|
+
* @property {string} isRealDevice - Equals to true if the current device is a real device
|
|
180
|
+
* @property {string} udid - The device UDID.
|
|
181
|
+
* @property {string} platformVersion - The platform version of OS.
|
|
182
|
+
* @property {string} platformName - The platform name of iOS, tvOS
|
|
183
|
+
*/
|
|
184
|
+
/**
|
|
185
|
+
* Creates xctestrun file per device & platform version.
|
|
186
|
+
* We expects to have WebDriverAgentRunner_iphoneos${sdkVersion|platformVersion}-arm64.xctestrun for real device
|
|
187
|
+
* and WebDriverAgentRunner_iphonesimulator${sdkVersion|platformVersion}-x86_64.xctestrun for simulator located @bootstrapPath
|
|
188
|
+
* Newer Xcode (Xcode 10.0 at least) generate xctestrun file following sdkVersion.
|
|
189
|
+
* e.g. Xcode which has iOS SDK Version 12.2 generate WebDriverAgentRunner_iphonesimulator.2-x86_64.xctestrun
|
|
190
|
+
* even if the cap has platform version 11.4
|
|
191
|
+
*
|
|
192
|
+
* @param {DeviceInfo} deviceInfo
|
|
193
|
+
* @param {string} sdkVersion - The Xcode SDK version of OS.
|
|
194
|
+
* @param {string} bootstrapPath - The folder path containing xctestrun file.
|
|
195
|
+
* @param {number|string} wdaRemotePort - The remote port WDA is listening on.
|
|
196
|
+
* @return {Promise<string>} returns xctestrunFilePath for given device
|
|
197
|
+
* @throws if WebDriverAgentRunner_iphoneos${sdkVersion|platformVersion}-arm64.xctestrun for real device
|
|
198
|
+
* or WebDriverAgentRunner_iphonesimulator${sdkVersion|platformVersion}-x86_64.xctestrun for simulator is not found @bootstrapPath,
|
|
199
|
+
* then it will throw file not found exception
|
|
200
|
+
*/
|
|
141
201
|
async function setXctestrunFile(deviceInfo, sdkVersion, bootstrapPath, wdaRemotePort) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
202
|
+
const xctestrunFilePath = await getXctestrunFilePath(deviceInfo, sdkVersion, bootstrapPath);
|
|
203
|
+
const xctestRunContent = await support_1.plist.parsePlistFile(xctestrunFilePath);
|
|
204
|
+
const updateWDAPort = getAdditionalRunContent(deviceInfo.platformName, wdaRemotePort);
|
|
205
|
+
const newXctestRunContent = lodash_1.default.merge(xctestRunContent, updateWDAPort);
|
|
206
|
+
await support_1.plist.updatePlistFile(xctestrunFilePath, newXctestRunContent, true);
|
|
207
|
+
return xctestrunFilePath;
|
|
148
208
|
}
|
|
209
|
+
exports.setXctestrunFile = setXctestrunFile;
|
|
210
|
+
/**
|
|
211
|
+
* Return the WDA object which appends existing xctest runner content
|
|
212
|
+
* @param {string} platformName - The name of the platform
|
|
213
|
+
* @param {number|string} wdaRemotePort - The remote port number
|
|
214
|
+
* @return {object} returns a runner object which has USE_PORT
|
|
215
|
+
*/
|
|
149
216
|
function getAdditionalRunContent(platformName, wdaRemotePort) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
217
|
+
const runner = `WebDriverAgentRunner${isTvOS(platformName) ? '_tvOS' : ''}`;
|
|
218
|
+
return {
|
|
219
|
+
[runner]: {
|
|
220
|
+
EnvironmentVariables: {
|
|
221
|
+
// USE_PORT must be 'string'
|
|
222
|
+
USE_PORT: `${wdaRemotePort}`
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
};
|
|
158
226
|
}
|
|
227
|
+
exports.getAdditionalRunContent = getAdditionalRunContent;
|
|
228
|
+
/**
|
|
229
|
+
* Return the path of xctestrun if it exists
|
|
230
|
+
* @param {DeviceInfo} deviceInfo
|
|
231
|
+
* @param {string} sdkVersion - The Xcode SDK version of OS.
|
|
232
|
+
* @param {string} bootstrapPath - The folder path containing xctestrun file.
|
|
233
|
+
* @returns {Promise<string>}
|
|
234
|
+
*/
|
|
159
235
|
async function getXctestrunFilePath(deviceInfo, sdkVersion, bootstrapPath) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
236
|
+
// First try the SDK path, for Xcode 10 (at least)
|
|
237
|
+
const sdkBased = [
|
|
238
|
+
path_1.default.resolve(bootstrapPath, `${deviceInfo.udid}_${sdkVersion}.xctestrun`),
|
|
239
|
+
sdkVersion,
|
|
240
|
+
];
|
|
241
|
+
// Next try Platform path, for earlier Xcode versions
|
|
242
|
+
const platformBased = [
|
|
243
|
+
path_1.default.resolve(bootstrapPath, `${deviceInfo.udid}_${deviceInfo.platformVersion}.xctestrun`),
|
|
244
|
+
deviceInfo.platformVersion,
|
|
245
|
+
];
|
|
246
|
+
for (const [filePath, version] of [sdkBased, platformBased]) {
|
|
247
|
+
if (await support_1.fs.exists(filePath)) {
|
|
248
|
+
logger_1.default.info(`Using '${filePath}' as xctestrun file`);
|
|
249
|
+
return filePath;
|
|
250
|
+
}
|
|
251
|
+
const originalXctestrunFile = path_1.default.resolve(bootstrapPath, getXctestrunFileName(deviceInfo, version));
|
|
252
|
+
if (await support_1.fs.exists(originalXctestrunFile)) {
|
|
253
|
+
// If this is first time run for given device, then first generate xctestrun file for device.
|
|
254
|
+
// We need to have a xctestrun file **per device** because we cant not have same wda port for all devices.
|
|
255
|
+
await support_1.fs.copyFile(originalXctestrunFile, filePath);
|
|
256
|
+
logger_1.default.info(`Using '${filePath}' as xctestrun file copied by '${originalXctestrunFile}'`);
|
|
257
|
+
return filePath;
|
|
258
|
+
}
|
|
172
259
|
}
|
|
173
|
-
|
|
174
|
-
|
|
260
|
+
throw new Error(`If you are using 'useXctestrunFile' capability then you ` +
|
|
261
|
+
`need to have a xctestrun file (expected: ` +
|
|
262
|
+
`'${path_1.default.resolve(bootstrapPath, getXctestrunFileName(deviceInfo, sdkVersion))}')`);
|
|
175
263
|
}
|
|
264
|
+
exports.getXctestrunFilePath = getXctestrunFilePath;
|
|
265
|
+
/**
|
|
266
|
+
* Return the name of xctestrun file
|
|
267
|
+
* @param {DeviceInfo} deviceInfo
|
|
268
|
+
* @param {string} version - The Xcode SDK version of OS.
|
|
269
|
+
* @return {string} returns xctestrunFilePath for given device
|
|
270
|
+
*/
|
|
176
271
|
function getXctestrunFileName(deviceInfo, version) {
|
|
177
|
-
|
|
272
|
+
return isTvOS(deviceInfo.platformName)
|
|
273
|
+
? `WebDriverAgentRunner_tvOS_appletv${deviceInfo.isRealDevice ? `os${version}-arm64` : `simulator${version}-x86_64`}.xctestrun`
|
|
274
|
+
: `WebDriverAgentRunner_iphone${deviceInfo.isRealDevice ? `os${version}-arm64` : `simulator${version}-x86_64`}.xctestrun`;
|
|
178
275
|
}
|
|
276
|
+
exports.getXctestrunFileName = getXctestrunFileName;
|
|
179
277
|
async function killProcess(name, proc) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
_logger.default.info(`Shutting down '${name}' process (pid '${proc.proc.pid}')`);
|
|
184
|
-
_logger.default.info(`Sending 'SIGTERM'...`);
|
|
185
|
-
try {
|
|
186
|
-
await proc.stop('SIGTERM', 1000);
|
|
187
|
-
return;
|
|
188
|
-
} catch (err) {
|
|
189
|
-
if (!err.message.includes(`Process didn't end after`)) {
|
|
190
|
-
throw err;
|
|
278
|
+
if (!proc || !proc.isRunning) {
|
|
279
|
+
return;
|
|
191
280
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
281
|
+
logger_1.default.info(`Shutting down '${name}' process (pid '${proc.proc.pid}')`);
|
|
282
|
+
logger_1.default.info(`Sending 'SIGTERM'...`);
|
|
283
|
+
try {
|
|
284
|
+
await proc.stop('SIGTERM', 1000);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
catch (err) {
|
|
288
|
+
if (!err.message.includes(`Process didn't end after`)) {
|
|
289
|
+
throw err;
|
|
290
|
+
}
|
|
291
|
+
logger_1.default.debug(`${name} process did not end in a timely fashion: '${err.message}'.`);
|
|
292
|
+
}
|
|
293
|
+
logger_1.default.info(`Sending 'SIGKILL'...`);
|
|
294
|
+
try {
|
|
295
|
+
await proc.stop('SIGKILL');
|
|
296
|
+
}
|
|
297
|
+
catch (err) {
|
|
298
|
+
if (err.message.includes('not currently running')) {
|
|
299
|
+
// the process ended but for some reason we were not informed
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
throw err;
|
|
200
303
|
}
|
|
201
|
-
throw err;
|
|
202
|
-
}
|
|
203
304
|
}
|
|
305
|
+
exports.killProcess = killProcess;
|
|
306
|
+
/**
|
|
307
|
+
* Generate a random integer.
|
|
308
|
+
*
|
|
309
|
+
* @return {number} A random integer number in range [low, hight). `low`` is inclusive and `high` is exclusive.
|
|
310
|
+
*/
|
|
204
311
|
function randomInt(low, high) {
|
|
205
|
-
|
|
312
|
+
return Math.floor(Math.random() * (high - low) + low);
|
|
206
313
|
}
|
|
314
|
+
exports.randomInt = randomInt;
|
|
315
|
+
/**
|
|
316
|
+
* Retrieves WDA upgrade timestamp
|
|
317
|
+
*
|
|
318
|
+
* @return {Promise<number?>} The UNIX timestamp of the package manifest. The manifest only gets modified on
|
|
319
|
+
* package upgrade.
|
|
320
|
+
*/
|
|
207
321
|
async function getWDAUpgradeTimestamp() {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
mtime
|
|
214
|
-
} = await _support.fs.stat(packageManifest);
|
|
215
|
-
return mtime.getTime();
|
|
322
|
+
const packageManifest = path_1.default.resolve(getModuleRoot(), 'package.json');
|
|
323
|
+
if (!await support_1.fs.exists(packageManifest)) {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
const { mtime } = await support_1.fs.stat(packageManifest);
|
|
327
|
+
return mtime.getTime();
|
|
216
328
|
}
|
|
329
|
+
exports.getWDAUpgradeTimestamp = getWDAUpgradeTimestamp;
|
|
330
|
+
/**
|
|
331
|
+
* Kills running XCTest processes for the particular device.
|
|
332
|
+
*
|
|
333
|
+
* @param {string} udid - The device UDID.
|
|
334
|
+
* @param {boolean} isSimulator - Equals to true if the current device is a Simulator
|
|
335
|
+
*/
|
|
217
336
|
async function resetTestProcesses(udid, isSimulator) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
337
|
+
const processPatterns = [`xcodebuild.*${udid}`];
|
|
338
|
+
if (isSimulator) {
|
|
339
|
+
processPatterns.push(`${udid}.*XCTRunner`);
|
|
340
|
+
// The pattern to find in case idb was used
|
|
341
|
+
processPatterns.push(`xctest.*${udid}`);
|
|
342
|
+
}
|
|
343
|
+
logger_1.default.debug(`Killing running processes '${processPatterns.join(', ')}' for the device ${udid}...`);
|
|
344
|
+
await bluebird_1.default.all(processPatterns.map(killAppUsingPattern));
|
|
225
345
|
}
|
|
346
|
+
exports.resetTestProcesses = resetTestProcesses;
|
|
347
|
+
/**
|
|
348
|
+
* Get the IDs of processes listening on the particular system port.
|
|
349
|
+
* It is also possible to apply additional filtering based on the
|
|
350
|
+
* process command line.
|
|
351
|
+
*
|
|
352
|
+
* @param {string|number} port - The port number.
|
|
353
|
+
* @param {?Function} filteringFunc - Optional lambda function, which
|
|
354
|
+
* receives command line string of the particular process
|
|
355
|
+
* listening on given port, and is expected to return
|
|
356
|
+
* either true or false to include/exclude the corresponding PID
|
|
357
|
+
* from the resulting array.
|
|
358
|
+
* @returns {Promise<string[]>} - the list of matched process ids.
|
|
359
|
+
*/
|
|
226
360
|
async function getPIDsListeningOnPort(port, filteringFunc = null) {
|
|
227
|
-
|
|
228
|
-
try {
|
|
229
|
-
const {
|
|
230
|
-
stdout
|
|
231
|
-
} = await (0, _teen_process.exec)('lsof', ['-ti', `tcp:${port}`]);
|
|
232
|
-
result.push(...stdout.trim().split(/\n+/));
|
|
233
|
-
} catch (e) {
|
|
234
|
-
if (e.code !== 1) {
|
|
235
|
-
_logger.default.debug(`Error getting processes listening on port '${port}': ${e.stderr || e.message}`);
|
|
236
|
-
}
|
|
237
|
-
return result;
|
|
238
|
-
}
|
|
239
|
-
if (!_lodash.default.isFunction(filteringFunc)) {
|
|
240
|
-
return result;
|
|
241
|
-
}
|
|
242
|
-
return await _bluebird.default.filter(result, async pid => {
|
|
243
|
-
let stdout;
|
|
361
|
+
const result = [];
|
|
244
362
|
try {
|
|
245
|
-
|
|
246
|
-
stdout
|
|
247
|
-
|
|
248
|
-
} catch (e) {
|
|
249
|
-
if (e.code === 1) {
|
|
250
|
-
return false;
|
|
251
|
-
}
|
|
252
|
-
throw e;
|
|
363
|
+
// This only works since Mac OS X El Capitan
|
|
364
|
+
const { stdout } = await (0, teen_process_1.exec)('lsof', ['-ti', `tcp:${port}`]);
|
|
365
|
+
result.push(...(stdout.trim().split(/\n+/)));
|
|
253
366
|
}
|
|
254
|
-
|
|
255
|
-
|
|
367
|
+
catch (e) {
|
|
368
|
+
if (e.code !== 1) {
|
|
369
|
+
// code 1 means no processes. Other errors need reporting
|
|
370
|
+
logger_1.default.debug(`Error getting processes listening on port '${port}': ${e.stderr || e.message}`);
|
|
371
|
+
}
|
|
372
|
+
return result;
|
|
373
|
+
}
|
|
374
|
+
if (!lodash_1.default.isFunction(filteringFunc)) {
|
|
375
|
+
return result;
|
|
376
|
+
}
|
|
377
|
+
return await bluebird_1.default.filter(result, async (pid) => {
|
|
378
|
+
let stdout;
|
|
379
|
+
try {
|
|
380
|
+
({ stdout } = await (0, teen_process_1.exec)('ps', ['-p', pid, '-o', 'command']));
|
|
381
|
+
}
|
|
382
|
+
catch (e) {
|
|
383
|
+
if (e.code === 1) {
|
|
384
|
+
// The process does not exist anymore, there's nothing to filter
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
throw e;
|
|
388
|
+
}
|
|
389
|
+
return await filteringFunc(stdout);
|
|
390
|
+
});
|
|
256
391
|
}
|
|
257
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfc3VwcG9ydCIsInJlcXVpcmUiLCJfdGVlbl9wcm9jZXNzIiwiX3BhdGgiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwiX2xvZ2dlciIsIl9sb2Rhc2giLCJfY29uc3RhbnRzIiwiX2JsdWViaXJkIiwiX2ZzMiIsIl9hc3luY2JveCIsIlBST0pFQ1RfRklMRSIsImdldE1vZHVsZVJvb3QiLCJfIiwibWVtb2l6ZSIsImN1cnJlbnREaXIiLCJwYXRoIiwiZGlybmFtZSIsInJlc29sdmUiLCJfX2ZpbGVuYW1lIiwiaXNBdEZzUm9vdCIsIm1hbmlmZXN0UGF0aCIsImpvaW4iLCJfZnMiLCJleGlzdHNTeW5jIiwiSlNPTiIsInBhcnNlIiwicmVhZEZpbGVTeW5jIiwibmFtZSIsImlnbiIsImxlbmd0aCIsIkVycm9yIiwiQk9PVFNUUkFQX1BBVEgiLCJleHBvcnRzIiwiZ2V0UElEc1VzaW5nUGF0dGVybiIsInBhdHRlcm4iLCJhcmdzIiwic3Rkb3V0IiwiZXhlYyIsInNwbGl0IiwibWFwIiwieCIsInBhcnNlSW50IiwiZmlsdGVyIiwiaXNJbnRlZ2VyIiwiZXJyIiwibG9nIiwiZGVidWciLCJjb2RlIiwia2lsbEFwcFVzaW5nUGF0dGVybiIsInBncmVwUGF0dGVybiIsInNpZ25hbHMiLCJzaWduYWwiLCJtYXRjaGVkUGlkcyIsImlzRW1wdHkiLCJtZXNzYWdlIiwibGFzdCIsIndhaXRGb3JDb25kaXRpb24iLCJwaWRDaGVja1Byb21pc2VzIiwicGlkIiwidGhlbiIsImNhdGNoIiwiQiIsImFsbCIsImV2ZXJ5Iiwid2FpdE1zIiwiaW50ZXJ2YWxNcyIsImlzVHZPUyIsInBsYXRmb3JtTmFtZSIsInRvTG93ZXIiLCJQTEFURk9STV9OQU1FX1RWT1MiLCJyZXBsYWNlSW5GaWxlIiwiZmlsZSIsImZpbmQiLCJyZXBsYWNlIiwiY29udGVudHMiLCJmcyIsInJlYWRGaWxlIiwibmV3Q29udGVudHMiLCJ3cml0ZUZpbGUiLCJ1cGRhdGVQcm9qZWN0RmlsZSIsImFnZW50UGF0aCIsIm5ld0J1bmRsZUlkIiwicHJvamVjdEZpbGVQYXRoIiwiY29weUZpbGUiLCJSZWdFeHAiLCJlc2NhcGVSZWdFeHAiLCJXREFfUlVOTkVSX0JVTkRMRV9JRCIsIndhcm4iLCJyZXNldFByb2plY3RGaWxlIiwiZXhpc3RzIiwibXYiLCJzZXRSZWFsRGV2aWNlU2VjdXJpdHkiLCJrZXljaGFpblBhdGgiLCJrZXljaGFpblBhc3N3b3JkIiwiZ2VuZXJhdGVYY29kZUNvbmZpZ0ZpbGUiLCJvcmdJZCIsInNpZ25pbmdJZCIsInhjY29uZmlnUGF0aCIsInRlbXBEaXIiLCJzZXRYY3Rlc3RydW5GaWxlIiwiZGV2aWNlSW5mbyIsInNka1ZlcnNpb24iLCJib290c3RyYXBQYXRoIiwid2RhUmVtb3RlUG9ydCIsInhjdGVzdHJ1bkZpbGVQYXRoIiwiZ2V0WGN0ZXN0cnVuRmlsZVBhdGgiLCJ4Y3Rlc3RSdW5Db250ZW50IiwicGxpc3QiLCJwYXJzZVBsaXN0RmlsZSIsInVwZGF0ZVdEQVBvcnQiLCJnZXRBZGRpdGlvbmFsUnVuQ29udGVudCIsIm5ld1hjdGVzdFJ1bkNvbnRlbnQiLCJtZXJnZSIsInVwZGF0ZVBsaXN0RmlsZSIsInJ1bm5lciIsIkVudmlyb25tZW50VmFyaWFibGVzIiwiVVNFX1BPUlQiLCJzZGtCYXNlZCIsInVkaWQiLCJwbGF0Zm9ybUJhc2VkIiwicGxhdGZvcm1WZXJzaW9uIiwiZmlsZVBhdGgiLCJ2ZXJzaW9uIiwiaW5mbyIsIm9yaWdpbmFsWGN0ZXN0cnVuRmlsZSIsImdldFhjdGVzdHJ1bkZpbGVOYW1lIiwiZXJyb3JBbmRUaHJvdyIsImlzUmVhbERldmljZSIsImtpbGxQcm9jZXNzIiwicHJvYyIsImlzUnVubmluZyIsInN0b3AiLCJpbmNsdWRlcyIsInJhbmRvbUludCIsImxvdyIsImhpZ2giLCJNYXRoIiwiZmxvb3IiLCJyYW5kb20iLCJnZXRXREFVcGdyYWRlVGltZXN0YW1wIiwicGFja2FnZU1hbmlmZXN0IiwibXRpbWUiLCJzdGF0IiwiZ2V0VGltZSIsInJlc2V0VGVzdFByb2Nlc3NlcyIsImlzU2ltdWxhdG9yIiwicHJvY2Vzc1BhdHRlcm5zIiwicHVzaCIsImdldFBJRHNMaXN0ZW5pbmdPblBvcnQiLCJwb3J0IiwiZmlsdGVyaW5nRnVuYyIsInJlc3VsdCIsInRyaW0iLCJlIiwic3RkZXJyIiwiaXNGdW5jdGlvbiJdLCJzb3VyY2VzIjpbIi4uLy4uL2xpYi91dGlscy5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBmcywgdGVtcERpciwgcGxpc3QgfSBmcm9tICdAYXBwaXVtL3N1cHBvcnQnO1xuaW1wb3J0IHsgZXhlYyB9IGZyb20gJ3RlZW5fcHJvY2Vzcyc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCBsb2cgZnJvbSAnLi9sb2dnZXInO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7IFdEQV9SVU5ORVJfQlVORExFX0lELCBQTEFURk9STV9OQU1FX1RWT1MgfSBmcm9tICcuL2NvbnN0YW50cyc7XG5pbXBvcnQgQiBmcm9tICdibHVlYmlyZCc7XG5pbXBvcnQgX2ZzIGZyb20gJ2ZzJztcbmltcG9ydCB7IHdhaXRGb3JDb25kaXRpb24gfSBmcm9tICdhc3luY2JveCc7XG5cbmNvbnN0IFBST0pFQ1RfRklMRSA9ICdwcm9qZWN0LnBieHByb2onO1xuXG4vKipcbiAqIENhbGN1bGF0ZXMgdGhlIHBhdGggdG8gdGhlIGN1cnJlbnQgbW9kdWxlJ3Mgcm9vdCBmb2xkZXJcbiAqXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZnVsbCBwYXRoIHRvIG1vZHVsZSByb290XG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIGN1cnJlbnQgbW9kdWxlIHJvb3QgZm9sZGVyIGNhbm5vdCBiZSBkZXRlcm1pbmVkXG4gKi9cbmNvbnN0IGdldE1vZHVsZVJvb3QgPSBfLm1lbW9pemUoZnVuY3Rpb24gZ2V0TW9kdWxlUm9vdCAoKSB7XG4gIGxldCBjdXJyZW50RGlyID0gcGF0aC5kaXJuYW1lKHBhdGgucmVzb2x2ZShfX2ZpbGVuYW1lKSk7XG4gIGxldCBpc0F0RnNSb290ID0gZmFsc2U7XG4gIHdoaWxlICghaXNBdEZzUm9vdCkge1xuICAgIGNvbnN0IG1hbmlmZXN0UGF0aCA9IHBhdGguam9pbihjdXJyZW50RGlyLCAncGFja2FnZS5qc29uJyk7XG4gICAgdHJ5IHtcbiAgICAgIGlmIChfZnMuZXhpc3RzU3luYyhtYW5pZmVzdFBhdGgpICYmXG4gICAgICAgICAgSlNPTi5wYXJzZShfZnMucmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCwgJ3V0ZjgnKSkubmFtZSA9PT0gJ2FwcGl1bS13ZWJkcml2ZXJhZ2VudCcpIHtcbiAgICAgICAgcmV0dXJuIGN1cnJlbnREaXI7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoaWduKSB7fVxuICAgIGN1cnJlbnREaXIgPSBwYXRoLmRpcm5hbWUoY3VycmVudERpcik7XG4gICAgaXNBdEZzUm9vdCA9IGN1cnJlbnREaXIubGVuZ3RoIDw9IHBhdGguZGlybmFtZShjdXJyZW50RGlyKS5sZW5ndGg7XG4gIH1cbiAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgZmluZCB0aGUgcm9vdCBmb2xkZXIgb2YgdGhlIGFwcGl1bS13ZWJkcml2ZXJhZ2VudCBOb2RlLmpzIG1vZHVsZScpO1xufSk7XG5cbmV4cG9ydCBjb25zdCBCT09UU1RSQVBfUEFUSCA9IGdldE1vZHVsZVJvb3QoKTtcblxuYXN5bmMgZnVuY3Rpb24gZ2V0UElEc1VzaW5nUGF0dGVybiAocGF0dGVybikge1xuICBjb25zdCBhcmdzID0gW1xuICAgICctaWYnLCAvLyBjYXNlIGluc2Vuc2l0aXZlLCBmdWxsIGNtZGxpbmUgbWF0Y2hcbiAgICBwYXR0ZXJuLFxuICBdO1xuICB0cnkge1xuICAgIGNvbnN0IHtzdGRvdXR9ID0gYXdhaXQgZXhlYygncGdyZXAnLCBhcmdzKTtcbiAgICByZXR1cm4gc3Rkb3V0LnNwbGl0KC9cXHMrLylcbiAgICAgIC5tYXAoKHgpID0+IHBhcnNlSW50KHgsIDEwKSlcbiAgICAgIC5maWx0ZXIoXy5pc0ludGVnZXIpXG4gICAgICAubWFwKCh4KSA9PiBgJHt4fWApO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBsb2cuZGVidWcoYCdwZ3JlcCAke2FyZ3Muam9pbignICcpfScgZGlkbid0IGRldGVjdCBhbnkgbWF0Y2hpbmcgcHJvY2Vzc2VzLiBSZXR1cm4gY29kZTogJHtlcnIuY29kZX1gKTtcbiAgICByZXR1cm4gW107XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24ga2lsbEFwcFVzaW5nUGF0dGVybiAocGdyZXBQYXR0ZXJuKSB7XG4gIGNvbnN0IHNpZ25hbHMgPSBbMiwgMTUsIDldO1xuICBmb3IgKGNvbnN0IHNpZ25hbCBvZiBzaWduYWxzKSB7XG4gICAgY29uc3QgbWF0Y2hlZFBpZHMgPSBhd2FpdCBnZXRQSURzVXNpbmdQYXR0ZXJuKHBncmVwUGF0dGVybik7XG4gICAgaWYgKF8uaXNFbXB0eShtYXRjaGVkUGlkcykpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgYXJncyA9IFtgLSR7c2lnbmFsfWAsIC4uLm1hdGNoZWRQaWRzXTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgZXhlYygna2lsbCcsIGFyZ3MpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgbG9nLmRlYnVnKGBraWxsICR7YXJncy5qb2luKCcgJyl9IC0+ICR7ZXJyLm1lc3NhZ2V9YCk7XG4gICAgfVxuICAgIGlmIChzaWduYWwgPT09IF8ubGFzdChzaWduYWxzKSkge1xuICAgICAgLy8gdGhlcmUgaXMgbm8gbmVlZCB0byB3YWl0IGFmdGVyIFNJR0tJTExcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHdhaXRGb3JDb25kaXRpb24oYXN5bmMgKCkgPT4ge1xuICAgICAgICBjb25zdCBwaWRDaGVja1Byb21pc2VzID0gbWF0Y2hlZFBpZHNcbiAgICAgICAgICAubWFwKChwaWQpID0+IGV4ZWMoJ2tpbGwnLCBbJy0wJywgcGlkXSlcbiAgICAgICAgICAgIC8vIHRoZSBwcm9jZXNzIGlzIHN0aWxsIGFsaXZlXG4gICAgICAgICAgICAudGhlbigoKSA9PiBmYWxzZSlcbiAgICAgICAgICAgIC8vIHRoZSBwcm9jZXNzIGlzIGRlYWRcbiAgICAgICAgICAgIC5jYXRjaCgoKSA9PiB0cnVlKVxuICAgICAgICAgICk7XG4gICAgICAgIHJldHVybiAoYXdhaXQgQi5hbGwocGlkQ2hlY2tQcm9taXNlcykpXG4gICAgICAgICAgLmV2ZXJ5KCh4KSA9PiB4ID09PSB0cnVlKTtcbiAgICAgIH0sIHtcbiAgICAgICAgd2FpdE1zOiAxMDAwLFxuICAgICAgICBpbnRlcnZhbE1zOiAxMDAsXG4gICAgICB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9IGNhdGNoIChpZ24pIHtcbiAgICAgIC8vIHRyeSB0aGUgbmV4dCBzaWduYWxcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm4gdHJ1ZSBpZiB0aGUgcGxhdGZvcm1OYW1lIGlzIHR2T1NcbiAqIEBwYXJhbSB7c3RyaW5nfSBwbGF0Zm9ybU5hbWUgVGhlIG5hbWUgb2YgdGhlIHBsYXRvcm1cbiAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm4gdHJ1ZSBpZiB0aGUgcGxhdGZvcm1OYW1lIGlzIHR2T1NcbiAqL1xuZnVuY3Rpb24gaXNUdk9TIChwbGF0Zm9ybU5hbWUpIHtcbiAgcmV0dXJuIF8udG9Mb3dlcihwbGF0Zm9ybU5hbWUpID09PSBfLnRvTG93ZXIoUExBVEZPUk1fTkFNRV9UVk9TKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVwbGFjZUluRmlsZSAoZmlsZSwgZmluZCwgcmVwbGFjZSkge1xuICBsZXQgY29udGVudHMgPSBhd2FpdCBmcy5yZWFkRmlsZShmaWxlLCAndXRmOCcpO1xuXG4gIGxldCBuZXdDb250ZW50cyA9IGNvbnRlbnRzLnJlcGxhY2UoZmluZCwgcmVwbGFjZSk7XG4gIGlmIChuZXdDb250ZW50cyAhPT0gY29udGVudHMpIHtcbiAgICBhd2FpdCBmcy53cml0ZUZpbGUoZmlsZSwgbmV3Q29udGVudHMsICd1dGY4Jyk7XG4gIH1cbn1cblxuLyoqXG4gKiBVcGRhdGUgV2ViRHJpdmVyQWdlbnRSdW5uZXIgcHJvamVjdCBidW5kbGUgSUQgd2l0aCBuZXdCdW5kbGVJZC5cbiAqIFRoaXMgbWV0aG9kIGFzc3VtZXMgcHJvamVjdCBmaWxlIGlzIGluIHRoZSBjb3JyZWN0IHN0YXRlLlxuICogQHBhcmFtIHtzdHJpbmd9IGFnZW50UGF0aCAtIFBhdGggdG8gdGhlIC54Y29kZXByb2ogZGlyZWN0b3J5LlxuICogQHBhcmFtIHtzdHJpbmd9IG5ld0J1bmRsZUlkIHRoZSBuZXcgYnVuZGxlIElEIHVzZWQgdG8gdXBkYXRlLlxuICovXG5hc3luYyBmdW5jdGlvbiB1cGRhdGVQcm9qZWN0RmlsZSAoYWdlbnRQYXRoLCBuZXdCdW5kbGVJZCkge1xuICBsZXQgcHJvamVjdEZpbGVQYXRoID0gcGF0aC5yZXNvbHZlKGFnZW50UGF0aCwgUFJPSkVDVF9GSUxFKTtcbiAgdHJ5IHtcbiAgICAvLyBBc3N1bWluZyBwcm9qZWN0RmlsZVBhdGggaXMgaW4gdGhlIGNvcnJlY3Qgc3RhdGUsIGNyZWF0ZSAub2xkIGZyb20gcHJvamVjdEZpbGVQYXRoXG4gICAgYXdhaXQgZnMuY29weUZpbGUocHJvamVjdEZpbGVQYXRoLCBgJHtwcm9qZWN0RmlsZVBhdGh9Lm9sZGApO1xuICAgIGF3YWl0IHJlcGxhY2VJbkZpbGUocHJvamVjdEZpbGVQYXRoLCBuZXcgUmVnRXhwKF8uZXNjYXBlUmVnRXhwKFdEQV9SVU5ORVJfQlVORExFX0lEKSwgJ2cnKSwgbmV3QnVuZGxlSWQpOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVzZWxlc3MtZXNjYXBlXG4gICAgbG9nLmRlYnVnKGBTdWNjZXNzZnVsbHkgdXBkYXRlZCAnJHtwcm9qZWN0RmlsZVBhdGh9JyB3aXRoIGJ1bmRsZSBpZCAnJHtuZXdCdW5kbGVJZH0nYCk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZy5kZWJ1ZyhgRXJyb3IgdXBkYXRpbmcgcHJvamVjdCBmaWxlOiAke2Vyci5tZXNzYWdlfWApO1xuICAgIGxvZy53YXJuKGBVbmFibGUgdG8gdXBkYXRlIHByb2plY3QgZmlsZSAnJHtwcm9qZWN0RmlsZVBhdGh9JyB3aXRoIGAgK1xuICAgICAgYGJ1bmRsZSBpZCAnJHtuZXdCdW5kbGVJZH0nLiBXZWJEcml2ZXJBZ2VudCBtYXkgbm90IHN0YXJ0YCk7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXNldCBXZWJEcml2ZXJBZ2VudFJ1bm5lciBwcm9qZWN0IGJ1bmRsZSBJRCB0byBjb3JyZWN0IHN0YXRlLlxuICogQHBhcmFtIHtzdHJpbmd9IGFnZW50UGF0aCAtIFBhdGggdG8gdGhlIC54Y29kZXByb2ogZGlyZWN0b3J5LlxuICovXG5hc3luYyBmdW5jdGlvbiByZXNldFByb2plY3RGaWxlIChhZ2VudFBhdGgpIHtcbiAgY29uc3QgcHJvamVjdEZpbGVQYXRoID0gcGF0aC5qb2luKGFnZW50UGF0aCwgUFJPSkVDVF9GSUxFKTtcbiAgdHJ5IHtcbiAgICAvLyByZXN0b3JlIHByb2plY3RGaWxlUGF0aCBmcm9tIC5vbGQgZmlsZVxuICAgIGlmICghYXdhaXQgZnMuZXhpc3RzKGAke3Byb2plY3RGaWxlUGF0aH0ub2xkYCkpIHtcbiAgICAgIHJldHVybjsgLy8gbm8gbmVlZCB0byByZXNldFxuICAgIH1cbiAgICBhd2FpdCBmcy5tdihgJHtwcm9qZWN0RmlsZVBhdGh9Lm9sZGAsIHByb2plY3RGaWxlUGF0aCk7XG4gICAgbG9nLmRlYnVnKGBTdWNjZXNzZnVsbHkgcmVzZXQgJyR7cHJvamVjdEZpbGVQYXRofScgd2l0aCBidW5kbGUgaWQgJyR7V0RBX1JVTk5FUl9CVU5ETEVfSUR9J2ApO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBsb2cuZGVidWcoYEVycm9yIHJlc2V0dGluZyBwcm9qZWN0IGZpbGU6ICR7ZXJyLm1lc3NhZ2V9YCk7XG4gICAgbG9nLndhcm4oYFVuYWJsZSB0byByZXNldCBwcm9qZWN0IGZpbGUgJyR7cHJvamVjdEZpbGVQYXRofScgd2l0aCBgICtcbiAgICAgIGBidW5kbGUgaWQgJyR7V0RBX1JVTk5FUl9CVU5ETEVfSUR9Jy4gV2ViRHJpdmVyQWdlbnQgaGFzIGJlZW4gYCArXG4gICAgICBgbW9kaWZpZWQgYW5kIG5vdCByZXR1cm5lZCB0byB0aGUgb3JpZ2luYWwgc3RhdGUuYCk7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gc2V0UmVhbERldmljZVNlY3VyaXR5IChrZXljaGFpblBhdGgsIGtleWNoYWluUGFzc3dvcmQpIHtcbiAgbG9nLmRlYnVnKCdTZXR0aW5nIHNlY3VyaXR5IGZvciBpT1MgZGV2aWNlJyk7XG4gIGF3YWl0IGV4ZWMoJ3NlY3VyaXR5JywgWyctdicsICdsaXN0LWtleWNoYWlucycsICctcycsIGtleWNoYWluUGF0aF0pO1xuICBhd2FpdCBleGVjKCdzZWN1cml0eScsIFsnLXYnLCAndW5sb2NrLWtleWNoYWluJywgJy1wJywga2V5Y2hhaW5QYXNzd29yZCwga2V5Y2hhaW5QYXRoXSk7XG4gIGF3YWl0IGV4ZWMoJ3NlY3VyaXR5JywgWydzZXQta2V5Y2hhaW4tc2V0dGluZ3MnLCAnLXQnLCAnMzYwMCcsICctbCcsIGtleWNoYWluUGF0aF0pO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZW5lcmF0ZVhjb2RlQ29uZmlnRmlsZSAob3JnSWQsIHNpZ25pbmdJZCkge1xuICBsb2cuZGVidWcoYEdlbmVyYXRpbmcgeGNvZGUgY29uZmlnIGZpbGUgZm9yIG9yZ0lkICcke29yZ0lkfScgYW5kIHNpZ25pbmdJZCBgICtcbiAgICAgICAgICAgIGAnJHtzaWduaW5nSWR9J2ApO1xuICBjb25zdCBjb250ZW50cyA9IGBERVZFTE9QTUVOVF9URUFNID0gJHtvcmdJZH1cbkNPREVfU0lHTl9JREVOVElUWSA9ICR7c2lnbmluZ0lkfVxuYDtcbiAgY29uc3QgeGNjb25maWdQYXRoID0gYXdhaXQgdGVtcERpci5wYXRoKCdhcHBpdW0tdGVtcC54Y2NvbmZpZycpO1xuICBsb2cuZGVidWcoYFdyaXRpbmcgeGNvZGUgY29uZmlnIGZpbGUgdG8gJHt4Y2NvbmZpZ1BhdGh9YCk7XG4gIGF3YWl0IGZzLndyaXRlRmlsZSh4Y2NvbmZpZ1BhdGgsIGNvbnRlbnRzLCAndXRmOCcpO1xuICByZXR1cm4geGNjb25maWdQYXRoO1xufVxuXG4vKipcbiAqIEluZm9ybWF0aW9uIG9mIHRoZSBkZXZpY2UgdW5kZXIgdGVzdFxuICogQHR5cGVkZWYge09iamVjdH0gRGV2aWNlSW5mb1xuICogQHByb3BlcnR5IHtzdHJpbmd9IGlzUmVhbERldmljZSAtIEVxdWFscyB0byB0cnVlIGlmIHRoZSBjdXJyZW50IGRldmljZSBpcyBhIHJlYWwgZGV2aWNlXG4gKiBAcHJvcGVydHkge3N0cmluZ30gdWRpZCAtIFRoZSBkZXZpY2UgVURJRC5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBwbGF0Zm9ybVZlcnNpb24gLSBUaGUgcGxhdGZvcm0gdmVyc2lvbiBvZiBPUy5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBwbGF0Zm9ybU5hbWUgLSBUaGUgcGxhdGZvcm0gbmFtZSBvZiBpT1MsIHR2T1NcbiovXG4vKipcbiAqIENyZWF0ZXMgeGN0ZXN0cnVuIGZpbGUgcGVyIGRldmljZSAmIHBsYXRmb3JtIHZlcnNpb24uXG4gKiBXZSBleHBlY3RzIHRvIGhhdmUgV2ViRHJpdmVyQWdlbnRSdW5uZXJfaXBob25lb3Mke3Nka1ZlcnNpb258cGxhdGZvcm1WZXJzaW9ufS1hcm02NC54Y3Rlc3RydW4gZm9yIHJlYWwgZGV2aWNlXG4gKiBhbmQgV2ViRHJpdmVyQWdlbnRSdW5uZXJfaXBob25lc2ltdWxhdG9yJHtzZGtWZXJzaW9ufHBsYXRmb3JtVmVyc2lvbn0teDg2XzY0LnhjdGVzdHJ1biBmb3Igc2ltdWxhdG9yIGxvY2F0ZWQgQGJvb3RzdHJhcFBhdGhcbiAqIE5ld2VyIFhjb2RlIChYY29kZSAxMC4wIGF0IGxlYXN0KSBnZW5lcmF0ZSB4Y3Rlc3RydW4gZmlsZSBmb2xsb3dpbmcgc2RrVmVyc2lvbi5cbiAqIGUuZy4gWGNvZGUgd2hpY2ggaGFzIGlPUyBTREsgVmVyc2lvbiAxMi4yIGdlbmVyYXRlIFdlYkRyaXZlckFnZW50UnVubmVyX2lwaG9uZXNpbXVsYXRvci4yLXg4Nl82NC54Y3Rlc3RydW5cbiAqICAgICAgZXZlbiBpZiB0aGUgY2FwIGhhcyBwbGF0Zm9ybSB2ZXJzaW9uIDExLjRcbiAqXG4gKiBAcGFyYW0ge0RldmljZUluZm99IGRldmljZUluZm9cbiAqIEBwYXJhbSB7c3RyaW5nfSBzZGtWZXJzaW9uIC0gVGhlIFhjb2RlIFNESyB2ZXJzaW9uIG9mIE9TLlxuICogQHBhcmFtIHtzdHJpbmd9IGJvb3RzdHJhcFBhdGggLSBUaGUgZm9sZGVyIHBhdGggY29udGFpbmluZyB4Y3Rlc3RydW4gZmlsZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSB3ZGFSZW1vdGVQb3J0IC0gVGhlIHJlbW90ZSBwb3J0IFdEQSBpcyBsaXN0ZW5pbmcgb24uXG4gKiBAcmV0dXJuIHtzdHJpbmd9IHJldHVybnMgeGN0ZXN0cnVuRmlsZVBhdGggZm9yIGdpdmVuIGRldmljZVxuICogQHRocm93cyBpZiBXZWJEcml2ZXJBZ2VudFJ1bm5lcl9pcGhvbmVvcyR7c2RrVmVyc2lvbnxwbGF0Zm9ybVZlcnNpb259LWFybTY0LnhjdGVzdHJ1biBmb3IgcmVhbCBkZXZpY2VcbiAqIG9yIFdlYkRyaXZlckFnZW50UnVubmVyX2lwaG9uZXNpbXVsYXRvciR7c2RrVmVyc2lvbnxwbGF0Zm9ybVZlcnNpb259LXg4Nl82NC54Y3Rlc3RydW4gZm9yIHNpbXVsYXRvciBpcyBub3QgZm91bmQgQGJvb3RzdHJhcFBhdGgsXG4gKiB0aGVuIGl0IHdpbGwgdGhyb3cgZmlsZSBub3QgZm91bmQgZXhjZXB0aW9uXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHNldFhjdGVzdHJ1bkZpbGUgKGRldmljZUluZm8sIHNka1ZlcnNpb24sIGJvb3RzdHJhcFBhdGgsIHdkYVJlbW90ZVBvcnQpIHtcbiAgY29uc3QgeGN0ZXN0cnVuRmlsZVBhdGggPSBhd2FpdCBnZXRYY3Rlc3RydW5GaWxlUGF0aChkZXZpY2VJbmZvLCBzZGtWZXJzaW9uLCBib290c3RyYXBQYXRoKTtcbiAgY29uc3QgeGN0ZXN0UnVuQ29udGVudCA9IGF3YWl0IHBsaXN0LnBhcnNlUGxpc3RGaWxlKHhjdGVzdHJ1bkZpbGVQYXRoKTtcbiAgY29uc3QgdXBkYXRlV0RBUG9ydCA9IGdldEFkZGl0aW9uYWxSdW5Db250ZW50KGRldmljZUluZm8ucGxhdGZvcm1OYW1lLCB3ZGFSZW1vdGVQb3J0KTtcbiAgY29uc3QgbmV3WGN0ZXN0UnVuQ29udGVudCA9IF8ubWVyZ2UoeGN0ZXN0UnVuQ29udGVudCwgdXBkYXRlV0RBUG9ydCk7XG4gIGF3YWl0IHBsaXN0LnVwZGF0ZVBsaXN0RmlsZSh4Y3Rlc3RydW5GaWxlUGF0aCwgbmV3WGN0ZXN0UnVuQ29udGVudCwgdHJ1ZSk7XG5cbiAgcmV0dXJuIHhjdGVzdHJ1bkZpbGVQYXRoO1xufVxuXG4vKipcbiAqIFJldHVybiB0aGUgV0RBIG9iamVjdCB3aGljaCBhcHBlbmRzIGV4aXN0aW5nIHhjdGVzdCBydW5uZXIgY29udGVudFxuICogQHBhcmFtIHtzdHJpbmd9IHBsYXRmb3JtTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBwbGF0Zm9ybVxuICogQHBhcmFtIHtzdHJpbmd9IHZlcnNpb24gLSBUaGUgWGNvZGUgU0RLIHZlcnNpb24gb2YgT1MuXG4gKiBAcmV0dXJuIHtvYmplY3R9IHJldHVybnMgYSBydW5uZXIgb2JqZWN0IHdoaWNoIGhhcyBVU0VfUE9SVFxuICovXG5mdW5jdGlvbiBnZXRBZGRpdGlvbmFsUnVuQ29udGVudCAocGxhdGZvcm1OYW1lLCB3ZGFSZW1vdGVQb3J0KSB7XG4gIGNvbnN0IHJ1bm5lciA9IGBXZWJEcml2ZXJBZ2VudFJ1bm5lciR7aXNUdk9TKHBsYXRmb3JtTmFtZSkgPyAnX3R2T1MnIDogJyd9YDtcblxuICByZXR1cm4ge1xuICAgIFtydW5uZXJdOiB7XG4gICAgICBFbnZpcm9ubWVudFZhcmlhYmxlczoge1xuICAgICAgICAvLyBVU0VfUE9SVCBtdXN0IGJlICdzdHJpbmcnXG4gICAgICAgIFVTRV9QT1JUOiBgJHt3ZGFSZW1vdGVQb3J0fWBcbiAgICAgIH1cbiAgICB9XG4gIH07XG59XG5cbi8qKlxuICogUmV0dXJuIHRoZSBwYXRoIG9mIHhjdGVzdHJ1biBpZiBpdCBleGlzdHNcbiAqIEBwYXJhbSB7RGV2aWNlSW5mb30gZGV2aWNlSW5mb1xuICogQHBhcmFtIHtzdHJpbmd9IHNka1ZlcnNpb24gLSBUaGUgWGNvZGUgU0RLIHZlcnNpb24gb2YgT1MuXG4gKiBAcGFyYW0ge3N0cmluZ30gYm9vdHN0cmFwUGF0aCAtIFRoZSBmb2xkZXIgcGF0aCBjb250YWluaW5nIHhjdGVzdHJ1biBmaWxlLlxuICovXG5hc3luYyBmdW5jdGlvbiBnZXRYY3Rlc3RydW5GaWxlUGF0aCAoZGV2aWNlSW5mbywgc2RrVmVyc2lvbiwgYm9vdHN0cmFwUGF0aCkge1xuICAvLyBGaXJzdCB0cnkgdGhlIFNESyBwYXRoLCBmb3IgWGNvZGUgMTAgKGF0IGxlYXN0KVxuICBjb25zdCBzZGtCYXNlZCA9IFtcbiAgICBwYXRoLnJlc29sdmUoYm9vdHN0cmFwUGF0aCwgYCR7ZGV2aWNlSW5mby51ZGlkfV8ke3Nka1ZlcnNpb259LnhjdGVzdHJ1bmApLFxuICAgIHNka1ZlcnNpb24sXG4gIF07XG4gIC8vIE5leHQgdHJ5IFBsYXRmb3JtIHBhdGgsIGZvciBlYXJsaWVyIFhjb2RlIHZlcnNpb25zXG4gIGNvbnN0IHBsYXRmb3JtQmFzZWQgPSBbXG4gICAgcGF0aC5yZXNvbHZlKGJvb3RzdHJhcFBhdGgsIGAke2RldmljZUluZm8udWRpZH1fJHtkZXZpY2VJbmZvLnBsYXRmb3JtVmVyc2lvbn0ueGN0ZXN0cnVuYCksXG4gICAgZGV2aWNlSW5mby5wbGF0Zm9ybVZlcnNpb24sXG4gIF07XG5cbiAgZm9yIChjb25zdCBbZmlsZVBhdGgsIHZlcnNpb25dIG9mIFtzZGtCYXNlZCwgcGxhdGZvcm1CYXNlZF0pIHtcbiAgICBpZiAoYXdhaXQgZnMuZXhpc3RzKGZpbGVQYXRoKSkge1xuICAgICAgbG9nLmluZm8oYFVzaW5nICcke2ZpbGVQYXRofScgYXMgeGN0ZXN0cnVuIGZpbGVgKTtcbiAgICAgIHJldHVybiBmaWxlUGF0aDtcbiAgICB9XG4gICAgY29uc3Qgb3JpZ2luYWxYY3Rlc3RydW5GaWxlID0gcGF0aC5yZXNvbHZlKGJvb3RzdHJhcFBhdGgsIGdldFhjdGVzdHJ1bkZpbGVOYW1lKGRldmljZUluZm8sIHZlcnNpb24pKTtcbiAgICBpZiAoYXdhaXQgZnMuZXhpc3RzKG9yaWdpbmFsWGN0ZXN0cnVuRmlsZSkpIHtcbiAgICAgIC8vIElmIHRoaXMgaXMgZmlyc3QgdGltZSBydW4gZm9yIGdpdmVuIGRldmljZSwgdGhlbiBmaXJzdCBnZW5lcmF0ZSB4Y3Rlc3RydW4gZmlsZSBmb3IgZGV2aWNlLlxuICAgICAgLy8gV2UgbmVlZCB0byBoYXZlIGEgeGN0ZXN0cnVuIGZpbGUgKipwZXIgZGV2aWNlKiogYmVjYXVzZSB3ZSBjYW50IG5vdCBoYXZlIHNhbWUgd2RhIHBvcnQgZm9yIGFsbCBkZXZpY2VzLlxuICAgICAgYXdhaXQgZnMuY29weUZpbGUob3JpZ2luYWxYY3Rlc3RydW5GaWxlLCBmaWxlUGF0aCk7XG4gICAgICBsb2cuaW5mbyhgVXNpbmcgJyR7ZmlsZVBhdGh9JyBhcyB4Y3Rlc3RydW4gZmlsZSBjb3BpZWQgYnkgJyR7b3JpZ2luYWxYY3Rlc3RydW5GaWxlfSdgKTtcbiAgICAgIHJldHVybiBmaWxlUGF0aDtcbiAgICB9XG4gIH1cblxuICBsb2cuZXJyb3JBbmRUaHJvdyhgSWYgeW91IGFyZSB1c2luZyAndXNlWGN0ZXN0cnVuRmlsZScgY2FwYWJpbGl0eSB0aGVuIHlvdSBgICtcbiAgICBgbmVlZCB0byBoYXZlIGEgeGN0ZXN0cnVuIGZpbGUgKGV4cGVjdGVkOiBgICtcbiAgICBgJyR7cGF0aC5yZXNvbHZlKGJvb3RzdHJhcFBhdGgsIGdldFhjdGVzdHJ1bkZpbGVOYW1lKGRldmljZUluZm8sIHNka1ZlcnNpb24pKX0nKWApO1xufVxuXG5cbi8qKlxuICogUmV0dXJuIHRoZSBuYW1lIG9mIHhjdGVzdHJ1biBmaWxlXG4gKiBAcGFyYW0ge0RldmljZUluZm99IGRldmljZUluZm9cbiAqIEBwYXJhbSB7c3RyaW5nfSB2ZXJzaW9uIC0gVGhlIFhjb2RlIFNESyB2ZXJzaW9uIG9mIE9TLlxuICogQHJldHVybiB7c3RyaW5nfSByZXR1cm5zIHhjdGVzdHJ1bkZpbGVQYXRoIGZvciBnaXZlbiBkZXZpY2VcbiAqL1xuZnVuY3Rpb24gZ2V0WGN0ZXN0cnVuRmlsZU5hbWUgKGRldmljZUluZm8sIHZlcnNpb24pIHtcbiAgcmV0dXJuIGlzVHZPUyhkZXZpY2VJbmZvLnBsYXRmb3JtTmFtZSlcbiAgICA/IGBXZWJEcml2ZXJBZ2VudFJ1bm5lcl90dk9TX2FwcGxldHYke2RldmljZUluZm8uaXNSZWFsRGV2aWNlID8gYG9zJHt2ZXJzaW9ufS1hcm02NGAgOiBgc2ltdWxhdG9yJHt2ZXJzaW9ufS14ODZfNjRgfS54Y3Rlc3RydW5gXG4gICAgOiBgV2ViRHJpdmVyQWdlbnRSdW5uZXJfaXBob25lJHtkZXZpY2VJbmZvLmlzUmVhbERldmljZSA/IGBvcyR7dmVyc2lvbn0tYXJtNjRgIDogYHNpbXVsYXRvciR7dmVyc2lvbn0teDg2XzY0YH0ueGN0ZXN0cnVuYDtcbn1cblxuYXN5bmMgZnVuY3Rpb24ga2lsbFByb2Nlc3MgKG5hbWUsIHByb2MpIHtcbiAgaWYgKCFwcm9jIHx8ICFwcm9jLmlzUnVubmluZykge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGxvZy5pbmZvKGBTaHV0dGluZyBkb3duICcke25hbWV9JyBwcm9jZXNzIChwaWQgJyR7cHJvYy5wcm9jLnBpZH0nKWApO1xuXG4gIGxvZy5pbmZvKGBTZW5kaW5nICdTSUdURVJNJy4uLmApO1xuICB0cnkge1xuICAgIGF3YWl0IHByb2Muc3RvcCgnU0lHVEVSTScsIDEwMDApO1xuICAgIHJldHVybjtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgaWYgKCFlcnIubWVzc2FnZS5pbmNsdWRlcyhgUHJvY2VzcyBkaWRuJ3QgZW5kIGFmdGVyYCkpIHtcbiAgICAgIHRocm93IGVycjtcbiAgICB9XG4gICAgbG9nLmRlYnVnKGAke25hbWV9IHByb2Nlc3MgZGlkIG5vdCBlbmQgaW4gYSB0aW1lbHkgZmFzaGlvbjogJyR7ZXJyLm1lc3NhZ2V9Jy5gKTtcbiAgfVxuXG4gIGxvZy5pbmZvKGBTZW5kaW5nICdTSUdLSUxMJy4uLmApO1xuICB0cnkge1xuICAgIGF3YWl0IHByb2Muc3RvcCgnU0lHS0lMTCcpO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBpZiAoZXJyLm1lc3NhZ2UuaW5jbHVkZXMoJ25vdCBjdXJyZW50bHkgcnVubmluZycpKSB7XG4gICAgICAvLyB0aGUgcHJvY2VzcyBlbmRlZCBidXQgZm9yIHNvbWUgcmVhc29uIHdlIHdlcmUgbm90IGluZm9ybWVkXG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRocm93IGVycjtcbiAgfVxufVxuXG4vKipcbiAqIEdlbmVyYXRlIGEgcmFuZG9tIGludGVnZXIuXG4gKlxuICogQHJldHVybiB7bnVtYmVyfSBBIHJhbmRvbSBpbnRlZ2VyIG51bWJlciBpbiByYW5nZSBbbG93LCBoaWdodCkuIGBsb3dgYCBpcyBpbmNsdXNpdmUgYW5kIGBoaWdoYCBpcyBleGNsdXNpdmUuXG4gKi9cbmZ1bmN0aW9uIHJhbmRvbUludCAobG93LCBoaWdoKSB7XG4gIHJldHVybiBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAoaGlnaCAtIGxvdykgKyBsb3cpO1xufVxuXG4vKipcbiAqIFJldHJpZXZlcyBXREEgdXBncmFkZSB0aW1lc3RhbXBcbiAqXG4gKiBAcmV0dXJuIHs/bnVtYmVyfSBUaGUgVU5JWCB0aW1lc3RhbXAgb2YgdGhlIHBhY2thZ2UgbWFuaWZlc3QuIFRoZSBtYW5pZmVzdCBvbmx5IGdldHMgbW9kaWZpZWQgb25cbiAqIHBhY2thZ2UgdXBncmFkZS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gZ2V0V0RBVXBncmFkZVRpbWVzdGFtcCAoKSB7XG4gIGNvbnN0IHBhY2thZ2VNYW5pZmVzdCA9IHBhdGgucmVzb2x2ZShnZXRNb2R1bGVSb290KCksICdwYWNrYWdlLmpzb24nKTtcbiAgaWYgKCFhd2FpdCBmcy5leGlzdHMocGFja2FnZU1hbmlmZXN0KSkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIGNvbnN0IHttdGltZX0gPSBhd2FpdCBmcy5zdGF0KHBhY2thZ2VNYW5pZmVzdCk7XG4gIHJldHVybiBtdGltZS5nZXRUaW1lKCk7XG59XG5cbi8qKlxuICogS2lsbHMgcnVubmluZyBYQ1Rlc3QgcHJvY2Vzc2VzIGZvciB0aGUgcGFydGljdWxhciBkZXZpY2UuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHVkaWQgLSBUaGUgZGV2aWNlIFVESUQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGlzU2ltdWxhdG9yIC0gRXF1YWxzIHRvIHRydWUgaWYgdGhlIGN1cnJlbnQgZGV2aWNlIGlzIGEgU2ltdWxhdG9yXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlc2V0VGVzdFByb2Nlc3NlcyAodWRpZCwgaXNTaW11bGF0b3IpIHtcbiAgY29uc3QgcHJvY2Vzc1BhdHRlcm5zID0gW2B4Y29kZWJ1aWxkLioke3VkaWR9YF07XG4gIGlmIChpc1NpbXVsYXRvcikge1xuICAgIHByb2Nlc3NQYXR0ZXJucy5wdXNoKGAke3VkaWR9LipYQ1RSdW5uZXJgKTtcbiAgICAvLyBUaGUgcGF0dGVybiB0byBmaW5kIGluIGNhc2UgaWRiIHdhcyB1c2VkXG4gICAgcHJvY2Vzc1BhdHRlcm5zLnB1c2goYHhjdGVzdC4qJHt1ZGlkfWApO1xuICB9XG4gIGxvZy5kZWJ1ZyhgS2lsbGluZyBydW5uaW5nIHByb2Nlc3NlcyAnJHtwcm9jZXNzUGF0dGVybnMuam9pbignLCAnKX0nIGZvciB0aGUgZGV2aWNlICR7dWRpZH0uLi5gKTtcbiAgYXdhaXQgQi5hbGwocHJvY2Vzc1BhdHRlcm5zLm1hcChraWxsQXBwVXNpbmdQYXR0ZXJuKSk7XG59XG5cbi8qKlxuICogR2V0IHRoZSBJRHMgb2YgcHJvY2Vzc2VzIGxpc3RlbmluZyBvbiB0aGUgcGFydGljdWxhciBzeXN0ZW0gcG9ydC5cbiAqIEl0IGlzIGFsc28gcG9zc2libGUgdG8gYXBwbHkgYWRkaXRpb25hbCBmaWx0ZXJpbmcgYmFzZWQgb24gdGhlXG4gKiBwcm9jZXNzIGNvbW1hbmQgbGluZS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ3xudW1iZXJ9IHBvcnQgLSBUaGUgcG9ydCBudW1iZXIuXG4gKiBAcGFyYW0gez9GdW5jdGlvbn0gZmlsdGVyaW5nRnVuYyAtIE9wdGlvbmFsIGxhbWJkYSBmdW5jdGlvbiwgd2hpY2hcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2ZXMgY29tbWFuZCBsaW5lIHN0cmluZyBvZiB0aGUgcGFydGljdWxhciBwcm9jZXNzXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3RlbmluZyBvbiBnaXZlbiBwb3J0LCBhbmQgaXMgZXhwZWN0ZWQgdG8gcmV0dXJuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVpdGhlciB0cnVlIG9yIGZhbHNlIHRvIGluY2x1ZGUvZXhjbHVkZSB0aGUgY29ycmVzcG9uZGluZyBQSURcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnJvbSB0aGUgcmVzdWx0aW5nIGFycmF5LlxuICogQHJldHVybnMge0FycmF5PHN0cmluZz59IC0gdGhlIGxpc3Qgb2YgbWF0Y2hlZCBwcm9jZXNzIGlkcy5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gZ2V0UElEc0xpc3RlbmluZ09uUG9ydCAocG9ydCwgZmlsdGVyaW5nRnVuYyA9IG51bGwpIHtcbiAgY29uc3QgcmVzdWx0ID0gW107XG4gIHRyeSB7XG4gICAgLy8gVGhpcyBvbmx5IHdvcmtzIHNpbmNlIE1hYyBPUyBYIEVsIENhcGl0YW5cbiAgICBjb25zdCB7c3Rkb3V0fSA9IGF3YWl0IGV4ZWMoJ2xzb2YnLCBbJy10aScsIGB0Y3A6JHtwb3J0fWBdKTtcbiAgICByZXN1bHQucHVzaCguLi4oc3Rkb3V0LnRyaW0oKS5zcGxpdCgvXFxuKy8pKSk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBpZiAoZS5jb2RlICE9PSAxKSB7XG4gICAgICAvLyBjb2RlIDEgbWVhbnMgbm8gcHJvY2Vzc2VzLiBPdGhlciBlcnJvcnMgbmVlZCByZXBvcnRpbmdcbiAgICAgIGxvZy5kZWJ1ZyhgRXJyb3IgZ2V0dGluZyBwcm9jZXNzZXMgbGlzdGVuaW5nIG9uIHBvcnQgJyR7cG9ydH0nOiAke2Uuc3RkZXJyIHx8IGUubWVzc2FnZX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGlmICghXy5pc0Z1bmN0aW9uKGZpbHRlcmluZ0Z1bmMpKSB7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuICByZXR1cm4gYXdhaXQgQi5maWx0ZXIocmVzdWx0LCBhc3luYyAocGlkKSA9PiB7XG4gICAgbGV0IHN0ZG91dDtcbiAgICB0cnkge1xuICAgICAgKHtzdGRvdXR9ID0gYXdhaXQgZXhlYygncHMnLCBbJy1wJywgcGlkLCAnLW8nLCAnY29tbWFuZCddKSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgaWYgKGUuY29kZSA9PT0gMSkge1xuICAgICAgICAvLyBUaGUgcHJvY2VzcyBkb2VzIG5vdCBleGlzdCBhbnltb3JlLCB0aGVyZSdzIG5vdGhpbmcgdG8gZmlsdGVyXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICAgIHRocm93IGU7XG4gICAgfVxuICAgIHJldHVybiBhd2FpdCBmaWx0ZXJpbmdGdW5jKHN0ZG91dCk7XG4gIH0pO1xufVxuXG5leHBvcnQgeyB1cGRhdGVQcm9qZWN0RmlsZSwgcmVzZXRQcm9qZWN0RmlsZSwgc2V0UmVhbERldmljZVNlY3VyaXR5LFxuICBnZXRBZGRpdGlvbmFsUnVuQ29udGVudCwgZ2V0WGN0ZXN0cnVuRmlsZU5hbWUsIGdlbmVyYXRlWGNvZGVDb25maWdGaWxlLFxuICBzZXRYY3Rlc3RydW5GaWxlLCBnZXRYY3Rlc3RydW5GaWxlUGF0aCwga2lsbFByb2Nlc3MsIHJhbmRvbUludCxcbiAgZ2V0V0RBVXBncmFkZVRpbWVzdGFtcCwgcmVzZXRUZXN0UHJvY2Vzc2VzLFxuICBnZXRQSURzTGlzdGVuaW5nT25Qb3J0LCBr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
|
|
392
|
+
exports.getPIDsListeningOnPort = getPIDsListeningOnPort;
|
|
393
|
+
//# sourceMappingURL=utils.js.map
|