ushman-ledger 1.2.1 → 1.2.2
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/ARCHITECTURE.md +79 -0
- package/README.md +87 -0
- package/TROUBLESHOOTING.md +170 -0
- package/dist/blobs.d.ts +3 -0
- package/dist/blobs.d.ts.map +1 -1
- package/dist/blobs.js +41 -15
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +85 -27
- package/dist/coverage.d.ts.map +1 -1
- package/dist/coverage.js +3 -2
- package/dist/doctor.d.ts +17 -4
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +224 -57
- package/dist/helpers.d.ts +1 -0
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +23 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/list.d.ts +2 -1
- package/dist/list.d.ts.map +1 -1
- package/dist/list.js +19 -9
- package/dist/patch-resolver.d.ts.map +1 -1
- package/dist/patch-resolver.js +193 -53
- package/dist/read-index.d.ts.map +1 -1
- package/dist/read-index.js +6 -5
- package/dist/record.d.ts.map +1 -1
- package/dist/record.js +2 -1
- package/dist/runtime-config.d.ts +12 -0
- package/dist/runtime-config.d.ts.map +1 -0
- package/dist/runtime-config.js +83 -0
- package/dist/storage/filesystem.d.ts +1 -0
- package/dist/storage/filesystem.d.ts.map +1 -1
- package/dist/storage/filesystem.js +33 -3
- package/dist/text-lines.d.ts +8 -0
- package/dist/text-lines.d.ts.map +1 -0
- package/dist/text-lines.js +20 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +2 -1
- package/package.json +4 -2
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ import path from 'node:path';
|
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import { promisify } from 'node:util';
|
|
8
8
|
import * as v from 'valibot';
|
|
9
|
+
import { readPatchTextFromFile } from "./blobs.js";
|
|
9
10
|
import { openLedger } from "./handle.js";
|
|
10
11
|
import { deriveFilesChangedFromPatch } from "./patch-resolver.js";
|
|
11
12
|
import { ChangeLogParityStatusSchema, ChangeLogSmokeResultSchema, ChangeLogSubkindSchema, LEDGER_KINDS, LEDGER_PHASES, parseLedgerRecord, WorkspaceRelativePathSchema, } from "./schema/entry.js";
|
|
@@ -14,6 +15,8 @@ import { LEDGER_LIBRARY_VERSION } from "./version.js";
|
|
|
14
15
|
const execFileAsync = promisify(execFile);
|
|
15
16
|
const DEFAULT_GIT_DIFF_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
|
|
16
17
|
const DEFAULT_GIT_DIFF_TIMEOUT_MS = 30_000;
|
|
18
|
+
const BOOLEAN_FLAG_NAMES = new Set(['from-stdin', 'help', 'json']);
|
|
19
|
+
const GIT_DIFF_FORMAT_ARGS = ['--no-color', '--no-ext-diff', '--src-prefix=a/', '--dst-prefix=b/'];
|
|
17
20
|
const RENDER_TARGETS = [
|
|
18
21
|
'retro',
|
|
19
22
|
'jsonl',
|
|
@@ -54,6 +57,15 @@ const renderValidValues = () => `Valid values:
|
|
|
54
57
|
note subkinds: ${NoteSubkindSchema.options.join(', ')}
|
|
55
58
|
render targets: ${RENDER_TARGETS.join(', ')}
|
|
56
59
|
`;
|
|
60
|
+
const renderRuntimeTuningHelp = () => `Runtime tuning env vars:
|
|
61
|
+
USHMAN_LEDGER_SCAN_BATCH_SIZE (default: 32)
|
|
62
|
+
USHMAN_LEDGER_SCAN_CONCURRENCY (default: 16)
|
|
63
|
+
USHMAN_LEDGER_READ_INDEX_REBUILD_BATCH_SIZE (default: USHMAN_LEDGER_SCAN_BATCH_SIZE)
|
|
64
|
+
USHMAN_LEDGER_READ_INDEX_REBUILD_CONCURRENCY (default: USHMAN_LEDGER_SCAN_CONCURRENCY)
|
|
65
|
+
USHMAN_LEDGER_COVERAGE_FILE_STAT_CONCURRENCY (default: USHMAN_LEDGER_SCAN_CONCURRENCY)
|
|
66
|
+
USHMAN_LEDGER_BLOB_HASH_CONCURRENCY (default: USHMAN_LEDGER_SCAN_CONCURRENCY)
|
|
67
|
+
USHMAN_LEDGER_MAX_PATCH_BYTES (default: 10485760)
|
|
68
|
+
`;
|
|
57
69
|
const renderHelp = (commandName) => `${commandName}
|
|
58
70
|
|
|
59
71
|
Commands:
|
|
@@ -64,28 +76,37 @@ Commands:
|
|
|
64
76
|
${commandName} tail [--workspace=<ws>] [--phase=<phase>] [--limit=<n>]
|
|
65
77
|
${commandName} render [--workspace=<ws>] [--to=retro|jsonl|timeline-html|dependency-graph|migration-log-md|workspace-narrative-md] [--phase=<phase>] [--since=<iso>] [--limit=<n>] [--out=<file>]
|
|
66
78
|
${commandName} archive [--workspace=<ws>] --out=<file.tgz>
|
|
67
|
-
${commandName} doctor [--workspace=<ws>]
|
|
79
|
+
${commandName} doctor [--workspace=<ws>] [--json]
|
|
68
80
|
${commandName} --version
|
|
69
81
|
|
|
70
|
-
${renderValidValues()}
|
|
82
|
+
${renderValidValues()}
|
|
83
|
+
${renderRuntimeTuningHelp()}`;
|
|
71
84
|
const renderCommandHelp = (commandName, command) => {
|
|
72
85
|
switch (command) {
|
|
73
86
|
case 'record':
|
|
74
87
|
return `${renderRecordUsage(commandName)}
|
|
75
88
|
|
|
76
|
-
${renderValidValues()}
|
|
89
|
+
${renderValidValues()}
|
|
90
|
+
${renderRuntimeTuningHelp()}`;
|
|
77
91
|
case 'note':
|
|
78
92
|
return `${commandName} note <subkind> [--workspace=<ws>] --phase=<phase> --summary="..." [--body=<markdown-file>] [--from-stdin]
|
|
79
93
|
|
|
80
|
-
${renderValidValues()}
|
|
94
|
+
${renderValidValues()}
|
|
95
|
+
${renderRuntimeTuningHelp()}`;
|
|
81
96
|
case 'list':
|
|
82
97
|
return `${commandName} list [--workspace=<ws>] [--phase=<phase>] [--kind=<kind>] [--since=<iso>] [--limit=<n>] [--json]
|
|
83
98
|
|
|
84
|
-
${renderValidValues()}
|
|
99
|
+
${renderValidValues()}
|
|
100
|
+
${renderRuntimeTuningHelp()}`;
|
|
85
101
|
case 'render':
|
|
86
102
|
return `${commandName} render [--workspace=<ws>] [--to=<target>] [--phase=<phase>] [--since=<iso>] [--limit=<n>] [--out=<file>]
|
|
87
103
|
|
|
88
|
-
${renderValidValues()}
|
|
104
|
+
${renderValidValues()}
|
|
105
|
+
${renderRuntimeTuningHelp()}`;
|
|
106
|
+
case 'doctor':
|
|
107
|
+
return `${commandName} doctor [--workspace=<ws>] [--json]
|
|
108
|
+
|
|
109
|
+
${renderRuntimeTuningHelp()}`;
|
|
89
110
|
default:
|
|
90
111
|
return renderHelp(commandName);
|
|
91
112
|
}
|
|
@@ -111,7 +132,7 @@ const parseArgv = (argv) => {
|
|
|
111
132
|
continue;
|
|
112
133
|
}
|
|
113
134
|
const next = argv[index + 1];
|
|
114
|
-
if (!next || next.startsWith('--')) {
|
|
135
|
+
if (BOOLEAN_FLAG_NAMES.has(name) || !next || next.startsWith('--')) {
|
|
115
136
|
flags[name] = true;
|
|
116
137
|
continue;
|
|
117
138
|
}
|
|
@@ -211,11 +232,31 @@ const isGitDiffTimeoutError = (error) => {
|
|
|
211
232
|
error.killed === true &&
|
|
212
233
|
error.signal === 'SIGTERM');
|
|
213
234
|
};
|
|
235
|
+
const buildGitDiffArgs = (gitOptions, gitRef) => gitOptions.scopedPaths.length === 0
|
|
236
|
+
? ['diff', ...GIT_DIFF_FORMAT_ARGS, gitRef]
|
|
237
|
+
: ['diff', ...GIT_DIFF_FORMAT_ARGS, gitRef, '--', ...gitOptions.scopedPaths];
|
|
238
|
+
const throwGitDiffFailure = ({ error, gitOptions, gitRef, }) => {
|
|
239
|
+
if (getErrorCode(error) === 'ENOENT') {
|
|
240
|
+
throw new CliUsageError('git is required for --diff-from-git and was not found in PATH. Install git or use --diff with a patch file.');
|
|
241
|
+
}
|
|
242
|
+
if (isGitDiffTimeoutError(error)) {
|
|
243
|
+
throw new CliUsageError(`git diff ${gitRef} timed out after ${gitOptions.timeoutMs}ms. Narrow the diff or increase --git-diff-timeout-ms.`);
|
|
244
|
+
}
|
|
245
|
+
if (isGitDiffMaxBufferError(error)) {
|
|
246
|
+
throw new CliUsageError(`git diff ${gitRef} exceeded the configured stdout buffer (${gitOptions.maxBufferBytes} bytes). Narrow the diff or increase --git-diff-max-buffer-bytes.`);
|
|
247
|
+
}
|
|
248
|
+
const stderr = typeof error === 'object' && error !== null && 'stderr' in error
|
|
249
|
+
? String(error.stderr ?? '').trim()
|
|
250
|
+
: '';
|
|
251
|
+
if (stderr.length > 0) {
|
|
252
|
+
throw new CliUsageError(`git diff ${gitRef} failed: ${stderr}`);
|
|
253
|
+
}
|
|
254
|
+
throw new CliUsageError(`git diff ${gitRef} failed. Ensure the ref exists and the workspace is a git repository.`);
|
|
255
|
+
};
|
|
214
256
|
const materializeGitDiff = async ({ gitOptions, gitRef, workspaceRoot, }) => {
|
|
215
257
|
let tempDir;
|
|
216
258
|
try {
|
|
217
|
-
const
|
|
218
|
-
const { stdout } = await execFileAsync('git', gitArgs, {
|
|
259
|
+
const { stdout } = await execFileAsync('git', buildGitDiffArgs(gitOptions, gitRef), {
|
|
219
260
|
cwd: workspaceRoot,
|
|
220
261
|
maxBuffer: gitOptions.maxBufferBytes,
|
|
221
262
|
timeout: gitOptions.timeoutMs,
|
|
@@ -229,16 +270,11 @@ const materializeGitDiff = async ({ gitOptions, gitRef, workspaceRoot, }) => {
|
|
|
229
270
|
if (tempDir) {
|
|
230
271
|
await rm(tempDir, { force: true, recursive: true });
|
|
231
272
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
238
|
-
if (isGitDiffMaxBufferError(error)) {
|
|
239
|
-
throw new CliUsageError(`git diff ${gitRef} exceeded the configured stdout buffer (${gitOptions.maxBufferBytes} bytes). Narrow the diff or increase --git-diff-max-buffer-bytes.`);
|
|
240
|
-
}
|
|
241
|
-
throw error;
|
|
273
|
+
return throwGitDiffFailure({
|
|
274
|
+
error,
|
|
275
|
+
gitOptions,
|
|
276
|
+
gitRef,
|
|
277
|
+
});
|
|
242
278
|
}
|
|
243
279
|
};
|
|
244
280
|
const parseJsonInput = (text, sourceLabel) => {
|
|
@@ -252,6 +288,9 @@ const parseJsonInput = (text, sourceLabel) => {
|
|
|
252
288
|
const print = (context, text) => {
|
|
253
289
|
context.stdout.write(text.endsWith('\n') ? text : `${text}\n`);
|
|
254
290
|
};
|
|
291
|
+
const printJson = (context, value) => {
|
|
292
|
+
print(context, JSON.stringify(value, null, 2));
|
|
293
|
+
};
|
|
255
294
|
const parseLimit = (flags) => getFlag(flags, 'limit')
|
|
256
295
|
? parsePositiveIntegerFlag({
|
|
257
296
|
defaultValue: 0,
|
|
@@ -397,7 +436,7 @@ const assertDiffRecordKindSupported = (kind) => {
|
|
|
397
436
|
}
|
|
398
437
|
throw new CliUsageError('--diff and --diff-from-git are only supported for patch and change-log records.');
|
|
399
438
|
};
|
|
400
|
-
const readPatchText = async (diffPath) =>
|
|
439
|
+
const readPatchText = async (diffPath) => readPatchTextFromFile(diffPath);
|
|
401
440
|
const readPatchTextForRecordKind = async (kind, diffPath) => {
|
|
402
441
|
if (kind === 'change-log' || kind === 'agent-patch' || kind === 'operator-patch') {
|
|
403
442
|
return readPatchText(diffPath);
|
|
@@ -695,16 +734,22 @@ const runNoteCli = async (parsed, context) => {
|
|
|
695
734
|
const runListCli = async (parsed, context) => {
|
|
696
735
|
const ledger = await openLedger(getWorkspaceRoot(parsed.flags));
|
|
697
736
|
if (hasFlag(parsed.flags, 'json')) {
|
|
698
|
-
|
|
737
|
+
let wroteEntry = false;
|
|
738
|
+
context.stdout.write('[\n');
|
|
699
739
|
for await (const entry of ledger.list({
|
|
700
740
|
kind: parseOptionalKind(parsed.flags),
|
|
701
741
|
limit: parseLimit(parsed.flags),
|
|
702
742
|
phase: parseOptionalPhase(parsed.flags),
|
|
703
743
|
since: parseSince(parsed.flags),
|
|
704
744
|
})) {
|
|
705
|
-
|
|
745
|
+
if (wroteEntry) {
|
|
746
|
+
context.stdout.write(',\n');
|
|
747
|
+
}
|
|
748
|
+
const renderedEntry = JSON.stringify(entry, null, 2).replaceAll('\n', '\n ');
|
|
749
|
+
context.stdout.write(` ${renderedEntry}`);
|
|
750
|
+
wroteEntry = true;
|
|
706
751
|
}
|
|
707
|
-
|
|
752
|
+
context.stdout.write(wroteEntry ? '\n]\n' : ']\n');
|
|
708
753
|
return 0;
|
|
709
754
|
}
|
|
710
755
|
for await (const entry of ledger.list({
|
|
@@ -762,16 +807,29 @@ const runArchiveCli = async (parsed, context) => {
|
|
|
762
807
|
print(context, result.integrityHash);
|
|
763
808
|
return 0;
|
|
764
809
|
};
|
|
810
|
+
const formatDoctorFinding = (finding) => [`[${finding.code}] ${finding.message}`, `Next step: ${finding.remediation}`].join('\n');
|
|
811
|
+
const printDoctorFindings = (context, report) => {
|
|
812
|
+
context.stderr.write(`doctor found ${report.issueCount} issue${report.issueCount === 1 ? '' : 's'}.\n`);
|
|
813
|
+
for (const [index, finding] of report.findings.entries()) {
|
|
814
|
+
context.stderr.write(`\n${formatDoctorFinding(finding)}`);
|
|
815
|
+
if (index < report.findings.length - 1) {
|
|
816
|
+
context.stderr.write('\n');
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
context.stderr.write('\n');
|
|
820
|
+
};
|
|
765
821
|
const runDoctorCli = async (parsed, context) => {
|
|
766
822
|
const ledger = await openLedger(getWorkspaceRoot(parsed.flags));
|
|
767
823
|
const result = await ledger.doctor();
|
|
824
|
+
if (hasFlag(parsed.flags, 'json')) {
|
|
825
|
+
printJson(context, result);
|
|
826
|
+
return result.ok ? 0 : 1;
|
|
827
|
+
}
|
|
768
828
|
if (result.ok) {
|
|
769
829
|
print(context, 'ok');
|
|
770
830
|
return 0;
|
|
771
831
|
}
|
|
772
|
-
|
|
773
|
-
context.stderr.write(`${issue}\n`);
|
|
774
|
-
}
|
|
832
|
+
printDoctorFindings(context, result);
|
|
775
833
|
return 1;
|
|
776
834
|
};
|
|
777
835
|
const formatCliError = (error) => {
|
|
@@ -787,7 +845,7 @@ const formatCliError = (error) => {
|
|
|
787
845
|
})
|
|
788
846
|
.join('\n');
|
|
789
847
|
}
|
|
790
|
-
return error instanceof Error ?
|
|
848
|
+
return error instanceof Error ? error.message : String(error);
|
|
791
849
|
};
|
|
792
850
|
export const runLedgerCli = async (argv, context = {}) => {
|
|
793
851
|
const mergedContext = { ...DEFAULT_CONTEXT, ...context };
|
package/dist/coverage.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../src/coverage.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../src/coverage.ts"],"names":[],"mappings":"AA+FA,MAAM,MAAM,cAAc,GAAG;IACzB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,EAAE,CAAC;CACrC,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,eAAe,MAAM,KAAG,OAAO,CAAC,cAAc,CAiDnF,CAAC"}
|
package/dist/coverage.js
CHANGED
|
@@ -4,10 +4,10 @@ import { mapWithConcurrencyLimit } from "./async.js";
|
|
|
4
4
|
import { CANDIDATE_EXCLUDE_GLOBS, CANDIDATE_FILE_GLOBS } from "./candidate-paths.js";
|
|
5
5
|
import { readLabManifestMin } from "./lab-min.js";
|
|
6
6
|
import { loadLedgerState } from "./recovery.js";
|
|
7
|
+
import { getLedgerRuntimeConfig } from "./runtime-config.js";
|
|
7
8
|
const EXCLUDED_ROOTS = new Set(CANDIDATE_EXCLUDE_GLOBS.map((glob) => glob.replace(/\/\*\*$/u, '')));
|
|
8
9
|
const CANDIDATE_DIRECTORIES = CANDIDATE_FILE_GLOBS.filter((glob) => glob.endsWith('/**/*')).map((glob) => glob.slice(0, -5));
|
|
9
10
|
const CANDIDATE_FILES = CANDIDATE_FILE_GLOBS.filter((glob) => !glob.endsWith('/**/*'));
|
|
10
|
-
const FILE_STAT_CONCURRENCY = 16;
|
|
11
11
|
const toPosix = (value) => value.replaceAll(path.sep, '/');
|
|
12
12
|
const isMissingPathError = (error) => {
|
|
13
13
|
const code = error.code;
|
|
@@ -85,13 +85,14 @@ const getWorkspaceInitMs = async (workspaceRoot) => {
|
|
|
85
85
|
return labManifestStat.birthtimeMs || labManifestStat.mtimeMs;
|
|
86
86
|
};
|
|
87
87
|
export const computeCoverage = async (workspaceRoot) => {
|
|
88
|
+
const { coverageFileStatConcurrency } = getLedgerRuntimeConfig();
|
|
88
89
|
const [{ readIndex }, candidateFiles, workspaceInitMs] = await Promise.all([
|
|
89
90
|
loadLedgerState(workspaceRoot),
|
|
90
91
|
collectCandidateFiles(workspaceRoot),
|
|
91
92
|
getWorkspaceInitMs(workspaceRoot),
|
|
92
93
|
]);
|
|
93
94
|
const coverageIndex = new Set(readIndex.coveredFiles.map((filePath) => toPosix(filePath)));
|
|
94
|
-
const candidateStats = await mapWithConcurrencyLimit(candidateFiles,
|
|
95
|
+
const candidateStats = await mapWithConcurrencyLimit(candidateFiles, coverageFileStatConcurrency, async (relativePath) => {
|
|
95
96
|
try {
|
|
96
97
|
return {
|
|
97
98
|
mtimeMs: (await stat(path.join(workspaceRoot, relativePath))).mtimeMs,
|
package/dist/doctor.d.ts
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
import { type PreparedLedgerState } from './recovery.ts';
|
|
2
|
+
export declare const DOCTOR_FINDING_CODES: readonly ["blob-corrupt", "blob-missing", "blob-unreadable", "change-log-rollback-missing-target", "change-log-smoke-failure-missing-rollback-plan", "manifest-entry-count-mismatch", "manifest-entry-location-missing", "manifest-entry-missing-on-disk", "manifest-last-sequence-mismatch", "manifest-per-phase-latest-mismatch", "manifest-phase-mismatch", "manifest-sequence-mismatch", "open-issue-stale", "phase-prev-entry-mismatch", "pre-change-checkpoint-stale", "read-failure"];
|
|
3
|
+
export type DoctorFindingCode = (typeof DOCTOR_FINDING_CODES)[number];
|
|
4
|
+
export type DoctorFindingMetadataValue = boolean | null | number | string;
|
|
5
|
+
export type DoctorFinding = {
|
|
6
|
+
readonly code: DoctorFindingCode;
|
|
7
|
+
readonly message: string;
|
|
8
|
+
readonly metadata?: Record<string, DoctorFindingMetadataValue>;
|
|
9
|
+
readonly remediation: string;
|
|
10
|
+
};
|
|
11
|
+
export type DoctorReport = {
|
|
12
|
+
readonly checkedAt: string;
|
|
13
|
+
readonly findings: DoctorFinding[];
|
|
14
|
+
readonly issueCount: number;
|
|
15
|
+
readonly issues: string[];
|
|
16
|
+
readonly ok: boolean;
|
|
17
|
+
};
|
|
2
18
|
export declare const runLedgerDoctor: (workspaceRoot: string, options?: {
|
|
3
19
|
readonly skipPrepare?: boolean;
|
|
4
20
|
readonly state?: PreparedLedgerState;
|
|
5
|
-
}) => Promise<
|
|
6
|
-
issues: string[];
|
|
7
|
-
ok: boolean;
|
|
8
|
-
}>;
|
|
21
|
+
}) => Promise<DoctorReport>;
|
|
9
22
|
//# sourceMappingURL=doctor.d.ts.map
|
package/dist/doctor.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAMA,OAAO,EAAmB,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAMA,OAAO,EAAmB,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAS1E,eAAO,MAAM,oBAAoB,8dAiBvB,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AACtE,MAAM,MAAM,0BAA0B,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1E,MAAM,MAAM,aAAa,GAAG;IACxB,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;IAC/D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;CACxB,CAAC;AAqjBF,eAAO,MAAM,eAAe,GACxB,eAAe,MAAM,EACrB,UAAS;IAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,mBAAmB,CAAA;CAAO,KACvF,OAAO,CAAC,YAAY,CAqCtB,CAAC"}
|