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,20 +1,18 @@
1
1
  "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
- Object.defineProperty(exports, "__esModule", {
5
- value: true
6
- });
7
- exports.helpers = exports.default = exports.WEBVIEW_WIN = exports.WEBVIEW_BASE = exports.NATIVE_WIN = exports.KNOWN_CHROME_PACKAGE_NAMES = exports.CHROMIUM_WIN = void 0;
8
- require("source-map-support/register");
9
- var _lodash = _interopRequireDefault(require("lodash"));
10
- var _logger = _interopRequireDefault(require("./logger"));
11
- var _axios = _interopRequireDefault(require("axios"));
12
- var _support = require("@appium/support");
13
- var _portscanner = require("portscanner");
14
- var _lruCache = _interopRequireDefault(require("lru-cache"));
15
- var _bluebird = _interopRequireDefault(require("bluebird"));
16
- var _path = _interopRequireDefault(require("path"));
17
- var _os = _interopRequireDefault(require("os"));
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.KNOWN_CHROME_PACKAGE_NAMES = exports.CHROMIUM_WIN = exports.WEBVIEW_BASE = exports.WEBVIEW_WIN = exports.NATIVE_WIN = exports.helpers = void 0;
7
+ const lodash_1 = __importDefault(require("lodash"));
8
+ const logger_1 = __importDefault(require("./logger"));
9
+ const axios_1 = __importDefault(require("axios"));
10
+ const support_1 = require("@appium/support");
11
+ const portscanner_1 = require("portscanner");
12
+ const lru_cache_1 = __importDefault(require("lru-cache"));
13
+ const bluebird_1 = __importDefault(require("bluebird"));
14
+ const path_1 = __importDefault(require("path"));
15
+ const os_1 = __importDefault(require("os"));
18
16
  const NATIVE_WIN = 'NATIVE_APP';
19
17
  exports.NATIVE_WIN = NATIVE_WIN;
20
18
  const WEBVIEW_WIN = 'WEBVIEW';
@@ -29,324 +27,504 @@ const DEVTOOLS_SOCKET_PATTERN = /@[\w.]+_devtools_remote_?(\d+)?\b/;
29
27
  const CROSSWALK_SOCKET_PATTERN = /@([\w.]+)_devtools_remote\b/;
30
28
  const CHROMIUM_DEVTOOLS_SOCKET = 'chrome_devtools_remote';
31
29
  const CHROME_PACKAGE_NAME = 'com.android.chrome';
32
- const KNOWN_CHROME_PACKAGE_NAMES = [CHROME_PACKAGE_NAME, 'com.chrome.beta', 'com.chrome.dev', 'com.chrome.canary'];
30
+ const KNOWN_CHROME_PACKAGE_NAMES = [
31
+ CHROME_PACKAGE_NAME,
32
+ 'com.chrome.beta',
33
+ 'com.chrome.dev',
34
+ 'com.chrome.canary',
35
+ ];
33
36
  exports.KNOWN_CHROME_PACKAGE_NAMES = KNOWN_CHROME_PACKAGE_NAMES;
34
37
  const DEVTOOLS_PORTS_RANGE = [10900, 11000];
