appium-android-driver 5.13.1 → 5.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/build/index.js +43 -40
  3. package/build/lib/android-helpers.d.ts +136 -0
  4. package/build/lib/android-helpers.d.ts.map +1 -0
  5. package/build/lib/android-helpers.js +760 -679
  6. package/build/lib/android-helpers.js.map +1 -1
  7. package/build/lib/bootstrap.d.ts +29 -0
  8. package/build/lib/bootstrap.d.ts.map +1 -0
  9. package/build/lib/bootstrap.js +192 -179
  10. package/build/lib/bootstrap.js.map +1 -1
  11. package/build/lib/commands/actions.d.ts +209 -0
  12. package/build/lib/commands/actions.d.ts.map +1 -0
  13. package/build/lib/commands/actions.js +327 -265
  14. package/build/lib/commands/actions.js.map +1 -1
  15. package/build/lib/commands/alert.d.ts +10 -0
  16. package/build/lib/commands/alert.d.ts.map +1 -0
  17. package/build/lib/commands/alert.js +12 -18
  18. package/build/lib/commands/alert.js.map +1 -1
  19. package/build/lib/commands/app-management.d.ts +314 -0
  20. package/build/lib/commands/app-management.d.ts.map +1 -0
  21. package/build/lib/commands/app-management.js +278 -110
  22. package/build/lib/commands/app-management.js.map +1 -1
  23. package/build/lib/commands/context.d.ts +94 -0
  24. package/build/lib/commands/context.d.ts.map +1 -0
  25. package/build/lib/commands/context.js +412 -260
  26. package/build/lib/commands/context.js.map +1 -1
  27. package/build/lib/commands/coverage.d.ts +5 -0
  28. package/build/lib/commands/coverage.d.ts.map +1 -0
  29. package/build/lib/commands/coverage.js +14 -17
  30. package/build/lib/commands/coverage.js.map +1 -1
  31. package/build/lib/commands/element.d.ts +36 -0
  32. package/build/lib/commands/element.d.ts.map +1 -0
  33. package/build/lib/commands/element.js +97 -127
  34. package/build/lib/commands/element.js.map +1 -1
  35. package/build/lib/commands/emu-console.d.ts +49 -0
  36. package/build/lib/commands/emu-console.d.ts.map +1 -0
  37. package/build/lib/commands/emu-console.js +36 -25
  38. package/build/lib/commands/emu-console.js.map +1 -1
  39. package/build/lib/commands/execute.d.ts +6 -0
  40. package/build/lib/commands/execute.d.ts.map +1 -0
  41. package/build/lib/commands/execute.js +68 -69
  42. package/build/lib/commands/execute.js.map +1 -1
  43. package/build/lib/commands/file-actions.d.ts +129 -0
  44. package/build/lib/commands/file-actions.d.ts.map +1 -0
  45. package/build/lib/commands/file-actions.js +321 -178
  46. package/build/lib/commands/file-actions.js.map +1 -1
  47. package/build/lib/commands/find.d.ts +13 -0
  48. package/build/lib/commands/find.d.ts.map +1 -0
  49. package/build/lib/commands/find.js +69 -51
  50. package/build/lib/commands/find.js.map +1 -1
  51. package/build/lib/commands/general.d.ts +133 -0
  52. package/build/lib/commands/general.d.ts.map +1 -0
  53. package/build/lib/commands/general.js +275 -216
  54. package/build/lib/commands/general.js.map +1 -1
  55. package/build/lib/commands/ime.d.ts +11 -0
  56. package/build/lib/commands/ime.d.ts.map +1 -0
  57. package/build/lib/commands/ime.js +27 -33
  58. package/build/lib/commands/ime.js.map +1 -1
  59. package/build/lib/commands/index.d.ts +3 -0
  60. package/build/lib/commands/index.d.ts.map +1 -0
  61. package/build/lib/commands/index.js +32 -35
  62. package/build/lib/commands/index.js.map +1 -1
  63. package/build/lib/commands/intent.d.ts +418 -0
  64. package/build/lib/commands/intent.d.ts.map +1 -0
  65. package/build/lib/commands/intent.js +281 -151
  66. package/build/lib/commands/intent.js.map +1 -1
  67. package/build/lib/commands/keyboard.d.ts +6 -0
  68. package/build/lib/commands/keyboard.d.ts.map +1 -0
  69. package/build/lib/commands/keyboard.js +6 -14
  70. package/build/lib/commands/keyboard.js.map +1 -1
  71. package/build/lib/commands/log.d.ts +45 -0
  72. package/build/lib/commands/log.d.ts.map +1 -0
  73. package/build/lib/commands/log.js +117 -103
  74. package/build/lib/commands/log.js.map +1 -1
  75. package/build/lib/commands/media-projection.d.ts +144 -0
  76. package/build/lib/commands/media-projection.d.ts.map +1 -0
  77. package/build/lib/commands/media-projection.js +228 -171
  78. package/build/lib/commands/media-projection.js.map +1 -1
  79. package/build/lib/commands/network.d.ts +139 -0
  80. package/build/lib/commands/network.d.ts.map +1 -0
  81. package/build/lib/commands/network.js +249 -181
  82. package/build/lib/commands/network.js.map +1 -1
  83. package/build/lib/commands/performance.d.ts +101 -0
  84. package/build/lib/commands/performance.d.ts.map +1 -0
  85. package/build/lib/commands/performance.js +390 -236
  86. package/build/lib/commands/performance.js.map +1 -1
  87. package/build/lib/commands/permissions.d.ts +93 -0
  88. package/build/lib/commands/permissions.d.ts.map +1 -0
  89. package/build/lib/commands/permissions.js +133 -93
  90. package/build/lib/commands/permissions.js.map +1 -1
  91. package/build/lib/commands/recordscreen.d.ts +194 -0
  92. package/build/lib/commands/recordscreen.d.ts.map +1 -0
  93. package/build/lib/commands/recordscreen.js +293 -224
  94. package/build/lib/commands/recordscreen.js.map +1 -1
  95. package/build/lib/commands/shell.d.ts +8 -0
  96. package/build/lib/commands/shell.d.ts.map +1 -0
  97. package/build/lib/commands/shell.js +38 -43
  98. package/build/lib/commands/shell.js.map +1 -1
  99. package/build/lib/commands/streamscreen.d.ts +104 -0
  100. package/build/lib/commands/streamscreen.d.ts.map +1 -0
  101. package/build/lib/commands/streamscreen.js +364 -305
  102. package/build/lib/commands/streamscreen.js.map +1 -1
  103. package/build/lib/commands/system-bars.d.ts +100 -0
  104. package/build/lib/commands/system-bars.d.ts.map +1 -0
  105. package/build/lib/commands/system-bars.js +148 -90
  106. package/build/lib/commands/system-bars.js.map +1 -1
  107. package/build/lib/commands/touch.d.ts +30 -0
  108. package/build/lib/commands/touch.d.ts.map +1 -0
  109. package/build/lib/commands/touch.js +311 -287
  110. package/build/lib/commands/touch.js.map +1 -1
  111. package/build/lib/desired-caps.d.ts +353 -0
  112. package/build/lib/desired-caps.d.ts.map +1 -0
  113. package/build/lib/desired-caps.js +291 -292
  114. package/build/lib/desired-caps.js.map +1 -1
  115. package/build/lib/driver.d.ts +430 -0
  116. package/build/lib/driver.d.ts.map +1 -0
  117. package/build/lib/driver.js +449 -384
  118. package/build/lib/driver.js.map +1 -1
  119. package/build/lib/logger.d.ts +3 -0
  120. package/build/lib/logger.d.ts.map +1 -0
  121. package/build/lib/logger.js +5 -11
  122. package/build/lib/logger.js.map +1 -1
  123. package/build/lib/method-map.d.ts +389 -0
  124. package/build/lib/method-map.d.ts.map +1 -0
  125. package/build/lib/method-map.js +220 -394
  126. package/build/lib/method-map.js.map +1 -1
  127. package/build/lib/stubs.d.ts +8 -0
  128. package/build/lib/stubs.d.ts.map +1 -0
  129. package/build/lib/stubs.js +5 -0
  130. package/build/lib/stubs.js.map +1 -0
  131. package/build/lib/uiautomator.d.ts +24 -0
  132. package/build/lib/uiautomator.d.ts.map +1 -0
  133. package/build/lib/uiautomator.js +86 -82
  134. package/build/lib/uiautomator.js.map +1 -1
  135. package/build/lib/unlock-helpers.d.ts +38 -0
  136. package/build/lib/unlock-helpers.d.ts.map +1 -0
  137. package/build/lib/unlock-helpers.js +228 -204
  138. package/build/lib/unlock-helpers.js.map +1 -1
  139. package/build/lib/utils.d.ts +11 -0
  140. package/build/lib/utils.d.ts.map +1 -0
  141. package/build/lib/utils.js +23 -18
  142. package/build/lib/utils.js.map +1 -1
  143. package/build/lib/webview-helpers.d.ts +223 -0
  144. package/build/lib/webview-helpers.d.ts.map +1 -0
  145. package/build/lib/webview-helpers.js +476 -298
  146. package/build/lib/webview-helpers.js.map +1 -1
  147. package/index.js +3 -1
  148. package/lib/android-helpers.js +2 -1
  149. package/lib/stubs.ts +8 -0
  150. package/lib/unlock-helpers.js +2 -2
  151. package/package.json +23 -14
@@ -1,277 +1,431 @@
1
1
  "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
- Object.defineProperty(exports, "__esModule", {
5
- value: true
6
- });
7
- exports.default = exports.commands = exports.SUPPORTED_PERFORMANCE_DATA_TYPES = exports.NETWORK_KEYS = exports.MEMORY_KEYS = exports.CPU_KEYS = exports.BATTERY_KEYS = void 0;
8
- exports.getBatteryInfo = getBatteryInfo;
9
- exports.getCPUInfo = getCPUInfo;
10
- exports.getMemoryInfo = getMemoryInfo;
11
- exports.getNetworkTrafficInfo = getNetworkTrafficInfo;
12
- require("source-map-support/register");
13
- var _lodash = _interopRequireDefault(require("lodash"));
14
- var _asyncbox = require("asyncbox");
15
- var _utils = require("../utils");
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getBatteryInfo = exports.getCPUInfo = exports.getNetworkTrafficInfo = exports.getMemoryInfo = exports.NETWORK_KEYS = exports.BATTERY_KEYS = exports.MEMORY_KEYS = exports.CPU_KEYS = exports.SUPPORTED_PERFORMANCE_DATA_TYPES = exports.commands = void 0;
7
+ const lodash_1 = __importDefault(require("lodash"));
8
+ const asyncbox_1 = require("asyncbox");
9
+ const utils_1 = require("../utils");
16
10
  const commands = {};
17
11
  exports.commands = commands;
18
- const NETWORK_KEYS = [['bucketStart', 'activeTime', 'rxBytes', 'rxPackets', 'txBytes', 'txPackets', 'operations', 'bucketDuration'], ['st', 'activeTime', 'rb', 'rp', 'tb', 'tp', 'op', 'bucketDuration']];
12
+ const NETWORK_KEYS = [
13
+ ['bucketStart', 'activeTime', 'rxBytes', 'rxPackets', 'txBytes', 'txPackets', 'operations', 'bucketDuration'],
14
+ ['st', 'activeTime', 'rb', 'rp', 'tb', 'tp', 'op', 'bucketDuration']
15
+ ];
19
16
  exports.NETWORK_KEYS = NETWORK_KEYS;
20
17
  const CPU_KEYS = ['user', 'kernel'];
21
18
  exports.CPU_KEYS = CPU_KEYS;
22
19
  const BATTERY_KEYS = ['power'];
23
20
  exports.BATTERY_KEYS = BATTERY_KEYS;
24
- const MEMORY_KEYS = ['totalPrivateDirty', 'nativePrivateDirty', 'dalvikPrivateDirty', 'eglPrivateDirty', 'glPrivateDirty', 'totalPss', 'nativePss', 'dalvikPss', 'eglPss', 'glPss', 'nativeHeapAllocatedSize', 'nativeHeapSize', 'nativeRss', 'dalvikRss', 'totalRss'];
21
+ const MEMORY_KEYS = [
22
+ 'totalPrivateDirty', 'nativePrivateDirty', 'dalvikPrivateDirty',
23
+ 'eglPrivateDirty', 'glPrivateDirty',
24
+ 'totalPss', 'nativePss', 'dalvikPss', 'eglPss', 'glPss',
25
+ 'nativeHeapAllocatedSize', 'nativeHeapSize',
26
+ 'nativeRss', 'dalvikRss', 'totalRss'
27
+ ];
25
28
  exports.MEMORY_KEYS = MEMORY_KEYS;
26
29
  const SUPPORTED_PERFORMANCE_DATA_TYPES = Object.freeze({
27
- cpuinfo: 'the amount of cpu by user and kernel process - cpu information for applications on real devices and simulators',
28
- memoryinfo: 'the amount of memory used by the process - memory information for applications on real devices and simulators',
29
- batteryinfo: 'the remaining battery power - battery power information for applications on real devices and simulators',
30
- networkinfo: 'the network statistics - network rx/tx information for applications on real devices and simulators'
30
+ cpuinfo: 'the amount of cpu by user and kernel process - cpu information for applications on real devices and simulators',
31
+ memoryinfo: 'the amount of memory used by the process - memory information for applications on real devices and simulators',
32
+ batteryinfo: 'the remaining battery power - battery power information for applications on real devices and simulators',
33
+ networkinfo: 'the network statistics - network rx/tx information for applications on real devices and simulators'
31
34
  });
32
35
  exports.SUPPORTED_PERFORMANCE_DATA_TYPES = SUPPORTED_PERFORMANCE_DATA_TYPES;
33
36
  const MEMINFO_TITLES = Object.freeze({
34
- NATIVE: 'Native',
35
- DALVIK: 'Dalvik',
36
- EGL: 'EGL',
37
- GL: 'GL',
38
- MTRACK: 'mtrack',
39
- TOTAL: 'TOTAL',
40
- HEAP: 'Heap'
37
+ NATIVE: 'Native',
38
+ DALVIK: 'Dalvik',
39
+ EGL: 'EGL',
40
+ GL: 'GL',
41
+ MTRACK: 'mtrack',
42
+ TOTAL: 'TOTAL',
43
+ HEAP: 'Heap'
41
44
  });
