@telorun/ide-support 0.4.1 → 0.4.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 +3 -3
- package/dist/completions/build.d.ts.map +1 -1
- package/dist/completions/build.js +141 -12
- package/dist/completions/detect-context.d.ts +71 -15
- package/dist/completions/detect-context.d.ts.map +1 -1
- package/dist/completions/detect-context.js +249 -43
- package/dist/completions/prop-keys.d.ts.map +1 -1
- package/dist/completions/prop-keys.js +33 -5
- package/dist/diagnostics/range-resolver.d.ts +9 -3
- package/dist/diagnostics/range-resolver.d.ts.map +1 -1
- package/dist/diagnostics/range-resolver.js +39 -6
- package/package.json +7 -4
- package/src/completions/build.ts +166 -12
- package/src/completions/detect-context.ts +283 -43
- package/src/completions/prop-keys.ts +43 -7
- package/src/diagnostics/range-resolver.ts +36 -5
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="
|
|
2
|
+
<img src="https://raw.githubusercontent.com/telorun/telo/main/assets/telo.png" alt="Telo" width="200" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<h1 align="center">Telo</h1>
|
|
@@ -61,12 +61,12 @@ targets:
|
|
|
61
61
|
kind: Telo.Import
|
|
62
62
|
metadata:
|
|
63
63
|
name: Http
|
|
64
|
-
source:
|
|
64
|
+
source: std/http-server@0.4.0
|
|
65
65
|
---
|
|
66
66
|
kind: Telo.Import
|
|
67
67
|
metadata:
|
|
68
68
|
name: Sql
|
|
69
|
-
source:
|
|
69
|
+
source: std/sql@0.2.3
|
|
70
70
|
---
|
|
71
71
|
# SQLite database — swap driver/host/database for PostgreSQL with zero YAML changes
|
|
72
72
|
kind: Sql.Connection
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/completions/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/completions/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAsK3E,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,gBAAgB,GAAG,SAAS,EACtC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA2B7B"}
|
|
@@ -1,16 +1,137 @@
|
|
|
1
|
-
import { detectContext } from "./detect-context.js";
|
|
1
|
+
import { detectContext, lookupRefConstraint } from "./detect-context.js";
|
|
2
2
|
import { importSourceCompletions } from "./import-source.js";
|
|
3
3
|
import { propKeyCompletions } from "./prop-keys.js";
|
|
4
4
|
import { CAPABILITY_VALUES } from "./valid-capabilities.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
/** Roughly extract `(kind, metadata.name)` pairs from a multi-doc YAML text.
|
|
6
|
+
* This is intentionally lightweight: it scans for top-level `kind:` and the
|
|
7
|
+
* first `name:` under a `metadata:` block per `---`-separated section, with
|
|
8
|
+
* no full YAML parse. The output is consumed only for completion ranking,
|
|
9
|
+
* so misses on edge-case manifests are acceptable; the analyzer remains
|
|
10
|
+
* the source of truth for validation. */
|
|
11
|
+
function extractInFileResources(text) {
|
|
12
|
+
const out = [];
|
|
13
|
+
const lines = text.split("\n");
|
|
14
|
+
let currentKind;
|
|
15
|
+
let currentName;
|
|
16
|
+
let inMetadata = false;
|
|
17
|
+
const flush = () => {
|
|
18
|
+
if (currentKind && currentName) {
|
|
19
|
+
out.push({ kind: currentKind, name: currentName });
|
|
20
|
+
}
|
|
21
|
+
currentKind = undefined;
|
|
22
|
+
currentName = undefined;
|
|
23
|
+
inMetadata = false;
|
|
24
|
+
};
|
|
25
|
+
for (const line of lines) {
|
|
26
|
+
if (line.trimEnd() === "---") {
|
|
27
|
+
flush();
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const kindMatch = line.match(/^kind:\s*(\S+)/);
|
|
31
|
+
if (kindMatch) {
|
|
32
|
+
currentKind = kindMatch[1];
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (/^metadata:\s*$/.test(line)) {
|
|
36
|
+
inMetadata = true;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (inMetadata) {
|
|
40
|
+
// Lines inside metadata are indented. Pick the first `name:` we see.
|
|
41
|
+
const nameMatch = line.match(/^\s+name:\s*(\S+)/);
|
|
42
|
+
if (nameMatch && !currentName) {
|
|
43
|
+
currentName = nameMatch[1];
|
|
44
|
+
}
|
|
45
|
+
// Leaving the metadata block — any line that is not indented marks
|
|
46
|
+
// the end of the block.
|
|
47
|
+
if (line.length > 0 && !/^\s/.test(line)) {
|
|
48
|
+
inMetadata = false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
flush();
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
/** Returns the resource records whose kind satisfies the slot. When the
|
|
56
|
+
* slot has a registry-resolvable `x-telo-ref` constraint, results are
|
|
57
|
+
* filtered to that abstract's implementations; otherwise (or when the
|
|
58
|
+
* user already typed a sibling `kind:`) they're filtered by an exact
|
|
59
|
+
* kind match. Falls back to listing every in-file resource so the
|
|
60
|
+
* user still sees something rather than nothing when the registry
|
|
61
|
+
* doesn't recognize the kind yet. */
|
|
62
|
+
function refNameCompletions(text, refKind, refConstraint, registry, valueStartColumn) {
|
|
63
|
+
const resources = extractInFileResources(text);
|
|
64
|
+
let acceptable;
|
|
65
|
+
if (refKind) {
|
|
66
|
+
acceptable = new Set([refKind]);
|
|
67
|
+
}
|
|
68
|
+
else if (refConstraint && registry) {
|
|
69
|
+
const kinds = registry.userFacingKindsForRef(refConstraint);
|
|
70
|
+
if (kinds)
|
|
71
|
+
acceptable = new Set(kinds);
|
|
72
|
+
}
|
|
73
|
+
const seen = new Set();
|
|
74
|
+
const out = [];
|
|
75
|
+
for (const r of resources) {
|
|
76
|
+
if (acceptable && !acceptable.has(r.kind))
|
|
77
|
+
continue;
|
|
78
|
+
if (seen.has(r.name))
|
|
79
|
+
continue;
|
|
80
|
+
seen.add(r.name);
|
|
81
|
+
out.push({
|
|
82
|
+
label: r.name,
|
|
83
|
+
kind: "value",
|
|
84
|
+
detail: r.kind,
|
|
85
|
+
// Anchor the replace range to the value's start column so names with
|
|
86
|
+
// `.`, `-`, or `/` (legal in resource names) replace the whole typed
|
|
87
|
+
// prefix instead of the trailing word VS Code would pick by default.
|
|
88
|
+
replaceFromColumn: valueStartColumn,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
/** Resolve the kinds that satisfy the `x-telo-ref` slot at `parentDocKind` +
|
|
94
|
+
* `parentYamlPath`. Returns `undefined` (caller falls back to the full list)
|
|
95
|
+
* when there's no constraint, the path doesn't resolve, or the ref can't
|
|
96
|
+
* be resolved through the registry. */
|
|
97
|
+
function refConstrainedKinds(registry, parentDocKind, parentYamlPath) {
|
|
98
|
+
const definition = registry.resolveDefinition(parentDocKind);
|
|
99
|
+
if (!definition?.schema)
|
|
100
|
+
return undefined;
|
|
101
|
+
const refString = lookupRefConstraint(definition.schema, parentYamlPath);
|
|
102
|
+
if (!refString)
|
|
103
|
+
return undefined;
|
|
104
|
+
return registry.userFacingKindsForRef(refString);
|
|
105
|
+
}
|
|
106
|
+
function kindCompletions(registry, docKind, yamlPath, valueStartColumn) {
|
|
107
|
+
let kinds;
|
|
108
|
+
if (registry && docKind && yamlPath && yamlPath.length > 0) {
|
|
109
|
+
const filtered = refConstrainedKinds(registry, docKind, yamlPath);
|
|
110
|
+
kinds = filtered ?? registry.validUserFacingKinds();
|
|
111
|
+
}
|
|
112
|
+
else if (registry) {
|
|
113
|
+
kinds = registry.validUserFacingKinds();
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
kinds = ["Telo.Application", "Telo.Library", "Telo.Import", "Telo.Definition"];
|
|
117
|
+
}
|
|
118
|
+
const seen = new Set();
|
|
119
|
+
const results = [];
|
|
120
|
+
for (const kind of kinds) {
|
|
121
|
+
if (seen.has(kind))
|
|
122
|
+
continue;
|
|
123
|
+
seen.add(kind);
|
|
124
|
+
const item = { label: kind, kind: "class", detail: "Telo resource kind" };
|
|
125
|
+
// Anchor the replace range to the value's start column so kinds with `.`
|
|
126
|
+
// (e.g. `Sql.Connection`) cleanly overwrite the existing prefix. Without
|
|
127
|
+
// this, VS Code's default word boundary stops at the last `.` and a pick
|
|
128
|
+
// of `Sql.Connection` while the buffer reads `Sql.Co|` becomes
|
|
129
|
+
// `Sql.Sql.Connection`.
|
|
130
|
+
if (valueStartColumn !== undefined)
|
|
131
|
+
item.replaceFromColumn = valueStartColumn;
|
|
132
|
+
results.push(item);
|
|
133
|
+
}
|
|
134
|
+
return results;
|
|
14
135
|
}
|
|
15
136
|
function capabilityCompletions() {
|
|
16
137
|
return CAPABILITY_VALUES.map((cap) => ({
|
|
@@ -23,10 +144,18 @@ export async function buildCompletions(text, line, character, registry, adapter)
|
|
|
23
144
|
const ctx = detectContext(text, line, character);
|
|
24
145
|
if (!ctx)
|
|
25
146
|
return [];
|
|
26
|
-
if (ctx.type === "kind")
|
|
27
|
-
return kindCompletions(registry);
|
|
147
|
+
if (ctx.type === "kind") {
|
|
148
|
+
return kindCompletions(registry, ctx.docKind, ctx.yamlPath, ctx.valueStartColumn);
|
|
149
|
+
}
|
|
28
150
|
if (ctx.type === "capability")
|
|
29
151
|
return capabilityCompletions();
|
|
152
|
+
if (ctx.type === "ref-name") {
|
|
153
|
+
const definition = registry?.resolveDefinition(ctx.docKind);
|
|
154
|
+
const refConstraint = definition?.schema
|
|
155
|
+
? lookupRefConstraint(definition.schema, ctx.yamlPath)
|
|
156
|
+
: undefined;
|
|
157
|
+
return refNameCompletions(text, ctx.refKind, refConstraint, registry, ctx.valueStartColumn);
|
|
158
|
+
}
|
|
30
159
|
if (ctx.type === "field-value") {
|
|
31
160
|
if (ctx.docKind === "Telo.Import" && ctx.field === "source") {
|
|
32
161
|
return importSourceCompletions(ctx.prefix, ctx.valueStartColumn, adapter);
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
export type CompletionCtx = {
|
|
2
2
|
type: "kind";
|
|
3
|
+
/** Set for indented `kind:` lines. The enclosing docKind + the YAML
|
|
4
|
+
* path to the parent of the `kind:` field (so the value slot's
|
|
5
|
+
* schema node can be looked up to discover `x-telo-ref` constraints).
|
|
6
|
+
* Absent for top-level `kind:` — there, no constraint applies. */
|
|
7
|
+
docKind?: string;
|
|
8
|
+
yamlPath?: string[];
|
|
9
|
+
/** Column where the kind value begins (after `kind:` + whitespace).
|
|
10
|
+
* Editor hosts use this to anchor the replace range so completions
|
|
11
|
+
* cleanly overwrite a kind that contains `.` (e.g. `Sql.Co|` →
|
|
12
|
+
* selecting `Sql.Connection` must replace `Sql.Co`, not just `Co`,
|
|
13
|
+
* which VS Code's default word range would). */
|
|
14
|
+
valueStartColumn: number;
|
|
3
15
|
} | {
|
|
4
16
|
type: "capability";
|
|
5
17
|
} | {
|
|
@@ -7,6 +19,20 @@ export type CompletionCtx = {
|
|
|
7
19
|
docKind: string;
|
|
8
20
|
yamlPath: string[];
|
|
9
21
|
existingKeys: Set<string>;
|
|
22
|
+
} | {
|
|
23
|
+
/** Cursor sits on the value of an object-form ref's `name:` field
|
|
24
|
+
* (e.g. `connection: { kind: Sql.Connection, name: |}`). Editor hosts
|
|
25
|
+
* use `refKind` (from the sibling `kind:` line) to filter the in-doc
|
|
26
|
+
* resource list to matching candidates. */
|
|
27
|
+
type: "ref-name";
|
|
28
|
+
docKind: string;
|
|
29
|
+
/** YAML path to the parent slot (e.g. `["connection"]`). The schema
|
|
30
|
+
* at this path declares the `x-telo-ref` constraint. */
|
|
31
|
+
yamlPath: string[];
|
|
32
|
+
/** The kind value of the sibling `kind:` line, if present. */
|
|
33
|
+
refKind?: string;
|
|
34
|
+
prefix: string;
|
|
35
|
+
valueStartColumn: number;
|
|
10
36
|
} | {
|
|
11
37
|
type: "field-value";
|
|
12
38
|
docKind: string;
|
|
@@ -21,22 +47,52 @@ export declare function findDocBounds(lines: string[], cursorLine: number): {
|
|
|
21
47
|
end: number;
|
|
22
48
|
};
|
|
23
49
|
export declare function extractKindFromDoc(lines: string[], start: number, end: number): string | undefined;
|
|
24
|
-
|
|
25
|
-
|
|
50
|
+
/** Collects every top-level key in the doc bounds, skipping `skipLine` so the
|
|
51
|
+
* cursor's own line is treated as "being edited" — its key (if any) stays in
|
|
52
|
+
* the suggestion list. Without this the user can't autocomplete an existing
|
|
53
|
+
* key from its own line (e.g. `ver|sion:`). */
|
|
54
|
+
export declare function extractRootKeys(lines: string[], start: number, end: number, skipLine?: number): Set<string>;
|
|
55
|
+
/** Walk backward from cursorLine to build the chain of parent YAML keys.
|
|
56
|
+
*
|
|
57
|
+
* List-item handling (` - request:` style): the `-` marker sits at the
|
|
58
|
+
* line's textual indent, but the key after it (`request`) lives at indent
|
|
59
|
+
* `+2`. Whether that post-dash key joins the path depends on the cursor's
|
|
60
|
+
* descent:
|
|
61
|
+
* - When the cursor's current target indent is GREATER than the post-dash
|
|
62
|
+
* key's column, the descent passes through that key (e.g. cursor inside
|
|
63
|
+
* `request.method` at indent 6, key `request` at column 4) → push it.
|
|
64
|
+
* - When the cursor's current target indent EQUALS the post-dash key's
|
|
65
|
+
* column, the post-dash key is a sibling at the list-item level
|
|
66
|
+
* (e.g. cursor on `handler:` at indent 4, key `request:` at column 4) →
|
|
67
|
+
* skip it; descend straight to the array's parent.
|
|
68
|
+
*
|
|
69
|
+
* In both cases the next walk step targets `lineIndent` so the `routes:` /
|
|
70
|
+
* `steps:` parent of the array is captured. The schema walker auto-descends
|
|
71
|
+
* arrays, so no `[]` marker is appended. */
|
|
26
72
|
export declare function buildYamlPath(lines: string[], cursorLine: number, docStart: number, cursorIndent: number): string[];
|
|
27
|
-
/** Extract sibling keys already present at `indent` within the doc bounds.
|
|
28
|
-
|
|
29
|
-
|
|
73
|
+
/** Extract sibling keys already present at `indent` within the doc bounds.
|
|
74
|
+
* `skipLine` lets the caller exclude the cursor's own line so a key being
|
|
75
|
+
* edited (`ver|sion:`) doesn't filter itself out of the suggestion list. */
|
|
76
|
+
export declare function extractKeysAtIndent(lines: string[], start: number, end: number, indent: number, skipLine?: number): Set<string>;
|
|
77
|
+
/** Navigate a JSON Schema hierarchy following `path`, auto-descending into
|
|
78
|
+
* array items and peeling `anyOf` / `oneOf` branches. When multiple peeled
|
|
79
|
+
* branches define `properties`, returns a synthetic node whose `properties`
|
|
80
|
+
* is the union (first-wins on key collision) and whose `required` is the
|
|
81
|
+
* intersection — enough for propKeyCompletions to surface every key a value
|
|
82
|
+
* at this slot can legally carry. */
|
|
30
83
|
export declare function navigateSchema(schema: Record<string, any>, path: string[]): Record<string, any> | undefined;
|
|
31
|
-
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
84
|
+
/** Walks up and down from `cursorLine` looking for a sibling line at the
|
|
85
|
+
* exact same indent whose key is `kind`. The value of the first such line
|
|
86
|
+
* is returned (alias form, e.g. `"Sql.Connection"`). Used by ref-name
|
|
87
|
+
* completion to discover what kind of resource the user is targeting in an
|
|
88
|
+
* object-form ref. Walking stops at the first line with a strictly smaller
|
|
89
|
+
* indent (that's the parent's structural boundary). */
|
|
90
|
+
export declare function findSiblingKindValue(lines: string[], docStart: number, docEnd: number, cursorLine: number, indent: number): string | undefined;
|
|
91
|
+
/** Looks up the `x-telo-ref` string carried by the schema node at `yamlPath`
|
|
92
|
+
* inside `definitionSchema`. Checks both the property node directly and its
|
|
93
|
+
* peeled `anyOf` / `oneOf` branches, since some library schemas place the
|
|
94
|
+
* annotation at the property level and others inside a branch. Returns
|
|
95
|
+
* `undefined` when the path doesn't resolve or no ref constraint is declared. */
|
|
96
|
+
export declare function lookupRefConstraint(definitionSchema: Record<string, any>, yamlPath: string[]): string | undefined;
|
|
41
97
|
export declare function detectContext(text: string, line: number, character: number): CompletionCtx | undefined;
|
|
42
98
|
//# sourceMappingURL=detect-context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detect-context.d.ts","sourceRoot":"","sources":["../../src/completions/detect-context.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GACrB;
|
|
1
|
+
{"version":3,"file":"detect-context.d.ts","sourceRoot":"","sources":["../../src/completions/detect-context.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GACrB;IACE,IAAI,EAAE,MAAM,CAAC;IACb;;;uEAGmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB;;;;qDAIiD;IACjD,gBAAgB,EAAE,MAAM,CAAC;CAC1B,GACD;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAE,GACpF;IACE;;;gDAG4C;IAC5C,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB;6DACyD;IACzD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;CAC1B,GACD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEN,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAgBjG;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMlG;AAED;;;gDAGgD;AAChD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,MAAM,GAChB,GAAG,CAAC,MAAM,CAAC,CAQb;AAED;;;;;;;;;;;;;;;;6CAgB6C;AAC7C,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EAAE,EACf,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,MAAM,EAAE,CAqCV;AAED;;6EAE6E;AAC7E,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,GAChB,GAAG,CAAC,MAAM,CAAC,CAcb;AAuBD;;;;;sCAKsC;AACtC,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,IAAI,EAAE,MAAM,EAAE,GACb,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CA4BjC;AAoCD;;;;;wDAKwD;AACxD,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EAAE,EACf,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,SAAS,CAsBpB;AAED;;;;kFAIkF;AAClF,wBAAgB,mBAAmB,CACjC,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACrC,QAAQ,EAAE,MAAM,EAAE,GACjB,MAAM,GAAG,SAAS,CAQpB;AAED,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,aAAa,GAAG,SAAS,CAyH3B"}
|