appium-android-driver 5.4.3 → 5.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/build/index.js +1 -9
  2. package/build/lib/android-helpers.js +10 -194
  3. package/build/lib/android-helpers.js.map +1 -1
  4. package/build/lib/bootstrap.js +4 -45
  5. package/build/lib/bootstrap.js.map +1 -1
  6. package/build/lib/commands/actions.js +3 -78
  7. package/build/lib/commands/actions.js.map +1 -1
  8. package/build/lib/commands/alert.js +3 -10
  9. package/build/lib/commands/alert.js.map +1 -1
  10. package/build/lib/commands/app-management.js +4 -32
  11. package/build/lib/commands/app-management.js.map +1 -1
  12. package/build/lib/commands/context.js +6 -78
  13. package/build/lib/commands/context.js.map +1 -1
  14. package/build/lib/commands/coverage.js +1 -6
  15. package/build/lib/commands/coverage.js.map +1 -1
  16. package/build/lib/commands/element.js +4 -47
  17. package/build/lib/commands/element.js.map +1 -1
  18. package/build/lib/commands/emu-console.js +2 -7
  19. package/build/lib/commands/emu-console.js.map +1 -1
  20. package/build/lib/commands/execute.js +1 -13
  21. package/build/lib/commands/execute.js.map +1 -1
  22. package/build/lib/commands/file-actions.js +3 -44
  23. package/build/lib/commands/file-actions.js.map +1 -1
  24. package/build/lib/commands/find.js +3 -16
  25. package/build/lib/commands/find.js.map +1 -1
  26. package/build/lib/commands/general.js +32 -91
  27. package/build/lib/commands/general.js.map +1 -1
  28. package/build/lib/commands/ime.js +3 -14
  29. package/build/lib/commands/ime.js.map +1 -1
  30. package/build/lib/commands/index.js +3 -27
  31. package/build/lib/commands/index.js.map +1 -1
  32. package/build/lib/commands/intent.js +1 -40
  33. package/build/lib/commands/intent.js.map +1 -1
  34. package/build/lib/commands/log.js +3 -35
  35. package/build/lib/commands/log.js.map +1 -1
  36. package/build/lib/commands/media-projection.js +2 -47
  37. package/build/lib/commands/media-projection.js.map +1 -1
  38. package/build/lib/commands/network.js +4 -40
  39. package/build/lib/commands/network.js.map +1 -1
  40. package/build/lib/commands/performance.js +5 -57
  41. package/build/lib/commands/performance.js.map +1 -1
  42. package/build/lib/commands/recordscreen.js +1 -59
  43. package/build/lib/commands/recordscreen.js.map +1 -1
  44. package/build/lib/commands/shell.js +1 -15
  45. package/build/lib/commands/shell.js.map +1 -1
  46. package/build/lib/commands/streamscreen.js +7 -74
  47. package/build/lib/commands/streamscreen.js.map +1 -1
  48. package/build/lib/commands/system-bars.js +1 -23
  49. package/build/lib/commands/system-bars.js.map +1 -1
  50. package/build/lib/commands/touch.js +13 -79
  51. package/build/lib/commands/touch.js.map +1 -1
  52. package/build/lib/desired-caps.js +3 -4
  53. package/build/lib/desired-caps.js.map +1 -1
  54. package/build/lib/driver.js +8 -97
  55. package/build/lib/driver.js.map +1 -1
  56. package/build/lib/logger.js +1 -5
  57. package/build/lib/logger.js.map +1 -1
  58. package/build/lib/uiautomator.js +3 -24
  59. package/build/lib/uiautomator.js.map +1 -1
  60. package/build/lib/unlock-helpers.js +1 -61
  61. package/build/lib/unlock-helpers.js.map +1 -1
  62. package/build/lib/utils.js +1 -7
  63. package/build/lib/utils.js.map +1 -1
  64. package/build/lib/webview-helpers.js +1 -94
  65. package/build/lib/webview-helpers.js.map +1 -1
  66. package/lib/android-helpers.js +2 -1
  67. package/lib/commands/general.js +34 -15
  68. package/package.json +1 -1
@@ -1,24 +1,16 @@
1
1
  "use strict";
2
2
 
3
3
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
-
5
4
  Object.defineProperty(exports, "__esModule", {
6
5
  value: true
7
6
  });
8
7
  exports.default = exports.commands = void 0;
9
-
10
8
  require("source-map-support/register");
11
-
12
9
  var _lodash = _interopRequireDefault(require("lodash"));
13
-
14
10
  var _asyncbox = require("asyncbox");
15
-
16
11
  var _support = require("appium/support");
17
-
18
12
  var _teen_process = require("teen_process");
19
-
20
13
  var _path = _interopRequireDefault(require("path"));
21
-
22
14
  const commands = {};
23
15
  exports.commands = commands;
24
16
  const RETRY_PAUSE = 300;
@@ -31,12 +23,10 @@ const SCREENRECORD_BINARY = 'screenrecord';
31
23
  const DEFAULT_EXT = '.mp4';
32
24
  const MIN_EMULATOR_API_LEVEL = 27;
33
25
  const FFMPEG_BINARY = `ffmpeg${_support.system.isWindows() ? '.exe' : ''}`;
