@onekeyfe/hd-transport-lowlevel 1.1.34-alpha.2 → 1.1.34-alpha.3

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/.eslintignore ADDED
@@ -0,0 +1,4 @@
1
+ coverage/
2
+ dist/
3
+ __tests__/
4
+ jest.config.js
@@ -0,0 +1,388 @@
1
+ /* eslint-disable @typescript-eslint/no-var-requires */
2
+ const LowlevelTransport = require('../src').default;
3
+ const { parseConfigure } = require('../../hd-transport/src/serialization/protobuf/messages');
4
+ const { ProtocolV1, ProtocolV2 } = require('../../hd-transport/src/protocols');
5
+ const { bytesToHex } = require('../../hd-transport/src/protocols/v2/session');
6
+ const { PROTOCOL_V2_CHANNEL_BLE_UART } = require('../../hd-transport/src/constants');
7
+
8
+ const protocolV1Schema = {
9
+ nested: {
10
+ Initialize: {
11
+ fields: {},
12
+ },
13
+ Success: {
14
+ fields: {
15
+ message: {
16
+ type: 'string',
17
+ id: 1,
18
+ },
19
+ },
20
+ },
21
+ MessageType: {
22
+ values: {
23
+ MessageType_Initialize: 1,
24
+ MessageType_Success: 2,
25
+ },
26
+ },
27
+ },
28
+ };
29
+
30
+ const protocolV2Schema = {
31
+ nested: {
32
+ ProtocolInfoRequest: {
33
+ fields: {},
34
+ },
35
+ ProtocolInfo: {
36
+ fields: {
37
+ version: {
38
+ type: 'uint32',
39
+ id: 1,
40
+ },
41
+ supported_messages: {
42
+ rule: 'repeated',
43
+ type: 'uint32',
44
+ id: 2,
45
+ options: {
46
+ packed: false,
47
+ },
48
+ },
49
+ protobuf_definition: {
50
+ type: 'string',
51
+ id: 3,
52
+ },
53
+ },
54
+ },
55
+ Ping: {
56
+ fields: {
57
+ message: {
58
+ type: 'string',
59
+ id: 1,
60
+ },
61
+ },
62
+ },
63
+ Success: {
64
+ fields: {
65
+ message: {
66
+ type: 'string',
67
+ id: 1,
68
+ },
69
+ },
70
+ },
71
+ MessageType: {
72
+ values: {
73
+ MessageType_ProtocolInfoRequest: 60200,
74
+ MessageType_ProtocolInfo: 60201,
75
+ MessageType_Ping: 60206,
76
+ MessageType_Success: 60207,
77
+ },
78
+ },
79
+ },
80
+ };
81
+
82
+ const schemas = {
83
+ protocolV1: parseConfigure(protocolV1Schema),
84
+ protocolV2: parseConfigure(protocolV2Schema),
85
+ };
86
+
87
+ const createLogger = () => ({
88
+ debug: jest.fn(),
89
+ error: jest.fn(),
90
+ });
91
+
92
+ const createPlugin = ({ devices, responses }) => ({
93
+ enumerate: jest.fn(() => Promise.resolve(devices)),
94
+ connect: jest.fn(() => Promise.resolve()),
95
+ disconnect: jest.fn(() => Promise.resolve()),
96
+ init: jest.fn(() => Promise.resolve()),
97
+ send: jest.fn(() => Promise.resolve()),
98
+ receive: jest.fn(() => {
99
+ const next = responses.shift();
100
+ if (next instanceof Error) {
101
+ return Promise.reject(next);
102
+ }
103
+ if (!next) {
104
+ return Promise.reject(new Error('No queued response'));
105
+ }
106
+ return Promise.resolve(next);
107
+ }),
108
+ version: 'test-plugin',
109
+ });
110
+
111
+ const configureTransport = plugin => {
112
+ const lowlevel = new LowlevelTransport();
113
+ lowlevel.init(createLogger(), undefined, plugin);
114
+ lowlevel.configure(protocolV1Schema);
115
+ lowlevel.configureProtocolV2(protocolV2Schema);
116
+ return lowlevel;
117
+ };
118
+
119
+ const splitFrame = (frame, index) => [
120
+ bytesToHex(frame.slice(0, index)),
121
+ bytesToHex(frame.slice(index)),
122
+ ];
123
+
124
+ describe('LowlevelTransport protocol framing', () => {
125
+ test('keeps Protocol V1 raw notification chunks compatible', async () => {
126
+ const responseChunks = ProtocolV1.encodeTransportPackets(schemas.protocolV1, 'Success', {
127
+ message: 'ok',
128
+ }).map(chunk => chunk.toString('hex'));
129
+ const plugin = createPlugin({
130
+ devices: [{ id: 'classic-id', name: 'OneKey Classic', commType: 'ble' }],
131
+ responses: [...responseChunks, ...responseChunks],
132
+ });
133
+ const lowlevel = configureTransport(plugin);
134
+
135
+ await expect(lowlevel.acquire({ uuid: 'classic-id' })).resolves.toEqual({
136
+ uuid: 'classic-id',
137
+ protocolType: 'V1',
138
+ });
139
+ await expect(lowlevel.call('classic-id', 'Initialize', {})).resolves.toEqual({
140
+ type: 'Success',
141
+ message: { message: 'ok' },
142
+ });
143
+ });
144
+
145
+ test('rejects calls before protocol detection', async () => {
146
+ const responseChunks = ProtocolV1.encodeTransportPackets(schemas.protocolV1, 'Success', {
147
+ message: 'ok',
148
+ }).map(chunk => chunk.toString('hex'));
149
+ const plugin = createPlugin({
150
+ devices: [{ id: 'classic-id', name: 'OneKey Classic', commType: 'ble' }],
151
+ responses: responseChunks,
152
+ });
153
+ const lowlevel = configureTransport(plugin);
154
+
155
+ await expect(lowlevel.call('classic-id', 'Initialize', {})).rejects.toThrow(
156
+ 'Device protocol has not been detected'
157
+ );
158
+ });
159
+
160
+ test('detects Protocol V2 devices and reassembles split Protocol V2 notifications', async () => {
161
+ const probeResponse = ProtocolV2.encodeFrame(
162
+ schemas,
163
+ 'Success',
164
+ { message: 'ok' },
165
+ { router: PROTOCOL_V2_CHANNEL_BLE_UART }
166
+ );
167
+ const callResponse = ProtocolV2.encodeFrame(
168
+ schemas,
169
+ 'ProtocolInfo',
170
+ {
171
+ version: 1,
172
+ supported_messages: [60200, 60201, 60206, 60207],
173
+ protobuf_definition: 'onekey-protocol-v2',
174
+ },
175
+ { router: PROTOCOL_V2_CHANNEL_BLE_UART }
176
+ );
177
+ const plugin = createPlugin({
178
+ devices: [{ id: 'pro2-id', name: 'OneKey Pro 2', commType: 'ble' }],
179
+ responses: [...splitFrame(probeResponse, 4), ...splitFrame(callResponse, 5)],
180
+ });
181
+ const lowlevel = configureTransport(plugin);
182
+
183
+ await expect(lowlevel.enumerate()).resolves.toEqual([
184
+ { id: 'pro2-id', name: 'OneKey Pro 2', commType: 'ble' },
185
+ ]);
186
+ await expect(lowlevel.acquire({ uuid: 'pro2-id' })).resolves.toEqual({
187
+ uuid: 'pro2-id',
188
+ protocolType: 'V2',
189
+ });
190
+ await expect(lowlevel.call('pro2-id', 'ProtocolInfoRequest', {})).resolves.toEqual({
191
+ type: 'ProtocolInfo',
192
+ message: {
193
+ version: 1,
194
+ supported_messages: [60200, 60201, 60206, 60207],
195
+ protobuf_definition: 'onekey-protocol-v2',
196
+ },
197
+ });
198
+ expect(plugin.send).toHaveBeenCalled();
199
+ const sentSeqs = plugin.send.mock.calls.map(([, hex]) =>
200
+ Number.parseInt(hex.slice(12, 14), 16)
201
+ );
202
+ expect(sentSeqs).toEqual([1, 2]);
203
+ });
204
+
205
+ test('falls back to Protocol V2 probe for unnamed Protocol V2 devices', async () => {
206
+ const probeResponse = ProtocolV2.encodeFrame(
207
+ schemas,
208
+ 'Success',
209
+ { message: 'ok' },
210
+ { router: PROTOCOL_V2_CHANNEL_BLE_UART }
211
+ );
212
+ const plugin = createPlugin({
213
+ devices: [{ id: 'unknown-pro2-id', name: 'Unknown BLE Device', commType: 'ble' }],
214
+ responses: [new Error('Protocol V1 probe timed out'), bytesToHex(probeResponse)],
215
+ });
216
+ const lowlevel = configureTransport(plugin);
217
+
218
+ await expect(lowlevel.acquire({ uuid: 'unknown-pro2-id' })).resolves.toEqual({
219
+ uuid: 'unknown-pro2-id',
220
+ protocolType: 'V2',
221
+ });
222
+ expect(lowlevel.getProtocolType('unknown-pro2-id')).toBe('V2');
223
+ });
224
+
225
+ test('retains the Protocol V2 hint and sequence cursor across release and reacquire', async () => {
226
+ const probeResponse = ProtocolV2.encodeFrame(
227
+ schemas,
228
+ 'Success',
229
+ { message: 'ok' },
230
+ { router: PROTOCOL_V2_CHANNEL_BLE_UART }
231
+ );
232
+ const plugin = createPlugin({
233
+ devices: [{ id: 'reconnect-pro2-id', name: 'OneKey Pro 2', commType: 'ble' }],
234
+ responses: [bytesToHex(probeResponse), bytesToHex(probeResponse)],
235
+ });
236
+ const lowlevel = configureTransport(plugin);
237
+
238
+ await lowlevel.enumerate();
239
+ await expect(lowlevel.acquire({ uuid: 'reconnect-pro2-id' })).resolves.toEqual({
240
+ uuid: 'reconnect-pro2-id',
241
+ protocolType: 'V2',
242
+ });
243
+ await lowlevel.release('reconnect-pro2-id');
244
+ await expect(lowlevel.acquire({ uuid: 'reconnect-pro2-id' })).resolves.toEqual({
245
+ uuid: 'reconnect-pro2-id',
246
+ protocolType: 'V2',
247
+ });
248
+
249
+ const sentSeqs = plugin.send.mock.calls.map(([, hex]) =>
250
+ Number.parseInt(hex.slice(12, 14), 16)
251
+ );
252
+ expect(sentSeqs).toEqual([1, 2]);
253
+ });
254
+
255
+ test('reuses the active generation when Core acquires the same BLE connection again', async () => {
256
+ const probeResponse = ProtocolV2.encodeFrame(
257
+ schemas,
258
+ 'Success',
259
+ { message: 'ok' },
260
+ { router: PROTOCOL_V2_CHANNEL_BLE_UART }
261
+ );
262
+ const plugin = createPlugin({
263
+ devices: [{ id: 'repeated-acquire-id', name: 'OneKey Pro 2', commType: 'ble' }],
264
+ responses: [bytesToHex(probeResponse), bytesToHex(probeResponse)],
265
+ });
266
+ const lowlevel = configureTransport(plugin);
267
+
268
+ await expect(
269
+ lowlevel.acquire({ uuid: 'repeated-acquire-id', expectedProtocol: 'V2' })
270
+ ).resolves.toEqual({
271
+ uuid: 'repeated-acquire-id',
272
+ protocolType: 'V2',
273
+ });
274
+ await lowlevel.call('repeated-acquire-id', 'Ping', { message: 'first-acquire' });
275
+ await expect(
276
+ lowlevel.acquire({ uuid: 'repeated-acquire-id', expectedProtocol: 'V2' })
277
+ ).resolves.toEqual({
278
+ uuid: 'repeated-acquire-id',
279
+ protocolType: 'V2',
280
+ });
281
+ await lowlevel.call('repeated-acquire-id', 'Ping', { message: 'second-acquire' });
282
+
283
+ const sentSeqs = plugin.send.mock.calls.map(([, hex]) =>
284
+ Number.parseInt(hex.slice(12, 14), 16)
285
+ );
286
+ expect(sentSeqs).toEqual([1, 2]);
287
+ });
288
+
289
+ test('trusts explicit Protocol V2 during bootloader reconnect without probing Ping', async () => {
290
+ const plugin = createPlugin({
291
+ devices: [{ id: 'bootloader-v2-id', name: 'OneKey Pro 2', commType: 'ble' }],
292
+ responses: [],
293
+ });
294
+ const lowlevel = configureTransport(plugin);
295
+
296
+ await expect(
297
+ lowlevel.acquire({ uuid: 'bootloader-v2-id', expectedProtocol: 'V2' })
298
+ ).resolves.toEqual({
299
+ uuid: 'bootloader-v2-id',
300
+ protocolType: 'V2',
301
+ });
302
+ expect(plugin.send).not.toHaveBeenCalled();
303
+ expect(plugin.receive).not.toHaveBeenCalled();
304
+ });
305
+
306
+ test('resets the lowlevel connection before probing Protocol V2 after a V1 timeout', async () => {
307
+ const probeResponse = ProtocolV2.encodeFrame(
308
+ schemas,
309
+ 'Success',
310
+ { message: 'ok' },
311
+ { router: PROTOCOL_V2_CHANNEL_BLE_UART }
312
+ );
313
+ let staleReceivePending = false;
314
+ let resetAfterTimeout = false;
315
+ const plugin = createPlugin({
316
+ devices: [{ id: 'slow-v2-id', name: 'Unknown BLE Device', commType: 'ble' }],
317
+ responses: [],
318
+ });
319
+ plugin.disconnect.mockImplementation(() => {
320
+ staleReceivePending = false;
321
+ resetAfterTimeout = true;
322
+ return Promise.resolve();
323
+ });
324
+ plugin.receive.mockImplementation(() => {
325
+ if (!staleReceivePending && !resetAfterTimeout) {
326
+ staleReceivePending = true;
327
+ return new Promise(() => {});
328
+ }
329
+ if (staleReceivePending) {
330
+ return Promise.reject(new Error('stale receive still pending'));
331
+ }
332
+ return Promise.resolve(bytesToHex(probeResponse));
333
+ });
334
+ const lowlevel = configureTransport(plugin);
335
+
336
+ await expect(lowlevel.acquire({ uuid: 'slow-v2-id' })).resolves.toEqual({
337
+ uuid: 'slow-v2-id',
338
+ protocolType: 'V2',
339
+ });
340
+ expect(plugin.disconnect).toHaveBeenCalledWith('slow-v2-id');
341
+ expect(plugin.connect).toHaveBeenCalledTimes(2);
342
+ });
343
+
344
+ test('disconnects a tainted Protocol V2 link after a response timeout', async () => {
345
+ const plugin = createPlugin({
346
+ devices: [{ id: 'timeout-v2-id', name: 'OneKey Pro 2', commType: 'ble' }],
347
+ responses: [],
348
+ });
349
+ plugin.receive.mockImplementation(() => new Promise(() => {}));
350
+ const lowlevel = configureTransport(plugin);
351
+
352
+ await lowlevel.acquire({ uuid: 'timeout-v2-id', expectedProtocol: 'V2' });
353
+ plugin.disconnect.mockClear();
354
+ await expect(
355
+ lowlevel.call('timeout-v2-id', 'Ping', { message: 'timeout' }, { timeoutMs: 10 })
356
+ ).rejects.toThrow('Lowlevel response timeout after 10ms for Ping');
357
+
358
+ expect(plugin.disconnect).toHaveBeenCalledWith('timeout-v2-id');
359
+ });
360
+
361
+ test('verifies expected Protocol V1 instead of trusting the requested protocol', async () => {
362
+ const plugin = createPlugin({
363
+ devices: [{ id: 'v2-id', name: 'Unknown BLE Device', commType: 'ble' }],
364
+ responses: [new Error('Protocol V1 probe timed out')],
365
+ });
366
+ const lowlevel = configureTransport(plugin);
367
+
368
+ await expect(lowlevel.acquire({ uuid: 'v2-id', expectedProtocol: 'V1' })).rejects.toThrow(
369
+ 'Device protocol mismatch: expected V1'
370
+ );
371
+ });
372
+
373
+ test('rejects automatic detection instead of caching V1 when both protocol probes fail', async () => {
374
+ const plugin = createPlugin({
375
+ devices: [{ id: 'flaky-pro2-id', name: 'Unknown BLE Device', commType: 'ble' }],
376
+ responses: [
377
+ new Error('Protocol V1 probe timed out'),
378
+ new Error('Protocol V2 probe timed out'),
379
+ ],
380
+ });
381
+ const lowlevel = configureTransport(plugin);
382
+
383
+ await expect(lowlevel.acquire({ uuid: 'flaky-pro2-id' })).rejects.toThrow(
384
+ 'Unable to detect BLE protocol'
385
+ );
386
+ expect(lowlevel.getProtocolType('flaky-pro2-id')).toBeUndefined();
387
+ });
388
+ });
package/dist/index.d.ts CHANGED
@@ -1,26 +1,53 @@
1
- import * as _onekeyfe_hd_transport from '@onekeyfe/hd-transport';
2
- import _onekeyfe_hd_transport__default, { LowlevelTransportSharedPlugin } from '@onekeyfe/hd-transport';
1
+ import * as transport from '@onekeyfe/hd-transport';
2
+ import transport__default, { ProtocolType, LowlevelTransportSharedPlugin, LowLevelDevice, TransportCallOptions } from '@onekeyfe/hd-transport';
3
3
  import EventEmitter from 'events';
