appium-android-driver 5.13.1 → 5.13.2
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 +43 -40
- package/build/lib/android-helpers.d.ts +136 -0
- package/build/lib/android-helpers.d.ts.map +1 -0
- package/build/lib/android-helpers.js +760 -679
- package/build/lib/android-helpers.js.map +1 -1
- package/build/lib/bootstrap.d.ts +29 -0
- package/build/lib/bootstrap.d.ts.map +1 -0
- package/build/lib/bootstrap.js +192 -179
- package/build/lib/bootstrap.js.map +1 -1
- package/build/lib/commands/actions.d.ts +209 -0
- package/build/lib/commands/actions.d.ts.map +1 -0
- package/build/lib/commands/actions.js +327 -265
- package/build/lib/commands/actions.js.map +1 -1
- package/build/lib/commands/alert.d.ts +10 -0
- package/build/lib/commands/alert.d.ts.map +1 -0
- package/build/lib/commands/alert.js +12 -18
- package/build/lib/commands/alert.js.map +1 -1
- package/build/lib/commands/app-management.d.ts +314 -0
- package/build/lib/commands/app-management.d.ts.map +1 -0
- package/build/lib/commands/app-management.js +278 -110
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/context.d.ts +94 -0
- package/build/lib/commands/context.d.ts.map +1 -0
- package/build/lib/commands/context.js +412 -260
- package/build/lib/commands/context.js.map +1 -1
- package/build/lib/commands/coverage.d.ts +5 -0
- package/build/lib/commands/coverage.d.ts.map +1 -0
- package/build/lib/commands/coverage.js +14 -17
- package/build/lib/commands/coverage.js.map +1 -1
- package/build/lib/commands/element.d.ts +36 -0
- package/build/lib/commands/element.d.ts.map +1 -0
- package/build/lib/commands/element.js +97 -127
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/emu-console.d.ts +49 -0
- package/build/lib/commands/emu-console.d.ts.map +1 -0
- package/build/lib/commands/emu-console.js +36 -25
- package/build/lib/commands/emu-console.js.map +1 -1
- package/build/lib/commands/execute.d.ts +6 -0
- package/build/lib/commands/execute.d.ts.map +1 -0
- package/build/lib/commands/execute.js +68 -69
- package/build/lib/commands/execute.js.map +1 -1
- package/build/lib/commands/file-actions.d.ts +129 -0
- package/build/lib/commands/file-actions.d.ts.map +1 -0
- package/build/lib/commands/file-actions.js +321 -178
- package/build/lib/commands/file-actions.js.map +1 -1
- package/build/lib/commands/find.d.ts +13 -0
- package/build/lib/commands/find.d.ts.map +1 -0
- package/build/lib/commands/find.js +69 -51
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/general.d.ts +133 -0
- package/build/lib/commands/general.d.ts.map +1 -0
- package/build/lib/commands/general.js +275 -216
- package/build/lib/commands/general.js.map +1 -1
- package/build/lib/commands/ime.d.ts +11 -0
- package/build/lib/commands/ime.d.ts.map +1 -0
- package/build/lib/commands/ime.js +27 -33
- package/build/lib/commands/ime.js.map +1 -1
- package/build/lib/commands/index.d.ts +3 -0
- package/build/lib/commands/index.d.ts.map +1 -0
- package/build/lib/commands/index.js +32 -35
- package/build/lib/commands/index.js.map +1 -1
- package/build/lib/commands/intent.d.ts +418 -0
- package/build/lib/commands/intent.d.ts.map +1 -0
- package/build/lib/commands/intent.js +281 -151
- package/build/lib/commands/intent.js.map +1 -1
- package/build/lib/commands/keyboard.d.ts +6 -0
- package/build/lib/commands/keyboard.d.ts.map +1 -0
- package/build/lib/commands/keyboard.js +6 -14
- package/build/lib/commands/keyboard.js.map +1 -1
- package/build/lib/commands/log.d.ts +45 -0
- package/build/lib/commands/log.d.ts.map +1 -0
- package/build/lib/commands/log.js +117 -103
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/media-projection.d.ts +144 -0
- package/build/lib/commands/media-projection.d.ts.map +1 -0
- package/build/lib/commands/media-projection.js +228 -171
- package/build/lib/commands/media-projection.js.map +1 -1
- package/build/lib/commands/network.d.ts +139 -0
- package/build/lib/commands/network.d.ts.map +1 -0
- package/build/lib/commands/network.js +249 -181
- package/build/lib/commands/network.js.map +1 -1
- package/build/lib/commands/performance.d.ts +101 -0
- package/build/lib/commands/performance.d.ts.map +1 -0
- package/build/lib/commands/performance.js +390 -236
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/permissions.d.ts +93 -0
- package/build/lib/commands/permissions.d.ts.map +1 -0
- package/build/lib/commands/permissions.js +133 -93
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/commands/recordscreen.d.ts +194 -0
- package/build/lib/commands/recordscreen.d.ts.map +1 -0
- package/build/lib/commands/recordscreen.js +293 -224
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/commands/shell.d.ts +8 -0
- package/build/lib/commands/shell.d.ts.map +1 -0
- package/build/lib/commands/shell.js +38 -43
- package/build/lib/commands/shell.js.map +1 -1
- package/build/lib/commands/streamscreen.d.ts +104 -0
- package/build/lib/commands/streamscreen.d.ts.map +1 -0
- package/build/lib/commands/streamscreen.js +364 -305
- package/build/lib/commands/streamscreen.js.map +1 -1
- package/build/lib/commands/system-bars.d.ts +100 -0
- package/build/lib/commands/system-bars.d.ts.map +1 -0
- package/build/lib/commands/system-bars.js +148 -90
- package/build/lib/commands/system-bars.js.map +1 -1
- package/build/lib/commands/touch.d.ts +30 -0
- package/build/lib/commands/touch.d.ts.map +1 -0
- package/build/lib/commands/touch.js +311 -287
- package/build/lib/commands/touch.js.map +1 -1
- package/build/lib/desired-caps.d.ts +353 -0
- package/build/lib/desired-caps.d.ts.map +1 -0
- package/build/lib/desired-caps.js +291 -292
- package/build/lib/desired-caps.js.map +1 -1
- package/build/lib/driver.d.ts +430 -0
- package/build/lib/driver.d.ts.map +1 -0
- package/build/lib/driver.js +449 -384
- package/build/lib/driver.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/method-map.d.ts +389 -0
- package/build/lib/method-map.d.ts.map +1 -0
- package/build/lib/method-map.js +220 -394
- package/build/lib/method-map.js.map +1 -1
- package/build/lib/stubs.d.ts +8 -0
- package/build/lib/stubs.d.ts.map +1 -0
- package/build/lib/stubs.js +5 -0
- package/build/lib/stubs.js.map +1 -0
- package/build/lib/uiautomator.d.ts +24 -0
- package/build/lib/uiautomator.d.ts.map +1 -0
- package/build/lib/uiautomator.js +86 -82
- package/build/lib/uiautomator.js.map +1 -1
- package/build/lib/unlock-helpers.d.ts +38 -0
- package/build/lib/unlock-helpers.d.ts.map +1 -0
- package/build/lib/unlock-helpers.js +228 -204
- package/build/lib/unlock-helpers.js.map +1 -1
- package/build/lib/utils.d.ts +11 -0
- package/build/lib/utils.d.ts.map +1 -0
- package/build/lib/utils.js +23 -18
- package/build/lib/utils.js.map +1 -1
- package/build/lib/webview-helpers.d.ts +223 -0
- package/build/lib/webview-helpers.d.ts.map +1 -0
- package/build/lib/webview-helpers.js +476 -298
- package/build/lib/webview-helpers.js.map +1 -1
- package/index.js +3 -1
- package/lib/android-helpers.js +2 -1
- package/lib/stubs.ts +8 -0
- package/lib/unlock-helpers.js +2 -2
- package/package.json +23 -14
|
@@ -1,774 +1,855 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
require("
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
var _bluebird = _interopRequireDefault(require("bluebird"));
|
|
20
|
-
var _appiumAdb = _interopRequireDefault(require("appium-adb"));
|
|
21
|
-
var _unlockHelpers = _interopRequireWildcard(require("./unlock-helpers"));
|
|
22
|
-
var _os = require("os");
|
|
23
|
-
var _semver = _interopRequireDefault(require("semver"));
|
|
24
|
-
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
25
|
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
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.ensureNetworkSpeed = exports.prepareAvdArgs = exports.APP_STATE = exports.SETTINGS_HELPER_PKG_ID = exports.helpers = void 0;
|
|
7
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const asyncbox_1 = require("asyncbox");
|
|
10
|
+
const logger_1 = __importDefault(require("./logger"));
|
|
11
|
+
const support_1 = require("@appium/support");
|
|
12
|
+
const io_appium_settings_1 = require("io.appium.settings");
|
|
13
|
+
const bootstrap_1 = __importDefault(require("./bootstrap"));
|
|
14
|
+
const bluebird_1 = __importDefault(require("bluebird"));
|
|
15
|
+
const appium_adb_1 = __importDefault(require("appium-adb"));
|
|
16
|
+
const unlock_helpers_1 = require("./unlock-helpers");
|
|
17
|
+
const os_1 = require("os");
|
|
18
|
+
const semver_1 = __importDefault(require("semver"));
|
|
26
19
|
const MOCK_APP_IDS_STORE = '/data/local/tmp/mock_apps.json';
|
|
27
20
|
const PACKAGE_INSTALL_TIMEOUT_MS = 90000;
|
|
28
21
|
const HELPER_APP_INSTALL_RETRIES = 3;
|
|
29
22
|
const HELPER_APP_INSTALL_RETRY_DELAY_MS = 5000;
|
|
23
|
+
// https://cs.chromium.org/chromium/src/chrome/browser/devtools/device/android_device_info_query.cc
|
|
30
24
|
const CHROME_BROWSER_PACKAGE_ACTIVITY = {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
25
|
+
chrome: {
|
|
26
|
+
pkg: 'com.android.chrome',
|
|
27
|
+
activity: 'com.google.android.apps.chrome.Main',
|
|
28
|
+
},
|
|
29
|
+
chromium: {
|
|
30
|
+
pkg: 'org.chromium.chrome.shell',
|
|
31
|
+
activity: '.ChromeShellActivity',
|
|
32
|
+
},
|
|
33
|
+
chromebeta: {
|
|
34
|
+
pkg: 'com.chrome.beta',
|
|
35
|
+
activity: 'com.google.android.apps.chrome.Main',
|
|
36
|
+
},
|
|
37
|
+
browser: {
|
|
38
|
+
pkg: 'com.android.browser',
|
|
39
|
+
activity: 'com.android.browser.BrowserActivity',
|
|
40
|
+
},
|
|
41
|
+
'chromium-browser': {
|
|
42
|
+
pkg: 'org.chromium.chrome',
|
|
43
|
+
activity: 'com.google.android.apps.chrome.Main',
|
|
44
|
+
},
|
|
45
|
+
'chromium-webview': {
|
|
46
|
+
pkg: 'org.chromium.webview_shell',
|
|
47
|
+
activity: 'org.chromium.webview_shell.WebViewBrowserActivity',
|
|
48
|
+
},
|
|
49
|
+
default: {
|
|
50
|
+
pkg: 'com.android.chrome',
|
|
51
|
+
activity: 'com.google.android.apps.chrome.Main',
|
|
52
|
+
},
|
|
59
53
|
};
|
|
60
54
|
const SETTINGS_HELPER_PKG_ID = 'io.appium.settings';
|
|
61
55
|
exports.SETTINGS_HELPER_PKG_ID = SETTINGS_HELPER_PKG_ID;
|
|
62
56
|
const SETTING_NOTIFICATIONS_LISTENER_SERVICE = `${SETTINGS_HELPER_PKG_ID}/.NLService`;
|
|
63
57
|
const EMULATOR_PATTERN = /\bemulator\b/i;
|
|
58
|
+
// These constants are in sync with
|
|
59
|
+
// https://developer.apple.com/documentation/xctest/xcuiapplicationstate/xcuiapplicationstaterunningbackground?language=objc
|
|
64
60
|
const APP_STATE = Object.freeze({
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
NOT_INSTALLED: 0,
|
|
62
|
+
NOT_RUNNING: 1,
|
|
63
|
+
RUNNING_IN_BACKGROUND: 3,
|
|
64
|
+
RUNNING_IN_FOREGROUND: 4
|
|
69
65
|
});
|
|
70
66
|
exports.APP_STATE = APP_STATE;
|
|
71
67
|
function ensureNetworkSpeed(adb, networkSpeed) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
if (lodash_1.default.values(adb.NETWORK_SPEED).includes(networkSpeed)) {
|
|
69
|
+
return networkSpeed;
|
|
70
|
+
}
|
|
71
|
+
logger_1.default.warn(`Wrong network speed param '${networkSpeed}', using default: ${adb.NETWORK_SPEED.FULL}. ` +
|
|
72
|
+
`Supported values: ${lodash_1.default.values(adb.NETWORK_SPEED)}`);
|
|
73
|
+
return adb.NETWORK_SPEED.FULL;
|
|
77
74
|
}
|
|
75
|
+
exports.ensureNetworkSpeed = ensureNetworkSpeed;
|
|
78
76
|
function prepareAvdArgs(adb, opts) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
result.push('-no-window');
|
|
97
|
-
}
|
|
98
|
-
return result;
|
|
77
|
+
const { networkSpeed, isHeadless, avdArgs, } = opts;
|
|
78
|
+
const result = [];
|
|
79
|
+
if (avdArgs) {
|
|
80
|
+
if (lodash_1.default.isArray(avdArgs)) {
|
|
81
|
+
result.push(...avdArgs);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
result.push(...(support_1.util.shellParse(`${avdArgs}`)));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (networkSpeed) {
|
|
88
|
+
result.push('-netspeed', ensureNetworkSpeed(adb, networkSpeed));
|
|
89
|
+
}
|
|
90
|
+
if (isHeadless) {
|
|
91
|
+
result.push('-no-window');
|
|
92
|
+
}
|
|
93
|
+
return result;
|
|
99
94
|
}
|
|
95
|
+
exports.prepareAvdArgs = prepareAvdArgs;
|
|
100
96
|
function toCredentialType(unlockType) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
97
|
+
const result = {
|
|
98
|
+
[unlock_helpers_1.PIN_UNLOCK]: 'pin',
|
|
99
|
+
[unlock_helpers_1.PIN_UNLOCK_KEY_EVENT]: 'pin',
|
|
100
|
+
[unlock_helpers_1.PASSWORD_UNLOCK]: 'password',
|
|
101
|
+
[unlock_helpers_1.PATTERN_UNLOCK]: 'pattern',
|
|
102
|
+
}[unlockType];
|
|
103
|
+
if (result) {
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
throw new Error(`Unlock type '${unlockType}' is not known`);
|
|
111
107
|
}
|
|
112
108
|
const helpers = {};
|
|
113
109
|
exports.helpers = helpers;
|
|
114
110
|
helpers.createBaseADB = async function createBaseADB(opts = {}) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
suppressKillServer,
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
remoteAdbHost,
|
|
135
|
-
clearDeviceLogsOnStart,
|
|
136
|
-
adbExecTimeout,
|
|
137
|
-
useKeystore,
|
|
138
|
-
keystorePath,
|
|
139
|
-
keystorePassword,
|
|
140
|
-
keyAlias,
|
|
141
|
-
keyPassword,
|
|
142
|
-
remoteAppsCacheLimit,
|
|
143
|
-
buildToolsVersion,
|
|
144
|
-
allowOfflineDevices,
|
|
145
|
-
allowDelayAdb
|
|
146
|
-
});
|
|
111
|
+
// filter out any unwanted options sent in
|
|
112
|
+
// this list should be updated as ADB takes more arguments
|
|
113
|
+
const { adbPort, suppressKillServer, remoteAdbHost, clearDeviceLogsOnStart, adbExecTimeout, useKeystore, keystorePath, keystorePassword, keyAlias, keyPassword, remoteAppsCacheLimit, buildToolsVersion, allowOfflineDevices, allowDelayAdb, } = opts;
|
|
114
|
+
return await appium_adb_1.default.createADB({
|
|
115
|
+
adbPort,
|
|
116
|
+
suppressKillServer,
|
|
117
|
+
remoteAdbHost,
|
|
118
|
+
clearDeviceLogsOnStart,
|
|
119
|
+
adbExecTimeout,
|
|
120
|
+
useKeystore,
|
|
121
|
+
keystorePath,
|
|
122
|
+
keystorePassword,
|
|
123
|
+
keyAlias,
|
|
124
|
+
keyPassword,
|
|
125
|
+
remoteAppsCacheLimit,
|
|
126
|
+
buildToolsVersion,
|
|
127
|
+
allowOfflineDevices,
|
|
128
|
+
allowDelayAdb,
|
|
129
|
+
});
|
|
147
130
|
};
|
|
148
131
|
helpers.prepareEmulator = async function prepareEmulator(adb, opts) {
|
|
149
|
-
|
|
150
|
-
avd
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
language,
|
|
182
|
-
country,
|
|
183
|
-
launchTimeout,
|
|
184
|
-
readyTimeout
|
|
185
|
-
});
|
|
132
|
+
const { avd, avdEnv: env, language, locale: country, avdLaunchTimeout: launchTimeout, avdReadyTimeout: readyTimeout, } = opts;
|
|
133
|
+
if (!avd) {
|
|
134
|
+
throw new Error('Cannot launch AVD without AVD name');
|
|
135
|
+
}
|
|
136
|
+
const avdName = avd.replace('@', '');
|
|
137
|
+
let isEmulatorRunning = true;
|
|
138
|
+
try {
|
|
139
|
+
await adb.getRunningAVDWithRetry(avdName, 5000);
|
|
140
|
+
}
|
|
141
|
+
catch (e) {
|
|
142
|
+
logger_1.default.debug(`Emulator '${avdName}' is not running: ${e.message}`);
|
|
143
|
+
isEmulatorRunning = false;
|
|
144
|
+
}
|
|
145
|
+
const args = prepareAvdArgs(adb, opts);
|
|
146
|
+
if (isEmulatorRunning) {
|
|
147
|
+
if (args.includes('-wipe-data')) {
|
|
148
|
+
logger_1.default.debug(`Killing '${avdName}' because it needs to be wiped at start.`);
|
|
149
|
+
await adb.killEmulator(avdName);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
logger_1.default.debug('Not launching AVD because it is already running.');
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
await adb.launchAVD(avd, {
|
|
157
|
+
args,
|
|
158
|
+
env,
|
|
159
|
+
language,
|
|
160
|
+
country,
|
|
161
|
+
launchTimeout,
|
|
162
|
+
readyTimeout,
|
|
163
|
+
});
|
|
186
164
|
};
|
|
165
|
+
/**
|
|
166
|
+
* Set and ensure the locale name of the device under test.
|
|
167
|
+
*
|
|
168
|
+
* @param {Object} adb - The adb module instance.
|
|
169
|
+
* @param {string} language - Language. The language field is case insensitive, but Locale always canonicalizes to lower case.
|
|
170
|
+
* format: [a-zA-Z]{2,8}. e.g. en, ja : https://developer.android.com/reference/java/util/Locale.html
|
|
171
|
+
* @param {string} country - Country. The country (region) field is case insensitive, but Locale always canonicalizes to upper case.
|
|
172
|
+
* format: [a-zA-Z]{2} | [0-9]{3}. e.g. US, JP : https://developer.android.com/reference/java/util/Locale.html
|
|
173
|
+
* @param {?string} script - Script. The script field is case insensitive but Locale always canonicalizes to title case.
|
|
174
|
+
* format: [a-zA-Z]{4}. e.g. Hans in zh-Hans-CN : https://developer.android.com/reference/java/util/Locale.html
|
|
175
|
+
* @throws {Error} If it failed to set locale properly
|
|
176
|
+
*/
|
|
187
177
|
helpers.ensureDeviceLocale = async function ensureDeviceLocale(adb, language, country, script = null) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
178
|
+
if (!lodash_1.default.isString(language) && !lodash_1.default.isString(country)) {
|
|
179
|
+
logger_1.default.warn(`setDeviceLanguageCountry requires language or country.`);
|
|
180
|
+
logger_1.default.warn(`Got language: '${language}' and country: '${country}'`);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
await adb.setDeviceLanguageCountry(language, country, script);
|
|
184
|
+
if (!await adb.ensureCurrentLocale(language, country, script)) {
|
|
185
|
+
const message = script ? `language: ${language}, country: ${country} and script: ${script}` : `language: ${language} and country: ${country}`;
|
|
186
|
+
throw new Error(`Failed to set ${message}`);
|
|
187
|
+
}
|
|
198
188
|
};
|
|
199
189
|
helpers.getDeviceInfoFromCaps = async function getDeviceInfoFromCaps(opts = {}) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
await helpers.
|
|
205
|
-
udid =
|
|
206
|
-
emPort =
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
190
|
+
// we can create a throwaway ADB instance here, so there is no dependency
|
|
191
|
+
// on instantiating on earlier (at this point, we have no udid)
|
|
192
|
+
// we can only use this ADB object for commands that would not be confused
|
|
193
|
+
// if multiple devices are connected
|
|
194
|
+
const adb = await helpers.createBaseADB(opts);
|
|
195
|
+
let udid = opts.udid;
|
|
196
|
+
let emPort = null;
|
|
197
|
+
// a specific avd name was given. try to initialize with that
|
|
198
|
+
if (opts.avd) {
|
|
199
|
+
await helpers.prepareEmulator(adb, opts);
|
|
200
|
+
udid = adb.curDeviceId;
|
|
201
|
+
emPort = adb.emulatorPort;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
// no avd given. lets try whatever's plugged in devices/emulators
|
|
205
|
+
logger_1.default.info('Retrieving device list');
|
|
206
|
+
let devices = await adb.getDevicesWithRetry();
|
|
207
|
+
// udid was given, lets try to init with that device
|
|
208
|
+
if (udid) {
|
|
209
|
+
if (!lodash_1.default.includes(lodash_1.default.map(devices, 'udid'), udid)) {
|
|
210
|
+
logger_1.default.errorAndThrow(`Device ${udid} was not in the list of connected devices`);
|
|
211
|
+
}
|
|
212
|
+
emPort = adb.getPortFromEmulatorString(udid);
|
|
213
|
+
}
|
|
214
|
+
else if (opts.platformVersion) {
|
|
215
|
+
opts.platformVersion = `${opts.platformVersion}`.trim();
|
|
216
|
+
// a platform version was given. lets try to find a device with the same os
|
|
217
|
+
const platformVersion = semver_1.default.coerce(opts.platformVersion) || opts.platformVersion;
|
|
218
|
+
logger_1.default.info(`Looking for a device with Android '${platformVersion}'`);
|
|
219
|
+
// in case we fail to find something, give the user a useful log that has
|
|
220
|
+
// the device udids and os versions so they know what's available
|
|
221
|
+
const availDevices = [];
|
|
222
|
+
let partialMatchCandidate = null;
|
|
223
|
+
// first try started devices/emulators
|
|
224
|
+
for (const device of devices) {
|
|
225
|
+
// direct adb calls to the specific device
|
|
226
|
+
await adb.setDeviceId(device.udid);
|
|
227
|
+
const rawDeviceOS = await adb.getPlatformVersion();
|
|
228
|
+
// The device OS could either be a number, like `6.0`
|
|
229
|
+
// or an abbreviation, like `R`
|
|
230
|
+
availDevices.push(`${device.udid} (${rawDeviceOS})`);
|
|
231
|
+
const deviceOS = semver_1.default.coerce(rawDeviceOS) || rawDeviceOS;
|
|
232
|
+
if (!deviceOS) {
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
const bothVersionsCanBeCoerced = semver_1.default.valid(deviceOS) && semver_1.default.valid(platformVersion);
|
|
236
|
+
const bothVersionsAreStrings = lodash_1.default.isString(deviceOS) && lodash_1.default.isString(platformVersion);
|
|
237
|
+
if (bothVersionsCanBeCoerced && deviceOS.version === platformVersion.version
|
|
238
|
+
|| bothVersionsAreStrings && lodash_1.default.toLower(deviceOS) === lodash_1.default.toLower(platformVersion)) {
|
|
239
|
+
// Got an exact match - proceed immediately
|
|
240
|
+
udid = device.udid;
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
else if (!bothVersionsCanBeCoerced) {
|
|
244
|
+
// There is no point to check for partial match if either of version numbers is not coercible
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if ((!lodash_1.default.includes(opts.platformVersion, '.') && platformVersion.major === deviceOS.major
|
|
248
|
+
|| platformVersion.major === deviceOS.major && platformVersion.minor === deviceOS.minor)
|
|
249
|
+
// Got a partial match - make sure we consider the most recent
|
|
250
|
+
// device version available on the host system
|
|
251
|
+
&& (partialMatchCandidate && semver_1.default.gt(deviceOS, lodash_1.default.values(partialMatchCandidate)[0])
|
|
252
|
+
|| !partialMatchCandidate)) {
|
|
253
|
+
partialMatchCandidate = { [device.udid]: deviceOS };
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (!udid && partialMatchCandidate) {
|
|
257
|
+
udid = lodash_1.default.keys(partialMatchCandidate)[0];
|
|
258
|
+
await adb.setDeviceId(udid);
|
|
259
|
+
}
|
|
260
|
+
if (!udid) {
|
|
261
|
+
// we couldn't find anything! quit
|
|
262
|
+
logger_1.default.errorAndThrow(`Unable to find an active device or emulator ` +
|
|
263
|
+
`with OS ${opts.platformVersion}. The following are available: ` +
|
|
264
|
+
availDevices.join(', '));
|
|
265
|
+
}
|
|
266
|
+
emPort = adb.getPortFromEmulatorString(udid);
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
// a udid was not given, grab the first device we see
|
|
270
|
+
udid = devices[0].udid;
|
|
271
|
+
emPort = adb.getPortFromEmulatorString(udid);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
logger_1.default.info(`Using device: ${udid}`);
|
|
275
|
+
return { udid, emPort };
|
|
261
276
|
};
|
|
277
|
+
// returns a new adb instance with deviceId set
|
|
262
278
|
helpers.createADB = async function createADB(opts = {}) {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
adb.setEmulatorPort(emPort);
|
|
271
|
-
}
|
|
272
|
-
return adb;
|
|
279
|
+
const { udid, emPort } = opts;
|
|
280
|
+
const adb = await helpers.createBaseADB(opts);
|
|
281
|
+
adb.setDeviceId(udid);
|
|
282
|
+
if (emPort) {
|
|
283
|
+
adb.setEmulatorPort(emPort);
|
|
284
|
+
}
|
|
285
|
+
return adb;
|
|
273
286
|
};
|
|
274
287
|
helpers.validatePackageActivityNames = function validatePackageActivityNames(opts) {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
288
|
+
for (const key of ['appPackage', 'appActivity', 'appWaitPackage', 'appWaitActivity']) {
|
|
289
|
+
const name = opts[key];
|
|
290
|
+
if (!name) {
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
const match = /([^\w.*,])+/.exec(name);
|
|
294
|
+
if (!match) {
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
logger_1.default.warn(`Capability '${key}' is expected to only include latin letters, digits, underscore, dot, comma and asterisk characters.`);
|
|
298
|
+
logger_1.default.warn(`Current value '${name}' has non-matching character at index ${match.index}: '${name.substring(0, match.index + 1)}'`);
|
|
283
299
|
}
|
|
284
|
-
_logger.default.warn(`Capability '${key}' is expected to only include latin letters, digits, underscore, dot, comma and asterisk characters.`);
|
|
285
|
-
_logger.default.warn(`Current value '${name}' has non-matching character at index ${match.index}: '${name.substring(0, match.index + 1)}'`);
|
|
286
|
-
}
|
|
287
300
|
};
|
|
288
301
|
helpers.getLaunchInfo = async function getLaunchInfo(adb, opts) {
|
|
289
|
-
|
|
290
|
-
app
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
appWaitPackage
|
|
314
|
-
}
|
|
315
|
-
if (apkActivity && !appActivity) {
|
|
316
|
-
appActivity = apkActivity;
|
|
317
|
-
}
|
|
318
|
-
if (!appWaitActivity) {
|
|
319
|
-
appWaitActivity = appActivity;
|
|
320
|
-
}
|
|
321
|
-
_logger.default.debug(`Parsed package and activity are: ${apkPackage}/${apkActivity}`);
|
|
322
|
-
return {
|
|
323
|
-
appPackage,
|
|
324
|
-
appWaitPackage,
|
|
325
|
-
appActivity,
|
|
326
|
-
appWaitActivity
|
|
327
|
-
};
|
|
302
|
+
let { app, appPackage, appActivity, appWaitPackage, appWaitActivity } = opts;
|
|
303
|
+
if (!app) {
|
|
304
|
+
logger_1.default.warn('No app sent in, not parsing package/activity');
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
this.validatePackageActivityNames(opts);
|
|
308
|
+
if (appPackage && appActivity) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
logger_1.default.debug('Parsing package and activity from app manifest');
|
|
312
|
+
let { apkPackage, apkActivity } = await adb.packageAndLaunchActivityFromManifest(app);
|
|
313
|
+
if (apkPackage && !appPackage) {
|
|
314
|
+
appPackage = apkPackage;
|
|
315
|
+
}
|
|
316
|
+
if (!appWaitPackage) {
|
|
317
|
+
appWaitPackage = appPackage;
|
|
318
|
+
}
|
|
319
|
+
if (apkActivity && !appActivity) {
|
|
320
|
+
appActivity = apkActivity;
|
|
321
|
+
}
|
|
322
|
+
if (!appWaitActivity) {
|
|
323
|
+
appWaitActivity = appActivity;
|
|
324
|
+
}
|
|
325
|
+
logger_1.default.debug(`Parsed package and activity are: ${apkPackage}/${apkActivity}`);
|
|
326
|
+
return { appPackage, appWaitPackage, appActivity, appWaitActivity };
|
|
328
327
|
};
|
|
329
328
|
helpers.resetApp = async function resetApp(adb, opts = {}) {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
autoGrantPermissions,
|
|
337
|
-
allowTestPackages
|
|
338
|
-
} = opts;
|
|
339
|
-
if (!appPackage) {
|
|
340
|
-
throw new Error("'appPackage' option is required");
|
|
341
|
-
}
|
|
342
|
-
const isInstalled = await adb.isAppInstalled(appPackage);
|
|
343
|
-
if (isInstalled) {
|
|
344
|
-
try {
|
|
345
|
-
await adb.forceStop(appPackage);
|
|
346
|
-
} catch (ign) {}
|
|
347
|
-
if (!fullReset && fastReset) {
|
|
348
|
-
const output = await adb.clear(appPackage);
|
|
349
|
-
if (_lodash.default.isString(output) && output.toLowerCase().includes('failed')) {
|
|
350
|
-
throw new Error(`Cannot clear the application data of '${appPackage}'. Original error: ${output}`);
|
|
351
|
-
}
|
|
352
|
-
if (autoGrantPermissions) {
|
|
329
|
+
const { app, appPackage, fastReset, fullReset, androidInstallTimeout = PACKAGE_INSTALL_TIMEOUT_MS, autoGrantPermissions, allowTestPackages } = opts;
|
|
330
|
+
if (!appPackage) {
|
|
331
|
+
throw new Error("'appPackage' option is required");
|
|
332
|
+
}
|
|
333
|
+
const isInstalled = await adb.isAppInstalled(appPackage);
|
|
334
|
+
if (isInstalled) {
|
|
353
335
|
try {
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
336
|
+
await adb.forceStop(appPackage);
|
|
337
|
+
}
|
|
338
|
+
catch (ign) { }
|
|
339
|
+
// fullReset has priority over fastReset
|
|
340
|
+
if (!fullReset && fastReset) {
|
|
341
|
+
const output = await adb.clear(appPackage);
|
|
342
|
+
if (lodash_1.default.isString(output) && output.toLowerCase().includes('failed')) {
|
|
343
|
+
throw new Error(`Cannot clear the application data of '${appPackage}'. Original error: ${output}`);
|
|
344
|
+
}
|
|
345
|
+
// executing `shell pm clear` resets previously assigned application permissions as well
|
|
346
|
+
if (autoGrantPermissions) {
|
|
347
|
+
try {
|
|
348
|
+
await adb.grantAllPermissions(appPackage);
|
|
349
|
+
}
|
|
350
|
+
catch (error) {
|
|
351
|
+
logger_1.default.error(`Unable to grant permissions requested. Original error: ${error.message}`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
logger_1.default.debug(`Performed fast reset on the installed '${appPackage}' application (stop and clear)`);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (!app) {
|
|
359
|
+
throw new Error(`Either provide 'app' option to install '${appPackage}' or ` +
|
|
360
|
+
`consider setting 'noReset' to 'true' if '${appPackage}' is supposed to be preinstalled.`);
|
|
361
|
+
}
|
|
362
|
+
logger_1.default.debug(`Running full reset on '${appPackage}' (reinstall)`);
|
|
363
|
+
if (isInstalled) {
|
|
364
|
+
await adb.uninstallApk(appPackage);
|
|
365
|
+
}
|
|
366
|
+
await adb.install(app, {
|
|
367
|
+
grantPermissions: autoGrantPermissions,
|
|
368
|
+
timeout: androidInstallTimeout,
|
|
369
|
+
allowTestPackages,
|
|
370
|
+
});
|
|
375
371
|
};
|
|
376
372
|
helpers.installApk = async function installApk(adb, opts = {}) {
|
|
377
|
-
|
|
378
|
-
app
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
fullReset
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
grantPermissions: autoGrantPermissions,
|
|
399
|
-
timeout: androidInstallTimeout,
|
|
400
|
-
allowTestPackages,
|
|
401
|
-
enforceCurrentBuild: enforceAppInstall
|
|
402
|
-
});
|
|
403
|
-
const isInstalledOverExistingApp = !wasUninstalled && appState !== adb.APP_INSTALL_STATE.NOT_INSTALLED;
|
|
404
|
-
if (fastReset && isInstalledOverExistingApp) {
|
|
405
|
-
_logger.default.info(`Performing fast reset on '${appPackage}'`);
|
|
406
|
-
await this.resetApp(adb, opts);
|
|
407
|
-
}
|
|
373
|
+
const { app, appPackage, fastReset, fullReset, androidInstallTimeout = PACKAGE_INSTALL_TIMEOUT_MS, autoGrantPermissions, allowTestPackages, enforceAppInstall, } = opts;
|
|
374
|
+
if (!app || !appPackage) {
|
|
375
|
+
throw new Error("'app' and 'appPackage' options are required");
|
|
376
|
+
}
|
|
377
|
+
if (fullReset) {
|
|
378
|
+
await this.resetApp(adb, opts);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
const { appState, wasUninstalled } = await adb.installOrUpgrade(app, appPackage, {
|
|
382
|
+
grantPermissions: autoGrantPermissions,
|
|
383
|
+
timeout: androidInstallTimeout,
|
|
384
|
+
allowTestPackages,
|
|
385
|
+
enforceCurrentBuild: enforceAppInstall,
|
|
386
|
+
});
|
|
387
|
+
// There is no need to reset the newly installed app
|
|
388
|
+
const isInstalledOverExistingApp = !wasUninstalled
|
|
389
|
+
&& appState !== adb.APP_INSTALL_STATE.NOT_INSTALLED;
|
|
390
|
+
if (fastReset && isInstalledOverExistingApp) {
|
|
391
|
+
logger_1.default.info(`Performing fast reset on '${appPackage}'`);
|
|
392
|
+
await this.resetApp(adb, opts);
|
|
393
|
+
}
|
|
408
394
|
};
|
|
395
|
+
/**
|
|
396
|
+
* Installs an array of apks
|
|
397
|
+
* @param {ADB} adb Instance of Appium ADB object
|
|
398
|
+
* @param {Object} opts Opts defined in driver.js
|
|
399
|
+
*/
|
|
409
400
|
helpers.installOtherApks = async function installOtherApks(otherApps, adb, opts) {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
allowTestPackages
|
|
421
|
-
});
|
|
422
|
-
}));
|
|
401
|
+
let { androidInstallTimeout = PACKAGE_INSTALL_TIMEOUT_MS, autoGrantPermissions, allowTestPackages } = opts;
|
|
402
|
+
// Install all of the APK's asynchronously
|
|
403
|
+
await bluebird_1.default.all(otherApps.map((otherApp) => {
|
|
404
|
+
logger_1.default.debug(`Installing app: ${otherApp}`);
|
|
405
|
+
return adb.installOrUpgrade(otherApp, null, {
|
|
406
|
+
grantPermissions: autoGrantPermissions,
|
|
407
|
+
timeout: androidInstallTimeout,
|
|
408
|
+
allowTestPackages,
|
|
409
|
+
});
|
|
410
|
+
}));
|
|
423
411
|
};
|
|
412
|
+
/**
|
|
413
|
+
* Uninstall an array of packages
|
|
414
|
+
* @param {ADB} adb Instance of Appium ADB object
|
|
415
|
+
* @param {Array<string>} appPackages An array of package names to uninstall. If this includes `'*'`, uninstall all of 3rd party apps
|
|
416
|
+
* @param {Array<string>} filterPackages An array of packages does not uninstall when `*` is provided as `appPackages`
|
|
417
|
+
*/
|
|
424
418
|
helpers.uninstallOtherPackages = async function uninstallOtherPackages(adb, appPackages, filterPackages = []) {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
419
|
+
if (appPackages.includes('*')) {
|
|
420
|
+
logger_1.default.debug('Uninstall third party packages');
|
|
421
|
+
appPackages = await this.getThirdPartyPackages(adb, filterPackages);
|
|
422
|
+
}
|
|
423
|
+
logger_1.default.debug(`Uninstalling packages: ${appPackages}`);
|
|
424
|
+
await bluebird_1.default.all(appPackages.map((appPackage) => adb.uninstallApk(appPackage)));
|
|
431
425
|
};
|
|
426
|
+
/**
|
|
427
|
+
* Get third party packages filtered with `filterPackages`
|
|
428
|
+
* @param {ADB} adb Instance of Appium ADB object
|
|
429
|
+
* @param {Array<string>} filterPackages An array of packages does not uninstall when `*` is provided as `appPackages`
|
|
430
|
+
* @returns {Array<string>} An array of installed third pary packages
|
|
431
|
+
*/
|
|
432
432
|
helpers.getThirdPartyPackages = async function getThirdPartyPackages(adb, filterPackages = []) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
433
|
+
try {
|
|
434
|
+
const packagesString = await adb.shell(['pm', 'list', 'packages', '-3']);
|
|
435
|
+
const appPackagesArray = packagesString.trim().replace(/package:/g, '').split(os_1.EOL);
|
|
436
|
+
logger_1.default.debug(`'${appPackagesArray}' filtered with '${filterPackages}'`);
|
|
437
|
+
return lodash_1.default.difference(appPackagesArray, filterPackages);
|
|
438
|
+
}
|
|
439
|
+
catch (err) {
|
|
440
|
+
logger_1.default.warn(`Unable to get packages with 'adb shell pm list packages -3': ${err.message}`);
|
|
441
|
+
return [];
|
|
442
|
+
}
|
|
442
443
|
};
|
|
443
444
|
helpers.initUnicodeKeyboard = async function initUnicodeKeyboard(adb) {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
445
|
+
logger_1.default.debug('Enabling Unicode keyboard support');
|
|
446
|
+
// get the default IME so we can return back to it later if we want
|
|
447
|
+
let defaultIME = await adb.defaultIME();
|
|
448
|
+
logger_1.default.debug(`Unsetting previous IME ${defaultIME}`);
|
|
449
|
+
const appiumIME = `${SETTINGS_HELPER_PKG_ID}/.UnicodeIME`;
|
|
450
|
+
logger_1.default.debug(`Setting IME to '${appiumIME}'`);
|
|
451
|
+
await adb.enableIME(appiumIME);
|
|
452
|
+
await adb.setIME(appiumIME);
|
|
453
|
+
return defaultIME;
|
|
452
454
|
};
|
|
453
455
|
helpers.setMockLocationApp = async function setMockLocationApp(adb, app) {
|
|
454
|
-
try {
|
|
455
|
-
if ((await adb.getApiLevel()) < 23) {
|
|
456
|
-
await adb.shell(['settings', 'put', 'secure', 'mock_location', '1']);
|
|
457
|
-
} else {
|
|
458
|
-
await adb.shell(['appops', 'set', app, 'android:mock_location', 'allow']);
|
|
459
|
-
}
|
|
460
|
-
} catch (err) {
|
|
461
|
-
_logger.default.warn(`Unable to set mock location for app '${app}': ${err.message}`);
|
|
462
|
-
return;
|
|
463
|
-
}
|
|
464
|
-
try {
|
|
465
|
-
let pkgIds = [];
|
|
466
|
-
if (await adb.fileExists(MOCK_APP_IDS_STORE)) {
|
|
467
|
-
try {
|
|
468
|
-
pkgIds = JSON.parse(await adb.shell(['cat', MOCK_APP_IDS_STORE]));
|
|
469
|
-
} catch (ign) {}
|
|
470
|
-
}
|
|
471
|
-
if (pkgIds.includes(app)) {
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
pkgIds.push(app);
|
|
475
|
-
const tmpRoot = await _support.tempDir.openDir();
|
|
476
|
-
const srcPath = _path.default.posix.join(tmpRoot, _path.default.posix.basename(MOCK_APP_IDS_STORE));
|
|
477
456
|
try {
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
457
|
+
if (await adb.getApiLevel() < 23) {
|
|
458
|
+
await adb.shell(['settings', 'put', 'secure', 'mock_location', '1']);
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
await adb.shell(['appops', 'set', app, 'android:mock_location', 'allow']);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
catch (err) {
|
|
465
|
+
logger_1.default.warn(`Unable to set mock location for app '${app}': ${err.message}`);
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
try {
|
|
469
|
+
let pkgIds = [];
|
|
470
|
+
if (await adb.fileExists(MOCK_APP_IDS_STORE)) {
|
|
471
|
+
try {
|
|
472
|
+
pkgIds = JSON.parse(await adb.shell(['cat', MOCK_APP_IDS_STORE]));
|
|
473
|
+
}
|
|
474
|
+
catch (ign) { }
|
|
475
|
+
}
|
|
476
|
+
if (pkgIds.includes(app)) {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
pkgIds.push(app);
|
|
480
|
+
const tmpRoot = await support_1.tempDir.openDir();
|
|
481
|
+
const srcPath = path_1.default.posix.join(tmpRoot, path_1.default.posix.basename(MOCK_APP_IDS_STORE));
|
|
482
|
+
try {
|
|
483
|
+
await support_1.fs.writeFile(srcPath, JSON.stringify(pkgIds), 'utf8');
|
|
484
|
+
await adb.push(srcPath, MOCK_APP_IDS_STORE);
|
|
485
|
+
}
|
|
486
|
+
finally {
|
|
487
|
+
await support_1.fs.rimraf(tmpRoot);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
catch (e) {
|
|
491
|
+
logger_1.default.warn(`Unable to persist mock location app id '${app}': ${e.message}`);
|
|
482
492
|
}
|
|
483
|
-
} catch (e) {
|
|
484
|
-
_logger.default.warn(`Unable to persist mock location app id '${app}': ${e.message}`);
|
|
485
|
-
}
|
|
486
493
|
};
|
|
487
494
|
helpers.resetMockLocation = async function resetMockLocation(adb) {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
await
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
495
|
+
try {
|
|
496
|
+
if (await adb.getApiLevel() < 23) {
|
|
497
|
+
await adb.shell(['settings', 'put', 'secure', 'mock_location', '0']);
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
const thirdPartyPkgIdsPromise = helpers.getThirdPartyPackages(adb);
|
|
501
|
+
let pkgIds = [];
|
|
502
|
+
if (await adb.fileExists(MOCK_APP_IDS_STORE)) {
|
|
503
|
+
try {
|
|
504
|
+
pkgIds = JSON.parse(await adb.shell(['cat', MOCK_APP_IDS_STORE]));
|
|
505
|
+
}
|
|
506
|
+
catch (ign) { }
|
|
507
|
+
}
|
|
508
|
+
const thirdPartyPkgIds = await thirdPartyPkgIdsPromise;
|
|
509
|
+
// Only include currently installed packages
|
|
510
|
+
const resultPkgs = lodash_1.default.intersection(pkgIds, thirdPartyPkgIds);
|
|
511
|
+
if (lodash_1.default.size(resultPkgs) <= 1) {
|
|
512
|
+
await adb.shell(['appops', 'set', resultPkgs[0] ?? SETTINGS_HELPER_PKG_ID, 'android:mock_location', 'deny']);
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
logger_1.default.debug(`Resetting mock_location permission for the following apps: ${resultPkgs}`);
|
|
516
|
+
await bluebird_1.default.all(resultPkgs.map((pkgId) => (async () => {
|
|
517
|
+
try {
|
|
518
|
+
await adb.shell(['appops', 'set', pkgId, 'android:mock_location', 'deny']);
|
|
519
|
+
}
|
|
520
|
+
catch (ign) { }
|
|
521
|
+
})()));
|
|
522
|
+
}
|
|
523
|
+
catch (err) {
|
|
524
|
+
logger_1.default.warn(`Unable to reset mock location: ${err.message}`);
|
|
525
|
+
}
|
|
515
526
|
};
|
|
516
527
|
helpers.installHelperApp = async function installHelperApp(adb, apkPath, packageId) {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
528
|
+
// Sometimes adb push or adb instal take more time than expected to install an app
|
|
529
|
+
// e.g. https://github.com/appium/io.appium.settings/issues/40#issuecomment-476593174
|
|
530
|
+
await (0, asyncbox_1.retryInterval)(HELPER_APP_INSTALL_RETRIES, HELPER_APP_INSTALL_RETRY_DELAY_MS, async function retryInstallHelperApp() {
|
|
531
|
+
await adb.installOrUpgrade(apkPath, packageId, { grantPermissions: true });
|
|
520
532
|
});
|
|
521
|
-
});
|
|
522
533
|
};
|
|
534
|
+
/**
|
|
535
|
+
* Pushes and installs io.appium.settings app.
|
|
536
|
+
* Throws an error if the setting app is required
|
|
537
|
+
*
|
|
538
|
+
* @param {Adb} adb - The adb module instance.
|
|
539
|
+
* @param {Object} opts - Driver options dictionary.
|
|
540
|
+
* @param {boolean} throwError [false] - Whether throw an error if Settings app fails to start
|
|
541
|
+
* @throws {Error} If throwError is true and something happens in installation step
|
|
542
|
+
*/
|
|
523
543
|
helpers.pushSettingsApp = async function pushSettingsApp(adb, throwError = false, opts = {}) {
|
|
524
|
-
|
|
525
|
-
try {
|
|
526
|
-
await helpers.installHelperApp(adb, _ioAppium.path, SETTINGS_HELPER_PKG_ID, throwError);
|
|
527
|
-
} catch (err) {
|
|
528
|
-
if (throwError) {
|
|
529
|
-
throw err;
|
|
530
|
-
}
|
|
531
|
-
_logger.default.warn(`Ignored error while installing '${_ioAppium.path}': ` + `'${err.message}'. Features that rely on this helper ` + 'require the apk such as toggle WiFi and getting location ' + 'will raise an error if you try to use them.');
|
|
532
|
-
}
|
|
533
|
-
if (await adb.processExists(SETTINGS_HELPER_PKG_ID)) {
|
|
534
|
-
_logger.default.debug(`${SETTINGS_HELPER_PKG_ID} is already running. ` + `There is no need to reset its permissions.`);
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
|
-
const apiLevel = await adb.getApiLevel();
|
|
538
|
-
if (apiLevel >= 29) {
|
|
544
|
+
logger_1.default.debug('Pushing settings apk to device...');
|
|
539
545
|
try {
|
|
540
|
-
|
|
541
|
-
}
|
|
542
|
-
|
|
546
|
+
await helpers.installHelperApp(adb, io_appium_settings_1.path, SETTINGS_HELPER_PKG_ID, throwError);
|
|
547
|
+
}
|
|
548
|
+
catch (err) {
|
|
549
|
+
if (throwError) {
|
|
550
|
+
throw err;
|
|
551
|
+
}
|
|
552
|
+
logger_1.default.warn(`Ignored error while installing '${io_appium_settings_1.path}': ` +
|
|
553
|
+
`'${err.message}'. Features that rely on this helper ` +
|
|
554
|
+
'require the apk such as toggle WiFi and getting location ' +
|
|
555
|
+
'will raise an error if you try to use them.');
|
|
556
|
+
}
|
|
557
|
+
// Reinstall would stop the settings helper process anyway, so
|
|
558
|
+
// there is no need to continue if the application is still running
|
|
559
|
+
if (await adb.processExists(SETTINGS_HELPER_PKG_ID)) {
|
|
560
|
+
logger_1.default.debug(`${SETTINGS_HELPER_PKG_ID} is already running. ` +
|
|
561
|
+
`There is no need to reset its permissions.`);
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
const apiLevel = await adb.getApiLevel();
|
|
565
|
+
if (apiLevel >= 29) {
|
|
566
|
+
// https://github.com/appium/io.appium.settings#internal-audio--video-recording
|
|
567
|
+
try {
|
|
568
|
+
await adb.shell(['appops', 'set', SETTINGS_HELPER_PKG_ID, 'PROJECT_MEDIA', 'allow']);
|
|
569
|
+
}
|
|
570
|
+
catch (err) {
|
|
571
|
+
logger_1.default.debug(err.message);
|
|
572
|
+
}
|
|
573
|
+
try {
|
|
574
|
+
await adb.shell(['cmd', 'notification', 'allow_listener', SETTING_NOTIFICATIONS_LISTENER_SERVICE]);
|
|
575
|
+
}
|
|
576
|
+
catch (err) {
|
|
577
|
+
logger_1.default.debug(err.message);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
if (apiLevel <= 23) { // Android 6- devices should have granted permissions
|
|
581
|
+
// https://github.com/appium/appium/pull/11640#issuecomment-438260477
|
|
582
|
+
const perms = ['SET_ANIMATION_SCALE', 'CHANGE_CONFIGURATION', 'ACCESS_FINE_LOCATION'];
|
|
583
|
+
logger_1.default.info(`Granting permissions ${perms} to '${SETTINGS_HELPER_PKG_ID}'`);
|
|
584
|
+
await adb.grantPermissions(SETTINGS_HELPER_PKG_ID, perms.map((x) => `android.permission.${x}`));
|
|
543
585
|
}
|
|
586
|
+
// launch io.appium.settings app due to settings failing to be set
|
|
587
|
+
// if the app is not launched prior to start the session on android 7+
|
|
588
|
+
// see https://github.com/appium/appium/issues/8957
|
|
544
589
|
try {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
}
|
|
555
|
-
try {
|
|
556
|
-
await adb.requireRunningSettingsApp({
|
|
557
|
-
timeout: helpers.isEmulator(adb, opts) ? 30000 : 5000
|
|
558
|
-
});
|
|
559
|
-
} catch (err) {
|
|
560
|
-
_logger.default.debug(err);
|
|
561
|
-
if (throwError) {
|
|
562
|
-
throw err;
|
|
590
|
+
await adb.requireRunningSettingsApp({
|
|
591
|
+
timeout: helpers.isEmulator(adb, opts) ? 30000 : 5000
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
catch (err) {
|
|
595
|
+
logger_1.default.debug(err);
|
|
596
|
+
if (throwError) {
|
|
597
|
+
throw err;
|
|
598
|
+
}
|
|
563
599
|
}
|
|
564
|
-
}
|
|
565
600
|
};
|
|
601
|
+
/**
|
|
602
|
+
* Extracts string.xml and converts it to string.json and pushes
|
|
603
|
+
* it to /data/local/tmp/string.json on for use of bootstrap
|
|
604
|
+
* If app is not present to extract string.xml it deletes remote strings.json
|
|
605
|
+
* If app does not have strings.xml we push an empty json object to remote
|
|
606
|
+
*
|
|
607
|
+
* @param {?string} language - Language abbreviation, for example 'fr'. The default language
|
|
608
|
+
* is used if this argument is not defined.
|
|
609
|
+
* @param {Object} adb - The adb module instance.
|
|
610
|
+
* @param {Object} opts - Driver options dictionary.
|
|
611
|
+
* @returns {Object} The dictionary, where string resource identifiers are keys
|
|
612
|
+
* along with their corresponding values for the given language or an empty object
|
|
613
|
+
* if no matching resources were extracted.
|
|
614
|
+
*/
|
|
566
615
|
helpers.pushStrings = async function pushStrings(language, adb, opts) {
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
616
|
+
const remoteDir = '/data/local/tmp';
|
|
617
|
+
const stringsJson = 'strings.json';
|
|
618
|
+
const remoteFile = path_1.default.posix.resolve(remoteDir, stringsJson);
|
|
619
|
+
// clean up remote string.json if present
|
|
620
|
+
await adb.rimraf(remoteFile);
|
|
621
|
+
let app;
|
|
622
|
+
try {
|
|
623
|
+
app = opts.app || await adb.pullApk(opts.appPackage, opts.tmpDir);
|
|
624
|
+
}
|
|
625
|
+
catch (err) {
|
|
626
|
+
logger_1.default.info(`Failed to pull an apk from '${opts.appPackage}' to '${opts.tmpDir}'. Original error: ${err.message}`);
|
|
627
|
+
}
|
|
628
|
+
if (lodash_1.default.isEmpty(opts.appPackage) || !(await support_1.fs.exists(app))) {
|
|
629
|
+
logger_1.default.debug(`No app or package specified. Returning empty strings`);
|
|
630
|
+
return {};
|
|
631
|
+
}
|
|
632
|
+
const stringsTmpDir = path_1.default.resolve(opts.tmpDir, opts.appPackage);
|
|
633
|
+
try {
|
|
634
|
+
logger_1.default.debug('Extracting strings from apk', app, language, stringsTmpDir);
|
|
635
|
+
const { apkStrings, localPath } = await adb.extractStringsFromApk(app, language, stringsTmpDir);
|
|
636
|
+
await adb.push(localPath, remoteDir);
|
|
637
|
+
return apkStrings;
|
|
638
|
+
}
|
|
639
|
+
catch (err) {
|
|
640
|
+
logger_1.default.warn(`Could not get strings, continuing anyway. Original error: ${err.message}`);
|
|
641
|
+
await adb.shell('echo', [`'{}' > ${remoteFile}`]);
|
|
642
|
+
}
|
|
643
|
+
finally {
|
|
644
|
+
await support_1.fs.rimraf(stringsTmpDir);
|
|
645
|
+
}
|
|
579
646
|
return {};
|
|
580
|
-
}
|
|
581
|
-
const stringsTmpDir = _path.default.resolve(opts.tmpDir, opts.appPackage);
|
|
582
|
-
try {
|
|
583
|
-
_logger.default.debug('Extracting strings from apk', app, language, stringsTmpDir);
|
|
584
|
-
const {
|
|
585
|
-
apkStrings,
|
|
586
|
-
localPath
|
|
587
|
-
} = await adb.extractStringsFromApk(app, language, stringsTmpDir);
|
|
588
|
-
await adb.push(localPath, remoteDir);
|
|
589
|
-
return apkStrings;
|
|
590
|
-
} catch (err) {
|
|
591
|
-
_logger.default.warn(`Could not get strings, continuing anyway. Original error: ${err.message}`);
|
|
592
|
-
await adb.shell('echo', [`'{}' > ${remoteFile}`]);
|
|
593
|
-
} finally {
|
|
594
|
-
await _support.fs.rimraf(stringsTmpDir);
|
|
595
|
-
}
|
|
596
|
-
return {};
|
|
597
647
|
};
|
|
598
648
|
helpers.unlock = async function unlock(driver, adb, capabilities) {
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
unlockType,
|
|
611
|
-
unlockKey
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
await helpers.verifyUnlock(adb, unlockSuccessTimeout);
|
|
649
|
+
if (!(await adb.isScreenLocked())) {
|
|
650
|
+
logger_1.default.info('Screen already unlocked, doing nothing');
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
logger_1.default.debug('Screen is locked, trying to unlock');
|
|
654
|
+
if (!capabilities.unlockType && !capabilities.unlockKey) {
|
|
655
|
+
logger_1.default.info(`Neither 'unlockType' nor 'unlockKey' capability is provided. ` +
|
|
656
|
+
`Assuming the device is locked with a simple lock screen.`);
|
|
657
|
+
await adb.dismissKeyguard();
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
const { unlockType, unlockKey, unlockStrategy, unlockSuccessTimeout, } = unlock_helpers_1.helpers.validateUnlockCapabilities(capabilities);
|
|
661
|
+
if (unlockKey && unlockType !== unlock_helpers_1.FINGERPRINT_UNLOCK
|
|
662
|
+
&& (lodash_1.default.isNil(unlockStrategy) || lodash_1.default.toLower(unlockStrategy) === 'locksettings')
|
|
663
|
+
&& await adb.isLockManagementSupported()) {
|
|
664
|
+
await unlock_helpers_1.helpers.fastUnlock(adb, {
|
|
665
|
+
credential: unlockKey,
|
|
666
|
+
credentialType: toCredentialType(unlockType),
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
else {
|
|
670
|
+
const unlockMethod = {
|
|
671
|
+
[unlock_helpers_1.PIN_UNLOCK]: unlock_helpers_1.helpers.pinUnlock,
|
|
672
|
+
[unlock_helpers_1.PIN_UNLOCK_KEY_EVENT]: unlock_helpers_1.helpers.pinUnlockWithKeyEvent,
|
|
673
|
+
[unlock_helpers_1.PASSWORD_UNLOCK]: unlock_helpers_1.helpers.passwordUnlock,
|
|
674
|
+
[unlock_helpers_1.PATTERN_UNLOCK]: unlock_helpers_1.helpers.patternUnlock,
|
|
675
|
+
[unlock_helpers_1.FINGERPRINT_UNLOCK]: unlock_helpers_1.helpers.fingerprintUnlock,
|
|
676
|
+
}[unlockType];
|
|
677
|
+
await unlockMethod(adb, driver, capabilities);
|
|
678
|
+
}
|
|
679
|
+
await helpers.verifyUnlock(adb, unlockSuccessTimeout);
|
|
631
680
|
};
|
|
632
681
|
helpers.verifyUnlock = async function verifyUnlock(adb, timeoutMs = null) {
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
682
|
+
try {
|
|
683
|
+
await (0, asyncbox_1.waitForCondition)(async () => !(await adb.isScreenLocked()), {
|
|
684
|
+
waitMs: timeoutMs ?? 2000,
|
|
685
|
+
intervalMs: 500,
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
catch (ign) {
|
|
689
|
+
throw new Error('The device has failed to be unlocked');
|
|
690
|
+
}
|
|
691
|
+
logger_1.default.info('The device has been successfully unlocked');
|
|
642
692
|
};
|
|
643
693
|
helpers.initDevice = async function initDevice(adb, opts) {
|
|
644
|
-
|
|
645
|
-
skipDeviceInitialization
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
694
|
+
const { skipDeviceInitialization, locale, language, localeScript, unicodeKeyboard, disableWindowAnimation, skipUnlock, mockLocationApp, skipLogcatCapture, logcatFormat, logcatFilterSpecs, } = opts;
|
|
695
|
+
if (skipDeviceInitialization) {
|
|
696
|
+
logger_1.default.info(`'skipDeviceInitialization' is set. Skipping device initialization.`);
|
|
697
|
+
}
|
|
698
|
+
else {
|
|
699
|
+
if (helpers.isEmulator(adb, opts)) {
|
|
700
|
+
// Check if the device wake up only for an emulator.
|
|
701
|
+
// It takes 1 second or so even when the device is already awake in a real device.
|
|
702
|
+
await adb.waitForDevice();
|
|
703
|
+
}
|
|
704
|
+
// pushSettingsApp required before calling ensureDeviceLocale for API Level 24+
|
|
705
|
+
// Some feature such as location/wifi are not necessary for all users,
|
|
706
|
+
// but they require the settings app. So, try to configure it while Appium
|
|
707
|
+
// does not throw error even if they fail.
|
|
708
|
+
const shouldThrowError = language
|
|
709
|
+
|| locale
|
|
710
|
+
|| localeScript
|
|
711
|
+
|| unicodeKeyboard
|
|
712
|
+
|| disableWindowAnimation
|
|
713
|
+
|| !skipUnlock;
|
|
714
|
+
await helpers.pushSettingsApp(adb, shouldThrowError, opts);
|
|
715
|
+
}
|
|
716
|
+
if (!helpers.isEmulator(adb, opts)) {
|
|
717
|
+
if (mockLocationApp || lodash_1.default.isUndefined(mockLocationApp)) {
|
|
718
|
+
await helpers.setMockLocationApp(adb, mockLocationApp || SETTINGS_HELPER_PKG_ID);
|
|
719
|
+
}
|
|
720
|
+
else {
|
|
721
|
+
await helpers.resetMockLocation(adb);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
if (language || locale) {
|
|
725
|
+
await helpers.ensureDeviceLocale(adb, language, locale, localeScript);
|
|
726
|
+
}
|
|
727
|
+
if (skipLogcatCapture) {
|
|
728
|
+
logger_1.default.info(`'skipLogcatCapture' is set. Skipping starting logcat capture.`);
|
|
729
|
+
}
|
|
730
|
+
else {
|
|
731
|
+
await adb.startLogcat({
|
|
732
|
+
format: logcatFormat,
|
|
733
|
+
filterSpecs: logcatFilterSpecs,
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
if (unicodeKeyboard) {
|
|
737
|
+
return await helpers.initUnicodeKeyboard(adb);
|
|
738
|
+
}
|
|
687
739
|
};
|
|
688
740
|
helpers.removeNullProperties = function removeNullProperties(obj) {
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
741
|
+
for (let key of lodash_1.default.keys(obj)) {
|
|
742
|
+
if (lodash_1.default.isNull(obj[key]) || lodash_1.default.isUndefined(obj[key])) {
|
|
743
|
+
delete obj[key];
|
|
744
|
+
}
|
|
692
745
|
}
|
|
693
|
-
}
|
|
694
746
|
};
|
|
695
747
|
helpers.truncateDecimals = function truncateDecimals(number, digits) {
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
truncatedNum = Math[adjustedNum < 0 ? 'ceil' : 'floor'](adjustedNum);
|
|
699
|
-
return truncatedNum / multiplier;
|
|
748
|
+
let multiplier = Math.pow(10, digits), adjustedNum = number * multiplier, truncatedNum = Math[adjustedNum < 0 ? 'ceil' : 'floor'](adjustedNum);
|
|
749
|
+
return truncatedNum / multiplier;
|
|
700
750
|
};
|
|
701
751
|
helpers.isChromeBrowser = function isChromeBrowser(browser) {
|
|
702
|
-
|
|
752
|
+
return lodash_1.default.includes(Object.keys(CHROME_BROWSER_PACKAGE_ACTIVITY), (browser || '').toLowerCase());
|
|
703
753
|
};
|
|
704
754
|
helpers.getChromePkg = function getChromePkg(browser) {
|
|
705
|
-
|
|
755
|
+
return CHROME_BROWSER_PACKAGE_ACTIVITY[browser.toLowerCase()] || CHROME_BROWSER_PACKAGE_ACTIVITY.default;
|
|
706
756
|
};
|
|
707
757
|
helpers.removeAllSessionWebSocketHandlers = async function removeAllSessionWebSocketHandlers(server, sessionId) {
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
758
|
+
if (!server || !lodash_1.default.isFunction(server.getWebSocketHandlers)) {
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
const activeHandlers = await server.getWebSocketHandlers(sessionId);
|
|
762
|
+
for (const pathname of lodash_1.default.keys(activeHandlers)) {
|
|
763
|
+
await server.removeWebSocketHandler(pathname);
|
|
764
|
+
}
|
|
715
765
|
};
|
|
766
|
+
/**
|
|
767
|
+
* Takes a desired capability and tries to JSON.parse it as an array,
|
|
768
|
+
* and either returns the parsed array or a singleton array.
|
|
769
|
+
*
|
|
770
|
+
* @param {any} cap A desired capability
|
|
771
|
+
*/
|
|
716
772
|
helpers.parseArray = function parseArray(cap) {
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
773
|
+
let parsedCaps;
|
|
774
|
+
try {
|
|
775
|
+
parsedCaps = JSON.parse(cap);
|
|
776
|
+
}
|
|
777
|
+
catch (ign) { }
|
|
778
|
+
if (lodash_1.default.isArray(parsedCaps)) {
|
|
779
|
+
return parsedCaps;
|
|
780
|
+
}
|
|
781
|
+
else if (lodash_1.default.isString(cap)) {
|
|
782
|
+
return [cap];
|
|
783
|
+
}
|
|
784
|
+
throw new Error(`must provide a string or JSON Array; received ${cap}`);
|
|
727
785
|
};
|
|
786
|
+
/**
|
|
787
|
+
* Validate desired capabilities. Returns true if capability is valid
|
|
788
|
+
*
|
|
789
|
+
* @param {*} cap A desired capability
|
|
790
|
+
* @return {boolean} Returns true if the capability is valid
|
|
791
|
+
* @throws {Error} If the caps has invalid capability
|
|
792
|
+
*/
|
|
728
793
|
helpers.validateDesiredCaps = function validateDesiredCaps(caps) {
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
794
|
+
if (caps.browserName) {
|
|
795
|
+
if (caps.app) {
|
|
796
|
+
// warn if the capabilities have both `app` and `browser, although this is common with selenium grid
|
|
797
|
+
logger_1.default.warn(`The desired capabilities should generally not include both an 'app' and a 'browserName'`);
|
|
798
|
+
}
|
|
799
|
+
if (caps.appPackage) {
|
|
800
|
+
logger_1.default.errorAndThrow(`The desired should not include both of an 'appPackage' and a 'browserName'`);
|
|
801
|
+
}
|
|
735
802
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
803
|
+
if (caps.uninstallOtherPackages) {
|
|
804
|
+
try {
|
|
805
|
+
this.parseArray(caps.uninstallOtherPackages);
|
|
806
|
+
}
|
|
807
|
+
catch (e) {
|
|
808
|
+
logger_1.default.errorAndThrow(`Could not parse "uninstallOtherPackages" capability: ${e.message}`);
|
|
809
|
+
}
|
|
742
810
|
}
|
|
743
|
-
|
|
744
|
-
return true;
|
|
811
|
+
return true;
|
|
745
812
|
};
|
|
813
|
+
/**
|
|
814
|
+
* Adjust the capabilities for a browser session
|
|
815
|
+
*
|
|
816
|
+
* @param {Object} caps - Current capabilities object
|
|
817
|
+
* !!! The object is mutated by this method call !!!
|
|
818
|
+
* @returns {Object} The same possibly mutated `opts` instance.
|
|
819
|
+
* No mutation is happening is the current session if
|
|
820
|
+
* appPackage/appActivity caps have already been provided.
|
|
821
|
+
*/
|
|
746
822
|
helpers.adjustBrowserSessionCaps = function adjustBrowserSessionCaps(caps = {}) {
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
823
|
+
const { browserName } = caps;
|
|
824
|
+
logger_1.default.info(`The current session is considered browser-based`);
|
|
825
|
+
logger_1.default.info(`Supported browser names: ${JSON.stringify(lodash_1.default.keys(CHROME_BROWSER_PACKAGE_ACTIVITY))}`);
|
|
826
|
+
if (caps.appPackage || caps.appActivity) {
|
|
827
|
+
logger_1.default.info(`Not overriding appPackage/appActivity capability values for '${browserName}' ` +
|
|
828
|
+
'because some of them have been already provided');
|
|
829
|
+
return caps;
|
|
830
|
+
}
|
|
831
|
+
const { pkg, activity } = this.getChromePkg(browserName);
|
|
832
|
+
caps.appPackage = pkg;
|
|
833
|
+
caps.appActivity = activity;
|
|
834
|
+
logger_1.default.info(`appPackage/appActivity capabilities have been automatically set to ${pkg}/${activity} ` +
|
|
835
|
+
`for '${browserName}'`);
|
|
836
|
+
logger_1.default.info(`Consider changing the browserName to the one from the list of supported browser names ` +
|
|
837
|
+
`or provide custom appPackage/appActivity capability values if the automatically assigned ones do ` +
|
|
838
|
+
`not make sense`);
|
|
754
839
|
return caps;
|
|
755
|
-
}
|
|
756
|
-
const {
|
|
757
|
-
pkg,
|
|
758
|
-
activity
|
|
759
|
-
} = this.getChromePkg(browserName);
|
|
760
|
-
caps.appPackage = pkg;
|
|
761
|
-
caps.appActivity = activity;
|
|
762
|
-
_logger.default.info(`appPackage/appActivity capabilities have been automatically set to ${pkg}/${activity} ` + `for '${browserName}'`);
|
|
763
|
-
_logger.default.info(`Consider changing the browserName to the one from the list of supported browser names ` + `or provide custom appPackage/appActivity capability values if the automatically assigned ones do ` + `not make sense`);
|
|
764
|
-
return caps;
|
|
765
840
|
};
|
|
841
|
+
/**
|
|
842
|
+
* Checks whether the current device under test is an emulator
|
|
843
|
+
*
|
|
844
|
+
* @param {ADB} adb - appium-adb instance
|
|
845
|
+
* @param {Object} opts - driver options mapping
|
|
846
|
+
* @returns {boolean} `true` if the device is an Android emulator
|
|
847
|
+
*/
|
|
766
848
|
helpers.isEmulator = function isEmulator(adb, opts) {
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
};
|
|
770
|
-
helpers.bootstrap =
|
|
771
|
-
helpers.unlocker =
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9kYXNoIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfcGF0aCIsIl9hc3luY2JveCIsIl9sb2dnZXIiLCJfc3VwcG9ydCIsIl9pb0FwcGl1bSIsIl9ib290c3RyYXAiLCJfYmx1ZWJpcmQiLCJfYXBwaXVtQWRiIiwiX3VubG9ja0hlbHBlcnMiLCJfaW50ZXJvcFJlcXVpcmVXaWxkY2FyZCIsIl9vcyIsIl9zZW12ZXIiLCJfZ2V0UmVxdWlyZVdpbGRjYXJkQ2FjaGUiLCJub2RlSW50ZXJvcCIsIldlYWtNYXAiLCJjYWNoZUJhYmVsSW50ZXJvcCIsImNhY2hlTm9kZUludGVyb3AiLCJvYmoiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsImNhY2hlIiwiaGFzIiwiZ2V0IiwibmV3T2JqIiwiaGFzUHJvcGVydHlEZXNjcmlwdG9yIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJrZXkiLCJwcm90b3R5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJkZXNjIiwic2V0IiwiTU9DS19BUFBfSURTX1NUT1JFIiwiUEFDS0FHRV9JTlNUQUxMX1RJTUVPVVRfTVMiLCJIRUxQRVJfQVBQX0lOU1RBTExfUkVUUklFUyIsIkhFTFBFUl9BUFBfSU5TVEFMTF9SRVRSWV9ERUxBWV9NUyIsIkNIUk9NRV9CUk9XU0VSX1BBQ0tBR0VfQUNUSVZJVFkiLCJjaHJvbWUiLCJwa2ciLCJhY3Rpdml0eSIsImNocm9taXVtIiwiY2hyb21lYmV0YSIsImJyb3dzZXIiLCJTRVRUSU5HU19IRUxQRVJfUEtHX0lEIiwiZXhwb3J0cyIsIlNFVFRJTkdfTk9USUZJQ0FUSU9OU19MSVNURU5FUl9TRVJWSUNFIiwiRU1VTEFUT1JfUEFUVEVSTiIsIkFQUF9TVEFURSIsImZyZWV6ZSIsIk5PVF9JTlNUQUxMRUQiLCJOT1RfUlVOTklORyIsIlJVTk5JTkdfSU5fQkFDS0dST1VORCIsIlJVTk5JTkdfSU5fRk9SRUdST1VORCIsImVuc3VyZU5ldHdvcmtTcGVlZCIsImFkYiIsIm5ldHdvcmtTcGVlZCIsIl8iLCJ2YWx1ZXMiLCJORVRXT1JLX1NQRUVEIiwiaW5jbHVkZXMiLCJsb2dnZXIiLCJ3YXJuIiwiRlVMTCIsInByZXBhcmVBdmRBcmdzIiwib3B0cyIsImlzSGVhZGxlc3MiLCJhdmRBcmdzIiwicmVzdWx0IiwiaXNBcnJheSIsInB1c2giLCJ1dGlsIiwic2hlbGxQYXJzZSIsInRvQ3JlZGVudGlhbFR5cGUiLCJ1bmxvY2tUeXBlIiwiUElOX1VOTE9DSyIsIlBJTl9VTkxPQ0tfS0VZX0VWRU5UIiwiUEFTU1dPUkRfVU5MT0NLIiwiUEFUVEVSTl9VTkxPQ0siLCJFcnJvciIsImhlbHBlcnMiLCJjcmVhdGVCYXNlQURCIiwiYWRiUG9ydCIsInN1cHByZXNzS2lsbFNlcnZlciIsInJlbW90ZUFkYkhvc3QiLCJjbGVhckRldmljZUxvZ3NPblN0YXJ0IiwiYWRiRXhlY1RpbWVvdXQiLCJ1c2VLZXlzdG9yZSIsImtleXN0b3JlUGF0aCIsImtleXN0b3JlUGFzc3dvcmQiLCJrZXlBbGlhcyIsImtleVBhc3N3b3JkIiwicmVtb3RlQXBwc0NhY2hlTGltaXQiLCJidWlsZFRvb2xzVmVyc2lvbiIsImFsbG93T2ZmbGluZURldmljZXMiLCJhbGxvd0RlbGF5QWRiIiwiQURCIiwiY3JlYXRlQURCIiwicHJlcGFyZUVtdWxhdG9yIiwiYXZkIiwiYXZkRW52IiwiZW52IiwibGFuZ3VhZ2UiLCJsb2NhbGUiLCJjb3VudHJ5IiwiYXZkTGF1bmNoVGltZW91dCIsImxhdW5jaFRpbWVvdXQiLCJhdmRSZWFkeVRpbWVvdXQiLCJyZWFkeVRpbWVvdXQiLCJhdmROYW1lIiwicmVwbGFjZSIsImlzRW11bGF0b3JSdW5uaW5nIiwiZ2V0UnVubmluZ0FWRFdpdGhSZXRyeSIsImUiLCJkZWJ1ZyIsIm1lc3NhZ2UiLCJhcmdzIiwia2lsbEVtdWxhdG9yIiwibGF1bmNoQVZEIiwiZW5zdXJlRGV2aWNlTG9jYWxlIiwic2NyaXB0IiwiaXNTdHJpbmciLCJzZXREZXZpY2VMYW5ndWFnZUNvdW50cnkiLCJlbnN1cmVDdXJyZW50TG9jYWxlIiwiZ2V0RGV2aWNlSW5mb0Zyb21DYXBzIiwidWRpZCIsImVtUG9ydCIsImN1ckRldmljZUlkIiwiZW11bGF0b3JQb3J0IiwiaW5mbyIsImRldmljZXMiLCJnZXREZXZpY2VzV2l0aFJldHJ5IiwibWFwIiwiZXJyb3JBbmRUaHJvdyIsImdldFBvcnRGcm9tRW11bGF0b3JTdHJpbmciLCJwbGF0Zm9ybVZlcnNpb24iLCJ0cmltIiwic2VtdmVyIiwiY29lcmNlIiwiYXZhaWxEZXZpY2VzIiwicGFydGlhbE1hdGNoQ2FuZGlkYXRlIiwiZGV2aWNlIiwic2V0RGV2aWNlSWQiLCJyYXdEZXZpY2VPUyIsImdldFBsYXRmb3JtVmVyc2lvbiIsImRldmljZU9TIiwiYm90aFZlcnNpb25zQ2FuQmVDb2VyY2VkIiwidmFsaWQiLCJib3RoVmVyc2lvbnNBcmVTdHJpbmdzIiwidmVyc2lvbiIsInRvTG93ZXIiLCJtYWpvciIsIm1pbm9yIiwiZ3QiLCJrZXlzIiwiam9pbiIsInNldEVtdWxhdG9yUG9ydCIsInZhbGlkYXRlUGFja2FnZUFjdGl2aXR5TmFtZXMiLCJuYW1lIiwibWF0Y2giLCJleGVjIiwiaW5kZXgiLCJzdWJzdHJpbmciLCJnZXRMYXVuY2hJbmZvIiwiYXBwIiwiYXBwUGFja2FnZSIsImFwcEFjdGl2aXR5IiwiYXBwV2FpdFBhY2thZ2UiLCJhcHBXYWl0QWN0aXZpdHkiLCJhcGtQYWNrYWdlIiwiYXBrQWN0aXZpdHkiLCJwYWNrYWdlQW5kTGF1bmNoQWN0aXZpdHlGcm9tTWFuaWZlc3QiLCJyZXNldEFwcCIsImZhc3RSZXNldCIsImZ1bGxSZXNldCIsImFuZHJvaWRJbnN0YWxsVGltZW91dCIsImF1dG9HcmFudFBlcm1pc3Npb25zIiwiYWxsb3dUZXN0UGFja2FnZXMiLCJpc0luc3RhbGxlZCIsImlzQXBwSW5zdGFsbGVkIiwiZm9yY2VTdG9wIiwiaWduIiwib3V0cHV0IiwiY2xlYXIiLCJ0b0xvd2VyQ2FzZSIsImdyYW50QWxsUGVybWlzc2lvbnMiLCJlcnJvciIsInVuaW5zdGFsbEFwayIsImluc3RhbGwiLCJncmFudFBlcm1pc3Npb25zIiwidGltZW91dCIsImluc3RhbGxBcGsiLCJlbmZvcmNlQXBwSW5zdGFsbCIsImFwcFN0YXRlIiwid2FzVW5pbnN0YWxsZWQiLCJpbnN0YWxsT3JVcGdyYWRlIiwiZW5mb3JjZUN1cnJlbnRCdWlsZCIsImlzSW5zdGFsbGVkT3ZlckV4aXN0aW5nQXBwIiwiQVBQX0lOU1RBTExfU1RBVEUiLCJpbnN0YWxsT3RoZXJBcGtzIiwib3RoZXJBcHBzIiwiQiIsImFsbCIsIm90aGVyQXBwIiwidW5pbnN0YWxsT3RoZXJQYWNrYWdlcyIsImFwcFBhY2thZ2VzIiwiZmlsdGVyUGFja2FnZXMiLCJnZXRUaGlyZFBhcnR5UGFja2FnZXMiLCJwYWNrYWdlc1N0cmluZyIsInNoZWxsIiwiYXBwUGFja2FnZXNBcnJheSIsInNwbGl0IiwiRU9MIiwiZGlmZmVyZW5jZSIsImVyciIsImluaXRVbmljb2RlS2V5Ym9hcmQiLCJkZWZhdWx0SU1FIiwiYXBwaXVtSU1FIiwiZW5hYmxlSU1FIiwic2V0SU1FIiwic2V0TW9ja0xvY2F0aW9uQXBwIiwiZ2V0QXBpTGV2ZWwiLCJwa2dJZHMiLCJmaWxlRXhpc3RzIiwiSlNPTiIsInBhcnNlIiwidG1wUm9vdCIsInRlbXBEaXIiLCJvcGVuRGlyIiwic3JjUGF0aCIsInBhdGgiLCJwb3NpeCIsImJhc2VuYW1lIiwiZnMiLCJ3cml0ZUZpbGUiLCJzdHJpbmdpZnkiLCJyaW1yYWYiLCJyZXNldE1vY2tMb2NhdGlvbiIsInRoaXJkUGFydHlQa2dJZHNQcm9taXNlIiwidGhpcmRQYXJ0eVBrZ0lkcyIsInJlc3VsdFBrZ3MiLCJpbnRlcnNlY3Rpb24iLCJzaXplIiwicGtnSWQiLCJpbnN0YWxsSGVscGVyQXBwIiwiYXBrUGF0aCIsInBhY2thZ2VJZCIsInJldHJ5SW50ZXJ2YWwiLCJyZXRyeUluc3RhbGxIZWxwZXJBcHAiLCJwdXNoU2V0dGluZ3NBcHAiLCJ0aHJvd0Vycm9yIiwic2V0dGluZ3NBcGtQYXRoIiwicHJvY2Vzc0V4aXN0cyIsImFwaUxldmVsIiwicGVybXMiLCJ4IiwicmVxdWlyZVJ1bm5pbmdTZXR0aW5nc0FwcCIsImlzRW11bGF0b3IiLCJwdXNoU3RyaW5ncyIsInJlbW90ZURpciIsInN0cmluZ3NKc29uIiwicmVtb3RlRmlsZSIsInJlc29sdmUiLCJwdWxsQXBrIiwidG1wRGlyIiwiaXNFbXB0eSIsImV4aXN0cyIsInN0cmluZ3NUbXBEaXIiLCJhcGtTdHJpbmdzIiwibG9jYWxQYXRoIiwiZXh0cmFjdFN0cmluZ3NGcm9tQXBrIiwidW5sb2NrIiwiZHJpdmVyIiwiY2FwYWJpbGl0aWVzIiwiaXNTY3JlZW5Mb2NrZWQiLCJ1bmxvY2tLZXkiLCJkaXNtaXNzS2V5Z3VhcmQiLCJ1bmxvY2tTdHJhdGVneSIsInVubG9ja1N1Y2Nlc3NUaW1lb3V0IiwidW5sb2NrZXIiLCJ2YWxpZGF0ZVVubG9ja0NhcGFiaWxpdGllcyIsIkZJTkdFUlBSSU5UX1VOTE9DSyIsImlzTmlsIiwiaXNMb2NrTWFuYWdlbWVudFN1cHBvcnRlZCIsImZhc3RVbmxvY2siLCJjcmVkZW50aWFsIiwiY3JlZGVudGlhbFR5cGUiLCJ1bmxvY2tNZXRob2QiLCJwaW5VbmxvY2siLCJwaW5VbmxvY2tXaXRoS2V5RXZlbnQiLCJwYXNzd29yZFVubG9jayIsInBhdHRlcm5VbmxvY2siLCJmaW5nZXJwcmludFVubG9jayIsInZlcmlmeVVubG9jayIsInRpbWVvdXRNcyIsIndhaXRGb3JDb25kaXRpb24iLCJ3YWl0TXMiLCJpbnRlcnZhbE1zIiwiaW5pdERldmljZSIsInNraXBEZXZpY2VJbml0aWFsaXphdGlvbiIsImxvY2FsZVNjcmlwdCIsInVuaWNvZGVLZXlib2FyZCIsImRpc2FibGVXaW5kb3dBbmltYXRpb24iLCJza2lwVW5sb2NrIiwibW9ja0xvY2F0aW9uQXBwIiwic2tpcExvZ2NhdENhcHR1cmUiLCJsb2djYXRGb3JtYXQiLCJsb2djYXRGaWx0ZXJTcGVjcyIsIndhaXRGb3JEZXZpY2UiLCJzaG91bGRUaHJvd0Vycm9yIiwiaXNVbmRlZmluZWQiLCJzdGFydExvZ2NhdCIsImZvcm1hdCIsImZpbHRlclNwZWNzIiwicmVtb3ZlTnVsbFByb3BlcnRpZXMiLCJpc051bGwiLCJ0cnVuY2F0ZURlY2ltYWxzIiwibnVtYmVyIiwiZGlnaXRzIiwibXVsdGlwbGllciIsIk1hdGgiLCJwb3ciLCJhZGp1c3RlZE51bSIsInRydW5jYXRlZE51bSIsImlzQ2hyb21lQnJvd3NlciIsImdldENocm9tZVBrZyIsInJlbW92ZUFsbFNlc3Npb25XZWJTb2NrZXRIYW5kbGVycyIsInNlcnZlciIsInNlc3Npb25JZCIsImlzRnVuY3Rpb24iLCJnZXRXZWJTb2NrZXRIYW5kbGVycyIsImFjdGl2ZUhhbmRsZXJzIiwicGF0aG5hbWUiLCJyZW1vdmVXZWJTb2NrZXRIYW5kbGVyIiwicGFyc2VBcnJheSIsImNhcCIsInBhcnNlZENhcHMiLCJ2YWxpZGF0ZURlc2lyZWRDYXBzIiwiY2FwcyIsImJyb3dzZXJOYW1lIiwiYWRqdXN0QnJvd3NlclNlc3Npb25DYXBzIiwicG9zc2libGVOYW1lcyIsInNvbWUiLCJ0ZXN0IiwiYm9vdHN0cmFwIiwiQm9vdHN0cmFwIiwiX2RlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi9saWIvYW5kcm9pZC1oZWxwZXJzLmpzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IHJldHJ5SW50ZXJ2YWwsIHdhaXRGb3JDb25kaXRpb24gfSBmcm9tICdhc3luY2JveCc7XG5pbXBvcnQgbG9nZ2VyIGZyb20gJy4vbG9nZ2VyJztcbmltcG9ydCB7IGZzLCB1dGlsLCB0ZW1wRGlyIH0gZnJvbSAnQGFwcGl1bS9zdXBwb3J0JztcbmltcG9ydCB7IHBhdGggYXMgc2V0dGluZ3NBcGtQYXRoIH0gZnJvbSAnaW8uYXBwaXVtLnNldHRpbmdzJztcbmltcG9ydCBCb290c3RyYXAgZnJvbSAnLi9ib290c3RyYXAnO1xuaW1wb3J0IEIgZnJvbSAnYmx1ZWJpcmQnO1xuaW1wb3J0IEFEQiBmcm9tICdhcHBpdW0tYWRiJztcbmltcG9ydCB7XG4gIGRlZmF1bHQgYXMgdW5sb2NrZXIsIFBJTl9VTkxPQ0ssIFBJTl9VTkxPQ0tfS0VZX0VWRU5ULFxuICBQQVNTV09SRF9VTkxPQ0ssIFBBVFRFUk5fVU5MT0NLLCBGSU5HRVJQUklOVF9VTkxPQ0tcbn0gZnJvbSAnLi91bmxvY2staGVscGVycyc7XG5pbXBvcnQgeyBFT0wgfSBmcm9tICdvcyc7XG5pbXBvcnQgc2VtdmVyIGZyb20gJ3NlbXZlcic7XG5cbmNvbnN0IE1PQ0tfQVBQX0lEU19TVE9SRSA9ICcvZGF0YS9sb2NhbC90bXAvbW9ja19hcHBzLmpzb24nO1xuY29uc3QgUEFDS0FHRV9JTlNUQUxMX1RJTUVPVVRfTVMgPSA5MDAwMDtcbmNvbnN0IEhFTFBFUl9BUFBfSU5TVEFMTF9SRVRSSUVTID0gMztcbmNvbnN0IEhFTFBFUl9BUFBfSU5TVEFMTF9SRVRSWV9ERUxBWV9NUyA9IDUwMDA7XG4vLyBodHRwczovL2NzLmNocm9taXVtLm9yZy9jaHJvbWl1bS9zcmMvY2hyb21lL2Jyb3dzZXIvZGV2dG9vbHMvZGV2aWNlL2FuZHJvaWRfZGV2aWNlX2luZm9fcXVlcnkuY2NcbmNvbnN0IENIUk9NRV9CUk9XU0VSX1BBQ0tBR0VfQUNUSVZJVFkgPSB7XG4gIGNocm9tZToge1xuICAgIHBrZzogJ2NvbS5hbmRyb2lkLmNocm9tZScsXG4gICAgYWN0aXZpdHk6ICdjb20uZ29vZ2xlLmFuZHJvaWQuYXBwcy5jaHJvbWUuTWFpbicsXG4gIH0sXG4gIGNocm9taXVtOiB7XG4gICAgcGtnOiAnb3JnLmNocm9taXVtLmNocm9tZS5zaGVsbCcsXG4gICAgYWN0aXZpdHk6ICcuQ2hyb21lU2hlbGxBY3Rpdml0eScsXG4gIH0sXG4gIGNocm9tZWJldGE6IHtcbiAgICBwa2c6ICdjb20uY2hyb21lLmJldGEnLFxuICAgIGFjdGl2aXR5OiAnY29tLmdvb2dsZS5hbmRyb2lkLmFwcHMuY2hyb21lLk1haW4nLFxuICB9LFxuICBicm93c2VyOiB7XG4gICAgcGtnOiAnY29tLmFuZHJvaWQuYnJvd3NlcicsXG4gICAgYWN0aXZpdHk6ICdjb20uYW5kcm9pZC5icm93c2VyLkJyb3dzZXJBY3Rpdml0eScsXG4gIH0sXG4gICdjaHJvbWl1bS1icm93c2VyJzoge1xuICAgIHBrZzogJ29yZy5jaHJvbWl1bS5jaHJvbWUnLFxuICAgIGFjdGl2aXR5OiAnY29tLmdvb2dsZS5hbmRyb2lkLmFwcHMuY2hyb21lLk1haW4nLFxuICB9LFxuICAnY2hyb21pdW0td2Vidmlldyc6IHtcbiAgICBwa2c6ICdvcmcuY2hyb21pdW0ud2Vidmlld19zaGVsbCcsXG4gICAgYWN0aXZpdHk6ICdvcmcuY2hyb21pdW0ud2Vidmlld19zaGVsbC5XZWJWaWV3QnJvd3NlckFjdGl2aXR5JyxcbiAgfSxcbiAgZGVmYXVsdDoge1xuICAgIHBrZzogJ2NvbS5hbmRyb2lkLmNocm9tZScsXG4gICAgYWN0aXZpdHk6ICdjb20uZ29vZ2xlLmFuZHJvaWQuYXBwcy5jaHJvbWUuTWFpbicsXG4gIH0sXG59O1xuY29uc3QgU0VUVElOR1NfSEVMUEVSX1BLR19JRCA9ICdpby5hcHBpdW0uc2V0dGluZ3MnO1xuY29uc3QgU0VUVElOR19OT1RJRklDQVRJT05TX0xJU1RFTkVSX1NFUlZJQ0UgPSBgJHtTRVRUSU5HU19IRUxQRVJfUEtHX0lEfS8uTkxTZXJ2aWNlYDtcbmNvbnN0IEVNVUxBVE9SX1BBVFRFUk4gPSAvXFxiZW11bGF0b3JcXGIvaTtcbi8vIFRoZXNlIGNvbnN0YW50cyBhcmUgaW4gc3luYyB3aXRoXG4vLyBodHRwczovL2RldmVsb3Blci5hcHBsZS5jb20vZG9jdW1lbnRhdGlvbi94Y3Rlc3QveGN1aWFwcGxpY2F0aW9uc3RhdGUveGN1aWFwcGxpY2F0aW9uc3RhdGVydW5uaW5nYmFja2dyb3VuZD9sYW5ndWFnZT1vYmpjXG5jb25zdCBBUFBfU1RBVEUgPSBPYmplY3QuZnJlZXplKHtcbiAgTk9UX0lOU1RBTExFRDogMCxcbiAgTk9UX1JVTk5JTkc6IDEsXG4gIFJVTk5JTkdfSU5fQkFDS0dST1VORDogMyxcbiAgUlVOTklOR19JTl9GT1JFR1JPVU5EOiA0XG59KTtcblxuXG5mdW5jdGlvbiBlbnN1cmVOZXR3b3JrU3BlZWQgKGFkYiwgbmV0d29ya1NwZWVkKSB7XG4gIGlmIChfLnZhbHVlcyhhZGIuTkVUV09SS19TUEVFRCkuaW5jbHVkZXMobmV0d29ya1NwZWVkKSkge1xuICAgIHJldHVybiBuZXR3b3JrU3BlZWQ7XG4gIH1cbiAgbG9nZ2VyLndhcm4oYFdyb25nIG5ldHdvcmsgc3BlZWQgcGFyYW0gJyR7bmV0d29ya1NwZWVkfScsIHVzaW5nIGRlZmF1bHQ6ICR7YWRiLk5FVFdPUktfU1BFRUQuRlVMTH0uIGAgK1xuICAgIGBTdXBwb3J0ZWQgdmFsdWVzOiAke18udmFsdWVzKGFkYi5ORVRXT1JLX1NQRUVEKX1gKTtcbiAgcmV0dXJuIGFkYi5ORVRXT1JLX1NQRUVELkZVTEw7XG59XG5cbmZ1bmN0aW9uIHByZXBhcmVBdmRBcmdzIChhZGIsIG9wdHMpIHtcbiAgY29uc3Qge1xuICAgIG5ldHdvcmtTcGVlZCxcbiAgICBpc0hlYWRsZXNzLFxuICAgIGF2ZEFyZ3MsXG4gIH0gPSBvcHRzO1xuICBjb25zdCByZXN1bHQgPSBbXTtcbiAgaWYgKGF2ZEFyZ3MpIHtcbiAgICBpZiAoXy5pc0FycmF5KGF2ZEFyZ3MpKSB7XG4gICAgICByZXN1bHQucHVzaCguLi5hdmRBcmdzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmVzdWx0LnB1c2goLi4uKHV0aWwuc2hlbGxQYXJzZShgJHthdmRBcmdzfWApKSk7XG4gICAgfVxuICB9XG4gIGlmIChuZXR3b3JrU3BlZWQpIHtcbiAgICByZXN1bHQucHVzaCgnLW5ldHNwZWVkJywgZW5zdXJlTmV0d29ya1NwZWVkKGFkYiwgbmV0d29ya1NwZWVkKSk7XG4gIH1cbiAgaWYgKGlzSGVhZGxlc3MpIHtcbiAgICByZXN1bHQucHVzaCgnLW5vLXdpbmRvdycpO1xuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbmZ1bmN0aW9uIHRvQ3JlZGVudGlhbFR5cGUgKHVubG9ja1R5cGUpIHtcbiAgY29uc3QgcmVzdWx0ID0ge1xuICAgIFtQSU5fVU5MT0NLXTogJ3BpbicsXG4gICAgW1BJTl9VTkxPQ0tfS0VZX0VWRU5UXTogJ3BpbicsXG4gICAgW1BBU1NXT1JEX1VOTE9DS106ICdwYXNzd29yZCcsXG4gICAgW1BBVFRFUk5fVU5MT0NLXTogJ3BhdHRlcm4nLFxuICB9W3VubG9ja1R5cGVdO1xuICBpZiAocmVzdWx0KSB7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuICB0aHJvdyBuZXcgRXJyb3IoYFVubG9jayB0eXBlICcke3VubG9ja1R5cGV9JyBpcyBub3Qga25vd25gKTtcbn1cblxuXG5jb25zdCBoZWxwZXJzID0ge307XG5cbmhlbHBlcnMuY3JlYXRlQmFzZUFEQiA9IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUJhc2VBREIgKG9wdHMgPSB7fSkge1xuICAvLyBmaWx0ZXIgb3V0IGFueSB1bndhbnRlZCBvcHRpb25zIHNlbnQgaW5cbiAgLy8gdGhpcyBsaXN0IHNob3VsZCBiZSB1cGRhdGVkIGFzIEFEQiB0YWtlcyBtb3JlIGFyZ3VtZW50c1xuICBjb25zdCB7XG4gICAgYWRiUG9ydCxcbiAgICBzdXBwcmVzc0tpbGxTZXJ2ZXIsXG4gICAgcmVtb3RlQWRiSG9zdCxcbiAgICBjbGVhckRldmljZUxvZ3NPblN0YXJ0LFxuICAgIGFkYkV4ZWNUaW1lb3V0LFxuICAgIHVzZUtleXN0b3JlLFxuICAgIGtleXN0b3JlUGF0aCxcbiAgICBrZXlzdG9yZVBhc3N3b3JkLFxuICAgIGtleUFsaWFzLFxuICAgIGtleVBhc3N3b3JkLFxuICAgIHJlbW90ZUFwcHNDYWNoZUxpbWl0LFxuICAgIGJ1aWxkVG9vbHNWZXJzaW9uLFxuICAgIGFsbG93T2ZmbGluZURldmljZXMsXG4gICAgYWxsb3dEZWxheUFkYixcbiAgfSA9IG9wdHM7XG4gIHJldHVybiBhd2FpdCBBREIuY3JlYXRlQURCKHtcbiAgICBhZGJQb3J0LFxuICAgIHN1cHByZXNzS2lsbFNlcnZlcixcbiAgICByZW1vdGVBZGJIb3N0LFxuICAgIGNsZWFyRGV2aWNlTG9nc09uU3RhcnQsXG4gICAgYWRiRXhlY1RpbWVvdXQsXG4gICAgdXNlS2V5c3RvcmUsXG4gICAga2V5c3RvcmVQYXRoLFxuICAgIGtleXN0b3JlUGFzc3dvcmQsXG4gICAga2V5QWxpYXMsXG4gICAga2V5UGFzc3dvcmQsXG4gICAgcmVtb3RlQXBwc0NhY2hlTGltaXQsXG4gICAgYnVpbGRUb29sc1ZlcnNpb24sXG4gICAgYWxsb3dPZmZsaW5lRGV2aWNlcyxcbiAgICBhbGxvd0RlbGF5QWRiLFxuICB9KTtcbn07XG5cbmhlbHBlcnMucHJlcGFyZUVtdWxhdG9yID0gYXN5bmMgZnVuY3Rpb24gcHJlcGFyZUVtdWxhdG9yIChhZGIsIG9wdHMpIHtcbiAgY29uc3Qge1xuICAgIGF2ZCxcbiAgICBhdmRFbnY6IGVudixcbiAgICBsYW5ndWFnZSxcbiAgICBsb2NhbGU6IGNvdW50cnksXG4gICAgYXZkTGF1bmNoVGltZW91dDogbGF1bmNoVGltZW91dCxcbiAgICBhdmRSZWFkeVRpbWVvdXQ6IHJlYWR5VGltZW91dCxcbiAgfSA9IG9wdHM7XG4gIGlmICghYXZkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgbGF1bmNoIEFWRCB3aXRob3V0IEFWRCBuYW1lJyk7XG4gIH1cblxuICBjb25zdCBhdmROYW1lID0gYXZkLnJlcGxhY2UoJ0AnLCAnJyk7XG4gIGxldCBpc0VtdWxhdG9yUnVubmluZyA9IHRydWU7XG4gIHRyeSB7XG4gICAgYXdhaXQgYWRiLmdldFJ1bm5pbmdBVkRXaXRoUmV0cnkoYXZkTmFtZSwgNTAwMCk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBsb2dnZXIuZGVidWcoYEVtdWxhdG9yICcke2F2ZE5hbWV9JyBpcyBub3QgcnVubmluZzogJHtlLm1lc3NhZ2V9YCk7XG4gICAgaXNFbXVsYXRvclJ1bm5pbmcgPSBmYWxzZTtcbiAgfVxuICBjb25zdCBhcmdzID0gcHJlcGFyZUF2ZEFyZ3MoYWRiLCBvcHRzKTtcbiAgaWYgKGlzRW11bGF0b3JSdW5uaW5nKSB7XG4gICAgaWYgKGFyZ3MuaW5jbHVkZXMoJy13aXBlLWRhdGEnKSkge1xuICAgICAgbG9nZ2VyLmRlYnVnKGBLaWxsaW5nICcke2F2ZE5hbWV9JyBiZWNhdXNlIGl0IG5lZWRzIHRvIGJlIHdpcGVkIGF0IHN0YXJ0LmApO1xuICAgICAgYXdhaXQgYWRiLmtpbGxFbXVsYXRvcihhdmROYW1lKTtcbiAgICB9IGVsc2Uge1xuICAgICAgbG9nZ2VyLmRlYnVnKCdOb3QgbGF1bmNoaW5nIEFWRCBiZWNhdXNlIGl0IGlzIGFscmVhZHkgcnVubmluZy4nKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gIH1cbiAgYXdhaXQgYWRiLmxhdW5jaEFWRChhdmQsIHtcbiAgICBhcmdzLFxuICAgIGVudixcbiAgICBsYW5ndWFnZSxcbiAgICBjb3VudHJ5LFxuICAgIGxhdW5jaFRpbWVvdXQsXG4gICAgcmVhZHlUaW1lb3V0LFxuICB9KTtcbn07XG5cbi8qKlxuICogU2V0IGFuZCBlbnN1cmUgdGhlIGxvY2FsZSBuYW1lIG9mIHRoZSBkZXZpY2UgdW5kZXIgdGVzdC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gYWRiIC0gVGhlIGFkYiBtb2R1bGUgaW5zdGFuY2UuXG4gKiBAcGFyYW0ge3N0cmluZ30gbGFuZ3VhZ2UgLSBMYW5ndWFnZS4gVGhlIGxhbmd1YWdlIGZpZWxkIGlzIGNhc2UgaW5zZW5zaXRpdmUsIGJ1dCBMb2NhbGUgYWx3YXlzIGNhbm9uaWNhbGl6ZXMgdG8gbG93ZXIgY2FzZS5cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdDogW2EtekEtWl17Miw4fS4gZS5nLiBlbiwgamEgOiBodHRwczovL2RldmVsb3Blci5hbmRyb2lkLmNvbS9yZWZlcmVuY2UvamF2YS91dGlsL0xvY2FsZS5odG1sXG4gKiBAcGFyYW0ge3N0cmluZ30gY291bnRyeSAtIENvdW50cnkuIFRoZSBjb3VudHJ5IChyZWdpb24pIGZpZWxkIGlzIGNhc2UgaW5zZW5zaXRpdmUsIGJ1dCBMb2NhbGUgYWx3YXlzIGNhbm9uaWNhbGl6ZXMgdG8gdXBwZXIgY2FzZS5cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdDogW2EtekEtWl17Mn0gfCBbMC05XXszfS4gZS5nLiBVUywgSlAgOiBodHRwczovL2RldmVsb3Blci5hbmRyb2lkLmNvbS9yZWZlcmVuY2UvamF2YS91dGlsL0xvY2FsZS5odG1sXG4gKiBAcGFyYW0gez9zdHJpbmd9IHNjcmlwdCAtIFNjcmlwdC4gVGhlIHNjcmlwdCBmaWVsZCBpcyBjYXNlIGluc2Vuc2l0aXZlIGJ1dCBMb2NhbGUgYWx3YXlzIGNhbm9uaWNhbGl6ZXMgdG8gdGl0bGUgY2FzZS5cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdDogW2EtekEtWl17NH0uIGUuZy4gSGFucyBpbiB6aC1IYW5zLUNOIDogaHR0cHM6Ly9kZXZlbG9wZXIuYW5kcm9pZC5jb20vcmVmZXJlbmNlL2phdmEvdXRpbC9Mb2NhbGUuaHRtbFxuICogQHRocm93cyB7RXJyb3J9IElmIGl0IGZhaWxlZCB0byBzZXQgbG9jYWxlIHByb3Blcmx5XG4gKi9cbmhlbHBlcnMuZW5zdXJlRGV2aWNlTG9jYWxlID0gYXN5bmMgZnVuY3Rpb24gZW5zdXJlRGV2aWNlTG9jYWxlIChhZGIsIGxhbmd1YWdlLCBjb3VudHJ5LCBzY3JpcHQgPSBudWxsKSB7XG4gIGlmICghXy5pc1N0cmluZyhsYW5ndWFnZSkgJiYgIV8uaXNTdHJpbmcoY291bnRyeSkpIHtcbiAgICBsb2dnZXIud2Fybihgc2V0RGV2aWNlTGFuZ3VhZ2VDb3VudHJ5IHJlcXVpcmVzIGxhbmd1YWdlIG9yIGNvdW50cnkuYCk7XG4gICAgbG9nZ2VyLndhcm4oYEdvdCBsYW5ndWFnZTogJyR7bGFuZ3VhZ2V9JyBhbmQgY291bnRyeTogJyR7Y291bnRyeX0nYCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgYXdhaXQgYWRiLnNldERldmljZUxhbmd1YWdlQ291bnRyeShsYW5ndWFnZSwgY291bnRyeSwgc2NyaXB0KTtcblxuICBpZiAoIWF3YWl0IGFkYi5lbnN1cmVDdXJyZW50TG9jYWxlKGxhbmd1YWdlLCBjb3VudHJ5LCBzY3JpcHQpKSB7XG4gICAgY29uc3QgbWVzc2FnZSA9IHNjcmlwdCA/IGBsYW5ndWFnZTogJHtsYW5ndWFnZX0sIGNvdW50cnk6ICR7Y291bnRyeX0gYW5kIHNjcmlwdDogJHtzY3JpcHR9YCA6IGBsYW5ndWFnZTogJHtsYW5ndWFnZX0gYW5kIGNvdW50cnk6ICR7Y291bnRyeX1gO1xuICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIHNldCAke21lc3NhZ2V9YCk7XG4gIH1cbn07XG5cbmhlbHBlcnMuZ2V0RGV2aWNlSW5mb0Zyb21DYXBzID0gYXN5bmMgZnVuY3Rpb24gZ2V0RGV2aWNlSW5mb0Zyb21DYXBzIChvcHRzID0ge30pIHtcbiAgLy8gd2UgY2FuIGNyZWF0ZSBhIHRocm93YXdheSBBREIgaW5zdGFuY2UgaGVyZSwgc28gdGhlcmUgaXMgbm8gZGVwZW5kZW5jeVxuICAvLyBvbiBpbnN0YW50aWF0aW5nIG9uIGVhcmxpZXIgKGF0IHRoaXMgcG9pbnQsIHdlIGhhdmUgbm8gdWRpZClcbiAgLy8gd2UgY2FuIG9ubHkgdXNlIHRoaXMgQURCIG9iamVjdCBmb3IgY29tbWFuZHMgdGhhdCB3b3VsZCBub3QgYmUgY29uZnVzZWRcbiAgLy8gaWYgbXVsdGlwbGUgZGV2aWNlcyBhcmUgY29ubmVjdGVkXG4gIGNvbnN0IGFkYiA9IGF3YWl0IGhlbHBlcnMuY3JlYXRlQmFzZUFEQihvcHRzKTtcbiAgbGV0IHVkaWQgPSBvcHRzLnVkaWQ7XG4gIGxldCBlbVBvcnQgPSBudWxsO1xuXG4gIC8vIGEgc3BlY2lmaWMgYXZkIG5hbWUgd2FzIGdpdmVuLiB0cnkgdG8gaW5pdGlhbGl6ZSB3aXRoIHRoYXRcbiAgaWYgKG9wdHMuYXZkKSB7XG4gICAgYXdhaXQgaGVscGVycy5wcmVwYXJlRW11bGF0b3IoYWRiLCBvcHRzKTtcbiAgICB1ZGlkID0gYWRiLmN1ckRldmljZUlkO1xuICAgIGVtUG9ydCA9IGFkYi5lbXVsYXRvclBvcnQ7XG4gIH0gZWxzZSB7XG4gICAgLy8gbm8gYXZkIGdpdmVuLiBsZXRzIHRyeSB3aGF0ZXZlcidzIHBsdWdnZWQgaW4gZGV2aWNlcy9lbXVsYXRvcnNcbiAgICBsb2dnZXIuaW5mbygnUmV0cmlldmluZyBkZXZpY2UgbGlzdCcpO1xuICAgIGxldCBkZXZpY2VzID0gYXdhaXQgYWRiLmdldERldmljZXNXaXRoUmV0cnkoKTtcblxuICAgIC8vIHVkaWQgd2FzIGdpdmVuLCBsZXRzIHRyeSB0byBpbml0IHdpdGggdGhhdCBkZXZpY2VcbiAgICBpZiAodWRpZCkge1xuICAgICAgaWYgKCFfLmluY2x1ZGVzKF8ubWFwKGRldmljZXMsICd1ZGlkJyksIHVkaWQpKSB7XG4gICAgICAgIGxvZ2dlci5lcnJvckFuZFRocm93KGBEZXZpY2UgJHt1ZGlkfSB3YXMgbm90IGluIHRoZSBsaXN0IG9mIGNvbm5lY3RlZCBkZXZpY2VzYCk7XG4gICAgICB9XG4gICAgICBlbVBvcnQgPSBhZGIuZ2V0UG9ydEZyb21FbXVsYXRvclN0cmluZyh1ZGlkKTtcbiAgICB9IGVsc2UgaWYgKG9wdHMucGxhdGZvcm1WZXJzaW9uKSB7XG4gICAgICBvcHRzLnBsYXRmb3JtVmVyc2lvbiA9IGAke29wdHMucGxhdGZvcm1WZXJzaW9ufWAudHJpbSgpO1xuXG4gICAgICAvLyBhIHBsYXRmb3JtIHZlcnNpb24gd2FzIGdpdmVuLiBsZXRzIHRyeSB0byBmaW5kIGEgZGV2aWNlIHdpdGggdGhlIHNhbWUgb3NcbiAgICAgIGNvbnN0IHBsYXRmb3JtVmVyc2lvbiA9IHNlbXZlci5jb2VyY2Uob3B0cy5wbGF0Zm9ybVZlcnNpb24pIHx8IG9wdHMucGxhdGZvcm1WZXJzaW9uO1xuICAgICAgbG9nZ2VyLmluZm8oYExvb2tpbmcgZm9yIGEgZGV2aWNlIHdpdGggQW5kcm9pZCAnJHtwbGF0Zm9ybVZlcnNpb259J2ApO1xuXG4gICAgICAvLyBpbiBjYXNlIHdlIGZhaWwgdG8gZmluZCBzb21ldGhpbmcsIGdpdmUgdGhlIHVzZXIgYSB1c2VmdWwgbG9nIHRoYXQgaGFzXG4gICAgICAvLyB0aGUgZGV2aWNlIHVkaWRzIGFuZCBvcyB2ZXJzaW9ucyBzbyB0aGV5IGtub3cgd2hhdCdzIGF2YWlsYWJsZVxuICAgICAgY29uc3QgYXZhaWxEZXZpY2VzID0gW107XG4gICAgICBsZXQgcGFydGlhbE1hdGNoQ2FuZGlkYXRlID0gbnVsbDtcbiAgICAgIC8vIGZpcnN0IHRyeSBzdGFydGVkIGRldmljZXMvZW11bGF0b3JzXG4gICAgICBmb3IgKGNvbnN0IGRldmljZSBvZiBkZXZpY2VzKSB7XG4gICAgICAgIC8vIGRpcmVjdCBhZGIgY2FsbHMgdG8gdGhlIHNwZWNpZmljIGRldmljZVxuICAgICAgICBhd2FpdCBhZGIuc2V0RGV2aWNlSWQoZGV2aWNlLnVkaWQpO1xuICAgICAgICBjb25zdCByYXdEZXZpY2VPUyA9IGF3YWl0IGFkYi5nZXRQbGF0Zm9ybVZlcnNpb24oKTtcbiAgICAgICAgLy8gVGhlIGRldmljZSBPUyBjb3VsZCBlaXRoZXIgYmUgYSBudW1iZXIsIGxpa2UgYDYuMGBcbiAgICAgICAgLy8gb3IgYW4gYWJicmV2aWF0aW9uLCBsaWtlIGBSYFxuICAgICAgICBhdmFpbERldmljZXMucHVzaChgJHtkZXZpY2UudWRpZH0gKCR7cmF3RGV2aWNlT1N9KWApO1xuICAgICAgICBjb25zdCBkZXZpY2VPUyA9IHNlbXZlci5jb2VyY2UocmF3RGV2aWNlT1MpIHx8IHJhd0RldmljZU9TO1xuICAgICAgICBpZiAoIWRldmljZU9TKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBib3RoVmVyc2lvbnNDYW5CZUNvZXJjZWQgPSBzZW12ZXIudmFsaWQoZGV2aWNlT1MpICYmIHNlbXZlci52YWxpZChwbGF0Zm9ybVZlcnNpb24pO1xuICAgICAgICBjb25zdCBib3RoVmVyc2lvbnNBcmVTdHJpbmdzID0gXy5pc1N0cmluZyhkZXZpY2VPUykgJiYgXy5pc1N0cmluZyhwbGF0Zm9ybVZlcnNpb24pO1xuICAgICAgICBpZiAoYm90aFZlcnNpb25zQ2FuQmVDb2VyY2VkICYmIGRldmljZU9TLnZlcnNpb24gPT09IHBsYXRmb3JtVmVyc2lvbi52ZXJzaW9uXG4gICAgICAgICAgICB8fCBib3RoVmVyc2lvbnNBcmVTdHJpbmdzICYmIF8udG9Mb3dlcihkZXZpY2VPUykgPT09IF8udG9Mb3dlcihwbGF0Zm9ybVZlcnNpb24pKSB7XG4gICAgICAgICAgLy8gR290IGFuIGV4YWN0IG1hdGNoIC0gcHJvY2VlZCBpbW1lZGlhdGVseVxuICAgICAgICAgIHVkaWQgPSBkZXZpY2UudWRpZDtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfSBlbHNlIGlmICghYm90aFZlcnNpb25zQ2FuQmVDb2VyY2VkKSB7XG4gICAgICAgICAgLy8gVGhlcmUgaXMgbm8gcG9pbnQgdG8gY2hlY2sgZm9yIHBhcnRpYWwgbWF0Y2ggaWYgZWl0aGVyIG9mIHZlcnNpb24gbnVtYmVycyBpcyBub3QgY29lcmNpYmxlXG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoKCFfLmluY2x1ZGVzKG9wdHMucGxhdGZvcm1WZXJzaW9uLCAnLicpICYmIHBsYXRmb3JtVmVyc2lvbi5tYWpvciA9PT0gZGV2aWNlT1MubWFqb3JcbiAgICAgICAgICAgIHx8IHBsYXRmb3JtVmVyc2lvbi5tYWpvciA9PT0gZGV2aWNlT1MubWFqb3IgJiYgcGxhdGZvcm1WZXJzaW9uLm1pbm9yID09PSBkZXZpY2VPUy5taW5vcilcbiAgICAgICAgICAgIC8vIEdvdCBhIHBhcnRpYWwgbWF0Y2ggLSBtYWtlIHN1cmUgd2UgY29uc2lkZXIgdGhlIG1vc3QgcmVjZW50XG4gICAgICAgICAgICAvLyBkZXZpY2UgdmVyc2lvbiBhdmFpbGFibGUgb24gdGhlIGhvc3Qgc3lzdGVtXG4gICAgICAgICAgICAmJiAocGFydGlhbE1hdGNoQ2FuZGlkYXRlICYmIHNlbXZlci5ndChkZXZpY2VPUywgXy52YWx1ZXMocGFydGlhbE1hdGNoQ2FuZGlkYXRlKVswXSlcbiAgICAgICAgICAgICAgICB8fCAhcGFydGlhbE1hdGNoQ2FuZGlkYXRlKSkge1xuICAgICAgICAgIHBhcnRpYWxNYXRjaENhbmRpZGF0ZSA9IHtbZGV2aWNlLnVkaWRdOiBkZXZpY2VPU307XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGlmICghdWRpZCAmJiBwYXJ0aWFsTWF0Y2hDYW5kaWRhdGUpIHtcbiAgICAgICAgdWRpZCA9IF8ua2V5cyhwYXJ0aWFsTWF0Y2hDYW5kaWRhdGUpWzBdO1xuICAgICAgICBhd2FpdCBhZGIuc2V0RGV2aWNlSWQodWRpZCk7XG4gICAgICB9XG5cbiAgICAgIGlmICghdWRpZCkge1xuICAgICAgICAvLyB3ZSBjb3VsZG4ndCBmaW5kIGFueXRoaW5nISBxdWl0XG4gICAgICAgIGxvZ2dlci5lcnJvckFuZFRocm93KGBVbmFibGUgdG8gZmluZCBhbiBhY3RpdmUgZGV2aWNlIG9yIGVtdWxhdG9yIGAgK1xuICAgICAgICAgIGB3aXRoIE9TICR7b3B0cy5wbGF0Zm9ybVZlcnNpb259LiBUaGUgZm9sbG93aW5nIGFyZSBhdmFpbGFibGU6IGAgK1xuICAgICAgICAgIGF2YWlsRGV2aWNlcy5qb2luKCcsICcpKTtcbiAgICAgIH1cblxuICAgICAgZW1Qb3J0ID0gYWRiLmdldFBvcnRGcm9tRW11bGF0b3JTdHJpbmcodWRpZCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIGEgdWRpZCB3YXMgbm90IGdpdmVuLCBncmFiIHRoZSBmaXJzdCBkZXZpY2Ugd2Ugc2VlXG4gICAgICB1ZGlkID0gZGV2aWNlc1swXS51ZGlkO1xuICAgICAgZW1Qb3J0ID0gYWRiLmdldFBvcnRGcm9tRW11bGF0b3JTdHJpbmcodWRpZCk7XG4gICAgfVxuICB9XG5cbiAgbG9nZ2VyLmluZm8oYFVzaW5nIGRldmljZTogJHt1ZGlkfWApO1xuICByZXR1cm4ge3VkaWQsIGVtUG9ydH07XG59O1xuXG4vLyByZXR1cm5zIGEgbmV3IGFkYiBpbnN0YW5jZSB3aXRoIGRldmljZUlkIHNldFxuaGVscGVycy5jcmVhdGVBREIgPSBhc3luYyBmdW5jdGlvbiBjcmVhdGVBREIgKG9wdHMgPSB7fSkge1xuICBjb25zdCB7dWRpZCwgZW1Qb3J0fSA9IG9wdHM7XG4gIGNvbnN0IGFkYiA9IGF3YWl0IGhlbHBlcnMuY3JlYXRlQmFzZUFEQihvcHRzKTtcbiAgYWRiLnNldERldmljZUlkKHVkaWQpO1xuICBpZiAoZW1Qb3J0KSB7XG4gICAgYWRiLnNldEVtdWxhdG9yUG9ydChlbVBvcnQpO1xuICB9XG5cbiAgcmV0dXJuIGFkYjtcbn07XG5cbmhlbHBlcnMudmFsaWRhdGVQYWNrYWdlQWN0aXZpdHlOYW1lcyA9IGZ1bmN0aW9uIHZhbGlkYXRlUGFja2FnZUFjdGl2aXR5TmFtZXMgKG9wdHMpIHtcbiAgZm9yIChjb25zdCBrZXkgb2YgWydhcHBQYWNrYWdlJywgJ2FwcEFjdGl2aXR5JywgJ2FwcFdhaXRQYWNrYWdlJywgJ2FwcFdhaXRBY3Rpdml0eSddKSB7XG4gICAgY29uc3QgbmFtZSA9IG9wdHNba2V5XTtcbiAgICBpZiAoIW5hbWUpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGNvbnN0IG1hdGNoID0gLyhbXlxcdy4qLF0pKy8uZXhlYyhuYW1lKTtcbiAgICBpZiAoIW1hdGNoKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBsb2dnZXIud2FybihgQ2FwYWJpbGl0eSAnJHtrZXl9JyBpcyBleHBlY3RlZCB0byBvbmx5IGluY2x1ZGUgbGF0aW4gbGV0dGVycywgZGlnaXRzLCB1bmRlcnNjb3JlLCBkb3QsIGNvbW1hIGFuZCBhc3RlcmlzayBjaGFyYWN0ZXJzLmApO1xuICAgIGxvZ2dlci53YXJuKGBDdXJyZW50IHZhbHVlICcke25hbWV9JyBoYXMgbm9uLW1hdGNoaW5nIGNoYXJhY3RlciBhdCBpbmRleCAke21hdGNoLmluZGV4fTogJyR7bmFtZS5zdWJzdHJpbmcoMCwgbWF0Y2guaW5kZXggKyAxKX0nYCk7XG4gIH1cbn07XG5cbmhlbHBlcnMuZ2V0TGF1bmNoSW5mbyA9IGFzeW5jIGZ1bmN0aW9uIGdldExhdW5jaEluZm8gKGFkYiwgb3B0cykge1xuICBsZXQge2FwcCwgYXBwUGFja2FnZSwgYXBwQWN0aXZpdHksIGFwcFdhaXRQYWNrYWdlLCBhcHBXYWl0QWN0aXZpdHl9ID0gb3B0cztcbiAgaWYgKCFhcHApIHtcbiAgICBsb2dnZXIud2FybignTm8gYXBwIHNlbnQgaW4sIG5vdCBwYXJzaW5nIHBhY2thZ2UvYWN0aXZpdHknKTtcbiAgICByZXR1cm47XG4gIH1cblxuICB0aGlzLnZhbGlkYXRlUGFja2FnZUFjdGl2aXR5TmFtZXMob3B0cyk7XG5cbiAgaWYgKGFwcFBhY2thZ2UgJiYgYXBwQWN0aXZpdHkpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBsb2dnZXIuZGVidWcoJ1BhcnNpbmcgcGFja2FnZSBhbmQgYWN0aXZpdHkgZnJvbSBhcHAgbWFuaWZlc3QnKTtcbiAgbGV0IHthcGtQYWNrYWdlLCBhcGtBY3Rpdml0eX0gPVxuICAgIGF3YWl0IGFkYi5wYWNrYWdlQW5kTGF1bmNoQWN0aXZpdHlGcm9tTWFuaWZlc3QoYXBwKTtcbiAgaWYgKGFwa1BhY2thZ2UgJiYgIWFwcFBhY2thZ2UpIHtcbiAgICBhcHBQYWNrYWdlID0gYXBrUGFja2FnZTtcbiAgfVxuICBpZiAoIWFwcFdhaXRQYWNrYWdlKSB7XG4gICAgYXBwV2FpdFBhY2thZ2UgPSBhcHBQYWNrYWdlO1xuICB9XG4gIGlmIChhcGtBY3Rpdml0eSAmJiAhYXBwQWN0aXZpdHkpIHtcbiAgICBhcHBBY3Rpdml0eSA9IGFwa0FjdGl2aXR5O1xuICB9XG4gIGlmICghYXBwV2FpdEFjdGl2aXR5KSB7XG4gICAgYXBwV2FpdEFjdGl2aXR5ID0gYXBwQWN0aXZpdHk7XG4gIH1cbiAgbG9nZ2VyLmRlYnVnKGBQYXJzZWQgcGFja2FnZSBhbmQgYWN0aXZpdHkgYXJlOiAke2Fwa1BhY2thZ2V9LyR7YXBrQWN0aXZpdHl9YCk7XG4gIHJldHVybiB7YXBwUGFja2FnZSwgYXBwV2FpdFBhY2thZ2UsIGFwcEFjdGl2aXR5LCBhcHBXYWl0QWN0aXZpdHl9O1xufTtcblxuaGVscGVycy5yZXNldEFwcCA9IGFzeW5jIGZ1bmN0aW9uIHJlc2V0QXBwIChhZGIsIG9wdHMgPSB7fSkge1xuICBjb25zdCB7XG4gICAgYXBwLFxuICAgIGFwcFBhY2thZ2UsXG4gICAgZmFzdFJlc2V0LFxuICAgIGZ1bGxSZXNldCxcbiAgICBhbmRyb2lkSW5zdGFsbFRpbWVvdXQgPSBQQUNLQUdFX0lOU1RBTExfVElNRU9VVF9NUyxcbiAgICBhdXRvR3JhbnRQZXJtaXNzaW9ucyxcbiAgICBhbGxvd1Rlc3RQYWNrYWdlc1xuICB9ID0gb3B0cztcblxuICBpZiAoIWFwcFBhY2thZ2UpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCInYXBwUGFja2FnZScgb3B0aW9uIGlzIHJlcXVpcmVkXCIpO1xuICB9XG5cbiAgY29uc3QgaXNJbnN0YWxsZWQgPSBhd2FpdCBhZGIuaXNBcHBJbnN0YWxsZWQoYXBwUGFja2FnZSk7XG5cbiAgaWYgKGlzSW5zdGFsbGVkKSB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGFkYi5mb3JjZVN0b3AoYXBwUGFja2FnZSk7XG4gICAgfSBjYXRjaCAoaWduKSB7fVxuICAgIC8vIGZ1bGxSZXNldCBoYXMgcHJpb3JpdHkgb3ZlciBmYXN0UmVzZXRcbiAgICBpZiAoIWZ1bGxSZXNldCAmJiBmYXN0UmVzZXQpIHtcbiAgICAgIGNvbnN0IG91dHB1dCA9IGF3YWl0IGFkYi5jbGVhcihhcHBQYWNrYWdlKTtcbiAgICAgIGlmIChfLmlzU3RyaW5nKG91dHB1dCkgJiYgb3V0cHV0LnRvTG93ZXJDYXNlKCkuaW5jbHVkZXMoJ2ZhaWxlZCcpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IGNsZWFyIHRoZSBhcHBsaWNhdGlvbiBkYXRhIG9mICcke2FwcFBhY2thZ2V9Jy4gT3JpZ2luYWwgZXJyb3I6ICR7b3V0cHV0fWApO1xuICAgICAgfVxuICAgICAgLy8gZXhlY3V0aW5nIGBzaGVsbCBwbSBjbGVhcmAgcmVzZXRzIHByZXZpb3VzbHkgYXNzaWduZWQgYXBwbGljYXRpb24gcGVybWlzc2lvbnMgYXMgd2VsbFxuICAgICAgaWYgKGF1dG9HcmFudFBlcm1pc3Npb25zKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgYWRiLmdyYW50QWxsUGVybWlzc2lvbnMoYXBwUGFja2FnZSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgbG9nZ2VyLmVycm9yKGBVbmFibGUgdG8gZ3JhbnQgcGVybWlzc2lvbnMgcmVxdWVzdGVkLiBPcmlnaW5hbCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBsb2dnZXIuZGVidWcoYFBlcmZvcm1lZCBmYXN0IHJlc2V0IG9uIHRoZSBpbnN0YWxsZWQgJyR7YXBwUGFja2FnZX0nIGFwcGxpY2F0aW9uIChzdG9wIGFuZCBjbGVhcilgKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gIH1cblxuICBpZiAoIWFwcCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgRWl0aGVyIHByb3ZpZGUgJ2FwcCcgb3B0aW9uIHRvIGluc3RhbGwgJyR7YXBwUGFja2FnZX0nIG9yIGAgK1xuICAgICAgYGNvbnNpZGVyIHNldHRpbmcgJ25vUmVzZXQnIHRvICd0cnVlJyBpZiAnJHthcHBQYWNrYWdlfScgaXMgc3VwcG9zZWQgdG8gYmUgcHJlaW5zdGFsbGVkLmApO1xuICB9XG5cbiAgbG9nZ2VyLmRlYnVnKGBSdW5uaW5nIGZ1bGwgcmVzZXQgb24gJyR7YXBwUGFja2FnZX0nIChyZWluc3RhbGwpYCk7XG4gIGlmIChpc0luc3RhbGxlZCkge1xuICAgIGF3YWl0IGFkYi51bmluc3RhbGxBcGsoYXBwUGFja2FnZSk7XG4gIH1cbiAgYXdhaXQgYWRiLmluc3RhbGwoYXBwLCB7XG4gICAgZ3JhbnRQZXJtaXNzaW9uczogYXV0b0dyYW50UGVybWlzc2lvbnMsXG4gICAgdGltZW91dDogYW5kcm9pZEluc3RhbGxUaW1lb3V0LFxuICAgIGFsbG93VGVzdFBhY2thZ2VzLFxuICB9KTtcbn07XG5cbmhlbHBlcnMuaW5zdGFsbEFwayA9IGFzeW5jIGZ1bmN0aW9uIGluc3RhbGxBcGsgKGFkYiwgb3B0cyA9IHt9KSB7XG4gIGNvbnN0IHtcbiAgICBhcHAsXG4gICAgYXBwUGFja2FnZSxcbiAgICBmYXN0UmVzZXQsXG4gICAgZnVsbFJlc2V0LFxuICAgIGFuZHJvaWRJbnN0YWxsVGltZW91dCA9IFBBQ0tBR0VfSU5TVEFMTF9USU1FT1VUX01TLFxuICAgIGF1dG9HcmFudFBlcm1pc3Npb25zLFxuICAgIGFsbG93VGVzdFBhY2thZ2VzLFxuICAgIGVuZm9yY2VBcHBJbnN0YWxsLFxuICB9ID0gb3B0cztcblxuICBpZiAoIWFwcCB8fCAhYXBwUGFja2FnZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcIidhcHAnIGFuZCAnYXBwUGFja2FnZScgb3B0aW9ucyBhcmUgcmVxdWlyZWRcIik7XG4gIH1cblxuICBpZiAoZnVsbFJlc2V0KSB7XG4gICAgYXdhaXQgdGhpcy5yZXNldEFwcChhZGIsIG9wdHMpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IHtcbiAgICBhcHBTdGF0ZSxcbiAgICB3YXNVbmluc3RhbGxlZFxuICB9ID0gYXdhaXQgYWRiLmluc3RhbGxPclVwZ3JhZGUoYXBwLCBhcHBQYWNrYWdlLCB7XG4gICAgZ3JhbnRQZXJtaXNzaW9uczogYXV0b0dyYW50UGVybWlzc2lvbnMsXG4gICAgdGltZW91dDogYW5kcm9pZEluc3RhbGxUaW1lb3V0LFxuICAgIGFsbG93VGVzdFBhY2thZ2VzLFxuICAgIGVuZm9yY2VDdXJyZW50QnVpbGQ6IGVuZm9yY2VBcHBJbnN0YWxsLFxuICB9KTtcblxuICAvLyBUaGVyZSBpcyBubyBuZWVkIHRvIHJlc2V0IHRoZSBuZXdseSBpbnN0YWxsZWQgYXBwXG4gIGNvbnN0IGlzSW5zdGFsbGVkT3ZlckV4aXN0aW5nQXBwID0gIXdhc1VuaW5zdGFsbGVkXG4gICAgJiYgYXBwU3RhdGUgIT09IGFkYi5BUFBfSU5TVEFMTF9TVEFURS5OT1RfSU5TVEFMTEVEO1xuICBpZiAoZmFzdFJlc2V0ICYmIGlzSW5zdGFsbGVkT3ZlckV4aXN0aW5nQXBwKSB7XG4gICAgbG9nZ2VyLmluZm8oYFBlcmZvcm1pbmcgZmFzdCByZXNldCBvbiAnJHthcHBQYWNrYWdlfSdgKTtcbiAgICBhd2FpdCB0aGlzLnJlc2V0QXBwKGFkYiwgb3B0cyk7XG4gIH1cbn07XG5cbi8qKlxuICogSW5zdGFsbHMgYW4gYXJyYXkgb2YgYXBrc1xuICogQHBhcmFtIHtBREJ9IGFkYiBJbnN0YW5jZSBvZiBBcHBpdW0gQURCIG9iamVjdFxuICogQHBhcmFtIHtPYmplY3R9IG9wdHMgT3B0cyBkZWZpbmVkIGluIGRyaXZlci5qc1xuICovXG5oZWxwZXJzLmluc3RhbGxPdGhlckFwa3MgPSBhc3luYyBmdW5jdGlvbiBpbnN0YWxsT3RoZXJBcGtzIChvdGhlckFwcHMsIGFkYiwgb3B0cykge1xuICBsZXQge1xuICAgIGFuZHJvaWRJbnN0YWxsVGltZW91dCA9IFBBQ0tBR0VfSU5TVEFMTF9USU1FT1VUX01TLFxuICAgIGF1dG9HcmFudFBlcm1pc3Npb25zLFxuICAgIGFsbG93VGVzdFBhY2thZ2VzXG4gIH0gPSBvcHRzO1xuXG4gIC8vIEluc3RhbGwgYWxsIG9mIHRoZSBBUEsncyBhc3luY2hyb25vdXNseVxuICBhd2FpdCBCLmFsbChvdGhlckFwcHMubWFwKChvdGhlckFwcCkgPT4ge1xuICAgIGxvZ2dlci5kZWJ1ZyhgSW5zdGFsbGluZyBhcHA6ICR7b3RoZXJBcHB9YCk7XG4gICAgcmV0dXJuIGFkYi5pbnN0YWxsT3JVcGdyYWRlKG90aGVyQXBwLCBudWxsLCB7XG4gICAgICBncmFudFBlcm1pc3Npb25zOiBhdXRvR3JhbnRQZXJtaXNzaW9ucyxcbiAgICAgIHRpbWVvdXQ6IGFuZHJvaWRJbnN0YWxsVGltZW91dCxcbiAgICAgIGFsbG93VGVzdFBhY2thZ2VzLFxuICAgIH0pO1xuICB9KSk7XG59O1xuXG4vKipcbiAqIFVuaW5zdGFsbCBhbiBhcnJheSBvZiBwYWNrYWdlc1xuICogQHBhcmFtIHtBREJ9IGFkYiBJbnN0YW5jZSBvZiBBcHBpdW0gQURCIG9iamVjdFxuICogQHBhcmFtIHtBcnJheTxzdHJpbmc+fSBhcHBQYWNrYWdlcyBBbiBhcnJheSBvZiBwYWNrYWdlIG5hbWVzIHRvIHVuaW5zdGFsbC4gSWYgdGhpcyBpbmNsdWRlcyBgJyonYCwgdW5pbnN0YWxsIGFsbCBvZiAzcmQgcGFydHkgYXBwc1xuICogQHBhcmFtIHtBcnJheTxzdHJpbmc+fSBmaWx0ZXJQYWNrYWdlcyBBbiBhcnJheSBvZiBwYWNrYWdlcyBkb2VzIG5vdCB1bmluc3RhbGwgd2hlbiBgKmAgaXMgcHJvdmlkZWQgYXMgYGFwcFBhY2thZ2VzYFxuICovXG5oZWxwZXJzLnVuaW5zdGFsbE90aGVyUGFja2FnZXMgPSBhc3luYyBmdW5jdGlvbiB1bmluc3RhbGxPdGhlclBhY2thZ2VzIChhZGIsIGFwcFBhY2thZ2VzLCBmaWx0ZXJQYWNrYWdlcyA9IFtdKSB7XG4gIGlmIChhcHBQYWNrYWdlcy5pbmNsdWRlcygnKicpKSB7XG4gICAgbG9nZ2VyLmRlYnVnKCdVbmluc3RhbGwgdGhpcmQgcGFydHkgcGFja2FnZXMnKTtcbiAgICBhcHBQYWNrYWdlcyA9IGF3YWl0IHRoaXMuZ2V0VGhpcmRQYXJ0eVBhY2thZ2VzKGFkYiwgZmlsdGVyUGFja2FnZXMpO1xuICB9XG5cbiAgbG9nZ2VyLmRlYnVnKGBVbmluc3RhbGxpbmcgcGFja2FnZXM6ICR7YXBwUGFja2FnZXN9YCk7XG4gIGF3YWl0IEIuYWxsKGFwcFBhY2thZ2VzLm1hcCgoYXBwUGFja2FnZSkgPT4gYWRiLnVuaW5zdGFsbEFwayhhcHBQYWNrYWdlKSkpO1xufTtcblxuLyoqXG4gKiBHZXQgdGhpcmQgcGFydHkgcGFja2FnZXMgZmlsdGVyZWQgd2l0aCBgZmlsdGVyUGFja2FnZXNgXG4gKiBAcGFyYW0ge0FEQn0gYWRiIEluc3RhbmNlIG9mIEFwcGl1bSBBREIgb2JqZWN0XG4gKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IGZpbHRlclBhY2thZ2VzIEFuIGFycmF5IG9mIHBhY2thZ2VzIGRvZXMgbm90IHVuaW5zdGFsbCB3aGVuIGAqYCBpcyBwcm92aWRlZCBhcyBgYXBwUGFja2FnZXNgXG4gKiBAcmV0dXJucyB7QXJyYXk8c3RyaW5nPn0gQW4gYXJyYXkgb2YgaW5zdGFsbGVkIHRoaXJkIHBhcnkgcGFja2FnZXNcbiAqL1xuaGVscGVycy5nZXRUaGlyZFBhcnR5UGFja2FnZXMgPSBhc3luYyBmdW5jdGlvbiBnZXRUaGlyZFBhcnR5UGFja2FnZXMgKGFkYiwgZmlsdGVyUGFja2FnZXMgPSBbXSkge1xuICB0cnkge1xuICAgIGNvbnN0IHBhY2thZ2VzU3RyaW5nID0gYXdhaXQgYWRiLnNoZWxsKFsncG0nLCAnbGlzdCcsICdwYWNrYWdlcycsICctMyddKTtcbiAgICBjb25zdCBhcHBQYWNrYWdlc0FycmF5ID0gcGFja2FnZXNTdHJpbmcudHJpbSgpLnJlcGxhY2UoL3BhY2thZ2U6L2csICcnKS5zcGxpdChFT0wpO1xuICAgIGxvZ2dlci5kZWJ1ZyhgJyR7YXBwUGFja2FnZXNBcnJheX0nIGZpbHRlcmVkIHdpdGggJyR7ZmlsdGVyUGFja2FnZXN9J2ApO1xuICAgIHJldHVybiBfLmRpZmZlcmVuY2UoYXBwUGFja2FnZXNBcnJheSwgZmlsdGVyUGFja2FnZXMpO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBsb2dnZXIud2FybihgVW5hYmxlIHRvIGdldCBwYWNrYWdlcyB3aXRoICdhZGIgc2hlbGwgcG0gbGlzdCBwYWNrYWdlcyAtMyc6ICR7ZXJyLm1lc3NhZ2V9YCk7XG4gICAgcmV0dXJuIFtdO1xuICB9XG59O1xuXG5oZWxwZXJzLmluaXRVbmljb2RlS2V5Ym9hcmQgPSBhc3luYyBmdW5jdGlvbiBpbml0VW5pY29kZUtleWJvYXJkIChhZGIpIHtcbiAgbG9nZ2VyLmRlYnVnKCdFbmFibGluZyBVbmljb2RlIGtleWJvYXJkIHN1cHBvcnQnKTtcblxuICAvLyBnZXQgdGhlIGRlZmF1bHQgSU1FIHNvIHdlIGNhbiByZXR1cm4gYmFjayB0byBpdCBsYXRlciBpZiB3ZSB3YW50XG4gIGxldCBkZWZhdWx0SU1FID0gYXdhaXQgYWRiLmRlZmF1bHRJTUUoKTtcblxuICBsb2dnZXIuZGVidWcoYFVuc2V0dGluZyBwcmV2aW91cyBJTUUgJHtkZWZhdWx0SU1FfWApO1xuICBjb25zdCBhcHBpdW1JTUUgPSBgJHtTRVRUSU5HU19IRUxQRVJfUEtHX0lEfS8uVW5pY29kZUlNRWA7XG4gIGxvZ2dlci5kZWJ1ZyhgU2V0dGluZyBJTUUgdG8gJyR7YXBwaXVtSU1FfSdgKTtcbiAgYXdhaXQgYWRiLmVuYWJsZUlNRShhcHBpdW1JTUUpO1xuICBhd2FpdCBhZGIuc2V0SU1FKGFwcGl1bUlNRSk7XG4gIHJldHVybiBkZWZhdWx0SU1FO1xufTtcblxuaGVscGVycy5zZXRNb2NrTG9jYXRpb25BcHAgPSBhc3luYyBmdW5jdGlvbiBzZXRNb2NrTG9jYXRpb25BcHAgKGFkYiwgYXBwKSB7XG4gIHRyeSB7XG4gICAgaWYgKGF3YWl0IGFkYi5nZXRBcGlMZXZlbCgpIDwgMjMpIHtcbiAgICAgIGF3YWl0IGFkYi5zaGVsbChbJ3NldHRpbmdzJywgJ3B1dCcsICdzZWN1cmUnLCAnbW9ja19sb2NhdGlvbicsICcxJ10pO1xuICAgIH0gZWxzZSB7XG4gICAgICBhd2FpdCBhZGIuc2hlbGwoWydhcHBvcHMnLCAnc2V0JywgYXBwLCAnYW5kcm9pZDptb2NrX2xvY2F0aW9uJywgJ2FsbG93J10pO1xuICAgIH1cbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nZ2VyLndhcm4oYFVuYWJsZSB0byBzZXQgbW9jayBsb2NhdGlvbiBmb3IgYXBwICcke2FwcH0nOiAke2Vyci5tZXNzYWdlfWApO1xuICAgIHJldHVybjtcbiAgfVxuICB0cnkge1xuICAgIGxldCBwa2dJZHMgPSBbXTtcbiAgICBpZiAoYXdhaXQgYWRiLmZpbGVFeGlzdHMoTU9DS19BUFBfSURTX1NUT1JFKSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcGtnSWRzID0gSlNPTi5wYXJzZShhd2FpdCBhZGIuc2hlbGwoWydjYXQnLCBNT0NLX0FQUF9JRFNfU1RPUkVdKSk7XG4gICAgICB9IGNhdGNoIChpZ24pIHt9XG4gICAgfVxuICAgIGlmIChwa2dJZHMuaW5jbHVkZXMoYXBwKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBwa2dJZHMucHVzaChhcHApO1xuICAgIGNvbnN0IHRtcFJvb3QgPSBhd2FpdCB0ZW1wRGlyLm9wZW5EaXIoKTtcbiAgICBjb25zdCBzcmNQYXRoID0gcGF0aC5wb3NpeC5qb2luKHRtcFJvb3QsIHBhdGgucG9zaXguYmFzZW5hbWUoTU9DS19BUFBfSURTX1NUT1JFKSk7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGZzLndyaXRlRmlsZShzcmNQYXRoLCBKU09OLnN0cmluZ2lmeShwa2dJZHMpLCAndXRmOCcpO1xuICAgICAgYXdhaXQgYWRiLnB1c2goc3JjUGF0aCwgTU9DS19BUFBfSURTX1NUT1JFKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgYXdhaXQgZnMucmltcmFmKHRtcFJvb3QpO1xuICAgIH1cbiAgfSBjYXRjaCAoZSkge1xuICAgIGxvZ2dlci53YXJuKGBVbmFibGUgdG8gcGVyc2lzdCBtb2NrIGxvY2F0aW9uIGFwcCBpZCAnJHthcHB9JzogJHtlLm1lc3NhZ2V9YCk7XG4gIH1cbn07XG5cbmhlbHBlcnMucmVzZXRNb2NrTG9jYXRpb24gPSBhc3luYyBmdW5jdGlvbiByZXNldE1vY2tMb2NhdGlvbiAoYWRiKSB7XG4gIHRyeSB7XG4gICAgaWYgKGF3YWl0IGFkYi5nZXRBcGlMZXZlbCgpIDwgMjMpIHtcbiAgICAgIGF3YWl0IGFkYi5zaGVsbChbJ3NldHRpbmdzJywgJ3B1dCcsICdzZWN1cmUnLCAnbW9ja19sb2NhdGlvbicsICcwJ10pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHRoaXJkUGFydHlQa2dJZHNQcm9taXNlID0gaGVscGVycy5nZXRUaGlyZFBhcnR5UGFja2FnZXMoYWRiKTtcbiAgICBsZXQgcGtnSWRzID0gW107XG4gICAgaWYgKGF3YWl0IGFkYi5maWxlRXhpc3RzKE1PQ0tfQVBQX0lEU19TVE9SRSkpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHBrZ0lkcyA9IEpTT04ucGFyc2UoYXdhaXQgYWRiLnNoZWxsKFsnY2F0JywgTU9DS19BUFBfSURTX1NUT1JFXSkpO1xuICAgICAgfSBjYXRjaCAoaWduKSB7fVxuICAgIH1cbiAgICBjb25zdCB0aGlyZFBhcnR5UGtnSWRzID0gYXdhaXQgdGhpcmRQYXJ0eVBrZ0lkc1Byb21pc2U7XG4gICAgLy8gT25seSBpbmNsdWRlIGN1cnJlbnRseSBpbnN0YWxsZWQgcGFja2FnZXNcbiAgICBjb25zdCByZXN1bHRQa2dzID0gXy5pbnRlcnNlY3Rpb24ocGtnSWRzLCB0aGlyZFBhcnR5UGtnSWRzKTtcbiAgICBpZiAoXy5zaXplKHJlc3VsdFBrZ3MpIDw9IDEpIHtcbiAgICAgIGF3YWl0IGFkYi5zaGVsbChbJ2FwcG9wcycsICdzZXQnLCByZXN1bHRQa2dzWzBdID8/IFNFVFRJTkdTX0hFTFBFUl9QS0dfSUQsICdhbmRyb2lkOm1vY2tfbG9jYXRpb24nLCAnZGVueSddKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBsb2dnZXIuZGVidWcoYFJlc2V0dGluZyBtb2NrX2xvY2F0aW9uIHBlcm1pc3Npb24gZm9yIHRoZSBmb2xsb3dpbmcgYXBwczogJHtyZXN1bHRQa2dzfWApO1xuICAgIGF3YWl0IEIuYWxsKHJlc3VsdFBrZ3MubWFwKChwa2dJZCkgPT4gKGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGFkYi5zaGVsbChbJ2FwcG9wcycsICdzZXQnLCBwa2dJZCwgJ2FuZHJvaWQ6bW9ja19sb2NhdGlvbicsICdkZW55J10pO1xuICAgICAgfSBjYXRjaCAoaWduKSB7fVxuICAgIH0pKCkpKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nZ2VyLndhcm4oYFVuYWJsZSB0byByZXNldCBtb2NrIGxvY2F0aW9uOiAke2Vyci5tZXNzYWdlfWApO1xuICB9XG59O1xuXG5oZWxwZXJzLmluc3RhbGxIZWxwZXJBcHAgPSBhc3luYyBmdW5jdGlvbiBpbnN0YWxsSGVscGVyQXBwIChhZGIsIGFwa1BhdGgsIHBhY2thZ2VJZCkge1xuICAvLyBTb21ldGltZXMgYWRiIHB1c2ggb3IgYWRiIGluc3RhbCB0YWtlIG1vcmUgdGltZSB0aGFuIGV4cGVjdGVkIHRvIGluc3RhbGwgYW4gYXBwXG4gIC8vIGUuZy4gaHR0cHM6Ly9naXRodWIuY29tL2FwcGl1bS9pby5hcHBpdW0uc2V0dGluZ3MvaXNzdWVzLzQwI2lzc3VlY29tbWVudC00NzY1OTMxNzRcbiAgYXdhaXQgcmV0cnlJbnRlcnZhbChIRUxQRVJfQVBQX0lOU1RBTExfUkVUUklFUywgSEVMUEVSX0FQUF9JTlNUQUxMX1JFVFJZX0RFTEFZX01TLFxuICAgIGFzeW5jIGZ1bmN0aW9uIHJldHJ5SW5zdGFsbEhlbHBlckFwcCAoKSB7XG4gICAgICBhd2FpdCBhZGIuaW5zdGFsbE9yVXBncmFkZShhcGtQYXRoLCBwYWNrYWdlSWQsIHtncmFudFBlcm1pc3Npb25zOiB0cnVlfSk7XG4gICAgfVxuICApO1xufTtcblxuLyoqXG4gKiBQdXNoZXMgYW5kIGluc3RhbGxzIGlvLmFwcGl1bS5zZXR0aW5ncyBhcHAuXG4gKiBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIHNldHRpbmcgYXBwIGlzIHJlcXVpcmVkXG4gKlxuICogQHBhcmFtIHtBZGJ9IGFkYiAtIFRoZSBhZGIgbW9kdWxlIGluc3RhbmNlLlxuICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBEcml2ZXIgb3B0aW9ucyBkaWN0aW9uYXJ5LlxuICogQHBhcmFtIHtib29sZWFufSB0aHJvd0Vycm9yIFtmYWxzZV0gLSBXaGV0aGVyIHRocm93IGFuIGVycm9yIGlmIFNldHRpbmdzIGFwcCBmYWlscyB0byBzdGFydFxuICogQHRocm93cyB7RXJyb3J9IElmIHRocm93RXJyb3IgaXMgdHJ1ZSBhbmQgc29tZXRoaW5nIGhhcHBlbnMgaW4gaW5zdGFsbGF0aW9uIHN0ZXBcbiAqL1xuaGVscGVycy5wdXNoU2V0dGluZ3NBcHAgPSBhc3luYyBmdW5jdGlvbiBwdXNoU2V0dGluZ3NBcHAgKGFkYiwgdGhyb3dFcnJvciA9IGZhbHNlLCBvcHRzID0ge30pIHtcbiAgbG9nZ2VyLmRlYnVnKCdQdXNoaW5nIHNldHRpbmdzIGFwayB0byBkZXZpY2UuLi4nKTtcblxuICB0cnkge1xuICAgIGF3YWl0IGhlbHBlcnMuaW5zdGFsbEhlbHBlckFwcChhZGIsIHNldHRpbmdzQXBrUGF0aCwgU0VUVElOR1NfSEVMUEVSX1BLR19JRCwgdGhyb3dFcnJvcik7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGlmICh0aHJvd0Vycm9yKSB7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuXG4gICAgbG9nZ2VyLndhcm4oYElnbm9yZWQgZXJyb3Igd2hpbGUgaW5zdGFsbGluZyAnJHtzZXR0aW5nc0Fwa1BhdGh9JzogYCArXG4gICAgICAgICAgICAgICAgYCcke2Vyci5tZXNzYWdlfScuIEZlYXR1cmVzIHRoYXQgcmVseSBvbiB0aGlzIGhlbHBlciBgICtcbiAgICAgICAgICAgICAgICAncmVxdWlyZSB0aGUgYXBrIHN1Y2ggYXMgdG9nZ2xlIFdpRmkgYW5kIGdldHRpbmcgbG9jYXRpb24gJyArXG4gICAgICAgICAgICAgICAgJ3dpbGwgcmFpc2UgYW4gZXJyb3IgaWYgeW91IHRyeSB0byB1c2UgdGhlbS4nKTtcbiAgfVxuXG4gIC8vIFJlaW5zdGFsbCB3b3VsZCBzdG9wIHRoZSBzZXR0aW5ncyBoZWxwZXIgcHJvY2VzcyBhbnl3YXksIHNvXG4gIC8vIHRoZXJlIGlzIG5vIG5lZWQgdG8gY29udGludWUgaWYgdGhlIGFwcGxpY2F0aW9uIGlzIHN0aWxsIHJ1bm5pbmdcbiAgaWYgKGF3YWl0IGFkYi5wcm9jZXNzRXhpc3RzKFNFVFRJTkdTX0hFTFBFUl9QS0dfSUQpKSB7XG4gICAgbG9nZ2VyLmRlYnVnKGAke1NFVFRJTkdTX0hFTFBFUl9QS0dfSUR9IGlzIGFscmVhZHkgcnVubmluZy4gYCArXG4gICAgICBgVGhlcmUgaXMgbm8gbmVlZCB0byByZXNldCBpdHMgcGVybWlzc2lvbnMuYCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3QgYXBpTGV2ZWwgPSBhd2FpdCBhZGIuZ2V0QXBpTGV2ZWwoKTtcbiAgaWYgKGFwaUxldmVsID49IDI5KSB7XG4gICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL2FwcGl1bS9pby5hcHBpdW0uc2V0dGluZ3MjaW50ZXJuYWwtYXVkaW8tLXZpZGVvLXJlY29yZGluZ1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBhZGIuc2hlbGwoWydhcHBvcHMnLCAnc2V0JywgU0VUVElOR1NfSEVMUEVSX1BLR19JRCwgJ1BST0pFQ1RfTUVESUEnLCAnYWxsb3cnXSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBsb2dnZXIuZGVidWcoZXJyLm1lc3NhZ2UpO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgYXdhaXQgYWRiLnNoZWxsKFsnY21kJywgJ25vdGlmaWNhdGlvbicsICdhbGxvd19saXN0ZW5lcicsIFNFVFRJTkdfTk9USUZJQ0FUSU9OU19MSVNURU5FUl9TRVJWSUNFXSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBsb2dnZXIuZGVidWcoZXJyLm1lc3NhZ2UpO1xuICAgIH1cbiAgfVxuICBpZiAoYXBpTGV2ZWwgPD0gMjMpIHsgLy8gQW5kcm9pZCA2LSBkZXZpY2VzIHNob3VsZCBoYXZlIGdyYW50ZWQgcGVybWlzc2lvbnNcbiAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vYXBwaXVtL2FwcGl1bS9wdWxsLzExNjQwI2lzc3VlY29tbWVudC00MzgyNjA0NzdcbiAgICBjb25zdCBwZXJtcyA9IFsnU0VUX0FOSU1BVElPTl9TQ0FMRScsICdDSEFOR0VfQ09ORklHVVJBVElPTicsICdBQ0NFU1NfRklORV9MT0NBVElPTiddO1xuICAgIGxvZ2dlci5pbmZvKGBHcmFudGluZyBwZXJtaXNzaW9ucyAke3Blcm1zfSB0byAnJHtTRVRUSU5HU19IRUxQRVJfUEtHX0lEfSdgKTtcbiAgICBhd2FpdCBhZGIuZ3JhbnRQZXJtaXNzaW9ucyhTRVRUSU5HU19IRUxQRVJfUEtHX0lELCBwZXJtcy5tYXAoKHgpID0+IGBhbmRyb2lkLnBlcm1pc3Npb24uJHt4fWApKTtcbiAgfVxuXG4gIC8vIGxhdW5jaCBpby5hcHBpdW0uc2V0dGluZ3MgYXBwIGR1ZSB0byBzZXR0aW5ncyBmYWlsaW5nIHRvIGJlIHNldFxuICAvLyBpZiB0aGUgYXBwIGlzIG5vdCBsYXVuY2hlZCBwcmlvciB0byBzdGFydCB0aGUgc2Vzc2lvbiBvbiBhbmRyb2lkIDcrXG4gIC8vIHNlZSBodHRwczovL2dpdGh1Yi5jb20vYXBwaXVtL2FwcGl1bS9pc3N1ZXMvODk1N1xuICB0cnkge1xuICAgIGF3YWl0IGFkYi5yZXF1aXJlUnVubmluZ1NldHRpbmdzQXBwKHtcbiAgICAgIHRpbWVvdXQ6IGhlbHBlcnMuaXNFbXVsYXRvcihhZGIsIG9wdHMpID8gMzAwMDAgOiA1MDAwXG4gICAgfSk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZ2dlci5kZWJ1ZyhlcnIpO1xuICAgIGlmICh0aHJvd0Vycm9yKSB7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIEV4dHJhY3RzIHN0cmluZy54bWwgYW5kIGNvbnZlcnRzIGl0IHRvIHN0cmluZy5qc29uIGFuZCBwdXNoZXNcbiAqIGl0IHRvIC9kYXRhL2xvY2FsL3RtcC9zdHJpbmcuanNvbiBvbiBmb3IgdXNlIG9mIGJvb3RzdHJhcFxuICogSWYgYXBwIGlzIG5vdCBwcmVzZW50IHRvIGV4dHJhY3Qgc3RyaW5nLnhtbCBpdCBkZWxldGVzIHJlbW90ZSBzdHJpbmdzLmpzb25cbiAqIElmIGFwcCBkb2VzIG5vdCBoYXZlIHN0cmluZ3MueG1sIHdlIHB1c2ggYW4gZW1wdHkganNvbiBvYmplY3QgdG8gcmVtb3RlXG4gKlxuICogQHBhcmFtIHs/c3RyaW5nfSBsYW5ndWFnZSAtIExhbmd1YWdlIGFiYnJldmlhdGlvbiwgZm9yIGV4YW1wbGUgJ2ZyJy4gVGhlIGRlZmF1bHQgbGFuZ3VhZ2VcbiAqIGlzIHVzZWQgaWYgdGhpcyBhcmd1bWVudCBpcyBub3QgZGVmaW5lZC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBhZGIgLSBUaGUgYWRiIG1vZHVsZSBpbnN0YW5jZS5cbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRzIC0gRHJpdmVyIG9wdGlvbnMgZGljdGlvbmFyeS5cbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBkaWN0aW9uYXJ5LCB3aGVyZSBzdHJpbmcgcmVzb3VyY2UgaWRlbnRpZmllcnMgYXJlIGtleXNcbiAqIGFsb25nIHdpdGggdGhlaXIgY29ycmVzcG9uZGluZyB2YWx1ZXMgZm9yIHRoZSBnaXZlbiBsYW5ndWFnZSBvciBhbiBlbXB0eSBvYmplY3RcbiAqIGlmIG5vIG1hdGNoaW5nIHJlc291cmNlcyB3ZXJlIGV4dHJhY3RlZC5cbiAqL1xuaGVscGVycy5wdXNoU3RyaW5ncyA9IGFzeW5jIGZ1bmN0aW9uIHB1c2hTdHJpbmdzIChsYW5ndWFnZSwgYWRiLCBvcHRzKSB7XG4gIGNvbnN0IHJlbW90ZURpciA9ICcvZGF0YS9sb2NhbC90bXAnO1xuICBjb25zdCBzdHJpbmdzSnNvbiA9ICdzdHJpbmdzLmpzb24nO1xuICBjb25zdCByZW1vdGVGaWxlID0gcGF0aC5wb3NpeC5yZXNvbHZlKHJlbW90ZURpciwgc3RyaW5nc0pzb24pO1xuXG4gIC8vIGNsZWFuIHVwIHJlbW90ZSBzdHJpbmcuanNvbiBpZiBwcmVzZW50XG4gIGF3YWl0IGFkYi5yaW1yYWYocmVtb3RlRmlsZSk7XG5cbiAgbGV0IGFwcDtcbiAgdHJ5IHtcbiAgICBhcHAgPSBvcHRzLmFwcCB8fCBhd2FpdCBhZGIucHVsbEFwayhvcHRzLmFwcFBhY2thZ2UsIG9wdHMudG1wRGlyKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nZ2VyLmluZm8oYEZhaWxlZCB0byBwdWxsIGFuIGFwayBmcm9tICcke29wdHMuYXBwUGFja2FnZX0nIHRvICcke29wdHMudG1wRGlyfScuIE9yaWdpbmFsIGVycm9yOiAke2Vyci5tZXNzYWdlfWApO1xuICB9XG5cbiAgaWYgKF8uaXNFbXB0eShvcHRzLmFwcFBhY2thZ2UpIHx8ICEoYXdhaXQgZnMuZXhpc3RzKGFwcCkpKSB7XG4gICAgbG9nZ2VyLmRlYnVnKGBObyBhcHAgb3IgcGFja2FnZSBzcGVjaWZpZWQuIFJldHVybmluZyBlbXB0eSBzdHJpbmdzYCk7XG4gICAgcmV0dXJuIHt9O1xuICB9XG5cbiAgY29uc3Qgc3RyaW5nc1RtcERpciA9IHBhdGgucmVzb2x2ZShvcHRzLnRtcERpciwgb3B0cy5hcHBQYWNrYWdlKTtcbiAgdHJ5IHtcbiAgICBsb2dnZXIuZGVidWcoJ0V4dHJhY3Rpbmcgc3RyaW5ncyBmcm9tIGFwaycsIGFwcCwgbGFuZ3VhZ2UsIHN0cmluZ3NUbXBEaXIpO1xuICAgIGNvbnN0IHthcGtTdHJpbmdzLCBsb2NhbFBhdGh9ID0gYXdhaXQgYWRiLmV4dHJhY3RTdHJpbmdzRnJvbUFwayhhcHAsIGxhbmd1YWdlLCBzdHJpbmdzVG1wRGlyKTtcbiAgICBhd2FpdCBhZGIucHVzaChsb2NhbFBhdGgsIHJlbW90ZURpcik7XG4gICAgcmV0dXJuIGFwa1N0cmluZ3M7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZ2dlci53YXJuKGBDb3VsZCBub3QgZ2V0IHN0cmluZ3MsIGNvbnRpbnVpbmcgYW55d2F5LiBPcmlnaW5hbCBlcnJvcjogJHtlcnIubWVzc2FnZX1gKTtcbiAgICBhd2FpdCBhZGIuc2hlbGwoJ2VjaG8nLCBbYCd7fScgPiAke3JlbW90ZUZpbGV9YF0pO1xuICB9IGZpbmFsbHkge1xuICAgIGF3YWl0IGZzLnJpbXJhZihzdHJpbmdzVG1wRGlyKTtcbiAgfVxuICByZXR1cm4ge307XG59O1xuXG5oZWxwZXJzLnVubG9jayA9IGFzeW5jIGZ1bmN0aW9uIHVubG9jayAoZHJpdmVyLCBhZGIsIGNhcGFiaWxpdGllcykge1xuICBpZiAoIShhd2FpdCBhZGIuaXNTY3JlZW5Mb2NrZWQoKSkpIHtcbiAgICBsb2dnZXIuaW5mbygnU2NyZWVuIGFscmVhZHkgdW5sb2NrZWQsIGRvaW5nIG5vdGhpbmcnKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBsb2dnZXIuZGVidWcoJ1NjcmVlbiBpcyBsb2NrZWQsIHRyeWluZyB0byB1bmxvY2snKTtcbiAgaWYgKCFjYXBhYmlsaXRpZXMudW5sb2NrVHlwZSAmJiAhY2FwYWJpbGl0aWVzLnVubG9ja0tleSkge1xuICAgIGxvZ2dlci5pbmZvKGBOZWl0aGVyICd1bmxvY2tUeXBlJyBub3IgJ3VubG9ja0tleScgY2FwYWJpbGl0eSBpcyBwcm92aWRlZC4gYCArXG4gICAgICBgQXNzdW1pbmcgdGhlIGRldmljZSBpcyBsb2NrZWQgd2l0aCBhIHNpbXBsZSBsb2NrIHNjcmVlbi5gKTtcbiAgICBhd2FpdCBhZGIuZGlzbWlzc0tleWd1YXJkKCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3Qge1xuICAgIHVubG9ja1R5cGUsXG4gICAgdW5sb2NrS2V5LFxuICAgIHVubG9ja1N0cmF0ZWd5LFxuICAgIHVubG9ja1N1Y2Nlc3NUaW1lb3V0LFxuICB9ID0gdW5sb2NrZXIudmFsaWRhdGVVbmxvY2tDYXBhYmlsaXRpZXMoY2FwYWJpbGl0aWVzKTtcbiAgaWYgKHVubG9ja0tleSAmJiB1bmxvY2tUeXBlICE9PSBGSU5HRVJQUklOVF9VTkxPQ0tcbiAgICAgICYmIChfLmlzTmlsKHVubG9ja1N0cmF0ZWd5KSB8fCBfLnRvTG93ZXIodW5sb2NrU3RyYXRlZ3kpID09PSAnbG9ja3NldHRpbmdzJylcbiAgICAgICYmIGF3YWl0IGFkYi5pc0xvY2tNYW5hZ2VtZW50U3VwcG9ydGVkKCkpIHtcbiAgICBhd2FpdCB1bmxvY2tlci5mYXN0VW5sb2NrKGFkYiwge1xuICAgICAgY3JlZGVudGlhbDogdW5sb2NrS2V5LFxuICAgICAgY3JlZGVudGlhbFR5cGU6IHRvQ3JlZGVudGlhbFR5cGUodW5sb2NrVHlwZSksXG4gICAgfSk7XG4gIH0gZWxzZSB7XG4gICAgY29uc3QgdW5sb2NrTWV0aG9kID0ge1xuICAgICAgW1BJTl9VTkxPQ0tdOiB1bmxvY2tlci5waW5VbmxvY2ssXG4gICAgICBbUElOX1VOTE9DS19LRVlfRVZFTlRdOiB1bmxvY2tlci5waW5VbmxvY2tXaXRoS2V5RXZlbnQsXG4gICAgICBbUEFTU1dPUkRfVU5MT0NLXTogdW5sb2NrZXIucGFzc3dvcmRVbmxvY2ssXG4gICAgICBbUEFUVEVSTl9VTkxPQ0tdOiB1bmxvY2tlci5wYXR0ZXJuVW5sb2NrLFxuICAgICAgW0ZJTkdFUlBSSU5UX1VOTE9DS106IHVubG9ja2VyLmZpbmdlcnByaW50VW5sb2NrLFxuICAgIH1bdW5sb2NrVHlwZV07XG4gICAgYXdhaXQgdW5sb2NrTWV0aG9kKGFkYiwgZHJpdmVyLCBjYXBhYmlsaXRpZXMpO1xuICB9XG4gIGF3YWl0IGhlbHBlcnMudmVyaWZ5VW5sb2NrKGFkYiwgdW5sb2NrU3VjY2Vzc1RpbWVvdXQpO1xufTtcblxuaGVscGVycy52ZXJpZnlVbmxvY2sgPSBhc3luYyBmdW5jdGlvbiB2ZXJpZnlVbmxvY2sgKGFkYiwgdGltZW91dE1zID0gbnVsbCkge1xuICB0cnkge1xuICAgIGF3YWl0IHdhaXRGb3JDb25kaXRpb24oYXN5bmMgKCkgPT4gIShhd2FpdCBhZGIuaXNTY3JlZW5Mb2NrZWQoKSksIHtcbiAgICAgIHdhaXRNczogdGltZW91dE1zID8/IDIwMDAsXG4gICAgICBpbnRlcnZhbE1zOiA1MDAsXG4gICAgfSk7XG4gIH0gY2F0Y2ggKGlnbikge1xuICAgIHRocm93IG5ldyBFcnJvcignVGhlIGRldmljZSBoYXMgZmFpbGVkIHRvIGJlIHVubG9ja2VkJyk7XG4gIH1cbiAgbG9nZ2VyLmluZm8oJ1RoZSBkZXZpY2UgaGFzIGJlZW4gc3VjY2Vzc2Z1bGx5IHVubG9ja2VkJyk7XG59O1xuXG5oZWxwZXJzLmluaXREZXZpY2UgPSBhc3luYyBmdW5jdGlvbiBpbml0RGV2aWNlIChhZGIsIG9wdHMpIHtcbiAgY29uc3Qge1xuICAgIHNraXBEZXZpY2VJbml0aWFsaXphdGlvbixcbiAgICBsb2NhbGUsXG4gICAgbGFuZ3VhZ2UsXG4gICAgbG9jYWxlU2NyaXB0LFxuICAgIHVuaWNvZGVLZXlib2FyZCxcbiAgICBkaXNhYmxlV2luZG93QW5pbWF0aW9uLFxuICAgIHNraXBVbmxvY2ssXG4gICAgbW9ja0xvY2F0aW9uQXBwLFxuICAgIHNraXBMb2djYXRDYXB0dXJlLFxuICAgIGxvZ2NhdEZvcm1hdCxcbiAgICBsb2djYXRGaWx0ZXJTcGVjcyxcbiAgfSA9IG9wdHM7XG5cbiAgaWYgKHNraXBEZXZpY2VJbml0aWFsaXphdGlvbikge1xuICAgIGxvZ2dlci5pbmZvKGAnc2tpcERldmljZUluaXRpYWxpemF0aW9uJyBpcyBzZXQuIFNraXBwaW5nIGRldmljZSBpbml0aWFsaXphdGlvbi5gKTtcbiAgfSBlbHNlIHtcbiAgICBpZiAoaGVscGVycy5pc0VtdWxhdG9yKGFkYiwgb3B0cykpIHtcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBkZXZpY2Ugd2FrZSB1cCBvbmx5IGZvciBhbiBlbXVsYXRvci5cbiAgICAgIC8vIEl0IHRha2VzIDEgc2Vjb25kIG9yIHNvIGV2ZW4gd2hlbiB0aGUgZGV2aWNlIGlzIGFscmVhZHkgYXdha2UgaW4gYSByZWFsIGRldmljZS5cbiAgICAgIGF3YWl0IGFkYi53YWl0Rm9yRGV2aWNlKCk7XG4gICAgfVxuICAgIC8vIHB1c2hTZXR0aW5nc0FwcCByZXF1aXJlZCBiZWZvcmUgY2FsbGluZyBlbnN1cmVEZXZpY2VMb2NhbGUgZm9yIEFQSSBMZXZlbCAyNCtcblxuICAgIC8vIFNvbWUgZmVhdHVyZSBzdWNoIGFzIGxvY2F0aW9uL3dpZmkgYXJlIG5vdCBuZWNlc3NhcnkgZm9yIGFsbCB1c2VycyxcbiAgICAvLyBidXQgdGhleSByZXF1aXJlIHRoZSBzZXR0aW5ncyBhcHAuIFNvLCB0cnkgdG8gY29uZmlndXJlIGl0IHdoaWxlIEFwcGl1bVxuICAgIC8vIGRvZXMgbm90IHRocm93IGVycm9yIGV2ZW4gaWYgdGhleSBmYWlsLlxuICAgIGNvbnN0IHNob3VsZFRocm93RXJyb3IgPSBsYW5ndWFnZVxuICAgICAgfHwgbG9jYWxlXG4gICAgICB8fCBsb2NhbGVTY3JpcHRcbiAgICAgIHx8IHVuaWNvZGVLZXlib2FyZFxuICAgICAgfHwgZGlzYWJsZVdpbmRvd0FuaW1hdGlvblxuICAgICAgfHwgIXNraXBVbmxvY2s7XG4gICAgYXdhaXQgaGVscGVycy5wdXNoU2V0dGluZ3NBcHAoYWRiLCBzaG91bGRUaHJvd0Vycm9yLCBvcHRzKTtcbiAgfVxuXG4gIGlmICghaGVscGVycy5pc0VtdWxhdG9yKGFkYiwgb3B0cykpIHtcbiAgICBpZiAobW9ja0xvY2F0aW9uQXBwIHx8IF8uaXNVbmRlZmluZWQobW9ja0xvY2F0aW9uQXBwKSkge1xuICAgICAgYXdhaXQgaGVscGVycy5zZXRNb2NrTG9jYXRpb25BcHAoYWRiLCBtb2NrTG9jYXRpb25BcHAgfHwgU0VUVElOR1NfSEVMUEVSX1BLR19JRCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IGhlbHBlcnMucmVzZXRNb2NrTG9jYXRpb24oYWRiKTtcbiAgICB9XG4gIH1cblxuICBpZiAobGFuZ3VhZ2UgfHwgbG9jYWxlKSB7XG4gICAgYXdhaXQgaGVscGVycy5lbnN1cmVEZXZpY2VMb2NhbGUoYWRiLCBsYW5ndWFnZSwgbG9jYWxlLCBsb2NhbGVTY3JpcHQpO1xuICB9XG5cbiAgaWYgKHNraXBMb2djYXRDYXB0dXJlKSB7XG4gICAgbG9nZ2VyLmluZm8oYCdza2lwTG9nY2F0Q2FwdHVyZScgaXMgc2V0LiBTa2lwcGluZyBzdGFydGluZyBsb2djYXQgY2FwdHVyZS5gKTtcbiAgfSBlbHNlIHtcbiAgICBhd2FpdCBhZGIuc3RhcnRMb2djYXQoe1xuICAgICAgZm9ybWF0OiBsb2djYXRGb3JtYXQsXG4gICAgICBmaWx0ZXJTcGVjczogbG9nY2F0RmlsdGVyU3BlY3MsXG4gICAgfSk7XG4gIH1cblxuICBpZiAodW5pY29kZUtleWJvYXJkKSB7XG4gICAgcmV0dXJuIGF3YWl0IGhlbHBlcnMuaW5pdFVuaWNvZGVLZXlib2FyZChhZGIpO1xuICB9XG59O1xuXG5oZWxwZXJzLnJlbW92ZU51bGxQcm9wZXJ0aWVzID0gZnVuY3Rpb24gcmVtb3ZlTnVsbFByb3BlcnRpZXMgKG9iaikge1xuICBmb3IgKGxldCBrZXkgb2YgXy5rZXlzKG9iaikpIHtcbiAgICBpZiAoXy5pc051bGwob2JqW2tleV0pIHx8IF8uaXNVbmRlZmluZWQob2JqW2tleV0pKSB7XG4gICAgICBkZWxldGUgb2JqW2tleV07XG4gICAgfVxuICB9XG59O1xuXG5oZWxwZXJzLnRydW5jYXRlRGVjaW1hbHMgPSBmdW5jdGlvbiB0cnVuY2F0ZURlY2ltYWxzIChudW1iZXIsIGRpZ2l0cykge1xuICBsZXQgbXVsdGlwbGllciA9IE1hdGgucG93KDEwLCBkaWdpdHMpLFxuICAgICAgYWRqdXN0ZWROdW0gPSBudW1iZXIgKiBtdWx0aXBsaWVyLFxuICAgICAgdHJ1bmNhdGVkTnVtID0gTWF0aFthZGp1c3RlZE51bSA8IDAgPyAnY2VpbCcgOiAnZmxvb3InXShhZGp1c3RlZE51bSk7XG5cbiAgcmV0dXJuIHRydW5jYXRlZE51bSAvIG11bHRpcGxpZXI7XG59O1xuXG5oZWxwZXJzLmlzQ2hyb21lQnJvd3NlciA9IGZ1bmN0aW9uIGlzQ2hyb21lQnJvd3NlciAoYnJvd3Nlcikge1xuICByZXR1cm4gXy5pbmNsdWRlcyhPYmplY3Qua2V5cyhDSFJPTUVfQlJPV1NFUl9QQUNLQUdFX0FDVElWSVRZKSwgKGJyb3dzZXIgfHwgJycpLnRvTG93ZXJDYXNlKCkpO1xufTtcblxuaGVscGVycy5nZXRDaHJvbWVQa2cgPSBmdW5jdGlvbiBnZXRDaHJvbWVQa2cgKGJyb3dzZXIpIHtcbiAgcmV0dXJuIENIUk9NRV9CUk9XU0VSX1BBQ0tBR0VfQUNUSVZJVFlbYnJvd3Nlci50b0xvd2VyQ2FzZSgpXSB8fCBDSFJPTUVfQlJPV1NFUl9QQUNLQUdFX0FDVElWSVRZLmRlZmF1bHQ7XG59O1xuXG5oZWxwZXJzLnJlbW92ZUFsbFNlc3Npb25XZWJTb2NrZXRIYW5kbGVycyA9IGFzeW5jIGZ1bmN0aW9uIHJlbW92ZUFsbFNlc3Npb25XZWJTb2NrZXRIYW5kbGVycyAoc2VydmVyLCBzZXNzaW9uSWQpIHtcbiAgaWYgKCFzZXJ2ZXIgfHwgIV8uaXNGdW5jdGlvbihzZXJ2ZXIuZ2V0V2ViU29ja2V0SGFuZGxlcnMpKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3QgYWN0aXZlSGFuZGxlcnMgPSBhd2FpdCBzZXJ2ZXIuZ2V0V2ViU29ja2V0SGFuZGxlcnMoc2Vzc2lvbklkKTtcbiAgZm9yIChjb25zdCBwYXRobmFtZSBvZiBfLmtleXMoYWN0aXZlSGFuZGxlcnMpKSB7XG4gICAgYXdhaXQgc2VydmVyLnJlbW92ZVdlYlNvY2tldEhhbmRsZXIocGF0aG5hbWUpO1xuICB9XG59O1xuXG4vKipcbiAqIFRha2VzIGEgZGVzaXJlZCBjYXBhYmlsaXR5IGFuZCB0cmllcyB0byBKU09OLnBhcnNlIGl0IGFzIGFuIGFycmF5LFxuICogYW5kIGVpdGhlciByZXR1cm5zIHRoZSBwYXJzZWQgYXJyYXkgb3IgYSBzaW5nbGV0b24gYXJyYXkuXG4gKlxuICogQHBhcmFtIHthbnl9IGNhcCBBIGRlc2lyZWQgY2FwYWJpbGl0eVxuICovXG5oZWxwZXJzLnBhcnNlQXJyYXkgPSBmdW5jdGlvbiBwYXJzZUFycmF5IChjYXApIHtcbiAgbGV0IHBhcnNlZENhcHM7XG4gIHRyeSB7XG4gICAgcGFyc2VkQ2FwcyA9IEpTT04ucGFyc2UoY2FwKTtcbiAgfSBjYXRjaCAoaWduKSB7IH1cblxuICBpZiAoXy5pc0FycmF5KHBhcnNlZENhcHMpKSB7XG4gICAgcmV0dXJuIHBhcnNlZENhcHM7XG4gIH0gZWxzZSBpZiAoXy5pc1N0cmluZyhjYXApKSB7XG4gICAgcmV0dXJuIFtjYXBdO1xuICB9XG5cbiAgdGhyb3cgbmV3IEVycm9yKGBtdXN0IHByb3ZpZGUgYSBzdHJpbmcgb3IgSlNPTiBBcnJheTsgcmVjZWl2ZWQgJHtjYXB9YCk7XG59O1xuXG4vKipcbiAqIFZhbGlkYXRlIGRlc2lyZWQgY2FwYWJpbGl0aWVzLiBSZXR1cm5zIHRydWUgaWYgY2FwYWJpbGl0eSBpcyB2YWxpZFxuICpcbiAqIEBwYXJhbSB7Kn0gY2FwIEEgZGVzaXJlZCBjYXBhYmlsaXR5XG4gKiBAcmV0dXJuIHtib29sZWFufSBSZXR1cm5zIHRydWUgaWYgdGhlIGNhcGFiaWxpdHkgaXMgdmFsaWRcbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgY2FwcyBoYXMgaW52YWxpZCBjYXBhYmlsaXR5XG4gKi9cbmhlbHBlcnMudmFsaWRhdGVEZXNpcmVkQ2FwcyA9IGZ1bmN0aW9uIHZhbGlkYXRlRGVzaXJlZENhcHMgKGNhcHMpIHtcbiAgaWYgKGNhcHMuYnJvd3Nlck5hbWUpIHtcbiAgICBpZiAoY2Fwcy5hcHApIHtcbiAgICAgIC8vIHdhcm4gaWYgdGhlIGNhcGFiaWxpdGllcyBoYXZlIGJvdGggYGFwcGAgYW5kIGBicm93c2VyLCBhbHRob3VnaCB0aGlzIGlzIGNvbW1vbiB3aXRoIHNlbGVuaXVtIGdyaWRcbiAgICAgIGxvZ2dlci53YXJuKGBUaGUgZGVzaXJlZCBjYXBhYmlsaXRpZXMgc2hvdWxkIGdlbmVyYWxseSBub3QgaW5jbHVkZSBib3RoIGFuICdhcHAnIGFuZCBhICdicm93c2VyTmFtZSdgKTtcbiAgICB9XG4gICAgaWYgKGNhcHMuYXBwUGFja2FnZSkge1xuICAgICAgbG9nZ2VyLmVycm9yQW5kVGhyb3coYFRoZSBkZXNpcmVkIHNob3VsZCBub3QgaW5jbHVkZSBib3RoIG9mIGFuICdhcHBQYWNrYWdlJyBhbmQgYSAnYnJvd3Nlck5hbWUnYCk7XG4gICAgfVxuICB9XG5cbiAgaWYgKGNhcHMudW5pbnN0YWxsT3RoZXJQYWNrYWdlcykge1xuICAgIHRyeSB7XG4gICAgICB0aGlzLnBhcnNlQXJyYXkoY2Fwcy51bmluc3RhbGxPdGhlclBhY2thZ2VzKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBsb2dnZXIuZXJyb3JBbmRUaHJvdyhgQ291bGQgbm90IHBhcnNlIFwidW5pbnN0YWxsT3RoZXJQYWNrYWdlc1wiIGNhcGFiaWxpdHk6ICR7ZS5tZXNzYWdlfWApO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0cnVlO1xufTtcblxuLyoqXG4gKiBBZGp1c3QgdGhlIGNhcGFiaWxpdGllcyBmb3IgYSBicm93c2VyIHNlc3Npb25cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gY2FwcyAtIEN1cnJlbnQgY2FwYWJpbGl0aWVzIG9iamVjdFxuICogISEhIFRoZSBvYmplY3QgaXMgbXV0YXRlZCBieSB0aGlzIG1ldGhvZCBjYWxsICEhIVxuICogQHJldHVybnMge09iamVjdH0gVGhlIHNhbWUgcG9zc2libHkgbXV0YXRlZCBgb3B0c2AgaW5zdGFuY2UuXG4gKiBObyBtdXRhdGlvbiBpcyBoYXBwZW5pbmcgaXMgdGhlIGN1cnJlbnQgc2Vzc2lvbiBpZlxuICogYXBwUGFja2FnZS9hcHBBY3Rpdml0eSBjYXBzIGhhdmUgYWxyZWFkeSBiZWVuIHByb3ZpZGVkLlxuICovXG5oZWxwZXJzLmFkanVzdEJyb3dzZXJTZXNzaW9uQ2FwcyA9IGZ1bmN0aW9uIGFkanVzdEJyb3dzZXJTZXNzaW9uQ2FwcyAoY2FwcyA9IHt9KSB7XG4gIGNvbnN0IHsgYnJvd3Nlck5hbWUgfSA9IGNhcHM7XG4gIGxvZ2dlci5pbmZvKGBUaGUgY3VycmVudCBzZXNzaW9uIGlzIGNvbnNpZGVyZWQgYnJvd3Nlci1iYXNlZGApO1xuICBsb2dnZXIuaW5mbyhgU3VwcG9ydGVkIGJyb3dzZXIgbmFtZXM6ICR7SlNPTi5zdHJpbmdpZnkoXy5rZXlzKENIUk9NRV9CUk9XU0VSX1BBQ0tBR0VfQUNUSVZJVFkpKX1gKTtcbiAgaWYgKGNhcHMuYXBwUGFja2FnZSB8fCBjYXBzLmFwcEFjdGl2aXR5KSB7XG4gICAgbG9nZ2VyLmluZm8oYE5vdCBvdmVycmlkaW5nIGFwcFBhY2thZ2UvYXBwQWN0aXZpdHkgY2FwYWJpbGl0eSB2YWx1ZXMgZm9yICcke2Jyb3dzZXJOYW1lfScgYCArXG4gICAgICAnYmVjYXVzZSBzb21lIG9mIHRoZW0gaGF2ZSBiZWVuIGFscmVhZHkgcHJvdmlkZWQnKTtcbiAgICByZXR1cm4gY2FwcztcbiAgfVxuXG4gIGNvbnN0IHtwa2csIGFjdGl2aXR5fSA9IHRoaXMuZ2V0Q2hyb21lUGtnKGJyb3dzZXJOYW1lKTtcbiAgY2Fwcy5hcHBQYWNrYWdlID0gcGtnO1xuICBjYXBzLmFwcEFjdGl2aXR5ID0gYWN0aXZpdHk7XG4gIGxvZ2dlci5pbmZvKGBhcHBQYWNrYWdlL2FwcEFjdGl2aXR5IGNhcGFiaWxpdGllcyBoYXZlIGJlZW4gYXV0b21hdGljYWxseSBzZXQgdG8gJHtwa2d9LyR7YWN0aXZpdHl9IGAgK1xuICAgIGBmb3IgJyR7YnJvd3Nlck5hbWV9J2ApO1xuICBsb2dnZXIuaW5mbyhgQ29uc2lkZXIgY2hhbmdpbmcgdGhlIGJyb3dzZXJOYW1lIHRvIHRoZSBvbmUgZnJvbSB0aGUgbGlzdCBvZiBzdXBwb3J0ZWQgYnJvd3NlciBuYW1lcyBgICtcbiAgICBgb3IgcHJvdmlkZSBjdXN0b20gYXBwUGFja2FnZS9hcHBBY3Rpdml0eSBjYXBhYmlsaXR5IHZhbHVlcyBpZiB0aGUgYXV0b21hdGljYWxseSBhc3NpZ25lZCBvbmVzIGRvIGAgK1xuICAgIGBub3QgbWFrZSBzZW5zZWApO1xuICByZXR1cm4gY2Fwcztcbn07XG5cbi8qKlxuICogQ2hlY2tzIHdoZXRoZXIgdGhlIGN1cnJlbnQgZGV2aWNlIHVuZGVyIHRlc3QgaXMgYW4gZW11bGF0b3JcbiAqXG4gKiBAcGFyYW0ge0FEQn0gYWRiIC0gYXBwaXVtLWFkYiBpbnN0YW5jZVxuICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBkcml2ZXIgb3B0aW9ucyBtYXBwaW5nXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gYHRydWVgIGlmIHRoZSBkZXZpY2UgaXMgYW4gQW5kcm9pZCBlbXVsYXRvclxuICovXG5oZWxwZXJzLmlzRW11bGF0b3IgPSBmdW5jdGlvbiBpc0VtdWxhdG9yIChhZGIsIG9wdHMpIHtcbiAgY29uc3QgcG9zc2libGVOYW1lcyA9IFtvcHRzLnVkaWQsIGFkYj8uY3VyRGV2aWNlSWRdO1xuICByZXR1cm4gISFvcHRzLmF2ZCB8fCBwb3NzaWJsZU5hbWVzLnNvbWUoKHgpID0+IEVNVUxBVE9SX1BBVFRFUk4udGVzdCh4KSk7XG59O1xuXG5oZWxwZXJzLmJvb3RzdHJhcCA9IEJvb3RzdHJhcDtcbmhlbHBlcnMudW5sb2NrZXIgPSB1bmxvY2tlcjtcblxuZXhwb3J0IHsgaGVscGVycywgU0VUVElOR1NfSEVMUEVSX1BLR19JRCwgQVBQX1NUQVRFLCBwcmVwYXJlQXZkQXJncywgZW5zdXJlTmV0d29ya1NwZWVkIH07XG5leHBvcnQgZGVmYXVsdCBoZWxwZXJzO1xuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLEtBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFFLFNBQUEsR0FBQUYsT0FBQTtBQUNBLElBQUFHLE9BQUEsR0FBQUosc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFJLFFBQUEsR0FBQUosT0FBQTtBQUNBLElBQUFLLFNBQUEsR0FBQUwsT0FBQTtBQUNBLElBQUFNLFVBQUEsR0FBQVAsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFPLFNBQUEsR0FBQVIsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFRLFVBQUEsR0FBQVQsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFTLGNBQUEsR0FBQUMsdUJBQUEsQ0FBQVYsT0FBQTtBQUlBLElBQUFXLEdBQUEsR0FBQVgsT0FBQTtBQUNBLElBQUFZLE9BQUEsR0FBQWIsc0JBQUEsQ0FBQUMsT0FBQTtBQUE0QixTQUFBYSx5QkFBQUMsV0FBQSxlQUFBQyxPQUFBLGtDQUFBQyxpQkFBQSxPQUFBRCxPQUFBLFFBQUFFLGdCQUFBLE9BQUFGLE9BQUEsWUFBQUYsd0JBQUEsWUFBQUEsQ0FBQUMsV0FBQSxXQUFBQSxXQUFBLEdBQUFHLGdCQUFBLEdBQUFELGlCQUFBLEtBQUFGLFdBQUE7QUFBQSxTQUFBSix3QkFBQVEsR0FBQSxFQUFBSixXQUFBLFNBQUFBLFdBQUEsSUFBQUksR0FBQSxJQUFBQSxHQUFBLENBQUFDLFVBQUEsV0FBQUQsR0FBQSxRQUFB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
|
|
849
|
+
const possibleNames = [opts.udid, adb?.curDeviceId];
|
|
850
|
+
return !!opts.avd || possibleNames.some((x) => EMULATOR_PATTERN.test(x));
|
|
851
|
+
};
|
|
852
|
+
helpers.bootstrap = bootstrap_1.default;
|
|
853
|
+
helpers.unlocker = unlock_helpers_1.helpers;
|
|
854
|
+
exports.default = helpers;
|
|
855
|
+
//# sourceMappingURL=android-helpers.js.map
|