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,424 @@
1
+ /**
2
+ * QA360 ZAP DAST Adapter (Sécurité Réelle)
3
+ * OWASP ZAP baseline scan for dynamic application security testing
4
+ */
5
+ import { spawn } from 'child_process';
6
+ import { existsSync, unlinkSync, readFileSync } from 'fs';
7
+ import { join } from 'path';
8
+ import { SecurityRedactor } from '../security/redactor.js';
9
+ export class ZapDastAdapter {
10
+ redactor;
11
+ workingDir;
12
+ constructor(workingDir = process.cwd()) {
13
+ this.redactor = SecurityRedactor.forLogs();
14
+ this.workingDir = workingDir;
15
+ }
16
+ /**
17
+ * Execute ZAP DAST scan
18
+ */
19
+ async runDastScan(config) {
20
+ const startTime = Date.now();
21
+ try {
22
+ console.log(`🔍 Running ZAP ${config.scanType || 'baseline'} scan on ${config.targetUrl}`);
23
+ // Validate target URL
24
+ if (!this.isValidUrl(config.targetUrl)) {
25
+ return {
26
+ success: false,
27
+ alerts: [],
28
+ summary: this.getEmptySummary(),
29
+ budgetCheck: this.getDefaultBudgetCheck(),
30
+ targetUrl: config.targetUrl,
31
+ scanDuration: 0,
32
+ error: 'Invalid target URL provided',
33
+ errorCode: 'ZAP001'
34
+ };
35
+ }
36
+ // Execute ZAP scan
37
+ const result = await this.executeZapScan(config);
38
+ result.scanDuration = Date.now() - startTime;
39
+ return result;
40
+ }
41
+ catch (error) {
42
+ return {
43
+ success: false,
44
+ alerts: [],
45
+ summary: this.getEmptySummary(),
46
+ budgetCheck: this.getDefaultBudgetCheck(),
47
+ targetUrl: config.targetUrl,
48
+ scanDuration: Date.now() - startTime,
49
+ error: this.redactor.redact(error instanceof Error ? error.message : 'Unknown error'),
50
+ errorCode: 'ZAP099'
51
+ };
52
+ }
53
+ }
54
+ /**
55
+ * Validate URL format
56
+ */
57
+ isValidUrl(url) {
58
+ try {
59
+ new URL(url);
60
+ return url.startsWith('http://') || url.startsWith('https://');
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ }
66
+ /**
67
+ * Execute ZAP scanner
68
+ */
69
+ async executeZapScan(config) {
70
+ return new Promise((resolve) => {
71
+ let output = '';
72
+ let error = '';
73
+ const reportPath = join(this.workingDir, `zap-report-${Date.now()}.json`);
74
+ const htmlReportPath = join(this.workingDir, `zap-report-${Date.now()}.html`);
75
+ // Try Docker first, then local installation
76
+ const useDocker = this.shouldUseDocker();
77
+ const args = this.buildZapArgs(config, reportPath, htmlReportPath, useDocker);
78
+ const command = useDocker ? 'docker' : 'zap-baseline.py';
79
+ console.log(`🐳 Using ${useDocker ? 'Docker' : 'local'} ZAP installation`);
80
+ const child = spawn(command, args, {
81
+ cwd: this.workingDir,
82
+ stdio: ['ignore', 'pipe', 'pipe']
83
+ });
84
+ const timeout = setTimeout(() => {
85
+ child.kill('SIGKILL');
86
+ resolve({
87
+ success: false,
88
+ alerts: [],
89
+ summary: this.getEmptySummary(),
90
+ budgetCheck: this.getDefaultBudgetCheck(),
91
+ targetUrl: config.targetUrl,
92
+ scanDuration: 0,
93
+ error: `ZAP scan timed out after ${config.security?.dast?.timeout_ms || 300000}ms`,
94
+ errorCode: 'ZAP002'
95
+ });
96
+ }, config.security?.dast?.timeout_ms || 300000); // 5 minutes default
97
+ if (child.stdout) {
98
+ child.stdout.on('data', (data) => {
99
+ output += data.toString();
100
+ });
101
+ }
102
+ if (child.stderr) {
103
+ child.stderr.on('data', (data) => {
104
+ error += data.toString();
105
+ });
106
+ }
107
+ child.on('close', (code) => {
108
+ clearTimeout(timeout);
109
+ // ZAP returns different codes: 0=no alerts, 1=low, 2=medium, 3=high
110
+ if (code !== null && code <= 3) {
111
+ const result = this.parseZapResults(reportPath, config, output);
112
+ resolve(result);
113
+ }
114
+ else {
115
+ resolve({
116
+ success: false,
117
+ alerts: [],
118
+ summary: this.getEmptySummary(),
119
+ budgetCheck: this.getDefaultBudgetCheck(),
120
+ targetUrl: config.targetUrl,
121
+ scanDuration: 0,
122
+ error: this.redactor.redact(error || `ZAP exited with code ${code}`),
123
+ rawOutput: this.redactor.redact(output),
124
+ errorCode: 'ZAP003'
125
+ });
126
+ }
127
+ });
128
+ child.on('error', (err) => {
129
+ clearTimeout(timeout);
130
+ // Fallback to mock scan
131
+ resolve(this.fallbackMockScan(config));
132
+ });
133
+ });
134
+ }
135
+ /**
136
+ * Check if Docker should be used for ZAP
137
+ */
138
+ shouldUseDocker() {
139
+ // Check if Docker is available and ZAP image exists
140
+ try {
141
+ const { execSync } = require('child_process');
142
+ execSync('docker --version', { stdio: 'ignore' });
143
+ return true;
144
+ }
145
+ catch {
146
+ return false;
147
+ }
148
+ }
149
+ /**
150
+ * Build ZAP command arguments
151
+ */
152
+ buildZapArgs(config, reportPath, htmlReportPath, useDocker) {
153
+ const args = [];
154
+ if (useDocker) {
155
+ args.push('run', '--rm', '-v', `${this.workingDir}:/zap/wrk/:rw`, 'owasp/zap2docker-stable', 'zap-baseline.py');
156
+ }
157
+ // Target URL
158
+ args.push('-t', config.targetUrl);
159
+ // Report formats
160
+ args.push('-J', reportPath.split('/').pop()); // JSON report
161
+ args.push('-r', htmlReportPath.split('/').pop()); // HTML report
162
+ // Scan configuration
163
+ if (config.scanType === 'full') {
164
+ args.push('-a'); // Full scan
165
+ }
166
+ // Exclude URLs
167
+ if (config.excludeUrls && config.excludeUrls.length > 0) {
168
+ for (const url of config.excludeUrls) {
169
+ args.push('-x', url);
170
+ }
171
+ }
172
+ // Include URLs
173
+ if (config.includeUrls && config.includeUrls.length > 0) {
174
+ for (const url of config.includeUrls) {
175
+ args.push('-i', url);
176
+ }
177
+ }
178
+ // Context file
179
+ if (config.contextFile && existsSync(config.contextFile)) {
180
+ args.push('-n', config.contextFile);
181
+ }
182
+ // Config file
183
+ if (config.configFile && existsSync(config.configFile)) {
184
+ args.push('-c', config.configFile);
185
+ }
186
+ // Additional options
187
+ args.push('-I'); // Ignore warnings
188
+ args.push('-d'); // Show debug messages
189
+ return args;
190
+ }
191
+ /**
192
+ * Parse ZAP scan results
193
+ */
194
+ parseZapResults(reportPath, config, output) {
195
+ try {
196
+ let alerts = [];
197
+ if (existsSync(reportPath)) {
198
+ const reportContent = readFileSync(reportPath, 'utf8');
199
+ const data = JSON.parse(reportContent);
200
+ if (data.site && data.site[0] && data.site[0].alerts) {
201
+ alerts = data.site[0].alerts;
202
+ }
203
+ // Cleanup report file
204
+ try {
205
+ unlinkSync(reportPath);
206
+ }
207
+ catch {
208
+ // Ignore cleanup errors
209
+ }
210
+ }
211
+ // Redact sensitive information from alerts
212
+ const redactedAlerts = alerts.map(alert => ({
213
+ ...alert,
214
+ instances: alert.instances?.map(instance => ({
215
+ ...instance,
216
+ uri: this.redactor.redact(instance.uri || ''),
217
+ attack: this.redactor.redact(instance.attack || ''),
218
+ evidence: this.redactor.redact(instance.evidence || ''),
219
+ otherinfo: this.redactor.redact(instance.otherinfo || '')
220
+ })) || []
221
+ }));
222
+ const summary = this.calculateSummary(redactedAlerts);
223
+ const budgetCheck = this.generateBudgetCheck(summary, config);
224
+ const success = budgetCheck.high_passed && budgetCheck.critical_passed;
225
+ const junit = this.generateJUnit(summary, success, config);
226
+ return {
227
+ success,
228
+ alerts: redactedAlerts,
229
+ summary,
230
+ budgetCheck,
231
+ targetUrl: config.targetUrl,
232
+ scanDuration: 0, // Will be set by caller
233
+ rawOutput: this.redactor.redact(output),
234
+ reportPath,
235
+ junit
236
+ };
237
+ }
238
+ catch (error) {
239
+ return {
240
+ success: false,
241
+ alerts: [],
242
+ summary: this.getEmptySummary(),
243
+ budgetCheck: this.getDefaultBudgetCheck(),
244
+ targetUrl: config.targetUrl,
245
+ scanDuration: 0,
246
+ error: `Failed to parse ZAP results: ${error}`,
247
+ rawOutput: this.redactor.redact(output),
248
+ errorCode: 'ZAP004'
249
+ };
250
+ }
251
+ }
252
+ /**
253
+ * Fallback mock scan when ZAP not available
254
+ */
255
+ fallbackMockScan(config) {
256
+ console.log('⚠️ ZAP not found, using mock scan (install OWASP ZAP for real scanning)');
257
+ return {
258
+ success: true,
259
+ alerts: [],
260
+ summary: this.getEmptySummary(),
261
+ budgetCheck: this.getDefaultBudgetCheck(),
262
+ targetUrl: config.targetUrl,
263
+ scanDuration: 1000,
264
+ error: 'ZAP not available - install from https://www.zaproxy.org/ or use Docker',
265
+ junit: this.generateJUnit(this.getEmptySummary(), true, config),
266
+ errorCode: 'ZAP005'
267
+ };
268
+ }
269
+ /**
270
+ * Calculate alerts summary
271
+ */
272
+ calculateSummary(alerts) {
273
+ const summary = {
274
+ total: alerts.length,
275
+ high: 0,
276
+ medium: 0,
277
+ low: 0,
278
+ informational: 0,
279
+ by_category: {}
280
+ };
281
+ for (const alert of alerts) {
282
+ const risk = alert.riskdesc?.toLowerCase() || '';
283
+ if (risk.includes('high')) {
284
+ summary.high++;
285
+ }
286
+ else if (risk.includes('medium')) {
287
+ summary.medium++;
288
+ }
289
+ else if (risk.includes('low')) {
290
+ summary.low++;
291
+ }
292
+ else {
293
+ summary.informational++;
294
+ }
295
+ // Count by category/plugin
296
+ const category = alert.alert || 'Unknown';
297
+ summary.by_category[category] = (summary.by_category[category] || 0) + 1;
298
+ }
299
+ return summary;
300
+ }
301
+ /**
302
+ * Generate budget check based on security config
303
+ */
304
+ generateBudgetCheck(summary, config) {
305
+ const dast = config.security?.dast;
306
+ return {
307
+ critical_passed: !dast?.max_critical || 0 <= (dast.max_critical || 0), // No critical in ZAP baseline
308
+ high_passed: !dast?.max_high || summary.high <= dast.max_high,
309
+ medium_passed: !dast?.max_medium || summary.medium <= dast.max_medium
310
+ };
311
+ }
312
+ /**
313
+ * Get empty summary structure
314
+ */
315
+ getEmptySummary() {
316
+ return {
317
+ total: 0,
318
+ high: 0,
319
+ medium: 0,
320
+ low: 0,
321
+ informational: 0,
322
+ by_category: {}
323
+ };
324
+ }
325
+ /**
326
+ * Get default budget check structure
327
+ */
328
+ getDefaultBudgetCheck() {
329
+ return {
330
+ critical_passed: true,
331
+ high_passed: true,
332
+ medium_passed: true
333
+ };
334
+ }
335
+ /**
336
+ * Generate JUnit XML report
337
+ */
338
+ generateJUnit(summary, success, config) {
339
+ const timestamp = new Date().toISOString();
340
+ const duration = '30.0'; // Typical ZAP scan duration
341
+ let junit = `<?xml version="1.0" encoding="UTF-8"?>
342
+ <testsuite name="ZAP DAST Scan" tests="1" failures="${success ? 0 : 1}" time="${duration}" timestamp="${timestamp}">
343
+ <testcase name="DAST Security Scan: ${config.targetUrl}" time="${duration}">
344
+ `;
345
+ if (!success) {
346
+ junit += ` <failure message="Security vulnerabilities found">
347
+ High: ${summary.high}
348
+ Medium: ${summary.medium}
349
+ Low: ${summary.low}
350
+ Informational: ${summary.informational}
351
+ Total: ${summary.total}
352
+ </failure>
353
+ `;
354
+ }
355
+ junit += ` </testcase>
356
+ </testsuite>`;
357
+ return junit;
358
+ }
359
+ /**
360
+ * Validate ZAP scan configuration
361
+ */
362
+ static validateConfig(config) {
363
+ const errors = [];
364
+ if (!config.targetUrl) {
365
+ errors.push('Target URL is required');
366
+ }
367
+ try {
368
+ new URL(config.targetUrl);
369
+ }
370
+ catch {
371
+ errors.push('Invalid target URL format');
372
+ }
373
+ if (config.contextFile && !existsSync(config.contextFile)) {
374
+ errors.push(`Context file does not exist: ${config.contextFile}`);
375
+ }
376
+ if (config.configFile && !existsSync(config.configFile)) {
377
+ errors.push(`Config file does not exist: ${config.configFile}`);
378
+ }
379
+ return {
380
+ valid: errors.length === 0,
381
+ errors
382
+ };
383
+ }
384
+ /**
385
+ * Check if ZAP is available (Docker or local)
386
+ */
387
+ static async isAvailable() {
388
+ // Check Docker first
389
+ try {
390
+ const { execSync } = require('child_process');
391
+ execSync('docker run --rm owasp/zap2docker-stable zap-baseline.py --version', {
392
+ stdio: 'ignore',
393
+ timeout: 10000
394
+ });
395
+ return { available: true, method: 'docker' };
396
+ }
397
+ catch {
398
+ // Check local installation
399
+ return new Promise((resolve) => {
400
+ const child = spawn('zap-baseline.py', ['--version'], { stdio: 'pipe' });
401
+ child.on('close', (code) => {
402
+ resolve({
403
+ available: code === 0,
404
+ method: 'local',
405
+ error: code !== 0 ? 'ZAP not found. Install from https://www.zaproxy.org/ or use Docker' : undefined
406
+ });
407
+ });
408
+ child.on('error', () => {
409
+ resolve({
410
+ available: false,
411
+ error: 'ZAP not found. Install from https://www.zaproxy.org/ or use Docker'
412
+ });
413
+ });
414
+ setTimeout(() => {
415
+ child.kill();
416
+ resolve({
417
+ available: false,
418
+ error: 'ZAP availability check timed out'
419
+ });
420
+ }, 5000);
421
+ });
422
+ }
423
+ }
424
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * QA360 Docker Compose Helper
3
+ * Safe Docker Compose operations with health checks and error handling
4
+ */
5
+ export interface ComposeOptions {
6
+ workingDir: string;
7
+ composeFile?: string;
8
+ }
9
+ export interface ComposeError extends Error {
10
+ code: string;
11
+ suggestion: string;
12
+ }
13
+ export declare class ComposeHelper {
14
+ private workingDir;
15
+ private composeFile;
16
+ private isUp;
17
+ constructor(options: ComposeOptions);
18
+ /**
19
+ * Start services with Docker Compose
20
+ */
21
+ up(timeout?: number): Promise<void>;
22
+ /**
23
+ * Stop and remove services
24
+ */
25
+ down(timeout?: number): Promise<void>;
26
+ /**
27
+ * Get service status
28
+ */
29
+ getStatus(): Promise<{
30
+ service: string;
31
+ status: string;
32
+ ports: string[];
33
+ }[]>;
34
+ /**
35
+ * Check if Docker is available
36
+ */
37
+ private checkDockerAvailable;
38
+ /**
39
+ * Execute Docker Compose command
40
+ */
41
+ private executeCompose;
42
+ /**
43
+ * Execute shell command with timeout
44
+ */
45
+ private executeCommand;
46
+ /**
47
+ * Validate compose file syntax
48
+ */
49
+ validateComposeFile(): Promise<{
50
+ valid: boolean;
51
+ errors: string[];
52
+ }>;
53
+ /**
54
+ * Get compose file path
55
+ */
56
+ getComposeFilePath(): string;
57
+ /**
58
+ * Check if services are currently up
59
+ */
60
+ isServicesUp(): boolean;
61
+ }
62
+ //# sourceMappingURL=compose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../../src/core/hooks/compose.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAa,SAAQ,KAAK;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,IAAI,CAAkB;gBAElB,OAAO,EAAE,cAAc;IAKnC;;OAEG;IACG,EAAE,CAAC,OAAO,GAAE,MAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IA6CjD;;OAEG;IACG,IAAI,CAAC,OAAO,GAAE,MAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBlD;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IA+BlF;;OAEG;YACW,oBAAoB;IAiBlC;;OAEG;YACW,cAAc;IAW5B;;OAEG;YACW,cAAc;IAwD5B;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAyB1E;;OAEG;IACH,kBAAkB,IAAI,MAAM;IAI5B;;OAEG;IACH,YAAY,IAAI,OAAO;CAGxB"}