42
45
  const RETRY_PAUSE_MS = 1000;
46
+ /**
47
+ * API level between 18 and 30
48
+ * ['<System Type>', '<Memory Type>', <pss total>, <private dirty>, <private clean>, <swapPss dirty>, <heap size>, <heap alloc>, <heap free>]
49
+ * except 'TOTAL', which skips the second type name
50
+ * !!! valDict gets mutated
51
+ */
43
52
  function parseMeminfoForApi19To29(entries, valDict) {
44
- const [type, subType] = entries;
45
- if (type === MEMINFO_TITLES.NATIVE && subType === MEMINFO_TITLES.HEAP) {
46
- [,, valDict.nativePss, valDict.nativePrivateDirty,,, valDict.nativeHeapSize, valDict.nativeHeapAllocatedSize] = entries;
47
- } else if (type === MEMINFO_TITLES.DALVIK && subType === MEMINFO_TITLES.HEAP) {
48
- [,, valDict.dalvikPss, valDict.dalvikPrivateDirty] = entries;
49
- } else if (type === MEMINFO_TITLES.EGL && subType === MEMINFO_TITLES.MTRACK) {
50
- [,, valDict.eglPss, valDict.eglPrivateDirty] = entries;
51
- } else if (type === MEMINFO_TITLES.GL && subType === MEMINFO_TITLES.MTRACK) {
52
- [,, valDict.glPss, valDict.glPrivateDirty] = entries;
53
- } else if (type === MEMINFO_TITLES.TOTAL && entries.length === 8) {
54
- [, valDict.totalPss, valDict.totalPrivateDirty] = entries;
55
- }
53
+ const [type, subType] = entries;
54
+ if (type === MEMINFO_TITLES.NATIVE && subType === MEMINFO_TITLES.HEAP) {
55
+ [, , valDict.nativePss, valDict.nativePrivateDirty, , , valDict.nativeHeapSize, valDict.nativeHeapAllocatedSize] = entries;
56
+ }
57
+ else if (type === MEMINFO_TITLES.DALVIK && subType === MEMINFO_TITLES.HEAP) {
58
+ [, , valDict.dalvikPss, valDict.dalvikPrivateDirty] = entries;
59
+ }
60
+ else if (type === MEMINFO_TITLES.EGL && subType === MEMINFO_TITLES.MTRACK) {
61
+ [, , valDict.eglPss, valDict.eglPrivateDirty] = entries;
62
+ }
63
+ else if (type === MEMINFO_TITLES.GL && subType === MEMINFO_TITLES.MTRACK) {
64
+ [, , valDict.glPss, valDict.glPrivateDirty] = entries;
65
+ }
66
+ else if (type === MEMINFO_TITLES.TOTAL && entries.length === 8) {
67
+ // there are two totals, and we only want the full listing, which has 8 entries
68
+ [, valDict.totalPss, valDict.totalPrivateDirty] = entries;
69
+ }
56
70
  }
71
+ /**
72
+ * ['<System Type', '<pps>', '<shared dirty>', '<private dirty>', '<heap size>', '<heap alloc>', '<heap free>']
73
+ * !!! valDict gets mutated
74
+ */
57
75
  function parseMeminfoForApiBelow19(entries, valDict) {
58
- const type = entries[0];
59
- if (type === MEMINFO_TITLES.NATIVE) {
60
- [, valDict.nativePss,, valDict.nativePrivateDirty, valDict.nativeHeapSize, valDict.nativeHeapAllocatedSize] = entries;
61
- } else if (type === MEMINFO_TITLES.DALVIK) {
62
- [, valDict.dalvikPss,, valDict.dalvikPrivateDirty] = entries;
63
- } else if (type === MEMINFO_TITLES.EGL) {
64
- [, valDict.eglPss,, valDict.eglPrivateDirty] = entries;
65
- } else if (type === MEMINFO_TITLES.GL) {
66
- [, valDict.glPss,, valDict.glPrivateDirty] = entries;
67
- } else if (type === MEMINFO_TITLES.TOTAL) {
68
- [, valDict.totalPss,, valDict.totalPrivateDirty] = entries;
69
- }
76
+ const type = entries[0];
77
+ if (type === MEMINFO_TITLES.NATIVE) {
78
+ [, valDict.nativePss, , valDict.nativePrivateDirty, valDict.nativeHeapSize, valDict.nativeHeapAllocatedSize] = entries;
79
+ }
80
+ else if (type === MEMINFO_TITLES.DALVIK) {
81
+ [, valDict.dalvikPss, , valDict.dalvikPrivateDirty] = entries;
82
+ }
83
+ else if (type === MEMINFO_TITLES.EGL) {
84
+ [, valDict.eglPss, , valDict.eglPrivateDirty] = entries;
85
+ }
86
+ else if (type === MEMINFO_TITLES.GL) {
87
+ [, valDict.glPss, , valDict.glPrivateDirty] = entries;
88
+ }
89
+ else if (type === MEMINFO_TITLES.TOTAL) {
90
+ [, valDict.totalPss, , valDict.totalPrivateDirty] = entries;
91
+ }
70
92
  }