4
4
 
5
5
  type LowLevelAcquireInput = {
6
6
  uuid: string;
7
+ expectedProtocol?: ProtocolType;
7
8
  };
8
9
 
9
10
  declare class LowlevelTransport {
10
- _messages: ReturnType<typeof _onekeyfe_hd_transport__default.parseConfigure> | undefined;
11
+ _messages: ReturnType<typeof transport__default.parseConfigure> | undefined;
12
+ _messagesV2: ReturnType<typeof transport__default.parseConfigure> | undefined;
11
13
  configured: boolean;
12
14
  Log?: any;
13
15
  emitter?: EventEmitter;
14
16
  plugin: LowlevelTransportSharedPlugin;
17
+ private deviceProtocol;
18
+ private deviceProtocolHints;
19
+ private protocolV2Assemblers;
20
+ private protocolV2Generations;
21
+ private connectedDevices;
22
+ private protocolV2Links;
23
+ getProtocolType(path: string): ProtocolType | undefined;
15
24
  init(logger: any, emitter: EventEmitter, plugin: LowlevelTransportSharedPlugin): void;
16
25
  configure(signedData: any): void;
26
+ configureProtocolV2(signedData: any): void;
17
27
  listen(): void;
18
- enumerate(): Promise<_onekeyfe_hd_transport.LowLevelDevice[]>;
28
+ enumerate(): Promise<LowLevelDevice[]>;
19
29
  acquire(input: LowLevelAcquireInput): Promise<{
20
30
  uuid: string;
31
+ protocolType: ProtocolType;
21
32
  }>;
22
33
  release(uuid: string): Promise<boolean>;
23
- call(uuid: string, name: string, data: Record<string, unknown>): Promise<_onekeyfe_hd_transport.MessageFromOneKey>;
34
+ call(uuid: string, name: string, data: Record<string, unknown>, options?: TransportCallOptions): Promise<transport.MessageFromOneKey>;
35
+ private callProtocolV1;
36
+ private createProtocolTimeoutError;
37
+ private createProtocolMismatchError;
38
+ private createProtocolDetectionError;
39
+ private clearProbeProtocol;
40
+ private detectProtocol;
41
+ private resetConnectionAfterProbe;
42
+ private probeProtocolV1;
43
+ private probeProtocolV2;
44
+ private receiveHex;
45
+ private readProtocolV1Message;
46
+ private readProtocolV2Frame;
47
+ private writeProtocolV2Frame;
48
+ private callProtocolV2;
49
+ private createProtocolV2Adapter;
50
+ private advanceProtocolV2Generation;
24
51
  cancel(): void;
25
52
  }