34
-
35
26
  async function uploadRecordedMedia(localFile, remotePath = null, uploadOptions = {}) {
36
27
  if (_lodash.default.isEmpty(remotePath)) {
37
28
  return (await _support.util.toInMemoryBase64(localFile)).toString();
38
29
  }
39
-
40
30
  const {
41
31
  user,
42
32
  pass,
@@ -51,35 +41,28 @@ async function uploadRecordedMedia(localFile, remotePath = null, uploadOptions =
51
41
  fileFieldName,
52
42
  formFields
53
43
  };
54
-
55
44
  if (user && pass) {
56
45
  options.auth = {
57
46
  user,
58
47
  pass
59
48
  };
60
49
  }
61
-
62
50
  await _support.net.uploadFile(localFile, remotePath, options);
63
51
  return '';
64
52
  }
65
-
66
53
  async function verifyScreenRecordIsSupported(adb, isEmulator) {
67
54
  const apiLevel = await adb.getApiLevel();
68
-
69
55
  if (isEmulator && apiLevel < MIN_EMULATOR_API_LEVEL) {
70
56
  throw new Error(`Screen recording does not work on emulators running Android API level less than ${MIN_EMULATOR_API_LEVEL}`);
71
57
  }
72
-
73
58
  if (apiLevel < 19) {
74
59
  throw new Error(`Screen recording not available on API Level ${apiLevel}. Minimum API Level is 19.`);
75
60
  }
76
61
  }
77
-
78
62
  async function scheduleScreenRecord(adb, recordingProperties, log = null) {
79
63
  if (recordingProperties.stopped) {
80
64
  return;
81
65
  }
82
-
83
66
  const {
84
67
  timer,
85
68
  videoSize,
@@ -88,15 +71,12 @@ async function scheduleScreenRecord(adb, recordingProperties, log = null) {
88
71
  bugReport
89
72
  } = recordingProperties;
90
73
  let currentTimeLimit = MAX_RECORDING_TIME_SEC;
91
-
92
74
  if (_support.util.hasValue(recordingProperties.currentTimeLimit)) {
93
75
  const currentTimeLimitInt = parseInt(recordingProperties.currentTimeLimit, 10);
94
-
95
76
  if (!isNaN(currentTimeLimitInt) && currentTimeLimitInt < MAX_RECORDING_TIME_SEC) {
96
77
  currentTimeLimit = currentTimeLimitInt;
97
78
  }
98
79
  }
99
-
100
80
  const pathOnDevice = `/sdcard/${_support.util.uuidV4().substring(0, 8)}${DEFAULT_EXT}`;
101
81
  const recordingProc = adb.screenrecord(pathOnDevice, {
102
82
  videoSize,
@@ -108,20 +88,16 @@ async function scheduleScreenRecord(adb, recordingProperties, log = null) {
108
88
  if (recordingProperties.stopped || !_support.util.hasValue(timeLimit)) {
109
89
  return;
110
90
  }
111
-
112
91
  const currentDuration = timer.getDuration().asSeconds.toFixed(0);
113
92
  log === null || log === void 0 ? void 0 : log.debug(`The overall screen recording duration is ${currentDuration}s so far`);
114
93
  const timeLimitInt = parseInt(timeLimit, 10);
115
-
116
94
  if (isNaN(timeLimitInt) || currentDuration >= timeLimitInt) {
117
95
  log === null || log === void 0 ? void 0 : log.debug('There is no need to start the next recording chunk');
118
96
  return;
119
97
  }
120
-
121
98
  recordingProperties.currentTimeLimit = timeLimitInt - currentDuration;
122
99
  const chunkDuration = recordingProperties.currentTimeLimit < MAX_RECORDING_TIME_SEC ? recordingProperties.currentTimeLimit : MAX_RECORDING_TIME_SEC;
123
100
  log === null || log === void 0 ? void 0 : log.debug(`Starting the next ${chunkDuration}s-chunk ` + `of screen recording in order to achieve ${timeLimitInt}s total duration`);
124
-
125
101
  (async () => {
126
102
  try {
127
103
  await scheduleScreenRecord(adb, recordingProperties, log);
@@ -132,7 +108,6 @@ async function scheduleScreenRecord(adb, recordingProperties, log = null) {
132
108
  })();
133
109
  });
134
110
  await recordingProc.start(0);
135
-
136
111
  try {
137
112
  await (0, _asyncbox.waitForCondition)(async () => await adb.fileExists(pathOnDevice), {
138
113
  waitMs: RETRY_TIMEOUT,
@@ -141,40 +116,30 @@ async function scheduleScreenRecord(adb, recordingProperties, log = null) {
141
116
  } catch (e) {
142
117
  throw new Error(`The expected screen record file '${pathOnDevice}' does not exist after ${RETRY_TIMEOUT}ms. ` + `Is ${SCREENRECORD_BINARY} utility available and operational on the device under test?`);
143
118
  }
144
-
145
119
  recordingProperties.records.push(pathOnDevice);
146
120
  recordingProperties.recordingProcess = recordingProc;
147
121
  }
148
-
149
122
  async function mergeScreenRecords(mediaFiles, log = null) {
150
123
  try {
151
124
  await _support.fs.which(FFMPEG_BINARY);
152
125
  } catch (e) {
153
126
  throw new Error(`${FFMPEG_BINARY} utility is not available in PATH. Please install it from https://www.ffmpeg.org/`);
154
127
  }
155
-
156
128
  const configContent = mediaFiles.map(x => `file '${x}'`).join('\n');
157
-
158
129
  const configFile = _path.default.resolve(_path.default.dirname(mediaFiles[0]), 'config.txt');
159
-
160
130
  await _support.fs.writeFile(configFile, configContent, 'utf8');
161
131
  log === null || log === void 0 ? void 0 : log.debug(`Generated ffmpeg merging config '${configFile}' with items:\n${configContent}`);
162
-
163
132
  const result = _path.default.resolve(_path.default.dirname(mediaFiles[0]), `merge_${Math.floor(new Date())}${DEFAULT_EXT}`);
164
-
165
133
  const args = ['-safe', '0', '-f', 'concat', '-i', configFile, '-c', 'copy', result];
166
134
  log === null || log === void 0 ? void 0 : log.info(`Initiating screen records merging using the command '${FFMPEG_BINARY} ${args.join(' ')}'`);
167
135
  await (0, _teen_process.exec)(FFMPEG_BINARY, args);
168
136
  return result;
169
137
  }
170
-
171
138
  async function terminateBackgroundScreenRecording(adb, force = true) {
172
139
  const pids = (await adb.getPIDsByName(SCREENRECORD_BINARY)).map(p => `${p}`);
173
-
174
140
  if (_lodash.default.isEmpty(pids)) {
175
141
  return false;
176
142
  }
177
-
178
143
  try {
179
144
  await adb.shell(['kill', force ? '-15' : '-2', ...pids]);
180
145
  await (0, _asyncbox.waitForCondition)(async () => _lodash.default.isEmpty(await adb.getPIDsByName(SCREENRECORD_BINARY)), {
@@ -197,29 +162,22 @@ commands.startRecordingScreen = async function startRecordingScreen(options = {}
197
162
  bitRate,
198
163
  forceRestart
199
164
  } = options;
200
-
201
165
  if (!forceRestart) {
202
166
  result = await this.stopRecordingScreen(options);
203
167
  }
204
-
205
168
  if (await terminateBackgroundScreenRecording(this.adb, true)) {
206
169
  this.log.warn(`There were some ${SCREENRECORD_BINARY} process leftovers running ` + `in the background. Make sure you stop screen recording each time after it is started, ` + `otherwise the recorded media might quickly exceed all the free space on the device under test.`);
207
170
  }
208
-
209
171
  if (!_lodash.default.isEmpty(this._screenRecordingProperties)) {
210
172
  for (const record of this._screenRecordingProperties.records || []) {
211
173
  await this.adb.rimraf(record);
212
174
  }
213
-
214
175
  this._screenRecordingProperties = null;
215
176
  }
216
-
217
177
  const timeout = parseFloat(timeLimit);
218
-
219
178
  if (isNaN(timeout) || timeout > MAX_TIME_SEC || timeout <= 0) {
220
179
  throw new Error(`The timeLimit value must be in range [1, ${MAX_TIME_SEC}] seconds. ` + `The value of '${timeLimit}' has been passed instead.`);
221
180
  }
222
-
223
181
  this._screenRecordingProperties = {
224
182
  timer: new _support.timing.Timer().start(),
225
183
  videoSize,
@@ -237,77 +195,61 @@ commands.startRecordingScreen = async function startRecordingScreen(options = {}
237
195
 
238
196
  commands.stopRecordingScreen = async function stopRecordingScreen(options = {}) {
239
197
  await verifyScreenRecordIsSupported(this.adb, this.isEmulator());
240
-
241
198
  if (!_lodash.default.isEmpty(this._screenRecordingProperties)) {
242
199
  this._screenRecordingProperties.stopped = true;
243
200
  }
244
-
245
201
  try {
246
202
  await terminateBackgroundScreenRecording(this.adb, false);
247
203
  } catch (err) {
248
204
  this.log.warn(err.message);
249
-
250
205
  if (!_lodash.default.isEmpty(this._screenRecordingProperties)) {
251
206
  this.log.warn('The resulting video might be corrupted');
252
207
  }
253
208
  }
254
-
255
209
  if (_lodash.default.isEmpty(this._screenRecordingProperties)) {
256
210
  this.log.info(`Screen recording has not been previously started by Appium. There is nothing to stop`);
257
211
  return '';
258
212
  }
259
-
260
213
  if (this._screenRecordingProperties.recordingProcess && this._screenRecordingProperties.recordingProcess.isRunning) {
261
214
  try {
262
215
  await this._screenRecordingProperties.recordingProcess.stop('SIGINT', PROCESS_SHUTDOWN_TIMEOUT);
263
216
  } catch (e) {
264
217
  this.log.errorAndThrow(`Unable to stop screen recording within ${PROCESS_SHUTDOWN_TIMEOUT}ms`);
265
218
  }
266
-
267
219
  this._screenRecordingProperties.recordingProcess = null;
268
220
  }
269
-
270
221
  if (_lodash.default.isEmpty(this._screenRecordingProperties.records)) {
271
222
  this.log.errorAndThrow(`No screen recordings have been stored on the device so far. ` + `Are you sure the ${SCREENRECORD_BINARY} utility works as expected?`);
272
223
  }
273
-
274
224
  const tmpRoot = await _support.tempDir.openDir();
275
-
276
225
  try {
277
226
  const localRecords = [];
278
-
279
227
  for (const pathOnDevice of this._screenRecordingProperties.records) {
280
228
  localRecords.push(_path.default.resolve(tmpRoot, _path.default.posix.basename(pathOnDevice)));
281
229
  await this.adb.pull(pathOnDevice, _lodash.default.last(localRecords));
282
230
  await this.adb.rimraf(pathOnDevice);
283
231
  }
284
-
285
232
  let resultFilePath = _lodash.default.last(localRecords);
286
-
287
233
  if (localRecords.length > 1) {
288
234
  this.log.info(`Got ${localRecords.length} screen recordings. Trying to merge them`);
289
-
290
235
  try {
291
236
  resultFilePath = await mergeScreenRecords(localRecords, this.log);
292
237
  } catch (e) {
293
238
  this.log.warn(`Cannot merge the recorded files. The most recent screen recording is going to be returned as the result. ` + `Original error: ${e.message}`);
294
239
  }
295
240
  }
296
-
297
241
  if (_lodash.default.isEmpty(options.remotePath)) {
298
242
  const {
299
243
  size
300
244
  } = await _support.fs.stat(resultFilePath);
301
245
  this.log.debug(`The size of the resulting screen recording is ${_support.util.toReadableSizeString(size)}`);
302
246
  }
303
-
304
247
  return await uploadRecordedMedia(resultFilePath, options.remotePath, options);
305
248
  } finally {
306
249
  await _support.fs.rimraf(tmpRoot);
307
250
  this._screenRecordingProperties = null;
308
251
  }
309
252
  };
310
-
311
253
  var _default = commands;
312
254
  exports.default = _default;
313
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJjb21tYW5kcyIsIlJFVFJZX1BBVVNFIiwiUkVUUllfVElNRU9VVCIsIk1BWF9SRUNPUkRJTkdfVElNRV9TRUMiLCJNQVhfVElNRV9TRUMiLCJERUZBVUxUX1JFQ09SRElOR19USU1FX1NFQyIsIlBST0NFU1NfU0hVVERPV05fVElNRU9VVCIsIlNDUkVFTlJFQ09SRF9CSU5BUlkiLCJERUZBVUxUX0VYVCIsIk1JTl9FTVVMQVRPUl9BUElfTEVWRUwiLCJGRk1QRUdfQklOQVJZIiwic3lzdGVtIiwiaXNXaW5kb3dzIiwidXBsb2FkUmVjb3JkZWRNZWRpYSIsImxvY2FsRmlsZSIsInJlbW90ZVBhdGgiLCJ1cGxvYWRPcHRpb25zIiwiXyIsImlzRW1wdHkiLCJ1dGlsIiwidG9Jbk1lbW9yeUJhc2U2NCIsInRvU3RyaW5nIiwidXNlciIsInBhc3MiLCJtZXRob2QiLCJoZWFkZXJzIiwiZmlsZUZpZWxkTmFtZSIsImZvcm1GaWVsZHMiLCJvcHRpb25zIiwiYXV0aCIsIm5ldCIsInVwbG9hZEZpbGUiLCJ2ZXJpZnlTY3JlZW5SZWNvcmRJc1N1cHBvcnRlZCIsImFkYiIsImlzRW11bGF0b3IiLCJhcGlMZXZlbCIsImdldEFwaUxldmVsIiwiRXJyb3IiLCJzY2hlZHVsZVNjcmVlblJlY29yZCIsInJlY29yZGluZ1Byb3BlcnRpZXMiLCJsb2ciLCJzdG9wcGVkIiwidGltZXIiLCJ2aWRlb1NpemUiLCJiaXRSYXRlIiwidGltZUxpbWl0IiwiYnVnUmVwb3J0IiwiY3VycmVudFRpbWVMaW1pdCIsImhhc1ZhbHVlIiwiY3VycmVudFRpbWVMaW1pdEludCIsInBhcnNlSW50IiwiaXNOYU4iLCJwYXRoT25EZXZpY2UiLCJ1dWlkVjQiLCJzdWJzdHJpbmciLCJyZWNvcmRpbmdQcm9jIiwic2NyZWVucmVjb3JkIiwib24iLCJjdXJyZW50RHVyYXRpb24iLCJnZXREdXJhdGlvbiIsImFzU2Vjb25kcyIsInRvRml4ZWQiLCJkZWJ1ZyIsInRpbWVMaW1pdEludCIsImNodW5rRHVyYXRpb24iLCJlIiwiZXJyb3IiLCJzdGFjayIsInN0YXJ0Iiwid2FpdEZvckNvbmRpdGlvbiIsImZpbGVFeGlzdHMiLCJ3YWl0TXMiLCJpbnRlcnZhbE1zIiwicmVjb3JkcyIsInB1c2giLCJyZWNvcmRpbmdQcm9jZXNzIiwibWVyZ2VTY3JlZW5SZWNvcmRzIiwibWVkaWFGaWxlcyIsImZzIiwid2hpY2giLCJjb25maWdDb250ZW50IiwibWFwIiwieCIsImpvaW4iLCJjb25maWdGaWxlIiwicGF0aCIsInJlc29sdmUiLCJkaXJuYW1lIiwid3JpdGVGaWxlIiwicmVzdWx0IiwiTWF0aCIsImZsb29yIiwiRGF0ZSIsImFyZ3MiLCJpbmZvIiwiZXhlYyIsInRlcm1pbmF0ZUJhY2tncm91bmRTY3JlZW5SZWNvcmRpbmciLCJmb3JjZSIsInBpZHMiLCJnZXRQSURzQnlOYW1lIiwicCIsInNoZWxsIiwiZXJyIiwibWVzc2FnZSIsInN0YXJ0UmVjb3JkaW5nU2NyZWVuIiwiZm9yY2VSZXN0YXJ0Iiwic3RvcFJlY29yZGluZ1NjcmVlbiIsIndhcm4iLCJfc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcyIsInJlY29yZCIsInJpbXJhZiIsInRpbWVvdXQiLCJwYXJzZUZsb2F0IiwidGltaW5nIiwiVGltZXIiLCJpc1J1bm5pbmciLCJzdG9wIiwiZXJyb3JBbmRUaHJvdyIsInRtcFJvb3QiLCJ0ZW1wRGlyIiwib3BlbkRpciIsImxvY2FsUmVjb3JkcyIsInBvc2l4IiwiYmFzZW5hbWUiLCJwdWxsIiwibGFzdCIsInJlc3VsdEZpbGVQYXRoIiwibGVuZ3RoIiwic2l6ZSIsInN0YXQiLCJ0b1JlYWRhYmxlU2l6ZVN0cmluZyJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2xpYi9jb21tYW5kcy9yZWNvcmRzY3JlZW4uanMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7IHdhaXRGb3JDb25kaXRpb24gfSBmcm9tICdhc3luY2JveCc7XG5pbXBvcnQgeyB1dGlsLCBmcywgbmV0LCB0ZW1wRGlyLCBzeXN0ZW0sIHRpbWluZyB9IGZyb20gJ2FwcGl1bS9zdXBwb3J0JztcbmltcG9ydCB7IGV4ZWMgfSBmcm9tICd0ZWVuX3Byb2Nlc3MnO1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5cblxuY29uc3QgY29tbWFuZHMgPSB7fTtcblxuY29uc3QgUkVUUllfUEFVU0UgPSAzMDA7XG5jb25zdCBSRVRSWV9USU1FT1VUID0gNTAwMDtcbmNvbnN0IE1BWF9SRUNPUkRJTkdfVElNRV9TRUMgPSA2MCAqIDM7XG5jb25zdCBNQVhfVElNRV9TRUMgPSA2MCAqIDMwO1xuY29uc3QgREVGQVVMVF9SRUNPUkRJTkdfVElNRV9TRUMgPSBNQVhfUkVDT1JESU5HX1RJTUVfU0VDO1xuY29uc3QgUFJPQ0VTU19TSFVURE9XTl9USU1FT1VUID0gMTAgKiAxMDAwO1xuY29uc3QgU0NSRUVOUkVDT1JEX0JJTkFSWSA9ICdzY3JlZW5yZWNvcmQnO1xuY29uc3QgREVGQVVMVF9FWFQgPSAnLm1wNCc7XG5jb25zdCBNSU5fRU1VTEFUT1JfQVBJX0xFVkVMID0gMjc7XG5jb25zdCBGRk1QRUdfQklOQVJZID0gYGZmbXBlZyR7c3lzdGVtLmlzV2luZG93cygpID8gJy5leGUnIDogJyd9YDtcblxuYXN5bmMgZnVuY3Rpb24gdXBsb2FkUmVjb3JkZWRNZWRpYSAobG9jYWxGaWxlLCByZW1vdGVQYXRoID0gbnVsbCwgdXBsb2FkT3B0aW9ucyA9IHt9KSB7XG4gIGlmIChfLmlzRW1wdHkocmVtb3RlUGF0aCkpIHtcbiAgICByZXR1cm4gKGF3YWl0IHV0aWwudG9Jbk1lbW9yeUJhc2U2NChsb2NhbEZpbGUpKS50b1N0cmluZygpO1xuICB9XG5cbiAgY29uc3Qge3VzZXIsIHBhc3MsIG1ldGhvZCwgaGVhZGVycywgZmlsZUZpZWxkTmFtZSwgZm9ybUZpZWxkc30gPSB1cGxvYWRPcHRpb25zO1xuICBjb25zdCBvcHRpb25zID0ge1xuICAgIG1ldGhvZDogbWV0aG9kIHx8ICdQVVQnLFxuICAgIGhlYWRlcnMsXG4gICAgZmlsZUZpZWxkTmFtZSxcbiAgICBmb3JtRmllbGRzLFxuICB9O1xuICBpZiAodXNlciAmJiBwYXNzKSB7XG4gICAgb3B0aW9ucy5hdXRoID0ge3VzZXIsIHBhc3N9O1xuICB9XG4gIGF3YWl0IG5ldC51cGxvYWRGaWxlKGxvY2FsRmlsZSwgcmVtb3RlUGF0aCwgb3B0aW9ucyk7XG4gIHJldHVybiAnJztcbn1cblxuYXN5bmMgZnVuY3Rpb24gdmVyaWZ5U2NyZWVuUmVjb3JkSXNTdXBwb3J0ZWQgKGFkYiwgaXNFbXVsYXRvcikge1xuICBjb25zdCBhcGlMZXZlbCA9IGF3YWl0IGFkYi5nZXRBcGlMZXZlbCgpO1xuICBpZiAoaXNFbXVsYXRvciAmJiBhcGlMZXZlbCA8IE1JTl9FTVVMQVRPUl9BUElfTEVWRUwpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFNjcmVlbiByZWNvcmRpbmcgZG9lcyBub3Qgd29yayBvbiBlbXVsYXRvcnMgcnVubmluZyBBbmRyb2lkIEFQSSBsZXZlbCBsZXNzIHRoYW4gJHtNSU5fRU1VTEFUT1JfQVBJX0xFVkVMfWApO1xuICB9XG4gIGlmIChhcGlMZXZlbCA8IDE5KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBTY3JlZW4gcmVjb3JkaW5nIG5vdCBhdmFpbGFibGUgb24gQVBJIExldmVsICR7YXBpTGV2ZWx9LiBNaW5pbXVtIEFQSSBMZXZlbCBpcyAxOS5gKTtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBzY2hlZHVsZVNjcmVlblJlY29yZCAoYWRiLCByZWNvcmRpbmdQcm9wZXJ0aWVzLCBsb2cgPSBudWxsKSB7XG4gIGlmIChyZWNvcmRpbmdQcm9wZXJ0aWVzLnN0b3BwZWQpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCB7XG4gICAgdGltZXIsXG4gICAgdmlkZW9TaXplLFxuICAgIGJpdFJhdGUsXG4gICAgdGltZUxpbWl0LFxuICAgIGJ1Z1JlcG9ydCxcbiAgfSA9IHJlY29yZGluZ1Byb3BlcnRpZXM7XG5cbiAgbGV0IGN1cnJlbnRUaW1lTGltaXQgPSBNQVhfUkVDT1JESU5HX1RJTUVfU0VDO1xuICBpZiAodXRpbC5oYXNWYWx1ZShyZWNvcmRpbmdQcm9wZXJ0aWVzLmN1cnJlbnRUaW1lTGltaXQpKSB7XG4gICAgY29uc3QgY3VycmVudFRpbWVMaW1pdEludCA9IHBhcnNlSW50KHJlY29yZGluZ1Byb3BlcnRpZXMuY3VycmVudFRpbWVMaW1pdCwgMTApO1xuICAgIGlmICghaXNOYU4oY3VycmVudFRpbWVMaW1pdEludCkgJiYgY3VycmVudFRpbWVMaW1pdEludCA8IE1BWF9SRUNPUkRJTkdfVElNRV9TRUMpIHtcbiAgICAgIGN1cnJlbnRUaW1lTGltaXQgPSBjdXJyZW50VGltZUxpbWl0SW50O1xuICAgIH1cbiAgfVxuICBjb25zdCBwYXRoT25EZXZpY2UgPSBgL3NkY2FyZC8ke3V0aWwudXVpZFY0KCkuc3Vic3RyaW5nKDAsIDgpfSR7REVGQVVMVF9FWFR9YDtcbiAgY29uc3QgcmVjb3JkaW5nUHJvYyA9IGFkYi5zY3JlZW5yZWNvcmQocGF0aE9uRGV2aWNlLCB7XG4gICAgdmlkZW9TaXplLFxuICAgIGJpdFJhdGUsXG4gICAgdGltZUxpbWl0OiBjdXJyZW50VGltZUxpbWl0LFxuICAgIGJ1Z1JlcG9ydCxcbiAgfSk7XG5cbiAgcmVjb3JkaW5nUHJvYy5vbignZW5kJywgKCkgPT4ge1xuICAgIGlmIChyZWNvcmRpbmdQcm9wZXJ0aWVzLnN0b3BwZWQgfHwgIXV0aWwuaGFzVmFsdWUodGltZUxpbWl0KSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBjdXJyZW50RHVyYXRpb24gPSB0aW1lci5nZXREdXJhdGlvbigpLmFzU2Vjb25kcy50b0ZpeGVkKDApO1xuICAgIGxvZz8uZGVidWcoYFRoZSBvdmVyYWxsIHNjcmVlbiByZWNvcmRpbmcgZHVyYXRpb24gaXMgJHtjdXJyZW50RHVyYXRpb259cyBzbyBmYXJgKTtcbiAgICBjb25zdCB0aW1lTGltaXRJbnQgPSBwYXJzZUludCh0aW1lTGltaXQsIDEwKTtcbiAgICBpZiAoaXNOYU4odGltZUxpbWl0SW50KSB8fCBjdXJyZW50RHVyYXRpb24gPj0gdGltZUxpbWl0SW50KSB7XG4gICAgICBsb2c/LmRlYnVnKCdUaGVyZSBpcyBubyBuZWVkIHRvIHN0YXJ0IHRoZSBuZXh0IHJlY29yZGluZyBjaHVuaycpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHJlY29yZGluZ1Byb3BlcnRpZXMuY3VycmVudFRpbWVMaW1pdCA9IHRpbWVMaW1pdEludCAtIGN1cnJlbnREdXJhdGlvbjtcbiAgICBjb25zdCBjaHVua0R1cmF0aW9uID0gcmVjb3JkaW5nUHJvcGVydGllcy5jdXJyZW50VGltZUxpbWl0IDwgTUFYX1JFQ09SRElOR19USU1FX1NFQ1xuICAgICAgPyByZWNvcmRpbmdQcm9wZXJ0aWVzLmN1cnJlbnRUaW1lTGltaXRcbiAgICAgIDogTUFYX1JFQ09SRElOR19USU1FX1NFQztcbiAgICBsb2c/LmRlYnVnKGBTdGFydGluZyB0aGUgbmV4dCAke2NodW5rRHVyYXRpb259cy1jaHVuayBgICtcbiAgICAgIGBvZiBzY3JlZW4gcmVjb3JkaW5nIGluIG9yZGVyIHRvIGFjaGlldmUgJHt0aW1lTGltaXRJbnR9cyB0b3RhbCBkdXJhdGlvbmApO1xuICAgIChhc3luYyAoKSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBzY2hlZHVsZVNjcmVlblJlY29yZChhZGIsIHJlY29yZGluZ1Byb3BlcnRpZXMsIGxvZyk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGxvZz8uZXJyb3IoZS5zdGFjayk7XG4gICAgICAgIHJlY29yZGluZ1Byb3BlcnRpZXMuc3RvcHBlZCA9IHRydWU7XG4gICAgICB9XG4gICAgfSkoKTtcbiAgfSk7XG5cbiAgYXdhaXQgcmVjb3JkaW5nUHJvYy5zdGFydCgwKTtcbiAgdHJ5IHtcbiAgICBhd2FpdCB3YWl0Rm9yQ29uZGl0aW9uKGFzeW5jICgpID0+IGF3YWl0IGFkYi5maWxlRXhpc3RzKHBhdGhPbkRldmljZSksXG4gICAgICB7d2FpdE1zOiBSRVRSWV9USU1FT1VULCBpbnRlcnZhbE1zOiBSRVRSWV9QQVVTRX0pO1xuICB9IGNhdGNoIChlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBUaGUgZXhwZWN0ZWQgc2NyZWVuIHJlY29yZCBmaWxlICcke3BhdGhPbkRldmljZX0nIGRvZXMgbm90IGV4aXN0IGFmdGVyICR7UkVUUllfVElNRU9VVH1tcy4gYCArXG4gICAgICBgSXMgJHtTQ1JFRU5SRUNPUkRfQklOQVJZfSB1dGlsaXR5IGF2YWlsYWJsZSBhbmQgb3BlcmF0aW9uYWwgb24gdGhlIGRldmljZSB1bmRlciB0ZXN0P2ApO1xuICB9XG5cbiAgcmVjb3JkaW5nUHJvcGVydGllcy5yZWNvcmRzLnB1c2gocGF0aE9uRGV2aWNlKTtcbiAgcmVjb3JkaW5nUHJvcGVydGllcy5yZWNvcmRpbmdQcm9jZXNzID0gcmVjb3JkaW5nUHJvYztcbn1cblxuYXN5bmMgZnVuY3Rpb24gbWVyZ2VTY3JlZW5SZWNvcmRzIChtZWRpYUZpbGVzLCBsb2cgPSBudWxsKSB7XG4gIHRyeSB7XG4gICAgYXdhaXQgZnMud2hpY2goRkZNUEVHX0JJTkFSWSk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCR7RkZNUEVHX0JJTkFSWX0gdXRpbGl0eSBpcyBub3QgYXZhaWxhYmxlIGluIFBBVEguIFBsZWFzZSBpbnN0YWxsIGl0IGZyb20gaHR0cHM6Ly93d3cuZmZtcGVnLm9yZy9gKTtcbiAgfVxuICBjb25zdCBjb25maWdDb250ZW50ID0gbWVkaWFGaWxlc1xuICAgIC5tYXAoKHgpID0+IGBmaWxlICcke3h9J2ApXG4gICAgLmpvaW4oJ1xcbicpO1xuICBjb25zdCBjb25maWdGaWxlID0gcGF0aC5yZXNvbHZlKHBhdGguZGlybmFtZShtZWRpYUZpbGVzWzBdKSwgJ2NvbmZpZy50eHQnKTtcbiAgYXdhaXQgZnMud3JpdGVGaWxlKGNvbmZpZ0ZpbGUsIGNvbmZpZ0NvbnRlbnQsICd1dGY4Jyk7XG4gIGxvZz8uZGVidWcoYEdlbmVyYXRlZCBmZm1wZWcgbWVyZ2luZyBjb25maWcgJyR7Y29uZmlnRmlsZX0nIHdpdGggaXRlbXM6XFxuJHtjb25maWdDb250ZW50fWApO1xuICBjb25zdCByZXN1bHQgPSBwYXRoLnJlc29sdmUocGF0aC5kaXJuYW1lKG1lZGlhRmlsZXNbMF0pLCBgbWVyZ2VfJHtNYXRoLmZsb29yKG5ldyBEYXRlKCkpfSR7REVGQVVMVF9FWFR9YCk7XG4gIGNvbnN0IGFyZ3MgPSBbJy1zYWZlJywgJzAnLCAnLWYnLCAnY29uY2F0JywgJy1pJywgY29uZmlnRmlsZSwgJy1jJywgJ2NvcHknLCByZXN1bHRdO1xuICBsb2c/LmluZm8oYEluaXRpYXRpbmcgc2NyZWVuIHJlY29yZHMgbWVyZ2luZyB1c2luZyB0aGUgY29tbWFuZCAnJHtGRk1QRUdfQklOQVJZfSAke2FyZ3Muam9pbignICcpfSdgKTtcbiAgYXdhaXQgZXhlYyhGRk1QRUdfQklOQVJZLCBhcmdzKTtcbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuYXN5bmMgZnVuY3Rpb24gdGVybWluYXRlQmFja2dyb3VuZFNjcmVlblJlY29yZGluZyAoYWRiLCBmb3JjZSA9IHRydWUpIHtcbiAgY29uc3QgcGlkcyA9IChhd2FpdCBhZGIuZ2V0UElEc0J5TmFtZShTQ1JFRU5SRUNPUkRfQklOQVJZKSlcbiAgICAubWFwKChwKSA9PiBgJHtwfWApO1xuICBpZiAoXy5pc0VtcHR5KHBpZHMpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBhd2FpdCBhZGIuc2hlbGwoWydraWxsJywgZm9yY2UgPyAnLTE1JyA6ICctMicsIC4uLnBpZHNdKTtcbiAgICBhd2FpdCB3YWl0Rm9yQ29uZGl0aW9uKGFzeW5jICgpID0+IF8uaXNFbXB0eShhd2FpdCBhZGIuZ2V0UElEc0J5TmFtZShTQ1JFRU5SRUNPUkRfQklOQVJZKSksIHtcbiAgICAgIHdhaXRNczogUFJPQ0VTU19TSFVURE9XTl9USU1FT1VULFxuICAgICAgaW50ZXJ2YWxNczogNTAwLFxuICAgIH0pO1xuICAgIHJldHVybiB0cnVlO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFVuYWJsZSB0byBzdG9wIHRoZSBiYWNrZ3JvdW5kIHNjcmVlbiByZWNvcmRpbmc6ICR7ZXJyLm1lc3NhZ2V9YCk7XG4gIH1cbn1cblxuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IFN0YXJ0UmVjb3JkaW5nT3B0aW9uc1xuICpcbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gcmVtb3RlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSByZW1vdGUgbG9jYXRpb24sIHdoZXJlIHRoZSBjYXB0dXJlZCB2aWRlbyBzaG91bGQgYmUgdXBsb2FkZWQuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaGUgZm9sbG93aW5nIHByb3RvY29scyBhcmUgc3VwcG9ydGVkOiBodHRwL2h0dHBzLCBmdHAuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOdWxsIG9yIGVtcHR5IHN0cmluZyB2YWx1ZSAodGhlIGRlZmF1bHQgc2V0dGluZykgbWVhbnMgdGhlIGNvbnRlbnQgb2YgcmVzdWx0aW5nXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlIHNob3VsZCBiZSBlbmNvZGVkIGFzIEJhc2U2NCBhbmQgcGFzc2VkIGFzIHRoZSBlbmRwb3VudCByZXNwb25zZSB2YWx1ZS5cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFuIGV4Y2VwdGlvbiB3aWxsIGJlIHRocm93biBpZiB0aGUgZ2VuZXJhdGVkIG1lZGlhIGZpbGUgaXMgdG9vIGJpZyB0b1xuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZml0IGludG8gdGhlIGF2YWlsYWJsZSBwcm9jZXNzIG1lbW9yeS5cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRoaXMgb3B0aW9uIG9ubHkgaGFzIGFuIGVmZmVjdCBpZiB0aGVyZSBpcyBzY3JlZW4gcmVjb3JkaW5nIHByb2Nlc3MgaW4gcHJvZ3JlZXNzXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbmQgYGZvcmNlUmVzdGFydGAgcGFyYW1ldGVyIGlzIG5vdCBzZXQgdG8gYHRydWVgLlxuICogQHByb3BlcnR5IHs/c3RyaW5nfSB1c2VyIC0gVGhlIG5hbWUgb2YgdGhlIHVzZXIgZm9yIHRoZSByZW1vdGUgYXV0aGVudGljYXRpb24uIE9ubHkgd29ya3MgaWYgYHJlbW90ZVBhdGhgIGlzIHByb3ZpZGVkLlxuICogQHByb3BlcnR5IHs/c3RyaW5nfSBwYXNzIC0gVGhlIHBhc3N3b3JkIGZvciB0aGUgcmVtb3RlIGF1dGhlbnRpY2F0aW9uLiBPbmx5IHdvcmtzIGlmIGByZW1vdGVQYXRoYCBpcyBwcm92aWRlZC5cbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gbWV0aG9kIFtQVVRdIC0gVGhlIGh0dHAgbXVsdGlwYXJ0IHVwbG9hZCBtZXRob2QgbmFtZS4gT25seSB3b3JrcyBpZiBgcmVtb3RlUGF0aGAgaXMgcHJvdmlkZWQuXG4gKiBAcHJvcGVydHkgez9PYmplY3R9IGhlYWRlcnMgLSBBZGRpdGlvbmFsIGhlYWRlcnMgbWFwcGluZyBmb3IgbXVsdGlwYXJ0IGh0dHAocykgdXBsb2Fkc1xuICogQHByb3BlcnR5IHs/c3RyaW5nfSBmaWxlRmllbGROYW1lIFtmaWxlXSAtIFRoZSBuYW1lIG9mIHRoZSBmb3JtIGZpZWxkLCB3aGVyZSB0aGUgZmlsZSBjb250ZW50IEJMT0Igc2hvdWxkIGJlIHN0b3JlZCBmb3JcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBodHRwKHMpIHVwbG9hZHNcbiAqIEBwcm9wZXJ0eSB7P09iamVjdHxBcnJheTxQYWlyPn0gZm9ybUZpZWxkcyAtIEFkZGl0aW9uYWwgZm9ybSBmaWVsZHMgZm9yIG11bHRpcGFydCBodHRwKHMpIHVwbG9hZHNcbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gdmlkZW9TaXplIC0gVGhlIGZvcm1hdCBpcyB3aWR0aHhoZWlnaHQuXG4gKiAgICAgICAgICAgICAgICAgIFRoZSBkZWZhdWx0IHZhbHVlIGlzIHRoZSBkZXZpY2UncyBuYXRpdmUgZGlzcGxheSByZXNvbHV0aW9uIChpZiBzdXBwb3J0ZWQpLFxuICogICAgICAgICAgICAgICAgICAxMjgweDcyMCBpZiBub3QuIEZvciBiZXN0IHJlc3VsdHMsXG4gKiAgICAgICAgICAgICAgICAgIHVzZSBhIHNpemUgc3VwcG9ydGVkIGJ5IHlvdXIgZGV2aWNlJ3MgQWR2YW5jZWQgVmlkZW8gQ29kaW5nIChBVkMpIGVuY29kZXIuXG4gKiAgICAgICAgICAgICAgICAgIEZvciBleGFtcGxlLCBcIjEyODB4NzIwXCJcbiAqIEBwcm9wZXJ0eSB7P2Jvb2xlYW59IGJ1Z1JlcG9ydCAtIFNldCBpdCB0byBgdHJ1ZWAgaW4gb3JkZXIgdG8gZGlzcGxheSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIG9uIHRoZSB2aWRlbyBvdmVybGF5LFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VjaCBhcyBhIHRpbWVzdGFtcCwgdGhhdCBpcyBoZWxwZnVsIGluIHZpZGVvcyBjYXB0dXJlZCB0byBpbGx1c3RyYXRlIGJ1Z3MuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaGlzIG9wdGlvbiBpcyBvbmx5IHN1cHBvcnRlZCBzaW5jZSBBUEkgbGV2ZWwgMjcgKEFuZHJvaWQgUCkuXG4gKiBAcHJvcGVydHkgez9zdHJpbmd8bnVtYmVyfSB0aW1lTGltaXQgLSBUaGUgbWF4aW11bSByZWNvcmRpbmcgdGltZSwgaW4gc2Vjb25kcy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgMTgwICgzIG1pbnV0ZXMpLlxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGhlIG1heGltdW0gdmFsdWUgaXMgMTgwMCAoMzAgbWludXRlcykuIElmIHRoZSBwYXNzZWQgdmFsdWUgaXMgZ3JlYXRlciB0aGFuIDE4MCB0aGVuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgYWxnb3JpdGhtIHdpbGwgdHJ5IHRvIHNjaGVkdWxlIG11bHRpcGxlIHNjcmVlbiByZWNvcmRpbmcgY2h1bmtzIGFuZCBtZXJnZSB0aGVcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdGluZyB2aWRlb3MgaW50byBhIHNpbmdsZSBtZWRpYSBmaWxlIHVzaW5nIGBmZm1wZWdgIHV0aWxpdHkuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJZiB0aGUgdXRpbGl0eSBpcyBub3QgYXZhaWxhYmxlIGluIFBBVEggdGhlbiB0aGUgbW9zdCByZWNlbnQgc2NyZWVuIHJlY29yZGluZyBjaHVuayBpc1xuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ29pbmcgdG8gYmUgcmV0dXJuZWQuXG4gKiBAcHJvcGVydHkgez9zdHJpbmd8bnVtYmVyfSBiaXRSYXRlIC0gVGhlIHZpZGVvIGJpdCByYXRlIGZvciB0aGUgdmlkZW8sIGluIGJpdHMgcGVyIHNlY29uZC5cbiAqICAgICAgICAgICAgICAgIFRoZSBkZWZhdWx0IHZhbHVlIGlzIDQwMDAwMDAgKDQgTWJpdC9zKS4gWW91IGNhbiBpbmNyZWFzZSB0aGUgYml0IHJhdGUgdG8gaW1wcm92ZSB2aWRlbyBxdWFsaXR5LFxuICogICAgICAgICAgICAgICAgYnV0IGRvaW5nIHNvIHJlc3VsdHMgaW4gbGFyZ2VyIG1vdmllIGZpbGVzLlxuICogQHByb3BlcnR5IHs/Ym9vbGVhbn0gZm9yY2VSZXN0YXJ0IC0gV2hldGhlciB0byB0cnkgdG8gY2F0Y2ggYW5kIHVwbG9hZC9yZXR1cm4gdGhlIGN1cnJlbnRseSBydW5uaW5nIHNjcmVlbiByZWNvcmRpbmdcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChgZmFsc2VgLCB0aGUgZGVmYXVsdCBzZXR0aW5nKSBvciBpZ25vcmUgdGhlIHJlc3VsdCBvZiBpdCBhbmQgc3RhcnQgYSBuZXcgcmVjb3JkaW5nXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbW1lZGlhdGVseSAoYHRydWVgKS5cbiAqL1xuXG4vKipcbiAqIFJlY29yZCB0aGUgZGlzcGxheSBvZiBhIHJlYWwgZGV2aWNlcyBydW5uaW5nIEFuZHJvaWQgNC40IChBUEkgbGV2ZWwgMTkpIGFuZCBoaWdoZXIuXG4gKiBFbXVsYXRvcnMgYXJlIHN1cHBvcnRlZCBzaW5jZSBBUEkgbGV2ZWwgMjcgKEFuZHJvaWQgUCkuXG4gKiBJdCByZWNvcmRzIHNjcmVlbiBhY3Rpdml0eSB0byBhbiBNUEVHLTQgZmlsZS4gQXVkaW8gaXMgbm90IHJlY29yZGVkIHdpdGggdGhlIHZpZGVvIGZpbGUuXG4gKiBJZiBzY3JlZW4gcmVjb3JkaW5nIGhhcyBiZWVuIGFscmVhZHkgc3RhcnRlZCB0aGVuIHRoZSBjb21tYW5kIHdpbGwgc3RvcCBpdCBmb3JjZWZ1bGx5IGFuZCBzdGFydCBhIG5ldyBvbmUuXG4gKiBUaGUgcHJldmlvdXNseSByZWNvcmRlZCB2aWRlbyBmaWxlIHdpbGwgYmUgZGVsZXRlZC5cbiAqXG4gKiBAcGFyYW0gez9TdGFydFJlY29yZGluZ09wdGlvbnN9IG9wdGlvbnMgLSBUaGUgYXZhaWxhYmxlIG9wdGlvbnMuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBCYXNlNjQtZW5jb2RlZCBjb250ZW50IG9mIHRoZSByZWNvcmRlZCBtZWRpYSBmaWxlIGlmXG4gKiAgICAgICAgICAgICAgICAgICBhbnkgc2NyZWVuIHJlY29yZGluZyBpcyBjdXJyZW50bHkgcnVubmluZyBvciBhbiBlbXB0eSBzdHJpbmcuXG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgc2NyZWVuIHJlY29yZGluZyBoYXMgZmFpbGVkIHRvIHN0YXJ0IG9yIGlzIG5vdCBzdXBwb3J0ZWQgb24gdGhlIGRldmljZSB1bmRlciB0ZXN0LlxuICovXG5jb21tYW5kcy5zdGFydFJlY29yZGluZ1NjcmVlbiA9IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0UmVjb3JkaW5nU2NyZWVuIChvcHRpb25zID0ge30pIHtcbiAgYXdhaXQgdmVyaWZ5U2NyZWVuUmVjb3JkSXNTdXBwb3J0ZWQodGhpcy5hZGIsIHRoaXMuaXNFbXVsYXRvcigpKTtcblxuICBsZXQgcmVzdWx0ID0gJyc7XG4gIGNvbnN0IHt2aWRlb1NpemUsIHRpbWVMaW1pdCA9IERFRkFVTFRfUkVDT1JESU5HX1RJTUVfU0VDLCBidWdSZXBvcnQsIGJpdFJhdGUsIGZvcmNlUmVzdGFydH0gPSBvcHRpb25zO1xuICBpZiAoIWZvcmNlUmVzdGFydCkge1xuICAgIHJlc3VsdCA9IGF3YWl0IHRoaXMuc3RvcFJlY29yZGluZ1NjcmVlbihvcHRpb25zKTtcbiAgfVxuXG4gIGlmIChhd2FpdCB0ZXJtaW5hdGVCYWNrZ3JvdW5kU2NyZWVuUmVjb3JkaW5nKHRoaXMuYWRiLCB0cnVlKSkge1xuICAgIHRoaXMubG9nLndhcm4oYFRoZXJlIHdlcmUgc29tZSAke1NDUkVFTlJFQ09SRF9CSU5BUll9IHByb2Nlc3MgbGVmdG92ZXJzIHJ1bm5pbmcgYCArXG4gICAgICBgaW4gdGhlIGJhY2tncm91bmQuIE1ha2Ugc3VyZSB5b3Ugc3RvcCBzY3JlZW4gcmVjb3JkaW5nIGVhY2ggdGltZSBhZnRlciBpdCBpcyBzdGFydGVkLCBgICtcbiAgICAgIGBvdGhlcndpc2UgdGhlIHJlY29yZGVkIG1lZGlhIG1pZ2h0IHF1aWNrbHkgZXhjZWVkIGFsbCB0aGUgZnJlZSBzcGFjZSBvbiB0aGUgZGV2aWNlIHVuZGVyIHRlc3QuYCk7XG4gIH1cblxuICBpZiAoIV8uaXNFbXB0eSh0aGlzLl9zY3JlZW5SZWNvcmRpbmdQcm9wZXJ0aWVzKSkge1xuICAgIGZvciAoY29uc3QgcmVjb3JkIG9mICh0aGlzLl9zY3JlZW5SZWNvcmRpbmdQcm9wZXJ0aWVzLnJlY29yZHMgfHwgW10pKSB7XG4gICAgICBhd2FpdCB0aGlzLmFkYi5yaW1yYWYocmVjb3JkKTtcbiAgICB9XG4gICAgdGhpcy5fc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcyA9IG51bGw7XG4gIH1cblxuICBjb25zdCB0aW1lb3V0ID0gcGFyc2VGbG9hdCh0aW1lTGltaXQpO1xuICBpZiAoaXNOYU4odGltZW91dCkgfHwgdGltZW91dCA+IE1BWF9USU1FX1NFQyB8fCB0aW1lb3V0IDw9IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFRoZSB0aW1lTGltaXQgdmFsdWUgbXVzdCBiZSBpbiByYW5nZSBbMSwgJHtNQVhfVElNRV9TRUN9XSBzZWNvbmRzLiBgICtcbiAgICAgIGBUaGUgdmFsdWUgb2YgJyR7dGltZUxpbWl0fScgaGFzIGJlZW4gcGFzc2VkIGluc3RlYWQuYCk7XG4gIH1cblxuICB0aGlzLl9zY3JlZW5SZWNvcmRpbmdQcm9wZXJ0aWVzID0ge1xuICAgIHRpbWVyOiBuZXcgdGltaW5nLlRpbWVyKCkuc3RhcnQoKSxcbiAgICB2aWRlb1NpemUsXG4gICAgdGltZUxpbWl0LFxuICAgIGN1cnJlbnRUaW1lTGltaXQ6IHRpbWVMaW1pdCxcbiAgICBiaXRSYXRlLFxuICAgIGJ1Z1JlcG9ydCxcbiAgICByZWNvcmRzOiBbXSxcbiAgICByZWNvcmRpbmdQcm9jZXNzOiBudWxsLFxuICAgIHN0b3BwZWQ6IGZhbHNlLFxuICB9O1xuICBhd2FpdCBzY2hlZHVsZVNjcmVlblJlY29yZCh0aGlzLmFkYiwgdGhpcy5fc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcywgdGhpcy5sb2cpO1xuICByZXR1cm4gcmVzdWx0O1xufTtcblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBTdG9wUmVjb3JkaW5nT3B0aW9uc1xuICpcbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gcmVtb3RlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSByZW1vdGUgbG9jYXRpb24sIHdoZXJlIHRoZSByZXN1bHRpbmcgdmlkZW8gc2hvdWxkIGJlIHVwbG9hZGVkLlxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGhlIGZvbGxvd2luZyBwcm90b2NvbHMgYXJlIHN1cHBvcnRlZDogaHR0cC9odHRwcywgZnRwLlxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTnVsbCBvciBlbXB0eSBzdHJpbmcgdmFsdWUgKHRoZSBkZWZhdWx0IHNldHRpbmcpIG1lYW5zIHRoZSBjb250ZW50IG9mIHJlc3VsdGluZ1xuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZSBzaG91bGQgYmUgZW5jb2RlZCBhcyBCYXNlNjQgYW5kIHBhc3NlZCBhcyB0aGUgZW5kcG91bnQgcmVzcG9uc2UgdmFsdWUuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBbiBleGNlcHRpb24gd2lsbCBiZSB0aHJvd24gaWYgdGhlIGdlbmVyYXRlZCBtZWRpYSBmaWxlIGlzIHRvbyBiaWcgdG9cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpdCBpbnRvIHRoZSBhdmFpbGFibGUgcHJvY2VzcyBtZW1vcnkuXG4gKiBAcHJvcGVydHkgez9zdHJpbmd9IHVzZXIgLSBUaGUgbmFtZSBvZiB0aGUgdXNlciBmb3IgdGhlIHJlbW90ZSBhdXRoZW50aWNhdGlvbi5cbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gcGFzcyAtIFRoZSBwYXNzd29yZCBmb3IgdGhlIHJlbW90ZSBhdXRoZW50aWNhdGlvbi5cbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gbWV0aG9kIC0gVGhlIGh0dHAgbXVsdGlwYXJ0IHVwbG9hZCBtZXRob2QgbmFtZS4gVGhlICdQVVQnIG9uZSBpcyB1c2VkIGJ5IGRlZmF1bHQuXG4gKiBAcHJvcGVydHkgez9PYmplY3R9IGhlYWRlcnMgLSBBZGRpdGlvbmFsIGhlYWRlcnMgbWFwcGluZyBmb3IgbXVsdGlwYXJ0IGh0dHAocykgdXBsb2Fkc1xuICogQHByb3BlcnR5IHs/c3RyaW5nfSBmaWxlRmllbGROYW1lIFtmaWxlXSAtIFRoZSBuYW1lIG9mIHRoZSBmb3JtIGZpZWxkLCB3aGVyZSB0aGUgZmlsZSBjb250ZW50IEJMT0Igc2hvdWxkIGJlIHN0b3JlZCBmb3JcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBodHRwKHMpIHVwbG9hZHNcbiAqIEBwcm9wZXJ0eSB7P09iamVjdHxBcnJheTxQYWlyPn0gZm9ybUZpZWxkcyAtIEFkZGl0aW9uYWwgZm9ybSBmaWVsZHMgZm9yIG11bHRpcGFydCBodHRwKHMpIHVwbG9hZHNcbiAqL1xuXG4vKipcbiAqIFN0b3AgcmVjb3JkaW5nIHRoZSBzY3JlZW4uXG4gKiBJZiBubyBzY3JlZW4gcmVjb3JkaW5nIGhhcyBiZWVuIHN0YXJ0ZWQgYmVmb3JlIHRoZW4gdGhlIG1ldGhvZCByZXR1cm5zIGFuIGVtcHR5IHN0cmluZy5cbiAqXG4gKiBAcGFyYW0gez9TdG9wUmVjb3JkaW5nT3B0aW9uc30gb3B0aW9ucyAtIFRoZSBhdmFpbGFibGUgb3B0aW9ucy5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IEJhc2U2NC1lbmNvZGVkIGNvbnRlbnQgb2YgdGhlIHJlY29yZGVkIG1lZGlhIGZpbGUgaWYgJ3JlbW90ZVBhdGgnXG4gKiAgICAgICAgICAgICAgICAgICBwYXJhbWV0ZXIgaXMgZmFsc3kgb3IgYW4gZW1wdHkgc3RyaW5nLlxuICogQHRocm93cyB7RXJyb3J9IElmIHRoZXJlIHdhcyBhbiBlcnJvciB3aGlsZSBnZXR0aW5nIHRoZSBuYW1lIG9mIGEgbWVkaWEgZmlsZVxuICogICAgICAgICAgICAgICAgIG9yIHRoZSBmaWxlIGNvbnRlbnQgY2Fubm90IGJlIHVwbG9hZGVkIHRvIHRoZSByZW1vdGUgbG9jYXRpb25cbiAqICAgICAgICAgICAgICAgICBvciBzY3JlZW4gcmVjb3JkaW5nIGlzIG5vdCBzdXBwb3J0ZWQgb24gdGhlIGRldmljZSB1bmRlciB0ZXN0LlxuICovXG5jb21tYW5kcy5zdG9wUmVjb3JkaW5nU2NyZWVuID0gYXN5bmMgZnVuY3Rpb24gc3RvcFJlY29yZGluZ1NjcmVlbiAob3B0aW9ucyA9IHt9KSB7XG4gIGF3YWl0IHZlcmlmeVNjcmVlblJlY29yZElzU3VwcG9ydGVkKHRoaXMuYWRiLCB0aGlzLmlzRW11bGF0b3IoKSk7XG5cbiAgaWYgKCFfLmlzRW1wdHkodGhpcy5fc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcykpIHtcbiAgICB0aGlzLl9zY3JlZW5SZWNvcmRpbmdQcm9wZXJ0aWVzLnN0b3BwZWQgPSB0cnVlO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBhd2FpdCB0ZXJtaW5hdGVCYWNrZ3JvdW5kU2NyZWVuUmVjb3JkaW5nKHRoaXMuYWRiLCBmYWxzZSk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIHRoaXMubG9nLndhcm4oZXJyLm1lc3NhZ2UpO1xuICAgIGlmICghXy5pc0VtcHR5KHRoaXMuX3NjcmVlblJlY29yZGluZ1Byb3BlcnRpZXMpKSB7XG4gICAgICB0aGlzLmxvZy53YXJuKCdUaGUgcmVzdWx0aW5nIHZpZGVvIG1pZ2h0IGJlIGNvcnJ1cHRlZCcpO1xuICAgIH1cbiAgfVxuXG4gIGlmIChfLmlzRW1wdHkodGhpcy5fc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcykpIHtcbiAgICB0aGlzLmxvZy5pbmZvKGBTY3JlZW4gcmVjb3JkaW5nIGhhcyBub3QgYmVlbiBwcmV2aW91c2x5IHN0YXJ0ZWQgYnkgQXBwaXVtLiBUaGVyZSBpcyBub3RoaW5nIHRvIHN0b3BgKTtcbiAgICByZXR1cm4gJyc7XG4gIH1cblxuICBpZiAodGhpcy5fc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcy5yZWNvcmRpbmdQcm9jZXNzICYmIHRoaXMuX3NjcmVlblJlY29yZGluZ1Byb3BlcnRpZXMucmVjb3JkaW5nUHJvY2Vzcy5pc1J1bm5pbmcpIHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5fc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcy5yZWNvcmRpbmdQcm9jZXNzLnN0b3AoJ1NJR0lOVCcsIFBST0NFU1NfU0hVVERPV05fVElNRU9VVCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhpcy5sb2cuZXJyb3JBbmRUaHJvdyhgVW5hYmxlIHRvIHN0b3Agc2NyZWVuIHJlY29yZGluZyB3aXRoaW4gJHtQUk9DRVNTX1NIVVRET1dOX1RJTUVPVVR9bXNgKTtcbiAgICB9XG4gICAgdGhpcy5fc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcy5yZWNvcmRpbmdQcm9jZXNzID0gbnVsbDtcbiAgfVxuXG4gIGlmIChfLmlzRW1wdHkodGhpcy5fc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcy5yZWNvcmRzKSkge1xuICAgIHRoaXMubG9nLmVycm9yQW5kVGhyb3coYE5vIHNjcmVlbiByZWNvcmRpbmdzIGhhdmUgYmVlbiBzdG9yZWQgb24gdGhlIGRldmljZSBzbyBmYXIuIGAgK1xuICAgICAgYEFyZSB5b3Ugc3VyZSB0aGUgJHtTQ1JFRU5SRUNPUkRfQklOQVJZfSB1dGlsaXR5IHdvcmtzIGFzIGV4cGVjdGVkP2ApO1xuICB9XG5cbiAgY29uc3QgdG1wUm9vdCA9IGF3YWl0IHRlbXBEaXIub3BlbkRpcigpO1xuICB0cnkge1xuICAgIGNvbnN0IGxvY2FsUmVjb3JkcyA9IFtdO1xuICAgIGZvciAoY29uc3QgcGF0aE9uRGV2aWNlIG9mIHRoaXMuX3NjcmVlblJlY29yZGluZ1Byb3BlcnRpZXMucmVjb3Jkcykge1xuICAgICAgbG9jYWxSZWNvcmRzLnB1c2gocGF0aC5yZXNvbHZlKHRtcFJvb3QsIHBhdGgucG9zaXguYmFzZW5hbWUocGF0aE9uRGV2aWNlKSkpO1xuICAgICAgYXdhaXQgdGhpcy5hZGIucHVsbChwYXRoT25EZXZpY2UsIF8ubGFzdChsb2NhbFJlY29yZHMpKTtcbiAgICAgIGF3YWl0IHRoaXMuYWRiLnJpbXJhZihwYXRoT25EZXZpY2UpO1xuICAgIH1cbiAgICBsZXQgcmVzdWx0RmlsZVBhdGggPSBfLmxhc3QobG9jYWxSZWNvcmRzKTtcbiAgICBpZiAobG9jYWxSZWNvcmRzLmxlbmd0aCA+IDEpIHtcbiAgICAgIHRoaXMubG9nLmluZm8oYEdvdCAke2xvY2FsUmVjb3Jkcy5sZW5ndGh9IHNjcmVlbiByZWNvcmRpbmdzLiBUcnlpbmcgdG8gbWVyZ2UgdGhlbWApO1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmVzdWx0RmlsZVBhdGggPSBhd2FpdCBtZXJnZVNjcmVlblJlY29yZHMobG9jYWxSZWNvcmRzLCB0aGlzLmxvZyk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRoaXMubG9nLndhcm4oYENhbm5vdCBtZXJnZSB0aGUgcmVjb3JkZWQgZmlsZXMuIFRoZSBtb3N0IHJlY2VudCBzY3JlZW4gcmVjb3JkaW5nIGlzIGdvaW5nIHRvIGJlIHJldHVybmVkIGFzIHRoZSByZXN1bHQuIGAgK1xuICAgICAgICAgIGBPcmlnaW5hbCBlcnJvcjogJHtlLm1lc3NhZ2V9YCk7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChfLmlzRW1wdHkob3B0aW9ucy5yZW1vdGVQYXRoKSkge1xuICAgICAgY29uc3Qge3NpemV9ID0gYXdhaXQgZnMuc3RhdChyZXN1bHRGaWxlUGF0aCk7XG4gICAgICB0aGlzLmxvZy5kZWJ1ZyhgVGhlIHNpemUgb2YgdGhlIHJlc3VsdGluZyBzY3JlZW4gcmVjb3JkaW5nIGlzICR7dXRpbC50b1JlYWRhYmxlU2l6ZVN0cmluZyhzaXplKX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIGF3YWl0IHVwbG9hZFJlY29yZGVkTWVkaWEocmVzdWx0RmlsZVBhdGgsIG9wdGlvbnMucmVtb3RlUGF0aCwgb3B0aW9ucyk7XG4gIH0gZmluYWxseSB7XG4gICAgYXdhaXQgZnMucmltcmFmKHRtcFJvb3QpO1xuICAgIHRoaXMuX3NjcmVlblJlY29yZGluZ1Byb3BlcnRpZXMgPSBudWxsO1xuICB9XG59O1xuXG5cbmV4cG9ydCB7IGNvbW1hbmRzIH07XG5leHBvcnQgZGVmYXVsdCBjb21tYW5kcztcbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFBQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFHQSxNQUFNQSxRQUFRLEdBQUcsRUFBakI7O0FBRUEsTUFBTUMsV0FBVyxHQUFHLEdBQXBCO0FBQ0EsTUFBTUMsYUFBYSxHQUFHLElBQXRCO0FBQ0EsTUFBTUMsc0JBQXNCLEdBQUcsS0FBSyxD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
255
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJjb21tYW5kcyIsIlJFVFJZX1BBVVNFIiwiUkVUUllfVElNRU9VVCIsIk1BWF9SRUNPUkRJTkdfVElNRV9TRUMiLCJNQVhfVElNRV9TRUMiLCJERUZBVUxUX1JFQ09SRElOR19USU1FX1NFQyIsIlBST0NFU1NfU0hVVERPV05fVElNRU9VVCIsIlNDUkVFTlJFQ09SRF9CSU5BUlkiLCJERUZBVUxUX0VYVCIsIk1JTl9FTVVMQVRPUl9BUElfTEVWRUwiLCJGRk1QRUdfQklOQVJZIiwic3lzdGVtIiwiaXNXaW5kb3dzIiwidXBsb2FkUmVjb3JkZWRNZWRpYSIsImxvY2FsRmlsZSIsInJlbW90ZVBhdGgiLCJ1cGxvYWRPcHRpb25zIiwiXyIsImlzRW1wdHkiLCJ1dGlsIiwidG9Jbk1lbW9yeUJhc2U2NCIsInRvU3RyaW5nIiwidXNlciIsInBhc3MiLCJtZXRob2QiLCJoZWFkZXJzIiwiZmlsZUZpZWxkTmFtZSIsImZvcm1GaWVsZHMiLCJvcHRpb25zIiwiYXV0aCIsIm5ldCIsInVwbG9hZEZpbGUiLCJ2ZXJpZnlTY3JlZW5SZWNvcmRJc1N1cHBvcnRlZCIsImFkYiIsImlzRW11bGF0b3IiLCJhcGlMZXZlbCIsImdldEFwaUxldmVsIiwiRXJyb3IiLCJzY2hlZHVsZVNjcmVlblJlY29yZCIsInJlY29yZGluZ1Byb3BlcnRpZXMiLCJsb2ciLCJzdG9wcGVkIiwidGltZXIiLCJ2aWRlb1NpemUiLCJiaXRSYXRlIiwidGltZUxpbWl0IiwiYnVnUmVwb3J0IiwiY3VycmVudFRpbWVMaW1pdCIsImhhc1ZhbHVlIiwiY3VycmVudFRpbWVMaW1pdEludCIsInBhcnNlSW50IiwiaXNOYU4iLCJwYXRoT25EZXZpY2UiLCJ1dWlkVjQiLCJzdWJzdHJpbmciLCJyZWNvcmRpbmdQcm9jIiwic2NyZWVucmVjb3JkIiwib24iLCJjdXJyZW50RHVyYXRpb24iLCJnZXREdXJhdGlvbiIsImFzU2Vjb25kcyIsInRvRml4ZWQiLCJkZWJ1ZyIsInRpbWVMaW1pdEludCIsImNodW5rRHVyYXRpb24iLCJlIiwiZXJyb3IiLCJzdGFjayIsInN0YXJ0Iiwid2FpdEZvckNvbmRpdGlvbiIsImZpbGVFeGlzdHMiLCJ3YWl0TXMiLCJpbnRlcnZhbE1zIiwicmVjb3JkcyIsInB1c2giLCJyZWNvcmRpbmdQcm9jZXNzIiwibWVyZ2VTY3JlZW5SZWNvcmRzIiwibWVkaWFGaWxlcyIsImZzIiwid2hpY2giLCJjb25maWdDb250ZW50IiwibWFwIiwieCIsImpvaW4iLCJjb25maWdGaWxlIiwicGF0aCIsInJlc29sdmUiLCJkaXJuYW1lIiwid3JpdGVGaWxlIiwicmVzdWx0IiwiTWF0aCIsImZsb29yIiwiRGF0ZSIsImFyZ3MiLCJpbmZvIiwiZXhlYyIsInRlcm1pbmF0ZUJhY2tncm91bmRTY3JlZW5SZWNvcmRpbmciLCJmb3JjZSIsInBpZHMiLCJnZXRQSURzQnlOYW1lIiwicCIsInNoZWxsIiwiZXJyIiwibWVzc2FnZSIsInN0YXJ0UmVjb3JkaW5nU2NyZWVuIiwiZm9yY2VSZXN0YXJ0Iiwic3RvcFJlY29yZGluZ1NjcmVlbiIsIndhcm4iLCJfc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcyIsInJlY29yZCIsInJpbXJhZiIsInRpbWVvdXQiLCJwYXJzZUZsb2F0IiwidGltaW5nIiwiVGltZXIiLCJpc1J1bm5pbmciLCJzdG9wIiwiZXJyb3JBbmRUaHJvdyIsInRtcFJvb3QiLCJ0ZW1wRGlyIiwib3BlbkRpciIsImxvY2FsUmVjb3JkcyIsInBvc2l4IiwiYmFzZW5hbWUiLCJwdWxsIiwibGFzdCIsInJlc3VsdEZpbGVQYXRoIiwibGVuZ3RoIiwic2l6ZSIsInN0YXQiLCJ0b1JlYWRhYmxlU2l6ZVN0cmluZyJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2xpYi9jb21tYW5kcy9yZWNvcmRzY3JlZW4uanMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7IHdhaXRGb3JDb25kaXRpb24gfSBmcm9tICdhc3luY2JveCc7XG5pbXBvcnQgeyB1dGlsLCBmcywgbmV0LCB0ZW1wRGlyLCBzeXN0ZW0sIHRpbWluZyB9IGZyb20gJ2FwcGl1bS9zdXBwb3J0JztcbmltcG9ydCB7IGV4ZWMgfSBmcm9tICd0ZWVuX3Byb2Nlc3MnO1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5cblxuY29uc3QgY29tbWFuZHMgPSB7fTtcblxuY29uc3QgUkVUUllfUEFVU0UgPSAzMDA7XG5jb25zdCBSRVRSWV9USU1FT1VUID0gNTAwMDtcbmNvbnN0IE1BWF9SRUNPUkRJTkdfVElNRV9TRUMgPSA2MCAqIDM7XG5jb25zdCBNQVhfVElNRV9TRUMgPSA2MCAqIDMwO1xuY29uc3QgREVGQVVMVF9SRUNPUkRJTkdfVElNRV9TRUMgPSBNQVhfUkVDT1JESU5HX1RJTUVfU0VDO1xuY29uc3QgUFJPQ0VTU19TSFVURE9XTl9USU1FT1VUID0gMTAgKiAxMDAwO1xuY29uc3QgU0NSRUVOUkVDT1JEX0JJTkFSWSA9ICdzY3JlZW5yZWNvcmQnO1xuY29uc3QgREVGQVVMVF9FWFQgPSAnLm1wNCc7XG5jb25zdCBNSU5fRU1VTEFUT1JfQVBJX0xFVkVMID0gMjc7XG5jb25zdCBGRk1QRUdfQklOQVJZID0gYGZmbXBlZyR7c3lzdGVtLmlzV2luZG93cygpID8gJy5leGUnIDogJyd9YDtcblxuYXN5bmMgZnVuY3Rpb24gdXBsb2FkUmVjb3JkZWRNZWRpYSAobG9jYWxGaWxlLCByZW1vdGVQYXRoID0gbnVsbCwgdXBsb2FkT3B0aW9ucyA9IHt9KSB7XG4gIGlmIChfLmlzRW1wdHkocmVtb3RlUGF0aCkpIHtcbiAgICByZXR1cm4gKGF3YWl0IHV0aWwudG9Jbk1lbW9yeUJhc2U2NChsb2NhbEZpbGUpKS50b1N0cmluZygpO1xuICB9XG5cbiAgY29uc3Qge3VzZXIsIHBhc3MsIG1ldGhvZCwgaGVhZGVycywgZmlsZUZpZWxkTmFtZSwgZm9ybUZpZWxkc30gPSB1cGxvYWRPcHRpb25zO1xuICBjb25zdCBvcHRpb25zID0ge1xuICAgIG1ldGhvZDogbWV0aG9kIHx8ICdQVVQnLFxuICAgIGhlYWRlcnMsXG4gICAgZmlsZUZpZWxkTmFtZSxcbiAgICBmb3JtRmllbGRzLFxuICB9O1xuICBpZiAodXNlciAmJiBwYXNzKSB7XG4gICAgb3B0aW9ucy5hdXRoID0ge3VzZXIsIHBhc3N9O1xuICB9XG4gIGF3YWl0IG5ldC51cGxvYWRGaWxlKGxvY2FsRmlsZSwgcmVtb3RlUGF0aCwgb3B0aW9ucyk7XG4gIHJldHVybiAnJztcbn1cblxuYXN5bmMgZnVuY3Rpb24gdmVyaWZ5U2NyZWVuUmVjb3JkSXNTdXBwb3J0ZWQgKGFkYiwgaXNFbXVsYXRvcikge1xuICBjb25zdCBhcGlMZXZlbCA9IGF3YWl0IGFkYi5nZXRBcGlMZXZlbCgpO1xuICBpZiAoaXNFbXVsYXRvciAmJiBhcGlMZXZlbCA8IE1JTl9FTVVMQVRPUl9BUElfTEVWRUwpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFNjcmVlbiByZWNvcmRpbmcgZG9lcyBub3Qgd29yayBvbiBlbXVsYXRvcnMgcnVubmluZyBBbmRyb2lkIEFQSSBsZXZlbCBsZXNzIHRoYW4gJHtNSU5fRU1VTEFUT1JfQVBJX0xFVkVMfWApO1xuICB9XG4gIGlmIChhcGlMZXZlbCA8IDE5KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBTY3JlZW4gcmVjb3JkaW5nIG5vdCBhdmFpbGFibGUgb24gQVBJIExldmVsICR7YXBpTGV2ZWx9LiBNaW5pbXVtIEFQSSBMZXZlbCBpcyAxOS5gKTtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBzY2hlZHVsZVNjcmVlblJlY29yZCAoYWRiLCByZWNvcmRpbmdQcm9wZXJ0aWVzLCBsb2cgPSBudWxsKSB7XG4gIGlmIChyZWNvcmRpbmdQcm9wZXJ0aWVzLnN0b3BwZWQpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCB7XG4gICAgdGltZXIsXG4gICAgdmlkZW9TaXplLFxuICAgIGJpdFJhdGUsXG4gICAgdGltZUxpbWl0LFxuICAgIGJ1Z1JlcG9ydCxcbiAgfSA9IHJlY29yZGluZ1Byb3BlcnRpZXM7XG5cbiAgbGV0IGN1cnJlbnRUaW1lTGltaXQgPSBNQVhfUkVDT1JESU5HX1RJTUVfU0VDO1xuICBpZiAodXRpbC5oYXNWYWx1ZShyZWNvcmRpbmdQcm9wZXJ0aWVzLmN1cnJlbnRUaW1lTGltaXQpKSB7XG4gICAgY29uc3QgY3VycmVudFRpbWVMaW1pdEludCA9IHBhcnNlSW50KHJlY29yZGluZ1Byb3BlcnRpZXMuY3VycmVudFRpbWVMaW1pdCwgMTApO1xuICAgIGlmICghaXNOYU4oY3VycmVudFRpbWVMaW1pdEludCkgJiYgY3VycmVudFRpbWVMaW1pdEludCA8IE1BWF9SRUNPUkRJTkdfVElNRV9TRUMpIHtcbiAgICAgIGN1cnJlbnRUaW1lTGltaXQgPSBjdXJyZW50VGltZUxpbWl0SW50O1xuICAgIH1cbiAgfVxuICBjb25zdCBwYXRoT25EZXZpY2UgPSBgL3NkY2FyZC8ke3V0aWwudXVpZFY0KCkuc3Vic3RyaW5nKDAsIDgpfSR7REVGQVVMVF9FWFR9YDtcbiAgY29uc3QgcmVjb3JkaW5nUHJvYyA9IGFkYi5zY3JlZW5yZWNvcmQocGF0aE9uRGV2aWNlLCB7XG4gICAgdmlkZW9TaXplLFxuICAgIGJpdFJhdGUsXG4gICAgdGltZUxpbWl0OiBjdXJyZW50VGltZUxpbWl0LFxuICAgIGJ1Z1JlcG9ydCxcbiAgfSk7XG5cbiAgcmVjb3JkaW5nUHJvYy5vbignZW5kJywgKCkgPT4ge1xuICAgIGlmIChyZWNvcmRpbmdQcm9wZXJ0aWVzLnN0b3BwZWQgfHwgIXV0aWwuaGFzVmFsdWUodGltZUxpbWl0KSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBjdXJyZW50RHVyYXRpb24gPSB0aW1lci5nZXREdXJhdGlvbigpLmFzU2Vjb25kcy50b0ZpeGVkKDApO1xuICAgIGxvZz8uZGVidWcoYFRoZSBvdmVyYWxsIHNjcmVlbiByZWNvcmRpbmcgZHVyYXRpb24gaXMgJHtjdXJyZW50RHVyYXRpb259cyBzbyBmYXJgKTtcbiAgICBjb25zdCB0aW1lTGltaXRJbnQgPSBwYXJzZUludCh0aW1lTGltaXQsIDEwKTtcbiAgICBpZiAoaXNOYU4odGltZUxpbWl0SW50KSB8fCBjdXJyZW50RHVyYXRpb24gPj0gdGltZUxpbWl0SW50KSB7XG4gICAgICBsb2c/LmRlYnVnKCdUaGVyZSBpcyBubyBuZWVkIHRvIHN0YXJ0IHRoZSBuZXh0IHJlY29yZGluZyBjaHVuaycpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHJlY29yZGluZ1Byb3BlcnRpZXMuY3VycmVudFRpbWVMaW1pdCA9IHRpbWVMaW1pdEludCAtIGN1cnJlbnREdXJhdGlvbjtcbiAgICBjb25zdCBjaHVua0R1cmF0aW9uID0gcmVjb3JkaW5nUHJvcGVydGllcy5jdXJyZW50VGltZUxpbWl0IDwgTUFYX1JFQ09SRElOR19USU1FX1NFQ1xuICAgICAgPyByZWNvcmRpbmdQcm9wZXJ0aWVzLmN1cnJlbnRUaW1lTGltaXRcbiAgICAgIDogTUFYX1JFQ09SRElOR19USU1FX1NFQztcbiAgICBsb2c/LmRlYnVnKGBTdGFydGluZyB0aGUgbmV4dCAke2NodW5rRHVyYXRpb259cy1jaHVuayBgICtcbiAgICAgIGBvZiBzY3JlZW4gcmVjb3JkaW5nIGluIG9yZGVyIHRvIGFjaGlldmUgJHt0aW1lTGltaXRJbnR9cyB0b3RhbCBkdXJhdGlvbmApO1xuICAgIChhc3luYyAoKSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBzY2hlZHVsZVNjcmVlblJlY29yZChhZGIsIHJlY29yZGluZ1Byb3BlcnRpZXMsIGxvZyk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGxvZz8uZXJyb3IoZS5zdGFjayk7XG4gICAgICAgIHJlY29yZGluZ1Byb3BlcnRpZXMuc3RvcHBlZCA9IHRydWU7XG4gICAgICB9XG4gICAgfSkoKTtcbiAgfSk7XG5cbiAgYXdhaXQgcmVjb3JkaW5nUHJvYy5zdGFydCgwKTtcbiAgdHJ5IHtcbiAgICBhd2FpdCB3YWl0Rm9yQ29uZGl0aW9uKGFzeW5jICgpID0+IGF3YWl0IGFkYi5maWxlRXhpc3RzKHBhdGhPbkRldmljZSksXG4gICAgICB7d2FpdE1zOiBSRVRSWV9USU1FT1VULCBpbnRlcnZhbE1zOiBSRVRSWV9QQVVTRX0pO1xuICB9IGNhdGNoIChlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBUaGUgZXhwZWN0ZWQgc2NyZWVuIHJlY29yZCBmaWxlICcke3BhdGhPbkRldmljZX0nIGRvZXMgbm90IGV4aXN0IGFmdGVyICR7UkVUUllfVElNRU9VVH1tcy4gYCArXG4gICAgICBgSXMgJHtTQ1JFRU5SRUNPUkRfQklOQVJZfSB1dGlsaXR5IGF2YWlsYWJsZSBhbmQgb3BlcmF0aW9uYWwgb24gdGhlIGRldmljZSB1bmRlciB0ZXN0P2ApO1xuICB9XG5cbiAgcmVjb3JkaW5nUHJvcGVydGllcy5yZWNvcmRzLnB1c2gocGF0aE9uRGV2aWNlKTtcbiAgcmVjb3JkaW5nUHJvcGVydGllcy5yZWNvcmRpbmdQcm9jZXNzID0gcmVjb3JkaW5nUHJvYztcbn1cblxuYXN5bmMgZnVuY3Rpb24gbWVyZ2VTY3JlZW5SZWNvcmRzIChtZWRpYUZpbGVzLCBsb2cgPSBudWxsKSB7XG4gIHRyeSB7XG4gICAgYXdhaXQgZnMud2hpY2goRkZNUEVHX0JJTkFSWSk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCR7RkZNUEVHX0JJTkFSWX0gdXRpbGl0eSBpcyBub3QgYXZhaWxhYmxlIGluIFBBVEguIFBsZWFzZSBpbnN0YWxsIGl0IGZyb20gaHR0cHM6Ly93d3cuZmZtcGVnLm9yZy9gKTtcbiAgfVxuICBjb25zdCBjb25maWdDb250ZW50ID0gbWVkaWFGaWxlc1xuICAgIC5tYXAoKHgpID0+IGBmaWxlICcke3h9J2ApXG4gICAgLmpvaW4oJ1xcbicpO1xuICBjb25zdCBjb25maWdGaWxlID0gcGF0aC5yZXNvbHZlKHBhdGguZGlybmFtZShtZWRpYUZpbGVzWzBdKSwgJ2NvbmZpZy50eHQnKTtcbiAgYXdhaXQgZnMud3JpdGVGaWxlKGNvbmZpZ0ZpbGUsIGNvbmZpZ0NvbnRlbnQsICd1dGY4Jyk7XG4gIGxvZz8uZGVidWcoYEdlbmVyYXRlZCBmZm1wZWcgbWVyZ2luZyBjb25maWcgJyR7Y29uZmlnRmlsZX0nIHdpdGggaXRlbXM6XFxuJHtjb25maWdDb250ZW50fWApO1xuICBjb25zdCByZXN1bHQgPSBwYXRoLnJlc29sdmUocGF0aC5kaXJuYW1lKG1lZGlhRmlsZXNbMF0pLCBgbWVyZ2VfJHtNYXRoLmZsb29yKG5ldyBEYXRlKCkpfSR7REVGQVVMVF9FWFR9YCk7XG4gIGNvbnN0IGFyZ3MgPSBbJy1zYWZlJywgJzAnLCAnLWYnLCAnY29uY2F0JywgJy1pJywgY29uZmlnRmlsZSwgJy1jJywgJ2NvcHknLCByZXN1bHRdO1xuICBsb2c/LmluZm8oYEluaXRpYXRpbmcgc2NyZWVuIHJlY29yZHMgbWVyZ2luZyB1c2luZyB0aGUgY29tbWFuZCAnJHtGRk1QRUdfQklOQVJZfSAke2FyZ3Muam9pbignICcpfSdgKTtcbiAgYXdhaXQgZXhlYyhGRk1QRUdfQklOQVJZLCBhcmdzKTtcbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuYXN5bmMgZnVuY3Rpb24gdGVybWluYXRlQmFja2dyb3VuZFNjcmVlblJlY29yZGluZyAoYWRiLCBmb3JjZSA9IHRydWUpIHtcbiAgY29uc3QgcGlkcyA9IChhd2FpdCBhZGIuZ2V0UElEc0J5TmFtZShTQ1JFRU5SRUNPUkRfQklOQVJZKSlcbiAgICAubWFwKChwKSA9PiBgJHtwfWApO1xuICBpZiAoXy5pc0VtcHR5KHBpZHMpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBhd2FpdCBhZGIuc2hlbGwoWydraWxsJywgZm9yY2UgPyAnLTE1JyA6ICctMicsIC4uLnBpZHNdKTtcbiAgICBhd2FpdCB3YWl0Rm9yQ29uZGl0aW9uKGFzeW5jICgpID0+IF8uaXNFbXB0eShhd2FpdCBhZGIuZ2V0UElEc0J5TmFtZShTQ1JFRU5SRUNPUkRfQklOQVJZKSksIHtcbiAgICAgIHdhaXRNczogUFJPQ0VTU19TSFVURE9XTl9USU1FT1VULFxuICAgICAgaW50ZXJ2YWxNczogNTAwLFxuICAgIH0pO1xuICAgIHJldHVybiB0cnVlO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFVuYWJsZSB0byBzdG9wIHRoZSBiYWNrZ3JvdW5kIHNjcmVlbiByZWNvcmRpbmc6ICR7ZXJyLm1lc3NhZ2V9YCk7XG4gIH1cbn1cblxuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IFN0YXJ0UmVjb3JkaW5nT3B0aW9uc1xuICpcbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gcmVtb3RlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSByZW1vdGUgbG9jYXRpb24sIHdoZXJlIHRoZSBjYXB0dXJlZCB2aWRlbyBzaG91bGQgYmUgdXBsb2FkZWQuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaGUgZm9sbG93aW5nIHByb3RvY29scyBhcmUgc3VwcG9ydGVkOiBodHRwL2h0dHBzLCBmdHAuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOdWxsIG9yIGVtcHR5IHN0cmluZyB2YWx1ZSAodGhlIGRlZmF1bHQgc2V0dGluZykgbWVhbnMgdGhlIGNvbnRlbnQgb2YgcmVzdWx0aW5nXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlIHNob3VsZCBiZSBlbmNvZGVkIGFzIEJhc2U2NCBhbmQgcGFzc2VkIGFzIHRoZSBlbmRwb3VudCByZXNwb25zZSB2YWx1ZS5cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFuIGV4Y2VwdGlvbiB3aWxsIGJlIHRocm93biBpZiB0aGUgZ2VuZXJhdGVkIG1lZGlhIGZpbGUgaXMgdG9vIGJpZyB0b1xuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZml0IGludG8gdGhlIGF2YWlsYWJsZSBwcm9jZXNzIG1lbW9yeS5cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRoaXMgb3B0aW9uIG9ubHkgaGFzIGFuIGVmZmVjdCBpZiB0aGVyZSBpcyBzY3JlZW4gcmVjb3JkaW5nIHByb2Nlc3MgaW4gcHJvZ3JlZXNzXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbmQgYGZvcmNlUmVzdGFydGAgcGFyYW1ldGVyIGlzIG5vdCBzZXQgdG8gYHRydWVgLlxuICogQHByb3BlcnR5IHs/c3RyaW5nfSB1c2VyIC0gVGhlIG5hbWUgb2YgdGhlIHVzZXIgZm9yIHRoZSByZW1vdGUgYXV0aGVudGljYXRpb24uIE9ubHkgd29ya3MgaWYgYHJlbW90ZVBhdGhgIGlzIHByb3ZpZGVkLlxuICogQHByb3BlcnR5IHs/c3RyaW5nfSBwYXNzIC0gVGhlIHBhc3N3b3JkIGZvciB0aGUgcmVtb3RlIGF1dGhlbnRpY2F0aW9uLiBPbmx5IHdvcmtzIGlmIGByZW1vdGVQYXRoYCBpcyBwcm92aWRlZC5cbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gbWV0aG9kIFtQVVRdIC0gVGhlIGh0dHAgbXVsdGlwYXJ0IHVwbG9hZCBtZXRob2QgbmFtZS4gT25seSB3b3JrcyBpZiBgcmVtb3RlUGF0aGAgaXMgcHJvdmlkZWQuXG4gKiBAcHJvcGVydHkgez9PYmplY3R9IGhlYWRlcnMgLSBBZGRpdGlvbmFsIGhlYWRlcnMgbWFwcGluZyBmb3IgbXVsdGlwYXJ0IGh0dHAocykgdXBsb2Fkc1xuICogQHByb3BlcnR5IHs/c3RyaW5nfSBmaWxlRmllbGROYW1lIFtmaWxlXSAtIFRoZSBuYW1lIG9mIHRoZSBmb3JtIGZpZWxkLCB3aGVyZSB0aGUgZmlsZSBjb250ZW50IEJMT0Igc2hvdWxkIGJlIHN0b3JlZCBmb3JcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBodHRwKHMpIHVwbG9hZHNcbiAqIEBwcm9wZXJ0eSB7P09iamVjdHxBcnJheTxQYWlyPn0gZm9ybUZpZWxkcyAtIEFkZGl0aW9uYWwgZm9ybSBmaWVsZHMgZm9yIG11bHRpcGFydCBodHRwKHMpIHVwbG9hZHNcbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gdmlkZW9TaXplIC0gVGhlIGZvcm1hdCBpcyB3aWR0aHhoZWlnaHQuXG4gKiAgICAgICAgICAgICAgICAgIFRoZSBkZWZhdWx0IHZhbHVlIGlzIHRoZSBkZXZpY2UncyBuYXRpdmUgZGlzcGxheSByZXNvbHV0aW9uIChpZiBzdXBwb3J0ZWQpLFxuICogICAgICAgICAgICAgICAgICAxMjgweDcyMCBpZiBub3QuIEZvciBiZXN0IHJlc3VsdHMsXG4gKiAgICAgICAgICAgICAgICAgIHVzZSBhIHNpemUgc3VwcG9ydGVkIGJ5IHlvdXIgZGV2aWNlJ3MgQWR2YW5jZWQgVmlkZW8gQ29kaW5nIChBVkMpIGVuY29kZXIuXG4gKiAgICAgICAgICAgICAgICAgIEZvciBleGFtcGxlLCBcIjEyODB4NzIwXCJcbiAqIEBwcm9wZXJ0eSB7P2Jvb2xlYW59IGJ1Z1JlcG9ydCAtIFNldCBpdCB0byBgdHJ1ZWAgaW4gb3JkZXIgdG8gZGlzcGxheSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIG9uIHRoZSB2aWRlbyBvdmVybGF5LFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VjaCBhcyBhIHRpbWVzdGFtcCwgdGhhdCBpcyBoZWxwZnVsIGluIHZpZGVvcyBjYXB0dXJlZCB0byBpbGx1c3RyYXRlIGJ1Z3MuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaGlzIG9wdGlvbiBpcyBvbmx5IHN1cHBvcnRlZCBzaW5jZSBBUEkgbGV2ZWwgMjcgKEFuZHJvaWQgUCkuXG4gKiBAcHJvcGVydHkgez9zdHJpbmd8bnVtYmVyfSB0aW1lTGltaXQgLSBUaGUgbWF4aW11bSByZWNvcmRpbmcgdGltZSwgaW4gc2Vjb25kcy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgMTgwICgzIG1pbnV0ZXMpLlxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGhlIG1heGltdW0gdmFsdWUgaXMgMTgwMCAoMzAgbWludXRlcykuIElmIHRoZSBwYXNzZWQgdmFsdWUgaXMgZ3JlYXRlciB0aGFuIDE4MCB0aGVuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgYWxnb3JpdGhtIHdpbGwgdHJ5IHRvIHNjaGVkdWxlIG11bHRpcGxlIHNjcmVlbiByZWNvcmRpbmcgY2h1bmtzIGFuZCBtZXJnZSB0aGVcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdGluZyB2aWRlb3MgaW50byBhIHNpbmdsZSBtZWRpYSBmaWxlIHVzaW5nIGBmZm1wZWdgIHV0aWxpdHkuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJZiB0aGUgdXRpbGl0eSBpcyBub3QgYXZhaWxhYmxlIGluIFBBVEggdGhlbiB0aGUgbW9zdCByZWNlbnQgc2NyZWVuIHJlY29yZGluZyBjaHVuayBpc1xuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ29pbmcgdG8gYmUgcmV0dXJuZWQuXG4gKiBAcHJvcGVydHkgez9zdHJpbmd8bnVtYmVyfSBiaXRSYXRlIC0gVGhlIHZpZGVvIGJpdCByYXRlIGZvciB0aGUgdmlkZW8sIGluIGJpdHMgcGVyIHNlY29uZC5cbiAqICAgICAgICAgICAgICAgIFRoZSBkZWZhdWx0IHZhbHVlIGlzIDQwMDAwMDAgKDQgTWJpdC9zKS4gWW91IGNhbiBpbmNyZWFzZSB0aGUgYml0IHJhdGUgdG8gaW1wcm92ZSB2aWRlbyBxdWFsaXR5LFxuICogICAgICAgICAgICAgICAgYnV0IGRvaW5nIHNvIHJlc3VsdHMgaW4gbGFyZ2VyIG1vdmllIGZpbGVzLlxuICogQHByb3BlcnR5IHs/Ym9vbGVhbn0gZm9yY2VSZXN0YXJ0IC0gV2hldGhlciB0byB0cnkgdG8gY2F0Y2ggYW5kIHVwbG9hZC9yZXR1cm4gdGhlIGN1cnJlbnRseSBydW5uaW5nIHNjcmVlbiByZWNvcmRpbmdcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChgZmFsc2VgLCB0aGUgZGVmYXVsdCBzZXR0aW5nKSBvciBpZ25vcmUgdGhlIHJlc3VsdCBvZiBpdCBhbmQgc3RhcnQgYSBuZXcgcmVjb3JkaW5nXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbW1lZGlhdGVseSAoYHRydWVgKS5cbiAqL1xuXG4vKipcbiAqIFJlY29yZCB0aGUgZGlzcGxheSBvZiBhIHJlYWwgZGV2aWNlcyBydW5uaW5nIEFuZHJvaWQgNC40IChBUEkgbGV2ZWwgMTkpIGFuZCBoaWdoZXIuXG4gKiBFbXVsYXRvcnMgYXJlIHN1cHBvcnRlZCBzaW5jZSBBUEkgbGV2ZWwgMjcgKEFuZHJvaWQgUCkuXG4gKiBJdCByZWNvcmRzIHNjcmVlbiBhY3Rpdml0eSB0byBhbiBNUEVHLTQgZmlsZS4gQXVkaW8gaXMgbm90IHJlY29yZGVkIHdpdGggdGhlIHZpZGVvIGZpbGUuXG4gKiBJZiBzY3JlZW4gcmVjb3JkaW5nIGhhcyBiZWVuIGFscmVhZHkgc3RhcnRlZCB0aGVuIHRoZSBjb21tYW5kIHdpbGwgc3RvcCBpdCBmb3JjZWZ1bGx5IGFuZCBzdGFydCBhIG5ldyBvbmUuXG4gKiBUaGUgcHJldmlvdXNseSByZWNvcmRlZCB2aWRlbyBmaWxlIHdpbGwgYmUgZGVsZXRlZC5cbiAqXG4gKiBAcGFyYW0gez9TdGFydFJlY29yZGluZ09wdGlvbnN9IG9wdGlvbnMgLSBUaGUgYXZhaWxhYmxlIG9wdGlvbnMuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBCYXNlNjQtZW5jb2RlZCBjb250ZW50IG9mIHRoZSByZWNvcmRlZCBtZWRpYSBmaWxlIGlmXG4gKiAgICAgICAgICAgICAgICAgICBhbnkgc2NyZWVuIHJlY29yZGluZyBpcyBjdXJyZW50bHkgcnVubmluZyBvciBhbiBlbXB0eSBzdHJpbmcuXG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgc2NyZWVuIHJlY29yZGluZyBoYXMgZmFpbGVkIHRvIHN0YXJ0IG9yIGlzIG5vdCBzdXBwb3J0ZWQgb24gdGhlIGRldmljZSB1bmRlciB0ZXN0LlxuICovXG5jb21tYW5kcy5zdGFydFJlY29yZGluZ1NjcmVlbiA9IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0UmVjb3JkaW5nU2NyZWVuIChvcHRpb25zID0ge30pIHtcbiAgYXdhaXQgdmVyaWZ5U2NyZWVuUmVjb3JkSXNTdXBwb3J0ZWQodGhpcy5hZGIsIHRoaXMuaXNFbXVsYXRvcigpKTtcblxuICBsZXQgcmVzdWx0ID0gJyc7XG4gIGNvbnN0IHt2aWRlb1NpemUsIHRpbWVMaW1pdCA9IERFRkFVTFRfUkVDT1JESU5HX1RJTUVfU0VDLCBidWdSZXBvcnQsIGJpdFJhdGUsIGZvcmNlUmVzdGFydH0gPSBvcHRpb25zO1xuICBpZiAoIWZvcmNlUmVzdGFydCkge1xuICAgIHJlc3VsdCA9IGF3YWl0IHRoaXMuc3RvcFJlY29yZGluZ1NjcmVlbihvcHRpb25zKTtcbiAgfVxuXG4gIGlmIChhd2FpdCB0ZXJtaW5hdGVCYWNrZ3JvdW5kU2NyZWVuUmVjb3JkaW5nKHRoaXMuYWRiLCB0cnVlKSkge1xuICAgIHRoaXMubG9nLndhcm4oYFRoZXJlIHdlcmUgc29tZSAke1NDUkVFTlJFQ09SRF9CSU5BUll9IHByb2Nlc3MgbGVmdG92ZXJzIHJ1bm5pbmcgYCArXG4gICAgICBgaW4gdGhlIGJhY2tncm91bmQuIE1ha2Ugc3VyZSB5b3Ugc3RvcCBzY3JlZW4gcmVjb3JkaW5nIGVhY2ggdGltZSBhZnRlciBpdCBpcyBzdGFydGVkLCBgICtcbiAgICAgIGBvdGhlcndpc2UgdGhlIHJlY29yZGVkIG1lZGlhIG1pZ2h0IHF1aWNrbHkgZXhjZWVkIGFsbCB0aGUgZnJlZSBzcGFjZSBvbiB0aGUgZGV2aWNlIHVuZGVyIHRlc3QuYCk7XG4gIH1cblxuICBpZiAoIV8uaXNFbXB0eSh0aGlzLl9zY3JlZW5SZWNvcmRpbmdQcm9wZXJ0aWVzKSkge1xuICAgIGZvciAoY29uc3QgcmVjb3JkIG9mICh0aGlzLl9zY3JlZW5SZWNvcmRpbmdQcm9wZXJ0aWVzLnJlY29yZHMgfHwgW10pKSB7XG4gICAgICBhd2FpdCB0aGlzLmFkYi5yaW1yYWYocmVjb3JkKTtcbiAgICB9XG4gICAgdGhpcy5fc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcyA9IG51bGw7XG4gIH1cblxuICBjb25zdCB0aW1lb3V0ID0gcGFyc2VGbG9hdCh0aW1lTGltaXQpO1xuICBpZiAoaXNOYU4odGltZW91dCkgfHwgdGltZW91dCA+IE1BWF9USU1FX1NFQyB8fCB0aW1lb3V0IDw9IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFRoZSB0aW1lTGltaXQgdmFsdWUgbXVzdCBiZSBpbiByYW5nZSBbMSwgJHtNQVhfVElNRV9TRUN9XSBzZWNvbmRzLiBgICtcbiAgICAgIGBUaGUgdmFsdWUgb2YgJyR7dGltZUxpbWl0fScgaGFzIGJlZW4gcGFzc2VkIGluc3RlYWQuYCk7XG4gIH1cblxuICB0aGlzLl9zY3JlZW5SZWNvcmRpbmdQcm9wZXJ0aWVzID0ge1xuICAgIHRpbWVyOiBuZXcgdGltaW5nLlRpbWVyKCkuc3RhcnQoKSxcbiAgICB2aWRlb1NpemUsXG4gICAgdGltZUxpbWl0LFxuICAgIGN1cnJlbnRUaW1lTGltaXQ6IHRpbWVMaW1pdCxcbiAgICBiaXRSYXRlLFxuICAgIGJ1Z1JlcG9ydCxcbiAgICByZWNvcmRzOiBbXSxcbiAgICByZWNvcmRpbmdQcm9jZXNzOiBudWxsLFxuICAgIHN0b3BwZWQ6IGZhbHNlLFxuICB9O1xuICBhd2FpdCBzY2hlZHVsZVNjcmVlblJlY29yZCh0aGlzLmFkYiwgdGhpcy5fc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcywgdGhpcy5sb2cpO1xuICByZXR1cm4gcmVzdWx0O1xufTtcblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBTdG9wUmVjb3JkaW5nT3B0aW9uc1xuICpcbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gcmVtb3RlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSByZW1vdGUgbG9jYXRpb24sIHdoZXJlIHRoZSByZXN1bHRpbmcgdmlkZW8gc2hvdWxkIGJlIHVwbG9hZGVkLlxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGhlIGZvbGxvd2luZyBwcm90b2NvbHMgYXJlIHN1cHBvcnRlZDogaHR0cC9odHRwcywgZnRwLlxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTnVsbCBvciBlbXB0eSBzdHJpbmcgdmFsdWUgKHRoZSBkZWZhdWx0IHNldHRpbmcpIG1lYW5zIHRoZSBjb250ZW50IG9mIHJlc3VsdGluZ1xuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZSBzaG91bGQgYmUgZW5jb2RlZCBhcyBCYXNlNjQgYW5kIHBhc3NlZCBhcyB0aGUgZW5kcG91bnQgcmVzcG9uc2UgdmFsdWUuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBbiBleGNlcHRpb24gd2lsbCBiZSB0aHJvd24gaWYgdGhlIGdlbmVyYXRlZCBtZWRpYSBmaWxlIGlzIHRvbyBiaWcgdG9cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpdCBpbnRvIHRoZSBhdmFpbGFibGUgcHJvY2VzcyBtZW1vcnkuXG4gKiBAcHJvcGVydHkgez9zdHJpbmd9IHVzZXIgLSBUaGUgbmFtZSBvZiB0aGUgdXNlciBmb3IgdGhlIHJlbW90ZSBhdXRoZW50aWNhdGlvbi5cbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gcGFzcyAtIFRoZSBwYXNzd29yZCBmb3IgdGhlIHJlbW90ZSBhdXRoZW50aWNhdGlvbi5cbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gbWV0aG9kIC0gVGhlIGh0dHAgbXVsdGlwYXJ0IHVwbG9hZCBtZXRob2QgbmFtZS4gVGhlICdQVVQnIG9uZSBpcyB1c2VkIGJ5IGRlZmF1bHQuXG4gKiBAcHJvcGVydHkgez9PYmplY3R9IGhlYWRlcnMgLSBBZGRpdGlvbmFsIGhlYWRlcnMgbWFwcGluZyBmb3IgbXVsdGlwYXJ0IGh0dHAocykgdXBsb2Fkc1xuICogQHByb3BlcnR5IHs/c3RyaW5nfSBmaWxlRmllbGROYW1lIFtmaWxlXSAtIFRoZSBuYW1lIG9mIHRoZSBmb3JtIGZpZWxkLCB3aGVyZSB0aGUgZmlsZSBjb250ZW50IEJMT0Igc2hvdWxkIGJlIHN0b3JlZCBmb3JcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBodHRwKHMpIHVwbG9hZHNcbiAqIEBwcm9wZXJ0eSB7P09iamVjdHxBcnJheTxQYWlyPn0gZm9ybUZpZWxkcyAtIEFkZGl0aW9uYWwgZm9ybSBmaWVsZHMgZm9yIG11bHRpcGFydCBodHRwKHMpIHVwbG9hZHNcbiAqL1xuXG4vKipcbiAqIFN0b3AgcmVjb3JkaW5nIHRoZSBzY3JlZW4uXG4gKiBJZiBubyBzY3JlZW4gcmVjb3JkaW5nIGhhcyBiZWVuIHN0YXJ0ZWQgYmVmb3JlIHRoZW4gdGhlIG1ldGhvZCByZXR1cm5zIGFuIGVtcHR5IHN0cmluZy5cbiAqXG4gKiBAcGFyYW0gez9TdG9wUmVjb3JkaW5nT3B0aW9uc30gb3B0aW9ucyAtIFRoZSBhdmFpbGFibGUgb3B0aW9ucy5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IEJhc2U2NC1lbmNvZGVkIGNvbnRlbnQgb2YgdGhlIHJlY29yZGVkIG1lZGlhIGZpbGUgaWYgJ3JlbW90ZVBhdGgnXG4gKiAgICAgICAgICAgICAgICAgICBwYXJhbWV0ZXIgaXMgZmFsc3kgb3IgYW4gZW1wdHkgc3RyaW5nLlxuICogQHRocm93cyB7RXJyb3J9IElmIHRoZXJlIHdhcyBhbiBlcnJvciB3aGlsZSBnZXR0aW5nIHRoZSBuYW1lIG9mIGEgbWVkaWEgZmlsZVxuICogICAgICAgICAgICAgICAgIG9yIHRoZSBmaWxlIGNvbnRlbnQgY2Fubm90IGJlIHVwbG9hZGVkIHRvIHRoZSByZW1vdGUgbG9jYXRpb25cbiAqICAgICAgICAgICAgICAgICBvciBzY3JlZW4gcmVjb3JkaW5nIGlzIG5vdCBzdXBwb3J0ZWQgb24gdGhlIGRldmljZSB1bmRlciB0ZXN0LlxuICovXG5jb21tYW5kcy5zdG9wUmVjb3JkaW5nU2NyZWVuID0gYXN5bmMgZnVuY3Rpb24gc3RvcFJlY29yZGluZ1NjcmVlbiAob3B0aW9ucyA9IHt9KSB7XG4gIGF3YWl0IHZlcmlmeVNjcmVlblJlY29yZElzU3VwcG9ydGVkKHRoaXMuYWRiLCB0aGlzLmlzRW11bGF0b3IoKSk7XG5cbiAgaWYgKCFfLmlzRW1wdHkodGhpcy5fc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcykpIHtcbiAgICB0aGlzLl9zY3JlZW5SZWNvcmRpbmdQcm9wZXJ0aWVzLnN0b3BwZWQgPSB0cnVlO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBhd2FpdCB0ZXJtaW5hdGVCYWNrZ3JvdW5kU2NyZWVuUmVjb3JkaW5nKHRoaXMuYWRiLCBmYWxzZSk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIHRoaXMubG9nLndhcm4oZXJyLm1lc3NhZ2UpO1xuICAgIGlmICghXy5pc0VtcHR5KHRoaXMuX3NjcmVlblJlY29yZGluZ1Byb3BlcnRpZXMpKSB7XG4gICAgICB0aGlzLmxvZy53YXJuKCdUaGUgcmVzdWx0aW5nIHZpZGVvIG1pZ2h0IGJlIGNvcnJ1cHRlZCcpO1xuICAgIH1cbiAgfVxuXG4gIGlmIChfLmlzRW1wdHkodGhpcy5fc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcykpIHtcbiAgICB0aGlzLmxvZy5pbmZvKGBTY3JlZW4gcmVjb3JkaW5nIGhhcyBub3QgYmVlbiBwcmV2aW91c2x5IHN0YXJ0ZWQgYnkgQXBwaXVtLiBUaGVyZSBpcyBub3RoaW5nIHRvIHN0b3BgKTtcbiAgICByZXR1cm4gJyc7XG4gIH1cblxuICBpZiAodGhpcy5fc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcy5yZWNvcmRpbmdQcm9jZXNzICYmIHRoaXMuX3NjcmVlblJlY29yZGluZ1Byb3BlcnRpZXMucmVjb3JkaW5nUHJvY2Vzcy5pc1J1bm5pbmcpIHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5fc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcy5yZWNvcmRpbmdQcm9jZXNzLnN0b3AoJ1NJR0lOVCcsIFBST0NFU1NfU0hVVERPV05fVElNRU9VVCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhpcy5sb2cuZXJyb3JBbmRUaHJvdyhgVW5hYmxlIHRvIHN0b3Agc2NyZWVuIHJlY29yZGluZyB3aXRoaW4gJHtQUk9DRVNTX1NIVVRET1dOX1RJTUVPVVR9bXNgKTtcbiAgICB9XG4gICAgdGhpcy5fc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcy5yZWNvcmRpbmdQcm9jZXNzID0gbnVsbDtcbiAgfVxuXG4gIGlmIChfLmlzRW1wdHkodGhpcy5fc2NyZWVuUmVjb3JkaW5nUHJvcGVydGllcy5yZWNvcmRzKSkge1xuICAgIHRoaXMubG9nLmVycm9yQW5kVGhyb3coYE5vIHNjcmVlbiByZWNvcmRpbmdzIGhhdmUgYmVlbiBzdG9yZWQgb24gdGhlIGRldmljZSBzbyBmYXIuIGAgK1xuICAgICAgYEFyZSB5b3Ugc3VyZSB0aGUgJHtTQ1JFRU5SRUNPUkRfQklOQVJZfSB1dGlsaXR5IHdvcmtzIGFzIGV4cGVjdGVkP2ApO1xuICB9XG5cbiAgY29uc3QgdG1wUm9vdCA9IGF3YWl0IHRlbXBEaXIub3BlbkRpcigpO1xuICB0cnkge1xuICAgIGNvbnN0IGxvY2FsUmVjb3JkcyA9IFtdO1xuICAgIGZvciAoY29uc3QgcGF0aE9uRGV2aWNlIG9mIHRoaXMuX3NjcmVlblJlY29yZGluZ1Byb3BlcnRpZXMucmVjb3Jkcykge1xuICAgICAgbG9jYWxSZWNvcmRzLnB1c2gocGF0aC5yZXNvbHZlKHRtcFJvb3QsIHBhdGgucG9zaXguYmFzZW5hbWUocGF0aE9uRGV2aWNlKSkpO1xuICAgICAgYXdhaXQgdGhpcy5hZGIucHVsbChwYXRoT25EZXZpY2UsIF8ubGFzdChsb2NhbFJlY29yZHMpKTtcbiAgICAgIGF3YWl0IHRoaXMuYWRiLnJpbXJhZihwYXRoT25EZXZpY2UpO1xuICAgIH1cbiAgICBsZXQgcmVzdWx0RmlsZVBhdGggPSBfLmxhc3QobG9jYWxSZWNvcmRzKTtcbiAgICBpZiAobG9jYWxSZWNvcmRzLmxlbmd0aCA+IDEpIHtcbiAgICAgIHRoaXMubG9nLmluZm8oYEdvdCAke2xvY2FsUmVjb3Jkcy5sZW5ndGh9IHNjcmVlbiByZWNvcmRpbmdzLiBUcnlpbmcgdG8gbWVyZ2UgdGhlbWApO1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmVzdWx0RmlsZVBhdGggPSBhd2FpdCBtZXJnZVNjcmVlblJlY29yZHMobG9jYWxSZWNvcmRzLCB0aGlzLmxvZyk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRoaXMubG9nLndhcm4oYENhbm5vdCBtZXJnZSB0aGUgcmVjb3JkZWQgZmlsZXMuIFRoZSBtb3N0IHJlY2VudCBzY3JlZW4gcmVjb3JkaW5nIGlzIGdvaW5nIHRvIGJlIHJldHVybmVkIGFzIHRoZSByZXN1bHQuIGAgK1xuICAgICAgICAgIGBPcmlnaW5hbCBlcnJvcjogJHtlLm1lc3NhZ2V9YCk7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChfLmlzRW1wdHkob3B0aW9ucy5yZW1vdGVQYXRoKSkge1xuICAgICAgY29uc3Qge3NpemV9ID0gYXdhaXQgZnMuc3RhdChyZXN1bHRGaWxlUGF0aCk7XG4gICAgICB0aGlzLmxvZy5kZWJ1ZyhgVGhlIHNpemUgb2YgdGhlIHJlc3VsdGluZyBzY3JlZW4gcmVjb3JkaW5nIGlzICR7dXRpbC50b1JlYWRhYmxlU2l6ZVN0cmluZyhzaXplKX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIGF3YWl0IHVwbG9hZFJlY29yZGVkTWVkaWEocmVzdWx0RmlsZVBhdGgsIG9wdGlvbnMucmVtb3RlUGF0aCwgb3B0aW9ucyk7XG4gIH0gZmluYWxseSB7XG4gICAgYXdhaXQgZnMucmltcmFmKHRtcFJvb3QpO1xuICAgIHRoaXMuX3NjcmVlblJlY29yZGluZ1Byb3BlcnRpZXMgPSBudWxsO1xuICB9XG59O1xuXG5cbmV4cG9ydCB7IGNvbW1hbmRzIH07XG5leHBvcnQgZGVmYXVsdCBjb21tYW5kcztcbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBR0EsTUFBTUEsUUFBUSxHQUFHLENBQUMsQ0FBQztBQUFDO0FBRXBCLE1BQU1DLFdBQVcsR0FBRyxHQUFHO0FBQ3ZCLE1BQU1DLGFBQWEsR0FBRyxJQUFJO0FBQzFCLE1BQU1DLHNCQUFzQixHQUFHLEVBQUUs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
@@ -1 +1 @@
1
- {"version":3,"file":"recordscreen.js","names":["commands","RETRY_PAUSE","RETRY_TIMEOUT","MAX_RECORDING_TIME_SEC","MAX_TIME_SEC","DEFAULT_RECORDING_TIME_SEC","PROCESS_SHUTDOWN_TIMEOUT","SCREENRECORD_BINARY","DEFAULT_EXT","MIN_EMULATOR_API_LEVEL","FFMPEG_BINARY","system","isWindows","uploadRecordedMedia","localFile","remotePath","uploadOptions","_","isEmpty","util","toInMemoryBase64","toString","user","pass","method","headers","fileFieldName","formFields","options","auth","net","uploadFile","verifyScreenRecordIsSupported","adb","isEmulator","apiLevel","getApiLevel","Error","scheduleScreenRecord","recordingProperties","log","stopped","timer","videoSize","bitRate","timeLimit","bugReport","currentTimeLimit","hasValue","currentTimeLimitInt","parseInt","isNaN","pathOnDevice","uuidV4","substring","recordingProc","screenrecord","on","currentDuration","getDuration","asSeconds","toFixed","debug","timeLimitInt","chunkDuration","e","error","stack","start","waitForCondition","fileExists","waitMs","intervalMs","records","push","recordingProcess","mergeScreenRecords","mediaFiles","fs","which","configContent","map","x","join","configFile","path","resolve","dirname","writeFile","result","Math","floor","Date","args","info","exec","terminateBackgroundScreenRecording","force","pids","getPIDsByName","p","shell","err","message","startRecordingScreen","forceRestart","stopRecordingScreen","warn","_screenRecordingProperties","record","rimraf","timeout","parseFloat","timing","Timer","isRunning","stop","errorAndThrow","tmpRoot","tempDir","openDir","localRecords","posix","basename","pull","last","resultFilePath","length","size","stat","toReadableSizeString"],"sources":["../../../lib/commands/recordscreen.js"],"sourcesContent":["import _ from 'lodash';\nimport { waitForCondition } from 'asyncbox';\nimport { util, fs, net, tempDir, system, timing } from 'appium/support';\nimport { exec } from 'teen_process';\nimport path from 'path';\n\n\nconst commands = {};\n\nconst RETRY_PAUSE = 300;\nconst RETRY_TIMEOUT = 5000;\nconst MAX_RECORDING_TIME_SEC = 60 * 3;\nconst MAX_TIME_SEC = 60 * 30;\nconst DEFAULT_RECORDING_TIME_SEC = MAX_RECORDING_TIME_SEC;\nconst PROCESS_SHUTDOWN_TIMEOUT = 10 * 1000;\nconst SCREENRECORD_BINARY = 'screenrecord';\nconst DEFAULT_EXT = '.mp4';\nconst MIN_EMULATOR_API_LEVEL = 27;\nconst FFMPEG_BINARY = `ffmpeg${system.isWindows() ? '.exe' : ''}`;\n\nasync function uploadRecordedMedia (localFile, remotePath = null, uploadOptions = {}) {\n if (_.isEmpty(remotePath)) {\n return (await util.toInMemoryBase64(localFile)).toString();\n }\n\n const {user, pass, method, headers, fileFieldName, formFields} = uploadOptions;\n const options = {\n method: method || 'PUT',\n headers,\n fileFieldName,\n formFields,\n };\n if (user && pass) {\n options.auth = {user, pass};\n }\n await net.uploadFile(localFile, remotePath, options);\n return '';\n}\n\nasync function verifyScreenRecordIsSupported (adb, isEmulator) {\n const apiLevel = await adb.getApiLevel();\n if (isEmulator && apiLevel < MIN_EMULATOR_API_LEVEL) {\n throw new Error(`Screen recording does not work on emulators running Android API level less than ${MIN_EMULATOR_API_LEVEL}`);\n }\n if (apiLevel < 19) {\n throw new Error(`Screen recording not available on API Level ${apiLevel}. Minimum API Level is 19.`);\n }\n}\n\nasync function scheduleScreenRecord (adb, recordingProperties, log = null) {\n if (recordingProperties.stopped) {\n return;\n }\n\n const {\n timer,\n videoSize,\n bitRate,\n timeLimit,\n bugReport,\n } = recordingProperties;\n\n let currentTimeLimit = MAX_RECORDING_TIME_SEC;\n if (util.hasValue(recordingProperties.currentTimeLimit)) {\n const currentTimeLimitInt = parseInt(recordingProperties.currentTimeLimit, 10);\n if (!isNaN(currentTimeLimitInt) && currentTimeLimitInt < MAX_RECORDING_TIME_SEC) {\n currentTimeLimit = currentTimeLimitInt;\n }\n }\n const pathOnDevice = `/sdcard/${util.uuidV4().substring(0, 8)}${DEFAULT_EXT}`;\n const recordingProc = adb.screenrecord(pathOnDevice, {\n videoSize,\n bitRate,\n timeLimit: currentTimeLimit,\n bugReport,\n });\n\n recordingProc.on('end', () => {\n if (recordingProperties.stopped || !util.hasValue(timeLimit)) {\n return;\n }\n const currentDuration = timer.getDuration().asSeconds.toFixed(0);\n log?.debug(`The overall screen recording duration is ${currentDuration}s so far`);\n const timeLimitInt = parseInt(timeLimit, 10);\n if (isNaN(timeLimitInt) || currentDuration >= timeLimitInt) {\n log?.debug('There is no need to start the next recording chunk');\n return;\n }\n\n recordingProperties.currentTimeLimit = timeLimitInt - currentDuration;\n const chunkDuration = recordingProperties.currentTimeLimit < MAX_RECORDING_TIME_SEC\n ? recordingProperties.currentTimeLimit\n : MAX_RECORDING_TIME_SEC;\n log?.debug(`Starting the next ${chunkDuration}s-chunk ` +\n `of screen recording in order to achieve ${timeLimitInt}s total duration`);\n (async () => {\n try {\n await scheduleScreenRecord(adb, recordingProperties, log);\n } catch (e) {\n log?.error(e.stack);\n recordingProperties.stopped = true;\n }\n })();\n });\n\n await recordingProc.start(0);\n try {\n await waitForCondition(async () => await adb.fileExists(pathOnDevice),\n {waitMs: RETRY_TIMEOUT, intervalMs: RETRY_PAUSE});\n } catch (e) {\n throw new Error(`The expected screen record file '${pathOnDevice}' does not exist after ${RETRY_TIMEOUT}ms. ` +\n `Is ${SCREENRECORD_BINARY} utility available and operational on the device under test?`);\n }\n\n recordingProperties.records.push(pathOnDevice);\n recordingProperties.recordingProcess = recordingProc;\n}\n\nasync function mergeScreenRecords (mediaFiles, log = null) {\n try {\n await fs.which(FFMPEG_BINARY);\n } catch (e) {\n throw new Error(`${FFMPEG_BINARY} utility is not available in PATH. Please install it from https://www.ffmpeg.org/`);\n }\n const configContent = mediaFiles\n .map((x) => `file '${x}'`)\n .join('\\n');\n const configFile = path.resolve(path.dirname(mediaFiles[0]), 'config.txt');\n await fs.writeFile(configFile, configContent, 'utf8');\n log?.debug(`Generated ffmpeg merging config '${configFile}' with items:\\n${configContent}`);\n const result = path.resolve(path.dirname(mediaFiles[0]), `merge_${Math.floor(new Date())}${DEFAULT_EXT}`);\n const args = ['-safe', '0', '-f', 'concat', '-i', configFile, '-c', 'copy', result];\n log?.info(`Initiating screen records merging using the command '${FFMPEG_BINARY} ${args.join(' ')}'`);\n await exec(FFMPEG_BINARY, args);\n return result;\n}\n\nasync function terminateBackgroundScreenRecording (adb, force = true) {\n const pids = (await adb.getPIDsByName(SCREENRECORD_BINARY))\n .map((p) => `${p}`);\n if (_.isEmpty(pids)) {\n return false;\n }\n\n try {\n await adb.shell(['kill', force ? '-15' : '-2', ...pids]);\n await waitForCondition(async () => _.isEmpty(await adb.getPIDsByName(SCREENRECORD_BINARY)), {\n waitMs: PROCESS_SHUTDOWN_TIMEOUT,\n intervalMs: 500,\n });\n return true;\n } catch (err) {\n throw new Error(`Unable to stop the background screen recording: ${err.message}`);\n }\n}\n\n\n/**\n * @typedef {Object} StartRecordingOptions\n *\n * @property {?string} remotePath - The path to the remote location, where the captured video should be uploaded.\n * The following protocols are supported: http/https, ftp.\n * Null or empty string value (the default setting) means the content of resulting\n * file should be encoded as Base64 and passed as the endpount response value.\n * An exception will be thrown if the generated media file is too big to\n * fit into the available process memory.\n * This option only has an effect if there is screen recording process in progreess\n * and `forceRestart` parameter is not set to `true`.\n * @property {?string} user - The name of the user for the remote authentication. Only works if `remotePath` is provided.\n * @property {?string} pass - The password for the remote authentication. Only works if `remotePath` is provided.\n * @property {?string} method [PUT] - The http multipart upload method name. Only works if `remotePath` is provided.\n * @property {?Object} headers - Additional headers mapping for multipart http(s) uploads\n * @property {?string} fileFieldName [file] - The name of the form field, where the file content BLOB should be stored for\n * http(s) uploads\n * @property {?Object|Array<Pair>} formFields - Additional form fields for multipart http(s) uploads\n * @property {?string} videoSize - The format is widthxheight.\n * The default value is the device's native display resolution (if supported),\n * 1280x720 if not. For best results,\n * use a size supported by your device's Advanced Video Coding (AVC) encoder.\n * For example, \"1280x720\"\n * @property {?boolean} bugReport - Set it to `true` in order to display additional information on the video overlay,\n * such as a timestamp, that is helpful in videos captured to illustrate bugs.\n * This option is only supported since API level 27 (Android P).\n * @property {?string|number} timeLimit - The maximum recording time, in seconds. The default value is 180 (3 minutes).\n * The maximum value is 1800 (30 minutes). If the passed value is greater than 180 then\n * the algorithm will try to schedule multiple screen recording chunks and merge the\n * resulting videos into a single media file using `ffmpeg` utility.\n * If the utility is not available in PATH then the most recent screen recording chunk is\n * going to be returned.\n * @property {?string|number} bitRate - The video bit rate for the video, in bits per second.\n * The default value is 4000000 (4 Mbit/s). You can increase the bit rate to improve video quality,\n * but doing so results in larger movie files.\n * @property {?boolean} forceRestart - Whether to try to catch and upload/return the currently running screen recording\n * (`false`, the default setting) or ignore the result of it and start a new recording\n * immediately (`true`).\n */\n\n/**\n * Record the display of a real devices running Android 4.4 (API level 19) and higher.\n * Emulators are supported since API level 27 (Android P).\n * It records screen activity to an MPEG-4 file. Audio is not recorded with the video file.\n * If screen recording has been already started then the command will stop it forcefully and start a new one.\n * The previously recorded video file will be deleted.\n *\n * @param {?StartRecordingOptions} options - The available options.\n * @returns {string} Base64-encoded content of the recorded media file if\n * any screen recording is currently running or an empty string.\n * @throws {Error} If screen recording has failed to start or is not supported on the device under test.\n */\ncommands.startRecordingScreen = async function startRecordingScreen (options = {}) {\n await verifyScreenRecordIsSupported(this.adb, this.isEmulator());\n\n let result = '';\n const {videoSize, timeLimit = DEFAULT_RECORDING_TIME_SEC, bugReport, bitRate, forceRestart} = options;\n if (!forceRestart) {\n result = await this.stopRecordingScreen(options);\n }\n\n if (await terminateBackgroundScreenRecording(this.adb, true)) {\n this.log.warn(`There were some ${SCREENRECORD_BINARY} process leftovers running ` +\n `in the background. Make sure you stop screen recording each time after it is started, ` +\n `otherwise the recorded media might quickly exceed all the free space on the device under test.`);\n }\n\n if (!_.isEmpty(this._screenRecordingProperties)) {\n for (const record of (this._screenRecordingProperties.records || [])) {\n await this.adb.rimraf(record);\n }\n this._screenRecordingProperties = null;\n }\n\n const timeout = parseFloat(timeLimit);\n if (isNaN(timeout) || timeout > MAX_TIME_SEC || timeout <= 0) {\n throw new Error(`The timeLimit value must be in range [1, ${MAX_TIME_SEC}] seconds. ` +\n `The value of '${timeLimit}' has been passed instead.`);\n }\n\n this._screenRecordingProperties = {\n timer: new timing.Timer().start(),\n videoSize,\n timeLimit,\n currentTimeLimit: timeLimit,\n bitRate,\n bugReport,\n records: [],\n recordingProcess: null,\n stopped: false,\n };\n await scheduleScreenRecord(this.adb, this._screenRecordingProperties, this.log);\n return result;\n};\n\n/**\n * @typedef {Object} StopRecordingOptions\n *\n * @property {?string} remotePath - The path to the remote location, where the resulting video should be uploaded.\n * The following protocols are supported: http/https, ftp.\n * Null or empty string value (the default setting) means the content of resulting\n * file should be encoded as Base64 and passed as the endpount response value.\n * An exception will be thrown if the generated media file is too big to\n * fit into the available process memory.\n * @property {?string} user - The name of the user for the remote authentication.\n * @property {?string} pass - The password for the remote authentication.\n * @property {?string} method - The http multipart upload method name. The 'PUT' one is used by default.\n * @property {?Object} headers - Additional headers mapping for multipart http(s) uploads\n * @property {?string} fileFieldName [file] - The name of the form field, where the file content BLOB should be stored for\n * http(s) uploads\n * @property {?Object|Array<Pair>} formFields - Additional form fields for multipart http(s) uploads\n */\n\n/**\n * Stop recording the screen.\n * If no screen recording has been started before then the method returns an empty string.\n *\n * @param {?StopRecordingOptions} options - The available options.\n * @returns {string} Base64-encoded content of the recorded media file if 'remotePath'\n * parameter is falsy or an empty string.\n * @throws {Error} If there was an error while getting the name of a media file\n * or the file content cannot be uploaded to the remote location\n * or screen recording is not supported on the device under test.\n */\ncommands.stopRecordingScreen = async function stopRecordingScreen (options = {}) {\n await verifyScreenRecordIsSupported(this.adb, this.isEmulator());\n\n if (!_.isEmpty(this._screenRecordingProperties)) {\n this._screenRecordingProperties.stopped = true;\n }\n\n try {\n await terminateBackgroundScreenRecording(this.adb, false);\n } catch (err) {\n this.log.warn(err.message);\n if (!_.isEmpty(this._screenRecordingProperties)) {\n this.log.warn('The resulting video might be corrupted');\n }\n }\n\n if (_.isEmpty(this._screenRecordingProperties)) {\n this.log.info(`Screen recording has not been previously started by Appium. There is nothing to stop`);\n return '';\n }\n\n if (this._screenRecordingProperties.recordingProcess && this._screenRecordingProperties.recordingProcess.isRunning) {\n try {\n await this._screenRecordingProperties.recordingProcess.stop('SIGINT', PROCESS_SHUTDOWN_TIMEOUT);\n } catch (e) {\n this.log.errorAndThrow(`Unable to stop screen recording within ${PROCESS_SHUTDOWN_TIMEOUT}ms`);\n }\n this._screenRecordingProperties.recordingProcess = null;\n }\n\n if (_.isEmpty(this._screenRecordingProperties.records)) {\n this.log.errorAndThrow(`No screen recordings have been stored on the device so far. ` +\n `Are you sure the ${SCREENRECORD_BINARY} utility works as expected?`);\n }\n\n const tmpRoot = await tempDir.openDir();\n try {\n const localRecords = [];\n for (const pathOnDevice of this._screenRecordingProperties.records) {\n localRecords.push(path.resolve(tmpRoot, path.posix.basename(pathOnDevice)));\n await this.adb.pull(pathOnDevice, _.last(localRecords));\n await this.adb.rimraf(pathOnDevice);\n }\n let resultFilePath = _.last(localRecords);\n if (localRecords.length > 1) {\n this.log.info(`Got ${localRecords.length} screen recordings. Trying to merge them`);\n try {\n resultFilePath = await mergeScreenRecords(localRecords, this.log);\n } catch (e) {\n this.log.warn(`Cannot merge the recorded files. The most recent screen recording is going to be returned as the result. ` +\n `Original error: ${e.message}`);\n }\n }\n if (_.isEmpty(options.remotePath)) {\n const {size} = await fs.stat(resultFilePath);\n this.log.debug(`The size of the resulting screen recording is ${util.toReadableSizeString(size)}`);\n }\n return await uploadRecordedMedia(resultFilePath, options.remotePath, options);\n } finally {\n await fs.rimraf(tmpRoot);\n this._screenRecordingProperties = null;\n }\n};\n\n\nexport { commands };\nexport default commands;\n"],"mappings":"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"}
1
+ {"version":3,"file":"recordscreen.js","names":["commands","RETRY_PAUSE","RETRY_TIMEOUT","MAX_RECORDING_TIME_SEC","MAX_TIME_SEC","DEFAULT_RECORDING_TIME_SEC","PROCESS_SHUTDOWN_TIMEOUT","SCREENRECORD_BINARY","DEFAULT_EXT","MIN_EMULATOR_API_LEVEL","FFMPEG_BINARY","system","isWindows","uploadRecordedMedia","localFile","remotePath","uploadOptions","_","isEmpty","util","toInMemoryBase64","toString","user","pass","method","headers","fileFieldName","formFields","options","auth","net","uploadFile","verifyScreenRecordIsSupported","adb","isEmulator","apiLevel","getApiLevel","Error","scheduleScreenRecord","recordingProperties","log","stopped","timer","videoSize","bitRate","timeLimit","bugReport","currentTimeLimit","hasValue","currentTimeLimitInt","parseInt","isNaN","pathOnDevice","uuidV4","substring","recordingProc","screenrecord","on","currentDuration","getDuration","asSeconds","toFixed","debug","timeLimitInt","chunkDuration","e","error","stack","start","waitForCondition","fileExists","waitMs","intervalMs","records","push","recordingProcess","mergeScreenRecords","mediaFiles","fs","which","configContent","map","x","join","configFile","path","resolve","dirname","writeFile","result","Math","floor","Date","args","info","exec","terminateBackgroundScreenRecording","force","pids","getPIDsByName","p","shell","err","message","startRecordingScreen","forceRestart","stopRecordingScreen","warn","_screenRecordingProperties","record","rimraf","timeout","parseFloat","timing","Timer","isRunning","stop","errorAndThrow","tmpRoot","tempDir","openDir","localRecords","posix","basename","pull","last","resultFilePath","length","size","stat","toReadableSizeString"],"sources":["../../../lib/commands/recordscreen.js"],"sourcesContent":["import _ from 'lodash';\nimport { waitForCondition } from 'asyncbox';\nimport { util, fs, net, tempDir, system, timing } from 'appium/support';\nimport { exec } from 'teen_process';\nimport path from 'path';\n\n\nconst commands = {};\n\nconst RETRY_PAUSE = 300;\nconst RETRY_TIMEOUT = 5000;\nconst MAX_RECORDING_TIME_SEC = 60 * 3;\nconst MAX_TIME_SEC = 60 * 30;\nconst DEFAULT_RECORDING_TIME_SEC = MAX_RECORDING_TIME_SEC;\nconst PROCESS_SHUTDOWN_TIMEOUT = 10 * 1000;\nconst SCREENRECORD_BINARY = 'screenrecord';\nconst DEFAULT_EXT = '.mp4';\nconst MIN_EMULATOR_API_LEVEL = 27;\nconst FFMPEG_BINARY = `ffmpeg${system.isWindows() ? '.exe' : ''}`;\n\nasync function uploadRecordedMedia (localFile, remotePath = null, uploadOptions = {}) {\n if (_.isEmpty(remotePath)) {\n return (await util.toInMemoryBase64(localFile)).toString();\n }\n\n const {user, pass, method, headers, fileFieldName, formFields} = uploadOptions;\n const options = {\n method: method || 'PUT',\n headers,\n fileFieldName,\n formFields,\n };\n if (user && pass) {\n options.auth = {user, pass};\n }\n await net.uploadFile(localFile, remotePath, options);\n return '';\n}\n\nasync function verifyScreenRecordIsSupported (adb, isEmulator) {\n const apiLevel = await adb.getApiLevel();\n if (isEmulator && apiLevel < MIN_EMULATOR_API_LEVEL) {\n throw new Error(`Screen recording does not work on emulators running Android API level less than ${MIN_EMULATOR_API_LEVEL}`);\n }\n if (apiLevel < 19) {\n throw new Error(`Screen recording not available on API Level ${apiLevel}. Minimum API Level is 19.`);\n }\n}\n\nasync function scheduleScreenRecord (adb, recordingProperties, log = null) {\n if (recordingProperties.stopped) {\n return;\n }\n\n const {\n timer,\n videoSize,\n bitRate,\n timeLimit,\n bugReport,\n } = recordingProperties;\n\n let currentTimeLimit = MAX_RECORDING_TIME_SEC;\n if (util.hasValue(recordingProperties.currentTimeLimit)) {\n const currentTimeLimitInt = parseInt(recordingProperties.currentTimeLimit, 10);\n if (!isNaN(currentTimeLimitInt) && currentTimeLimitInt < MAX_RECORDING_TIME_SEC) {\n currentTimeLimit = currentTimeLimitInt;\n }\n }\n const pathOnDevice = `/sdcard/${util.uuidV4().substring(0, 8)}${DEFAULT_EXT}`;\n const recordingProc = adb.screenrecord(pathOnDevice, {\n videoSize,\n bitRate,\n timeLimit: currentTimeLimit,\n bugReport,\n });\n\n recordingProc.on('end', () => {\n if (recordingProperties.stopped || !util.hasValue(timeLimit)) {\n return;\n }\n const currentDuration = timer.getDuration().asSeconds.toFixed(0);\n log?.debug(`The overall screen recording duration is ${currentDuration}s so far`);\n const timeLimitInt = parseInt(timeLimit, 10);\n if (isNaN(timeLimitInt) || currentDuration >= timeLimitInt) {\n log?.debug('There is no need to start the next recording chunk');\n return;\n }\n\n recordingProperties.currentTimeLimit = timeLimitInt - currentDuration;\n const chunkDuration = recordingProperties.currentTimeLimit < MAX_RECORDING_TIME_SEC\n ? recordingProperties.currentTimeLimit\n : MAX_RECORDING_TIME_SEC;\n log?.debug(`Starting the next ${chunkDuration}s-chunk ` +\n `of screen recording in order to achieve ${timeLimitInt}s total duration`);\n (async () => {\n try {\n await scheduleScreenRecord(adb, recordingProperties, log);\n } catch (e) {\n log?.error(e.stack);\n recordingProperties.stopped = true;\n }\n })();\n });\n\n await recordingProc.start(0);\n try {\n await waitForCondition(async () => await adb.fileExists(pathOnDevice),\n {waitMs: RETRY_TIMEOUT, intervalMs: RETRY_PAUSE});\n } catch (e) {\n throw new Error(`The expected screen record file '${pathOnDevice}' does not exist after ${RETRY_TIMEOUT}ms. ` +\n `Is ${SCREENRECORD_BINARY} utility available and operational on the device under test?`);\n }\n\n recordingProperties.records.push(pathOnDevice);\n recordingProperties.recordingProcess = recordingProc;\n}\n\nasync function mergeScreenRecords (mediaFiles, log = null) {\n try {\n await fs.which(FFMPEG_BINARY);\n } catch (e) {\n throw new Error(`${FFMPEG_BINARY} utility is not available in PATH. Please install it from https://www.ffmpeg.org/`);\n }\n const configContent = mediaFiles\n .map((x) => `file '${x}'`)\n .join('\\n');\n const configFile = path.resolve(path.dirname(mediaFiles[0]), 'config.txt');\n await fs.writeFile(configFile, configContent, 'utf8');\n log?.debug(`Generated ffmpeg merging config '${configFile}' with items:\\n${configContent}`);\n const result = path.resolve(path.dirname(mediaFiles[0]), `merge_${Math.floor(new Date())}${DEFAULT_EXT}`);\n const args = ['-safe', '0', '-f', 'concat', '-i', configFile, '-c', 'copy', result];\n log?.info(`Initiating screen records merging using the command '${FFMPEG_BINARY} ${args.join(' ')}'`);\n await exec(FFMPEG_BINARY, args);\n return result;\n}\n\nasync function terminateBackgroundScreenRecording (adb, force = true) {\n const pids = (await adb.getPIDsByName(SCREENRECORD_BINARY))\n .map((p) => `${p}`);\n if (_.isEmpty(pids)) {\n return false;\n }\n\n try {\n await adb.shell(['kill', force ? '-15' : '-2', ...pids]);\n await waitForCondition(async () => _.isEmpty(await adb.getPIDsByName(SCREENRECORD_BINARY)), {\n waitMs: PROCESS_SHUTDOWN_TIMEOUT,\n intervalMs: 500,\n });\n return true;\n } catch (err) {\n throw new Error(`Unable to stop the background screen recording: ${err.message}`);\n }\n}\n\n\n/**\n * @typedef {Object} StartRecordingOptions\n *\n * @property {?string} remotePath - The path to the remote location, where the captured video should be uploaded.\n * The following protocols are supported: http/https, ftp.\n * Null or empty string value (the default setting) means the content of resulting\n * file should be encoded as Base64 and passed as the endpount response value.\n * An exception will be thrown if the generated media file is too big to\n * fit into the available process memory.\n * This option only has an effect if there is screen recording process in progreess\n * and `forceRestart` parameter is not set to `true`.\n * @property {?string} user - The name of the user for the remote authentication. Only works if `remotePath` is provided.\n * @property {?string} pass - The password for the remote authentication. Only works if `remotePath` is provided.\n * @property {?string} method [PUT] - The http multipart upload method name. Only works if `remotePath` is provided.\n * @property {?Object} headers - Additional headers mapping for multipart http(s) uploads\n * @property {?string} fileFieldName [file] - The name of the form field, where the file content BLOB should be stored for\n * http(s) uploads\n * @property {?Object|Array<Pair>} formFields - Additional form fields for multipart http(s) uploads\n * @property {?string} videoSize - The format is widthxheight.\n * The default value is the device's native display resolution (if supported),\n * 1280x720 if not. For best results,\n * use a size supported by your device's Advanced Video Coding (AVC) encoder.\n * For example, \"1280x720\"\n * @property {?boolean} bugReport - Set it to `true` in order to display additional information on the video overlay,\n * such as a timestamp, that is helpful in videos captured to illustrate bugs.\n * This option is only supported since API level 27 (Android P).\n * @property {?string|number} timeLimit - The maximum recording time, in seconds. The default value is 180 (3 minutes).\n * The maximum value is 1800 (30 minutes). If the passed value is greater than 180 then\n * the algorithm will try to schedule multiple screen recording chunks and merge the\n * resulting videos into a single media file using `ffmpeg` utility.\n * If the utility is not available in PATH then the most recent screen recording chunk is\n * going to be returned.\n * @property {?string|number} bitRate - The video bit rate for the video, in bits per second.\n * The default value is 4000000 (4 Mbit/s). You can increase the bit rate to improve video quality,\n * but doing so results in larger movie files.\n * @property {?boolean} forceRestart - Whether to try to catch and upload/return the currently running screen recording\n * (`false`, the default setting) or ignore the result of it and start a new recording\n * immediately (`true`).\n */\n\n/**\n * Record the display of a real devices running Android 4.4 (API level 19) and higher.\n * Emulators are supported since API level 27 (Android P).\n * It records screen activity to an MPEG-4 file. Audio is not recorded with the video file.\n * If screen recording has been already started then the command will stop it forcefully and start a new one.\n * The previously recorded video file will be deleted.\n *\n * @param {?StartRecordingOptions} options - The available options.\n * @returns {string} Base64-encoded content of the recorded media file if\n * any screen recording is currently running or an empty string.\n * @throws {Error} If screen recording has failed to start or is not supported on the device under test.\n */\ncommands.startRecordingScreen = async function startRecordingScreen (options = {}) {\n await verifyScreenRecordIsSupported(this.adb, this.isEmulator());\n\n let result = '';\n const {videoSize, timeLimit = DEFAULT_RECORDING_TIME_SEC, bugReport, bitRate, forceRestart} = options;\n if (!forceRestart) {\n result = await this.stopRecordingScreen(options);\n }\n\n if (await terminateBackgroundScreenRecording(this.adb, true)) {\n this.log.warn(`There were some ${SCREENRECORD_BINARY} process leftovers running ` +\n `in the background. Make sure you stop screen recording each time after it is started, ` +\n `otherwise the recorded media might quickly exceed all the free space on the device under test.`);\n }\n\n if (!_.isEmpty(this._screenRecordingProperties)) {\n for (const record of (this._screenRecordingProperties.records || [])) {\n await this.adb.rimraf(record);\n }\n this._screenRecordingProperties = null;\n }\n\n const timeout = parseFloat(timeLimit);\n if (isNaN(timeout) || timeout > MAX_TIME_SEC || timeout <= 0) {\n throw new Error(`The timeLimit value must be in range [1, ${MAX_TIME_SEC}] seconds. ` +\n `The value of '${timeLimit}' has been passed instead.`);\n }\n\n this._screenRecordingProperties = {\n timer: new timing.Timer().start(),\n videoSize,\n timeLimit,\n currentTimeLimit: timeLimit,\n bitRate,\n bugReport,\n records: [],\n recordingProcess: null,\n stopped: false,\n };\n await scheduleScreenRecord(this.adb, this._screenRecordingProperties, this.log);\n return result;\n};\n\n/**\n * @typedef {Object} StopRecordingOptions\n *\n * @property {?string} remotePath - The path to the remote location, where the resulting video should be uploaded.\n * The following protocols are supported: http/https, ftp.\n * Null or empty string value (the default setting) means the content of resulting\n * file should be encoded as Base64 and passed as the endpount response value.\n * An exception will be thrown if the generated media file is too big to\n * fit into the available process memory.\n * @property {?string} user - The name of the user for the remote authentication.\n * @property {?string} pass - The password for the remote authentication.\n * @property {?string} method - The http multipart upload method name. The 'PUT' one is used by default.\n * @property {?Object} headers - Additional headers mapping for multipart http(s) uploads\n * @property {?string} fileFieldName [file] - The name of the form field, where the file content BLOB should be stored for\n * http(s) uploads\n * @property {?Object|Array<Pair>} formFields - Additional form fields for multipart http(s) uploads\n */\n\n/**\n * Stop recording the screen.\n * If no screen recording has been started before then the method returns an empty string.\n *\n * @param {?StopRecordingOptions} options - The available options.\n * @returns {string} Base64-encoded content of the recorded media file if 'remotePath'\n * parameter is falsy or an empty string.\n * @throws {Error} If there was an error while getting the name of a media file\n * or the file content cannot be uploaded to the remote location\n * or screen recording is not supported on the device under test.\n */\ncommands.stopRecordingScreen = async function stopRecordingScreen (options = {}) {\n await verifyScreenRecordIsSupported(this.adb, this.isEmulator());\n\n if (!_.isEmpty(this._screenRecordingProperties)) {\n this._screenRecordingProperties.stopped = true;\n }\n\n try {\n await terminateBackgroundScreenRecording(this.adb, false);\n } catch (err) {\n this.log.warn(err.message);\n if (!_.isEmpty(this._screenRecordingProperties)) {\n this.log.warn('The resulting video might be corrupted');\n }\n }\n\n if (_.isEmpty(this._screenRecordingProperties)) {\n this.log.info(`Screen recording has not been previously started by Appium. There is nothing to stop`);\n return '';\n }\n\n if (this._screenRecordingProperties.recordingProcess && this._screenRecordingProperties.recordingProcess.isRunning) {\n try {\n await this._screenRecordingProperties.recordingProcess.stop('SIGINT', PROCESS_SHUTDOWN_TIMEOUT);\n } catch (e) {\n this.log.errorAndThrow(`Unable to stop screen recording within ${PROCESS_SHUTDOWN_TIMEOUT}ms`);\n }\n this._screenRecordingProperties.recordingProcess = null;\n }\n\n if (_.isEmpty(this._screenRecordingProperties.records)) {\n this.log.errorAndThrow(`No screen recordings have been stored on the device so far. ` +\n `Are you sure the ${SCREENRECORD_BINARY} utility works as expected?`);\n }\n\n const tmpRoot = await tempDir.openDir();\n try {\n const localRecords = [];\n for (const pathOnDevice of this._screenRecordingProperties.records) {\n localRecords.push(path.resolve(tmpRoot, path.posix.basename(pathOnDevice)));\n await this.adb.pull(pathOnDevice, _.last(localRecords));\n await this.adb.rimraf(pathOnDevice);\n }\n let resultFilePath = _.last(localRecords);\n if (localRecords.length > 1) {\n this.log.info(`Got ${localRecords.length} screen recordings. Trying to merge them`);\n try {\n resultFilePath = await mergeScreenRecords(localRecords, this.log);\n } catch (e) {\n this.log.warn(`Cannot merge the recorded files. The most recent screen recording is going to be returned as the result. ` +\n `Original error: ${e.message}`);\n }\n }\n if (_.isEmpty(options.remotePath)) {\n const {size} = await fs.stat(resultFilePath);\n this.log.debug(`The size of the resulting screen recording is ${util.toReadableSizeString(size)}`);\n }\n return await uploadRecordedMedia(resultFilePath, options.remotePath, options);\n } finally {\n await fs.rimraf(tmpRoot);\n this._screenRecordingProperties = null;\n }\n};\n\n\nexport { commands };\nexport default commands;\n"],"mappings":"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"}