@aelionsdk/sdk 0.1.0-beta.1

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 (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +63 -0
  3. package/dist/audio-controller.d.ts +25 -0
  4. package/dist/audio-controller.d.ts.map +1 -0
  5. package/dist/audio-controller.js +235 -0
  6. package/dist/audio-mastering.d.ts +27 -0
  7. package/dist/audio-mastering.d.ts.map +1 -0
  8. package/dist/audio-mastering.js +160 -0
  9. package/dist/composition.d.ts +75 -0
  10. package/dist/composition.d.ts.map +1 -0
  11. package/dist/composition.js +146 -0
  12. package/dist/default-schemas.d.ts +7 -0
  13. package/dist/default-schemas.d.ts.map +1 -0
  14. package/dist/default-schemas.js +18 -0
  15. package/dist/export-job.d.ts +22 -0
  16. package/dist/export-job.d.ts.map +1 -0
  17. package/dist/export-job.js +126 -0
  18. package/dist/extension-host.d.ts +90 -0
  19. package/dist/extension-host.d.ts.map +1 -0
  20. package/dist/extension-host.js +367 -0
  21. package/dist/index.d.ts +18 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +19 -0
  24. package/dist/media-provider.d.ts +49 -0
  25. package/dist/media-provider.d.ts.map +1 -0
  26. package/dist/media-provider.js +388 -0
  27. package/dist/migration-materials.d.ts +10 -0
  28. package/dist/migration-materials.d.ts.map +1 -0
  29. package/dist/migration-materials.js +148 -0
  30. package/dist/migration.d.ts +109 -0
  31. package/dist/migration.d.ts.map +1 -0
  32. package/dist/migration.js +1232 -0
  33. package/dist/persistence.d.ts +73 -0
  34. package/dist/persistence.d.ts.map +1 -0
  35. package/dist/persistence.js +245 -0
  36. package/dist/player.d.ts +22 -0
  37. package/dist/player.d.ts.map +1 -0
  38. package/dist/player.js +522 -0
  39. package/dist/preview-controller.d.ts +62 -0
  40. package/dist/preview-controller.d.ts.map +1 -0
  41. package/dist/preview-controller.js +377 -0
  42. package/dist/preview-quality.d.ts +7 -0
  43. package/dist/preview-quality.d.ts.map +1 -0
  44. package/dist/preview-quality.js +8 -0
  45. package/dist/production-media-provider.d.ts +112 -0
  46. package/dist/production-media-provider.d.ts.map +1 -0
  47. package/dist/production-media-provider.js +749 -0
  48. package/dist/project-builder.d.ts +249 -0
  49. package/dist/project-builder.d.ts.map +1 -0
  50. package/dist/project-builder.js +953 -0
  51. package/dist/runtime-material-registry.d.ts +10 -0
  52. package/dist/runtime-material-registry.d.ts.map +1 -0
  53. package/dist/runtime-material-registry.js +23 -0
  54. package/dist/session.d.ts +29 -0
  55. package/dist/session.d.ts.map +1 -0
  56. package/dist/session.js +1114 -0
  57. package/dist/types.d.ts +392 -0
  58. package/dist/types.d.ts.map +1 -0
  59. package/dist/types.js +1 -0
  60. package/package.json +60 -0
@@ -0,0 +1,367 @@
1
+ export const AELION_EXTENSION_PROTOCOL = 'aelion.extension/1';
2
+ function positiveInteger(value, fallback, name) {
3
+ const resolved = value ?? fallback;
4
+ if (!Number.isSafeInteger(resolved) || resolved <= 0) {
5
+ throw new RangeError(`${name} must be a positive safe integer`);
6
+ }
7
+ return resolved;
8
+ }
9
+ function payloadBytes(value) {
10
+ let serialized;
11
+ try {
12
+ serialized = JSON.stringify(value);
13
+ }
14
+ catch {
15
+ throw new TypeError('Extension payload must be acyclic JSON');
16
+ }
17
+ if (typeof serialized !== 'string')
18
+ throw new TypeError('Extension payload must be JSON');
19
+ return new TextEncoder().encode(serialized).byteLength;
20
+ }
21
+ function clonePayload(value, maximum) {
22
+ if (payloadBytes(value) > maximum) {
23
+ throw new RangeError(`Extension payload exceeds ${maximum.toString()} bytes`);
24
+ }
25
+ return structuredClone(value);
26
+ }
27
+ function validManifest(value) {
28
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
29
+ return false;
30
+ const manifest = value;
31
+ return (typeof manifest.id === 'string' &&
32
+ /^[A-Za-z][A-Za-z0-9._:-]*$/u.test(manifest.id) &&
33
+ typeof manifest.version === 'string' &&
34
+ manifest.version.length > 0 &&
35
+ Array.isArray(manifest.methods) &&
36
+ manifest.methods.length > 0 &&
37
+ manifest.methods.every(method => typeof method === 'string' && /^[A-Za-z][A-Za-z0-9._:-]*$/u.test(method)) &&
38
+ new Set(manifest.methods).size === manifest.methods.length);
39
+ }
40
+ function asWorkerMessage(value) {
41
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
42
+ return undefined;
43
+ const message = value;
44
+ if (message.protocol !== AELION_EXTENSION_PROTOCOL)
45
+ return undefined;
46
+ if (message.type === 'ready' && validManifest(message.manifest)) {
47
+ return message;
48
+ }
49
+ if (message.type === 'result' &&
50
+ Number.isSafeInteger(message.id) &&
51
+ (message.id ?? 0) > 0 &&
52
+ 'payload' in message) {
53
+ return message;
54
+ }
55
+ if (message.type === 'error' &&
56
+ Number.isSafeInteger(message.id) &&
57
+ (message.id ?? 0) > 0 &&
58
+ typeof message.name === 'string' &&
59
+ typeof message.message === 'string') {
60
+ return message;
61
+ }
62
+ return undefined;
63
+ }
64
+ function asHostMessage(value) {
65
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
66
+ return undefined;
67
+ const message = value;
68
+ if (message.protocol !== AELION_EXTENSION_PROTOCOL)
69
+ return undefined;
70
+ if (message.type === 'initialize' &&
71
+ Number.isSafeInteger(message.maxPayloadBytes) &&
72
+ message.maxPayloadBytes > 0) {
73
+ return message;
74
+ }
75
+ if (message.type === 'invoke' &&
76
+ Number.isSafeInteger(message.id) &&
77
+ message.id > 0 &&
78
+ typeof message.method === 'string' &&
79
+ /^[A-Za-z][A-Za-z0-9._:-]*$/u.test(message.method) &&
80
+ 'payload' in message) {
81
+ return message;
82
+ }
83
+ if (message.type === 'cancel' && Number.isSafeInteger(message.id) && message.id > 0) {
84
+ return message;
85
+ }
86
+ return undefined;
87
+ }
88
+ function abortRejection(reason) {
89
+ return reason instanceof Error
90
+ ? reason
91
+ : new DOMException('Extension call aborted', 'AbortError');
92
+ }
93
+ /**
94
+ * Fault-isolated RPC host for extension module Workers. The Worker receives
95
+ * cloned JSON only—never Session, media providers, DOM nodes or credentials.
96
+ */
97
+ export class AelionExtensionHost {
98
+ #transport;
99
+ #maxPendingCalls;
100
+ #maxPayloadBytes;
101
+ #invocationTimeoutMs;
102
+ #pending = new Map();
103
+ #readyPromise;
104
+ #resolveReady;
105
+ #rejectReady;
106
+ #handshakeTimer;
107
+ #manifest;
108
+ #nextRequestId = 1;
109
+ #disposed = false;
110
+ constructor(transport, options = {}) {
111
+ this.#transport = transport;
112
+ this.#maxPendingCalls = positiveInteger(options.maxPendingCalls, 8, 'maxPendingCalls');
113
+ this.#maxPayloadBytes = positiveInteger(options.maxPayloadBytes, 1_048_576, 'maxPayloadBytes');
114
+ this.#invocationTimeoutMs = positiveInteger(options.invocationTimeoutMs, 5_000, 'invocationTimeoutMs');
115
+ const handshakeTimeoutMs = positiveInteger(options.handshakeTimeoutMs, 5_000, 'handshakeTimeoutMs');
116
+ this.#readyPromise = new Promise((resolve, reject) => {
117
+ this.#resolveReady = resolve;
118
+ this.#rejectReady = reject;
119
+ });
120
+ this.#transport.addEventListener('message', this.#handleMessage);
121
+ this.#transport.addEventListener('error', this.#handleError);
122
+ this.#handshakeTimer = setTimeout(() => {
123
+ this.#fault(new DOMException('Extension handshake timed out', 'TimeoutError'));
124
+ }, handshakeTimeoutMs);
125
+ this.#transport.postMessage({
126
+ protocol: AELION_EXTENSION_PROTOCOL,
127
+ type: 'initialize',
128
+ maxPayloadBytes: this.#maxPayloadBytes,
129
+ });
130
+ }
131
+ get ready() {
132
+ return this.#readyPromise;
133
+ }
134
+ snapshot() {
135
+ return {
136
+ ready: this.#manifest !== undefined,
137
+ disposed: this.#disposed,
138
+ pendingCalls: this.#pending.size,
139
+ nextRequestId: this.#nextRequestId,
140
+ manifest: this.#manifest === undefined ? null : structuredClone(this.#manifest),
141
+ };
142
+ }
143
+ async invoke(method, payload, options = {}) {
144
+ const manifest = await this.#readyPromise;
145
+ if (this.#disposed)
146
+ throw new ReferenceError('AelionExtensionHost is disposed');
147
+ if (!manifest.methods.includes(method)) {
148
+ throw new ReferenceError(`Extension ${manifest.id} does not expose ${method}`);
149
+ }
150
+ if (this.#pending.size >= this.#maxPendingCalls) {
151
+ throw new RangeError(`Extension call queue reached its ${this.#maxPendingCalls.toString()} call limit`);
152
+ }
153
+ if (options.signal?.aborted === true) {
154
+ throw options.signal.reason ?? new DOMException('Extension call aborted', 'AbortError');
155
+ }
156
+ const clonedPayload = clonePayload(payload, this.#maxPayloadBytes);
157
+ const id = this.#nextRequestId;
158
+ this.#nextRequestId += 1;
159
+ const timeoutMs = positiveInteger(options.timeoutMs, this.#invocationTimeoutMs, 'timeoutMs');
160
+ return new Promise((resolve, reject) => {
161
+ const timer = setTimeout(() => {
162
+ this.#fault(new DOMException(`Extension call ${method} timed out`, 'TimeoutError'));
163
+ }, timeoutMs);
164
+ const abort = options.signal === undefined
165
+ ? undefined
166
+ : () => {
167
+ const pending = this.#pending.get(id);
168
+ if (pending === undefined)
169
+ return;
170
+ this.#settle(id, () => {
171
+ this.#transport.postMessage({
172
+ protocol: AELION_EXTENSION_PROTOCOL,
173
+ type: 'cancel',
174
+ id,
175
+ });
176
+ reject(abortRejection(options.signal?.reason));
177
+ });
178
+ };
179
+ this.#pending.set(id, {
180
+ resolve,
181
+ reject,
182
+ timer,
183
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
184
+ ...(abort === undefined ? {} : { abort }),
185
+ });
186
+ options.signal?.addEventListener('abort', abort, { once: true });
187
+ try {
188
+ this.#transport.postMessage({
189
+ protocol: AELION_EXTENSION_PROTOCOL,
190
+ type: 'invoke',
191
+ id,
192
+ method,
193
+ payload: clonedPayload,
194
+ });
195
+ }
196
+ catch (error) {
197
+ this.#fault(error);
198
+ }
199
+ });
200
+ }
201
+ dispose(reason = new DOMException('Extension host disposed', 'AbortError')) {
202
+ if (this.#disposed)
203
+ return;
204
+ this.#disposed = true;
205
+ clearTimeout(this.#handshakeTimer);
206
+ this.#transport.removeEventListener('message', this.#handleMessage);
207
+ this.#transport.removeEventListener('error', this.#handleError);
208
+ this.#transport.terminate();
209
+ this.#rejectReady(reason);
210
+ for (const [id, pending] of this.#pending) {
211
+ this.#settle(id, () => pending.reject(reason));
212
+ }
213
+ }
214
+ #handleMessage = (event) => {
215
+ if (this.#disposed)
216
+ return;
217
+ const message = asWorkerMessage(event.data);
218
+ if (message === undefined) {
219
+ this.#fault(new TypeError('Extension emitted an invalid protocol message'));
220
+ return;
221
+ }
222
+ if (message.type === 'ready') {
223
+ if (this.#manifest !== undefined) {
224
+ this.#fault(new TypeError('Extension emitted duplicate ready messages'));
225
+ return;
226
+ }
227
+ try {
228
+ if (payloadBytes(message.manifest) > this.#maxPayloadBytes) {
229
+ throw new RangeError('Extension manifest exceeds the payload budget');
230
+ }
231
+ }
232
+ catch (error) {
233
+ this.#fault(error);
234
+ return;
235
+ }
236
+ clearTimeout(this.#handshakeTimer);
237
+ this.#manifest = structuredClone(message.manifest);
238
+ this.#resolveReady(structuredClone(message.manifest));
239
+ return;
240
+ }
241
+ const pending = this.#pending.get(message.id);
242
+ if (pending === undefined)
243
+ return;
244
+ if (message.type === 'result') {
245
+ try {
246
+ const payload = clonePayload(message.payload, this.#maxPayloadBytes);
247
+ this.#settle(message.id, () => pending.resolve(payload));
248
+ }
249
+ catch (error) {
250
+ this.#fault(error);
251
+ }
252
+ return;
253
+ }
254
+ this.#settle(message.id, () => {
255
+ const error = new Error(message.message);
256
+ error.name = message.name;
257
+ pending.reject(error);
258
+ });
259
+ };
260
+ #handleError = (event) => {
261
+ this.#fault(event.error ?? new Error(event.message || 'Extension Worker failed'));
262
+ };
263
+ #settle(id, callback) {
264
+ const pending = this.#pending.get(id);
265
+ if (pending === undefined)
266
+ return;
267
+ this.#pending.delete(id);
268
+ clearTimeout(pending.timer);
269
+ if (pending.signal !== undefined && pending.abort !== undefined) {
270
+ pending.signal.removeEventListener('abort', pending.abort);
271
+ }
272
+ callback();
273
+ }
274
+ #fault(error) {
275
+ if (this.#disposed)
276
+ return;
277
+ const ready = this.#manifest !== undefined;
278
+ this.dispose(error);
279
+ if (ready) {
280
+ // `dispose` rejects all invocations. The ready Promise is already settled.
281
+ return;
282
+ }
283
+ }
284
+ }
285
+ /**
286
+ * Worker-side counterpart. It exposes an explicit method table and supports
287
+ * cooperative cancellation without importing or receiving the editor Session.
288
+ */
289
+ export function exposeAelionExtension(endpoint, manifest, handlers) {
290
+ if (!validManifest(manifest))
291
+ throw new TypeError('Invalid Aelion extension manifest');
292
+ for (const method of manifest.methods) {
293
+ if (handlers[method] === undefined) {
294
+ throw new ReferenceError(`Missing extension handler ${method}`);
295
+ }
296
+ }
297
+ const active = new Map();
298
+ let maximumPayloadBytes;
299
+ const listener = (event) => {
300
+ const message = asHostMessage(event.data);
301
+ if (message === undefined)
302
+ return;
303
+ if (message.type === 'initialize') {
304
+ if (maximumPayloadBytes !== undefined)
305
+ return;
306
+ maximumPayloadBytes = message.maxPayloadBytes;
307
+ endpoint.postMessage({
308
+ protocol: AELION_EXTENSION_PROTOCOL,
309
+ type: 'ready',
310
+ manifest: structuredClone(manifest),
311
+ });
312
+ return;
313
+ }
314
+ if (message.type === 'cancel') {
315
+ active.get(message.id)?.abort(new DOMException('Extension call aborted', 'AbortError'));
316
+ return;
317
+ }
318
+ if (maximumPayloadBytes === undefined || active.has(message.id))
319
+ return;
320
+ const maximum = maximumPayloadBytes;
321
+ const handler = handlers[message.method];
322
+ if (handler === undefined) {
323
+ endpoint.postMessage({
324
+ protocol: AELION_EXTENSION_PROTOCOL,
325
+ type: 'error',
326
+ id: message.id,
327
+ name: 'ReferenceError',
328
+ message: `Unknown extension method ${message.method}`,
329
+ });
330
+ return;
331
+ }
332
+ const controller = new AbortController();
333
+ active.set(message.id, controller);
334
+ void Promise.resolve()
335
+ .then(() => handler(clonePayload(message.payload, maximum), { signal: controller.signal }))
336
+ .then(payload => {
337
+ if (controller.signal.aborted)
338
+ return;
339
+ endpoint.postMessage({
340
+ protocol: AELION_EXTENSION_PROTOCOL,
341
+ type: 'result',
342
+ id: message.id,
343
+ payload: clonePayload(payload, maximum),
344
+ });
345
+ })
346
+ .catch((error) => {
347
+ if (controller.signal.aborted)
348
+ return;
349
+ endpoint.postMessage({
350
+ protocol: AELION_EXTENSION_PROTOCOL,
351
+ type: 'error',
352
+ id: message.id,
353
+ name: error instanceof Error ? error.name : 'Error',
354
+ message: error instanceof Error ? error.message : String(error),
355
+ });
356
+ })
357
+ .finally(() => active.delete(message.id));
358
+ };
359
+ endpoint.addEventListener('message', listener);
360
+ return () => {
361
+ endpoint.removeEventListener('message', listener);
362
+ for (const controller of active.values()) {
363
+ controller.abort(new DOMException('Extension runtime disposed', 'AbortError'));
364
+ }
365
+ active.clear();
366
+ };
367
+ }
@@ -0,0 +1,18 @@
1
+ import type { AelionApi } from './types.js';
2
+ export * from './runtime-material-registry.js';
3
+ export * from './media-provider.js';
4
+ export * from './production-media-provider.js';
5
+ export * from './project-builder.js';
6
+ export * from './composition.js';
7
+ export * from './migration.js';
8
+ export * from './migration-materials.js';
9
+ export * from './audio-controller.js';
10
+ export * from './audio-mastering.js';
11
+ export * from './persistence.js';
12
+ export * from './extension-host.js';
13
+ export * from './preview-controller.js';
14
+ export * from './default-schemas.js';
15
+ export * from './session.js';
16
+ export * from './types.js';
17
+ export declare const Aelion: AelionApi;
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAE3B,eAAO,MAAM,MAAM,EAAE,SAEpB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ import { AelionSession } from './session.js';
2
+ export * from './runtime-material-registry.js';
3
+ export * from './media-provider.js';
4
+ export * from './production-media-provider.js';
5
+ export * from './project-builder.js';
6
+ export * from './composition.js';
7
+ export * from './migration.js';
8
+ export * from './migration-materials.js';
9
+ export * from './audio-controller.js';
10
+ export * from './audio-mastering.js';
11
+ export * from './persistence.js';
12
+ export * from './extension-host.js';
13
+ export * from './preview-controller.js';
14
+ export * from './default-schemas.js';
15
+ export * from './session.js';
16
+ export * from './types.js';
17
+ export const Aelion = {
18
+ createSession: options => Promise.resolve(new AelionSession(options)),
19
+ };
@@ -0,0 +1,49 @@
1
+ import type { PcmSourceBlock } from '@aelionsdk/audio';
2
+ import type { AelionMediaProvider } from './types.js';
3
+ export type AelionAssetBytesResolver = (assetId: string, signal?: AbortSignal) => Promise<Uint8Array>;
4
+ export interface ByteMediaProviderOptions {
5
+ readonly resolveAssetBytes: AelionAssetBytesResolver;
6
+ readonly maxCachedBytes?: number;
7
+ /** Maximum byte-load, SampleIndex and decode operations allowed at once. Defaults to 4. */
8
+ readonly maxConcurrentOperations?: number;
9
+ /** Maximum bounded operations waiting for a slot. Defaults to 64. */
10
+ readonly maxPendingOperations?: number;
11
+ /** Compatibility alias for maxConcurrentOperations; covers load, index and decode work. */
12
+ readonly maxConcurrentLoads?: number;
13
+ }
14
+ /**
15
+ * Convenience provider for small Alpha projects. It keeps a bounded LRU of
16
+ * immutable asset bytes and reuses SampleIndex across exact seeks. Large/CDN
17
+ * integrations should provide their own Range-backed AelionMediaProvider.
18
+ */
19
+ export declare class ByteMediaProvider implements AelionMediaProvider {
20
+ #private;
21
+ constructor(options: ByteMediaProviderOptions);
22
+ frameAt(assetId: string, streamIndex: number, sourceTimeUs: number, signal?: AbortSignal): Promise<VideoFrame>;
23
+ pcmRange(assetId: string, streamIndex: number, startUs: number, durationUs: number, signal?: AbortSignal): Promise<PcmSourceBlock>;
24
+ clear(): void;
25
+ snapshot(): {
26
+ readonly assets: number;
27
+ readonly cachedBytes: number;
28
+ readonly maxCachedBytes: number;
29
+ readonly inFlightAssetLoads: number;
30
+ readonly inFlightSampleIndexes: number;
31
+ /** Public frameAt/pcmRange calls currently admitted across their full lifecycle. */
32
+ readonly inFlightRequests: number;
33
+ /** Hard request cap, derived as maxConcurrentOperations + maxPendingOperations. */
34
+ readonly maxInFlightRequests: number;
35
+ /** Subscribers retained by active single-flight load and index operations. */
36
+ readonly sharedOperationSubscribers: number;
37
+ readonly activeOperations: number;
38
+ readonly pendingOperations: number;
39
+ readonly maxConcurrentOperations: number;
40
+ readonly maxPendingOperations: number;
41
+ /** Compatibility alias for activeOperations. */
42
+ readonly activeLoads: number;
43
+ /** Compatibility alias for pendingOperations. */
44
+ readonly pendingLoads: number;
45
+ /** Compatibility alias for maxConcurrentOperations. */
46
+ readonly maxConcurrentLoads: number;
47
+ };
48
+ }
49
+ //# sourceMappingURL=media-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-provider.d.ts","sourceRoot":"","sources":["../src/media-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAWvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,MAAM,wBAAwB,GAAG,CACrC,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,WAAW,KACjB,OAAO,CAAC,UAAU,CAAC,CAAC;AAEzB,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,iBAAiB,EAAE,wBAAwB,CAAC;IACrD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,2FAA2F;IAC3F,QAAQ,CAAC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAC1C,qEAAqE;IACrE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IACvC,2FAA2F;IAC3F,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CACtC;AAgID;;;;GAIG;AACH,qBAAa,iBAAkB,YAAW,mBAAmB;;gBAgBxC,OAAO,EAAE,wBAAwB;IA2BvC,OAAO,CAClB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC;IA+BT,QAAQ,CACnB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,CAAC;IAiBnB,KAAK,IAAI,IAAI;IAOb,QAAQ,IAAI;QACjB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;QACpC,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC;QACvC,oFAAoF;QACpF,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;QAClC,mFAAmF;QACnF,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;QACrC,8EAA8E;QAC9E,QAAQ,CAAC,0BAA0B,EAAE,MAAM,CAAC;QAC5C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;QAClC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;QACnC,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC;QACzC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;QACtC,gDAAgD;QAChD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,iDAAiD;QACjD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;QAC9B,uDAAuD;QACvD,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;KACrC;CA4NF"}