@ansvar/us-regulations-mcp 1.0.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/LICENSE +190 -0
- package/README.md +275 -0
- package/data/.gitkeep +0 -0
- package/data/regulations.db +0 -0
- package/data/seed/applicability/rules.json +74 -0
- package/data/seed/mappings/ccpa-nist-csf.json +144 -0
- package/data/seed/mappings/hipaa-nist-800-53.json +377 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest/adapters/california-leginfo.d.ts +72 -0
- package/dist/ingest/adapters/california-leginfo.d.ts.map +1 -0
- package/dist/ingest/adapters/california-leginfo.js +270 -0
- package/dist/ingest/adapters/california-leginfo.js.map +1 -0
- package/dist/ingest/adapters/ecfr.d.ts +76 -0
- package/dist/ingest/adapters/ecfr.d.ts.map +1 -0
- package/dist/ingest/adapters/ecfr.js +355 -0
- package/dist/ingest/adapters/ecfr.js.map +1 -0
- package/dist/ingest/adapters/regulations-gov.d.ts +47 -0
- package/dist/ingest/adapters/regulations-gov.d.ts.map +1 -0
- package/dist/ingest/adapters/regulations-gov.js +91 -0
- package/dist/ingest/adapters/regulations-gov.js.map +1 -0
- package/dist/ingest/framework.d.ts +84 -0
- package/dist/ingest/framework.d.ts.map +1 -0
- package/dist/ingest/framework.js +8 -0
- package/dist/ingest/framework.js.map +1 -0
- package/dist/tools/action-items.d.ts +23 -0
- package/dist/tools/action-items.d.ts.map +1 -0
- package/dist/tools/action-items.js +118 -0
- package/dist/tools/action-items.js.map +1 -0
- package/dist/tools/applicability.d.ts +26 -0
- package/dist/tools/applicability.d.ts.map +1 -0
- package/dist/tools/applicability.js +49 -0
- package/dist/tools/applicability.js.map +1 -0
- package/dist/tools/compare.d.ts +20 -0
- package/dist/tools/compare.d.ts.map +1 -0
- package/dist/tools/compare.js +35 -0
- package/dist/tools/compare.js.map +1 -0
- package/dist/tools/definitions.d.ts +22 -0
- package/dist/tools/definitions.d.ts.map +1 -0
- package/dist/tools/definitions.js +43 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/evidence.d.ts +23 -0
- package/dist/tools/evidence.d.ts.map +1 -0
- package/dist/tools/evidence.js +27 -0
- package/dist/tools/evidence.js.map +1 -0
- package/dist/tools/list.d.ts +25 -0
- package/dist/tools/list.d.ts.map +1 -0
- package/dist/tools/list.js +66 -0
- package/dist/tools/list.js.map +1 -0
- package/dist/tools/map.d.ts +26 -0
- package/dist/tools/map.d.ts.map +1 -0
- package/dist/tools/map.js +58 -0
- package/dist/tools/map.js.map +1 -0
- package/dist/tools/registry.d.ts +19 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +260 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/search.d.ts +15 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +94 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/section.d.ts +19 -0
- package/dist/tools/section.d.ts.map +1 -0
- package/dist/tools/section.js +50 -0
- package/dist/tools/section.js.map +1 -0
- package/package.json +76 -0
- package/scripts/build-db.ts +268 -0
- package/scripts/ingest.ts +214 -0
- package/scripts/load-seed-data.ts +133 -0
- package/scripts/quality-test.ts +346 -0
- package/scripts/test-mcp-tools.ts +187 -0
- package/scripts/test-remaining-tools.ts +107 -0
- package/src/index.ts +55 -0
- package/src/ingest/adapters/california-leginfo.ts +322 -0
- package/src/ingest/adapters/ecfr.ts +403 -0
- package/src/ingest/adapters/regulations-gov.ts +112 -0
- package/src/ingest/framework.ts +92 -0
- package/src/tools/action-items.ts +164 -0
- package/src/tools/applicability.ts +91 -0
- package/src/tools/compare.ts +61 -0
- package/src/tools/definitions.ts +79 -0
- package/src/tools/evidence.ts +53 -0
- package/src/tools/list.ts +120 -0
- package/src/tools/map.ts +100 -0
- package/src/tools/registry.ts +275 -0
- package/src/tools/search.ts +132 -0
- package/src/tools/section.ts +85 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* California Legislative Information Adapter
|
|
3
|
+
*
|
|
4
|
+
* Fetches CCPA/CPRA regulations from California LegInfo.
|
|
5
|
+
* Source: California Civil Code § 1798.100-1798.199
|
|
6
|
+
*
|
|
7
|
+
* PRODUCTION IMPLEMENTATION
|
|
8
|
+
* Uses HTML scraping with fail-fast DOM validation
|
|
9
|
+
*/
|
|
10
|
+
import * as cheerio from 'cheerio';
|
|
11
|
+
/**
|
|
12
|
+
* Scraping error thrown when DOM structure validation fails
|
|
13
|
+
*/
|
|
14
|
+
class ScrapingError extends Error {
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = 'ScrapingError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Adapter for fetching CCPA/CPRA from California Legislative Information
|
|
22
|
+
*/
|
|
23
|
+
export class CaliforniaLeginfoAdapter {
|
|
24
|
+
regulationId;
|
|
25
|
+
civilCodeStart;
|
|
26
|
+
civilCodeEnd;
|
|
27
|
+
constructor(regulationId, civilCodeStart, civilCodeEnd) {
|
|
28
|
+
this.regulationId = regulationId;
|
|
29
|
+
this.civilCodeStart = civilCodeStart;
|
|
30
|
+
this.civilCodeEnd = civilCodeEnd;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Fetch CCPA metadata
|
|
34
|
+
*
|
|
35
|
+
* PLACEHOLDER: Returns hardcoded CCPA metadata
|
|
36
|
+
* TODO: Integrate with California LegInfo to fetch live metadata
|
|
37
|
+
*/
|
|
38
|
+
async fetchMetadata() {
|
|
39
|
+
// Placeholder metadata for CCPA/CPRA
|
|
40
|
+
return {
|
|
41
|
+
id: this.regulationId,
|
|
42
|
+
full_name: 'California Consumer Privacy Act',
|
|
43
|
+
citation: 'Cal. Civ. Code § 1798.100-1798.199',
|
|
44
|
+
effective_date: '2020-01-01',
|
|
45
|
+
last_amended: '2023-01-01',
|
|
46
|
+
source_url: 'https://leginfo.legislature.ca.gov/faces/codes_displayText.xhtml?division=3.&part=4.&lawCode=CIV&title=1.81.5',
|
|
47
|
+
jurisdiction: 'california',
|
|
48
|
+
regulation_type: 'statute',
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Fetch all CCPA sections
|
|
53
|
+
*
|
|
54
|
+
* Scrapes HTML from California LegInfo with fail-fast validation
|
|
55
|
+
* Source: https://leginfo.legislature.ca.gov/faces/codes.xhtml
|
|
56
|
+
*/
|
|
57
|
+
async *fetchSections() {
|
|
58
|
+
const BASE_URL = 'https://leginfo.legislature.ca.gov/faces/codes_displayText.xhtml';
|
|
59
|
+
const sections = [];
|
|
60
|
+
// CCPA main sections (based on actual structure)
|
|
61
|
+
// Use strings to preserve trailing zeros (1798.100 not 1798.1)
|
|
62
|
+
const sectionNumbers = [
|
|
63
|
+
'1798.100', '1798.105', '1798.110', '1798.115', '1798.120', '1798.121', '1798.125',
|
|
64
|
+
'1798.130', '1798.135', '1798.140', '1798.145', '1798.150', '1798.155', '1798.160',
|
|
65
|
+
'1798.175', '1798.180', '1798.185', '1798.190', '1798.192', '1798.194', '1798.196',
|
|
66
|
+
'1798.198', '1798.199'
|
|
67
|
+
];
|
|
68
|
+
console.log(`Fetching ${sectionNumbers.length} CCPA sections from California LegInfo...`);
|
|
69
|
+
for (const sectionNum of sectionNumbers) {
|
|
70
|
+
try {
|
|
71
|
+
// Use displaySection endpoint which has cleaner structure
|
|
72
|
+
const url = `https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=CIV§ionNum=${sectionNum}`;
|
|
73
|
+
// Fetch HTML with polite delay
|
|
74
|
+
await this.sleep(500); // 500ms between requests
|
|
75
|
+
const response = await this.fetchWithRetry(url);
|
|
76
|
+
const html = await response.text();
|
|
77
|
+
// Parse HTML
|
|
78
|
+
const $ = cheerio.load(html);
|
|
79
|
+
// Validate DOM structure
|
|
80
|
+
this.validateDOM($);
|
|
81
|
+
// Extract section content
|
|
82
|
+
const section = this.parseSection($, sectionNum.toString());
|
|
83
|
+
if (section) {
|
|
84
|
+
sections.push(section);
|
|
85
|
+
console.log(` Fetched § ${sectionNum}`);
|
|
86
|
+
}
|
|
87
|
+
// Yield in batches of 10
|
|
88
|
+
if (sections.length >= 10) {
|
|
89
|
+
yield sections.splice(0, 10);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
if (error instanceof ScrapingError) {
|
|
94
|
+
console.error(`Scraping failed for § ${sectionNum}:`, error.message);
|
|
95
|
+
throw error; // Fail fast on DOM structure issues
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
console.warn(`Failed to fetch § ${sectionNum}, continuing...`, error);
|
|
99
|
+
// Continue with other sections
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Yield remaining sections
|
|
104
|
+
if (sections.length > 0) {
|
|
105
|
+
yield sections;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Validate DOM structure with fail-fast assertions
|
|
110
|
+
*/
|
|
111
|
+
validateDOM($) {
|
|
112
|
+
// Check for expected structure - single_law_section div
|
|
113
|
+
const sectionContent = $('#single_law_section, #codeLawSectionNoHead');
|
|
114
|
+
if (sectionContent.length === 0) {
|
|
115
|
+
throw new ScrapingError('DOM structure changed: no section content found. Expected #single_law_section or #codeLawSectionNoHead');
|
|
116
|
+
}
|
|
117
|
+
// Additional validation: check if we got an error page
|
|
118
|
+
if ($('title').text().includes('Error') || $('body').text().includes('not found')) {
|
|
119
|
+
throw new ScrapingError('Section not found or error page returned');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Parse section from HTML
|
|
124
|
+
*/
|
|
125
|
+
parseSection($, sectionNum) {
|
|
126
|
+
// Extract from the main content div
|
|
127
|
+
const sectionDiv = $('#single_law_section');
|
|
128
|
+
if (sectionDiv.length === 0) {
|
|
129
|
+
console.warn(`Section § ${sectionNum} not found in HTML`);
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
// Get text content
|
|
133
|
+
let text = sectionDiv.text().trim();
|
|
134
|
+
// Clean up extra whitespace
|
|
135
|
+
text = text.replace(/\s+/g, ' ').replace(/\n\s*\n/g, '\n');
|
|
136
|
+
// Validate text length
|
|
137
|
+
if (!text || text.length < 100) {
|
|
138
|
+
console.warn(`Section § ${sectionNum} text too short (${text.length} chars) - may be empty or truncated`);
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
// Extract title from h6 tag (section number and title)
|
|
142
|
+
let title;
|
|
143
|
+
const titleElement = sectionDiv.find('h6, p').first();
|
|
144
|
+
if (titleElement.length > 0) {
|
|
145
|
+
title = titleElement.text().trim();
|
|
146
|
+
// Remove section number from title if present
|
|
147
|
+
title = title.replace(/^1798\.\d+\.?\s*/, '');
|
|
148
|
+
}
|
|
149
|
+
// Extract cross-references (sections mentioned in text)
|
|
150
|
+
const crossReferences = this.extractCrossReferences(text);
|
|
151
|
+
return {
|
|
152
|
+
sectionNumber: sectionNum,
|
|
153
|
+
title,
|
|
154
|
+
text,
|
|
155
|
+
chapter: 'Title 1.81.5 - California Consumer Privacy Act',
|
|
156
|
+
parentSection: undefined,
|
|
157
|
+
crossReferences: crossReferences.length > 0 ? crossReferences : undefined,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Extract cross-references from text
|
|
162
|
+
*/
|
|
163
|
+
extractCrossReferences(text) {
|
|
164
|
+
const refs = [];
|
|
165
|
+
// Pattern: "Section 1798.XXX" or "§ 1798.XXX"
|
|
166
|
+
const pattern = /(?:Section|§)\s+1798\.\d+/g;
|
|
167
|
+
const matches = text.match(pattern);
|
|
168
|
+
if (matches) {
|
|
169
|
+
for (const match of matches) {
|
|
170
|
+
const ref = match.replace(/^(?:Section|§)\s+/, '');
|
|
171
|
+
if (!refs.includes(ref)) {
|
|
172
|
+
refs.push(ref);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return refs;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Fetch with retry logic and exponential backoff
|
|
180
|
+
*/
|
|
181
|
+
async fetchWithRetry(url, maxRetries = 3) {
|
|
182
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
183
|
+
try {
|
|
184
|
+
const response = await fetch(url);
|
|
185
|
+
if (response.status === 429) {
|
|
186
|
+
const delay = Math.min(1000 * 2 ** attempt + Math.random() * 1000, 30000);
|
|
187
|
+
console.warn(`Rate limited, retrying in ${delay}ms...`);
|
|
188
|
+
await this.sleep(delay);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (!response.ok) {
|
|
192
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
193
|
+
}
|
|
194
|
+
return response;
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
if (attempt === maxRetries - 1)
|
|
198
|
+
throw error;
|
|
199
|
+
const delay = 1000 * 2 ** attempt;
|
|
200
|
+
console.warn(`Fetch failed, retrying in ${delay}ms...`, error);
|
|
201
|
+
await this.sleep(delay);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
throw new Error('Max retries exceeded');
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Sleep helper
|
|
208
|
+
*/
|
|
209
|
+
sleep(ms) {
|
|
210
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Check for updates since last fetch
|
|
214
|
+
*
|
|
215
|
+
* Checks California LegInfo for amendments to Civil Code § 1798
|
|
216
|
+
* Note: This is best-effort since there's no official API
|
|
217
|
+
*/
|
|
218
|
+
async checkForUpdates(lastFetched) {
|
|
219
|
+
try {
|
|
220
|
+
// Fetch a sample section to check for updates
|
|
221
|
+
const url = 'https://leginfo.legislature.ca.gov/faces/codes_displayText.xhtml?lawCode=CIV&division=3.&part=4.§ion=1798.100';
|
|
222
|
+
const response = await fetch(url);
|
|
223
|
+
const lastModifiedHeader = response.headers.get('last-modified');
|
|
224
|
+
if (!lastModifiedHeader) {
|
|
225
|
+
console.warn('No last-modified header from California LegInfo');
|
|
226
|
+
return {
|
|
227
|
+
hasChanges: false,
|
|
228
|
+
lastModified: new Date(),
|
|
229
|
+
changes: [],
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
const lastModified = new Date(lastModifiedHeader);
|
|
233
|
+
return {
|
|
234
|
+
hasChanges: lastModified > lastFetched,
|
|
235
|
+
lastModified,
|
|
236
|
+
changes: lastModified > lastFetched
|
|
237
|
+
? [`California Civil Code § 1798 (CCPA) may have been updated on ${lastModified.toISOString()}`]
|
|
238
|
+
: [],
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
console.error('Error checking for updates:', error);
|
|
243
|
+
return {
|
|
244
|
+
hasChanges: false,
|
|
245
|
+
lastModified: new Date(),
|
|
246
|
+
changes: [],
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Extract definitions from CCPA sections
|
|
252
|
+
*
|
|
253
|
+
* Future enhancement: Parse definition sections (primarily § 1798.140)
|
|
254
|
+
* For now, returns empty array - definitions can be added manually if needed
|
|
255
|
+
*/
|
|
256
|
+
async extractDefinitions() {
|
|
257
|
+
// TODO: Implement definition extraction
|
|
258
|
+
// CCPA definitions are primarily in § 1798.140
|
|
259
|
+
// Format: "(a) 'Term' means definition."
|
|
260
|
+
// Would need careful parsing to extract all term-definition pairs
|
|
261
|
+
return [];
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Factory function to create CCPA adapter
|
|
266
|
+
*/
|
|
267
|
+
export function createCcpaAdapter() {
|
|
268
|
+
return new CaliforniaLeginfoAdapter('CCPA', 1798.100, 1798.199);
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=california-leginfo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"california-leginfo.js","sourceRoot":"","sources":["../../../src/ingest/adapters/california-leginfo.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* eCFR Adapter (Electronic Code of Federal Regulations)
|
|
3
|
+
*
|
|
4
|
+
* Fetches HIPAA regulations from ecfr.gov API.
|
|
5
|
+
* Source: 45 CFR Parts 160, 162, 164 (Privacy Rule, Security Rule, Breach Notification)
|
|
6
|
+
*
|
|
7
|
+
* PRODUCTION IMPLEMENTATION
|
|
8
|
+
* Uses the eCFR API: https://www.ecfr.gov/developers/documentation/api/v1
|
|
9
|
+
*/
|
|
10
|
+
import { SourceAdapter, RegulationMetadata, Section, Definition, UpdateStatus } from '../framework.js';
|
|
11
|
+
/**
|
|
12
|
+
* Adapter for fetching HIPAA from eCFR API
|
|
13
|
+
*/
|
|
14
|
+
export declare class EcfrAdapter implements SourceAdapter {
|
|
15
|
+
private readonly regulationId;
|
|
16
|
+
private readonly cfr_title;
|
|
17
|
+
private readonly cfr_parts;
|
|
18
|
+
constructor(regulationId: string, cfr_title: number, cfr_parts: number[]);
|
|
19
|
+
/**
|
|
20
|
+
* Fetch HIPAA metadata
|
|
21
|
+
*
|
|
22
|
+
* PLACEHOLDER: Returns hardcoded HIPAA metadata
|
|
23
|
+
* TODO: Integrate with eCFR API to fetch live metadata
|
|
24
|
+
*/
|
|
25
|
+
fetchMetadata(): Promise<RegulationMetadata>;
|
|
26
|
+
/**
|
|
27
|
+
* Fetch all HIPAA sections
|
|
28
|
+
*
|
|
29
|
+
* Fetches XML from eCFR API and parses sections with hierarchical structure
|
|
30
|
+
* API endpoint: https://www.ecfr.gov/api/versioner/v1/full/{date}/title-{title}.xml
|
|
31
|
+
*/
|
|
32
|
+
fetchSections(): AsyncGenerator<Section[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Parse a section from XML DIV8 element
|
|
35
|
+
*/
|
|
36
|
+
private parseSection;
|
|
37
|
+
/**
|
|
38
|
+
* Extract text content from XML element recursively
|
|
39
|
+
*/
|
|
40
|
+
private extractText;
|
|
41
|
+
/**
|
|
42
|
+
* Extract cross-references from CITA tags
|
|
43
|
+
*/
|
|
44
|
+
private extractCrossReferences;
|
|
45
|
+
/**
|
|
46
|
+
* Extract numeric part from section number
|
|
47
|
+
*/
|
|
48
|
+
private extractNumber;
|
|
49
|
+
/**
|
|
50
|
+
* Get the latest available date for this title from eCFR titles API
|
|
51
|
+
*/
|
|
52
|
+
private getLatestDate;
|
|
53
|
+
/**
|
|
54
|
+
* Fetch with retry logic and exponential backoff
|
|
55
|
+
*/
|
|
56
|
+
private fetchWithRetry;
|
|
57
|
+
/**
|
|
58
|
+
* Check for updates since last fetch
|
|
59
|
+
*
|
|
60
|
+
* Queries eCFR API for revision dates and compares with lastFetched
|
|
61
|
+
* eCFR updates daily from Federal Register
|
|
62
|
+
*/
|
|
63
|
+
checkForUpdates(lastFetched: Date): Promise<UpdateStatus>;
|
|
64
|
+
/**
|
|
65
|
+
* Extract definitions from HIPAA sections
|
|
66
|
+
*
|
|
67
|
+
* Future enhancement: Parse definition sections (e.g., 45 CFR 160.103, 164.103)
|
|
68
|
+
* For now, returns empty array - definitions can be added manually if needed
|
|
69
|
+
*/
|
|
70
|
+
extractDefinitions(): Promise<Definition[]>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Factory function to create HIPAA adapter
|
|
74
|
+
*/
|
|
75
|
+
export declare function createHipaaAdapter(): EcfrAdapter;
|
|
76
|
+
//# sourceMappingURL=ecfr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecfr.d.ts","sourceRoot":"","sources":["../../../src/ingest/adapters/ecfr.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,OAAO,EACP,UAAU,EACV,YAAY,EACb,MAAM,iBAAiB,CAAC;AAGzB;;GAEG;AACH,qBAAa,WAAY,YAAW,aAAa;IAC/C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAW;gBAEzB,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE;IAMxE;;;;;OAKG;IACG,aAAa,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAclD;;;;;OAKG;IACI,aAAa,IAAI,cAAc,CAAC,OAAO,EAAE,CAAC;IAoHjD;;OAEG;IACH,OAAO,CAAC,YAAY;IA8BpB;;OAEG;IACH,OAAO,CAAC,WAAW;IAkCnB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAyB9B;;OAEG;IACH,OAAO,CAAC,aAAa;IAMrB;;OAEG;YACW,aAAa;IAkB3B;;OAEG;YACW,cAAc;IA6B5B;;;;;OAKG;IACG,eAAe,CAAC,WAAW,EAAE,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;IAqC/D;;;;;OAKG;IACG,kBAAkB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;CAWlD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,WAAW,CAEhD"}
|