supercov 0.0.1 → 0.0.3
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 +21 -0
- package/README.md +115 -20
- package/bin/supercov.js +10 -0
- package/dist/atomic.d.ts +6 -0
- package/dist/atomic.d.ts.map +1 -0
- package/dist/atomic.js +47 -0
- package/dist/atomic.js.map +1 -0
- package/dist/cli.js +431 -214
- package/dist/cli.js.map +1 -1
- package/dist/directInstrumenter.d.ts +8 -0
- package/dist/directInstrumenter.d.ts.map +1 -0
- package/dist/directInstrumenter.js +70 -0
- package/dist/directInstrumenter.js.map +1 -0
- package/dist/instrumenter.d.ts.map +1 -1
- package/dist/instrumenter.js +251 -41
- package/dist/instrumenter.js.map +1 -1
- package/dist/integrity.d.ts.map +1 -1
- package/dist/integrity.js +27 -0
- package/dist/integrity.js.map +1 -1
- package/dist/launchSupervisor.d.ts +24 -0
- package/dist/launchSupervisor.d.ts.map +1 -0
- package/dist/launchSupervisor.js +397 -0
- package/dist/launchSupervisor.js.map +1 -0
- package/dist/playwright.d.ts +0 -4
- package/dist/playwright.d.ts.map +1 -1
- package/dist/playwright.js +33 -17
- package/dist/playwright.js.map +1 -1
- package/dist/playwrightReporter.d.ts.map +1 -1
- package/dist/playwrightReporter.js +3 -2
- package/dist/playwrightReporter.js.map +1 -1
- package/dist/project.d.ts +5 -2
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +192 -27
- package/dist/project.js.map +1 -1
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +1 -0
- package/dist/query.js.map +1 -1
- package/dist/register.mjs +18 -13
- package/dist/register.mjs.map +1 -1
- package/dist/reporter.d.ts +4 -1
- package/dist/reporter.d.ts.map +1 -1
- package/dist/reporter.js +13 -11
- package/dist/reporter.js.map +1 -1
- package/dist/resolve-loader.d.mts.map +1 -1
- package/dist/resolve-loader.mjs +11 -3
- package/dist/resolve-loader.mjs.map +1 -1
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +35 -7
- package/dist/runtime.js.map +1 -1
- package/dist/transport.d.ts +2 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +2 -0
- package/dist/transport.js.map +1 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/vitePlugin.d.ts.map +1 -1
- package/dist/vitePlugin.js +4 -3
- package/dist/vitePlugin.js.map +1 -1
- package/dist/vitest.js +3 -2
- package/dist/vitest.js.map +1 -1
- package/dist/vitestReporter.d.ts +17 -2
- package/dist/vitestReporter.d.ts.map +1 -1
- package/dist/vitestReporter.js +51 -2
- package/dist/vitestReporter.js.map +1 -1
- package/dist/workspace.d.ts +46 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +284 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +30 -5
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Supercov contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -18,24 +18,51 @@ npm link
|
|
|
18
18
|
|
|
19
19
|
## Verifying the instrumenter
|
|
20
20
|
|
|
21
|
-
The coverage engine has
|
|
21
|
+
The coverage engine has seven independent release gates:
|
|
22
22
|
|
|
23
23
|
- semantic differential fixtures execute original and instrumented programs
|
|
24
24
|
in isolated scopes and compare return values, thrown errors, and observable
|
|
25
25
|
side-effect order;
|
|
26
26
|
- a deterministic generated corpus exercises 160 nested combinations of
|
|
27
27
|
short-circuiting, ternaries, coercion, and thrown expressions on every run;
|
|
28
|
+
- seeded `fast-check` properties exercise another 500 generated nested
|
|
29
|
+
expressions and 300 generated control-flow executions, with shrinking and a
|
|
30
|
+
reproducible seed on failure;
|
|
28
31
|
- coverage oracles assert exact decision vectors, MC/DC witnesses, and branch
|
|
29
|
-
alternatives independently of program behavior
|
|
32
|
+
alternatives independently of program behavior;
|
|
33
|
+
- the same three-condition masking-MC/DC golden cases must report 100% for a
|
|
34
|
+
complete witness set and 33.33% for an incomplete one under both Supercov
|
|
35
|
+
and Clang/LLVM source-based MC/DC;
|
|
36
|
+
- release CI shards the pinned TC39 Test262 corpus across 16 workers, runs the
|
|
37
|
+
official Test262 harness on original and instrumented sources, and rejects
|
|
38
|
+
any scenario that passes originally but fails after transformation; and
|
|
39
|
+
- checked performance budgets cover transform latency, output expansion, and
|
|
40
|
+
runtime probe overhead.
|
|
30
41
|
|
|
31
42
|
```sh
|
|
32
43
|
npm test
|
|
44
|
+
npm run test:clang-mcdc
|
|
45
|
+
npm run benchmark:check
|
|
46
|
+
TEST262_DIR=/path/to/test262 npm run test:test262
|
|
33
47
|
```
|
|
34
48
|
|
|
35
49
|
The differential suite includes getters, proxies, optional calls and `this`,
|
|
36
50
|
computed logical assignments, defaults, `try`/`catch`/`finally`, iterator
|
|
37
51
|
closing, switch fallthrough, labeled loops, async functions, and generators.
|
|
38
|
-
|
|
52
|
+
The compatibility workflow additionally runs Node 22/24/25, Playwright
|
|
53
|
+
1.55/current, Vite 5/current, Vitest 2/current, Chromium, Firefox, WebKit, and
|
|
54
|
+
modern JavaScript/JSX/TypeScript/TSX syntax fixtures. Test262's module, async,
|
|
55
|
+
raw, parse/resolution-negative, Annex B sloppy-script extension, and explicit
|
|
56
|
+
`Function.prototype.toString`/function-source-coercion tests are intentionally
|
|
57
|
+
excluded from the source-rewrite comparison, with reason counts printed for
|
|
58
|
+
every shard. Annex B does not apply to the Vite application modules Supercov
|
|
59
|
+
instruments; exact source reflection necessarily observes a source transform.
|
|
60
|
+
When application code directly coerces or observes a function's source,
|
|
61
|
+
Supercov leaves that function body uninstrumented and records a visible
|
|
62
|
+
`semantic-safety` completeness blocker. The release corpus covers every other eligible synchronous
|
|
63
|
+
script and runtime-negative scenario, while dedicated differential fixtures
|
|
64
|
+
cover async functions and generators. Every semantic-equivalence failure
|
|
65
|
+
blocks the trusted-publishing workflow.
|
|
39
66
|
|
|
40
67
|
## Agent query workflow
|
|
41
68
|
|
|
@@ -87,31 +114,99 @@ Text output is concise for an interactive agent; JSON is the stable machine
|
|
|
87
114
|
interface that can later back hosted coverage tools without changing the
|
|
88
115
|
stored schema.
|
|
89
116
|
|
|
90
|
-
For a conventional Vite project, the
|
|
117
|
+
For a conventional Vite project, or a Node project with no build step, the
|
|
118
|
+
CLI:
|
|
91
119
|
|
|
92
|
-
1.
|
|
93
|
-
`.supercov
|
|
120
|
+
1. refreshes a stable isolated source namespace under
|
|
121
|
+
`.supercov/cache/instrumented-workspace/<project>/`, links the existing
|
|
122
|
+
dependency tree, and creates all Vite, Vitest, Playwright, and build output
|
|
123
|
+
only there; the stable path lets VM/container snapshot systems reuse a
|
|
124
|
+
coverage build without touching the application's ordinary build;
|
|
94
125
|
2. inventories every `app/**/*.ts(x)` and `src/**/*.ts(x)` file for the
|
|
95
|
-
denominator, then
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
126
|
+
denominator, then instruments modules loaded by Vite without changing the
|
|
127
|
+
project's config; when no build script exists, it instruments only the
|
|
128
|
+
disposable source copy and supplies a module-format-neutral runtime through
|
|
129
|
+
the inherited Node preload;
|
|
130
|
+
3. discovers the Playwright-compatible fixture provider, test export, and
|
|
131
|
+
additional named exports from the suite's existing imports, then redirects
|
|
132
|
+
that provider at module-load time; Vitest setup is injected through the
|
|
133
|
+
child runner's generated config;
|
|
134
|
+
4. runs the exact command following `--`, propagating coverage through every
|
|
135
|
+
Node child process it launches;
|
|
101
136
|
5. attributes every source hit and decision vector to its individual test,
|
|
102
137
|
automatically wraps Playwright actions and assertions, and records the
|
|
103
138
|
action/assertion phase responsible for each correlated hit; then merges
|
|
104
139
|
server and browser evidence into HTML and JSON reports; and
|
|
105
|
-
6.
|
|
140
|
+
6. atomically publishes the evidence/report into `.supercov/` and retains only
|
|
141
|
+
the disposable isolated build namespace as a provider snapshot cache. The
|
|
142
|
+
ordinary application build is never read as an input, overwritten, or
|
|
143
|
+
rebuilt afterward.
|
|
144
|
+
|
|
145
|
+
Only `.supercov/` is modified in the user's checkout. A per-project lock
|
|
146
|
+
rejects overlapping runs before either can build. Run state is durably written
|
|
147
|
+
through preparing/building/testing/reporting/terminal phases; SIGINT, SIGTERM,
|
|
148
|
+
and SIGHUP are forwarded to the entire child process group. If the process is
|
|
149
|
+
killed without a cleanup opportunity, the next invocation marks the dead PID's
|
|
150
|
+
run abandoned and refreshes the isolated namespace before using it. Report,
|
|
151
|
+
evidence, and state writes use sibling-temp files, fsync, and atomic rename;
|
|
152
|
+
lock acquisition uses exclusive creation and fsync.
|
|
153
|
+
|
|
154
|
+
Retention is deterministic because UTC run IDs sort chronologically:
|
|
155
|
+
|
|
156
|
+
```sh
|
|
157
|
+
npx supercov clean --keep 20
|
|
158
|
+
npx supercov clean --keep 20 --dry-run
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The cleanup command never removes an active workspace and never touches files
|
|
162
|
+
outside `.supercov/`.
|
|
106
163
|
|
|
107
164
|
The automatic adapters currently support standard Playwright suites (ESM and
|
|
108
|
-
CommonJS specs in arbitrary project directories),
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
165
|
+
CommonJS specs in arbitrary project directories), project-owned Playwright
|
|
166
|
+
fixture packages, Vitest, no-build Node commands, and Node coordinators that
|
|
167
|
+
launch tests inside a mounted VM/container workspace. A single command such as
|
|
168
|
+
`supercov -- npm test` can collect Vitest and Playwright evidence into the same
|
|
169
|
+
run. No-build Node execution is retained as background/unattributed evidence
|
|
170
|
+
until a recognized test-runner adapter supplies exact test boundaries. Jest,
|
|
171
|
+
exact `node:test` attribution, non-Vite application builds, browser component
|
|
172
|
+
runners, and distributed multi-host merging still require adapters; they are
|
|
173
|
+
not silently reported as per-test coverage.
|
|
174
|
+
|
|
175
|
+
Remote execution discovery is structural rather than provider-specific. The
|
|
176
|
+
preload observes CommonJS exports for a static `build(options)` capability,
|
|
177
|
+
activates only when those options contain a host-to-guest mount that includes
|
|
178
|
+
the isolated project, scopes an existing cache/snapshot identity to the run's
|
|
179
|
+
source fingerprint, and follows the opaque returned object graph. A method
|
|
180
|
+
whose options contain `argv`, `cmd`, or `command` receives guest-translated
|
|
181
|
+
Supercov paths and a guest-valid Node preload. The execution log records this
|
|
182
|
+
process/capability graph but hashes long or multiline arguments so embedded
|
|
183
|
+
shell bodies and credentials are never persisted.
|
|
184
|
+
|
|
185
|
+
This first zero-edit mechanism has explicit boundaries. It follows Node child
|
|
186
|
+
processes, not arbitrary non-Node supervisors or a remote control plane that
|
|
187
|
+
never exposes launches to the local process. The remote SDK must currently be
|
|
188
|
+
visible through CommonJS loading, its build options must expose the workspace
|
|
189
|
+
mount, and its execution call must accept an environment. Pure-ESM executor
|
|
190
|
+
SDKs, positional-only remote exec APIs, and providers that hide all launch
|
|
191
|
+
state behind an RPC need additional interception layers. Supercov reports
|
|
192
|
+
missing evidence rather than claiming those paths are covered.
|
|
193
|
+
|
|
194
|
+
The public regression suite includes a provider-neutral opaque executor. Its
|
|
195
|
+
CommonJS SDK exposes only a static build capability, a host-to-guest mount,
|
|
196
|
+
an existing snapshot key, an opaque image/pool/machine chain, and an
|
|
197
|
+
argv-shaped execution method. CI requires Supercov to discover that structure,
|
|
198
|
+
scope the cache identity, translate paths and the Node preload into the guest,
|
|
199
|
+
run nested Vitest and Playwright commands, parse every concurrent trace shard,
|
|
200
|
+
and produce 100% fixture coverage. A separate clean-room gate packs the npm
|
|
201
|
+
tarball and invokes it through `npx` in a project with no build step, asserting
|
|
202
|
+
that no source or configuration file changes.
|
|
203
|
+
|
|
204
|
+
Before the isolated build, Supercov also compares the invoked npm/pnpm/yarn/bun
|
|
205
|
+
script with explicit string-valued `process.env` mode checks in the project's
|
|
206
|
+
build config. A semantic match such as `test:preview` and
|
|
207
|
+
`process.env.TEST_PREVIEW === "true"` activates that build-only flag and is
|
|
208
|
+
printed before the build. It never guesses values for unrelated environment
|
|
209
|
+
variables.
|
|
115
210
|
|
|
116
211
|
Each test carries two independent provenance fields:
|
|
117
212
|
|
package/bin/supercov.js
CHANGED
|
@@ -13,6 +13,16 @@ const child = spawn(
|
|
|
13
13
|
},
|
|
14
14
|
);
|
|
15
15
|
|
|
16
|
+
for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
|
|
17
|
+
process.once(signal, () => {
|
|
18
|
+
try {
|
|
19
|
+
child.kill(signal);
|
|
20
|
+
} catch {
|
|
21
|
+
// The child may already have completed.
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
16
26
|
child.on("error", (error) => {
|
|
17
27
|
console.error("[supercov] failed to start", error);
|
|
18
28
|
process.exitCode = 1;
|
package/dist/atomic.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type WriteFileOptions } from "node:fs";
|
|
2
|
+
/** Write a complete sibling file and atomically replace the destination. */
|
|
3
|
+
export declare function atomicWriteFileSync(path: string, data: string | NodeJS.ArrayBufferView, options?: WriteFileOptions): void;
|
|
4
|
+
/** Atomically publish a fully prepared file or directory and persist its entry. */
|
|
5
|
+
export declare function atomicRenameSync(source: string, destination: string): void;
|
|
6
|
+
//# sourceMappingURL=atomic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atomic.d.ts","sourceRoot":"","sources":["../src/atomic.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,gBAAgB,EACtB,MAAM,SAAS,CAAC;AAiBjB,4EAA4E;AAC5E,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,eAAe,EACrC,OAAO,CAAC,EAAE,gBAAgB,GACzB,IAAI,CAmBN;AAED,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAI1E"}
|
package/dist/atomic.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { mkdirSync, openSync, closeSync, fsyncSync, renameSync, rmSync, writeFileSync, } from "node:fs";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
function fsyncDirectory(path) {
|
|
5
|
+
try {
|
|
6
|
+
const directory = openSync(path, "r");
|
|
7
|
+
try {
|
|
8
|
+
fsyncSync(directory);
|
|
9
|
+
}
|
|
10
|
+
finally {
|
|
11
|
+
closeSync(directory);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// Some platforms (notably Windows) do not permit opening directories.
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Write a complete sibling file and atomically replace the destination. */
|
|
19
|
+
export function atomicWriteFileSync(path, data, options) {
|
|
20
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
21
|
+
const temporary = `${path}.${process.pid}.${randomUUID()}.tmp`;
|
|
22
|
+
let descriptor;
|
|
23
|
+
try {
|
|
24
|
+
descriptor = openSync(temporary, "wx", 0o600);
|
|
25
|
+
writeFileSync(descriptor, data, options);
|
|
26
|
+
fsyncSync(descriptor);
|
|
27
|
+
closeSync(descriptor);
|
|
28
|
+
descriptor = undefined;
|
|
29
|
+
renameSync(temporary, path);
|
|
30
|
+
// Persist the directory entry as well as the file contents on POSIX. Some
|
|
31
|
+
// platforms (notably Windows) do not permit opening directories, so file
|
|
32
|
+
// fsync + atomic rename remains the portable fallback there.
|
|
33
|
+
fsyncDirectory(dirname(path));
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
if (descriptor !== undefined)
|
|
37
|
+
closeSync(descriptor);
|
|
38
|
+
rmSync(temporary, { force: true });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Atomically publish a fully prepared file or directory and persist its entry. */
|
|
42
|
+
export function atomicRenameSync(source, destination) {
|
|
43
|
+
mkdirSync(dirname(destination), { recursive: true });
|
|
44
|
+
renameSync(source, destination);
|
|
45
|
+
fsyncDirectory(dirname(destination));
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=atomic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atomic.js","sourceRoot":"","sources":["../src/atomic.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,QAAQ,EACR,SAAS,EACT,SAAS,EACT,UAAU,EACV,MAAM,EACN,aAAa,GAEd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,SAAS,cAAc,CAAC,IAAY;IAClC,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACtC,IAAI,CAAC;YACH,SAAS,CAAC,SAAS,CAAC,CAAC;QACvB,CAAC;gBAAS,CAAC;YACT,SAAS,CAAC,SAAS,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,sEAAsE;IACxE,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,mBAAmB,CACjC,IAAY,EACZ,IAAqC,EACrC,OAA0B;IAE1B,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,SAAS,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,IAAI,UAAU,EAAE,MAAM,CAAC;IAC/D,IAAI,UAA8B,CAAC;IACnC,IAAI,CAAC;QACH,UAAU,GAAG,QAAQ,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QAC9C,aAAa,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACzC,SAAS,CAAC,UAAU,CAAC,CAAC;QACtB,SAAS,CAAC,UAAU,CAAC,CAAC;QACtB,UAAU,GAAG,SAAS,CAAC;QACvB,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAC5B,0EAA0E;QAC1E,yEAAyE;QACzE,6DAA6D;QAC7D,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAChC,CAAC;YAAS,CAAC;QACT,IAAI,UAAU,KAAK,SAAS;YAAE,SAAS,CAAC,UAAU,CAAC,CAAC;QACpD,MAAM,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;AACH,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,gBAAgB,CAAC,MAAc,EAAE,WAAmB;IAClE,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,UAAU,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAChC,cAAc,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;AACvC,CAAC"}
|