@jjchill/probity-rules 0.1.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.
Files changed (71) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/GLOSSARY.template.md +33 -0
  3. package/README.md +96 -0
  4. package/dist/index.d.ts +20 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +20 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/presets/js.d.ts +63 -0
  9. package/dist/presets/js.d.ts.map +1 -0
  10. package/dist/presets/js.js +112 -0
  11. package/dist/presets/js.js.map +1 -0
  12. package/dist/presets/kmp.d.ts +27 -0
  13. package/dist/presets/kmp.d.ts.map +1 -0
  14. package/dist/presets/kmp.js +253 -0
  15. package/dist/presets/kmp.js.map +1 -0
  16. package/dist/presets/kotlin.d.ts +40 -0
  17. package/dist/presets/kotlin.d.ts.map +1 -0
  18. package/dist/presets/kotlin.js +172 -0
  19. package/dist/presets/kotlin.js.map +1 -0
  20. package/dist/presets/swift.d.ts +10 -0
  21. package/dist/presets/swift.d.ts.map +1 -0
  22. package/dist/presets/swift.js +285 -0
  23. package/dist/presets/swift.js.map +1 -0
  24. package/dist/rules/acceptance-language.d.ts +95 -0
  25. package/dist/rules/acceptance-language.d.ts.map +1 -0
  26. package/dist/rules/acceptance-language.js +443 -0
  27. package/dist/rules/acceptance-language.js.map +1 -0
  28. package/dist/rules/gates.d.ts +125 -0
  29. package/dist/rules/gates.d.ts.map +1 -0
  30. package/dist/rules/gates.js +285 -0
  31. package/dist/rules/gates.js.map +1 -0
  32. package/dist/rules/kotlin.d.ts +323 -0
  33. package/dist/rules/kotlin.d.ts.map +1 -0
  34. package/dist/rules/kotlin.js +722 -0
  35. package/dist/rules/kotlin.js.map +1 -0
  36. package/dist/rules/ports-and-adapters.d.ts +86 -0
  37. package/dist/rules/ports-and-adapters.d.ts.map +1 -0
  38. package/dist/rules/ports-and-adapters.js +366 -0
  39. package/dist/rules/ports-and-adapters.js.map +1 -0
  40. package/dist/rules/scoping.d.ts +68 -0
  41. package/dist/rules/scoping.d.ts.map +1 -0
  42. package/dist/rules/scoping.js +93 -0
  43. package/dist/rules/scoping.js.map +1 -0
  44. package/dist/rules/spec-test-parity.d.ts +164 -0
  45. package/dist/rules/spec-test-parity.d.ts.map +1 -0
  46. package/dist/rules/spec-test-parity.js +456 -0
  47. package/dist/rules/spec-test-parity.js.map +1 -0
  48. package/dist/rules/swift.d.ts +50 -0
  49. package/dist/rules/swift.d.ts.map +1 -0
  50. package/dist/rules/swift.js +50 -0
  51. package/dist/rules/swift.js.map +1 -0
  52. package/dist/rules/ubiquitous-language.d.ts +36 -0
  53. package/dist/rules/ubiquitous-language.d.ts.map +1 -0
  54. package/dist/rules/ubiquitous-language.js +140 -0
  55. package/dist/rules/ubiquitous-language.js.map +1 -0
  56. package/dist/scripts/scope-report.d.ts +3 -0
  57. package/dist/scripts/scope-report.d.ts.map +1 -0
  58. package/dist/scripts/scope-report.js +184 -0
  59. package/dist/scripts/scope-report.js.map +1 -0
  60. package/kiro/README.md +20 -0
  61. package/kiro/kiro-agent.template.json +45 -0
  62. package/kiro/kiro-transcript-to-claude.py +183 -0
  63. package/kiro/probity-kiro-translate.py +132 -0
  64. package/kiro/probity-kiro.sh +87 -0
  65. package/kiro/skill-activation-forced-eval.sh +45 -0
  66. package/package.json +68 -0
  67. package/probity.config.kmp.ts +40 -0
  68. package/probity.config.kotlin.ts +37 -0
  69. package/probity.config.swift.ts +38 -0
  70. package/probity.config.ts +43 -0
  71. package/scripts/spec-parity.mjs +345 -0
