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.
- package/build/index.js +1 -9
- package/build/lib/android-helpers.js +10 -194
- package/build/lib/android-helpers.js.map +1 -1
- package/build/lib/bootstrap.js +4 -45
- package/build/lib/bootstrap.js.map +1 -1
- package/build/lib/commands/actions.js +3 -78
- package/build/lib/commands/actions.js.map +1 -1
- package/build/lib/commands/alert.js +3 -10
- package/build/lib/commands/alert.js.map +1 -1
- package/build/lib/commands/app-management.js +4 -32
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/context.js +6 -78
- package/build/lib/commands/context.js.map +1 -1
- package/build/lib/commands/coverage.js +1 -6
- package/build/lib/commands/coverage.js.map +1 -1
- package/build/lib/commands/element.js +4 -47
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/emu-console.js +2 -7
- package/build/lib/commands/emu-console.js.map +1 -1
- package/build/lib/commands/execute.js +1 -13
- package/build/lib/commands/execute.js.map +1 -1
- package/build/lib/commands/file-actions.js +3 -44
- package/build/lib/commands/file-actions.js.map +1 -1
- package/build/lib/commands/find.js +3 -16
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/general.js +32 -91
- package/build/lib/commands/general.js.map +1 -1
- package/build/lib/commands/ime.js +3 -14
- package/build/lib/commands/ime.js.map +1 -1
- package/build/lib/commands/index.js +3 -27
- package/build/lib/commands/index.js.map +1 -1
- package/build/lib/commands/intent.js +1 -40
- package/build/lib/commands/intent.js.map +1 -1
- package/build/lib/commands/log.js +3 -35
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/media-projection.js +2 -47
- package/build/lib/commands/media-projection.js.map +1 -1
- package/build/lib/commands/network.js +4 -40
- package/build/lib/commands/network.js.map +1 -1
- package/build/lib/commands/performance.js +5 -57
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/recordscreen.js +1 -59
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/commands/shell.js +1 -15
- package/build/lib/commands/shell.js.map +1 -1
- package/build/lib/commands/streamscreen.js +7 -74
- package/build/lib/commands/streamscreen.js.map +1 -1
- package/build/lib/commands/system-bars.js +1 -23
- package/build/lib/commands/system-bars.js.map +1 -1
- package/build/lib/commands/touch.js +13 -79
- package/build/lib/commands/touch.js.map +1 -1
- package/build/lib/desired-caps.js +3 -4
- package/build/lib/desired-caps.js.map +1 -1
- package/build/lib/driver.js +8 -97
- package/build/lib/driver.js.map +1 -1
- package/build/lib/logger.js +1 -5
- package/build/lib/logger.js.map +1 -1
- package/build/lib/uiautomator.js +3 -24
- package/build/lib/uiautomator.js.map +1 -1
- package/build/lib/unlock-helpers.js +1 -61
- package/build/lib/unlock-helpers.js.map +1 -1
- package/build/lib/utils.js +1 -7
- package/build/lib/utils.js.map +1 -1
- package/build/lib/webview-helpers.js +1 -94
- package/build/lib/webview-helpers.js.map +1 -1
- package/lib/android-helpers.js +2 -1
- package/lib/commands/general.js +34 -15
- 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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"}
|