35
- const WEBVIEWS_DETAILS_CACHE = new _lruCache.default({
36
- max: 100,
37
- updateAgeOnGet: true
38
- });
39
- const CDP_REQ_TIMEOUT = 2000;
40
- const DEVTOOLS_PORT_ALLOCATION_GUARD = _support.util.getLockFileGuard(_path.default.resolve(_os.default.tmpdir(), 'android_devtools_port_guard'), {
41
- timeout: 7,
42
- tryRecovery: true
38
+ const WEBVIEWS_DETAILS_CACHE = new lru_cache_1.default({
39
+ max: 100,
40
+ updateAgeOnGet: true,
43
41
  });
42
+ const CDP_REQ_TIMEOUT = 2000; // ms
43
+ const DEVTOOLS_PORT_ALLOCATION_GUARD = support_1.util.getLockFileGuard(path_1.default.resolve(os_1.default.tmpdir(), 'android_devtools_port_guard'), { timeout: 7, tryRecovery: true });
44
44
  const helpers = {};
45
45
  exports.helpers = helpers;
46
46
  function toDetailsCacheKey(adb, webview) {
47
- return `${adb === null || adb === void 0 ? void 0 : adb.curDeviceId}:${webview}`;
47
+ return `${adb?.curDeviceId}:${webview}`;
48
48
  }
49
+ /**
50
+ * This function gets a list of android system processes and returns ones
51
+ * that look like webviews
52
+ * See https://cs.chromium.org/chromium/src/chrome/browser/devtools/device/android_device_info_query.cc
53
+ * for more details
54
+ *
55
+ * @param {object} adb - an ADB instance
56
+ *
57
+ * @return {Array.<string>} - a list of matching webview socket names (including the leading '@')
58
+ */
49
59
  async function getPotentialWebviewProcs(adb) {
50
- const out = await adb.shell(['cat', '/proc/net/unix']);
51
- const names = [];
52
- const allMatches = [];
53
- for (const line of out.split('\n')) {
54
- const [,,, flags,, st,, sockPath] = line.trim().split(/\s+/);
55
- if (!sockPath) {
56
- continue;
57
- }
58
- if (sockPath.startsWith('@')) {
59
- allMatches.push(line.trim());
60
- }
61
- if (flags !== '00010000' || st !== '01') {
62
- continue;
60
+ const out = await adb.shell(['cat', '/proc/net/unix']);
61
+ const names = [];
62
+ const allMatches = [];
63
+ for (const line of out.split('\n')) {
64
+ // Num RefCount Protocol Flags Type St Inode Path
65
+ const [, , , flags, , st, , sockPath] = line.trim().split(/\s+/);
66
+ if (!sockPath) {
67
+ continue;
68
+ }
69
+ if (sockPath.startsWith('@')) {
70
+ allMatches.push(line.trim());
71
+ }
72
+ if (flags !== '00010000' || st !== '01') {
73
+ continue;
74
+ }
75
+ if (!DEVTOOLS_SOCKET_PATTERN.test(sockPath)) {
76
+ continue;
77
+ }
78
+ names.push(sockPath);
63
79
  }
64
- if (!DEVTOOLS_SOCKET_PATTERN.test(sockPath)) {
65
- continue;
80
+ if (lodash_1.default.isEmpty(names)) {
81
+ logger_1.default.debug('Found no active devtools sockets');
82
+ if (!lodash_1.default.isEmpty(allMatches)) {
83
+ logger_1.default.debug(`Other sockets are: ${JSON.stringify(allMatches, null, 2)}`);
84
+ }
66
85
  }
67
- names.push(sockPath);
68
- }
69
- if (_lodash.default.isEmpty(names)) {
70
- _logger.default.debug('Found no active devtools sockets');
71
- if (!_lodash.default.isEmpty(allMatches)) {
72
- _logger.default.debug(`Other sockets are: ${JSON.stringify(allMatches, null, 2)}`);
86
+ else {
87
+ logger_1.default.debug(`Parsed ${names.length} active devtools ${support_1.util.pluralize('socket', names.length, false)}: ` +
88
+ JSON.stringify(names));
73
89
  }
74
- } else {
75
- _logger.default.debug(`Parsed ${names.length} active devtools ${_support.util.pluralize('socket', names.length, false)}: ` + JSON.stringify(names));
76
- }
77
- return _lodash.default.uniq(names);
90
+ // sometimes the webview process shows up multiple times per app
91
+ return lodash_1.default.uniq(names);
78
92
  }
93
+ /**
94
+ * @typedef {Object} WebviewProc
95
+ * @property {string} proc - The webview process name (as returned by
96
+ * getPotentialWebviewProcs
97
+ * @property {string} webview - The actual webview context name
98
+ */
99
+ /**
100
+ * This function retrieves a list of system processes that look like webviews,
101
+ * and returns them along with the webview context name appropriate for it.
102
+ * If we pass in a deviceSocket, we only attempt to find webviews which match
103
+ * that socket name (this is for apps which embed Chromium, which isn't the
104
+ * same as chrome-backed webviews).
105
+ *
106
+ * @param {object} adb - an ADB instance
107
+ * @param {?string} deviceSocket - the explictly-named device socket to use
108
+ *
109
+ * @return {Array.<WebviewProc>}
110
+ */
79
111
  async function webviewsFromProcs(adb, deviceSocket = null) {
80
- const socketNames = await getPotentialWebviewProcs(adb);
81
- const webviews = [];
82
- for (const socketName of socketNames) {
83
- if (deviceSocket === CHROMIUM_DEVTOOLS_SOCKET && socketName === `@${deviceSocket}`) {
84
- webviews.push({
85
- proc: socketName,
86
- webview: CHROMIUM_WIN
87
- });
88
- continue;
89
- }
90
- const socketNameMatch = DEVTOOLS_SOCKET_PATTERN.exec(socketName);
91
- if (!socketNameMatch) {
92
- continue;
93
- }
94
- const crosswalkMatch = CROSSWALK_SOCKET_PATTERN.exec(socketName);
95
- if (!socketNameMatch[1] && !crosswalkMatch) {
96
- continue;
97
- }
98
- if (deviceSocket && socketName === `@${deviceSocket}` || !deviceSocket) {
99
- webviews.push({
100
- proc: socketName,
101
- webview: socketNameMatch[1] ? `${WEBVIEW_BASE}${socketNameMatch[1]}` : `${WEBVIEW_BASE}${crosswalkMatch[1]}`
102
- });
112
+ const socketNames = await getPotentialWebviewProcs(adb);
113
+ const webviews = [];
114
+ for (const socketName of socketNames) {
115
+ if (deviceSocket === CHROMIUM_DEVTOOLS_SOCKET && socketName === `@${deviceSocket}`) {
116
+ webviews.push({
117
+ proc: socketName,
118
+ webview: CHROMIUM_WIN,
119
+ });
120
+ continue;
121
+ }
122
+ const socketNameMatch = DEVTOOLS_SOCKET_PATTERN.exec(socketName);
123
+ if (!socketNameMatch) {
124
+ continue;
125
+ }
126
+ const crosswalkMatch = CROSSWALK_SOCKET_PATTERN.exec(socketName);
127
+ if (!socketNameMatch[1] && !crosswalkMatch) {
128
+ continue;
129
+ }
130
+ if (deviceSocket && socketName === `@${deviceSocket}` || !deviceSocket) {
131
+ webviews.push({
132
+ proc: socketName,
133
+ webview: socketNameMatch[1]
134
+ ? `${WEBVIEW_BASE}${socketNameMatch[1]}`
135
+ : `${WEBVIEW_BASE}${crosswalkMatch[1]}`,
136
+ });
137
+ }
103
138
  }
104
- }
105
- return webviews;
139
+ return webviews;
106
140
  }
141
+ /**
142
+ * Allocates a local port for devtools communication
143
+ *
144
+ * @param {ADB} adb ADB instance
145
+ * @param {string} socketName The remote Unix socket name
146
+ * @param {?number} webviewDevtoolsPort The local port number or null to apply
147
+ * autodetection
148
+ * @returns {number} The local port number if the remote socket has been forwarded
149
+ * successfully or `null` otherwise
150
+ * @throws {Error} If there was an error while allocating the local port
151
+ */
107
152
  async function allocateDevtoolsPort(adb, socketName, webviewDevtoolsPort = null) {
108
- const remotePort = socketName.replace(/^@/, '');
109
- let [startPort, endPort] = DEVTOOLS_PORTS_RANGE;
110
- if (webviewDevtoolsPort) {
111
- endPort = webviewDevtoolsPort + (endPort - startPort);
112
- startPort = webviewDevtoolsPort;
113
- }
114
- _logger.default.debug(`Forwarding remote port ${remotePort} to a local ` + `port in range ${startPort}..${endPort}`);
115
- if (!webviewDevtoolsPort) {
116
- _logger.default.debug(`You could use the 'webviewDevtoolsPort' capability to customize ` + `the starting port number`);
117
- }
118
- return await DEVTOOLS_PORT_ALLOCATION_GUARD(async () => {
119
- let localPort;
120
- try {
121
- localPort = await (0, _portscanner.findAPortNotInUse)(startPort, endPort);
122
- } catch (e) {
123
- throw new Error(`Cannot find any free port to forward the Devtools socket ` + `in range ${startPort}..${endPort}. You could set the starting port number ` + `manually by providing the 'webviewDevtoolsPort' capability`);
153
+ // socket names come with '@', but this should not be a part of the abstract
154
+ // remote port, so remove it
155
+ const remotePort = socketName.replace(/^@/, '');
156
+ let [startPort, endPort] = DEVTOOLS_PORTS_RANGE;
157
+ if (webviewDevtoolsPort) {
158
+ endPort = webviewDevtoolsPort + (endPort - startPort);
159
+ startPort = webviewDevtoolsPort;
124
160
  }
125
- await adb.adbExec(['forward', `tcp:${localPort}`, `localabstract:${remotePort}`]);
126
- return localPort;
127
- });
128
- }
129
- async function collectWebviewsDetails(adb, webviewsMapping, opts = {}) {
130
- if (_lodash.default.isEmpty(webviewsMapping)) {
131
- return;
132
- }
133
- const {
134
- webviewDevtoolsPort = null,
135
- ensureWebviewsHavePages = null,
136
- enableWebviewDetailsCollection = null
137
- } = opts;
138
- if (!ensureWebviewsHavePages) {
139
- _logger.default.info(`Not checking whether webviews have active pages; use the ` + `'ensureWebviewsHavePages' cap to turn this check on`);
140
- }
141
- if (!enableWebviewDetailsCollection) {
142
- _logger.default.info(`Not collecting web view details. Details collection might help ` + `to make Chromedriver initialization more precise. Use the 'enableWebviewDetailsCollection' ` + `cap to turn it on`);
143
- }
144
- if (!ensureWebviewsHavePages && !enableWebviewDetailsCollection) {
145
- return;
146
- }
147
- _logger.default.debug(`Collecting CDP data of ${_support.util.pluralize('webview', webviewsMapping.length, true)}`);
148
- const detailCollectors = [];
149
- for (const item of webviewsMapping) {
150
- detailCollectors.push((async () => {
151
- let localPort;
152
- try {
153
- localPort = await allocateDevtoolsPort(adb, item.proc, webviewDevtoolsPort);
154
- if (enableWebviewDetailsCollection) {
155
- item.info = await cdpInfo(localPort);
156
- }
157
- if (ensureWebviewsHavePages) {
158
- item.pages = await cdpList(localPort);
161
+ logger_1.default.debug(`Forwarding remote port ${remotePort} to a local ` +
162
+ `port in range ${startPort}..${endPort}`);
163
+ if (!webviewDevtoolsPort) {
164
+ logger_1.default.debug(`You could use the 'webviewDevtoolsPort' capability to customize ` +
165
+ `the starting port number`);
166
+ }
167
+ return await DEVTOOLS_PORT_ALLOCATION_GUARD(async () => {
168
+ let localPort;
169
+ try {
170
+ localPort = await (0, portscanner_1.findAPortNotInUse)(startPort, endPort);
159
171
  }
160
- } catch (e) {
161
- _logger.default.debug(e);
162
- } finally {
163
- if (localPort) {
164
- try {
165
- await adb.removePortForward(localPort);
166
- } catch (e) {
167
- _logger.default.debug(e);
168
- }
172
+ catch (e) {
173
+ throw new Error(`Cannot find any free port to forward the Devtools socket ` +
174
+ `in range ${startPort}..${endPort}. You could set the starting port number ` +
175
+ `manually by providing the 'webviewDevtoolsPort' capability`);
169
176
  }
170
- }
171
- })());
172
- }
173
- await _bluebird.default.all(detailCollectors);
174
- _logger.default.debug(`CDP data collection completed`);
177
+ await adb.adbExec(['forward', `tcp:${localPort}`, `localabstract:${remotePort}`]);
178
+ return localPort;
179
+ });
180
+ }
181
+ /**
182
+ * @typedef {Object} WebviewProps
183
+ * @property {string} proc The name of the Devtools Unix socket
184
+ * @property {string} webview The web view alias. Looks like `WEBVIEW_`
185
+ * prefix plus PID or package name
186
+ * @property {?Object} info Webview information as it is retrieved by
187
+ * /json/version CDP endpoint
188
+ * @property {?Array<Object>} pages Webview pages list as it is retrieved by
189
+ * /json/list CDP endpoint
190
+ */
191
+ /**
192
+ * @typedef {Object} DetailCollectionOptions
193
+ * @property {?string|number} webviewDevtoolsPort The starting port to use for webview page
194
+ * presence check (if not the default of 9222).
195
+ * @property {?boolean} ensureWebviewsHavePages Whether to check for webview
196
+ * pages presence
197
+ * @property {boolean} enableWebviewDetailsCollection Whether to collect
198
+ * web view details and send them to Chromedriver constructor, so it could
199
+ * select a binary more precisely based on this info.
200
+ */
201
+ /**
202
+ * This is a wrapper for Chrome Debugger Protocol data collection.
203
+ * No error is thrown if CDP request fails - in such case no data will be
204
+ * recorded into the corresponding `webviewsMapping` item.
205
+ *
206
+ * @param {ADB} adb The ADB instance
207
+ * @param {Array<WebviewProps>} webviewsMapping The current webviews mapping
208
+ * !!! Each item of this array gets mutated (`info`/`pages` properties get added
209
+ * based on the provided `opts`) if the requested details have been
210
+ * successfully retrieved for it !!!
211
+ * @param {DetailCollectionOptions} opts If both `ensureWebviewsHavePages` and
212
+ * `enableWebviewDetailsCollection` properties are falsy then no details collection
213
+ * is performed
214
+ */
215
+ async function collectWebviewsDetails(adb, webviewsMapping, opts = {}) {
216
+ if (lodash_1.default.isEmpty(webviewsMapping)) {
217
+ return;
218
+ }
219
+ const { webviewDevtoolsPort = null, ensureWebviewsHavePages = null, enableWebviewDetailsCollection = null, } = opts;
220
+ if (!ensureWebviewsHavePages) {
221
+ logger_1.default.info(`Not checking whether webviews have active pages; use the ` +
222
+ `'ensureWebviewsHavePages' cap to turn this check on`);
223
+ }
224
+ if (!enableWebviewDetailsCollection) {
225
+ logger_1.default.info(`Not collecting web view details. Details collection might help ` +
226
+ `to make Chromedriver initialization more precise. Use the 'enableWebviewDetailsCollection' ` +
227
+ `cap to turn it on`);
228
+ }
229
+ if (!ensureWebviewsHavePages && !enableWebviewDetailsCollection) {
230
+ return;
231
+ }
232
+ // Connect to each devtools socket and retrieve web view details
233
+ logger_1.default.debug(`Collecting CDP data of ${support_1.util.pluralize('webview', webviewsMapping.length, true)}`);
234
+ const detailCollectors = [];
235
+ for (const item of webviewsMapping) {
236
+ detailCollectors.push((async () => {
237
+ let localPort;
238
+ try {
239
+ localPort = await allocateDevtoolsPort(adb, item.proc, webviewDevtoolsPort);
240
+ if (enableWebviewDetailsCollection) {
241
+ item.info = await cdpInfo(localPort);
242
+ }
243
+ if (ensureWebviewsHavePages) {
244
+ item.pages = await cdpList(localPort);
245
+ }
246
+ }
247
+ catch (e) {
248
+ logger_1.default.debug(e);
249
+ }
250
+ finally {
251
+ if (localPort) {
252
+ try {
253
+ await adb.removePortForward(localPort);
254
+ }
255
+ catch (e) {
256
+ logger_1.default.debug(e);
257
+ }
258
+ }
259
+ }
260
+ })());
261
+ }
262
+ await bluebird_1.default.all(detailCollectors);
263
+ logger_1.default.debug(`CDP data collection completed`);
175
264
  }
265
+ // https://chromedevtools.github.io/devtools-protocol/
176
266
  async function cdpList(localPort) {
177
- return (await (0, _axios.default)({
178
- url: `http://127.0.0.1:${localPort}/json/list`,
179
- timeout: CDP_REQ_TIMEOUT
180
- })).data;
267
+ return (await (0, axios_1.default)({
268
+ url: `http://127.0.0.1:${localPort}/json/list`,
269
+ timeout: CDP_REQ_TIMEOUT,
270
+ })).data;
181
271
  }
272
+ // https://chromedevtools.github.io/devtools-protocol/
182
273
  async function cdpInfo(localPort) {
183
- return (await (0, _axios.default)({
184
- url: `http://127.0.0.1:${localPort}/json/version`,
185
- timeout: CDP_REQ_TIMEOUT
186
- })).data;
274
+ return (await (0, axios_1.default)({
275
+ url: `http://127.0.0.1:${localPort}/json/version`,
276
+ timeout: CDP_REQ_TIMEOUT,
277
+ })).data;
187
278
  }
279
+ /**
280
+ * Take a webview name like WEBVIEW_4296 and use 'adb shell ps' to figure out
281
+ * which app package is associated with that webview. One of the reasons we
282
+ * want to do this is to make sure we're listing webviews for the actual AUT,
283
+ * not some other running app
284
+ *
285
+ * @param {object} adb - an ADB instance
286
+ * @param {string} webview - a webview process name
287
+ *
288
+ * @returns {string} - the package name of the app running the webview
289
+ * @throws {Error} If there was a failure while retrieving the process name
290
+ */
188
291
  helpers.procFromWebview = async function procFromWebview(adb, webview) {
189
- const pidMatch = WEBVIEW_PID_PATTERN.exec(webview);
190
- if (!pidMatch) {
191
- throw new Error(`Could not find PID for webview '${webview}'`);
192
- }
193
- const pid = pidMatch[1];
194
- _logger.default.debug(`${webview} mapped to pid ${pid}`);
195
- _logger.default.debug(`Getting process name for webview '${webview}'`);
196
- const pkg = await adb.getNameByPid(pid);
197
- _logger.default.debug(`Got process name: '${pkg}'`);
198
- return pkg;
292
+ const pidMatch = WEBVIEW_PID_PATTERN.exec(webview);
293
+ if (!pidMatch) {
294
+ throw new Error(`Could not find PID for webview '${webview}'`);
295
+ }
296
+ const pid = pidMatch[1];
297
+ logger_1.default.debug(`${webview} mapped to pid ${pid}`);
298
+ logger_1.default.debug(`Getting process name for webview '${webview}'`);
299
+ const pkg = await adb.getNameByPid(pid);
300
+ logger_1.default.debug(`Got process name: '${pkg}'`);
301
+ return pkg;
199
302
  };
200
- helpers.parseWebviewNames = function parseWebviewNames(webviewsMapping, {
201
- ensureWebviewsHavePages = true,
202
- isChromeSession = false
203
- } = {}) {
204
- if (isChromeSession) {
205
- return [CHROMIUM_WIN];
206
- }
207
- const result = [];
208
- for (const {
209
- webview,
210
- pages,
211
- proc,
212
- webviewName
213
- } of webviewsMapping) {
214
- if (ensureWebviewsHavePages && (pages === null || pages === void 0 ? void 0 : pages.length) === 0) {
215
- _logger.default.info(`Skipping the webview '${webview}' at '${proc}' ` + `since it has reported having zero pages`);
216
- continue;
303
+ /**
304
+ * Parse webview names for getContexts
305
+ *
306
+ * @param {Array<WebviewsMapping>} webviewsMapping See note on getWebViewsMapping
307
+ * @param {GetWebviewsOpts} opts See note on getWebViewsMapping
308
+ * @return {Array.<string>} - a list of webview names
309
+ */
310
+ helpers.parseWebviewNames = function parseWebviewNames(webviewsMapping, { ensureWebviewsHavePages = true, isChromeSession = false } = {}) {
311
+ if (isChromeSession) {
312
+ return [CHROMIUM_WIN];
217
313
  }
218
- if (webviewName) {
219
- result.push(webviewName);
314
+ const result = [];
315
+ for (const { webview, pages, proc, webviewName } of webviewsMapping) {
316
+ if (ensureWebviewsHavePages && pages?.length === 0) {
317
+ logger_1.default.info(`Skipping the webview '${webview}' at '${proc}' ` +
318
+ `since it has reported having zero pages`);
319
+ continue;
320
+ }
321
+ if (webviewName) {
322
+ result.push(webviewName);
323
+ }
220
324
  }
221
- }
222
- _logger.default.debug(`Found ${_support.util.pluralize('webview', result.length, true)}: ${JSON.stringify(result)}`);
223
- return result;
325
+ logger_1.default.debug(`Found ${support_1.util.pluralize('webview', result.length, true)}: ${JSON.stringify(result)}`);
326
+ return result;
224
327
  };
225
- helpers.getWebViewsMapping = async function getWebViewsMapping(adb, {
226
- androidDeviceSocket = null,
227
- ensureWebviewsHavePages = true,
228
- webviewDevtoolsPort = null,
229
- enableWebviewDetailsCollection = true
230
- } = {}) {
231
- _logger.default.debug('Getting a list of available webviews');
232
- const webviewsMapping = await webviewsFromProcs(adb, androidDeviceSocket);
233
- await collectWebviewsDetails(adb, webviewsMapping, {
234
- ensureWebviewsHavePages,
235
- enableWebviewDetailsCollection,
236
- webviewDevtoolsPort
237
- });
238
- for (const webviewMapping of webviewsMapping) {
239
- const {
240
- webview,
241
- info
242
- } = webviewMapping;
243
- webviewMapping.webviewName = null;
244
- let wvName = webview;
245
- let process = undefined;
246
- if (!androidDeviceSocket) {
247
- const pkgMatch = WEBVIEW_PKG_PATTERN.exec(webview);
248
- try {
249
- const pkg = pkgMatch ? pkgMatch[1] : await helpers.procFromWebview(adb, webview);
250
- wvName = `${WEBVIEW_BASE}${pkg}`;
251
- const pidMatch = WEBVIEW_PID_PATTERN.exec(webview);
252
- process = {
253
- name: pkg,
254
- id: pidMatch ? pidMatch[1] : null
255
- };
256
- } catch (e) {
257
- _logger.default.warn(e.message);
258
- continue;
259
- }
260
- }
261
- webviewMapping.webviewName = wvName;
262
- const key = toDetailsCacheKey(adb, wvName);
263
- if (info || process) {
264
- WEBVIEWS_DETAILS_CACHE.set(key, {
265
- info,
266
- process
267
- });
268
- } else if (WEBVIEWS_DETAILS_CACHE.has(key)) {
269
- WEBVIEWS_DETAILS_CACHE.delete(key);
328
+ /**
329
+ * @typedef {Object} GetWebviewsOpts
330
+ * @property {string} androidDeviceSocket [null] - device socket name
331
+ * @property {boolean} ensureWebviewsHavePages [true] - whether to check for webview
332
+ * page presence
333
+ * @property {number} webviewDevtoolsPort [9222] - port to use for webview page
334
+ * presence check.
335
+ * @property {boolean} enableWebviewDetailsCollection [true] - whether to collect
336
+ * web view details and send them to Chromedriver constructor, so it could
337
+ * select a binary more precisely based on this info.
338
+ */
339
+ /**
340
+ * @typedef {Object} WebviewsMapping
341
+ * @property {string} proc See note on WebviewProps
342
+ * @property {string} webview See note on WebviewProps
343
+ * @property {?Object} info See note on WebviewProps
344
+ * @property {?Array<Object>} pages See note on WebviewProps
345
+ * @propery {?string} webviewName An actual webview name for switching context
346
+ */
347
+ /**
348
+ * Get a list of available webviews mapping by introspecting processes with adb,
349
+ * where webviews are listed. It's possible to pass in a 'deviceSocket' arg, which
350
+ * limits the webview possibilities to the one running on the Chromium devtools
351
+ * socket we're interested in (see note on webviewsFromProcs). We can also
352
+ * direct this method to verify whether a particular webview process actually
353
+ * has any pages (if a process exists but no pages are found, Chromedriver will
354
+ * not actually be able to connect to it, so this serves as a guard for that
355
+ * strange failure mode). The strategy for checking whether any pages are
356
+ * active involves sending a request to the remote debug server on the device,
357
+ * hence it is also possible to specify the port on the host machine which
358
+ * should be used for this communication.
359
+ *
360
+ * @param {object} adb - an ADB instance
361
+ * @param {GetWebviewsOpts} opts
362
+ *
363
+ * @return {Array<WebviewsMapping>} webviewsMapping
364
+ */
365
+ helpers.getWebViewsMapping = async function getWebViewsMapping(adb, { androidDeviceSocket = null, ensureWebviewsHavePages = true, webviewDevtoolsPort = null, enableWebviewDetailsCollection = true } = {}) {
366
+ logger_1.default.debug('Getting a list of available webviews');
367
+ const webviewsMapping = await webviewsFromProcs(adb, androidDeviceSocket);
368
+ await collectWebviewsDetails(adb, webviewsMapping, {
369
+ ensureWebviewsHavePages,
370
+ enableWebviewDetailsCollection,
371
+ webviewDevtoolsPort,
372
+ });
373
+ for (const webviewMapping of webviewsMapping) {
374
+ const { webview, info } = webviewMapping;
375
+ webviewMapping.webviewName = null;
376
+ let wvName = webview;
377
+ let process = undefined;
378
+ if (!androidDeviceSocket) {
379
+ const pkgMatch = WEBVIEW_PKG_PATTERN.exec(webview);
380
+ try {
381
+ // web view name could either be suffixed with PID or the package name
382
+ // package names could not start with a digit
383
+ const pkg = pkgMatch ? pkgMatch[1] : await helpers.procFromWebview(adb, webview);
384
+ wvName = `${WEBVIEW_BASE}${pkg}`;
385
+ const pidMatch = WEBVIEW_PID_PATTERN.exec(webview);
386
+ process = {
387
+ name: pkg,
388
+ id: pidMatch ? pidMatch[1] : null,
389
+ };
390
+ }
391
+ catch (e) {
392
+ logger_1.default.warn(e.message);
393
+ continue;
394
+ }
395
+ }
396
+ webviewMapping.webviewName = wvName;
397
+ const key = toDetailsCacheKey(adb, wvName);
398
+ if (info || process) {
399
+ WEBVIEWS_DETAILS_CACHE.set(key, { info, process });
400
+ }
401
+ else if (WEBVIEWS_DETAILS_CACHE.has(key)) {
402
+ WEBVIEWS_DETAILS_CACHE.delete(key);
403
+ }
270
404
  }
271
- }
272
- return webviewsMapping;
405
+ return webviewsMapping;
273
406
  };
407
+ /**
408
+ * @typedef {Object} ProcessInfo
409
+ * @property {string} name The process name
410
+ * @property {?string} id The process id (if could be retrieved)
411
+ */
412
+ /**
413
+ * @typedef {Object} WebViewDetails
414
+ * @property {?ProcessInfo} process - Web view process details
415
+ * @property {Object} info - Web view details as returned by /json/version CDP endpoint, for example:
416
+ * {
417
+ * "Browser": "Chrome/72.0.3601.0",
418
+ * "Protocol-Version": "1.3",
419
+ * "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3601.0 Safari/537.36",
420
+ * "V8-Version": "7.2.233",
421
+ * "WebKit-Version": "537.36 (@cfede9db1d154de0468cb0538479f34c0755a0f4)",
422
+ * "webSocketDebuggerUrl": "ws://localhost:9222/devtools/browser/b0b8a4fb-bb17-4359-9533-a8d9f3908bd8"
423
+ * }
424
+ */
425
+ /**
426
+ * Retrieves web view details previously cached by `getWebviews` call
427
+ *
428
+ * @param {ADB} adb ADB instance
429
+ * @param {string} webview The name of the web view
430
+ * @returns {?WebViewDetails} Either `undefined` or the recent web view details
431
+ */
274
432
  helpers.getWebviewDetails = function getWebviewDetails(adb, webview) {
275
- const key = toDetailsCacheKey(adb, webview);
276
- return WEBVIEWS_DETAILS_CACHE.get(key);
433
+ const key = toDetailsCacheKey(adb, webview);
434
+ return WEBVIEWS_DETAILS_CACHE.get(key);
277
435
  };
436
+ /**
437
+ * Create Chrome driver capabilities based on the provided
438
+ * Appium capabilities
439
+ *
440
+ * @param {Object} opts User-provided capabilities object
441
+ * @param {string} deviceId The identifier of the Android device under test
442
+ * @param {?WebViewDetails} webViewDetails
443
+ * @returns {Object} The capabilities object.
444
+ * See https://chromedriver.chromium.org/capabilities for more details.
445
+ */
278
446
  helpers.createChromedriverCaps = function createChromedriverCaps(opts, deviceId, webViewDetails) {
279
- var _opts$chromeOptions, _webViewDetails$info, _webViewDetails$proce, _webViewDetails$proce2, _opts$chromeOptions2;
280
- const caps = {
281
- chromeOptions: {}
282
- };
283
- const androidPackage = ((_opts$chromeOptions = opts.chromeOptions) === null || _opts$chromeOptions === void 0 ? void 0 : _opts$chromeOptions.androidPackage) || opts.appPackage || (webViewDetails === null || webViewDetails === void 0 ? void 0 : (_webViewDetails$info = webViewDetails.info) === null || _webViewDetails$info === void 0 ? void 0 : _webViewDetails$info['Android-Package']);
284
- if (androidPackage) {
285
- caps.chromeOptions.androidPackage = androidPackage;
286
- }
287
- if (_lodash.default.isBoolean(opts.chromeUseRunningApp)) {
288
- caps.chromeOptions.androidUseRunningApp = opts.chromeUseRunningApp;
289
- }
290
- if (opts.chromeAndroidPackage) {
291
- caps.chromeOptions.androidPackage = opts.chromeAndroidPackage;
292
- }
293
- if (opts.chromeAndroidActivity) {
294
- caps.chromeOptions.androidActivity = opts.chromeAndroidActivity;
295
- }
296
- if (opts.chromeAndroidProcess) {
297
- caps.chromeOptions.androidProcess = opts.chromeAndroidProcess;
298
- } else if (webViewDetails !== null && webViewDetails !== void 0 && (_webViewDetails$proce = webViewDetails.process) !== null && _webViewDetails$proce !== void 0 && _webViewDetails$proce.name && webViewDetails !== null && webViewDetails !== void 0 && (_webViewDetails$proce2 = webViewDetails.process) !== null && _webViewDetails$proce2 !== void 0 && _webViewDetails$proce2.id) {
299
- caps.chromeOptions.androidProcess = webViewDetails.process.name;
300
- }
301
- if (_lodash.default.toLower(opts.browserName) === 'chromium-webview') {
302
- caps.chromeOptions.androidActivity = opts.appActivity;
303
- }
304
- if (opts.pageLoadStrategy) {
305
- caps.pageLoadStrategy = opts.pageLoadStrategy;
306
- }
307
- const isChrome = _lodash.default.toLower(caps.chromeOptions.androidPackage) === 'chrome';
308
- if (_lodash.default.includes(KNOWN_CHROME_PACKAGE_NAMES, caps.chromeOptions.androidPackage) || isChrome) {
309
- if (isChrome) {
310
- caps.chromeOptions.androidPackage = CHROME_PACKAGE_NAME;
447
+ const caps = { chromeOptions: {} };
448
+ const androidPackage = opts.chromeOptions?.androidPackage
449
+ || opts.appPackage
450
+ || webViewDetails?.info?.['Android-Package'];
451
+ if (androidPackage) {
452
+ // chromedriver raises an invalid argument error when androidPackage is 'null'
453
+ caps.chromeOptions.androidPackage = androidPackage;
454
+ }
455
+ if (lodash_1.default.isBoolean(opts.chromeUseRunningApp)) {
456
+ caps.chromeOptions.androidUseRunningApp = opts.chromeUseRunningApp;
457
+ }
458
+ if (opts.chromeAndroidPackage) {
459
+ caps.chromeOptions.androidPackage = opts.chromeAndroidPackage;
460
+ }
461
+ if (opts.chromeAndroidActivity) {
462
+ caps.chromeOptions.androidActivity = opts.chromeAndroidActivity;
311
463
  }
312
- delete caps.chromeOptions.androidActivity;
313
- delete caps.chromeOptions.androidProcess;
314
- }
315
- caps.chromeOptions.androidDeviceSerial = deviceId;
316
- if (_lodash.default.isPlainObject(opts.loggingPrefs) || _lodash.default.isPlainObject(opts.chromeLoggingPrefs)) {
317
- if (opts.loggingPrefs) {
318
- _logger.default.warn(`The 'loggingPrefs' cap is deprecated; use the 'chromeLoggingPrefs' cap instead`);
464
+ if (opts.chromeAndroidProcess) {
465
+ caps.chromeOptions.androidProcess = opts.chromeAndroidProcess;
319
466
  }
320
- caps.loggingPrefs = opts.chromeLoggingPrefs || opts.loggingPrefs;
321
- }
322
- if (opts.enablePerformanceLogging) {
323
- _logger.default.warn(`The 'enablePerformanceLogging' cap is deprecated; simply use ` + `the 'chromeLoggingPrefs' cap instead, with a 'performance' key set to 'ALL'`);
324
- const newPref = {
325
- performance: 'ALL'
326
- };
327
- caps.loggingPrefs = caps.loggingPrefs ? Object.assign({}, caps.loggingPrefs, newPref) : newPref;
328
- }
329
- if ((_opts$chromeOptions2 = opts.chromeOptions) !== null && _opts$chromeOptions2 !== void 0 && _opts$chromeOptions2.Arguments) {
330
- opts.chromeOptions.args = [...(opts.chromeOptions.args || []), ...opts.chromeOptions.Arguments];
331
- delete opts.chromeOptions.Arguments;
332
- }
333
- _logger.default.debug('Precalculated Chromedriver capabilities: ' + JSON.stringify(caps.chromeOptions, null, 2));
334
- const protectedCapNames = [];
335
- for (const [opt, val] of _lodash.default.toPairs(opts.chromeOptions)) {
336
- if (_lodash.default.isUndefined(caps.chromeOptions[opt])) {
337
- caps.chromeOptions[opt] = val;
338
- } else {
339
- protectedCapNames.push(opt);
467
+ else if (webViewDetails?.process?.name && webViewDetails?.process?.id) {
468
+ caps.chromeOptions.androidProcess = webViewDetails.process.name;
340
469
  }
341
- }
342
- if (!_lodash.default.isEmpty(protectedCapNames)) {
343
- _logger.default.info('The following Chromedriver capabilities cannot be overridden ' + 'by the provided chromeOptions:');
344
- for (const optName of protectedCapNames) {
345
- _logger.default.info(` ${optName} (${JSON.stringify(opts.chromeOptions[optName])})`);
470
+ if (lodash_1.default.toLower(opts.browserName) === 'chromium-webview') {
471
+ caps.chromeOptions.androidActivity = opts.appActivity;
472
+ }
473
+ if (opts.pageLoadStrategy) {
474
+ caps.pageLoadStrategy = opts.pageLoadStrategy;
475
+ }
476
+ const isChrome = lodash_1.default.toLower(caps.chromeOptions.androidPackage) === 'chrome';
477
+ if (lodash_1.default.includes(KNOWN_CHROME_PACKAGE_NAMES, caps.chromeOptions.androidPackage) || isChrome) {
478
+ // if we have extracted package from context name, it could come in as bare
479
+ // "chrome", and so we should make sure the details are correct, including
480
+ // not using an activity or process id
481
+ if (isChrome) {
482
+ caps.chromeOptions.androidPackage = CHROME_PACKAGE_NAME;
483
+ }
484
+ delete caps.chromeOptions.androidActivity;
485
+ delete caps.chromeOptions.androidProcess;
486
+ }
487
+ // add device id from adb
488
+ caps.chromeOptions.androidDeviceSerial = deviceId;
489
+ if (lodash_1.default.isPlainObject(opts.loggingPrefs) || lodash_1.default.isPlainObject(opts.chromeLoggingPrefs)) {
490
+ if (opts.loggingPrefs) {
491
+ logger_1.default.warn(`The 'loggingPrefs' cap is deprecated; use the 'chromeLoggingPrefs' cap instead`);
492
+ }
493
+ caps.loggingPrefs = opts.chromeLoggingPrefs || opts.loggingPrefs;
494
+ }
495
+ if (opts.enablePerformanceLogging) {
496
+ logger_1.default.warn(`The 'enablePerformanceLogging' cap is deprecated; simply use ` +
497
+ `the 'chromeLoggingPrefs' cap instead, with a 'performance' key set to 'ALL'`);
498
+ const newPref = { performance: 'ALL' };
499
+ // don't overwrite other logging prefs that have been sent in if they exist
500
+ caps.loggingPrefs = caps.loggingPrefs
501
+ ? Object.assign({}, caps.loggingPrefs, newPref)
502
+ : newPref;
503
+ }
504
+ if (opts.chromeOptions?.Arguments) {
505
+ // merge `Arguments` and `args`
506
+ opts.chromeOptions.args = [...(opts.chromeOptions.args || []), ...opts.chromeOptions.Arguments];
507
+ delete opts.chromeOptions.Arguments;
508
+ }
509
+ logger_1.default.debug('Precalculated Chromedriver capabilities: ' +
510
+ JSON.stringify(caps.chromeOptions, null, 2));
511
+ const protectedCapNames = [];
512
+ for (const [opt, val] of lodash_1.default.toPairs(opts.chromeOptions)) {
513
+ if (lodash_1.default.isUndefined(caps.chromeOptions[opt])) {
514
+ caps.chromeOptions[opt] = val;
515
+ }
516
+ else {
517
+ protectedCapNames.push(opt);
518
+ }
519
+ }
520
+ if (!lodash_1.default.isEmpty(protectedCapNames)) {
521
+ logger_1.default.info('The following Chromedriver capabilities cannot be overridden ' +
522
+ 'by the provided chromeOptions:');
523
+ for (const optName of protectedCapNames) {
524
+ logger_1.default.info(` ${optName} (${JSON.stringify(opts.chromeOptions[optName])})`);
525
+ }
346
526
  }
347
- }
348
- return caps;
527
+ return caps;
349
528
  };
350
- var _default = helpers;
351
- exports.default = _default;
352
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9kYXNoIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfbG9nZ2VyIiwiX2F4aW9zIiwiX3N1cHBvcnQiLCJfcG9ydHNjYW5uZXIiLCJfbHJ1Q2FjaGUiLCJfYmx1ZWJpcmQiLCJfcGF0aCIsIl9vcyIsIk5BVElWRV9XSU4iLCJleHBvcnRzIiwiV0VCVklFV19XSU4iLCJDSFJPTUlVTV9XSU4iLCJXRUJWSUVXX0JBU0UiLCJXRUJWSUVXX1BJRF9QQVRURVJOIiwiUmVnRXhwIiwiV0VCVklFV19QS0dfUEFUVEVSTiIsIkRFVlRPT0xTX1NPQ0tFVF9QQVRURVJOIiwiQ1JPU1NXQUxLX1NPQ0tFVF9QQVRURVJOIiwiQ0hST01JVU1fREVWVE9PTFNfU09DS0VUIiwiQ0hST01FX1BBQ0tBR0VfTkFNRSIsIktOT1dOX0NIUk9NRV9QQUNLQUdFX05BTUVTIiwiREVWVE9PTFNfUE9SVFNfUkFOR0UiLCJXRUJWSUVXU19ERVRBSUxTX0NBQ0hFIiwiTFJVIiwibWF4IiwidXBkYXRlQWdlT25HZXQiLCJDRFBfUkVRX1RJTUVPVVQiLCJERVZUT09MU19QT1JUX0FMTE9DQVRJT05fR1VBUkQiLCJ1dGlsIiwiZ2V0TG9ja0ZpbGVHdWFyZCIsInBhdGgiLCJyZXNvbHZlIiwib3MiLCJ0bXBkaXIiLCJ0aW1lb3V0IiwidHJ5UmVjb3ZlcnkiLCJoZWxwZXJzIiwidG9EZXRhaWxzQ2FjaGVLZXkiLCJhZGIiLCJ3ZWJ2aWV3IiwiY3VyRGV2aWNlSWQiLCJnZXRQb3RlbnRpYWxXZWJ2aWV3UHJvY3MiLCJvdXQiLCJzaGVsbCIsIm5hbWVzIiwiYWxsTWF0Y2hlcyIsImxpbmUiLCJzcGxpdCIsImZsYWdzIiwic3QiLCJzb2NrUGF0aCIsInRyaW0iLCJzdGFydHNXaXRoIiwicHVzaCIsInRlc3QiLCJfIiwiaXNFbXB0eSIsImxvZ2dlciIsImRlYnVnIiwiSlNPTiIsInN0cmluZ2lmeSIsImxlbmd0aCIsInBsdXJhbGl6ZSIsInVuaXEiLCJ3ZWJ2aWV3c0Zyb21Qcm9jcyIsImRldmljZVNvY2tldCIsInNvY2tldE5hbWVzIiwid2Vidmlld3MiLCJzb2NrZXROYW1lIiwicHJvYyIsInNvY2tldE5hbWVNYXRjaCIsImV4ZWMiLCJjcm9zc3dhbGtNYXRjaCIsImFsbG9jYXRlRGV2dG9vbHNQb3J0Iiwid2Vidmlld0RldnRvb2xzUG9ydCIsInJlbW90ZVBvcnQiLCJyZXBsYWNlIiwic3RhcnRQb3J0IiwiZW5kUG9ydCIsImxvY2FsUG9ydCIsImZpbmRBUG9ydE5vdEluVXNlIiwiZSIsIkVycm9yIiwiYWRiRXhlYyIsImNvbGxlY3RXZWJ2aWV3c0RldGFpbHMiLCJ3ZWJ2aWV3c01hcHBpbmciLCJvcHRzIiwiZW5zdXJlV2Vidmlld3NIYXZlUGFnZXMiLCJlbmFibGVXZWJ2aWV3RGV0YWlsc0NvbGxlY3Rpb24iLCJpbmZvIiwiZGV0YWlsQ29sbGVjdG9ycyIsIml0ZW0iLCJjZHBJbmZvIiwicGFnZXMiLCJjZHBMaXN0IiwicmVtb3ZlUG9ydEZvcndhcmQiLCJCIiwiYWxsIiwiYXhpb3MiLCJ1cmwiLCJkYXRhIiwicHJvY0Zyb21XZWJ2aWV3IiwicGlkTWF0Y2giLCJwaWQiLCJwa2ciLCJnZXROYW1lQnlQaWQiLCJwYXJzZVdlYnZpZXdOYW1lcyIsImlzQ2hyb21lU2Vzc2lvbiIsInJlc3VsdCIsIndlYnZpZXdOYW1lIiwiZ2V0V2ViVmlld3NNYXBwaW5nIiwiYW5kcm9pZERldmljZVNvY2tldCIsIndlYnZpZXdNYXBwaW5nIiwid3ZOYW1lIiwicHJvY2VzcyIsInVuZGVmaW5lZCIsInBrZ01hdGNoIiwibmFtZSIsImlkIiwid2FybiIsIm1lc3NhZ2UiLCJrZXkiLCJzZXQiLCJoYXMiLCJkZWxldGUiLCJnZXRXZWJ2aWV3RGV0YWlscyIsImdldCIsImNyZWF0ZUNocm9tZWRyaXZlckNhcHMiLCJkZXZpY2VJZCIsIndlYlZpZXdEZXRhaWxzIiwiX29wdHMkY2hyb21lT3B0aW9ucyIsIl93ZWJWaWV3RGV0YWlscyRpbmZvIiwiX3dlYlZpZXdEZXRhaWxzJHByb2NlIiwiX3dlYlZpZXdEZXRhaWxzJHByb2NlMiIsIl9vcHRzJGNocm9tZU9wdGlvbnMyIiwiY2FwcyIsImNocm9tZU9wdGlvbnMiLCJhbmRyb2lkUGFja2FnZSIsImFwcFBhY2thZ2UiLCJpc0Jvb2xlYW4iLCJjaHJvbWVVc2VSdW5uaW5nQXBwIiwiYW5kcm9pZFVzZVJ1bm5pbmdBcHAiLCJjaHJvbWVBbmRyb2lkUGFja2FnZSIsImNocm9tZUFuZHJvaWRBY3Rpdml0eSIsImFuZHJvaWRBY3Rpdml0eSIsImNocm9tZUFuZHJvaWRQcm9jZXNzIiwiYW5kcm9pZFByb2Nlc3MiLCJ0b0xvd2VyIiwiYnJvd3Nlck5hbWUiLCJhcHBBY3Rpdml0eSIsInBhZ2VMb2FkU3RyYXRlZ3kiLCJpc0Nocm9tZSIsImluY2x1ZGVzIiwiYW5kcm9pZERldmljZVNlcmlhbCIsImlzUGxhaW5PYmplY3QiLCJsb2dnaW5nUHJlZnMiLCJjaHJvbWVMb2dnaW5nUHJlZnMiLCJlbmFibGVQZXJmb3JtYW5jZUxvZ2dpbmciLCJuZXdQcmVmIiwicGVyZm9ybWFuY2UiLCJPYmplY3QiLCJhc3NpZ24iLCJBcmd1bWVudHMiLCJhcmdzIiwicHJvdGVjdGVkQ2FwTmFtZXMiLCJvcHQiLCJ2YWwiLCJ0b1BhaXJzIiwiaXNVbmRlZmluZWQiLCJvcHROYW1lIiwiX2RlZmF1bHQiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vbGliL3dlYnZpZXctaGVscGVycy5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IGxvZ2dlciBmcm9tICcuL2xvZ2dlcic7XG5pbXBvcnQgYXhpb3MgZnJvbSAnYXhpb3MnO1xuaW1wb3J0IHsgdXRpbCB9IGZyb20gJ0BhcHBpdW0vc3VwcG9ydCc7XG5pbXBvcnQgeyBmaW5kQVBvcnROb3RJblVzZSB9IGZyb20gJ3BvcnRzY2FubmVyJztcbmltcG9ydCBMUlUgZnJvbSAnbHJ1LWNhY2hlJztcbmltcG9ydCBCIGZyb20gJ2JsdWViaXJkJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IG9zIGZyb20gJ29zJztcblxuY29uc3QgTkFUSVZFX1dJTiA9ICdOQVRJVkVfQVBQJztcbmNvbnN0IFdFQlZJRVdfV0lOID0gJ1dFQlZJRVcnO1xuY29uc3QgQ0hST01JVU1fV0lOID0gJ0NIUk9NSVVNJztcbmNvbnN0IFdFQlZJRVdfQkFTRSA9IGAke1dFQlZJRVdfV0lOfV9gO1xuY29uc3QgV0VCVklFV19QSURfUEFUVEVSTiA9IG5ldyBSZWdFeHAoYF4ke1dFQlZJRVdfQkFTRX0oXFxcXGQrKWApO1xuY29uc3QgV0VCVklFV19QS0dfUEFUVEVSTiA9IG5ldyBSZWdFeHAoYF4ke1dFQlZJRVdfQkFTRX0oW15cXFxcZFxcXFxzXVtcXFxcdy5dKilgKTtcbmNvbnN0IERFVlRPT0xTX1NPQ0tFVF9QQVRURVJOID0gL0BbXFx3Ll0rX2RldnRvb2xzX3JlbW90ZV8/KFxcZCspP1xcYi87XG5jb25zdCBDUk9TU1dBTEtfU09DS0VUX1BBVFRFUk4gPSAvQChbXFx3Ll0rKV9kZXZ0b29sc19yZW1vdGVcXGIvO1xuY29uc3QgQ0hST01JVU1fREVWVE9PTFNfU09DS0VUID0gJ2Nocm9tZV9kZXZ0b29sc19yZW1vdGUnO1xuY29uc3QgQ0hST01FX1BBQ0tBR0VfTkFNRSA9ICdjb20uYW5kcm9pZC5jaHJvbWUnO1xuY29uc3QgS05PV05fQ0hST01FX1BBQ0tBR0VfTkFNRVMgPSBbXG4gIENIUk9NRV9QQUNLQUdFX05BTUUsXG4gICdjb20uY2hyb21lLmJldGEnLFxuICAnY29tLmNocm9tZS5kZXYnLFxuICAnY29tLmNocm9tZS5jYW5hcnknLFxuXTtcbmNvbnN0IERFVlRPT0xTX1BPUlRTX1JBTkdFID0gWzEwOTAwLCAxMTAwMF07XG5jb25zdCBXRUJWSUVXU19ERVRBSUxTX0NBQ0hFID0gbmV3IExSVSh7XG4gIG1heDogMTAwLFxuICB1cGRhdGVBZ2VPbkdldDogdHJ1ZSxcbn0pO1xuY29uc3QgQ0RQX1JFUV9USU1FT1VUID0gMjAwMDsgLy8gbXNcbmNvbnN0IERFVlRPT0xTX1BPUlRfQUxMT0NBVElPTl9HVUFSRCA9IHV0aWwuZ2V0TG9ja0ZpbGVHdWFyZChcbiAgcGF0aC5yZXNvbHZlKG9zLnRtcGRpcigpLCAnYW5kcm9pZF9kZXZ0b29sc19wb3J0X2d1YXJkJyksXG4gIHt0aW1lb3V0OiA3LCB0cnlSZWNvdmVyeTogdHJ1ZX1cbik7XG5cbmNvbnN0IGhlbHBlcnMgPSB7fTtcblxuZnVuY3Rpb24gdG9EZXRhaWxzQ2FjaGVLZXkgKGFkYiwgd2Vidmlldykge1xuICByZXR1cm4gYCR7YWRiPy5jdXJEZXZpY2VJZH06JHt3ZWJ2aWV3fWA7XG59XG5cbi8qKlxuICogVGhpcyBmdW5jdGlvbiBnZXRzIGEgbGlzdCBvZiBhbmRyb2lkIHN5c3RlbSBwcm9jZXNzZXMgYW5kIHJldHVybnMgb25lc1xuICogdGhhdCBsb29rIGxpa2Ugd2Vidmlld3NcbiAqIFNlZSBodHRwczovL2NzLmNocm9taXVtLm9yZy9jaHJvbWl1bS9zcmMvY2hyb21lL2Jyb3dzZXIvZGV2dG9vbHMvZGV2aWNlL2FuZHJvaWRfZGV2aWNlX2luZm9fcXVlcnkuY2NcbiAqIGZvciBtb3JlIGRldGFpbHNcbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gYWRiIC0gYW4gQURCIGluc3RhbmNlXG4gKlxuICogQHJldHVybiB7QXJyYXkuPHN0cmluZz59IC0gYSBsaXN0IG9mIG1hdGNoaW5nIHdlYnZpZXcgc29ja2V0IG5hbWVzIChpbmNsdWRpbmcgdGhlIGxlYWRpbmcgJ0AnKVxuICovXG5hc3luYyBmdW5jdGlvbiBnZXRQb3RlbnRpYWxXZWJ2aWV3UHJvY3MgKGFkYikge1xuICBjb25zdCBvdXQgPSBhd2FpdCBhZGIuc2hlbGwoWydjYXQnLCAnL3Byb2MvbmV0L3VuaXgnXSk7XG4gIGNvbnN0IG5hbWVzID0gW107XG4gIGNvbnN0IGFsbE1hdGNoZXMgPSBbXTtcbiAgZm9yIChjb25zdCBsaW5lIG9mIG91dC5zcGxpdCgnXFxuJykpIHtcbiAgICAvLyBOdW0gUmVmQ291bnQgUHJvdG9jb2wgRmxhZ3MgVHlwZSBTdCBJbm9kZSBQYXRoXG4gICAgY29uc3QgWywsLCBmbGFncywsIHN0LCwgc29ja1BhdGhdID0gbGluZS50cmltKCkuc3BsaXQoL1xccysvKTtcbiAgICBpZiAoIXNvY2tQYXRoKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgaWYgKHNvY2tQYXRoLnN0YXJ0c1dpdGgoJ0AnKSkge1xuICAgICAgYWxsTWF0Y2hlcy5wdXNoKGxpbmUudHJpbSgpKTtcbiAgICB9XG4gICAgaWYgKGZsYWdzICE9PSAnMDAwMTAwMDAnIHx8IHN0ICE9PSAnMDEnKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgaWYgKCFERVZUT09MU19TT0NLRVRfUEFUVEVSTi50ZXN0KHNvY2tQYXRoKSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgbmFtZXMucHVzaChzb2NrUGF0aCk7XG4gIH1cbiAgaWYgKF8uaXNFbXB0eShuYW1lcykpIHtcbiAgICBsb2dnZXIuZGVidWcoJ0ZvdW5kIG5vIGFjdGl2ZSBkZXZ0b29scyBzb2NrZXRzJyk7XG4gICAgaWYgKCFfLmlzRW1wdHkoYWxsTWF0Y2hlcykpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhgT3RoZXIgc29ja2V0cyBhcmU6ICR7SlNPTi5zdHJpbmdpZnkoYWxsTWF0Y2hlcywgbnVsbCwgMil9YCk7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGxvZ2dlci5kZWJ1ZyhgUGFyc2VkICR7bmFtZXMubGVuZ3RofSBhY3RpdmUgZGV2dG9vbHMgJHt1dGlsLnBsdXJhbGl6ZSgnc29ja2V0JywgbmFtZXMubGVuZ3RoLCBmYWxzZSl9OiBgICtcbiAgICAgIEpTT04uc3RyaW5naWZ5KG5hbWVzKSk7XG4gIH1cbiAgLy8gc29tZXRpbWVzIHRoZSB3ZWJ2aWV3IHByb2Nlc3Mgc2hvd3MgdXAgbXVsdGlwbGUgdGltZXMgcGVyIGFwcFxuICByZXR1cm4gXy51bmlxKG5hbWVzKTtcbn1cblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBXZWJ2aWV3UHJvY1xuICogQHByb3BlcnR5IHtzdHJpbmd9IHByb2MgLSBUaGUgd2VidmlldyBwcm9jZXNzIG5hbWUgKGFzIHJldHVybmVkIGJ5XG4gKiBnZXRQb3RlbnRpYWxXZWJ2aWV3UHJvY3NcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSB3ZWJ2aWV3IC0gVGhlIGFjdHVhbCB3ZWJ2aWV3IGNvbnRleHQgbmFtZVxuICovXG4vKipcbiAqIFRoaXMgZnVuY3Rpb24gcmV0cmlldmVzIGEgbGlzdCBvZiBzeXN0ZW0gcHJvY2Vzc2VzIHRoYXQgbG9vayBsaWtlIHdlYnZpZXdzLFxuICogYW5kIHJldHVybnMgdGhlbSBhbG9uZyB3aXRoIHRoZSB3ZWJ2aWV3IGNvbnRleHQgbmFtZSBhcHByb3ByaWF0ZSBmb3IgaXQuXG4gKiBJZiB3ZSBwYXNzIGluIGEgZGV2aWNlU29ja2V0LCB3ZSBvbmx5IGF0dGVtcHQgdG8gZmluZCB3ZWJ2aWV3cyB3aGljaCBtYXRjaFxuICogdGhhdCBzb2NrZXQgbmFtZSAodGhpcyBpcyBmb3IgYXBwcyB3aGljaCBlbWJlZCBDaHJvbWl1bSwgd2hpY2ggaXNuJ3QgdGhlXG4gKiBzYW1lIGFzIGNocm9tZS1iYWNrZWQgd2Vidmlld3MpLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBhZGIgLSBhbiBBREIgaW5zdGFuY2VcbiAqIEBwYXJhbSB7P3N0cmluZ30gZGV2aWNlU29ja2V0IC0gdGhlIGV4cGxpY3RseS1uYW1lZCBkZXZpY2Ugc29ja2V0IHRvIHVzZVxuICpcbiAqIEByZXR1cm4ge0FycmF5LjxXZWJ2aWV3UHJvYz59XG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHdlYnZpZXdzRnJvbVByb2NzIChhZGIsIGRldmljZVNvY2tldCA9IG51bGwpIHtcbiAgY29uc3Qgc29ja2V0TmFtZXMgPSBhd2FpdCBnZXRQb3RlbnRpYWxXZWJ2aWV3UHJvY3MoYWRiKTtcbiAgY29uc3Qgd2Vidmlld3MgPSBbXTtcbiAgZm9yIChjb25zdCBzb2NrZXROYW1lIG9mIHNvY2tldE5hbWVzKSB7XG4gICAgaWYgKGRldmljZVNvY2tldCA9PT0gQ0hST01JVU1fREVWVE9PTFNfU09DS0VUICYmIHNvY2tldE5hbWUgPT09IGBAJHtkZXZpY2VTb2NrZXR9YCkge1xuICAgICAgd2Vidmlld3MucHVzaCh7XG4gICAgICAgIHByb2M6IHNvY2tldE5hbWUsXG4gICAgICAgIHdlYnZpZXc6IENIUk9NSVVNX1dJTixcbiAgICAgIH0pO1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgY29uc3Qgc29ja2V0TmFtZU1hdGNoID0gREVWVE9PTFNfU09DS0VUX1BBVFRFUk4uZXhlYyhzb2NrZXROYW1lKTtcbiAgICBpZiAoIXNvY2tldE5hbWVNYXRjaCkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGNvbnN0IGNyb3Nzd2Fsa01hdGNoID0gQ1JPU1NXQUxLX1NPQ0tFVF9QQVRURVJOLmV4ZWMoc29ja2V0TmFtZSk7XG4gICAgaWYgKCFzb2NrZXROYW1lTWF0Y2hbMV0gJiYgIWNyb3Nzd2Fsa01hdGNoKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBpZiAoZGV2aWNlU29ja2V0ICYmIHNvY2tldE5hbWUgPT09IGBAJHtkZXZpY2VTb2NrZXR9YCB8fCAhZGV2aWNlU29ja2V0KSB7XG4gICAgICB3ZWJ2aWV3cy5wdXNoKHtcbiAgICAgICAgcHJvYzogc29ja2V0TmFtZSxcbiAgICAgICAgd2Vidmlldzogc29ja2V0TmFtZU1hdGNoWzFdXG4gICAgICAgICAgPyBgJHtXRUJWSUVXX0JBU0V9JHtzb2NrZXROYW1lTWF0Y2hbMV19YFxuICAgICAgICAgIDogYCR7V0VCVklFV19CQVNFfSR7Y3Jvc3N3YWxrTWF0Y2hbMV19YCxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuICByZXR1cm4gd2Vidmlld3M7XG59XG5cbi8qKlxuICogQWxsb2NhdGVzIGEgbG9jYWwgcG9ydCBmb3IgZGV2dG9vbHMgY29tbXVuaWNhdGlvblxuICpcbiAqIEBwYXJhbSB7QURCfSBhZGIgQURCIGluc3RhbmNlXG4gKiBAcGFyYW0ge3N0cmluZ30gc29ja2V0TmFtZSBUaGUgcmVtb3RlIFVuaXggc29ja2V0IG5hbWVcbiAqIEBwYXJhbSB7P251bWJlcn0gd2Vidmlld0RldnRvb2xzUG9ydCBUaGUgbG9jYWwgcG9ydCBudW1iZXIgb3IgbnVsbCB0byBhcHBseVxuICogYXV0b2RldGVjdGlvblxuICogQHJldHVybnMge251bWJlcn0gVGhlIGxvY2FsIHBvcnQgbnVtYmVyIGlmIHRoZSByZW1vdGUgc29ja2V0IGhhcyBiZWVuIGZvcndhcmRlZFxuICogc3VjY2Vzc2Z1bGx5IG9yIGBudWxsYCBvdGhlcndpc2VcbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGVyZSB3YXMgYW4gZXJyb3Igd2hpbGUgYWxsb2NhdGluZyB0aGUgbG9jYWwgcG9ydFxuICovXG5hc3luYyBmdW5jdGlvbiBhbGxvY2F0ZURldnRvb2xzUG9ydCAoYWRiLCBzb2NrZXROYW1lLCB3ZWJ2aWV3RGV2dG9vbHNQb3J0ID0gbnVsbCkge1xuICAvLyBzb2NrZXQgbmFtZXMgY29tZSB3aXRoICdAJywgYnV0IHRoaXMgc2hvdWxkIG5vdCBiZSBhIHBhcnQgb2YgdGhlIGFic3RyYWN0XG4gIC8vIHJlbW90ZSBwb3J0LCBzbyByZW1vdmUgaXRcbiAgY29uc3QgcmVtb3RlUG9ydCA9IHNvY2tldE5hbWUucmVwbGFjZSgvXkAvLCAnJyk7XG4gIGxldCBbc3RhcnRQb3J0LCBlbmRQb3J0XSA9IERFVlRPT0xTX1BPUlRTX1JBTkdFO1xuICBpZiAod2Vidmlld0RldnRvb2xzUG9ydCkge1xuICAgIGVuZFBvcnQgPSB3ZWJ2aWV3RGV2dG9vbHNQb3J0ICsgKGVuZFBvcnQgLSBzdGFydFBvcnQpO1xuICAgIHN0YXJ0UG9ydCA9IHdlYnZpZXdEZXZ0b29sc1BvcnQ7XG4gIH1cbiAgbG9nZ2VyLmRlYnVnKGBGb3J3YXJkaW5nIHJlbW90ZSBwb3J0ICR7cmVtb3RlUG9ydH0gdG8gYSBsb2NhbCBgICtcbiAgICBgcG9ydCBpbiByYW5nZSAke3N0YXJ0UG9ydH0uLiR7ZW5kUG9ydH1gKTtcbiAgaWYgKCF3ZWJ2aWV3RGV2dG9vbHNQb3J0KSB7XG4gICAgbG9nZ2VyLmRlYnVnKGBZb3UgY291bGQgdXNlIHRoZSAnd2Vidmlld0RldnRvb2xzUG9ydCcgY2FwYWJpbGl0eSB0byBjdXN0b21pemUgYCArXG4gICAgICBgdGhlIHN0YXJ0aW5nIHBvcnQgbnVtYmVyYCk7XG4gIH1cbiAgcmV0dXJuIGF3YWl0IERFVlRPT0xTX1BPUlRfQUxMT0NBVElPTl9HVUFSRChhc3luYyAoKSA9PiB7XG4gICAgbGV0IGxvY2FsUG9ydDtcbiAgICB0cnkge1xuICAgICAgbG9jYWxQb3J0ID0gYXdhaXQgZmluZEFQb3J0Tm90SW5Vc2Uoc3RhcnRQb3J0LCBlbmRQb3J0KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBmaW5kIGFueSBmcmVlIHBvcnQgdG8gZm9yd2FyZCB0aGUgRGV2dG9vbHMgc29ja2V0IGAgK1xuICAgICAgICBgaW4gcmFuZ2UgJHtzdGFydFBvcnR9Li4ke2VuZFBvcnR9LiBZb3UgY291bGQgc2V0IHRoZSBzdGFydGluZyBwb3J0IG51bWJlciBgICtcbiAgICAgICAgYG1hbnVhbGx5IGJ5IHByb3ZpZGluZyB0aGUgJ3dlYnZpZXdEZXZ0b29sc1BvcnQnIGNhcGFiaWxpdHlgKTtcbiAgICB9XG4gICAgYXdhaXQgYWRiLmFkYkV4ZWMoWydmb3J3YXJkJywgYHRjcDoke2xvY2FsUG9ydH1gLCBgbG9jYWxhYnN0cmFjdDoke3JlbW90ZVBvcnR9YF0pO1xuICAgIHJldHVybiBsb2NhbFBvcnQ7XG4gIH0pO1xufVxuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IFdlYnZpZXdQcm9wc1xuICogQHByb3BlcnR5IHtzdHJpbmd9IHByb2MgVGhlIG5hbWUgb2YgdGhlIERldnRvb2xzIFVuaXggc29ja2V0XG4gKiBAcHJvcGVydHkge3N0cmluZ30gd2VidmlldyBUaGUgd2ViIHZpZXcgYWxpYXMuIExvb2tzIGxpa2UgYFdFQlZJRVdfYFxuICogcHJlZml4IHBsdXMgUElEIG9yIHBhY2thZ2UgbmFtZVxuICogQHByb3BlcnR5IHs/T2JqZWN0fSBpbmZvIFdlYnZpZXcgaW5mb3JtYXRpb24gYXMgaXQgaXMgcmV0cmlldmVkIGJ5XG4gKiAvanNvbi92ZXJzaW9uIENEUCBlbmRwb2ludFxuICogQHByb3BlcnR5IHs/QXJyYXk8T2JqZWN0Pn0gcGFnZXMgV2VidmlldyBwYWdlcyBsaXN0IGFzIGl0IGlzIHJldHJpZXZlZCBieVxuICogL2pzb24vbGlzdCBDRFAgZW5kcG9pbnRcbiAqL1xuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IERldGFpbENvbGxlY3Rpb25PcHRpb25zXG4gKiBAcHJvcGVydHkgez9zdHJpbmd8bnVtYmVyfSB3ZWJ2aWV3RGV2dG9vbHNQb3J0IFRoZSBzdGFydGluZyBwb3J0IHRvIHVzZSBmb3Igd2VidmlldyBwYWdlXG4gKiBwcmVzZW5jZSBjaGVjayAoaWYgbm90IHRoZSBkZWZhdWx0IG9mIDkyMjIpLlxuICogQHByb3BlcnR5IHs/Ym9vbGVhbn0gZW5zdXJlV2Vidmlld3NIYXZlUGFnZXMgV2hldGhlciB0byBjaGVjayBmb3Igd2Vidmlld1xuICogcGFnZXMgcHJlc2VuY2VcbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gZW5hYmxlV2Vidmlld0RldGFpbHNDb2xsZWN0aW9uIFdoZXRoZXIgdG8gY29sbGVjdFxuICogd2ViIHZpZXcgZGV0YWlscyBhbmQgc2VuZCB0aGVtIHRvIENocm9tZWRyaXZlciBjb25zdHJ1Y3Rvciwgc28gaXQgY291bGRcbiAqIHNlbGVjdCBhIGJpbmFyeSBtb3JlIHByZWNpc2VseSBiYXNlZCBvbiB0aGlzIGluZm8uXG4gKi9cblxuLyoqXG4gKiBUaGlzIGlzIGEgd3JhcHBlciBmb3IgQ2hyb21lIERlYnVnZ2VyIFByb3RvY29sIGRhdGEgY29sbGVjdGlvbi5cbiAqIE5vIGVycm9yIGlzIHRocm93biBpZiBDRFAgcmVxdWVzdCBmYWlscyAtIGluIHN1Y2ggY2FzZSBubyBkYXRhIHdpbGwgYmVcbiAqIHJlY29yZGVkIGludG8gdGhlIGNvcnJlc3BvbmRpbmcgYHdlYnZpZXdzTWFwcGluZ2AgaXRlbS5cbiAqXG4gKiBAcGFyYW0ge0FEQn0gYWRiIFRoZSBBREIgaW5zdGFuY2VcbiAqIEBwYXJhbSB7QXJyYXk8V2Vidmlld1Byb3BzPn0gd2Vidmlld3NNYXBwaW5nIFRoZSBjdXJyZW50IHdlYnZpZXdzIG1hcHBpbmdcbiAqICEhISBFYWNoIGl0ZW0gb2YgdGhpcyBhcnJheSBnZXRzIG11dGF0ZWQgKGBpbmZvYC9gcGFnZXNgIHByb3BlcnRpZXMgZ2V0IGFkZGVkXG4gKiBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgYG9wdHNgKSBpZiB0aGUgcmVxdWVzdGVkIGRldGFpbHMgaGF2ZSBiZWVuXG4gKiBzdWNjZXNzZnVsbHkgcmV0cmlldmVkIGZvciBpdCAhISFcbiAqIEBwYXJhbSB7RGV0YWlsQ29sbGVjdGlvbk9wdGlvbnN9IG9wdHMgSWYgYm90aCBgZW5zdXJlV2Vidmlld3NIYXZlUGFnZXNgIGFuZFxuICogYGVuYWJsZVdlYnZpZXdEZXRhaWxzQ29sbGVjdGlvbmAgcHJvcGVydGllcyBhcmUgZmFsc3kgdGhlbiBubyBkZXRhaWxzIGNvbGxlY3Rpb25cbiAqIGlzIHBlcmZvcm1lZFxuICovXG5hc3luYyBmdW5jdGlvbiBjb2xsZWN0V2Vidmlld3NEZXRhaWxzIChhZGIsIHdlYnZpZXdzTWFwcGluZywgb3B0cyA9IHt9KSB7XG4gIGlmIChfLmlzRW1wdHkod2Vidmlld3NNYXBwaW5nKSkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IHtcbiAgICB3ZWJ2aWV3RGV2dG9vbHNQb3J0ID0gbnVsbCxcbiAgICBlbnN1cmVXZWJ2aWV3c0hhdmVQYWdlcyA9IG51bGwsXG4gICAgZW5hYmxlV2Vidmlld0RldGFpbHNDb2xsZWN0aW9uID0gbnVsbCxcbiAgfSA9IG9wdHM7XG5cbiAgaWYgKCFlbnN1cmVXZWJ2aWV3c0hhdmVQYWdlcykge1xuICAgIGxvZ2dlci5pbmZvKGBOb3QgY2hlY2tpbmcgd2hldGhlciB3ZWJ2aWV3cyBoYXZlIGFjdGl2ZSBwYWdlczsgdXNlIHRoZSBgICtcbiAgICAgIGAnZW5zdXJlV2Vidmlld3NIYXZlUGFnZXMnIGNhcCB0byB0dXJuIHRoaXMgY2hlY2sgb25gKTtcbiAgfVxuXG4gIGlmICghZW5hYmxlV2Vidmlld0RldGFpbHNDb2xsZWN0aW9uKSB7XG4gICAgbG9nZ2VyLmluZm8oYE5vdCBjb2xsZWN0aW5nIHdlYiB2aWV3IGRldGFpbHMuIERldGFpbHMgY29sbGVjdGlvbiBtaWdodCBoZWxwIGAgK1xuICAgICAgYHRvIG1ha2UgQ2hyb21lZHJpdmVyIGluaXRpYWxpemF0aW9uIG1vcmUgcHJlY2lzZS4gVXNlIHRoZSAnZW5hYmxlV2Vidmlld0RldGFpbHNDb2xsZWN0aW9uJyBgICtcbiAgICAgIGBjYXAgdG8gdHVybiBpdCBvbmApO1xuICB9XG5cbiAgaWYgKCFlbnN1cmVXZWJ2aWV3c0hhdmVQYWdlcyAmJiAhZW5hYmxlV2Vidmlld0RldGFpbHNDb2xsZWN0aW9uKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gQ29ubmVjdCB0byBlYWNoIGRldnRvb2xzIHNvY2tldCBhbmQgcmV0cmlldmUgd2ViIHZpZXcgZGV0YWlsc1xuICBsb2dnZXIuZGVidWcoYENvbGxlY3RpbmcgQ0RQIGRhdGEgb2YgJHt1dGlsLnBsdXJhbGl6ZSgnd2VidmlldycsIHdlYnZpZXdzTWFwcGluZy5sZW5ndGgsIHRydWUpfWApO1xuICBjb25zdCBkZXRhaWxDb2xsZWN0b3JzID0gW107XG4gIGZvciAoY29uc3QgaXRlbSBvZiB3ZWJ2aWV3c01hcHBpbmcpIHtcbiAgICBkZXRhaWxDb2xsZWN0b3JzLnB1c2goKGFzeW5jICgpID0+IHtcbiAgICAgIGxldCBsb2NhbFBvcnQ7XG4gICAgICB0cnkge1xuICAgICAgICBsb2NhbFBvcnQgPSBhd2FpdCBhbGxvY2F0ZURldnRvb2xzUG9ydChhZGIsIGl0ZW0ucHJvYywgd2Vidmlld0RldnRvb2xzUG9ydCk7XG4gICAgICAgIGlmIChlbmFibGVXZWJ2aWV3RGV0YWlsc0NvbGxlY3Rpb24pIHtcbiAgICAgICAgICBpdGVtLmluZm8gPSBhd2FpdCBjZHBJbmZvKGxvY2FsUG9ydCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGVuc3VyZVdlYnZpZXdzSGF2ZVBhZ2VzKSB7XG4gICAgICAgICAgaXRlbS5wYWdlcyA9IGF3YWl0IGNkcExpc3QobG9jYWxQb3J0KTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBsb2dnZXIuZGVidWcoZSk7XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBpZiAobG9jYWxQb3J0KSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IGFkYi5yZW1vdmVQb3J0Rm9yd2FyZChsb2NhbFBvcnQpO1xuICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KSgpKTtcbiAgfVxuICBhd2FpdCBCLmFsbChkZXRhaWxDb2xsZWN0b3JzKTtcbiAgbG9nZ2VyLmRlYnVnKGBDRFAgZGF0YSBjb2xsZWN0aW9uIGNvbXBsZXRlZGApO1xufVxuXG4vLyBodHRwczovL2Nocm9tZWRldnRvb2xzLmdpdGh1Yi5pby9kZXZ0b29scy1wcm90b2NvbC9cbmFzeW5jIGZ1bmN0aW9uIGNkcExpc3QgKGxvY2FsUG9ydCkge1xuICByZXR1cm4gKGF3YWl0IGF4aW9zKHtcbiAgICB1cmw6IGBodHRwOi8vMTI3LjAuMC4xOiR7bG9jYWxQb3J0fS9qc29uL2xpc3RgLFxuICAgIHRpbWVvdXQ6IENEUF9SRVFfVElNRU9VVCxcbiAgfSkpLmRhdGE7XG59XG5cbi8vIGh0dHBzOi8vY2hyb21lZGV2dG9vbHMuZ2l0aHViLmlvL2RldnRvb2xzLXByb3RvY29sL1xuYXN5bmMgZnVuY3Rpb24gY2RwSW5mbyAobG9jYWxQb3J0KSB7XG4gIHJldHVybiAoYXdhaXQgYXhpb3Moe1xuICAgIHVybDogYGh0dHA6Ly8xMjcuMC4wLjE6JHtsb2NhbFBvcnR9L2pzb24vdmVyc2lvbmAsXG4gICAgdGltZW91dDogQ0RQX1JFUV9USU1FT1VULFxuICB9KSkuZGF0YTtcbn1cblxuLyoqXG4gKiBUYWtlIGEgd2VidmlldyBuYW1lIGxpa2UgV0VCVklFV180Mjk2IGFuZCB1c2UgJ2FkYiBzaGVsbCBwcycgdG8gZmlndXJlIG91dFxuICogd2hpY2ggYXBwIHBhY2thZ2UgaXMgYXNzb2NpYXRlZCB3aXRoIHRoYXQgd2Vidmlldy4gT25lIG9mIHRoZSByZWFzb25zIHdlXG4gKiB3YW50IHRvIGRvIHRoaXMgaXMgdG8gbWFrZSBzdXJlIHdlJ3JlIGxpc3Rpbmcgd2Vidmlld3MgZm9yIHRoZSBhY3R1YWwgQVVULFxuICogbm90IHNvbWUgb3RoZXIgcnVubmluZyBhcHBcbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gYWRiIC0gYW4gQURCIGluc3RhbmNlXG4gKiBAcGFyYW0ge3N0cmluZ30gd2VidmlldyAtIGEgd2VidmlldyBwcm9jZXNzIG5hbWVcbiAqXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIHRoZSBwYWNrYWdlIG5hbWUgb2YgdGhlIGFwcCBydW5uaW5nIHRoZSB3ZWJ2aWV3XG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlcmUgd2FzIGEgZmFpbHVyZSB3aGlsZSByZXRyaWV2aW5nIHRoZSBwcm9jZXNzIG5hbWVcbiAqL1xuaGVscGVycy5wcm9jRnJvbVdlYnZpZXcgPSBhc3luYyBmdW5jdGlvbiBwcm9jRnJvbVdlYnZpZXcgKGFkYiwgd2Vidmlldykge1xuICBjb25zdCBwaWRNYXRjaCA9IFdFQlZJRVdfUElEX1BBVFRFUk4uZXhlYyh3ZWJ2aWV3KTtcbiAgaWYgKCFwaWRNYXRjaCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgQ291bGQgbm90IGZpbmQgUElEIGZvciB3ZWJ2aWV3ICcke3dlYnZpZXd9J2ApO1xuICB9XG5cbiAgY29uc3QgcGlkID0gcGlkTWF0Y2hbMV07XG4gIGxvZ2dlci5kZWJ1ZyhgJHt3ZWJ2aWV3fSBtYXBwZWQgdG8gcGlkICR7cGlkfWApO1xuICBsb2dnZXIuZGVidWcoYEdldHRpbmcgcHJvY2VzcyBuYW1lIGZvciB3ZWJ2aWV3ICcke3dlYnZpZXd9J2ApO1xuICBjb25zdCBwa2cgPSBhd2FpdCBhZGIuZ2V0TmFtZUJ5UGlkKHBpZCk7XG4gIGxvZ2dlci5kZWJ1ZyhgR290IHByb2Nlc3MgbmFtZTogJyR7cGtnfSdgKTtcbiAgcmV0dXJuIHBrZztcbn07XG5cbi8qKlxuICogUGFyc2Ugd2VidmlldyBuYW1lcyBmb3IgZ2V0Q29udGV4dHNcbiAqXG4gKiBAcGFyYW0ge0FycmF5PFdlYnZpZXdzTWFwcGluZz59IHdlYnZpZXdzTWFwcGluZyBTZWUgbm90ZSBvbiBnZXRXZWJWaWV3c01hcHBpbmdcbiAqIEBwYXJhbSB7R2V0V2Vidmlld3NPcHRzfSBvcHRzIFNlZSBub3RlIG9uIGdldFdlYlZpZXdzTWFwcGluZ1xuICogQHJldHVybiB7QXJyYXkuPHN0cmluZz59IC0gYSBsaXN0IG9mIHdlYnZpZXcgbmFtZXNcbiAqL1xuaGVscGVycy5wYXJzZVdlYnZpZXdOYW1lcyA9IGZ1bmN0aW9uIHBhcnNlV2Vidmlld05hbWVzICh3ZWJ2aWV3c01hcHBpbmcsIHtcbiAgZW5zdXJlV2Vidmlld3NIYXZlUGFnZXMgPSB0cnVlLFxuICBpc0Nocm9tZVNlc3Npb24gPSBmYWxzZVxufSA9IHt9KSB7XG4gIGlmIChpc0Nocm9tZVNlc3Npb24pIHtcbiAgICByZXR1cm4gW0NIUk9NSVVNX1dJTl07XG4gIH1cblxuICBjb25zdCByZXN1bHQgPSBbXTtcbiAgZm9yIChjb25zdCB7d2VidmlldywgcGFnZXMsIHByb2MsIHdlYnZpZXdOYW1lfSBvZiB3ZWJ2aWV3c01hcHBpbmcpIHtcbiAgICBpZiAoZW5zdXJlV2Vidmlld3NIYXZlUGFnZXMgJiYgcGFnZXM/Lmxlbmd0aCA9PT0gMCkge1xuICAgICAgbG9nZ2VyLmluZm8oYFNraXBwaW5nIHRoZSB3ZWJ2aWV3ICcke3dlYnZpZXd9JyBhdCAnJHtwcm9jfScgYCArXG4gICAgICAgIGBzaW5jZSBpdCBoYXMgcmVwb3J0ZWQgaGF2aW5nIHplcm8gcGFnZXNgKTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBpZiAod2Vidmlld05hbWUpIHtcbiAgICAgIHJlc3VsdC5wdXNoKHdlYnZpZXdOYW1lKTtcbiAgICB9XG4gIH1cbiAgbG9nZ2VyLmRlYnVnKGBGb3VuZCAke3V0aWwucGx1cmFsaXplKCd3ZWJ2aWV3JywgcmVzdWx0Lmxlbmd0aCwgdHJ1ZSl9OiAke0pTT04uc3RyaW5naWZ5KHJlc3VsdCl9YCk7XG4gIHJldHVybiByZXN1bHQ7XG59O1xuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IEdldFdlYnZpZXdzT3B0c1xuICogQHByb3BlcnR5IHtzdHJpbmd9IGFuZHJvaWREZXZpY2VTb2NrZXQgW251bGxdIC0gZGV2aWNlIHNvY2tldCBuYW1lXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IGVuc3VyZVdlYnZpZXdzSGF2ZVBhZ2VzIFt0cnVlXSAtIHdoZXRoZXIgdG8gY2hlY2sgZm9yIHdlYnZpZXdcbiAqIHBhZ2UgcHJlc2VuY2VcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSB3ZWJ2aWV3RGV2dG9vbHNQb3J0IFs5MjIyXSAtIHBvcnQgdG8gdXNlIGZvciB3ZWJ2aWV3IHBhZ2VcbiAqIHByZXNlbmNlIGNoZWNrLlxuICogQHByb3BlcnR5IHtib29sZWFufSBlbmFibGVXZWJ2aWV3RGV0YWlsc0NvbGxlY3Rpb24gW3RydWVdIC0gd2hldGhlciB0byBjb2xsZWN0XG4gKiB3ZWIgdmlldyBkZXRhaWxzIGFuZCBzZW5kIHRoZW0gdG8gQ2hyb21lZHJpdmVyIGNvbnN0cnVjdG9yLCBzbyBpdCBjb3VsZFxuICogc2VsZWN0IGEgYmluYXJ5IG1vcmUgcHJlY2lzZWx5IGJhc2VkIG9uIHRoaXMgaW5mby5cbiAqL1xuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IFdlYnZpZXdzTWFwcGluZ1xuICogQHByb3BlcnR5IHtzdHJpbmd9IHByb2MgU2VlIG5vdGUgb24gV2Vidmlld1Byb3BzXG4gKiBAcHJvcGVydHkge3N0cmluZ30gd2VidmlldyBTZWUgbm90ZSBvbiBXZWJ2aWV3UHJvcHNcbiAqIEBwcm9wZXJ0eSB7P09iamVjdH0gaW5mbyBTZWUgbm90ZSBvbiBXZWJ2aWV3UHJvcHNcbiAqIEBwcm9wZXJ0eSB7P0FycmF5PE9iamVjdD59IHBhZ2VzIFNlZSBub3RlIG9uIFdlYnZpZXdQcm9wc1xuICogQHByb3Blcnkgez9zdHJpbmd9IHdlYnZpZXdOYW1lIEFuIGFjdHVhbCB3ZWJ2aWV3IG5hbWUgZm9yIHN3aXRjaGluZyBjb250ZXh0XG4gKi9cblxuLyoqXG4gKiBHZXQgYSBsaXN0IG9mIGF2YWlsYWJsZSB3ZWJ2aWV3cyBtYXBwaW5nIGJ5IGludHJvc3BlY3RpbmcgcHJvY2Vzc2VzIHdpdGggYWRiLFxuICogd2hlcmUgd2Vidmlld3MgYXJlIGxpc3RlZC4gSXQncyBwb3NzaWJsZSB0byBwYXNzIGluIGEgJ2RldmljZVNvY2tldCcgYXJnLCB3aGljaFxuICogbGltaXRzIHRoZSB3ZWJ2aWV3IHBvc3NpYmlsaXRpZXMgdG8gdGhlIG9uZSBydW5uaW5nIG9uIHRoZSBDaHJvbWl1bSBkZXZ0b29sc1xuICogc29ja2V0IHdlJ3JlIGludGVyZXN0ZWQgaW4gKHNlZSBub3RlIG9uIHdlYnZpZXdzRnJvbVByb2NzKS4gV2UgY2FuIGFsc29cbiAqIGRpcmVjdCB0aGlzIG1ldGhvZCB0byB2ZXJpZnkgd2hldGhlciBhIHBhcnRpY3VsYXIgd2VidmlldyBwcm9jZXNzIGFjdHVhbGx5XG4gKiBoYXMgYW55IHBhZ2VzIChpZiBhIHByb2Nlc3MgZXhpc3RzIGJ1dCBubyBwYWdlcyBhcmUgZm91bmQsIENocm9tZWRyaXZlciB3aWxsXG4gKiBub3QgYWN0dWFsbHkgYmUgYWJsZSB0byBjb25uZWN0IHRvIGl0LCBzbyB0aGlzIHNlcnZlcyBhcyBhIGd1YXJkIGZvciB0aGF0XG4gKiBzdHJhbmdlIGZhaWx1cmUgbW9kZSkuIFRoZSBzdHJhdGVneSBmb3IgY2hlY2tpbmcgd2hldGhlciBhbnkgcGFnZXMgYXJlXG4gKiBhY3RpdmUgaW52b2x2ZXMgc2VuZGluZyBhIHJlcXVlc3QgdG8gdGhlIHJlbW90ZSBkZWJ1ZyBzZXJ2ZXIgb24gdGhlIGRldmljZSxcbiAqIGhlbmNlIGl0IGlzIGFsc28gcG9zc2libGUgdG8gc3BlY2lmeSB0aGUgcG9ydCBvbiB0aGUgaG9zdCBtYWNoaW5lIHdoaWNoXG4gKiBzaG91bGQgYmUgdXNlZCBmb3IgdGhpcyBjb21tdW5pY2F0aW9uLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBhZGIgLSBhbiBBREIgaW5zdGFuY2VcbiAqIEBwYXJhbSB7R2V0V2Vidmlld3NPcHRzfSBvcHRzXG4gKlxuICogQHJldHVybiB7QXJyYXk8V2Vidmlld3NNYXBwaW5nPn0gd2Vidmlld3NNYXBwaW5nXG4gKi9cbmhlbHBlcnMuZ2V0V2ViVmlld3NNYXBwaW5nID0gYXN5bmMgZnVuY3Rpb24gZ2V0V2ViVmlld3NNYXBwaW5nIChhZGIsIHtcbiAgYW5kcm9pZERldmljZVNvY2tldCA9IG51bGwsXG4gIGVuc3VyZVdlYnZpZXdzSGF2ZVBhZ2VzID0gdHJ1ZSxcbiAgd2Vidmlld0RldnRvb2xzUG9ydCA9IG51bGwsXG4gIGVuYWJsZVdlYnZpZXdEZXRhaWxzQ29sbGVjdGlvbiA9IHRydWVcbn0gPSB7fSkge1xuICBsb2dnZXIuZGVidWcoJ0dldHRpbmcgYSBsaXN0IG9mIGF2YWlsYWJsZSB3ZWJ2aWV3cycpO1xuICBjb25zdCB3ZWJ2aWV3c01hcHBpbmcgPSBhd2FpdCB3ZWJ2aWV3c0Zyb21Qcm9jcyhhZGIsIGFuZHJvaWREZXZpY2VTb2NrZXQpO1xuXG4gIGF3YWl0IGNvbGxlY3RXZWJ2aWV3c0RldGFpbHMoYWRiLCB3ZWJ2aWV3c01hcHBpbmcsIHtcbiAgICBlbnN1cmVXZWJ2aWV3c0hhdmVQYWdlcyxcbiAgICBlbmFibGVXZWJ2aWV3RGV0YWlsc0NvbGxlY3Rpb24sXG4gICAgd2Vidmlld0RldnRvb2xzUG9ydCxcbiAgfSk7XG5cbiAgZm9yIChjb25zdCB3ZWJ2aWV3TWFwcGluZyBvZiB3ZWJ2aWV3c01hcHBpbmcpIHtcbiAgICBjb25zdCB7d2VidmlldywgaW5mb30gPSB3ZWJ2aWV3TWFwcGluZztcbiAgICB3ZWJ2aWV3TWFwcGluZy53ZWJ2aWV3TmFtZSA9IG51bGw7XG5cbiAgICBsZXQgd3ZOYW1lID0gd2VidmlldztcbiAgICBsZXQgcHJvY2VzcyA9IHVuZGVmaW5lZDtcbiAgICBpZiAoIWFuZHJvaWREZXZpY2VTb2NrZXQpIHtcbiAgICAgIGNvbnN0IHBrZ01hdGNoID0gV0VCVklFV19QS0dfUEFUVEVSTi5leGVjKHdlYnZpZXcpO1xuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gd2ViIHZpZXcgbmFtZSBjb3VsZCBlaXRoZXIgYmUgc3VmZml4ZWQgd2l0aCBQSUQgb3IgdGhlIHBhY2thZ2UgbmFtZVxuICAgICAgICAvLyBwYWNrYWdlIG5hbWVzIGNvdWxkIG5vdCBzdGFydCB3aXRoIGEgZGlnaXRcbiAgICAgICAgY29uc3QgcGtnID0gcGtnTWF0Y2ggPyBwa2dNYXRjaFsxXSA6IGF3YWl0IGhlbHBlcnMucHJvY0Zyb21XZWJ2aWV3KGFkYiwgd2Vidmlldyk7XG4gICAgICAgIHd2TmFtZSA9IGAke1dFQlZJRVdfQkFTRX0ke3BrZ31gO1xuICAgICAgICBjb25zdCBwaWRNYXRjaCA9IFdFQlZJRVdfUElEX1BBVFRFUk4uZXhlYyh3ZWJ2aWV3KTtcbiAgICAgICAgcHJvY2VzcyA9IHtcbiAgICAgICAgICBuYW1lOiBwa2csXG4gICAgICAgICAgaWQ6IHBpZE1hdGNoID8gcGlkTWF0Y2hbMV0gOiBudWxsLFxuICAgICAgICB9O1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBsb2dnZXIud2FybihlLm1lc3NhZ2UpO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB3ZWJ2aWV3TWFwcGluZy53ZWJ2aWV3TmFtZSA9IHd2TmFtZTtcbiAgICBjb25zdCBrZXkgPSB0b0RldGFpbHNDYWNoZUtleShhZGIsIHd2TmFtZSk7XG4gICAgaWYgKGluZm8gfHwgcHJvY2Vzcykge1xuICAgICAgV0VCVklFV1NfREVUQUlMU19DQUNIRS5zZXQoa2V5LCB7IGluZm8sIHByb2Nlc3MgfSk7XG4gICAgfSBlbHNlIGlmIChXRUJWSUVXU19ERVRBSUxTX0NBQ0hFLmhhcyhrZXkpKSB7XG4gICAgICBXRUJWSUVXU19ERVRBSUxTX0NBQ0hFLmRlbGV0ZShrZXkpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gd2Vidmlld3NNYXBwaW5nO1xufTtcblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBQcm9jZXNzSW5mb1xuICogQHByb3BlcnR5IHtzdHJpbmd9IG5hbWUgVGhlIHByb2Nlc3MgbmFtZVxuICogQHByb3BlcnR5IHs/c3RyaW5nfSBpZCBUaGUgcHJvY2VzcyBpZCAoaWYgY291bGQgYmUgcmV0cmlldmVkKVxuICovXG5cbi8qKlxuICogQHR5cGVkZWYge09iamVjdH0gV2ViVmlld0RldGFpbHNcbiAqIEBwcm9wZXJ0eSB7P1Byb2Nlc3NJbmZvfSBwcm9jZXNzIC0gV2ViIHZpZXcgcHJvY2VzcyBkZXRhaWxzXG4gKiBAcHJvcGVydHkge09iamVjdH0gaW5mbyAtIFdlYiB2aWV3IGRldGFpbHMgYXMgcmV0dXJuZWQgYnkgL2pzb24vdmVyc2lvbiBDRFAgZW5kcG9pbnQsIGZvciBleGFtcGxlOlxuICoge1xuICogIFwiQnJvd3NlclwiOiBcIkNocm9tZS83Mi4wLjM2MDEuMFwiLFxuICogIFwiUHJvdG9jb2wtVmVyc2lvblwiOiBcIjEuM1wiLFxuICogIFwiVXNlci1BZ2VudFwiOiBcIk1vemlsbGEvNS4wIChNYWNpbnRvc2g7IEludGVsIE1hYyBPUyBYIDEwXzEzXzYpIEFwcGxlV2ViS2l0LzUzNy4zNiAoS0hUTUwsIGxpa2UgR2Vja28pIENocm9tZS83Mi4wLjM2MDEuMCBTYWZhcmkvNTM3LjM2XCIsXG4gKiAgXCJWOC1WZXJzaW9uXCI6IFwiNy4yLjIzM1wiLFxuICogIFwiV2ViS2l0LVZlcnNpb25cIjogXCI1MzcuMzYgKEBjZmVkZTlkYjFkMTU0ZGUwNDY4Y2IwNTM4NDc5ZjM0YzA3NTVhMGY0KVwiLFxuICogIFwid2ViU29ja2V0RGVidWdnZXJVcmxcIjogXCJ3czovL2xvY2FsaG9zdDo5MjIyL2RldnRvb2xzL2Jyb3dzZXIvYjBiOGE0ZmItYmIxNy00MzU5LTk1MzMtYThkOWYzOTA4YmQ4XCJcbiAqIH1cbiAqL1xuXG4vKipcbiAqIFJldHJpZXZlcyB3ZWIgdmlldyBkZXRhaWxzIHByZXZpb3VzbHkgY2FjaGVkIGJ5IGBnZXRXZWJ2aWV3c2AgY2FsbFxuICpcbiAqIEBwYXJhbSB7QURCfSBhZGIgQURCIGluc3RhbmNlXG4gKiBAcGFyYW0ge3N0cmluZ30gd2VidmlldyBUaGUgbmFtZSBvZiB0aGUgd2ViIHZpZXdcbiAqIEByZXR1cm5zIHs/V2ViVmlld0RldGFpbHN9IEVpdGhlciBgdW5kZWZpbmVkYCBvciB0aGUgcmVjZW50IHdlYiB2aWV3IGRldGFpbHNcbiAqL1xuaGVscGVycy5nZXRXZWJ2aWV3RGV0YWlscyA9IGZ1bmN0aW9uIGdldFdlYnZpZXdEZXRhaWxzIChhZGIsIHdlYnZpZXcpIHtcbiAgY29uc3Qga2V5ID0gdG9EZXRhaWxzQ2FjaGVLZXkoYWRiLCB3ZWJ2aWV3KTtcbiAgcmV0dXJuIFdFQlZJRVdTX0RFVEFJTFNfQ0FDSEUuZ2V0KGtleSk7XG59O1xuXG4vKipcbiAqIENyZWF0ZSBDaHJvbWUgZHJpdmVyIGNhcGFiaWxpdGllcyBiYXNlZCBvbiB0aGUgcHJvdmlkZWRcbiAqIEFwcGl1bSBjYXBhYmlsaXRpZXNcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0cyBVc2VyLXByb3ZpZGVkIGNhcGFiaWxpdGllcyBvYmplY3RcbiAqIEBwYXJhbSB7c3RyaW5nfSBkZXZpY2VJZCBUaGUgaWRlbnRpZmllciBvZiB0aGUgQW5kcm9pZCBkZXZpY2UgdW5kZXIgdGVzdFxuICogQHBhcmFtIHs/V2ViVmlld0RldGFpbHN9IHdlYlZpZXdEZXRhaWxzXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgY2FwYWJpbGl0aWVzIG9iamVjdC5cbiAqIFNlZSBodHRwczovL2Nocm9tZWRyaXZlci5jaHJvbWl1bS5vcmcvY2FwYWJpbGl0aWVzIGZvciBtb3JlIGRldGFpbHMuXG4gKi9cbmhlbHBlcnMuY3JlYXRlQ2hyb21lZHJpdmVyQ2FwcyA9IGZ1bmN0aW9uIGNyZWF0ZUNocm9tZWRyaXZlckNhcHMgKG9wdHMsIGRldmljZUlkLCB3ZWJWaWV3RGV0YWlscykge1xuICBjb25zdCBjYXBzID0geyBjaHJvbWVPcHRpb25zOiB7fSB9O1xuXG4gIGNvbnN0IGFuZHJvaWRQYWNrYWdlID0gb3B0cy5jaHJvbWVPcHRpb25zPy5hbmRyb2lkUGFja2FnZVxuICAgIHx8IG9wdHMuYXBwUGFja2FnZVxuICAgIHx8IHdlYlZpZXdEZXRhaWxzPy5pbmZvPy5bJ0FuZHJvaWQtUGFja2FnZSddO1xuICBpZiAoYW5kcm9pZFBhY2thZ2UpIHtcbiAgICAvLyBjaHJvbWVkcml2ZXIgcmFpc2VzIGFuIGludmFsaWQgYXJndW1lbnQgZXJyb3Igd2hlbiBhbmRyb2lkUGFja2FnZSBpcyAnbnVsbCdcbiAgICBjYXBzLmNocm9tZU9wdGlvbnMuYW5kcm9pZFBhY2thZ2UgPSBhbmRyb2lkUGFja2FnZTtcbiAgfVxuICBpZiAoXy5pc0Jvb2xlYW4ob3B0cy5jaHJvbWVVc2VSdW5uaW5nQXBwKSkge1xuICAgIGNhcHMuY2hyb21lT3B0aW9ucy5hbmRyb2lkVXNlUnVubmluZ0FwcCA9IG9wdHMuY2hyb21lVXNlUnVubmluZ0FwcDtcbiAgfVxuICBpZiAob3B0cy5jaHJvbWVBbmRyb2lkUGFja2FnZSkge1xuICAgIGNhcHMuY2hyb21lT3B0aW9ucy5hbmRyb2lkUGFja2FnZSA9IG9wdHMuY2hyb21lQW5kcm9pZFBhY2thZ2U7XG4gIH1cbiAgaWYgKG9wdHMuY2hyb21lQW5kcm9pZEFjdGl2aXR5KSB7XG4gICAgY2Fwcy5jaHJvbWVPcHRpb25zLmFuZHJvaWRBY3Rpdml0eSA9IG9wdHMuY2hyb21lQW5kcm9pZEFjdGl2aXR5O1xuICB9XG4gIGlmIChvcHRzLmNocm9tZUFuZHJvaWRQcm9jZXNzKSB7XG4gICAgY2Fwcy5jaHJvbWVPcHRpb25zLmFuZHJvaWRQcm9jZXNzID0gb3B0cy5jaHJvbWVBbmRyb2lkUHJvY2VzcztcbiAgfSBlbHNlIGlmICh3ZWJWaWV3RGV0YWlscz8ucHJvY2Vzcz8ubmFtZSAmJiB3ZWJWaWV3RGV0YWlscz8ucHJvY2Vzcz8uaWQpIHtcbiAgICBjYXBzLmNocm9tZU9wdGlvbnMuYW5kcm9pZFByb2Nlc3MgPSB3ZWJWaWV3RGV0YWlscy5wcm9jZXNzLm5hbWU7XG4gIH1cbiAgaWYgKF8udG9Mb3dlcihvcHRzLmJyb3dzZXJOYW1lKSA9PT0gJ2Nocm9taXVtLXdlYnZpZXcnKSB7XG4gICAgY2Fwcy5jaHJvbWVPcHRpb25zLmFuZHJvaWRBY3Rpdml0eSA9IG9wdHMuYXBwQWN0aXZpdHk7XG4gIH1cbiAgaWYgKG9wdHMucGFnZUxvYWRTdHJhdGVneSkge1xuICAgIGNhcHMucGFnZUxvYWRTdHJhdGVneSA9IG9wdHMucGFnZUxvYWRTdHJhdGVneTtcbiAgfVxuICBjb25zdCBpc0Nocm9tZSA9IF8udG9Mb3dlcihjYXBzLmNocm9tZU9wdGlvbnMuYW5kcm9pZFBhY2thZ2UpID09PSAnY2hyb21lJztcbiAgaWYgKF8uaW5jbHVkZXMoS05PV05fQ0hST01FX1BBQ0tBR0VfTkFNRVMsIGNhcHMuY2hyb21lT3B0aW9ucy5hbmRyb2lkUGFja2FnZSkgfHwgaXNDaHJvbWUpIHtcbiAgICAvLyBpZiB3ZSBoYXZlIGV4dHJhY3RlZCBwYWNrYWdlIGZyb20gY29udGV4dCBuYW1lLCBpdCBjb3VsZCBjb21lIGluIGFzIGJhcmVcbiAgICAvLyBcImNocm9tZVwiLCBhbmQgc28gd2Ugc2hvdWxkIG1ha2Ugc3VyZSB0aGUgZGV0YWlscyBhcmUgY29ycmVjdCwgaW5jbHVkaW5nXG4gICAgLy8gbm90IHVzaW5nIGFuIGFjdGl2aXR5IG9yIHByb2Nlc3MgaWRcbiAgICBpZiAoaXNDaHJvbWUpIHtcbiAgICAgIGNhcHMuY2hyb21lT3B0aW9ucy5hbmRyb2lkUGFja2FnZSA9IENIUk9NRV9QQUNLQUdFX05BTUU7XG4gICAgfVxuICAgIGRlbGV0ZSBjYXBzLmNocm9tZU9wdGlvbnMuYW5kcm9pZEFjdGl2aXR5O1xuICAgIGRlbGV0ZSBjYXBzLmNocm9tZU9wdGlvbnMuYW5kcm9pZFByb2Nlc3M7XG4gIH1cbiAgLy8gYWRkIGRldmljZSBpZCBmcm9tIGFkYlxuICBjYXBzLmNocm9tZU9wdGlvbnMuYW5kcm9pZERldmljZVNlcmlhbCA9IGRldmljZUlkO1xuXG4gIGlmIChfLmlzUGxhaW5PYmplY3Qob3B0cy5sb2dnaW5nUHJlZnMpIHx8IF8uaXNQbGFpbk9iamVjdChvcHRzLmNocm9tZUxvZ2dpbmdQcmVmcykpIHtcbiAgICBpZiAob3B0cy5sb2dnaW5nUHJlZnMpIHtcbiAgICAgIGxvZ2dlci53YXJuKGBUaGUgJ2xvZ2dpbmdQcmVmcycgY2FwIGlzIGRlcHJlY2F0ZWQ7IHVzZSB0aGUgJ2Nocm9tZUxvZ2dpbmdQcmVmcycgY2FwIGluc3RlYWRgKTtcbiAgICB9XG4gICAgY2Fwcy5sb2dnaW5nUHJlZnMgPSBvcHRzLmNocm9tZUxvZ2dpbmdQcmVmcyB8fCBvcHRzLmxvZ2dpbmdQcmVmcztcbiAgfVxuICBpZiAob3B0cy5lbmFibGVQZXJmb3JtYW5jZUxvZ2dpbmcpIHtcbiAgICBsb2dnZXIud2FybihgVGhlICdlbmFibGVQZXJmb3JtYW5jZUxvZ2dpbmcnIGNhcCBpcyBkZXByZWNhdGVkOyBzaW1wbHkgdXNlIGAgK1xuICAgICAgYHRoZSAnY2hyb21lTG9nZ2luZ1ByZWZzJyBjYXAgaW5zdGVhZCwgd2l0aCBhICdwZXJmb3JtYW5jZScga2V5IHNldCB0byAnQUxMJ2ApO1xuICAgIGNvbnN0IG5ld1ByZWYgPSB7cGVyZm9ybWFuY2U6ICdBTEwnfTtcbiAgICAvLyBkb24ndCBvdmVyd3JpdGUgb3RoZXIgbG9nZ2luZyBwcmVmcyB0aGF0IGhhdmUgYmVlbiBzZW50IGluIGlmIHRoZXkgZXhpc3RcbiAgICBjYXBzLmxvZ2dpbmdQcmVmcyA9IGNhcHMubG9nZ2luZ1ByZWZzXG4gICAgICA/IE9iamVjdC5hc3NpZ24oe30sIGNhcHMubG9nZ2luZ1ByZWZzLCBuZXdQcmVmKVxuICAgICAgOiBuZXdQcmVmO1xuICB9XG5cbiAgaWYgKG9wdHMuY2hyb21lT3B0aW9ucz8uQXJndW1lbnRzKSB7XG4gICAgLy8gbWVyZ2UgYEFyZ3VtZW50c2AgYW5kIGBhcmdzYFxuICAgIG9wdHMuY2hyb21lT3B0aW9ucy5hcmdzID0gWy4uLihvcHRzLmNocm9tZU9wdGlvbnMuYXJncyB8fCBbXSksIC4uLm9wdHMuY2hyb21lT3B0aW9ucy5Bcmd1bWVudHNdO1xuICAgIGRlbGV0ZSBvcHRzLmNocm9tZU9wdGlvbnMuQXJndW1lbnRzO1xuICB9XG5cbiAgbG9nZ2VyLmRlYnVnKCdQcmVjYWxjdWxhdGVkIENocm9tZWRyaXZlciBjYXBhYmlsaXRpZXM6ICcgK1xuICAgIEpTT04uc3RyaW5naWZ5KGNhcHMuY2hyb21lT3B0aW9ucywgbnVsbCwgMikpO1xuXG4gIGNvbnN0IHByb3RlY3RlZENhcE5hbWVzID0gW107XG4gIGZvciAoY29uc3QgW29wdCwgdmFsXSBvZiBfLnRvUGFpcnMob3B0cy5jaHJvbWVPcHRpb25zKSkge1xuICAgIGlmIChfLmlzVW5kZWZpbmVkKGNhcHMuY2hyb21lT3B0aW9uc1tvcHRdKSkge1xuICAgICAgY2Fwcy5jaHJvbWVPcHRpb25zW29wdF0gPSB2YWw7XG4gICAgfSBlbHNlIHtcbiAgICAgIHByb3RlY3RlZENhcE5hbWVzLnB1c2gob3B0KTtcbiAgICB9XG4gIH1cbiAgaWYgKCFfLmlzRW1wdHkocHJvdGVjdGVkQ2FwTmFtZXMpKSB7XG4gICAgbG9nZ2VyLmluZm8oJ1RoZSBmb2xsb3dpbmcgQ2hyb21lZHJpdmVyIGNhcGFiaWxpdGllcyBjYW5ub3QgYmUgb3ZlcnJpZGRlbiAnICtcbiAgICAgICdieSB0aGUgcHJvdmlkZWQgY2hyb21lT3B0aW9uczonKTtcbiAgICBmb3IgKGNvbnN0IG9wdE5hbWUgb2YgcHJvdGVjdGVkQ2FwTmFtZXMpIHtcbiAgICAgIGxvZ2dlci5pbmZvKGAgICR7b3B0TmFtZX0gKCR7SlNPTi5zdHJpbmdpZnkob3B0cy5jaHJvbWVPcHRpb25zW29wdE5hbWVdKX0pYCk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGNhcHM7XG59O1xuXG5leHBvcnQgZGVmYXVsdCBoZWxwZXJzO1xuZXhwb3J0IHsgaGVscGVycywgTkFUSVZFX1dJTiwgV0VCVklFV19XSU4sIFdFQlZJRVdfQkFTRSwgQ0hST01JVU1fV0lOLCBLTk9XTl9DSFJPTUVfUEFDS0FHRV9OQU1FUyB9O1xuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7OztBQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLE9BQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFFLE1BQUEsR0FBQUgsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFHLFFBQUEsR0FBQUgsT0FBQTtBQUNBLElBQUFJLFlBQUEsR0FBQUosT0FBQTtBQUNBLElBQUFLLFNBQUEsR0FBQU4sc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFNLFNBQUEsR0FBQVAsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFPLEtBQUEsR0FBQVIsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFRLEdBQUEsR0FBQVQsc0JBQUEsQ0FBQUMsT0FBQTtBQUVBLE1BQU1TLFVBQVUsR0FBRyxZQUFZO0FBQUNDLE9BQUEsQ0FBQUQsVUFBQSxHQUFBQSxVQUFBO0FBQ2hDLE1BQU1FLFdBQVcsR0FBRyxTQUFTO0FBQUNELE9BQUEsQ0FBQUMsV0FBQSxHQUFBQSxXQUFBO0FBQzlCLE1BQU1DLFlBQVksR0FBRyxVQUFVO0FBQUNGLE9BQUEsQ0FBQUUsWUFBQSxHQUFBQSxZQUFBO0FBQ2hDLE1BQU1DLFlBQVksR0FBSSxHQUFFRixXQUFZLEdBQUU7QUFBQ0QsT0FBQSxDQUFBRyxZQUFBLEdBQUFBLFlBQUE7QUFDdkMsTUFBTUMsbUJBQW1CLEdBQUcsSUFBSUMsTUFBTSxDQUFFLElBQUdGLFlBQWEsUUFBTyxDQUFDO0FBQ2hFLE1BQU1HLG1CQUFtQixHQUFHLElBQUlELE1BQU0sQ0FBRSxJQUFHRixZQUFhLG9CQUFtQixDQUFDO0FBQzVFLE1BQU1JLHVCQUF1QixHQUFHLG1DQUFtQztBQUNuRSxNQUFN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
529
+ exports.default = helpers;
530
+ //# sourceMappingURL=webview-helpers.js.map