93
+ /**
94
+ * API level 30 and above
95
+ * ['<System Type>', '<Memory Type>', <pss total>, <private dirty>, <private clean>, <swapPss dirty>, <rss total>, <heap size>, <heap alloc>, <heap free>]
96
+ * !!! valDict gets mutated
97
+ */
71
98
  function parseMeminfoForApiAbove29(entries, valDict) {
72
- const [type, subType] = entries;
73
- if (type === MEMINFO_TITLES.NATIVE && subType === MEMINFO_TITLES.HEAP) {
74
- [,, valDict.nativePss, valDict.nativePrivateDirty,,, valDict.nativeRss, valDict.nativeHeapSize, valDict.nativeHeapAllocatedSize] = entries;
75
- } else if (type === MEMINFO_TITLES.DALVIK && subType === MEMINFO_TITLES.HEAP) {
76
- [,, valDict.dalvikPss, valDict.dalvikPrivateDirty,,, valDict.dalvikRss] = entries;
77
- } else if (type === MEMINFO_TITLES.EGL && subType === MEMINFO_TITLES.MTRACK) {
78
- [,, valDict.eglPss, valDict.eglPrivateDirty] = entries;
79
- } else if (type === MEMINFO_TITLES.GL && subType === MEMINFO_TITLES.MTRACK) {
80
- [,, valDict.glPss, valDict.glPrivateDirty] = entries;
81
- } else if (type === MEMINFO_TITLES.TOTAL && entries.length === 9) {
82
- [, valDict.totalPss, valDict.totalPrivateDirty,,, valDict.totalRss] = entries;
83
- }
84
- }
85
- async function getMemoryInfo(packageName, retries = 2) {
86
- return await (0, _asyncbox.retryInterval)(retries, RETRY_PAUSE_MS, async () => {
87
- const cmd = ['dumpsys', 'meminfo', `'${packageName}'`, '|', 'grep', '-E', `'${MEMINFO_TITLES.NATIVE}|${MEMINFO_TITLES.DALVIK}|${MEMINFO_TITLES.EGL}` + `|${MEMINFO_TITLES.GL}|${MEMINFO_TITLES.TOTAL}'`];
88
- const data = await this.adb.shell(cmd);
89
- if (!data) {
90
- throw new Error('No data from dumpsys');
99
+ const [type, subType] = entries;
100
+ if (type === MEMINFO_TITLES.NATIVE && subType === MEMINFO_TITLES.HEAP) {
101
+ [, , valDict.nativePss, valDict.nativePrivateDirty, , , valDict.nativeRss, valDict.nativeHeapSize, valDict.nativeHeapAllocatedSize] = entries;
91
102
  }
92
- const valDict = {
93
- totalPrivateDirty: ''
94
- };
95
- const apiLevel = await this.adb.getApiLevel();
96
- for (const line of data.split('\n')) {
97
- const entries = line.trim().split(/\s+/).filter(Boolean);
98
- if (apiLevel >= 30) {
99
- parseMeminfoForApiAbove29(entries, valDict);
100
- } else if (apiLevel > 18 && apiLevel < 30) {
101
- parseMeminfoForApi19To29(entries, valDict);
102
- } else {
103
- parseMeminfoForApiBelow19(entries, valDict);
104
- }
103
+ else if (type === MEMINFO_TITLES.DALVIK && subType === MEMINFO_TITLES.HEAP) {
104
+ [, , valDict.dalvikPss, valDict.dalvikPrivateDirty, , , valDict.dalvikRss] = entries;
105
105
  }
106
- if (valDict.totalPrivateDirty && valDict.totalPrivateDirty !== 'nodex') {
107
- const headers = _lodash.default.clone(MEMORY_KEYS);
108
- const values = headers.map(header => valDict[header]);
109
- return [headers, values];
106
+ else if (type === MEMINFO_TITLES.EGL && subType === MEMINFO_TITLES.MTRACK) {
107
+ [, , valDict.eglPss, valDict.eglPrivateDirty] = entries;
110
108
  }
111
- throw new Error(`Unable to parse memory data: '${data}'`);
112
- });
113
- }
114
- ;
115
- async function getNetworkTrafficInfo(retries = 2) {
116
- return await (0, _asyncbox.retryInterval)(retries, RETRY_PAUSE_MS, async () => {
117
- let returnValue = [];
118
- let bucketDuration, bucketStart, activeTime, rxBytes, rxPackets, txBytes, txPackets, operations;
119
- let cmd = ['dumpsys', 'netstats'];
120
- let data = await this.adb.shell(cmd);
121
- if (!data) throw new Error('No data from dumpsys');
122
- let index = 0;
123
- let fromXtstats = data.indexOf('Xt stats:');
124
- let start = data.indexOf('Pending bytes:', fromXtstats);
125
- let delimiter = data.indexOf(':', start + 1);
126
- let end = data.indexOf('\n', delimiter + 1);
127
- let pendingBytes = data.substring(delimiter + 1, end).trim();
128
- if (end > delimiter) {
129
- start = data.indexOf('bucketDuration', end + 1);
130
- delimiter = data.indexOf('=', start + 1);
131
- end = data.indexOf('\n', delimiter + 1);
132
- bucketDuration = data.substring(delimiter + 1, end).trim();
109
+ else if (type === MEMINFO_TITLES.GL && subType === MEMINFO_TITLES.MTRACK) {
110
+ [, , valDict.glPss, valDict.glPrivateDirty] = entries;
133
111
  }
134
- if (start >= 0) {
135
- data = data.substring(end + 1, data.length);
136
- let arrayList = data.split('\n');
137
- if (arrayList.length > 0) {
138
- start = -1;
139
- for (let j = 0; j < NETWORK_KEYS.length; ++j) {
140
- start = arrayList[0].indexOf(NETWORK_KEYS[j][0]);
141
- if (start >= 0) {
142
- index = j;
143
- returnValue[0] = [];
144
- for (let k = 0; k < NETWORK_KEYS[j].length; ++k) {
145
- returnValue[0][k] = NETWORK_KEYS[j][k];
146
- }
147
- break;
148
- }
112
+ else if (type === MEMINFO_TITLES.TOTAL && entries.length === 9) {
113
+ // has 9 entries
114
+ [, valDict.totalPss, valDict.totalPrivateDirty, , , valDict.totalRss] = entries;
115
+ }
116
+ }
117
+ async function getMemoryInfo(packageName, retries = 2) {
118
+ return await (0, asyncbox_1.retryInterval)(retries, RETRY_PAUSE_MS, async () => {
119
+ const cmd = [
120
+ 'dumpsys', 'meminfo', `'${packageName}'`,
121
+ '|', 'grep', '-E',
122
+ `'${MEMINFO_TITLES.NATIVE}|${MEMINFO_TITLES.DALVIK}|${MEMINFO_TITLES.EGL}` +
123
+ `|${MEMINFO_TITLES.GL}|${MEMINFO_TITLES.TOTAL}'`
124
+ ];
125
+ const data = await this.adb.shell(cmd);
126
+ if (!data) {
127
+ throw new Error('No data from dumpsys');
149
128
  }
150
- let returnIndex = 1;
151
- for (let i = 0; i < arrayList.length; i++) {
152
- data = arrayList[i];
153
- start = data.indexOf(NETWORK_KEYS[index][0]);
154
- if (start >= 0) {
155
- delimiter = data.indexOf('=', start + 1);
156
- end = data.indexOf(' ', delimiter + 1);
157
- bucketStart = data.substring(delimiter + 1, end).trim();
158
- if (end > delimiter) {
159
- start = data.indexOf(NETWORK_KEYS[index][1], end + 1);
160
- if (start >= 0) {
161
- delimiter = data.indexOf('=', start + 1);
162
- end = data.indexOf(' ', delimiter + 1);
163
- activeTime = data.substring(delimiter + 1, end).trim();
164
- }
165
- }
166
- if (end > delimiter) {
167
- start = data.indexOf(NETWORK_KEYS[index][2], end + 1);
168
- if (start >= 0) {
169
- delimiter = data.indexOf('=', start + 1);
170
- end = data.indexOf(' ', delimiter + 1);
171
- rxBytes = data.substring(delimiter + 1, end).trim();
172
- }
129
+ const valDict = { totalPrivateDirty: '' };
130
+ const apiLevel = await this.adb.getApiLevel();
131
+ for (const line of data.split('\n')) {
132
+ const entries = line.trim().split(/\s+/).filter(Boolean);
133
+ if (apiLevel >= 30) {
134
+ parseMeminfoForApiAbove29(entries, valDict);
173
135
  }
174
- if (end > delimiter) {
175
- start = data.indexOf(NETWORK_KEYS[index][3], end + 1);
176
- if (start >= 0) {
177
- delimiter = data.indexOf('=', start + 1);
178
- end = data.indexOf(' ', delimiter + 1);
179
- rxPackets = data.substring(delimiter + 1, end).trim();
180
- }
136
+ else if (apiLevel > 18 && apiLevel < 30) {
137
+ parseMeminfoForApi19To29(entries, valDict);
181
138
  }
182
- if (end > delimiter) {
183
- start = data.indexOf(NETWORK_KEYS[index][4], end + 1);
184
- if (start >= 0) {
185
- delimiter = data.indexOf('=', start + 1);
186
- end = data.indexOf(' ', delimiter + 1);
187
- txBytes = data.substring(delimiter + 1, end).trim();
188
- }
139
+ else {
140
+ parseMeminfoForApiBelow19(entries, valDict);
189
141
  }
190
- if (end > delimiter) {
191
- start = data.indexOf(NETWORK_KEYS[index][5], end + 1);
192
- if (start >= 0) {
193
- delimiter = data.indexOf('=', start + 1);
194
- end = data.indexOf(' ', delimiter + 1);
195
- txPackets = data.substring(delimiter + 1, end).trim();
196
- }
197
- }
198
- if (end > delimiter) {
199
- start = data.indexOf(NETWORK_KEYS[index][6], end + 1);
200
- if (start >= 0) {
201
- delimiter = data.indexOf('=', start + 1);
202
- end = data.length;
203
- operations = data.substring(delimiter + 1, end).trim();
204
- }
142
+ }
143
+ if (valDict.totalPrivateDirty && valDict.totalPrivateDirty !== 'nodex') {
144
+ const headers = lodash_1.default.clone(MEMORY_KEYS);
145
+ const values = headers.map((header) => valDict[header]);
146
+ return [headers, values];
147
+ }
148
+ throw new Error(`Unable to parse memory data: '${data}'`);
149
+ });
150
+ }
151
+ exports.getMemoryInfo = getMemoryInfo;
152
+ ;
153
+ /**
154
+ * @this {AndroidDriver}
155
+ * @param {number} retries
156
+ */
157
+ async function getNetworkTrafficInfo(retries = 2) {
158
+ return await (0, asyncbox_1.retryInterval)(retries, RETRY_PAUSE_MS, async () => {
159
+ let returnValue = [];
160
+ let bucketDuration, bucketStart, activeTime, rxBytes, rxPackets, txBytes, txPackets, operations;
161
+ let cmd = ['dumpsys', 'netstats'];
162
+ let data = await this.adb.shell(cmd);
163
+ if (!data)
164
+ throw new Error('No data from dumpsys'); //eslint-disable-line curly
165
+ // In case of network traffic information, it is different for the return data between emulator and real device.
166
+ // the return data of emulator
167
+ // Xt stats:
168
+ // Pending bytes: 39250
169
+ // History since boot:
170
+ // ident=[[type=WIFI, subType=COMBINED, networkId="WiredSSID"]] uid=-1 set=ALL tag=0x0
171
+ // NetworkStatsHistory: bucketDuration=3600000
172
+ // bucketStart=1478098800000 activeTime=31824 rxBytes=21502 rxPackets=78 txBytes=17748 txPackets=90 operations=0
173
+ //
174
+ // 7.1
175
+ // Xt stats:
176
+ // Pending bytes: 481487
177
+ // History since boot:
178
+ // ident=[{type=MOBILE, subType=COMBINED, subscriberId=310260..., metered=true}] uid=-1 set=ALL tag=0x0
179
+ // NetworkStatsHistory: bucketDuration=3600
180
+ // st=1483984800 rb=0 rp=0 tb=12031 tp=184 op=0
181
+ // st=1483988400 rb=0 rp=0 tb=38476 tp=587 op=0
182
+ // st=1483999200 rb=315616 rp=400 tb=94800 tp=362 op=0
183
+ // st=1484002800 rb=15826 rp=20 tb=4738 tp=16 op=0
184
+ //
185
+ // the return data of real device
186
+ // Xt stats:
187
+ // Pending bytes: 0
188
+ // History since boot:
189
+ // ident=[{type=MOBILE, subType=COMBINED, subscriberId=450050...}] uid=-1 set=ALL tag=0x0
190
+ // NetworkStatsHistory: bucketDuration=3600
191
+ // st=1478088000 rb=32115296 rp=34291 tb=2956805 tp=25705 op=0
192
+ // st=1478091600 rb=2714683 rp=11821 tb=1420564 tp=12650 op=0
193
+ // st=1478095200 rb=10079213 rp=19962 tb=2487705 tp=20015 op=0
194
+ // st=1478098800 rb=4444433 rp=10227 tb=1430356 tp=10493 op=0
195
+ let index = 0;
196
+ let fromXtstats = data.indexOf('Xt stats:');
197
+ let start = data.indexOf('Pending bytes:', fromXtstats);
198
+ let delimiter = data.indexOf(':', start + 1);
199
+ let end = data.indexOf('\n', delimiter + 1);
200
+ let pendingBytes = data.substring(delimiter + 1, end).trim();
201
+ if (end > delimiter) {
202
+ start = data.indexOf('bucketDuration', end + 1);
203
+ delimiter = data.indexOf('=', start + 1);
204
+ end = data.indexOf('\n', delimiter + 1);
205
+ bucketDuration = data.substring(delimiter + 1, end).trim();
206
+ }
207
+ if (start >= 0) {
208
+ data = data.substring(end + 1, data.length);
209
+ let arrayList = data.split('\n');
210
+ if (arrayList.length > 0) {
211
+ start = -1;
212
+ for (let j = 0; j < NETWORK_KEYS.length; ++j) {
213
+ start = arrayList[0].indexOf(NETWORK_KEYS[j][0]);
214
+ if (start >= 0) {
215
+ index = j;
216
+ returnValue[0] = [];
217
+ for (let k = 0; k < NETWORK_KEYS[j].length; ++k) {
218
+ returnValue[0][k] = NETWORK_KEYS[j][k];
219
+ }
220
+ break;
221
+ }
222
+ }
223
+ let returnIndex = 1;
224
+ for (let i = 0; i < arrayList.length; i++) {
225
+ data = arrayList[i];
226
+ start = data.indexOf(NETWORK_KEYS[index][0]);
227
+ if (start >= 0) {
228
+ delimiter = data.indexOf('=', start + 1);
229
+ end = data.indexOf(' ', delimiter + 1);
230
+ bucketStart = data.substring(delimiter + 1, end).trim();
231
+ if (end > delimiter) {
232
+ start = data.indexOf(NETWORK_KEYS[index][1], end + 1);
233
+ if (start >= 0) {
234
+ delimiter = data.indexOf('=', start + 1);
235
+ end = data.indexOf(' ', delimiter + 1);
236
+ activeTime = data.substring(delimiter + 1, end).trim();
237
+ }
238
+ }
239
+ if (end > delimiter) {
240
+ start = data.indexOf(NETWORK_KEYS[index][2], end + 1);
241
+ if (start >= 0) {
242
+ delimiter = data.indexOf('=', start + 1);
243
+ end = data.indexOf(' ', delimiter + 1);
244
+ rxBytes = data.substring(delimiter + 1, end).trim();
245
+ }
246
+ }
247
+ if (end > delimiter) {
248
+ start = data.indexOf(NETWORK_KEYS[index][3], end + 1);
249
+ if (start >= 0) {
250
+ delimiter = data.indexOf('=', start + 1);
251
+ end = data.indexOf(' ', delimiter + 1);
252
+ rxPackets = data.substring(delimiter + 1, end).trim();
253
+ }
254
+ }
255
+ if (end > delimiter) {
256
+ start = data.indexOf(NETWORK_KEYS[index][4], end + 1);
257
+ if (start >= 0) {
258
+ delimiter = data.indexOf('=', start + 1);
259
+ end = data.indexOf(' ', delimiter + 1);
260
+ txBytes = data.substring(delimiter + 1, end).trim();
261
+ }
262
+ }
263
+ if (end > delimiter) {
264
+ start = data.indexOf(NETWORK_KEYS[index][5], end + 1);
265
+ if (start >= 0) {
266
+ delimiter = data.indexOf('=', start + 1);
267
+ end = data.indexOf(' ', delimiter + 1);
268
+ txPackets = data.substring(delimiter + 1, end).trim();
269
+ }
270
+ }
271
+ if (end > delimiter) {
272
+ start = data.indexOf(NETWORK_KEYS[index][6], end + 1);
273
+ if (start >= 0) {
274
+ delimiter = data.indexOf('=', start + 1);
275
+ end = data.length;
276
+ operations = data.substring(delimiter + 1, end).trim();
277
+ }
278
+ }
279
+ returnValue[returnIndex++] = [bucketStart, activeTime, rxBytes, rxPackets, txBytes, txPackets, operations, bucketDuration];
280
+ }
281
+ }
205
282
  }
206
- returnValue[returnIndex++] = [bucketStart, activeTime, rxBytes, rxPackets, txBytes, txPackets, operations, bucketDuration];
207
- }
208
283
  }
209
- }
210
- }
211
- if (!_lodash.default.isEqual(pendingBytes, '') && !_lodash.default.isUndefined(pendingBytes) && !_lodash.default.isEqual(pendingBytes, 'nodex')) {
212
- return returnValue;
213
- } else {
214
- throw new Error(`Unable to parse network traffic data: '${data}'`);
215
- }
216
- });
284
+ if (!lodash_1.default.isEqual(pendingBytes, '') && !lodash_1.default.isUndefined(pendingBytes) && !lodash_1.default.isEqual(pendingBytes, 'nodex')) {
285
+ return returnValue;
286
+ }
287
+ else {
288
+ throw new Error(`Unable to parse network traffic data: '${data}'`);
289
+ }
290
+ });
217
291
  }
292
+ exports.getNetworkTrafficInfo = getNetworkTrafficInfo;
293
+ /**
294
+ * Return the CPU information related to the given packageName.
295
+ * It raises an exception if the dumped CPU information did not include the given packageName
296
+ * or the format was wrong.
297
+ * The CPU information's sampling interval depends on the device under test.
298
+ * For example, some devices have 5 minutes interval. When you get the information
299
+ * from 2023-02-07 11:59:40.468 to 2023-02-07 12:04:40.556, then the next will be
300
+ * from 2023-02-07 12:04:40.556 to 2023-02-07 12:09:40.668. No process information
301
+ * exists in the result if the process was not running during the period.
302
+ *
303
+ * @this {AndroidDriver}
304
+ * @param {string} packageName The package name to get the CPU information.
305
+ * @param {number} retries The number of retry count.
306
+ * @returns {Array} The array of the parsed CPU upsage percentages.
307
+ * e.g. ['cpuinfo', ['14.3', '28.2']]
308
+ * '14.3' is usage by the user (%), '28.2' is usage by the kernel (%)
309
+ * @throw {Error} If it failed to parse the result of dumpsys, or no package name exists.
310
+ */
218
311
  async function getCPUInfo(packageName, retries = 2) {
219
- return await (0, _asyncbox.retryInterval)(retries, RETRY_PAUSE_MS, async () => {
220
- let output;
221
- try {
222
- output = await this.adb.shell(['dumpsys', 'cpuinfo']);
223
- } catch (e) {
224
- if (e.stderr) {
225
- this.log.info(e.stderr);
226
- }
227
- throw e;
228
- }
229
- const usagesPattern = new RegExp(`^.+\\/${_lodash.default.escapeRegExp(packageName)}:\\D+([\\d.]+)%\\s+user\\s+\\+\\s+([\\d.]+)%\\s+kernel`, 'm');
230
- const match = usagesPattern.exec(output);
231
- if (!match) {
232
- this.log.debug(output);
233
- throw new Error(`Unable to parse cpu usage data for '${packageName}'. Check the server log for more details`);
234
- }
235
- return [CPU_KEYS, [match[1], match[2]]];
236
- });
312
+ // TODO: figure out why this is
313
+ // sometimes, the function of 'adb.shell' fails. when I tested this function on the target of 'Galaxy Note5',
314
+ // adb.shell(dumpsys cpuinfo) returns cpu datas for other application packages, but I can't find the data for packageName.
315
+ // It usually fails 30 times and success for the next time,
316
+ // Since then, he has continued to succeed.
317
+ return await (0, asyncbox_1.retryInterval)(retries, RETRY_PAUSE_MS, async () => {
318
+ let output;
319
+ try {
320
+ output = await this.adb.shell(['dumpsys', 'cpuinfo']);
321
+ }
322
+ catch (e) {
323
+ if (e.stderr) {
324
+ this.log.info(e.stderr);
325
+ }
326
+ throw e;
327
+ }
328
+ // `output` will be something like
329
+ // +0% 2209/io.appium.android.apis: 0.1% user + 0.2% kernel / faults: 70 minor
330
+ const usagesPattern = new RegExp(`^.+\\/${lodash_1.default.escapeRegExp(packageName)}:\\D+([\\d.]+)%\\s+user\\s+\\+\\s+([\\d.]+)%\\s+kernel`, 'm');
331
+ const match = usagesPattern.exec(output);
332
+ if (!match) {
333
+ this.log.debug(output);
334
+ throw new Error(`Unable to parse cpu usage data for '${packageName}'. Check the server log for more details`);
335
+ }
336
+ return [CPU_KEYS, [match[1], match[2]]];
337
+ });
237
338
  }
339
+ exports.getCPUInfo = getCPUInfo;
340
+ /**
341
+ * @this {AndroidDriver}
342
+ * @param {number} retries
343
+ */
238
344
  async function getBatteryInfo(retries = 2) {
239
- return await (0, _asyncbox.retryInterval)(retries, RETRY_PAUSE_MS, async () => {
240
- let cmd = ['dumpsys', 'battery', '|', 'grep', 'level'];
241
- let data = await this.adb.shell(cmd);
242
- if (!data) throw new Error('No data from dumpsys');
243
- let power = parseInt((data.split(':')[1] || '').trim(), 10);
244
- if (!Number.isNaN(power)) {
245
- return [_lodash.default.clone(BATTERY_KEYS), [power.toString()]];
246
- } else {
247
- throw new Error(`Unable to parse battery data: '${data}'`);
248
- }
249
- });
345
+ return await (0, asyncbox_1.retryInterval)(retries, RETRY_PAUSE_MS, async () => {
346
+ let cmd = ['dumpsys', 'battery', '|', 'grep', 'level'];
347
+ let data = await this.adb.shell(cmd);
348
+ if (!data)
349
+ throw new Error('No data from dumpsys'); //eslint-disable-line curly
350
+ let power = parseInt((data.split(':')[1] || '').trim(), 10);
351
+ if (!Number.isNaN(power)) {
352
+ return [lodash_1.default.clone(BATTERY_KEYS), [power.toString()]];
353
+ }
354
+ else {
355
+ throw new Error(`Unable to parse battery data: '${data}'`);
356
+ }
357
+ });
250
358
  }
359
+ exports.getBatteryInfo = getBatteryInfo;
360
+ //
361
+ // returns the information type of the system state which is supported to read as like cpu, memory, network traffic, and battery.
362
+ // output - array like below
363
+ // [cpuinfo, batteryinfo, networkinfo, memoryinfo]
364
+ //
251
365
  commands.getPerformanceDataTypes = function getPerformanceDataTypes() {
252
- return _lodash.default.keys(SUPPORTED_PERFORMANCE_DATA_TYPES);
366
+ return lodash_1.default.keys(SUPPORTED_PERFORMANCE_DATA_TYPES);
253
367
  };
368
+ /**
369
+ * @returns The information type of the system state which is supported to read as like cpu, memory, network traffic, and battery.
370
+ * input - (packageName) the package name of the application
371
+ * (dataType) the type of system state which wants to read. It should be one of the keys of the SUPPORTED_PERFORMANCE_DATA_TYPES
372
+ * (dataReadTimeout) the number of attempts to read
373
+ * output - table of the performance data, The first line of the table represents the type of data. The remaining lines represent the values of the data.
374
+ *
375
+ * in case of battery info : [[power], [23]]
376
+ * in case of memory info : [[totalPrivateDirty, nativePrivateDirty, dalvikPrivateDirty, eglPrivateDirty, glPrivateDirty, totalPss,
377
+ * nativePss, dalvikPss, eglPss, glPss, nativeHeapAllocatedSize, nativeHeapSize], [18360, 8296, 6132, null, null, 42588, 8406, 7024, null, null, 26519, 10344]]
378
+ * in case of network info : [[bucketStart, activeTime, rxBytes, rxPackets, txBytes, txPackets, operations, bucketDuration,],
379
+ * [1478091600000, null, 1099075, 610947, 928, 114362, 769, 0, 3600000], [1478095200000, null, 1306300, 405997, 509, 46359, 370, 0, 3600000]]
380
+ * in case of network info : [[st, activeTime, rb, rp, tb, tp, op, bucketDuration], [1478088000, null, null, 32115296, 34291, 2956805, 25705, 0, 3600],
381
+ * [1478091600, null, null, 2714683, 11821, 1420564, 12650, 0, 3600], [1478095200, null, null, 10079213, 19962, 2487705, 20015, 0, 3600],
382
+ * [1478098800, null, null, 4444433, 10227, 1430356, 10493, 0, 3600]]
383
+ * in case of cpu info : [[user, kernel], [0.9, 1.3]]
384
+ */
254
385
  commands.getPerformanceData = async function getPerformanceData(packageName, dataType, retries = 2) {
255
- switch (_lodash.default.toLower(dataType)) {
256
- case 'batteryinfo':
257
- return await getBatteryInfo.bind(this)(retries);
258
- case 'cpuinfo':
259
- return await getCPUInfo.bind(this)(packageName, retries);
260
- case 'memoryinfo':
261
- return await getMemoryInfo.bind(this)(packageName, retries);
262
- case 'networkinfo':
263
- return await getNetworkTrafficInfo.bind(this)(retries);
264
- default:
265
- throw new Error(`No performance data of type '${dataType}' found. ` + `Only the following values are supported: ${JSON.stringify(SUPPORTED_PERFORMANCE_DATA_TYPES, ' ', 2)}`);
266
- }
386
+ switch (lodash_1.default.toLower(dataType)) {
387
+ case 'batteryinfo':
388
+ return await getBatteryInfo.bind(this)(retries);
389
+ case 'cpuinfo':
390
+ return await getCPUInfo.bind(this)(packageName, retries);
391
+ case 'memoryinfo':
392
+ return await getMemoryInfo.bind(this)(packageName, retries);
393
+ case 'networkinfo':
394
+ return await getNetworkTrafficInfo.bind(this)(retries);
395
+ default:
396
+ throw new Error(`No performance data of type '${dataType}' found. ` +
397
+ `Only the following values are supported: ${JSON.stringify(SUPPORTED_PERFORMANCE_DATA_TYPES, ' ', 2)}`);
398
+ }
267
399
  };
400
+ /**
401
+ * @typedef {Object} PerformanceDataOptions
402
+ * @property {string} packageName The name of the package identifier to fetch the data for
403
+ * @property {'batteryinfo' | 'cpuinfo' | 'memoryinfo' | 'networkinfo'} dataType One of supported subsystem
404
+ * to fetch the data for.
405
+ */
406
+ /**
407
+ * Retrieves performance data about the given Android subsystem.
408
+ * The data is parsed from the output of the dumpsys utility.
409
+ *
410
+ * @param {PerformanceDataOptions} opts
411
+ * @returns {Promise<any[][]>} The output depends on the selected subsystem.
412
+ * It is orginized into a table, where the first row represent column names
413
+ * and the following rows represent the sampled data for each column.
414
+ * Example output for different data types:
415
+ * - batteryinfo: [[power], [23]]
416
+ * - memory info: [[totalPrivateDirty, nativePrivateDirty, dalvikPrivateDirty, eglPrivateDirty, glPrivateDirty, totalPss,
417
+ * nativePss, dalvikPss, eglPss, glPss, nativeHeapAllocatedSize, nativeHeapSize], [18360, 8296, 6132, null, null, 42588, 8406, 7024, null, null, 26519, 10344]]
418
+ * - networkinfo: [[bucketStart, activeTime, rxBytes, rxPackets, txBytes, txPackets, operations, bucketDuration,],
419
+ * [1478091600000, null, 1099075, 610947, 928, 114362, 769, 0, 3600000], [1478095200000, null, 1306300, 405997, 509, 46359, 370, 0, 3600000]]
420
+ *
421
+ * [[st, activeTime, rb, rp, tb, tp, op, bucketDuration], [1478088000, null, null, 32115296, 34291, 2956805, 25705, 0, 3600],
422
+ * [1478091600, null, null, 2714683, 11821, 1420564, 12650, 0, 3600], [1478095200, null, null, 10079213, 19962, 2487705, 20015, 0, 3600],
423
+ * [1478098800, null, null, 4444433, 10227, 1430356, 10493, 0, 3600]]
424
+ * - cpuinfo: [[user, kernel], [0.9, 1.3]]
425
+ */
268
426
  commands.mobileGetPerformanceData = async function mobileGetPerformanceData(opts = {}) {
269
- const {
270
- packageName,
271
- dataType
272
- } = (0, _utils.requireArgs)(['packageName', 'dataType'], opts);
273
- return await this.getPerformanceData(packageName, dataType);
427
+ const { packageName, dataType } = (0, utils_1.requireArgs)(['packageName', 'dataType'], opts);
428
+ return await this.getPerformanceData(packageName, dataType);
274
429
  };
275
- var _default = commands;
276
- exports.default = _default;
277
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9kYXNoIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfYXN5bmNib3giLCJfdXRpbHMiLCJjb21tYW5kcyIsImV4cG9ydHMiLCJORVRXT1JLX0tFWVMiLCJDUFVfS0VZUyIsIkJBVFRFUllfS0VZUyIsIk1FTU9SWV9LRVlTIiwiU1VQUE9SVEVEX1BFUkZPUk1BTkNFX0RBVEFfVFlQRVMiLCJPYmplY3QiLCJmcmVlemUiLCJjcHVpbmZvIiwibWVtb3J5aW5mbyIsImJhdHRlcnlpbmZvIiwibmV0d29ya2luZm8iLCJNRU1JTkZPX1RJVExFUyIsIk5BVElWRSIsIkRBTFZJSyIsIkVHTCIsIkdMIiwiTVRSQUNLIiwiVE9UQUwiLCJIRUFQIiwiUkVUUllfUEFVU0VfTVMiLCJwYXJzZU1lbWluZm9Gb3JBcGkxOVRvMjkiLCJlbnRyaWVzIiwidmFsRGljdCIsInR5cGUiLCJzdWJUeXBlIiwibmF0aXZlUHNzIiwibmF0aXZlUHJpdmF0ZURpcnR5IiwibmF0aXZlSGVhcFNpemUiLCJuYXRpdmVIZWFwQWxsb2NhdGVkU2l6ZSIsImRhbHZpa1BzcyIsImRhbHZpa1ByaXZhdGVEaXJ0eSIsImVnbFBzcyIsImVnbFByaXZhdGVEaXJ0eSIsImdsUHNzIiwiZ2xQcml2YXRlRGlydHkiLCJsZW5ndGgiLCJ0b3RhbFBzcyIsInRvdGFsUHJpdmF0ZURpcnR5IiwicGFyc2VNZW1pbmZvRm9yQXBpQmVsb3cxOSIsInBhcnNlTWVtaW5mb0ZvckFwaUFib3ZlMjkiLCJuYXRpdmVSc3MiLCJkYWx2aWtSc3MiLCJ0b3RhbFJzcyIsImdldE1lbW9yeUluZm8iLCJwYWNrYWdlTmFtZSIsInJldHJpZXMiLCJyZXRyeUludGVydmFsIiwiY21kIiwiZGF0YSIsImFkYiIsInNoZWxsIiwiRXJyb3IiLCJhcGlMZXZlbCIsImdldEFwaUxldmVsIiwibGluZSIsInNwbGl0IiwidHJpbSIsImZpbHRlciIsIkJvb2xlYW4iLCJoZWFkZXJzIiwiXyIsImNsb25lIiwidmFsdWVzIiwibWFwIiwiaGVhZGVyIiwiZ2V0TmV0d29ya1RyYWZmaWNJbmZvIiwicmV0dXJuVmFsdWUiLCJidWNrZXREdXJhdGlvbiIsImJ1Y2tldFN0YXJ0IiwiYWN0aXZlVGltZSIsInJ4Qnl0ZXMiLCJyeFBhY2tldHMiLCJ0eEJ5dGVzIiwidHhQYWNrZXRzIiwib3BlcmF0aW9ucyIsImluZGV4IiwiZnJvbVh0c3RhdHMiLCJpbmRleE9mIiwic3RhcnQiLCJkZWxpbWl0ZXIiLCJlbmQiLCJwZW5kaW5nQnl0ZXMiLCJzdWJzdHJpbmciLCJhcnJheUxpc3QiLCJqIiwiayIsInJldHVybkluZGV4IiwiaSIsImlzRXF1YWwiLCJpc1VuZGVmaW5lZCIsImdldENQVUluZm8iLCJvdXRwdXQiLCJlIiwic3RkZXJyIiwibG9nIiwiaW5mbyIsInVzYWdlc1BhdHRlcm4iLCJSZWdFeHAiLCJlc2NhcGVSZWdFeHAiLCJtYXRjaCIsImV4ZWMiLCJkZWJ1ZyIsImdldEJhdHRlcnlJbmZvIiwicG93ZXIiLCJwYXJzZUludCIsIk51bWJlciIsImlzTmFOIiwidG9TdHJpbmciLCJnZXRQZXJmb3JtYW5jZURhdGFUeXBlcyIsImtleXMiLCJnZXRQZXJmb3JtYW5jZURhdGEiLCJkYXRhVHlwZSIsInRvTG93ZXIiLCJiaW5kIiwiSlNPTiIsInN0cmluZ2lmeSIsIm1vYmlsZUdldFBlcmZvcm1hbmNlRGF0YSIsIm9wdHMiLCJyZXF1aXJlQXJncyIsIl9kZWZhdWx0IiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2xpYi9jb21tYW5kcy9wZXJmb3JtYW5jZS5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHsgcmV0cnlJbnRlcnZhbCB9IGZyb20gJ2FzeW5jYm94JztcbmltcG9ydCB7IHJlcXVpcmVBcmdzIH0gZnJvbSAnLi4vdXRpbHMnO1xuXG5jb25zdCBjb21tYW5kcyA9IHt9O1xuXG5jb25zdCBORVRXT1JLX0tFWVMgPSBbXG4gIFsnYnVja2V0U3RhcnQnLCAnYWN0aXZlVGltZScsICdyeEJ5dGVzJywgJ3J4UGFja2V0cycsICd0eEJ5dGVzJywgJ3R4UGFja2V0cycsICdvcGVyYXRpb25zJywgJ2J1Y2tldER1cmF0aW9uJ10sXG4gIFsnc3QnLCAnYWN0aXZlVGltZScsICdyYicsICdycCcsICd0YicsICd0cCcsICdvcCcsICdidWNrZXREdXJhdGlvbiddXG5dO1xuY29uc3QgQ1BVX0tFWVMgPSBbJ3VzZXInLCAna2VybmVsJ107XG5jb25zdCBCQVRURVJZX0tFWVMgPSBbJ3Bvd2VyJ107XG5jb25zdCBNRU1PUllfS0VZUyA9IFtcbiAgJ3RvdGFsUHJpdmF0ZURpcnR5JywgJ25hdGl2ZVByaXZhdGVEaXJ0eScsICdkYWx2aWtQcml2YXRlRGlydHknLFxuICAnZWdsUHJpdmF0ZURpcnR5JywgJ2dsUHJpdmF0ZURpcnR5JyxcbiAgJ3RvdGFsUHNzJywgJ25hdGl2ZVBzcycsICdkYWx2aWtQc3MnLCAnZWdsUHNzJywgJ2dsUHNzJyxcbiAgJ25hdGl2ZUhlYXBBbGxvY2F0ZWRTaXplJywgJ25hdGl2ZUhlYXBTaXplJyxcbiAgJ25hdGl2ZVJzcycsICdkYWx2aWtSc3MnLCAndG90YWxSc3MnXG5dO1xuY29uc3QgU1VQUE9SVEVEX1BFUkZPUk1BTkNFX0RBVEFfVFlQRVMgPSBPYmplY3QuZnJlZXplKHtcbiAgY3B1aW5mbzogJ3RoZSBhbW91bnQgb2YgY3B1IGJ5IHVzZXIgYW5kIGtlcm5lbCBwcm9jZXNzIC0gY3B1IGluZm9ybWF0aW9uIGZvciBhcHBsaWNhdGlvbnMgb24gcmVhbCBkZXZpY2VzIGFuZCBzaW11bGF0b3JzJyxcbiAgbWVtb3J5aW5mbzogJ3RoZSBhbW91bnQgb2YgbWVtb3J5IHVzZWQgYnkgdGhlIHByb2Nlc3MgLSBtZW1vcnkgaW5mb3JtYXRpb24gZm9yIGFwcGxpY2F0aW9ucyBvbiByZWFsIGRldmljZXMgYW5kIHNpbXVsYXRvcnMnLFxuICBiYXR0ZXJ5aW5mbzogJ3RoZSByZW1haW5pbmcgYmF0dGVyeSBwb3dlciAtIGJhdHRlcnkgcG93ZXIgaW5mb3JtYXRpb24gZm9yIGFwcGxpY2F0aW9ucyBvbiByZWFsIGRldmljZXMgYW5kIHNpbXVsYXRvcnMnLFxuICBuZXR3b3JraW5mbzogJ3RoZSBuZXR3b3JrIHN0YXRpc3RpY3MgLSBuZXR3b3JrIHJ4L3R4IGluZm9ybWF0aW9uIGZvciBhcHBsaWNhdGlvbnMgb24gcmVhbCBkZXZpY2VzIGFuZCBzaW11bGF0b3JzJ1xufSk7XG5jb25zdCBNRU1JTkZPX1RJVExFUyA9IE9iamVjdC5mcmVlemUoe1xuICBOQVRJVkU6ICdOYXRpdmUnLFxuICBEQUxWSUs6ICdEYWx2aWsnLFxuICBFR0w6ICdFR0wnLFxuICBHTDogJ0dMJyxcbiAgTVRSQUNLOiAnbXRyYWNrJyxcbiAgVE9UQUw6ICdUT1RBTCcsXG4gIEhFQVA6ICdIZWFwJ1xufSk7XG5jb25zdCBSRVRSWV9QQVVTRV9NUyA9IDEwMDA7XG5cbi8qKlxuICogQVBJIGxldmVsIGJldHdlZW4gMTggYW5kIDMwXG4gKiBbJzxTeXN0ZW0gVHlwZT4nLCAnPE1lbW9yeSBUeXBlPicsIDxwc3MgdG90YWw+LCA8cHJpdmF0ZSBkaXJ0eT4sIDxwcml2YXRlIGNsZWFuPiwgPHN3YXBQc3MgZGlydHk+LCA8aGVhcCBzaXplPiwgPGhlYXAgYWxsb2M+LCA8aGVhcCBmcmVlPl1cbiAqIGV4Y2VwdCAnVE9UQUwnLCB3aGljaCBza2lwcyB0aGUgc2Vjb25kIHR5cGUgbmFtZVxuICogISEhIHZhbERpY3QgZ2V0cyBtdXRhdGVkXG4gKi9cbmZ1bmN0aW9uIHBhcnNlTWVtaW5mb0ZvckFwaTE5VG8yOSAoZW50cmllcywgdmFsRGljdCkge1xuICBjb25zdCBbdHlwZSwgc3ViVHlwZV0gPSBlbnRyaWVzO1xuICBpZiAodHlwZSA9PT0gTUVNSU5GT19USVRMRVMuTkFUSVZFICYmIHN1YlR5cGUgPT09IE1FTUlORk9fVElUTEVTLkhFQVApIHtcbiAgICBbLCwgdmFsRGljdC5uYXRpdmVQc3MsIHZhbERpY3QubmF0aXZlUHJpdmF0ZURpcnR5LCwsIHZhbERpY3QubmF0aXZlSGVhcFNpemUsIHZhbERpY3QubmF0aXZlSGVhcEFsbG9jYXRlZFNpemVdID0gZW50cmllcztcbiAgfSBlbHNlIGlmICh0eXBlID09PSBNRU1JTkZPX1RJVExFUy5EQUxWSUsgJiYgc3ViVHlwZSA9PT0gTUVNSU5GT19USVRMRVMuSEVBUCkge1xuICAgIFssLCB2YWxEaWN0LmRhbHZpa1BzcywgdmFsRGljdC5kYWx2aWtQcml2YXRlRGlydHldID0gZW50cmllcztcbiAgfSBlbHNlIGlmICh0eXBlID09PSBNRU1JTkZPX1RJVExFUy5FR0wgJiYgc3ViVHlwZSA9PT0gTUVNSU5GT19USVRMRVMuTVRSQUNLKSB7XG4gICAgWywsIHZhbERpY3QuZWdsUHNzLCB2YWxEaWN0LmVnbFByaXZhdGVEaXJ0eV0gPSBlbnRyaWVzO1xuICB9IGVsc2UgaWYgKHR5cGUgPT09IE1FTUlORk9fVElUTEVTLkdMICYmIHN1YlR5cGUgPT09IE1FTUlORk9fVElUTEVTLk1UUkFDSykge1xuICAgIFssLCB2YWxEaWN0LmdsUHNzLCB2YWxEaWN0LmdsUHJpdmF0ZURpcnR5XSA9IGVudHJpZXM7XG4gIH0gZWxzZSBpZiAodHlwZSA9PT0gTUVNSU5GT19USVRMRVMuVE9UQUwgJiYgZW50cmllcy5sZW5ndGggPT09IDgpIHtcbiAgICAvLyB0aGVyZSBhcmUgdHdvIHRvdGFscywgYW5kIHdlIG9ubHkgd2FudCB0aGUgZnVsbCBsaXN0aW5nLCB3aGljaCBoYXMgOCBlbnRyaWVzXG4gICAgWywgdmFsRGljdC50b3RhbFBzcywgdmFsRGljdC50b3RhbFByaXZhdGVEaXJ0eV0gPSBlbnRyaWVzO1xuICB9XG59XG5cbi8qKlxuICogWyc8U3lzdGVtIFR5cGUnLCAnPHBwcz4nLCAnPHNoYXJlZCBkaXJ0eT4nLCAnPHByaXZhdGUgZGlydHk+JywgJzxoZWFwIHNpemU+JywgJzxoZWFwIGFsbG9jPicsICc8aGVhcCBmcmVlPiddXG4gKiAhISEgdmFsRGljdCBnZXRzIG11dGF0ZWRcbiAqL1xuZnVuY3Rpb24gcGFyc2VNZW1pbmZvRm9yQXBpQmVsb3cxOSAoZW50cmllcywgdmFsRGljdCkge1xuICBjb25zdCB0eXBlID0gZW50cmllc1swXTtcbiAgaWYgKHR5cGUgPT09IE1FTUlORk9fVElUTEVTLk5BVElWRSkge1xuICAgIFssIHZhbERpY3QubmF0aXZlUHNzLCwgdmFsRGljdC5uYXRpdmVQcml2YXRlRGlydHksIHZhbERpY3QubmF0aXZlSGVhcFNpemUsIHZhbERpY3QubmF0aXZlSGVhcEFsbG9jYXRlZFNpemVdID0gZW50cmllcztcbiAgfSBlbHNlIGlmICh0eXBlID09PSBNRU1JTkZPX1RJVExFUy5EQUxWSUspIHtcbiAgICBbLCB2YWxEaWN0LmRhbHZpa1BzcywsIHZhbERpY3QuZGFsdmlrUHJpdmF0ZURpcnR5XSA9IGVudHJpZXM7XG4gIH0gZWxzZSBpZiAodHlwZSA9PT0gTUVNSU5GT19USVRMRVMuRUdMKSB7XG4gICAgWywgdmFsRGljdC5lZ2xQc3MsLCB2YWxEaWN0LmVnbFByaXZhdGVEaXJ0eV0gPSBlbnRyaWVzO1xuICB9IGVsc2UgaWYgKHR5cGUgPT09IE1FTUlORk9fVElUTEVTLkdMKSB7XG4gICAgWywgdmFsRGljdC5nbFBzcywsIHZhbERpY3QuZ2xQcml2YXRlRGlydHldID0gZW50cmllcztcbiAgfSBlbHNlIGlmICh0eXBlID09PSBNRU1JTkZPX1RJVExFUy5UT1RBTCkge1xuICAgIFssIHZhbERpY3QudG90YWxQc3MsLCB2YWxEaWN0LnRvdGFsUHJpdmF0ZURpcnR5XSA9IGVudHJpZXM7XG4gIH1cbn1cblxuLyoqXG4gKiBBUEkgbGV2ZWwgMzAgYW5kIGFib3ZlXG4gKiBbJzxTeXN0ZW0gVHlwZT4nLCAnPE1lbW9yeSBUeXBlPicsIDxwc3MgdG90YWw+LCA8cHJpdmF0ZSBkaXJ0eT4sIDxwcml2YXRlIGNsZWFuPiwgPHN3YXBQc3MgZGlydHk+LCA8cnNzIHRvdGFsPiwgPGhlYXAgc2l6ZT4sIDxoZWFwIGFsbG9jPiwgPGhlYXAgZnJlZT5dXG4gKiAhISEgdmFsRGljdCBnZXRzIG11dGF0ZWRcbiAqL1xuZnVuY3Rpb24gcGFyc2VNZW1pbmZvRm9yQXBpQWJvdmUyOSAoZW50cmllcywgdmFsRGljdCkge1xuICBjb25zdCBbdHlwZSwgc3ViVHlwZV0gPSBlbnRyaWVzO1xuICBpZiAodHlwZSA9PT0gTUVNSU5GT19USVRMRVMuTkFUSVZFICYmIHN1YlR5cGUgPT09IE1FTUlORk9fVElUTEVTLkhFQVApIHtcbiAgICBbLCwgdmFsRGljdC5uYXRpdmVQc3MsIHZhbERpY3QubmF0aXZlUHJpdmF0ZURpcnR5LCwsIHZhbERpY3QubmF0aXZlUnNzLCB2YWxEaWN0Lm5hdGl2ZUhlYXBTaXplLCB2YWxEaWN0Lm5hdGl2ZUhlYXBBbGxvY2F0ZWRTaXplXSA9IGVudHJpZXM7XG4gIH0gZWxzZSBpZiAodHlwZSA9PT0gTUVNSU5GT19USVRMRVMuREFMVklLICYmIHN1YlR5cGUgPT09IE1FTUlORk9fVElUTEVTLkhFQVApIHtcbiAgICBbLCwgdmFsRGljdC5kYWx2aWtQc3MsIHZhbERpY3QuZGFsdmlrUHJpdmF0ZURpcnR5LCwsIHZhbERpY3QuZGFsdmlrUnNzXSA9IGVudHJpZXM7XG4gIH0gZWxzZSBpZiAodHlwZSA9PT0gTUVNSU5GT19USVRMRVMuRUdMICYmIHN1YlR5cGUgPT09IE1FTUlORk9fVElUTEVTLk1UUkFDSykge1xuICAgIFssLCB2YWxEaWN0LmVnbFBzcywgdmFsRGljdC5lZ2xQcml2YXRlRGlydHldID0gZW50cmllcztcbiAgfSBlbHNlIGlmICh0eXBlID09PSBNRU1JTkZPX1RJVExFUy5HTCAmJiBzdWJUeXBlID09PSBNRU1JTkZPX1RJVExFUy5NVFJBQ0spIHtcbiAgICBbLCwgdmFsRGljdC5nbFBzcywgdmFsRGljdC5nbFByaXZhdGVEaXJ0eV0gPSBlbnRyaWVzO1xuICB9IGVsc2UgaWYgKHR5cGUgPT09IE1FTUlORk9fVElUTEVTLlRPVEFMICYmIGVudHJpZXMubGVuZ3RoID09PSA5KSB7XG4gICAgLy8gaGFzIDkgZW50cmllc1xuICAgIFssIHZhbERpY3QudG90YWxQc3MsIHZhbERpY3QudG90YWxQcml2YXRlRGlydHksLCwgdmFsRGljdC50b3RhbFJzc10gPSBlbnRyaWVzO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldE1lbW9yeUluZm8gKHBhY2thZ2VOYW1lLCByZXRyaWVzID0gMikge1xuICByZXR1cm4gYXdhaXQgcmV0cnlJbnRlcnZhbChyZXRyaWVzLCBSRVRSWV9QQVVTRV9NUywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGNtZCA9IFtcbiAgICAgICdkdW1wc3lzJywgJ21lbWluZm8nLCBgJyR7cGFja2FnZU5hbWV9J2AsXG4gICAgICAnfCcsICdncmVwJywgJy1FJyxcbiAgICAgIGAnJHtNRU1JTkZPX1RJVExFUy5OQVRJVkV9fCR7TUVNSU5GT19USVRMRVMuREFMVklLfXwke01FTUlORk9fVElUTEVTLkVHTH1gICtcbiAgICAgIGB8JHtNRU1JTkZPX1RJVExFUy5HTH18JHtNRU1JTkZPX1RJVExFUy5UT1RBTH0nYFxuICAgIF07XG4gICAgY29uc3QgZGF0YSA9IGF3YWl0IHRoaXMuYWRiLnNoZWxsKGNtZCk7XG4gICAgaWYgKCFkYXRhKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGRhdGEgZnJvbSBkdW1wc3lzJyk7XG4gICAgfVxuICAgIGNvbnN0IHZhbERpY3QgPSB7dG90YWxQcml2YXRlRGlydHk6ICcnfTtcbiAgICBjb25zdCBhcGlMZXZlbCA9IGF3YWl0IHRoaXMuYWRiLmdldEFwaUxldmVsKCk7XG4gICAgZm9yIChjb25zdCBsaW5lIG9mIGRhdGEuc3BsaXQoJ1xcbicpKSB7XG4gICAgICBjb25zdCBlbnRyaWVzID0gbGluZS50cmltKCkuc3BsaXQoL1xccysvKS5maWx0ZXIoQm9vbGVhbik7XG4gICAgICBpZiAoYXBpTGV2ZWwgPj0gMzApIHtcbiAgICAgICAgcGFyc2VNZW1pbmZvRm9yQXBpQWJvdmUyOShlbnRyaWVzLCB2YWxEaWN0KTtcbiAgICAgIH0gZWxzZSBpZiAoYXBpTGV2ZWwgPiAxOCAmJiBhcGlMZXZlbCA8IDMwKSB7XG4gICAgICAgIHBhcnNlTWVtaW5mb0ZvckFwaTE5VG8yOShlbnRyaWVzLCB2YWxEaWN0KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBhcnNlTWVtaW5mb0ZvckFwaUJlbG93MTkoZW50cmllcywgdmFsRGljdCk7XG4gICAgICB9XG4gICAgfVxuICAgIGlmICh2YWxEaWN0LnRvdGFsUHJpdmF0ZURpcnR5ICYmIHZhbERpY3QudG90YWxQcml2YXRlRGlydHkgIT09ICdub2RleCcpIHtcbiAgICAgIGNvbnN0IGhlYWRlcnMgPSBfLmNsb25lKE1FTU9SWV9LRVlTKTtcbiAgICAgIGNvbnN0IHZhbHVlcyA9IGhlYWRlcnMubWFwKChoZWFkZXIpID0+IHZhbERpY3RbaGVhZGVyXSk7XG4gICAgICByZXR1cm4gW2hlYWRlcnMsIHZhbHVlc107XG4gICAgfVxuXG4gICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gcGFyc2UgbWVtb3J5IGRhdGE6ICcke2RhdGF9J2ApO1xuICB9KTtcbn07XG5cbi8qKlxuICogQHRoaXMge0FuZHJvaWREcml2ZXJ9XG4gKiBAcGFyYW0ge251bWJlcn0gcmV0cmllc1xuICovXG5hc3luYyBmdW5jdGlvbiBnZXROZXR3b3JrVHJhZmZpY0luZm8gKHJldHJpZXMgPSAyKSB7XG4gIHJldHVybiBhd2FpdCByZXRyeUludGVydmFsKHJldHJpZXMsIFJFVFJZX1BBVVNFX01TLCBhc3luYyAoKSA9PiB7XG4gICAgbGV0IHJldHVyblZhbHVlID0gW107XG4gICAgbGV0IGJ1Y2tldER1cmF0aW9uLCBidWNrZXRTdGFydCwgYWN0aXZlVGltZSwgcnhCeXRlcywgcnhQYWNrZXRzLCB0eEJ5dGVzLCB0eFBhY2tldHMsIG9wZXJhdGlvbnM7XG5cbiAgICBsZXQgY21kID0gWydkdW1wc3lzJywgJ25ldHN0YXRzJ107XG4gICAgbGV0IGRhdGEgPSBhd2FpdCB0aGlzLmFkYi5zaGVsbChjbWQpO1xuICAgIGlmICghZGF0YSkgdGhyb3cgbmV3IEVycm9yKCdObyBkYXRhIGZyb20gZHVtcHN5cycpOyAvL2VzbGludC1kaXNhYmxlLWxpbmUgY3VybHlcblxuICAgIC8vIEluIGNhc2Ugb2YgbmV0d29yayB0cmFmZmljIGluZm9ybWF0aW9uLCBpdCBpcyBkaWZmZXJlbnQgZm9yIHRoZSByZXR1cm4gZGF0YSBiZXR3ZWVuIGVtdWxhdG9yIGFuZCByZWFsIGRldmljZS5cbiAgICAvLyB0aGUgcmV0dXJuIGRhdGEgb2YgZW11bGF0b3JcbiAgICAvLyAgIFh0IHN0YXRzOlxuICAgIC8vICAgUGVuZGluZyBieXRlczogMzkyNTBcbiAgICAvLyAgIEhpc3Rvcnkgc2luY2UgYm9vdDpcbiAgICAvLyAgIGlkZW50PVtbdHlwZT1XSUZJLCBzdWJUeXBlPUNPTUJJTkVELCBuZXR3b3JrSWQ9XCJXaXJlZFNTSURcIl1dIHVpZD0tMSBzZXQ9QUxMIHRhZz0weDBcbiAgICAvLyAgIE5ldHdvcmtTdGF0c0hpc3Rvcnk6IGJ1Y2tldER1cmF0aW9uPTM2MDAwMDBcbiAgICAvLyAgIGJ1Y2tldFN0YXJ0PTE0NzgwOTg4MDAwMDAgYWN0aXZlVGltZT0zMTgyNCByeEJ5dGVzPTIxNTAyIHJ4UGFja2V0cz03OCB0eEJ5dGVzPTE3NzQ4IHR4UGFja2V0cz05MCBvcGVyYXRpb25zPTBcbiAgICAvL1xuICAgIC8vIDcuMVxuICAgIC8vICAgWHQgc3RhdHM6XG4gICAgLy8gICBQZW5kaW5nIGJ5dGVzOiA0ODE0ODdcbiAgICAvLyAgIEhpc3Rvcnkgc2luY2UgYm9vdDpcbiAgICAvLyAgIGlkZW50PVt7dHlwZT1NT0JJTEUsIHN1YlR5cGU9Q09NQklORUQsIHN1YnNjcmliZXJJZD0zMTAyNjAuLi4sIG1ldGVyZWQ9dHJ1ZX1dIHVpZD0tMSBzZXQ9QUxMIHRhZz0weDBcbiAgICAvLyAgICAgTmV0d29ya1N0YXRzSGlzdG9yeTogYnVja2V0RHVyYXRpb249MzYwMFxuICAgIC8vICAgICAgIHN0PTE0ODM5ODQ4MDAgcmI9MCBycD0wIHRiPTEyMDMxIHRwPTE4NCBvcD0wXG4gICAgLy8gICAgICAgc3Q9MTQ4Mzk4ODQwMCByYj0wIHJwPTAgdGI9Mzg0NzYgdHA9NTg3IG9wPTBcbiAgICAvLyAgICAgICBzdD0xNDgzOTk5MjAwIHJiPTMxNTYxNiBycD00MDAgdGI9OTQ4MDAgdHA9MzYyIG9wPTBcbiAgICAvLyAgICAgICBzdD0xNDg0MDAyODAwIHJiPTE1ODI2IHJwPTIwIHRiPTQ3MzggdHA9MTYgb3A9MFxuICAgIC8vXG4gICAgLy8gdGhlIHJldHVybiBkYXRhIG9mIHJlYWwgZGV2aWNlXG4gICAgLy8gICBYdCBzdGF0czpcbiAgICAvLyAgIFBlbmRpbmcgYnl0ZXM6IDBcbiAgICAvLyAgIEhpc3Rvcnkgc2luY2UgYm9vdDpcbiAgICAvLyAgIGlkZW50PVt7dHlwZT1NT0JJTEUsIHN1YlR5cGU9Q09NQklORUQsIHN1YnNjcmliZXJJZD00NTAwNTAuLi59XSB1aWQ9LTEgc2V0PUFMTCB0YWc9MHgwXG4gICAgLy8gICBOZXR3b3JrU3RhdHNIaXN0b3J5OiBidWNrZXREdXJhdGlvbj0zNjAwXG4gICAgLy8gICBzdD0xNDc4MDg4MDAwIHJiPTMyMTE1Mjk2IHJwPTM0MjkxIHRiPTI5NTY4MDUgdHA9MjU3MDUgb3A9MFxuICAgIC8vICAgc3Q9MTQ3ODA5MTYwMCByYj0yNzE0NjgzIHJwPTExODIxIHRiPTE0MjA1NjQgdHA9MTI2NTAgb3A9MFxuICAgIC8vICAgc3Q9MTQ3ODA5NTIwMCByYj0xMDA3OTIxMyBycD0xOTk2MiB0Yj0yNDg3NzA1IHRwPTIwMDE1IG9wPTBcbiAgICAvLyAgIHN0PTE0NzgwOTg4MDAgcmI9NDQ0NDQzMyBycD0xMDIyNyB0Yj0xNDMwMzU2IHRwPTEwNDkzIG9wPTBcbiAgICBsZXQgaW5kZXggPSAwO1xuICAgIGxldCBmcm9tWHRzdGF0cyA9IGRhdGEuaW5kZXhPZignWHQgc3RhdHM6Jyk7XG5cbiAgICBsZXQgc3RhcnQgPSBkYXRhLmluZGV4T2YoJ1BlbmRpbmcgYnl0ZXM6JywgZnJvbVh0c3RhdHMpO1xuICAgIGxldCBkZWxpbWl0ZXIgPSBkYXRhLmluZGV4T2YoJzonLCBzdGFydCArIDEpO1xuICAgIGxldCBlbmQgPSBkYXRhLmluZGV4T2YoJ1xcbicsIGRlbGltaXRlciArIDEpO1xuICAgIGxldCBwZW5kaW5nQnl0ZXMgPSBkYXRhLnN1YnN0cmluZyhkZWxpbWl0ZXIgKyAxLCBlbmQpLnRyaW0oKTtcblxuICAgIGlmIChlbmQgPiBkZWxpbWl0ZXIpIHtcbiAgICAgIHN0YXJ0ID0gZGF0YS5pbmRleE9mKCdidWNrZXREdXJhdGlvbicsIGVuZCArIDEpO1xuICAgICAgZGVsaW1pdGVyID0gZGF0YS5pbmRleE9mKCc9Jywgc3RhcnQgKyAxKTtcbiAgICAgIGVuZCA9IGRhdGEuaW5kZXhPZignXFxuJywgZGVsaW1pdGVyICsgMSk7XG4gICAgICBidWNrZXREdXJhdGlvbiA9IGRhdGEuc3Vic3RyaW5nKGRlbGltaXRlciArIDEsIGVuZCkudHJpbSgpO1xuICAgIH1cblxuICAgIGlmIChzdGFydCA+PSAwKSB7XG4gICAgICBkYXRhID0gZGF0YS5zdWJzdHJpbmcoZW5kICsgMSwgZGF0YS5sZW5ndGgpO1xuICAgICAgbGV0IGFycmF5TGlzdCA9IGRhdGEuc3BsaXQoJ1xcbicpO1xuXG4gICAgICBpZiAoYXJyYXlMaXN0Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgc3RhcnQgPSAtMTtcblxuICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IE5FVFdPUktfS0VZUy5sZW5ndGg7ICsraikge1xuICAgICAgICAgIHN0YXJ0ID0gYXJyYXlMaXN0WzBdLmluZGV4T2YoTkVUV09SS19LRVlTW2pdWzBdKTtcblxuICAgICAgICAgIGlmIChzdGFydCA+PSAwKSB7XG4gICAgICAgICAgICBpbmRleCA9IGo7XG4gICAgICAgICAgICByZXR1cm5WYWx1ZVswXSA9IFtdO1xuXG4gICAgICAgICAgICBmb3IgKGxldCBrID0gMDsgayA8IE5FVFdPUktfS0VZU1tqXS5sZW5ndGg7ICsraykge1xuICAgICAgICAgICAgICByZXR1cm5WYWx1ZVswXVtrXSA9IE5FVFdPUktfS0VZU1tqXVtrXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGxldCByZXR1cm5JbmRleCA9IDE7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYXJyYXlMaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgZGF0YSA9IGFycmF5TGlzdFtpXTtcbiAgICAgICAgICBzdGFydCA9IGRhdGEuaW5kZXhPZihORVRXT1JLX0tFWVNbaW5kZXhdWzBdKTtcblxuICAgICAgICAgIGlmIChzdGFydCA+PSAwKSB7XG4gICAgICAgICAgICBkZWxpbWl0ZXIgPSBkYXRhLmluZGV4T2YoJz0nLCBzdGFydCArIDEpO1xuICAgICAgICAgICAgZW5kID0gZGF0YS5pbmRleE9mKCcgJywgZGVsaW1pdGVyICsgMSk7XG4gICAgICAgICAgICBidWNrZXRTdGFydCA9IGRhdGEuc3Vic3RyaW5nKGRlbGltaXRlciArIDEsIGVuZCkudHJpbSgpO1xuXG4gICAgICAgICAgICBpZiAoZW5kID4gZGVsaW1pdGVyKSB7XG4gICAgICAgICAgICAgIHN0YXJ0ID0gZGF0YS5pbmRleE9mKE5FVFdPUktfS0VZU1tpbmRleF1bMV0sIGVuZCArIDEpO1xuICAgICAgICAgICAgICBpZiAoc3RhcnQgPj0gMCkge1xuICAgICAgICAgICAgICAgIGRlbGltaXRlciA9IGRhdGEuaW5kZXhPZignPScsIHN0YXJ0ICsgMSk7XG4gICAgICAgICAgICAgICAgZW5kID0gZGF0YS5pbmRleE9mKCcgJywgZGVsaW1pdGVyICsgMSk7XG4gICAgICAgICAgICAgICAgYWN0aXZlVGltZSA9IGRhdGEuc3Vic3RyaW5nKGRlbGltaXRlciArIDEsIGVuZCkudHJpbSgpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChlbmQgPiBkZWxpbWl0ZXIpIHtcbiAgICAgICAgICAgICAgc3RhcnQgPSBkYXRhLmluZGV4T2YoTkVUV09SS19LRVlTW2luZGV4XVsyXSwgZW5kICsgMSk7XG4gICAgICAgICAgICAgIGlmIChzdGFydCA+PSAwKSB7XG4gICAgICAgICAgICAgICAgZGVsaW1pdGVyID0gZGF0YS5pbmRleE9mKCc9Jywgc3RhcnQgKyAxKTtcbiAgICAgICAgICAgICAgICBlbmQgPSBkYXRhLmluZGV4T2YoJyAnLCBkZWxpbWl0ZXIgKyAxKTtcbiAgICAgICAgICAgICAgICByeEJ5dGVzID0gZGF0YS5zdWJzdHJpbmcoZGVsaW1pdGVyICsgMSwgZW5kKS50cmltKCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGVuZCA+IGRlbGltaXRlcikge1xuICAgICAgICAgICAgICBzdGFydCA9IGRhdGEuaW5kZXhPZihORVRXT1JLX0tFWVNbaW5kZXhdWzNdLCBlbmQgKyAxKTtcbiAgICAgICAgICAgICAgaWYgKHN0YXJ0ID49IDApIHtcbiAgICAgICAgICAgICAgICBkZWxpbWl0ZXIgPSBkYXRhLmluZGV4T2YoJz0nLCBzdGFydCArIDEpO1xuICAgICAgICAgICAgICAgIGVuZCA9IGRhdGEuaW5kZXhPZignICcsIGRlbGltaXRlciArIDEpO1xuICAgICAgICAgICAgICAgIHJ4UGFja2V0cyA9IGRhdGEuc3Vic3RyaW5nKGRlbGltaXRlciArIDEsIGVuZCkudHJpbSgpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChlbmQgPiBkZWxpbWl0ZXIpIHtcbiAgICAgICAgICAgICAgc3RhcnQgPSBkYXRhLmluZGV4T2YoTkVUV09SS19LRVlTW2luZGV4XVs0XSwgZW5kICsgMSk7XG4gICAgICAgICAgICAgIGlmIChzdGFydCA+PSAwKSB7XG4gICAgICAgICAgICAgICAgZGVsaW1pdGVyID0gZGF0YS5pbmRleE9mKCc9Jywgc3RhcnQgKyAxKTtcbiAgICAgICAgICAgICAgICBlbmQgPSBkYXRhLmluZGV4T2YoJyAnLCBkZWxpbWl0ZXIgKyAxKTtcbiAgICAgICAgICAgICAgICB0eEJ5dGVzID0gZGF0YS5zdWJzdHJpbmcoZGVsaW1pdGVyICsgMSwgZW5kKS50cmltKCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGVuZCA+IGRlbGltaXRlcikge1xuICAgICAgICAgICAgICBzdGFydCA9IGRhdGEuaW5kZXhPZihORVRXT1JLX0tFWVNbaW5kZXhdWzVdLCBlbmQgKyAxKTtcbiAgICAgICAgICAgICAgaWYgKHN0YXJ0ID49IDApIHtcbiAgICAgICAgICAgICAgICBkZWxpbWl0ZXIgPSBkYXRhLmluZGV4T2YoJz0nLCBzdGFydCArIDEpO1xuICAgICAgICAgICAgICAgIGVuZCA9IGRhdGEuaW5kZXhPZignICcsIGRlbGltaXRlciArIDEpO1xuICAgICAgICAgICAgICAgIHR4UGFja2V0cyA9IGRhdGEuc3Vic3RyaW5nKGRlbGltaXRlciArIDEsIGVuZCkudHJpbSgpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChlbmQgPiBkZWxpbWl0ZXIpIHtcbiAgICAgICAgICAgICAgc3RhcnQgPSBkYXRhLmluZGV4T2YoTkVUV09SS19LRVlTW2luZGV4XVs2XSwgZW5kICsgMSk7XG4gICAgICAgICAgICAgIGlmIChzdGFydCA+PSAwKSB7XG4gICAgICAgICAgICAgICAgZGVsaW1pdGVyID0gZGF0YS5pbmRleE9mKCc9Jywgc3RhcnQgKyAxKTtcbiAgICAgICAgICAgICAgICBlbmQgPSBkYXRhLmxlbmd0aDtcbiAgICAgICAgICAgICAgICBvcGVyYXRpb25zID0gZGF0YS5zdWJzdHJpbmcoZGVsaW1pdGVyICsgMSwgZW5kKS50cmltKCk7XG5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuVmFsdWVbcmV0dXJuSW5kZXgrK10gPSBbYnVja2V0U3RhcnQsIGFjdGl2ZVRpbWUsIHJ4Qnl0ZXMsIHJ4UGFja2V0cywgdHhCeXRlcywgdHhQYWNrZXRzLCBvcGVyYXRpb25zLCBidWNrZXREdXJhdGlvbl07XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKCFfLmlzRXF1YWwocGVuZGluZ0J5dGVzLCAnJykgJiYgIV8uaXNVbmRlZmluZWQocGVuZGluZ0J5dGVzKSAmJiAhXy5pc0VxdWFsKHBlbmRpbmdCeXRlcywgJ25vZGV4JykpIHtcbiAgICAgIHJldHVybiByZXR1cm5WYWx1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gcGFyc2UgbmV0d29yayB0cmFmZmljIGRhdGE6ICcke2RhdGF9J2ApO1xuICAgIH1cbiAgfSk7XG59XG5cbi8qKlxuICogUmV0dXJuIHRoZSBDUFUgaW5mb3JtYXRpb24gcmVsYXRlZCB0byB0aGUgZ2l2ZW4gcGFja2FnZU5hbWUuXG4gKiBJdCByYWlzZXMgYW4gZXhjZXB0aW9uIGlmIHRoZSBkdW1wZWQgQ1BVIGluZm9ybWF0aW9uIGRpZCBub3QgaW5jbHVkZSB0aGUgZ2l2ZW4gcGFja2FnZU5hbWVcbiAqIG9yIHRoZSBmb3JtYXQgd2FzIHdyb25nLlxuICogVGhlIENQVSBpbmZvcm1hdGlvbidzIHNhbXBsaW5nIGludGVydmFsIGRlcGVuZHMgb24gdGhlIGRldmljZSB1bmRlciB0ZXN0LlxuICogRm9yIGV4YW1wbGUsIHNvbWUgZGV2aWNlcyBoYXZlIDUgbWludXRlcyBpbnRlcnZhbC4gV2hlbiB5b3UgZ2V0IHRoZSBpbmZvcm1hdGlvblxuICogZnJvbSAyMDIzLTAyLTA3IDExOjU5OjQwLjQ2OCB0byAyMDIzLTAyLTA3IDEyOjA0OjQwLjU1NiwgdGhlbiB0aGUgbmV4dCB3aWxsIGJlXG4gKiBmcm9tIDIwMjMtMDItMDcgMTI6MDQ6NDAuNTU2IHRvIDIwMjMtMDItMDcgMTI6MDk6NDAuNjY4LiBObyBwcm9jZXNzIGluZm9ybWF0aW9uXG4gKiBleGlzdHMgaW4gdGhlIHJlc3VsdCBpZiB0aGUgcHJvY2VzcyB3YXMgbm90IHJ1bm5pbmcgZHVyaW5nIHRoZSBwZXJpb2QuXG4gKlxuICogQHRoaXMge0FuZHJvaWREcml2ZXJ9XG4gKiBAcGFyYW0ge3N0cmluZ30gcGFja2FnZU5hbWUgVGhlIHBhY2thZ2UgbmFtZSB0byBnZXQgdGhlIENQVSBpbmZvcm1hdGlvbi5cbiAqIEBwYXJhbSB7bnVtYmVyfSByZXRyaWVzIFRoZSBudW1iZXIgb2YgcmV0cnkgY291bnQuXG4gKiBAcmV0dXJucyB7QXJyYXl9IFRoZSBhcnJheSBvZiB0aGUgcGFyc2VkIENQVSB1cHNhZ2UgcGVyY2VudGFnZXMuXG4gKiAgICAgICAgICAgICAgICAgIGUuZy4gWydjcHVpbmZvJywgWycxNC4zJywgJzI4LjInXV1cbiAqICAgICAgICAgICAgICAgICAgJzE0LjMnIGlzIHVzYWdlIGJ5IHRoZSB1c2VyICglKSwgJzI4LjInIGlzIHVzYWdlIGJ5IHRoZSBrZXJuZWwgKCUpXG4gKiBAdGhyb3cge0Vycm9yfSBJZiBpdCBmYWlsZWQgdG8gcGFyc2UgdGhlIHJlc3VsdCBvZiBkdW1wc3lzLCBvciBubyBwYWNrYWdlIG5hbWUgZXhpc3RzLlxuICovXG5hc3luYyBmdW5jdGlvbiBnZXRDUFVJbmZvIChwYWNrYWdlTmFtZSwgcmV0cmllcyA9IDIpIHtcbiAgLy8gVE9ETzogZmlndXJlIG91dCB3aHkgdGhpcyBpc1xuICAvLyBzb21ldGltZXMsIHRoZSBmdW5jdGlvbiBvZiAnYWRiLnNoZWxsJyBmYWlscy4gd2hlbiBJIHRlc3RlZCB0aGlzIGZ1bmN0aW9uIG9uIHRoZSB0YXJnZXQgb2YgJ0dhbGF4eSBOb3RlNScsXG4gIC8vIGFkYi5zaGVsbChkdW1wc3lzIGNwdWluZm8pIHJldHVybnMgY3B1IGRhdGFzIGZvciBvdGhlciBhcHBsaWNhdGlvbiBwYWNrYWdlcywgYnV0IEkgY2FuJ3QgZmluZCB0aGUgZGF0YSBmb3IgcGFja2FnZU5hbWUuXG4gIC8vIEl0IHVzdWFsbHkgZmFpbHMgMzAgdGltZXMgYW5kIHN1Y2Nlc3MgZm9yIHRoZSBuZXh0IHRpbWUsXG4gIC8vIFNpbmNlIHRoZW4sIGhlIGhhcyBjb250aW51ZWQgdG8gc3VjY2VlZC5cbiAgcmV0dXJuIGF3YWl0IHJldHJ5SW50ZXJ2YWwocmV0cmllcywgUkVUUllfUEFVU0VfTVMsIGFzeW5jICgpID0+IHtcbiAgICBsZXQgb3V0cHV0O1xuICAgIHRyeSB7XG4gICAgICBvdXRwdXQgPSBhd2FpdCB0aGlzLmFkYi5zaGVsbChbJ2R1bXBzeXMnLCAnY3B1aW5mbyddKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBpZiAoZS5zdGRlcnIpIHtcbiAgICAgICAgdGhpcy5sb2cuaW5mbyhlLnN0ZGVycik7XG4gICAgICB9XG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgICAvLyBgb3V0cHV0YCB3aWxsIGJlIHNvbWV0aGluZyBsaWtlXG4gICAgLy8gICAgKzAlIDIyMDkvaW8uYXBwaXVtLmFuZHJvaWQuYXBpczogMC4xJSB1c2VyICsgMC4yJSBrZXJuZWwgLyBmYXVsdHM6IDcwIG1pbm9yXG4gICAgY29uc3QgdXNhZ2VzUGF0dGVybiA9XG4gICAgICBuZXcgUmVnRXhwKGBeLitcXFxcLyR7Xy5lc2NhcGVSZWdFeHAocGFja2FnZU5hbWUpfTpcXFxcRCsoW1xcXFxkLl0rKSVcXFxccyt1c2VyXFxcXHMrXFxcXCtcXFxccysoW1xcXFxkLl0rKSVcXFxccytrZXJuZWxgLCAnbScpO1xuICAgIGNvbnN0IG1hdGNoID0gdXNhZ2VzUGF0dGVybi5leGVjKG91dHB1dCk7XG4gICAgaWYgKCFtYXRjaCkge1xuICAgICAgdGhpcy5sb2cuZGVidWcob3V0cHV0KTtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgVW5hYmxlIHRvIHBhcnNlIGNwdSB1c2FnZSBkYXRhIGZvciAnJHtwYWNrYWdlTmFtZX0nLiBDaGVjayB0aGUgc2VydmVyIGxvZyBmb3IgbW9yZSBkZXRhaWxzYCk7XG4gICAgfVxuICAgIHJldHVybiBbQ1BVX0tFWVMsIFttYXRjaFsxXSwgbWF0Y2hbMl1dXTtcbiAgfSk7XG59XG5cbi8qKlxuICogQHRoaXMge0FuZHJvaWREcml2ZXJ9XG4gKiBAcGFyYW0ge251bWJlcn0gcmV0cmllc1xuICovXG5hc3luYyBmdW5jdGlvbiBnZXRCYXR0ZXJ5SW5mbyAocmV0cmllcyA9IDIpIHtcbiAgcmV0dXJuIGF3YWl0IHJldHJ5SW50ZXJ2YWwocmV0cmllcywgUkVUUllfUEFVU0VfTVMsIGFzeW5jICgpID0+IHtcbiAgICBsZXQgY21kID0gWydkdW1wc3lzJywgJ2JhdHRlcnknLCAnfCcsICdncmVwJywgJ2xldmVsJ107XG4gICAgbGV0IGRhdGEgPSBhd2FpdCB0aGlzLmFkYi5zaGVsbChjbWQpO1xuICAgIGlmICghZGF0YSkgdGhyb3cgbmV3IEVycm9yKCdObyBkYXRhIGZyb20gZHVtcHN5cycpOyAvL2VzbGludC1kaXNhYmxlLWxpbmUgY3VybHlcblxuICAgIGxldCBwb3dlciA9IHBhcnNlSW50KChkYXRhLnNwbGl0KCc6JylbMV0gfHwgJycpLnRyaW0oKSwgMTApO1xuXG4gICAgaWYgKCFOdW1iZXIuaXNOYU4ocG93ZXIpKSB7XG4gICAgICByZXR1cm4gW18uY2xvbmUoQkFUVEVSWV9LRVlTKSwgW3Bvd2VyLnRvU3RyaW5nKCldXTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gcGFyc2UgYmF0dGVyeSBkYXRhOiAnJHtkYXRhfSdgKTtcbiAgICB9XG4gIH0pO1xufVxuXG4vL1xuLy8gcmV0dXJucyB0aGUgaW5mb3JtYXRpb24gdHlwZSBvZiB0aGUgc3lzdGVtIHN0YXRlIHdoaWNoIGlzIHN1cHBvcnRlZCB0byByZWFkIGFzIGxpa2UgY3B1LCBtZW1vcnksIG5ldHdvcmsgdHJhZmZpYywgYW5kIGJhdHRlcnkuXG4vLyBvdXRwdXQgLSBhcnJheSBsaWtlIGJlbG93XG4vLyBbY3B1aW5mbywgYmF0dGVyeWluZm8sIG5ldHdvcmtpbmZvLCBtZW1vcnlpbmZvXVxuLy9cbmNvbW1hbmRzLmdldFBlcmZvcm1hbmNlRGF0YVR5cGVzID0gZnVuY3Rpb24gZ2V0UGVyZm9ybWFuY2VEYXRhVHlwZXMgKCkge1xuICByZXR1cm4gXy5rZXlzKFNVUFBPUlRFRF9QRVJGT1JNQU5DRV9EQVRBX1RZUEVTKTtcbn07XG5cbi8qKlxuICogQHJldHVybnMgVGhlIGluZm9ybWF0aW9uIHR5cGUgb2YgdGhlIHN5c3RlbSBzdGF0ZSB3aGljaCBpcyBzdXBwb3J0ZWQgdG8gcmVhZCBhcyBsaWtlIGNwdSwgbWVtb3J5LCBuZXR3b3JrIHRyYWZmaWMsIGFuZCBiYXR0ZXJ5LlxuICogaW5wdXQgLSAocGFja2FnZU5hbWUpIHRoZSBwYWNrYWdlIG5hbWUgb2YgdGhlIGFwcGxpY2F0aW9uXG4gKiAgICAgICAgKGRhdGFUeXBlKSB0aGUgdHlwZSBvZiBzeXN0ZW0gc3RhdGUgd2hpY2ggd2FudHMgdG8gcmVhZC4gSXQgc2hvdWxkIGJlIG9uZSBvZiB0aGUga2V5cyBvZiB0aGUgU1VQUE9SVEVEX1BFUkZPUk1BTkNFX0RBVEFfVFlQRVNcbiAqICAgICAgICAoZGF0YVJlYWRUaW1lb3V0KSB0aGUgbnVtYmVyIG9mIGF0dGVtcHRzIHRvIHJlYWRcbiAqIG91dHB1dCAtIHRhYmxlIG9mIHRoZSBwZXJmb3JtYW5jZSBkYXRhLCBUaGUgZmlyc3QgbGluZSBvZiB0aGUgdGFibGUgcmVwcmVzZW50cyB0aGUgdHlwZSBvZiBkYXRhLiBUaGUgcmVtYWluaW5nIGxpbmVzIHJlcHJlc2VudCB0aGUgdmFsdWVzIG9mIHRoZSBkYXRhLlxuICpcbiAqIGluIGNhc2Ugb2YgYmF0dGVyeSBpbmZvIDogW1twb3dlcl0sIFsyM11dXG4gKiBpbiBjYXNlIG9mIG1lbW9yeSBpbmZvIDogIFtbdG90YWxQcml2YXRlRGlydHksIG5hdGl2ZVByaXZhdGVEaXJ0eSwgZGFsdmlrUHJpdmF0ZURpcnR5LCBlZ2xQcml2YXRlRGlydHksIGdsUHJpdmF0ZURpcnR5LCB0b3RhbFBzcyxcbiAqICAgbmF0aXZlUHNzLCBkYWx2aWtQc3MsIGVnbFBzcywgZ2xQc3MsIG5hdGl2ZUhlYXBBbGxvY2F0ZWRTaXplLCBuYXRpdmVIZWFwU2l6ZV0sIFsxODM2MCwgODI5NiwgNjEzMiwgbnVsbCwgbnVsbCwgNDI1ODgsIDg0MDYsIDcwMjQsIG51bGwsIG51bGwsIDI2NTE5LCAxMDM0NF1dXG4gKiBpbiBjYXNlIG9mIG5ldHdvcmsgaW5mbyA6IFtbYnVja2V0U3RhcnQsIGFjdGl2ZVRpbWUsIHJ4Qnl0ZXMsIHJ4UGFja2V0cywgdHhCeXRlcywgdHhQYWNrZXRzLCBvcGVyYXRpb25zLCBidWNrZXREdXJhdGlvbixdLFxuICogICBbMTQ3ODA5MTYwMDAwMCwgbnVsbCwgMTA5OTA3NSwgNjEwOTQ3LCA5MjgsIDExNDM2MiwgNzY5LCAwLCAzNjAwMDAwXSwgWzE0NzgwOTUyMDAwMDAsIG51bGwsIDEzMDYzMDAsIDQwNTk5NywgNTA5LCA0NjM1OSwgMzcwLCAwLCAzNjAwMDAwXV1cbiAqIGluIGNhc2Ugb2YgbmV0d29yayBpbmZvIDogW1tzdCwgYWN0aXZlVGltZSwgcmIsIHJwLCB0YiwgdHAsIG9wLCBidWNrZXREdXJhdGlvbl0sIFsxNDc4MDg4MDAwLCBudWxsLCBudWxsLCAzMjExNTI5NiwgMzQyOTEsIDI5NTY4MDUsIDI1NzA1LCAwLCAzNjAwXSxcbiAqICAgWzE0NzgwOTE2MDAsIG51bGwsIG51bGwsIDI3MTQ2ODMsIDExODIxLCAxNDIwNTY0LCAxMjY1MCwgMCwgMzYwMF0sIFsxNDc4MDk1MjAwLCBudWxsLCBudWxsLCAxMDA3OTIxMywgMTk5NjIsIDI0ODc3MDUsIDIwMDE1LCAwLCAzNjAwXSxcbiAqICAgWzE0NzgwOTg4MDAsIG51bGwsIG51bGwsIDQ0NDQ0MzMsIDEwMjI3LCAxNDMwMzU2LCAxMDQ5MywgMCwgMzYwMF1dXG4gKiBpbiBjYXNlIG9mIGNwdSBpbmZvIDogW1t1c2VyLCBrZXJuZWxdLCBbMC45LCAxLjNdXVxuICovXG5jb21tYW5kcy5nZXRQZXJmb3JtYW5jZURhdGEgPSBhc3luYyBmdW5jdGlvbiBnZXRQZXJmb3JtYW5jZURhdGEgKHBhY2thZ2VOYW1lLCBkYXRhVHlwZSwgcmV0cmllcyA9IDIpIHtcbiAgc3dpdGNoIChfLnRvTG93ZXIoZGF0YVR5cGUpKSB7XG4gICAgY2FzZSAnYmF0dGVyeWluZm8nOlxuICAgICAgcmV0dXJuIGF3YWl0IGdldEJhdHRlcnlJbmZvLmJpbmQodGhpcykocmV0cmllcyk7XG4gICAgY2FzZSAnY3B1aW5mbyc6XG4gICAgICByZXR1cm4gYXdhaXQgZ2V0Q1BVSW5mby5iaW5kKHRoaXMpKHBhY2thZ2VOYW1lLCByZXRyaWVzKTtcbiAgICBjYXNlICdtZW1vcnlpbmZvJzpcbiAgICAgIHJldHVybiBhd2FpdCBnZXRNZW1vcnlJbmZvLmJpbmQodGhpcykocGFja2FnZU5hbWUsIHJldHJpZXMpO1xuICAgIGNhc2UgJ25ldHdvcmtpbmZvJzpcbiAgICAgIHJldHVybiBhd2FpdCBnZXROZXR3b3JrVHJhZmZpY0luZm8uYmluZCh0aGlzKShyZXRyaWVzKTtcbiAgICBkZWZhdWx0OlxuICAgICAgdGhyb3cgbmV3IEVycm9yKGBObyBwZXJmb3JtYW5jZSBkYXRhIG9mIHR5cGUgJyR7ZGF0YVR5cGV9JyBmb3VuZC4gYCArXG4gICAgICAgIGBPbmx5IHRoZSBmb2xsb3dpbmcgdmFsdWVzIGFyZSBzdXBwb3J0ZWQ6ICR7SlNPTi5zdHJpbmdpZnkoU1VQUE9SVEVEX1BFUkZPUk1BTkNFX0RBVEFfVFlQRVMsICcgJywgMil9YCk7XG4gIH1cbn07XG5cbi8qKlxuICogQHR5cGVkZWYge09iamVjdH0gUGVyZm9ybWFuY2VEYXRhT3B0aW9uc1xuICogQHByb3BlcnR5IHtzdHJpbmd9IHBhY2thZ2VOYW1lIFRoZSBuYW1lIG9mIHRoZSBwYWNrYWdlIGlkZW50aWZpZXIgdG8gZmV0Y2ggdGhlIGRhdGEgZm9yXG4gKiBAcHJvcGVydHkgeydiYXR0ZXJ5aW5mbycgfCAnY3B1aW5mbycgfCAnbWVtb3J5aW5mbycgfCAnbmV0d29ya2luZm8nfSBkYXRhVHlwZSBPbmUgb2Ygc3VwcG9ydGVkIHN1YnN5c3RlbVxuICogdG8gZmV0Y2ggdGhlIGRhdGEgZm9yLlxuICovXG5cbi8qKlxuICogUmV0cmlldmVzIHBlcmZvcm1hbmNlIGRhdGEgYWJvdXQgdGhlIGdpdmVuIEFuZHJvaWQgc3Vic3lzdGVtLlxuICogVGhlIGRhdGEgaXMgcGFyc2VkIGZyb20gdGhlIG91dHB1dCBvZiB0aGUgZHVtcHN5cyB1dGlsaXR5LlxuICpcbiAqIEBwYXJhbSB7UGVyZm9ybWFuY2VEYXRhT3B0aW9uc30gb3B0c1xuICogQHJldHVybnMge1Byb21pc2U8YW55W11bXT59IFRoZSBvdXRwdXQgZGVwZW5kcyBvbiB0aGUgc2VsZWN0ZWQgc3Vic3lzdGVtLlxuICogSXQgaXMgb3JnaW5pemVkIGludG8gYSB0YWJsZSwgd2hlcmUgdGhlIGZpcnN0IHJvdyByZXByZXNlbnQgY29sdW1uIG5hbWVzXG4gKiBhbmQgdGhlIGZvbGxvd2luZyByb3dzIHJlcHJlc2VudCB0aGUgc2FtcGxlZCBkYXRhIGZvciBlYWNoIGNvbHVtbi5cbiAqIEV4YW1wbGUgb3V0cHV0IGZvciBkaWZmZXJlbnQgZGF0YSB0eXBlczpcbiAqIC0gYmF0dGVyeWluZm86IFtbcG93ZXJdLCBbMjNdXVxuICogLSBtZW1vcnkgaW5mbzogW1t0b3RhbFByaXZhdGVEaXJ0eSwgbmF0aXZlUHJpdmF0ZURpcnR5LCBkYWx2aWtQcml2YXRlRGlydHksIGVnbFByaXZhdGVEaXJ0eSwgZ2xQcml2YXRlRGlydHksIHRvdGFsUHNzLFxuICogICBuYXRpdmVQc3MsIGRhbHZpa1BzcywgZWdsUHNzLCBnbFBzcywgbmF0aXZlSGVhcEFsbG9jYXRlZFNpemUsIG5hdGl2ZUhlYXBTaXplXSwgWzE4MzYwLCA4Mjk2LCA2MTMyLCBudWxsLCBudWxsLCA0MjU4OCwgODQwNiwgNzAyNCwgbnVsbCwgbnVsbCwgMjY1MTksIDEwMzQ0XV1cbiAqIC0gbmV0d29ya2luZm86IFtbYnVja2V0U3RhcnQsIGFjdGl2ZVRpbWUsIHJ4Qnl0ZXMsIHJ4UGFja2V0cywgdHhCeXRlcywgdHhQYWNrZXRzLCBvcGVyYXRpb25zLCBidWNrZXREdXJhdGlvbixdLFxuICogICBbMTQ3ODA5MTYwMDAwMCwgbnVsbCwgMTA5OTA3NSwgNjEwOTQ3LCA5MjgsIDExNDM2MiwgNzY5LCAwLCAzNjAwMDAwXSwgWzE0NzgwOTUyMDAwMDAsIG51bGwsIDEzMDYzMDAsIDQwNTk5NywgNTA5LCA0NjM1OSwgMzcwLCAwLCAzNjAwMDAwXV1cbiAqXG4gKiAgIFtbc3QsIGFjdGl2ZVRpbWUsIHJiLCBycCwgdGIsIHRwLCBvcCwgYnVja2V0RHVyYXRpb25dLCBbMTQ3ODA4ODAwMCwgbnVsbCwgbnVsbCwgMzIxMTUyOTYsIDM0MjkxLCAyOTU2ODA1LCAyNTcwNSwgMCwgMzYwMF0sXG4gKiAgIFsxNDc4MDkxNjAwLCBudWxsLCBudWxsLCAyNzE0NjgzLCAxMTgyMSwgMTQyMDU2NCwgMTI2NTAsIDAsIDM2MDBdLCBbMTQ3ODA5NTIwMCwgbnVsbCwgbnVsbCwgMTAwNzkyMTMsIDE5OTYyLCAyNDg3NzA1LCAyMDAxNSwgMCwgMzYwMF0sXG4gKiAgIFsxNDc4MDk4ODAwLCBudWxsLCBudWxsLCA0NDQ0NDMzLCAxMDIyNywgMTQzMDM1NiwgMTA0OTMsIDAsIDM2MDBdXVxuICogLSBjcHVpbmZvOiBbW3VzZXIsIGtlcm5lbF0sIFswLjksIDEuM11dXG4gKi9cbmNvbW1hbmRzLm1vYmlsZUdldFBlcmZvcm1hbmNlRGF0YSA9IGFzeW5jIGZ1bmN0aW9uIG1vYmlsZUdldFBlcmZvcm1hbmNlRGF0YSAob3B0cyA9IHt9KSB7XG4gIGNvbnN0IHsgcGFja2FnZU5hbWUsIGRhdGFUeXBlIH0gPSByZXF1aXJlQXJncyhbJ3BhY2thZ2VOYW1lJywgJ2RhdGFUeXBlJ10sIG9wdHMpO1xuICByZXR1cm4gYXdhaXQgdGhpcy5nZXRQZXJmb3JtYW5jZURhdGEocGFja2FnZU5hbWUsIGRhdGFUeXBlKTtcbn07XG5cbmV4cG9ydCB7XG4gIGNvbW1hbmRzLCBTVVBQT1JURURfUEVSRk9STUFOQ0VfREFUQV9UWVBFUywgQ1BVX0tFWVMsIE1FTU9SWV9LRVlTLFxuICBCQVRURVJZX0tFWVMsIE5FVFdPUktfS0VZUywgZ2V0TWVtb3J5SW5mbywgZ2V0TmV0d29ya1RyYWZmaWNJbmZvLFxuICBnZXRDUFVJbmZvLCBnZXRCYXR0ZXJ5SW5mbyxcbn07XG5leHBvcnQgZGVmYXVsdCBjb21tYW5kcztcbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBQUEsSUFBQUEsT0FBQSxHQUFBQyxzQkFBQSxDQUFBQyxP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
430
+ exports.default = commands;
431
+ //# sourceMappingURL=performance.js.map