@intomind/sdk 0.0.0-stage → 1.4.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.
@@ -0,0 +1,523 @@
1
+ /**
2
+ * One device, as a state machine.
3
+ *
4
+ * Bytes go in, events come out, and commands go back. Nothing here performs
5
+ * input or output, so the same code runs behind a browser's Bluetooth
6
+ * stack, a desktop one, or a test with no Bluetooth at all.
7
+ */
8
+ import { CODE_BY_GAIN, CODE_BY_RATE, DeviceInfo, FILL, Invalid, continuity, decodeDeviceInfo, decodeEmbedding, decodePacket, decodePrediction, decodeResponse, decodeStatus, decodeTimeSync, encodeRequest, microvolts, BIAS_MODES, EMBEDDING_FORMS, IDENTIFY_MAX_SECONDS, INDICATOR_LEVELS, checkChain, encodeChain, encodePredictionInput, MODES, NAME_MAX_COMPOSED, PRODUCT_NAME, composeName, encodeModelInterval, encodeNameParts, nameFits, } from "./protocol.js";
9
+ import { Exchange, Timebase } from "./timebase.js";
10
+ /** Something a caller asked of a device that the device has not offered. */
11
+ export class SessionError extends Error {
12
+ /** Build one with the message explaining what was asked for. */
13
+ constructor(message) {
14
+ super(message);
15
+ this.name = "SessionError";
16
+ }
17
+ }
18
+ /** The device has not said what it is yet, so nothing can be decoded. */
19
+ export class NoDeviceInfo extends SessionError {
20
+ constructor() {
21
+ super("read device info first, so nothing has to be assumed");
22
+ this.name = "NoDeviceInfo";
23
+ }
24
+ }
25
+ /** The device does not claim the capability this needs. */
26
+ export class NotCapable extends SessionError {
27
+ /** Which capability was missing. */
28
+ capability;
29
+ /** Build one naming the missing capability. */
30
+ constructor(capability) {
31
+ super(`this device does not claim the ${capability} capability`);
32
+ this.name = "NotCapable";
33
+ this.capability = capability;
34
+ }
35
+ }
36
+ /** A run of samples that arrived together. */
37
+ export class Batch {
38
+ /** The device's own index for the first sample. */
39
+ index;
40
+ /** The device time of the first sample, in the device's ticks. */
41
+ deviceTime;
42
+ /** Channels per row. */
43
+ channels;
44
+ /** Converter counts, one row per sample, laid out row after row. */
45
+ counts;
46
+ /** Lead-off status latched with the most recent sample. */
47
+ leadoff;
48
+ /** Whether lead-off detection was running when these samples were taken, from the packet's flag. `leadoff` is zero both when every electrode was attached and when nothing was checking, and this tells the two apart. */
49
+ leadoffActive;
50
+ /** The gain the samples were taken at. */
51
+ gain;
52
+ /** The rate the samples were taken at, or null for a code this contract does not define. */
53
+ sampleRateHz;
54
+ /** The mode the samples were taken in: 0 normal, 1 test signal, 2 inputs shorted, 3 synthetic (1.3). */
55
+ mode;
56
+ /** 1.3: the samples were generated by the device, not measured (packet type 0x04). Never store one as a measurement. */
57
+ synthetic;
58
+ /** Build from decoded fields. `Session` is what calls this. */
59
+ constructor(f) {
60
+ this.index = f.index;
61
+ this.deviceTime = f.deviceTime;
62
+ this.channels = f.channels;
63
+ this.counts = f.counts;
64
+ this.leadoff = f.leadoff;
65
+ this.leadoffActive = f.leadoffActive ?? false;
66
+ this.gain = f.gain;
67
+ this.sampleRateHz = f.sampleRateHz;
68
+ this.mode = f.mode ?? 0;
69
+ this.synthetic = f.synthetic ?? false;
70
+ }
71
+ /** Samples in this batch. */
72
+ get rows() {
73
+ return this.channels === 0 ? 0 : this.counts.length / this.channels;
74
+ }
75
+ /** One converter count. */
76
+ count(row, channel) {
77
+ return this.counts[row * this.channels + channel];
78
+ }
79
+ /**
80
+ * One sample, in microvolts, with the device's own reference and width.
81
+ * Nothing is assumed about either.
82
+ */
83
+ microvolts(row, channel, info) {
84
+ return microvolts(this.count(row, channel), info.vrefUv, this.gain, info.adcBits);
85
+ }
86
+ }
87
+ /** One device. */
88
+ export class Session {
89
+ #info = null;
90
+ #timebase = null;
91
+ #previous = null;
92
+ /** The first index and device time of the last few packets passed on, what a copy is recognized by. */
93
+ #recent = [];
94
+ /** Samples the device's own indexing says never arrived, over this session. */
95
+ samplesLost = 0;
96
+ /** Breaks counted as a re-base rather than a loss, over this session. */
97
+ rebases = 0;
98
+ /** Notifications that were not a message, over this session: see the "undecodable" event. */
99
+ undecodable = 0;
100
+ /** Data packets delivered twice by the host and dropped: see the "duplicate" event. */
101
+ duplicates = 0;
102
+ /** What was read from the device info characteristic. */
103
+ onDeviceInfo(bytes) {
104
+ const info = decodeDeviceInfo(bytes);
105
+ this.#timebase = new Timebase(info.tickHz);
106
+ this.#info = info;
107
+ return info;
108
+ }
109
+ /** What the device said it is, or null before it has been read. */
110
+ get info() {
111
+ return this.#info;
112
+ }
113
+ /** The same, for a caller that cannot proceed without it. */
114
+ requireInfo() {
115
+ if (this.#info === null)
116
+ throw new NoDeviceInfo();
117
+ return this.#info;
118
+ }
119
+ /**
120
+ * Whether the device claims a capability. A device that has not said what
121
+ * it is claims nothing.
122
+ */
123
+ can(capability) {
124
+ return this.#info?.can(capability) ?? false;
125
+ }
126
+ /** The timebase fit from time exchanges, or null before `onDeviceInfo`. */
127
+ get timebase() {
128
+ return this.#timebase;
129
+ }
130
+ /** Host time for a device time, once enough exchanges have been taken. */
131
+ hostTime(deviceTicks) {
132
+ return this.#timebase?.hostTime(deviceTicks) ?? null;
133
+ }
134
+ // --- commands -------------------------------------------------------------
135
+ #command(opcode, arg = null) {
136
+ return { characteristic: FILL.CONTROL, bytes: encodeRequest(opcode, arg), withResponse: true };
137
+ }
138
+ #require(capability) {
139
+ if (!this.can(capability))
140
+ throw new NotCapable(capability);
141
+ }
142
+ /** Whether the device claims a capability from the second word of Device Info (1.3): synthetic, device_name. */
143
+ canHigh(capability) {
144
+ return this.#info !== null && this.#info.can(capability);
145
+ }
146
+ #requireHigh(capability) {
147
+ if (!this.canHigh(capability))
148
+ throw new NotCapable(capability);
149
+ }
150
+ /** Ask the device to stream. */
151
+ startStream() {
152
+ return this.#command("start_stream");
153
+ }
154
+ /** Ask the device to stop streaming. */
155
+ stopStream() {
156
+ return this.#command("stop_stream");
157
+ }
158
+ /**
159
+ * Set the rate, in samples per second. The device refuses a change while
160
+ * it is streaming, so every sample of a recording sits under one
161
+ * configuration.
162
+ */
163
+ setRate(sps) {
164
+ const code = CODE_BY_RATE.get(sps);
165
+ if (code === undefined)
166
+ throw new Invalid(`${sps} samples per second is not a rate this contract defines`);
167
+ return this.#command("set_rate", code);
168
+ }
169
+ /** Set the gain. Refused while streaming. */
170
+ setGain(gain) {
171
+ const code = CODE_BY_GAIN.get(gain);
172
+ if (code === undefined)
173
+ throw new Invalid(`a gain of ${gain} is not one this contract defines`);
174
+ return this.#command("set_gain", code);
175
+ }
176
+ /**
177
+ * What the amplifier listens to: 0 the electrodes, 1 the internal test
178
+ * signal, 2 shorted inputs. The last two are capabilities a device
179
+ * declares, so a device that does not offer one is not asked for it.
180
+ */
181
+ setMode(mode) {
182
+ const code = typeof mode === "string" ? MODES[mode] : mode;
183
+ if (code === 1)
184
+ this.#require("test_signal");
185
+ else if (code === 2)
186
+ this.#require("input_short");
187
+ // 1.3: the device generates the signal, converter off. Only a device
188
+ // that claims it; the device itself refuses it while streaming and at a
189
+ // rate other than 500 samples a second.
190
+ else if (code === 3)
191
+ this.#requireHigh("synthetic");
192
+ else if (code !== 0)
193
+ throw new Invalid(`mode ${mode} is not one this contract defines`);
194
+ return this.#command("set_mode", code);
195
+ }
196
+ /** Turn lead-off detection on or off. */
197
+ setLeadoff(on) {
198
+ this.#require("leadoff");
199
+ return this.#command("set_leadoff", on ? 1 : 0);
200
+ }
201
+ /**
202
+ * Ask the device what time it is. Note the host clock either side and
203
+ * give both to `onTimeSync`.
204
+ */
205
+ timeSync() {
206
+ return this.#command("time_sync");
207
+ }
208
+ /** The answer to a time request, with the host clock either side of it. */
209
+ onTimeSync(payload, before, after) {
210
+ const ticks = decodeTimeSync(payload);
211
+ if (this.#timebase === null)
212
+ throw new NoDeviceInfo();
213
+ return this.#timebase.observe(new Exchange(before, after, ticks));
214
+ }
215
+ /** Zero the sample index and start a fresh epoch. */
216
+ resetEpoch() {
217
+ this.#previous = null;
218
+ return this.#command("reset_epoch");
219
+ }
220
+ /** Ask for the measured battery voltage and charge. */
221
+ getBattery() {
222
+ this.#require("battery_voltage");
223
+ return this.#command("get_battery");
224
+ }
225
+ /** Ask why and how many times the device has booted. */
226
+ getBootInfo() {
227
+ return this.#command("get_boot_info");
228
+ }
229
+ /** Turn predictions on or off. */
230
+ setPredictions(on) {
231
+ this.#require("model");
232
+ return this.#command("set_predictions", on ? 1 : 0);
233
+ }
234
+ /** Ask for the model runtime's state. */
235
+ getModelInfo() {
236
+ this.#require("model");
237
+ return this.#command("get_model_info");
238
+ }
239
+ /** Select a head slot. 0 is the built-in head. */
240
+ selectHead(slot) {
241
+ this.#require("heads");
242
+ return this.#command("select_head", slot);
243
+ }
244
+ /** Ask for the head slots and which one is selected. */
245
+ listHeads() {
246
+ this.#require("heads");
247
+ return this.#command("list_heads");
248
+ }
249
+ /**
250
+ * Ask which encoder each head names (1.4): one record for each LIST_HEADS record, read with `decodeHeadEncoders`.
251
+ * A device before 1.4 is not asked, and its heads say nothing of their encoder.
252
+ */
253
+ listHeadEncoders() {
254
+ this.#require("heads");
255
+ const [major, minor] = this.#info?.protocol ?? [0, 0];
256
+ if (major < 1 || (major === 1 && minor < 4))
257
+ throw new NotCapable("head_encoders");
258
+ return this.#command("list_head_encoders");
259
+ }
260
+ /** Remove a user head slot's contents. */
261
+ removeHead(slot) {
262
+ this.#require("heads");
263
+ return this.#command("remove_head", slot);
264
+ }
265
+ // --- processing, on devices that run a chain ------------------------------
266
+ //
267
+ // The device preprocesses its own signal. When a chain is in force only
268
+ // its output streams, and the chain is readable at any time, so a
269
+ // recording can say exactly what produced its samples. The rules a chain
270
+ // must meet are the device's, restated in `protocol.checkChain`, so a
271
+ // chain that cannot run is refused here in words before anything is
272
+ // sent. The device refuses a change while streaming: stop, set, start.
273
+ /** Ask for the stage kinds the device runs. `protocol.decodeCatalog` reads the answer. */
274
+ pipelineCatalog() {
275
+ this.#require("pipeline");
276
+ return this.#command("get_pipeline_catalog");
277
+ }
278
+ /** Ask for the chain in force. `protocol.decodePipelineState` reads the answer. */
279
+ pipeline() {
280
+ this.#require("pipeline");
281
+ return this.#command("get_pipeline");
282
+ }
283
+ /** Put a chain on the device's signal path, checked here first against the rate the device runs at. */
284
+ setPipeline(stages, rateSps, catalog) {
285
+ this.#require("pipeline");
286
+ checkChain(stages, rateSps, catalog);
287
+ return this.#command("set_pipeline", encodeChain(stages));
288
+ }
289
+ /** The natural signal, as this host's choice. */
290
+ clearPipeline() {
291
+ this.#require("pipeline");
292
+ return this.#command("clear_pipeline");
293
+ }
294
+ /** The device's own default chain for its current rate. */
295
+ restorePipelineDefault() {
296
+ this.#require("pipeline");
297
+ return this.#command("restore_pipeline_default");
298
+ }
299
+ /** Ask where the model's input comes from. `protocol.decodePredictionInput` reads the answer. */
300
+ predictionInput() {
301
+ this.#require("model");
302
+ return this.#command("get_prediction_input");
303
+ }
304
+ /**
305
+ * Point the model at the stream as it is, at the natural signal, or at a
306
+ * chain of its own, without touching the stream. Only the model's own
307
+ * source carries a chain, checked here against the rate.
308
+ */
309
+ setPredictionInput(source, stages = [], rateSps = 500, catalog) {
310
+ this.#require("model");
311
+ if (source === "own_chain")
312
+ checkChain(stages, rateSps, catalog);
313
+ else if (stages.length !== 0)
314
+ throw new Invalid("only the model's own chain carries stages");
315
+ return this.#command("set_prediction_input", encodePredictionInput(source, stages));
316
+ }
317
+ /** The bias drive, on a device that claims one: off, on, or loop open. */
318
+ setBias(mode) {
319
+ this.#require("bias_drive");
320
+ const code = BIAS_MODES[mode];
321
+ if (code === undefined)
322
+ throw new Invalid(`${mode} is not a bias mode this contract defines`);
323
+ return this.#command("set_bias", code);
324
+ }
325
+ /** Ask for the bias output measured. `protocol.decodeBiasDiagnostic` reads the answer. */
326
+ biasDiagnostic() {
327
+ this.#require("bias_drive");
328
+ return this.#command("get_bias_diagnostic");
329
+ }
330
+ // --- the lamp, the converter's registers, embeddings (1.2) ----------------
331
+ /** Ask for the status lamp's level. The answer's one byte is an `INDICATOR_LEVELS` value. */
332
+ indicator() {
333
+ this.#require("indicator");
334
+ return this.#command("get_indicator");
335
+ }
336
+ /**
337
+ * Put the lamp at a level: silent, reserved (the default: low battery and a
338
+ * converter fault at power on), or verbose. The device keeps it across
339
+ * power cycles.
340
+ */
341
+ setIndicator(level) {
342
+ this.#require("indicator");
343
+ const code = INDICATOR_LEVELS[level];
344
+ if (code === undefined)
345
+ throw new Invalid(`${level} is not a lamp level this contract defines`);
346
+ return this.#command("set_indicator", code);
347
+ }
348
+ /** Blink the lamp so this device can be told from others, for 1 to 30 seconds at every level; 0 stops one in progress. */
349
+ identify(seconds = 5) {
350
+ this.#require("indicator");
351
+ if (!Number.isInteger(seconds) || seconds < 0 || seconds > IDENTIFY_MAX_SECONDS) {
352
+ throw new Invalid(`identify runs 1 to ${IDENTIFY_MAX_SECONDS} seconds, or 0 to stop`);
353
+ }
354
+ return this.#command("identify", seconds);
355
+ }
356
+ /** Ask for the converter's registers, raw, for debugging; read only, and only while not streaming. `protocol.decodeConverterRegisters` reads the answer. */
357
+ converterRegisters() {
358
+ this.#require("converter_registers");
359
+ return this.#command("get_converter_registers");
360
+ }
361
+ /**
362
+ * Ask the device for its encoder's output for each window while it
363
+ * streams: "window" for the one vector a head consumes, "tokens" for the
364
+ * per-slice vectors reconstruction consumes, "both", or "off". Whole
365
+ * windows come from `protocol.EmbeddingAssembler` fed with embedding events.
366
+ */
367
+ setEmbeddings(form) {
368
+ this.#require("embeddings");
369
+ const code = EMBEDDING_FORMS[form];
370
+ if (code === undefined)
371
+ throw new Invalid(`${form} is not an embedding form this contract defines`);
372
+ return this.#command("set_embeddings", code);
373
+ }
374
+ // --- 1.3: the model's cadence and the device's name -----------------------
375
+ /** Ask how often the model describes a window and the least interval the device keeps; `protocol.decodeModelInterval` reads the answer. */
376
+ modelInterval() {
377
+ this.#require("model_cadence");
378
+ return this.#command("get_model_interval");
379
+ }
380
+ /**
381
+ * One described window every `seconds`, on a grid from the stream's start;
382
+ * 0 is every window the device can. The device refuses a value below its
383
+ * minimum and keeps the setting across power cycles.
384
+ */
385
+ setModelInterval(seconds) {
386
+ this.#require("model_cadence");
387
+ return this.#command("set_model_interval", encodeModelInterval(seconds));
388
+ }
389
+ /** Ask for the name and the adjective a host set; `protocol.decodeNameParts` reads the answer. */
390
+ getName() {
391
+ this.#requireHigh("device_name");
392
+ return this.#command("get_name");
393
+ }
394
+ /**
395
+ * Name the device. It advertises `name's adjective IntoMind One` from the
396
+ * next advertisement and keeps both parts across power cycles. The
397
+ * composition must fit the 29 bytes a scan response carries, so every scan
398
+ * list shows the whole of it; refused here when it does not, or when a
399
+ * part has a leading or trailing space or a control character.
400
+ */
401
+ setName(name, adjective, product = PRODUCT_NAME) {
402
+ this.#requireHigh("device_name");
403
+ if (!nameFits(name, adjective, product)) {
404
+ throw new Invalid(`"${composeName(name, adjective, product)}" does not fit the ${NAME_MAX_COMPOSED} bytes the air carries, or a part has a leading or trailing space or a control character`);
405
+ }
406
+ return this.#command("set_name", encodeNameParts(name, adjective));
407
+ }
408
+ // --- notifications --------------------------------------------------------
409
+ /**
410
+ * Hand in one notification, and take whatever it meant.
411
+ *
412
+ * A batch that follows a break is preceded by the gap, so a caller that
413
+ * writes samples down writes the gap down first and can never splice.
414
+ */
415
+ onNotification(characteristic, bytes) {
416
+ switch (characteristic) {
417
+ case FILL.EEG_DATA:
418
+ return this.#onSamples(bytes);
419
+ case FILL.STATUS:
420
+ return this.#decoded(characteristic, () => ({ type: "status", status: decodeStatus(bytes) }));
421
+ case FILL.CONTROL_RESPONSE:
422
+ return this.#decoded(characteristic, () => ({ type: "answer", answer: decodeResponse(bytes) }));
423
+ case FILL.PREDICTIONS:
424
+ return this.#decoded(characteristic, () => ({
425
+ type: "prediction",
426
+ prediction: decodePrediction(bytes),
427
+ }));
428
+ case FILL.EMBEDDINGS:
429
+ return this.#decoded(characteristic, () => ({
430
+ type: "embedding",
431
+ embedding: decodeEmbedding(bytes),
432
+ }));
433
+ default:
434
+ return this.#undecodable(characteristic);
435
+ }
436
+ }
437
+ #decoded(characteristic, decode) {
438
+ try {
439
+ return [decode()];
440
+ }
441
+ catch {
442
+ return this.#undecodable(characteristic);
443
+ }
444
+ }
445
+ #undecodable(characteristic) {
446
+ this.undecodable += 1;
447
+ return [{ type: "undecodable", characteristic }];
448
+ }
449
+ #onSamples(bytes) {
450
+ const info = this.#info;
451
+ // A device that has not said how wide it is cannot have its samples
452
+ // read, because the payload length only means something against a
453
+ // channel count.
454
+ if (info === null)
455
+ return this.#undecodable(FILL.EEG_DATA);
456
+ let packet;
457
+ try {
458
+ packet = decodePacket(bytes, info.channels);
459
+ }
460
+ catch {
461
+ return this.#undecodable(FILL.EEG_DATA);
462
+ }
463
+ const events = [];
464
+ const previous = this.#previous;
465
+ // A packet with the first index and the device time of one just passed
466
+ // on is that packet again, delivered twice by the host. Dropped and
467
+ // counted, so no sample is passed on twice and no break is announced
468
+ // that did not happen. A device that restarts its count carries a new
469
+ // device time, so a restart is never taken for a copy, and anything else
470
+ // is judged by the contract's continuity rule unchanged.
471
+ const key = `${packet.index}:${packet.deviceTime}`;
472
+ if (this.#recent.includes(key)) {
473
+ this.duplicates += 1;
474
+ return [{ type: "duplicate", index: packet.index }];
475
+ }
476
+ this.#recent.push(key);
477
+ if (this.#recent.length > 8)
478
+ this.#recent.shift();
479
+ if (previous !== null) {
480
+ const verdict = continuity(previous.index, previous.nSamples, packet.index, packet.discontinuity);
481
+ if (verdict.broken) {
482
+ if (verdict.lost === null)
483
+ this.rebases += 1;
484
+ else
485
+ this.samplesLost += verdict.lost;
486
+ events.push({
487
+ type: "gap",
488
+ gap: {
489
+ lastIndexBefore: (previous.index + previous.nSamples - 1) >>> 0,
490
+ firstIndexAfter: packet.index,
491
+ samplesLost: verdict.lost,
492
+ deviceTimeBefore: previous.deviceTime,
493
+ deviceTimeAfter: packet.deviceTime,
494
+ isRebase: verdict.lost === null,
495
+ },
496
+ });
497
+ }
498
+ }
499
+ this.#previous = { index: packet.index, nSamples: packet.nSamples, deviceTime: packet.deviceTime };
500
+ const counts = new Int32Array(packet.nSamples * info.channels);
501
+ for (let row = 0; row < packet.nSamples; row++) {
502
+ for (let c = 0; c < info.channels; c++)
503
+ counts[row * info.channels + c] = packet.counts[row][c];
504
+ }
505
+ events.push({
506
+ type: "samples",
507
+ batch: new Batch({
508
+ index: packet.index,
509
+ deviceTime: packet.deviceTime,
510
+ channels: info.channels,
511
+ counts,
512
+ leadoff: packet.loffStatp,
513
+ leadoffActive: packet.leadoffActive,
514
+ gain: packet.gain,
515
+ sampleRateHz: packet.sps,
516
+ mode: packet.mode,
517
+ synthetic: packet.synthetic,
518
+ }),
519
+ });
520
+ return events;
521
+ }
522
+ }
523
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,IAAI,EACJ,OAAO,EAOP,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,aAAa,EACb,UAAU,EACV,UAAU,EACV,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,qBAAqB,EACrB,KAAK,EACL,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,mBAAmB,EACnB,eAAe,EACf,QAAQ,GACT,MAAM,eAAe,CAAC;AAWvB,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAY,MAAM,eAAe,CAAC;AAE7D,4EAA4E;AAC5E,MAAM,OAAO,YAAa,SAAQ,KAAK;IACrC,gEAAgE;IAChE,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAED,yEAAyE;AACzE,MAAM,OAAO,YAAa,SAAQ,YAAY;IAC5C;QACE,KAAK,CAAC,sDAAsD,CAAC,CAAC;QAC9D,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAED,2DAA2D;AAC3D,MAAM,OAAO,UAAW,SAAQ,YAAY;IAC1C,oCAAoC;IAC3B,UAAU,CAAS;IAE5B,+CAA+C;IAC/C,YAAY,UAAkB;QAC5B,KAAK,CAAC,kCAAkC,UAAU,aAAa,CAAC,CAAC;QACjE,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AAeD,8CAA8C;AAC9C,MAAM,OAAO,KAAK;IAChB,mDAAmD;IAC1C,KAAK,CAAS;IACvB,kEAAkE;IACzD,UAAU,CAAS;IAC5B,wBAAwB;IACf,QAAQ,CAAS;IAC1B,oEAAoE;IAC3D,MAAM,CAAa;IAC5B,2DAA2D;IAClD,OAAO,CAAS;IACzB,0NAA0N;IACjN,aAAa,CAAU;IAChC,0CAA0C;IACjC,IAAI,CAAS;IACtB,4FAA4F;IACnF,YAAY,CAAgB;IACrC,wGAAwG;IAC/F,IAAI,CAAS;IACtB,wHAAwH;IAC/G,SAAS,CAAU;IAE5B,+DAA+D;IAC/D,YAAY,CAWX;QACC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;QACzB,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,aAAa,IAAI,KAAK,CAAC;QAC9C,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;QACnB,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;QACxB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC;IACxC,CAAC;IAED,6BAA6B;IAC7B,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC;IACtE,CAAC;IAED,2BAA2B;IAC3B,KAAK,CAAC,GAAW,EAAE,OAAe;QAChC,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAE,CAAC;IACrD,CAAC;IAED;;;OAGG;IACH,UAAU,CAAC,GAAW,EAAE,OAAe,EAAE,IAAgB;QACvD,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACpF,CAAC;CACF;AAwCD,kBAAkB;AAClB,MAAM,OAAO,OAAO;IAClB,KAAK,GAAsB,IAAI,CAAC;IAChC,SAAS,GAAoB,IAAI,CAAC;IAClC,SAAS,GAAmE,IAAI,CAAC;IACjF,uGAAuG;IACvG,OAAO,GAAa,EAAE,CAAC;IAEvB,+EAA+E;IAC/E,WAAW,GAAG,CAAC,CAAC;IAChB,yEAAyE;IACzE,OAAO,GAAG,CAAC,CAAC;IACZ,6FAA6F;IAC7F,WAAW,GAAG,CAAC,CAAC;IAChB,uFAAuF;IACvF,UAAU,GAAG,CAAC,CAAC;IAEf,yDAAyD;IACzD,YAAY,CAAC,KAAiB;QAC5B,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,CAAC,SAAS,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,mEAAmE;IACnE,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,6DAA6D;IAC7D,WAAW;QACT,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI;YAAE,MAAM,IAAI,YAAY,EAAE,CAAC;QAClD,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;;OAGG;IACH,GAAG,CAAC,UAAmC;QACrC,OAAO,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC;IAC9C,CAAC;IAED,2EAA2E;IAC3E,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,0EAA0E;IAC1E,QAAQ,CAAC,WAAmB;QAC1B,OAAO,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC;IACvD,CAAC;IAED,6EAA6E;IAE7E,QAAQ,CAAC,MAAkB,EAAE,MAAkC,IAAI;QACjE,OAAO,EAAE,cAAc,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;IACjG,CAAC;IAED,QAAQ,CAAC,UAA0B;QACjC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC;IAC9D,CAAC;IAED,gHAAgH;IAChH,OAAO,CAAC,UAA8B;QACpC,OAAO,IAAI,CAAC,KAAK,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC3D,CAAC;IAED,YAAY,CAAC,UAA8B;QACzC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC;IAClE,CAAC;IAED,gCAAgC;IAChC,WAAW;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IACvC,CAAC;IAED,wCAAwC;IACxC,UAAU;QACR,OAAO,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IACtC,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,GAAW;QACjB,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,IAAI,OAAO,CAAC,GAAG,GAAG,yDAAyD,CAAC,CAAC;QAC3G,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,6CAA6C;IAC7C,OAAO,CAAC,IAAY;QAClB,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,IAAI,OAAO,CAAC,aAAa,IAAI,mCAAmC,CAAC,CAAC;QAChG,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IACzC,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,IAAuB;QAC7B,MAAM,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC3D,IAAI,IAAI,KAAK,CAAC;YAAE,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;aACxC,IAAI,IAAI,KAAK,CAAC;YAAE,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QAClD,qEAAqE;QACrE,wEAAwE;QACxE,wCAAwC;aACnC,IAAI,IAAI,KAAK,CAAC;YAAE,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;aAC/C,IAAI,IAAI,KAAK,CAAC;YAAE,MAAM,IAAI,OAAO,CAAC,QAAQ,IAAI,mCAAmC,CAAC,CAAC;QACxF,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,yCAAyC;IACzC,UAAU,CAAC,EAAW;QACpB,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;IAED;;;OAGG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IACpC,CAAC;IAED,2EAA2E;IAC3E,UAAU,CAAC,OAAmB,EAAE,MAAc,EAAE,KAAa;QAC3D,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI;YAAE,MAAM,IAAI,YAAY,EAAE,CAAC;QACtD,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IACpE,CAAC;IAED,qDAAqD;IACrD,UAAU;QACR,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,OAAO,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IACtC,CAAC;IAED,uDAAuD;IACvD,UAAU;QACR,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IACtC,CAAC;IAED,wDAAwD;IACxD,WAAW;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IACxC,CAAC;IAED,kCAAkC;IAClC,cAAc,CAAC,EAAW;QACxB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC,QAAQ,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,yCAAyC;IACzC,YAAY;QACV,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACzC,CAAC;IAED,kDAAkD;IAClD,UAAU,CAAC,IAAY;QACrB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IAC5C,CAAC;IAED,wDAAwD;IACxD,SAAS;QACP,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACrC,CAAC;IAED;;;OAGG;IACH,gBAAgB;QACd,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACvB,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,QAAQ,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtD,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,eAAe,CAAC,CAAC;QACnF,OAAO,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;IAC7C,CAAC;IAED,0CAA0C;IAC1C,UAAU,CAAC,IAAY;QACrB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IAC5C,CAAC;IAED,6EAA6E;IAC7E,EAAE;IACF,wEAAwE;IACxE,kEAAkE;IAClE,yEAAyE;IACzE,sEAAsE;IACtE,oEAAoE;IACpE,uEAAuE;IAEvE,0FAA0F;IAC1F,eAAe;QACb,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC1B,OAAO,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC;IAC/C,CAAC;IAED,mFAAmF;IACnF,QAAQ;QACN,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC1B,OAAO,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IACvC,CAAC;IAED,uGAAuG;IACvG,WAAW,CAAC,MAAwB,EAAE,OAAe,EAAE,OAAiC;QACtF,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC1B,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,iDAAiD;IACjD,aAAa;QACX,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC1B,OAAO,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACzC,CAAC;IAED,2DAA2D;IAC3D,sBAAsB;QACpB,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC1B,OAAO,IAAI,CAAC,QAAQ,CAAC,0BAA0B,CAAC,CAAC;IACnD,CAAC;IAED,iGAAiG;IACjG,eAAe;QACb,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC;IAC/C,CAAC;IAED;;;;OAIG;IACH,kBAAkB,CAAC,MAAuB,EAAE,SAA2B,EAAE,EAAE,OAAO,GAAG,GAAG,EAAE,OAAiC;QACzH,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACvB,IAAI,MAAM,KAAK,WAAW;YAAE,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;aAC5D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,IAAI,OAAO,CAAC,2CAA2C,CAAC,CAAC;QAC7F,OAAO,IAAI,CAAC,QAAQ,CAAC,sBAAsB,EAAE,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtF,CAAC;IAED,0EAA0E;IAC1E,OAAO,CAAC,IAAkB;QACxB,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAC5B,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,IAAI,OAAO,CAAC,GAAG,IAAI,2CAA2C,CAAC,CAAC;QAC9F,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,0FAA0F;IAC1F,cAAc;QACZ,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAC5B,OAAO,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC;IAC9C,CAAC;IAED,6EAA6E;IAE7E,6FAA6F;IAC7F,SAAS;QACP,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC3B,OAAO,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IACxC,CAAC;IAED;;;;OAIG;IACH,YAAY,CAAC,KAAyB;QACpC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC3B,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,IAAI,OAAO,CAAC,GAAG,KAAK,4CAA4C,CAAC,CAAC;QAChG,OAAO,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;IAC9C,CAAC;IAED,0HAA0H;IAC1H,QAAQ,CAAC,OAAO,GAAG,CAAC;QAClB,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC3B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,oBAAoB,EAAE,CAAC;YAChF,MAAM,IAAI,OAAO,CAAC,sBAAsB,oBAAoB,wBAAwB,CAAC,CAAC;QACxF,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED,4JAA4J;IAC5J,kBAAkB;QAChB,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC;IAClD,CAAC;IAED;;;;;OAKG;IACH,aAAa,CAAC,IAAuB;QACnC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAC5B,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,IAAI,OAAO,CAAC,GAAG,IAAI,iDAAiD,CAAC,CAAC;QACpG,OAAO,IAAI,CAAC,QAAQ,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;IAC/C,CAAC;IAED,6EAA6E;IAE7E,2IAA2I;IAC3I,aAAa;QACX,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;IAC7C,CAAC;IAED;;;;OAIG;IACH,gBAAgB,CAAC,OAAe;QAC9B,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC,QAAQ,CAAC,oBAAoB,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3E,CAAC;IAED,kGAAkG;IAClG,OAAO;QACL,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACnC,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,IAAY,EAAE,SAAiB,EAAE,UAAkB,YAAY;QACrE,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;QACjC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC;YACxC,MAAM,IAAI,OAAO,CAAC,IAAI,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,sBAAsB,iBAAiB,0FAA0F,CAAC,CAAC;QAChM,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IACrE,CAAC;IAED,6EAA6E;IAE7E;;;;;OAKG;IACH,cAAc,CAAC,cAAsB,EAAE,KAAiB;QACtD,QAAQ,cAAc,EAAE,CAAC;YACvB,KAAK,IAAI,CAAC,QAAQ;gBAChB,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YAChC,KAAK,IAAI,CAAC,MAAM;gBACd,OAAO,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;YAChG,KAAK,IAAI,CAAC,gBAAgB;gBACxB,OAAO,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;YAClG,KAAK,IAAI,CAAC,WAAW;gBACnB,OAAO,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;oBAC1C,IAAI,EAAE,YAAY;oBAClB,UAAU,EAAE,gBAAgB,CAAC,KAAK,CAAC;iBACpC,CAAC,CAAC,CAAC;YACN,KAAK,IAAI,CAAC,UAAU;gBAClB,OAAO,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;oBAC1C,IAAI,EAAE,WAAW;oBACjB,SAAS,EAAE,eAAe,CAAC,KAAK,CAAC;iBAClC,CAAC,CAAC,CAAC;YACN;gBACE,OAAO,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,cAAsB,EAAE,MAAmB;QAClD,IAAI,CAAC;YACH,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,YAAY,CAAC,cAAsB;QACjC,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC;QACtB,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,UAAU,CAAC,KAAiB;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,oEAAoE;QACpE,kEAAkE;QAClE,iBAAiB;QACjB,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3D,IAAI,MAAM,CAAC;QACX,IAAI,CAAC;YACH,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC;QAED,MAAM,MAAM,GAAY,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC;QAChC,uEAAuE;QACvE,oEAAoE;QACpE,qEAAqE;QACrE,sEAAsE;QACtE,yEAAyE;QACzE,yDAAyD;QACzD,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACnD,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC;YACrB,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAClD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;YAClG,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACnB,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI;oBAAE,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;;oBACxC,IAAI,CAAC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;gBACtC,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,KAAK;oBACX,GAAG,EAAE;wBACH,eAAe,EAAE,CAAC,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC;wBAC/D,eAAe,EAAE,MAAM,CAAC,KAAK;wBAC7B,WAAW,EAAE,OAAO,CAAC,IAAI;wBACzB,gBAAgB,EAAE,QAAQ,CAAC,UAAU;wBACrC,eAAe,EAAE,MAAM,CAAC,UAAU;wBAClC,QAAQ,EAAE,OAAO,CAAC,IAAI,KAAK,IAAI;qBAChC;iBACF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;QAEnG,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/D,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,MAAM,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,CAAC;YAC/C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE;gBAAE,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAE,CAAC,CAAC,CAAE,CAAC;QACpG,CAAC;QACD,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,IAAI,KAAK,CAAC;gBACf,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,MAAM;gBACN,OAAO,EAAE,MAAM,CAAC,SAAS;gBACzB,aAAa,EAAE,MAAM,CAAC,aAAa;gBACnC,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,YAAY,EAAE,MAAM,CAAC,GAAG;gBACxB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,SAAS,EAAE,MAAM,CAAC,SAAS;aAC5B,CAAC;SACH,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Device time onto a host clock.
3
+ *
4
+ * A device's clock is monotonic and free running. A host's is a different
5
+ * crystal. The fit between them is a line, and the point of taking several
6
+ * exchanges rather than one is that a single exchange cannot tell a clock
7
+ * difference from a slow answer.
8
+ *
9
+ * The fit is refused rather than believed when it is absurd. Two crystals
10
+ * do not differ by a thousand parts per million, and a measurement that
11
+ * says they do is measuring something else, usually a link that stalled in
12
+ * the middle of an exchange.
13
+ */
14
+ /** Beyond this, a skew is not two crystals disagreeing. */
15
+ export declare const MAX_SKEW_PPM = 1000;
16
+ /** And it has to be measured rather than drawn through noise. */
17
+ export declare const MAX_SKEW_STDERR_PPM = 100;
18
+ /** One time exchange, read on both clocks. */
19
+ export declare class Exchange {
20
+ /** Host time before the request, in seconds. */
21
+ readonly before: number;
22
+ /** Host time after the answer. */
23
+ readonly after: number;
24
+ /** The device's own time, in its ticks, captured when it read the request. */
25
+ readonly deviceTicks: bigint;
26
+ /** One exchange: the host clock either side of the request, and the device's own answer in its ticks. */
27
+ constructor(before: number, after: number, deviceTicks: bigint);
28
+ /** The middle of the window the device's answer must lie in. */
29
+ get host(): number;
30
+ /**
31
+ * How wide that window is. Half the round trip, which is the uncertainty
32
+ * in this one exchange.
33
+ */
34
+ get uncertainty(): number;
35
+ }
36
+ /** The line through the exchanges. */
37
+ export interface Fit {
38
+ /** host = deviceSeconds * (1 + skew) + offset. */
39
+ readonly offsetS: number;
40
+ /** The measured clock skew, in parts per million. 0 when `skewUsed` is false. */
41
+ readonly skewPpm: number;
42
+ /** Exchanges this fit was computed from. */
43
+ readonly exchanges: number;
44
+ /** How far the exchanges sit from the line, in microseconds. */
45
+ readonly residualUs: number;
46
+ /** Whether the skew was measured well enough to be used. */
47
+ readonly skewUsed: boolean;
48
+ }
49
+ /** Device time onto host time, and the exchanges it was learned from. */
50
+ export declare class Timebase {
51
+ #private;
52
+ /** The device's own tick rate, from device info. */
53
+ readonly tickHz: number;
54
+ /** `tickHz` is the device's own, from device info. */
55
+ constructor(tickHz: number);
56
+ /** Take one exchange. The fit is redone from everything so far. */
57
+ observe(exchange: Exchange): Fit | null;
58
+ /** Every exchange taken so far. */
59
+ get exchanges(): readonly Exchange[];
60
+ /** The current fit, or null before the first exchange. */
61
+ get fit(): Fit | null;
62
+ /** Host time for a device time, in seconds. Null until there is a fit. */
63
+ hostTime(deviceTicks: bigint): number | null;
64
+ }
65
+ //# sourceMappingURL=timebase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timebase.d.ts","sourceRoot":"","sources":["../src/timebase.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,2DAA2D;AAC3D,eAAO,MAAM,YAAY,OAAS,CAAC;AACnC,iEAAiE;AACjE,eAAO,MAAM,mBAAmB,MAAQ,CAAC;AAEzC,8CAA8C;AAC9C,qBAAa,QAAQ;IACnB,gDAAgD;IAChD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kCAAkC;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B,yGAAyG;gBAC7F,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAM9D,gEAAgE;IAChE,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;OAGG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;CACF;AAED,sCAAsC;AACtC,MAAM,WAAW,GAAG;IAClB,kDAAkD;IAClD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,4CAA4C;IAC5C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,gEAAgE;IAChE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED,yEAAyE;AACzE,qBAAa,QAAQ;;IACnB,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAIxB,sDAAsD;gBAC1C,MAAM,EAAE,MAAM;IAI1B,mEAAmE;IACnE,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,GAAG,GAAG,IAAI;IAMvC,mCAAmC;IACnC,IAAI,SAAS,IAAI,SAAS,QAAQ,EAAE,CAEnC;IAED,0DAA0D;IAC1D,IAAI,GAAG,IAAI,GAAG,GAAG,IAAI,CAEpB;IAED,0EAA0E;IAC1E,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;CA4C7C"}