@yasserkhanorg/e2e-agents 0.3.3 → 0.3.5

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 (48) hide show
  1. package/README.md +66 -3
  2. package/dist/agent/ai_flow_analysis.d.ts +12 -0
  3. package/dist/agent/ai_flow_analysis.d.ts.map +1 -0
  4. package/dist/agent/ai_flow_analysis.js +326 -0
  5. package/dist/agent/ai_mapping.d.ts +14 -0
  6. package/dist/agent/ai_mapping.d.ts.map +1 -0
  7. package/dist/agent/ai_mapping.js +374 -0
  8. package/dist/agent/config.d.ts +32 -0
  9. package/dist/agent/config.d.ts.map +1 -1
  10. package/dist/agent/config.js +187 -1
  11. package/dist/agent/flow_catalog.d.ts.map +1 -1
  12. package/dist/agent/flow_catalog.js +10 -1
  13. package/dist/agent/operational_insights.d.ts +1 -1
  14. package/dist/agent/operational_insights.d.ts.map +1 -1
  15. package/dist/agent/operational_insights.js +2 -1
  16. package/dist/agent/pipeline.d.ts +2 -0
  17. package/dist/agent/pipeline.d.ts.map +1 -1
  18. package/dist/agent/pipeline.js +409 -68
  19. package/dist/agent/plan.d.ts +40 -0
  20. package/dist/agent/plan.d.ts.map +1 -1
  21. package/dist/agent/plan.js +159 -4
  22. package/dist/agent/report.d.ts +13 -2
  23. package/dist/agent/report.d.ts.map +1 -1
  24. package/dist/agent/report.js +9 -0
  25. package/dist/agent/runner.d.ts.map +1 -1
  26. package/dist/agent/runner.js +246 -19
  27. package/dist/agent/tests.d.ts +1 -1
  28. package/dist/agent/tests.d.ts.map +1 -1
  29. package/dist/api.d.ts.map +1 -1
  30. package/dist/api.js +1 -0
  31. package/dist/cli.js +97 -4
  32. package/dist/esm/agent/ai_flow_analysis.js +323 -0
  33. package/dist/esm/agent/ai_mapping.js +371 -0
  34. package/dist/esm/agent/config.js +187 -1
  35. package/dist/esm/agent/flow_catalog.js +10 -1
  36. package/dist/esm/agent/operational_insights.js +2 -1
  37. package/dist/esm/agent/pipeline.js +409 -68
  38. package/dist/esm/agent/plan.js +158 -5
  39. package/dist/esm/agent/report.js +9 -0
  40. package/dist/esm/agent/runner.js +246 -19
  41. package/dist/esm/api.js +2 -1
  42. package/dist/esm/cli.js +98 -5
  43. package/dist/esm/provider_factory.js +7 -3
  44. package/dist/provider_factory.d.ts.map +1 -1
  45. package/dist/provider_factory.js +7 -3
  46. package/package.json +4 -1
  47. package/schemas/impact.schema.json +40 -3
  48. package/schemas/plan.schema.json +48 -0
@@ -14,6 +14,8 @@ export interface DecisionSummary {
14
14
  }
