@chestnutlabs/gcode-parser 0.17.0 → 0.19.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.
- package/dist/parse.d.ts +25 -0
- package/dist/parse.d.ts.map +1 -1
- package/dist/parse.js +88 -2
- package/dist/rs274-flow.d.ts +69 -0
- package/dist/rs274-flow.d.ts.map +1 -0
- package/dist/rs274-flow.js +702 -0
- package/dist/rs274.d.ts +107 -0
- package/dist/rs274.d.ts.map +1 -0
- package/dist/rs274.js +723 -0
- package/dist/streaming.d.ts.map +1 -1
- package/dist/streaming.js +5 -0
- package/package.json +5 -5
package/dist/parse.d.ts
CHANGED
|
@@ -34,6 +34,19 @@ export interface ParseLimits {
|
|
|
34
34
|
maxBufferBytes: number;
|
|
35
35
|
maxLineLength: number;
|
|
36
36
|
maxWarnings: number;
|
|
37
|
+
/**
|
|
38
|
+
* Total loop work across an RS274NGC O-word program (DD-017 §4.5, Phase 2). Charged per loop pass and
|
|
39
|
+
* per statement executed inside a loop body; exceeding it stops the program with a partial IR and a
|
|
40
|
+
* `rs274-iteration-limit` disclosure, so a hostile `o while [1]` wastes only bounded CPU. Irrelevant to
|
|
41
|
+
* FDM / non-parametric input, which never enters the interpreter.
|
|
42
|
+
*/
|
|
43
|
+
maxProgramIterations: number;
|
|
44
|
+
/**
|
|
45
|
+
* Subroutine call-recursion depth for an RS274NGC O-word program (DD-017 §4.5, Phase 3). A `call` that
|
|
46
|
+
* would exceed this depth is disclosed (`rs274-call-depth`) and skipped, so unbounded recursion cannot
|
|
47
|
+
* exhaust the stack. Irrelevant to FDM / non-parametric input.
|
|
48
|
+
*/
|
|
49
|
+
maxCallDepth: number;
|
|
37
50
|
}
|
|
38
51
|
export declare const DEFAULT_LIMITS: ParseLimits;
|
|
39
52
|
/**
|
|
@@ -144,6 +157,18 @@ export interface Engine {
|
|
|
144
157
|
processLine(rawLine: string, offset: number): void;
|
|
145
158
|
stopped(): boolean;
|
|
146
159
|
markInputTooBig(): void;
|
|
160
|
+
/**
|
|
161
|
+
* Interpret the buffered `text` as an RS274NGC O-word program (DD-017 Phase 2). Called by the
|
|
162
|
+
* in-memory drivers INSTEAD of the forward-only line loop when `programUsesOWords(text)` is true;
|
|
163
|
+
* the interpreter re-feeds every plain line through `processLine`, so geometry stays on one path.
|
|
164
|
+
*/
|
|
165
|
+
runOWordFlow(): void;
|
|
166
|
+
/**
|
|
167
|
+
* Streaming only: record that an O-word control line was seen but NOT interpreted (control flow needs a
|
|
168
|
+
* fully-buffered program — DD-017 §4.1). Discloses once and marks the parametric capability degraded;
|
|
169
|
+
* the line still runs linearly (the honest pre-Phase-2 behaviour), never silently as if flow had run.
|
|
170
|
+
*/
|
|
171
|
+
noteUninterpretedOWord(srcByte: number): void;
|
|
147
172
|
/** Streaming driver: record the true source byte count as it becomes known. */
|
|
148
173
|
setSourceBytes(bytes: number): void;
|
|
149
174
|
/**
|
package/dist/parse.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,EASL,KAAK,UAAU,EAIhB,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}
|
package/dist/parse.js
CHANGED
|
@@ -29,12 +29,16 @@
|
|
|
29
29
|
*/
|
|
30
30
|
import { IR_SCHEMA_VERSION, MoveKind, buildSourceIndex, classifyModelBounds, computeSegmentBounds, emptyBounds } from '@chestnutlabs/toolpath-core';
|
|
31
31
|
import { BudgetExceededError, SegmentWriter } from './growable.js';
|
|
32
|
+
import { Rs274Context, lineUsesParametric } from './rs274.js';
|
|
33
|
+
import { RS274_FLOW_WARN, interpretOWordProgram, programUsesOWords } from './rs274-flow.js';
|
|
32
34
|
export const DEFAULT_LIMITS = {
|
|
33
35
|
maxInputBytes: 512 * 1024 * 1024,
|
|
34
36
|
maxSegments: 20_000_000,
|
|
35
37
|
maxBufferBytes: 1536 * 1024 * 1024,
|
|
36
38
|
maxLineLength: 64 * 1024,
|
|
37
|
-
maxWarnings: 10_000
|
|
39
|
+
maxWarnings: 10_000,
|
|
40
|
+
maxProgramIterations: 1_000_000,
|
|
41
|
+
maxCallDepth: 50
|
|
38
42
|
};
|
|
39
43
|
const LAYER_TOLERANCE = 0.05;
|
|
40
44
|
const UNRESOLVED_LAYER = 0xffffffff;
|
|
@@ -186,6 +190,10 @@ export function createEngine(input, opts) {
|
|
|
186
190
|
let cannedInitialZ = 0; // Z when the cycle activated — the G98 retract plane
|
|
187
191
|
let cannedRetractInitial = true; // G98 (retract to initial Z) vs G99 (retract to R); modal, default G98
|
|
188
192
|
let cannedCyclesSeen = false; // any G81/G82/G83 expanded → cannedCycles capability 'known'
|
|
193
|
+
// RS274NGC parametric programs (DD-017 Phase 1, #189 phase 7). The store + expression evaluator resolve
|
|
194
|
+
// `#params`/`[expr]` on any line that uses them; non-parametric lines never touch it (byte-identical).
|
|
195
|
+
// The system-parameter allow-list (#5420–#5422 = current position) reads live engine position.
|
|
196
|
+
const rs274 = new Rs274Context(warn, () => ({ x: sx, y: sy, z: sz }));
|
|
189
197
|
// Per-axis position certainty (DD-010 D4 amendment, #158). A G31 probe endpoint is reached at
|
|
190
198
|
// RUNTIME (workpiece contact), not the commanded value, so it marks the probed axes uncertain. A
|
|
191
199
|
// following G92 then RESYNCS the logical frame at the datum (rather than datum-shifting a stale
|
|
@@ -573,7 +581,22 @@ export function createEngine(input, opts) {
|
|
|
573
581
|
if (ci !== -1)
|
|
574
582
|
onComment(rawLine.slice(ci + 1), offset);
|
|
575
583
|
}
|
|
576
|
-
|
|
584
|
+
// RS274NGC parametric programs (DD-017 Phase 1): a line using `#`/`[` is resolved by the parameter +
|
|
585
|
+
// expression interpreter; a `#n = <expr>` assignment executes and the line ends there. Every other
|
|
586
|
+
// line (all FDM, all simple CNC) takes the untouched lexer below — byte-identical.
|
|
587
|
+
let cmd;
|
|
588
|
+
// Hot-path gate: a cheap `#`/`[` scan of the RAW line — no allocation. Every FDM line fails this and
|
|
589
|
+
// takes the untouched lexer (byte-identical). A `#`/`[` that turns out to be only inside a comment
|
|
590
|
+
// routes through the resolver, which strips comments and returns 'plain' → the normal lexer.
|
|
591
|
+
if (lineUsesParametric(rawLine)) {
|
|
592
|
+
const r = rs274.lexLine(rawLine, offset);
|
|
593
|
+
if (r.kind === 'assign' || r.kind === 'empty')
|
|
594
|
+
return; // assignment applied / nothing to do
|
|
595
|
+
cmd = r.kind === 'cmd' ? { codes: r.codes, params: r.params } : lexLine(rawLine); // 'plain' → normal
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
cmd = lexLine(rawLine);
|
|
599
|
+
}
|
|
577
600
|
// Skip only genuinely empty lines. A line with no lexable words but real content (a dialect
|
|
578
601
|
// extended command like `EXCLUDE_OBJECT_START NAME=cube`, a macro) must NOT be dropped — the
|
|
579
602
|
// observer below still forwards its raw line. The body split runs only when there are no words.
|
|
@@ -838,6 +861,46 @@ export function createEngine(input, opts) {
|
|
|
838
861
|
truncatedAtByte = offset;
|
|
839
862
|
}
|
|
840
863
|
};
|
|
864
|
+
// RS274NGC O-word control flow (DD-017 Phase 2). Engaged only when the buffered program actually
|
|
865
|
+
// contains a control line; it buffers the lines with their byte offsets and hands them to the tree
|
|
866
|
+
// interpreter, which re-feeds each plain line through `processLine` (one geometry path) and evaluates
|
|
867
|
+
// conditions/counts against the SAME parameter store. `used`/`degraded` tier the capability.
|
|
868
|
+
const runOWordFlow = () => {
|
|
869
|
+
rs274.used = true;
|
|
870
|
+
const flowLines = [];
|
|
871
|
+
const len = text.length;
|
|
872
|
+
let offset = 0;
|
|
873
|
+
while (offset < len) {
|
|
874
|
+
let nl = text.indexOf('\n', offset);
|
|
875
|
+
if (nl === -1)
|
|
876
|
+
nl = len;
|
|
877
|
+
flowLines.push({ text: text.slice(offset, nl), offset });
|
|
878
|
+
offset = nl + 1;
|
|
879
|
+
}
|
|
880
|
+
const { degraded } = interpretOWordProgram(flowLines, {
|
|
881
|
+
processLine,
|
|
882
|
+
stopped: () => stopReason !== undefined,
|
|
883
|
+
evalExpression: (t, b) => rs274.evalExpression(t, b),
|
|
884
|
+
pushScope: (args) => rs274.pushScope(args),
|
|
885
|
+
popScope: () => rs274.popScope(),
|
|
886
|
+
warn,
|
|
887
|
+
maxProgramIterations: limits.maxProgramIterations,
|
|
888
|
+
maxCallDepth: limits.maxCallDepth
|
|
889
|
+
});
|
|
890
|
+
if (degraded)
|
|
891
|
+
rs274.degraded = true;
|
|
892
|
+
};
|
|
893
|
+
// Streaming can't interpret control flow from a partial stream (a loop needs its whole body — DD-017
|
|
894
|
+
// §4.1); disclose once and let the program run linearly (control lines are inert). Honest, bounded.
|
|
895
|
+
let streamingOWordWarned = false;
|
|
896
|
+
const noteUninterpretedOWord = (srcByte) => {
|
|
897
|
+
if (streamingOWordWarned)
|
|
898
|
+
return;
|
|
899
|
+
streamingOWordWarned = true;
|
|
900
|
+
rs274.used = true;
|
|
901
|
+
rs274.degraded = true;
|
|
902
|
+
warn(RS274_FLOW_WARN.streamingUnsupported, 'O-word control flow is only interpreted for fully-buffered input; this streamed program ran linearly (control flow not executed).', srcByte);
|
|
903
|
+
};
|
|
841
904
|
const finish = (cancelledAtByte) => {
|
|
842
905
|
if (stopReason !== undefined && truncatedAtByte === undefined) {
|
|
843
906
|
truncatedAtByte = currentSrcByte;
|
|
@@ -891,6 +954,11 @@ export function createEngine(input, opts) {
|
|
|
891
954
|
// Canned drilling cycles expanded to geometry (DD-012 phase 2, #189). 'known' once a G81/G82/G83
|
|
892
955
|
// was seen (holes are real segments), else 'unavailable' (no cycles / FDM).
|
|
893
956
|
cannedCycles: cannedCyclesSeen ? 'known' : 'unavailable',
|
|
957
|
+
// RS274NGC parametric programs (DD-017, #189 phase 7). 'known' once a `#param`/`[expr]`/O-word was
|
|
958
|
+
// executed deterministically within limits (the interpreter computes geometry — it does not infer);
|
|
959
|
+
// 'approximated' when Phase 2 flow was degraded (a hit iteration cap, an unbalanced/unsupported
|
|
960
|
+
// O-word, or a malformed condition — always disclosed); 'unavailable' for non-parametric input.
|
|
961
|
+
parametricProgram: rs274.parametricConfidence(),
|
|
894
962
|
// Motion-model modes (DD-010 E10 phase 1). 'known' when the governing command was seen
|
|
895
963
|
// (M82/M83, or a firmware-known G90/G91 for E); 'inferred' when defaulted (absolute).
|
|
896
964
|
extrusionMode: eModeExplicit !== null || (extruderFollowsPositioning && positioningSeen) ? 'known' : 'inferred',
|
|
@@ -1012,6 +1080,7 @@ export function createEngine(input, opts) {
|
|
|
1012
1080
|
seamMoves: 'unavailable',
|
|
1013
1081
|
cutMoves: 'unavailable', // non-extrusion classification resolves on the final IR (DD-012)
|
|
1014
1082
|
cannedCycles: 'unavailable', // canned-cycle expansion resolves on the final IR (DD-012)
|
|
1083
|
+
parametricProgram: 'unavailable', // parametric resolution resolves on the final IR (DD-017)
|
|
1015
1084
|
extrusionMode: 'inferred', // motion modes resolve fully on the final IR (E10)
|
|
1016
1085
|
positioningMode: 'inferred',
|
|
1017
1086
|
arcPlanes: 'inferred',
|
|
@@ -1037,6 +1106,8 @@ export function createEngine(input, opts) {
|
|
|
1037
1106
|
limits,
|
|
1038
1107
|
processLine,
|
|
1039
1108
|
stopped: () => stopReason !== undefined,
|
|
1109
|
+
runOWordFlow,
|
|
1110
|
+
noteUninterpretedOWord,
|
|
1040
1111
|
snapshot,
|
|
1041
1112
|
markInputTooBig: () => {
|
|
1042
1113
|
stopReason = {
|
|
@@ -1062,6 +1133,13 @@ export function parseGcodeToIR(input, opts = {}) {
|
|
|
1062
1133
|
return engine.finish();
|
|
1063
1134
|
}
|
|
1064
1135
|
const text = engine.text;
|
|
1136
|
+
// RS274NGC O-word program (DD-017 Phase 2): interpret with control flow instead of the forward-only
|
|
1137
|
+
// loop. The cheap detection scan fails for every FDM / non-parametric file, which takes the untouched
|
|
1138
|
+
// loop below (byte-identical).
|
|
1139
|
+
if (programUsesOWords(text)) {
|
|
1140
|
+
engine.runOWordFlow();
|
|
1141
|
+
return engine.finish();
|
|
1142
|
+
}
|
|
1065
1143
|
const len = text.length;
|
|
1066
1144
|
let offset = 0;
|
|
1067
1145
|
while (offset < len && !engine.stopped()) {
|
|
@@ -1101,6 +1179,14 @@ export async function parseGcodeToIRAsync(input, opts = {}, hooks = {}) {
|
|
|
1101
1179
|
const yieldEvery = hooks.yieldIntervalMs ?? 50;
|
|
1102
1180
|
const partial = makePartialEmitter(engine, hooks);
|
|
1103
1181
|
const text = engine.text;
|
|
1182
|
+
// RS274NGC O-word program (DD-017 Phase 2): a bounded synchronous interpretation section (loops are
|
|
1183
|
+
// capped by `maxProgramIterations`, and these programs are small — hand/CAM-written). Non-parametric
|
|
1184
|
+
// input takes the cooperative line loop below unchanged.
|
|
1185
|
+
if (programUsesOWords(text)) {
|
|
1186
|
+
engine.runOWordFlow();
|
|
1187
|
+
hooks.onProgress?.(text.length, byteLength, 0);
|
|
1188
|
+
return { ...engine.finish(), cancelled: false };
|
|
1189
|
+
}
|
|
1104
1190
|
const len = text.length;
|
|
1105
1191
|
let offset = 0;
|
|
1106
1192
|
let sliceStart = Date.now();
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** Warning codes surfaced to the IR by the flow interpreter (DD-017 §4.6). */
|
|
2
|
+
export declare const RS274_FLOW_WARN: {
|
|
3
|
+
readonly iterationLimit: "rs274-iteration-limit";
|
|
4
|
+
readonly unbalancedOword: "rs274-unbalanced-oword";
|
|
5
|
+
readonly unsupportedOword: "rs274-unsupported-oword";
|
|
6
|
+
readonly controlNesting: "rs274-control-nesting";
|
|
7
|
+
readonly misplacedControl: "rs274-misplaced-control";
|
|
8
|
+
readonly streamingUnsupported: "rs274-streaming-flow-unsupported";
|
|
9
|
+
readonly callDepth: "rs274-call-depth";
|
|
10
|
+
readonly unknownSub: "rs274-unknown-sub";
|
|
11
|
+
readonly duplicateSub: "rs274-duplicate-sub";
|
|
12
|
+
};
|
|
13
|
+
/** The recognized O-word keywords. An `o<id>` line with any OTHER trailing word is NOT a control line
|
|
14
|
+
* (e.g. a stray `o5 g1`) — it falls through to the normal lexer, so detection never hijacks plain code. */
|
|
15
|
+
export declare const KNOWN_OWORD_KEYWORDS: ReadonlySet<string>;
|
|
16
|
+
export type WarnFn = (code: string, message: string, srcByte?: number) => void;
|
|
17
|
+
/** A classified O-word control line: its keyword, its (opaque, normalized) id token, and any trailing
|
|
18
|
+
* expression (an `if`/`while` condition or a `repeat` count). */
|
|
19
|
+
export interface OwInfo {
|
|
20
|
+
keyword: string;
|
|
21
|
+
/** The id token verbatim-normalized: `100`, `<name>`, or a literal `[expr]` — matched, never evaluated. */
|
|
22
|
+
id: string;
|
|
23
|
+
expr: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Classify one raw line as an O-word control line, or `null` when it is not one. `null` covers every
|
|
27
|
+
* plain line (all FDM, all geometry/param lines) AND an `o<id>` whose trailing word is not a recognized
|
|
28
|
+
* keyword (e.g. `o5 g1 x10`) — those fall through to the normal lexer, so classification never hijacks
|
|
29
|
+
* ordinary code. The id is read as an opaque token (numeric / `<name>` / balanced `[expr]`) and is used
|
|
30
|
+
* only to pair an opener with its closer — it is deliberately NOT evaluated here.
|
|
31
|
+
*/
|
|
32
|
+
export declare function classifyOWord(rawLine: string): OwInfo | null;
|
|
33
|
+
/** One buffered source line with its byte offset (for `srcByte` on any geometry it emits). */
|
|
34
|
+
export interface FlowLine {
|
|
35
|
+
text: string;
|
|
36
|
+
offset: number;
|
|
37
|
+
}
|
|
38
|
+
/** The engine surface the interpreter drives — supplied by `createEngine` with its closures. */
|
|
39
|
+
export interface FlowHost {
|
|
40
|
+
/** Execute one plain (non-control) source line through the normal engine path. */
|
|
41
|
+
processLine(text: string, offset: number): void;
|
|
42
|
+
/** True once a geometry limit (segments/buffer) has stopped emission — the interpreter then halts. */
|
|
43
|
+
stopped(): boolean;
|
|
44
|
+
/** Evaluate a control expression against the shared parameter store; `null` = malformed/non-finite. */
|
|
45
|
+
evalExpression(text: string, srcByte: number): number | null;
|
|
46
|
+
/** Push a subroutine call-frame scope with `args` bound to `#1`..`#30` (Phase 3). */
|
|
47
|
+
pushScope(args: readonly number[]): void;
|
|
48
|
+
/** Pop the current call-frame scope (Phase 3). */
|
|
49
|
+
popScope(): void;
|
|
50
|
+
warn: WarnFn;
|
|
51
|
+
maxProgramIterations: number;
|
|
52
|
+
/** Subroutine recursion depth cap (Phase 3); exceeding it discloses and skips the call. */
|
|
53
|
+
maxCallDepth: number;
|
|
54
|
+
}
|
|
55
|
+
export interface FlowOutcome {
|
|
56
|
+
/** True when execution was degraded (limit hit, unbalanced/unsupported O-word, malformed condition). */
|
|
57
|
+
degraded: boolean;
|
|
58
|
+
}
|
|
59
|
+
/** True once the built tree used any recognized control construct (drives the capability). */
|
|
60
|
+
export declare function programUsesOWords(text: string): boolean;
|
|
61
|
+
/** True when a single line is a recognized O-word control line (used by the streaming disclosure). */
|
|
62
|
+
export declare function isOWordControlLine(line: string): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Interpret a fully-buffered O-word program. Builds the block tree (tolerant of unbalanced O-words —
|
|
65
|
+
* disclosed, never thrown out), then executes it with bounded iteration. Returns whether execution was
|
|
66
|
+
* degraded so the caller can tier the `parametricProgram` capability.
|
|
67
|
+
*/
|
|
68
|
+
export declare function interpretOWordProgram(lines: readonly FlowLine[], host: FlowHost): FlowOutcome;
|
|
69
|
+
//# sourceMappingURL=rs274-flow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rs274-flow.d.ts","sourceRoot":"","sources":["../src/rs274-flow.ts"],"names":[],"mappings":"AAgCA,8EAA8E;AAC9E,eAAO,MAAM,eAAe;;;;;;;;;;CAUlB,CAAC;AAeX;4GAC4G;AAC5G,eAAO,MAAM,oBAAoB,EAAE,WAAW,CAAC,MAAM,CAgBnD,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAE/E;kEACkE;AAClE,MAAM,WAAW,MAAM;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,2GAA2G;IAC3G,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkD5D;AAED,8FAA8F;AAC9F,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,gGAAgG;AAChG,MAAM,WAAW,QAAQ;IACvB,kFAAkF;IAClF,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAChD,sGAAsG;IACtG,OAAO,IAAI,OAAO,CAAC;IACnB,uGAAuG;IACvG,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC7D,qFAAqF;IACrF,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IACzC,kDAAkD;IAClD,QAAQ,IAAI,IAAI,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB,EAAE,MAAM,CAAC;IAC7B,2FAA2F;IAC3F,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,wGAAwG;IACxG,QAAQ,EAAE,OAAO,CAAC;CACnB;AAoCD,8FAA8F;AAC9F,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAUvD;AAED,sGAAsG;AACtG,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AA2FD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,GAAG,WAAW,CAmb7F"}
|