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