@@ -0,0 +1,93 @@
1
+ import picomatch from 'picomatch';
2
+ /**
3
+ * Replica of Probity's glob-scoping internals, for the tooling in
4
+ * this template set — the workflow eval and `scripts/scope-report.ts`
5
+ * — which must resolve `{ files, rules }` blocks exactly the way the
6
+ * real engine does. Hand-mirrored scoping predicates were the eval's
7
+ * main blind spot: a template glob edit could silently diverge from
8
+ * what the eval exercised.
9
+ *
10
+ * Probity implements these in `src/rules/utils/match-paths.ts`
11
+ * (`buildMatcher`, `actionMatchesFilesScope`) and `src/config.ts`
12
+ * (`anchorGlob` inside `loadConfig`), but its package `exports` map
13
+ * (".", "./types", "./rules") does not expose them, so they are
14
+ * ported here verbatim — same picomatch options, same anchoring
15
+ * convention. Pinned against @nizos/probity 1.10.0: on a Probity
16
+ * upgrade, diff this file against those two sources; if upstream
17
+ * starts exporting them, delete this file and import instead.
18
+ *
19
+ * picomatch is Probity's own matcher dependency, so the same version
20
+ * resolves here in any project with @nizos/probity installed; if your
21
+ * package manager doesn't hoist it, add it: `npm install -D picomatch`.
22
+ */
23
+ /** A `Config.rules` entry that carries a `files` scope. */
24
+ export function isRuleBlock(entry) {
25
+ return typeof entry !== 'function';
26
+ }
27
+ /**
28
+ * Builds a path matcher from include/exclude patterns. Patterns
29
+ * prefixed with `!` are negations (picomatch's `ignore` option);
30
+ * everything else is an include. An all-negations list gets `**` as
31
+ * the default include. `dot: true` so `*`/`**` traverse dot-prefixed
32
+ * segments — without it a scoped rule silently skips dotfiles.
33
+ *
34
+ * Port of @nizos/probity `src/rules/utils/match-paths.ts#buildMatcher`.
35
+ */
36
+ export function buildMatcher(patterns) {
37
+ if (patterns.length === 0)
38
+ return () => false;
39
+ const includes = patterns.filter((p) => !p.startsWith('!'));
40
+ const ignore = patterns
41
+ .filter((p) => p.startsWith('!'))
42
+ .map((p) => p.slice(1));
43
+ const matcher = picomatch(includes.length ? [...includes] : '**', {
44
+ dot: true,
45
+ ignore,
46
+ });
47
+ return (path) => matcher(path);
48
+ }
49
+ /**
50
+ * Whether a `{ files, rules }` block applies to an action. Empty
51
+ * `files` matches nothing; non-write actions (commands) pass the
52
+ * block-level filter and rules self-filter by action kind; write
53
+ * actions are matched against `files`.
54
+ *
55
+ * Port of @nizos/probity
56
+ * `src/rules/utils/match-paths.ts#actionMatchesFilesScope`.
57
+ */
58
+ export function actionMatchesFilesScope(files, action) {
59
+ if (files.length === 0)
60
+ return false;
61
+ if (action.kind !== 'write')
62
+ return true;
63
+ return buildMatcher(files)(action.path);
64
+ }
65
+ /**
66
+ * `**`-prefixed globs are intentional "match anywhere" patterns;
67
+ * anchoring them at the config dir would defeat the user's intent.
68
+ * Negations carry the same convention through the `!` prefix.
69
+ *
70
+ * Port of @nizos/probity `src/config.ts#anchorGlob`.
71
+ */
72
+ export function anchorGlob(glob, root) {
73
+ if (glob.startsWith('!'))
74
+ return '!' + anchorGlob(glob.slice(1), root);
75
+ if (glob.startsWith('**'))
76
+ return glob;
77
+ return `${root.replace(/\\/g, '/').replace(/\/$/, '')}/${glob}`;
78
+ }
79
+ /**
80
+ * Anchors every block's relative globs against `root`, the way
81
+ * Probity's `loadConfig` anchors them against the config file's
82
+ * directory — so paths in `Action.path` (absolute POSIX) match
83
+ * regardless of where the session is rooted. Flat rules pass through.
84
+ */
85
+ export function anchorEntries(entries, root) {
86
+ return entries.map((entry) => {
87
+ if (!isRuleBlock(entry) || !entry.files)
88
+ return entry;
89
+ const [first, ...rest] = entry.files.map((glob) => anchorGlob(glob, root));
90
+ return { ...entry, files: [first, ...rest] };
91
+ });
92
+ }
93
+ //# sourceMappingURL=scoping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoping.js","sourceRoot":"","sources":["../../rules/scoping.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,WAAW,CAAA;AAIjC;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,2DAA2D;AAC3D,MAAM,UAAU,WAAW,CAAC,KAAgB;IAC1C,OAAO,OAAO,KAAK,KAAK,UAAU,CAAA;AACpC,CAAC;AAWD;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAC1B,QAA2B;IAE3B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,EAAE,CAAC,KAAK,CAAA;IAC7C,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAA;IAC3D,MAAM,MAAM,GAAG,QAAQ;SACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;SAChC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IACzB,MAAM,OAAO,GAAG,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;QAChE,GAAG,EAAE,IAAI;QACT,MAAM;KACP,CAAC,CAAA;IACF,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;AAChC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAwB,EACxB,MAAc;IAEd,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACpC,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,IAAI,CAAA;IACxC,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;AACzC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,IAAY;IACnD,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;IACtE,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IACtC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE,CAAA;AACjE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAC3B,OAA6B,EAC7B,IAAY;IAEZ,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAC3B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK;YAAE,OAAO,KAAK,CAAA;QACrD,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;QAC1E,OAAO,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,CAAC,KAAM,EAAE,GAAG,IAAI,CAAU,EAAE,CAAA;IACxD,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,164 @@
1
+ import type { Rule } from '@nizos/probity';
2
+ type Scenario = {
3
+ key: string;
4
+ specFile: string;
5
+ title: string;
6
+ wip: boolean;
7
+ /** Driver scopes the heading declares, e.g. `[system]` → ['system']. */
8
+ scopes: string[];
9
+ };
10
+ type CoversRef = {
11
+ key: string;
12
+ testFile: string;
13
+ specFile: string;
14
+ title: string;
15
+ };
16
+ export declare function extractScenarios(specFile: string, content: string): Scenario[];
17
+ export declare function extractCoversRefs(testFile: string, content: string): CoversRef[];
18
+ /**
19
+ * A named driver scope: which test files count as coverage from a
20
+ * given driver suite. Scope names are the vocabulary scenario
21
+ * headings may use in `[scope, ...]` tags — lowercase by convention
22
+ * (tags are lowercased before matching).
23
+ */
24
+ export type DriverScope = {
25
+ name: string;
26
+ filePattern: RegExp;
27
+ };
28
+ type ScanOptions = {
29
+ specsDir: string;
30
+ testRoots: string[];
31
+ testFilePattern?: RegExp;
32
+ /**
33
+ * Per-scenario driver mapping (optional). Each entry names a driver
34
+ * suite and the test files that belong to it (e.g.
35
+ * `{ name: 'system', filePattern: /AcceptanceTests[/\\]UITests[/\\]/ }`).
36
+ * A scenario tagged `## Scenario [system]:` must then be covered by
37
+ * at least one test matching that scope's pattern — **in addition
38
+ * to** the base requirement that some acceptance test covers it.
39
+ * Tags are floors, never ceilings: extra coverage in other scopes
40
+ * is always fine, and untagged scenarios only need `defaultScopes`
41
+ * (below) plus the base requirement. A tag naming a scope absent
42
+ * from this list is a violation (misspelling protection); with no
43
+ * `driverScopes` configured, any tag is unknown, so adopting tags
44
+ * requires configuring scopes first.
45
+ */
46
+ driverScopes?: DriverScope[];
47
+ /**
48
+ * Scope names every non-wip, non-baselined scenario must satisfy
49
+ * even without a tag — the project's standard driver set (e.g.
50
+ * `['view-model']`). Names must exist in `driverScopes`. Omit for
51
+ * the status-quo default: untagged scenarios need any one covering
52
+ * test, regardless of driver.
53
+ */
54
+ defaultScopes?: string[];
55
+ /**
56
+ * Incremental-adoption baseline (optional). Path to a text file of
57
+ * scenario keys — one `<spec>.feature.md :: <title>` per line, `#`
58
+ * comments allowed — that are exempt from the orphan check. Use it
59
+ * to adopt the parity gate on a brownfield spec suite: generate the
60
+ * baseline once (`spec-parity.mjs --baseline <path> --write-baseline`),
61
+ * commit it, and from then on only scenarios *not* in the baseline
62
+ * must carry a covering test — new specs are enforced from day one
63
+ * while the backlog burns down by deleting lines. A missing file
64
+ * means full enforcement (the greenfield default). Dangling Covers
65
+ * tags are never baselined: they are actively wrong, not legacy.
66
+ */
67
+ baselinePath?: string;
68
+ };
69
+ /** Parses a baseline file into normalized scenario keys. Missing file → empty set. */
70
+ export declare function readBaseline(path: string | undefined): Set<string>;
71
+ /** All spec files (either extension) under a directory. */
72
+ export declare function findSpecFiles(specsDir: string): string[];
73
+ export declare function scanSpecs(specsDir: string): Scenario[];
74
+ export declare function scanCoversRefs(testRoots: string[], testFilePattern: RegExp): CoversRef[];
75
+ /**
76
+ * Bidirectional parity gate on `git commit`: blocks when any
77
+ * non-wip `## Scenario:` heading in `specsDir` has no acceptance
78
+ * test claiming it via a `Covers:` tag, or when any `Covers:` tag
79
+ * points at a scenario that no longer exists (spec renamed or
80
+ * removed). Deterministic filesystem scan — no AI call; milliseconds
81
+ * at typical spec-suite scale.
82
+ *
83
+ * The test claiming a scenario may still be red or quarantined —
84
+ * parity requires the *link*, not a passing run; keeping in-progress
85
+ * specs out of the pipeline is the pipeline's job. Alternatively
86
+ * mark the scenario `## Scenario (wip):` to exempt it entirely.
87
+ *
88
+ * Applies to: command actions matching `git commit`.
89
+ *
90
+ * @param options.specsDir — absolute path to the specs directory
91
+ * (e.g. `<root>/docs/specs`). A missing directory passes: no
92
+ * specs, nothing to enforce.
93
+ * @param options.testRoots — absolute paths to scan for acceptance
94
+ * tests (the repo root is fine; node_modules/build dirs are
95
+ * skipped).
96
+ * @param options.testFilePattern — which files count as acceptance
97
+ * tests (default: any file under an `acceptance/` directory).
98
+ * @param options.baselinePath — optional incremental-adoption
99
+ * baseline; scenarios listed there are exempt from the orphan
100
+ * check (see {@link readBaseline}). Missing file → full enforcement.
101
+ * @param options.driverScopes — optional per-scenario driver mapping;
102
+ * see {@link DriverScope}. Scenarios tagged `[scope]` (and every
103
+ * scenario, for `defaultScopes` entries) must be covered by a test
104
+ * matching that scope's `filePattern`, on top of the base check.
105
+ * @param options.defaultScopes — scope names required of untagged
106
+ * scenarios too (the project's standard driver set).
107
+ */
108
+ export declare function enforceSpecTestParity(options: ScanOptions): Rule;
109
+ /**
110
+ * Spec-first, made mechanical: a write that adds a new acceptance
111
+ * test case is blocked unless it also adds a `Covers:` tag pointing
112
+ * at a `## Scenario:` heading that ALREADY EXISTS in `specsDir`. The
113
+ * executable specification (`*.feature.md`) must be written before
114
+ * the test that claims it — an agent that codes the test first gets
115
+ * told exactly what to create and where.
116
+ *
117
+ * This is the write-time front half of the traceability story;
118
+ * {@link enforceSpecTestParity} is the commit-time back half (every
119
+ * scenario covered, every tag resolving). Together they close the
120
+ * gap where an agent authors a whole acceptance suite with no
121
+ * feature file and nothing objects until commit — or ever, if the
122
+ * tests carry no tags at all.
123
+ *
124
+ * Delta-based and deterministic (no AI call): only NEW test cases
125
+ * demand a NEW resolving tag, so edits inside an existing brownfield
126
+ * test file pass untouched, and a pre-existing dangling tag can't
127
+ * block unrelated work (the commit gate owns that). `(wip)` and
128
+ * `(planned)` scenarios count as existing — they are exactly the
129
+ * headings outside-in work drives against.
130
+ *
131
+ * Applies to: write actions — scope it via a `{ files, rules }`
132
+ * block to the acceptance test-case layer only (e.g.
133
+ * `**\/acceptance/**\/*Spec.kt`), never to drivers/DSL/infrastructure.
134
+ *
135
+ * @param options.specsDir — absolute path to the specs directory.
136
+ * Missing directory ⇒ every new tag is unresolved ⇒ the deny
137
+ * message says to create the first feature file (greenfield
138
+ * enforcement, not a free pass).
139
+ * @param options.testDeclarationPattern — what counts as a test-case
140
+ * declaration (default: Kotlin/Java `@Test` or Swift `func test…`).
141
+ */
142
+ export declare function requireSpecBackedAcceptanceTest(options: {
143
+ specsDir: string;
144
+ testDeclarationPattern?: RegExp;
145
+ }): Rule;
146
+ /**
147
+ * Surfaces link breakage at the moment it is created: when a write
148
+ * to a `*.feature.md` file removes or renames a `## Scenario:`
149
+ * heading that acceptance tests still claim, the write is blocked
150
+ * with the list of affected tests — update their `Covers:` tags (or
151
+ * delete the tests) in the same change, then re-apply the spec edit.
152
+ * Removing a scenario nothing covers passes silently.
153
+ *
154
+ * Applies to: write actions to `*.feature.md` files (scope via a
155
+ * `{ files, rules }` block). Deterministic — no AI call.
156
+ *
157
+ * @param options.testRoots — absolute paths to scan for acceptance
158
+ * tests.
159
+ * @param options.testFilePattern — which files count as acceptance
160
+ * tests (default: any file under an `acceptance/` directory).
161
+ */
162
+ export declare function surfaceScenarioLinkBreakage(options: Omit<ScanOptions, 'specsDir'>): Rule;
163
+ export {};
164
+ //# sourceMappingURL=spec-test-parity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-test-parity.d.ts","sourceRoot":"","sources":["../../rules/spec-test-parity.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAU,IAAI,EAA2B,MAAM,gBAAgB,CAAA;AAuE3E,KAAK,QAAQ,GAAG;IACd,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,OAAO,CAAA;IACZ,wEAAwE;IACxE,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB,CAAA;AACD,KAAK,SAAS,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAUnF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,EAAE,CA6C9E;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,CAahF;AAqBD;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/D,KAAK,WAAW,GAAG;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,WAAW,EAAE,CAAA;IAC5B;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,sFAAsF;AACtF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,CAelE;AAED,2DAA2D;AAC3D,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAIxD;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,EAAE,CAItD;AAED,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EAAE,EACnB,eAAe,EAAE,MAAM,GACtB,SAAS,EAAE,CAUb;AAQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAyGhE;AAcD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE;IACvD,QAAQ,EAAE,MAAM,CAAA;IAChB,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAChC,GAAG,IAAI,CAqDP;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,GACrC,IAAI,CAyCN"}