@spatialwalk/avatarkit-rtc 1.0.0-beta.4 → 1.0.0-beta.6
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/core/AvatarPlayer.d.ts +13 -0
- package/dist/core/AvatarPlayer.d.ts.map +1 -1
- package/dist/core/RTCProvider.d.ts +2 -13
- package/dist/core/RTCProvider.d.ts.map +1 -1
- package/dist/index10.js +47 -80
- package/dist/index10.js.map +1 -1
- package/dist/index11.js +386 -14
- package/dist/index11.js.map +1 -1
- package/dist/index12.js +64 -346
- package/dist/index12.js.map +1 -1
- package/dist/index13.js +14 -174
- package/dist/index13.js.map +1 -1
- package/dist/index2.js +2 -2
- package/dist/index2.js.map +1 -1
- package/dist/index3.js +136 -27
- package/dist/index3.js.map +1 -1
- package/dist/index4.js +6 -18
- package/dist/index4.js.map +1 -1
- package/dist/index6.js +246 -5
- package/dist/index6.js.map +1 -1
- package/dist/index8.js +1 -1
- package/dist/index9.js +163 -60
- package/dist/index9.js.map +1 -1
- package/dist/providers/agora/AgoraProvider.d.ts +0 -13
- package/dist/providers/agora/AgoraProvider.d.ts.map +1 -1
- package/dist/providers/base/BaseProvider.d.ts +47 -1
- package/dist/providers/base/BaseProvider.d.ts.map +1 -1
- package/dist/providers/livekit/LiveKitProvider.d.ts +0 -13
- package/dist/providers/livekit/LiveKitProvider.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -14,6 +14,19 @@ export interface AvatarPlayerOptions {
|
|
|
14
14
|
* - 'none': Disable all logs
|
|
15
15
|
*/
|
|
16
16
|
logLevel?: LogLevel;
|
|
17
|
+
/**
|
|
18
|
+
* Enable jitter buffer for smoother animation playback.
|
|
19
|
+
* When enabled, frames are buffered and rendered in sequence order at a steady 25fps,
|
|
20
|
+
* absorbing network jitter and out-of-order delivery.
|
|
21
|
+
* Default: true
|
|
22
|
+
*/
|
|
23
|
+
enableJitterBuffer?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Maximum delay (in ms) a frame can sit in the jitter buffer before being rendered.
|
|
26
|
+
* Only used when enableJitterBuffer is true.
|
|
27
|
+
* Default: 80 (2 frames at 25fps)
|
|
28
|
+
*/
|
|
29
|
+
maxBufferDelayMs?: number;
|
|
17
30
|
}
|
|
18
31
|
/**
|
|
19
32
|
* Unified Avatar Player.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AvatarPlayer.d.ts","sourceRoot":"","sources":["../../src/core/AvatarPlayer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAGpD,OAAO,EAA2B,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAGlE,OAAO,KAAK,EAAE,UAAU,EAAgB,MAAM,wBAAwB,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"AvatarPlayer.d.ts","sourceRoot":"","sources":["../../src/core/AvatarPlayer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAGpD,OAAO,EAA2B,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAGlE,OAAO,KAAK,EAAE,UAAU,EAAgB,MAAM,wBAAwB,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAEpB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBAAa,YAAY;IA4BvB;;;;;OAKG;gBAED,QAAQ,EAAE,WAAW,EACrB,UAAU,EAAE,UAAU,EACtB,OAAO,CAAC,EAAE,mBAAmB;IA2B/B;;OAEG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;;;OAIG;IACG,OAAO,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAczD;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBjC;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACG,YAAY,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB1D;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IASrC;;;;;;;;;;;;;;OAcG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBtC;;;;;OAKG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAYrC;;;OAGG;IACH,kBAAkB,IAAI,MAAM;IAI5B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,eAAe,IAAI,OAAO;IAI1B;;;;OAIG;IACH,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI;IAa1C;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI;IAyB3C;;;;;;;;;;;;;OAaG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAmIjC"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { RTCConnectionConfig } from '../types';
|
|
2
|
-
import { RTCProviderEvents } from './types';
|
|
3
2
|
/**
|
|
4
3
|
* RTC Provider interface.
|
|
5
4
|
*
|
|
@@ -49,28 +48,18 @@ export interface RTCProvider {
|
|
|
49
48
|
* Unpublish audio track from the RTC server.
|
|
50
49
|
*/
|
|
51
50
|
unpublishAudioTrack(): Promise<void>;
|
|
52
|
-
/**
|
|
53
|
-
* Play remote audio (resume playback).
|
|
54
|
-
* Used to sync audio with animation transitions.
|
|
55
|
-
*/
|
|
56
|
-
playRemoteAudio(): void;
|
|
57
|
-
/**
|
|
58
|
-
* Pause remote audio.
|
|
59
|
-
* Used to sync audio with animation transitions.
|
|
60
|
-
*/
|
|
61
|
-
pauseRemoteAudio(): void;
|
|
62
51
|
/**
|
|
63
52
|
* Add event listener.
|
|
64
53
|
* @param event - Event name
|
|
65
54
|
* @param handler - Event handler function
|
|
66
55
|
*/
|
|
67
|
-
on
|
|
56
|
+
on(event: string, handler: Function): void;
|
|
68
57
|
/**
|
|
69
58
|
* Remove event listener.
|
|
70
59
|
* @param event - Event name
|
|
71
60
|
* @param handler - Event handler function
|
|
72
61
|
*/
|
|
73
|
-
off
|
|
62
|
+
off(event: string, handler: Function): void;
|
|
74
63
|
/**
|
|
75
64
|
* Get the native RTC client object.
|
|
76
65
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RTCProvider.d.ts","sourceRoot":"","sources":["../../src/core/RTCProvider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"RTCProvider.d.ts","sourceRoot":"","sources":["../../src/core/RTCProvider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAMpD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;;OAIG;IACH,OAAO,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpD;;;OAGG;IACH,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B;;;OAGG;IACH,kBAAkB,IAAI,MAAM,CAAC;IA4B7B;;;OAGG;IACH,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1D;;OAEG;IACH,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAErC;;;;OAIG;IACH,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IAE3C;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IAE5C;;;;;;;OAOG;IACH,eAAe,IAAI,OAAO,CAAC;CAC5B"}
|
package/dist/index10.js
CHANGED
|
@@ -1,108 +1,75 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
-
import { createAnimationReceiverTransform } from "./index14.js";
|
|
5
4
|
import { logger } from "./index7.js";
|
|
6
|
-
|
|
7
|
-
const DEFAULT_TRANSITION_START_FRAMES = 8;
|
|
8
|
-
const DEFAULT_TRANSITION_END_FRAMES = 12;
|
|
9
|
-
class VP8Extractor {
|
|
5
|
+
class BaseProvider {
|
|
10
6
|
constructor() {
|
|
11
7
|
/** @internal */
|
|
12
|
-
__publicField(this, "
|
|
8
|
+
__publicField(this, "connectionState", "disconnected");
|
|
13
9
|
/** @internal */
|
|
14
|
-
__publicField(this, "
|
|
15
|
-
/** @internal */
|
|
16
|
-
__publicField(this, "transform", null);
|
|
10
|
+
__publicField(this, "eventHandlers", /* @__PURE__ */ new Map());
|
|
17
11
|
}
|
|
18
12
|
/**
|
|
19
|
-
*
|
|
20
|
-
* @param
|
|
21
|
-
* @param
|
|
22
|
-
* @internal
|
|
13
|
+
* Add event listener.
|
|
14
|
+
* @param event - Event name
|
|
15
|
+
* @param handler - Event handler
|
|
23
16
|
*/
|
|
24
|
-
|
|
25
|
-
if (this.
|
|
26
|
-
|
|
17
|
+
on(event, handler) {
|
|
18
|
+
if (!this.eventHandlers.has(event)) {
|
|
19
|
+
this.eventHandlers.set(event, /* @__PURE__ */ new Set());
|
|
27
20
|
}
|
|
28
|
-
this.
|
|
29
|
-
this.callbacks = callbacks;
|
|
30
|
-
if (receiver.transform) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
const worker = new WorkerWrapper();
|
|
34
|
-
const onEvent = (evt) => {
|
|
35
|
-
this.handleTransformEvent(evt);
|
|
36
|
-
};
|
|
37
|
-
this.transform = createAnimationReceiverTransform(worker, onEvent);
|
|
38
|
-
receiver.transform = this.transform;
|
|
21
|
+
this.eventHandlers.get(event).add(handler);
|
|
39
22
|
}
|
|
40
23
|
/**
|
|
41
|
-
*
|
|
42
|
-
* @
|
|
24
|
+
* Remove event listener.
|
|
25
|
+
* @param event - Event name
|
|
26
|
+
* @param handler - Event handler
|
|
43
27
|
*/
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
framesPerSec: evt.framesPerSec,
|
|
49
|
-
totalFrames: evt.totalFrames ?? 0,
|
|
50
|
-
framesSent: evt.framesSent ?? 0,
|
|
51
|
-
framesLost: evt.framesLost ?? 0,
|
|
52
|
-
framesRecovered: evt.framesRecovered ?? 0,
|
|
53
|
-
framesDropped: evt.framesDropped ?? 0,
|
|
54
|
-
framesOutOfOrder: evt.framesOutOfOrder ?? 0,
|
|
55
|
-
framesDuplicate: evt.framesDuplicate ?? 0,
|
|
56
|
-
lastRenderedSeq: evt.lastRenderedSeq ?? -1
|
|
57
|
-
});
|
|
58
|
-
} else if (evt.type === "transition") {
|
|
59
|
-
this.callbacks.onTransition(evt.protobufData, DEFAULT_TRANSITION_START_FRAMES);
|
|
60
|
-
} else if (evt.type === "transitionEnd") {
|
|
61
|
-
this.callbacks.onTransitionEnd(evt.protobufData, DEFAULT_TRANSITION_END_FRAMES);
|
|
62
|
-
} else if (evt.type === "animation") {
|
|
63
|
-
if (!evt.isIdle) {
|
|
64
|
-
this.callbacks.onAnimationData(evt.protobufData, {
|
|
65
|
-
frameSeq: evt.frameSeq,
|
|
66
|
-
isStart: evt.isStart,
|
|
67
|
-
isEnd: evt.isEnd,
|
|
68
|
-
isIdle: evt.isIdle,
|
|
69
|
-
isRecovered: evt.isRecovered
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
} else if (evt.type === "idleStart") {
|
|
73
|
-
this.callbacks.onIdleStart();
|
|
74
|
-
} else if (evt.type === "error") {
|
|
75
|
-
logger.error("VP8Extractor", "Error:", evt.error);
|
|
28
|
+
off(event, handler) {
|
|
29
|
+
const handlers = this.eventHandlers.get(event);
|
|
30
|
+
if (handlers) {
|
|
31
|
+
handlers.delete(handler);
|
|
76
32
|
}
|
|
77
33
|
}
|
|
78
34
|
/**
|
|
79
|
-
*
|
|
80
|
-
* @param
|
|
81
|
-
* @
|
|
82
|
-
* @internal
|
|
83
|
-
*/
|
|
84
|
-
isConnectedTo(receiver) {
|
|
85
|
-
return this.receiver === receiver;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Get the receiver this extractor is connected to.
|
|
89
|
-
* @returns The connected RTCRtpReceiver or null
|
|
35
|
+
* Emit event to all listeners.
|
|
36
|
+
* @param event - Event name
|
|
37
|
+
* @param args - Event arguments
|
|
90
38
|
* @internal
|
|
91
39
|
*/
|
|
92
|
-
|
|
93
|
-
|
|
40
|
+
emit(event, ...args) {
|
|
41
|
+
const handlers = this.eventHandlers.get(event);
|
|
42
|
+
if (handlers) {
|
|
43
|
+
handlers.forEach((handler) => {
|
|
44
|
+
try {
|
|
45
|
+
handler(...args);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
logger.error(this.name, `Error in event handler for ${event}:`, error);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
94
51
|
}
|
|
95
52
|
/**
|
|
96
|
-
*
|
|
53
|
+
* Update connection state and emit event.
|
|
54
|
+
* @param state - New connection state
|
|
97
55
|
* @internal
|
|
98
56
|
*/
|
|
99
|
-
|
|
100
|
-
this.
|
|
101
|
-
|
|
102
|
-
|
|
57
|
+
setConnectionState(state) {
|
|
58
|
+
if (this.connectionState !== state) {
|
|
59
|
+
const prevState = this.connectionState;
|
|
60
|
+
this.connectionState = state;
|
|
61
|
+
if (state === "disconnected" || state === "failed") {
|
|
62
|
+
logger.error(this.name, `Connection state: ${prevState} -> ${state}`);
|
|
63
|
+
} else if (state === "reconnecting") {
|
|
64
|
+
logger.warn(this.name, `Connection state: ${prevState} -> ${state}`);
|
|
65
|
+
} else {
|
|
66
|
+
logger.info(this.name, `Connection state: ${prevState} -> ${state}`);
|
|
67
|
+
}
|
|
68
|
+
this.emit("connection-state-changed", state);
|
|
69
|
+
}
|
|
103
70
|
}
|
|
104
71
|
}
|
|
105
72
|
export {
|
|
106
|
-
|
|
73
|
+
BaseProvider
|
|
107
74
|
};
|
|
108
75
|
//# sourceMappingURL=index10.js.map
|
package/dist/index10.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index10.js","sources":["../src/providers/
|
|
1
|
+
{"version":3,"file":"index10.js","sources":["../src/providers/base/BaseProvider.ts"],"sourcesContent":["/**\n * Base Provider - Common implementation for RTC providers.\n *\n * This class provides common functionality that can be shared\n * across different provider implementations.\n *\n * @internal\n * @packageDocumentation\n */\n\nimport type { RTCProviderEvents, AnimationTrackCallbacks, AudioTrackCallbacks } from '../../core/types';\nimport { logger } from '../../utils';\n\n/**\n * Base class for RTC providers.\n * Provides common event handling and state management.\n */\nexport abstract class BaseProvider {\n /** Provider name identifier */\n abstract readonly name: string;\n\n /** @internal */\n protected connectionState: string = 'disconnected';\n /** @internal */\n protected eventHandlers: Map<string, Set<Function>> = new Map();\n\n /**\n * Connect to RTC server.\n * @param config - Connection configuration\n */\n abstract connect(config: import('../../types').RTCConnectionConfig): Promise<void>;\n\n /**\n * Disconnect from RTC server.\n */\n abstract disconnect(): Promise<void>;\n\n /**\n * Get current connection state.\n */\n abstract getConnectionState(): string;\n\n /**\n * Subscribe to animation track.\n * @param callbacks - Animation track callbacks\n * @internal\n */\n abstract subscribeAnimationTrack(callbacks: AnimationTrackCallbacks): Promise<void>;\n\n /**\n * Unsubscribe from animation track.\n * @internal\n */\n abstract unsubscribeAnimationTrack(): Promise<void>;\n\n /**\n * Subscribe to audio track.\n * @param callbacks - Audio track callbacks\n * @internal\n */\n abstract subscribeAudioTrack(callbacks: AudioTrackCallbacks): Promise<void>;\n\n /**\n * Unsubscribe from audio track.\n * @internal\n */\n abstract unsubscribeAudioTrack(): Promise<void>;\n\n /**\n * Publish local audio track.\n * @param track - MediaStreamTrack to publish\n */\n abstract publishAudioTrack(track: MediaStreamTrack): Promise<void>;\n\n /**\n * Unpublish audio track.\n */\n abstract unpublishAudioTrack(): Promise<void>;\n\n /**\n * Get the native RTC client object.\n * @returns The native client, or null if not connected\n */\n abstract getNativeClient(): unknown;\n\n /**\n * Add event listener.\n * @param event - Event name\n * @param handler - Event handler\n */\n on(event: string, handler: Function): void {\n if (!this.eventHandlers.has(event)) {\n this.eventHandlers.set(event, new Set());\n }\n this.eventHandlers.get(event)!.add(handler);\n }\n\n /**\n * Remove event listener.\n * @param event - Event name\n * @param handler - Event handler\n */\n off(event: string, handler: Function): void {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.delete(handler);\n }\n }\n\n /**\n * Emit event to all listeners.\n * @param event - Event name\n * @param args - Event arguments\n * @internal\n */\n protected emit<K extends keyof RTCProviderEvents>(\n event: K,\n ...args: Parameters<RTCProviderEvents[K]>\n ): void {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (handler as any)(...args);\n } catch (error) {\n logger.error(this.name, `Error in event handler for ${event}:`, error);\n }\n });\n }\n }\n\n /**\n * Update connection state and emit event.\n * @param state - New connection state\n * @internal\n */\n protected setConnectionState(state: string): void {\n if (this.connectionState !== state) {\n const prevState = this.connectionState;\n this.connectionState = state;\n \n // Log connection state changes\n if (state === 'disconnected' || state === 'failed') {\n logger.error(this.name, `Connection state: ${prevState} -> ${state}`);\n } else if (state === 'reconnecting') {\n logger.warn(this.name, `Connection state: ${prevState} -> ${state}`);\n } else {\n logger.info(this.name, `Connection state: ${prevState} -> ${state}`);\n }\n \n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this.emit('connection-state-changed', state as any);\n }\n }\n}\n"],"names":[],"mappings":";;;;AAiBO,MAAe,aAAa;AAAA,EAA5B;AAKK;AAAA,2CAA0B;AAE1B;AAAA,6DAAgD,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkE1D,GAAG,OAAe,SAAyB;AACzC,QAAI,CAAC,KAAK,cAAc,IAAI,KAAK,GAAG;AAClC,WAAK,cAAc,IAAI,OAAO,oBAAI,KAAK;AAAA,IACzC;AACA,SAAK,cAAc,IAAI,KAAK,EAAG,IAAI,OAAO;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,OAAe,SAAyB;AAC1C,UAAM,WAAW,KAAK,cAAc,IAAI,KAAK;AAC7C,QAAI,UAAU;AACZ,eAAS,OAAO,OAAO;AAAA,IACzB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQU,KACR,UACG,MACG;AACN,UAAM,WAAW,KAAK,cAAc,IAAI,KAAK;AAC7C,QAAI,UAAU;AACZ,eAAS,QAAQ,CAAC,YAAY;AAC5B,YAAI;AAED,kBAAgB,GAAG,IAAI;AAAA,QAC1B,SAAS,OAAO;AACd,iBAAO,MAAM,KAAK,MAAM,8BAA8B,KAAK,KAAK,KAAK;AAAA,QACvE;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,mBAAmB,OAAqB;AAChD,QAAI,KAAK,oBAAoB,OAAO;AAClC,YAAM,YAAY,KAAK;AACvB,WAAK,kBAAkB;AAGvB,UAAI,UAAU,kBAAkB,UAAU,UAAU;AAClD,eAAO,MAAM,KAAK,MAAM,qBAAqB,SAAS,OAAO,KAAK,EAAE;AAAA,MACtE,WAAW,UAAU,gBAAgB;AACnC,eAAO,KAAK,KAAK,MAAM,qBAAqB,SAAS,OAAO,KAAK,EAAE;AAAA,MACrE,OAAO;AACL,eAAO,KAAK,KAAK,MAAM,qBAAqB,SAAS,OAAO,KAAK,EAAE;AAAA,MACrE;AAGA,WAAK,KAAK,4BAA4B,KAAY;AAAA,IACpD;AAAA,EACF;AACF;"}
|