@flow-as-code/cli 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 (120) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +446 -0
  3. package/dist/aws.d.ts +28 -0
  4. package/dist/aws.d.ts.map +1 -0
  5. package/dist/aws.js +104 -0
  6. package/dist/aws.js.map +1 -0
  7. package/dist/bin.d.ts +3 -0
  8. package/dist/bin.d.ts.map +1 -0
  9. package/dist/bin.js +132 -0
  10. package/dist/bin.js.map +1 -0
  11. package/dist/bridge/exportFiles.d.ts +16 -0
  12. package/dist/bridge/exportFiles.d.ts.map +1 -0
  13. package/dist/bridge/exportFiles.js +95 -0
  14. package/dist/bridge/exportFiles.js.map +1 -0
  15. package/dist/bridge/pair.d.ts +103 -0
  16. package/dist/bridge/pair.d.ts.map +1 -0
  17. package/dist/bridge/pair.js +219 -0
  18. package/dist/bridge/pair.js.map +1 -0
  19. package/dist/bridge/protocol.d.ts +187 -0
  20. package/dist/bridge/protocol.d.ts.map +1 -0
  21. package/dist/bridge/protocol.js +132 -0
  22. package/dist/bridge/protocol.js.map +1 -0
  23. package/dist/bridge/server.d.ts +95 -0
  24. package/dist/bridge/server.d.ts.map +1 -0
  25. package/dist/bridge/server.js +669 -0
  26. package/dist/bridge/server.js.map +1 -0
  27. package/dist/cdk-scaffold.d.ts +16 -0
  28. package/dist/cdk-scaffold.d.ts.map +1 -0
  29. package/dist/cdk-scaffold.js +28 -0
  30. package/dist/cdk-scaffold.js.map +1 -0
  31. package/dist/codegen.d.ts +5 -0
  32. package/dist/codegen.d.ts.map +1 -0
  33. package/dist/codegen.js +27 -0
  34. package/dist/codegen.js.map +1 -0
  35. package/dist/diff.d.ts +33 -0
  36. package/dist/diff.d.ts.map +1 -0
  37. package/dist/diff.js +225 -0
  38. package/dist/diff.js.map +1 -0
  39. package/dist/docs.d.ts +46 -0
  40. package/dist/docs.d.ts.map +1 -0
  41. package/dist/docs.js +223 -0
  42. package/dist/docs.js.map +1 -0
  43. package/dist/emit.d.ts +8 -0
  44. package/dist/emit.d.ts.map +1 -0
  45. package/dist/emit.js +55 -0
  46. package/dist/emit.js.map +1 -0
  47. package/dist/errors.d.ts +12 -0
  48. package/dist/errors.d.ts.map +1 -0
  49. package/dist/errors.js +25 -0
  50. package/dist/errors.js.map +1 -0
  51. package/dist/export.d.ts +27 -0
  52. package/dist/export.d.ts.map +1 -0
  53. package/dist/export.js +126 -0
  54. package/dist/export.js.map +1 -0
  55. package/dist/index.d.ts +4 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +23 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/lint.d.ts +6 -0
  60. package/dist/lint.d.ts.map +1 -0
  61. package/dist/lint.js +31 -0
  62. package/dist/lint.js.map +1 -0
  63. package/dist/render.d.ts +6 -0
  64. package/dist/render.d.ts.map +1 -0
  65. package/dist/render.js +49 -0
  66. package/dist/render.js.map +1 -0
  67. package/dist/run.d.ts +13 -0
  68. package/dist/run.d.ts.map +1 -0
  69. package/dist/run.js +38 -0
  70. package/dist/run.js.map +1 -0
  71. package/dist/simulate.d.ts +35 -0
  72. package/dist/simulate.d.ts.map +1 -0
  73. package/dist/simulate.js +194 -0
  74. package/dist/simulate.js.map +1 -0
  75. package/dist/studio.d.ts +23 -0
  76. package/dist/studio.d.ts.map +1 -0
  77. package/dist/studio.js +120 -0
  78. package/dist/studio.js.map +1 -0
  79. package/dist/synth-resolve-hook.d.ts +19 -0
  80. package/dist/synth-resolve-hook.d.ts.map +1 -0
  81. package/dist/synth-resolve-hook.js +127 -0
  82. package/dist/synth-resolve-hook.js.map +1 -0
  83. package/dist/synth-runner.d.ts +12 -0
  84. package/dist/synth-runner.d.ts.map +1 -0
  85. package/dist/synth-runner.js +145 -0
  86. package/dist/synth-runner.js.map +1 -0
  87. package/dist/synth.d.ts +55 -0
  88. package/dist/synth.d.ts.map +1 -0
  89. package/dist/synth.js +327 -0
  90. package/dist/synth.js.map +1 -0
  91. package/dist/watch.d.ts +66 -0
  92. package/dist/watch.d.ts.map +1 -0
  93. package/dist/watch.js +293 -0
  94. package/dist/watch.js.map +1 -0
  95. package/package.json +85 -0
  96. package/schema/flowdoc-0.1.schema.json +669 -0
  97. package/schema/scenario-0.1.schema.json +318 -0
  98. package/src/aws.ts +149 -0
  99. package/src/bin.ts +179 -0
  100. package/src/bridge/exportFiles.ts +116 -0
  101. package/src/bridge/pair.ts +312 -0
  102. package/src/bridge/protocol.ts +289 -0
  103. package/src/bridge/server.ts +827 -0
  104. package/src/cdk-scaffold.ts +41 -0
  105. package/src/codegen.ts +36 -0
  106. package/src/diff.ts +279 -0
  107. package/src/docs.ts +249 -0
  108. package/src/emit.ts +69 -0
  109. package/src/errors.ts +27 -0
  110. package/src/export.ts +167 -0
  111. package/src/index.ts +27 -0
  112. package/src/lint.ts +42 -0
  113. package/src/render.ts +58 -0
  114. package/src/run.ts +42 -0
  115. package/src/simulate.ts +244 -0
  116. package/src/studio.ts +143 -0
  117. package/src/synth-resolve-hook.ts +152 -0
  118. package/src/synth-runner.ts +157 -0
  119. package/src/synth.ts +380 -0
  120. package/src/watch.ts +388 -0
