@onekeyfe/hd-transport-lowlevel 1.2.0-alpha.1 → 1.2.0-alpha.100
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/__tests__/firmware-upload-progress.test.js +42 -0
- package/__tests__/protocol-v2.test.js +228 -18
- package/dist/index.d.ts +17 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +179 -70
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/index.ts +225 -84
- package/src/types.ts +1 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
2
|
+
const { getProtocolV1SendOptions, shouldLogFirmwareUploadProgress } = require('../src');
|
|
3
|
+
|
|
4
|
+
describe('firmware upload progress logging', () => {
|
|
5
|
+
test('按 5% 进度限流打印', () => {
|
|
6
|
+
expect(
|
|
7
|
+
shouldLogFirmwareUploadProgress({
|
|
8
|
+
percent: 9,
|
|
9
|
+
lastLoggedPercent: 5,
|
|
10
|
+
now: 5_000,
|
|
11
|
+
lastLoggedAt: 0,
|
|
12
|
+
})
|
|
13
|
+
).toBe(false);
|
|
14
|
+
|
|
15
|
+
expect(
|
|
16
|
+
shouldLogFirmwareUploadProgress({
|
|
17
|
+
percent: 10,
|
|
18
|
+
lastLoggedPercent: 5,
|
|
19
|
+
now: 5_000,
|
|
20
|
+
lastLoggedAt: 0,
|
|
21
|
+
})
|
|
22
|
+
).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('进度不足 5% 时最长每 10 秒打印一次心跳', () => {
|
|
26
|
+
expect(
|
|
27
|
+
shouldLogFirmwareUploadProgress({
|
|
28
|
+
percent: 7,
|
|
29
|
+
lastLoggedPercent: 5,
|
|
30
|
+
now: 10_000,
|
|
31
|
+
lastLoggedAt: 0,
|
|
32
|
+
})
|
|
33
|
+
).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('firmware upload write mode', () => {
|
|
38
|
+
test('固件上传使用带响应写入,普通命令保持默认模式', () => {
|
|
39
|
+
expect(getProtocolV1SendOptions('FirmwareUpload')).toEqual({ withoutResponse: false });
|
|
40
|
+
expect(getProtocolV1SendOptions('Initialize')).toBeUndefined();
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -29,21 +29,25 @@ const protocolV1Schema = {
|
|
|
29
29
|
|
|
30
30
|
const protocolV2Schema = {
|
|
31
31
|
nested: {
|
|
32
|
-
|
|
32
|
+
ProtocolInfoRequest: {
|
|
33
33
|
fields: {},
|
|
34
34
|
},
|
|
35
|
-
|
|
35
|
+
ProtocolInfo: {
|
|
36
36
|
fields: {
|
|
37
|
-
|
|
37
|
+
version: {
|
|
38
38
|
type: 'uint32',
|
|
39
39
|
id: 1,
|
|
40
40
|
},
|
|
41
|
-
|
|
41
|
+
supported_messages: {
|
|
42
|
+
rule: 'repeated',
|
|
42
43
|
type: 'uint32',
|
|
43
44
|
id: 2,
|
|
45
|
+
options: {
|
|
46
|
+
packed: false,
|
|
47
|
+
},
|
|
44
48
|
},
|
|
45
|
-
|
|
46
|
-
type: '
|
|
49
|
+
protobuf_definition: {
|
|
50
|
+
type: 'string',
|
|
47
51
|
id: 3,
|
|
48
52
|
},
|
|
49
53
|
},
|
|
@@ -66,8 +70,8 @@ const protocolV2Schema = {
|
|
|
66
70
|
},
|
|
67
71
|
MessageType: {
|
|
68
72
|
values: {
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
MessageType_ProtocolInfoRequest: 60200,
|
|
74
|
+
MessageType_ProtocolInfo: 60201,
|
|
71
75
|
MessageType_Ping: 60206,
|
|
72
76
|
MessageType_Success: 60207,
|
|
73
77
|
},
|
|
@@ -118,6 +122,49 @@ const splitFrame = (frame, index) => [
|
|
|
118
122
|
];
|
|
119
123
|
|
|
120
124
|
describe('LowlevelTransport protocol framing', () => {
|
|
125
|
+
test('falls back to Protocol V2 when a cached V1 hint is stale', async () => {
|
|
126
|
+
const plugin = createPlugin({ devices: [], responses: [] });
|
|
127
|
+
const lowlevel = configureTransport(plugin);
|
|
128
|
+
const events = [];
|
|
129
|
+
lowlevel.probeProtocolV1 = jest.fn().mockImplementation(() => {
|
|
130
|
+
events.push('probe-v1');
|
|
131
|
+
return Promise.resolve(false);
|
|
132
|
+
});
|
|
133
|
+
lowlevel.resetConnectionAfterProbe = jest.fn().mockImplementation(() => {
|
|
134
|
+
events.push('reset');
|
|
135
|
+
return Promise.resolve();
|
|
136
|
+
});
|
|
137
|
+
lowlevel.probeProtocolV2 = jest.fn().mockImplementation(() => {
|
|
138
|
+
events.push('probe-v2');
|
|
139
|
+
return Promise.resolve(true);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
await expect(lowlevel.detectProtocol('pro-lowlevel', undefined, 'V1')).resolves.toBe('V2');
|
|
143
|
+
|
|
144
|
+
expect(events).toEqual(['probe-v1', 'reset', 'probe-v2']);
|
|
145
|
+
expect(lowlevel.getProtocolType('pro-lowlevel')).toBe('V2');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test('keeps active links when the Protocol V2 schema is configured repeatedly', () => {
|
|
149
|
+
const lowlevel = new LowlevelTransport();
|
|
150
|
+
const invalidateAllLinks = jest.fn().mockResolvedValue(undefined);
|
|
151
|
+
lowlevel.protocolV2Links.invalidateAllLinks = invalidateAllLinks;
|
|
152
|
+
|
|
153
|
+
lowlevel.configureProtocolV2(protocolV2Schema);
|
|
154
|
+
lowlevel.configureProtocolV2(protocolV2Schema);
|
|
155
|
+
|
|
156
|
+
expect(invalidateAllLinks).not.toHaveBeenCalled();
|
|
157
|
+
|
|
158
|
+
lowlevel.configureProtocolV2({
|
|
159
|
+
nested: {
|
|
160
|
+
...protocolV2Schema.nested,
|
|
161
|
+
ExtraMessage: { fields: {} },
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
expect(invalidateAllLinks).toHaveBeenCalledWith('Protocol V2 schema reconfigured');
|
|
166
|
+
});
|
|
167
|
+
|
|
121
168
|
test('keeps Protocol V1 raw notification chunks compatible', async () => {
|
|
122
169
|
const responseChunks = ProtocolV1.encodeTransportPackets(schemas.protocolV1, 'Success', {
|
|
123
170
|
message: 'ok',
|
|
@@ -138,6 +185,23 @@ describe('LowlevelTransport protocol framing', () => {
|
|
|
138
185
|
});
|
|
139
186
|
});
|
|
140
187
|
|
|
188
|
+
test('uses the Protocol V2 BLE writer with the lowlevel compatibility packet size', async () => {
|
|
189
|
+
const plugin = createPlugin({ devices: [], responses: [] });
|
|
190
|
+
const lowlevel = configureTransport(plugin);
|
|
191
|
+
const context = {
|
|
192
|
+
messageName: 'Ping',
|
|
193
|
+
timeoutMs: 1000,
|
|
194
|
+
highThroughput: false,
|
|
195
|
+
generation: 1,
|
|
196
|
+
signal: new AbortController().signal,
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
await lowlevel.writeProtocolV2Frame('pro2-id', new Uint8Array(130), context, jest.fn());
|
|
200
|
+
|
|
201
|
+
expect(plugin.send).toHaveBeenCalledTimes(3);
|
|
202
|
+
expect(plugin.send.mock.calls.map(([, hex]) => hex.length / 2)).toEqual([64, 64, 2]);
|
|
203
|
+
});
|
|
204
|
+
|
|
141
205
|
test('rejects calls before protocol detection', async () => {
|
|
142
206
|
const responseChunks = ProtocolV1.encodeTransportPackets(schemas.protocolV1, 'Success', {
|
|
143
207
|
message: 'ok',
|
|
@@ -162,13 +226,13 @@ describe('LowlevelTransport protocol framing', () => {
|
|
|
162
226
|
);
|
|
163
227
|
const callResponse = ProtocolV2.encodeFrame(
|
|
164
228
|
schemas,
|
|
165
|
-
'
|
|
229
|
+
'ProtocolInfo',
|
|
166
230
|
{
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
231
|
+
version: 1,
|
|
232
|
+
supported_messages: [60200, 60201, 60206, 60207],
|
|
233
|
+
protobuf_definition: 'onekey-protocol-v2',
|
|
170
234
|
},
|
|
171
|
-
{ router: PROTOCOL_V2_CHANNEL_BLE_UART }
|
|
235
|
+
{ router: PROTOCOL_V2_CHANNEL_BLE_UART, seq: 2 }
|
|
172
236
|
);
|
|
173
237
|
const plugin = createPlugin({
|
|
174
238
|
devices: [{ id: 'pro2-id', name: 'OneKey Pro 2', commType: 'ble' }],
|
|
@@ -183,15 +247,19 @@ describe('LowlevelTransport protocol framing', () => {
|
|
|
183
247
|
uuid: 'pro2-id',
|
|
184
248
|
protocolType: 'V2',
|
|
185
249
|
});
|
|
186
|
-
await expect(lowlevel.call('pro2-id', '
|
|
187
|
-
type: '
|
|
250
|
+
await expect(lowlevel.call('pro2-id', 'ProtocolInfoRequest', {})).resolves.toEqual({
|
|
251
|
+
type: 'ProtocolInfo',
|
|
188
252
|
message: {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
253
|
+
version: 1,
|
|
254
|
+
supported_messages: [60200, 60201, 60206, 60207],
|
|
255
|
+
protobuf_definition: 'onekey-protocol-v2',
|
|
192
256
|
},
|
|
193
257
|
});
|
|
194
258
|
expect(plugin.send).toHaveBeenCalled();
|
|
259
|
+
const sentSeqs = plugin.send.mock.calls.map(([, hex]) =>
|
|
260
|
+
Number.parseInt(hex.slice(12, 14), 16)
|
|
261
|
+
);
|
|
262
|
+
expect(sentSeqs).toEqual([1, 2]);
|
|
195
263
|
});
|
|
196
264
|
|
|
197
265
|
test('falls back to Protocol V2 probe for unnamed Protocol V2 devices', async () => {
|
|
@@ -214,6 +282,97 @@ describe('LowlevelTransport protocol framing', () => {
|
|
|
214
282
|
expect(lowlevel.getProtocolType('unknown-pro2-id')).toBe('V2');
|
|
215
283
|
});
|
|
216
284
|
|
|
285
|
+
test('retains the Protocol V2 hint and sequence cursor across release and reacquire', async () => {
|
|
286
|
+
const probeResponse = ProtocolV2.encodeFrame(
|
|
287
|
+
schemas,
|
|
288
|
+
'Success',
|
|
289
|
+
{ message: 'ok' },
|
|
290
|
+
{ router: PROTOCOL_V2_CHANNEL_BLE_UART }
|
|
291
|
+
);
|
|
292
|
+
const plugin = createPlugin({
|
|
293
|
+
devices: [{ id: 'reconnect-pro2-id', name: 'OneKey Pro 2', commType: 'ble' }],
|
|
294
|
+
responses: [bytesToHex(probeResponse), bytesToHex(probeResponse)],
|
|
295
|
+
});
|
|
296
|
+
const lowlevel = configureTransport(plugin);
|
|
297
|
+
|
|
298
|
+
await lowlevel.enumerate();
|
|
299
|
+
await expect(lowlevel.acquire({ uuid: 'reconnect-pro2-id' })).resolves.toEqual({
|
|
300
|
+
uuid: 'reconnect-pro2-id',
|
|
301
|
+
protocolType: 'V2',
|
|
302
|
+
});
|
|
303
|
+
await lowlevel.release('reconnect-pro2-id');
|
|
304
|
+
await expect(lowlevel.acquire({ uuid: 'reconnect-pro2-id' })).resolves.toEqual({
|
|
305
|
+
uuid: 'reconnect-pro2-id',
|
|
306
|
+
protocolType: 'V2',
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
const sentSeqs = plugin.send.mock.calls.map(([, hex]) =>
|
|
310
|
+
Number.parseInt(hex.slice(12, 14), 16)
|
|
311
|
+
);
|
|
312
|
+
expect(sentSeqs).toEqual([1, 2]);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
test('reuses the active generation when Core acquires the same BLE connection again', async () => {
|
|
316
|
+
const responses = [1, 2, 3, 4].map(seq =>
|
|
317
|
+
bytesToHex(
|
|
318
|
+
ProtocolV2.encodeFrame(
|
|
319
|
+
schemas,
|
|
320
|
+
'Success',
|
|
321
|
+
{ message: 'ok' },
|
|
322
|
+
{ router: PROTOCOL_V2_CHANNEL_BLE_UART, seq }
|
|
323
|
+
)
|
|
324
|
+
)
|
|
325
|
+
);
|
|
326
|
+
const plugin = createPlugin({
|
|
327
|
+
devices: [{ id: 'repeated-acquire-id', name: 'OneKey Pro 2', commType: 'ble' }],
|
|
328
|
+
responses,
|
|
329
|
+
});
|
|
330
|
+
const lowlevel = configureTransport(plugin);
|
|
331
|
+
|
|
332
|
+
await expect(
|
|
333
|
+
lowlevel.acquire({ uuid: 'repeated-acquire-id', expectedProtocol: 'V2' })
|
|
334
|
+
).resolves.toEqual({
|
|
335
|
+
uuid: 'repeated-acquire-id',
|
|
336
|
+
protocolType: 'V2',
|
|
337
|
+
});
|
|
338
|
+
await lowlevel.call('repeated-acquire-id', 'Ping', { message: 'first-acquire' });
|
|
339
|
+
await expect(
|
|
340
|
+
lowlevel.acquire({ uuid: 'repeated-acquire-id', expectedProtocol: 'V2' })
|
|
341
|
+
).resolves.toEqual({
|
|
342
|
+
uuid: 'repeated-acquire-id',
|
|
343
|
+
protocolType: 'V2',
|
|
344
|
+
});
|
|
345
|
+
await lowlevel.call('repeated-acquire-id', 'Ping', { message: 'second-acquire' });
|
|
346
|
+
|
|
347
|
+
const sentSeqs = plugin.send.mock.calls.map(([, hex]) =>
|
|
348
|
+
Number.parseInt(hex.slice(12, 14), 16)
|
|
349
|
+
);
|
|
350
|
+
expect(sentSeqs).toEqual([1, 2, 3, 4]);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
test('actively probes explicit Protocol V2 during bootloader reconnect', async () => {
|
|
354
|
+
const probeResponse = ProtocolV2.encodeFrame(
|
|
355
|
+
schemas,
|
|
356
|
+
'Success',
|
|
357
|
+
{ message: 'ok' },
|
|
358
|
+
{ router: PROTOCOL_V2_CHANNEL_BLE_UART }
|
|
359
|
+
);
|
|
360
|
+
const plugin = createPlugin({
|
|
361
|
+
devices: [{ id: 'bootloader-v2-id', name: 'OneKey Pro 2', commType: 'ble' }],
|
|
362
|
+
responses: [bytesToHex(probeResponse)],
|
|
363
|
+
});
|
|
364
|
+
const lowlevel = configureTransport(plugin);
|
|
365
|
+
|
|
366
|
+
await expect(
|
|
367
|
+
lowlevel.acquire({ uuid: 'bootloader-v2-id', expectedProtocol: 'V2' })
|
|
368
|
+
).resolves.toEqual({
|
|
369
|
+
uuid: 'bootloader-v2-id',
|
|
370
|
+
protocolType: 'V2',
|
|
371
|
+
});
|
|
372
|
+
expect(plugin.send).toHaveBeenCalledTimes(1);
|
|
373
|
+
expect(plugin.receive).toHaveBeenCalledTimes(1);
|
|
374
|
+
});
|
|
375
|
+
|
|
217
376
|
test('resets the lowlevel connection before probing Protocol V2 after a V1 timeout', async () => {
|
|
218
377
|
const probeResponse = ProtocolV2.encodeFrame(
|
|
219
378
|
schemas,
|
|
@@ -252,6 +411,57 @@ describe('LowlevelTransport protocol framing', () => {
|
|
|
252
411
|
expect(plugin.connect).toHaveBeenCalledTimes(2);
|
|
253
412
|
});
|
|
254
413
|
|
|
414
|
+
test('disconnects a tainted Protocol V2 link after a response timeout', async () => {
|
|
415
|
+
const probeResponse = ProtocolV2.encodeFrame(
|
|
416
|
+
schemas,
|
|
417
|
+
'Success',
|
|
418
|
+
{ message: 'ok' },
|
|
419
|
+
{ router: PROTOCOL_V2_CHANNEL_BLE_UART }
|
|
420
|
+
);
|
|
421
|
+
const plugin = createPlugin({
|
|
422
|
+
devices: [{ id: 'timeout-v2-id', name: 'OneKey Pro 2', commType: 'ble' }],
|
|
423
|
+
responses: [bytesToHex(probeResponse)],
|
|
424
|
+
});
|
|
425
|
+
let receiveCount = 0;
|
|
426
|
+
plugin.receive.mockImplementation(() => {
|
|
427
|
+
receiveCount += 1;
|
|
428
|
+
return receiveCount === 1
|
|
429
|
+
? Promise.resolve(bytesToHex(probeResponse))
|
|
430
|
+
: new Promise(() => {});
|
|
431
|
+
});
|
|
432
|
+
const lowlevel = configureTransport(plugin);
|
|
433
|
+
|
|
434
|
+
await lowlevel.acquire({ uuid: 'timeout-v2-id', expectedProtocol: 'V2' });
|
|
435
|
+
plugin.disconnect.mockClear();
|
|
436
|
+
await expect(
|
|
437
|
+
lowlevel.call('timeout-v2-id', 'Ping', { message: 'timeout' }, { timeoutMs: 10 })
|
|
438
|
+
).rejects.toThrow('Lowlevel response timeout after 10ms for Ping');
|
|
439
|
+
|
|
440
|
+
expect(plugin.disconnect).toHaveBeenCalledWith('timeout-v2-id');
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
test('preserves an undefined business timeout outside explicit probes', async () => {
|
|
444
|
+
const plugin = createPlugin({
|
|
445
|
+
devices: [{ id: 'v2-id', name: 'OneKey Pro 2', commType: 'ble' }],
|
|
446
|
+
responses: [],
|
|
447
|
+
});
|
|
448
|
+
const lowlevel = configureTransport(plugin);
|
|
449
|
+
lowlevel.deviceProtocol.set('v2-id', 'V2');
|
|
450
|
+
const linkCall = jest
|
|
451
|
+
.spyOn(lowlevel.protocolV2Links, 'call')
|
|
452
|
+
.mockResolvedValue({ type: 'Success', message: {} });
|
|
453
|
+
|
|
454
|
+
await lowlevel.call('v2-id', 'Ping', { message: 'no-business-timeout' });
|
|
455
|
+
|
|
456
|
+
expect(linkCall).toHaveBeenCalledWith(
|
|
457
|
+
'v2-id',
|
|
458
|
+
expect.any(Function),
|
|
459
|
+
'Ping',
|
|
460
|
+
{ message: 'no-business-timeout' },
|
|
461
|
+
undefined
|
|
462
|
+
);
|
|
463
|
+
});
|
|
464
|
+
|
|
255
465
|
test('verifies expected Protocol V1 instead of trusting the requested protocol', async () => {
|
|
256
466
|
const plugin = createPlugin({
|
|
257
467
|
devices: [{ id: 'v2-id', name: 'Unknown BLE Device', commType: 'ble' }],
|
package/dist/index.d.ts
CHANGED
|
@@ -5,8 +5,18 @@ import EventEmitter from 'events';
|
|
|
5
5
|
type LowLevelAcquireInput = {
|
|
6
6
|
uuid: string;
|
|
7
7
|
expectedProtocol?: ProtocolType;
|
|
8
|
+
protocolHint?: ProtocolType;
|
|
8
9
|
};
|
|
9
10
|
|
|
11
|
+
declare function shouldLogFirmwareUploadProgress({ percent, lastLoggedPercent, now, lastLoggedAt, }: {
|
|
12
|
+
percent: number;
|
|
13
|
+
lastLoggedPercent: number;
|
|
14
|
+
now: number;
|
|
15
|
+
lastLoggedAt: number;
|
|
16
|
+
}): boolean;
|
|
17
|
+
declare function getProtocolV1SendOptions(name: string): {
|
|
18
|
+
withoutResponse: boolean;
|
|
19
|
+
} | undefined;
|
|
10
20
|
declare class LowlevelTransport {
|
|
11
21
|
_messages: ReturnType<typeof transport__default.parseConfigure> | undefined;
|
|
12
22
|
_messagesV2: ReturnType<typeof transport__default.parseConfigure> | undefined;
|
|
@@ -17,6 +27,10 @@ declare class LowlevelTransport {
|
|
|
17
27
|
private deviceProtocol;
|
|
18
28
|
private deviceProtocolHints;
|
|
19
29
|
private protocolV2Assemblers;
|
|
30
|
+
private protocolV2Generations;
|
|
31
|
+
private connectedDevices;
|
|
32
|
+
private protocolV2Links;
|
|
33
|
+
private protocolV2SchemaConfiguration;
|
|
20
34
|
getProtocolType(path: string): ProtocolType | undefined;
|
|
21
35
|
init(logger: any, emitter: EventEmitter, plugin: LowlevelTransportSharedPlugin): void;
|
|
22
36
|
configure(signedData: any): void;
|
|
@@ -43,7 +57,9 @@ declare class LowlevelTransport {
|
|
|
43
57
|
private readProtocolV2Frame;
|
|
44
58
|
private writeProtocolV2Frame;
|
|
45
59
|
private callProtocolV2;
|
|
60
|
+
private createProtocolV2Adapter;
|
|
61
|
+
private advanceProtocolV2Generation;
|
|
46
62
|
cancel(): void;
|
|
47
63
|
}
|
|
48
64
|
|
|
49
|
-
export { LowlevelTransport as default };
|
|
65
|
+
export { LowlevelTransport as default, getProtocolV1SendOptions, shouldLogFirmwareUploadProgress };
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,SAYN,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EACV,cAAc,EACd,6BAA6B,EAC7B,YAAY,EAEZ,oBAAoB,EACrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAUpD,wBAAgB,+BAA+B,CAAC,EAC9C,OAAO,EACP,iBAAiB,EACjB,GAAG,EACH,YAAY,GACb,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;CACtB,WAMA;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM;;cAEpD;AAcD,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,OAAO,CAAC,6BAA6B,CAAqB;IAE1D,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;IAiBnC,MAAM;IAIA,SAAS;IAWT,OAAO,CAAC,KAAK,EAAE,oBAAoB;;;;IAgCnC,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;IA6E5B,OAAO,CAAC,0BAA0B;IAOlC,OAAO,CAAC,2BAA2B;IAOnC,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,kBAAkB;YAMZ,cAAc;YA2Cd,yBAAyB;YAiCzB,eAAe;YAgBf,eAAe;YA6Bf,UAAU;YAUV,qBAAqB;YAmBrB,mBAAmB;YAqBnB,oBAAoB;YAgBpB,cAAc;IAwB5B,OAAO,CAAC,uBAAuB;IAgC/B,OAAO,CAAC,2BAA2B;IAMnC,MAAM;CAGP"}
|