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.
- package/dist/commands/history.js +1 -1
- package/dist/commands/pack.js +1 -1
- package/dist/commands/run.d.ts +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +1 -1
- package/dist/commands/secrets.js +1 -1
- package/dist/commands/serve.js +1 -1
- package/dist/commands/verify.js +1 -1
- package/dist/core/adapters/gitleaks-secrets.d.ts +115 -0
- package/dist/core/adapters/gitleaks-secrets.d.ts.map +1 -0
- package/dist/core/adapters/gitleaks-secrets.js +410 -0
- package/dist/core/adapters/k6-perf.d.ts +86 -0
- package/dist/core/adapters/k6-perf.d.ts.map +1 -0
- package/dist/core/adapters/k6-perf.js +398 -0
- package/dist/core/adapters/osv-deps.d.ts +124 -0
- package/dist/core/adapters/osv-deps.d.ts.map +1 -0
- package/dist/core/adapters/osv-deps.js +372 -0
- package/dist/core/adapters/playwright-api.d.ts +82 -0
- package/dist/core/adapters/playwright-api.d.ts.map +1 -0
- package/dist/core/adapters/playwright-api.js +252 -0
- package/dist/core/adapters/playwright-ui.d.ts +115 -0
- package/dist/core/adapters/playwright-ui.d.ts.map +1 -0
- package/dist/core/adapters/playwright-ui.js +346 -0
- package/dist/core/adapters/semgrep-sast.d.ts +100 -0
- package/dist/core/adapters/semgrep-sast.d.ts.map +1 -0
- package/dist/core/adapters/semgrep-sast.js +322 -0
- package/dist/core/adapters/zap-dast.d.ts +134 -0
- package/dist/core/adapters/zap-dast.d.ts.map +1 -0
- package/dist/core/adapters/zap-dast.js +424 -0
- package/dist/core/hooks/compose.d.ts +62 -0
- package/dist/core/hooks/compose.d.ts.map +1 -0
- package/dist/core/hooks/compose.js +225 -0
- package/dist/core/hooks/runner.d.ts +69 -0
- package/dist/core/hooks/runner.d.ts.map +1 -0
- package/dist/core/hooks/runner.js +303 -0
- package/dist/core/index.d.ts +74 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +39 -0
- package/dist/core/pack/migrator.d.ts +52 -0
- package/dist/core/pack/migrator.d.ts.map +1 -0
- package/dist/core/pack/migrator.js +304 -0
- package/dist/core/pack/validator.d.ts +43 -0
- package/dist/core/pack/validator.d.ts.map +1 -0
- package/dist/core/pack/validator.js +292 -0
- package/dist/core/proof/bundle.d.ts +138 -0
- package/dist/core/proof/bundle.d.ts.map +1 -0
- package/dist/core/proof/bundle.js +160 -0
- package/dist/core/proof/canonicalize.d.ts +48 -0
- package/dist/core/proof/canonicalize.d.ts.map +1 -0
- package/dist/core/proof/canonicalize.js +105 -0
- package/dist/core/proof/index.d.ts +14 -0
- package/dist/core/proof/index.d.ts.map +1 -0
- package/dist/core/proof/index.js +18 -0
- package/dist/core/proof/schema.d.ts +218 -0
- package/dist/core/proof/schema.d.ts.map +1 -0
- package/dist/core/proof/schema.js +263 -0
- package/dist/core/proof/signer.d.ts +112 -0
- package/dist/core/proof/signer.d.ts.map +1 -0
- package/dist/core/proof/signer.js +226 -0
- package/dist/core/proof/verifier.d.ts +98 -0
- package/dist/core/proof/verifier.d.ts.map +1 -0
- package/dist/core/proof/verifier.js +302 -0
- package/dist/core/runner/phase3-runner.d.ts +102 -0
- package/dist/core/runner/phase3-runner.d.ts.map +1 -0
- package/dist/core/runner/phase3-runner.js +471 -0
- package/dist/core/secrets/crypto.d.ts +76 -0
- package/dist/core/secrets/crypto.d.ts.map +1 -0
- package/dist/core/secrets/crypto.js +225 -0
- package/dist/core/secrets/manager.d.ts +77 -0
- package/dist/core/secrets/manager.d.ts.map +1 -0
- package/dist/core/secrets/manager.js +219 -0
- package/dist/core/security/redaction-patterns-extended.d.ts +28 -0
- package/dist/core/security/redaction-patterns-extended.d.ts.map +1 -0
- package/dist/core/security/redaction-patterns-extended.js +247 -0
- package/dist/core/security/redactor.d.ts +72 -0
- package/dist/core/security/redactor.d.ts.map +1 -0
- package/dist/core/security/redactor.js +279 -0
- package/dist/core/serve/diagnostics-collector.d.ts +33 -0
- package/dist/core/serve/diagnostics-collector.d.ts.map +1 -0
- package/dist/core/serve/diagnostics-collector.js +149 -0
- package/dist/core/serve/health-checker.d.ts +45 -0
- package/dist/core/serve/health-checker.d.ts.map +1 -0
- package/dist/core/serve/health-checker.js +219 -0
- package/dist/core/serve/index.d.ts +9 -0
- package/dist/core/serve/index.d.ts.map +1 -0
- package/dist/core/serve/index.js +8 -0
- package/dist/core/serve/metrics-collector.d.ts +25 -0
- package/dist/core/serve/metrics-collector.d.ts.map +1 -0
- package/dist/core/serve/metrics-collector.js +322 -0
- package/dist/core/serve/process-manager.d.ts +37 -0
- package/dist/core/serve/process-manager.d.ts.map +1 -0
- package/dist/core/serve/process-manager.js +213 -0
- package/dist/core/serve/server.d.ts +37 -0
- package/dist/core/serve/server.d.ts.map +1 -0
- package/dist/core/serve/server.js +191 -0
- package/dist/core/types/pack-v1.d.ts +162 -0
- package/dist/core/types/pack-v1.d.ts.map +1 -0
- package/dist/core/types/pack-v1.js +5 -0
- package/dist/core/types/trust-score.d.ts +70 -0
- package/dist/core/types/trust-score.d.ts.map +1 -0
- package/dist/core/types/trust-score.js +191 -0
- package/dist/core/vault/cas.d.ts +87 -0
- package/dist/core/vault/cas.d.ts.map +1 -0
- package/dist/core/vault/cas.js +255 -0
- package/dist/core/vault/index.d.ts +205 -0
- package/dist/core/vault/index.d.ts.map +1 -0
- package/dist/core/vault/index.js +631 -0
- package/package.json +12 -6
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Playwright API Adapter (Socle OOTB)
|
|
3
|
+
* Smoke tests for REST/GraphQL APIs with retry logic
|
|
4
|
+
*/
|
|
5
|
+
import { chromium } from '@playwright/test';
|
|
6
|
+
import { SecurityRedactor } from '../security/redactor.js';
|
|
7
|
+
export class PlaywrightApiAdapter {
|
|
8
|
+
browser;
|
|
9
|
+
context;
|
|
10
|
+
redactor;
|
|
11
|
+
constructor() {
|
|
12
|
+
this.redactor = SecurityRedactor.forLogs();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Execute API smoke tests
|
|
16
|
+
*/
|
|
17
|
+
async runSmokeTests(config) {
|
|
18
|
+
try {
|
|
19
|
+
await this.setupBrowser();
|
|
20
|
+
const results = [];
|
|
21
|
+
const smokeTests = config.target.smoke || [`GET ${config.target.baseUrl}/health -> 200`];
|
|
22
|
+
console.log(`🌐 Running API smoke tests (${smokeTests.length} endpoints)`);
|
|
23
|
+
for (const test of smokeTests) {
|
|
24
|
+
const testResult = await this.executeApiTest(test, config);
|
|
25
|
+
results.push(testResult);
|
|
26
|
+
if (testResult.success) {
|
|
27
|
+
console.log(` ✅ ${testResult.method} ${testResult.endpoint} -> ${testResult.status} (${testResult.responseTime}ms)`);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
console.log(` ❌ ${testResult.method} ${testResult.endpoint} -> ${testResult.error}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const summary = this.calculateSummary(results);
|
|
34
|
+
const junit = this.generateJUnit(results);
|
|
35
|
+
return {
|
|
36
|
+
success: summary.failed === 0,
|
|
37
|
+
results,
|
|
38
|
+
summary,
|
|
39
|
+
junit
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
await this.cleanup();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Execute single API test with retry logic
|
|
48
|
+
*/
|
|
49
|
+
async executeApiTest(testSpec, config) {
|
|
50
|
+
const { method, endpoint, expectedStatus } = this.parseTestSpec(testSpec, config.target.baseUrl);
|
|
51
|
+
const maxRetries = config.retries || 1;
|
|
52
|
+
let lastError = '';
|
|
53
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
54
|
+
try {
|
|
55
|
+
const startTime = Date.now();
|
|
56
|
+
const response = await this.context.request.fetch(endpoint, {
|
|
57
|
+
method: method,
|
|
58
|
+
timeout: config.timeout || 10000,
|
|
59
|
+
headers: {
|
|
60
|
+
'User-Agent': 'QA360-API-Smoke/1.0',
|
|
61
|
+
'Accept': 'application/json, text/plain, */*'
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
const responseTime = Date.now() - startTime;
|
|
65
|
+
const status = response.status();
|
|
66
|
+
const success = status === expectedStatus;
|
|
67
|
+
// Get response body safely
|
|
68
|
+
let body;
|
|
69
|
+
try {
|
|
70
|
+
const contentType = response.headers()['content-type'] || '';
|
|
71
|
+
if (contentType.includes('application/json')) {
|
|
72
|
+
body = await response.json();
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
const text = await response.text();
|
|
76
|
+
body = text.substring(0, 200); // Limit body size
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
body = '[Response body not readable]';
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
endpoint,
|
|
84
|
+
method,
|
|
85
|
+
status,
|
|
86
|
+
responseTime,
|
|
87
|
+
success,
|
|
88
|
+
error: success ? undefined : `Expected status ${expectedStatus}, got ${status}`,
|
|
89
|
+
headers: response.headers(),
|
|
90
|
+
body: this.redactor.redactObject(body)
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
lastError = error instanceof Error ? error.message : 'Unknown error';
|
|
95
|
+
// Check if this is a retryable error
|
|
96
|
+
const isRetryable = this.isRetryableError(lastError);
|
|
97
|
+
if (isRetryable && attempt < maxRetries) {
|
|
98
|
+
console.log(` 🔄 Retry ${attempt + 1}/${maxRetries} for ${method} ${endpoint} (${lastError})`);
|
|
99
|
+
await new Promise(resolve => setTimeout(resolve, 1000 * (attempt + 1))); // Exponential backoff
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
endpoint,
|
|
107
|
+
method,
|
|
108
|
+
status: 0,
|
|
109
|
+
responseTime: 0,
|
|
110
|
+
success: false,
|
|
111
|
+
error: this.redactor.redact(lastError)
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Parse test specification string
|
|
116
|
+
*/
|
|
117
|
+
parseTestSpec(spec, baseUrl) {
|
|
118
|
+
// Format: "GET /path -> 200" or "POST /api/users -> 201"
|
|
119
|
+
const match = spec.match(/^(\w+)\s+(.+?)\s*->\s*(\d+)$/);
|
|
120
|
+
if (!match) {
|
|
121
|
+
throw new Error(`Invalid test spec format: ${spec}. Expected: "METHOD /path -> STATUS"`);
|
|
122
|
+
}
|
|
123
|
+
const [, method, path, statusStr] = match;
|
|
124
|
+
const expectedStatus = parseInt(statusStr, 10);
|
|
125
|
+
// Build full endpoint URL
|
|
126
|
+
let endpoint = path;
|
|
127
|
+
if (!path.startsWith('http')) {
|
|
128
|
+
endpoint = baseUrl.replace(/\/$/, '') + (path.startsWith('/') ? path : `/${path}`);
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
method: method.toUpperCase(),
|
|
132
|
+
endpoint,
|
|
133
|
+
expectedStatus
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Check if error is retryable
|
|
138
|
+
*/
|
|
139
|
+
isRetryableError(error) {
|
|
140
|
+
const retryablePatterns = [
|
|
141
|
+
/ECONNRESET/,
|
|
142
|
+
/ETIMEDOUT/,
|
|
143
|
+
/ECONNREFUSED/,
|
|
144
|
+
/502 Bad Gateway/,
|
|
145
|
+
/503 Service Unavailable/,
|
|
146
|
+
/504 Gateway Timeout/,
|
|
147
|
+
/timeout/i,
|
|
148
|
+
/network/i
|
|
149
|
+
];
|
|
150
|
+
return retryablePatterns.some(pattern => pattern.test(error));
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Calculate test summary
|
|
154
|
+
*/
|
|
155
|
+
calculateSummary(results) {
|
|
156
|
+
const total = results.length;
|
|
157
|
+
const passed = results.filter(r => r.success).length;
|
|
158
|
+
const failed = total - passed;
|
|
159
|
+
const avgResponseTime = total > 0 ?
|
|
160
|
+
Math.round(results.reduce((sum, r) => sum + r.responseTime, 0) / total) : 0;
|
|
161
|
+
return { total, passed, failed, avgResponseTime };
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Generate JUnit XML fragment
|
|
165
|
+
*/
|
|
166
|
+
generateJUnit(results) {
|
|
167
|
+
const summary = this.calculateSummary(results);
|
|
168
|
+
const timestamp = new Date().toISOString();
|
|
169
|
+
let junit = `<?xml version="1.0" encoding="UTF-8"?>
|
|
170
|
+
<testsuite name="API Smoke Tests" tests="${summary.total}" failures="${summary.failed}" time="${summary.avgResponseTime / 1000}" timestamp="${timestamp}">
|
|
171
|
+
`;
|
|
172
|
+
for (const result of results) {
|
|
173
|
+
const testName = `${result.method} ${result.endpoint}`;
|
|
174
|
+
const time = result.responseTime / 1000;
|
|
175
|
+
junit += ` <testcase name="${this.escapeXml(testName)}" time="${time}">
|
|
176
|
+
`;
|
|
177
|
+
if (!result.success) {
|
|
178
|
+
junit += ` <failure message="${this.escapeXml(result.error || 'Test failed')}">${this.escapeXml(JSON.stringify(result, null, 2))}</failure>
|
|
179
|
+
`;
|
|
180
|
+
}
|
|
181
|
+
junit += ` </testcase>
|
|
182
|
+
`;
|
|
183
|
+
}
|
|
184
|
+
junit += `</testsuite>`;
|
|
185
|
+
return junit;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Escape XML special characters
|
|
189
|
+
*/
|
|
190
|
+
escapeXml(str) {
|
|
191
|
+
return str
|
|
192
|
+
.replace(/&/g, '&')
|
|
193
|
+
.replace(/</g, '<')
|
|
194
|
+
.replace(/>/g, '>')
|
|
195
|
+
.replace(/"/g, '"')
|
|
196
|
+
.replace(/'/g, ''');
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Setup browser context
|
|
200
|
+
*/
|
|
201
|
+
async setupBrowser() {
|
|
202
|
+
this.browser = await chromium.launch({
|
|
203
|
+
headless: true,
|
|
204
|
+
args: ['--no-sandbox', '--disable-dev-shm-usage']
|
|
205
|
+
});
|
|
206
|
+
this.context = await this.browser.newContext({
|
|
207
|
+
userAgent: 'QA360-API-Smoke/1.0',
|
|
208
|
+
extraHTTPHeaders: {
|
|
209
|
+
'Accept': 'application/json, text/plain, */*'
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Cleanup browser resources
|
|
215
|
+
*/
|
|
216
|
+
async cleanup() {
|
|
217
|
+
if (this.context) {
|
|
218
|
+
await this.context.close();
|
|
219
|
+
}
|
|
220
|
+
if (this.browser) {
|
|
221
|
+
await this.browser.close();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Validate API target configuration
|
|
226
|
+
*/
|
|
227
|
+
static validateConfig(target) {
|
|
228
|
+
const errors = [];
|
|
229
|
+
if (!target.baseUrl) {
|
|
230
|
+
errors.push('API target requires baseUrl');
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
try {
|
|
234
|
+
new URL(target.baseUrl);
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
errors.push('API target baseUrl must be a valid URL');
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (target.smoke) {
|
|
241
|
+
for (const test of target.smoke) {
|
|
242
|
+
if (!/^\w+\s+.+\s*->\s*\d+$/.test(test)) {
|
|
243
|
+
errors.push(`Invalid smoke test format: ${test}. Expected: "METHOD /path -> STATUS"`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
valid: errors.length === 0,
|
|
249
|
+
errors
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Playwright UI Adapter (Socle OOTB)
|
|
3
|
+
* UI smoke tests + accessibility via axe-core
|
|
4
|
+
*/
|
|
5
|
+
import { WebTarget, PackBudgets } from '../types/pack-v1.js';
|
|
6
|
+
export interface UiTestConfig {
|
|
7
|
+
target: WebTarget;
|
|
8
|
+
budgets?: PackBudgets;
|
|
9
|
+
timeout?: number;
|
|
10
|
+
login?: {
|
|
11
|
+
url?: string;
|
|
12
|
+
username?: string;
|
|
13
|
+
password?: string;
|
|
14
|
+
usernameSelector?: string;
|
|
15
|
+
passwordSelector?: string;
|
|
16
|
+
submitSelector?: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export interface UiTestResult {
|
|
20
|
+
page: string;
|
|
21
|
+
success: boolean;
|
|
22
|
+
loadTime: number;
|
|
23
|
+
error?: string;
|
|
24
|
+
screenshot?: string;
|
|
25
|
+
accessibility?: {
|
|
26
|
+
score: number;
|
|
27
|
+
violations: Array<{
|
|
28
|
+
id: string;
|
|
29
|
+
impact: 'minor' | 'moderate' | 'serious' | 'critical';
|
|
30
|
+
description: string;
|
|
31
|
+
nodes: number;
|
|
32
|
+
}>;
|
|
33
|
+
};
|
|
34
|
+
domSnapshot?: {
|
|
35
|
+
title: string;
|
|
36
|
+
url: string;
|
|
37
|
+
elements: {
|
|
38
|
+
buttons: number;
|
|
39
|
+
links: number;
|
|
40
|
+
forms: number;
|
|
41
|
+
inputs: number;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export interface UiSmokeResult {
|
|
46
|
+
success: boolean;
|
|
47
|
+
results: UiTestResult[];
|
|
48
|
+
summary: {
|
|
49
|
+
total: number;
|
|
50
|
+
passed: number;
|
|
51
|
+
failed: number;
|
|
52
|
+
avgLoadTime: number;
|
|
53
|
+
avgA11yScore: number;
|
|
54
|
+
};
|
|
55
|
+
junit?: string;
|
|
56
|
+
}
|
|
57
|
+
export declare class PlaywrightUiAdapter {
|
|
58
|
+
private browser?;
|
|
59
|
+
private context?;
|
|
60
|
+
private page?;
|
|
61
|
+
private redactor;
|
|
62
|
+
constructor();
|
|
63
|
+
/**
|
|
64
|
+
* Execute UI smoke tests with accessibility
|
|
65
|
+
*/
|
|
66
|
+
runSmokeTests(config: UiTestConfig): Promise<UiSmokeResult>;
|
|
67
|
+
/**
|
|
68
|
+
* Test single page with accessibility
|
|
69
|
+
*/
|
|
70
|
+
private testPage;
|
|
71
|
+
/**
|
|
72
|
+
* Perform login if configured
|
|
73
|
+
*/
|
|
74
|
+
private performLogin;
|
|
75
|
+
/**
|
|
76
|
+
* Run accessibility tests using axe-core
|
|
77
|
+
*/
|
|
78
|
+
private runAccessibilityTests;
|
|
79
|
+
/**
|
|
80
|
+
* Get DOM snapshot for debugging
|
|
81
|
+
*/
|
|
82
|
+
private getDomSnapshot;
|
|
83
|
+
/**
|
|
84
|
+
* Take screenshot for debugging
|
|
85
|
+
*/
|
|
86
|
+
private takeScreenshot;
|
|
87
|
+
/**
|
|
88
|
+
* Calculate test summary
|
|
89
|
+
*/
|
|
90
|
+
private calculateSummary;
|
|
91
|
+
/**
|
|
92
|
+
* Generate JUnit XML fragment
|
|
93
|
+
*/
|
|
94
|
+
private generateJUnit;
|
|
95
|
+
/**
|
|
96
|
+
* Escape XML special characters
|
|
97
|
+
*/
|
|
98
|
+
private escapeXml;
|
|
99
|
+
/**
|
|
100
|
+
* Setup browser context
|
|
101
|
+
*/
|
|
102
|
+
private setupBrowser;
|
|
103
|
+
/**
|
|
104
|
+
* Cleanup browser resources
|
|
105
|
+
*/
|
|
106
|
+
private cleanup;
|
|
107
|
+
/**
|
|
108
|
+
* Validate UI target configuration
|
|
109
|
+
*/
|
|
110
|
+
static validateConfig(target: WebTarget): {
|
|
111
|
+
valid: boolean;
|
|
112
|
+
errors: string[];
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=playwright-ui.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright-ui.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/playwright-ui.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAa7D,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE;QACN,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE;QACd,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,KAAK,CAAC;YAChB,EAAE,EAAE,MAAM,CAAC;YACX,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC;YACtD,WAAW,EAAE,MAAM,CAAC;YACpB,KAAK,EAAE,MAAM,CAAC;SACf,CAAC,CAAC;KACJ,CAAC;IACF,WAAW,CAAC,EAAE;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE;YACR,OAAO,EAAE,MAAM,CAAC;YAChB,KAAK,EAAE,MAAM,CAAC;YACd,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;SAChB,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,OAAO,CAAC,CAAU;IAC1B,OAAO,CAAC,OAAO,CAAC,CAAiB;IACjC,OAAO,CAAC,IAAI,CAAC,CAAO;IACpB,OAAO,CAAC,QAAQ,CAAmB;;IAMnC;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IA0CjE;;OAEG;YACW,QAAQ;IAuDtB;;OAEG;YACW,YAAY;IA8B1B;;OAEG;YACW,qBAAqB;IAkEnC;;OAEG;YACW,cAAc;IAyB5B;;OAEG;YACW,cAAc;IAc5B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAgBxB;;OAEG;IACH,OAAO,CAAC,aAAa;IA6BrB;;OAEG;IACH,OAAO,CAAC,SAAS;IASjB;;OAEG;YACW,YAAY;IAc1B;;OAEG;YACW,OAAO;IAYrB;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;CA4B/E"}
|