@testdroid-ai/cli 0.1.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 (229) hide show
  1. package/dist/adb/adb-path-resolver.d.ts +6 -0
  2. package/dist/adb/adb-path-resolver.d.ts.map +1 -0
  3. package/dist/adb/adb-path-resolver.js +93 -0
  4. package/dist/adb/adb-path-resolver.js.map +1 -0
  5. package/dist/adb/adb-shell.d.ts +29 -0
  6. package/dist/adb/adb-shell.d.ts.map +1 -0
  7. package/dist/adb/adb-shell.js +128 -0
  8. package/dist/adb/adb-shell.js.map +1 -0
  9. package/dist/adb/detector.d.ts +12 -0
  10. package/dist/adb/detector.d.ts.map +1 -0
  11. package/dist/adb/detector.js +44 -0
  12. package/dist/adb/detector.js.map +1 -0
  13. package/dist/adb/device-tracker.d.ts +23 -0
  14. package/dist/adb/device-tracker.d.ts.map +1 -0
  15. package/dist/adb/device-tracker.js +134 -0
  16. package/dist/adb/device-tracker.js.map +1 -0
  17. package/dist/adb/emulator-detector.d.ts +11 -0
  18. package/dist/adb/emulator-detector.d.ts.map +1 -0
  19. package/dist/adb/emulator-detector.js +54 -0
  20. package/dist/adb/emulator-detector.js.map +1 -0
  21. package/dist/appium/health-check.d.ts +6 -0
  22. package/dist/appium/health-check.d.ts.map +1 -0
  23. package/dist/appium/health-check.js +61 -0
  24. package/dist/appium/health-check.js.map +1 -0
  25. package/dist/appium/session-manager.d.ts +15 -0
  26. package/dist/appium/session-manager.d.ts.map +1 -0
  27. package/dist/appium/session-manager.js +82 -0
  28. package/dist/appium/session-manager.js.map +1 -0
  29. package/dist/auth/credential-store.d.ts +31 -0
  30. package/dist/auth/credential-store.d.ts.map +1 -0
  31. package/dist/auth/credential-store.js +154 -0
  32. package/dist/auth/credential-store.js.map +1 -0
  33. package/dist/auth/pairing-auth.d.ts +26 -0
  34. package/dist/auth/pairing-auth.d.ts.map +1 -0
  35. package/dist/auth/pairing-auth.js +177 -0
  36. package/dist/auth/pairing-auth.js.map +1 -0
  37. package/dist/auth/token-manager.d.ts +20 -0
  38. package/dist/auth/token-manager.d.ts.map +1 -0
  39. package/dist/auth/token-manager.js +101 -0
  40. package/dist/auth/token-manager.js.map +1 -0
  41. package/dist/commands/connect.d.ts +9 -0
  42. package/dist/commands/connect.d.ts.map +1 -0
  43. package/dist/commands/connect.js +270 -0
  44. package/dist/commands/connect.js.map +1 -0
  45. package/dist/commands/devices.d.ts +2 -0
  46. package/dist/commands/devices.d.ts.map +1 -0
  47. package/dist/commands/devices.js +52 -0
  48. package/dist/commands/devices.js.map +1 -0
  49. package/dist/commands/doctor.d.ts +2 -0
  50. package/dist/commands/doctor.d.ts.map +1 -0
  51. package/dist/commands/doctor.js +214 -0
  52. package/dist/commands/doctor.js.map +1 -0
  53. package/dist/commands/mirror.d.ts +2 -0
  54. package/dist/commands/mirror.d.ts.map +1 -0
  55. package/dist/commands/mirror.js +77 -0
  56. package/dist/commands/mirror.js.map +1 -0
  57. package/dist/commands/prompt.d.ts +12 -0
  58. package/dist/commands/prompt.d.ts.map +1 -0
  59. package/dist/commands/prompt.js +174 -0
  60. package/dist/commands/prompt.js.map +1 -0
  61. package/dist/commands/record.d.ts +7 -0
  62. package/dist/commands/record.d.ts.map +1 -0
  63. package/dist/commands/record.js +129 -0
  64. package/dist/commands/record.js.map +1 -0
  65. package/dist/commands/run.d.ts +16 -0
  66. package/dist/commands/run.d.ts.map +1 -0
  67. package/dist/commands/run.js +271 -0
  68. package/dist/commands/run.js.map +1 -0
  69. package/dist/commands/setup.d.ts +6 -0
  70. package/dist/commands/setup.d.ts.map +1 -0
  71. package/dist/commands/setup.js +50 -0
  72. package/dist/commands/setup.js.map +1 -0
  73. package/dist/commands/status.d.ts +2 -0
  74. package/dist/commands/status.d.ts.map +1 -0
  75. package/dist/commands/status.js +32 -0
  76. package/dist/commands/status.js.map +1 -0
  77. package/dist/healing/ai-adapter.d.ts +44 -0
  78. package/dist/healing/ai-adapter.d.ts.map +1 -0
  79. package/dist/healing/ai-adapter.js +87 -0
  80. package/dist/healing/ai-adapter.js.map +1 -0
  81. package/dist/healing/healer.d.ts +109 -0
  82. package/dist/healing/healer.d.ts.map +1 -0
  83. package/dist/healing/healer.js +475 -0
  84. package/dist/healing/healer.js.map +1 -0
  85. package/dist/healing/similarity.d.ts +63 -0
  86. package/dist/healing/similarity.d.ts.map +1 -0
  87. package/dist/healing/similarity.js +172 -0
  88. package/dist/healing/similarity.js.map +1 -0
  89. package/dist/index.d.ts +3 -0
  90. package/dist/index.d.ts.map +1 -0
  91. package/dist/index.js +107 -0
  92. package/dist/index.js.map +1 -0
  93. package/dist/recording/capture-strategies/capture-strategy.interface.d.ts +6 -0
  94. package/dist/recording/capture-strategies/capture-strategy.interface.d.ts.map +1 -0
  95. package/dist/recording/capture-strategies/capture-strategy.interface.js +3 -0
  96. package/dist/recording/capture-strategies/capture-strategy.interface.js.map +1 -0
  97. package/dist/recording/capture-strategies/getevent.strategy.d.ts +27 -0
  98. package/dist/recording/capture-strategies/getevent.strategy.d.ts.map +1 -0
  99. package/dist/recording/capture-strategies/getevent.strategy.js +163 -0
  100. package/dist/recording/capture-strategies/getevent.strategy.js.map +1 -0
  101. package/dist/recording/capture-strategies/key-capture.strategy.d.ts +16 -0
  102. package/dist/recording/capture-strategies/key-capture.strategy.d.ts.map +1 -0
  103. package/dist/recording/capture-strategies/key-capture.strategy.js +67 -0
  104. package/dist/recording/capture-strategies/key-capture.strategy.js.map +1 -0
  105. package/dist/recording/capture-strategies/logcat-capture.strategy.d.ts +32 -0
  106. package/dist/recording/capture-strategies/logcat-capture.strategy.d.ts.map +1 -0
  107. package/dist/recording/capture-strategies/logcat-capture.strategy.js +176 -0
  108. package/dist/recording/capture-strategies/logcat-capture.strategy.js.map +1 -0
  109. package/dist/recording/confidence-scorer.d.ts +13 -0
  110. package/dist/recording/confidence-scorer.d.ts.map +1 -0
  111. package/dist/recording/confidence-scorer.js +34 -0
  112. package/dist/recording/confidence-scorer.js.map +1 -0
  113. package/dist/recording/event-capture.d.ts +40 -0
  114. package/dist/recording/event-capture.d.ts.map +1 -0
  115. package/dist/recording/event-capture.js +168 -0
  116. package/dist/recording/event-capture.js.map +1 -0
  117. package/dist/recording/recorder.d.ts +32 -0
  118. package/dist/recording/recorder.d.ts.map +1 -0
  119. package/dist/recording/recorder.js +107 -0
  120. package/dist/recording/recorder.js.map +1 -0
  121. package/dist/runner/adb-executor.d.ts +116 -0
  122. package/dist/runner/adb-executor.d.ts.map +1 -0
  123. package/dist/runner/adb-executor.js +323 -0
  124. package/dist/runner/adb-executor.js.map +1 -0
  125. package/dist/runner/appium-executor.d.ts +35 -0
  126. package/dist/runner/appium-executor.d.ts.map +1 -0
  127. package/dist/runner/appium-executor.js +191 -0
  128. package/dist/runner/appium-executor.js.map +1 -0
  129. package/dist/runner/parse-strategies/appium-default.strategy.d.ts +12 -0
  130. package/dist/runner/parse-strategies/appium-default.strategy.d.ts.map +1 -0
  131. package/dist/runner/parse-strategies/appium-default.strategy.js +342 -0
  132. package/dist/runner/parse-strategies/appium-default.strategy.js.map +1 -0
  133. package/dist/runner/parse-strategies/index.d.ts +7 -0
  134. package/dist/runner/parse-strategies/index.d.ts.map +1 -0
  135. package/dist/runner/parse-strategies/index.js +14 -0
  136. package/dist/runner/parse-strategies/index.js.map +1 -0
  137. package/dist/runner/parse-strategies/java.strategy.d.ts +8 -0
  138. package/dist/runner/parse-strategies/java.strategy.d.ts.map +1 -0
  139. package/dist/runner/parse-strategies/java.strategy.js +170 -0
  140. package/dist/runner/parse-strategies/java.strategy.js.map +1 -0
  141. package/dist/runner/parse-strategies/maestro.strategy.d.ts +8 -0
  142. package/dist/runner/parse-strategies/maestro.strategy.d.ts.map +1 -0
  143. package/dist/runner/parse-strategies/maestro.strategy.js +105 -0
  144. package/dist/runner/parse-strategies/maestro.strategy.js.map +1 -0
  145. package/dist/runner/parse-strategies/python.strategy.d.ts +8 -0
  146. package/dist/runner/parse-strategies/python.strategy.d.ts.map +1 -0
  147. package/dist/runner/parse-strategies/python.strategy.js +140 -0
  148. package/dist/runner/parse-strategies/python.strategy.js.map +1 -0
  149. package/dist/runner/parse-strategies/robot.strategy.d.ts +8 -0
  150. package/dist/runner/parse-strategies/robot.strategy.d.ts.map +1 -0
  151. package/dist/runner/parse-strategies/robot.strategy.js +81 -0
  152. package/dist/runner/parse-strategies/robot.strategy.js.map +1 -0
  153. package/dist/runner/parse-strategies/types.d.ts +17 -0
  154. package/dist/runner/parse-strategies/types.d.ts.map +1 -0
  155. package/dist/runner/parse-strategies/types.js +3 -0
  156. package/dist/runner/parse-strategies/types.js.map +1 -0
  157. package/dist/runner/parse-strategies/utils.d.ts +39 -0
  158. package/dist/runner/parse-strategies/utils.d.ts.map +1 -0
  159. package/dist/runner/parse-strategies/utils.js +217 -0
  160. package/dist/runner/parse-strategies/utils.js.map +1 -0
  161. package/dist/runner/script-parser.d.ts +43 -0
  162. package/dist/runner/script-parser.d.ts.map +1 -0
  163. package/dist/runner/script-parser.js +68 -0
  164. package/dist/runner/script-parser.js.map +1 -0
  165. package/dist/runner/selector-resolver.d.ts +87 -0
  166. package/dist/runner/selector-resolver.d.ts.map +1 -0
  167. package/dist/runner/selector-resolver.js +206 -0
  168. package/dist/runner/selector-resolver.js.map +1 -0
  169. package/dist/runner/step-executor.d.ts +112 -0
  170. package/dist/runner/step-executor.d.ts.map +1 -0
  171. package/dist/runner/step-executor.js +518 -0
  172. package/dist/runner/step-executor.js.map +1 -0
  173. package/dist/runner/test-runner.d.ts +89 -0
  174. package/dist/runner/test-runner.d.ts.map +1 -0
  175. package/dist/runner/test-runner.js +320 -0
  176. package/dist/runner/test-runner.js.map +1 -0
  177. package/dist/scrcpy/launcher.d.ts +16 -0
  178. package/dist/scrcpy/launcher.d.ts.map +1 -0
  179. package/dist/scrcpy/launcher.js +87 -0
  180. package/dist/scrcpy/launcher.js.map +1 -0
  181. package/dist/services/device-poller.d.ts +10 -0
  182. package/dist/services/device-poller.d.ts.map +1 -0
  183. package/dist/services/device-poller.js +44 -0
  184. package/dist/services/device-poller.js.map +1 -0
  185. package/dist/services/execution-manager.d.ts +18 -0
  186. package/dist/services/execution-manager.d.ts.map +1 -0
  187. package/dist/services/execution-manager.js +185 -0
  188. package/dist/services/execution-manager.js.map +1 -0
  189. package/dist/services/recording-manager.d.ts +13 -0
  190. package/dist/services/recording-manager.d.ts.map +1 -0
  191. package/dist/services/recording-manager.js +234 -0
  192. package/dist/services/recording-manager.js.map +1 -0
  193. package/dist/setup/adb-installer.d.ts +8 -0
  194. package/dist/setup/adb-installer.d.ts.map +1 -0
  195. package/dist/setup/adb-installer.js +115 -0
  196. package/dist/setup/adb-installer.js.map +1 -0
  197. package/dist/setup/appium-installer.d.ts +8 -0
  198. package/dist/setup/appium-installer.d.ts.map +1 -0
  199. package/dist/setup/appium-installer.js +113 -0
  200. package/dist/setup/appium-installer.js.map +1 -0
  201. package/dist/setup/base-installer.d.ts +33 -0
  202. package/dist/setup/base-installer.d.ts.map +1 -0
  203. package/dist/setup/base-installer.js +170 -0
  204. package/dist/setup/base-installer.js.map +1 -0
  205. package/dist/setup/build-tools-installer.d.ts +8 -0
  206. package/dist/setup/build-tools-installer.d.ts.map +1 -0
  207. package/dist/setup/build-tools-installer.js +109 -0
  208. package/dist/setup/build-tools-installer.js.map +1 -0
  209. package/dist/setup/java-installer.d.ts +8 -0
  210. package/dist/setup/java-installer.d.ts.map +1 -0
  211. package/dist/setup/java-installer.js +132 -0
  212. package/dist/setup/java-installer.js.map +1 -0
  213. package/dist/setup/paths.d.ts +12 -0
  214. package/dist/setup/paths.d.ts.map +1 -0
  215. package/dist/setup/paths.js +90 -0
  216. package/dist/setup/paths.js.map +1 -0
  217. package/dist/setup/scrcpy-installer.d.ts +8 -0
  218. package/dist/setup/scrcpy-installer.d.ts.map +1 -0
  219. package/dist/setup/scrcpy-installer.js +143 -0
  220. package/dist/setup/scrcpy-installer.js.map +1 -0
  221. package/dist/setup/setup-manager.d.ts +18 -0
  222. package/dist/setup/setup-manager.d.ts.map +1 -0
  223. package/dist/setup/setup-manager.js +113 -0
  224. package/dist/setup/setup-manager.js.map +1 -0
  225. package/dist/ws/socket.d.ts +38 -0
  226. package/dist/ws/socket.d.ts.map +1 -0
  227. package/dist/ws/socket.js +91 -0
  228. package/dist/ws/socket.js.map +1 -0
  229. package/package.json +53 -0
