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.
Files changed (151) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/build/index.js +43 -40
  3. package/build/lib/android-helpers.d.ts +136 -0
  4. package/build/lib/android-helpers.d.ts.map +1 -0
  5. package/build/lib/android-helpers.js +760 -679
  6. package/build/lib/android-helpers.js.map +1 -1
  7. package/build/lib/bootstrap.d.ts +29 -0
  8. package/build/lib/bootstrap.d.ts.map +1 -0
  9. package/build/lib/bootstrap.js +192 -179
  10. package/build/lib/bootstrap.js.map +1 -1
  11. package/build/lib/commands/actions.d.ts +209 -0
  12. package/build/lib/commands/actions.d.ts.map +1 -0
  13. package/build/lib/commands/actions.js +327 -265
  14. package/build/lib/commands/actions.js.map +1 -1
  15. package/build/lib/commands/alert.d.ts +10 -0
  16. package/build/lib/commands/alert.d.ts.map +1 -0
  17. package/build/lib/commands/alert.js +12 -18
  18. package/build/lib/commands/alert.js.map +1 -1
  19. package/build/lib/commands/app-management.d.ts +314 -0
  20. package/build/lib/commands/app-management.d.ts.map +1 -0
  21. package/build/lib/commands/app-management.js +278 -110
  22. package/build/lib/commands/app-management.js.map +1 -1
  23. package/build/lib/commands/context.d.ts +94 -0
  24. package/build/lib/commands/context.d.ts.map +1 -0
  25. package/build/lib/commands/context.js +412 -260
  26. package/build/lib/commands/context.js.map +1 -1
  27. package/build/lib/commands/coverage.d.ts +5 -0
  28. package/build/lib/commands/coverage.d.ts.map +1 -0
  29. package/build/lib/commands/coverage.js +14 -17
  30. package/build/lib/commands/coverage.js.map +1 -1
  31. package/build/lib/commands/element.d.ts +36 -0
  32. package/build/lib/commands/element.d.ts.map +1 -0
  33. package/build/lib/commands/element.js +97 -127
  34. package/build/lib/commands/element.js.map +1 -1
  35. package/build/lib/commands/emu-console.d.ts +49 -0
  36. package/build/lib/commands/emu-console.d.ts.map +1 -0
  37. package/build/lib/commands/emu-console.js +36 -25
  38. package/build/lib/commands/emu-console.js.map +1 -1
  39. package/build/lib/commands/execute.d.ts +6 -0
  40. package/build/lib/commands/execute.d.ts.map +1 -0
  41. package/build/lib/commands/execute.js +68 -69
  42. package/build/lib/commands/execute.js.map +1 -1
  43. package/build/lib/commands/file-actions.d.ts +129 -0
  44. package/build/lib/commands/file-actions.d.ts.map +1 -0
  45. package/build/lib/commands/file-actions.js +321 -178
  46. package/build/lib/commands/file-actions.js.map +1 -1
  47. package/build/lib/commands/find.d.ts +13 -0
  48. package/build/lib/commands/find.d.ts.map +1 -0
  49. package/build/lib/commands/find.js +69 -51
  50. package/build/lib/commands/find.js.map +1 -1
  51. package/build/lib/commands/general.d.ts +133 -0
  52. package/build/lib/commands/general.d.ts.map +1 -0
  53. package/build/lib/commands/general.js +275 -216
  54. package/build/lib/commands/general.js.map +1 -1
  55. package/build/lib/commands/ime.d.ts +11 -0
  56. package/build/lib/commands/ime.d.ts.map +1 -0
  57. package/build/lib/commands/ime.js +27 -33
  58. package/build/lib/commands/ime.js.map +1 -1
  59. package/build/lib/commands/index.d.ts +3 -0
  60. package/build/lib/commands/index.d.ts.map +1 -0
  61. package/build/lib/commands/index.js +32 -35
  62. package/build/lib/commands/index.js.map +1 -1
  63. package/build/lib/commands/intent.d.ts +418 -0
  64. package/build/lib/commands/intent.d.ts.map +1 -0
  65. package/build/lib/commands/intent.js +281 -151
  66. package/build/lib/commands/intent.js.map +1 -1
  67. package/build/lib/commands/keyboard.d.ts +6 -0
  68. package/build/lib/commands/keyboard.d.ts.map +1 -0
  69. package/build/lib/commands/keyboard.js +6 -14
  70. package/build/lib/commands/keyboard.js.map +1 -1
  71. package/build/lib/commands/log.d.ts +45 -0
  72. package/build/lib/commands/log.d.ts.map +1 -0
  73. package/build/lib/commands/log.js +117 -103
  74. package/build/lib/commands/log.js.map +1 -1
  75. package/build/lib/commands/media-projection.d.ts +144 -0
  76. package/build/lib/commands/media-projection.d.ts.map +1 -0
  77. package/build/lib/commands/media-projection.js +228 -171
  78. package/build/lib/commands/media-projection.js.map +1 -1
  79. package/build/lib/commands/network.d.ts +139 -0
  80. package/build/lib/commands/network.d.ts.map +1 -0
  81. package/build/lib/commands/network.js +249 -181
  82. package/build/lib/commands/network.js.map +1 -1
  83. package/build/lib/commands/performance.d.ts +101 -0
  84. package/build/lib/commands/performance.d.ts.map +1 -0
  85. package/build/lib/commands/performance.js +390 -236
  86. package/build/lib/commands/performance.js.map +1 -1
  87. package/build/lib/commands/permissions.d.ts +93 -0
  88. package/build/lib/commands/permissions.d.ts.map +1 -0
  89. package/build/lib/commands/permissions.js +133 -93
  90. package/build/lib/commands/permissions.js.map +1 -1
  91. package/build/lib/commands/recordscreen.d.ts +194 -0
  92. package/build/lib/commands/recordscreen.d.ts.map +1 -0
  93. package/build/lib/commands/recordscreen.js +293 -224
  94. package/build/lib/commands/recordscreen.js.map +1 -1
  95. package/build/lib/commands/shell.d.ts +8 -0
  96. package/build/lib/commands/shell.d.ts.map +1 -0
  97. package/build/lib/commands/shell.js +38 -43
  98. package/build/lib/commands/shell.js.map +1 -1
  99. package/build/lib/commands/streamscreen.d.ts +104 -0
  100. package/build/lib/commands/streamscreen.d.ts.map +1 -0
  101. package/build/lib/commands/streamscreen.js +364 -305
  102. package/build/lib/commands/streamscreen.js.map +1 -1
  103. package/build/lib/commands/system-bars.d.ts +100 -0
  104. package/build/lib/commands/system-bars.d.ts.map +1 -0
  105. package/build/lib/commands/system-bars.js +148 -90
  106. package/build/lib/commands/system-bars.js.map +1 -1
  107. package/build/lib/commands/touch.d.ts +30 -0
  108. package/build/lib/commands/touch.d.ts.map +1 -0
  109. package/build/lib/commands/touch.js +311 -287
  110. package/build/lib/commands/touch.js.map +1 -1
  111. package/build/lib/desired-caps.d.ts +353 -0
  112. package/build/lib/desired-caps.d.ts.map +1 -0
  113. package/build/lib/desired-caps.js +291 -292
  114. package/build/lib/desired-caps.js.map +1 -1
  115. package/build/lib/driver.d.ts +430 -0
  116. package/build/lib/driver.d.ts.map +1 -0
  117. package/build/lib/driver.js +449 -384
  118. package/build/lib/driver.js.map +1 -1
  119. package/build/lib/logger.d.ts +3 -0
  120. package/build/lib/logger.d.ts.map +1 -0
  121. package/build/lib/logger.js +5 -11
  122. package/build/lib/logger.js.map +1 -1
  123. package/build/lib/method-map.d.ts +389 -0
  124. package/build/lib/method-map.d.ts.map +1 -0
  125. package/build/lib/method-map.js +220 -394
  126. package/build/lib/method-map.js.map +1 -1
  127. package/build/lib/stubs.d.ts +8 -0
  128. package/build/lib/stubs.d.ts.map +1 -0
  129. package/build/lib/stubs.js +5 -0
  130. package/build/lib/stubs.js.map +1 -0
  131. package/build/lib/uiautomator.d.ts +24 -0
  132. package/build/lib/uiautomator.d.ts.map +1 -0
  133. package/build/lib/uiautomator.js +86 -82
  134. package/build/lib/uiautomator.js.map +1 -1
  135. package/build/lib/unlock-helpers.d.ts +38 -0
  136. package/build/lib/unlock-helpers.d.ts.map +1 -0
  137. package/build/lib/unlock-helpers.js +228 -204
  138. package/build/lib/unlock-helpers.js.map +1 -1
  139. package/build/lib/utils.d.ts +11 -0
  140. package/build/lib/utils.d.ts.map +1 -0
  141. package/build/lib/utils.js +23 -18
  142. package/build/lib/utils.js.map +1 -1
  143. package/build/lib/webview-helpers.d.ts +223 -0
  144. package/build/lib/webview-helpers.d.ts.map +1 -0
  145. package/build/lib/webview-helpers.js +476 -298
  146. package/build/lib/webview-helpers.js.map +1 -1
  147. package/index.js +3 -1
  148. package/lib/android-helpers.js +2 -1
  149. package/lib/stubs.ts +8 -0
  150. package/lib/unlock-helpers.js +2 -2
  151. package/package.json +23 -14
