modestbench 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (332) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +131 -34
  3. package/dist/cli/commands/analyze.cjs +60 -0
  4. package/dist/cli/commands/analyze.cjs.map +1 -0
  5. package/dist/cli/commands/analyze.d.cts +35 -0
  6. package/dist/cli/commands/analyze.d.cts.map +1 -0
  7. package/dist/cli/commands/analyze.d.ts +35 -0
  8. package/dist/cli/commands/analyze.d.ts.map +1 -0
  9. package/dist/cli/commands/analyze.js +56 -0
  10. package/dist/cli/commands/analyze.js.map +1 -0
  11. package/dist/cli/commands/baseline.cjs +404 -0
  12. package/dist/cli/commands/baseline.cjs.map +1 -0
  13. package/dist/cli/commands/baseline.d.cts +72 -0
  14. package/dist/cli/commands/baseline.d.cts.map +1 -0
  15. package/dist/cli/commands/baseline.d.ts +72 -0
  16. package/dist/cli/commands/baseline.d.ts.map +1 -0
  17. package/dist/cli/commands/baseline.js +396 -0
  18. package/dist/cli/commands/baseline.js.map +1 -0
  19. package/dist/cli/commands/history.d.cts +1 -1
  20. package/dist/cli/commands/history.d.cts.map +1 -1
  21. package/dist/cli/commands/history.d.ts +1 -1
  22. package/dist/cli/commands/history.d.ts.map +1 -1
  23. package/dist/cli/commands/init.cjs +88 -155
  24. package/dist/cli/commands/init.cjs.map +1 -1
  25. package/dist/cli/commands/init.d.cts +4 -4
  26. package/dist/cli/commands/init.d.cts.map +1 -1
  27. package/dist/cli/commands/init.d.ts +4 -4
  28. package/dist/cli/commands/init.d.ts.map +1 -1
  29. package/dist/cli/commands/init.js +88 -155
  30. package/dist/cli/commands/init.js.map +1 -1
  31. package/dist/cli/commands/run.cjs +132 -114
  32. package/dist/cli/commands/run.cjs.map +1 -1
  33. package/dist/cli/commands/run.d.cts +16 -3
  34. package/dist/cli/commands/run.d.cts.map +1 -1
  35. package/dist/cli/commands/run.d.ts +16 -3
  36. package/dist/cli/commands/run.d.ts.map +1 -1
  37. package/dist/cli/commands/run.js +131 -80
  38. package/dist/cli/commands/run.js.map +1 -1
  39. package/dist/cli/index.cjs +583 -394
  40. package/dist/cli/index.cjs.map +1 -1
  41. package/dist/cli/index.d.cts +4 -16
  42. package/dist/cli/index.d.cts.map +1 -1
  43. package/dist/cli/index.d.ts +4 -16
  44. package/dist/cli/index.d.ts.map +1 -1
  45. package/dist/cli/index.js +575 -386
  46. package/dist/cli/index.js.map +1 -1
  47. package/dist/config/budget-schema.cjs +172 -0
  48. package/dist/config/budget-schema.cjs.map +1 -0
  49. package/dist/config/budget-schema.d.cts +59 -0
  50. package/dist/config/budget-schema.d.cts.map +1 -0
  51. package/dist/config/budget-schema.d.ts +59 -0
  52. package/dist/config/budget-schema.d.ts.map +1 -0
  53. package/dist/config/budget-schema.js +166 -0
  54. package/dist/config/budget-schema.js.map +1 -0
  55. package/dist/config/schema.cjs +182 -2
  56. package/dist/config/schema.cjs.map +1 -1
  57. package/dist/config/schema.d.cts +122 -3
  58. package/dist/config/schema.d.cts.map +1 -1
  59. package/dist/config/schema.d.ts +122 -3
  60. package/dist/config/schema.d.ts.map +1 -1
  61. package/dist/config/schema.js +180 -1
  62. package/dist/config/schema.js.map +1 -1
  63. package/dist/constants.cjs +45 -2
  64. package/dist/constants.cjs.map +1 -1
  65. package/dist/constants.d.cts +41 -0
  66. package/dist/constants.d.cts.map +1 -1
  67. package/dist/constants.d.ts +41 -0
  68. package/dist/constants.d.ts.map +1 -1
  69. package/dist/constants.js +44 -1
  70. package/dist/constants.js.map +1 -1
  71. package/dist/core/engine.cjs +103 -21
  72. package/dist/core/engine.cjs.map +1 -1
  73. package/dist/core/engine.d.cts +7 -7
  74. package/dist/core/engine.d.cts.map +1 -1
  75. package/dist/core/engine.d.ts +7 -7
  76. package/dist/core/engine.d.ts.map +1 -1
  77. package/dist/core/engine.js +104 -22
  78. package/dist/core/engine.js.map +1 -1
  79. package/dist/core/output-path-resolver.cjs +8 -1
  80. package/dist/core/output-path-resolver.cjs.map +1 -1
  81. package/dist/core/output-path-resolver.d.cts.map +1 -1
  82. package/dist/core/output-path-resolver.d.ts.map +1 -1
  83. package/dist/core/output-path-resolver.js +9 -2
  84. package/dist/core/output-path-resolver.js.map +1 -1
  85. package/dist/errors/base.cjs +12 -3
  86. package/dist/errors/base.cjs.map +1 -1
  87. package/dist/errors/base.d.cts +7 -0
  88. package/dist/errors/base.d.cts.map +1 -1
  89. package/dist/errors/base.d.ts +7 -0
  90. package/dist/errors/base.d.ts.map +1 -1
  91. package/dist/errors/base.js +10 -2
  92. package/dist/errors/base.js.map +1 -1
  93. package/dist/errors/budget.cjs +37 -0
  94. package/dist/errors/budget.cjs.map +1 -0
  95. package/dist/errors/budget.d.cts +31 -0
  96. package/dist/errors/budget.d.cts.map +1 -0
  97. package/dist/errors/budget.d.ts +31 -0
  98. package/dist/errors/budget.d.ts.map +1 -0
  99. package/dist/errors/budget.js +33 -0
  100. package/dist/errors/budget.js.map +1 -0
  101. package/dist/errors/index.cjs +4 -1
  102. package/dist/errors/index.cjs.map +1 -1
  103. package/dist/errors/index.d.cts +1 -0
  104. package/dist/errors/index.d.cts.map +1 -1
  105. package/dist/errors/index.d.ts +1 -0
  106. package/dist/errors/index.d.ts.map +1 -1
  107. package/dist/errors/index.js +2 -0
  108. package/dist/errors/index.js.map +1 -1
  109. package/dist/index.cjs +13 -1
  110. package/dist/index.cjs.map +1 -1
  111. package/dist/index.d.cts +5 -0
  112. package/dist/index.d.cts.map +1 -1
  113. package/dist/index.d.ts +5 -0
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.js +7 -0
  116. package/dist/index.js.map +1 -1
  117. package/dist/reporters/csv.cjs +37 -17
  118. package/dist/reporters/csv.cjs.map +1 -1
  119. package/dist/reporters/csv.d.cts +3 -6
  120. package/dist/reporters/csv.d.cts.map +1 -1
  121. package/dist/reporters/csv.d.ts +3 -6
  122. package/dist/reporters/csv.d.ts.map +1 -1
  123. package/dist/reporters/csv.js +37 -17
  124. package/dist/reporters/csv.js.map +1 -1
  125. package/dist/reporters/human.cjs +66 -40
  126. package/dist/reporters/human.cjs.map +1 -1
  127. package/dist/reporters/human.d.cts +14 -13
  128. package/dist/reporters/human.d.cts.map +1 -1
  129. package/dist/reporters/human.d.ts +14 -13
  130. package/dist/reporters/human.d.ts.map +1 -1
  131. package/dist/reporters/human.js +66 -40
  132. package/dist/reporters/human.js.map +1 -1
  133. package/dist/reporters/json.cjs +23 -48
  134. package/dist/reporters/json.cjs.map +1 -1
  135. package/dist/reporters/json.d.cts +2 -28
  136. package/dist/reporters/json.d.cts.map +1 -1
  137. package/dist/reporters/json.d.ts +2 -28
  138. package/dist/reporters/json.d.ts.map +1 -1
  139. package/dist/reporters/json.js +25 -50
  140. package/dist/reporters/json.js.map +1 -1
  141. package/dist/reporters/profile-human.cjs +149 -0
  142. package/dist/reporters/profile-human.cjs.map +1 -0
  143. package/dist/reporters/profile-human.d.cts +44 -0
  144. package/dist/reporters/profile-human.d.cts.map +1 -0
  145. package/dist/reporters/profile-human.d.ts +44 -0
  146. package/dist/reporters/profile-human.d.ts.map +1 -0
  147. package/dist/reporters/profile-human.js +142 -0
  148. package/dist/reporters/profile-human.js.map +1 -0
  149. package/dist/reporters/simple.cjs +64 -44
  150. package/dist/reporters/simple.cjs.map +1 -1
  151. package/dist/reporters/simple.d.cts +14 -14
  152. package/dist/reporters/simple.d.cts.map +1 -1
  153. package/dist/reporters/simple.d.ts +14 -14
  154. package/dist/reporters/simple.d.ts.map +1 -1
  155. package/dist/reporters/simple.js +64 -44
  156. package/dist/reporters/simple.js.map +1 -1
  157. package/dist/schema/modestbench-config.schema.json +153 -0
  158. package/dist/services/baseline-storage.cjs +151 -0
  159. package/dist/services/baseline-storage.cjs.map +1 -0
  160. package/dist/services/baseline-storage.d.cts +55 -0
  161. package/dist/services/baseline-storage.d.cts.map +1 -0
  162. package/dist/services/baseline-storage.d.ts +55 -0
  163. package/dist/services/baseline-storage.d.ts.map +1 -0
  164. package/dist/services/baseline-storage.js +147 -0
  165. package/dist/services/baseline-storage.js.map +1 -0
  166. package/dist/services/budget-evaluator.cjs +146 -0
  167. package/dist/services/budget-evaluator.cjs.map +1 -0
  168. package/dist/services/budget-evaluator.d.cts +29 -0
  169. package/dist/services/budget-evaluator.d.cts.map +1 -0
  170. package/dist/services/budget-evaluator.d.ts +29 -0
  171. package/dist/services/budget-evaluator.d.ts.map +1 -0
  172. package/dist/services/budget-evaluator.js +142 -0
  173. package/dist/services/budget-evaluator.js.map +1 -0
  174. package/dist/services/config-manager.cjs +23 -9
  175. package/dist/services/config-manager.cjs.map +1 -1
  176. package/dist/services/config-manager.d.cts +6 -1
  177. package/dist/services/config-manager.d.cts.map +1 -1
  178. package/dist/services/config-manager.d.ts +6 -1
  179. package/dist/services/config-manager.d.ts.map +1 -1
  180. package/dist/services/config-manager.js +23 -9
  181. package/dist/services/config-manager.js.map +1 -1
  182. package/dist/services/file-loader.cjs +3 -6
  183. package/dist/services/file-loader.cjs.map +1 -1
  184. package/dist/services/file-loader.d.cts.map +1 -1
  185. package/dist/services/file-loader.d.ts.map +1 -1
  186. package/dist/services/file-loader.js +3 -6
  187. package/dist/services/file-loader.js.map +1 -1
  188. package/dist/services/profiler/profile-filter.cjs +113 -0
  189. package/dist/services/profiler/profile-filter.cjs.map +1 -0
  190. package/dist/services/profiler/profile-filter.d.cts +20 -0
  191. package/dist/services/profiler/profile-filter.d.cts.map +1 -0
  192. package/dist/services/profiler/profile-filter.d.ts +20 -0
  193. package/dist/services/profiler/profile-filter.d.ts.map +1 -0
  194. package/dist/services/profiler/profile-filter.js +109 -0
  195. package/dist/services/profiler/profile-filter.js.map +1 -0
  196. package/dist/services/profiler/profile-parser.cjs +139 -0
  197. package/dist/services/profiler/profile-parser.cjs.map +1 -0
  198. package/dist/services/profiler/profile-parser.d.cts +18 -0
  199. package/dist/services/profiler/profile-parser.d.cts.map +1 -0
  200. package/dist/services/profiler/profile-parser.d.ts +18 -0
  201. package/dist/services/profiler/profile-parser.d.ts.map +1 -0
  202. package/dist/services/profiler/profile-parser.js +132 -0
  203. package/dist/services/profiler/profile-parser.js.map +1 -0
  204. package/dist/services/profiler/profile-runner.cjs +90 -0
  205. package/dist/services/profiler/profile-runner.cjs.map +1 -0
  206. package/dist/services/profiler/profile-runner.d.cts +29 -0
  207. package/dist/services/profiler/profile-runner.d.cts.map +1 -0
  208. package/dist/services/profiler/profile-runner.d.ts +29 -0
  209. package/dist/services/profiler/profile-runner.d.ts.map +1 -0
  210. package/dist/services/profiler/profile-runner.js +86 -0
  211. package/dist/services/profiler/profile-runner.js.map +1 -0
  212. package/dist/services/reporter-registry.cjs +18 -24
  213. package/dist/services/reporter-registry.cjs.map +1 -1
  214. package/dist/services/reporter-registry.d.cts +18 -40
  215. package/dist/services/reporter-registry.d.cts.map +1 -1
  216. package/dist/services/reporter-registry.d.ts +18 -40
  217. package/dist/services/reporter-registry.d.ts.map +1 -1
  218. package/dist/services/reporter-registry.js +18 -24
  219. package/dist/services/reporter-registry.js.map +1 -1
  220. package/dist/types/budgets.cjs +8 -0
  221. package/dist/types/budgets.cjs.map +1 -0
  222. package/dist/types/budgets.d.cts +149 -0
  223. package/dist/types/budgets.d.cts.map +1 -0
  224. package/dist/types/budgets.d.ts +149 -0
  225. package/dist/types/budgets.d.ts.map +1 -0
  226. package/dist/types/budgets.js +7 -0
  227. package/dist/types/budgets.js.map +1 -0
  228. package/dist/types/cli.cjs +2 -11
  229. package/dist/types/cli.cjs.map +1 -1
  230. package/dist/types/cli.d.cts +3 -227
  231. package/dist/types/cli.d.cts.map +1 -1
  232. package/dist/types/cli.d.ts +3 -227
  233. package/dist/types/cli.d.ts.map +1 -1
  234. package/dist/types/cli.js +2 -11
  235. package/dist/types/cli.js.map +1 -1
  236. package/dist/types/core.cjs +6 -1
  237. package/dist/types/core.cjs.map +1 -1
  238. package/dist/types/core.d.cts +13 -2
  239. package/dist/types/core.d.cts.map +1 -1
  240. package/dist/types/core.d.ts +13 -2
  241. package/dist/types/core.d.ts.map +1 -1
  242. package/dist/types/core.js +2 -1
  243. package/dist/types/core.js.map +1 -1
  244. package/dist/types/index.cjs +5 -0
  245. package/dist/types/index.cjs.map +1 -1
  246. package/dist/types/index.d.cts +2 -0
  247. package/dist/types/index.d.cts.map +1 -1
  248. package/dist/types/index.d.ts +2 -0
  249. package/dist/types/index.d.ts.map +1 -1
  250. package/dist/types/index.js +2 -0
  251. package/dist/types/index.js.map +1 -1
  252. package/dist/types/interfaces.d.cts +15 -8
  253. package/dist/types/interfaces.d.cts.map +1 -1
  254. package/dist/types/interfaces.d.ts +15 -8
  255. package/dist/types/interfaces.d.ts.map +1 -1
  256. package/dist/types/profiler.cjs +11 -0
  257. package/dist/types/profiler.cjs.map +1 -0
  258. package/dist/types/profiler.d.cts +100 -0
  259. package/dist/types/profiler.d.cts.map +1 -0
  260. package/dist/types/profiler.d.ts +100 -0
  261. package/dist/types/profiler.d.ts.map +1 -0
  262. package/dist/types/profiler.js +10 -0
  263. package/dist/types/profiler.js.map +1 -0
  264. package/dist/types/utility.cjs.map +1 -1
  265. package/dist/types/utility.d.cts +0 -8
  266. package/dist/types/utility.d.cts.map +1 -1
  267. package/dist/types/utility.d.ts +0 -8
  268. package/dist/types/utility.d.ts.map +1 -1
  269. package/dist/types/utility.js.map +1 -1
  270. package/dist/utils/identifiers.cjs +32 -0
  271. package/dist/utils/identifiers.cjs.map +1 -0
  272. package/dist/utils/identifiers.d.cts +32 -0
  273. package/dist/utils/identifiers.d.cts.map +1 -0
  274. package/dist/utils/identifiers.d.ts +32 -0
  275. package/dist/utils/identifiers.d.ts.map +1 -0
  276. package/dist/utils/identifiers.js +27 -0
  277. package/dist/utils/identifiers.js.map +1 -0
  278. package/dist/utils/package.cjs +40 -0
  279. package/dist/utils/package.cjs.map +1 -0
  280. package/dist/utils/package.d.cts +15 -0
  281. package/dist/utils/package.d.cts.map +1 -0
  282. package/dist/utils/package.d.ts +15 -0
  283. package/dist/utils/package.d.ts.map +1 -0
  284. package/dist/utils/package.js +33 -0
  285. package/dist/utils/package.js.map +1 -0
  286. package/dist/utils/type-guards.cjs +48 -0
  287. package/dist/utils/type-guards.cjs.map +1 -0
  288. package/dist/utils/type-guards.d.cts +22 -0
  289. package/dist/utils/type-guards.d.cts.map +1 -0
  290. package/dist/utils/type-guards.d.ts +22 -0
  291. package/dist/utils/type-guards.d.ts.map +1 -0
  292. package/dist/utils/type-guards.js +43 -0
  293. package/dist/utils/type-guards.js.map +1 -0
  294. package/package.json +10 -10
  295. package/src/cli/commands/analyze.ts +101 -0
  296. package/src/cli/commands/baseline.ts +577 -0
  297. package/src/cli/commands/history.ts +1 -1
  298. package/src/cli/commands/init.ts +105 -183
  299. package/src/cli/commands/run.ts +167 -98
  300. package/src/cli/index.ts +425 -183
  301. package/src/config/budget-schema.ts +189 -0
  302. package/src/config/schema.ts +260 -1
  303. package/src/constants.ts +53 -1
  304. package/src/core/engine.ts +151 -20
  305. package/src/core/output-path-resolver.ts +10 -2
  306. package/src/errors/base.ts +11 -2
  307. package/src/errors/budget.ts +38 -0
  308. package/src/errors/index.ts +3 -0
  309. package/src/index.ts +9 -0
  310. package/src/reporters/csv.ts +54 -25
  311. package/src/reporters/human.ts +88 -47
  312. package/src/reporters/json.ts +26 -71
  313. package/src/reporters/profile-human.ts +204 -0
  314. package/src/reporters/simple.ts +84 -53
  315. package/src/services/baseline-storage.ts +199 -0
  316. package/src/services/budget-evaluator.ts +182 -0
  317. package/src/services/config-manager.ts +23 -8
  318. package/src/services/file-loader.ts +3 -6
  319. package/src/services/profiler/profile-filter.ts +143 -0
  320. package/src/services/profiler/profile-parser.ts +194 -0
  321. package/src/services/profiler/profile-runner.ts +121 -0
  322. package/src/services/reporter-registry.ts +46 -81
  323. package/src/types/budgets.ts +180 -0
  324. package/src/types/cli.ts +5 -238
  325. package/src/types/core.ts +50 -10
  326. package/src/types/index.ts +5 -0
  327. package/src/types/interfaces.ts +16 -6
  328. package/src/types/profiler.ts +132 -0
  329. package/src/types/utility.ts +0 -10
  330. package/src/utils/identifiers.ts +58 -0
  331. package/src/utils/package.ts +35 -0
  332. package/src/utils/type-guards.ts +51 -0
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ /**
3
+ * Profile Parser Service
4
+ *
5
+ * Parses Chrome DevTools CPU profile format (*.cpuprofile files) generated by
6
+ * Node.js --cpu-prof flag. Extracts JavaScript function execution data
7
+ * including file paths, line numbers, hit counts, and percentages.
8
+ *
9
+ * @packageDocumentation
10
+ */
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.parseProfile = void 0;
16
+ const promises_1 = require("node:fs/promises");
17
+ const node_path_1 = __importDefault(require("node:path"));
18
+ const node_url_1 = require("node:url");
19
+ /**
20
+ * Parse a CPU profile file
21
+ *
22
+ * @param profilePath - Path to *.cpuprofile file
23
+ * @returns Parsed profile data
24
+ */
25
+ const parseProfile = async (profilePath) => {
26
+ // Read and parse JSON profile
27
+ const content = await (0, promises_1.readFile)(profilePath, 'utf-8');
28
+ const profile = JSON.parse(content);
29
+ // Extract functions and calculate statistics
30
+ return parseCpuProfile(profile, profilePath);
31
+ };
32
+ exports.parseProfile = parseProfile;
33
+ /**
34
+ * Parse CPU profile data structure
35
+ */
36
+ const parseCpuProfile = (profile, profilePath) => {
37
+ const functions = [];
38
+ let totalTicks = 0;
39
+ // Calculate total ticks from all node hit counts
40
+ for (const node of profile.nodes) {
41
+ totalTicks += node.hitCount || 0;
42
+ }
43
+ // Extract function information from nodes with hit counts
44
+ for (const node of profile.nodes) {
45
+ const hitCount = node.hitCount || 0;
46
+ if (hitCount === 0) {
47
+ continue; // Skip nodes with no samples
48
+ }
49
+ const { callFrame } = node;
50
+ const percentage = totalTicks > 0 ? (hitCount / totalTicks) * 100 : 0;
51
+ // Parse file path from URL
52
+ const filePath = parseFileUrl(callFrame.url);
53
+ // Determine category based on URL
54
+ const category = determineCategory(callFrame.url);
55
+ functions.push({
56
+ category,
57
+ file: filePath,
58
+ line: callFrame.lineNumber >= 0 ? callFrame.lineNumber + 1 : null, // DevTools uses 0-based line numbers
59
+ name: callFrame.functionName || '(anonymous)',
60
+ percentage,
61
+ ticks: hitCount,
62
+ });
63
+ }
64
+ // Calculate summary statistics
65
+ const javascriptTicks = functions
66
+ .filter((fn) => fn.category === 'JavaScript')
67
+ .reduce((sum, fn) => sum + fn.ticks, 0);
68
+ const cppTicks = functions
69
+ .filter((fn) => fn.category === 'C++')
70
+ .reduce((sum, fn) => sum + fn.ticks, 0);
71
+ const summary = {
72
+ cppTicks,
73
+ gcTicks: 0, // CPU profiles don't separate GC
74
+ javascriptTicks,
75
+ sharedLibraryTicks: 0,
76
+ totalTicks,
77
+ };
78
+ return {
79
+ functions,
80
+ logPath: profilePath,
81
+ summary,
82
+ totalTicks,
83
+ };
84
+ };
85
+ /**
86
+ * Parse file URL from call frame
87
+ */
88
+ const parseFileUrl = (url) => {
89
+ if (!url) {
90
+ return '<unknown>';
91
+ }
92
+ // Handle file:// URLs
93
+ if (url.startsWith('file://')) {
94
+ try {
95
+ return (0, node_url_1.fileURLToPath)(url);
96
+ }
97
+ catch {
98
+ // Fallback if URL is malformed
99
+ return node_path_1.default.normalize(url.replace('file://', ''));
100
+ }
101
+ }
102
+ // Handle node: internal modules
103
+ if (url.startsWith('node:')) {
104
+ return url;
105
+ }
106
+ // Handle plain paths
107
+ return node_path_1.default.normalize(url);
108
+ };
109
+ /**
110
+ * Determine function category based on URL
111
+ */
112
+ const determineCategory = (url) => {
113
+ if (!url) {
114
+ return 'Unknown';
115
+ }
116
+ // Node.js internals and native modules
117
+ if (url.startsWith('node:') || url.includes('[native code]')) {
118
+ return 'C++';
119
+ }
120
+ // eval'd code is JavaScript
121
+ if (url === '[eval]') {
122
+ return 'JavaScript';
123
+ }
124
+ // JavaScript files
125
+ if (url.endsWith('.js') ||
126
+ url.endsWith('.mjs') ||
127
+ url.endsWith('.cjs') ||
128
+ url.endsWith('.ts') ||
129
+ url.endsWith('.mts') ||
130
+ url.endsWith('.cts')) {
131
+ return 'JavaScript';
132
+ }
133
+ // Default to JavaScript for file:// URLs
134
+ if (url.startsWith('file://')) {
135
+ return 'JavaScript';
136
+ }
137
+ return 'Unknown';
138
+ };
139
+ //# sourceMappingURL=profile-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-parser.js","sourceRoot":"","sources":["../../../src/services/profiler/profile-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Profile Parser Service
3
+ *
4
+ * Parses Chrome DevTools CPU profile format (*.cpuprofile files) generated by
5
+ * Node.js --cpu-prof flag. Extracts JavaScript function execution data
6
+ * including file paths, line numbers, hit counts, and percentages.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+ import type { RawProfileData } from "../../types/profiler.cjs";
11
+ /**
12
+ * Parse a CPU profile file
13
+ *
14
+ * @param profilePath - Path to *.cpuprofile file
15
+ * @returns Parsed profile data
16
+ */
17
+ export declare const parseProfile: (profilePath: string) => Promise<RawProfileData>;
18
+ //# sourceMappingURL=profile-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-parser.d.ts","sourceRoot":"","sources":["../../../src/services/profiler/profile-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAGV,cAAc,EACf,iCAAgC;AA2BjC;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GACvB,aAAa,MAAM,KAClB,OAAO,CAAC,cAAc,CAOxB,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Profile Parser Service
3
+ *
4
+ * Parses Chrome DevTools CPU profile format (*.cpuprofile files) generated by
5
+ * Node.js --cpu-prof flag. Extracts JavaScript function execution data
6
+ * including file paths, line numbers, hit counts, and percentages.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+ import type { RawProfileData } from "../../types/profiler.js";
11
+ /**
12
+ * Parse a CPU profile file
13
+ *
14
+ * @param profilePath - Path to *.cpuprofile file
15
+ * @returns Parsed profile data
16
+ */
17
+ export declare const parseProfile: (profilePath: string) => Promise<RawProfileData>;
18
+ //# sourceMappingURL=profile-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-parser.d.ts","sourceRoot":"","sources":["../../../src/services/profiler/profile-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAGV,cAAc,EACf,gCAAgC;AA2BjC;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GACvB,aAAa,MAAM,KAClB,OAAO,CAAC,cAAc,CAOxB,CAAC"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Profile Parser Service
3
+ *
4
+ * Parses Chrome DevTools CPU profile format (*.cpuprofile files) generated by
5
+ * Node.js --cpu-prof flag. Extracts JavaScript function execution data
6
+ * including file paths, line numbers, hit counts, and percentages.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+ import { readFile } from 'node:fs/promises';
11
+ import path from 'node:path';
12
+ import { fileURLToPath } from 'node:url';
13
+ /**
14
+ * Parse a CPU profile file
15
+ *
16
+ * @param profilePath - Path to *.cpuprofile file
17
+ * @returns Parsed profile data
18
+ */
19
+ export const parseProfile = async (profilePath) => {
20
+ // Read and parse JSON profile
21
+ const content = await readFile(profilePath, 'utf-8');
22
+ const profile = JSON.parse(content);
23
+ // Extract functions and calculate statistics
24
+ return parseCpuProfile(profile, profilePath);
25
+ };
26
+ /**
27
+ * Parse CPU profile data structure
28
+ */
29
+ const parseCpuProfile = (profile, profilePath) => {
30
+ const functions = [];
31
+ let totalTicks = 0;
32
+ // Calculate total ticks from all node hit counts
33
+ for (const node of profile.nodes) {
34
+ totalTicks += node.hitCount || 0;
35
+ }
36
+ // Extract function information from nodes with hit counts
37
+ for (const node of profile.nodes) {
38
+ const hitCount = node.hitCount || 0;
39
+ if (hitCount === 0) {
40
+ continue; // Skip nodes with no samples
41
+ }
42
+ const { callFrame } = node;
43
+ const percentage = totalTicks > 0 ? (hitCount / totalTicks) * 100 : 0;
44
+ // Parse file path from URL
45
+ const filePath = parseFileUrl(callFrame.url);
46
+ // Determine category based on URL
47
+ const category = determineCategory(callFrame.url);
48
+ functions.push({
49
+ category,
50
+ file: filePath,
51
+ line: callFrame.lineNumber >= 0 ? callFrame.lineNumber + 1 : null, // DevTools uses 0-based line numbers
52
+ name: callFrame.functionName || '(anonymous)',
53
+ percentage,
54
+ ticks: hitCount,
55
+ });
56
+ }
57
+ // Calculate summary statistics
58
+ const javascriptTicks = functions
59
+ .filter((fn) => fn.category === 'JavaScript')
60
+ .reduce((sum, fn) => sum + fn.ticks, 0);
61
+ const cppTicks = functions
62
+ .filter((fn) => fn.category === 'C++')
63
+ .reduce((sum, fn) => sum + fn.ticks, 0);
64
+ const summary = {
65
+ cppTicks,
66
+ gcTicks: 0, // CPU profiles don't separate GC
67
+ javascriptTicks,
68
+ sharedLibraryTicks: 0,
69
+ totalTicks,
70
+ };
71
+ return {
72
+ functions,
73
+ logPath: profilePath,
74
+ summary,
75
+ totalTicks,
76
+ };
77
+ };
78
+ /**
79
+ * Parse file URL from call frame
80
+ */
81
+ const parseFileUrl = (url) => {
82
+ if (!url) {
83
+ return '<unknown>';
84
+ }
85
+ // Handle file:// URLs
86
+ if (url.startsWith('file://')) {
87
+ try {
88
+ return fileURLToPath(url);
89
+ }
90
+ catch {
91
+ // Fallback if URL is malformed
92
+ return path.normalize(url.replace('file://', ''));
93
+ }
94
+ }
95
+ // Handle node: internal modules
96
+ if (url.startsWith('node:')) {
97
+ return url;
98
+ }
99
+ // Handle plain paths
100
+ return path.normalize(url);
101
+ };
102
+ /**
103
+ * Determine function category based on URL
104
+ */
105
+ const determineCategory = (url) => {
106
+ if (!url) {
107
+ return 'Unknown';
108
+ }
109
+ // Node.js internals and native modules
110
+ if (url.startsWith('node:') || url.includes('[native code]')) {
111
+ return 'C++';
112
+ }
113
+ // eval'd code is JavaScript
114
+ if (url === '[eval]') {
115
+ return 'JavaScript';
116
+ }
117
+ // JavaScript files
118
+ if (url.endsWith('.js') ||
119
+ url.endsWith('.mjs') ||
120
+ url.endsWith('.cjs') ||
121
+ url.endsWith('.ts') ||
122
+ url.endsWith('.mts') ||
123
+ url.endsWith('.cts')) {
124
+ return 'JavaScript';
125
+ }
126
+ // Default to JavaScript for file:// URLs
127
+ if (url.startsWith('file://')) {
128
+ return 'JavaScript';
129
+ }
130
+ return 'Unknown';
131
+ };
132
+ //# sourceMappingURL=profile-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-parser.js","sourceRoot":"","sources":["../../../src/services/profiler/profile-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ /**
3
+ * Profile Runner Service
4
+ *
5
+ * Executes commands with Node.js CPU profiling enabled and captures profiler
6
+ * output to *.cpuprofile files in .modestbench/profiles/.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.runWithProfiling = void 0;
12
+ const glob_1 = require("glob");
13
+ const node_child_process_1 = require("node:child_process");
14
+ const promises_1 = require("node:fs/promises");
15
+ const node_path_1 = require("node:path");
16
+ /**
17
+ * Run a command with Node.js profiling enabled
18
+ *
19
+ * @param command - Command to run (e.g., "npm test")
20
+ * @param options - Execution options
21
+ * @returns Path to generated *.cpuprofile file
22
+ */
23
+ const runWithProfiling = async (command, options = {}) => {
24
+ const cwd = options.cwd || process.cwd();
25
+ // Create profiles directory
26
+ const profilesDir = (0, node_path_1.join)(cwd, '.modestbench', 'profiles');
27
+ await (0, promises_1.mkdir)(profilesDir, { recursive: true });
28
+ // Run command with NODE_OPTIONS="--cpu-prof --cpu-prof-dir=..."
29
+ const proc = (0, node_child_process_1.spawn)(command, {
30
+ cwd,
31
+ env: {
32
+ ...process.env,
33
+ ...options.env,
34
+ NODE_OPTIONS: `--cpu-prof --cpu-prof-dir=${profilesDir}`,
35
+ },
36
+ shell: true,
37
+ stdio: 'inherit',
38
+ });
39
+ // Wait for process to complete
40
+ await new Promise((resolve, reject) => {
41
+ const timeout = options.timeout
42
+ ? setTimeout(() => {
43
+ proc.kill();
44
+ reject(new Error(`Profile command timed out after ${options.timeout}ms`));
45
+ }, options.timeout)
46
+ : null;
47
+ proc.on('close', (code) => {
48
+ if (timeout) {
49
+ clearTimeout(timeout);
50
+ }
51
+ if (code === 0 || code === null) {
52
+ resolve();
53
+ }
54
+ else {
55
+ reject(new Error(`Profile command exited with code ${code}`));
56
+ }
57
+ });
58
+ proc.on('error', (err) => {
59
+ if (timeout) {
60
+ clearTimeout(timeout);
61
+ }
62
+ reject(err);
63
+ });
64
+ });
65
+ // Find generated *.cpuprofile file in profiles directory
66
+ const profileFiles = await (0, glob_1.glob)('*.cpuprofile', { cwd: profilesDir });
67
+ if (profileFiles.length === 0) {
68
+ throw new Error('No CPU profile generated. Ensure the command runs Node.js code.');
69
+ }
70
+ // Return most recent profile file
71
+ return await getMostRecentFile(profileFiles, profilesDir);
72
+ };
73
+ exports.runWithProfiling = runWithProfiling;
74
+ /**
75
+ * Get the most recently modified file from a list
76
+ */
77
+ const getMostRecentFile = async (files, cwd) => {
78
+ let mostRecent = files[0];
79
+ let mostRecentTime = (await (0, promises_1.stat)(`${cwd}/${mostRecent}`)).mtimeMs;
80
+ for (const file of files.slice(1)) {
81
+ const filePath = `${cwd}/${file}`;
82
+ const fileTime = (await (0, promises_1.stat)(filePath)).mtimeMs;
83
+ if (fileTime > mostRecentTime) {
84
+ mostRecent = file;
85
+ mostRecentTime = fileTime;
86
+ }
87
+ }
88
+ return `${cwd}/${mostRecent}`;
89
+ };
90
+ //# sourceMappingURL=profile-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-runner.js","sourceRoot":"","sources":["../../../src/services/profiler/profile-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Profile Runner Service
3
+ *
4
+ * Executes commands with Node.js CPU profiling enabled and captures profiler
5
+ * output to *.cpuprofile files in .modestbench/profiles/.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ /**
10
+ * Options for running with profiling
11
+ */
12
+ interface RunOptions {
13
+ /** Working directory */
14
+ cwd?: string;
15
+ /** Environment variables */
16
+ env?: NodeJS.ProcessEnv;
17
+ /** Timeout in milliseconds */
18
+ timeout?: number;
19
+ }
20
+ /**
21
+ * Run a command with Node.js profiling enabled
22
+ *
23
+ * @param command - Command to run (e.g., "npm test")
24
+ * @param options - Execution options
25
+ * @returns Path to generated *.cpuprofile file
26
+ */
27
+ export declare const runWithProfiling: (command: string, options?: RunOptions) => Promise<string>;
28
+ export {};
29
+ //# sourceMappingURL=profile-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-runner.d.ts","sourceRoot":"","sources":["../../../src/services/profiler/profile-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH;;GAEG;AACH,UAAU,UAAU;IAClB,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,4BAA4B;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IAExB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAC3B,SAAS,MAAM,EACf,UAAS,UAAe,KACvB,OAAO,CAAC,MAAM,CA4DhB,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Profile Runner Service
3
+ *
4
+ * Executes commands with Node.js CPU profiling enabled and captures profiler
5
+ * output to *.cpuprofile files in .modestbench/profiles/.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ /**
10
+ * Options for running with profiling
11
+ */
12
+ interface RunOptions {
13
+ /** Working directory */
14
+ cwd?: string;
15
+ /** Environment variables */
16
+ env?: NodeJS.ProcessEnv;
17
+ /** Timeout in milliseconds */
18
+ timeout?: number;
19
+ }
20
+ /**
21
+ * Run a command with Node.js profiling enabled
22
+ *
23
+ * @param command - Command to run (e.g., "npm test")
24
+ * @param options - Execution options
25
+ * @returns Path to generated *.cpuprofile file
26
+ */
27
+ export declare const runWithProfiling: (command: string, options?: RunOptions) => Promise<string>;
28
+ export {};
29
+ //# sourceMappingURL=profile-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-runner.d.ts","sourceRoot":"","sources":["../../../src/services/profiler/profile-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH;;GAEG;AACH,UAAU,UAAU;IAClB,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,4BAA4B;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IAExB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAC3B,SAAS,MAAM,EACf,UAAS,UAAe,KACvB,OAAO,CAAC,MAAM,CA4DhB,CAAC"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Profile Runner Service
3
+ *
4
+ * Executes commands with Node.js CPU profiling enabled and captures profiler
5
+ * output to *.cpuprofile files in .modestbench/profiles/.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ import { glob } from 'glob';
10
+ import { spawn } from 'node:child_process';
11
+ import { mkdir, stat } from 'node:fs/promises';
12
+ import { join } from 'node:path';
13
+ /**
14
+ * Run a command with Node.js profiling enabled
15
+ *
16
+ * @param command - Command to run (e.g., "npm test")
17
+ * @param options - Execution options
18
+ * @returns Path to generated *.cpuprofile file
19
+ */
20
+ export const runWithProfiling = async (command, options = {}) => {
21
+ const cwd = options.cwd || process.cwd();
22
+ // Create profiles directory
23
+ const profilesDir = join(cwd, '.modestbench', 'profiles');
24
+ await mkdir(profilesDir, { recursive: true });
25
+ // Run command with NODE_OPTIONS="--cpu-prof --cpu-prof-dir=..."
26
+ const proc = spawn(command, {
27
+ cwd,
28
+ env: {
29
+ ...process.env,
30
+ ...options.env,
31
+ NODE_OPTIONS: `--cpu-prof --cpu-prof-dir=${profilesDir}`,
32
+ },
33
+ shell: true,
34
+ stdio: 'inherit',
35
+ });
36
+ // Wait for process to complete
37
+ await new Promise((resolve, reject) => {
38
+ const timeout = options.timeout
39
+ ? setTimeout(() => {
40
+ proc.kill();
41
+ reject(new Error(`Profile command timed out after ${options.timeout}ms`));
42
+ }, options.timeout)
43
+ : null;
44
+ proc.on('close', (code) => {
45
+ if (timeout) {
46
+ clearTimeout(timeout);
47
+ }
48
+ if (code === 0 || code === null) {
49
+ resolve();
50
+ }
51
+ else {
52
+ reject(new Error(`Profile command exited with code ${code}`));
53
+ }
54
+ });
55
+ proc.on('error', (err) => {
56
+ if (timeout) {
57
+ clearTimeout(timeout);
58
+ }
59
+ reject(err);
60
+ });
61
+ });
62
+ // Find generated *.cpuprofile file in profiles directory
63
+ const profileFiles = await glob('*.cpuprofile', { cwd: profilesDir });
64
+ if (profileFiles.length === 0) {
65
+ throw new Error('No CPU profile generated. Ensure the command runs Node.js code.');
66
+ }
67
+ // Return most recent profile file
68
+ return await getMostRecentFile(profileFiles, profilesDir);
69
+ };
70
+ /**
71
+ * Get the most recently modified file from a list
72
+ */
73
+ const getMostRecentFile = async (files, cwd) => {
74
+ let mostRecent = files[0];
75
+ let mostRecentTime = (await stat(`${cwd}/${mostRecent}`)).mtimeMs;
76
+ for (const file of files.slice(1)) {
77
+ const filePath = `${cwd}/${file}`;
78
+ const fileTime = (await stat(filePath)).mtimeMs;
79
+ if (fileTime > mostRecentTime) {
80
+ mostRecent = file;
81
+ mostRecentTime = fileTime;
82
+ }
83
+ }
84
+ return `${cwd}/${mostRecent}`;
85
+ };
86
+ //# sourceMappingURL=profile-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-runner.js","sourceRoot":"","sources":["../../../src/services/profiler/profile-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAgBjC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EACnC,OAAe,EACf,UAAsB,EAAE,EACP,EAAE;IACnB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAEzC,4BAA4B;IAC5B,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,EAAE,UAAU,CAAC,CAAC;IAC1D,MAAM,KAAK,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE9C,gEAAgE;IAChE,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,EAAE;QAC1B,GAAG;QACH,GAAG,EAAE;YACH,GAAG,OAAO,CAAC,GAAG;YACd,GAAG,OAAO,CAAC,GAAG;YACd,YAAY,EAAE,6BAA6B,WAAW,EAAE;SACzD;QACD,KAAK,EAAE,IAAI;QACX,KAAK,EAAE,SAAS;KACjB,CAAC,CAAC;IAEH,+BAA+B;IAC/B,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO;YAC7B,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE;gBACd,IAAI,CAAC,IAAI,EAAE,CAAC;gBACZ,MAAM,CACJ,IAAI,KAAK,CAAC,mCAAmC,OAAO,CAAC,OAAO,IAAI,CAAC,CAClE,CAAC;YACJ,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC;YACrB,CAAC,CAAC,IAAI,CAAC;QAET,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,OAAO,EAAE,CAAC;gBACZ,YAAY,CAAC,OAAO,CAAC,CAAC;YACxB,CAAC;YACD,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAChC,OAAO,EAAE,CAAC;YACZ,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,KAAK,CAAC,oCAAoC,IAAI,EAAE,CAAC,CAAC,CAAC;YAChE,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACvB,IAAI,OAAO,EAAE,CAAC;gBACZ,YAAY,CAAC,OAAO,CAAC,CAAC;YACxB,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,yDAAyD;IACzD,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;IAEtE,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,iEAAiE,CAClE,CAAC;IACJ,CAAC;IAED,kCAAkC;IAClC,OAAO,MAAM,iBAAiB,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;AAC5D,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,iBAAiB,GAAG,KAAK,EAC7B,KAAe,EACf,GAAW,EACM,EAAE;IACnB,IAAI,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,cAAc,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,GAAG,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;IAElE,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;QAChD,IAAI,QAAQ,GAAG,cAAc,EAAE,CAAC;YAC9B,UAAU,GAAG,IAAI,CAAC;YAClB,cAAc,GAAG,QAAQ,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,OAAO,GAAG,GAAG,IAAI,UAAU,EAAE,CAAC;AAChC,CAAC,CAAC"}