qa360 1.0.3 → 1.1.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 (108) hide show
  1. package/dist/commands/history.js +1 -1
  2. package/dist/commands/pack.js +1 -1
  3. package/dist/commands/run.d.ts +1 -1
  4. package/dist/commands/run.d.ts.map +1 -1
  5. package/dist/commands/run.js +1 -1
  6. package/dist/commands/secrets.js +1 -1
  7. package/dist/commands/serve.js +1 -1
  8. package/dist/commands/verify.js +1 -1
  9. package/dist/core/adapters/gitleaks-secrets.d.ts +115 -0
  10. package/dist/core/adapters/gitleaks-secrets.d.ts.map +1 -0
  11. package/dist/core/adapters/gitleaks-secrets.js +410 -0
  12. package/dist/core/adapters/k6-perf.d.ts +86 -0
  13. package/dist/core/adapters/k6-perf.d.ts.map +1 -0
  14. package/dist/core/adapters/k6-perf.js +398 -0
  15. package/dist/core/adapters/osv-deps.d.ts +124 -0
  16. package/dist/core/adapters/osv-deps.d.ts.map +1 -0
  17. package/dist/core/adapters/osv-deps.js +372 -0
  18. package/dist/core/adapters/playwright-api.d.ts +82 -0
  19. package/dist/core/adapters/playwright-api.d.ts.map +1 -0
  20. package/dist/core/adapters/playwright-api.js +252 -0
  21. package/dist/core/adapters/playwright-ui.d.ts +115 -0
  22. package/dist/core/adapters/playwright-ui.d.ts.map +1 -0
  23. package/dist/core/adapters/playwright-ui.js +346 -0
  24. package/dist/core/adapters/semgrep-sast.d.ts +100 -0
  25. package/dist/core/adapters/semgrep-sast.d.ts.map +1 -0
  26. package/dist/core/adapters/semgrep-sast.js +322 -0
  27. package/dist/core/adapters/zap-dast.d.ts +134 -0
  28. package/dist/core/adapters/zap-dast.d.ts.map +1 -0
  29. package/dist/core/adapters/zap-dast.js +424 -0
  30. package/dist/core/hooks/compose.d.ts +62 -0
  31. package/dist/core/hooks/compose.d.ts.map +1 -0
  32. package/dist/core/hooks/compose.js +225 -0
  33. package/dist/core/hooks/runner.d.ts +69 -0
  34. package/dist/core/hooks/runner.d.ts.map +1 -0
  35. package/dist/core/hooks/runner.js +303 -0
  36. package/dist/core/index.d.ts +74 -0
  37. package/dist/core/index.d.ts.map +1 -0
  38. package/dist/core/index.js +39 -0
  39. package/dist/core/pack/migrator.d.ts +52 -0
  40. package/dist/core/pack/migrator.d.ts.map +1 -0
  41. package/dist/core/pack/migrator.js +304 -0
  42. package/dist/core/pack/validator.d.ts +43 -0
  43. package/dist/core/pack/validator.d.ts.map +1 -0
  44. package/dist/core/pack/validator.js +292 -0
  45. package/dist/core/proof/bundle.d.ts +138 -0
  46. package/dist/core/proof/bundle.d.ts.map +1 -0
  47. package/dist/core/proof/bundle.js +160 -0
  48. package/dist/core/proof/canonicalize.d.ts +48 -0
  49. package/dist/core/proof/canonicalize.d.ts.map +1 -0
  50. package/dist/core/proof/canonicalize.js +105 -0
  51. package/dist/core/proof/index.d.ts +14 -0
  52. package/dist/core/proof/index.d.ts.map +1 -0
  53. package/dist/core/proof/index.js +18 -0
  54. package/dist/core/proof/schema.d.ts +218 -0
  55. package/dist/core/proof/schema.d.ts.map +1 -0
  56. package/dist/core/proof/schema.js +263 -0
  57. package/dist/core/proof/signer.d.ts +112 -0
  58. package/dist/core/proof/signer.d.ts.map +1 -0
  59. package/dist/core/proof/signer.js +226 -0
  60. package/dist/core/proof/verifier.d.ts +98 -0
  61. package/dist/core/proof/verifier.d.ts.map +1 -0
  62. package/dist/core/proof/verifier.js +302 -0
  63. package/dist/core/runner/phase3-runner.d.ts +102 -0
  64. package/dist/core/runner/phase3-runner.d.ts.map +1 -0
  65. package/dist/core/runner/phase3-runner.js +471 -0
  66. package/dist/core/secrets/crypto.d.ts +76 -0
  67. package/dist/core/secrets/crypto.d.ts.map +1 -0
  68. package/dist/core/secrets/crypto.js +225 -0
  69. package/dist/core/secrets/manager.d.ts +77 -0
  70. package/dist/core/secrets/manager.d.ts.map +1 -0
  71. package/dist/core/secrets/manager.js +219 -0
  72. package/dist/core/security/redaction-patterns-extended.d.ts +28 -0
  73. package/dist/core/security/redaction-patterns-extended.d.ts.map +1 -0
  74. package/dist/core/security/redaction-patterns-extended.js +247 -0
  75. package/dist/core/security/redactor.d.ts +72 -0
  76. package/dist/core/security/redactor.d.ts.map +1 -0
  77. package/dist/core/security/redactor.js +279 -0
  78. package/dist/core/serve/diagnostics-collector.d.ts +33 -0
  79. package/dist/core/serve/diagnostics-collector.d.ts.map +1 -0
  80. package/dist/core/serve/diagnostics-collector.js +149 -0
  81. package/dist/core/serve/health-checker.d.ts +45 -0
  82. package/dist/core/serve/health-checker.d.ts.map +1 -0
  83. package/dist/core/serve/health-checker.js +219 -0
  84. package/dist/core/serve/index.d.ts +9 -0
  85. package/dist/core/serve/index.d.ts.map +1 -0
  86. package/dist/core/serve/index.js +8 -0
  87. package/dist/core/serve/metrics-collector.d.ts +25 -0
  88. package/dist/core/serve/metrics-collector.d.ts.map +1 -0
  89. package/dist/core/serve/metrics-collector.js +322 -0
  90. package/dist/core/serve/process-manager.d.ts +37 -0
  91. package/dist/core/serve/process-manager.d.ts.map +1 -0
  92. package/dist/core/serve/process-manager.js +213 -0
  93. package/dist/core/serve/server.d.ts +37 -0
  94. package/dist/core/serve/server.d.ts.map +1 -0
  95. package/dist/core/serve/server.js +191 -0
  96. package/dist/core/types/pack-v1.d.ts +162 -0
  97. package/dist/core/types/pack-v1.d.ts.map +1 -0
  98. package/dist/core/types/pack-v1.js +5 -0
  99. package/dist/core/types/trust-score.d.ts +70 -0
  100. package/dist/core/types/trust-score.d.ts.map +1 -0
  101. package/dist/core/types/trust-score.js +191 -0
  102. package/dist/core/vault/cas.d.ts +87 -0
  103. package/dist/core/vault/cas.d.ts.map +1 -0
  104. package/dist/core/vault/cas.js +255 -0
  105. package/dist/core/vault/index.d.ts +205 -0
  106. package/dist/core/vault/index.d.ts.map +1 -0
  107. package/dist/core/vault/index.js +631 -0
  108. package/package.json +12 -6