@@ -1,774 +1,855 @@
1
1
  "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
- Object.defineProperty(exports, "__esModule", {
5
- value: true
6
- });
7
- exports.default = exports.SETTINGS_HELPER_PKG_ID = exports.APP_STATE = void 0;
8
- exports.ensureNetworkSpeed = ensureNetworkSpeed;
9
- exports.helpers = void 0;
10
- exports.prepareAvdArgs = prepareAvdArgs;
11
- require("source-map-support/register");
12
- var _lodash = _interopRequireDefault(require("lodash"));
13
- var _path = _interopRequireDefault(require("path"));
14
- var _asyncbox = require("asyncbox");
15
- var _logger = _interopRequireDefault(require("./logger"));
16
- var _support = require("@appium/support");
17
- var _ioAppium = require("io.appium.settings");
18
- var _bootstrap = _interopRequireDefault(require("./bootstrap"));
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
- chrome: {
32
- pkg: 'com.android.chrome',
33
- activity: 'com.google.android.apps.chrome.Main'
34
- },
35
- chromium: {
36
- pkg: 'org.chromium.chrome.shell',
37
- activity: '.ChromeShellActivity'
38
- },
39
- chromebeta: {
40
- pkg: 'com.chrome.beta',
41
- activity: 'com.google.android.apps.chrome.Main'
42
- },
43
- browser: {
44
- pkg: 'com.android.browser',
45
- activity: 'com.android.browser.BrowserActivity'
46
- },
47
- 'chromium-browser': {
48
- pkg: 'org.chromium.chrome',
49
- activity: 'com.google.android.apps.chrome.Main'
50
- },
51
- 'chromium-webview': {
52
- pkg: 'org.chromium.webview_shell',
53
- activity: 'org.chromium.webview_shell.WebViewBrowserActivity'
54
- },
55
- default: {
56
- pkg: 'com.android.chrome',
57
- activity: 'com.google.android.apps.chrome.Main'
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
- NOT_INSTALLED: 0,
66
- NOT_RUNNING: 1,
67
- RUNNING_IN_BACKGROUND: 3,
68
- RUNNING_IN_FOREGROUND: 4
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
- if (_lodash.default.values(adb.NETWORK_SPEED).includes(networkSpeed)) {
73
- return networkSpeed;
74
- }
75
- _logger.default.warn(`Wrong network speed param '${networkSpeed}', using default: ${adb.NETWORK_SPEED.FULL}. ` + `Supported values: ${_lodash.default.values(adb.NETWORK_SPEED)}`);
76
- return adb.NETWORK_SPEED.FULL;
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
- const {
80
- networkSpeed,
81
- isHeadless,
82
- avdArgs
83
- } = opts;
84
- const result = [];
85
- if (avdArgs) {
86
- if (_lodash.default.isArray(avdArgs)) {
87
- result.push(...avdArgs);
88
- } else {
89
- result.push(..._support.util.shellParse(`${avdArgs}`));
90
- }
91
- }
92
- if (networkSpeed) {
93
- result.push('-netspeed', ensureNetworkSpeed(adb, networkSpeed));
94
- }
95
- if (isHeadless) {
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
- const result = {
102
- [_unlockHelpers.PIN_UNLOCK]: 'pin',
103
- [_unlockHelpers.PIN_UNLOCK_KEY_EVENT]: 'pin',
104
- [_unlockHelpers.PASSWORD_UNLOCK]: 'password',
105
- [_unlockHelpers.PATTERN_UNLOCK]: 'pattern'
106
- }[unlockType];
107
- if (result) {
108
- return result;
109
- }
110
- throw new Error(`Unlock type '${unlockType}' is not known`);
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
- const {
116
- adbPort,
117
- suppressKillServer,
118
- remoteAdbHost,
119
- clearDeviceLogsOnStart,
120
- adbExecTimeout,
121
- useKeystore,
122
- keystorePath,
123
- keystorePassword,
124
- keyAlias,
125
- keyPassword,
126
- remoteAppsCacheLimit,
127
- buildToolsVersion,
128
- allowOfflineDevices,
129
- allowDelayAdb
130
- } = opts;
131
- return await _appiumAdb.default.createADB({
132
- adbPort,
133
- suppressKillServer,
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
- const {
150
- avd,
151
- avdEnv: env,
152
- language,
153
- locale: country,
154
- avdLaunchTimeout: launchTimeout,
155
- avdReadyTimeout: readyTimeout
156
- } = opts;
157
- if (!avd) {
158
- throw new Error('Cannot launch AVD without AVD name');
159
- }
160
- const avdName = avd.replace('@', '');
161
- let isEmulatorRunning = true;
162
- try {
163
- await adb.getRunningAVDWithRetry(avdName, 5000);
164
- } catch (e) {
165
- _logger.default.debug(`Emulator '${avdName}' is not running: ${e.message}`);
166
- isEmulatorRunning = false;
167
- }
168
- const args = prepareAvdArgs(adb, opts);
169
- if (isEmulatorRunning) {
170
- if (args.includes('-wipe-data')) {
171
- _logger.default.debug(`Killing '${avdName}' because it needs to be wiped at start.`);
172
- await adb.killEmulator(avdName);
173
- } else {
174
- _logger.default.debug('Not launching AVD because it is already running.');
175
- return;
176
- }
177
- }
178
- await adb.launchAVD(avd, {
179
- args,
180
- env,
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
- if (!_lodash.default.isString(language) && !_lodash.default.isString(country)) {
189
- _logger.default.warn(`setDeviceLanguageCountry requires language or country.`);
190
- _logger.default.warn(`Got language: '${language}' and country: '${country}'`);
191
- return;
192
- }
193
- await adb.setDeviceLanguageCountry(language, country, script);
194
- if (!(await adb.ensureCurrentLocale(language, country, script))) {
195
- const message = script ? `language: ${language}, country: ${country} and script: ${script}` : `language: ${language} and country: ${country}`;
196
- throw new Error(`Failed to set ${message}`);
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
- const adb = await helpers.createBaseADB(opts);
201
- let udid = opts.udid;
202
- let emPort = null;
203
- if (opts.avd) {
204
- await helpers.prepareEmulator(adb, opts);
205
- udid = adb.curDeviceId;
206
- emPort = adb.emulatorPort;
207
- } else {
208
- _logger.default.info('Retrieving device list');
209
- let devices = await adb.getDevicesWithRetry();
210
- if (udid) {
211
- if (!_lodash.default.includes(_lodash.default.map(devices, 'udid'), udid)) {
212
- _logger.default.errorAndThrow(`Device ${udid} was not in the list of connected devices`);
213
- }
214
- emPort = adb.getPortFromEmulatorString(udid);
215
- } else if (opts.platformVersion) {
216
- opts.platformVersion = `${opts.platformVersion}`.trim();
217
- const platformVersion = _semver.default.coerce(opts.platformVersion) || opts.platformVersion;
218
- _logger.default.info(`Looking for a device with Android '${platformVersion}'`);
219
- const availDevices = [];
220
- let partialMatchCandidate = null;
221
- for (const device of devices) {
222
- await adb.setDeviceId(device.udid);
223
- const rawDeviceOS = await adb.getPlatformVersion();
224
- availDevices.push(`${device.udid} (${rawDeviceOS})`);
225
- const deviceOS = _semver.default.coerce(rawDeviceOS) || rawDeviceOS;
226
- if (!deviceOS) {
227
- continue;
228
- }
229
- const bothVersionsCanBeCoerced = _semver.default.valid(deviceOS) && _semver.default.valid(platformVersion);
230
- const bothVersionsAreStrings = _lodash.default.isString(deviceOS) && _lodash.default.isString(platformVersion);
231
- if (bothVersionsCanBeCoerced && deviceOS.version === platformVersion.version || bothVersionsAreStrings && _lodash.default.toLower(deviceOS) === _lodash.default.toLower(platformVersion)) {
232
- udid = device.udid;
233
- break;
234
- } else if (!bothVersionsCanBeCoerced) {
235
- continue;
236
- }
237
- if ((!_lodash.default.includes(opts.platformVersion, '.') && platformVersion.major === deviceOS.major || platformVersion.major === deviceOS.major && platformVersion.minor === deviceOS.minor) && (partialMatchCandidate && _semver.default.gt(deviceOS, _lodash.default.values(partialMatchCandidate)[0]) || !partialMatchCandidate)) {
238
- partialMatchCandidate = {
239
- [device.udid]: deviceOS
240
- };
241
- }
242
- }
243
- if (!udid && partialMatchCandidate) {
244
- udid = _lodash.default.keys(partialMatchCandidate)[0];
245
- await adb.setDeviceId(udid);
246
- }
247
- if (!udid) {
248
- _logger.default.errorAndThrow(`Unable to find an active device or emulator ` + `with OS ${opts.platformVersion}. The following are available: ` + availDevices.join(', '));
249
- }
250
- emPort = adb.getPortFromEmulatorString(udid);
251
- } else {
252
- udid = devices[0].udid;
253
- emPort = adb.getPortFromEmulatorString(udid);
254
- }
255
- }
256
- _logger.default.info(`Using device: ${udid}`);
257
- return {
258
- udid,
259
- emPort
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
- const {
264
- udid,
265
- emPort
266
- } = opts;
267
- const adb = await helpers.createBaseADB(opts);
268
- adb.setDeviceId(udid);
269
- if (emPort) {
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
- for (const key of ['appPackage', 'appActivity', 'appWaitPackage', 'appWaitActivity']) {
276
- const name = opts[key];
277
- if (!name) {
278
- continue;
279
- }
280
- const match = /([^\w.*,])+/.exec(name);
281
- if (!match) {
282
- continue;
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
- let {
290
- app,
291
- appPackage,
292
- appActivity,
293
- appWaitPackage,
294
- appWaitActivity
295
- } = opts;
296
- if (!app) {
297
- _logger.default.warn('No app sent in, not parsing package/activity');
298
- return;
299
- }
300
- this.validatePackageActivityNames(opts);
301
- if (appPackage && appActivity) {
302
- return;
303
- }
304
- _logger.default.debug('Parsing package and activity from app manifest');
305
- let {
306
- apkPackage,
307
- apkActivity
308
- } = await adb.packageAndLaunchActivityFromManifest(app);
309
- if (apkPackage && !appPackage) {
310
- appPackage = apkPackage;
311
- }
312
- if (!appWaitPackage) {
313
- appWaitPackage = appPackage;
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
- const {
331
- app,
332
- appPackage,
333
- fastReset,
334
- fullReset,
335
- androidInstallTimeout = PACKAGE_INSTALL_TIMEOUT_MS,
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
- await adb.grantAllPermissions(appPackage);
355
- } catch (error) {
356
- _logger.default.error(`Unable to grant permissions requested. Original error: ${error.message}`);
357
- }
358
- }
359
- _logger.default.debug(`Performed fast reset on the installed '${appPackage}' application (stop and clear)`);
360
- return;
361
- }
362
- }
363
- if (!app) {
364
- throw new Error(`Either provide 'app' option to install '${appPackage}' or ` + `consider setting 'noReset' to 'true' if '${appPackage}' is supposed to be preinstalled.`);
365
- }
366
- _logger.default.debug(`Running full reset on '${appPackage}' (reinstall)`);
367
- if (isInstalled) {
368
- await adb.uninstallApk(appPackage);
369
- }
370
- await adb.install(app, {
371
- grantPermissions: autoGrantPermissions,
372
- timeout: androidInstallTimeout,
373
- allowTestPackages
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
- const {
378
- app,
379
- appPackage,
380
- fastReset,
381
- fullReset,
382
- androidInstallTimeout = PACKAGE_INSTALL_TIMEOUT_MS,
383
- autoGrantPermissions,
384
- allowTestPackages,
385
- enforceAppInstall
386
- } = opts;
387
- if (!app || !appPackage) {
388
- throw new Error("'app' and 'appPackage' options are required");
389
- }
390
- if (fullReset) {
391
- await this.resetApp(adb, opts);
392
- return;
393
- }
394
- const {
395
- appState,
396
- wasUninstalled
397
- } = await adb.installOrUpgrade(app, appPackage, {
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
- let {
411
- androidInstallTimeout = PACKAGE_INSTALL_TIMEOUT_MS,
412
- autoGrantPermissions,
413
- allowTestPackages
414
- } = opts;
415
- await _bluebird.default.all(otherApps.map(otherApp => {
416
- _logger.default.debug(`Installing app: ${otherApp}`);
417
- return adb.installOrUpgrade(otherApp, null, {
418
- grantPermissions: autoGrantPermissions,
419
- timeout: androidInstallTimeout,
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
- if (appPackages.includes('*')) {
426
- _logger.default.debug('Uninstall third party packages');
427
- appPackages = await this.getThirdPartyPackages(adb, filterPackages);
428
- }
429
- _logger.default.debug(`Uninstalling packages: ${appPackages}`);
430
- await _bluebird.default.all(appPackages.map(appPackage => adb.uninstallApk(appPackage)));
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
- try {
434
- const packagesString = await adb.shell(['pm', 'list', 'packages', '-3']);
435
- const appPackagesArray = packagesString.trim().replace(/package:/g, '').split(_os.EOL);
436
- _logger.default.debug(`'${appPackagesArray}' filtered with '${filterPackages}'`);
437
- return _lodash.default.difference(appPackagesArray, filterPackages);
438
- } catch (err) {
439
- _logger.default.warn(`Unable to get packages with 'adb shell pm list packages -3': ${err.message}`);
440
- return [];
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
- _logger.default.debug('Enabling Unicode keyboard support');
445
- let defaultIME = await adb.defaultIME();
446
- _logger.default.debug(`Unsetting previous IME ${defaultIME}`);
447
- const appiumIME = `${SETTINGS_HELPER_PKG_ID}/.UnicodeIME`;
448
- _logger.default.debug(`Setting IME to '${appiumIME}'`);
449
- await adb.enableIME(appiumIME);
450
- await adb.setIME(appiumIME);
451
- return defaultIME;
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
- await _support.fs.writeFile(srcPath, JSON.stringify(pkgIds), 'utf8');
479
- await adb.push(srcPath, MOCK_APP_IDS_STORE);
480
- } finally {
481
- await _support.fs.rimraf(tmpRoot);
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
- try {
489
- if ((await adb.getApiLevel()) < 23) {
490
- await adb.shell(['settings', 'put', 'secure', 'mock_location', '0']);
491
- return;
492
- }
493
- const thirdPartyPkgIdsPromise = helpers.getThirdPartyPackages(adb);
494
- let pkgIds = [];
495
- if (await adb.fileExists(MOCK_APP_IDS_STORE)) {
496
- try {
497
- pkgIds = JSON.parse(await adb.shell(['cat', MOCK_APP_IDS_STORE]));
498
- } catch (ign) {}
499
- }
500
- const thirdPartyPkgIds = await thirdPartyPkgIdsPromise;
501
- const resultPkgs = _lodash.default.intersection(pkgIds, thirdPartyPkgIds);
502
- if (_lodash.default.size(resultPkgs) <= 1) {
503
- await adb.shell(['appops', 'set', resultPkgs[0] ?? SETTINGS_HELPER_PKG_ID, 'android:mock_location', 'deny']);
504
- return;
505
- }
506
- _logger.default.debug(`Resetting mock_location permission for the following apps: ${resultPkgs}`);
507
- await _bluebird.default.all(resultPkgs.map(pkgId => (async () => {
508
- try {
509
- await adb.shell(['appops', 'set', pkgId, 'android:mock_location', 'deny']);
510
- } catch (ign) {}
511
- })()));
512
- } catch (err) {
513
- _logger.default.warn(`Unable to reset mock location: ${err.message}`);
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
- await (0, _asyncbox.retryInterval)(HELPER_APP_INSTALL_RETRIES, HELPER_APP_INSTALL_RETRY_DELAY_MS, async function retryInstallHelperApp() {
518
- await adb.installOrUpgrade(apkPath, packageId, {
519
- grantPermissions: true
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
- _logger.default.debug('Pushing settings apk to device...');
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
- await adb.shell(['appops', 'set', SETTINGS_HELPER_PKG_ID, 'PROJECT_MEDIA', 'allow']);
541
- } catch (err) {
542
- _logger.default.debug(err.message);
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
- await adb.shell(['cmd', 'notification', 'allow_listener', SETTING_NOTIFICATIONS_LISTENER_SERVICE]);
546
- } catch (err) {
547
- _logger.default.debug(err.message);
548
- }
549
- }
550
- if (apiLevel <= 23) {
551
- const perms = ['SET_ANIMATION_SCALE', 'CHANGE_CONFIGURATION', 'ACCESS_FINE_LOCATION'];
552
- _logger.default.info(`Granting permissions ${perms} to '${SETTINGS_HELPER_PKG_ID}'`);
553
- await adb.grantPermissions(SETTINGS_HELPER_PKG_ID, perms.map(x => `android.permission.${x}`));
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
- const remoteDir = '/data/local/tmp';
568
- const stringsJson = 'strings.json';
569
- const remoteFile = _path.default.posix.resolve(remoteDir, stringsJson);
570
- await adb.rimraf(remoteFile);
571
- let app;
572
- try {
573
- app = opts.app || (await adb.pullApk(opts.appPackage, opts.tmpDir));
574
- } catch (err) {
575
- _logger.default.info(`Failed to pull an apk from '${opts.appPackage}' to '${opts.tmpDir}'. Original error: ${err.message}`);
576
- }
577
- if (_lodash.default.isEmpty(opts.appPackage) || !(await _support.fs.exists(app))) {
578
- _logger.default.debug(`No app or package specified. Returning empty strings`);
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
- if (!(await adb.isScreenLocked())) {
600
- _logger.default.info('Screen already unlocked, doing nothing');
601
- return;
602
- }
603
- _logger.default.debug('Screen is locked, trying to unlock');
604
- if (!capabilities.unlockType && !capabilities.unlockKey) {
605
- _logger.default.info(`Neither 'unlockType' nor 'unlockKey' capability is provided. ` + `Assuming the device is locked with a simple lock screen.`);
606
- await adb.dismissKeyguard();
607
- return;
608
- }
609
- const {
610
- unlockType,
611
- unlockKey,
612
- unlockStrategy,
613
- unlockSuccessTimeout
614
- } = _unlockHelpers.default.validateUnlockCapabilities(capabilities);
615
- if (unlockKey && unlockType !== _unlockHelpers.FINGERPRINT_UNLOCK && (_lodash.default.isNil(unlockStrategy) || _lodash.default.toLower(unlockStrategy) === 'locksettings') && (await adb.isLockManagementSupported())) {
616
- await _unlockHelpers.default.fastUnlock(adb, {
617
- credential: unlockKey,
618
- credentialType: toCredentialType(unlockType)
619
- });
620
- } else {
621
- const unlockMethod = {
622
- [_unlockHelpers.PIN_UNLOCK]: _unlockHelpers.default.pinUnlock,
623
- [_unlockHelpers.PIN_UNLOCK_KEY_EVENT]: _unlockHelpers.default.pinUnlockWithKeyEvent,
624
- [_unlockHelpers.PASSWORD_UNLOCK]: _unlockHelpers.default.passwordUnlock,
625
- [_unlockHelpers.PATTERN_UNLOCK]: _unlockHelpers.default.patternUnlock,
626
- [_unlockHelpers.FINGERPRINT_UNLOCK]: _unlockHelpers.default.fingerprintUnlock
627
- }[unlockType];
628
- await unlockMethod(adb, driver, capabilities);
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
- try {
634
- await (0, _asyncbox.waitForCondition)(async () => !(await adb.isScreenLocked()), {
635
- waitMs: timeoutMs ?? 2000,
636
- intervalMs: 500
637
- });
638
- } catch (ign) {
639
- throw new Error('The device has failed to be unlocked');
640
- }
641
- _logger.default.info('The device has been successfully unlocked');
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
- const {
645
- skipDeviceInitialization,
646
- locale,
647
- language,
648
- localeScript,
649
- unicodeKeyboard,
650
- disableWindowAnimation,
651
- skipUnlock,
652
- mockLocationApp,
653
- skipLogcatCapture,
654
- logcatFormat,
655
- logcatFilterSpecs
656
- } = opts;
657
- if (skipDeviceInitialization) {
658
- _logger.default.info(`'skipDeviceInitialization' is set. Skipping device initialization.`);
659
- } else {
660
- if (helpers.isEmulator(adb, opts)) {
661
- await adb.waitForDevice();
662
- }
663
- const shouldThrowError = language || locale || localeScript || unicodeKeyboard || disableWindowAnimation || !skipUnlock;
664
- await helpers.pushSettingsApp(adb, shouldThrowError, opts);
665
- }
666
- if (!helpers.isEmulator(adb, opts)) {
667
- if (mockLocationApp || _lodash.default.isUndefined(mockLocationApp)) {
668
- await helpers.setMockLocationApp(adb, mockLocationApp || SETTINGS_HELPER_PKG_ID);
669
- } else {
670
- await helpers.resetMockLocation(adb);
671
- }
672
- }
673
- if (language || locale) {
674
- await helpers.ensureDeviceLocale(adb, language, locale, localeScript);
675
- }
676
- if (skipLogcatCapture) {
677
- _logger.default.info(`'skipLogcatCapture' is set. Skipping starting logcat capture.`);
678
- } else {
679
- await adb.startLogcat({
680
- format: logcatFormat,
681
- filterSpecs: logcatFilterSpecs
682
- });
683
- }
684
- if (unicodeKeyboard) {
685
- return await helpers.initUnicodeKeyboard(adb);
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
- for (let key of _lodash.default.keys(obj)) {
690
- if (_lodash.default.isNull(obj[key]) || _lodash.default.isUndefined(obj[key])) {
691
- delete obj[key];
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
- let multiplier = Math.pow(10, digits),
697
- adjustedNum = number * multiplier,
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
- return _lodash.default.includes(Object.keys(CHROME_BROWSER_PACKAGE_ACTIVITY), (browser || '').toLowerCase());
752
+ return lodash_1.default.includes(Object.keys(CHROME_BROWSER_PACKAGE_ACTIVITY), (browser || '').toLowerCase());
703
753
  };
704
754
  helpers.getChromePkg = function getChromePkg(browser) {
705
- return CHROME_BROWSER_PACKAGE_ACTIVITY[browser.toLowerCase()] || CHROME_BROWSER_PACKAGE_ACTIVITY.default;
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
- if (!server || !_lodash.default.isFunction(server.getWebSocketHandlers)) {
709
- return;
710
- }
711
- const activeHandlers = await server.getWebSocketHandlers(sessionId);
712
- for (const pathname of _lodash.default.keys(activeHandlers)) {
713
- await server.removeWebSocketHandler(pathname);
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
- let parsedCaps;
718
- try {
719
- parsedCaps = JSON.parse(cap);
720
- } catch (ign) {}
721
- if (_lodash.default.isArray(parsedCaps)) {
722
- return parsedCaps;
723
- } else if (_lodash.default.isString(cap)) {
724
- return [cap];
725
- }
726
- throw new Error(`must provide a string or JSON Array; received ${cap}`);
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
- if (caps.browserName) {
730
- if (caps.app) {
731
- _logger.default.warn(`The desired capabilities should generally not include both an 'app' and a 'browserName'`);
732
- }
733
- if (caps.appPackage) {
734
- _logger.default.errorAndThrow(`The desired should not include both of an 'appPackage' and a 'browserName'`);
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
- if (caps.uninstallOtherPackages) {
738
- try {
739
- this.parseArray(caps.uninstallOtherPackages);
740
- } catch (e) {
741
- _logger.default.errorAndThrow(`Could not parse "uninstallOtherPackages" capability: ${e.message}`);
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
- const {
748
- browserName
749
- } = caps;
750
- _logger.default.info(`The current session is considered browser-based`);
751
- _logger.default.info(`Supported browser names: ${JSON.stringify(_lodash.default.keys(CHROME_BROWSER_PACKAGE_ACTIVITY))}`);
752
- if (caps.appPackage || caps.appActivity) {
753
- _logger.default.info(`Not overriding appPackage/appActivity capability values for '${browserName}' ` + 'because some of them have been already provided');
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
- const possibleNames = [opts.udid, adb === null || adb === void 0 ? void 0 : adb.curDeviceId];
768
- return !!opts.avd || possibleNames.some(x => EMULATOR_PATTERN.test(x));
769
- };
770
- helpers.bootstrap = _bootstrap.default;
771
- helpers.unlocker = _unlockHelpers.default;
772
- var _default = helpers;
773
- exports.default = _default;
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