@spec-box/sdd 0.6.4
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/README.md +81 -0
- package/assets/adapters/openspec/instructions.md +47 -0
- package/assets/adapters/spec-box/instructions.md +44 -0
- package/assets/ci/Dockerfile +9 -0
- package/assets/ci/github-sbox-run.yml +85 -0
- package/assets/ci/github-tests.yml +25 -0
- package/assets/project/architecture.md +29 -0
- package/assets/project/contracts.md +29 -0
- package/assets/project/conventions.md +29 -0
- package/assets/project/decisions.README.md +3 -0
- package/assets/project/glossary.md +13 -0
- package/assets/project/overview.md +29 -0
- package/assets/project/testing.md +34 -0
- package/assets/project/workflow.md +29 -0
- package/assets/prompts/fill-project-docs.md +43 -0
- package/assets/roles/challenger.md +33 -0
- package/assets/roles/distiller.md +18 -0
- package/assets/roles/implementer.md +39 -0
- package/assets/roles/planner.md +58 -0
- package/assets/roles/researcher.md +47 -0
- package/assets/roles/reviewer.md +68 -0
- package/assets/roles/tester.md +36 -0
- package/assets/roles/verifier.md +57 -0
- package/assets/schema/default.yaml +121 -0
- package/assets/schema/sbox-answer.schema.json +42 -0
- package/assets/templates/coverage.yaml +12 -0
- package/assets/templates/design.md +48 -0
- package/assets/templates/proposal.md +27 -0
- package/assets/templates/tasks.md +9 -0
- package/assets/templates/test-plan.md +7 -0
- package/bin/sbox.js +5 -0
- package/dist/adapters/host/claude/index.js +112 -0
- package/dist/adapters/host/claude/index.js.map +1 -0
- package/dist/adapters/repo/git.js +81 -0
- package/dist/adapters/repo/git.js.map +1 -0
- package/dist/adapters/repo/github/index.js +136 -0
- package/dist/adapters/repo/github/index.js.map +1 -0
- package/dist/adapters/repo/index.js +4 -0
- package/dist/adapters/repo/index.js.map +1 -0
- package/dist/adapters/repo/local.js +47 -0
- package/dist/adapters/repo/local.js.map +1 -0
- package/dist/adapters/runner/claude.js +129 -0
- package/dist/adapters/runner/claude.js.map +1 -0
- package/dist/adapters/runner/codex.js +151 -0
- package/dist/adapters/runner/codex.js.map +1 -0
- package/dist/adapters/runner/index.js +4 -0
- package/dist/adapters/runner/index.js.map +1 -0
- package/dist/adapters/spec/index.js +4 -0
- package/dist/adapters/spec/index.js.map +1 -0
- package/dist/adapters/spec/openspec/delta.js +268 -0
- package/dist/adapters/spec/openspec/delta.js.map +1 -0
- package/dist/adapters/spec/openspec/index.js +107 -0
- package/dist/adapters/spec/openspec/index.js.map +1 -0
- package/dist/adapters/spec/openspec/parser.js +188 -0
- package/dist/adapters/spec/openspec/parser.js.map +1 -0
- package/dist/adapters/spec/spec-box/delta.js +198 -0
- package/dist/adapters/spec/spec-box/delta.js.map +1 -0
- package/dist/adapters/spec/spec-box/index.js +112 -0
- package/dist/adapters/spec/spec-box/index.js.map +1 -0
- package/dist/adapters/spec/spec-box/yaml.js +74 -0
- package/dist/adapters/spec/spec-box/yaml.js.map +1 -0
- package/dist/cli/commands/artifacts.js +86 -0
- package/dist/cli/commands/artifacts.js.map +1 -0
- package/dist/cli/commands/change.js +111 -0
- package/dist/cli/commands/change.js.map +1 -0
- package/dist/cli/commands/changeset.js +81 -0
- package/dist/cli/commands/changeset.js.map +1 -0
- package/dist/cli/commands/ci.js +45 -0
- package/dist/cli/commands/ci.js.map +1 -0
- package/dist/cli/commands/coverage.js +45 -0
- package/dist/cli/commands/coverage.js.map +1 -0
- package/dist/cli/commands/deliver.js +71 -0
- package/dist/cli/commands/deliver.js.map +1 -0
- package/dist/cli/commands/doctor.js +55 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/host.js +30 -0
- package/dist/cli/commands/host.js.map +1 -0
- package/dist/cli/commands/init.js +150 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/metrics.js +62 -0
- package/dist/cli/commands/metrics.js.map +1 -0
- package/dist/cli/commands/prompt.js +68 -0
- package/dist/cli/commands/prompt.js.map +1 -0
- package/dist/cli/commands/protocol.js +151 -0
- package/dist/cli/commands/protocol.js.map +1 -0
- package/dist/cli/commands/run.js +157 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/spec.js +84 -0
- package/dist/cli/commands/spec.js.map +1 -0
- package/dist/cli/commands/wiring.js +50 -0
- package/dist/cli/commands/wiring.js.map +1 -0
- package/dist/cli/context.js +18 -0
- package/dist/cli/context.js.map +1 -0
- package/dist/cli/main.js +63 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/output.js +31 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/core/archive.js +77 -0
- package/dist/core/archive.js.map +1 -0
- package/dist/core/change.js +240 -0
- package/dist/core/change.js.map +1 -0
- package/dist/core/changeset.js +98 -0
- package/dist/core/changeset.js.map +1 -0
- package/dist/core/config.js +144 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/coverage.js +69 -0
- package/dist/core/coverage.js.map +1 -0
- package/dist/core/deliver.js +190 -0
- package/dist/core/deliver.js.map +1 -0
- package/dist/core/diagnostics.js +12 -0
- package/dist/core/diagnostics.js.map +1 -0
- package/dist/core/drift.js +44 -0
- package/dist/core/drift.js.map +1 -0
- package/dist/core/errors.js +12 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/gates.js +76 -0
- package/dist/core/gates.js.map +1 -0
- package/dist/core/lock.js +57 -0
- package/dist/core/lock.js.map +1 -0
- package/dist/core/metrics.js +140 -0
- package/dist/core/metrics.js.map +1 -0
- package/dist/core/packet.js +172 -0
- package/dist/core/packet.js.map +1 -0
- package/dist/core/paths.js +63 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/phases.js +203 -0
- package/dist/core/phases.js.map +1 -0
- package/dist/core/pr-body.js +64 -0
- package/dist/core/pr-body.js.map +1 -0
- package/dist/core/project-docs.js +246 -0
- package/dist/core/project-docs.js.map +1 -0
- package/dist/core/protect.js +47 -0
- package/dist/core/protect.js.map +1 -0
- package/dist/core/repo-host.js +11 -0
- package/dist/core/repo-host.js.map +1 -0
- package/dist/core/report.js +286 -0
- package/dist/core/report.js.map +1 -0
- package/dist/core/result.js +90 -0
- package/dist/core/result.js.map +1 -0
- package/dist/core/roles.js +18 -0
- package/dist/core/roles.js.map +1 -0
- package/dist/core/run.js +222 -0
- package/dist/core/run.js.map +1 -0
- package/dist/core/runner.js +40 -0
- package/dist/core/runner.js.map +1 -0
- package/dist/core/schema.js +104 -0
- package/dist/core/schema.js.map +1 -0
- package/dist/core/spec-adapter.js +12 -0
- package/dist/core/spec-adapter.js.map +1 -0
- package/dist/core/spec-model.js +8 -0
- package/dist/core/spec-model.js.map +1 -0
- package/dist/core/tasks.js +15 -0
- package/dist/core/tasks.js.map +1 -0
- package/dist/core/test-reports.js +60 -0
- package/dist/core/test-reports.js.map +1 -0
- package/dist/core/wiki.js +86 -0
- package/dist/core/wiki.js.map +1 -0
- package/dist/core/wiring.js +65 -0
- package/dist/core/wiring.js.map +1 -0
- package/docs/design.md +829 -0
- package/package.json +66 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { SboxError } from './errors.js';
|
|
4
|
+
/** Jest и Vitest (`--reporter=json`): testResults[].assertionResults[] с ancestorTitles и title. */
|
|
5
|
+
export const jestReport = {
|
|
6
|
+
name: 'jest',
|
|
7
|
+
read(file) {
|
|
8
|
+
const raw = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
9
|
+
const out = [];
|
|
10
|
+
for (const suite of raw.testResults ?? []) {
|
|
11
|
+
for (const a of suite.assertionResults ?? []) {
|
|
12
|
+
const titles = [...(a.ancestorTitles ?? []), a.title];
|
|
13
|
+
out.push({ fullName: a.fullName ?? titles.join(' '), titles, status: normalize(a.status), file: suite.name });
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return out;
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
/** Playwright JSON reporter: suites[] с вложенными suites и specs[].tests[].results[]. */
|
|
20
|
+
export const playwrightReport = {
|
|
21
|
+
name: 'playwright',
|
|
22
|
+
read(file) {
|
|
23
|
+
const raw = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
24
|
+
const out = [];
|
|
25
|
+
const walk = (suite, ancestors) => {
|
|
26
|
+
const here = suite.title && !/\.(spec|test)\.[jt]sx?$/.test(suite.title) ? [...ancestors, suite.title] : ancestors;
|
|
27
|
+
for (const spec of suite.specs ?? []) {
|
|
28
|
+
const titles = [...here, spec.title];
|
|
29
|
+
const results = spec.tests?.flatMap((t) => t.results ?? []) ?? [];
|
|
30
|
+
const statuses = results.map((r) => r.status);
|
|
31
|
+
const status = statuses.includes('failed') || statuses.includes('timedOut') ? 'failed' : statuses.includes('passed') ? 'passed' : statuses.includes('skipped') ? 'skipped' : 'pending';
|
|
32
|
+
out.push({ fullName: titles.join(' › '), titles, status, file: spec.file });
|
|
33
|
+
}
|
|
34
|
+
for (const child of suite.suites ?? [])
|
|
35
|
+
walk(child, here);
|
|
36
|
+
};
|
|
37
|
+
for (const s of raw.suites ?? [])
|
|
38
|
+
walk(s, []);
|
|
39
|
+
return out;
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
function normalize(status) {
|
|
43
|
+
if (status === 'passed')
|
|
44
|
+
return 'passed';
|
|
45
|
+
if (status === 'failed')
|
|
46
|
+
return 'failed';
|
|
47
|
+
if (status === 'skipped' || status === 'todo' || status === 'disabled')
|
|
48
|
+
return 'skipped';
|
|
49
|
+
return 'pending';
|
|
50
|
+
}
|
|
51
|
+
const ADAPTERS = { jest: jestReport, vitest: jestReport, playwright: playwrightReport };
|
|
52
|
+
export function readTestReport(kind, file) {
|
|
53
|
+
const adapter = ADAPTERS[kind];
|
|
54
|
+
if (!adapter)
|
|
55
|
+
throw new SboxError('REPORT_KIND', `Неизвестный формат отчёта ${kind}; доступны: ${Object.keys(ADAPTERS).join(', ')}`);
|
|
56
|
+
if (!fs.existsSync(file))
|
|
57
|
+
throw new SboxError('REPORT_MISSING', `Нет файла отчёта ${path.resolve(file)}`);
|
|
58
|
+
return adapter.read(file);
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=test-reports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-reports.js","sourceRoot":"","sources":["../../src/core/test-reports.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import fg from 'fast-glob';
|
|
4
|
+
import { diag } from './diagnostics.js';
|
|
5
|
+
import { parseDoc } from './project-docs.js';
|
|
6
|
+
import { exists, readText, toPosix } from './paths.js';
|
|
7
|
+
export function wikiDir(root, config) {
|
|
8
|
+
return path.join(root, config.project.wiki);
|
|
9
|
+
}
|
|
10
|
+
function asList(value) {
|
|
11
|
+
if (Array.isArray(value))
|
|
12
|
+
return value.map(String);
|
|
13
|
+
if (typeof value === 'string' && value.trim())
|
|
14
|
+
return [value];
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
export function loadWiki(root, config) {
|
|
18
|
+
const dir = wikiDir(root, config);
|
|
19
|
+
if (!exists(dir))
|
|
20
|
+
return [];
|
|
21
|
+
return fg
|
|
22
|
+
.sync('**/*.md', { cwd: dir, onlyFiles: true, absolute: true })
|
|
23
|
+
.filter((f) => path.basename(f).toLowerCase() !== 'readme.md')
|
|
24
|
+
.sort()
|
|
25
|
+
.map((f) => {
|
|
26
|
+
const doc = parseDoc(readText(f));
|
|
27
|
+
const fm = doc.frontmatter;
|
|
28
|
+
return {
|
|
29
|
+
file: toPosix(path.relative(root, f)),
|
|
30
|
+
id: String(fm.id ?? path.basename(f, '.md')),
|
|
31
|
+
summary: String(fm.summary ?? ''),
|
|
32
|
+
read_when: asList(fm.read_when),
|
|
33
|
+
source_roots: asList(fm.source_roots),
|
|
34
|
+
areas: asList(fm.areas),
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/** Страницы, чьи source_roots пересекаются с путями задачи; без путей возвращаются все. */
|
|
39
|
+
export function relevantWiki(pages, paths) {
|
|
40
|
+
if (paths.length === 0)
|
|
41
|
+
return pages;
|
|
42
|
+
const hit = pages.filter((p) => p.source_roots.some((r) => paths.some((x) => x.startsWith(r) || r.startsWith(x))));
|
|
43
|
+
return hit.length > 0 ? hit : pages;
|
|
44
|
+
}
|
|
45
|
+
export function doctorWiki(root, config) {
|
|
46
|
+
const out = [];
|
|
47
|
+
for (const page of loadWiki(root, config)) {
|
|
48
|
+
if (!page.summary)
|
|
49
|
+
out.push(diag('warning', 'WIKI_SUMMARY', 'У страницы нет summary во фронтматтере', page.file));
|
|
50
|
+
if (page.read_when.length === 0)
|
|
51
|
+
out.push(diag('warning', 'WIKI_READ_WHEN', 'У страницы нет read_when: роли не поймут, когда её читать', page.file));
|
|
52
|
+
for (const r of page.source_roots) {
|
|
53
|
+
if (!fs.existsSync(path.join(root, r)))
|
|
54
|
+
out.push(diag('warning', 'WIKI_SOURCE_ROOT', `source_roots указывает на несуществующий путь ${r}`, page.file));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
export const WIKI_README = `# Wiki проекта для ролей @spec-box/sdd
|
|
60
|
+
|
|
61
|
+
Здесь лежат локальные знания об областях кода, которым не место в общей документации \`.sbox/project/\`:
|
|
62
|
+
как устроен конкретный модуль, какой образец повторять при добавлении похожей функциональности,
|
|
63
|
+
подводные камни области. Одна страница на область или тему. Файл README.md страницей не считается.
|
|
64
|
+
|
|
65
|
+
Каждая страница начинается с фронтматтера:
|
|
66
|
+
|
|
67
|
+
\`\`\`yaml
|
|
68
|
+
---
|
|
69
|
+
id: wiki.exports # уникальный идентификатор
|
|
70
|
+
summary: Как устроены модули экспорта и какой образец повторять
|
|
71
|
+
read_when: # когда роль обязана прочитать страницу
|
|
72
|
+
- Добавляется или меняется экспорт данных
|
|
73
|
+
- Создаётся новый модуль в src/features
|
|
74
|
+
source_roots: # пути области; по ним страница попадает в пакет роли
|
|
75
|
+
- src/features/export
|
|
76
|
+
areas: [client]
|
|
77
|
+
updated: 2026-09-16
|
|
78
|
+
verification: needs-review # verified после проверки человеком
|
|
79
|
+
---
|
|
80
|
+
\`\`\`
|
|
81
|
+
|
|
82
|
+
Тело: факты с путями, образец для единообразия («новый модуль повторяет структуру \`src/features/export\`: …»),
|
|
83
|
+
подводные камни, что нельзя делать. Индекс всех страниц (summary и read_when) попадает в пакет каждой роли;
|
|
84
|
+
саму страницу роль читает, если read_when подходит к задаче.
|
|
85
|
+
`;
|
|
86
|
+
//# sourceMappingURL=wiki.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wiki.js","sourceRoot":"","sources":["../../src/core/wiki.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import fg from 'fast-glob';
|
|
5
|
+
import { exists, readText, toPosix } from './paths.js';
|
|
6
|
+
const SKIP_DIRS = ['node_modules', '.git', '.sbox', 'openspec', 'dist', 'bin', 'obj', 'coverage', 'build'];
|
|
7
|
+
function filesMentioning(root, needle) {
|
|
8
|
+
try {
|
|
9
|
+
const out = execFileSync('git', ['grep', '-l', '-I', '-F', '--untracked', '--', needle], { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
10
|
+
return out.split('\n').map((l) => l.trim()).filter(Boolean);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
const files = fg.sync(['**/*'], { cwd: root, onlyFiles: true, dot: false, ignore: SKIP_DIRS.map((d) => `**/${d}/**`) });
|
|
14
|
+
return files.filter((f) => {
|
|
15
|
+
try {
|
|
16
|
+
return fs.readFileSync(path.join(root, f), 'utf8').includes(needle);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function isUnderModuleDir(file, moduleId) {
|
|
25
|
+
const segs = toPosix(file).split('/');
|
|
26
|
+
return segs.slice(0, -1).some((s) => s === moduleId || s.endsWith(moduleId));
|
|
27
|
+
}
|
|
28
|
+
export function wiringGaps(root, analog, fresh, exceptions = []) {
|
|
29
|
+
const mentioning = filesMentioning(root, analog).filter((f) => !isUnderModuleDir(f, analog) && !isUnderModuleDir(f, fresh) && !SKIP_DIRS.some((d) => toPosix(f).split('/').includes(d)));
|
|
30
|
+
const registrationFiles = mentioning.filter((f) => !/\.(md|txt|lock)$/i.test(f) || /README/i.test(f) === false).filter((f) => !/\.md$/i.test(f));
|
|
31
|
+
const gaps = [];
|
|
32
|
+
for (const f of registrationFiles) {
|
|
33
|
+
const abs = path.join(root, f);
|
|
34
|
+
if (!exists(abs))
|
|
35
|
+
continue;
|
|
36
|
+
const text = readText(abs);
|
|
37
|
+
if (text.includes(fresh))
|
|
38
|
+
continue;
|
|
39
|
+
if (exceptions.some((e) => toPosix(f) === e || toPosix(f).endsWith(`/${e}`)))
|
|
40
|
+
continue;
|
|
41
|
+
gaps.push({ file: toPosix(f), analogMentions: text.split(analog).length - 1 });
|
|
42
|
+
}
|
|
43
|
+
return { analog, fresh, registrationFiles: registrationFiles.map(toPosix), gaps, exceptions };
|
|
44
|
+
}
|
|
45
|
+
/** Образец и новый модуль из раздела «Единообразие» design.md: строки `- Образец: \`X\`` и `- Новый модуль: \`Y\``. */
|
|
46
|
+
export function parseAnalogFromDesign(designText) {
|
|
47
|
+
const analog = designText.match(/^[-*]?\s*Образец\s*[:—-]\s*`([^`]+)`/im)?.[1]?.trim();
|
|
48
|
+
const fresh = designText.match(/^[-*]?\s*Новый модуль\s*[:—-]\s*`([^`]+)`/im)?.[1]?.trim();
|
|
49
|
+
if (!analog || !fresh)
|
|
50
|
+
return null;
|
|
51
|
+
const exc = designText.match(/^[-*]?\s*Исключения подключения\s*[:—-]\s*(.+)$/im)?.[1] ?? '';
|
|
52
|
+
const exceptions = [...exc.matchAll(/`([^`]+)`/g)].map((m) => m[1].trim());
|
|
53
|
+
return { analog, fresh, exceptions };
|
|
54
|
+
}
|
|
55
|
+
/** Результат проверки для изменения по строкам «Образец» и «Новый модуль» из design.md; null, если образец не объявлен. */
|
|
56
|
+
export function wiringForChange(root, changeDir) {
|
|
57
|
+
const designFile = path.join(changeDir, 'design.md');
|
|
58
|
+
if (!exists(designFile))
|
|
59
|
+
return null;
|
|
60
|
+
const parsed = parseAnalogFromDesign(readText(designFile));
|
|
61
|
+
if (!parsed)
|
|
62
|
+
return null;
|
|
63
|
+
return wiringGaps(root, parsed.analog, parsed.fresh, parsed.exceptions);
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=wiring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wiring.js","sourceRoot":"","sources":["../../src/core/wiring.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,WAAW,CAAC;AAC3B,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAoBvD,MAAM,SAAS,GAAG,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;AAE3G,SAAS,eAAe,CAAC,IAAY,EAAE,MAAc;IACnD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC/J,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACxH,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;YACxB,IAAI,CAAC;gBACH,OAAO,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACtE,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY,EAAE,QAAgB;IACtD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACtC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,MAAc,EAAE,KAAa,EAAE,UAAU,GAAa,EAAE;IAC/F,MAAM,UAAU,GAAG,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,gBAAgB,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzL,MAAM,iBAAiB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACjJ,MAAM,IAAI,GAAgB,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;YAAE,SAAS;QAC3B,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,SAAS;QACnC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAAE,SAAS;QACvF,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AAChG,CAAC;AAED,uHAAuH;AACvH,MAAM,UAAU,qBAAqB,CAAC,UAAkB;IACtD,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,wCAAwC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IACvF,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,6CAA6C,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IAC3F,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,mDAAmD,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7F,MAAM,UAAU,GAAG,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5E,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;AACvC,CAAC;AAED,2HAA2H;AAC3H,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,SAAiB;IAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IACrD,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,MAAM,GAAG,qBAAqB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;IAC3D,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,OAAO,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;AAC1E,CAAC"}
|