@@ -0,0 +1,32 @@
1
+ import { RecordingEvent } from '@testdroid-ai/shared';
2
+ import { CaptureStrategy } from './capture-strategy.interface';
3
+ /**
4
+ * Captures user interactions via the TestDroid accessibility service APK.
5
+ *
6
+ * The APK (com.testdroid.capture) is an AccessibilityService that logs
7
+ * every user interaction to logcat with tag TESTDROID_CAPTURE.
8
+ *
9
+ * Format: EVENT|action|text|resourceId|className|bounds|packageName|inputText
10
+ *
11
+ * This is the PRIMARY capture strategy — it captures ALL interaction types:
12
+ * tap, long_press, type_text, swipe, navigate, back.
13
+ */
14
+ export declare class LogcatCaptureStrategy implements CaptureStrategy {
15
+ private serial;
16
+ private process;
17
+ private onEventCb;
18
+ private typingTimer;
19
+ private typingEvent;
20
+ private lastEventKey;
21
+ private lastEventTime;
22
+ private currentPackage;
23
+ constructor(serial: string);
24
+ start(onEvent: (event: RecordingEvent) => void): Promise<void>;
25
+ stop(): void;
26
+ /** Current foreground package (from last event) */
27
+ getPackage(): string;
28
+ private parseLine;
29
+ private emit;
30
+ private decodeEntities;
31
+ }
32
+ //# sourceMappingURL=logcat-capture.strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logcat-capture.strategy.d.ts","sourceRoot":"","sources":["../../../src/recording/capture-strategies/logcat-capture.strategy.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAsB,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAG/D;;;;;;;;;;GAUG;AACH,qBAAa,qBAAsB,YAAW,eAAe;IAe/C,OAAO,CAAC,MAAM;IAd1B,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,SAAS,CAAkD;IAGnE,OAAO,CAAC,WAAW,CAA8C;IACjE,OAAO,CAAC,WAAW,CAA+B;IAGlD,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,aAAa,CAAK;IAG1B,OAAO,CAAC,cAAc,CAAM;gBAER,MAAM,EAAE,MAAM;IAE5B,KAAK,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BpE,IAAI,IAAI,IAAI;IAeZ,mDAAmD;IACnD,UAAU,IAAI,MAAM;IAEpB,OAAO,CAAC,SAAS;IA4FjB,OAAO,CAAC,IAAI;IAKZ,OAAO,CAAC,cAAc;CAUvB"}
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LogcatCaptureStrategy = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const confidence_scorer_1 = require("../confidence-scorer");
6
+ /**
7
+ * Captures user interactions via the TestDroid accessibility service APK.
8
+ *
9
+ * The APK (com.testdroid.capture) is an AccessibilityService that logs
10
+ * every user interaction to logcat with tag TESTDROID_CAPTURE.
11
+ *
12
+ * Format: EVENT|action|text|resourceId|className|bounds|packageName|inputText
13
+ *
14
+ * This is the PRIMARY capture strategy — it captures ALL interaction types:
15
+ * tap, long_press, type_text, swipe, navigate, back.
16
+ */
17
+ class LogcatCaptureStrategy {
18
+ serial;
19
+ process = null;
20
+ onEventCb = null;
21
+ // Typing debounce: accumulate text, emit once when typing stops
22
+ typingTimer = null;
23
+ typingEvent = null;
24
+ // Dedup: skip duplicate events within 150ms (same action on same element)
25
+ lastEventKey = '';
26
+ lastEventTime = 0;
27
+ // Track current package for appPackage detection
28
+ currentPackage = '';
29
+ constructor(serial) {
30
+ this.serial = serial;
31
+ }
32
+ async start(onEvent) {
33
+ this.onEventCb = onEvent;
34
+ // Clear logcat buffer
35
+ try {
36
+ (0, child_process_1.execFileSync)('adb', ['-s', this.serial, 'logcat', '-c'], { stdio: 'pipe', timeout: 3000 });
37
+ }
38
+ catch { }
39
+ // Start logcat monitor
40
+ this.process = (0, child_process_1.spawn)('adb', [
41
+ '-s', this.serial, 'logcat', '-s', 'TESTDROID_CAPTURE:I',
42
+ ], { stdio: ['ignore', 'pipe', 'pipe'] });
43
+ let buffer = '';
44
+ this.process.stdout?.on('data', (data) => {
45
+ buffer += data.toString();
46
+ const lines = buffer.split('\n');
47
+ buffer = lines.pop() || '';
48
+ for (const line of lines) {
49
+ this.parseLine(line.trim());
50
+ }
51
+ });
52
+ this.process.stderr?.on('data', () => { });
53
+ this.process.on('error', () => { });
54
+ }
55
+ stop() {
56
+ // Flush pending typing
57
+ if (this.typingEvent) {
58
+ clearTimeout(this.typingTimer);
59
+ this.emit(this.typingEvent);
60
+ this.typingEvent = null;
61
+ this.typingTimer = null;
62
+ }
63
+ // Kill logcat process
64
+ if (this.process) {
65
+ try {
66
+ this.process.kill('SIGKILL');
67
+ }
68
+ catch { }
69
+ this.process = null;
70
+ }
71
+ }
72
+ /** Current foreground package (from last event) */
73
+ getPackage() { return this.currentPackage; }
74
+ parseLine(line) {
75
+ const match = line.match(/TESTDROID_CAPTURE:\s*EVENT\|([^|]*)\|([^|]*)\|([^|]*)\|([^|]*)\|([^|]*)\|([^|]*)\|([^|]*)/);
76
+ if (!match)
77
+ return;
78
+ const [, action, text, resourceId, className, bounds, packageName, inputText] = match;
79
+ // Map action to RecordingEventType
80
+ const typeMap = {
81
+ tap: 'tap',
82
+ long_press: 'long_press',
83
+ type_text: 'type_text',
84
+ swipe: 'scroll',
85
+ navigate: 'window_changed',
86
+ notification: 'window_changed',
87
+ };
88
+ const eventType = typeMap[action];
89
+ if (!eventType)
90
+ return;
91
+ // Skip system UI (status bar, keyboard)
92
+ if (packageName === 'com.android.systemui')
93
+ return;
94
+ if (packageName?.startsWith('com.google.android.inputmethod'))
95
+ return;
96
+ if (packageName?.startsWith('com.android.inputmethod'))
97
+ return;
98
+ // Track package
99
+ if (packageName && packageName !== 'com.android.systemui') {
100
+ this.currentPackage = packageName;
101
+ }
102
+ // Parse bounds center
103
+ let x;
104
+ let y;
105
+ if (bounds) {
106
+ const parts = bounds.split(',').map(Number);
107
+ if (parts.length === 4 && !isNaN(parts[0])) {
108
+ x = Math.round((parts[0] + parts[2]) / 2);
109
+ y = Math.round((parts[1] + parts[3]) / 2);
110
+ }
111
+ }
112
+ // Decode HTML entities in text
113
+ const cleanText = text ? this.decodeEntities(text) : undefined;
114
+ // Build event
115
+ const event = {
116
+ type: eventType,
117
+ timestamp: Date.now(),
118
+ x, y,
119
+ elementId: resourceId || undefined,
120
+ elementText: cleanText,
121
+ elementClass: className || undefined,
122
+ elementBounds: bounds || undefined,
123
+ };
124
+ // Handle type_text: debounce, emit final text
125
+ if (action === 'type_text') {
126
+ const typedText = inputText ? inputText.replace(/^\[/, '').replace(/\]$/, '') : cleanText;
127
+ event.text = typedText;
128
+ // Check for password field
129
+ if (typedText && /[\u2022\u25CF*]/.test(typedText)) {
130
+ event.text = '<PASSWORD>';
131
+ }
132
+ this.typingEvent = event;
133
+ if (this.typingTimer)
134
+ clearTimeout(this.typingTimer);
135
+ this.typingTimer = setTimeout(() => {
136
+ if (this.typingEvent) {
137
+ this.emit(this.typingEvent);
138
+ this.typingEvent = null;
139
+ }
140
+ }, 1500);
141
+ return;
142
+ }
143
+ // Non-typing event: flush pending typing first
144
+ if (this.typingEvent) {
145
+ clearTimeout(this.typingTimer);
146
+ this.emit(this.typingEvent);
147
+ this.typingEvent = null;
148
+ this.typingTimer = null;
149
+ }
150
+ // Dedup: skip if same action+element within 150ms
151
+ const eventKey = `${action}|${resourceId}|${cleanText}`;
152
+ const now = Date.now();
153
+ if (eventKey === this.lastEventKey && now - this.lastEventTime < 150)
154
+ return;
155
+ this.lastEventKey = eventKey;
156
+ this.lastEventTime = now;
157
+ this.emit(event);
158
+ }
159
+ emit(event) {
160
+ event.confidence = (0, confidence_scorer_1.scoreConfidence)(event);
161
+ if (this.onEventCb)
162
+ this.onEventCb(event);
163
+ }
164
+ decodeEntities(text) {
165
+ return text
166
+ .replace(/&#(\d+);/g, (_, code) => String.fromCodePoint(parseInt(code, 10)))
167
+ .replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCodePoint(parseInt(hex, 16)))
168
+ .replace(/&amp;/g, '&')
169
+ .replace(/&lt;/g, '<')
170
+ .replace(/&gt;/g, '>')
171
+ .replace(/&quot;/g, '"')
172
+ .replace(/&apos;/g, "'");
173
+ }
174
+ }
175
+ exports.LogcatCaptureStrategy = LogcatCaptureStrategy;
176
+ //# sourceMappingURL=logcat-capture.strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logcat-capture.strategy.js","sourceRoot":"","sources":["../../../src/recording/capture-strategies/logcat-capture.strategy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { RecordingEvent } from '@testdroid-ai/shared';
2
+ /**
3
+ * Scores the confidence of a recording event's selectors.
4
+ * Higher score = more reliable for test generation and replay.
5
+ *
6
+ * 100: unique resourceId (most stable)
7
+ * 85: elementText exists and is non-empty
8
+ * 70: elementClass exists
9
+ * 50: only coordinates (fragile)
10
+ * 30: no actionable data
11
+ */
12
+ export declare function scoreConfidence(event: RecordingEvent): number;
13
+ //# sourceMappingURL=confidence-scorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confidence-scorer.d.ts","sourceRoot":"","sources":["../../src/recording/confidence-scorer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAuB7D"}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.scoreConfidence = scoreConfidence;
4
+ /**
5
+ * Scores the confidence of a recording event's selectors.
6
+ * Higher score = more reliable for test generation and replay.
7
+ *
8
+ * 100: unique resourceId (most stable)
9
+ * 85: elementText exists and is non-empty
10
+ * 70: elementClass exists
11
+ * 50: only coordinates (fragile)
12
+ * 30: no actionable data
13
+ */
14
+ function scoreConfidence(event) {
15
+ // ResourceId is the most stable selector
16
+ if (event.elementId && event.elementId.includes(':id/')) {
17
+ return 100;
18
+ }
19
+ // Text is second best
20
+ if (event.elementText && event.elementText.length > 0) {
21
+ return 85;
22
+ }
23
+ // Class name gives some context
24
+ if (event.elementClass) {
25
+ return 70;
26
+ }
27
+ // Only coordinates -- fragile
28
+ if (event.x !== undefined && event.y !== undefined) {
29
+ return 50;
30
+ }
31
+ // Nothing useful
32
+ return 30;
33
+ }
34
+ //# sourceMappingURL=confidence-scorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confidence-scorer.js","sourceRoot":"","sources":["../../src/recording/confidence-scorer.ts"],"names":[],"mappings":";;AAYA,0CAuBC;AAjCD;;;;;;;;;GASG;AACH,SAAgB,eAAe,CAAC,KAAqB;IACnD,yCAAyC;IACzC,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACxD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,sBAAsB;IACtB,IAAI,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,gCAAgC;IAChC,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;QACvB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,8BAA8B;IAC9B,IAAI,KAAK,CAAC,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;QACnD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,iBAAiB;IACjB,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { RecordingEvent } from '@testdroid-ai/shared';
2
+ export interface EventCaptureOptions {
3
+ useAppium?: boolean;
4
+ appiumUrl?: string;
5
+ }
6
+ /**
7
+ * Orchestrates capture of user interactions on Android devices.
8
+ *
9
+ * Strategy selection (in priority order):
10
+ * 1. LogcatCapture — accessibility service APK (captures ALL events)
11
+ * 2. GeteventStrategy — raw kernel input (fallback, coords only)
12
+ *
13
+ * KeyCaptureStrategy always runs alongside for back/home hardware keys.
14
+ */
15
+ export declare class EventCapture {
16
+ private serial;
17
+ private options;
18
+ private strategy;
19
+ private keyCapture;
20
+ private screenSize;
21
+ private appiumActive;
22
+ private logcatStrategy;
23
+ constructor(serial: string, options?: EventCaptureOptions);
24
+ /** Whether Appium mode is active */
25
+ isAppiumActive(): boolean;
26
+ /** Get current foreground app package */
27
+ getAppPackage(): string;
28
+ getScreenSize(): Promise<{
29
+ width: number;
30
+ height: number;
31
+ }>;
32
+ start(onEvent: (event: RecordingEvent) => void): Promise<void>;
33
+ stop(): void;
34
+ /**
35
+ * Ensures the TestDroid accessibility service APK is installed and active.
36
+ * Returns true if service is ready for capture.
37
+ */
38
+ private ensureAccessibilityService;
39
+ }
40
+ //# sourceMappingURL=event-capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-capture.d.ts","sourceRoot":"","sources":["../../src/recording/event-capture.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAMtD,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,qBAAa,YAAY;IAQrB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,OAAO;IARjB,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,UAAU,CAAmC;IACrD,OAAO,CAAC,UAAU,CAAiC;IACnD,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,cAAc,CAAa;gBAGzB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,mBAAwB;IAG3C,oCAAoC;IACpC,cAAc,IAAI,OAAO;IAEzB,yCAAyC;IACzC,aAAa,IAAI,MAAM;IAOjB,aAAa,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAa3D,KAAK,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA8BpE,IAAI,IAAI,IAAI;IAMZ;;;OAGG;YACW,0BAA0B;CAsDzC"}
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.EventCapture = void 0;
37
+ const child_process_1 = require("child_process");
38
+ const key_capture_strategy_1 = require("./capture-strategies/key-capture.strategy");
39
+ const confidence_scorer_1 = require("./confidence-scorer");
40
+ const path = __importStar(require("path"));
41
+ /**
42
+ * Orchestrates capture of user interactions on Android devices.
43
+ *
44
+ * Strategy selection (in priority order):
45
+ * 1. LogcatCapture — accessibility service APK (captures ALL events)
46
+ * 2. GeteventStrategy — raw kernel input (fallback, coords only)
47
+ *
48
+ * KeyCaptureStrategy always runs alongside for back/home hardware keys.
49
+ */
50
+ class EventCapture {
51
+ serial;
52
+ options;
53
+ strategy = null;
54
+ keyCapture = null;
55
+ screenSize = { width: 1080, height: 2400 };
56
+ appiumActive = false;
57
+ logcatStrategy = null; // LogcatCaptureStrategy reference for getPackage()
58
+ constructor(serial, options = {}) {
59
+ this.serial = serial;
60
+ this.options = options;
61
+ }
62
+ /** Whether Appium mode is active */
63
+ isAppiumActive() { return this.appiumActive; }
64
+ /** Get current foreground app package */
65
+ getAppPackage() {
66
+ if (this.logcatStrategy?.getPackage) {
67
+ return this.logcatStrategy.getPackage();
68
+ }
69
+ return '';
70
+ }
71
+ async getScreenSize() {
72
+ try {
73
+ const output = (0, child_process_1.execFileSync)('adb', ['-s', this.serial, 'shell', 'wm', 'size'], {
74
+ encoding: 'utf-8', stdio: 'pipe', timeout: 5000,
75
+ });
76
+ const match = output.match(/(\d+)x(\d+)/);
77
+ if (match) {
78
+ this.screenSize = { width: parseInt(match[1], 10), height: parseInt(match[2], 10) };
79
+ }
80
+ }
81
+ catch { }
82
+ return this.screenSize;
83
+ }
84
+ async start(onEvent) {
85
+ const enrichedEmit = (event) => {
86
+ event.confidence = (0, confidence_scorer_1.scoreConfidence)(event);
87
+ onEvent(event);
88
+ };
89
+ // Try LogcatCapture (APK accessibility service) first
90
+ const apkReady = await this.ensureAccessibilityService();
91
+ if (apkReady) {
92
+ // PRIMARY: LogcatCapture — captures ALL user interactions
93
+ const { LogcatCaptureStrategy } = await Promise.resolve().then(() => __importStar(require('./capture-strategies/logcat-capture.strategy')));
94
+ this.logcatStrategy = new LogcatCaptureStrategy(this.serial);
95
+ this.strategy = this.logcatStrategy;
96
+ await this.strategy.start(enrichedEmit);
97
+ this.appiumActive = true;
98
+ }
99
+ else {
100
+ // FALLBACK: GeteventStrategy — raw coords only, no element context
101
+ const { GeteventStrategy } = await Promise.resolve().then(() => __importStar(require('./capture-strategies/getevent.strategy')));
102
+ const getevent = new GeteventStrategy(this.serial);
103
+ getevent.setScreenSize(this.screenSize);
104
+ this.strategy = getevent;
105
+ await this.strategy.start(enrichedEmit);
106
+ }
107
+ // KeyCapture always runs (back/home hardware keys)
108
+ this.keyCapture = new key_capture_strategy_1.KeyCaptureStrategy(this.serial);
109
+ await this.keyCapture.start(enrichedEmit);
110
+ }
111
+ stop() {
112
+ if (this.strategy) {
113
+ this.strategy.stop();
114
+ this.strategy = null;
115
+ }
116
+ if (this.keyCapture) {
117
+ this.keyCapture.stop();
118
+ this.keyCapture = null;
119
+ }
120
+ this.logcatStrategy = null;
121
+ }
122
+ /**
123
+ * Ensures the TestDroid accessibility service APK is installed and active.
124
+ * Returns true if service is ready for capture.
125
+ */
126
+ async ensureAccessibilityService() {
127
+ const SERVICE = 'com.testdroid.capture/com.testdroid.capture.CaptureService';
128
+ // Check if APK is installed
129
+ try {
130
+ const installed = (0, child_process_1.execFileSync)('adb', ['-s', this.serial, 'shell', 'pm', 'list', 'packages', 'com.testdroid.capture'], { encoding: 'utf-8', stdio: 'pipe', timeout: 5000 });
131
+ if (!installed.includes('com.testdroid.capture')) {
132
+ // Install the APK
133
+ const apkPath = path.resolve(__dirname, '../../android-service/testdroid-capture-aligned.apk');
134
+ try {
135
+ (0, child_process_1.execFileSync)('adb', ['-s', this.serial, 'install', '-r', '-g', apkPath], { stdio: 'pipe', timeout: 30000 });
136
+ }
137
+ catch {
138
+ return false;
139
+ }
140
+ }
141
+ }
142
+ catch {
143
+ return false;
144
+ }
145
+ // Re-enable the service (fixes stale state)
146
+ try {
147
+ (0, child_process_1.execFileSync)('adb', ['-s', this.serial, 'shell', 'settings', 'put', 'secure',
148
+ 'enabled_accessibility_services', '""'], { stdio: 'pipe', timeout: 3000 });
149
+ await new Promise(r => setTimeout(r, 1000));
150
+ (0, child_process_1.execFileSync)('adb', ['-s', this.serial, 'shell', 'settings', 'put', 'secure',
151
+ 'enabled_accessibility_services', SERVICE], { stdio: 'pipe', timeout: 3000 });
152
+ await new Promise(r => setTimeout(r, 1500));
153
+ }
154
+ catch {
155
+ return false;
156
+ }
157
+ // Verify service is running
158
+ try {
159
+ const output = (0, child_process_1.execFileSync)('adb', ['-s', this.serial, 'shell', 'settings', 'get', 'secure', 'enabled_accessibility_services'], { encoding: 'utf-8', stdio: 'pipe', timeout: 3000 });
160
+ return output.includes('com.testdroid.capture');
161
+ }
162
+ catch {
163
+ return false;
164
+ }
165
+ }
166
+ }
167
+ exports.EventCapture = EventCapture;
168
+ //# sourceMappingURL=event-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-capture.js","sourceRoot":"","sources":["../../src/recording/event-capture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { RecordingEvent, Recording } from '@testdroid-ai/shared';
2
+ export interface RecorderOptions {
3
+ includeScreenshots?: boolean;
4
+ useAppium?: boolean;
5
+ appiumUrl?: string;
6
+ }
7
+ export declare class Recorder {
8
+ private serial;
9
+ private options;
10
+ private events;
11
+ private capture;
12
+ private startTime;
13
+ private screenSize;
14
+ private onEventCallback?;
15
+ constructor(serial: string, options?: RecorderOptions);
16
+ /** Whether Appium/APK mode is active */
17
+ isAppiumActive(): boolean;
18
+ start(onEvent?: (event: RecordingEvent) => void): Promise<void>;
19
+ stop(): Recording & {
20
+ screenSize: {
21
+ width: number;
22
+ height: number;
23
+ };
24
+ };
25
+ /**
26
+ * Detects appPackage from elementId prefix in events.
27
+ * Format: "com.example.app:id/button_name" → "com.example.app"
28
+ */
29
+ private detectAppPackageFromEvents;
30
+ private getCurrentPackageFromDevice;
31
+ }
32
+ //# sourceMappingURL=recorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/recording/recorder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAIjE,MAAM,WAAW,eAAe;IAC9B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,QAAQ;IAQjB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,OAAO;IARjB,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,UAAU,CAAiC;IACnD,OAAO,CAAC,eAAe,CAAC,CAAkC;gBAGhD,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,eAAoB;IAQvC,wCAAwC;IACxC,cAAc,IAAI,OAAO;IAEnB,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBrE,IAAI,IAAI,SAAS,GAAG;QAAE,UAAU,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE;IA0BrE;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAsBlC,OAAO,CAAC,2BAA2B;CAqBpC"}
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Recorder = void 0;
4
+ const event_capture_1 = require("./event-capture");
5
+ const child_process_1 = require("child_process");
6
+ class Recorder {
7
+ serial;
8
+ options;
9
+ events = [];
10
+ capture;
11
+ startTime = 0;
12
+ screenSize = { width: 1080, height: 2400 };
13
+ onEventCallback;
14
+ constructor(serial, options = {}) {
15
+ this.serial = serial;
16
+ this.options = options;
17
+ this.capture = new event_capture_1.EventCapture(serial, {
18
+ useAppium: options.useAppium,
19
+ appiumUrl: options.appiumUrl,
20
+ });
21
+ }
22
+ /** Whether Appium/APK mode is active */
23
+ isAppiumActive() { return this.capture.isAppiumActive(); }
24
+ async start(onEvent) {
25
+ this.events = [];
26
+ this.startTime = Date.now();
27
+ this.onEventCallback = onEvent;
28
+ this.screenSize = await this.capture.getScreenSize();
29
+ await this.capture.start((event) => {
30
+ // Make timestamp relative to recording start
31
+ event.timestamp = event.timestamp - this.startTime;
32
+ // Store event
33
+ this.events.push(event);
34
+ // Notify callback
35
+ if (this.onEventCallback) {
36
+ this.onEventCallback(event);
37
+ }
38
+ });
39
+ }
40
+ stop() {
41
+ this.capture.stop();
42
+ const duration = Date.now() - this.startTime;
43
+ const eventsCopy = this.events.map(e => ({ ...e }));
44
+ // Detect appPackage: prefer capture source, then events, then ADB
45
+ const launcherPkgs = ['com.google.android.apps.nexuslauncher', 'com.android.launcher', 'com.android.launcher3'];
46
+ const appFromCapture = this.capture.getAppPackage();
47
+ const appFromEvents = this.detectAppPackageFromEvents(eventsCopy);
48
+ const appPackage = appFromEvents
49
+ || (appFromCapture && !launcherPkgs.includes(appFromCapture) ? appFromCapture : '')
50
+ || this.getCurrentPackageFromDevice();
51
+ return {
52
+ id: `rec_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
53
+ projectId: '',
54
+ events: eventsCopy,
55
+ deviceSerial: this.serial,
56
+ appPackage,
57
+ screenSize: this.screenSize,
58
+ duration,
59
+ createdAt: new Date(),
60
+ };
61
+ }
62
+ /**
63
+ * Detects appPackage from elementId prefix in events.
64
+ * Format: "com.example.app:id/button_name" → "com.example.app"
65
+ */
66
+ detectAppPackageFromEvents(events) {
67
+ const packageCounts = {};
68
+ const systemPackages = new Set([
69
+ 'com.google.android.apps.nexuslauncher',
70
+ 'com.android.launcher', 'com.android.launcher3',
71
+ 'com.android.systemui',
72
+ 'com.google.android.inputmethod', 'com.android.inputmethod',
73
+ ]);
74
+ for (const event of events) {
75
+ if (!event.elementId)
76
+ continue;
77
+ const match = event.elementId.match(/^([a-zA-Z][a-zA-Z0-9_.]+):id\//);
78
+ if (!match)
79
+ continue;
80
+ const pkg = match[1];
81
+ if (systemPackages.has(pkg))
82
+ continue;
83
+ packageCounts[pkg] = (packageCounts[pkg] || 0) + 1;
84
+ }
85
+ const sorted = Object.entries(packageCounts).sort((a, b) => b[1] - a[1]);
86
+ return sorted.length > 0 ? sorted[0][0] : '';
87
+ }
88
+ getCurrentPackageFromDevice() {
89
+ try {
90
+ const raw = (0, child_process_1.execFileSync)('adb', ['-s', this.serial, 'shell', 'dumpsys', 'activity', 'activities'], { encoding: 'utf-8', stdio: 'pipe', timeout: 5000 });
91
+ const match = raw.match(/topResumedActivity=.*?([a-zA-Z][a-zA-Z0-9_.]+)\//);
92
+ if (match)
93
+ return match[1];
94
+ }
95
+ catch { }
96
+ try {
97
+ const raw = (0, child_process_1.execFileSync)('adb', ['-s', this.serial, 'shell', 'dumpsys', 'window'], { encoding: 'utf-8', stdio: 'pipe', timeout: 5000 });
98
+ const match = raw.match(/mCurrentFocus=.*?([a-zA-Z][a-zA-Z0-9_.]+)\//);
99
+ if (match)
100
+ return match[1];
101
+ }
102
+ catch { }
103
+ return '';
104
+ }
105
+ }
106
+ exports.Recorder = Recorder;
107
+ //# sourceMappingURL=recorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recorder.js","sourceRoot":"","sources":["../../src/recording/recorder.ts"],"names":[],"mappings":"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"}