@@ -0,0 +1,346 @@
1
+ /**
2
+ * QA360 Playwright UI Adapter (Socle OOTB)
3
+ * UI smoke tests + accessibility via axe-core
4
+ */
5
+ import { chromium } from '@playwright/test';
6
+ import { SecurityRedactor } from '../security/redactor.js';
7
+ export class PlaywrightUiAdapter {
8
+ browser;
9
+ context;
10
+ page;
11
+ redactor;
12
+ constructor() {
13
+ this.redactor = SecurityRedactor.forLogs();
14
+ }
15
+ /**
16
+ * Execute UI smoke tests with accessibility
17
+ */
18
+ async runSmokeTests(config) {
19
+ try {
20
+ await this.setupBrowser();
21
+ const results = [];
22
+ const pages = config.target.pages || [config.target.baseUrl];
23
+ console.log(`🖥️ Running UI smoke tests (${pages.length} pages)`);
24
+ // Optional login first
25
+ if (config.login) {
26
+ await this.performLogin(config.login);
27
+ }
28
+ for (const pageUrl of pages) {
29
+ const testResult = await this.testPage(pageUrl, config);
30
+ results.push(testResult);
31
+ if (testResult.success) {
32
+ const a11yInfo = testResult.accessibility ?
33
+ ` | A11y: ${testResult.accessibility.score}% (${testResult.accessibility.violations.length} issues)` : '';
34
+ console.log(` ✅ ${pageUrl} -> ${testResult.loadTime}ms${a11yInfo}`);
35
+ }
36
+ else {
37
+ console.log(` ❌ ${pageUrl} -> ${testResult.error}`);
38
+ }
39
+ }
40
+ const summary = this.calculateSummary(results);
41
+ const junit = this.generateJUnit(results);
42
+ return {
43
+ success: summary.failed === 0,
44
+ results,
45
+ summary,
46
+ junit
47
+ };
48
+ }
49
+ finally {
50
+ await this.cleanup();
51
+ }
52
+ }
53
+ /**
54
+ * Test single page with accessibility
55
+ */
56
+ async testPage(pageUrl, config) {
57
+ try {
58
+ const startTime = Date.now();
59
+ // Navigate to page
60
+ const response = await this.page.goto(pageUrl, {
61
+ timeout: config.timeout || 30000,
62
+ waitUntil: 'networkidle'
63
+ });
64
+ const loadTime = Date.now() - startTime;
65
+ if (!response || !response.ok()) {
66
+ return {
67
+ page: pageUrl,
68
+ success: false,
69
+ loadTime,
70
+ error: `HTTP ${response?.status() || 'unknown'}: Failed to load page`
71
+ };
72
+ }
73
+ // Take screenshot
74
+ const screenshot = await this.takeScreenshot(pageUrl);
75
+ // Get DOM snapshot
76
+ const domSnapshot = await this.getDomSnapshot();
77
+ // Run accessibility tests
78
+ const accessibility = await this.runAccessibilityTests(config.budgets);
79
+ // Check if accessibility meets budget
80
+ const a11yPassed = !config.budgets?.a11y_min ||
81
+ (accessibility?.score !== undefined && accessibility.score >= config.budgets.a11y_min);
82
+ return {
83
+ page: pageUrl,
84
+ success: a11yPassed,
85
+ loadTime,
86
+ screenshot,
87
+ accessibility,
88
+ domSnapshot,
89
+ error: a11yPassed ? undefined :
90
+ `Accessibility score ${accessibility?.score || 0}% below budget ${config.budgets?.a11y_min}%`
91
+ };
92
+ }
93
+ catch (error) {
94
+ return {
95
+ page: pageUrl,
96
+ success: false,
97
+ loadTime: 0,
98
+ error: this.redactor.redact(error instanceof Error ? error.message : 'Unknown error')
99
+ };
100
+ }
101
+ }
102
+ /**
103
+ * Perform login if configured
104
+ */
105
+ async performLogin(login) {
106
+ if (!login || !login.username || !login.password) {
107
+ return;
108
+ }
109
+ console.log(` 🔐 Performing login...`);
110
+ const loginUrl = login.url || this.page.url();
111
+ await this.page.goto(loginUrl);
112
+ // Fill login form
113
+ const usernameSelector = login.usernameSelector ||
114
+ 'input[name="username"], input[name="email"], input[type="email"], #username, #email';
115
+ const passwordSelector = login.passwordSelector ||
116
+ 'input[name="password"], input[type="password"], #password';
117
+ const submitSelector = login.submitSelector ||
118
+ 'button[type="submit"], input[type="submit"], button:has-text("Login"), button:has-text("Sign in")';
119
+ await this.page.fill(usernameSelector, login.username);
120
+ await this.page.fill(passwordSelector, login.password);
121
+ await this.page.click(submitSelector);
122
+ // Wait for navigation or login completion
123
+ try {
124
+ await this.page.waitForLoadState('networkidle', { timeout: 10000 });
125
+ }
126
+ catch {
127
+ // Continue even if navigation doesn't complete
128
+ }
129
+ }
130
+ /**
131
+ * Run accessibility tests using axe-core
132
+ */
133
+ async runAccessibilityTests(budgets) {
134
+ try {
135
+ // Inject axe-core
136
+ await this.page.addScriptTag({
137
+ url: 'https://unpkg.com/axe-core@4.8.2/axe.min.js'
138
+ });
139
+ // Run axe analysis
140
+ const axeResults = await this.page.evaluate(() => {
141
+ return new Promise((resolve) => {
142
+ // @ts-ignore - axe is injected
143
+ if (typeof axe !== 'undefined') {
144
+ // @ts-ignore
145
+ axe.run((err, results) => {
146
+ if (err) {
147
+ resolve({ violations: [], passes: [], incomplete: [], inapplicable: [] });
148
+ }
149
+ else {
150
+ resolve(results);
151
+ }
152
+ });
153
+ }
154
+ else {
155
+ resolve({ violations: [], passes: [], incomplete: [], inapplicable: [] });
156
+ }
157
+ });
158
+ });
159
+ // Process violations
160
+ const violations = axeResults.violations?.map((violation) => ({
161
+ id: violation.id,
162
+ impact: violation.impact || 'minor',
163
+ description: violation.description || violation.help || 'Accessibility issue',
164
+ nodes: violation.nodes?.length || 0
165
+ })) || [];
166
+ // Calculate score (simple scoring: 100 - weighted violations)
167
+ const criticalCount = violations.filter((v) => v.impact === 'critical').length;
168
+ const seriousCount = violations.filter((v) => v.impact === 'serious').length;
169
+ const moderateCount = violations.filter((v) => v.impact === 'moderate').length;
170
+ const minorCount = violations.filter((v) => v.impact === 'minor').length;
171
+ const score = Math.max(0, 100 - (criticalCount * 25 +
172
+ seriousCount * 10 +
173
+ moderateCount * 5 +
174
+ minorCount * 1));
175
+ return {
176
+ score: Math.round(score),
177
+ violations
178
+ };
179
+ }
180
+ catch (error) {
181
+ console.log(` ⚠️ Accessibility test failed: ${error}`);
182
+ return {
183
+ score: 0,
184
+ violations: [{
185
+ id: 'axe-error',
186
+ impact: 'critical',
187
+ description: 'Failed to run accessibility analysis',
188
+ nodes: 0
189
+ }]
190
+ };
191
+ }
192
+ }
193
+ /**
194
+ * Get DOM snapshot for debugging
195
+ */
196
+ async getDomSnapshot() {
197
+ try {
198
+ const snapshot = await this.page.evaluate(() => {
199
+ return {
200
+ title: document.title,
201
+ url: window.location.href,
202
+ elements: {
203
+ buttons: document.querySelectorAll('button, input[type="button"], input[type="submit"]').length,
204
+ links: document.querySelectorAll('a[href]').length,
205
+ forms: document.querySelectorAll('form').length,
206
+ inputs: document.querySelectorAll('input, textarea, select').length
207
+ }
208
+ };
209
+ });
210
+ return snapshot;
211
+ }
212
+ catch {
213
+ return {
214
+ title: 'Unknown',
215
+ url: this.page.url(),
216
+ elements: { buttons: 0, links: 0, forms: 0, inputs: 0 }
217
+ };
218
+ }
219
+ }
220
+ /**
221
+ * Take screenshot for debugging
222
+ */
223
+ async takeScreenshot(pageUrl) {
224
+ try {
225
+ const screenshot = await this.page.screenshot({
226
+ type: 'png',
227
+ fullPage: false // Just viewport for performance
228
+ });
229
+ // Return base64 data URL for embedding
230
+ return `data:image/png;base64,${screenshot.toString('base64')}`;
231
+ }
232
+ catch {
233
+ return '';
234
+ }
235
+ }
236
+ /**
237
+ * Calculate test summary
238
+ */
239
+ calculateSummary(results) {
240
+ const total = results.length;
241
+ const passed = results.filter(r => r.success).length;
242
+ const failed = total - passed;
243
+ const avgLoadTime = total > 0 ?
244
+ Math.round(results.reduce((sum, r) => sum + r.loadTime, 0) / total) : 0;
245
+ const a11yScores = results
246
+ .map(r => r.accessibility?.score)
247
+ .filter((score) => typeof score === 'number');
248
+ const avgA11yScore = a11yScores.length > 0 ?
249
+ Math.round(a11yScores.reduce((sum, score) => sum + score, 0) / a11yScores.length) : 0;
250
+ return { total, passed, failed, avgLoadTime, avgA11yScore };
251
+ }
252
+ /**
253
+ * Generate JUnit XML fragment
254
+ */
255
+ generateJUnit(results) {
256
+ const summary = this.calculateSummary(results);
257
+ const timestamp = new Date().toISOString();
258
+ let junit = `<?xml version="1.0" encoding="UTF-8"?>
259
+ <testsuite name="UI Smoke Tests" tests="${summary.total}" failures="${summary.failed}" time="${summary.avgLoadTime / 1000}" timestamp="${timestamp}">
260
+ `;
261
+ for (const result of results) {
262
+ const testName = `UI Test: ${result.page}`;
263
+ const time = result.loadTime / 1000;
264
+ junit += ` <testcase name="${this.escapeXml(testName)}" time="${time}">
265
+ `;
266
+ if (!result.success) {
267
+ junit += ` <failure message="${this.escapeXml(result.error || 'Test failed')}">${this.escapeXml(JSON.stringify(result, null, 2))}</failure>
268
+ `;
269
+ }
270
+ junit += ` </testcase>
271
+ `;
272
+ }
273
+ junit += `</testsuite>`;
274
+ return junit;
275
+ }
276
+ /**
277
+ * Escape XML special characters
278
+ */
279
+ escapeXml(str) {
280
+ return str
281
+ .replace(/&/g, '&amp;')
282
+ .replace(/</g, '&lt;')
283
+ .replace(/>/g, '&gt;')
284
+ .replace(/"/g, '&quot;')
285
+ .replace(/'/g, '&apos;');
286
+ }
287
+ /**
288
+ * Setup browser context
289
+ */
290
+ async setupBrowser() {
291
+ this.browser = await chromium.launch({
292
+ headless: true,
293
+ args: ['--no-sandbox', '--disable-dev-shm-usage']
294
+ });
295
+ this.context = await this.browser.newContext({
296
+ viewport: { width: 1280, height: 720 },
297
+ userAgent: 'QA360-UI-Smoke/1.0'
298
+ });
299
+ this.page = await this.context.newPage();
300
+ }
301
+ /**
302
+ * Cleanup browser resources
303
+ */
304
+ async cleanup() {
305
+ if (this.page) {
306
+ await this.page.close();
307
+ }
308
+ if (this.context) {
309
+ await this.context.close();
310
+ }
311
+ if (this.browser) {
312
+ await this.browser.close();
313
+ }
314
+ }
315
+ /**
316
+ * Validate UI target configuration
317
+ */
318
+ static validateConfig(target) {
319
+ const errors = [];
320
+ if (!target.baseUrl) {
321
+ errors.push('UI target requires baseUrl');
322
+ }
323
+ else {
324
+ try {
325
+ new URL(target.baseUrl);
326
+ }
327
+ catch {
328
+ errors.push('UI target baseUrl must be a valid URL');
329
+ }
330
+ }
331
+ if (target.pages) {
332
+ for (const page of target.pages) {
333
+ try {
334
+ new URL(page, target.baseUrl);
335
+ }
336
+ catch {
337
+ errors.push(`Invalid page URL: ${page}`);
338
+ }
339
+ }
340
+ }
341
+ return {
342
+ valid: errors.length === 0,
343
+ errors
344
+ };
345
+ }
346
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * QA360 Semgrep SAST Adapter (Socle OOTB)
3
+ * Static Application Security Testing with configurable severity thresholds
4
+ */
5
+ import { PackSecurity } from '../types/pack-v1.js';
6
+ export interface SemgrepTestConfig {
7
+ workingDir: string;
8
+ security?: PackSecurity;
9
+ rules?: string[];
10
+ paths?: string[];
11
+ timeout?: number;
12
+ configFile?: string;
13
+ }
14
+ export interface SemgrepFinding {
15
+ ruleId: string;
16
+ severity: 'INFO' | 'WARNING' | 'ERROR';
17
+ message: string;
18
+ file: string;
19
+ line: number;
20
+ column: number;
21
+ code?: string;
22
+ fix?: string;
23
+ }
24
+ export interface SemgrepTestResult {
25
+ success: boolean;
26
+ findings: SemgrepFinding[];
27
+ summary: {
28
+ total: number;
29
+ critical: number;
30
+ high: number;
31
+ medium: number;
32
+ low: number;
33
+ info: number;
34
+ };
35
+ thresholds: {
36
+ sast_max_high: {
37
+ passed: boolean;
38
+ actual: number;
39
+ budget: number;
40
+ };
41
+ };
42
+ error?: string;
43
+ rawOutput?: string;
44
+ junit?: string;
45
+ }
46
+ export declare class SemgrepSastAdapter {
47
+ private redactor;
48
+ constructor();
49
+ /**
50
+ * Execute Semgrep SAST scan
51
+ */
52
+ runSastScan(config: SemgrepTestConfig): Promise<SemgrepTestResult>;
53
+ /**
54
+ * Execute Semgrep command
55
+ */
56
+ private executeSemgrep;
57
+ /**
58
+ * Parse Semgrep JSON results
59
+ */
60
+ private parseSemgrepResults;
61
+ /**
62
+ * Map Semgrep severity to standard levels
63
+ */
64
+ private mapSeverity;
65
+ /**
66
+ * Calculate findings summary
67
+ */
68
+ private calculateSummary;
69
+ /**
70
+ * Check security thresholds
71
+ */
72
+ private checkThresholds;
73
+ /**
74
+ * Generate JUnit XML
75
+ */
76
+ private generateJUnit;
77
+ /**
78
+ * Get default summary structure
79
+ */
80
+ private getDefaultSummary;
81
+ /**
82
+ * Get default thresholds
83
+ */
84
+ private getDefaultThresholds;
85
+ /**
86
+ * Check if Semgrep is available
87
+ */
88
+ static isAvailable(): Promise<{
89
+ available: boolean;
90
+ error?: string;
91
+ }>;
92
+ /**
93
+ * Validate SAST configuration
94
+ */
95
+ static validateConfig(config: SemgrepTestConfig): {
96
+ valid: boolean;
97
+ errors: string[];
98
+ };
99
+ }
100
+ //# sourceMappingURL=semgrep-sast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semgrep-sast.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/semgrep-sast.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,UAAU,EAAE;QACV,aAAa,EAAE;YACb,MAAM,EAAE,OAAO,CAAC;YAChB,MAAM,EAAE,MAAM,CAAC;YACf,MAAM,EAAE,MAAM,CAAC;SAChB,CAAC;KACH,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAmB;;IAMnC;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAgCxE;;OAEG;YACW,cAAc;IAiF5B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA4D3B;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA2BxB;;OAEG;IACH,OAAO,CAAC,eAAe;IAYvB;;OAEG;IACH,OAAO,CAAC,aAAa;IA2BrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;OAEG;WACU,WAAW,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAoB3E;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,iBAAiB,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;CA4BvF"}