@am_shork/attest 0.1.6 → 0.2.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/CHANGELOG.md +293 -83
- package/README.md +73 -5
- package/dist/cli/index.js +38 -13
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/json.d.ts +4 -2
- package/dist/cli/json.d.ts.map +1 -1
- package/dist/cli/json.js +2 -2
- package/dist/cli/json.js.map +1 -1
- package/dist/cli/report.d.ts +10 -2
- package/dist/cli/report.d.ts.map +1 -1
- package/dist/cli/report.js +18 -2
- package/dist/cli/report.js.map +1 -1
- package/dist/core/apply.d.ts.map +1 -1
- package/dist/core/apply.js +7 -1
- package/dist/core/apply.js.map +1 -1
- package/dist/core/gate.d.ts +9 -0
- package/dist/core/gate.d.ts.map +1 -1
- package/dist/core/gate.js +25 -12
- package/dist/core/gate.js.map +1 -1
- package/dist/core/loader.d.ts.map +1 -1
- package/dist/core/loader.js +16 -1
- package/dist/core/loader.js.map +1 -1
- package/dist/core/locate.d.ts +61 -5
- package/dist/core/locate.d.ts.map +1 -1
- package/dist/core/locate.js +130 -48
- package/dist/core/locate.js.map +1 -1
- package/dist/core/order.d.ts +3 -0
- package/dist/core/order.d.ts.map +1 -0
- package/dist/core/order.js +13 -0
- package/dist/core/order.js.map +1 -0
- package/dist/core/pipeline.d.ts +38 -6
- package/dist/core/pipeline.d.ts.map +1 -1
- package/dist/core/pipeline.js +156 -69
- package/dist/core/pipeline.js.map +1 -1
- package/dist/core/render.d.ts.map +1 -1
- package/dist/core/render.js +8 -4
- package/dist/core/render.js.map +1 -1
- package/dist/core/runner.d.ts.map +1 -1
- package/dist/core/runner.js +6 -0
- package/dist/core/runner.js.map +1 -1
- package/dist/core/static-registry.d.ts +14 -0
- package/dist/core/static-registry.d.ts.map +1 -0
- package/dist/core/static-registry.js +255 -0
- package/dist/core/static-registry.js.map +1 -0
- package/dist/core/validator.d.ts.map +1 -1
- package/dist/core/validator.js +16 -4
- package/dist/core/validator.js.map +1 -1
- package/package.json +1 -1
package/dist/core/locate.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
// Locate layer (design §4, L1): find registry + spec files, load the registry
|
|
2
2
|
// via the TS loader, and parse all spec files into one merged AttestPlan.
|
|
3
3
|
import { readdir, readFile } from 'node:fs/promises';
|
|
4
|
-
import { join, relative } from 'node:path';
|
|
4
|
+
import { basename, join, relative } from 'node:path';
|
|
5
5
|
import { parseSpecFile } from './parser.js';
|
|
6
|
+
import { readRegistrySource } from './static-registry.js';
|
|
7
|
+
import { byCodeUnit } from './order.js';
|
|
6
8
|
// Proposed changes and archived changes are excluded from normal scanning:
|
|
7
9
|
// a change's requirements/specs only count once its gate passes and it is
|
|
8
10
|
// merged (design §7, §8). `attest archive <name>` includes them explicitly.
|
|
@@ -16,61 +18,136 @@ const SKIP_DIRS = new Set([
|
|
|
16
18
|
]);
|
|
17
19
|
export const isReqsFile = (name) => name.endsWith('.reqs.ts');
|
|
18
20
|
export const isSpecFile = (name) => name.endsWith('.spec.ts');
|
|
19
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* Recursively find files under root whose basename matches `match`.
|
|
23
|
+
*
|
|
24
|
+
* Sibling directories are walked concurrently — the tree is I/O bound, and a
|
|
25
|
+
* serial `for await` spent one filesystem round-trip per directory, which is
|
|
26
|
+
* the dominant cost of `check` on a large repo. The result is sorted, so the
|
|
27
|
+
* order never depends on which `readdir` happened to resolve first.
|
|
28
|
+
*/
|
|
20
29
|
export async function findFiles(root, match) {
|
|
21
30
|
const out = [];
|
|
22
31
|
const walk = async (dir) => {
|
|
23
32
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
33
|
+
const subdirs = [];
|
|
24
34
|
for (const e of entries) {
|
|
25
35
|
const full = join(dir, e.name);
|
|
26
36
|
if (e.isDirectory()) {
|
|
27
37
|
if (!SKIP_DIRS.has(e.name))
|
|
28
|
-
|
|
38
|
+
subdirs.push(full);
|
|
29
39
|
}
|
|
30
40
|
else if (e.isFile() && match(e.name)) {
|
|
31
41
|
out.push(full);
|
|
32
42
|
}
|
|
33
43
|
}
|
|
44
|
+
await Promise.all(subdirs.map(walk));
|
|
34
45
|
};
|
|
35
46
|
await walk(root);
|
|
36
|
-
return out.sort();
|
|
47
|
+
return out.sort(byCodeUnit);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Find the registry and spec files under root in a **single** traversal.
|
|
51
|
+
*
|
|
52
|
+
* Calling findFiles once per pattern meant `check` walked the tree twice and
|
|
53
|
+
* `archive` four times, over a tree that cannot change in between.
|
|
54
|
+
*/
|
|
55
|
+
export async function scanProject(root) {
|
|
56
|
+
const files = await findFiles(root, (n) => isReqsFile(n) || isSpecFile(n));
|
|
57
|
+
const reqsFiles = [];
|
|
58
|
+
const specFiles = [];
|
|
59
|
+
for (const f of files) {
|
|
60
|
+
if (isReqsFile(basename(f)))
|
|
61
|
+
reqsFiles.push(f);
|
|
62
|
+
else
|
|
63
|
+
specFiles.push(f);
|
|
64
|
+
}
|
|
65
|
+
return { reqsFiles, specFiles };
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Read registries by **executing** the module through the Vite loader.
|
|
69
|
+
*
|
|
70
|
+
* This is what `verify` and `archive` use: they run the whole suite anyway, so
|
|
71
|
+
* declining to evaluate one more module buys them nothing. Everywhere else it
|
|
72
|
+
* is the opt-in behaviour behind `--eval`.
|
|
73
|
+
*/
|
|
74
|
+
export function evalReader(loader) {
|
|
75
|
+
return {
|
|
76
|
+
async read(absPath) {
|
|
77
|
+
let mod;
|
|
78
|
+
try {
|
|
79
|
+
mod = await loader.load(absPath);
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
return {
|
|
83
|
+
issue: {
|
|
84
|
+
level: 'ERROR',
|
|
85
|
+
code: 'registry-invalid',
|
|
86
|
+
message: `Failed to load registry: ${err instanceof Error ? err.message : String(err)}`,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const reg = mod.default;
|
|
91
|
+
if (!reg || typeof reg !== 'object') {
|
|
92
|
+
return {
|
|
93
|
+
issue: {
|
|
94
|
+
level: 'ERROR',
|
|
95
|
+
code: 'registry-no-default',
|
|
96
|
+
message: 'A registry file must default-export the result of defineRequirements(...).',
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return { registry: reg };
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Read registries from the AST, without running a line of the project.
|
|
106
|
+
*
|
|
107
|
+
* The default for `check`, `cover` and `render`, which have no other reason to
|
|
108
|
+
* execute user code — and were advertised as static while doing exactly that.
|
|
109
|
+
*/
|
|
110
|
+
export function staticReader() {
|
|
111
|
+
return {
|
|
112
|
+
async read(absPath) {
|
|
113
|
+
const source = await readFile(absPath, 'utf8');
|
|
114
|
+
const result = readRegistrySource(basename(absPath), source);
|
|
115
|
+
if (result.ok)
|
|
116
|
+
return { registry: result.registry };
|
|
117
|
+
return {
|
|
118
|
+
issue: {
|
|
119
|
+
level: 'ERROR',
|
|
120
|
+
code: result.code,
|
|
121
|
+
message: result.message,
|
|
122
|
+
...(result.line === undefined ? {} : { line: result.line }),
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
};
|
|
37
127
|
}
|
|
38
128
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
129
|
+
* Read and merge every `*.reqs.ts` registry under root, with the given reader.
|
|
130
|
+
* A registry the reader rejects becomes its own ERROR; a duplicate id across
|
|
131
|
+
* files becomes a duplicate-requirement ERROR.
|
|
132
|
+
*
|
|
133
|
+
* Pass `files` to reuse a {@link scanProject} result instead of re-walking.
|
|
42
134
|
*/
|
|
43
|
-
export async function loadRegistry(root,
|
|
44
|
-
const
|
|
135
|
+
export async function loadRegistry(root, reader, files) {
|
|
136
|
+
const paths = files ?? (await scanProject(root)).reqsFiles;
|
|
137
|
+
// Read the files concurrently, then fold the results in sorted file order:
|
|
138
|
+
// the issue list stays deterministic regardless of which one finished first.
|
|
139
|
+
const loaded = await Promise.all(paths.map(async (file) => ({ file, outcome: await reader.read(file) })));
|
|
45
140
|
const registry = {};
|
|
46
141
|
const issues = [];
|
|
47
|
-
for (const
|
|
48
|
-
const display = relative(root, file);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
catch (err) {
|
|
54
|
-
issues.push({
|
|
55
|
-
level: 'ERROR',
|
|
56
|
-
code: 'registry-invalid',
|
|
57
|
-
file: display,
|
|
58
|
-
message: `Failed to load registry: ${err instanceof Error ? err.message : String(err)}`,
|
|
59
|
-
});
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
const reg = mod.default;
|
|
63
|
-
if (!reg || typeof reg !== 'object') {
|
|
64
|
-
issues.push({
|
|
65
|
-
level: 'ERROR',
|
|
66
|
-
code: 'registry-no-default',
|
|
67
|
-
file: display,
|
|
68
|
-
message: 'A registry file must default-export the result of defineRequirements(...).',
|
|
69
|
-
});
|
|
142
|
+
for (const entry of loaded) {
|
|
143
|
+
const display = relative(root, entry.file);
|
|
144
|
+
const { outcome } = entry;
|
|
145
|
+
if ('issue' in outcome) {
|
|
146
|
+
issues.push({ ...outcome.issue, file: display });
|
|
70
147
|
continue;
|
|
71
148
|
}
|
|
72
|
-
for (const [id, req] of Object.entries(
|
|
73
|
-
if (id
|
|
149
|
+
for (const [id, req] of Object.entries(outcome.registry)) {
|
|
150
|
+
if (Object.hasOwn(registry, id)) {
|
|
74
151
|
issues.push({
|
|
75
152
|
level: 'ERROR',
|
|
76
153
|
code: 'duplicate-requirement',
|
|
@@ -86,33 +163,38 @@ export async function loadRegistry(root, loader) {
|
|
|
86
163
|
}
|
|
87
164
|
return { registry, issues };
|
|
88
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Parse the given spec files into one merged plan (paths shown relative to
|
|
168
|
+
* `displayRoot`). Files are read concurrently; the merge follows the input
|
|
169
|
+
* order, so the plan never depends on I/O timing.
|
|
170
|
+
*/
|
|
171
|
+
export async function parseSpecs(files, displayRoot) {
|
|
172
|
+
const sources = await Promise.all(files.map((file) => readFile(file, 'utf8')));
|
|
173
|
+
const plan = { scenarios: [], paramRefs: [] };
|
|
174
|
+
for (const [i, file] of files.entries()) {
|
|
175
|
+
const parsed = parseSpecFile(relative(displayRoot, file), sources[i]);
|
|
176
|
+
plan.scenarios.push(...parsed.scenarios);
|
|
177
|
+
plan.paramRefs.push(...parsed.paramRefs);
|
|
178
|
+
}
|
|
179
|
+
return plan;
|
|
180
|
+
}
|
|
89
181
|
/** Parse every `*.spec.ts` under root into one merged plan (file paths shown relative to root). */
|
|
90
182
|
export async function parseAllSpecFiles(root) {
|
|
91
|
-
return
|
|
183
|
+
return parseSpecs(await findFiles(root, isSpecFile), root);
|
|
92
184
|
}
|
|
93
185
|
/** Parse the spec files belonging to a single proposed change (design §8). */
|
|
94
186
|
export async function parseChangeSpecs(root, changeName) {
|
|
95
|
-
|
|
187
|
+
const dir = join(root, 'changes', changeName);
|
|
188
|
+
return parseSpecs(await findFiles(dir, isSpecFile), root);
|
|
96
189
|
}
|
|
97
190
|
/** List the names of proposed changes under `root/changes`. */
|
|
98
191
|
export async function listChangeNames(root) {
|
|
99
192
|
try {
|
|
100
193
|
const entries = await readdir(join(root, 'changes'), { withFileTypes: true });
|
|
101
|
-
return entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
194
|
+
return entries.filter((e) => e.isDirectory()).map((e) => e.name).sort(byCodeUnit);
|
|
102
195
|
}
|
|
103
196
|
catch {
|
|
104
197
|
return [];
|
|
105
198
|
}
|
|
106
199
|
}
|
|
107
|
-
async function parseSpecsUnder(dir, displayRoot) {
|
|
108
|
-
const files = await findFiles(dir, isSpecFile);
|
|
109
|
-
const plan = { scenarios: [], paramRefs: [] };
|
|
110
|
-
for (const file of files) {
|
|
111
|
-
const source = await readFile(file, 'utf8');
|
|
112
|
-
const parsed = parseSpecFile(relative(displayRoot, file), source);
|
|
113
|
-
plan.scenarios.push(...parsed.scenarios);
|
|
114
|
-
plan.paramRefs.push(...parsed.paramRefs);
|
|
115
|
-
}
|
|
116
|
-
return plan;
|
|
117
|
-
}
|
|
118
200
|
//# sourceMappingURL=locate.js.map
|
package/dist/core/locate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locate.js","sourceRoot":"","sources":["../../src/core/locate.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,0EAA0E;AAE1E,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"locate.js","sourceRoot":"","sources":["../../src/core/locate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"order.d.ts","sourceRoot":"","sources":["../../src/core/order.ts"],"names":[],"mappings":"AASA,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Deterministic ordering primitives.
|
|
2
|
+
//
|
|
3
|
+
// Anything Attest writes to disk or compares for equality has to sort on the
|
|
4
|
+
// strings themselves and nothing else. `localeCompare` does not: it returns 0
|
|
5
|
+
// for *distinct* strings (a precomposed "ä" against its combining-mark
|
|
6
|
+
// spelling), and since `Array#sort` is stable, whatever it calls equal keeps
|
|
7
|
+
// its insertion order — so the result encodes how the input happened to be
|
|
8
|
+
// written. Which strings collate equal is ICU-dependent on top of that.
|
|
9
|
+
/** Compare by UTF-16 code unit — the same order as a bare `Array#sort()`. */
|
|
10
|
+
export function byCodeUnit(a, b) {
|
|
11
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=order.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"order.js","sourceRoot":"","sources":["../../src/core/order.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,uEAAuE;AACvE,6EAA6E;AAC7E,2EAA2E;AAC3E,wEAAwE;AAExE,6EAA6E;AAC7E,MAAM,UAAU,UAAU,CAAC,CAAS,EAAE,CAAS;IAC7C,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,CAAC"}
|
package/dist/core/pipeline.d.ts
CHANGED
|
@@ -1,11 +1,36 @@
|
|
|
1
1
|
import type { RenderTarget } from './render.js';
|
|
2
2
|
import type { Issue } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* How the commands that do not run the suite should read the registry.
|
|
5
|
+
*
|
|
6
|
+
* Reading is static by default (design §5.1): `check`, `cover` and `render`
|
|
7
|
+
* describe themselves as analysis, and a reader that evaluates every
|
|
8
|
+
* `*.reqs.ts` it finds gives them the threat model of a test run — on a fork
|
|
9
|
+
* MR, a top-level `fetch` in a registry file is enough. `evaluate` is the named
|
|
10
|
+
* way back for a project whose registry is not a literal.
|
|
11
|
+
*/
|
|
12
|
+
export interface ReadOptions {
|
|
13
|
+
/** Read the registry by executing each `*.reqs.ts` (CLI: `--eval`). */
|
|
14
|
+
evaluate?: boolean;
|
|
15
|
+
}
|
|
3
16
|
/** Static structural check (design §9: `attest check`). */
|
|
4
|
-
export declare function runCheck(root: string): Promise<Issue[]>;
|
|
17
|
+
export declare function runCheck(root: string, options?: ReadOptions): Promise<Issue[]>;
|
|
18
|
+
/** What a run actually looked at. Reported so a green cannot be read blind. */
|
|
19
|
+
export interface VerifyCounts {
|
|
20
|
+
/** Requirements in the registry. */
|
|
21
|
+
requirements: number;
|
|
22
|
+
/** Scenarios the static plan found. */
|
|
23
|
+
scenarios: number;
|
|
24
|
+
/** `*.spec.ts` files located under the root. */
|
|
25
|
+
specFiles: number;
|
|
26
|
+
/** Of those, the ones declaring at least one `requirement()` — the run scope. */
|
|
27
|
+
attesting: number;
|
|
28
|
+
}
|
|
5
29
|
export interface VerifyResult {
|
|
6
30
|
issues: Issue[];
|
|
7
31
|
passed: boolean;
|
|
8
32
|
ok: boolean;
|
|
33
|
+
counts: VerifyCounts;
|
|
9
34
|
}
|
|
10
35
|
/** Options common to the commands that start a child Vitest run. */
|
|
11
36
|
export interface RunOptions {
|
|
@@ -20,7 +45,7 @@ export interface CoverageRow {
|
|
|
20
45
|
scenarioCount: number;
|
|
21
46
|
}
|
|
22
47
|
/** Coverage-only report (design §9: `attest cover`). */
|
|
23
|
-
export declare function runCover(root: string): Promise<CoverageRow[]>;
|
|
48
|
+
export declare function runCover(root: string, options?: ReadOptions): Promise<CoverageRow[]>;
|
|
24
49
|
export interface RenderResult {
|
|
25
50
|
/** The rendered document; empty string when `issues` contains an ERROR. */
|
|
26
51
|
markdown: string;
|
|
@@ -35,7 +60,7 @@ export interface RenderResult {
|
|
|
35
60
|
* `*.reqs.ts` files, so a committed rendering can be gated without going stale
|
|
36
61
|
* every time a line moves in a test file.
|
|
37
62
|
*/
|
|
38
|
-
export declare function runRender(root: string): Promise<RenderResult>;
|
|
63
|
+
export declare function runRender(root: string, options?: ReadOptions): Promise<RenderResult>;
|
|
39
64
|
/**
|
|
40
65
|
* Freshness gate for a committed rendering (`attest render --check`).
|
|
41
66
|
*
|
|
@@ -43,9 +68,16 @@ export declare function runRender(root: string): Promise<RenderResult>;
|
|
|
43
68
|
* failure mode Attest exists to remove — so the projection only earns its place
|
|
44
69
|
* alongside a gate that fails when the file no longer matches its source.
|
|
45
70
|
*/
|
|
46
|
-
export declare function runRenderCheck(root: string, outFile: string, target: RenderTarget): Promise<Issue[]>;
|
|
71
|
+
export declare function runRenderCheck(root: string, outFile: string, target: RenderTarget, options?: ReadOptions): Promise<Issue[]>;
|
|
72
|
+
/**
|
|
73
|
+
* The globs that keep *other* proposals out of a change's gate run.
|
|
74
|
+
*
|
|
75
|
+
* Sibling names come from `readdir`, not from the guard above, so they are
|
|
76
|
+
* escaped: a directory called `feat(auth)` pasted in raw is a *pattern*, it
|
|
77
|
+
* matches nothing, and that sibling's specs silently join the run — quietly
|
|
78
|
+
* widening the scope of the one check that decides "done".
|
|
79
|
+
*/
|
|
80
|
+
export declare function changeExcludeGlobs(others: string[]): string[];
|
|
47
81
|
/** Archive gate for a change (design §8, §9: `attest archive <change>`). */
|
|
48
82
|
export declare function runArchive(root: string, changeName: string, options?: RunOptions): Promise<Issue[]>;
|
|
49
|
-
/** True when a spec suite exists at all (used by the CLI to warn on empty roots). */
|
|
50
|
-
export declare function hasSpecs(root: string): Promise<boolean>;
|
|
51
83
|
//# sourceMappingURL=pipeline.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/core/pipeline.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/core/pipeline.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD,OAAO,KAAK,EAAc,KAAK,EAAY,MAAM,YAAY,CAAC;AAE9D;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B,uEAAuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAoBD,2DAA2D;AAC3D,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CASxF;AAED,+EAA+E;AAC/E,MAAM,WAAW,YAAY;IAC3B,oCAAoC;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,YAAY,CAAC;CACtB;AAeD,oEAAoE;AACpE,MAAM,WAAW,UAAU;IACzB,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,4DAA4D;AAC5D,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CA6D7F;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wDAAwD;AACxD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAe9F;AAED,MAAM,WAAW,YAAY;IAC3B,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CAM9F;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,KAAK,EAAE,CAAC,CAOlB;AA2BD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAE7D;AAMD,4EAA4E;AAC5E,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,KAAK,EAAE,CAAC,CAoElB"}
|