15
15
  export interface PlanReport {
16
16
  schemaVersion: '1.0.0';
17
+ runId: string;
18
+ sourceRunId?: string;
17
19
  generatedAt: string;
18
20
  source: 'impact';
19
21
  runSet: RecommendedRunSet;
@@ -23,6 +25,13 @@ export interface PlanReport {
23
25
  requiredNewTests: string[];
24
26
  policy: PolicyEvaluation;
25
27
  decision: DecisionSummary;
28
+ enforcement: {
29
+ mode: PolicyConfig['enforcementMode'];
30
+ blockOnActions: CiAction[];
31
+ matchedAction: boolean;
32
+ shouldFail: boolean;
33
+ summary: string;
34
+ };
26
35
  insights?: {
27
36
  flaky?: {
28
37
  highRiskRecommendedTests: Array<{
@@ -79,13 +88,44 @@ export interface PlanReport {
79
88
  warnings: number;
80
89
  };
81
90
  }
91
+ export declare function refreshPlanEnforcement(plan: PlanReport): PlanReport;
82
92
  export declare function buildPlanFromImpactReport(impact: ReportData, policyOverride?: Partial<PolicyConfig>): PlanReport;
83
93
  export declare function attachDeveloperActions(plan: PlanReport, context: {
84
94
  appPath: string;
85
95
  testsRoot: string;
86
96
  sinceRef?: string;
97
+ configPath?: string;
87
98
  }): PlanReport;
88
99
  export declare function writePlanReport(appRoot: string, plan: PlanReport): string;
89
100
  export declare function renderCiSummaryMarkdown(plan: PlanReport): string;
101
+ export interface PlanMetricEvent {
102
+ schemaVersion: '1.0.0';
103
+ timestamp: string;
104
+ runId: string;
105
+ sourceRunId?: string;
106
+ action: CiAction;
107
+ runSet: RecommendedRunSet;
108
+ confidence: number;
109
+ changedFiles: number;
110
+ impactedFlows: number;
111
+ uncoveredP0P1Flows: number;
112
+ warnings: number;
113
+ enforcementMode: PolicyConfig['enforcementMode'];
114
+ enforcementShouldFail: boolean;
115
+ }
116
+ export interface PlanMetricsSummary {
117
+ schemaVersion: '1.0.0';
118
+ generatedAt: string;
119
+ totalRuns: number;
120
+ averageConfidence: number;
121
+ byAction: Record<CiAction, number>;
122
+ byRunSet: Record<RecommendedRunSet, number>;
123
+ blockingRecommendations: number;
124
+ blockingRate: number;
125
+ }
126
+ export declare function appendPlanMetrics(appRoot: string, plan: PlanReport): {
127
+ eventsPath: string;
128
+ summaryPath: string;
129
+ };
90
130
  export declare function writeCiSummary(appRoot: string, markdown: string, relativePath?: string): string;
91
131
  //# sourceMappingURL=plan.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../src/agent/plan.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../src/agent/plan.ts"],"names":[],"mappings":"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"}
@@ -2,10 +2,12 @@
2
2
  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
3
3
  // See LICENSE.txt for license information.
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.refreshPlanEnforcement = refreshPlanEnforcement;
5
6
  exports.buildPlanFromImpactReport = buildPlanFromImpactReport;
6
7
  exports.attachDeveloperActions = attachDeveloperActions;
7
8
  exports.writePlanReport = writePlanReport;
8
9
  exports.renderCiSummaryMarkdown = renderCiSummaryMarkdown;
10
+ exports.appendPlanMetrics = appendPlanMetrics;
9
11
  exports.writeCiSummary = writeCiSummary;
10
12
  const fs_1 = require("fs");
11
13
  const path_1 = require("path");
@@ -27,6 +29,8 @@ const DEFAULT_POLICY = {
27
29
  '**/*.sql',
28
30
  '**/webhook/**',
29
31
  ],
32
+ enforcementMode: 'advisory',
33
+ blockOnActions: ['must-add-tests'],
30
34
  };
31
35
  function countPriority(flows) {
32
36
  const counts = { p0: 0, p1: 0, p2: 0 };
@@ -54,12 +58,18 @@ function computeConfidence(impact, p0, p1) {
54
58
  if (impact.impactModel.flowMapping === 'catalog') {
55
59
  confidence += 4;
56
60
  }
61
+ else if (impact.impactModel.flowMapping === 'ai') {
62
+ confidence += 4;
63
+ }
57
64
  if (impact.impactModel.testMapping === 'catalog') {
58
65
  confidence += 4;
59
66
  }
60
67
  else if (impact.impactModel.testMapping === 'traceability') {
61
68
  confidence += 6;
62
69
  }
70
+ else if (impact.impactModel.testMapping === 'ai') {
71
+ confidence += 4;
72
+ }
63
73
  if (impact.impactModel.confidenceClass === 'medium') {
64
74
  confidence -= 4;
65
75
  }
@@ -109,7 +119,7 @@ function pickRunSet(impact, p0, confidence, policy) {
109
119
  }
110
120
  if (impact.impactModel?.confidenceClass === 'low') {
111
121
  triggeredRules.push('low-traceability');
112
- reasons.push('Impact mapping confidence is low (heuristic traceability).');
122
+ reasons.push('Impact mapping confidence is low.');
113
123
  }
114
124
  if (impact.impactModel?.traceability?.manifestFound && impact.impactModel.traceability.coverageRatio < 0.4) {
115
125
  triggeredRules.push('traceability-low-coverage');
@@ -172,6 +182,61 @@ function buildDecision(runSet, confidence, impact, policy) {
172
182
  summary: `Execute the ${runSet} suite for this change set.`,
173
183
  };
174
184
  }
185
+ function evaluateEnforcement(decision, policy) {
186
+ const blockOnActions = (policy.blockOnActions && policy.blockOnActions.length > 0)
187
+ ? [...policy.blockOnActions]
188
+ : ['must-add-tests'];
189
+ const matchedAction = blockOnActions.includes(decision.action);
190
+ if (policy.enforcementMode === 'block' && matchedAction) {
191
+ return {
192
+ mode: policy.enforcementMode,
193
+ blockOnActions,
194
+ matchedAction,
195
+ shouldFail: true,
196
+ summary: `Blocking mode active: decision "${decision.action}" is configured to fail CI.`,
197
+ };
198
+ }
199
+ if (policy.enforcementMode === 'warn' && matchedAction) {
200
+ return {
201
+ mode: policy.enforcementMode,
202
+ blockOnActions,
203
+ matchedAction,
204
+ shouldFail: false,
205
+ summary: `Warning mode active: decision "${decision.action}" is advisory-only for CI.`,
206
+ };
207
+ }
208
+ if (policy.enforcementMode === 'block') {
209
+ return {
210
+ mode: policy.enforcementMode,
211
+ blockOnActions,
212
+ matchedAction,
213
+ shouldFail: false,
214
+ summary: `Blocking mode active, but decision "${decision.action}" is not configured for CI failure.`,
215
+ };
216
+ }
217
+ if (policy.enforcementMode === 'warn') {
218
+ return {
219
+ mode: policy.enforcementMode,
220
+ blockOnActions,
221
+ matchedAction,
222
+ shouldFail: false,
223
+ summary: `Warning mode active, but decision "${decision.action}" is not configured for warning.`,
224
+ };
225
+ }
226
+ return {
227
+ mode: policy.enforcementMode,
228
+ blockOnActions,
229
+ matchedAction,
230
+ shouldFail: false,
231
+ summary: 'Advisory mode active: recommendations do not fail CI by default.',
232
+ };
233
+ }
234
+ function refreshPlanEnforcement(plan) {
235
+ return {
236
+ ...plan,
237
+ enforcement: evaluateEnforcement(plan.decision, plan.policy.applied),
238
+ };
239
+ }
175
240
  function buildPlanFromImpactReport(impact, policyOverride) {
176
241
  if (impact.mode !== 'impact') {
177
242
  throw new Error(`Plan generation requires impact report data, received mode=${impact.mode}`);
@@ -181,9 +246,14 @@ function buildPlanFromImpactReport(impact, policyOverride) {
181
246
  const confidence = computeConfidence(impact, p0, p1);
182
247
  const runSet = pickRunSet(impact, p0, confidence, policy);
183
248
  const decision = buildDecision(runSet.runSet, confidence, impact, policy);
249
+ const enforcement = evaluateEnforcement(decision, policy);
184
250
  const requiredNewTests = impact.gaps.map((flow) => `${flow.id}: ${flow.name}`);
251
+ const sourceRunId = impact.runMetadata?.runId;
252
+ const runId = `plan-${sourceRunId || Date.now().toString(36)}`;
185
253
  return {
186
254
  schemaVersion: '1.0.0',
255
+ runId,
256
+ sourceRunId,
187
257
  generatedAt: new Date().toISOString(),
188
258
  source: 'impact',
189
259
  runSet: runSet.runSet,
@@ -197,6 +267,7 @@ function buildPlanFromImpactReport(impact, policyOverride) {
197
267
  applied: policy,
198
268
  },
199
269
  decision,
270
+ enforcement,
200
271
  metrics: {
201
272
  changedFiles: impact.changedFiles.length,
202
273
  impactedFlows: impact.flows.length,
@@ -210,6 +281,9 @@ function buildPlanFromImpactReport(impact, policyOverride) {
210
281
  }
211
282
  function attachDeveloperActions(plan, context) {
212
283
  const safeSince = context.sinceRef ? ` --since "${context.sinceRef}"` : '';
284
+ const generateBaseCommand = context.configPath
285
+ ? `npx e2e-ai-agents approve-and-generate --config "${context.configPath}" --pipeline --pipeline-mcp --pipeline-mcp-only${safeSince}`
286
+ : `npx e2e-ai-agents approve-and-generate --path "${context.appPath}" --tests-root "${context.testsRoot}" --pipeline --pipeline-mcp --pipeline-mcp-only${safeSince}`;
213
287
  const runRecommendedTests = plan.recommendedTests.length > 0
214
288
  ? `node -e "const fs=require('fs'); const p=JSON.parse(fs.readFileSync('${context.testsRoot}/.e2e-ai-agents/plan.json','utf8')); const tests=p.recommendedTests.map((t)=>t.replace(/ \\(flags:.*\\)$/,'')); console.log(tests.join(' '));" | xargs npx playwright test`
215
289
  : undefined;
@@ -220,9 +294,9 @@ function attachDeveloperActions(plan, context) {
220
294
  runRecommendedTests,
221
295
  runSmokeSuite: 'npx playwright test --grep @smoke --project=chrome',
222
296
  runFullSuite: 'npx playwright test --project=chrome',
223
- approveAndGenerate: `npx e2e-ai-agents approve-and-generate --path "${context.appPath}" --tests-root "${context.testsRoot}" --pipeline --pipeline-mcp${safeSince}`,
224
- generateMissingTests: `npx e2e-ai-agents approve-and-generate --path "${context.appPath}" --tests-root "${context.testsRoot}" --pipeline${safeSince}`,
225
- healGeneratedTests: `npx e2e-ai-agents approve-and-generate --path "${context.appPath}" --tests-root "${context.testsRoot}" --pipeline --pipeline-mcp${safeSince}`,
297
+ approveAndGenerate: generateBaseCommand,
298
+ generateMissingTests: generateBaseCommand,
299
+ healGeneratedTests: generateBaseCommand,
226
300
  commitGeneratedTests: `npx e2e-ai-agents finalize-generated-tests --path "${context.appPath}" --tests-root "${context.testsRoot}" --commit-message "test(e2e): add generated coverage and healed specs"`,
227
301
  openPullRequest: `npx e2e-ai-agents finalize-generated-tests --path "${context.appPath}" --tests-root "${context.testsRoot}" --create-pr`,
228
302
  },
@@ -243,6 +317,8 @@ function renderCiSummaryMarkdown(plan) {
243
317
  lines.push(`- Run set: \`${plan.runSet}\``);
244
318
  lines.push(`- Confidence: \`${plan.confidence}\``);
245
319
  lines.push(`- Summary: ${plan.decision.summary}`);
320
+ lines.push(`- Enforcement: mode=\`${plan.enforcement.mode}\`, shouldFail=\`${plan.enforcement.shouldFail}\``);
321
+ lines.push(`- Enforcement detail: ${plan.enforcement.summary}`);
246
322
  if (plan.policy.triggeredRules.length > 0) {
247
323
  lines.push(`- Policy triggers: ${plan.policy.triggeredRules.join(', ')}`);
248
324
  }
@@ -322,6 +398,85 @@ function renderCiSummaryMarkdown(plan) {
322
398
  }
323
399
  return lines.join('\n');
324
400
  }
401
+ const PLAN_METRICS_EVENTS_PATH = '.e2e-ai-agents/metrics.jsonl';
402
+ const PLAN_METRICS_SUMMARY_PATH = '.e2e-ai-agents/metrics-summary.json';
403
+ function parsePlanMetricLine(line) {
404
+ const trimmed = line.trim();
405
+ if (!trimmed) {
406
+ return null;
407
+ }
408
+ try {
409
+ const parsed = JSON.parse(trimmed);
410
+ if (!parsed || parsed.schemaVersion !== '1.0.0' || typeof parsed.runId !== 'string') {
411
+ return null;
412
+ }
413
+ return parsed;
414
+ }
415
+ catch {
416
+ return null;
417
+ }
418
+ }
419
+ function appendPlanMetrics(appRoot, plan) {
420
+ const baseDir = (0, path_1.join)(appRoot, '.e2e-ai-agents');
421
+ (0, fs_1.mkdirSync)(baseDir, { recursive: true });
422
+ const eventsPath = (0, path_1.join)(appRoot, PLAN_METRICS_EVENTS_PATH);
423
+ const summaryPath = (0, path_1.join)(appRoot, PLAN_METRICS_SUMMARY_PATH);
424
+ const event = {
425
+ schemaVersion: '1.0.0',
426
+ timestamp: new Date().toISOString(),
427
+ runId: plan.runId,
428
+ sourceRunId: plan.sourceRunId,
429
+ action: plan.decision.action,
430
+ runSet: plan.runSet,
431
+ confidence: plan.confidence,
432
+ changedFiles: plan.metrics.changedFiles,
433
+ impactedFlows: plan.metrics.impactedFlows,
434
+ uncoveredP0P1Flows: plan.metrics.uncoveredP0P1Flows,
435
+ warnings: plan.metrics.warnings,
436
+ enforcementMode: plan.enforcement.mode,
437
+ enforcementShouldFail: plan.enforcement.shouldFail,
438
+ };
439
+ (0, fs_1.appendFileSync)(eventsPath, `${JSON.stringify(event)}\n`, 'utf-8');
440
+ const allEvents = (0, fs_1.existsSync)(eventsPath)
441
+ ? (0, fs_1.readFileSync)(eventsPath, 'utf-8')
442
+ .split('\n')
443
+ .map(parsePlanMetricLine)
444
+ .filter((item) => Boolean(item))
445
+ : [event];
446
+ const byAction = {
447
+ 'run-now': 0,
448
+ 'must-add-tests': 0,
449
+ 'safe-to-merge': 0,
450
+ };
451
+ const byRunSet = {
452
+ smoke: 0,
453
+ targeted: 0,
454
+ full: 0,
455
+ };
456
+ let totalConfidence = 0;
457
+ let blockingRecommendations = 0;
458
+ for (const metricEvent of allEvents) {
459
+ byAction[metricEvent.action] += 1;
460
+ byRunSet[metricEvent.runSet] += 1;
461
+ totalConfidence += metricEvent.confidence;
462
+ if (metricEvent.enforcementShouldFail) {
463
+ blockingRecommendations += 1;
464
+ }
465
+ }
466
+ const totalRuns = allEvents.length;
467
+ const summary = {
468
+ schemaVersion: '1.0.0',
469
+ generatedAt: new Date().toISOString(),
470
+ totalRuns,
471
+ averageConfidence: totalRuns > 0 ? Number((totalConfidence / totalRuns).toFixed(2)) : 0,
472
+ byAction,
473
+ byRunSet,
474
+ blockingRecommendations,
475
+ blockingRate: totalRuns > 0 ? Number((blockingRecommendations / totalRuns).toFixed(4)) : 0,
476
+ };
477
+ (0, fs_1.writeFileSync)(summaryPath, JSON.stringify(summary, null, 2), 'utf-8');
478
+ return { eventsPath, summaryPath };
479
+ }
325
480
  function writeCiSummary(appRoot, markdown, relativePath = '.e2e-ai-agents/ci-summary.md') {
326
481
  const fullPath = (0, path_1.join)(appRoot, relativePath);
327
482
  const dir = (0, path_1.dirname)(fullPath);
@@ -5,6 +5,15 @@ import type { DataTestIdSuggestion } from './selectors.js';
5
5
  import type { GapTestSuggestion } from './gap_suggestions.js';
6
6
  export interface ReportData {
7
7
  mode: 'impact' | 'gap';
8
+ runMetadata?: {
9
+ runId: string;
10
+ startedAt: string;
11
+ completedAt: string;
12
+ durationMs: number;
13
+ sinceRef: string;
14
+ appPath: string;
15
+ testsRoot: string;
16
+ };
8
17
  changedFiles: string[];
9
18
  flows: FlowImpact[];
10
19
  coverage: FlowCoverage[];
@@ -20,8 +29,8 @@ export interface ReportData {
20
29
  recommendedTests?: string[];
21
30
  impactModel?: {
22
31
  schemaVersion: '1.0.0';
23
- flowMapping: 'catalog' | 'heuristic';
24
- testMapping: 'catalog' | 'traceability' | 'heuristic';
32
+ flowMapping: 'catalog' | 'heuristic' | 'ai';
33
+ testMapping: 'catalog' | 'traceability' | 'heuristic' | 'ai';
25
34
  confidenceClass: 'high' | 'medium' | 'low';
26
35
  traceability?: {
27
36
  source: 'manifest';
@@ -65,6 +74,8 @@ export interface ReportData {
65
74
  generateStatus: string;
66
75
  healStatus?: string;
67
76
  error?: string;
77
+ failureCategory?: string;
78
+ failureCode?: string;
68
79
  }>;
69
80
  warnings: string[];
70
81
  mcp?: {
@@ -1 +1 @@
1
- {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/agent/report.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/agent/report.ts"],"names":[],"mappings":"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"}
@@ -45,6 +45,12 @@ function writeReport(appRoot, config, data) {
45
45
  const markdownLines = [];
46
46
  markdownLines.push(`# ${data.mode === 'impact' ? 'Impact Analysis' : 'Gap Analysis'} Report`);
47
47
  markdownLines.push('');
48
+ if (data.runMetadata) {
49
+ markdownLines.push(`Run ID: ${data.runMetadata.runId}`);
50
+ markdownLines.push(`Run window: ${data.runMetadata.startedAt} -> ${data.runMetadata.completedAt}`);
51
+ markdownLines.push(`Run duration (ms): ${data.runMetadata.durationMs}`);
52
+ markdownLines.push(`Since ref: ${data.runMetadata.sinceRef}`);
53
+ }
48
54
  markdownLines.push(`Framework: ${data.framework}`);
49
55
  markdownLines.push(`Test Patterns: ${data.testPatterns.join(', ') || 'None'}`);
50
56
  if (data.flowCatalog) {
@@ -103,6 +109,9 @@ function writeReport(appRoot, config, data) {
103
109
  if (result.error) {
104
110
  markdownLines.push(` Error: ${result.error}`);
105
111
  }
112
+ if (result.failureCategory || result.failureCode) {
113
+ markdownLines.push(` Failure taxonomy: category=${result.failureCategory || 'unknown'} code=${result.failureCode || 'unknown'}`);
114
+ }
106
115
  }
107
116
  if (data.pipeline.warnings.length > 0) {
108
117
  markdownLines.push('Pipeline warnings:');
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,aAAa,CAAC;AAiN7C,MAAM,WAAW,UAAU;IACvB,KAAK,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA6LzF;AAED,wBAAsB,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA0MtF"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,aAAa,CAAC;AAkR7C,MAAM,WAAW,UAAU;IACvB,KAAK,EAAE,OAAO,CAAC;CAClB;AAYD,wBAAsB,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAoSzF;AAED,wBAAsB,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAiTtF"}