26
53
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,SAA8B,MAAM,wBAAwB,CAAC;AAEpE,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AAC5E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAIpD,MAAM,CAAC,OAAO,OAAO,iBAAiB;IACpC,SAAS,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAEnE,UAAU,UAAS;IAEnB,GAAG,CAAC,EAAE,GAAG,CAAC;IAEV,OAAO,CAAC,EAAE,YAAY,CAAC;IAEvB,MAAM,EAAE,6BAA6B,CAAuC;IAE5E,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,6BAA6B;IAO9E,SAAS,CAAC,UAAU,EAAE,GAAG;IAMzB,MAAM;IAIN,SAAS;IAIH,OAAO,CAAC,KAAK,EAAE,oBAAoB;;;IAanC,OAAO,CAAC,IAAI,EAAE,MAAM;IAUpB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAuCpE,MAAM;CAGP"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,SAWN,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EACV,cAAc,EACd,6BAA6B,EAC7B,YAAY,EACZ,oBAAoB,EACrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAqBpD,MAAM,CAAC,OAAO,OAAO,iBAAiB;IACpC,SAAS,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAEnE,WAAW,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAErE,UAAU,UAAS;IAEnB,GAAG,CAAC,EAAE,GAAG,CAAC;IAEV,OAAO,CAAC,EAAE,YAAY,CAAC;IAEvB,MAAM,EAAE,6BAA6B,CAAuC;IAE5E,OAAO,CAAC,cAAc,CAAwC;IAE9D,OAAO,CAAC,mBAAmB,CAAwC;IAEnE,OAAO,CAAC,oBAAoB,CAAoD;IAEhF,OAAO,CAAC,qBAAqB,CAAkC;IAE/D,OAAO,CAAC,gBAAgB,CAA0B;IAElD,OAAO,CAAC,eAAe,CA6BpB;IAEH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAIvD,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,6BAA6B;IAO9E,SAAS,CAAC,UAAU,EAAE,GAAG;IAMzB,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAOnC,MAAM;IAIA,SAAS;IAWT,OAAO,CAAC,KAAK,EAAE,oBAAoB;;;;IA6BnC,OAAO,CAAC,IAAI,EAAE,MAAM;IAgBpB,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,oBAAoB;YAsBlB,cAAc;IAoC5B,OAAO,CAAC,0BAA0B;IAOlC,OAAO,CAAC,2BAA2B;IAOnC,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,kBAAkB;YAMZ,cAAc;YAsDd,yBAAyB;YAiCzB,eAAe;YAgBf,eAAe;YA6Bf,UAAU;YAUV,qBAAqB;YAmBrB,mBAAmB;YAqBnB,oBAAoB;YAOpB,cAAc;IA6B5B,OAAO,CAAC,uBAAuB;IAkC/B,OAAO,CAAC,2BAA2B;IAMnC,MAAM;CAGP"}