@descryy/adapter-go 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.
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The Go `LanguageAdapter` — all seven methods, breadth tier.
3
+ *
4
+ * Structurally this is the Java adapter with a different grammar and a different
5
+ * rule set, which is the whole claim the tree-sitter harness was built to test.
6
+ * Nothing in `@descryy/adapter-treesitter` changed to accommodate Go.
7
+ */
8
+ import { type LanguageAdapter, type ResolutionLevel } from "@descryy/ir";
9
+ import { toRepoRelative } from "@descryy/adapter-common";
10
+ import { LANGUAGE } from "./extract.ts";
11
+ export declare const ADAPTER_ID = "adapter-go";
12
+ export declare const ADAPTER_VERSION = "0.1.0";
13
+ export declare const DEFAULT_GO_GLOBS: readonly ["**/*.go"];
14
+ export interface GoAdapterOptions {
15
+ readonly globs?: readonly string[];
16
+ readonly maxResolution?: ResolutionLevel;
17
+ }
18
+ export interface GoAdapter extends LanguageAdapter {
19
+ readonly id: string;
20
+ readonly version: string;
21
+ }
22
+ export declare function createGoAdapter(options?: GoAdapterOptions): GoAdapter;
23
+ /** Content hash of a repo-relative file, for `FileRef`. */
24
+ export declare function hashOf(root: string, relative: string): string;
25
+ export { LANGUAGE, toRepoRelative };
26
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,EAML,KAAK,eAAe,EAGpB,KAAK,eAAe,EAGrB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAyB,cAAc,EAAwB,MAAM,yBAAyB,CAAC;AAKtG,OAAO,EAAW,QAAQ,EAA4B,MAAM,cAAc,CAAC;AAE3E,eAAO,MAAM,UAAU,eAAe,CAAC;AACvC,eAAO,MAAM,eAAe,UAAU,CAAC;AACvC,eAAO,MAAM,gBAAgB,sBAAuB,CAAC;AAuBrD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,aAAa,CAAC,EAAE,eAAe,CAAC;CAC1C;AAcD,MAAM,WAAW,SAAU,SAAQ,eAAe;IAChD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,OAAO,GAAE,gBAAqB,GAAG,SAAS,CAkNzE;AAED,2DAA2D;AAC3D,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM7D;AAED,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC"}
@@ -0,0 +1,247 @@
1
+ /**
2
+ * The Go `LanguageAdapter` — all seven methods, breadth tier.
3
+ *
4
+ * Structurally this is the Java adapter with a different grammar and a different
5
+ * rule set, which is the whole claim the tree-sitter harness was built to test.
6
+ * Nothing in `@descryy/adapter-treesitter` changed to accommodate Go.
7
+ */
8
+ import { createHash } from "node:crypto";
9
+ import { createRequire } from "node:module";
10
+ import { existsSync, readFileSync } from "node:fs";
11
+ import { join } from "node:path";
12
+ import { CLIENT_CALL_EXTRACTOR, ROUTE_EXTRACTOR, } from "@descryy/ir";
13
+ import { discover, isolateFile, toRepoRelative } from "@descryy/adapter-common";
14
+ import { parserFor, parseText } from "@descryy/adapter-treesitter";
15
+ import { buildConstraintOf, readFile as readGoFile } from "./parse.js";
16
+ import { goModules, importPathOf } from "./modules.js";
17
+ import { extract, LANGUAGE, REASONS } from "./extract.js";
18
+ export const ADAPTER_ID = "adapter-go";
19
+ export const ADAPTER_VERSION = "0.1.0";
20
+ export const DEFAULT_GO_GLOBS = ["**/*.go"];
21
+ const PRODUCED_BY = `${ADAPTER_ID}@${ADAPTER_VERSION}`;
22
+ function grammarPath() {
23
+ const beside = join(import.meta.dirname, "tree-sitter-go.wasm");
24
+ if (existsSync(beside))
25
+ return beside;
26
+ return createRequire(import.meta.url).resolve("tree-sitter-go/tree-sitter-go.wasm");
27
+ }
28
+ /**
29
+ * Vendored dependencies are somebody else's source.
30
+ *
31
+ * `vendor/` holds a copy of the module graph, and analysing it both doubles the
32
+ * work and puts a second declaration of every vendored symbol in the graph.
33
+ * Unlike Java's build directories this needs no source-root caveat: `vendor` is
34
+ * a reserved directory name in the Go toolchain, not a package name a project
35
+ * chooses, and `go build` excludes it by the same rule.
36
+ */
37
+ function isVendored(file) {
38
+ return `/${file}`.includes("/vendor/") || `/${file}`.includes("/testdata/");
39
+ }
40
+ export function createGoAdapter(options = {}) {
41
+ const globs = options.globs ?? DEFAULT_GO_GLOBS;
42
+ const ceiling = options.maxResolution ?? 2;
43
+ let session;
44
+ let parser;
45
+ const filesUnder = (root) => discover(root.absolutePath, globs).filter((file) => !isVendored(file));
46
+ return {
47
+ id: ADAPTER_ID,
48
+ version: ADAPTER_VERSION,
49
+ async detect(root) {
50
+ const files = filesUnder(root);
51
+ const evidence = [];
52
+ if (files.length > 0)
53
+ evidence.push(`${files.length} .go files outside vendor/ and testdata/`);
54
+ const modules = goModules(root.absolutePath, files);
55
+ if (modules.length > 0) {
56
+ evidence.push(`${modules.length} go.mod file(s); root module ${modules[modules.length - 1]?.path}`);
57
+ }
58
+ else if (files.length > 0) {
59
+ // Not a failure, but it caps what identity can be: without a module path
60
+ // there is no import path, and nothing outside can name these packages.
61
+ evidence.push("no go.mod found — packages have no import path and cannot be identified");
62
+ }
63
+ return { detected: files.length > 0, roots: files.length > 0 ? [root.absolutePath] : [], evidence };
64
+ },
65
+ capabilities() {
66
+ return {
67
+ maxResolution: ceiling,
68
+ nodeTypes: ["MODULE", "CLASS", "FUNCTION", "TEST_CASE", "API_ROUTE", "API_ENDPOINT"],
69
+ /**
70
+ * `IMPLEMENTS` is absent, and its absence is the honest part.
71
+ *
72
+ * Go's interface satisfaction is structural: a type implements an
73
+ * interface by having the right method set, and no line of source says
74
+ * so. Deciding it means comparing method sets, which is R3 evidence this
75
+ * adapter does not have — and inferring it from names would be a guess
76
+ * in the one place the corpus has a negative pattern for guessing.
77
+ * Embedding is written down and becomes `INHERITS`.
78
+ */
79
+ edgeTypes: ["IMPORTS", "CALLS", "TESTS", "INHERITS", "USES_TYPE", "SERVES_API", "USES_API"],
80
+ hasCallHierarchy: false,
81
+ hasTypeHierarchy: false,
82
+ /**
83
+ * Directories this ecosystem installs dependencies or build output into —
84
+ * DEC-110's end state. The engine used to hold `node_modules`/`vendor`/`target`
85
+ * in a hardcoded list; it holds none of them now and consumes this instead.
86
+ *
87
+ * `vendor/` holds a copy of the module graph — analysing it doubles the work and
88
+ * puts a second declaration of every vendored symbol in the graph.
89
+ *
90
+ * Names only — the walk matches one path component, so a path or glob matches
91
+ * nothing. Nothing dotted — those are skipped structurally already.
92
+ */
93
+ noiseDirectories: ["vendor"],
94
+ frameworkExtractors: [
95
+ "net/http",
96
+ "github.com/gin-gonic/gin",
97
+ "github.com/go-chi/chi",
98
+ "github.com/labstack/echo",
99
+ "github.com/gorilla/mux",
100
+ "google.golang.org/grpc",
101
+ ],
102
+ /**
103
+ * `net/http` now supplies both halves of the HTTP boundary. `route-extractor`
104
+ * grades pattern 04 as before; `client-call-extractor` reads `client.ts`'s
105
+ * three call shapes (package-level convenience funcs, `*http.Client`
106
+ * methods, `NewRequest`'s own literal arguments) and genuinely produces
107
+ * `USES_API` edges — see `client.ts`'s own header. Whether golden pattern
108
+ * 08 can confirm it is a separate question from whether the extraction is
109
+ * honest: it needs `order_page` retyped away from `COMPONENT` in this
110
+ * corpus's own `manifest.json` (DEC-262's fork — Go is backend-only and
111
+ * has no honest claim to a UI component, the same reason Kotlin and
112
+ * Python already carry this override) and a fixture that makes a real
113
+ * call. Declaring the capability here is safe either way — DEC-262 found
114
+ * this exact declaration never fails a golden pattern, it either passes
115
+ * genuinely or stays permanently skipped on an honest incapacity, never
116
+ * both silently wrong.
117
+ */
118
+ frameworkCapabilities: [ROUTE_EXTRACTOR, CLIENT_CALL_EXTRACTOR],
119
+ };
120
+ },
121
+ async prepare(ctx) {
122
+ // Sorted, so that which declaration wins a build-constraint collision is a
123
+ // property of the repository and not of the order the filesystem happened
124
+ // to hand the files over.
125
+ const files = [...filesUnder(ctx.root)].sort();
126
+ parser ??= await parserFor(grammarPath());
127
+ const modules = goModules(ctx.root.absolutePath, files);
128
+ const units = [];
129
+ const failures = [];
130
+ const unfinished = [];
131
+ const withoutModule = [];
132
+ const pathCache = new Map();
133
+ for (const file of files) {
134
+ if (ctx.signal.aborted)
135
+ break;
136
+ let text;
137
+ try {
138
+ text = readFileSync(join(ctx.root.absolutePath, file), "utf8");
139
+ }
140
+ catch (error) {
141
+ failures.push({ kind: "unreadable", file, detail: error instanceof Error ? error.message : String(error) });
142
+ continue;
143
+ }
144
+ const outcome = parseText(parser, file, text);
145
+ if (outcome.tree === undefined) {
146
+ if (outcome.failure !== undefined)
147
+ failures.push(outcome.failure);
148
+ continue;
149
+ }
150
+ /**
151
+ * The tree walk is isolated because a throw here used to cost the run,
152
+ * not the file. Reading and parsing were already per-file; this step was
153
+ * the gap, and it is the one that fires on half-written source — which is
154
+ * exactly what someone analysing code they just wrote is handing us.
155
+ */
156
+ const read = isolateFile(file, () => readGoFile(outcome.tree.rootNode, file, outcome.tree.rootNode.hasError));
157
+ outcome.tree.delete();
158
+ if (read.failure !== undefined) {
159
+ unfinished.push(read.failure);
160
+ continue;
161
+ }
162
+ const unit = read.value;
163
+ let importPath = pathCache.get(unit.directory);
164
+ if (!pathCache.has(unit.directory)) {
165
+ importPath = importPathOf(modules, unit.directory);
166
+ pathCache.set(unit.directory, importPath);
167
+ }
168
+ if (importPath === undefined) {
169
+ withoutModule.push(file);
170
+ continue;
171
+ }
172
+ units.push({ ...unit, importPath, buildConstraint: buildConstraintOf(text) });
173
+ }
174
+ const reached = units.length === 0 ? 0 : ceiling;
175
+ session = { root: ctx.root, files, units, reached, failures, unfinished, withoutModule };
176
+ return reached;
177
+ },
178
+ async parseFiles(files) {
179
+ const byFile = new Map((session?.units ?? []).map((unit) => [unit.file, unit]));
180
+ return files.map((file) => ({ file, tree: byFile.get(file.path) ?? {} }));
181
+ },
182
+ extractNodes() {
183
+ return current().nodes;
184
+ },
185
+ extractEdges() {
186
+ return current().edges;
187
+ },
188
+ async emit(ctx) {
189
+ const reached = await this.prepare(ctx);
190
+ const active = session;
191
+ const extraction = current();
192
+ const excludedFiles = new Set([
193
+ ...active.failures.map((f) => f.file),
194
+ ...active.unfinished.map((f) => f.file),
195
+ ...active.withoutModule,
196
+ ]);
197
+ return {
198
+ repo: ctx.root.repo,
199
+ ...(ctx.root.workspace === undefined ? {} : { workspace: ctx.root.workspace }),
200
+ commitSha: ctx.root.commitSha,
201
+ producedBy: PRODUCED_BY,
202
+ sourceFiles: active.files.filter((f) => !excludedFiles.has(f)),
203
+ skippedFiles: [
204
+ ...active.failures.map((f) => ({ file: f.file, reason: f.kind, detail: f.detail })),
205
+ // `other`, not a fifth reason code. The canonical vocabulary does not
206
+ // grow for this: the file was read and parsed, and what failed is our
207
+ // walk of it, which the detail says outright.
208
+ ...active.unfinished.map((f) => ({ file: f.file, reason: "other", detail: f.detail })),
209
+ ...active.withoutModule.map((file) => ({ file, reason: "other", detail: REASONS.noImportPath })),
210
+ ],
211
+ reachedResolution: reached,
212
+ nodes: extraction.nodes,
213
+ edges: extraction.edges,
214
+ unresolved: extraction.unresolved,
215
+ };
216
+ },
217
+ async dispose() {
218
+ session = undefined;
219
+ parser?.delete();
220
+ parser = undefined;
221
+ },
222
+ };
223
+ function current() {
224
+ const active = session;
225
+ if (active === undefined || active.units.length === 0) {
226
+ return { nodes: [], edges: [], unresolved: [] };
227
+ }
228
+ return extract({
229
+ repo: active.root.repo,
230
+ scope: { repo: active.root.repo, ...(active.root.workspace === undefined ? {} : { workspace: active.root.workspace }) },
231
+ producedBy: PRODUCED_BY,
232
+ reached: active.reached,
233
+ files: active.units,
234
+ });
235
+ }
236
+ }
237
+ /** Content hash of a repo-relative file, for `FileRef`. */
238
+ export function hashOf(root, relative) {
239
+ try {
240
+ return createHash("sha256").update(readFileSync(join(root, relative))).digest("hex").slice(0, 32);
241
+ }
242
+ catch {
243
+ return "";
244
+ }
245
+ }
246
+ export { LANGUAGE, toRepoRelative };
247
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * The caller's half of the HTTP boundary: `USES_API`, golden pattern 08.
3
+ *
4
+ * `SERVES_API` is minted in `routes.ts`/`extract.ts` from a route registration.
5
+ * This reads the other end — an outbound call with a statically knowable path —
6
+ * and mints the **same** `API_ENDPOINT` node from the same `endpointQsp`, so the
7
+ * two join without either side knowing the other ran (DEC-115).
8
+ *
9
+ * FUNCTION ──USES_API──▶ API_ENDPOINT ◀──SERVES_API── API_ROUTE
10
+ *
11
+ * ## Structured like `routes.ts`, not like Java's `client.ts`
12
+ *
13
+ * Java's client reader walks `JavaRef` — a flat, already-collected list of
14
+ * references with a `firstStringArgument` field captured at parse time. Go has
15
+ * no equivalent: `GoRef` keeps a short `raw` summary but not positional argument
16
+ * access, because nothing before this needed it. `net/http.NewRequest(method,
17
+ * url, body)` needs **two** literal positions read out of one call — the verb
18
+ * and the path both — so this reads `call_expression` nodes directly off the
19
+ * tree, the same shape `routes.ts`'s `readCall` already uses for the provider
20
+ * side of this exact boundary.
21
+ *
22
+ * ## Three shapes, one budget
23
+ *
24
+ * | shape | evidence |
25
+ * | --- | --- |
26
+ * | `http.Get(url)` / `Head` / `Post` / `PostForm` | the receiver is the `net/http` package itself, resolved through the file's own import table |
27
+ * | `client.Get(url)` / `Head` / `Post` / `PostForm` / `Do(req)` | the receiver's **declared type** is `http.Client` (pointer stripped), from a parameter, a `:=` composite literal, or a `var` |
28
+ * | `http.NewRequest(method, url, body)` / `NewRequestWithContext(ctx, method, url, body)` | the receiver is the `net/http` package; verb **and** path are both this call's own arguments — the verb as a string literal or one of `net/http`'s own exported `Method*` constants, the path as a string literal |
29
+ *
30
+ * `Do(req)` is refused unconditionally, never traced back to whatever built
31
+ * `req` — the same shape Java's `OkHttpClient`/`java.net.http.HttpClient`
32
+ * builder-client rows are refused for (D-FIX-3): the request is a separately
33
+ * constructed object, and reading through a builder chain to find where it was
34
+ * built is a different, larger row. `NewRequest`'s own call is a separate,
35
+ * independent extraction site — its literal arguments are read directly, never
36
+ * traced forward into whatever `.Do()` call eventually consumes the request it
37
+ * returns, so nothing here double-counts one HTTP call as two edges.
38
+ *
39
+ * ## Why the receiver's type must be written down
40
+ *
41
+ * `Get`, `Post`, `Do` are ordinary method names — a cache client, a mock, a
42
+ * test double could all have one. Admitting a call on the name alone would emit
43
+ * `USES_API` for anything shaped like `thing.Get(x)`, joining a caller to a
44
+ * route it never calls. So `client.*` is only admitted when the receiver's
45
+ * declared type resolves, through the import table, to `net/http.Client` —
46
+ * the same discipline `routes.ts` already holds for `NewServeMux`.
47
+ *
48
+ * ## The origin check, reused rather than re-derived
49
+ *
50
+ * `namesAnotherOrigin`/`relativePath` are copied verbatim from
51
+ * `adapter-java/src/client.ts` (via `adapter-csharp`'s DEC-260/261 fix): only an
52
+ * unambiguous absolute form (an explicit scheme, or `//host/...`) earns
53
+ * "another origin"; a bare relative path with no leading slash is `undetermined`
54
+ * — it may resolve against a `Client.BaseURL` this reader does not see, or it
55
+ * may not, and claiming either is a guess. This project has now found the
56
+ * identical latent bug in three languages that copied "does not start with a
57
+ * scheme" as sufficient evidence; the fourth and fifth (Rust, Ruby, PHP) reuse
58
+ * this same text rather than re-deriving it a fourth time.
59
+ */
60
+ import type { Node } from "@descryy/adapter-treesitter";
61
+ import { type IdentityScope, type IRNode } from "@descryy/ir";
62
+ import type { GoFile } from "./parse.ts";
63
+ export interface GoClientCallSite {
64
+ readonly method: string;
65
+ readonly template: string;
66
+ readonly verb: string;
67
+ readonly line: number;
68
+ /** `test` when the file is a `_test.go` file, else `production`. */
69
+ readonly callerKind: "test" | "production";
70
+ }
71
+ export interface GoClientRefusalSite {
72
+ readonly raw: string;
73
+ readonly line: number;
74
+ readonly reason: string;
75
+ /** DEC-242's `attrs.blockedBy` — the literal blocking expression, or `null`. */
76
+ readonly blockedBy: string | null;
77
+ /** DEC-242's `attrs.refusalClass` — `undefined` means unclassified, never askable. */
78
+ readonly refusalClass: BaseRefusalClass | "out-of-scope" | undefined;
79
+ /**
80
+ * Diagnostic only, not part of DEC-242 — see `adapter-rust/src/client.ts`'s
81
+ * own doc for what this is and why it is not shipped as part of the
82
+ * contract. Present only on the generic fallthrough of `diagnoseArgument`.
83
+ */
84
+ readonly argumentKind?: "field" | "call" | "concatenation" | "other";
85
+ }
86
+ export type BaseRefusalClass = "value-unknown" | "varies-per-call" | "capability-gap";
87
+ export interface GoClientCall extends GoClientCallSite {
88
+ readonly fromId: string;
89
+ }
90
+ export interface GoClientRefusal extends GoClientRefusalSite {
91
+ readonly fromId: string;
92
+ }
93
+ /**
94
+ * Every outbound HTTP call in one function body, with a ledger row for each
95
+ * refusal.
96
+ *
97
+ * `locals` is the function's **already-fully-walked** local table — parameters
98
+ * and `:=`/`var` declarations alike — so a `*http.Client` parameter and a
99
+ * `client := &http.Client{}` local are both visible with no separate pass. It
100
+ * is read, never written: this module adds no new declarations to it.
101
+ */
102
+ export declare function readGoClientCalls(body: Node, unit: GoFile, locals: ReadonlyMap<string, string | null>, isTest: boolean, parameterNames?: ReadonlySet<string>): {
103
+ readonly calls: readonly GoClientCallSite[];
104
+ readonly refusals: readonly GoClientRefusalSite[];
105
+ };
106
+ /**
107
+ * The `API_ENDPOINT` a call joins to — minted identically to the route side.
108
+ *
109
+ * Shares `endpointQsp` with `extract.ts`'s `SERVES_API` block, so the two ids
110
+ * agree exactly. DEC-115's one hard constraint: two producers that mint
111
+ * different ids for the same route do not conflict, they silently fail to join.
112
+ */
113
+ export declare function endpointFor(scope: IdentityScope, call: GoClientCall, producedBy: string, normalise: (template: string) => string): IRNode;
114
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAuB,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAEnF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAoCzC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,CAAC;CAC5C;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,gFAAgF;IAChF,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,sFAAsF;IACtF,QAAQ,CAAC,YAAY,EAAE,gBAAgB,GAAG,cAAc,GAAG,SAAS,CAAC;IACrE;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,eAAe,GAAG,OAAO,CAAC;CACtE;AAmBD,MAAM,MAAM,gBAAgB,GAAG,eAAe,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAqCtF,MAAM,WAAW,YAAa,SAAQ,gBAAgB;IACpD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAgB,SAAQ,mBAAmB;IAC1D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAwED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EAC1C,MAAM,EAAE,OAAO,EACf,cAAc,GAAE,WAAW,CAAC,MAAM,CAAa,GAC9C;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAA;CAAE,CAsHpG;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE,YAAY,EAClB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,GACtC,MAAM,CAaR"}