@fluxpointstudios/orynq-sdk-flight-recorder 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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/dist/crypto/compression.d.ts +37 -0
  3. package/dist/crypto/compression.d.ts.map +1 -0
  4. package/dist/crypto/compression.js +84 -0
  5. package/dist/crypto/compression.js.map +1 -0
  6. package/dist/crypto/encryption.d.ts +44 -0
  7. package/dist/crypto/encryption.d.ts.map +1 -0
  8. package/dist/crypto/encryption.js +129 -0
  9. package/dist/crypto/encryption.js.map +1 -0
  10. package/dist/crypto/hashing.d.ts +63 -0
  11. package/dist/crypto/hashing.d.ts.map +1 -0
  12. package/dist/crypto/hashing.js +182 -0
  13. package/dist/crypto/hashing.js.map +1 -0
  14. package/dist/crypto/index.d.ts +4 -0
  15. package/dist/crypto/index.d.ts.map +1 -0
  16. package/dist/crypto/index.js +4 -0
  17. package/dist/crypto/index.js.map +1 -0
  18. package/dist/index.d.ts +48 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +54 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/integration/index.d.ts +2 -0
  23. package/dist/integration/index.d.ts.map +1 -0
  24. package/dist/integration/index.js +2 -0
  25. package/dist/integration/index.js.map +1 -0
  26. package/dist/integration/openclaw-adapter.d.ts +64 -0
  27. package/dist/integration/openclaw-adapter.d.ts.map +1 -0
  28. package/dist/integration/openclaw-adapter.js +137 -0
  29. package/dist/integration/openclaw-adapter.js.map +1 -0
  30. package/dist/manifest/index.d.ts +2 -0
  31. package/dist/manifest/index.d.ts.map +1 -0
  32. package/dist/manifest/index.js +2 -0
  33. package/dist/manifest/index.js.map +1 -0
  34. package/dist/manifest/manifest-builder.d.ts +72 -0
  35. package/dist/manifest/manifest-builder.d.ts.map +1 -0
  36. package/dist/manifest/manifest-builder.js +84 -0
  37. package/dist/manifest/manifest-builder.js.map +1 -0
  38. package/dist/recorder/chunk-manager.d.ts +56 -0
  39. package/dist/recorder/chunk-manager.d.ts.map +1 -0
  40. package/dist/recorder/chunk-manager.js +172 -0
  41. package/dist/recorder/chunk-manager.js.map +1 -0
  42. package/dist/recorder/event-buffer.d.ts +61 -0
  43. package/dist/recorder/event-buffer.d.ts.map +1 -0
  44. package/dist/recorder/event-buffer.js +101 -0
  45. package/dist/recorder/event-buffer.js.map +1 -0
  46. package/dist/recorder/index.d.ts +4 -0
  47. package/dist/recorder/index.d.ts.map +1 -0
  48. package/dist/recorder/index.js +4 -0
  49. package/dist/recorder/index.js.map +1 -0
  50. package/dist/recorder/stream-recorder.d.ts +66 -0
  51. package/dist/recorder/stream-recorder.d.ts.map +1 -0
  52. package/dist/recorder/stream-recorder.js +329 -0
  53. package/dist/recorder/stream-recorder.js.map +1 -0
  54. package/dist/storage/index.d.ts +2 -0
  55. package/dist/storage/index.d.ts.map +1 -0
  56. package/dist/storage/index.js +2 -0
  57. package/dist/storage/index.js.map +1 -0
  58. package/dist/storage/local-adapter.d.ts +65 -0
  59. package/dist/storage/local-adapter.d.ts.map +1 -0
  60. package/dist/storage/local-adapter.js +152 -0
  61. package/dist/storage/local-adapter.js.map +1 -0
  62. package/dist/types.d.ts +284 -0
  63. package/dist/types.d.ts.map +1 -0
  64. package/dist/types.js +28 -0
  65. package/dist/types.js.map +1 -0
  66. package/package.json +43 -0
  67. package/src/__tests__/flight-recorder.test.ts +211 -0
  68. package/src/crypto/compression.ts +105 -0
  69. package/src/crypto/encryption.ts +210 -0
  70. package/src/crypto/hashing.ts +225 -0
  71. package/src/crypto/index.ts +3 -0
  72. package/src/index.ts +96 -0
  73. package/src/integration/index.ts +1 -0
  74. package/src/integration/openclaw-adapter.ts +206 -0
  75. package/src/manifest/index.ts +1 -0
  76. package/src/manifest/manifest-builder.ts +152 -0
  77. package/src/recorder/chunk-manager.ts +224 -0
  78. package/src/recorder/event-buffer.ts +124 -0
  79. package/src/recorder/index.ts +3 -0
  80. package/src/recorder/stream-recorder.ts +427 -0
  81. package/src/storage/index.ts +1 -0
  82. package/src/storage/local-adapter.ts +181 -0
  83. package/src/types.ts +347 -0
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Chunk manager for the flight recorder.
3
+ * Handles chunk creation, compression, encryption, and storage.
4
+ */
5
+ import { generateKey, encrypt } from "../crypto/encryption.js";
6
+ import { compress } from "../crypto/compression.js";
7
+ import { sha256, merkleLeaf } from "../crypto/hashing.js";
8
+ export class ChunkManager {
9
+ storage;
10
+ encryptionConfig;
11
+ compressionType;
12
+ chunks = [];
13
+ leafHashes = [];
14
+ chunkIndex = 0;
15
+ encryptionKey = null;
16
+ constructor(storage, encryptionConfig, compressionType = "gzip") {
17
+ this.storage = storage;
18
+ this.encryptionConfig = encryptionConfig;
19
+ this.compressionType = compressionType;
20
+ }
21
+ /**
22
+ * Initialize encryption key for the session.
23
+ */
24
+ async initializeKey() {
25
+ this.encryptionKey = await generateKey(this.encryptionConfig.algorithm);
26
+ }
27
+ /**
28
+ * Get the current encryption key ID.
29
+ */
30
+ getKeyId() {
31
+ return this.encryptionKey?.keyId ?? null;
32
+ }
33
+ /**
34
+ * Create a chunk from buffered events.
35
+ */
36
+ async createChunk(events, eventRange, spanIds) {
37
+ if (!this.encryptionKey) {
38
+ throw new Error("Encryption key not initialized. Call initializeKey() first.");
39
+ }
40
+ // Serialize events to JSONL
41
+ const lines = events.map((e) => JSON.stringify(e.event));
42
+ const jsonl = lines.join("\n");
43
+ const rawData = new TextEncoder().encode(jsonl);
44
+ // Compress
45
+ const compressed = await compress(rawData, this.compressionType);
46
+ // Encrypt
47
+ const chunkMeta = {
48
+ index: this.chunkIndex,
49
+ eventRange,
50
+ spanIds,
51
+ createdAt: new Date().toISOString(),
52
+ };
53
+ const additionalData = new TextEncoder().encode(JSON.stringify(chunkMeta));
54
+ const encrypted = await encrypt(compressed.data, this.encryptionKey, additionalData);
55
+ // Create chunk data structure
56
+ const chunkData = {
57
+ ciphertext: encrypted.ciphertext,
58
+ nonce: encrypted.nonce,
59
+ tag: encrypted.tag,
60
+ meta: chunkMeta,
61
+ };
62
+ // Compute content hash of encrypted data
63
+ const encryptedPayload = new Uint8Array(encrypted.ciphertext.length + encrypted.nonce.length + encrypted.tag.length);
64
+ encryptedPayload.set(encrypted.ciphertext, 0);
65
+ encryptedPayload.set(encrypted.nonce, encrypted.ciphertext.length);
66
+ encryptedPayload.set(encrypted.tag, encrypted.ciphertext.length + encrypted.nonce.length);
67
+ const chunkHash = await sha256(encryptedPayload, "encryptedChunk");
68
+ const chunkId = `chunk-${this.chunkIndex.toString().padStart(6, "0")}-${chunkHash.slice(0, 16)}`;
69
+ // Store chunk
70
+ const storagePayload = this.serializeChunkForStorage(chunkData);
71
+ const storageRef = await this.storage.store(storagePayload);
72
+ // Create chunk reference
73
+ const chunkRef = {
74
+ id: chunkId,
75
+ hash: chunkHash,
76
+ size: storagePayload.length,
77
+ storageUri: storageRef.uri,
78
+ encryptionKeyId: this.encryptionKey.keyId,
79
+ compression: this.compressionType === "gzip" ? "gzip" : "none",
80
+ };
81
+ // Compute Merkle leaf hash
82
+ const leafHash = await merkleLeaf(encryptedPayload);
83
+ // Track chunk
84
+ this.chunks.push(chunkRef);
85
+ this.leafHashes.push(leafHash);
86
+ this.chunkIndex++;
87
+ return {
88
+ chunkRef,
89
+ chunkData,
90
+ leafHash,
91
+ };
92
+ }
93
+ /**
94
+ * Get all chunk references.
95
+ */
96
+ getChunks() {
97
+ return [...this.chunks];
98
+ }
99
+ /**
100
+ * Get all Merkle leaf hashes.
101
+ */
102
+ getLeafHashes() {
103
+ return [...this.leafHashes];
104
+ }
105
+ /**
106
+ * Get chunk count.
107
+ */
108
+ getChunkCount() {
109
+ return this.chunks.length;
110
+ }
111
+ /**
112
+ * Serialize chunk data for storage.
113
+ * Format: [4-byte meta length][meta JSON][nonce][tag][ciphertext]
114
+ */
115
+ serializeChunkForStorage(chunk) {
116
+ const metaJson = JSON.stringify(chunk.meta);
117
+ const metaBytes = new TextEncoder().encode(metaJson);
118
+ const metaLength = new Uint32Array([metaBytes.length]);
119
+ const metaLengthBytes = new Uint8Array(metaLength.buffer);
120
+ const totalLength = 4 + // meta length
121
+ metaBytes.length +
122
+ chunk.nonce.length +
123
+ chunk.tag.length +
124
+ chunk.ciphertext.length;
125
+ const result = new Uint8Array(totalLength);
126
+ let offset = 0;
127
+ result.set(metaLengthBytes, offset);
128
+ offset += 4;
129
+ result.set(metaBytes, offset);
130
+ offset += metaBytes.length;
131
+ result.set(chunk.nonce, offset);
132
+ offset += chunk.nonce.length;
133
+ result.set(chunk.tag, offset);
134
+ offset += chunk.tag.length;
135
+ result.set(chunk.ciphertext, offset);
136
+ return result;
137
+ }
138
+ /**
139
+ * Deserialize chunk data from storage.
140
+ */
141
+ static deserializeChunkFromStorage(data) {
142
+ let offset = 0;
143
+ // Read meta length
144
+ const metaLengthBytes = data.slice(offset, offset + 4);
145
+ const metaLengthArr = new Uint32Array(metaLengthBytes.buffer);
146
+ const metaLength = metaLengthArr[0];
147
+ if (metaLength === undefined) {
148
+ throw new Error("Invalid chunk data: missing meta length");
149
+ }
150
+ offset += 4;
151
+ // Read meta
152
+ const metaBytes = data.slice(offset, offset + metaLength);
153
+ const metaJson = new TextDecoder().decode(metaBytes);
154
+ const meta = JSON.parse(metaJson);
155
+ offset += metaLength;
156
+ // Read nonce (12 bytes for AES-GCM)
157
+ const nonce = data.slice(offset, offset + 12);
158
+ offset += 12;
159
+ // Read tag (16 bytes)
160
+ const tag = data.slice(offset, offset + 16);
161
+ offset += 16;
162
+ // Read ciphertext (rest)
163
+ const ciphertext = data.slice(offset);
164
+ return {
165
+ ciphertext,
166
+ nonce,
167
+ tag,
168
+ meta,
169
+ };
170
+ }
171
+ }
172
+ //# sourceMappingURL=chunk-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-manager.js","sourceRoot":"","sources":["../../src/recorder/chunk-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * In-memory event buffer for the flight recorder.
3
+ * Buffers events until chunk threshold is reached.
4
+ */
5
+ import type { RecorderEvent } from "../types.js";
6
+ export interface BufferedEvent {
7
+ event: RecorderEvent;
8
+ serialized: Uint8Array;
9
+ hash: string;
10
+ }
11
+ export interface BufferStats {
12
+ eventCount: number;
13
+ byteSize: number;
14
+ oldestEventTs: string | null;
15
+ newestEventTs: string | null;
16
+ }
17
+ export declare class EventBuffer {
18
+ private readonly maxSizeBytes;
19
+ private events;
20
+ private byteSize;
21
+ private seq;
22
+ constructor(maxSizeBytes: number);
23
+ /**
24
+ * Add an event to the buffer.
25
+ * Returns true if buffer should be flushed (threshold reached).
26
+ */
27
+ add(event: Omit<RecorderEvent, "seq">): Promise<boolean>;
28
+ /**
29
+ * Get all buffered events and clear the buffer.
30
+ */
31
+ flush(): BufferedEvent[];
32
+ /**
33
+ * Peek at buffered events without clearing.
34
+ */
35
+ peek(): BufferedEvent[];
36
+ /**
37
+ * Get buffer statistics.
38
+ */
39
+ getStats(): BufferStats;
40
+ /**
41
+ * Check if buffer is empty.
42
+ */
43
+ isEmpty(): boolean;
44
+ /**
45
+ * Get current sequence number.
46
+ */
47
+ getSeq(): number;
48
+ /**
49
+ * Get event range in buffer.
50
+ */
51
+ getEventRange(): [number, number] | null;
52
+ /**
53
+ * Get unique span IDs in buffer.
54
+ */
55
+ getSpanIds(): string[];
56
+ /**
57
+ * Serialize all events to a single byte array (for chunking).
58
+ */
59
+ serialize(): Uint8Array;
60
+ }
61
+ //# sourceMappingURL=event-buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-buffer.d.ts","sourceRoot":"","sources":["../../src/recorder/event-buffer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,qBAAa,WAAW;IAKV,OAAO,CAAC,QAAQ,CAAC,YAAY;IAJzC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,GAAG,CAAK;gBAEa,YAAY,EAAE,MAAM;IAEjD;;;OAGG;IACG,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IAgB9D;;OAEG;IACH,KAAK,IAAI,aAAa,EAAE;IAOxB;;OAEG;IACH,IAAI,IAAI,aAAa,EAAE;IAIvB;;OAEG;IACH,QAAQ,IAAI,WAAW;IASvB;;OAEG;IACH,OAAO,IAAI,OAAO;IAIlB;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;OAEG;IACH,aAAa,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAQxC;;OAEG;IACH,UAAU,IAAI,MAAM,EAAE;IAUtB;;OAEG;IACH,SAAS,IAAI,UAAU;CAKxB"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * In-memory event buffer for the flight recorder.
3
+ * Buffers events until chunk threshold is reached.
4
+ */
5
+ import { sha256Json } from "../crypto/hashing.js";
6
+ export class EventBuffer {
7
+ maxSizeBytes;
8
+ events = [];
9
+ byteSize = 0;
10
+ seq = 0;
11
+ constructor(maxSizeBytes) {
12
+ this.maxSizeBytes = maxSizeBytes;
13
+ }
14
+ /**
15
+ * Add an event to the buffer.
16
+ * Returns true if buffer should be flushed (threshold reached).
17
+ */
18
+ async add(event) {
19
+ const seqEvent = { ...event, seq: this.seq++ };
20
+ const serialized = new TextEncoder().encode(JSON.stringify(seqEvent));
21
+ const hash = await sha256Json(seqEvent, "event");
22
+ this.events.push({
23
+ event: seqEvent,
24
+ serialized,
25
+ hash,
26
+ });
27
+ this.byteSize += serialized.length;
28
+ return this.byteSize >= this.maxSizeBytes;
29
+ }
30
+ /**
31
+ * Get all buffered events and clear the buffer.
32
+ */
33
+ flush() {
34
+ const events = this.events;
35
+ this.events = [];
36
+ this.byteSize = 0;
37
+ return events;
38
+ }
39
+ /**
40
+ * Peek at buffered events without clearing.
41
+ */
42
+ peek() {
43
+ return [...this.events];
44
+ }
45
+ /**
46
+ * Get buffer statistics.
47
+ */
48
+ getStats() {
49
+ return {
50
+ eventCount: this.events.length,
51
+ byteSize: this.byteSize,
52
+ oldestEventTs: this.events[0]?.event.ts ?? null,
53
+ newestEventTs: this.events[this.events.length - 1]?.event.ts ?? null,
54
+ };
55
+ }
56
+ /**
57
+ * Check if buffer is empty.
58
+ */
59
+ isEmpty() {
60
+ return this.events.length === 0;
61
+ }
62
+ /**
63
+ * Get current sequence number.
64
+ */
65
+ getSeq() {
66
+ return this.seq;
67
+ }
68
+ /**
69
+ * Get event range in buffer.
70
+ */
71
+ getEventRange() {
72
+ if (this.events.length === 0)
73
+ return null;
74
+ const first = this.events[0];
75
+ const last = this.events[this.events.length - 1];
76
+ if (!first || !last)
77
+ return null;
78
+ return [first.event.seq, last.event.seq];
79
+ }
80
+ /**
81
+ * Get unique span IDs in buffer.
82
+ */
83
+ getSpanIds() {
84
+ const spanIds = new Set();
85
+ for (const { event } of this.events) {
86
+ if (event.spanId) {
87
+ spanIds.add(event.spanId);
88
+ }
89
+ }
90
+ return Array.from(spanIds);
91
+ }
92
+ /**
93
+ * Serialize all events to a single byte array (for chunking).
94
+ */
95
+ serialize() {
96
+ const lines = this.events.map((e) => JSON.stringify(e.event));
97
+ const jsonl = lines.join("\n");
98
+ return new TextEncoder().encode(jsonl);
99
+ }
100
+ }
101
+ //# sourceMappingURL=event-buffer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-buffer.js","sourceRoot":"","sources":["../../src/recorder/event-buffer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { FlightRecorder } from "./stream-recorder.js";
2
+ export { EventBuffer } from "./event-buffer.js";
3
+ export { ChunkManager } from "./chunk-manager.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/recorder/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { FlightRecorder } from "./stream-recorder.js";
2
+ export { EventBuffer } from "./event-buffer.js";
3
+ export { ChunkManager } from "./chunk-manager.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/recorder/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Main streaming flight recorder.
3
+ * Captures inference events, manages chunking, and builds manifests.
4
+ */
5
+ import type { RecorderConfig, RecorderEvent, RecordingSession, RecordingResult } from "../types.js";
6
+ export declare class FlightRecorder {
7
+ private readonly config;
8
+ private session;
9
+ private buffer;
10
+ private chunkManager;
11
+ private rollingHashState;
12
+ private startTime;
13
+ private toolCallCount;
14
+ private totalTokens;
15
+ private completionTokens;
16
+ private transcriptHashes;
17
+ private promptHash;
18
+ private systemPromptHash;
19
+ private modelName;
20
+ private inferenceParams;
21
+ private activeSpans;
22
+ private completedSpanCount;
23
+ private chunkTimeout;
24
+ constructor(config: RecorderConfig);
25
+ /**
26
+ * Start a recording session.
27
+ */
28
+ start(): Promise<RecordingSession>;
29
+ /**
30
+ * Record an event.
31
+ */
32
+ record(event: Omit<RecorderEvent, "seq" | "ts">): Promise<void>;
33
+ /**
34
+ * Start a span for grouping related events.
35
+ */
36
+ startSpan(name: string): string;
37
+ /**
38
+ * End a span.
39
+ */
40
+ endSpan(spanId: string): void;
41
+ /**
42
+ * Record an event within a span.
43
+ */
44
+ recordInSpan<T>(_spanId: string, fn: () => Promise<T>): Promise<T>;
45
+ /**
46
+ * Finalize the recording and produce a manifest.
47
+ */
48
+ finalize(): Promise<RecordingResult>;
49
+ /**
50
+ * Abort the recording.
51
+ */
52
+ abort(reason?: string): Promise<void>;
53
+ /**
54
+ * Get current session info.
55
+ */
56
+ getSession(): RecordingSession | null;
57
+ private flushBuffer;
58
+ private trackEventData;
59
+ private buildManifest;
60
+ private captureRuntimeInfo;
61
+ private buildInputs;
62
+ private buildParams;
63
+ private startChunkTimeout;
64
+ private resetChunkTimeout;
65
+ }
66
+ //# sourceMappingURL=stream-recorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-recorder.d.ts","sourceRoot":"","sources":["../../src/recorder/stream-recorder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,eAAe,EAIhB,MAAM,aAAa,CAAC;AAQrB,qBAAa,cAAc;IA2Bb,OAAO,CAAC,QAAQ,CAAC,MAAM;IA1BnC,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,YAAY,CAAe;IAEnC,OAAO,CAAC,gBAAgB,CAAM;IAC9B,OAAO,CAAC,SAAS,CAAqB;IAGtC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,gBAAgB,CAAgB;IAGxC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,eAAe,CAAgC;IAGvD,OAAO,CAAC,WAAW,CAAwD;IAC3E,OAAO,CAAC,kBAAkB,CAAK;IAG/B,OAAO,CAAC,YAAY,CAA8C;gBAErC,MAAM,EAAE,cAAc;IASnD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,gBAAgB,CAAC;IA+BxC;;OAEG;IACG,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAsCrE;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAM/B;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAO7B;;OAEG;IACG,YAAY,CAAC,CAAC,EAClB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC;IAMb;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,eAAe,CAAC;IA6E1C;;OAEG;IACG,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB3C;;OAEG;IACH,UAAU,IAAI,gBAAgB,GAAG,IAAI;YAMvB,WAAW;YAsBX,cAAc;YAyBd,aAAa;IA+C3B,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,WAAW;IA4BnB,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,iBAAiB;CAM1B"}