appium-adb 9.10.2 → 9.10.3
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/README.md +1 -1
- package/lib/helpers.js +26 -3
- package/lib/tools/apk-signing.js +3 -4
- package/package.json +39 -26
- package/build/index.js +0 -30
- package/build/lib/adb.js +0 -132
- package/build/lib/helpers.js +0 -957
- package/build/lib/logcat.js +0 -221
- package/build/lib/logger.js +0 -18
- package/build/lib/tools/aab-utils.js +0 -157
- package/build/lib/tools/adb-commands.js +0 -1150
- package/build/lib/tools/adb-emu-commands.js +0 -397
- package/build/lib/tools/android-manifest.js +0 -231
- package/build/lib/tools/apk-signing.js +0 -333
- package/build/lib/tools/apk-utils.js +0 -992
- package/build/lib/tools/apks-utils.js +0 -219
- package/build/lib/tools/index.js +0 -49
- package/build/lib/tools/keyboard-commands.js +0 -71
- package/build/lib/tools/lockmgmt.js +0 -224
- package/build/lib/tools/settings-client-commands.js +0 -362
- package/build/lib/tools/system-calls.js +0 -1064
|
@@ -1,992 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
|
|
5
|
-
Object.defineProperty(exports, "__esModule", {
|
|
6
|
-
value: true
|
|
7
|
-
});
|
|
8
|
-
exports.default = exports.REMOTE_CACHE_ROOT = void 0;
|
|
9
|
-
|
|
10
|
-
require("source-map-support/register");
|
|
11
|
-
|
|
12
|
-
var _helpers = require("../helpers.js");
|
|
13
|
-
|
|
14
|
-
var _teen_process = require("teen_process");
|
|
15
|
-
|
|
16
|
-
var _logger = _interopRequireDefault(require("../logger.js"));
|
|
17
|
-
|
|
18
|
-
var _path = _interopRequireDefault(require("path"));
|
|
19
|
-
|
|
20
|
-
var _lodash = _interopRequireDefault(require("lodash"));
|
|
21
|
-
|
|
22
|
-
var _asyncbox = require("asyncbox");
|
|
23
|
-
|
|
24
|
-
var _support = require("@appium/support");
|
|
25
|
-
|
|
26
|
-
var _semver = _interopRequireDefault(require("semver"));
|
|
27
|
-
|
|
28
|
-
var _os = _interopRequireDefault(require("os"));
|
|
29
|
-
|
|
30
|
-
var _lruCache = _interopRequireDefault(require("lru-cache"));
|
|
31
|
-
|
|
32
|
-
var _adbkitApkreader = _interopRequireDefault(require("adbkit-apkreader"));
|
|
33
|
-
|
|
34
|
-
const apkUtilsMethods = {};
|
|
35
|
-
const ACTIVITIES_TROUBLESHOOTING_LINK = 'https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/android/activity-startup.md';
|
|
36
|
-
apkUtilsMethods.APP_INSTALL_STATE = {
|
|
37
|
-
UNKNOWN: 'unknown',
|
|
38
|
-
NOT_INSTALLED: 'notInstalled',
|
|
39
|
-
NEWER_VERSION_INSTALLED: 'newerVersionInstalled',
|
|
40
|
-
SAME_VERSION_INSTALLED: 'sameVersionInstalled',
|
|
41
|
-
OLDER_VERSION_INSTALLED: 'olderVersionInstalled'
|
|
42
|
-
};
|
|
43
|
-
const REMOTE_CACHE_ROOT = '/data/local/tmp/appium_cache';
|
|
44
|
-
exports.REMOTE_CACHE_ROOT = REMOTE_CACHE_ROOT;
|
|
45
|
-
|
|
46
|
-
apkUtilsMethods.isAppInstalled = async function isAppInstalled(pkg) {
|
|
47
|
-
_logger.default.debug(`Getting install status for ${pkg}`);
|
|
48
|
-
|
|
49
|
-
const installedPattern = new RegExp(`^\\s*Package\\s+\\[${_lodash.default.escapeRegExp(pkg)}\\][^:]+:$`, 'm');
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
const stdout = await this.shell(['dumpsys', 'package', pkg]);
|
|
53
|
-
const isInstalled = installedPattern.test(stdout);
|
|
54
|
-
|
|
55
|
-
_logger.default.debug(`'${pkg}' is${!isInstalled ? ' not' : ''} installed`);
|
|
56
|
-
|
|
57
|
-
return isInstalled;
|
|
58
|
-
} catch (e) {
|
|
59
|
-
throw new Error(`Error finding if '${pkg}' is installed. Original error: ${e.message}`);
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
apkUtilsMethods.startUri = async function startUri(uri, pkg, opts = {}) {
|
|
64
|
-
const {
|
|
65
|
-
waitForLaunch = true
|
|
66
|
-
} = opts;
|
|
67
|
-
|
|
68
|
-
if (!uri || !pkg) {
|
|
69
|
-
throw new Error('URI and package arguments are required');
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const args = ['am', 'start'];
|
|
73
|
-
|
|
74
|
-
if (waitForLaunch) {
|
|
75
|
-
args.push('-W');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
args.push('-a', 'android.intent.action.VIEW', '-d', (0, _helpers.escapeShellArg)(uri), pkg);
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
const res = await this.shell(args);
|
|
82
|
-
|
|
83
|
-
if (res.toLowerCase().includes('unable to resolve intent')) {
|
|
84
|
-
throw new Error(res);
|
|
85
|
-
}
|
|
86
|
-
} catch (e) {
|
|
87
|
-
throw new Error(`Error attempting to start URI. Original error: ${e}`);
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
apkUtilsMethods.startApp = async function startApp(startAppOptions = {}) {
|
|
92
|
-
if (!startAppOptions.pkg || !(startAppOptions.activity || startAppOptions.action)) {
|
|
93
|
-
throw new Error('pkg, and activity or intent action, are required to start an application');
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
startAppOptions = _lodash.default.clone(startAppOptions);
|
|
97
|
-
|
|
98
|
-
if (startAppOptions.activity) {
|
|
99
|
-
startAppOptions.activity = startAppOptions.activity.replace('$', '\\$');
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
_lodash.default.defaults(startAppOptions, {
|
|
103
|
-
waitPkg: startAppOptions.pkg,
|
|
104
|
-
waitForLaunch: true,
|
|
105
|
-
waitActivity: false,
|
|
106
|
-
retry: true,
|
|
107
|
-
stopApp: true
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
startAppOptions.waitPkg = startAppOptions.waitPkg || startAppOptions.pkg;
|
|
111
|
-
const apiLevel = await this.getApiLevel();
|
|
112
|
-
const cmd = (0, _helpers.buildStartCmd)(startAppOptions, apiLevel);
|
|
113
|
-
const intentName = `${startAppOptions.action}${startAppOptions.optionalIntentArguments ? ' ' + startAppOptions.optionalIntentArguments : ''}`;
|
|
114
|
-
|
|
115
|
-
try {
|
|
116
|
-
const shellOpts = {};
|
|
117
|
-
|
|
118
|
-
if (_lodash.default.isInteger(startAppOptions.waitDuration) && startAppOptions.waitDuration >= 0) {
|
|
119
|
-
shellOpts.timeout = startAppOptions.waitDuration;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const stdout = await this.shell(cmd, shellOpts);
|
|
123
|
-
|
|
124
|
-
if (stdout.includes('Error: Activity class') && stdout.includes('does not exist')) {
|
|
125
|
-
if (startAppOptions.retry && !startAppOptions.activity.startsWith('.')) {
|
|
126
|
-
_logger.default.debug(`We tried to start an activity that doesn't exist, ` + `retrying with '.${startAppOptions.activity}' activity name`);
|
|
127
|
-
|
|
128
|
-
startAppOptions.activity = `.${startAppOptions.activity}`;
|
|
129
|
-
startAppOptions.retry = false;
|
|
130
|
-
return await this.startApp(startAppOptions);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
throw new Error(`Activity name '${startAppOptions.activity}' used to start the app doesn't ` + `exist or cannot be launched! Make sure it exists and is a launchable activity`);
|
|
134
|
-
} else if (stdout.includes('Error: Intent does not match any activities') || stdout.includes('Error: Activity not started, unable to resolve Intent')) {
|
|
135
|
-
throw new Error(`Activity for intent '${intentName}' used to start the app doesn't ` + `exist or cannot be launched! Make sure it exists and is a launchable activity`);
|
|
136
|
-
} else if (stdout.includes('java.lang.SecurityException')) {
|
|
137
|
-
throw new Error(`The permission to start '${startAppOptions.activity}' activity has been denied.` + `Make sure the activity/package names are correct.`);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (startAppOptions.waitActivity) {
|
|
141
|
-
await this.waitForActivity(startAppOptions.waitPkg, startAppOptions.waitActivity, startAppOptions.waitDuration);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return stdout;
|
|
145
|
-
} catch (e) {
|
|
146
|
-
const appDescriptor = startAppOptions.pkg || intentName;
|
|
147
|
-
throw new Error(`Cannot start the '${appDescriptor}' application. ` + `Visit ${ACTIVITIES_TROUBLESHOOTING_LINK} for troubleshooting. ` + `Original error: ${e.message}`);
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
apkUtilsMethods.dumpWindows = async function dumpWindows() {
|
|
152
|
-
const apiLevel = await this.getApiLevel();
|
|
153
|
-
const dumpsysArg = apiLevel >= 29 ? 'displays' : 'windows';
|
|
154
|
-
const cmd = ['dumpsys', 'window', dumpsysArg];
|
|
155
|
-
return await this.shell(cmd);
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
apkUtilsMethods.getFocusedPackageAndActivity = async function getFocusedPackageAndActivity() {
|
|
159
|
-
_logger.default.debug('Getting focused package and activity');
|
|
160
|
-
|
|
161
|
-
let stdout;
|
|
162
|
-
|
|
163
|
-
try {
|
|
164
|
-
stdout = await this.dumpWindows();
|
|
165
|
-
} catch (e) {
|
|
166
|
-
throw new Error(`Could not retrieve the currently focused package and activity. Original error: ${e.message}`);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const nullFocusedAppRe = /^\s*mFocusedApp=null/m;
|
|
170
|
-
const focusedAppRe = new RegExp('^\\s*mFocusedApp.+Record\\{.*\\s([^\\s\\/\\}]+)\\/([^\\s\\/\\}\\,]+)\\,?(\\s[^\\s\\/\\}]+)*\\}', 'mg');
|
|
171
|
-
const nullCurrentFocusRe = /^\s*mCurrentFocus=null/m;
|
|
172
|
-
const currentFocusAppRe = new RegExp('^\\s*mCurrentFocus.+\\{.+\\s([^\\s\\/]+)\\/([^\\s]+)\\b', 'mg');
|
|
173
|
-
const focusedAppCandidates = [];
|
|
174
|
-
const currentFocusAppCandidates = [];
|
|
175
|
-
|
|
176
|
-
for (const [candidates, pattern] of [[focusedAppCandidates, focusedAppRe], [currentFocusAppCandidates, currentFocusAppRe]]) {
|
|
177
|
-
let match;
|
|
178
|
-
|
|
179
|
-
while (match = pattern.exec(stdout)) {
|
|
180
|
-
candidates.push({
|
|
181
|
-
appPackage: match[1].trim(),
|
|
182
|
-
appActivity: match[2].trim()
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (focusedAppCandidates.length > 1 && currentFocusAppCandidates.length > 0) {
|
|
188
|
-
var _$intersectionWith$;
|
|
189
|
-
|
|
190
|
-
return (_$intersectionWith$ = _lodash.default.intersectionWith(focusedAppCandidates, currentFocusAppCandidates, _lodash.default.isEqual)[0]) !== null && _$intersectionWith$ !== void 0 ? _$intersectionWith$ : focusedAppCandidates[0];
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (focusedAppCandidates.length > 0 || currentFocusAppCandidates.length > 0) {
|
|
194
|
-
var _focusedAppCandidates;
|
|
195
|
-
|
|
196
|
-
return (_focusedAppCandidates = focusedAppCandidates[0]) !== null && _focusedAppCandidates !== void 0 ? _focusedAppCandidates : currentFocusAppCandidates[0];
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
for (const pattern of [nullFocusedAppRe, nullCurrentFocusRe]) {
|
|
200
|
-
if (pattern.exec(stdout)) {
|
|
201
|
-
return {
|
|
202
|
-
appPackage: null,
|
|
203
|
-
appActivity: null
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
_logger.default.debug(stdout);
|
|
209
|
-
|
|
210
|
-
throw new Error('Could not retrieve the currently focused package and activity');
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
apkUtilsMethods.waitForActivityOrNot = async function waitForActivityOrNot(pkg, activity, waitForStop, waitMs = 20000) {
|
|
214
|
-
if (!pkg || !activity) {
|
|
215
|
-
throw new Error('Package and activity required.');
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
_logger.default.debug(`Waiting up to ${waitMs}ms for activity matching pkg: '${pkg}' and ` + `activity: '${activity}' to${waitForStop ? ' not' : ''} be focused`);
|
|
219
|
-
|
|
220
|
-
const splitNames = names => names.split(',').map(name => name.trim());
|
|
221
|
-
|
|
222
|
-
const allPackages = splitNames(pkg);
|
|
223
|
-
const allActivities = splitNames(activity);
|
|
224
|
-
const possibleActivityNames = [];
|
|
225
|
-
|
|
226
|
-
for (const oneActivity of allActivities) {
|
|
227
|
-
if (oneActivity.startsWith('.')) {
|
|
228
|
-
for (const currentPkg of allPackages) {
|
|
229
|
-
possibleActivityNames.push(`${currentPkg}${oneActivity}`.replace(/\.+/g, '.'));
|
|
230
|
-
}
|
|
231
|
-
} else {
|
|
232
|
-
possibleActivityNames.push(oneActivity);
|
|
233
|
-
possibleActivityNames.push(`${pkg}.${oneActivity}`);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
_logger.default.debug(`Possible activities, to be checked: ${possibleActivityNames.map(name => `'${name}'`).join(', ')}`);
|
|
238
|
-
|
|
239
|
-
const possibleActivityPatterns = possibleActivityNames.map(actName => new RegExp(`^${actName.replace(/\./g, '\\.').replace(/\*/g, '.*?').replace(/\$/g, '\\$')}$`));
|
|
240
|
-
|
|
241
|
-
const conditionFunc = async () => {
|
|
242
|
-
let appPackage;
|
|
243
|
-
let appActivity;
|
|
244
|
-
|
|
245
|
-
try {
|
|
246
|
-
({
|
|
247
|
-
appPackage,
|
|
248
|
-
appActivity
|
|
249
|
-
} = await this.getFocusedPackageAndActivity());
|
|
250
|
-
} catch (e) {
|
|
251
|
-
_logger.default.debug(e.message);
|
|
252
|
-
|
|
253
|
-
return false;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (appActivity && appPackage) {
|
|
257
|
-
const fullyQualifiedActivity = appActivity.startsWith('.') ? `${appPackage}${appActivity}` : appActivity;
|
|
258
|
-
|
|
259
|
-
_logger.default.debug(`Found package: '${appPackage}' and fully qualified activity name : '${fullyQualifiedActivity}'`);
|
|
260
|
-
|
|
261
|
-
const isActivityFound = _lodash.default.includes(allPackages, appPackage) && possibleActivityPatterns.some(p => p.test(fullyQualifiedActivity));
|
|
262
|
-
|
|
263
|
-
if (!waitForStop && isActivityFound || waitForStop && !isActivityFound) {
|
|
264
|
-
return true;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
_logger.default.debug('Incorrect package and activity. Retrying.');
|
|
269
|
-
|
|
270
|
-
return false;
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
try {
|
|
274
|
-
await (0, _asyncbox.waitForCondition)(conditionFunc, {
|
|
275
|
-
waitMs: parseInt(waitMs, 10),
|
|
276
|
-
intervalMs: 500
|
|
277
|
-
});
|
|
278
|
-
} catch (e) {
|
|
279
|
-
throw new Error(`${possibleActivityNames.map(name => `'${name}'`).join(' or ')} never ${waitForStop ? 'stopped' : 'started'}. ` + `Visit ${ACTIVITIES_TROUBLESHOOTING_LINK} for troubleshooting`);
|
|
280
|
-
}
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
apkUtilsMethods.waitForActivity = async function waitForActivity(pkg, act, waitMs = 20000) {
|
|
284
|
-
await this.waitForActivityOrNot(pkg, act, false, waitMs);
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
apkUtilsMethods.waitForNotActivity = async function waitForNotActivity(pkg, act, waitMs = 20000) {
|
|
288
|
-
await this.waitForActivityOrNot(pkg, act, true, waitMs);
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
apkUtilsMethods.uninstallApk = async function uninstallApk(pkg, options = {}) {
|
|
292
|
-
_logger.default.debug(`Uninstalling ${pkg}`);
|
|
293
|
-
|
|
294
|
-
if (!(await this.isAppInstalled(pkg))) {
|
|
295
|
-
_logger.default.info(`${pkg} was not uninstalled, because it was not present on the device`);
|
|
296
|
-
|
|
297
|
-
return false;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
const cmd = ['uninstall'];
|
|
301
|
-
|
|
302
|
-
if (options.keepData) {
|
|
303
|
-
cmd.push('-k');
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
cmd.push(pkg);
|
|
307
|
-
let stdout;
|
|
308
|
-
|
|
309
|
-
try {
|
|
310
|
-
await this.forceStop(pkg);
|
|
311
|
-
stdout = (await this.adbExec(cmd, {
|
|
312
|
-
timeout: options.timeout
|
|
313
|
-
})).trim();
|
|
314
|
-
} catch (e) {
|
|
315
|
-
throw new Error(`Unable to uninstall APK. Original error: ${e.message}`);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
_logger.default.debug(`'adb ${cmd.join(' ')}' command output: ${stdout}`);
|
|
319
|
-
|
|
320
|
-
if (stdout.includes('Success')) {
|
|
321
|
-
_logger.default.info(`${pkg} was successfully uninstalled`);
|
|
322
|
-
|
|
323
|
-
return true;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
_logger.default.info(`${pkg} was not uninstalled`);
|
|
327
|
-
|
|
328
|
-
return false;
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
apkUtilsMethods.installFromDevicePath = async function installFromDevicePath(apkPathOnDevice, opts = {}) {
|
|
332
|
-
let stdout = await this.shell(['pm', 'install', '-r', apkPathOnDevice], opts);
|
|
333
|
-
|
|
334
|
-
if (stdout.indexOf('Failure') !== -1) {
|
|
335
|
-
throw new Error(`Remote install failed: ${stdout}`);
|
|
336
|
-
}
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
apkUtilsMethods.cacheApk = async function cacheApk(apkPath, options = {}) {
|
|
340
|
-
const appHash = await _support.fs.hash(apkPath);
|
|
341
|
-
|
|
342
|
-
const remotePath = _path.default.posix.join(REMOTE_CACHE_ROOT, `${appHash}.apk`);
|
|
343
|
-
|
|
344
|
-
const remoteCachedFiles = [];
|
|
345
|
-
|
|
346
|
-
try {
|
|
347
|
-
const errorMarker = '_ERROR_';
|
|
348
|
-
let lsOutput = null;
|
|
349
|
-
|
|
350
|
-
if (this._areExtendedLsOptionsSupported === true || !_lodash.default.isBoolean(this._areExtendedLsOptionsSupported)) {
|
|
351
|
-
lsOutput = await this.shell([`ls -t -1 ${REMOTE_CACHE_ROOT} 2>&1 || echo ${errorMarker}`]);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
if (!_lodash.default.isString(lsOutput) || lsOutput.includes(errorMarker) && !lsOutput.includes(REMOTE_CACHE_ROOT)) {
|
|
355
|
-
if (!_lodash.default.isBoolean(this._areExtendedLsOptionsSupported)) {
|
|
356
|
-
_logger.default.debug('The current Android API does not support extended ls options. ' + 'Defaulting to no-options call');
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
lsOutput = await this.shell([`ls ${REMOTE_CACHE_ROOT} 2>&1 || echo ${errorMarker}`]);
|
|
360
|
-
this._areExtendedLsOptionsSupported = false;
|
|
361
|
-
} else {
|
|
362
|
-
this._areExtendedLsOptionsSupported = true;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
if (lsOutput.includes(errorMarker)) {
|
|
366
|
-
throw new Error(lsOutput.substring(0, lsOutput.indexOf(errorMarker)));
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
remoteCachedFiles.push(...lsOutput.split('\n').map(x => x.trim()).filter(Boolean));
|
|
370
|
-
} catch (e) {
|
|
371
|
-
_logger.default.debug(`Got an error '${e.message.trim()}' while getting the list of files in the cache. ` + `Assuming the cache does not exist yet`);
|
|
372
|
-
|
|
373
|
-
await this.shell(['mkdir', '-p', REMOTE_CACHE_ROOT]);
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
_logger.default.debug(`The count of applications in the cache: ${remoteCachedFiles.length}`);
|
|
377
|
-
|
|
378
|
-
const toHash = remotePath => _path.default.posix.parse(remotePath).name;
|
|
379
|
-
|
|
380
|
-
if (remoteCachedFiles.some(x => toHash(x) === appHash)) {
|
|
381
|
-
_logger.default.info(`The application at '${apkPath}' is already cached to '${remotePath}'`);
|
|
382
|
-
|
|
383
|
-
this.shell(['touch', '-am', remotePath]).catch(() => {});
|
|
384
|
-
} else {
|
|
385
|
-
_logger.default.info(`Caching the application at '${apkPath}' to '${remotePath}'`);
|
|
386
|
-
|
|
387
|
-
const timer = new _support.timing.Timer().start();
|
|
388
|
-
await this.push(apkPath, remotePath, {
|
|
389
|
-
timeout: options.timeout
|
|
390
|
-
});
|
|
391
|
-
const {
|
|
392
|
-
size
|
|
393
|
-
} = await _support.fs.stat(apkPath);
|
|
394
|
-
|
|
395
|
-
_logger.default.info(`The upload of '${_path.default.basename(apkPath)}' (${_support.util.toReadableSizeString(size)}) ` + `took ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
if (!this.remoteAppsCache) {
|
|
399
|
-
this.remoteAppsCache = new _lruCache.default({
|
|
400
|
-
max: this.remoteAppsCacheLimit
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
_lodash.default.difference([...this.remoteAppsCache.keys()], remoteCachedFiles.map(toHash)).forEach(hash => this.remoteAppsCache.del(hash));
|
|
405
|
-
|
|
406
|
-
this.remoteAppsCache.set(appHash, remotePath);
|
|
407
|
-
const entriesToCleanup = remoteCachedFiles.map(x => _path.default.posix.join(REMOTE_CACHE_ROOT, x)).filter(x => !this.remoteAppsCache.has(toHash(x))).slice(this.remoteAppsCacheLimit - [...this.remoteAppsCache.keys()].length);
|
|
408
|
-
|
|
409
|
-
if (!_lodash.default.isEmpty(entriesToCleanup)) {
|
|
410
|
-
try {
|
|
411
|
-
await this.shell(['rm', '-f', ...entriesToCleanup]);
|
|
412
|
-
|
|
413
|
-
_logger.default.debug(`Deleted ${entriesToCleanup.length} expired application cache entries`);
|
|
414
|
-
} catch (e) {
|
|
415
|
-
_logger.default.warn(`Cannot delete ${entriesToCleanup.length} expired application cache entries. ` + `Original error: ${e.message}`);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
return remotePath;
|
|
420
|
-
};
|
|
421
|
-
|
|
422
|
-
apkUtilsMethods.install = async function install(appPath, options = {}) {
|
|
423
|
-
if (appPath.endsWith(_helpers.APKS_EXTENSION)) {
|
|
424
|
-
return await this.installApks(appPath, options);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
options = _lodash.default.cloneDeep(options);
|
|
428
|
-
|
|
429
|
-
_lodash.default.defaults(options, {
|
|
430
|
-
replace: true,
|
|
431
|
-
timeout: this.adbExecTimeout === _helpers.DEFAULT_ADB_EXEC_TIMEOUT ? _helpers.APK_INSTALL_TIMEOUT : this.adbExecTimeout,
|
|
432
|
-
timeoutCapName: 'androidInstallTimeout'
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
const installArgs = (0, _helpers.buildInstallArgs)(await this.getApiLevel(), options);
|
|
436
|
-
|
|
437
|
-
if (options.noIncremental && (await this.isIncrementalInstallSupported())) {
|
|
438
|
-
installArgs.push('--no-incremental');
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
const installOpts = {
|
|
442
|
-
timeout: options.timeout,
|
|
443
|
-
timeoutCapName: options.timeoutCapName
|
|
444
|
-
};
|
|
445
|
-
const installCmd = ['install', ...installArgs, appPath];
|
|
446
|
-
|
|
447
|
-
let performAppInstall = async () => await this.adbExec(installCmd, installOpts);
|
|
448
|
-
|
|
449
|
-
let shouldCacheApp = this.remoteAppsCacheLimit > 0;
|
|
450
|
-
|
|
451
|
-
if (shouldCacheApp) {
|
|
452
|
-
shouldCacheApp = !(await this.isStreamedInstallSupported());
|
|
453
|
-
|
|
454
|
-
if (!shouldCacheApp) {
|
|
455
|
-
_logger.default.info(`The application at '${appPath}' will not be cached, because the device under test has ` + `confirmed the support of streamed installs`);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
if (shouldCacheApp) {
|
|
460
|
-
const clearCache = async () => {
|
|
461
|
-
_logger.default.info(`Clearing the cache at '${REMOTE_CACHE_ROOT}'`);
|
|
462
|
-
|
|
463
|
-
await this.shell(['rm', '-rf', `${REMOTE_CACHE_ROOT}/*`]);
|
|
464
|
-
};
|
|
465
|
-
|
|
466
|
-
const cacheApp = async () => await this.cacheApk(appPath, {
|
|
467
|
-
timeout: options.timeout
|
|
468
|
-
});
|
|
469
|
-
|
|
470
|
-
try {
|
|
471
|
-
const cachedAppPath = await cacheApp();
|
|
472
|
-
|
|
473
|
-
performAppInstall = async () => {
|
|
474
|
-
const pmInstallCmdByRemotePath = remotePath => ['pm', 'install', ...installArgs, remotePath];
|
|
475
|
-
|
|
476
|
-
const output = await this.shell(pmInstallCmdByRemotePath(cachedAppPath), installOpts);
|
|
477
|
-
|
|
478
|
-
if (/\bINSTALL_FAILED_INSUFFICIENT_STORAGE\b/.test(output)) {
|
|
479
|
-
_logger.default.warn(`There was a failure while installing '${appPath}' ` + `because of the insufficient device storage space`);
|
|
480
|
-
|
|
481
|
-
await clearCache();
|
|
482
|
-
|
|
483
|
-
_logger.default.info(`Consider decreasing the maximum amount of cached apps ` + `(currently ${this.remoteAppsCacheLimit}) to avoid such issues in the future`);
|
|
484
|
-
|
|
485
|
-
const newCachedAppPath = await cacheApp();
|
|
486
|
-
return await this.shell(pmInstallCmdByRemotePath(newCachedAppPath), installOpts);
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
return output;
|
|
490
|
-
};
|
|
491
|
-
} catch (e) {
|
|
492
|
-
_logger.default.debug(e);
|
|
493
|
-
|
|
494
|
-
_logger.default.warn(`There was a failure while caching '${appPath}': ${e.message}`);
|
|
495
|
-
|
|
496
|
-
_logger.default.warn('Falling back to the default installation procedure');
|
|
497
|
-
|
|
498
|
-
await clearCache();
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
try {
|
|
503
|
-
const timer = new _support.timing.Timer().start();
|
|
504
|
-
const output = await performAppInstall();
|
|
505
|
-
|
|
506
|
-
_logger.default.info(`The installation of '${_path.default.basename(appPath)}' took ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
507
|
-
|
|
508
|
-
const truncatedOutput = !_lodash.default.isString(output) || output.length <= 300 ? output : `${output.substr(0, 150)}...${output.substr(output.length - 150)}`;
|
|
509
|
-
|
|
510
|
-
_logger.default.debug(`Install command stdout: ${truncatedOutput}`);
|
|
511
|
-
|
|
512
|
-
if (/\[INSTALL[A-Z_]+FAILED[A-Z_]+\]/.test(output)) {
|
|
513
|
-
if (this.isTestPackageOnlyError(output)) {
|
|
514
|
-
const msg = `Set 'allowTestPackages' capability to true in order to allow test packages installation.`;
|
|
515
|
-
|
|
516
|
-
_logger.default.warn(msg);
|
|
517
|
-
|
|
518
|
-
throw new Error(`${output}\n${msg}`);
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
throw new Error(output);
|
|
522
|
-
}
|
|
523
|
-
} catch (err) {
|
|
524
|
-
if (!err.message.includes('INSTALL_FAILED_ALREADY_EXISTS')) {
|
|
525
|
-
throw err;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
_logger.default.debug(`Application '${appPath}' already installed. Continuing.`);
|
|
529
|
-
}
|
|
530
|
-
};
|
|
531
|
-
|
|
532
|
-
apkUtilsMethods.getApplicationInstallState = async function getApplicationInstallState(appPath, pkg = null) {
|
|
533
|
-
let apkInfo = null;
|
|
534
|
-
|
|
535
|
-
if (!pkg) {
|
|
536
|
-
apkInfo = await this.getApkInfo(appPath);
|
|
537
|
-
pkg = apkInfo.name;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
if (!pkg) {
|
|
541
|
-
_logger.default.warn(`Cannot read the package name of '${appPath}'`);
|
|
542
|
-
|
|
543
|
-
return this.APP_INSTALL_STATE.UNKNOWN;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
if (!(await this.isAppInstalled(pkg))) {
|
|
547
|
-
_logger.default.debug(`App '${appPath}' is not installed`);
|
|
548
|
-
|
|
549
|
-
return this.APP_INSTALL_STATE.NOT_INSTALLED;
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
const {
|
|
553
|
-
versionCode: pkgVersionCode,
|
|
554
|
-
versionName: pkgVersionNameStr
|
|
555
|
-
} = await this.getPackageInfo(pkg);
|
|
556
|
-
|
|
557
|
-
const pkgVersionName = _semver.default.valid(_semver.default.coerce(pkgVersionNameStr));
|
|
558
|
-
|
|
559
|
-
if (!apkInfo) {
|
|
560
|
-
apkInfo = await this.getApkInfo(appPath);
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
const {
|
|
564
|
-
versionCode: apkVersionCode,
|
|
565
|
-
versionName: apkVersionNameStr
|
|
566
|
-
} = apkInfo;
|
|
567
|
-
|
|
568
|
-
const apkVersionName = _semver.default.valid(_semver.default.coerce(apkVersionNameStr));
|
|
569
|
-
|
|
570
|
-
if (!_lodash.default.isInteger(apkVersionCode) || !_lodash.default.isInteger(pkgVersionCode)) {
|
|
571
|
-
_logger.default.warn(`Cannot read version codes of '${appPath}' and/or '${pkg}'`);
|
|
572
|
-
|
|
573
|
-
if (!_lodash.default.isString(apkVersionName) || !_lodash.default.isString(pkgVersionName)) {
|
|
574
|
-
_logger.default.warn(`Cannot read version names of '${appPath}' and/or '${pkg}'`);
|
|
575
|
-
|
|
576
|
-
return this.APP_INSTALL_STATE.UNKNOWN;
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
if (_lodash.default.isInteger(apkVersionCode) && _lodash.default.isInteger(pkgVersionCode)) {
|
|
581
|
-
if (pkgVersionCode > apkVersionCode) {
|
|
582
|
-
_logger.default.debug(`The version code of the installed '${pkg}' is greater than the application version code (${pkgVersionCode} > ${apkVersionCode})`);
|
|
583
|
-
|
|
584
|
-
return this.APP_INSTALL_STATE.NEWER_VERSION_INSTALLED;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
if (pkgVersionCode === apkVersionCode) {
|
|
588
|
-
if (_lodash.default.isString(apkVersionName) && _lodash.default.isString(pkgVersionName) && _semver.default.satisfies(pkgVersionName, `>=${apkVersionName}`)) {
|
|
589
|
-
_logger.default.debug(`The version name of the installed '${pkg}' is greater or equal to the application version name ('${pkgVersionName}' >= '${apkVersionName}')`);
|
|
590
|
-
|
|
591
|
-
return _semver.default.satisfies(pkgVersionName, `>${apkVersionName}`) ? this.APP_INSTALL_STATE.NEWER_VERSION_INSTALLED : this.APP_INSTALL_STATE.SAME_VERSION_INSTALLED;
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
if (!_lodash.default.isString(apkVersionName) || !_lodash.default.isString(pkgVersionName)) {
|
|
595
|
-
_logger.default.debug(`The version name of the installed '${pkg}' is equal to application version name (${pkgVersionCode} === ${apkVersionCode})`);
|
|
596
|
-
|
|
597
|
-
return this.APP_INSTALL_STATE.SAME_VERSION_INSTALLED;
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
} else if (_lodash.default.isString(apkVersionName) && _lodash.default.isString(pkgVersionName) && _semver.default.satisfies(pkgVersionName, `>=${apkVersionName}`)) {
|
|
601
|
-
_logger.default.debug(`The version name of the installed '${pkg}' is greater or equal to the application version name ('${pkgVersionName}' >= '${apkVersionName}')`);
|
|
602
|
-
|
|
603
|
-
return _semver.default.satisfies(pkgVersionName, `>${apkVersionName}`) ? this.APP_INSTALL_STATE.NEWER_VERSION_INSTALLED : this.APP_INSTALL_STATE.SAME_VERSION_INSTALLED;
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
_logger.default.debug(`The installed '${pkg}' package is older than '${appPath}' (${pkgVersionCode} < ${apkVersionCode} or '${pkgVersionName}' < '${apkVersionName}')'`);
|
|
607
|
-
|
|
608
|
-
return this.APP_INSTALL_STATE.OLDER_VERSION_INSTALLED;
|
|
609
|
-
};
|
|
610
|
-
|
|
611
|
-
apkUtilsMethods.installOrUpgrade = async function installOrUpgrade(appPath, pkg = null, options = {}) {
|
|
612
|
-
if (!pkg) {
|
|
613
|
-
const apkInfo = await this.getApkInfo(appPath);
|
|
614
|
-
pkg = apkInfo.name;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
const {
|
|
618
|
-
enforceCurrentBuild
|
|
619
|
-
} = options;
|
|
620
|
-
const appState = await this.getApplicationInstallState(appPath, pkg);
|
|
621
|
-
let wasUninstalled = false;
|
|
622
|
-
|
|
623
|
-
const uninstallPackage = async () => {
|
|
624
|
-
if (!(await this.uninstallApk(pkg))) {
|
|
625
|
-
throw new Error(`'${pkg}' package cannot be uninstalled`);
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
wasUninstalled = true;
|
|
629
|
-
};
|
|
630
|
-
|
|
631
|
-
switch (appState) {
|
|
632
|
-
case this.APP_INSTALL_STATE.NOT_INSTALLED:
|
|
633
|
-
_logger.default.debug(`Installing '${appPath}'`);
|
|
634
|
-
|
|
635
|
-
await this.install(appPath, Object.assign({}, options, {
|
|
636
|
-
replace: false
|
|
637
|
-
}));
|
|
638
|
-
return {
|
|
639
|
-
appState,
|
|
640
|
-
wasUninstalled
|
|
641
|
-
};
|
|
642
|
-
|
|
643
|
-
case this.APP_INSTALL_STATE.NEWER_VERSION_INSTALLED:
|
|
644
|
-
if (enforceCurrentBuild) {
|
|
645
|
-
_logger.default.info(`Downgrading '${pkg}' as requested`);
|
|
646
|
-
|
|
647
|
-
await uninstallPackage();
|
|
648
|
-
break;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
_logger.default.debug(`There is no need to downgrade '${pkg}'`);
|
|
652
|
-
|
|
653
|
-
return {
|
|
654
|
-
appState,
|
|
655
|
-
wasUninstalled
|
|
656
|
-
};
|
|
657
|
-
|
|
658
|
-
case this.APP_INSTALL_STATE.SAME_VERSION_INSTALLED:
|
|
659
|
-
if (enforceCurrentBuild) {
|
|
660
|
-
break;
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
_logger.default.debug(`There is no need to install/upgrade '${appPath}'`);
|
|
664
|
-
|
|
665
|
-
return {
|
|
666
|
-
appState,
|
|
667
|
-
wasUninstalled
|
|
668
|
-
};
|
|
669
|
-
|
|
670
|
-
case this.APP_INSTALL_STATE.OLDER_VERSION_INSTALLED:
|
|
671
|
-
_logger.default.debug(`Executing upgrade of '${appPath}'`);
|
|
672
|
-
|
|
673
|
-
break;
|
|
674
|
-
|
|
675
|
-
default:
|
|
676
|
-
_logger.default.debug(`The current install state of '${appPath}' is unknown. Installing anyway`);
|
|
677
|
-
|
|
678
|
-
break;
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
try {
|
|
682
|
-
await this.install(appPath, Object.assign({}, options, {
|
|
683
|
-
replace: true
|
|
684
|
-
}));
|
|
685
|
-
} catch (err) {
|
|
686
|
-
_logger.default.warn(`Cannot install/upgrade '${pkg}' because of '${err.message}'. Trying full reinstall`);
|
|
687
|
-
|
|
688
|
-
await uninstallPackage();
|
|
689
|
-
await this.install(appPath, Object.assign({}, options, {
|
|
690
|
-
replace: false
|
|
691
|
-
}));
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
return {
|
|
695
|
-
appState,
|
|
696
|
-
wasUninstalled
|
|
697
|
-
};
|
|
698
|
-
};
|
|
699
|
-
|
|
700
|
-
apkUtilsMethods.extractStringsFromApk = async function extractStringsFromApk(appPath, language, out) {
|
|
701
|
-
_logger.default.debug(`Extracting strings from for language: ${language || 'default'}`);
|
|
702
|
-
|
|
703
|
-
const originalAppPath = appPath;
|
|
704
|
-
|
|
705
|
-
if (appPath.endsWith(_helpers.APKS_EXTENSION)) {
|
|
706
|
-
appPath = await this.extractLanguageApk(appPath, language);
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
let apkStrings = {};
|
|
710
|
-
let configMarker;
|
|
711
|
-
|
|
712
|
-
try {
|
|
713
|
-
await this.initAapt();
|
|
714
|
-
configMarker = await (0, _helpers.formatConfigMarker)(async () => {
|
|
715
|
-
const {
|
|
716
|
-
stdout
|
|
717
|
-
} = await (0, _teen_process.exec)(this.binaries.aapt, ['d', 'configurations', appPath]);
|
|
718
|
-
return _lodash.default.uniq(stdout.split(_os.default.EOL));
|
|
719
|
-
}, language, '(default)');
|
|
720
|
-
const {
|
|
721
|
-
stdout
|
|
722
|
-
} = await (0, _teen_process.exec)(this.binaries.aapt, ['d', '--values', 'resources', appPath]);
|
|
723
|
-
apkStrings = (0, _helpers.parseAaptStrings)(stdout, configMarker);
|
|
724
|
-
} catch (e) {
|
|
725
|
-
_logger.default.debug('Cannot extract resources using aapt. Trying aapt2. ' + `Original error: ${e.stderr || e.message}`);
|
|
726
|
-
|
|
727
|
-
await this.initAapt2();
|
|
728
|
-
configMarker = await (0, _helpers.formatConfigMarker)(async () => {
|
|
729
|
-
const {
|
|
730
|
-
stdout
|
|
731
|
-
} = await (0, _teen_process.exec)(this.binaries.aapt2, ['d', 'configurations', appPath]);
|
|
732
|
-
return _lodash.default.uniq(stdout.split(_os.default.EOL));
|
|
733
|
-
}, language, '');
|
|
734
|
-
|
|
735
|
-
try {
|
|
736
|
-
const {
|
|
737
|
-
stdout
|
|
738
|
-
} = await (0, _teen_process.exec)(this.binaries.aapt2, ['d', 'resources', appPath]);
|
|
739
|
-
apkStrings = (0, _helpers.parseAapt2Strings)(stdout, configMarker);
|
|
740
|
-
} catch (e) {
|
|
741
|
-
throw new Error(`Cannot extract resources from '${originalAppPath}'. ` + `Original error: ${e.message}`);
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
if (_lodash.default.isEmpty(apkStrings)) {
|
|
746
|
-
_logger.default.warn(`No strings have been found in '${originalAppPath}' resources ` + `for '${configMarker || 'default'}' configuration`);
|
|
747
|
-
} else {
|
|
748
|
-
_logger.default.info(`Successfully extracted ${_lodash.default.keys(apkStrings).length} strings from ` + `'${originalAppPath}' resources for '${configMarker || 'default'}' configuration`);
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
const localPath = _path.default.resolve(out, 'strings.json');
|
|
752
|
-
|
|
753
|
-
await (0, _support.mkdirp)(out);
|
|
754
|
-
await _support.fs.writeFile(localPath, JSON.stringify(apkStrings, null, 2), 'utf-8');
|
|
755
|
-
return {
|
|
756
|
-
apkStrings,
|
|
757
|
-
localPath
|
|
758
|
-
};
|
|
759
|
-
};
|
|
760
|
-
|
|
761
|
-
apkUtilsMethods.getDeviceLanguage = async function getDeviceLanguage() {
|
|
762
|
-
let language;
|
|
763
|
-
|
|
764
|
-
if ((await this.getApiLevel()) < 23) {
|
|
765
|
-
language = await this.getDeviceSysLanguage();
|
|
766
|
-
|
|
767
|
-
if (!language) {
|
|
768
|
-
language = await this.getDeviceProductLanguage();
|
|
769
|
-
}
|
|
770
|
-
} else {
|
|
771
|
-
language = (await this.getDeviceLocale()).split('-')[0];
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
return language;
|
|
775
|
-
};
|
|
776
|
-
|
|
777
|
-
apkUtilsMethods.getDeviceCountry = async function getDeviceCountry() {
|
|
778
|
-
let country = await this.getDeviceSysCountry();
|
|
779
|
-
|
|
780
|
-
if (!country) {
|
|
781
|
-
country = await this.getDeviceProductCountry();
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
return country;
|
|
785
|
-
};
|
|
786
|
-
|
|
787
|
-
apkUtilsMethods.getDeviceLocale = async function getDeviceLocale() {
|
|
788
|
-
let locale = await this.getDeviceSysLocale();
|
|
789
|
-
|
|
790
|
-
if (!locale) {
|
|
791
|
-
locale = await this.getDeviceProductLocale();
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
return locale;
|
|
795
|
-
};
|
|
796
|
-
|
|
797
|
-
apkUtilsMethods.setDeviceLocale = async function setDeviceLocale(locale) {
|
|
798
|
-
const validateLocale = new RegExp(/[a-zA-Z]+-[a-zA-Z0-9]+/);
|
|
799
|
-
|
|
800
|
-
if (!validateLocale.test(locale)) {
|
|
801
|
-
_logger.default.warn(`setDeviceLocale requires the following format: en-US or ja-JP`);
|
|
802
|
-
|
|
803
|
-
return;
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
let split_locale = locale.split('-');
|
|
807
|
-
await this.setDeviceLanguageCountry(split_locale[0], split_locale[1]);
|
|
808
|
-
};
|
|
809
|
-
|
|
810
|
-
apkUtilsMethods.ensureCurrentLocale = async function ensureCurrentLocale(language, country, script = null) {
|
|
811
|
-
const hasLanguage = _lodash.default.isString(language);
|
|
812
|
-
|
|
813
|
-
const hasCountry = _lodash.default.isString(country);
|
|
814
|
-
|
|
815
|
-
if (!hasLanguage && !hasCountry) {
|
|
816
|
-
_logger.default.warn('ensureCurrentLocale requires language or country');
|
|
817
|
-
|
|
818
|
-
return false;
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
language = (language || '').toLowerCase();
|
|
822
|
-
country = (country || '').toLowerCase();
|
|
823
|
-
const apiLevel = await this.getApiLevel();
|
|
824
|
-
return await (0, _asyncbox.retryInterval)(5, 1000, async () => {
|
|
825
|
-
try {
|
|
826
|
-
if (apiLevel < 23) {
|
|
827
|
-
let curLanguage, curCountry;
|
|
828
|
-
|
|
829
|
-
if (hasLanguage) {
|
|
830
|
-
curLanguage = (await this.getDeviceLanguage()).toLowerCase();
|
|
831
|
-
|
|
832
|
-
if (!hasCountry && language === curLanguage) {
|
|
833
|
-
return true;
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
if (hasCountry) {
|
|
838
|
-
curCountry = (await this.getDeviceCountry()).toLowerCase();
|
|
839
|
-
|
|
840
|
-
if (!hasLanguage && country === curCountry) {
|
|
841
|
-
return true;
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
if (language === curLanguage && country === curCountry) {
|
|
846
|
-
return true;
|
|
847
|
-
}
|
|
848
|
-
} else {
|
|
849
|
-
const curLocale = (await this.getDeviceLocale()).toLowerCase();
|
|
850
|
-
const localeCode = script ? `${language}-${script.toLowerCase()}-${country}` : `${language}-${country}`;
|
|
851
|
-
|
|
852
|
-
if (localeCode === curLocale) {
|
|
853
|
-
_logger.default.debug(`Requested locale is equal to current locale: '${curLocale}'`);
|
|
854
|
-
|
|
855
|
-
return true;
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
return false;
|
|
860
|
-
} catch (err) {
|
|
861
|
-
_logger.default.error(`Unable to check device localization: ${err.message}`);
|
|
862
|
-
|
|
863
|
-
try {
|
|
864
|
-
await this.reconnect();
|
|
865
|
-
} catch (ign) {
|
|
866
|
-
await this.restartAdb();
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
throw err;
|
|
870
|
-
}
|
|
871
|
-
});
|
|
872
|
-
};
|
|
873
|
-
|
|
874
|
-
apkUtilsMethods.setDeviceLanguageCountry = async function setDeviceLanguageCountry(language, country, script = null) {
|
|
875
|
-
let hasLanguage = language && _lodash.default.isString(language);
|
|
876
|
-
|
|
877
|
-
let hasCountry = country && _lodash.default.isString(country);
|
|
878
|
-
|
|
879
|
-
if (!hasLanguage || !hasCountry) {
|
|
880
|
-
_logger.default.warn(`setDeviceLanguageCountry requires language and country at least`);
|
|
881
|
-
|
|
882
|
-
_logger.default.warn(`Got language: '${language}' and country: '${country}'`);
|
|
883
|
-
|
|
884
|
-
return;
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
let apiLevel = await this.getApiLevel();
|
|
888
|
-
language = (language || '').toLowerCase();
|
|
889
|
-
country = (country || '').toUpperCase();
|
|
890
|
-
|
|
891
|
-
if (apiLevel < 23) {
|
|
892
|
-
let curLanguage = (await this.getDeviceLanguage()).toLowerCase();
|
|
893
|
-
let curCountry = (await this.getDeviceCountry()).toUpperCase();
|
|
894
|
-
|
|
895
|
-
if (language !== curLanguage || country !== curCountry) {
|
|
896
|
-
await this.setDeviceSysLocaleViaSettingApp(language, country);
|
|
897
|
-
}
|
|
898
|
-
} else {
|
|
899
|
-
let curLocale = await this.getDeviceLocale();
|
|
900
|
-
const localeCode = script ? `${language}-${script}-${country}` : `${language}-${country}`;
|
|
901
|
-
|
|
902
|
-
_logger.default.debug(`Current locale: '${curLocale}'; requested locale: '${localeCode}'`);
|
|
903
|
-
|
|
904
|
-
if (localeCode.toLowerCase() !== curLocale.toLowerCase()) {
|
|
905
|
-
await this.setDeviceSysLocaleViaSettingApp(language, country, script);
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
};
|
|
909
|
-
|
|
910
|
-
apkUtilsMethods.getApkInfo = async function getApkInfo(appPath) {
|
|
911
|
-
if (!(await _support.fs.exists(appPath))) {
|
|
912
|
-
throw new Error(`The file at path ${appPath} does not exist or is not accessible`);
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
if (appPath.endsWith(_helpers.APKS_EXTENSION)) {
|
|
916
|
-
appPath = await this.extractBaseApk(appPath);
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
try {
|
|
920
|
-
const apkReader = await _adbkitApkreader.default.open(appPath);
|
|
921
|
-
const manifest = await apkReader.readManifest();
|
|
922
|
-
const {
|
|
923
|
-
pkg,
|
|
924
|
-
versionName,
|
|
925
|
-
versionCode
|
|
926
|
-
} = (0, _helpers.parseManifest)(manifest);
|
|
927
|
-
return {
|
|
928
|
-
name: pkg,
|
|
929
|
-
versionCode,
|
|
930
|
-
versionName
|
|
931
|
-
};
|
|
932
|
-
} catch (e) {
|
|
933
|
-
_logger.default.warn(`Error '${e.message}' while getting badging info`);
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
return {};
|
|
937
|
-
};
|
|
938
|
-
|
|
939
|
-
apkUtilsMethods.getPackageInfo = async function getPackageInfo(pkg) {
|
|
940
|
-
_logger.default.debug(`Getting package info for '${pkg}'`);
|
|
941
|
-
|
|
942
|
-
let result = {
|
|
943
|
-
name: pkg
|
|
944
|
-
};
|
|
945
|
-
|
|
946
|
-
try {
|
|
947
|
-
const stdout = await this.shell(['dumpsys', 'package', pkg]);
|
|
948
|
-
const versionNameMatch = new RegExp(/versionName=([\d+.]+)/).exec(stdout);
|
|
949
|
-
|
|
950
|
-
if (versionNameMatch) {
|
|
951
|
-
result.versionName = versionNameMatch[1];
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
const versionCodeMatch = new RegExp(/versionCode=(\d+)/).exec(stdout);
|
|
955
|
-
|
|
956
|
-
if (versionCodeMatch) {
|
|
957
|
-
result.versionCode = parseInt(versionCodeMatch[1], 10);
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
return result;
|
|
961
|
-
} catch (err) {
|
|
962
|
-
_logger.default.warn(`Error '${err.message}' while dumping package info`);
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
return result;
|
|
966
|
-
};
|
|
967
|
-
|
|
968
|
-
apkUtilsMethods.pullApk = async function pullApk(pkg, tmpDir) {
|
|
969
|
-
const stdout = _lodash.default.trim(await this.shell(['pm', 'path', pkg]));
|
|
970
|
-
|
|
971
|
-
const packageMarker = 'package:';
|
|
972
|
-
|
|
973
|
-
if (!_lodash.default.startsWith(stdout, packageMarker)) {
|
|
974
|
-
throw new Error(`Cannot pull the .apk package for '${pkg}'. Original error: ${stdout}`);
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
const remotePath = stdout.replace(packageMarker, '');
|
|
978
|
-
|
|
979
|
-
const tmpApp = _path.default.resolve(tmpDir, `${pkg}.apk`);
|
|
980
|
-
|
|
981
|
-
await this.pull(remotePath, tmpApp);
|
|
982
|
-
|
|
983
|
-
_logger.default.debug(`Pulled app for package '${pkg}' to '${tmpApp}'`);
|
|
984
|
-
|
|
985
|
-
return tmpApp;
|
|
986
|
-
};
|
|
987
|
-
|
|
988
|
-
var _default = apkUtilsMethods;
|
|
989
|
-
exports.default = _default;require('source-map-support').install();
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGliL3Rvb2xzL2Fway11dGlscy5qcyIsIm5hbWVzIjpbImFwa1V0aWxzTWV0aG9kcyIsIkFDVElWSVRJRVNfVFJPVUJMRVNIT09USU5HX0xJTksiLCJBUFBfSU5TVEFMTF9TVEFURSIsIlVOS05PV04iLCJOT1RfSU5TVEFMTEVEIiwiTkVXRVJfVkVSU0lPTl9JTlNUQUxMRUQiLCJTQU1FX1ZFUlNJT05fSU5TVEFMTEVEIiwiT0xERVJfVkVSU0lPTl9JTlNUQUxMRUQiLCJSRU1PVEVfQ0FDSEVfUk9PVCIsImlzQXBwSW5zdGFsbGVkIiwicGtnIiwibG9nIiwiZGVidWciLCJpbnN0YWxsZWRQYXR0ZXJuIiwiUmVnRXhwIiwiXyIsImVzY2FwZVJlZ0V4cCIsInN0ZG91dCIsInNoZWxsIiwiaXNJbnN0YWxsZWQiLCJ0ZXN0IiwiZSIsIkVycm9yIiwibWVzc2FnZSIsInN0YXJ0VXJpIiwidXJpIiwib3B0cyIsIndhaXRGb3JMYXVuY2giLCJhcmdzIiwicHVzaCIsImVzY2FwZVNoZWxsQXJnIiwicmVzIiwidG9Mb3dlckNhc2UiLCJpbmNsdWRlcyIsInN0YXJ0QXBwIiwic3RhcnRBcHBPcHRpb25zIiwiYWN0aXZpdHkiLCJhY3Rpb24iLCJjbG9uZSIsInJlcGxhY2UiLCJkZWZhdWx0cyIsIndhaXRQa2ciLCJ3YWl0QWN0aXZpdHkiLCJyZXRyeSIsInN0b3BBcHAiLCJhcGlMZXZlbCIsImdldEFwaUxldmVsIiwiY21kIiwiYnVpbGRTdGFydENtZCIsImludGVudE5hbWUiLCJvcHRpb25hbEludGVudEFyZ3VtZW50cyIsInNoZWxsT3B0cyIsImlzSW50ZWdlciIsIndhaXREdXJhdGlvbiIsInRpbWVvdXQiLCJzdGFydHNXaXRoIiwid2FpdEZvckFjdGl2aXR5IiwiYXBwRGVzY3JpcHRvciIsImR1bXBXaW5kb3dzIiwiZHVtcHN5c0FyZyIsImdldEZvY3VzZWRQYWNrYWdlQW5kQWN0aXZpdHkiLCJudWxsRm9jdXNlZEFwcFJlIiwiZm9jdXNlZEFwcFJlIiwibnVsbEN1cnJlbnRGb2N1c1JlIiwiY3VycmVudEZvY3VzQXBwUmUiLCJmb2N1c2VkQXBwQ2FuZGlkYXRlcyIsImN1cnJlbnRGb2N1c0FwcENhbmRpZGF0ZXMiLCJjYW5kaWRhdGVzIiwicGF0dGVybiIsIm1hdGNoIiwiZXhlYyIsImFwcFBhY2thZ2UiLCJ0cmltIiwiYXBwQWN0aXZpdHkiLCJsZW5ndGgiLCJpbnRlcnNlY3Rpb25XaXRoIiwiaXNFcXVhbCIsIndhaXRGb3JBY3Rpdml0eU9yTm90Iiwid2FpdEZvclN0b3AiLCJ3YWl0TXMiLCJzcGxpdE5hbWVzIiwibmFtZXMiLCJzcGxpdCIsIm1hcCIsIm5hbWUiLCJhbGxQYWNrYWdlcyIsImFsbEFjdGl2aXRpZXMiLCJwb3NzaWJsZUFjdGl2aXR5TmFtZXMiLCJvbmVBY3Rpdml0eSIsImN1cnJlbnRQa2ciLCJqb2luIiwicG9zc2libGVBY3Rpdml0eVBhdHRlcm5zIiwiYWN0TmFtZSIsImNvbmRpdGlvbkZ1bmMiLCJmdWxseVF1YWxpZmllZEFjdGl2aXR5IiwiaXNBY3Rpdml0eUZvdW5kIiwic29tZSIsInAiLCJ3YWl0Rm9yQ29uZGl0aW9uIiwicGFyc2VJbnQiLCJpbnRlcnZhbE1zIiwiYWN0Iiwid2FpdEZvck5vdEFjdGl2aXR5IiwidW5pbnN0YWxsQXBrIiwib3B0aW9ucyIsImluZm8iLCJrZWVwRGF0YSIsImZvcmNlU3RvcCIsImFkYkV4ZWMiLCJpbnN0YWxsRnJvbURldmljZVBhdGgiLCJhcGtQYXRoT25EZXZpY2UiLCJpbmRleE9mIiwiY2FjaGVBcGsiLCJhcGtQYXRoIiwiYXBwSGFzaCIsImZzIiwiaGFzaCIsInJlbW90ZVBhdGgiLCJwYXRoIiwicG9zaXgiLCJyZW1vdGVDYWNoZWRGaWxlcyIsImVycm9yTWFya2VyIiwibHNPdXRwdXQiLCJfYXJlRXh0ZW5kZWRMc09wdGlvbnNTdXBwb3J0ZWQiLCJpc0Jvb2xlYW4iLCJpc1N0cmluZyIsInN1YnN0cmluZyIsIngiLCJmaWx0ZXIiLCJCb29sZWFuIiwidG9IYXNoIiwicGFyc2UiLCJjYXRjaCIsInRpbWVyIiwidGltaW5nIiwiVGltZXIiLCJzdGFydCIsInNpemUiLCJzdGF0IiwiYmFzZW5hbWUiLCJ1dGlsIiwidG9SZWFkYWJsZVNpemVTdHJpbmciLCJnZXREdXJhdGlvbiIsImFzTWlsbGlTZWNvbmRzIiwidG9GaXhlZCIsInJlbW90ZUFwcHNDYWNoZSIsIkxSVSIsIm1heCIsInJlbW90ZUFwcHNDYWNoZUxpbWl0IiwiZGlmZmVyZW5jZSIsImtleXMiLCJmb3JFYWNoIiwiZGVsIiwic2V0IiwiZW50cmllc1RvQ2xlYW51cCIsImhhcyIsInNsaWNlIiwiaXNFbXB0eSIsIndhcm4iLCJpbnN0YWxsIiwiYXBwUGF0aCIsImVuZHNXaXRoIiwiQVBLU19FWFRFTlNJT04iLCJpbnN0YWxsQXBrcyIsImNsb25lRGVlcCIsImFkYkV4ZWNUaW1lb3V0IiwiREVGQVVMVF9BREJfRVhFQ19USU1FT1VUIiwiQVBLX0lOU1RBTExfVElNRU9VVCIsInRpbWVvdXRDYXBOYW1lIiwiaW5zdGFsbEFyZ3MiLCJidWlsZEluc3RhbGxBcmdzIiwibm9JbmNyZW1lbnRhbCIsImlzSW5jcmVtZW50YWxJbnN0YWxsU3VwcG9ydGVkIiwiaW5zdGFsbE9wdHMiLCJpbnN0YWxsQ21kIiwicGVyZm9ybUFwcEluc3RhbGwiLCJzaG91bGRDYWNoZUFwcCIsImlzU3RyZWFtZWRJbnN0YWxsU3VwcG9ydGVkIiwiY2xlYXJDYWNoZSIsImNhY2hlQXBwIiwiY2FjaGVkQXBwUGF0aCIsInBtSW5zdGFsbENtZEJ5UmVtb3RlUGF0aCIsIm91dHB1dCIsIm5ld0NhY2hlZEFwcFBhdGgiLCJ0cnVuY2F0ZWRPdXRwdXQiLCJzdWJzdHIiLCJpc1Rlc3RQYWNrYWdlT25seUVycm9yIiwibXNnIiwiZXJyIiwiZ2V0QXBwbGljYXRpb25JbnN0YWxsU3RhdGUiLCJhcGtJbmZvIiwiZ2V0QXBrSW5mbyIsInZlcnNpb25Db2RlIiwicGtnVmVyc2lvbkNvZGUiLCJ2ZXJzaW9uTmFtZSIsInBrZ1ZlcnNpb25OYW1lU3RyIiwiZ2V0UGFja2FnZUluZm8iLCJwa2dWZXJzaW9uTmFtZSIsInNlbXZlciIsInZhbGlkIiwiY29lcmNlIiwiYXBrVmVyc2lvbkNvZGUiLCJhcGtWZXJzaW9uTmFtZVN0ciIsImFwa1ZlcnNpb25OYW1lIiwic2F0aXNmaWVzIiwiaW5zdGFsbE9yVXBncmFkZSIsImVuZm9yY2VDdXJyZW50QnVpbGQiLCJhcHBTdGF0ZSIsIndhc1VuaW5zdGFsbGVkIiwidW5pbnN0YWxsUGFja2FnZSIsIk9iamVjdCIsImFzc2lnbiIsImV4dHJhY3RTdHJpbmdzRnJvbUFwayIsImxhbmd1YWdlIiwib3V0Iiwib3JpZ2luYWxBcHBQYXRoIiwiZXh0cmFjdExhbmd1YWdlQXBrIiwiYXBrU3RyaW5ncyIsImNvbmZpZ01hcmtlciIsImluaXRBYXB0IiwiZm9ybWF0Q29uZmlnTWFya2VyIiwiYmluYXJpZXMiLCJhYXB0IiwidW5pcSIsIm9zIiwiRU9MIiwicGFyc2VBYXB0U3RyaW5ncyIsInN0ZGVyciIsImluaXRBYXB0MiIsImFhcHQyIiwicGFyc2VBYXB0MlN0cmluZ3MiLCJsb2NhbFBhdGgiLCJyZXNvbHZlIiwibWtkaXJwIiwid3JpdGVGaWxlIiwiSlNPTiIsInN0cmluZ2lmeSIsImdldERldmljZUxhbmd1YWdlIiwiZ2V0RGV2aWNlU3lzTGFuZ3VhZ2UiLCJnZXREZXZpY2VQcm9kdWN0TGFuZ3VhZ2UiLCJnZXREZXZpY2VMb2NhbGUiLCJnZXREZXZpY2VDb3VudHJ5IiwiY291bnRyeSIsImdldERldmljZVN5c0NvdW50cnkiLCJnZXREZXZpY2VQcm9kdWN0Q291bnRyeSIsImxvY2FsZSIsImdldERldmljZVN5c0xvY2FsZSIsImdldERldmljZVByb2R1Y3RMb2NhbGUiLCJzZXREZXZpY2VMb2NhbGUiLCJ2YWxpZGF0ZUxvY2FsZSIsInNwbGl0X2xvY2FsZSIsInNldERldmljZUxhbmd1YWdlQ291bnRyeSIsImVuc3VyZUN1cnJlbnRMb2NhbGUiLCJzY3JpcHQiLCJoYXNMYW5ndWFnZSIsImhhc0NvdW50cnkiLCJyZXRyeUludGVydmFsIiwiY3VyTGFuZ3VhZ2UiLCJjdXJDb3VudHJ5IiwiY3VyTG9jYWxlIiwibG9jYWxlQ29kZSIsImVycm9yIiwicmVjb25uZWN0IiwiaWduIiwicmVzdGFydEFkYiIsInRvVXBwZXJDYXNlIiwic2V0RGV2aWNlU3lzTG9jYWxlVmlhU2V0dGluZ0FwcCIsImV4aXN0cyIsImV4dHJhY3RCYXNlQXBrIiwiYXBrUmVhZGVyIiwiQXBrUmVhZGVyIiwib3BlbiIsIm1hbmlmZXN0IiwicmVhZE1hbmlmZXN0IiwicGFyc2VNYW5pZmVzdCIsInJlc3VsdCIsInZlcnNpb25OYW1lTWF0Y2giLCJ2ZXJzaW9uQ29kZU1hdGNoIiwicHVsbEFwayIsInRtcERpciIsInBhY2thZ2VNYXJrZXIiLCJ0bXBBcHAiLCJwdWxsIl0sInNvdXJjZVJvb3QiOiIuLi8uLi8uLiIsInNvdXJjZXMiOlsibGliL3Rvb2xzL2Fway11dGlscy5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBidWlsZFN0YXJ0Q21kLCBBUEtTX0VYVEVOU0lPTiwgYnVpbGRJbnN0YWxsQXJncyxcbiAgQVBLX0lOU1RBTExfVElNRU9VVCwgREVGQVVMVF9BREJfRVhFQ19USU1FT1VULFxuICBwYXJzZU1hbmlmZXN0LCBwYXJzZUFhcHRTdHJpbmdzLCBwYXJzZUFhcHQyU3RyaW5ncywgZm9ybWF0Q29uZmlnTWFya2VyLFxuICBlc2NhcGVTaGVsbEFyZyxcbn0gZnJvbSAnLi4vaGVscGVycy5qcyc7XG5pbXBvcnQgeyBleGVjIH0gZnJvbSAndGVlbl9wcm9jZXNzJztcbmltcG9ydCBsb2cgZnJvbSAnLi4vbG9nZ2VyLmpzJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7IHJldHJ5SW50ZXJ2YWwsIHdhaXRGb3JDb25kaXRpb24gfSBmcm9tICdhc3luY2JveCc7XG5pbXBvcnQgeyBmcywgdXRpbCwgbWtkaXJwLCB0aW1pbmcgfSBmcm9tICdAYXBwaXVtL3N1cHBvcnQnO1xuaW1wb3J0IHNlbXZlciBmcm9tICdzZW12ZXInO1xuaW1wb3J0IG9zIGZyb20gJ29zJztcbmltcG9ydCBMUlUgZnJvbSAnbHJ1LWNhY2hlJztcbmltcG9ydCBBcGtSZWFkZXIgZnJvbSAnYWRia2l0LWFwa3JlYWRlcic7XG5cbmNvbnN0IGFwa1V0aWxzTWV0aG9kcyA9IHt9O1xuXG5jb25zdCBBQ1RJVklUSUVTX1RST1VCTEVTSE9PVElOR19MSU5LID1cbiAgJ2h0dHBzOi8vZ2l0aHViLmNvbS9hcHBpdW0vYXBwaXVtL2Jsb2IvbWFzdGVyL2RvY3MvZW4vd3JpdGluZy1ydW5uaW5nLWFwcGl1bS9hbmRyb2lkL2FjdGl2aXR5LXN0YXJ0dXAubWQnO1xuYXBrVXRpbHNNZXRob2RzLkFQUF9JTlNUQUxMX1NUQVRFID0ge1xuICBVTktOT1dOOiAndW5rbm93bicsXG4gIE5PVF9JTlNUQUxMRUQ6ICdub3RJbnN0YWxsZWQnLFxuICBORVdFUl9WRVJTSU9OX0lOU1RBTExFRDogJ25ld2VyVmVyc2lvbkluc3RhbGxlZCcsXG4gIFNBTUVfVkVSU0lPTl9JTlNUQUxMRUQ6ICdzYW1lVmVyc2lvbkluc3RhbGxlZCcsXG4gIE9MREVSX1ZFUlNJT05fSU5TVEFMTEVEOiAnb2xkZXJWZXJzaW9uSW5zdGFsbGVkJyxcbn07XG5jb25zdCBSRU1PVEVfQ0FDSEVfUk9PVCA9ICcvZGF0YS9sb2NhbC90bXAvYXBwaXVtX2NhY2hlJztcblxuXG4vKipcbiAqIENoZWNrIHdoZXRoZXIgdGhlIHBhcnRpY3VsYXIgcGFja2FnZSBpcyBwcmVzZW50IG9uIHRoZSBkZXZpY2UgdW5kZXIgdGVzdC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcGtnIC0gVGhlIG5hbWUgb2YgdGhlIHBhY2thZ2UgdG8gY2hlY2suXG4gKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoZSBwYWNrYWdlIGlzIGluc3RhbGxlZC5cbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGVyZSB3YXMgYW4gZXJyb3Igd2hpbGUgZGV0ZWN0aW5nIGFwcGxpY2F0aW9uIHN0YXRlXG4gKi9cbmFwa1V0aWxzTWV0aG9kcy5pc0FwcEluc3RhbGxlZCA9IGFzeW5jIGZ1bmN0aW9uIGlzQXBwSW5zdGFsbGVkIChwa2cpIHtcbiAgbG9nLmRlYnVnKGBHZXR0aW5nIGluc3RhbGwgc3RhdHVzIGZvciAke3BrZ31gKTtcbiAgY29uc3QgaW5zdGFsbGVkUGF0dGVybiA9IG5ldyBSZWdFeHAoYF5cXFxccypQYWNrYWdlXFxcXHMrXFxcXFske18uZXNjYXBlUmVnRXhwKHBrZyl9XFxcXF1bXjpdKzokYCwgJ20nKTtcbiAgdHJ5IHtcbiAgICBjb25zdCBzdGRvdXQgPSBhd2FpdCB0aGlzLnNoZWxsKFsnZHVtcHN5cycsICdwYWNrYWdlJywgcGtnXSk7XG4gICAgY29uc3QgaXNJbnN0YWxsZWQgPSBpbnN0YWxsZWRQYXR0ZXJuLnRlc3Qoc3Rkb3V0KTtcbiAgICBsb2cuZGVidWcoYCcke3BrZ30nIGlzJHshaXNJbnN0YWxsZWQgPyAnIG5vdCcgOiAnJ30gaW5zdGFsbGVkYCk7XG4gICAgcmV0dXJuIGlzSW5zdGFsbGVkO1xuICB9IGNhdGNoIChlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciBmaW5kaW5nIGlmICcke3BrZ30nIGlzIGluc3RhbGxlZC4gT3JpZ2luYWwgZXJyb3I6ICR7ZS5tZXNzYWdlfWApO1xuICB9XG59O1xuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IFN0YXJ0VXJpT3B0aW9uc1xuICogQHByb3BlcnR5IHs/Ym9vbGVhbn0gd2FpdEZvckxhdW5jaCBbdHJ1ZV0gLSBpZiBgZmFsc2VgIHRoZW4gYWRiIHdvbid0IHdhaXRcbiAqIGZvciB0aGUgc3RhcnRlZCBhY3Rpdml0eSB0byByZXR1cm4gdGhlIGNvbnRyb2xcbiAqL1xuXG4vKipcbiAqIFN0YXJ0IHRoZSBwYXJ0aWN1bGFyIFVSSSBvbiB0aGUgZGV2aWNlIHVuZGVyIHRlc3QuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHVyaSAtIFRoZSBuYW1lIG9mIFVSSSB0byBzdGFydC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwa2cgLSBUaGUgbmFtZSBvZiB0aGUgcGFja2FnZSB0byBzdGFydCB0aGUgVVJJIHdpdGguXG4gKiBAcGFyYW0ge1N0YXJ0VXJpT3B0aW9uc30gb3B0c1xuICovXG5hcGtVdGlsc01ldGhvZHMuc3RhcnRVcmkgPSBhc3luYyBmdW5jdGlvbiBzdGFydFVyaSAodXJpLCBwa2csIG9wdHMgPSB7fSkge1xuICBjb25zdCB7XG4gICAgd2FpdEZvckxhdW5jaCA9IHRydWUsXG4gIH0gPSBvcHRzO1xuXG4gIGlmICghdXJpIHx8ICFwa2cpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1VSSSBhbmQgcGFja2FnZSBhcmd1bWVudHMgYXJlIHJlcXVpcmVkJyk7XG4gIH1cblxuICBjb25zdCBhcmdzID0gWydhbScsICdzdGFydCddO1xuICBpZiAod2FpdEZvckxhdW5jaCkge1xuICAgIGFyZ3MucHVzaCgnLVcnKTtcbiAgfVxuICBhcmdzLnB1c2goJy1hJywgJ2FuZHJvaWQuaW50ZW50LmFjdGlvbi5WSUVXJyxcbiAgICAnLWQnLCBlc2NhcGVTaGVsbEFyZyh1cmkpLFxuICAgIHBrZyk7XG5cbiAgdHJ5IHtcbiAgICBjb25zdCByZXMgPSBhd2FpdCB0aGlzLnNoZWxsKGFyZ3MpO1xuICAgIGlmIChyZXMudG9Mb3dlckNhc2UoKS5pbmNsdWRlcygndW5hYmxlIHRvIHJlc29sdmUgaW50ZW50JykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihyZXMpO1xuICAgIH1cbiAgfSBjYXRjaCAoZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgRXJyb3IgYXR0ZW1wdGluZyB0byBzdGFydCBVUkkuIE9yaWdpbmFsIGVycm9yOiAke2V9YCk7XG4gIH1cbn07XG5cbi8qKlxuICogQHR5cGVkZWYge09iamVjdH0gU3RhcnRBcHBPcHRpb25zXG4gKiBAcHJvcGVydHkgeyFzdHJpbmd9IHBrZyAtIFRoZSBuYW1lIG9mIHRoZSBhcHBsaWNhdGlvbiBwYWNrYWdlXG4gKiBAcHJvcGVydHkgez9zdHJpbmd9IGFjdGl2aXR5IC0gVGhlIG5hbWUgb2YgdGhlIG1haW4gYXBwbGljYXRpb24gYWN0aXZpdHkuXG4gKiBUaGlzIG9yIGFjdGlvbiBpcyByZXF1aXJlZCBpbiBvcmRlciB0byBiZSBhYmxlIHRvIGxhdW5jaCBhbiBhcHAuXG4gKiBAcHJvcGVydHkgez9zdHJpbmd9IGFjdGlvbiAtIFRoZSBuYW1lIG9mIHRoZSBpbnRlbnQgYWN0aW9uIHRoYXQgd2lsbCBsYXVuY2ggdGhlIHJlcXVpcmVkIGFwcC5cbiAqIFRoaXMgb3IgYWN0aXZpdHkgaXMgcmVxdWlyZWQgaW4gb3JkZXIgdG8gYmUgYWJsZSB0byBsYXVuY2ggYW4gYXBwLlxuICogQHByb3BlcnR5IHs/Ym9vbGVhbn0gcmV0cnkgW3RydWVdIC0gSWYgdGhpcyBwcm9wZXJ0eSBpcyBzZXQgdG8gYHRydWVgXG4gKiBhbmQgdGhlIGFjdGl2aXR5IG5hbWUgZG9lcyBub3Qgc3RhcnQgd2l0aCAnLicgdGhlbiB0aGUgbWV0aG9kXG4gKiB3aWxsIHRyeSB0byBhZGQgdGhlIG1pc3NpbmcgZG90IGFuZCBzdGFydCB0aGUgYWN0aXZpdHkgb25jZSBtb3JlXG4gKiBpZiB0aGUgZmlyc3Qgc3RhcnR1cCB0cnkgZmFpbHMuXG4gKiBAcHJvcGVydHkgez9ib29sZWFufSBzdG9wQXBwIFt0cnVlXSAtIFNldCBpdCB0byBgdHJ1ZWAgaW4gb3JkZXIgdG8gZm9yY2VmdWxseVxuICogc3RvcCB0aGUgYWN0aXZpdHkgaWYgaXQgaXMgYWxyZWFkeSBydW5uaW5nLlxuICogQHByb3BlcnR5IHs/c3RyaW5nfSB3YWl0UGtnIC0gVGhlIG5hbWUgb2YgdGhlIHBhY2thZ2UgdG8gd2FpdCB0byBvblxuICogc3RhcnR1cCAodGhpcyBvbmx5IG1ha2VzIHNlbnNlIGlmIHRoaXMgbmFtZSBpcyBkaWZmZXJlbnQgZnJvbSB0aGUgb25lLCB3aGljaCBpcyBzZXQgYXMgYHBrZ2ApXG4gKiBAcHJvcGVydHkgez9zdHJpbmd9IHdhaXRBY3Rpdml0eSAtIFRoZSBuYW1lIG9mIHRoZSBhY3Rpdml0eSB0byB3YWl0IHRvIG9uXG4gKiBzdGFydHVwICh0aGlzIG9ubHkgbWFrZXMgc2Vuc2UgaWYgdGhpcyBuYW1lIGlzIGRpZmZlcmVudCBmcm9tIHRoZSBvbmUsIHdoaWNoIGlzIHNldCBhcyBgYWN0aXZpdHlgKVxuICogQHByb3BlcnR5IHs/bnVtYmVyfSB3YWl0RHVyYXRpb24gLSBUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IHVudGlsIHRoZVxuICogYHdhaXRBY3Rpdml0eWAgaXMgZm9jdXNlZFxuICogQHByb3BlcnR5IHs/c3RyaW5nfG51bWJlcn0gdXNlciAtIFRoZSBudW1iZXIgb2YgdGhlIHVzZXIgcHJvZmlsZSB0byBzdGFydFxuICogdGhlIGdpdmVuIGFjdGl2aXR5IHdpdGguIFRoZSBkZWZhdWx0IE9TIHVzZXIgcHJvZmlsZSAodXN1YWxseSB6ZXJvKSBpcyB1c2VkXG4gKiB3aGVuIHRoaXMgcHJvcGVydHkgaXMgdW5zZXRcbiAqIEBwcm9wZXJ0eSB7P2Jvb2xlYW59IHdhaXRGb3JMYXVuY2ggW3RydWVdIC0gaWYgYGZhbHNlYCB0aGVuIGFkYiB3b24ndCB3YWl0XG4gKiBmb3IgdGhlIHN0YXJ0ZWQgYWN0aXZpdHkgdG8gcmV0dXJuIHRoZSBjb250cm9sXG4gKi9cblxuLyoqXG4gKiBTdGFydCB0aGUgcGFydGljdWxhciBwYWNrYWdlL2FjdGl2aXR5IG9uIHRoZSBkZXZpY2UgdW5kZXIgdGVzdC5cbiAqXG4gKiBAcGFyYW0ge1N0YXJ0QXBwT3B0aW9uc30gc3RhcnRBcHBPcHRpb25zIFt7fV0gLSBTdGFydHVwIG9wdGlvbnMgbWFwcGluZy5cbiAqIEByZXR1cm4ge3N0cmluZ30gVGhlIG91dHB1dCBvZiB0aGUgY29ycmVzcG9uZGluZyBhZGIgY29tbWFuZC5cbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGVyZSBpcyBhbiBlcnJvciB3aGlsZSBleGVjdXRpbmcgdGhlIGFjdGl2aXR5XG4gKi9cbmFwa1V0aWxzTWV0aG9kcy5zdGFydEFwcCA9IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0QXBwIChzdGFydEFwcE9wdGlvbnMgPSB7fSkge1xuICBpZiAoIXN0YXJ0QXBwT3B0aW9ucy5wa2cgfHwgIShzdGFydEFwcE9wdGlvbnMuYWN0aXZpdHkgfHwgc3RhcnRBcHBPcHRpb25zLmFjdGlvbikpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3BrZywgYW5kIGFjdGl2aXR5IG9yIGludGVudCBhY3Rpb24sIGFyZSByZXF1aXJlZCB0byBzdGFydCBhbiBhcHBsaWNhdGlvbicpO1xuICB9XG5cbiAgc3RhcnRBcHBPcHRpb25zID0gXy5jbG9uZShzdGFydEFwcE9wdGlvbnMpO1xuICBpZiAoc3RhcnRBcHBPcHRpb25zLmFjdGl2aXR5KSB7XG4gICAgc3RhcnRBcHBPcHRpb25zLmFjdGl2aXR5ID0gc3RhcnRBcHBPcHRpb25zLmFjdGl2aXR5LnJlcGxhY2UoJyQnLCAnXFxcXCQnKTtcbiAgfVxuICAvLyBpbml0aWFsaXppbmcgZGVmYXVsdHNcbiAgXy5kZWZhdWx0cyhzdGFydEFwcE9wdGlvbnMsIHtcbiAgICB3YWl0UGtnOiBzdGFydEFwcE9wdGlvbnMucGtnLFxuICAgIHdhaXRGb3JMYXVuY2g6IHRydWUsXG4gICAgd2FpdEFjdGl2aXR5OiBmYWxzZSxcbiAgICByZXRyeTogdHJ1ZSxcbiAgICBzdG9wQXBwOiB0cnVlXG4gIH0pO1xuICAvLyBwcmV2ZW50aW5nIG51bGwgd2FpdHBrZ1xuICBzdGFydEFwcE9wdGlvbnMud2FpdFBrZyA9IHN0YXJ0QXBwT3B0aW9ucy53YWl0UGtnIHx8IHN0YXJ0QXBwT3B0aW9ucy5wa2c7XG5cbiAgY29uc3QgYXBpTGV2ZWwgPSBhd2FpdCB0aGlzLmdldEFwaUxldmVsKCk7XG4gIGNvbnN0IGNtZCA9IGJ1aWxkU3RhcnRDbWQoc3RhcnRBcHBPcHRpb25zLCBhcGlMZXZlbCk7XG4gIGNvbnN0IGludGVudE5hbWUgPSBgJHtzdGFydEFwcE9wdGlvbnMuYWN0aW9ufSR7c3RhcnRBcHBPcHRpb25zLm9wdGlvbmFsSW50ZW50QXJndW1lbnRzID8gJyAnICsgc3RhcnRBcHBPcHRpb25zLm9wdGlvbmFsSW50ZW50QXJndW1lbnRzIDogJyd9YDtcbiAgdHJ5IHtcbiAgICBjb25zdCBzaGVsbE9wdHMgPSB7fTtcbiAgICBpZiAoXy5pc0ludGVnZXIoc3RhcnRBcHBPcHRpb25zLndhaXREdXJhdGlvbikgJiYgc3RhcnRBcHBPcHRpb25zLndhaXREdXJhdGlvbiA+PSAwKSB7XG4gICAgICBzaGVsbE9wdHMudGltZW91dCA9IHN0YXJ0QXBwT3B0aW9ucy53YWl0RHVyYXRpb247XG4gICAgfVxuICAgIGNvbnN0IHN0ZG91dCA9IGF3YWl0IHRoaXMuc2hlbGwoY21kLCBzaGVsbE9wdHMpO1xuICAgIGlmIChzdGRvdXQuaW5jbHVkZXMoJ0Vycm9yOiBBY3Rpdml0eSBjbGFzcycpICYmIHN0ZG91dC5pbmNsdWRlcygnZG9lcyBub3QgZXhpc3QnKSkge1xuICAgICAgaWYgKHN0YXJ0QXBwT3B0aW9ucy5yZXRyeSAmJiAhc3RhcnRBcHBPcHRpb25zLmFjdGl2aXR5LnN0YXJ0c1dpdGgoJy4nKSkge1xuICAgICAgICBsb2cuZGVidWcoYFdlIHRyaWVkIHRvIHN0YXJ0IGFuIGFjdGl2aXR5IHRoYXQgZG9lc24ndCBleGlzdCwgYCArXG4gICAgICAgICAgICAgICAgICBgcmV0cnlpbmcgd2l0aCAnLiR7c3RhcnRBcHBPcHRpb25zLmFjdGl2aXR5fScgYWN0aXZpdHkgbmFtZWApO1xuICAgICAgICBzdGFydEFwcE9wdGlvbnMuYWN0aXZpdHkgPSBgLiR7c3RhcnRBcHBPcHRpb25zLmFjdGl2aXR5fWA7XG4gICAgICAgIHN0YXJ0QXBwT3B0aW9ucy5yZXRyeSA9IGZhbHNlO1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5zdGFydEFwcChzdGFydEFwcE9wdGlvbnMpO1xuICAgICAgfVxuICAgICAgdGhyb3cgbmV3IEVycm9yKGBBY3Rpdml0eSBuYW1lICcke3N0YXJ0QXBwT3B0aW9ucy5hY3Rpdml0eX0nIHVzZWQgdG8gc3RhcnQgdGhlIGFwcCBkb2Vzbid0IGAgK1xuICAgICAgICAgICAgICAgICAgICAgIGBleGlzdCBvciBjYW5ub3QgYmUgbGF1bmNoZWQhIE1ha2Ugc3VyZSBpdCBleGlzdHMgYW5kIGlzIGEgbGF1bmNoYWJsZSBhY3Rpdml0eWApO1xuICAgIH0gZWxzZSBpZiAoc3Rkb3V0LmluY2x1ZGVzKCdFcnJvcjogSW50ZW50IGRvZXMgbm90IG1hdGNoIGFueSBhY3Rpdml0aWVzJykgfHwgc3Rkb3V0LmluY2x1ZGVzKCdFcnJvcjogQWN0aXZpdHkgbm90IHN0YXJ0ZWQsIHVuYWJsZSB0byByZXNvbHZlIEludGVudCcpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEFjdGl2aXR5IGZvciBpbnRlbnQgJyR7aW50ZW50TmFtZX0nIHVzZWQgdG8gc3RhcnQgdGhlIGFwcCBkb2Vzbid0IGAgK1xuICAgICAgICAgICAgICAgICAgICAgIGBleGlzdCBvciBjYW5ub3QgYmUgbGF1bmNoZWQhIE1ha2Ugc3VyZSBpdCBleGlzdHMgYW5kIGlzIGEgbGF1bmNoYWJsZSBhY3Rpdml0eWApO1xuICAgIH0gZWxzZSBpZiAoc3Rkb3V0LmluY2x1ZGVzKCdqYXZhLmxhbmcuU2VjdXJpdHlFeGNlcHRpb24nKSkge1xuICAgICAgLy8gaWYgdGhlIGFwcCBpcyBkaXNhYmxlZCBvbiBhIHJlYWwgZGV2aWNlIGl0IHdpbGwgdGhyb3cgYSBzZWN1cml0eSBleGNlcHRpb25cbiAgICAgIHRocm93IG5ldyBFcnJvcihgVGhlIHBlcm1pc3Npb24gdG8gc3RhcnQgJyR7c3RhcnRBcHBPcHRpb25zLmFjdGl2aXR5fScgYWN0aXZpdHkgaGFzIGJlZW4gZGVuaWVkLmAgK1xuICAgICAgICAgICAgICAgICAgICAgIGBNYWtlIHN1cmUgdGhlIGFjdGl2aXR5L3BhY2thZ2UgbmFtZXMgYXJlIGNvcnJlY3QuYCk7XG4gICAgfVxuICAgIGlmIChzdGFydEFwcE9wdGlvbnMud2FpdEFjdGl2aXR5KSB7XG4gICAgICBhd2FpdCB0aGlzLndhaXRGb3JBY3Rpdml0eShzdGFydEFwcE9wdGlvbnMud2FpdFBrZywgc3RhcnRBcHBPcHRpb25zLndhaXRBY3Rpdml0eSwgc3RhcnRBcHBPcHRpb25zLndhaXREdXJhdGlvbik7XG4gICAgfVxuICAgIHJldHVybiBzdGRvdXQ7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBjb25zdCBhcHBEZXNjcmlwdG9yID0gc3RhcnRBcHBPcHRpb25zLnBrZyB8fCBpbnRlbnROYW1lO1xuICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IHN0YXJ0IHRoZSAnJHthcHBEZXNjcmlwdG9yfScgYXBwbGljYXRpb24uIGAgK1xuICAgICAgYFZpc2l0ICR7QUNUSVZJVElFU19UUk9VQkxFU0hPT1RJTkdfTElOS30gZm9yIHRyb3VibGVzaG9vdGluZy4gYCArXG4gICAgICBgT3JpZ2luYWwgZXJyb3I6ICR7ZS5tZXNzYWdlfWApO1xuICB9XG59O1xuXG4vKipcbiAqIEhlbHBlciBtZXRob2QgdG8gY2FsbCBgYWRiIGR1bXBzeXMgd2luZG93IHdpbmRvd3MvZGlzcGxheXNgXG4gKi9cbmFwa1V0aWxzTWV0aG9kcy5kdW1wV2luZG93cyA9IGFzeW5jIGZ1bmN0aW9uIGR1bXBXaW5kb3dzICgpIHtcbiAgY29uc3QgYXBpTGV2ZWwgPSBhd2FpdCB0aGlzLmdldEFwaUxldmVsKCk7XG5cbiAgLy8gV2l0aCB2ZXJzaW9uIDI5LCBBbmRyb2lkIGNoYW5nZWQgdGhlIGR1bXBzeXMgc3ludGF4XG4gIGNvbnN0IGR1bXBzeXNBcmcgPSBhcGlMZXZlbCA+PSAyOSA/ICdkaXNwbGF5cycgOiAnd2luZG93cyc7XG4gIGNvbnN0IGNtZCA9IFsnZHVtcHN5cycsICd3aW5kb3cnLCBkdW1wc3lzQXJnXTtcblxuICByZXR1cm4gYXdhaXQgdGhpcy5zaGVsbChjbWQpO1xufTtcblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBQYWNrYWdlQWN0aXZpdHlJbmZvXG4gKiBAcHJvcGVydHkgez9zdHJpbmd9IGFwcFBhY2thZ2UgLSBUaGUgbmFtZSBvZiBhcHBsaWNhdGlvbiBwYWNrYWdlLFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIGV4YW1wbGUgJ2NvbS5hY21lLmFwcCcuXG4gKiBAcHJvcGVydHkgez9zdHJpbmd9IGFwcEFjdGl2aXR5IC0gVGhlIG5hbWUgb2YgbWFpbiBhcHBsaWNhdGlvbiBhY3Rpdml0eS5cbiAqL1xuXG4vKipcbiAqIEdldCB0aGUgbmFtZSBvZiBjdXJyZW50bHkgZm9jdXNlZCBwYWNrYWdlIGFuZCBhY3Rpdml0eS5cbiAqXG4gKiBAcmV0dXJuIHtQYWNrYWdlQWN0aXZpdHlJbmZvfSBUaGUgbWFwcGluZywgd2hlcmUgcHJvcGVydHkgbmFtZXMgYXJlICdhcHBQYWNrYWdlJyBhbmQgJ2FwcEFjdGl2aXR5Jy5cbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGVyZSBpcyBhbiBlcnJvciB3aGlsZSBwYXJzaW5nIHRoZSBkYXRhLlxuICovXG5hcGtVdGlsc01ldGhvZHMuZ2V0Rm9jdXNlZFBhY2thZ2VBbmRBY3Rpdml0eSA9IGFzeW5jIGZ1bmN0aW9uIGdldEZvY3VzZWRQYWNrYWdlQW5kQWN0aXZpdHkgKCkge1xuICBsb2cuZGVidWcoJ0dldHRpbmcgZm9jdXNlZCBwYWNrYWdlIGFuZCBhY3Rpdml0eScpO1xuICBsZXQgc3Rkb3V0O1xuICB0cnkge1xuICAgIHN0ZG91dCA9IGF3YWl0IHRoaXMuZHVtcFdpbmRvd3MoKTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBDb3VsZCBub3QgcmV0cmlldmUgdGhlIGN1cnJlbnRseSBmb2N1c2VkIHBhY2thZ2UgYW5kIGFjdGl2aXR5LiBPcmlnaW5hbCBlcnJvcjogJHtlLm1lc3NhZ2V9YFxuICAgICk7XG4gIH1cblxuICBjb25zdCBudWxsRm9jdXNlZEFwcFJlID0gL15cXHMqbUZvY3VzZWRBcHA9bnVsbC9tO1xuICAvLyBodHRwczovL3JlZ2V4MTAxLmNvbS9yL3haOHZGNy8xXG4gIGNvbnN0IGZvY3VzZWRBcHBSZSA9IG5ldyBSZWdFeHAoXG4gICAgJ15cXFxccyptRm9jdXNlZEFwcC4rUmVjb3JkXFxcXHsuKlxcXFxzKFteXFxcXHNcXFxcL1xcXFx9XSspXFxcXC8oW15cXFxcc1xcXFwvXFxcXH1cXFxcLF0rKVxcXFwsPyhcXFxcc1teXFxcXHNcXFxcL1xcXFx9XSspKlxcXFx9JyxcbiAgICAnbWcnXG4gICk7XG4gIGNvbnN0IG51bGxDdXJyZW50Rm9jdXNSZSA9IC9eXFxzKm1DdXJyZW50Rm9jdXM9bnVsbC9tO1xuICBjb25zdCBjdXJyZW50Rm9jdXNBcHBSZSA9IG5ldyBSZWdFeHAoJ15cXFxccyptQ3VycmVudEZvY3VzLitcXFxcey4rXFxcXHMoW15cXFxcc1xcXFwvXSspXFxcXC8oW15cXFxcc10rKVxcXFxiJywgJ21nJyk7XG5cbiAgY29uc3QgZm9jdXNlZEFwcENhbmRpZGF0ZXMgPSBbXTtcbiAgY29uc3QgY3VycmVudEZvY3VzQXBwQ2FuZGlkYXRlcyA9IFtdO1xuICBmb3IgKGNvbnN0IFtjYW5kaWRhdGVzLCBwYXR0ZXJuXSBvZiBbXG4gICAgW2ZvY3VzZWRBcHBDYW5kaWRhdGVzLCBmb2N1c2VkQXBwUmVdLFxuICAgIFtjdXJyZW50Rm9jdXNBcHBDYW5kaWRhdGVzLCBjdXJyZW50Rm9jdXNBcHBSZV1cbiAgXSkge1xuICAgIGxldCBtYXRjaDtcbiAgICB3aGlsZSAoKG1hdGNoID0gcGF0dGVybi5leGVjKHN0ZG91dCkpKSB7XG4gICAgICBjYW5kaWRhdGVzLnB1c2goe1xuICAgICAgICBhcHBQYWNrYWdlOiBtYXRjaFsxXS50cmltKCksXG4gICAgICAgIGFwcEFjdGl2aXR5OiBtYXRjaFsyXS50cmltKClcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuICBpZiAoZm9jdXNlZEFwcENhbmRpZGF0ZXMubGVuZ3RoID4gMSAmJiBjdXJyZW50Rm9jdXNBcHBDYW5kaWRhdGVzLmxlbmd0aCA+IDApIHtcbiAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vYXBwaXVtL2FwcGl1bS9pc3N1ZXMvMTcxMDZcbiAgICByZXR1cm4gXy5pbnRlcnNlY3Rpb25XaXRoKGZvY3VzZWRBcHBDYW5kaWRhdGVzLCBjdXJyZW50Rm9jdXNBcHBDYW5kaWRhdGVzLCBfLmlzRXF1YWwpWzBdXG4gICAgICA/PyBmb2N1c2VkQXBwQ2FuZGlkYXRlc1swXTtcbiAgfVxuICBpZiAoZm9jdXNlZEFwcENhbmRpZGF0ZXMubGVuZ3RoID4gMCB8fCBjdXJyZW50Rm9jdXNBcHBDYW5kaWRhdGVzLmxlbmd0aCA+IDApIHtcbiAgICByZXR1cm4gZm9jdXNlZEFwcENhbmRpZGF0ZXNbMF0gPz8gY3VycmVudEZvY3VzQXBwQ2FuZGlkYXRlc1swXTtcbiAgfVxuXG4gIGZvciAoY29uc3QgcGF0dGVybiBvZiBbbnVsbEZvY3VzZWRBcHBSZSwgbnVsbEN1cnJlbnRGb2N1c1JlXSkge1xuICAgIGlmIChwYXR0ZXJuLmV4ZWMoc3Rkb3V0KSkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYXBwUGFja2FnZTogbnVsbCxcbiAgICAgICAgYXBwQWN0aXZpdHk6IG51bGxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgbG9nLmRlYnVnKHN0ZG91dCk7XG4gIHRocm93IG5ldyBFcnJvcignQ291bGQgbm90IHJldHJpZXZlIHRoZSBjdXJyZW50bHkgZm9jdXNlZCBwYWNrYWdlIGFuZCBhY3Rpdml0eScpO1xufTtcblxuLyoqXG4gKiBXYWl0IGZvciB0aGUgZ2l2ZW4gYWN0aXZpdHkgdG8gYmUgZm9jdXNlZC9ub24tZm9jdXNlZC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcGtnIC0gVGhlIG5hbWUgb2YgdGhlIHBhY2thZ2UgdG8gd2FpdCBmb3IuXG4gKiBAcGFyYW0ge3N0cmluZ30gYWN0aXZpdHkgLSBUaGUgbmFtZSBvZiB0aGUgYWN0aXZpdHksIGJlbG9uZ2luZyB0byB0aGF0IHBhY2thZ2UsXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0byB3YWl0IGZvci5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gd2FpdEZvclN0b3AgLSBXaGV0aGVyIHRvIHdhaXQgdW50aWwgdGhlIGFjdGl2aXR5IGlzIGZvY3VzZWQgKHRydWUpXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3IgaXMgbm90IGZvY3VzZWQgKGZhbHNlKS5cbiAqIEBwYXJhbSB7bnVtYmVyfSB3YWl0TXMgWzIwMDAwXSAtIE51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBiZWZvcmUgdGltZW91dCBvY2N1cnMuXG4gKiBAdGhyb3dzIHtlcnJvcn0gSWYgdGltZW91dCBoYXBwZW5zLlxuICovXG5hcGtVdGlsc01ldGhvZHMud2FpdEZvckFjdGl2aXR5T3JOb3QgPSBhc3luYyBmdW5jdGlvbiB3YWl0Rm9yQWN0aXZpdHlPck5vdCAocGtnLCBhY3Rpdml0eSwgd2FpdEZvclN0b3AsIHdhaXRNcyA9IDIwMDAwKSB7XG4gIGlmICghcGtnIHx8ICFhY3Rpdml0eSkge1xuICAgIHRocm93IG5ldyBFcnJvcignUGFja2FnZSBhbmQgYWN0aXZpdHkgcmVxdWlyZWQuJyk7XG4gIH1cbiAgbG9nLmRlYnVnKGBXYWl0aW5nIHVwIHRvICR7d2FpdE1zfW1zIGZvciBhY3Rpdml0eSBtYXRjaGluZyBwa2c6ICcke3BrZ30nIGFuZCBgICtcbiAgICAgICAgICAgIGBhY3Rpdml0eTogJyR7YWN0aXZpdHl9JyB0byR7d2FpdEZvclN0b3AgPyAnIG5vdCcgOiAnJ30gYmUgZm9jdXNlZGApO1xuXG4gIGNvbnN0IHNwbGl0TmFtZXMgPSAobmFtZXMpID0+IG5hbWVzLnNwbGl0KCcsJykubWFwKChuYW1lKSA9PiBuYW1lLnRyaW0oKSk7XG4gIGNvbnN0IGFsbFBhY2thZ2VzID0gc3BsaXROYW1lcyhwa2cpO1xuICBjb25zdCBhbGxBY3Rpdml0aWVzID0gc3BsaXROYW1lcyhhY3Rpdml0eSk7XG5cbiAgY29uc3QgcG9zc2libGVBY3Rpdml0eU5hbWVzID0gW107XG4gIGZvciAoY29uc3Qgb25lQWN0aXZpdHkgb2YgYWxsQWN0aXZpdGllcykge1xuICAgIGlmIChvbmVBY3Rpdml0eS5zdGFydHNXaXRoKCcuJykpIHtcbiAgICAgIC8vIGFkZCB0aGUgcGFja2FnZSBuYW1lIGlmIGFjdGl2aXR5IGlzIG5vdCBmdWxsIHF1YWxpZmllZFxuICAgICAgZm9yIChjb25zdCBjdXJyZW50UGtnIG9mIGFsbFBhY2thZ2VzKSB7XG4gICAgICAgIHBvc3NpYmxlQWN0aXZpdHlOYW1lcy5wdXNoKGAke2N1cnJlbnRQa2d9JHtvbmVBY3Rpdml0eX1gLnJlcGxhY2UoL1xcLisvZywgJy4nKSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIGFjY2VwdCBmdWxseSBxdWFsaWZpZWQgYWN0aXZpdHkgbmFtZS5cbiAgICAgIHBvc3NpYmxlQWN0aXZpdHlOYW1lcy5wdXNoKG9uZUFjdGl2aXR5KTtcbiAgICAgIHBvc3NpYmxlQWN0aXZpdHlOYW1lcy5wdXNoKGAke3BrZ30uJHtvbmVBY3Rpdml0eX1gKTtcbiAgICB9XG4gIH1cbiAgbG9nLmRlYnVnKGBQb3NzaWJsZSBhY3Rpdml0aWVzLCB0byBiZSBjaGVja2VkOiAke3Bvc3NpYmxlQWN0aXZpdHlOYW1lcy5tYXAoKG5hbWUpID0+IGAnJHtuYW1lfSdgKS5qb2luKCcsICcpfWApO1xuXG4gIGNvbnN0IHBvc3NpYmxlQWN0aXZpdHlQYXR0ZXJucyA9IHBvc3NpYmxlQWN0aXZpdHlOYW1lcy5tYXAoXG4gICAgKGFjdE5hbWUpID0+IG5ldyBSZWdFeHAoYF4ke2FjdE5hbWUucmVwbGFjZSgvXFwuL2csICdcXFxcLicpLnJlcGxhY2UoL1xcKi9nLCAnLio/JykucmVwbGFjZSgvXFwkL2csICdcXFxcJCcpfSRgKVxuICApO1xuXG4gIGNvbnN0IGNvbmRpdGlvbkZ1bmMgPSBhc3luYyAoKSA9PiB7XG4gICAgbGV0IGFwcFBhY2thZ2U7XG4gICAgbGV0IGFwcEFjdGl2aXR5O1xuICAgIHRyeSB7XG4gICAgICAoe2FwcFBhY2thZ2UsIGFwcEFjdGl2aXR5fSA9IGF3YWl0IHRoaXMuZ2V0Rm9jdXNlZFBhY2thZ2VBbmRBY3Rpdml0eSgpKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBsb2cuZGVidWcoZS5tZXNzYWdlKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKGFwcEFjdGl2aXR5ICYmIGFwcFBhY2thZ2UpIHtcbiAgICAgIGNvbnN0IGZ1bGx5UXVhbGlmaWVkQWN0aXZpdHkgPSBhcHBBY3Rpdml0eS5zdGFydHNXaXRoKCcuJykgPyBgJHthcHBQYWNrYWdlfSR7YXBwQWN0aXZpdHl9YCA6IGFwcEFjdGl2aXR5O1xuICAgICAgbG9nLmRlYnVnKGBGb3VuZCBwYWNrYWdlOiAnJHthcHBQYWNrYWdlfScgYW5kIGZ1bGx5IHF1YWxpZmllZCBhY3Rpdml0eSBuYW1lIDogJyR7ZnVsbHlRdWFsaWZpZWRBY3Rpdml0eX0nYCk7XG4gICAgICBjb25zdCBpc0FjdGl2aXR5Rm91bmQgPSBfLmluY2x1ZGVzKGFsbFBhY2thZ2VzLCBhcHBQYWNrYWdlKVxuICAgICAgICAmJiBwb3NzaWJsZUFjdGl2aXR5UGF0dGVybnMuc29tZSgocCkgPT4gcC50ZXN0KGZ1bGx5UXVhbGlmaWVkQWN0aXZpdHkpKTtcbiAgICAgIGlmICgoIXdhaXRGb3JTdG9wICYmIGlzQWN0aXZpdHlGb3VuZCkgfHwgKHdhaXRGb3JTdG9wICYmICFpc0FjdGl2aXR5Rm91bmQpKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgIH1cbiAgICBsb2cuZGVidWcoJ0luY29ycmVjdCBwYWNrYWdlIGFuZCBhY3Rpdml0eS4gUmV0cnlpbmcuJyk7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9O1xuXG4gIHRyeSB7XG4gICAgYXdhaXQgd2FpdEZvckNvbmRpdGlvbihjb25kaXRpb25GdW5jLCB7XG4gICAgICB3YWl0TXM6IHBhcnNlSW50KHdhaXRNcywgMTApLFxuICAgICAgaW50ZXJ2YWxNczogNTAwLFxuICAgIH0pO1xuICB9IGNhdGNoIChlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGAke3Bvc3NpYmxlQWN0aXZpdHlOYW1lcy5tYXAoKG5hbWUpID0+IGAnJHtuYW1lfSdgKS5qb2luKCcgb3IgJyl9IG5ldmVyICR7d2FpdEZvclN0b3AgPyAnc3RvcHBlZCcgOiAnc3RhcnRlZCd9LiBgICtcbiAgICAgIGBWaXNpdCAke0FDVElWSVRJRVNfVFJPVUJMRVNIT09USU5HX0xJTkt9IGZvciB0cm91Ymxlc2hvb3RpbmdgKTtcbiAgfVxufTtcblxuLyoqXG4gKiBXYWl0IGZvciB0aGUgZ2l2ZW4gYWN0aXZpdHkgdG8gYmUgZm9jdXNlZFxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBwa2cgLSBUaGUgbmFtZSBvZiB0aGUgcGFja2FnZSB0byB3YWl0IGZvci5cbiAqIEBwYXJhbSB7c3RyaW5nfSBhY3Rpdml0eSAtIFRoZSBuYW1lIG9mIHRoZSBhY3Rpdml0eSwgYmVsb25naW5nIHRvIHRoYXQgcGFja2FnZSxcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvIHdhaXQgZm9yLlxuICogQHBhcmFtIHtudW1iZXJ9IHdhaXRNcyBbMjAwMDBdIC0gTnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGJlZm9yZSB0aW1lb3V0IG9jY3Vycy5cbiAqIEB0aHJvd3Mge2Vycm9yfSBJZiB0aW1lb3V0IGhhcHBlbnMuXG4gKi9cbmFwa1V0aWxzTWV0aG9kcy53YWl0Rm9yQWN0aXZpdHkgPSBhc3luYyBmdW5jdGlvbiB3YWl0Rm9yQWN0aXZpdHkgKHBrZywgYWN0LCB3YWl0TXMgPSAyMDAwMCkge1xuICBhd2FpdCB0aGlzLndhaXRGb3JBY3Rpdml0eU9yTm90KHBrZywgYWN0LCBmYWxzZSwgd2FpdE1zKTtcbn07XG5cbi8qKlxuICogV2FpdCBmb3IgdGhlIGdpdmVuIGFjdGl2aXR5IHRvIGJlIG5vbi1mb2N1c2VkLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBwa2cgLSBUaGUgbmFtZSBvZiB0aGUgcGFja2FnZSB0byB3YWl0IGZvci5cbiAqIEBwYXJhbSB7c3RyaW5nfSBhY3Rpdml0eSAtIFRoZSBuYW1lIG9mIHRoZSBhY3Rpdml0eSwgYmVsb25naW5nIHRvIHRoYXQgcGFja2FnZSxcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvIHdhaXQgZm9yLlxuICogQHBhcmFtIHtudW1iZXJ9IHdhaXRNcyBbMjAwMDBdIC0gTnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGJlZm9yZSB0aW1lb3V0IG9jY3Vycy5cbiAqIEB0aHJvd3Mge2Vycm9yfSBJZiB0aW1lb3V0IGhhcHBlbnMuXG4gKi9cbmFwa1V0aWxzTWV0aG9kcy53YWl0Rm9yTm90QWN0aXZpdHkgPSBhc3luYyBmdW5jdGlvbiB3YWl0Rm9yTm90QWN0aXZpdHkgKHBrZywgYWN0LCB3YWl0TXMgPSAyMDAwMCkge1xuICBhd2FpdCB0aGlzLndhaXRGb3JBY3Rpdml0eU9yTm90KHBrZywgYWN0LCB0cnVlLCB3YWl0TXMpO1xufTtcblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBVbmluc3RhbGxPcHRpb25zXG4gKiBAcHJvcGVydHkge251bWJlcn0gdGltZW91dCBbYWRiRXhlY1RpbWVvdXRdIC0gVGhlIGNvdW50IG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IHVudGlsIHRoZVxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFwcCBpcyB1bmluc3RhbGxlZC5cbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0ga2VlcERhdGEgW2ZhbHNlXSAtIFNldCB0byB0cnVlIGluIG9yZGVyIHRvIGtlZXAgdGhlXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcHBsaWNhdGlvbiBkYXRhIGFuZCBjYWNoZSBmb2xkZXJzIGFmdGVyIHVuaW5zdGFsbC5cbiAqL1xuXG4vKipcbiAqIFVuaW5zdGFsbCB0aGUgZ2l2ZW4gcGFja2FnZSBmcm9tIHRoZSBkZXZpY2UgdW5kZXIgdGVzdC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcGtnIC0gVGhlIG5hbWUgb2YgdGhlIHBhY2thZ2UgdG8gYmUgdW5pbnN0YWxsZWQuXG4gKiBAcGFyYW0gez9Vbmluc3RhbGxPcHRpb25zfSBvcHRpb25zIC0gVGhlIHNldCBvZiB1bmluc3RhbGwgb3B0aW9ucy5cbiAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgdGhlIHBhY2thZ2Ugd2FzIGZvdW5kIG9uIHRoZSBkZXZpY2UgYW5kXG4gKiAgICAgICAgICAgICAgICAgICBzdWNjZXNzZnVsbHkgdW5pbnN0YWxsZWQuXG4gKi9cbmFwa1V0aWxzTWV0aG9kcy51bmluc3RhbGxBcGsgPSBhc3luYyBmdW5jdGlvbiB1bmluc3RhbGxBcGsgKHBrZywgb3B0aW9ucyA9IHt9KSB7XG4gIGxvZy5kZWJ1ZyhgVW5pbnN0YWxsaW5nICR7cGtnfWApO1xuICBpZiAoIWF3YWl0IHRoaXMuaXNBcHBJbnN0YWxsZWQocGtnKSkge1xuICAgIGxvZy5pbmZvKGAke3BrZ30gd2FzIG5vdCB1bmluc3RhbGxlZCwgYmVjYXVzZSBpdCB3YXMgbm90IHByZXNlbnQgb24gdGhlIGRldmljZWApO1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIGNvbnN0IGNtZCA9IFsndW5pbnN0YWxsJ107XG4gIGlmIChvcHRpb25zLmtlZXBEYXRhKSB7XG4gICAgY21kLnB1c2goJy1rJyk7XG4gIH1cbiAgY21kLnB1c2gocGtnKTtcblxuICBsZXQgc3Rkb3V0O1xuICB0cnkge1xuICAgIGF3YWl0IHRoaXMuZm9yY2VTdG9wKHBrZyk7XG4gICAgc3Rkb3V0ID0gKGF3YWl0IHRoaXMuYWRiRXhlYyhjbWQsIHt0aW1lb3V0OiBvcHRpb25zLnRpbWVvdXR9KSkudHJpbSgpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gdW5pbnN0YWxsIEFQSy4gT3JpZ2luYWwgZXJyb3I6ICR7ZS5tZXNzYWdlfWApO1xuICB9XG4gIGxvZy5kZWJ1ZyhgJ2FkYiAke2NtZC5qb2luKCcgJyl9JyBjb21tYW5kIG91dHB1dDogJHtzdGRvdXR9YCk7XG4gIGlmIChzdGRvdXQuaW5jbHVkZXMoJ1N1Y2Nlc3MnKSkge1xuICAgIGxvZy5pbmZvKGAke3BrZ30gd2FzIHN1Y2Nlc3NmdWxseSB1bmluc3RhbGxlZGApO1xuICAgIHJldHVybiB0cnVlO1xuICB9XG4gIGxvZy5pbmZvKGAke3BrZ30gd2FzIG5vdCB1bmluc3RhbGxlZGApO1xuICByZXR1cm4gZmFsc2U7XG59O1xuXG4vKipcbiAqIEluc3RhbGwgdGhlIHBhY2thZ2UgYWZ0ZXIgaXQgd2FzIHB1c2hlZCB0byB0aGUgZGV2aWNlIHVuZGVyIHRlc3QuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGFwa1BhdGhPbkRldmljZSAtIFRoZSBmdWxsIHBhdGggdG8gdGhlIHBhY2thZ2Ugb24gdGhlIGRldmljZSBmaWxlIHN5c3RlbS5cbiAqIEBwYXJhbSB7b2JqZWN0fSBvcHRzIFt7fV0gLSBBZGRpdGlvbmFsIGV4ZWMgb3B0aW9ucy4gU2VlIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vYXBwaXVtL25vZGUtdGVlbl9wcm9jZXNzfVxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciBtb3JlIGRldGFpbHMgb24gdGhpcyBwYXJhbWV0ZXIuXG4gKiBAdGhyb3dzIHtlcnJvcn0gSWYgdGhlcmUgd2FzIGEgZmFpbHVyZSBkdXJpbmcgYXBwbGljYXRpb24gaW5zdGFsbC5cbiAqL1xuYXBrVXRpbHNNZXRob2RzLmluc3RhbGxGcm9tRGV2aWNlUGF0aCA9IGFzeW5jIGZ1bmN0aW9uIGluc3RhbGxGcm9tRGV2aWNlUGF0aCAoYXBrUGF0aE9uRGV2aWNlLCBvcHRzID0ge30pIHtcbiAgbGV0IHN0ZG91dCA9IGF3YWl0IHRoaXMuc2hlbGwoWydwbScsICdpbnN0YWxsJywgJy1yJywgYXBrUGF0aE9uRGV2aWNlXSwgb3B0cyk7XG4gIGlmIChzdGRvdXQuaW5kZXhPZignRmFpbHVyZScpICE9PSAtMSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgUmVtb3RlIGluc3RhbGwgZmFpbGVkOiAke3N0ZG91dH1gKTtcbiAgfVxufTtcblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBDYWNoaW5nT3B0aW9uc1xuICogQHByb3BlcnR5IHs/bnVtYmVyfSB0aW1lb3V0IFthZGJFeGVjVGltZW91dF0gLSBUaGUgY291bnQgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgdW50aWwgdGhlXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFwcCBpcyB1cGxvYWRlZCB0byB0aGUgcmVtb3RlIGxvY2F0aW9uLlxuICovXG5cbi8qKlxuICogQ2FjaGVzIHRoZSBnaXZlbiBBUEsgYXQgYSByZW1vdGUgbG9jYXRpb24gdG8gc3BlZWQgdXAgZnVydGhlciBBUEsgZGVwbG95bWVudHMuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGFwa1BhdGggLSBGdWxsIHBhdGggdG8gdGhlIGFwayBvbiB0aGUgbG9jYWwgRlNcbiAqIEBwYXJhbSB7P0NhY2hpbmdPcHRpb25zfSBvcHRpb25zIC0gQ2FjaGluZyBvcHRpb25zXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIEZ1bGwgcGF0aCB0byB0aGUgY2FjaGVkIGFwayBvbiB0aGUgcmVtb3RlIGZpbGUgc3lzdGVtXG4gKiBAdGhyb3dzIHtFcnJvcn0gaWYgdGhlcmUgd2FzIGEgZmFpbHVyZSB3aGlsZSBjYWNoaW5nIHRoZSBhcHBcbiAqL1xuYXBrVXRpbHNNZXRob2RzLmNhY2hlQXBrID0gYXN5bmMgZnVuY3Rpb24gY2FjaGVBcGsgKGFwa1BhdGgsIG9wdGlvbnMgPSB7fSkge1xuICBjb25zdCBhcHBIYXNoID0gYXdhaXQgZnMuaGFzaChhcGtQYXRoKTtcbiAgY29uc3QgcmVtb3RlUGF0aCA9IHBhdGgucG9zaXguam9pbihSRU1PVEVfQ0FDSEVfUk9PVCwgYCR7YXBwSGFzaH0uYXBrYCk7XG4gIGNvbnN0IHJlbW90ZUNhY2hlZEZpbGVzID0gW107XG4gIC8vIEdldCBjdXJyZW50IGNvbnRlbnRzIG9mIHRoZSByZW1vdGUgY2FjaGUgb3IgY3JlYXRlIGl0IGZvciB0aGUgZmlyc3QgdGltZVxuICB0cnkge1xuICAgIGNvbnN0IGVycm9yTWFya2VyID0gJ19FUlJPUl8nO1xuICAgIGxldCBsc091dHB1dCA9IG51bGw7XG4gICAgaWYgKHRoaXMuX2FyZUV4dGVuZGVkTHNPcHRpb25zU3VwcG9ydGVkID09PSB0cnVlIHx8ICFfLmlzQm9vbGVhbih0aGlzLl9hcmVFeHRlbmRlZExzT3B0aW9uc1N1cHBvcnRlZCkpIHtcbiAgICAgIGxzT3V0cHV0ID0gYXdhaXQgdGhpcy5zaGVsbChbYGxzIC10IC0xICR7UkVNT1RFX0NBQ0hFX1JPT1R9IDI+JjEgfHwgZWNobyAke2Vycm9yTWFya2VyfWBdKTtcbiAgICB9XG4gICAgaWYgKCFfLmlzU3RyaW5nKGxzT3V0cHV0KSB8fCAobHNPdXRwdXQuaW5jbHVkZXMoZXJyb3JNYXJrZXIpICYmICFsc091dHB1dC5pbmNsdWRlcyhSRU1PVEVfQ0FDSEVfUk9PVCkpKSB7XG4gICAgICBpZiAoIV8uaXNCb29sZWFuKHRoaXMuX2FyZUV4dGVuZGVkTHNPcHRpb25zU3VwcG9ydGVkKSkge1xuICAgICAgICBsb2cuZGVidWcoJ1RoZSBjdXJyZW50IEFuZHJvaWQgQVBJIGRvZXMgbm90IHN1cHBvcnQgZXh0ZW5kZWQgbHMgb3B0aW9ucy4gJyArXG4gICAgICAgICAgJ0RlZmF1bHRpbmcgdG8gbm8tb3B0aW9ucyBjYWxsJyk7XG4gICAgICB9XG4gICAgICBsc091dHB1dCA9IGF3YWl0IHRoaXMuc2hlbGwoW2BscyAke1JFTU9URV9DQUNIRV9ST09UfSAyPiYxIHx8IGVjaG8gJHtlcnJvck1hcmtlcn1gXSk7XG4gICAgICB0aGlzLl9hcmVFeHRlbmRlZExzT3B0aW9uc1N1cHBvcnRlZCA9IGZhbHNlO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLl9hcmVFeHRlbmRlZExzT3B0aW9uc1N1cHBvcnRlZCA9IHRydWU7XG4gICAgfVxuICAgIGlmIChsc091dHB1dC5pbmNsdWRlcyhlcnJvck1hcmtlcikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihsc091dHB1dC5zdWJzdHJpbmcoMCwgbHNPdXRwdXQuaW5kZXhPZihlcnJvck1hcmtlcikpKTtcbiAgICB9XG4gICAgcmVtb3RlQ2FjaGVkRmlsZXMucHVzaCguLi4oXG4gICAgICBsc091dHB1dC5zcGxpdCgnXFxuJylcbiAgICAgICAgLm1hcCgoeCkgPT4geC50cmltKCkpXG4gICAgICAgIC5maWx0ZXIoQm9vbGVhbilcbiAgICApKTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIGxvZy5kZWJ1ZyhgR290IGFuIGVycm9yICcke2UubWVzc2FnZS50cmltKCl9JyB3aGlsZSBnZXR0aW5nIHRoZSBsaXN0IG9mIGZpbGVzIGluIHRoZSBjYWNoZS4gYCArXG4gICAgICBgQXNzdW1pbmcgdGhlIGNhY2hlIGRvZXMgbm90IGV4aXN0IHlldGApO1xuICAgIGF3YWl0IHRoaXMuc2hlbGwoWydta2RpcicsICctcCcsIFJFTU9URV9DQUNIRV9ST09UXSk7XG4gIH1cbiAgbG9nLmRlYnVnKGBUaGUgY291bnQgb2YgYXBwbGljYXRpb25zIGluIHRoZSBjYWNoZTogJHtyZW1vdGVDYWNoZWRGaWxlcy5sZW5ndGh9YCk7XG4gIGNvbnN0IHRvSGFzaCA9IChyZW1vdGVQYXRoKSA9PiBwYXRoLnBvc2l4LnBhcnNlKHJlbW90ZVBhdGgpLm5hbWU7XG4gIC8vIFB1c2ggdGhlIGFwayB0byB0aGUgcmVtb3RlIGNhY2hlIGlmIG5lZWRlZFxuICBpZiAocmVtb3RlQ2FjaGVkRmlsZXMuc29tZSgoeCkgPT4gdG9IYXNoKHgpID09PSBhcHBIYXNoKSkge1xuICAgIGxvZy5pbmZvKGBUaGUgYXBwbGljYXRpb24gYXQgJyR7YXBrUGF0aH0nIGlzIGFscmVhZHkgY2FjaGVkIHRvICcke3JlbW90ZVBhdGh9J2ApO1xuICAgIC8vIFVwZGF0ZSB0aGUgYXBwbGljYXRpb24gdGltZXN0YW1wIGFzeW5jaHJvbm91c2x5IGluIG9yZGVyIHRvIGJ1bXAgaXRzIHBvc2l0aW9uXG4gICAgLy8gaW4gdGhlIHNvcnRlZCBscyBvdXRwdXRcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcHJvbWlzZS9wcmVmZXItYXdhaXQtdG8tdGhlblxuICAgIHRoaXMuc2hlbGwoWyd0b3VjaCcsICctYW0nLCByZW1vdGVQYXRoXSkuY2F0Y2goKCkgPT4ge30pO1xuICB9IGVsc2Uge1xuICAgIGxvZy5pbmZvKGBDYWNoaW5nIHRoZSBhcHBsaWNhdGlvbiBhdCAnJHthcGtQYXRofScgdG8gJyR7cmVtb3RlUGF0aH0nYCk7XG4gICAgY29uc3QgdGltZXIgPSBuZXcgdGltaW5nLlRpbWVyKCkuc3RhcnQoKTtcbiAgICBhd2FpdCB0aGlzLnB1c2goYXBrUGF0aCwgcmVtb3RlUGF0aCwge3RpbWVvdXQ6IG9wdGlvbnMudGltZW91dH0pO1xuICAgIGNvbnN0IHtzaXplfSA9IGF3YWl0IGZzLnN0YXQoYXBrUGF0aCk7XG4gICAgbG9nLmluZm8oYFRoZSB1cGxvYWQgb2YgJyR7cGF0aC5iYXNlbmFtZShhcGtQYXRoKX0nICgke3V0aWwudG9SZWFkYWJsZVNpemVTdHJpbmcoc2l6ZSl9KSBgICtcbiAgICAgIGB0b29rICR7dGltZXIuZ2V0RHVyYXRpb24oKS5hc01pbGxpU2Vjb25kcy50b0ZpeGVkKDApfW1zYCk7XG4gIH1cbiAgaWYgKCF0aGlzLnJlbW90ZUFwcHNDYWNoZSkge1xuICAgIHRoaXMucmVtb3RlQXBwc0NhY2hlID0gbmV3IExSVSh7XG4gICAgICBtYXg6IHRoaXMucmVtb3RlQXBwc0NhY2hlTGltaXQsXG4gICAgfSk7XG4gIH1cbiAgLy8gQ2xlYW51cCB0aGUgaW52YWxpZCBlbnRyaWVzIGZyb20gdGhlIGNhY2hlXG4gIF8uZGlmZmVyZW5jZShbLi4udGhpcy5yZW1vdGVBcHBzQ2FjaGUua2V5cygpXSwgcmVtb3RlQ2FjaGVkRmlsZXMubWFwKHRvSGFzaCkpXG4gICAgLmZvckVhY2goKGhhc2gpID0+IHRoaXMucmVtb3RlQXBwc0NhY2hlLmRlbChoYXNoKSk7XG4gIC8vIEJ1bXAgdGhlIGNhY2hlIHJlY29yZCBmb3IgdGhlIHJlY2VudGx5IGNhY2hlZCBpdGVtXG4gIHRoaXMucmVtb3RlQXBwc0NhY2hlLnNldChhcHBIYXNoLCByZW1vdGVQYXRoKTtcbiAgLy8gSWYgdGhlIHJlbW90ZSBjYWNoZSBleGNlZWRzIHRoaXMucmVtb3RlQXBwc0NhY2hlTGltaXQsIHJlbW92ZSB0aGUgbGVhc3QgcmVjZW50bHkgdXNlZCBlbnRyaWVzXG4gIGNvbnN0IGVudHJpZXNUb0NsZWFudXAgPSByZW1vdGVDYWNoZWRGaWxlc1xuICAgIC5tYXAoKHgpID0+IHBhdGgucG9zaXguam9pbihSRU1PVEVfQ0FDSEVfUk9PVCwgeCkpXG4gICAgLmZpbHRlcigoeCkgPT4gIXRoaXMucmVtb3RlQXBwc0NhY2hlLmhhcyh0b0hhc2goeCkpKVxuICAgIC5zbGljZSh0aGlzLnJlbW90ZUFwcHNDYWNoZUxpbWl0IC0gWy4uLnRoaXMucmVtb3RlQXBwc0NhY2hlLmtleXMoKV0ubGVuZ3RoKTtcbiAgaWYgKCFfLmlzRW1wdHkoZW50cmllc1RvQ2xlYW51cCkpIHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5zaGVsbChbJ3JtJywgJy1mJywgLi4uZW50cmllc1RvQ2xlYW51cF0pO1xuICAgICAgbG9nLmRlYnVnKGBEZWxldGVkICR7ZW50cmllc1RvQ2xlYW51cC5sZW5ndGh9IGV4cGlyZWQgYXBwbGljYXRpb24gY2FjaGUgZW50cmllc2ApO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGxvZy53YXJuKGBDYW5ub3QgZGVsZXRlICR7ZW50cmllc1RvQ2xlYW51cC5sZW5ndGh9IGV4cGlyZWQgYXBwbGljYXRpb24gY2FjaGUgZW50cmllcy4gYCArXG4gICAgICAgIGBPcmlnaW5hbCBlcnJvcjogJHtlLm1lc3NhZ2V9YCk7XG4gICAgfVxuICB9XG4gIHJldHVybiByZW1vdGVQYXRoO1xufTtcblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBJbnN0YWxsT3B0aW9uc1xuICogQHByb3BlcnR5IHtudW1iZXJ9IHRpbWVvdXQgWzYwMDAwXSAtIFRoZSBjb3VudCBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCB1bnRpbCB0aGVcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcHAgaXMgaW5zdGFsbGVkLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IHRpbWVvdXRDYXBOYW1lIFthbmRyb2lkSW5zdGFsbFRpbWVvdXRdIC0gVGhlIHRpbWVvdXQgb3B0aW9uIG5hbWVcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzZXJzIGNhbiBpbmNyZWFzZSB0aGUgdGltZW91dC5cbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gYWxsb3dUZXN0UGFja2FnZXMgW2ZhbHNlXSAtIFNldCB0byB0cnVlIGluIG9yZGVyIHRvIGFsbG93IHRlc3RcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhY2thZ2VzIGluc3RhbGxhdGlvbi5cbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gdXNlU2RjYXJkIFtmYWxzZV0gLSBTZXQgdG8gdHJ1ZSB0byBpbnN0YWxsIHRoZSBhcHAgb24gc2RjYXJkXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5zdGVhZCBvZiB0aGUgZGV2aWNlIG1lbW9yeS5cbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gZ3JhbnRQZXJtaXNzaW9ucyBbZmFsc2VdIC0gU2V0IHRvIHRydWUgaW4gb3JkZXIgdG8gZ3JhbnQgYWxsIHRoZVxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZXJtaXNzaW9ucyByZXF1ZXN0ZWQgaW4gdGhlIGFwcGxpY2F0aW9uJ3MgbWFuaWZlc3RcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXV0b21hdGljYWxseSBhZnRlciB0aGUgaW5zdGFsbGF0aW9uIGlzIGNvbXBsZXRlZFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmRlciBBbmRyb2lkIDYrLlxuICogQHByb3BlcnR5IHtib29sZWFufSByZXBsYWNlIFt0cnVlXSAtIFNldCBpdCB0byBmYWxzZSBpZiB5b3UgZG9uJ3Qgd2FudFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBhcHBsaWNhdGlvbiB0byBiZSB1cGdyYWRlZC9yZWluc3RhbGxlZFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIGl0IGlzIGFscmVhZHkgcHJlc2VudCBvbiB0aGUgZGV2aWNlLlxuICogQHByb3BlcnR5IHtib29sZWFufSBub0luY3JlbWVudGFsIFtmYWxzZV0gLSBGb3JjZWZ1bGx5IGRpc2FibGVzIGluY3JlbWVudGFsIGluc3RhbGxzIGlmIHNldCB0byBgdHJ1ZWAuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJlYWQgaHR0cHM6Ly9kZXZlbG9wZXIuYW5kcm9pZC5jb20vcHJldmlldy9mZWF0dXJlcyNpbmNyZW1lbnRhbFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgbW9yZSBkZXRhaWxzLlxuICovXG5cbi8qKlxuICogSW5zdGFsbCB0aGUgcGFja2FnZSBmcm9tIHRoZSBsb2NhbCBmaWxlIHN5c3RlbS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gYXBwUGF0aCAtIFRoZSBmdWxsIHBhdGggdG8gdGhlIGxvY2FsIHBhY2thZ2UuXG4gKiBAcGFyYW0gez9JbnN0YWxsT3B0aW9uc30gb3B0aW9ucyAtIFRoZSBzZXQgb2YgaW5zdGFsbGF0aW9uIG9wdGlvbnMuXG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgYW4gdW5leHBlY3RlZCBlcnJvciBoYXBwZW5zIGR1cmluZyBpbnN0YWxsLlxuICovXG5hcGtVdGlsc01ldGhvZHMuaW5zdGFsbCA9IGFzeW5jIGZ1bmN0aW9uIGluc3RhbGwgKGFwcFBhdGgsIG9wdGlvbnMgPSB7fSkge1xuICBpZiAoYXBwUGF0aC5lbmRzV2l0aChBUEtTX0VYVEVOU0lPTikpIHtcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5pbnN0YWxsQXBrcyhhcHBQYXRoLCBvcHRpb25zKTtcbiAgfVxuXG4gIG9wdGlvbnMgPSBfLmNsb25lRGVlcChvcHRpb25zKTtcbiAgXy5kZWZhdWx0cyhvcHRpb25zLCB7XG4gICAgcmVwbGFjZTogdHJ1ZSxcbiAgICB0aW1lb3V0OiB0aGlzLmFkYkV4ZWNUaW1lb3V0ID09PSBERUZBVUxUX0FEQl9FWEVDX1RJTUVPVVQgPyBBUEtfSU5TVEFMTF9USU1FT1VUIDogdGhpcy5hZGJFeGVjVGltZW91dCxcbiAgICB0aW1lb3V0Q2FwTmFtZTogJ2FuZHJvaWRJbnN0YWxsVGltZW91dCcsXG4gIH0pO1xuXG4gIGNvbnN0IGluc3RhbGxBcmdzID0gYnVpbGRJbnN0YWxsQXJncyhhd2FpdCB0aGlzLmdldEFwaUxldmVsKCksIG9wdGlvbnMpO1xuICBpZiAob3B0aW9ucy5ub0luY3JlbWVudGFsICYmIGF3YWl0IHRoaXMuaXNJbmNyZW1lbnRhbEluc3RhbGxTdXBwb3J0ZWQoKSkge1xuICAgIC8vIEFkYiB0aHJvd3MgYW4gZXJyb3IgaWYgaXQgZG9lcyBub3Qga25vdyBhYm91dCBhbiBhcmcsXG4gICAgLy8gd2hpY2ggaXMgdGhlIGNhc2UgaGVyZSBmb3Igb2xkZXIgYWRiIHZlcnNpb25zLlxuICAgIGluc3RhbGxBcmdzLnB1c2goJy0tbm8taW5jcmVtZW50YWwnKTtcbiAgfVxuICBjb25zdCBpbnN0YWxsT3B0cyA9IHtcbiAgICB0aW1lb3V0OiBvcHRpb25zLnRpbWVvdXQsXG4gICAgdGltZW91dENhcE5hbWU6IG9wdGlvbnMudGltZW91dENhcE5hbWUsXG4gIH07XG4gIGNvbnN0IGluc3RhbGxDbWQgPSBbXG4gICAgJ2luc3RhbGwnLFxuICAgIC4uLmluc3RhbGxBcmdzLFxuICAgIGFwcFBhdGgsXG4gIF07XG4gIGxldCBwZXJmb3JtQXBwSW5zdGFsbCA9IGFzeW5jICgpID0+IGF3YWl0IHRoaXMuYWRiRXhlYyhpbnN0YWxsQ21kLCBpbnN0YWxsT3B0cyk7XG4gIC8vIHRoaXMucmVtb3RlQXBwc0NhY2hlTGltaXQgPD0gMCBtZWFucyBubyBjYWNoaW5nIHNob3VsZCBiZSBhcHBsaWVkXG4gIGxldCBzaG91bGRDYWNoZUFwcCA9IHRoaXMucmVtb3RlQXBwc0NhY2hlTGltaXQgPiAwO1xuICBpZiAoc2hvdWxkQ2FjaGVBcHApIHtcbiAgICBzaG91bGRDYWNoZUFwcCA9ICEoYXdhaXQgdGhpcy5pc1N0cmVhbWVkSW5zdGFsbFN1cHBvcnRlZCgpKTtcbiAgICBpZiAoIXNob3VsZENhY2hlQXBwKSB7XG4gICAgICBsb2cuaW5mbyhgVGhlIGFwcGxpY2F0aW9uIGF0ICcke2FwcFBhdGh9JyB3aWxsIG5vdCBiZSBjYWNoZWQsIGJlY2F1c2UgdGhlIGRldmljZSB1bmRlciB0ZXN0IGhhcyBgICtcbiAgICAgICAgYGNvbmZpcm1lZCB0aGUgc3VwcG9ydCBvZiBzdHJlYW1lZCBpbnN0YWxsc2ApO1xuICAgIH1cbiAgfVxuICBpZiAoc2hvdWxkQ2FjaGVBcHApIHtcbiAgICBjb25zdCBjbGVhckNhY2hlID0gYXN5bmMgKCkgPT4ge1xuICAgICAgbG9nLmluZm8oYENsZWFyaW5nIHRoZSBjYWNoZSBhdCAnJHtSRU1PVEVfQ0FDSEVfUk9PVH0nYCk7XG4gICAgICBhd2FpdCB0aGlzLnNoZWxsKFsncm0nLCAnLXJmJywgYCR7UkVNT1RFX0NBQ0hFX1JPT1R9LypgXSk7XG4gICAgfTtcbiAgICBjb25zdCBjYWNoZUFwcCA9IGFzeW5jICgpID0+IGF3YWl0IHRoaXMuY2FjaGVBcGsoYXBwUGF0aCwge1xuICAgICAgdGltZW91dDogb3B0aW9ucy50aW1lb3V0LFxuICAgIH0pO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjYWNoZWRBcHBQYXRoID0gYXdhaXQgY2FjaGVBcHAoKTtcbiAgICAgIHBlcmZvcm1BcHBJbnN0YWxsID0gYXN5bmMgKCkgPT4ge1xuICAgICAgICBjb25zdCBwbUluc3RhbGxDbWRCeVJlbW90ZVBhdGggPSAocmVtb3RlUGF0aCkgPT4gW1xuICAgICAgICAgICdwbScsICdpbnN0YWxsJyxcbiAgICAgICAgICAuLi5pbnN0YWxsQXJncyxcbiAgICAgICAgICByZW1vdGVQYXRoLFxuICAgICAgICBdO1xuICAgICAgICBjb25zdCBvdXRwdXQgPSBhd2FpdCB0aGlzLnNoZWxsKHBtSW5zdGFsbENtZEJ5UmVtb3RlUGF0aChjYWNoZWRBcHBQYXRoKSwgaW5zdGFsbE9wdHMpO1xuICAgICAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vYXBwaXVtL2FwcGl1bS9pc3N1ZXMvMTM5NzBcbiAgICAgICAgaWYgKC9cXGJJTlNUQUxMX0ZBSUxFRF9JTlNVRkZJQ0lFTlRfU1RPUkFHRVxcYi8udGVzdChvdXRwdXQpKSB7XG4gICAgICAgICAgbG9nLndhcm4oYFRoZXJlIHdhcyBhIGZhaWx1cmUgd2hpbGUgaW5zdGFsbGluZyAnJHthcHBQYXRofScgYCArXG4gICAgICAgICAgICBgYmVjYXVzZSBvZiB0aGUgaW5zdWZmaWNpZW50IGRldmljZSBzdG9yYWdlIHNwYWNlYCk7XG4gICAgICAgICAgYXdhaXQgY2xlYXJDYWNoZSgpO1xuICAgICAgICAgIGxvZy5pbmZvKGBDb25zaWRlciBkZWNyZWFzaW5nIHRoZSBtYXhpbXVtIGFtb3VudCBvZiBjYWNoZWQgYXBwcyBgICtcbiAgICAgICAgICAgIGAoY3VycmVudGx5ICR7dGhpcy5yZW1vdGVBcHBzQ2FjaGVMaW1pdH0pIHRvIGF2b2lkIHN1Y2ggaXNzdWVzIGluIHRoZSBmdXR1cmVgKTtcbiAgICAgICAgICBjb25zdCBuZXdDYWNoZWRBcHBQYXRoID0gYXdhaXQgY2FjaGVBcHAoKTtcbiAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5zaGVsbChwbUluc3RhbGxDbWRCeVJlbW90ZVBhdGgobmV3Q2FjaGVkQXBwUGF0aCksIGluc3RhbGxPcHRzKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gb3V0cHV0O1xuICAgICAgfTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBsb2cuZGVidWcoZSk7XG4gICAgICBsb2cud2FybihgVGhlcmUgd2FzIGEgZmFpbHVyZSB3aGlsZSBjYWNoaW5nICcke2FwcFBhdGh9JzogJHtlLm1lc3NhZ2V9YCk7XG4gICAgICBsb2cud2FybignRmFsbGluZyBiYWNrIHRvIHRoZSBkZWZhdWx0IGluc3RhbGxhdGlvbiBwcm9jZWR1cmUnKTtcbiAgICAgIGF3YWl0IGNsZWFyQ2FjaGUoKTtcbiAgICB9XG4gIH1cbiAgdHJ5IHtcbiAgICBjb25zdCB0aW1lciA9IG5ldyB0aW1pbmcuVGltZXIoKS5zdGFydCgpO1xuICAgIGNvbnN0IG91dHB1dCA9IGF3YWl0IHBlcmZvcm1BcHBJbnN0YWxsKCk7XG4gICAgbG9nLmluZm8oYFRoZSBpbnN0YWxsYXRpb24gb2YgJyR7cGF0aC5iYXNlbmFtZShhcHBQYXRoKX0nIHRvb2sgJHt0aW1lci5nZXREdXJhdGlvbigpLmFzTWlsbGlTZWNvbmRzLnRvRml4ZWQoMCl9bXNgKTtcbiAgICBjb25zdCB0cnVuY2F0ZWRPdXRwdXQgPSAoIV8uaXNTdHJpbmcob3V0cHV0KSB8fCBvdXRwdXQubGVuZ3RoIDw9IDMwMCkgP1xuICAgICAgb3V0cHV0IDogYCR7b3V0cHV0LnN1YnN0cigwLCAxNTApfS4uLiR7b3V0cHV0LnN1YnN0cihvdXRwdXQubGVuZ3RoIC0gMTUwKX1gO1xuICAgIGxvZy5kZWJ1ZyhgSW5zdGFsbCBjb21tYW5kIHN0ZG91dDogJHt0cnVuY2F0ZWRPdXRwdXR9YCk7XG4gICAgaWYgKC9cXFtJTlNUQUxMW0EtWl9dK0ZBSUxFRFtBLVpfXStcXF0vLnRlc3Qob3V0cHV0KSkge1xuICAgICAgaWYgKHRoaXMuaXNUZXN0UGFja2FnZU9ubHlFcnJvcihvdXRwdXQpKSB7XG4gICAgICAgIGNvbnN0IG1zZyA9IGBTZXQgJ2FsbG93VGVzdFBhY2thZ2VzJyBjYXBhYmlsaXR5IHRvIHRydWUgaW4gb3JkZXIgdG8gYWxsb3cgdGVzdCBwYWNrYWdlcyBpbnN0YWxsYXRpb24uYDtcbiAgICAgICAgbG9nLndhcm4obXNnKTtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke291dHB1dH1cXG4ke21zZ31gKTtcbiAgICAgIH1cbiAgICAgIHRocm93IG5ldyBFcnJvcihvdXRwdXQpO1xuICAgIH1cbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgLy8gb24gc29tZSBzeXN0ZW1zIHRoaXMgd2lsbCB0aHJvdyBhbiBlcnJvciBpZiB0aGUgYXBwIGFscmVhZHlcbiAgICAvLyBleGlzdHNcbiAgICBpZiAoIWVyci5tZXNzYWdlLmluY2x1ZGVzKCdJTlNUQUxMX0ZBSUxFRF9BTFJFQURZX0VYSVNUUycpKSB7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuICAgIGxvZy5kZWJ1ZyhgQXBwbGljYXRpb24gJyR7YXBwUGF0aH0nIGFscmVhZHkgaW5zdGFsbGVkLiBDb250aW51aW5nLmApO1xuICB9XG59O1xuXG4vKipcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBpbnN0YWxsYXRpb24gc3RhdGUgb2YgdGhlIHBhcnRpY3VsYXIgYXBwbGljYXRpb25cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gYXBwUGF0aCAtIEZ1bGwgcGF0aCB0byB0aGUgYXBwbGljYXRpb25cbiAqIEBwYXJhbSB7P3N0cmluZ30gcGtnIC0gUGFja2FnZSBpZGVudGlmaWVyLiBJZiBvbWl0dGVkIHRoZW4gdGhlIHNjcmlwdCB3aWxsXG4gKiAgICAgICAgICAgICAgICAgICAgICAgIHRyeSB0byBleHRyYWN0IGl0IG9uIGl0cyBvd25cbiAqIEByZXR1cm5zIHtzdHJpbmd9XU9uZSBvZiBgQVBQX0lOU1RBTExfU1RBVEVgIGNvbnN0YW50c1xuICovXG5hcGtVdGlsc01ldGhvZHMuZ2V0QXBwbGljYXRpb25JbnN0YWxsU3RhdGUgPSBhc3luYyBmdW5jdGlvbiBnZXRBcHBsaWNhdGlvbkluc3RhbGxTdGF0ZSAoYXBwUGF0aCwgcGtnID0gbnVsbCkge1xuICBsZXQgYXBrSW5mbyA9IG51bGw7XG4gIGlmICghcGtnKSB7XG4gICAgYXBrSW5mbyA9IGF3YWl0IHRoaXMuZ2V0QXBrSW5mbyhhcHBQYXRoKTtcbiAgICBwa2cgPSBhcGtJbmZvLm5hbWU7XG4gIH1cbiAgaWYgKCFwa2cpIHtcbiAgICBsb2cud2FybihgQ2Fubm90IHJlYWQgdGhlIHBhY2thZ2UgbmFtZSBvZiAnJHthcHBQYXRofSdgKTtcbiAgICByZXR1cm4gdGhpcy5BUFBfSU5TVEFMTF9TVEFURS5VTktOT1dOO1xuICB9XG5cbiAgaWYgKCFhd2FpdCB0aGlzLmlzQXBwSW5zdGFsbGVkKHBrZykpIHtcbiAgICBsb2cuZGVidWcoYEFwcCAnJHthcHBQYXRofScgaXMgbm90IGluc3RhbGxlZGApO1xuICAgIHJldHVybiB0aGlzLkFQUF9JTlNUQUxMX1NUQVRFLk5PVF9JTlNUQUxMRUQ7XG4gIH1cblxuICBjb25zdCB7dmVyc2lvbkNvZGU6IHBrZ1ZlcnNpb25Db2RlLCB2ZXJzaW9uTmFtZTogcGtnVmVyc2lvbk5hbWVTdHJ9ID0gYXdhaXQgdGhpcy5nZXRQYWNrYWdlSW5mbyhwa2cpO1xuICBjb25zdCBwa2dWZXJzaW9uTmFtZSA9IHNlbXZlci52YWxpZChzZW12ZXIuY29lcmNlKHBrZ1ZlcnNpb25OYW1lU3RyKSk7XG4gIGlmICghYXBrSW5mbykge1xuICAgIGFwa0luZm8gPSBhd2FpdCB0aGlzLmdldEFwa0luZm8oYXBwUGF0aCk7XG4gIH1cbiAgY29uc3Qge3ZlcnNpb25Db2RlOiBhcGtWZXJzaW9uQ29kZSwgdmVyc2lvbk5hbWU6IGFwa1ZlcnNpb25OYW1lU3RyfSA9IGFwa0luZm87XG4gIGNvbnN0IGFwa1ZlcnNpb25OYW1lID0gc2VtdmVyLnZhbGlkKHNlbXZlci5jb2VyY2UoYXBrVmVyc2lvbk5hbWVTdHIpKTtcblxuICBpZiAoIV8uaXNJbnRlZ2VyKGFwa1ZlcnNpb25Db2RlKSB8fCAhXy5pc0ludGVnZXIocGtnVmVyc2lvbkNvZGUpKSB7XG4gICAgbG9nLndhcm4oYENhbm5vdCByZWFkIHZlcnNpb24gY29kZXMgb2YgJyR7YXBwUGF0aH0nIGFuZC9vciAnJHtwa2d9J2ApO1xuICAgIGlmICghXy5pc1N0cmluZyhhcGtWZXJzaW9uTmFtZSkgfHwgIV8uaXNTdHJpbmcocGtnVmVyc2lvbk5hbWUpKSB7XG4gICAgICBsb2cud2FybihgQ2Fubm90IHJlYWQgdmVyc2lvbiBuYW1lcyBvZiAnJHthcHBQYXRofScgYW5kL29yICcke3BrZ30nYCk7XG4gICAgICByZXR1cm4gdGhpcy5BUFBfSU5TVEFMTF9TVEFURS5VTktOT1dOO1xuICAgIH1cbiAgfVxuICBpZiAoXy5pc0ludGVnZXIoYXBrVmVyc2lvbkNvZGUpICYmIF8uaXNJbnRlZ2VyKHBrZ1ZlcnNpb25Db2RlKSkge1xuICAgIGlmIChwa2dWZXJzaW9uQ29kZSA+IGFwa1ZlcnNpb25Db2RlKSB7XG4gICAgICBsb2cuZGVidWcoYFRoZSB2ZXJzaW9uIGNvZGUgb2YgdGhlIGluc3RhbGxlZCAnJHtwa2d9JyBpcyBncmVhdGVyIHRoYW4gdGhlIGFwcGxpY2F0aW9uIHZlcnNpb24gY29kZSAoJHtwa2dWZXJzaW9uQ29kZX0gPiAke2Fwa1ZlcnNpb25Db2RlfSlgKTtcbiAgICAgIHJldHVybiB0aGlzLkFQUF9JTlNUQUxMX1NUQVRFLk5FV0VSX1ZFUlNJT05fSU5TVEFMTEVEO1xuICAgIH1cbiAgICAvLyBWZXJzaW9uIGNvZGVzIG1pZ2h0IG5vdCBiZSBtYWludGFpbmVkLiBDaGVjayB2ZXJzaW9uIG5hbWVzLlxuICAgIGlmIChwa2dWZXJzaW9uQ29kZSA9PT0gYXBrVmVyc2lvbkNvZGUpIHtcbiAgICAgIGlmIChfLmlzU3RyaW5nKGFwa1ZlcnNpb25OYW1lKSAmJiBfLmlzU3RyaW5nKHBrZ1ZlcnNpb25OYW1lKSAmJiBzZW12ZXIuc2F0aXNmaWVzKHBrZ1ZlcnNpb25OYW1lLCBgPj0ke2Fwa1ZlcnNpb25OYW1lfWApKSB7XG4gICAgICAgIGxvZy5kZWJ1ZyhgVGhlIHZlcnNpb24gbmFtZSBvZiB0aGUgaW5zdGFsbGVkICcke3BrZ30nIGlzIGdyZWF0ZXIgb3IgZXF1YWwgdG8gdGhlIGFwcGxpY2F0aW9uIHZlcnNpb24gbmFtZSAoJyR7cGtnVmVyc2lvbk5hbWV9JyA+PSAnJHthcGtWZXJzaW9uTmFtZX0nKWApO1xuICAgICAgICByZXR1cm4gc2VtdmVyLnNhdGlzZmllcyhwa2dWZXJzaW9uTmFtZSwgYD4ke2Fwa1ZlcnNpb25OYW1lfWApXG4gICAgICAgICAgPyB0aGlzLkFQUF9JTlNUQUxMX1NUQVRFLk5FV0VSX1ZFUlNJT05fSU5TVEFMTEVEXG4gICAgICAgICAgOiB0aGlzLkFQUF9JTlNUQUxMX1NUQVRFLlNBTUVfVkVSU0lPTl9JTlNUQUxMRUQ7XG4gICAgICB9XG4gICAgICBpZiAoIV8uaXNTdHJpbmcoYXBrVmVyc2lvbk5hbWUpIHx8ICFfLmlzU3RyaW5nKHBrZ1ZlcnNpb25OYW1lKSkge1xuICAgICAgICBsb2cuZGVidWcoYFRoZSB2ZXJzaW9uIG5hbWUgb2YgdGhlIGluc3RhbGxlZCAnJHtwa2d9JyBpcyBlcXVhbCB0byBhcHBsaWNhdGlvbiB2ZXJzaW9uIG5hbWUgKCR7cGtnVmVyc2lvbkNvZGV9ID09PSAke2Fwa1ZlcnNpb25Db2RlfSlgKTtcbiAgICAgICAgcmV0dXJuIHRoaXMuQVBQX0lOU1RBTExfU1RBVEUuU0FNRV9WRVJTSU9OX0lOU1RBTExFRDtcbiAgICAgIH1cbiAgICB9XG4gIH0gZWxzZSBpZiAoXy5pc1N0cmluZyhhcGtWZXJzaW9uTmFtZSkgJiYgXy5pc1N0cmluZyhwa2dWZXJzaW9uTmFtZSkgJiYgc2VtdmVyLnNhdGlzZmllcyhwa2dWZXJzaW9uTmFtZSwgYD49JHthcGtWZXJzaW9uTmFtZX1gKSkge1xuICAgIGxvZy5kZWJ1ZyhgVGhlIHZlcnNpb24gbmFtZSBvZiB0aGUgaW5zdGFsbGVkICcke3BrZ30nIGlzIGdyZWF0ZXIgb3IgZXF1YWwgdG8gdGhlIGFwcGxpY2F0aW9uIHZlcnNpb24gbmFtZSAoJyR7cGtnVmVyc2lvbk5hbWV9JyA+PSAnJHthcGtWZXJzaW9uTmFtZX0nKWApO1xuICAgIHJldHVybiBzZW12ZXIuc2F0aXNmaWVzKHBrZ1ZlcnNpb25OYW1lLCBgPiR7YXBrVmVyc2lvbk5hbWV9YClcbiAgICAgID8gdGhpcy5BUFBfSU5TVEFMTF9TVEFURS5ORVdFUl9WRVJTSU9OX0lOU1RBTExFRFxuICAgICAgOiB0aGlzLkFQUF9JTlNUQUxMX1NUQVRFLlNBTUVfVkVSU0lPTl9JTlNUQUxMRUQ7XG4gIH1cblxuICBsb2cuZGVidWcoYFRoZSBpbnN0YWxsZWQgJyR7cGtnfScgcGFja2FnZSBpcyBvbGRlciB0aGFuICcke2FwcFBhdGh9JyAoJHtwa2dWZXJzaW9uQ29kZX0gPCAke2Fwa1ZlcnNpb25Db2RlfSBvciAnJHtwa2dWZXJzaW9uTmFtZX0nIDwgJyR7YXBrVmVyc2lvbk5hbWV9JyknYCk7XG4gIHJldHVybiB0aGlzLkFQUF9JTlNUQUxMX1NUQVRFLk9MREVSX1ZFUlNJT05fSU5TVEFMTEVEO1xufTtcblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBJbnN0YWxsT3JVcGdyYWRlT3B0aW9uc1xuICogQHByb3BlcnR5IHtudW1iZXJ9IHRpbWVvdXQgWzYwMDAwXSAtIFRoZSBjb3VudCBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCB1bnRpbCB0aGVcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcHAgaXMgaW5zdGFsbGVkLlxuICogQHByb3BlcnR5IHtib29sZWFufSBhbGxvd1Rlc3RQYWNrYWdlcyBbZmFsc2VdIC0gU2V0IHRvIHRydWUgaW4gb3JkZXIgdG8gYWxsb3cgdGVzdFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFja2FnZXMgaW5zdGFsbGF0aW9uLlxuICogQHByb3BlcnR5IHtib29sZWFufSB1c2VTZGNhcmQgW2ZhbHNlXSAtIFNldCB0byB0cnVlIHRvIGluc3RhbGwgdGhlIGFwcCBvbiBTRENhcmRcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnN0ZWFkIG9mIHRoZSBkZXZpY2UgbWVtb3J5LlxuICogQHByb3BlcnR5IHtib29sZWFufSBncmFudFBlcm1pc3Npb25zIFtmYWxzZV0gLSBTZXQgdG8gdHJ1ZSBpbiBvcmRlciB0byBncmFudCBhbGwgdGhlXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlcm1pc3Npb25zIHJlcXVlc3RlZCBpbiB0aGUgYXBwbGljYXRpb24ncyBtYW5pZmVzdFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhdXRvbWF0aWNhbGx5IGFmdGVyIHRoZSBpbnN0YWxsYXRpb24gaXMgY29tcGxldGVkXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuZGVyIEFuZHJvaWQgNisuXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IGVuZm9yY2VDdXJyZW50QnVpbGQgW2ZhbHNlXSAtIFNldCB0byBgdHJ1ZWAgaW4gb3JkZXIgdG8gYWx3YXlzIHByZWZlclxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgY3VycmVudCBidWlsZCBvdmVyIGFueSBpbnN0YWxsZWQgcGFja2FnZXMgaGF2aW5nXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBzYW1lIGlkZW50aWZpZXJcbiAqL1xuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IEluc3RhbGxPclVwZ3JhZGVSZXN1bHRcbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gd2FzVW5pbnN0YWxsZWQgLSBFcXVhbHMgdG8gYHRydWVgIGlmIHRoZSB0YXJnZXQgYXBwIGhhcyBiZWVuIHVuaW5zdGFsbGVkXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmVmb3JlIGJlaW5nIGluc3RhbGxlZFxuICogQHByb3BlcnR5IHtBUFBfSU5TVEFMTF9TVEFURX0gYXBwU3RhdGUgLSBPbmUgb2YgYGFkYi5BUFBfSU5TVEFMTF9TVEFURWAgc3RhdGVzLCB3aGljaCByZWZsZWN0c1xuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgc3RhdGUgb2YgdGhlIGFwcGxpY2F0aW9uIGJlZm9yZSBiZWluZyBpbnN0YWxsZWQuXG4gKi9cblxuLyoqXG4gKiBJbnN0YWxsIHRoZSBwYWNrYWdlIGZyb20gdGhlIGxvY2FsIGZpbGUgc3lzdGVtIG9yIHVwZ3JhZGUgaXQgaWYgYW4gb2xkZXJcbiAqIHZlcnNpb24gb2YgdGhlIHNhbWUgcGFja2FnZSBpcyBhbHJlYWR5IGluc3RhbGxlZC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gYXBwUGF0aCAtIFRoZSBmdWxsIHBhdGggdG8gdGhlIGxvY2FsIHBhY2thZ2UuXG4gKiBAcGFyYW0gez9zdHJpbmd9IHBrZyAtIFRoZSBuYW1lIG9mIHRoZSBpbnN0YWxsZWQgcGFja2FnZS4gVGhlIG1ldGhvZCB3aWxsXG4gKiAgICAgICAgICAgICAgICAgICAgICAgIHBlcmZvcm0gZmFzdGVyIGlmIGl0IGlzIHNldC5cbiAqIEBwYXJhbSB7P0luc3RhbGxPclVwZ3JhZGVPcHRpb25zfSBvcHRpb25zIC0gU2V0IG9mIGluc3RhbGwgb3B0aW9ucy5cbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiBhbiB1bmV4cGVjdGVkIGVycm9yIGhhcHBlbnMgZHVyaW5nIGluc3RhbGwuXG4gKiBAcmV0dXJucyB7SW5zdGFsbE9yVXBncmFkZVJlc3VsdH1cbiAqL1xuYXBrVXRpbHNNZXRob2RzLmluc3RhbGxPclVwZ3JhZGUgPSBhc3luYyBmdW5jdGlvbiBpbnN0YWxsT3JVcGdyYWRlIChhcHBQYXRoLCBwa2cgPSBudWxsLCBvcHRpb25zID0ge30pIHtcbiAgaWYgKCFwa2cpIHtcbiAgICBjb25zdCBhcGtJbmZvID0gYXdhaXQgdGhpcy5nZXRBcGtJbmZvKGFwcFBhdGgpO1xuICAgIHBrZyA9IGFwa0luZm8ubmFtZTtcbiAgfVxuXG4gIGNvbnN0IHtcbiAgICBlbmZvcmNlQ3VycmVudEJ1aWxkLFxuICB9ID0gb3B0aW9ucztcbiAgY29uc3QgYXBwU3RhdGUgPSBhd2FpdCB0aGlzLmdldEFwcGxpY2F0aW9uSW5zdGFsbFN0YXRlKGFwcFBhdGgsIHBrZyk7XG4gIGxldCB3YXNVbmluc3RhbGxlZCA9IGZhbHNlO1xuICBjb25zdCB1bmluc3RhbGxQYWNrYWdlID0gYXN5bmMgKCkgPT4ge1xuICAgIGlmICghYXdhaXQgdGhpcy51bmluc3RhbGxBcGsocGtnKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGAnJHtwa2d9JyBwYWNrYWdlIGNhbm5vdCBiZSB1bmluc3RhbGxlZGApO1xuICAgIH1cbiAgICB3YXNVbmluc3RhbGxlZCA9IHRydWU7XG4gIH07XG4gIHN3aXRjaCAoYXBwU3RhdGUpIHtcbiAgICBjYXNlIHRoaXMuQVBQX0lOU1RBTExfU1RBVEUuTk9UX0lOU1RBTExFRDpcbiAgICAgIGxvZy5kZWJ1ZyhgSW5zdGFsbGluZyAnJHthcHBQYXRofSdgKTtcbiAgICAgIGF3YWl0IHRoaXMuaW5zdGFsbChhcHBQYXRoLCBPYmplY3QuYXNzaWduKHt9LCBvcHRpb25zLCB7cmVwbGFjZTogZmFsc2V9KSk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBhcHBTdGF0ZSxcbiAgICAgICAgd2FzVW5pbnN0YWxsZWQsXG4gICAgICB9O1xuICAgIGNhc2UgdGhpcy5BUFBfSU5TVEFMTF9TVEFURS5ORVdFUl9WRVJTSU9OX0lOU1RBTExFRDpcbiAgICAgIGlmIChlbmZvcmNlQ3VycmVudEJ1aWxkKSB7XG4gICAgICAgIGxvZy5pbmZvKGBEb3duZ3JhZGluZyAnJHtwa2d9JyBhcyByZXF1ZXN0ZWRgKTtcbiAgICAgICAgYXdhaXQgdW5pbnN0YWxsUGFja2FnZSgpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGxvZy5kZWJ1ZyhgVGhlcmUgaXMgbm8gbmVlZCB0byBkb3duZ3JhZGUgJyR7cGtnfSdgKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGFwcFN0YXRlLFxuICAgICAgICB3YXNVbmluc3RhbGxlZCxcbiAgICAgIH07XG4gICAgY2FzZSB0aGlzLkFQUF9JTlNUQUxMX1NUQVRFLlNBTUVfVkVSU0lPTl9JTlNUQUxMRUQ6XG4gICAgICBpZiAoZW5mb3JjZUN1cnJlbnRCdWlsZCkge1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGxvZy5kZWJ1ZyhgVGhlcmUgaXMgbm8gbmVlZCB0byBpbnN0YWxsL3VwZ3JhZGUgJyR7YXBwUGF0aH0nYCk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBhcHBTdGF0ZSxcbiAgICAgICAgd2FzVW5pbnN0YWxsZWQsXG4gICAgICB9O1xuICAgIGNhc2UgdGhpcy5BUFBfSU5TVEFMTF9TVEFURS5PTERFUl9WRVJTSU9OX0lOU1RBTExFRDpcbiAgICAgIGxvZy5kZWJ1ZyhgRXhlY3V0aW5nIHVwZ3JhZGUgb2YgJyR7YXBwUGF0aH0nYCk7XG4gICAgICBicmVhaztcbiAgICBkZWZhdWx0OlxuICAgICAgbG9nLmRlYnVnKGBUaGUgY3VycmVudCBpbnN0YWxsIHN0YXRlIG9mICcke2FwcFBhdGh9JyBpcyB1bmtub3duLiBJbnN0YWxsaW5nIGFueXdheWApO1xuICAgICAgYnJlYWs7XG4gIH1cblxuICB0cnkge1xuICAgIGF3YWl0IHRoaXMuaW5zdGFsbChhcHBQYXRoLCBPYmplY3QuYXNzaWduKHt9LCBvcHRpb25zLCB7cmVwbGFjZTogdHJ1ZX0pKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nLndhcm4oYENhbm5vdCBpbnN0YWxsL3VwZ3JhZGUgJyR7cGtnfScgYmVjYXVzZSBvZiAnJHtlcnIubWVzc2FnZX0nLiBUcnlpbmcgZnVsbCByZWluc3RhbGxgKTtcbiAgICBhd2FpdCB1bmluc3RhbGxQYWNrYWdlKCk7XG4gICAgYXdhaXQgdGhpcy5pbnN0YWxsKGFwcFBhdGgsIE9iamVjdC5hc3NpZ24oe30sIG9wdGlvbnMsIHtyZXBsYWNlOiBmYWxzZX0pKTtcbiAgfVxuICByZXR1cm4ge1xuICAgIGFwcFN0YXRlLFxuICAgIHdhc1VuaW5zdGFsbGVkLFxuICB9O1xufTtcblxuLyoqXG4gKiBFeHRyYWN0IHN0cmluZyByZXNvdXJjZXMgZnJvbSB0aGUgZ2l2ZW4gcGFja2FnZSBvbiBsb2NhbCBmaWxlIHN5c3RlbS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gYXBwUGF0aCAtIFRoZSBmdWxsIHBhdGggdG8gdGhlIC5hcGsocykgcGFja2FnZS5cbiAqIEBwYXJhbSB7P3N0cmluZ30gbGFuZ3VhZ2UgLSBUaGUgbmFtZSBvZiB0aGUgbGFuZ3VhZ2UgdG8gZXh0cmFjdCB0aGUgcmVzb3VyY2VzIGZvci5cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaGUgZGVmYXVsdCBsYW5ndWFnZSBpcyB1c2VkIGlmIHRoaXMgZXF1YWxzIHRvIGBudWxsYC9gdW5kZWZpbmVkYFxuICogQHBhcmFtIHtzdHJpbmd9IG91dCAtIFRoZSBuYW1lIG9mIHRoZSBkZXN0aW5hdGlvbiBmb2xkZXIgb24gdGhlIGxvY2FsIGZpbGUgc3lzdGVtIHRvXG4gKiAgICAgICAgICAgICAgICAgICAgICAgc3RvcmUgdGhlIGV4dHJhY3RlZCBmaWxlIHRvLlxuICogQHJldHVybiB7T2JqZWN0fSBBIG1hcHBpbmcgb2JqZWN0LCB3aGVyZSBwcm9wZXJ0aWVzIGFyZTogJ2Fwa1N0cmluZ3MnLCBjb250YWluaW5nXG4gKiAgICAgICAgICAgICAgICAgIHBhcnNlZCByZXNvdXJjZSBmaWxlIHJlcHJlc2VudGVkIGFzIEpTT04gb2JqZWN0LCBhbmQgJ2xvY2FsUGF0aCcsXG4gKiAgICAgICAgICAgICAgICAgIGNvbnRhaW5pbmcgdGhlIHBhdGggdG8gdGhlIGV4dHJhY3RlZCBmaWxlIG9uIHRoZSBsb2NhbCBmaWxlIHN5c3RlbS5cbiAqL1xuYXBrVXRpbHNNZXRob2RzLmV4dHJhY3RTdHJpbmdzRnJvbUFwayA9IGFzeW5jIGZ1bmN0aW9uIGV4dHJhY3RTdHJpbmdzRnJvbUFwayAoYXBwUGF0aCwgbGFuZ3VhZ2UsIG91dCkge1xuICBsb2cuZGVidWcoYEV4dHJhY3Rpbmcgc3RyaW5ncyBmcm9tIGZvciBsYW5ndWFnZTogJHtsYW5ndWFnZSB8fCAnZGVmYXVsdCd9YCk7XG4gIGNvbnN0IG9yaWdpbmFsQXBwUGF0aCA9IGFwcFBhdGg7XG4gIGlmIChhcHBQYXRoLmVuZHNXaXRoKEFQS1NfRVhURU5TSU9OKSkge1xuICAgIGFwcFBhdGggPSBhd2FpdCB0aGlzLmV4dHJhY3RMYW5ndWFnZUFwayhhcHBQYXRoLCBsYW5ndWFnZSk7XG4gIH1cblxuICBsZXQgYXBrU3RyaW5ncyA9IHt9O1xuICBsZXQgY29uZmlnTWFya2VyO1xuICB0cnkge1xuICAgIGF3YWl0IHRoaXMuaW5pdEFhcHQoKTtcblxuICAgIGNvbmZpZ01hcmtlciA9IGF3YWl0IGZvcm1hdENvbmZpZ01hcmtlcihhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCB7c3Rkb3V0fSA9IGF3YWl0IGV4ZWModGhpcy5iaW5hcmllcy5hYXB0LCBbXG4gICAgICAgICdkJywgJ2NvbmZpZ3VyYXRpb25zJywgYXBwUGF0aCxcbiAgICAgIF0pO1xuICAgICAgcmV0dXJuIF8udW5pcShzdGRvdXQuc3BsaXQob3MuRU9MKSk7XG4gICAgfSwgbGFuZ3VhZ2UsICcoZGVmYXVsdCknKTtcblxuICAgIGNvbnN0IHtzdGRvdXR9ID0gYXdhaXQgZXhlYyh0aGlzLmJpbmFyaWVzLmFhcHQsIFtcbiAgICAgICdkJywgJy0tdmFsdWVzJywgJ3Jlc291cmNlcycsIGFwcFBhdGgsXG4gICAgXSk7XG4gICAgYXBrU3RyaW5ncyA9IHBhcnNlQWFwdFN0cmluZ3Moc3Rkb3V0LCBjb25maWdNYXJrZXIpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgbG9nLmRlYnVnKCdDYW5ub3QgZXh0cmFjdCByZXNvdXJjZXMgdXNpbmcgYWFwdC4gVHJ5aW5nIGFhcHQyLiAnICtcbiAgICAgIGBPcmlnaW5hbCBlcnJvcjogJHtlLnN0ZGVyciB8fCBlLm1lc3NhZ2V9YCk7XG5cbiAgICBhd2FpdCB0aGlzLmluaXRBYXB0MigpO1xuXG4gICAgY29uZmlnTWFya2VyID0gYXdhaXQgZm9ybWF0Q29uZmlnTWFya2VyKGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHtzdGRvdXR9ID0gYXdhaXQgZXhlYyh0aGlzLmJpbmFyaWVzLmFhcHQyLCBbXG4gICAgICAgICdkJywgJ2NvbmZpZ3VyYXRpb25zJywgYXBwUGF0aCxcbiAgICAgIF0pO1xuICAgICAgcmV0dXJuIF8udW5pcShzdGRvdXQuc3BsaXQob3MuRU9MKSk7XG4gICAgfSwgbGFuZ3VhZ2UsICcnKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCB7c3Rkb3V0fSA9IGF3YWl0IGV4ZWModGhpcy5iaW5hcmllcy5hYXB0MiwgW1xuICAgICAgICAnZCcsICdyZXNvdXJjZXMnLCBhcHBQYXRoLFxuICAgICAgXSk7XG4gICAgICBhcGtTdHJpbmdzID0gcGFyc2VBYXB0MlN0cmluZ3Moc3Rkb3V0LCBjb25maWdNYXJrZXIpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IGV4dHJhY3QgcmVzb3VyY2VzIGZyb20gJyR7b3JpZ2luYWxBcHBQYXRofScuIGAgK1xuICAgICAgICBgT3JpZ2luYWwgZXJyb3I6ICR7ZS5tZXNzYWdlfWApO1xuICAgIH1cbiAgfVxuXG4gIGlmIChfLmlzRW1wdHkoYXBrU3RyaW5ncykpIHtcbiAgICBsb2cud2FybihgTm8gc3RyaW5ncyBoYXZlIGJlZW4gZm91bmQgaW4gJyR7b3JpZ2luYWxBcHBQYXRofScgcmVzb3VyY2VzIGAgK1xuICAgICAgYGZvciAnJHtjb25maWdNYXJrZXIgfHwgJ2RlZmF1bHQnfScgY29uZmlndXJhdGlvbmApO1xuICB9IGVsc2Uge1xuICAgIGxvZy5pbmZvKGBTdWNjZXNzZnVsbHkgZXh0cmFjdGVkICR7Xy5rZXlzKGFwa1N0cmluZ3MpLmxlbmd0aH0gc3RyaW5ncyBmcm9tIGAgK1xuICAgICAgYCcke29yaWdpbmFsQXBwUGF0aH0nIHJlc291cmNlcyBmb3IgJyR7Y29uZmlnTWFya2VyIHx8ICdkZWZhdWx0J30nIGNvbmZpZ3VyYXRpb25gKTtcbiAgfVxuXG4gIGNvbnN0IGxvY2FsUGF0aCA9IHBhdGgucmVzb2x2ZShvdXQsICdzdHJpbmdzLmpzb24nKTtcbiAgYXdhaXQgbWtkaXJwKG91dCk7XG4gIGF3YWl0IGZzLndyaXRlRmlsZShsb2NhbFBhdGgsIEpTT04uc3RyaW5naWZ5KGFwa1N0cmluZ3MsIG51bGwsIDIpLCAndXRmLTgnKTtcbiAgcmV0dXJuIHthcGtTdHJpbmdzLCBsb2NhbFBhdGh9O1xufTtcblxuLyoqXG4gKiBHZXQgdGhlIGxhbmd1YWdlIG5hbWUgb2YgdGhlIGRldmljZSB1bmRlciB0ZXN0LlxuICpcbiAqIEByZXR1cm4ge3N0cmluZ30gVGhlIG5hbWUgb2YgZGV2aWNlIGxhbmd1YWdlLlxuICovXG5hcGtVdGlsc01ldGhvZHMuZ2V0RGV2aWNlTGFuZ3VhZ2UgPSBhc3luYyBmdW5jdGlvbiBnZXREZXZpY2VMYW5ndWFnZSAoKSB7XG4gIGxldCBsYW5ndWFnZTtcbiAgaWYgKGF3YWl0IHRoaXMuZ2V0QXBpTGV2ZWwoKSA8IDIzKSB7XG4gICAgbGFuZ3VhZ2UgPSBhd2FpdCB0aGlzLmdldERldmljZVN5c0xhbmd1YWdlKCk7XG4gICAgaWYgKCFsYW5ndWFnZSkge1xuICAgICAgbGFuZ3VhZ2UgPSBhd2FpdCB0aGlzLmdldERldmljZVByb2R1Y3RMYW5ndWFnZSgpO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBsYW5ndWFnZSA9IChhd2FpdCB0aGlzLmdldERldmljZUxvY2FsZSgpKS5zcGxpdCgnLScpWzBdO1xuICB9XG4gIHJldHVybiBsYW5ndWFnZTtcbn07XG5cbi8qKlxuICogR2V0IHRoZSBjb3VudHJ5IG5hbWUgb2YgdGhlIGRldmljZSB1bmRlciB0ZXN0LlxuICpcbiAqIEByZXR1cm4ge3N0cmluZ30gVGhlIG5hbWUgb2YgZGV2aWNlIGNvdW50cnkuXG4gKi9cbmFwa1V0aWxzTWV0aG9kcy5nZXREZXZpY2VDb3VudHJ5ID0gYXN5bmMgZnVuY3Rpb24gZ2V0RGV2aWNlQ291bnRyeSAoKSB7XG4gIC8vIHRoaXMgbWV0aG9kIGlzIG9ubHkgdXNlZCBpbiBBUEkgPCAyM1xuICBsZXQgY291bnRyeSA9IGF3YWl0IHRoaXMuZ2V0RGV2aWNlU3lzQ291bnRyeSgpO1xuICBpZiAoIWNvdW50cnkpIHtcbiAgICBjb3VudHJ5ID0gYXdhaXQgdGhpcy5nZXREZXZpY2VQcm9kdWN0Q291bnRyeSgpO1xuICB9XG4gIHJldHVybiBjb3VudHJ5O1xufTtcblxuLyoqXG4gKiBHZXQgdGhlIGxvY2FsZSBuYW1lIG9mIHRoZSBkZXZpY2UgdW5kZXIgdGVzdC5cbiAqXG4gKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBuYW1lIG9mIGRldmljZSBsb2NhbGUuXG4gKi9cbmFwa1V0aWxzTWV0aG9kcy5nZXREZXZpY2VMb2NhbGUgPSBhc3luYyBmdW5jdGlvbiBnZXREZXZpY2VMb2NhbGUgKCkge1xuICAvLyB0aGlzIG1ldGhvZCBpcyBvbmx5IHVzZWQgaW4gQVBJID49IDIzXG4gIGxldCBsb2NhbGUgPSBhd2FpdCB0aGlzLmdldERldmljZVN5c0xvY2FsZSgpO1xuICBpZiAoIWxvY2FsZSkge1xuICAgIGxvY2FsZSA9IGF3YWl0IHRoaXMuZ2V0RGV2aWNlUHJvZHVjdExvY2FsZSgpO1xuICB9XG4gIHJldHVybiBsb2NhbGU7XG59O1xuXG4vKipcbiAqIFNldCB0aGUgbG9jYWxlIG5hbWUgb2YgdGhlIGRldmljZSB1bmRlciB0ZXN0IGFuZCB0aGUgZm9ybWF0IG9mIHRoZSBsb2NhbGUgaXMgZW4tVVMsIGZvciBleGFtcGxlLlxuICogVGhpcyBtZXRob2QgY2FsbCBzZXREZXZpY2VMYW5ndWFnZUNvdW50cnksIHNvLCBwbGVhc2UgdXNlIHNldERldmljZUxhbmd1YWdlQ291bnRyeSBhcyBwb3NzaWJsZS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9jYWxlIC0gTmFtZXMgb2YgdGhlIGRldmljZSBsYW5ndWFnZSBhbmQgdGhlIGNvdW50cnkgY29ubmVjdGVkIHdpdGggYC1gLiBlLmcuIGVuLVVTLlxuICovXG5hcGtVdGlsc01ldGhvZHMuc2V0RGV2aWNlTG9jYWxlID0gYXN5bmMgZnVuY3Rpb24gc2V0RGV2aWNlTG9jYWxlIChsb2NhbGUpIHtcbiAgY29uc3QgdmFsaWRhdGVMb2NhbGUgPSBuZXcgUmVnRXhwKC9bYS16QS1aXSstW2EtekEtWjAtOV0rLyk7XG4gIGlmICghdmFsaWRhdGVMb2NhbGUudGVzdChsb2NhbGUpKSB7XG4gICAgbG9nLndhcm4oYHNldERldmljZUxvY2FsZSByZXF1aXJlcyB0aGUgZm9sbG93aW5nIGZvcm1hdDogZW4tVVMgb3IgamEtSlBgKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBsZXQgc3BsaXRfbG9jYWxlID0gbG9jYWxlLnNwbGl0KCctJyk7XG4gIGF3YWl0IHRoaXMuc2V0RGV2aWNlTGFuZ3VhZ2VDb3VudHJ5KHNwbGl0X2xvY2FsZVswXSwgc3BsaXRfbG9jYWxlWzFdKTtcbn07XG5cbi8qKlxuICogTWFrZSBzdXJlIGN1cnJlbnQgZGV2aWNlIGxvY2FsZSBpcyBleHBlY3RlZCBvciBub3QuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGxhbmd1YWdlIC0gTGFuZ3VhZ2UuIFRoZSBsYW5ndWFnZSBmaWVsZCBpcyBjYXNlIGluc2Vuc2l0aXZlLCBidXQgTG9jYWxlIGFsd2F5cyBjYW5vbmljYWxpemVzIHRvIGxvd2VyIGNhc2UuXG4gKiBAcGFyYW0ge3N0cmluZ30gY291bnRyeSAtIENvdW50cnkuIFRoZSBsYW5ndWFnZSBmaWVsZCBpcyBjYXNlIGluc2Vuc2l0aXZlLCBidXQgTG9jYWxlIGFsd2F5cyBjYW5vbmljYWxpemVzIHRvIGxvd2VyIGNhc2UuXG4gKiBAcGFyYW0gez9zdHJpbmd9IHNjcmlwdCAtIFNjcmlwdC4gVGhlIHNjcmlwdCBmaWVsZCBpcyBjYXNlIGluc2Vuc2l0aXZlIGJ1dCBMb2NhbGUgYWx3YXlzIGNhbm9uaWNhbGl6ZXMgdG8gdGl0bGUgY2FzZS5cbiAqXG4gKiBAcmV0dXJuIHtib29sZWFufSBJZiBjdXJyZW50IGxvY2FsZSBpcyBsYW5ndWFnZSBhbmQgY291bnRyeSBhcyBhcmd1bWVudHMsIHJldHVybiB0cnVlLlxuICovXG5hcGtVdGlsc01ldGhvZHMuZW5zdXJlQ3VycmVudExvY2FsZSA9IGFzeW5jIGZ1bmN0aW9uIGVuc3VyZUN1cnJlbnRMb2NhbGUgKGxhbmd1YWdlLCBjb3VudHJ5LCBzY3JpcHQgPSBudWxsKSB7XG4gIGNvbnN0IGhhc0xhbmd1YWdlID0gXy5pc1N0cmluZyhsYW5ndWFnZSk7XG4gIGNvbnN0IGhhc0NvdW50cnkgPSBfLmlzU3RyaW5nKGNvdW50cnkpO1xuXG4gIGlmICghaGFzTGFuZ3VhZ2UgJiYgIWhhc0NvdW50cnkpIHtcbiAgICBsb2cud2FybignZW5zdXJlQ3VycmVudExvY2FsZSByZXF1aXJlcyBsYW5ndWFnZSBvciBjb3VudHJ5Jyk7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gZ2V0IGxvd2VyIGNhc2UgdmVyc2lvbnMgb2YgdGhlIHN0cmluZ3NcbiAgbGFuZ3VhZ2UgPSAobGFuZ3VhZ2UgfHwgJycpLnRvTG93ZXJDYXNlKCk7XG4gIGNvdW50cnkgPSAoY291bnRyeSB8fCAnJykudG9Mb3dlckNhc2UoKTtcblxuICBjb25zdCBhcGlMZXZlbCA9IGF3YWl0IHRoaXMuZ2V0QXBpTGV2ZWwoKTtcblxuICByZXR1cm4gYXdhaXQgcmV0cnlJbnRlcnZhbCg1LCAxMDAwLCBhc3luYyAoKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGlmIChhcGlMZXZlbCA8IDIzKSB7XG4gICAgICAgIGxldCBjdXJMYW5ndWFnZSwgY3VyQ291bnRyeTtcbiAgICAgICAgaWYgKGhhc0xhbmd1YWdlKSB7XG4gICAgICAgICAgY3VyTGFuZ3VhZ2UgPSAoYXdhaXQgdGhpcy5nZXREZXZpY2VMYW5ndWFnZSgpKS50b0xvd2VyQ2FzZSgpO1xuICAgICAgICAgIGlmICghaGFzQ291bnRyeSAmJiBsYW5ndWFnZSA9PT0gY3VyTGFuZ3VhZ2UpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoaGFzQ291bnRyeSkge1xuICAgICAgICAgIGN1ckNvdW50cnkgPSAoYXdhaXQgdGhpcy5nZXREZXZpY2VDb3VudHJ5KCkpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgICAgaWYgKCFoYXNMYW5ndWFnZSAmJiBjb3VudHJ5ID09PSBjdXJDb3VudHJ5KSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGxhbmd1YWdlID09PSBjdXJMYW5ndWFnZSAmJiBjb3VudHJ5ID09PSBjdXJDb3VudHJ5KSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGN1ckxvY2FsZSA9IChhd2FpdCB0aGlzLmdldERldmljZUxvY2FsZSgpKS50b0xvd2VyQ2FzZSgpO1xuICAgICAgICAvLyB6aC1oYW5zLWNuIDogemgtY25cbiAgICAgICAgY29uc3QgbG9jYWxlQ29kZSA9IHNjcmlwdCA/IGAke2xhbmd1YWdlfS0ke3NjcmlwdC50b0xvd2VyQ2FzZSgpfS0ke2NvdW50cnl9YCA6IGAke2xhbmd1YWdlfS0ke2NvdW50cnl9YDtcblxuICAgICAgICBpZiAobG9jYWxlQ29kZSA9PT0gY3VyTG9jYWxlKSB7XG4gICAgICAgICAgbG9nLmRlYnVnKGBSZXF1ZXN0ZWQgbG9jYWxlIGlzIGVxdWFsIHRvIGN1cnJlbnQgbG9jYWxlOiAnJHtjdXJMb2NhbGV9J2ApO1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAvLyBpZiB0aGVyZSBoYXMgYmVlbiBhbiBlcnJvciwgcmVzdGFydCBhZGIgYW5kIHJldHJ5XG4gICAgICBsb2cuZXJyb3IoYFVuYWJsZSB0byBjaGVjayBkZXZpY2UgbG9jYWxpemF0aW9uOiAke2Vyci5tZXNzYWdlfWApO1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgdGhpcy5yZWNvbm5lY3QoKTtcbiAgICAgIH0gY2F0Y2ggKGlnbikge1xuICAgICAgICBhd2FpdCB0aGlzLnJlc3RhcnRBZGIoKTtcbiAgICAgIH1cbiAgICAgIHRocm93IGVycjtcbiAgICB9XG4gIH0pO1xufTtcblxuLyoqXG4gKiBTZXQgdGhlIGxvY2FsZSBuYW1lIG9mIHRoZSBkZXZpY2UgdW5kZXIgdGVzdC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbGFuZ3VhZ2UgLSBMYW5ndWFnZS4gVGhlIGxhbmd1YWdlIGZpZWxkIGlzIGNhc2UgaW5zZW5zaXRpdmUsIGJ1dCBMb2NhbGUgYWx3YXlzIGNhbm9uaWNhbGl6ZXMgdG8gbG93ZXIgY2FzZS5cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdDogW2EtekEtWl17Miw4fS4gZS5nLiBlbiwgamEgOiBodHRwczovL2RldmVsb3Blci5hbmRyb2lkLmNvbS9yZWZlcmVuY2UvamF2YS91dGlsL0xvY2FsZS5odG1sXG4gKiBAcGFyYW0ge3N0cmluZ30gY291bnRyeSAtIENvdW50cnkuIFRoZSBjb3VudHJ5IChyZWdpb24pIGZpZWxkIGlzIGNhc2UgaW5zZW5zaXRpdmUsIGJ1dCBMb2NhbGUgYWx3YXlzIGNhbm9uaWNhbGl6ZXMgdG8gdXBwZXIgY2FzZS5cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdDogW2EtekEtWl17Mn0gfCBbMC05XXszfS4gZS5nLiBVUywgSlAgOiBodHRwczovL2RldmVsb3Blci5hbmRyb2lkLmNvbS9yZWZlcmVuY2UvamF2YS91dGlsL0xvY2FsZS5odG1sXG4gKiBAcGFyYW0gez9zdHJpbmd9IHNjcmlwdCAtIFNjcmlwdC4gVGhlIHNjcmlwdCBmaWVsZCBpcyBjYXNlIGluc2Vuc2l0aXZlIGJ1dCBMb2NhbGUgYWx3YXlzIGNhbm9uaWNhbGl6ZXMgdG8gdGl0bGUgY2FzZS5cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdDogW2EtekEtWl17NH0uIGUuZy4gSGFucyBpbiB6aC1IYW5zLUNOIDogaHR0cHM6Ly9kZXZlbG9wZXIuYW5kcm9pZC5jb20vcmVmZXJlbmNlL2phdmEvdXRpbC9Mb2NhbGUuaHRtbFxuICovXG5hcGtVdGlsc01ldGhvZHMuc2V0RGV2aWNlTGFuZ3VhZ2VDb3VudHJ5ID0gYXN5bmMgZnVuY3Rpb24gc2V0RGV2aWNlTGFuZ3VhZ2VDb3VudHJ5IChsYW5ndWFnZSwgY291bnRyeSwgc2NyaXB0ID0gbnVsbCkge1xuICBsZXQgaGFzTGFuZ3VhZ2UgPSBsYW5ndWFnZSAmJiBfLmlzU3RyaW5nKGxhbmd1YWdlKTtcbiAgbGV0IGhhc0NvdW50cnkgPSBjb3VudHJ5ICYmIF8uaXNTdHJpbmcoY291bnRyeSk7XG4gIGlmICghaGFzTGFuZ3VhZ2UgfHwgIWhhc0NvdW50cnkpIHtcbiAgICBsb2cud2Fybihgc2V0RGV2aWNlTGFuZ3VhZ2VDb3VudHJ5IHJlcXVpcmVzIGxhbmd1YWdlIGFuZCBjb3VudHJ5IGF0IGxlYXN0YCk7XG4gICAgbG9nLndhcm4oYEdvdCBsYW5ndWFnZTogJyR7bGFuZ3VhZ2V9JyBhbmQgY291bnRyeTogJyR7Y291bnRyeX0nYCk7XG4gICAgcmV0dXJuO1xuICB9XG4gIGxldCBhcGlMZXZlbCA9IGF3YWl0IHRoaXMuZ2V0QXBpTGV2ZWwoKTtcblxuICBsYW5ndWFnZSA9IChsYW5ndWFnZSB8fCAnJykudG9Mb3dlckNhc2UoKTtcbiAgY291bnRyeSA9IChjb3VudHJ5IHx8ICcnKS50b1VwcGVyQ2FzZSgpO1xuXG4gIGlmIChhcGlMZXZlbCA8IDIzKSB7XG4gICAgbGV0IGN1ckxhbmd1YWdlID0gKGF3YWl0IHRoaXMuZ2V0RGV2aWNlTGFuZ3VhZ2UoKSkudG9Mb3dlckNhc2UoKTtcbiAgICBsZXQgY3VyQ291bnRyeSA9IChhd2FpdCB0aGlzLmdldERldmljZUNvdW50cnkoKSkudG9VcHBlckNhc2UoKTtcblxuICAgIGlmIChsYW5ndWFnZSAhPT0gY3VyTGFuZ3VhZ2UgfHwgY291bnRyeSAhPT0gY3VyQ291bnRyeSkge1xuICAgICAgYXdhaXQgdGhpcy5zZXREZXZpY2VTeXNMb2NhbGVWaWFTZXR0aW5nQXBwKGxhbmd1YWdlLCBjb3VudHJ5KTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgbGV0IGN1ckxvY2FsZSA9IGF3YWl0IHRoaXMuZ2V0RGV2aWNlTG9jYWxlKCk7XG5cbiAgICAvLyB6aC1IYW5zLUNOIDogemgtQ05cbiAgICBjb25zdCBsb2NhbGVDb2RlID0gc2NyaXB0ID8gYCR7bGFuZ3VhZ2V9LSR7c2NyaXB0fS0ke2NvdW50cnl9YCA6IGAke2xhbmd1YWdlfS0ke2NvdW50cnl9YDtcbiAgICBsb2cuZGVidWcoYEN1cnJlbnQgbG9jYWxlOiAnJHtjdXJMb2NhbGV9JzsgcmVxdWVzdGVkIGxvY2FsZTogJyR7bG9jYWxlQ29kZX0nYCk7XG4gICAgaWYgKGxvY2FsZUNvZGUudG9Mb3dlckNhc2UoKSAhPT0gY3VyTG9jYWxlLnRvTG93ZXJDYXNlKCkpIHtcbiAgICAgIGF3YWl0IHRoaXMuc2V0RGV2aWNlU3lzTG9jYWxlVmlhU2V0dGluZ0FwcChsYW5ndWFnZSwgY291bnRyeSwgc2NyaXB0KTtcbiAgICB9XG4gIH1cbn07XG5cbi8qKlxuICogQHR5cGVkZWYge09iamVjdH0gQXBwSW5mb1xuICogQHByb3BlcnR5IHtzdHJpbmd9IG5hbWUgLSBQYWNrYWdlIG5hbWUsIGZvciBleGFtcGxlICdjb20uYWNtZS5hcHAnLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IHZlcnNpb25Db2RlIC0gVmVyc2lvbiBjb2RlLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IHZlcnNpb25OYW1lIC0gVmVyc2lvbiBuYW1lLCBmb3IgZXhhbXBsZSAnMS4wJy5cbiAqL1xuXG4vKipcbiAqIEdldCB0aGUgcGFja2FnZSBpbmZvIGZyb20gbG9jYWwgYXBrIGZpbGUuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGFwcFBhdGggLSBUaGUgZnVsbCBwYXRoIHRvIGV4aXN0aW5nIC5hcGsocykgcGFja2FnZSBvbiB0aGUgbG9jYWxcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZSBzeXN0ZW0uXG4gKiBAcmV0dXJuIHs/QXBwSW5mb30gVGhlIHBhcnNlZCBhcHBsaWNhdGlvbiBpbmZvcm1hdGlvbi5cbiAqL1xuYXBrVXRpbHNNZXRob2RzLmdldEFwa0luZm8gPSBhc3luYyBmdW5jdGlvbiBnZXRBcGtJbmZvIChhcHBQYXRoKSB7XG4gIGlmICghYXdhaXQgZnMuZXhpc3RzKGFwcFBhdGgpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBUaGUgZmlsZSBhdCBwYXRoICR7YXBwUGF0aH0gZG9lcyBub3QgZXhpc3Qgb3IgaXMgbm90IGFjY2Vzc2libGVgKTtcbiAgfVxuXG4gIGlmIChhcHBQYXRoLmVuZHNXaXRoKEFQS1NfRVhURU5TSU9OKSkge1xuICAgIGFwcFBhdGggPSBhd2FpdCB0aGlzLmV4dHJhY3RCYXNlQXBrKGFwcFBhdGgpO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBjb25zdCBhcGtSZWFkZXIgPSBhd2FpdCBBcGtSZWFkZXIub3BlbihhcHBQYXRoKTtcbiAgICBjb25zdCBtYW5pZmVzdCA9IGF3YWl0IGFwa1JlYWRlci5yZWFkTWFuaWZlc3QoKTtcbiAgICBjb25zdCB7cGtnLCB2ZXJzaW9uTmFtZSwgdmVyc2lvbkNvZGV9ID0gcGFyc2VNYW5pZmVzdChtYW5pZmVzdCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIG5hbWU6IHBrZyxcbiAgICAgIHZlcnNpb25Db2RlLFxuICAgICAgdmVyc2lvbk5hbWUsXG4gICAgfTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIGxvZy53YXJuKGBFcnJvciAnJHtlLm1lc3NhZ2V9JyB3aGlsZSBnZXR0aW5nIGJhZGdpbmcgaW5mb2ApO1xuICB9XG4gIHJldHVybiB7fTtcbn07XG5cbi8qKlxuICogR2V0IHRoZSBwYWNrYWdlIGluZm8gZnJvbSB0aGUgaW5zdGFsbGVkIGFwcGxpY2F0aW9uLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBwa2cgLSBUaGUgbmFtZSBvZiB0aGUgaW5zdGFsbGVkIHBhY2thZ2UuXG4gKiBAcmV0dXJuIHs/QXBwSW5mb30gVGhlIHBhcnNlZCBhcHBsaWNhdGlvbiBpbmZvcm1hdGlvbi5cbiAqL1xuYXBrVXRpbHNNZXRob2RzLmdldFBhY2thZ2VJbmZvID0gYXN5bmMgZnVuY3Rpb24gZ2V0UGFja2FnZUluZm8gKHBrZykge1xuICBsb2cuZGVidWcoYEdldHRpbmcgcGFja2FnZSBpbmZvIGZvciAnJHtwa2d9J2ApO1xuICBsZXQgcmVzdWx0ID0ge25hbWU6IHBrZ307XG4gIHRyeSB7XG4gICAgY29uc3Qgc3Rkb3V0ID0gYXdhaXQgdGhpcy5zaGVsbChbJ2R1bXBzeXMnLCAncGFja2FnZScsIHBrZ10pO1xuICAgIGNvbnN0IHZlcnNpb25OYW1lTWF0Y2ggPSBuZXcgUmVnRXhwKC92ZXJzaW9uTmFtZT0oW1xcZCsuXSspLykuZXhlYyhzdGRvdXQpO1xuICAgIGlmICh2ZXJzaW9uTmFtZU1hdGNoKSB7XG4gICAgICByZXN1bHQudmVyc2lvbk5hbWUgPSB2ZXJzaW9uTmFtZU1hdGNoWzFdO1xuICAgIH1cbiAgICBjb25zdCB2ZXJzaW9uQ29kZU1hdGNoID0gbmV3IFJlZ0V4cCgvdmVyc2lvbkNvZGU9KFxcZCspLykuZXhlYyhzdGRvdXQpO1xuICAgIGlmICh2ZXJzaW9uQ29kZU1hdGNoKSB7XG4gICAgICByZXN1bHQudmVyc2lvbkNvZGUgPSBwYXJzZUludCh2ZXJzaW9uQ29kZU1hdGNoWzFdLCAxMCk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZy53YXJuKGBFcnJvciAnJHtlcnIubWVzc2FnZX0nIHdoaWxlIGR1bXBpbmcgcGFja2FnZSBpbmZvYCk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn07XG5cbi8qKlxuICogRmV0Y2hlcyBiYXNlLmFwayBvZiB0aGUgZ2l2ZW4gcGFja2FnZSB0byB0aGUgbG9jYWwgZmlsZSBzeXN0ZW1cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcGtnIFRoZSBwYWNrYWdlIGlkZW50aWZpZXIgKG11c3QgYmUgYWxyZWFkeSBpbnN0YWxsZWQgb24gdGhlIGRldmljZSlcbiAqIEBwYXJhbSB7c3RyaW5nfSB0bXBEaXIgVGhlIGRlc3RpbmF0aW9uIGZvbGRlciBwYXRoXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBGdWxsIHBhdGggdG8gdGhlIGRvd25sb2FkZWQgZmlsZVxuICogQHRocm93cyB7RXJyb3J9IElmIHRoZXJlIHdhcyBhbiBlcnJvciB3aGlsZSBmZXRjaGluZyB0aGUgLmFwa1xuICovXG5hcGtVdGlsc01ldGhvZHMucHVsbEFwayA9IGFzeW5jIGZ1bmN0aW9uIHB1bGxBcGsgKHBrZywgdG1wRGlyKSB7XG4gIGNvbnN0IHN0ZG91dCA9IF8udHJpbShhd2FpdCB0aGlzLnNoZWxsKFsncG0nLCAncGF0aCcsIHBrZ10pKTtcbiAgY29uc3QgcGFja2FnZU1hcmtlciA9ICdwYWNrYWdlOic7XG4gIGlmICghXy5zdGFydHNXaXRoKHN0ZG91dCwgcGFja2FnZU1hcmtlcikpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBwdWxsIHRoZSAuYXBrIHBhY2thZ2UgZm9yICcke3BrZ30nLiBPcmlnaW5hbCBlcnJvcjogJHtzdGRvdXR9YCk7XG4gIH1cblxuICBjb25zdCByZW1vdGVQYXRoID0gc3Rkb3V0LnJlcGxhY2UocGFja2FnZU1hcmtlciwgJycpO1xuICBjb25zdCB0bXBBcHAgPSBwYXRoLnJlc29sdmUodG1wRGlyLCBgJHtwa2d9LmFwa2ApO1xuICBhd2FpdCB0aGlzLnB1bGwocmVtb3RlUGF0aCwgdG1wQXBwKTtcbiAgbG9nLmRlYnVnKGBQdWxsZWQgYXBwIGZvciBwYWNrYWdlICcke3BrZ30nIHRvICcke3RtcEFwcH0nYCk7XG4gIHJldHVybiB0bXBBcHA7XG59O1xuXG5leHBvcnQgeyBSRU1PVEVfQ0FDSEVfUk9PVCB9O1xuZXhwb3J0IGRlZmF1bHQgYXBrVXRpbHNNZXRob2RzO1xuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQUFBOztBQU1BOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUVBLE1BQU1BLGVBQWUsR0FBRyxFQUF4QjtBQUVBLE1BQU1DLCtCQUErQixHQUNuQyx5R0FERjtBQUVBRCxlQUFlLENBQUNFLGlCQUFoQixHQUFvQztFQUNsQ0MsT0FBTyxFQUFFLFNBRHlCO0VBRWxDQyxhQUFhLEVBQUUsY0FGbUI7RUFHbENDLHVCQUF1QixFQUFFLHVCQUhTO0VBSWxD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
|