@@ -0,0 +1,127 @@
1
+ /*
2
+ * Copyright 2026 The flow-as-code Authors
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ // Module-resolution hook for the `flow-cli synth` child process. Two jobs,
6
+ // both aimed at the same thing: a `<name>.flow.ts` sitting in a plain folder
7
+ // of FlowDocs must synth, because that is where `flow-cli codegen` writes it
8
+ // and what `flow-cli studio` re-synths on every save.
9
+ //
10
+ // 1. TypeScript in the builder graph is ESM when nothing says otherwise.
11
+ // Without a package.json above it, the TypeScript loader compiles the file
12
+ // to CommonJS, so its `import { Flow } from "@flow-as-code/core"`
13
+ // becomes a `require` of an ESM-only package, which is not the module
14
+ // system codegen emits for.
15
+ // A directory that does declare a type keeps it: this only fills in a
16
+ // decision nobody made.
17
+ //
18
+ // "Nobody made a decision" is read off the filesystem rather than off the
19
+ // resolver's answer, because runtimes have answered differently for the same
20
+ // plain folder: Node 22 and later return a null `format` for the builder
21
+ // file, while Node 20 returned "commonjs". Trusting a nullish `format` alone
22
+ // therefore fixed the plain-folder case on 22 and left it broken on 20.
23
+ // Node 20 is no longer supported, but the answer is not a contract, so the
24
+ // walk stays: a TypeScript file with no package.json anywhere above it is
25
+ // ESM whatever the resolver said, and one with a package.json above it is
26
+ // left exactly as resolved.
27
+ //
28
+ // 2. @flow-as-code/core resolves from @flow-as-code/cli when it resolves from
29
+ // nowhere else. A folder of FlowDocs has no node_modules, and requiring the
30
+ // user to install @flow-as-code/core beside every such folder to edit a file
31
+ // the CLI generated is not a reasonable price. It is a hard dependency of
32
+ // @flow-as-code/cli, so resolving from the CLI's own module always finds the
33
+ // copy the CLI is running against.
34
+ //
35
+ // The fallback runs after the default resolver, never before it, so a copy
36
+ // installed next to the builder file still wins and version skew stays the
37
+ // user's choice. It is scoped to @flow-as-code/core alone: a builder file
38
+ // cannot use it to reach the rest of the CLI's dependency tree.
39
+ //
40
+ // Nothing about the sandbox changes. The child keeps its stripped environment,
41
+ // its pinned working directory, and the permission flags synth.ts passes; the
42
+ // fallback only reads a file the child could already read under
43
+ // `--allow-fs-read=*`. See SECURITY.md.
44
+ //
45
+ // Loaded on the module-customization hooks thread by `module.register`
46
+ // (https://nodejs.org/api/module.html#customization-hooks), which is why the
47
+ // fallback target arrives through `initialize` rather than a module-level
48
+ // import.
49
+ import { existsSync } from "node:fs";
50
+ import { dirname, join } from "node:path";
51
+ import { fileURLToPath } from "node:url";
52
+ /** Module URL whose resolution scope holds the CLI's own @flow-as-code/core. */
53
+ let fallbackParentURL;
54
+ /**
55
+ * @flow-as-code/core's package name, from PACKAGE_NAMES rather than a literal: the npm
56
+ * scope is written down in exactly one module (packages/core/src/package-names.ts)
57
+ * and this file runs on a thread that should not import it to find out.
58
+ */
59
+ let flowCorePackage;
60
+ export function initialize(data) {
61
+ fallbackParentURL = data?.fallbackParentURL;
62
+ flowCorePackage = data?.flowCorePackage;
63
+ }
64
+ function isFlowCore(specifier) {
65
+ if (flowCorePackage === undefined)
66
+ return false;
67
+ return specifier === flowCorePackage || specifier.startsWith(`${flowCorePackage}/`);
68
+ }
69
+ function isTypeScript(url) {
70
+ return url.startsWith("file:") && (url.endsWith(".ts") || url.endsWith(".tsx"));
71
+ }
72
+ /**
73
+ * True when no package.json exists in the file's directory or any directory
74
+ * above it, so nothing has declared a module type for it. This is the same walk
75
+ * node itself does to answer that question
76
+ * (https://nodejs.org/api/packages.html#determining-module-system); doing it
77
+ * here is what makes the answer the same whatever the resolver reports.
78
+ */
79
+ function nothingDeclaredATypeFor(url) {
80
+ let dir;
81
+ try {
82
+ dir = dirname(fileURLToPath(url));
83
+ }
84
+ catch {
85
+ return false;
86
+ }
87
+ for (;;) {
88
+ if (existsSync(join(dir, "package.json")))
89
+ return false;
90
+ const parent = dirname(dir);
91
+ if (parent === dir)
92
+ return true;
93
+ dir = parent;
94
+ }
95
+ }
96
+ export async function resolve(specifier, context, nextResolve) {
97
+ let resolution;
98
+ try {
99
+ resolution = await nextResolve(specifier, context);
100
+ }
101
+ catch (error) {
102
+ // Only a specifier that could not be found at all, and only
103
+ // @flow-as-code/core: an export map violation or a syntax error in the
104
+ // installed copy is the user's problem to see, not something to paper
105
+ // over with a second copy.
106
+ if (fallbackParentURL === undefined)
107
+ throw error;
108
+ if (!isFlowCore(specifier))
109
+ throw error;
110
+ if (error.code !== "ERR_MODULE_NOT_FOUND")
111
+ throw error;
112
+ resolution = await nextResolve(specifier, { ...context, parentURL: fallbackParentURL });
113
+ }
114
+ // A nullish `format` (Node 22 and later) or a defaulted "commonjs" (the
115
+ // answer Node 20 gave) on a TypeScript file with no package.json above it is
116
+ // the plain-folder case described above, and nothing else. Any other format
117
+ // is a decision somebody made and is left alone.
118
+ if (isTypeScript(resolution.url) &&
119
+ (resolution.format === null ||
120
+ resolution.format === undefined ||
121
+ resolution.format === "commonjs") &&
122
+ nothingDeclaredATypeFor(resolution.url)) {
123
+ return { ...resolution, format: "module" };
124
+ }
125
+ return resolution;
126
+ }
127
+ //# sourceMappingURL=synth-resolve-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synth-resolve-hook.js","sourceRoot":"","sources":["../src/synth-resolve-hook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export declare const SYNTH_ENVELOPE_SENTINEL = "__FLOW_CLI_SYNTH_ENVELOPE_V1__";
2
+ export interface SynthEnvelope {
3
+ flows?: {
4
+ name: string;
5
+ doc: unknown;
6
+ }[];
7
+ error?: {
8
+ message: string;
9
+ stack?: string;
10
+ };
11
+ }
12
+ //# sourceMappingURL=synth-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synth-runner.d.ts","sourceRoot":"","sources":["../src/synth-runner.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,uBAAuB,mCAAmC,CAAC;AAExE,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;IACzC,KAAK,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C"}
@@ -0,0 +1,145 @@
1
+ /*
2
+ * Copyright 2026 The flow-as-code Authors
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ // Child-process entry point for `flow-cli synth`. Never imported by the
6
+ // parent: it is spawned (see synth.ts) so that evaluating an untrusted
7
+ // builder file cannot touch the CLI process. Runs under tsx (--import), so
8
+ // this file works both compiled (dist/synth-runner.js) and straight from
9
+ // source in tests (src/synth-runner.ts).
10
+ //
11
+ // Contract with the parent: argv[2] is the absolute path of the builder file,
12
+ // argv[3] the path of the resolution hook module, and argv[4] the module URL
13
+ // that hook resolves @flow-as-code/core from when the builder file's own directory
14
+ // cannot. The runner prints exactly one envelope line to stdout, prefixed with
15
+ // SYNTH_ENVELOPE_SENTINEL, so user code writing to stdout during module
16
+ // evaluation cannot corrupt the channel. Everything else on stdout is ignored
17
+ // by the parent.
18
+ import { register } from "node:module";
19
+ import { pathToFileURL } from "node:url";
20
+ import { PACKAGE_NAMES, synth } from "@flow-as-code/core";
21
+ export const SYNTH_ENVELOPE_SENTINEL = "__FLOW_CLI_SYNTH_ENVELOPE_V1__";
22
+ /**
23
+ * Structural check instead of `instanceof Flow`: the builder file may resolve
24
+ * its own copy of @flow-as-code/core (dual-package or version skew), and a Flow from
25
+ * that copy is still a Flow for our purposes.
26
+ */
27
+ function isFlowLike(value) {
28
+ if (typeof value !== "object" || value === null)
29
+ return false;
30
+ const v = value;
31
+ return (typeof v.name === "string" &&
32
+ (v.kind === "flow" || v.kind === "module") &&
33
+ typeof v.all === "function" &&
34
+ typeof v.startId === "function");
35
+ }
36
+ /**
37
+ * Convention: every exported Flow instance, plus the result of every exported
38
+ * zero-argument function that returns one. Functions that throw when called
39
+ * (including classes, which throw without `new`) are skipped; a throw during
40
+ * module evaluation itself is a hard error and is reported by main().
41
+ */
42
+ function collectFlows(mod) {
43
+ const flows = [];
44
+ const seen = new Set();
45
+ const push = (f) => {
46
+ if (!seen.has(f)) {
47
+ seen.add(f);
48
+ flows.push(f);
49
+ }
50
+ };
51
+ for (const value of Object.values(mod)) {
52
+ if (isFlowLike(value)) {
53
+ push(value);
54
+ }
55
+ else if (typeof value === "function" && value.length === 0) {
56
+ let result;
57
+ try {
58
+ result = value();
59
+ }
60
+ catch {
61
+ continue; // not a flow factory (e.g. a class, or a helper that needs setup)
62
+ }
63
+ if (isFlowLike(result))
64
+ push(result);
65
+ }
66
+ }
67
+ return flows;
68
+ }
69
+ function emit(envelope) {
70
+ process.stdout.write("\n" + SYNTH_ENVELOPE_SENTINEL + JSON.stringify(envelope) + "\n");
71
+ }
72
+ /**
73
+ * Registers the @flow-as-code/core resolution fallback before the builder file is
74
+ * imported. See synth-resolve-hook.ts for what it does and why it is safe.
75
+ *
76
+ * `module.register` is the only registration API present on every Node this
77
+ * package supports (`registerHooks` landed in 22.15). Its deprecation warning
78
+ * on newer runtimes would otherwise reach the user inside a synth failure
79
+ * message, which is why it is silenced for the length of the call and no
80
+ * longer.
81
+ */
82
+ function registerResolveFallback(hookPath, fallbackParentURL) {
83
+ const { noDeprecation } = process;
84
+ process.noDeprecation = true;
85
+ try {
86
+ register(pathToFileURL(hookPath).href, {
87
+ parentURL: import.meta.url,
88
+ data: { fallbackParentURL, flowCorePackage: PACKAGE_NAMES.core },
89
+ });
90
+ }
91
+ finally {
92
+ process.noDeprecation = noDeprecation;
93
+ }
94
+ }
95
+ async function main() {
96
+ const sourcePath = process.argv[2];
97
+ if (sourcePath === undefined) {
98
+ emit({ error: { message: "synth-runner: missing source file argument" } });
99
+ process.exitCode = 1;
100
+ return;
101
+ }
102
+ const hookPath = process.argv[3];
103
+ const fallbackParentURL = process.argv[4];
104
+ if (hookPath !== undefined && fallbackParentURL !== undefined) {
105
+ registerResolveFallback(hookPath, fallbackParentURL);
106
+ }
107
+ let mod;
108
+ try {
109
+ mod = (await import(pathToFileURL(sourcePath).href));
110
+ }
111
+ catch (e) {
112
+ const err = e instanceof Error ? e : new Error(String(e));
113
+ emit({ error: { message: err.message, stack: err.stack } });
114
+ process.exitCode = 1;
115
+ return;
116
+ }
117
+ const flows = collectFlows(mod);
118
+ const byName = new Map();
119
+ for (const flow of flows) {
120
+ if (byName.has(flow.name)) {
121
+ emit({
122
+ error: {
123
+ message: `Two exported flows share the name "${flow.name}". Flow names must be unique per file because each becomes <name>.flowdoc.json.`,
124
+ },
125
+ });
126
+ process.exitCode = 1;
127
+ return;
128
+ }
129
+ byName.set(flow.name, flow);
130
+ }
131
+ try {
132
+ // meta is stamped by the parent (generator + sourceHash of the file it
133
+ // actually read), so the runner synths without one.
134
+ emit({
135
+ flows: flows.map((f) => ({ name: f.name, doc: synth(f, { includeMeta: false }) })),
136
+ });
137
+ }
138
+ catch (e) {
139
+ const err = e instanceof Error ? e : new Error(String(e));
140
+ emit({ error: { message: err.message, stack: err.stack } });
141
+ process.exitCode = 1;
142
+ }
143
+ }
144
+ void main();
145
+ //# sourceMappingURL=synth-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synth-runner.js","sourceRoot":"","sources":["../src/synth-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import type { FlowDoc } from "@flow-as-code/core";
2
+ /** Recorded in meta.generator of every FlowDoc this CLI writes. */
3
+ export declare const GENERATOR = "cli@0.0.1";
4
+ /** A synth failure with a message meant for the terminal. */
5
+ export declare class SynthError extends Error {
6
+ }
7
+ /**
8
+ * The frames of a thrown value's stack that point at the user's own code.
9
+ *
10
+ * A syntax error in a builder file used to print the actionable line and then
11
+ * ten frames of esbuild and node stream internals under it
12
+ * (`at failureErrorWithLog (.../node_modules/esbuild/lib/main.js:1752:15)`,
13
+ * `at Pipe.onStreamRead (node:internal/stream_base_commons:191:23)`), which buries
14
+ * the file, line and column that the message above already names. The studio's
15
+ * badge shows only the first line for the same reason; the terminal now matches
16
+ * that intent.
17
+ *
18
+ * Frames inside node_modules and node's own internals are dropped, and so are
19
+ * the header lines the stack repeats from the message that is printed above it.
20
+ * A frame in the builder file or anywhere else the user wrote survives, because
21
+ * that is the one a runtime error in a flow needs. There is no verbose flag or
22
+ * env var in this CLI to hide the full stack behind, so what is dropped here is
23
+ * dropped: the retained frames plus the message carry the location.
24
+ *
25
+ * `builderPath` is the file being synthesized. Its own frames are kept even
26
+ * when it sits under a directory named node_modules, which a vendored or
27
+ * linked builder file legitimately does: the node_modules rule is about
28
+ * dependency code, and the file the user asked to run is never that. Without
29
+ * the exemption such a file reports a throw with no line or column at all.
30
+ */
31
+ export declare function actionableFrames(stack: string | undefined, builderPath?: string): string[];
32
+ export interface SynthesizedFlow {
33
+ name: string;
34
+ doc: FlowDoc;
35
+ }
36
+ export interface SynthFileResult {
37
+ flows: SynthesizedFlow[];
38
+ /** `sha256:<hex>` of the builder file bytes, ready for meta.sourceHash. */
39
+ sourceHash: string;
40
+ }
41
+ export declare function sha256Hex(bytes: Buffer | string): string;
42
+ /**
43
+ * Evaluates the builder file in the sandboxed child and returns its flows.
44
+ * Throws SynthError with an actionable message on any failure.
45
+ */
46
+ export declare function synthFile(sourcePath: string): Promise<SynthFileResult>;
47
+ /** Serializes a doc with the meta this CLI stamps. Byte-stable. */
48
+ export declare function serializeWithMeta(doc: FlowDoc, sourceHash: string): string;
49
+ /**
50
+ * The `flow-cli synth` command body: synth every flow the file exports and
51
+ * write <flow.name>.flowdoc.json into outDir (default: the source file's
52
+ * directory). Returns the written paths in write order.
53
+ */
54
+ export declare function synthToFiles(sourcePath: string, outDir?: string): Promise<string[]>;
55
+ //# sourceMappingURL=synth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synth.d.ts","sourceRoot":"","sources":["../src/synth.ts"],"names":[],"mappings":"AAmDA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAGlD,mEAAmE;AACnE,eAAO,MAAM,SAAS,cAAc,CAAC;AAIrC,6DAA6D;AAC7D,qBAAa,UAAW,SAAQ,KAAK;CAAG;AAoDxC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CA2B1F;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,2EAA2E;IAC3E,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAExD;AAiFD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAoF5E;AAED,mEAAmE;AACnE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAoBzF"}