@muhkoo/connect 0.14.0-alpha.2 → 0.14.0-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.
@@ -1,2670 +0,0 @@
1
- const _isTty = (() => {
2
- try {
3
- const proc = globalThis.process;
4
- return !!proc?.stdout?.isTTY;
5
- }
6
- catch {
7
- return false;
8
- }
9
- })();
10
- const _ansi = (code) => _isTty ? (s) => `\x1b[${code}m${s}\x1b[0m` : (s) => s;
11
- const colors = {
12
- gray: _ansi('90'),
13
- red: _ansi('31'),
14
- green: _ansi('32'),
15
- yellow: _ansi('33'),
16
- blue: _ansi('34'),
17
- magenta: _ansi('35'),
18
- cyan: _ansi('36'),
19
- dim: _ansi('2'),
20
- };
21
- var LogLevel;
22
- (function (LogLevel) {
23
- LogLevel[LogLevel["VERBOSE"] = 0] = "VERBOSE";
24
- LogLevel[LogLevel["DEBUG"] = 1] = "DEBUG";
25
- LogLevel[LogLevel["INFO"] = 2] = "INFO";
26
- LogLevel[LogLevel["SUCCESS"] = 3] = "SUCCESS";
27
- LogLevel[LogLevel["WARN"] = 4] = "WARN";
28
- LogLevel[LogLevel["ERROR"] = 5] = "ERROR";
29
- })(LogLevel || (LogLevel = {}));
30
- class Logger {
31
- prefix;
32
- logLevel;
33
- console;
34
- showCaller;
35
- level = 'INFO';
36
- constructor(prefix = 'CONNECT', LOGLEVEL = 'INFO', showCaller = false) {
37
- this.prefix = colors.gray(`[${prefix}]`);
38
- this.showCaller = showCaller;
39
- let envLevel;
40
- // Check environment: browser vs Node.js
41
- if (typeof window !== 'undefined') {
42
- // Browser environment
43
- envLevel = (LOGLEVEL).toUpperCase();
44
- }
45
- else {
46
- // Node.js environment - safely access process.env
47
- const globalProcess = globalThis.process;
48
- const nodeEnv = globalProcess?.env?.LOG_LEVEL;
49
- envLevel = (nodeEnv || LOGLEVEL).toUpperCase();
50
- }
51
- this.level = envLevel;
52
- this.logLevel = LogLevel[envLevel] ?? LogLevel.INFO;
53
- this.console = globalThis.console;
54
- }
55
- shouldLog(level) {
56
- return level >= this.logLevel;
57
- }
58
- /**
59
- * Extract caller information from stack trace
60
- */
61
- getCallerInfo() {
62
- if (!this.showCaller)
63
- return null;
64
- try {
65
- const stack = new Error().stack;
66
- if (!stack)
67
- return null;
68
- // Split stack trace into lines
69
- const lines = stack.split('\n');
70
- // Skip first 3 lines (Error, getCallerInfo, the log method itself)
71
- // The 4th line should be the actual caller
72
- const callerLine = lines[3];
73
- if (!callerLine)
74
- return null;
75
- // Parse stack trace line
76
- // Format: " at ClassName.methodName (file:line:column)"
77
- // or: " at file:line:column"
78
- const match = callerLine.match(/at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?/);
79
- if (!match)
80
- return null;
81
- const [, functionName, filePath, line, column] = match;
82
- // Extract just the filename from the full path
83
- const file = filePath.split('/').pop()?.split('?')[0];
84
- return {
85
- file,
86
- line: parseInt(line, 10),
87
- column: parseInt(column, 10),
88
- function: functionName || undefined,
89
- };
90
- }
91
- catch (error) {
92
- // If we can't parse the stack, just return null
93
- return null;
94
- }
95
- }
96
- /**
97
- * Format caller info for display
98
- */
99
- formatCallerInfo(info) {
100
- if (!info)
101
- return '';
102
- const parts = [];
103
- if (info.function) {
104
- parts.push(colors.cyan(info.function));
105
- }
106
- if (info.file) {
107
- const location = info.line ? `${info.file}:${info.line}` : info.file;
108
- parts.push(colors.dim(`(${location})`));
109
- }
110
- return parts.length > 0 ? ' ' + parts.join(' ') : '';
111
- }
112
- setLevel(level) {
113
- this.level = level.toUpperCase();
114
- const envLevel = level.toUpperCase();
115
- this.logLevel = LogLevel[envLevel] ?? LogLevel.INFO;
116
- }
117
- setShowCaller(show) {
118
- this.showCaller = show;
119
- }
120
- // Logging methods with automatic caller detection
121
- info(...args) {
122
- if (this.shouldLog(LogLevel.INFO)) {
123
- const caller = this.formatCallerInfo(this.getCallerInfo());
124
- this.console.info(this.prefix, colors.blue('INFO') + caller, ...args);
125
- }
126
- }
127
- log(...args) {
128
- this.info(...args); // Alias for info
129
- }
130
- verbose(...args) {
131
- if (this.shouldLog(LogLevel.VERBOSE)) {
132
- const caller = this.formatCallerInfo(this.getCallerInfo());
133
- this.console.log(this.prefix, colors.cyan('VERBOSE') + caller, ...args);
134
- }
135
- }
136
- success(...args) {
137
- if (this.shouldLog(LogLevel.SUCCESS)) {
138
- const caller = this.formatCallerInfo(this.getCallerInfo());
139
- this.console.debug(this.prefix, colors.green('SUCCESS') + caller, ...args);
140
- }
141
- }
142
- warn(...args) {
143
- if (this.shouldLog(LogLevel.WARN)) {
144
- const caller = this.formatCallerInfo(this.getCallerInfo());
145
- this.console.warn(this.prefix, colors.yellow('WARN') + caller, ...args);
146
- }
147
- }
148
- error(...args) {
149
- if (this.shouldLog(LogLevel.ERROR)) {
150
- const caller = this.formatCallerInfo(this.getCallerInfo());
151
- this.console.error(this.prefix, colors.red('ERROR') + caller, ...args);
152
- }
153
- }
154
- debug(...args) {
155
- if (this.shouldLog(LogLevel.DEBUG)) {
156
- const caller = this.formatCallerInfo(this.getCallerInfo());
157
- this.console.debug(this.prefix, colors.magenta('DEBUG') + caller, ...args);
158
- }
159
- }
160
- // Rest of the methods remain unchanged
161
- assert(condition, ...data) {
162
- this.console.assert(condition, ...data);
163
- }
164
- clear() {
165
- this.console.clear();
166
- }
167
- count(label) {
168
- this.console.count(label);
169
- }
170
- countReset(label) {
171
- this.console.countReset(label);
172
- }
173
- dir(item, options) {
174
- this.console.dir(item, options);
175
- }
176
- dirxml(...data) {
177
- this.console.dirxml(...data);
178
- }
179
- group(...data) {
180
- this.console.group(...data);
181
- }
182
- groupCollapsed(...data) {
183
- this.console.groupCollapsed(...data);
184
- }
185
- groupEnd() {
186
- this.console.groupEnd();
187
- }
188
- table(tabularData, properties) {
189
- this.console.table(tabularData, properties);
190
- }
191
- time(label) {
192
- this.console.time(label);
193
- }
194
- timeEnd(label) {
195
- this.console.timeEnd(label);
196
- }
197
- timeLog(label, ...data) {
198
- this.console.timeLog(label, ...data);
199
- }
200
- trace(...data) {
201
- this.console.trace(...data);
202
- }
203
- // Note: Console property removed as it's Node.js-specific and not needed
204
- profile(label) {
205
- if ('profile' in this.console) {
206
- this.console.profile(label);
207
- }
208
- }
209
- profileEnd(label) {
210
- if ('profileEnd' in this.console) {
211
- this.console.profileEnd(label);
212
- }
213
- }
214
- timeStamp(label) {
215
- if ('timeStamp' in this.console) {
216
- this.console.timeStamp(label);
217
- }
218
- }
219
- }
220
- // Export default instance for general use
221
- const log = new Logger('CONNECT', 'INFO', false);
222
-
223
- /**
224
- * Byte conversion helpers usable in both Node and the browser.
225
- *
226
- * Replaces Node's `Buffer` API for the small set of operations we actually
227
- * need in the crypto layer: hex/base64/base64url encode + decode, and array
228
- * concatenation. Lets `DoubleRatchet`, `KeyStore`, etc. compile against
229
- * platforms without `Buffer` (browsers, CF Workers).
230
- */
231
- const HEX_CHARS = "0123456789abcdef";
232
- /** Encode a byte array as a lowercase hex string. */
233
- function toHex(bytes) {
234
- let out = "";
235
- for (let i = 0; i < bytes.length; i++) {
236
- const b = bytes[i];
237
- out += HEX_CHARS[b >> 4] + HEX_CHARS[b & 0x0f];
238
- }
239
- return out;
240
- }
241
- /** Decode a hex string into a byte array. Accepts upper/lowercase; rejects odd-length input. */
242
- function fromHex(hex) {
243
- if (hex.length % 2 !== 0) {
244
- throw new Error(`fromHex: input length must be even (got ${hex.length})`);
245
- }
246
- const ab = new ArrayBuffer(hex.length / 2);
247
- const out = new Uint8Array(ab);
248
- for (let i = 0; i < out.length; i++) {
249
- const byte = parseInt(hex.substring(i * 2, i * 2 + 2), 16);
250
- if (Number.isNaN(byte)) {
251
- throw new Error(`fromHex: invalid hex character at offset ${i * 2}`);
252
- }
253
- out[i] = byte;
254
- }
255
- return out;
256
- }
257
- /** Encode a byte array as a standard base64 string. */
258
- function toBase64(bytes) {
259
- let binary = "";
260
- for (let i = 0; i < bytes.length; i++) {
261
- binary += String.fromCharCode(bytes[i]);
262
- }
263
- return btoa(binary);
264
- }
265
- /** Decode a standard base64 string to bytes. */
266
- function fromBase64(b64) {
267
- const binary = atob(b64);
268
- const ab = new ArrayBuffer(binary.length);
269
- const out = new Uint8Array(ab);
270
- for (let i = 0; i < binary.length; i++)
271
- out[i] = binary.charCodeAt(i);
272
- return out;
273
- }
274
- /** Decode a base64url string (with or without padding) to bytes. */
275
- function fromBase64Url(b64url) {
276
- const padded = b64url.replace(/-/g, "+").replace(/_/g, "/") +
277
- "=".repeat((4 - (b64url.length % 4)) % 4);
278
- return fromBase64(padded);
279
- }
280
- /** Concatenate any number of byte arrays into a single Uint8Array. */
281
- function concatBytes(...arrays) {
282
- let total = 0;
283
- for (const a of arrays)
284
- total += a.byteLength;
285
- const ab = new ArrayBuffer(total);
286
- const out = new Uint8Array(ab);
287
- let offset = 0;
288
- for (const a of arrays) {
289
- const view = a instanceof Uint8Array ? a : new Uint8Array(a);
290
- out.set(view, offset);
291
- offset += view.length;
292
- }
293
- return out;
294
- }
295
- /** Encode a UTF-8 string as bytes. Thin wrapper around TextEncoder for symmetry. */
296
- function utf8Encode(s) {
297
- // TextEncoder.encode returns Uint8Array<ArrayBufferLike>; widen to the
298
- // ArrayBuffer variant explicitly so WebCrypto's BufferSource type accepts it.
299
- const u8 = new TextEncoder().encode(s);
300
- const ab = new ArrayBuffer(u8.byteLength);
301
- const out = new Uint8Array(ab);
302
- out.set(u8);
303
- return out;
304
- }
305
- /** Decode UTF-8 bytes to a string. */
306
- function utf8Decode(bytes) {
307
- return new TextDecoder().decode(bytes);
308
- }
309
-
310
- const base58Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
311
- //0ba25dcb0db07dbac27435857ab55150d2a2e6c8f73a969c74b7659c7a8dd3a3
312
- /**
313
- * @public
314
- * @remarks Asserts the basic type of a variable
315
- * @param value - The value to check
316
- * @param type - The expected type
317
- *
318
- * @throws Error - If the type of the value does not match the expected type
319
- *
320
- */
321
- function assertType(value, typeOrConstructors) {
322
- {
323
- // Single primitive type
324
- if (typeof value !== typeOrConstructors) {
325
- throw new Error(`Expected type '${typeOrConstructors}', received '${typeof value}'`);
326
- }
327
- }
328
- }
329
- /**
330
- * @public
331
- * @remarks Encodes a string to Base58
332
- * @param input - the data to encode, must be a cloneable object
333
- * @returns string
334
- */
335
- function base58Encode(input) {
336
- const bytes = typeof input === "string"
337
- ? new TextEncoder().encode(input)
338
- : new Uint8Array(input);
339
- let num = BigInt(0);
340
- for (const byte of bytes) {
341
- num = (num << BigInt(8)) + BigInt(byte);
342
- }
343
- let result = "";
344
- while (num > 0) {
345
- const remainder = Number(num % BigInt(58));
346
- num = num / BigInt(58);
347
- result = base58Alphabet[remainder] + result;
348
- }
349
- // Preserve leading zero bytes as "1" in Base58
350
- for (const byte of bytes) {
351
- if (byte === 0)
352
- result = "1" + result;
353
- else
354
- break;
355
- }
356
- return result;
357
- }
358
- /**
359
- * @public
360
- * @remarks Decodes a Base58 string to a Uint8Array
361
- * @param input - the Base58 string to decode
362
- * @returns Uint8Array
363
- */
364
- // Function to decode a Base58 string to ArrayBuffer
365
- function base58Decode(input) {
366
- try {
367
- const base58Map = new Map(base58Alphabet.split("").map((char, index) => [char, index]));
368
- let num = BigInt(0);
369
- for (const char of input) {
370
- const value = base58Map.get(char);
371
- if (value === undefined)
372
- throw new Error(`Invalid Base58 character: ${char}`);
373
- num = num * BigInt(58) + BigInt(value);
374
- }
375
- const byteArray = [];
376
- while (num > 0) {
377
- byteArray.push(Number(num % BigInt(256)));
378
- num = num / BigInt(256);
379
- }
380
- byteArray.reverse();
381
- // Restore leading zero bytes from Base58 "1"
382
- const leadingZeros = Array.from(input).filter((char) => char === "1").length;
383
- return new Uint8Array([...Array(leadingZeros).fill(0), ...byteArray]).buffer;
384
- }
385
- catch (e) {
386
- log.error(e);
387
- throw new Error("Invalid input");
388
- }
389
- }
390
- /**
391
- * Simple checksum function using djb2 hash algorithm
392
- * Works in both browser and Node.js environments
393
- */
394
- function simpleChecksum(str) {
395
- let hash = 5381;
396
- for (let i = 0; i < str.length; i++) {
397
- hash = ((hash << 5) + hash) + str.charCodeAt(i); // hash * 33 + c
398
- }
399
- return (hash >>> 0).toString(16); // Convert to unsigned 32-bit hex
400
- }
401
- /**
402
- * @public
403
- * @remarks Generates a checksum for a given input
404
- * @param input - The input to generate a checksum for as a string
405
- * @returns string
406
- */
407
- function generateChecksum(input) {
408
- assertType(input, "string");
409
- return simpleChecksum(input);
410
- }
411
- /**
412
- * @public
413
- * @remarks Verifies a checksum for a given input
414
- * @param input - The input to verify as a string
415
- * @param checksum - The checksum to verify as a string
416
- * @returns boolean
417
- */
418
- function verifyChecksum(input, checksum) {
419
- assertType(input, "string");
420
- assertType(checksum, "string");
421
- return !!(simpleChecksum(input) === checksum);
422
- }
423
- /**
424
- * @internal
425
- * @remarks Generates a random UUID for a given packet
426
- * @returns string
427
- */
428
- function _packetId() {
429
- return "PKT" + generateId();
430
- }
431
- /**
432
- * @internal
433
- * @remarks Generates a random UUID for a message
434
- * @returns string
435
- */
436
- function _messageId() {
437
- return "MSG" + generateId();
438
- }
439
- /**
440
- * @public
441
- * @remarks Generates a random UUID and base58 encodes it
442
- * @returns string
443
- */
444
- function generateId() {
445
- // Web-standard UUID generator (available in every modern browser and
446
- // Node 14+). Replaces the npm `uuid` dep so the browser bundle has one
447
- // fewer external import to resolve.
448
- return base58Encode(crypto.randomUUID());
449
- }
450
- /**
451
- * @public
452
- * @remarks Serializes data to a base58 encoded string
453
- * @param data - The data to serialize
454
- * @typeParam T - The type of the data to serialize
455
- * @returns base58 encoded string
456
- */
457
- function serialize(data) {
458
- const arrayBuffer = structuredCloneToArrayBuffer(data);
459
- return base58Encode(arrayBuffer);
460
- }
461
- /**
462
- * @public
463
- * @remarks Deserializes a base58 encoded string to data
464
- * @param base58String - The base58 encoded string to deserialize
465
- * @returns Deserialized data
466
- */
467
- function deserialize(base58String) {
468
- const arrayBuffer = base58Decode(base58String);
469
- return deserializeWithStructuredClone(arrayBufferToData(arrayBuffer));
470
- }
471
- function deserializeWithStructuredClone(data) {
472
- const deserializeHelper = (item) => {
473
- if (item === null || typeof item !== 'object') {
474
- return item; // Handle primitives directly
475
- }
476
- if (item.__type === "Symbol") {
477
- return Symbol.for(item.value) || Symbol(item.value);
478
- }
479
- if (item.__type === 'Date') {
480
- return new Date(item.value); // Rehydrate Date
481
- }
482
- if (item.__type === 'Map') {
483
- return new Map(item.value); // Rehydrate Map
484
- }
485
- if (item.__type === 'Set') {
486
- return new Set(item.value); // Rehydrate Set
487
- }
488
- if (Array.isArray(item)) {
489
- return item.map(deserializeHelper); // Rehydrate Array recursively
490
- }
491
- // Generic object case
492
- const deserializedObject = {};
493
- for (const key of Object.keys(item)) {
494
- deserializedObject[key] = deserializeHelper(item[key]);
495
- }
496
- return deserializedObject;
497
- };
498
- return deserializeHelper(data);
499
- }
500
- function structuredCloneToArrayBuffer(data) {
501
- // Clone and transform the data for serialization
502
- const serializeHelper = (item) => {
503
- if (item === null || typeof item !== "object")
504
- return item;
505
- if (typeof item === "symbol") {
506
- const key = Symbol.keyFor(item) || item.description || "";
507
- return { __type: "Symbol", value: key };
508
- }
509
- if (item.constructor === Date)
510
- return { __type: "Date", value: item.toISOString() };
511
- if (item.constructor === Map)
512
- return { __type: "Map", value: Array.from(item.entries()) };
513
- if (item.constructor === Set)
514
- return { __type: "Set", value: Array.from(item) };
515
- if (Array.isArray(item))
516
- return item.map(serializeHelper);
517
- const serializedObject = {};
518
- for (const key of Object.keys(item)) {
519
- serializedObject[key] = serializeHelper(item[key]);
520
- }
521
- return serializedObject;
522
- };
523
- // Serialize the structured data into a JSON string
524
- const jsonString = JSON.stringify(serializeHelper(data));
525
- return new TextEncoder().encode(jsonString).buffer;
526
- }
527
- function arrayBufferToData(arrayBuffer) {
528
- let jsonString = new TextDecoder().decode(new Uint8Array(arrayBuffer));
529
- jsonString = jsonString.replace(/^\0+/, '');
530
- return JSON.parse(jsonString);
531
- }
532
- /**
533
- * Converts bytes into a more human-friendly format (e.g., KB, MB, GB).
534
- * @internal
535
- * @param bytes - The number of bytes to convert.
536
- * @param decimals - The number of decimals to display (default is 2).
537
- * @returns A formatted string representing the size in appropriate units.
538
- */
539
- function _formatBytes(bytes, decimals = 2) {
540
- if (bytes === 0)
541
- return "0 Bytes";
542
- const k = 1024; // 1 KB = 1024 Bytes
543
- const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
544
- const i = Math.floor(Math.log(bytes) / Math.log(k)); // Determines the index for size
545
- const sizeInUnit = bytes / Math.pow(k, i); // Converts bytes to appropriate unit
546
- return `${sizeInUnit.toFixed(decimals)} ${sizes[i]}`;
547
- }
548
-
549
- /**
550
- * @public
551
- * @remarks
552
- * The message class is a simple class that represents a message object.
553
- * @sealed
554
- */
555
- class Message {
556
- id = _messageId();
557
- timestamp = Date.now();
558
- status = "pending";
559
- checksum;
560
- _body;
561
- constructor(msg) {
562
- if (typeof msg === 'object' && msg.hasOwnProperty('body')) {
563
- this.id = msg.id || this.id;
564
- this.timestamp = msg.timestamp || this.timestamp;
565
- this.status = msg.status || this.status;
566
- this.checksum = msg.checksum || this.checksum;
567
- this.body = msg.body;
568
- }
569
- else {
570
- this.body = msg;
571
- }
572
- this.validatebodySize();
573
- }
574
- get body() {
575
- return deserialize(this._body);
576
- }
577
- set body(value) {
578
- this._body = serialize(value);
579
- if (!this.checksum) {
580
- this.checksum = generateChecksum(this._body);
581
- }
582
- }
583
- verifyChecksum = () => {
584
- if (!this.checksum)
585
- throw new Error("No message checksum");
586
- const isValid = verifyChecksum(this._body, this.checksum);
587
- if (!isValid)
588
- throw new Error("Invalid message checksum");
589
- };
590
- validatebodySize(maxSize = 1024 * 1024 * 3) {
591
- const sizeInBytes = new TextEncoder().encode(this._body).length;
592
- if (sizeInBytes > maxSize) {
593
- throw new Error(`body size exceeds the limit of ${_formatBytes(maxSize)}.`);
594
- }
595
- }
596
- serialize = () => {
597
- return JSON.stringify({
598
- id: this.id,
599
- timestamp: this.timestamp,
600
- body: this.body,
601
- status: this.status,
602
- checksum: this.checksum,
603
- });
604
- };
605
- static deserialize = (data) => {
606
- if (typeof data !== 'string') {
607
- log.warn('Message.deserialize: data is not a string', data);
608
- }
609
- const msg = JSON.parse(data);
610
- return new Message(msg);
611
- };
612
- }
613
-
614
- /**
615
- * @public
616
- * @remarks
617
- * This class represents a message object that can be sent over the network
618
- * @sealed
619
- */
620
- class Packet {
621
- id;
622
- subject;
623
- source;
624
- target;
625
- headers; // Optional: Additional headers for the packet
626
- message; // By making the message optional, we can send packets without messages. Essentially performing a GET request or other bodyless requests
627
- timestamp;
628
- ttl; // Optional: Time-to-live in milliseconds
629
- signature; // Optional: Cryptographic signature for verification
630
- constructor({ id, subject, source, target, headers, message, ttl, signature, timestamp }) {
631
- this.id = id || _packetId(); // Ensure the packet has a unique ID
632
- this.subject = subject;
633
- this.source = source;
634
- this.target = target;
635
- this.headers = headers || {};
636
- this.message = message;
637
- this.timestamp = Date.now(); // Automatically track packet creation time
638
- this.ttl = ttl;
639
- this.signature = signature;
640
- this.timestamp = timestamp || Date.now();
641
- }
642
- // Serialize the packet for network transmission
643
- serialize() {
644
- return JSON.stringify({
645
- id: this.id,
646
- source: this.source,
647
- subject: this.subject,
648
- target: this.target,
649
- headers: this.headers,
650
- message: this.message && this.message.serialize(),
651
- timestamp: this.timestamp,
652
- ttl: this.ttl,
653
- signature: this.signature,
654
- });
655
- }
656
- // Deserialize a packet from a string
657
- static deserialize(data) {
658
- const obj = JSON.parse(data);
659
- return new Packet({
660
- id: obj.id,
661
- subject: obj.subject,
662
- source: obj.source,
663
- target: obj.target,
664
- headers: obj.headers,
665
- message: obj.message && Message.deserialize(obj.message),
666
- timestamp: obj.timestamp,
667
- ttl: obj.ttl,
668
- signature: obj.signature,
669
- });
670
- }
671
- // Verify TTL: Checks if the packet is still valid based on TTL
672
- isExpired() {
673
- if (!this.ttl)
674
- return false; // No TTL means no expiration
675
- return Date.now() > this.timestamp + this.ttl;
676
- }
677
- }
678
-
679
- function SerializeMessage(target, propertyKey, descriptor) {
680
- const originalMethod = descriptor.value;
681
- descriptor.value = function (...args) {
682
- const [subject, message] = args;
683
- if (typeof message !== "string") {
684
- throw new Error("Message must be a string");
685
- }
686
- const serializedMessage = new Message({
687
- subject,
688
- payload: message,
689
- status: "pending",
690
- headers: new Map([["Content-Type", "application/json"]]),
691
- }).serialize();
692
- return originalMethod.apply(this, [subject, serializedMessage]);
693
- };
694
- return descriptor;
695
- }
696
-
697
- // Re-export Message and its types
698
- const decorators = {
699
- SerializeMessage
700
- };
701
-
702
- /**
703
- * Shared zero-knowledge types and circuit constants.
704
- *
705
- * Used by both the browser/server builds (where snarkjs handles proof generation
706
- * and verification) and the workers build (where verification runs through
707
- * `bn128.wasm` via `src/workers/groth16-verifier.ts`). Keeping these here ensures
708
- * proof shapes and verification keys stay identical across runtimes.
709
- */
710
- /**
711
- * Verification key for the `preimagePoK` circuit (Poseidon-commitment
712
- * proof-of-knowledge with three public signals: commitment, nonce, ecdsaPubHash).
713
- *
714
- * Pinned here so worker-side and SDK-side verification agree on the key being
715
- * checked. If the circuit is recompiled, regenerate this constant and
716
- * `public/circuits/build/preimagePoK_verification_key.json` together.
717
- */
718
- const PREIMAGE_POK_VERIFICATION_KEY = {
719
- protocol: "groth16",
720
- curve: "bn128",
721
- nPublic: 3,
722
- vk_alpha_1: [
723
- "20491192805390485299153009773594534940189261866228447918068658471970481763042",
724
- "9383485363053290200918347156157836566562967994039712273449902621266178545958",
725
- "1"
726
- ],
727
- vk_beta_2: [
728
- [
729
- "6375614351688725206403948262868962793625744043794305715222011528459656738731",
730
- "4252822878758300859123897981450591353533073413197771768651442665752259397132"
731
- ],
732
- [
733
- "10505242626370262277552901082094356697409835680220590971873171140371331206856",
734
- "21847035105528745403288232691147584728191162732299865338377159692350059136679"
735
- ],
736
- [
737
- "1",
738
- "0"
739
- ]
740
- ],
741
- vk_gamma_2: [
742
- [
743
- "10857046999023057135944570762232829481370756359578518086990519993285655852781",
744
- "11559732032986387107991004021392285783925812861821192530917403151452391805634"
745
- ],
746
- [
747
- "8495653923123431417604973247489272438418190587263600148770280649306958101930",
748
- "4082367875863433681332203403145435568316851327593401208105741076214120093531"
749
- ],
750
- [
751
- "1",
752
- "0"
753
- ]
754
- ],
755
- vk_delta_2: [
756
- [
757
- "16843627858994773805056502117979518680360297888097507527057721641174626133429",
758
- "2669618170444825402403730985182974839894668798317345855172970345856260721653"
759
- ],
760
- [
761
- "20564952487570762020467138133408075499830271526522626813107251678961587215295",
762
- "9630342855454833575580303045534431010412631371159617591163132980579520487965"
763
- ],
764
- [
765
- "1",
766
- "0"
767
- ]
768
- ],
769
- vk_alphabeta_12: [
770
- [
771
- [
772
- "2029413683389138792403550203267699914886160938906632433982220835551125967885",
773
- "21072700047562757817161031222997517981543347628379360635925549008442030252106"
774
- ],
775
- [
776
- "5940354580057074848093997050200682056184807770593307860589430076672439820312",
777
- "12156638873931618554171829126792193045421052652279363021382169897324752428276"
778
- ],
779
- [
780
- "7898200236362823042373859371574133993780991612861777490112507062703164551277",
781
- "7074218545237549455313236346927434013100842096812539264420499035217050630853"
782
- ]
783
- ],
784
- [
785
- [
786
- "7077479683546002997211712695946002074877511277312570035766170199895071832130",
787
- "10093483419865920389913245021038182291233451549023025229112148274109565435465"
788
- ],
789
- [
790
- "4595479056700221319381530156280926371456704509942304414423590385166031118820",
791
- "19831328484489333784475432780421641293929726139240675179672856274388269393268"
792
- ],
793
- [
794
- "11934129596455521040620786944827826205713621633706285934057045369193958244500",
795
- "8037395052364110730298837004334506829870972346962140206007064471173334027475"
796
- ]
797
- ]
798
- ],
799
- IC: [
800
- [
801
- "6593633352362890744195366164011945207337919238085164401989523182031213441232",
802
- "21183283244721822514187218730411278389501771108619619957207607994811554523781",
803
- "1"
804
- ],
805
- [
806
- "19317830753800014286972931403860527733342849870141075528271937285218206220756",
807
- "14626265811834596630857393417326981325583938311796888424299048456918853093257",
808
- "1"
809
- ],
810
- [
811
- "7942727853353225551121019923926808347232536417992238353855978019969636961405",
812
- "8824649763391398686420260814761862276544573369118345976741973565095405175062",
813
- "1"
814
- ],
815
- [
816
- "8369441262422248167284752361555580367206817200973928868895308479466335503315",
817
- "7836653245051994305208746627300011506099851195782496031197976259815728652585",
818
- "1"
819
- ]
820
- ]
821
- };
822
-
823
- /**
824
- * WebCrypto subtle-interface resolver.
825
- *
826
- * Available natively in every runtime this SDK targets (modern browsers,
827
- * Node 16+, CF Workers). Centralized here so the runtime check + error
828
- * message are consistent across every primitive — and so a future polyfill
829
- * shim has one place to plug in.
830
- */
831
- function getSubtle() {
832
- const s = globalThis.crypto?.subtle;
833
- if (!s) {
834
- throw new Error("@muhkoo/connect crypto: `globalThis.crypto.subtle` is unavailable. " +
835
- "Modern browsers, Node 16+, and CF Workers expose it natively.");
836
- }
837
- return s;
838
- }
839
-
840
- /**
841
- * Cryptographically secure random bytes.
842
- *
843
- * Wraps `crypto.getRandomValues` with two small affordances every caller
844
- * needs:
845
- * - Allocates over a fresh, non-shared `ArrayBuffer` so the returned
846
- * `Uint8Array` satisfies WebCrypto's `BufferSource` type under strict
847
- * TS lib settings (where `Uint8Array<ArrayBufferLike>` isn't directly
848
- * assignable).
849
- * - Chunks requests larger than 65 KiB, the per-call cap browsers enforce
850
- * on `getRandomValues`.
851
- */
852
- const MAX_PER_CALL = 65536;
853
- function randomBytes(n) {
854
- if (!Number.isInteger(n) || n < 0) {
855
- throw new Error(`randomBytes: n must be a non-negative integer (got ${n})`);
856
- }
857
- const buf = new Uint8Array(new ArrayBuffer(n));
858
- for (let offset = 0; offset < n; offset += MAX_PER_CALL) {
859
- const slice = buf.subarray(offset, Math.min(offset + MAX_PER_CALL, n));
860
- globalThis.crypto.getRandomValues(slice);
861
- }
862
- return buf;
863
- }
864
-
865
- /**
866
- * AES-256-GCM encryption / decryption with raw key bytes.
867
- *
868
- * The two functions here are the single canonical AES-GCM call site in the
869
- * SDK. Earlier copies of this logic existed inline in `DoubleRatchet`, in the
870
- * storage `ChunkCipher`, and in the passphrase-wrap helpers — they all now
871
- * route through here so the algorithm, IV size, and tag handling stay in one
872
- * place.
873
- *
874
- * Conventions:
875
- * - 256-bit keys only. Passing 16- or 24-byte keys throws; callers that
876
- * need AES-128 should add a dedicated primitive.
877
- * - 96-bit IVs. WebCrypto's recommended GCM IV length; trades the 4-byte
878
- * IV economy of 128-bit for compatibility with every spec-compliant
879
- * implementation.
880
- * - The 16-byte GCM authentication tag is appended to the ciphertext by
881
- * WebCrypto's default behavior. Callers don't manage it separately.
882
- *
883
- * If a future need arises for AAD (associated data), add an optional `aad`
884
- * parameter to both functions rather than introducing a parallel primitive.
885
- */
886
- /** Length of the AES key in bytes. */
887
- const AES_GCM_KEY_BYTES = 32;
888
- /** Length of the AES-GCM IV in bytes (WebCrypto-recommended). */
889
- const AES_GCM_IV_BYTES = 12;
890
- /** Length of the AES-GCM authentication tag in bytes (appended to ciphertext). */
891
- const AES_GCM_TAG_BYTES = 16;
892
- /**
893
- * Encrypt `plaintext` under a 32-byte AES-256 key with the supplied 12-byte
894
- * IV. Returns ciphertext with the 16-byte GCM tag appended (so the output
895
- * length is `plaintext.length + 16`).
896
- *
897
- * The IV must be unique per (key, message). Callers that generate the IV
898
- * randomly should grab it via `randomBytes(AES_GCM_IV_BYTES)`; callers
899
- * managing a counter pass their own.
900
- */
901
- async function encryptAesGcm(key, iv, plaintext) {
902
- assertKey(key);
903
- assertIv(iv);
904
- const cryptoKey = await importAesGcmKey(key, ["encrypt"]);
905
- const ciphertext = await getSubtle().encrypt({ name: "AES-GCM", iv: iv }, cryptoKey, plaintext);
906
- return new Uint8Array(ciphertext);
907
- }
908
- /**
909
- * Inverse of {@link encryptAesGcm}. Throws if the GCM auth tag fails — this
910
- * captures "wrong key", "wrong IV", or "ciphertext was tampered with",
911
- * indistinguishably. Callers that care about distinguishing those should
912
- * keep separate provenance bookkeeping, not invent a parallel MAC.
913
- */
914
- async function decryptAesGcm(key, iv, ciphertext) {
915
- assertKey(key);
916
- assertIv(iv);
917
- const cryptoKey = await importAesGcmKey(key, ["decrypt"]);
918
- const plaintext = await getSubtle().decrypt({ name: "AES-GCM", iv: iv }, cryptoKey, ciphertext);
919
- return new Uint8Array(plaintext);
920
- }
921
- async function importAesGcmKey(key, usages) {
922
- return await getSubtle().importKey("raw", key, { name: "AES-GCM" }, false, usages);
923
- }
924
- function assertKey(key) {
925
- if (key.byteLength !== AES_GCM_KEY_BYTES) {
926
- throw new Error(`aes-gcm: key must be ${AES_GCM_KEY_BYTES} bytes (got ${key.byteLength})`);
927
- }
928
- }
929
- function assertIv(iv) {
930
- if (iv.byteLength !== AES_GCM_IV_BYTES) {
931
- throw new Error(`aes-gcm: iv must be ${AES_GCM_IV_BYTES} bytes (got ${iv.byteLength})`);
932
- }
933
- }
934
-
935
- /**
936
- * Key-derivation primitives — PBKDF2 (for passphrase → key) and HKDF (for
937
- * symmetric key material → expanded key material).
938
- *
939
- * PBKDF2 is the slow, salted KDF the passphrase-wrap helper uses to harden
940
- * user passwords against offline guessing. HKDF is the fast, deterministic
941
- * KDF the Double Ratchet uses to derive root + chain + message keys from
942
- * shared secrets.
943
- *
944
- * Both are SHA-256-backed everywhere in this codebase — keep it that way
945
- * unless there's a concrete reason to diverge.
946
- */
947
- /**
948
- * Iteration count default for PBKDF2 passphrase hardening. Tuned for
949
- * 2024–2026 hardware: slow enough to deter offline guessing of weak
950
- * passphrases (~100ms on commodity laptops), fast enough that interactive
951
- * unlock stays sub-second.
952
- */
953
- const PBKDF2_DEFAULT_ITERATIONS = 200_000;
954
- /**
955
- * Derive a 256-bit AES-GCM key from `passphrase + salt` via PBKDF2-SHA256.
956
- *
957
- * Returned as raw bytes (not a `CryptoKey`) so callers can hand it straight
958
- * to {@link encryptAesGcm} — that's the convention everywhere else in the
959
- * primitive layer. If a future caller needs the non-extractable
960
- * `CryptoKey` form, add a parallel `deriveCryptoKeyFromPassphrase` variant
961
- * rather than overloading this one.
962
- */
963
- async function deriveAesKeyFromPassphrase(passphrase, salt, iterations = PBKDF2_DEFAULT_ITERATIONS) {
964
- if (typeof passphrase !== "string" || passphrase.length === 0) {
965
- throw new Error("kdf.deriveAesKeyFromPassphrase: passphrase must be a non-empty string");
966
- }
967
- const s = getSubtle();
968
- const passphraseKey = await s.importKey("raw", new TextEncoder().encode(passphrase), { name: "PBKDF2" }, false, ["deriveBits"]);
969
- const bits = await s.deriveBits({
970
- name: "PBKDF2",
971
- salt: salt,
972
- iterations,
973
- hash: "SHA-256",
974
- }, passphraseKey, 256);
975
- return new Uint8Array(bits);
976
- }
977
- /**
978
- * HKDF-Expand with SHA-256, returning `lengthBytes` raw bytes of key material.
979
- *
980
- * `info` is the per-purpose label (e.g. `"DoubleRatchetMsg"`). Optional
981
- * `salt` defaults to an empty buffer, matching the way the Double Ratchet
982
- * code has always used it.
983
- *
984
- * Note: this is intentionally a one-shot Extract-then-Expand call rather than
985
- * exposing Extract and Expand separately — every call site in this codebase
986
- * wants the same shape, and a richer API can be added later if needed.
987
- */
988
- async function deriveBitsHkdf(inputKeyMaterial, info, lengthBytes, salt = new Uint8Array(0)) {
989
- if (lengthBytes <= 0) {
990
- throw new Error(`kdf.deriveBitsHkdf: lengthBytes must be > 0 (got ${lengthBytes})`);
991
- }
992
- const s = getSubtle();
993
- const key = await s.importKey("raw", inputKeyMaterial, { name: "HKDF" }, false, ["deriveBits"]);
994
- const bits = await s.deriveBits({
995
- name: "HKDF",
996
- hash: "SHA-256",
997
- salt: salt,
998
- info: new TextEncoder().encode(info),
999
- }, key, lengthBytes * 8);
1000
- return new Uint8Array(bits);
1001
- }
1002
-
1003
- class KeyStore {
1004
- static instance;
1005
- _keys = new Map();
1006
- _authKeys = new Map();
1007
- constructor() { }
1008
- static getInstance() {
1009
- if (!KeyStore.instance) {
1010
- KeyStore.instance = new KeyStore();
1011
- }
1012
- return KeyStore.instance;
1013
- }
1014
- get keys() {
1015
- return this._keys;
1016
- }
1017
- get authKeys() {
1018
- return this._authKeys;
1019
- }
1020
- async generateOwnKeyPair(id) {
1021
- if (this._keys.has(id)) {
1022
- throw new Error(`Key pair for ${id} already exists.`);
1023
- }
1024
- const ecdhKeyPair = await crypto.subtle.generateKey({ name: 'ECDH', namedCurve: 'P-384' }, true, ['deriveKey', 'deriveBits']);
1025
- this._keys.set(id, { privateKey: ecdhKeyPair.privateKey, publicKey: ecdhKeyPair.publicKey });
1026
- const ecdsaKeyPair = await crypto.subtle.generateKey({ name: 'ECDSA', namedCurve: 'P-384' }, true, ['sign', 'verify']);
1027
- this._authKeys.set(id, { privateKey: ecdsaKeyPair.privateKey, publicKey: ecdsaKeyPair.publicKey });
1028
- const dehydrated = await this.dehydrateKeyPair(id);
1029
- appLogger.debug(`Generated key pair for ${id}: publicKey=${dehydrated.ecdhPub.slice(0, 16)}...`);
1030
- return { privateKey: ecdhKeyPair.privateKey, publicKey: ecdhKeyPair.publicKey };
1031
- }
1032
- async storeRemotePublicKeys(id, ecdhPublicKey, ecdsaPublicKey) {
1033
- const existing = this._keys.get(id);
1034
- if (!existing || !existing.privateKey) {
1035
- this._keys.set(id, { privateKey: null, publicKey: ecdhPublicKey });
1036
- }
1037
- const existingAuth = this._authKeys.get(id);
1038
- if (!existingAuth || !existingAuth.privateKey) {
1039
- this._authKeys.set(id, { privateKey: null, publicKey: ecdsaPublicKey });
1040
- }
1041
- const dehydrated = await this.dehydrateKeyPair(id);
1042
- appLogger.debug(`Stored remote public keys for ${id}: ecdhPub=${dehydrated.ecdhPub.slice(0, 16)}...`);
1043
- }
1044
- async hydrateKeyPair(id, dehydrated) {
1045
- const ecdhPubJwk = JSON.parse(deserialize(dehydrated.ecdhPub));
1046
- const ecdhPublicKey = await crypto.subtle.importKey('jwk', ecdhPubJwk, { name: 'ECDH', namedCurve: 'P-384' }, true, []);
1047
- const ecdsaPubJwk = JSON.parse(deserialize(dehydrated.ecdsaPub));
1048
- const ecdsaPublicKey = await crypto.subtle.importKey('jwk', ecdsaPubJwk, { name: 'ECDSA', namedCurve: 'P-384' }, true, ['verify']);
1049
- let ecdhPrivateKey = null;
1050
- let ecdsaPrivateKey = null;
1051
- if (dehydrated.ecdhPriv) {
1052
- const ecdhPrivJwk = JSON.parse(deserialize(dehydrated.ecdhPriv));
1053
- ecdhPrivateKey = await crypto.subtle.importKey('jwk', ecdhPrivJwk, { name: 'ECDH', namedCurve: 'P-384' }, true, ['deriveKey', 'deriveBits']);
1054
- }
1055
- if (dehydrated.ecdsaPriv) {
1056
- const ecdsaPrivJwk = JSON.parse(deserialize(dehydrated.ecdsaPriv));
1057
- ecdsaPrivateKey = await crypto.subtle.importKey('jwk', ecdsaPrivJwk, { name: 'ECDSA', namedCurve: 'P-384' }, true, ['sign']);
1058
- }
1059
- const existing = this._keys.get(id);
1060
- if (!existing || !existing.privateKey) {
1061
- this._keys.set(id, { privateKey: ecdhPrivateKey, publicKey: ecdhPublicKey });
1062
- }
1063
- const existingAuth = this._authKeys.get(id);
1064
- if (!existingAuth || !existingAuth.privateKey) {
1065
- this._authKeys.set(id, { privateKey: ecdsaPrivateKey, publicKey: ecdsaPublicKey });
1066
- }
1067
- }
1068
- getKeyPair(id) {
1069
- return this._keys.get(id) || null;
1070
- }
1071
- getAuthKeyPair(id) {
1072
- return this._authKeys.get(id) || null;
1073
- }
1074
- async dehydrateKeyPair(id) {
1075
- const keyPair = this._keys.get(id);
1076
- const authKeyPair = this._authKeys.get(id);
1077
- if (!keyPair || !authKeyPair) {
1078
- throw new Error(`No key pair for ${id}`);
1079
- }
1080
- const ecdhPubJwk = await crypto.subtle.exportKey('jwk', keyPair.publicKey);
1081
- const ecdhPrivJwk = keyPair.privateKey ? await crypto.subtle.exportKey('jwk', keyPair.privateKey) : null;
1082
- const ecdsaPubJwk = await crypto.subtle.exportKey('jwk', authKeyPair.publicKey);
1083
- const ecdsaPrivJwk = authKeyPair.privateKey ? await crypto.subtle.exportKey('jwk', authKeyPair.privateKey) : null;
1084
- const ecdhPubBase64 = JSON.stringify(ecdhPubJwk).replace(/=+$/, '');
1085
- const ecdhPrivBase64 = ecdhPrivJwk ? JSON.stringify(ecdhPrivJwk).replace(/=+$/, '') : '';
1086
- const ecdsaPubBase64 = JSON.stringify(ecdsaPubJwk).replace(/=+$/, '');
1087
- const ecdsaPrivBase64 = ecdsaPrivJwk ? JSON.stringify(ecdsaPrivJwk).replace(/=+$/, '') : '';
1088
- return {
1089
- ecdhPub: serialize(ecdhPubBase64),
1090
- ecdhPriv: ecdhPrivBase64 ? serialize(ecdhPrivBase64) : '',
1091
- ecdsaPub: serialize(ecdsaPubBase64),
1092
- ecdsaPriv: ecdsaPrivBase64 ? serialize(ecdsaPrivBase64) : '',
1093
- };
1094
- }
1095
- async getRawEcdsaPublicKey(id) {
1096
- const authKeyPair = this._authKeys.get(id);
1097
- if (!authKeyPair) {
1098
- return null;
1099
- }
1100
- const jwk = await crypto.subtle.exportKey('jwk', authKeyPair.publicKey);
1101
- const x = fromBase64Url(jwk.x);
1102
- const y = fromBase64Url(jwk.y);
1103
- // SEC1 uncompressed point: 0x04 || x || y
1104
- return concatBytes(new Uint8Array([0x04]), x, y);
1105
- }
1106
- async packDehydratedKeys(id) {
1107
- const dehydrated = await this.dehydrateKeyPair(id);
1108
- const combined = JSON.stringify(dehydrated);
1109
- return toBase64(new TextEncoder().encode(combined));
1110
- }
1111
- async hydrateFromPacked(id, masterKey) {
1112
- const decoded = utf8Decode(fromBase64(masterKey));
1113
- const dehydrated = JSON.parse(decoded);
1114
- await this.hydrateKeyPair(id, dehydrated);
1115
- }
1116
- }
1117
-
1118
- // We rely on the WebCrypto global (`crypto`/`globalThis.crypto`) — present in
1119
- // browsers, CF Workers, and Node 19+. No `require('crypto')` Node fallback;
1120
- // supported runtimes all expose WebCrypto natively.
1121
- async function getPubKeyHex(pubKey) {
1122
- const exported = await crypto.subtle.exportKey('raw', pubKey);
1123
- return toHex(new Uint8Array(exported));
1124
- }
1125
- async function keysEqual(key1, key2) {
1126
- const hex1 = await getPubKeyHex(key1);
1127
- const hex2 = await getPubKeyHex(key2);
1128
- return hex1 === hex2;
1129
- }
1130
- class DoubleRatchet {
1131
- state;
1132
- sessionType;
1133
- maxSkip = 3000;
1134
- overlapPeriod = 30000; // ms
1135
- windowSize = 100; // messages per DH ratchet
1136
- constructor(senderId, recipientId, sessionType, isClient = true) {
1137
- this.sessionType = sessionType;
1138
- const keyStore = KeyStore.getInstance();
1139
- const senderKeyPair = keyStore.getKeyPair(senderId);
1140
- const recipientKeyPair = keyStore.getKeyPair(recipientId);
1141
- if (!senderKeyPair || !senderKeyPair.privateKey) {
1142
- throw new Error(`Missing own key pair for sender ${senderId}`);
1143
- }
1144
- if (!recipientKeyPair || !recipientKeyPair.publicKey) {
1145
- throw new Error(`Missing public key for recipient ${recipientId}`);
1146
- }
1147
- this.state = {
1148
- clientDhPriv: isClient ? senderKeyPair.privateKey : null,
1149
- clientDhPub: isClient ? senderKeyPair.publicKey : recipientKeyPair.publicKey,
1150
- serverDhPriv: isClient ? null : senderKeyPair.privateKey,
1151
- serverDhPub: isClient ? recipientKeyPair.publicKey : senderKeyPair.publicKey,
1152
- rootKey: null,
1153
- sendChainKey: null,
1154
- recvChainKey: null,
1155
- sendCount: 0,
1156
- recvCount: 0,
1157
- prevChainLength: 0,
1158
- currentSkippedKeys: new Map(),
1159
- oldSkippedMessageKeys: new Map(),
1160
- };
1161
- appLogger.debug(`Constructor: senderId=${senderId}, recipientId=${recipientId}, isClient=${isClient}`);
1162
- }
1163
- hkdf(input, info, length) {
1164
- return deriveBitsHkdf(input, info, length);
1165
- }
1166
- async initializeSession(isClient = true) {
1167
- appLogger.debug(`Initializing session: isClient=${isClient}, sessionType=${this.sessionType}`);
1168
- const ownPriv = isClient ? this.state.clientDhPriv : this.state.serverDhPriv;
1169
- if (!ownPriv) {
1170
- throw new Error('Missing own private key');
1171
- }
1172
- const remotePub = isClient ? this.state.serverDhPub : this.state.clientDhPub;
1173
- const sharedSecret = await crypto.subtle.deriveBits({ name: 'ECDH', public: remotePub }, ownPriv, 384);
1174
- const keys = await this.hkdf(new Uint8Array(sharedSecret), 'DoubleRatchetInit', 32);
1175
- this.state.rootKey = keys;
1176
- this.state.sendChainKey = this.state.rootKey;
1177
- this.state.recvChainKey = this.state.rootKey;
1178
- appLogger.debug(`Initialized: rootKey set`);
1179
- }
1180
- async dhRatchet(newPubKey, isClient = true) {
1181
- appLogger.debug(`DH ratchet: isClient=${isClient}`);
1182
- const ownPriv = isClient ? this.state.clientDhPriv : this.state.serverDhPriv;
1183
- if (!ownPriv) {
1184
- throw new Error('Missing own private key');
1185
- }
1186
- const sharedSecret = await crypto.subtle.deriveBits({ name: 'ECDH', public: newPubKey }, ownPriv, 384);
1187
- const input = concatBytes(this.state.rootKey, new Uint8Array(sharedSecret));
1188
- const keys = await this.hkdf(input, 'DoubleRatchetDH', 64);
1189
- this.state.rootKey = keys.subarray(0, 32);
1190
- this.state.recvChainKey = keys.subarray(32);
1191
- this.state.sendChainKey = isClient ? this.state.recvChainKey : this.state.rootKey;
1192
- this.state.prevChainLength = this.state.sendCount;
1193
- this.state.sendCount = 0;
1194
- this.state.recvCount = 0;
1195
- appLogger.debug(`DH ratchet complete`);
1196
- }
1197
- async symmetricRatchet(chainKey) {
1198
- const keys = await this.hkdf(chainKey, 'DoubleRatchetMsg', 64);
1199
- const messageKey = keys.subarray(0, 32);
1200
- const newChainKey = keys.subarray(32);
1201
- appLogger.debug(`Symmetric ratchet: messageKey generated`);
1202
- return [messageKey, newChainKey];
1203
- }
1204
- async encrypt(plaintext, newDhKey = false, senderId, recipientId, sessionId, sessionType) {
1205
- if (sessionType !== this.sessionType) {
1206
- throw new Error(`Session type mismatch: expected ${this.sessionType}, got ${sessionType}`);
1207
- }
1208
- const keyStore = KeyStore.getInstance();
1209
- if (this.sessionType === 'specific' && this.state.sendCount >= this.windowSize && this.state.sendCount > 0) {
1210
- newDhKey = true;
1211
- }
1212
- if (newDhKey && this.sessionType === 'specific') {
1213
- appLogger.debug(`Generating new DH key pair for ${senderId}`);
1214
- const ecdhKeyPair = await crypto.subtle.generateKey({ name: 'ECDH', namedCurve: 'P-384' }, true, ['deriveKey', 'deriveBits']);
1215
- this.state.clientDhPriv = ecdhKeyPair.privateKey;
1216
- this.state.clientDhPub = ecdhKeyPair.publicKey;
1217
- keyStore.keys.set(senderId, { privateKey: ecdhKeyPair.privateKey, publicKey: ecdhKeyPair.publicKey });
1218
- await this.dhRatchet(this.state.serverDhPub, true);
1219
- }
1220
- const [messageKey, newChainKey] = await this.symmetricRatchet(this.state.sendChainKey);
1221
- this.state.sendChainKey = newChainKey;
1222
- const iv = randomBytes(AES_GCM_IV_BYTES);
1223
- const encrypted = await encryptAesGcm(messageKey, iv, utf8Encode(plaintext));
1224
- const cipherTextWithTag = toHex(encrypted);
1225
- appLogger.debug(`Encrypt: plaintextLength=${plaintext.length}, ciphertextLength=${encrypted.byteLength}`);
1226
- this.state.sendCount++;
1227
- const dehydratedSender = await keyStore.dehydrateKeyPair(senderId);
1228
- const header = {
1229
- dhPub: dehydratedSender.ecdhPub,
1230
- prevChainLength: this.state.prevChainLength,
1231
- messageNumber: this.state.sendCount,
1232
- sessionId,
1233
- sessionType,
1234
- senderId,
1235
- recipientId,
1236
- timestamp: Date.now(),
1237
- signature: '',
1238
- };
1239
- appLogger.debug(`Message header:`, header);
1240
- appLogger.debug(`Message header:`, keyStore.getAuthKeyPair(senderId).privateKey);
1241
- const sign = await crypto.subtle.sign({ name: 'ECDSA', hash: 'SHA-256' }, keyStore.getAuthKeyPair(senderId).privateKey, utf8Encode(JSON.stringify({
1242
- dhPub: header.dhPub,
1243
- prevChainLength: header.prevChainLength,
1244
- messageNumber: header.messageNumber,
1245
- sessionId,
1246
- sessionType,
1247
- senderId,
1248
- recipientId,
1249
- timestamp: header.timestamp
1250
- })));
1251
- header.signature = toHex(new Uint8Array(sign));
1252
- appLogger.debug(`Encrypted: sessionId=${sessionId}, messageNumber=${this.state.sendCount}, sender=${senderId}, recipient=${recipientId}`);
1253
- return {
1254
- header,
1255
- ciphertext: cipherTextWithTag,
1256
- nonce: toHex(iv),
1257
- };
1258
- }
1259
- cleanOldSkippedKeys() {
1260
- const now = Date.now();
1261
- for (const skipped of this.state.oldSkippedMessageKeys.entries()) {
1262
- // [pubHex, { created }]
1263
- const pubHex = skipped[0];
1264
- const data = skipped[1];
1265
- const created = data.created;
1266
- if (now > created + this.overlapPeriod) {
1267
- this.state.oldSkippedMessageKeys.delete(pubHex);
1268
- }
1269
- }
1270
- }
1271
- async decrypt(message, isClient = true) {
1272
- // const { header, ciphertext, nonce } = message;
1273
- const header = message.header;
1274
- const ciphertext = message.ciphertext;
1275
- const nonce = message.nonce;
1276
- if (header.sessionType !== this.sessionType) {
1277
- throw new Error(`Session type mismatch: expected ${this.sessionType}, got ${header.sessionType}`);
1278
- }
1279
- const keyStore = KeyStore.getInstance();
1280
- const verify = await crypto.subtle.verify({ name: 'ECDSA', hash: 'SHA-256' }, keyStore.getAuthKeyPair(header.senderId).publicKey, fromHex(header.signature), utf8Encode(JSON.stringify({
1281
- dhPub: header.dhPub,
1282
- prevChainLength: header.prevChainLength,
1283
- messageNumber: header.messageNumber,
1284
- sessionId: header.sessionId,
1285
- sessionType: header.sessionType,
1286
- senderId: header.senderId,
1287
- recipientId: header.recipientId,
1288
- timestamp: header.timestamp
1289
- })));
1290
- if (!verify) {
1291
- throw new Error('Invalid signature');
1292
- }
1293
- const maxAge = 5 * 60 * 1000;
1294
- if (Math.abs(Date.now() - header.timestamp) > maxAge) {
1295
- throw new Error('CipherMessage too old, possible replay attack');
1296
- }
1297
- appLogger.debug(`Decrypting: sessionId=${header.sessionId}, messageNumber=${header.messageNumber}, sender=${header.senderId}, recipient=${header.recipientId}`);
1298
- if (!ciphertext || !nonce || !header.dhPub) {
1299
- throw new Error('Invalid message: missing ciphertext, nonce, or dhPub');
1300
- }
1301
- if (!/^[0-9a-fA-F]+$/.test(ciphertext) || ciphertext.length % 2 !== 0) {
1302
- throw new Error(`Invalid ciphertext: not a valid hex string (length=${ciphertext.length})`);
1303
- }
1304
- if (!/^[0-9a-fA-F]+$/.test(nonce) || nonce.length % 2 !== 0) {
1305
- throw new Error(`Invalid nonce: not a valid hex string (length=${nonce.length})`);
1306
- }
1307
- const ciphertextBuffer = fromHex(ciphertext);
1308
- const nonceBuffer = fromHex(nonce);
1309
- if (nonceBuffer.length !== 12) {
1310
- throw new Error(`Invalid nonce: must be 12 bytes (length=${nonceBuffer.length})`);
1311
- }
1312
- const senderPubJwk = JSON.parse(deserialize(header.dhPub));
1313
- const senderPubKey = await crypto.subtle.importKey('jwk', senderPubJwk, { name: 'ECDH', namedCurve: 'P-384' }, true, []);
1314
- const senderPubHex = await getPubKeyHex(senderPubKey);
1315
- const currentSenderPub = isClient ? this.state.serverDhPub : this.state.clientDhPub;
1316
- const currentSenderPubHex = await getPubKeyHex(currentSenderPub);
1317
- this.cleanOldSkippedKeys();
1318
- let messageKey;
1319
- if (senderPubHex === currentSenderPubHex) {
1320
- // Current chain
1321
- if (header.messageNumber > this.state.recvCount) {
1322
- const numSkips = header.messageNumber - this.state.recvCount - 1;
1323
- if (numSkips > this.maxSkip) {
1324
- throw new Error('Too many skipped messages');
1325
- }
1326
- for (let i = 0; i < numSkips; i++) {
1327
- const [skippedKey, newChainKey] = await this.symmetricRatchet(this.state.recvChainKey);
1328
- this.state.currentSkippedKeys.set(this.state.recvCount + 1 + i, skippedKey);
1329
- this.state.recvChainKey = newChainKey;
1330
- }
1331
- }
1332
- if (this.state.currentSkippedKeys.has(header.messageNumber)) {
1333
- messageKey = this.state.currentSkippedKeys.get(header.messageNumber);
1334
- this.state.currentSkippedKeys.delete(header.messageNumber);
1335
- appLogger.debug(`Using skipped key for messageNumber=${header.messageNumber}`);
1336
- }
1337
- else {
1338
- const [msgKey, newChainKey] = await this.symmetricRatchet(this.state.recvChainKey);
1339
- messageKey = msgKey;
1340
- this.state.recvChainKey = newChainKey;
1341
- }
1342
- this.state.recvCount = Math.max(this.state.recvCount, header.messageNumber);
1343
- }
1344
- else {
1345
- // Check if new DH pub
1346
- const expectedPubKey = keyStore.getKeyPair(header.senderId).publicKey;
1347
- if (!(await keysEqual(senderPubKey, expectedPubKey))) {
1348
- // New DH key, handle skip on old chain before ratchet
1349
- const oldSenderPubHex = currentSenderPubHex;
1350
- const numSkips = header.prevChainLength - this.state.recvCount;
1351
- if (numSkips > this.maxSkip) {
1352
- throw new Error('Too many skipped messages on old chain');
1353
- }
1354
- let oldSkips = this.state.oldSkippedMessageKeys.get(oldSenderPubHex)?.skips || new Map();
1355
- let tempRecvChainKey = this.state.recvChainKey;
1356
- for (let i = 0; i < numSkips; i++) {
1357
- const [skippedKey, newChainKey] = await this.symmetricRatchet(tempRecvChainKey);
1358
- oldSkips.set(this.state.recvCount + 1 + i, skippedKey);
1359
- tempRecvChainKey = newChainKey;
1360
- }
1361
- this.state.oldSkippedMessageKeys.set(oldSenderPubHex, { skips: oldSkips, created: Date.now() });
1362
- // Clear current skipped
1363
- this.state.currentSkippedKeys.clear();
1364
- // Perform DH ratchet
1365
- await this.dhRatchet(senderPubKey, isClient);
1366
- // Update state sender pub
1367
- if (isClient) {
1368
- this.state.serverDhPub = senderPubKey;
1369
- }
1370
- else {
1371
- this.state.clientDhPub = senderPubKey;
1372
- }
1373
- // Update keyStore
1374
- keyStore.storeRemotePublicKeys(header.senderId, senderPubKey, keyStore.getAuthKeyPair(header.senderId).publicKey);
1375
- // Now derive message key for new chain
1376
- if (header.messageNumber > this.state.recvCount) {
1377
- const numSkipsNew = header.messageNumber - this.state.recvCount - 1;
1378
- if (numSkipsNew > this.maxSkip) {
1379
- throw new Error('Too many skipped messages');
1380
- }
1381
- for (let i = 0; i < numSkipsNew; i++) {
1382
- const [skippedKey, newChainKey] = await this.symmetricRatchet(this.state.recvChainKey);
1383
- this.state.currentSkippedKeys.set(this.state.recvCount + 1 + i, skippedKey);
1384
- this.state.recvChainKey = newChainKey;
1385
- }
1386
- }
1387
- if (this.state.currentSkippedKeys.has(header.messageNumber)) {
1388
- messageKey = this.state.currentSkippedKeys.get(header.messageNumber);
1389
- this.state.currentSkippedKeys.delete(header.messageNumber);
1390
- }
1391
- else {
1392
- const [msgKey, newChainKey] = await this.symmetricRatchet(this.state.recvChainKey);
1393
- messageKey = msgKey;
1394
- this.state.recvChainKey = newChainKey;
1395
- }
1396
- this.state.recvCount = Math.max(this.state.recvCount, header.messageNumber);
1397
- }
1398
- else {
1399
- // Old chain
1400
- const oldData = this.state.oldSkippedMessageKeys.get(senderPubHex);
1401
- if (oldData && oldData.skips.has(header.messageNumber)) {
1402
- messageKey = oldData.skips.get(header.messageNumber);
1403
- oldData.skips.delete(header.messageNumber);
1404
- if (oldData.skips.size === 0) {
1405
- this.state.oldSkippedMessageKeys.delete(senderPubHex);
1406
- }
1407
- appLogger.debug(`Using old skipped key for messageNumber=${header.messageNumber} on old chain`);
1408
- }
1409
- else {
1410
- throw new Error('No key for message on old chain');
1411
- }
1412
- }
1413
- }
1414
- try {
1415
- const decrypted = await decryptAesGcm(messageKey, nonceBuffer, ciphertextBuffer);
1416
- appLogger.debug(`Decrypted successfully: sessionId=${header.sessionId}, messageNumber=${header.messageNumber}`);
1417
- return new TextDecoder().decode(decrypted);
1418
- }
1419
- catch (error) {
1420
- appLogger.error(`Decryption failed: ${error instanceof Error ? error.message : 'unknown error'}`);
1421
- throw new Error(`Decryption failed: ${error instanceof Error ? error.message : 'unknown error'}`);
1422
- }
1423
- }
1424
- getState() {
1425
- return { ...this.state };
1426
- }
1427
- setState(state) {
1428
- this.state = { ...state };
1429
- }
1430
- }
1431
-
1432
- /**
1433
- * Per-chunk AES-256-GCM encryption with random keys and IVs.
1434
- *
1435
- * Each chunk of a stored file gets its own freshly generated 256-bit AES key
1436
- * and 96-bit IV. The (key, IV) pair lives in the file manifest, which the
1437
- * application is responsible for storing under whatever access-control regime
1438
- * it uses (in this codebase: the `SharedSpaceClient` writes manifests into
1439
- * ZK-gated multi-user spaces; the shard store itself is open).
1440
- *
1441
- * Per-chunk keys (rather than a per-file DEK) lets future versions revoke or
1442
- * re-share individual chunks without re-encrypting the whole file. The
1443
- * additional manifest size is dominated by the shard hash list anyway.
1444
- *
1445
- * The cipher itself delegates to the canonical `encryptAesGcm` / `decryptAesGcm`
1446
- * primitives — this class only wraps them with key-material generation and
1447
- * the JSON-friendly base64 serialization the manifest needs.
1448
- */
1449
- class ChunkCipher {
1450
- /**
1451
- * Generate a fresh random (key, iv) pair encoded for the manifest.
1452
- * Callers should generate one of these per chunk before calling
1453
- * {@link encryptChunk}.
1454
- */
1455
- generateKeyMaterial() {
1456
- return {
1457
- key: toBase64(randomBytes(AES_GCM_KEY_BYTES)),
1458
- iv: toBase64(randomBytes(AES_GCM_IV_BYTES)),
1459
- };
1460
- }
1461
- /**
1462
- * Encrypt `plaintext` under the supplied key + IV. Returns the AES-GCM
1463
- * ciphertext with the 16-byte auth tag appended (WebCrypto's default
1464
- * GCM behavior).
1465
- */
1466
- async encryptChunk(plaintext, material) {
1467
- return encryptAesGcm(fromBase64(material.key), fromBase64(material.iv), plaintext);
1468
- }
1469
- /**
1470
- * Inverse of {@link encryptChunk}. Throws if the auth tag fails — that
1471
- * means the ciphertext was tampered with, the key/iv was wrong, or the
1472
- * shards were reassembled incorrectly.
1473
- */
1474
- async decryptChunk(ciphertext, material) {
1475
- try {
1476
- return await decryptAesGcm(fromBase64(material.key), fromBase64(material.iv), ciphertext);
1477
- }
1478
- catch {
1479
- // WebCrypto throws a vague OperationError on GCM tag mismatch.
1480
- // Surface a stable, readable message so callers can react to it.
1481
- throw new Error("ChunkCipher.decryptChunk: decryption failed (key/iv mismatch, corrupted ciphertext, or reassembly error)");
1482
- }
1483
- }
1484
- }
1485
-
1486
- /**
1487
- * Passphrase-based wrap / unwrap helpers using WebCrypto.
1488
- *
1489
- * Encrypt a payload with a user-supplied passphrase before persisting it
1490
- * somewhere the server can see (e.g. the manifest blob in a ZK-gated
1491
- * SharedSpace, or chat-key material in a PersonalSpace). The server never
1492
- * sees the passphrase or the plaintext — both wrap and unwrap run entirely
1493
- * client-side.
1494
- *
1495
- * Algorithm (the only one this codebase has ever shipped):
1496
- * - PBKDF2-SHA256 with 200_000 iterations derives a 256-bit AES key from
1497
- * `passphrase || salt`.
1498
- * - AES-256-GCM encrypts the plaintext with a fresh random 12-byte IV.
1499
- * - The auth tag is appended to the ciphertext by WebCrypto's default
1500
- * GCM behaviour, so {@link WrappedPayload.ciphertext} carries it implicitly.
1501
- *
1502
- * The returned {@link WrappedPayload} is JSON-friendly (all base64 fields), so
1503
- * it can be `JSON.stringify`-ed straight into a KV layer.
1504
- */
1505
- /** Length of the PBKDF2 salt, in bytes. */
1506
- const SALT_BYTES = 16;
1507
- /** Encode a `Uint8Array` to standard base64 (with padding). */
1508
- function bytesToBase64(bytes) {
1509
- // Build chunk-wise to avoid blowing the call stack on large payloads.
1510
- let binary = "";
1511
- const CHUNK = 0x8000;
1512
- for (let i = 0; i < bytes.length; i += CHUNK) {
1513
- binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
1514
- }
1515
- if (typeof btoa === "function")
1516
- return btoa(binary);
1517
- return Buffer.from(bytes).toString("base64");
1518
- }
1519
- /** Decode a base64 string back into a `Uint8Array`. */
1520
- function base64ToBytes(b64) {
1521
- if (typeof atob === "function") {
1522
- const binary = atob(b64);
1523
- const bytes = new Uint8Array(binary.length);
1524
- for (let i = 0; i < binary.length; i++)
1525
- bytes[i] = binary.charCodeAt(i);
1526
- return bytes;
1527
- }
1528
- return new Uint8Array(Buffer.from(b64, "base64"));
1529
- }
1530
- /**
1531
- * Encrypt `plaintext` under a key derived from `passphrase`. The returned
1532
- * payload bundles the salt, IV, and ciphertext so unwrap only needs the
1533
- * passphrase to reverse the operation.
1534
- */
1535
- async function wrapWithPassphrase(passphrase, plaintext) {
1536
- if (typeof passphrase !== "string" || passphrase.length === 0) {
1537
- throw new Error("wrapWithPassphrase: passphrase must be a non-empty string");
1538
- }
1539
- const salt = randomBytes(SALT_BYTES);
1540
- const iv = randomBytes(AES_GCM_IV_BYTES);
1541
- const key = await deriveAesKeyFromPassphrase(passphrase, salt, PBKDF2_DEFAULT_ITERATIONS);
1542
- const ciphertext = await encryptAesGcm(key, iv, plaintext);
1543
- return {
1544
- salt: bytesToBase64(salt),
1545
- iv: bytesToBase64(iv),
1546
- ciphertext: bytesToBase64(ciphertext),
1547
- alg: "PBKDF2-SHA256/AES-256-GCM",
1548
- iter: PBKDF2_DEFAULT_ITERATIONS,
1549
- };
1550
- }
1551
- /**
1552
- * Decrypt a {@link WrappedPayload} produced by {@link wrapWithPassphrase}.
1553
- * Throws if the passphrase is wrong, the payload is tampered with, or the
1554
- * algorithm marker is unrecognised.
1555
- */
1556
- async function unwrapWithPassphrase(passphrase, wrapped) {
1557
- if (typeof passphrase !== "string" || passphrase.length === 0) {
1558
- throw new Error("unwrapWithPassphrase: passphrase must be a non-empty string");
1559
- }
1560
- if (wrapped.alg !== "PBKDF2-SHA256/AES-256-GCM") {
1561
- throw new Error(`unwrapWithPassphrase: unsupported alg "${wrapped.alg}"`);
1562
- }
1563
- const salt = base64ToBytes(wrapped.salt);
1564
- const iv = base64ToBytes(wrapped.iv);
1565
- const ciphertext = base64ToBytes(wrapped.ciphertext);
1566
- const key = await deriveAesKeyFromPassphrase(passphrase, salt, wrapped.iter ?? PBKDF2_DEFAULT_ITERATIONS);
1567
- try {
1568
- return await decryptAesGcm(key, iv, ciphertext);
1569
- }
1570
- catch {
1571
- // WebCrypto throws a vague OperationError on GCM tag mismatch; turn it
1572
- // into a stable, readable message so callers can react to it.
1573
- throw new Error("unwrapWithPassphrase: decryption failed (wrong passphrase or tampered payload)");
1574
- }
1575
- }
1576
-
1577
- var EventCoreEvents;
1578
- (function (EventCoreEvents) {
1579
- EventCoreEvents["CONNECTED"] = "connected";
1580
- EventCoreEvents["DISCONNECTED"] = "disconnected";
1581
- EventCoreEvents["RECONNECTING"] = "reconnecting";
1582
- EventCoreEvents["ERROR"] = "error";
1583
- EventCoreEvents["DATA_RECEIVED"] = "data_received";
1584
- EventCoreEvents["DATA_SENT"] = "data_sent";
1585
- EventCoreEvents["MESSAGE"] = "message";
1586
- EventCoreEvents["GET_HISTORY"] = "get_history";
1587
- EventCoreEvents["RECEIVED_HISTORY"] = "received_history";
1588
- // Offline layer — connectivity + background sync lifecycle. Emitted by the
1589
- // ConnectivityManager / SyncEngine; apps subscribe to drive a status UI.
1590
- EventCoreEvents["ONLINE"] = "online";
1591
- EventCoreEvents["OFFLINE"] = "offline";
1592
- EventCoreEvents["SYNCING"] = "syncing";
1593
- EventCoreEvents["SYNC_PROGRESS"] = "sync_progress";
1594
- EventCoreEvents["SYNC_COMPLETE"] = "sync_complete";
1595
- EventCoreEvents["SYNC_ERROR"] = "sync_error";
1596
- })(EventCoreEvents || (EventCoreEvents = {}));
1597
- /**
1598
- * @public
1599
- * EventCore is a static event emitter with singleton functionality for global event handling.
1600
- */
1601
- class EventCore {
1602
- static eventTarget = new EventTarget();
1603
- static events = new Map();
1604
- /**
1605
- * @remarks Listen to an event.
1606
- * @example EventCore.on('event', (e) =\> appLogger.debug(e));
1607
- */
1608
- static on(event, handler) {
1609
- if (!EventCore.events.has(event)) {
1610
- EventCore.events.set(event, handler);
1611
- }
1612
- EventCore.eventTarget.addEventListener(event, handler);
1613
- }
1614
- /**
1615
- * @remarks Stop listening to an event.
1616
- * @example EventCore.off('event', handler);
1617
- */
1618
- static off(event, handler) {
1619
- if (EventCore.events.has(event)) {
1620
- EventCore.events.delete(event);
1621
- }
1622
- EventCore.eventTarget.removeEventListener(event, handler);
1623
- }
1624
- /**
1625
- * @remarks Emit an event.
1626
- * @example EventCore.emit('event', data);
1627
- */
1628
- static emit(event, data) {
1629
- if (!EventCore.events.has(event)) {
1630
- appLogger.debug(`Warning: No listeners for event: ${event}`);
1631
- // appLogger.verbose(`Event data:`, data);
1632
- }
1633
- EventCore.eventTarget.dispatchEvent(new CustomEvent(event, { detail: data }));
1634
- }
1635
- }
1636
-
1637
- /**
1638
- * An end-to-end-encrypted communication session for one local identity
1639
- * (`myId`) talking to an arbitrary set of peers. Wraps `KeyStore` +
1640
- * per-pair `DoubleRatchet` instances and owns the protocol bookkeeping
1641
- * (handshake reciprocation, dedup, role assignment, broadcast fan-out,
1642
- * recipient filtering) so application code doesn't have to.
1643
- *
1644
- * Transport-agnostic by design: the Session never touches a WebSocket
1645
- * (or HTTP, or anything else). Application code:
1646
- * - calls `session.encrypt(text)` and gets back an array of frames it
1647
- * ships over whatever transport it has;
1648
- * - calls `session.receive(frame)` with each inbound frame and acts on
1649
- * the typed result (plaintext, handshake-done, ignored).
1650
- *
1651
- * Frames are plain JSON objects with the same shape the existing chat
1652
- * protocol uses (`{ keyExchange: {...} }` and `{ cipherMessage: {...} }`),
1653
- * so this can drop into a chat app without changing the wire format.
1654
- */
1655
- // ---------------------------------------------------------------------------
1656
- // EncryptedSession
1657
- // ---------------------------------------------------------------------------
1658
- class EncryptedSession {
1659
- myId;
1660
- keyStore;
1661
- /** One DoubleRatchet per peer pair. */
1662
- ratchets = new Map();
1663
- /** Peers we've already sent our keyExchange to in this Session. */
1664
- sentHandshakeTo = new Set();
1665
- /** Resolved when own keys are generated and ready to use. */
1666
- _ready;
1667
- _resolveReady;
1668
- _initialized = false;
1669
- constructor(opts) {
1670
- if (!opts || !opts.myId) {
1671
- throw new Error("EncryptedSession: `myId` is required");
1672
- }
1673
- this.myId = opts.myId;
1674
- this.keyStore = KeyStore.getInstance();
1675
- this._ready = new Promise((resolve) => {
1676
- this._resolveReady = resolve;
1677
- });
1678
- }
1679
- /** A promise that resolves once `initialize()` has completed. */
1680
- get ready() {
1681
- return this._ready;
1682
- }
1683
- /** Our local identifier. */
1684
- get id() {
1685
- return this.myId;
1686
- }
1687
- /**
1688
- * Generate this client's ECDH + ECDSA keypair (idempotent — safe to call
1689
- * multiple times across reconnects; only the first call generates).
1690
- */
1691
- async initialize() {
1692
- if (this._initialized)
1693
- return;
1694
- if (!this.keyStore.getKeyPair(this.myId)) {
1695
- await this.keyStore.generateOwnKeyPair(this.myId);
1696
- }
1697
- this._initialized = true;
1698
- this._resolveReady();
1699
- }
1700
- /**
1701
- * Build the keyExchange frame this client should send to peers when it
1702
- * comes online. Application is responsible for actually transmitting it
1703
- * (e.g. ws.send(JSON.stringify(frame))).
1704
- */
1705
- async getOwnKeyExchange() {
1706
- await this._ready;
1707
- const ownEcdh = this.keyStore.getKeyPair(this.myId);
1708
- const ownEcdsa = this.keyStore.getAuthKeyPair(this.myId);
1709
- if (!ownEcdh || !ownEcdsa) {
1710
- throw new Error("EncryptedSession.getOwnKeyExchange: keys not initialized");
1711
- }
1712
- return {
1713
- keyExchange: {
1714
- type: "handshake",
1715
- userId: this.myId,
1716
- ecdhPublicKey: await exportJwkBase64(ownEcdh.publicKey),
1717
- ecdsaPublicKey: await exportJwkBase64(ownEcdsa.publicKey),
1718
- },
1719
- };
1720
- }
1721
- /**
1722
- * Encrypt a plaintext to every peer we currently have a ratchet for, and
1723
- * return one cipherMessage frame per recipient. The application sends
1724
- * each frame over its transport.
1725
- *
1726
- * If there are no peers yet (or all peers are still mid-handshake), the
1727
- * returned array may be empty — the caller should typically render the
1728
- * outgoing message locally in that case (since there's no one to send
1729
- * it to yet).
1730
- */
1731
- async encrypt(plaintext) {
1732
- await this._ready;
1733
- const frames = [];
1734
- for (const peerId of this.ratchets.keys()) {
1735
- const ratchet = this.ratchets.get(peerId);
1736
- const sessionId = this._sessionIdFor(peerId);
1737
- const cipherMessage = await ratchet.encrypt(plaintext,
1738
- /* newDhKey */ false, this.myId, peerId, sessionId, "specific");
1739
- frames.push({ cipherMessage });
1740
- }
1741
- return frames;
1742
- }
1743
- /**
1744
- * Hand an inbound frame to the session. Returns a typed result the
1745
- * application acts on.
1746
- *
1747
- * - `kind: 'plaintext'` — decrypted; render `result.text`
1748
- * - `kind: 'handshake'` — a peer's keys are now stored, and if
1749
- * `result.outbound` is set, send it
1750
- * - `kind: 'ignored'` — not for us, malformed, duplicate, etc.
1751
- *
1752
- * Calling code should always handle `'ignored'` (no UI side effect).
1753
- */
1754
- async receive(frame) {
1755
- await this._ready;
1756
- // -- handshake frame -----------------------------------------------------
1757
- if (isKeyExchangeFrame(frame)) {
1758
- const kx = frame.keyExchange;
1759
- const peerId = kx.userId;
1760
- if (peerId === this.myId) {
1761
- return { kind: "ignored", reason: "own keyExchange echo" };
1762
- }
1763
- const isNew = !this.ratchets.has(peerId);
1764
- // (Re-)store the peer's pubkeys + (re-)build the ratchet if needed.
1765
- const peerEcdh = await importJwkBase64(kx.ecdhPublicKey, "ECDH");
1766
- const peerEcdsa = await importJwkBase64(kx.ecdsaPublicKey, "ECDSA");
1767
- await this.keyStore.storeRemotePublicKeys(peerId, peerEcdh, peerEcdsa);
1768
- if (isNew) {
1769
- const isClient = this.myId < peerId;
1770
- const ratchet = new DoubleRatchet(this.myId, peerId, "specific", isClient);
1771
- await ratchet.initializeSession(isClient);
1772
- this.ratchets.set(peerId, ratchet);
1773
- }
1774
- // Reciprocate exactly once per peer per session lifetime.
1775
- let outbound = null;
1776
- if (isNew && !this.sentHandshakeTo.has(peerId)) {
1777
- outbound = await this.getOwnKeyExchange();
1778
- this.sentHandshakeTo.add(peerId);
1779
- }
1780
- return { kind: "handshake", peerId, outbound };
1781
- }
1782
- // -- ciphertext frame ----------------------------------------------------
1783
- if (isCipherFrame(frame)) {
1784
- const cipherMessage = frame.cipherMessage;
1785
- const header = cipherMessage?.header;
1786
- if (!header) {
1787
- return { kind: "ignored", reason: "cipherMessage has no header" };
1788
- }
1789
- if (header.senderId === this.myId) {
1790
- return { kind: "ignored", reason: "own outbound echo" };
1791
- }
1792
- if (header.recipientId && header.recipientId !== this.myId) {
1793
- return { kind: "ignored", reason: "addressed to a different peer" };
1794
- }
1795
- const ratchet = this.ratchets.get(header.senderId);
1796
- if (!ratchet) {
1797
- return {
1798
- kind: "ignored",
1799
- reason: `no ratchet with sender ${header.senderId} (handshake hasn't completed)`,
1800
- };
1801
- }
1802
- const isClient = this.myId < header.senderId;
1803
- let text;
1804
- try {
1805
- text = await ratchet.decrypt(cipherMessage, isClient);
1806
- }
1807
- catch (err) {
1808
- // DoubleRatchet's wallclock-based replay-protection check throws
1809
- // "CipherMessage too old, possible replay attack" for any frame
1810
- // older than 5 minutes. Real replays still fail downstream because
1811
- // the message key has been consumed; the wallclock check is a
1812
- // defense-in-depth heuristic, not a security boundary. Treating it
1813
- // as `ignored` lets the channel survive legacy backlog replays and
1814
- // CF WS-idle-timeout reconnect cycles without spamming the
1815
- // channel's ERROR stream.
1816
- const msg = err instanceof Error ? err.message : String(err);
1817
- if (msg.includes("too old") || msg.includes("replay attack")) {
1818
- return { kind: "ignored", reason: `stale cipherMessage rejected: ${msg}` };
1819
- }
1820
- throw err;
1821
- }
1822
- return { kind: "plaintext", from: header.senderId, text, cipherMessage };
1823
- }
1824
- return { kind: "ignored", reason: "unknown frame type" };
1825
- }
1826
- // -- introspection ---------------------------------------------------------
1827
- /** List of peer ids we have an established ratchet for. */
1828
- peers() {
1829
- return Array.from(this.ratchets.keys());
1830
- }
1831
- /** Has the handshake completed for this peer? */
1832
- hasRatchetFor(peerId) {
1833
- return this.ratchets.has(peerId);
1834
- }
1835
- /**
1836
- * Tear down a peer's ratchet (e.g. when they leave the room). The peer's
1837
- * stored keys remain in `KeyStore` so a fresh handshake can be set up
1838
- * later without re-fetching them, but the ratchet state is dropped.
1839
- */
1840
- forgetPeer(peerId) {
1841
- this.ratchets.delete(peerId);
1842
- this.sentHandshakeTo.delete(peerId);
1843
- }
1844
- // -- internals -------------------------------------------------------------
1845
- /** Deterministic per-pair session id — same string on both sides. */
1846
- _sessionIdFor(peerId) {
1847
- return [this.myId, peerId].sort().join(":");
1848
- }
1849
- }
1850
- // ---------------------------------------------------------------------------
1851
- // Helpers — JWK <-> base64 string for key transport
1852
- // ---------------------------------------------------------------------------
1853
- async function exportJwkBase64(key) {
1854
- const jwk = await crypto.subtle.exportKey("jwk", key);
1855
- return btoa(JSON.stringify(jwk));
1856
- }
1857
- async function importJwkBase64(b64, type) {
1858
- const jwk = JSON.parse(atob(b64));
1859
- const algorithm = type === "ECDH"
1860
- ? { name: "ECDH", namedCurve: "P-384" }
1861
- : { name: "ECDSA", namedCurve: "P-384" };
1862
- const usages = type === "ECDH" ? [] : ["verify"];
1863
- return await crypto.subtle.importKey("jwk", jwk, algorithm, true, usages);
1864
- }
1865
- // ---------------------------------------------------------------------------
1866
- // Type guards
1867
- // ---------------------------------------------------------------------------
1868
- function isKeyExchangeFrame(frame) {
1869
- const kx = frame.keyExchange;
1870
- if (!kx || typeof kx !== "object")
1871
- return false;
1872
- const k = kx;
1873
- return (typeof k.userId === "string" &&
1874
- typeof k.ecdhPublicKey === "string" &&
1875
- typeof k.ecdsaPublicKey === "string");
1876
- }
1877
- function isCipherFrame(frame) {
1878
- const cm = frame.cipherMessage;
1879
- if (!cm || typeof cm !== "object")
1880
- return false;
1881
- const m = cm;
1882
- return Boolean(m.header && m.ciphertext && m.nonce);
1883
- }
1884
-
1885
- /**
1886
- * Pure WebSocket transport — owns the socket lifecycle and nothing else.
1887
- *
1888
- * Hands raw frame strings up (via the `MESSAGE` event) and accepts raw frame
1889
- * strings down (via `send`). Anything frame-shape, encryption, or serialization
1890
- * related belongs in the layer above (e.g. `Network` for client↔server
1891
- * encrypted pipes, `BroadcastChannel` for multi-peer E2E rooms).
1892
- *
1893
- * Responsibilities:
1894
- * - Open / close the WebSocket
1895
- * - Auto-reconnect with linear backoff after an unexpected close
1896
- * - Buffer outbound frames while disconnected (capped queue)
1897
- * - Emit lifecycle events (CONNECTED / DISCONNECTED / RECONNECTING / ERROR)
1898
- * plus raw inbound MESSAGE events
1899
- */
1900
- /** Monotonic source of unique transport ids when a caller doesn't supply one. */
1901
- let __wsInstanceSeq = 0;
1902
- class WSTransport extends EventCore {
1903
- /**
1904
- * Per-instance event scope. `EventCore` is a process-global static emitter,
1905
- * so without namespacing every WSTransport would hear every other one's
1906
- * frames. We prefix each event with this transport's `id` and expose
1907
- * `on`/`off`/`emit` that scope transparently — callers still use the plain
1908
- * `EventCoreEvents` enum and only ever see their own connection's events.
1909
- */
1910
- id;
1911
- emit = (event, data) => {
1912
- EventCore.emit(this.scopedEvent(event), data);
1913
- };
1914
- on = (event, handler) => {
1915
- EventCore.on(this.scopedEvent(event), handler);
1916
- };
1917
- off = (event, handler) => {
1918
- EventCore.off(this.scopedEvent(event), handler);
1919
- };
1920
- scopedEvent(event) {
1921
- return `${this.id}:${event}`;
1922
- }
1923
- url;
1924
- urlProvider;
1925
- socket = null;
1926
- _isConnected = false;
1927
- _isConnecting = false;
1928
- // Reconnect state
1929
- autoReconnect;
1930
- reconnectDelay;
1931
- maxReconnectAttempts;
1932
- reconnectAttempts = 0;
1933
- reconnectTimeout = null;
1934
- // Outbound queue (raw frame strings — already serialized by caller)
1935
- outboundQueue = [];
1936
- maxQueueSize;
1937
- // Heartbeat / liveness state
1938
- heartbeatInterval;
1939
- heartbeatTimeout;
1940
- pingFrame;
1941
- pongFrame;
1942
- heartbeatTimer = null;
1943
- pongTimer = null;
1944
- constructor(opts) {
1945
- super();
1946
- if (!opts || !opts.url) {
1947
- throw new Error("WSTransport: `url` is required");
1948
- }
1949
- this.url = opts.url;
1950
- this.urlProvider = opts.urlProvider;
1951
- this.id = opts.id ?? `ws${++__wsInstanceSeq}`;
1952
- this.autoReconnect = opts.autoReconnect ?? true;
1953
- this.reconnectDelay = opts.reconnectDelay ?? 3000;
1954
- this.maxReconnectAttempts = opts.maxReconnectAttempts ?? 5;
1955
- this.maxQueueSize = opts.maxQueueSize ?? 100;
1956
- this.heartbeatInterval = opts.heartbeatInterval ?? 30000;
1957
- this.heartbeatTimeout = opts.heartbeatTimeout ?? 10000;
1958
- this.pingFrame = opts.pingFrame ?? "ping";
1959
- this.pongFrame = opts.pongFrame ?? "pong";
1960
- }
1961
- /** Open the socket. Resolves when CONNECTED fires. Rejects on first error. */
1962
- async connect() {
1963
- if (this._isConnected || this._isConnecting) {
1964
- throw new Error("WSTransport: already connected or connecting");
1965
- }
1966
- this._isConnecting = true;
1967
- // On a RECONNECT, refresh the URL (the baked-in single-use ticket is spent).
1968
- // The first connect uses `url` as-is. If the provider throws (e.g. can't
1969
- // mint a ticket), surface it and let scheduleReconnect retry.
1970
- if (this.urlProvider && this.reconnectAttempts > 0) {
1971
- try {
1972
- this.url = await this.urlProvider();
1973
- }
1974
- catch (err) {
1975
- this._isConnecting = false;
1976
- throw err;
1977
- }
1978
- }
1979
- return new Promise((resolve, reject) => {
1980
- try {
1981
- const socket = new WebSocket(this.url);
1982
- this.socket = socket;
1983
- socket.onopen = () => {
1984
- this._isConnected = true;
1985
- this._isConnecting = false;
1986
- this.reconnectAttempts = 0;
1987
- this.emit(EventCoreEvents.CONNECTED, undefined);
1988
- this.flushQueue();
1989
- this.startHeartbeat();
1990
- resolve();
1991
- };
1992
- socket.onmessage = (event) => {
1993
- // Heartbeat ack — swallow it (don't surface as a MESSAGE) and clear
1994
- // the liveness deadline. The layer above never sees keep-alive frames.
1995
- if (event.data === this.pongFrame) {
1996
- if (this.pongTimer) {
1997
- clearTimeout(this.pongTimer);
1998
- this.pongTimer = null;
1999
- }
2000
- return;
2001
- }
2002
- // Raw inbound frame — layer above is responsible for parsing.
2003
- this.emit(EventCoreEvents.MESSAGE, event.data);
2004
- };
2005
- socket.onerror = (err) => {
2006
- this.emit(EventCoreEvents.ERROR, err);
2007
- if (this._isConnecting) {
2008
- this._isConnecting = false;
2009
- reject(err);
2010
- }
2011
- };
2012
- socket.onclose = () => {
2013
- const wasConnected = this._isConnected;
2014
- this._isConnected = false;
2015
- this._isConnecting = false;
2016
- this.stopHeartbeat();
2017
- this.emit(EventCoreEvents.DISCONNECTED, undefined);
2018
- if (this.autoReconnect && wasConnected) {
2019
- this.scheduleReconnect();
2020
- }
2021
- };
2022
- }
2023
- catch (err) {
2024
- this._isConnecting = false;
2025
- reject(err);
2026
- }
2027
- });
2028
- }
2029
- /** Close the socket and stop reconnecting. */
2030
- disconnect() {
2031
- if (this.reconnectTimeout) {
2032
- clearTimeout(this.reconnectTimeout);
2033
- this.reconnectTimeout = null;
2034
- }
2035
- this.stopHeartbeat();
2036
- this.autoReconnect = false;
2037
- if (this.socket) {
2038
- try {
2039
- this.socket.close();
2040
- }
2041
- catch { /* ignore */ }
2042
- this.socket = null;
2043
- }
2044
- this._isConnected = false;
2045
- this._isConnecting = false;
2046
- }
2047
- /**
2048
- * Send a raw frame. If currently disconnected, the frame is queued and sent
2049
- * after the next successful reconnect (up to `maxQueueSize`).
2050
- */
2051
- send(frame) {
2052
- if (this._isConnected && this.socket) {
2053
- this.socket.send(frame);
2054
- return;
2055
- }
2056
- if (this.outboundQueue.length >= this.maxQueueSize) {
2057
- throw new Error(`WSTransport: outbound queue full (${this.maxQueueSize}); drop or wait for reconnect`);
2058
- }
2059
- this.outboundQueue.push(frame);
2060
- }
2061
- isConnected() { return this._isConnected; }
2062
- isConnecting() { return this._isConnecting; }
2063
- queuedFrames() { return this.outboundQueue.length; }
2064
- reconnectAttemptCount() { return this.reconnectAttempts; }
2065
- // -- internals -------------------------------------------------------------
2066
- /** Begin the keep-alive loop (no-op when disabled). */
2067
- startHeartbeat() {
2068
- if (this.heartbeatInterval <= 0)
2069
- return;
2070
- this.stopHeartbeat();
2071
- this.heartbeatTimer = setInterval(() => this.sendHeartbeat(), this.heartbeatInterval);
2072
- }
2073
- /** Stop the keep-alive loop and clear any pending liveness deadline. */
2074
- stopHeartbeat() {
2075
- if (this.heartbeatTimer) {
2076
- clearInterval(this.heartbeatTimer);
2077
- this.heartbeatTimer = null;
2078
- }
2079
- if (this.pongTimer) {
2080
- clearTimeout(this.pongTimer);
2081
- this.pongTimer = null;
2082
- }
2083
- }
2084
- /**
2085
- * Send one ping and arm a liveness deadline. If no `pongFrame` arrives before
2086
- * `heartbeatTimeout`, the connection is considered dead and we force a
2087
- * reconnect — this is what catches a silently-dropped TCP connection that
2088
- * never fired `onclose` (the failure mode that "loses connection with the
2089
- * Accelerator" on long sessions).
2090
- */
2091
- sendHeartbeat() {
2092
- if (!this._isConnected || !this.socket)
2093
- return;
2094
- try {
2095
- this.socket.send(this.pingFrame);
2096
- }
2097
- catch {
2098
- this.forceReconnect();
2099
- return;
2100
- }
2101
- // A still-pending deadline means the previous pong never came back.
2102
- if (this.pongTimer)
2103
- return;
2104
- this.pongTimer = setTimeout(() => {
2105
- this.pongTimer = null;
2106
- this.forceReconnect();
2107
- }, this.heartbeatTimeout);
2108
- }
2109
- /**
2110
- * Tear down a connection we believe is dead and kick off reconnect, without
2111
- * waiting on the OS/browser to eventually fire `onclose` (which a half-open
2112
- * socket may never do). We detach the handlers first so the normal close path
2113
- * can't double-fire the reconnect.
2114
- */
2115
- forceReconnect() {
2116
- this.stopHeartbeat();
2117
- const sock = this.socket;
2118
- const wasConnected = this._isConnected;
2119
- this.socket = null;
2120
- this._isConnected = false;
2121
- this._isConnecting = false;
2122
- if (sock) {
2123
- sock.onopen = null;
2124
- sock.onmessage = null;
2125
- sock.onerror = null;
2126
- sock.onclose = null;
2127
- try {
2128
- sock.close();
2129
- }
2130
- catch { /* already gone */ }
2131
- }
2132
- this.emit(EventCoreEvents.ERROR, new Error("WSTransport: heartbeat timeout"));
2133
- this.emit(EventCoreEvents.DISCONNECTED, undefined);
2134
- if (this.autoReconnect && wasConnected) {
2135
- this.scheduleReconnect();
2136
- }
2137
- }
2138
- scheduleReconnect() {
2139
- if (this.maxReconnectAttempts > 0 &&
2140
- this.reconnectAttempts >= this.maxReconnectAttempts) {
2141
- this.emit(EventCoreEvents.ERROR, new Error("WSTransport: max reconnect attempts reached"));
2142
- return;
2143
- }
2144
- this.reconnectAttempts++;
2145
- this.emit(EventCoreEvents.RECONNECTING, { attempt: this.reconnectAttempts });
2146
- this.reconnectTimeout = setTimeout(async () => {
2147
- try {
2148
- await this.connect();
2149
- }
2150
- catch {
2151
- // A failed reconnect never opened the socket, so its `onclose` won't
2152
- // re-schedule (that path is guarded by `wasConnected`). Re-schedule here
2153
- // so we keep retrying (with a fresh ticket each time) until we succeed
2154
- // or hit the attempt cap.
2155
- if (this.autoReconnect)
2156
- this.scheduleReconnect();
2157
- }
2158
- }, this.reconnectDelay);
2159
- }
2160
- flushQueue() {
2161
- if (this.outboundQueue.length === 0 || !this.socket)
2162
- return;
2163
- const pending = this.outboundQueue;
2164
- this.outboundQueue = [];
2165
- for (const frame of pending) {
2166
- try {
2167
- this.socket.send(frame);
2168
- }
2169
- catch {
2170
- // re-queue if a flush fails
2171
- this.outboundQueue.push(frame);
2172
- }
2173
- }
2174
- }
2175
- }
2176
-
2177
- /**
2178
- * BroadcastChannel — a turnkey end-to-end encrypted channel for multi-peer
2179
- * "room"-style apps (e.g. a chat). Wires together:
2180
- *
2181
- * - `WSTransport` for socket lifecycle, reconnect, and offline frame queue
2182
- * - `EncryptedSession` for per-peer Double Ratchet state, handshake
2183
- * reciprocation, fan-out encryption, and recipient filtering
2184
- *
2185
- * The host app only deals with high-level events and method calls; it never
2186
- * touches `new WebSocket(...)` or builds cipherMessage frames by hand.
2187
- *
2188
- * Wire protocol (kept compatible with the existing chat protocol so this
2189
- * drops into the deployed Accelerator without server changes):
2190
- *
2191
- * outbound: `{ keyExchange: {...} }` — produced by us on `announce()`
2192
- * `{ cipherMessage: {...} }` — produced by `send(text)`,
2193
- * one frame per peer
2194
- * arbitrary JSON — sent via `sendRaw(obj)`
2195
- *
2196
- * inbound: `{ keyExchange: {...} }` — routed into EncryptedSession;
2197
- * emits `peer_handshake`
2198
- * `{ cipherMessage: {...} }` — decrypted; emits `message`
2199
- * anything else — passes through as `raw_frame`
2200
- * (the app decides what to do)
2201
- *
2202
- * **Event scoping.** Unlike `Network`, BroadcastChannel uses a per-instance
2203
- * `EventTarget`, so two channels (e.g. two rooms in the same app) don't
2204
- * cross-contaminate each other's events.
2205
- *
2206
- * Note: this class shadows the `BroadcastChannel` Web API global (cross-tab
2207
- * messaging) only when imported by name. They're unrelated.
2208
- */
2209
- // ---------------------------------------------------------------------------
2210
- // Event names
2211
- // ---------------------------------------------------------------------------
2212
- /**
2213
- * Event names BroadcastChannel emits. Lifecycle events reuse the
2214
- * `EventCoreEvents` string values (`connected`, `disconnected`, etc.) so
2215
- * apps can use shared constants if they want. Channel-specific events are
2216
- * prefixed `channel:` to avoid colliding with other event systems in the
2217
- * same app.
2218
- */
2219
- const BroadcastChannelEvents = {
2220
- CONNECTED: EventCoreEvents.CONNECTED,
2221
- DISCONNECTED: EventCoreEvents.DISCONNECTED,
2222
- RECONNECTING: EventCoreEvents.RECONNECTING,
2223
- ERROR: EventCoreEvents.ERROR,
2224
- /** A peer's ratchet is now ready. `detail.peerId` is the peer's id. */
2225
- PEER_HANDSHAKE: "channel:peer_handshake",
2226
- /** Decrypted message. `detail` is `{ from, text, cipherMessage }`. */
2227
- MESSAGE: "channel:message",
2228
- /** Inbound frame BroadcastChannel didn't recognize. App handles it. */
2229
- RAW_FRAME: "channel:raw_frame",
2230
- };
2231
- // ---------------------------------------------------------------------------
2232
- // BroadcastChannel
2233
- // ---------------------------------------------------------------------------
2234
- class BroadcastChannel {
2235
- transport;
2236
- session;
2237
- myId;
2238
- autoAnnounce;
2239
- announced = false;
2240
- /** Per-instance EventTarget — events do NOT leak across BroadcastChannels. */
2241
- events = new EventTarget();
2242
- constructor(opts) {
2243
- if (!opts || !opts.myId) {
2244
- throw new Error("BroadcastChannel: `myId` is required");
2245
- }
2246
- this.myId = opts.myId;
2247
- this.autoAnnounce = opts.autoAnnounce ?? false;
2248
- this.transport = new WSTransport(opts);
2249
- this.session = new EncryptedSession({ myId: opts.myId });
2250
- // Pass-through lifecycle events from the transport. `EventCore.on` is
2251
- // static so it routes back through the shared singleton; we bridge it
2252
- // into our instance-scoped event target.
2253
- this.transport.on(EventCoreEvents.CONNECTED, () => {
2254
- // Reset the announce flag on every (re)connect. CF Workers WebSockets
2255
- // hit an idle timeout and force reconnects; without resetting, the
2256
- // SDK would short-circuit announce() and any peer who joined the
2257
- // room after our last announce would never see our pubkey.
2258
- this.announced = false;
2259
- this.emit(BroadcastChannelEvents.CONNECTED);
2260
- if (this.autoAnnounce) {
2261
- void this.announce();
2262
- }
2263
- });
2264
- this.transport.on(EventCoreEvents.DISCONNECTED, () => {
2265
- this.emit(BroadcastChannelEvents.DISCONNECTED);
2266
- });
2267
- this.transport.on(EventCoreEvents.RECONNECTING, (e) => {
2268
- this.emit(BroadcastChannelEvents.RECONNECTING, e.detail);
2269
- });
2270
- this.transport.on(EventCoreEvents.ERROR, (e) => {
2271
- this.emit(BroadcastChannelEvents.ERROR, e.detail);
2272
- });
2273
- // Route inbound raw frames through our framing/decryption logic.
2274
- this.transport.on(EventCoreEvents.MESSAGE, (e) => {
2275
- void this.handleInboundFrame(e.detail);
2276
- });
2277
- }
2278
- // -- event API -------------------------------------------------------------
2279
- /** Subscribe to a channel event. Handler receives a CustomEvent. */
2280
- on(event, handler) {
2281
- this.events.addEventListener(event, handler);
2282
- }
2283
- /** Unsubscribe. */
2284
- off(event, handler) {
2285
- this.events.removeEventListener(event, handler);
2286
- }
2287
- emit(event, detail) {
2288
- this.events.dispatchEvent(new CustomEvent(event, { detail }));
2289
- }
2290
- // -- lifecycle -------------------------------------------------------------
2291
- /** Generate our keys (idempotent) and open the WebSocket. */
2292
- async connect() {
2293
- await this.session.initialize();
2294
- await this.transport.connect();
2295
- }
2296
- /** Close the WebSocket and stop reconnecting. */
2297
- disconnect() {
2298
- this.transport.disconnect();
2299
- }
2300
- /**
2301
- * Send our `keyExchange` frame to the room. Idempotent — only sends on the
2302
- * first call. Call this once your higher-level handshake (e.g. sending a
2303
- * `{name}` identification frame) has completed.
2304
- */
2305
- async announce() {
2306
- if (this.announced)
2307
- return;
2308
- this.announced = true;
2309
- const frame = await this.session.getOwnKeyExchange();
2310
- this.transport.send(JSON.stringify(frame));
2311
- }
2312
- /**
2313
- * Encrypt `plaintext` to every peer we have a ratchet with, and send each
2314
- * cipherMessage as its own WS frame. Returns the number of peers we sent to
2315
- * (0 if no peers are handshaken yet — in which case the caller should
2316
- * typically render the message locally for the sender and try again later).
2317
- */
2318
- async send(plaintext) {
2319
- const frames = await this.session.encrypt(plaintext);
2320
- for (const frame of frames) {
2321
- this.transport.send(JSON.stringify(frame));
2322
- }
2323
- return frames.length;
2324
- }
2325
- /**
2326
- * Send an arbitrary JSON-serializable frame as-is. The app uses this for
2327
- * any frame that isn't channel-managed (e.g. a chat's `{name}`, `{file}`,
2328
- * or unencrypted `{message}`).
2329
- */
2330
- sendRaw(frame) {
2331
- this.transport.send(JSON.stringify(frame));
2332
- }
2333
- // -- introspection ---------------------------------------------------------
2334
- /** List of peer ids we have an established ratchet for. */
2335
- peers() {
2336
- return this.session.peers();
2337
- }
2338
- /** Drop a peer's ratchet (e.g. when they leave the room). */
2339
- forgetPeer(peerId) {
2340
- this.session.forgetPeer(peerId);
2341
- }
2342
- isConnected() {
2343
- return this.transport.isConnected();
2344
- }
2345
- // -- internals -------------------------------------------------------------
2346
- async handleInboundFrame(raw) {
2347
- let parsed;
2348
- try {
2349
- parsed = JSON.parse(raw);
2350
- }
2351
- catch (err) {
2352
- this.emit(BroadcastChannelEvents.ERROR, err);
2353
- return;
2354
- }
2355
- if (!parsed || typeof parsed !== "object") {
2356
- this.emit(BroadcastChannelEvents.RAW_FRAME, parsed);
2357
- return;
2358
- }
2359
- const obj = parsed;
2360
- // Channel-managed: keyExchange & cipherMessage. Anything else is RAW_FRAME.
2361
- if ("keyExchange" in obj || "cipherMessage" in obj) {
2362
- try {
2363
- const result = await this.session.receive(obj);
2364
- if (result.kind === "handshake") {
2365
- if (result.outbound) {
2366
- this.transport.send(JSON.stringify(result.outbound));
2367
- }
2368
- this.emit(BroadcastChannelEvents.PEER_HANDSHAKE, { peerId: result.peerId });
2369
- }
2370
- else if (result.kind === "plaintext") {
2371
- this.emit(BroadcastChannelEvents.MESSAGE, {
2372
- from: result.from,
2373
- text: result.text,
2374
- cipherMessage: result.cipherMessage,
2375
- });
2376
- }
2377
- // `ignored` is intentionally swallowed; subscribe to ERROR for bad frames.
2378
- }
2379
- catch (err) {
2380
- this.emit(BroadcastChannelEvents.ERROR, err);
2381
- }
2382
- return;
2383
- }
2384
- this.emit(BroadcastChannelEvents.RAW_FRAME, obj);
2385
- }
2386
- }
2387
-
2388
- function _loadWasmModule (sync, filepath, src, imports) {
2389
- function _instantiateOrCompile(source, imports, stream) {
2390
- var instantiateFunc = stream ? WebAssembly.instantiateStreaming : WebAssembly.instantiate;
2391
- var compileFunc = stream ? WebAssembly.compileStreaming : WebAssembly.compile;
2392
-
2393
- if (imports) {
2394
- return instantiateFunc(source, imports)
2395
- } else {
2396
- return compileFunc(source)
2397
- }
2398
- }
2399
-
2400
-
2401
- var buf = null;
2402
- var isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
2403
- if (isNode) {
2404
-
2405
- buf = Buffer.from(src, 'base64');
2406
-
2407
- } else {
2408
-
2409
- var raw = globalThis.atob(src);
2410
- var rawLength = raw.length;
2411
- buf = new Uint8Array(new ArrayBuffer(rawLength));
2412
- for(var i = 0; i < rawLength; i++) {
2413
- buf[i] = raw.charCodeAt(i);
2414
- }
2415
-
2416
- }
2417
-
2418
-
2419
- {
2420
- return _instantiateOrCompile(buf, imports, false)
2421
- }
2422
- }
2423
-
2424
- function loadBundledBn128(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABlAESYAJ/fwBgAX8AYAF/AX9gAn9/AX9gA39/fwF/YAN/f38AYAN/fn8AYAJ/fgBgBH9/f38AYAV/f39/fwBgBH9/f38Bf2AHf39/f39/fwBgBn9/f39/fwBgCn9/f39/f39/f38AYAV/f39/fwF/YAd/f39/f39/AX9gCX9/f39/f39/fwF/YAt/f39/f39/f39/fwF/Ag8BA2VudgZtZW1vcnkCABkDwQK/AgABAgEDAwQEBQAABgcIBQIFBQAABQAAAAACAgABBQgJBQUFCAgICAACAgUFAAAFAAAAAAICAAEFCAkFBQUICAgIAAIFAAACAgIBAQAAAAMDAwAABQUFAAAFBQUAAAAAAAICBQAFAAAAAAUFBQUFCgALCQoACwkICAMACAgCAAAJDAwFBQwACA0JCAICAQEABQUABQUAAAAAAwAIAgIJCAACAgIBAQAAAAMDAwAABQUFAAAFBQUAAAAAAAICBQAFAAAAAAUFBQUFCgALCQoACwkICAUDAAgIAgAACQwMBQUMBQMACAgCAAAJDAwFBQwFBQkJCQkJAAICAQEABQAFBQACAAADAAgCCQgAAgIBAQAFBQAFBQAAAAADAAgCAgkIAAIFAAAAAAgIBQAAAAAAAAAAAAAAAAAAAAAEDg8QEQUH9SSoAghpbnRfY29weQAACGludF96ZXJvAAEHaW50X29uZQADCmludF9pc1plcm8AAgZpbnRfZXEABAdpbnRfZ3RlAAUHaW50X2FkZAAGB2ludF9zdWIABwdpbnRfbXVsAAgKaW50X3NxdWFyZQAJDWludF9zcXVhcmVPbGQACgdpbnRfZGl2AA0OaW50X2ludmVyc2VNb2QADghmMW1fY29weQAACGYxbV96ZXJvAAEKZjFtX2lzWmVybwACBmYxbV9lcQAEB2YxbV9hZGQAEAdmMW1fc3ViABEHZjFtX25lZwASDmYxbV9pc05lZ2F0aXZlABkJZjFtX2lzT25lAA8IZjFtX3NpZ24AGgtmMW1fbVJlZHVjdAATB2YxbV9tdWwAFApmMW1fc3F1YXJlABUNZjFtX3NxdWFyZU9sZAAWEmYxbV9mcm9tTW9udGdvbWVyeQAYEGYxbV90b01vbnRnb21lcnkAFwtmMW1faW52ZXJzZQAbB2YxbV9vbmUAHAhmMW1fbG9hZAAdD2YxbV90aW1lc1NjYWxhcgAeB2YxbV9leHAAJhBmMW1fYmF0Y2hJbnZlcnNlAB8IZjFtX3NxcnQAJwxmMW1faXNTcXVhcmUAKBVmMW1fYmF0Y2hUb01vbnRnb21lcnkAIBdmMW1fYmF0Y2hGcm9tTW9udGdvbWVyeQAhCGZybV9jb3B5AAAIZnJtX3plcm8AAQpmcm1faXNaZXJvAAIGZnJtX2VxAAQHZnJtX2FkZAAqB2ZybV9zdWIAKwdmcm1fbmVnACwOZnJtX2lzTmVnYXRpdmUAMwlmcm1faXNPbmUAKQhmcm1fc2lnbgA0C2ZybV9tUmVkdWN0AC0HZnJtX211bAAuCmZybV9zcXVhcmUALw1mcm1fc3F1YXJlT2xkADASZnJtX2Zyb21Nb250Z29tZXJ5ADIQZnJtX3RvTW9udGdvbWVyeQAxC2ZybV9pbnZlcnNlADUHZnJtX29uZQA2CGZybV9sb2FkADcPZnJtX3RpbWVzU2NhbGFyADgHZnJtX2V4cABAEGZybV9iYXRjaEludmVyc2UAOQhmcm1fc3FydABBDGZybV9pc1NxdWFyZQBCFWZybV9iYXRjaFRvTW9udGdvbWVyeQA6F2ZybV9iYXRjaEZyb21Nb250Z29tZXJ5ADsGZnJfYWRkACoGZnJfc3ViACsGZnJfbmVnACwGZnJfbXVsAEMJZnJfc3F1YXJlAEQKZnJfaW52ZXJzZQBFDWZyX2lzTmVnYXRpdmUARgdmcl9jb3B5AAAHZnJfemVybwABBmZyX29uZQA2CWZyX2lzWmVybwACBWZyX2VxAAQMZzFtX211bHRpZXhwAHESZzFtX211bHRpZXhwX2NodW5rAHASZzFtX211bHRpZXhwQWZmaW5lAHUYZzFtX211bHRpZXhwQWZmaW5lX2NodW5rAHQKZzFtX2lzWmVybwBIEGcxbV9pc1plcm9BZmZpbmUARwZnMW1fZXEAUAtnMW1fZXFNaXhlZABPDGcxbV9lcUFmZmluZQBOCGcxbV9jb3B5AEwOZzFtX2NvcHlBZmZpbmUASwhnMW1femVybwBKDmcxbV96ZXJvQWZmaW5lAEkKZzFtX2RvdWJsZQBSEGcxbV9kb3VibGVBZmZpbmUAUQdnMW1fYWRkAFUMZzFtX2FkZE1peGVkAFQNZzFtX2FkZEFmZmluZQBTB2cxbV9uZWcAVw1nMW1fbmVnQWZmaW5lAFYHZzFtX3N1YgBaDGcxbV9zdWJNaXhlZABZDWcxbV9zdWJBZmZpbmUAWBJnMW1fZnJvbU1vbnRnb21lcnkAXBhnMW1fZnJvbU1vbnRnb21lcnlBZmZpbmUAWxBnMW1fdG9Nb250Z29tZXJ5AF4WZzFtX3RvTW9udGdvbWVyeUFmZmluZQBdD2cxbV90aW1lc1NjYWxhcgB2FWcxbV90aW1lc1NjYWxhckFmZmluZQB3DWcxbV9ub3JtYWxpemUAYwpnMW1fTEVNdG9VAGUKZzFtX0xFTXRvQwBmCmcxbV9VdG9MRU0AZwpnMW1fQ3RvTEVNAGgPZzFtX2JhdGNoTEVNdG9VAGkPZzFtX2JhdGNoTEVNdG9DAGoPZzFtX2JhdGNoVXRvTEVNAGsPZzFtX2JhdGNoQ3RvTEVNAGwMZzFtX3RvQWZmaW5lAF8OZzFtX3RvSmFjb2JpYW4ATRFnMW1fYmF0Y2hUb0FmZmluZQBiE2cxbV9iYXRjaFRvSmFjb2JpYW4AbQtnMW1faW5DdXJ2ZQBhEWcxbV9pbkN1cnZlQWZmaW5lAGAHZnJtX2ZmdAB9CGZybV9pZmZ0AH4KZnJtX3Jhd2ZmdAB7C2ZybV9mZnRKb2luAH8OZnJtX2ZmdEpvaW5FeHQAgAERZnJtX2ZmdEpvaW5FeHRJbnYAgQEKZnJtX2ZmdE1peACCAQxmcm1fZmZ0RmluYWwAgwEdZnJtX3ByZXBhcmVMYWdyYW5nZUV2YWx1YXRpb24AhAEIcG9sX3plcm8AhQEPcG9sX2NvbnN0cnVjdExDAIYBDHFhcF9idWlsZEFCQwCHAQtxYXBfam9pbkFCQwCIAQxxYXBfYmF0Y2hBZGQAiQEKZjJtX2lzWmVybwCKAQlmMm1faXNPbmUAiwEIZjJtX3plcm8AjAEHZjJtX29uZQCNAQhmMm1fY29weQCOAQdmMm1fbXVsAI8BCGYybV9tdWwxAJABCmYybV9zcXVhcmUAkQEHZjJtX2FkZACSAQdmMm1fc3ViAJMBB2YybV9uZWcAlAEIZjJtX3NpZ24AmwENZjJtX2Nvbmp1Z2F0ZQCVARJmMm1fZnJvbU1vbnRnb21lcnkAlwEQZjJtX3RvTW9udGdvbWVyeQCWAQZmMm1fZXEAmAELZjJtX2ludmVyc2UAmQEHZjJtX2V4cACeAQ9mMm1fdGltZXNTY2FsYXIAmgEQZjJtX2JhdGNoSW52ZXJzZQCdAQhmMm1fc3FydACfAQxmMm1faXNTcXVhcmUAoAEOZjJtX2lzTmVnYXRpdmUAnAEMZzJtX211bHRpZXhwAMsBEmcybV9tdWx0aWV4cF9jaHVuawDKARJnMm1fbXVsdGlleHBBZmZpbmUAzwEYZzJtX211bHRpZXhwQWZmaW5lX2NodW5rAM4BCmcybV9pc1plcm8AogEQZzJtX2lzWmVyb0FmZmluZQChAQZnMm1fZXEAqgELZzJtX2VxTWl4ZWQAqQEMZzJtX2VxQWZmaW5lAKgBCGcybV9jb3B5AKYBDmcybV9jb3B5QWZmaW5lAKUBCGcybV96ZXJvAKQBDmcybV96ZXJvQWZmaW5lAKMBCmcybV9kb3VibGUArAEQZzJtX2RvdWJsZUFmZmluZQCrAQdnMm1fYWRkAK8BDGcybV9hZGRNaXhlZACuAQ1nMm1fYWRkQWZmaW5lAK0BB2cybV9uZWcAsQENZzJtX25lZ0FmZmluZQCwAQdnMm1fc3ViALQBDGcybV9zdWJNaXhlZACzAQ1nMm1fc3ViQWZmaW5lALIBEmcybV9mcm9tTW9udGdvbWVyeQC2ARhnMm1fZnJvbU1vbnRnb21lcnlBZmZpbmUAtQEQZzJtX3RvTW9udGdvbWVyeQC4ARZnMm1fdG9Nb250Z29tZXJ5QWZmaW5lALcBD2cybV90aW1lc1NjYWxhcgDQARVnMm1fdGltZXNTY2FsYXJBZmZpbmUA0QENZzJtX25vcm1hbGl6ZQC9AQpnMm1fTEVNdG9VAL8BCmcybV9MRU10b0MAwAEKZzJtX1V0b0xFTQDBAQpnMm1fQ3RvTEVNAMIBD2cybV9iYXRjaExFTXRvVQDDAQ9nMm1fYmF0Y2hMRU10b0MAxAEPZzJtX2JhdGNoVXRvTEVNAMUBD2cybV9iYXRjaEN0b0xFTQDGAQxnMm1fdG9BZmZpbmUAuQEOZzJtX3RvSmFjb2JpYW4ApwERZzJtX2JhdGNoVG9BZmZpbmUAvAETZzJtX2JhdGNoVG9KYWNvYmlhbgDHAQtnMm1faW5DdXJ2ZQC7ARFnMm1faW5DdXJ2ZUFmZmluZQC6AQtnMW1fdGltZXNGcgDSAQdnMW1fZmZ0ANgBCGcxbV9pZmZ0ANkBCmcxbV9yYXdmZnQA1gELZzFtX2ZmdEpvaW4A2gEOZzFtX2ZmdEpvaW5FeHQA2wERZzFtX2ZmdEpvaW5FeHRJbnYA3AEKZzFtX2ZmdE1peADdAQxnMW1fZmZ0RmluYWwA3gEdZzFtX3ByZXBhcmVMYWdyYW5nZUV2YWx1YXRpb24A3wELZzJtX3RpbWVzRnIA4AEHZzJtX2ZmdADmAQhnMm1faWZmdADnAQpnMm1fcmF3ZmZ0AOQBC2cybV9mZnRKb2luAOgBDmcybV9mZnRKb2luRXh0AOkBEWcybV9mZnRKb2luRXh0SW52AOoBCmcybV9mZnRNaXgA6wEMZzJtX2ZmdEZpbmFsAOwBHWcybV9wcmVwYXJlTGFncmFuZ2VFdmFsdWF0aW9uAO0BEWcxbV90aW1lc0ZyQWZmaW5lAO4BEWcybV90aW1lc0ZyQWZmaW5lAO8BEWZybV9iYXRjaEFwcGx5S2V5APABEWcxbV9iYXRjaEFwcGx5S2V5APEBFmcxbV9iYXRjaEFwcGx5S2V5TWl4ZWQA8gERZzJtX2JhdGNoQXBwbHlLZXkA8wEWZzJtX2JhdGNoQXBwbHlLZXlNaXhlZAD0AQpmNm1faXNaZXJvAPYBCWY2bV9pc09uZQD3AQhmNm1femVybwD4AQdmNm1fb25lAPkBCGY2bV9jb3B5APoBB2Y2bV9tdWwA+wEKZjZtX3NxdWFyZQD8AQdmNm1fYWRkAP0BB2Y2bV9zdWIA/gEHZjZtX25lZwD/AQhmNm1fc2lnbgCAAhJmNm1fZnJvbU1vbnRnb21lcnkAggIQZjZtX3RvTW9udGdvbWVyeQCBAgZmNm1fZXEAgwILZjZtX2ludmVyc2UAhAIHZjZtX2V4cACIAg9mNm1fdGltZXNTY2FsYXIAhQIQZjZtX2JhdGNoSW52ZXJzZQCHAg5mNm1faXNOZWdhdGl2ZQCGAgpmdG1faXNaZXJvAIoCCWZ0bV9pc09uZQCLAghmdG1femVybwCMAgdmdG1fb25lAI0CCGZ0bV9jb3B5AI4CB2Z0bV9tdWwAjwIIZnRtX211bDEAkAIKZnRtX3NxdWFyZQCRAgdmdG1fYWRkAJICB2Z0bV9zdWIAkwIHZnRtX25lZwCUAghmdG1fc2lnbgCbAg1mdG1fY29uanVnYXRlAJUCEmZ0bV9mcm9tTW9udGdvbWVyeQCXAhBmdG1fdG9Nb250Z29tZXJ5AJYCBmZ0bV9lcQCYAgtmdG1faW52ZXJzZQCZAgdmdG1fZXhwAJ4CD2Z0bV90aW1lc1NjYWxhcgCaAhBmdG1fYmF0Y2hJbnZlcnNlAJ0CCGZ0bV9zcXJ0AJ8CDGZ0bV9pc1NxdWFyZQCgAg5mdG1faXNOZWdhdGl2ZQCcAhRibjEyOF9fZnJvYmVuaXVzTWFwMACpAhRibjEyOF9fZnJvYmVuaXVzTWFwMQCqAhRibjEyOF9fZnJvYmVuaXVzTWFwMgCrAhRibjEyOF9fZnJvYmVuaXVzTWFwMwCsAhRibjEyOF9fZnJvYmVuaXVzTWFwNACtAhRibjEyOF9fZnJvYmVuaXVzTWFwNQCuAhRibjEyOF9fZnJvYmVuaXVzTWFwNgCvAhRibjEyOF9fZnJvYmVuaXVzTWFwNwCwAhRibjEyOF9fZnJvYmVuaXVzTWFwOACxAhRibjEyOF9fZnJvYmVuaXVzTWFwOQCyAhBibjEyOF9wYWlyaW5nRXExALkCEGJuMTI4X3BhaXJpbmdFcTIAugIQYm4xMjhfcGFpcmluZ0VxMwC7AhBibjEyOF9wYWlyaW5nRXE0ALwCEGJuMTI4X3BhaXJpbmdFcTUAvQINYm4xMjhfcGFpcmluZwC+Ag9ibjEyOF9wcmVwYXJlRzEAowIPYm4xMjhfcHJlcGFyZUcyAKUCEGJuMTI4X21pbGxlckxvb3AAqAIZYm4xMjhfZmluYWxFeHBvbmVudGlhdGlvbgC4AhxibjEyOF9maW5hbEV4cG9uZW50aWF0aW9uT2xkALMCD2JuMTI4X19tdWxCeTAyNACmAhJibjEyOF9fbXVsQnkwMjRPbGQApwIXYm4xMjhfX2N5Y2xvdG9taWNTcXVhcmUAtQIXYm4xMjhfX2N5Y2xvdG9taWNFeHBfdzAAtgIK/d8DvwIqACABIAApAwA3AwAgASAAKQMINwMIIAEgACkDEDcDECABIAApAxg3AxgLHgAgAEIANwMAIABCADcDCCAAQgA3AxAgAEIANwMYCzMAIAApAxhQBEAgACkDEFAEQCAAKQMIUARAIAApAwBQDwVBAA8LBUEADwsFQQAPC0EADwseACAAQgE3AwAgAEIANwMIIABCADcDECAAQgA3AxgLRwAgACkDGCABKQMYUQRAIAApAxAgASkDEFEEQCAAKQMIIAEpAwhRBEAgACkDACABKQMAUQ8FQQAPCwVBAA8LBUEADwtBAA8LfQAgACkDGCABKQMYVARAQQAPBSAAKQMYIAEpAxhWBEBBAQ8FIAApAxAgASkDEFQEQEEADwUgACkDECABKQMQVgRAQQEPBSAAKQMIIAEpAwhUBEBBAA8FIAApAwggASkDCFYEQEEBDwUgACkDACABKQMAWg8LCwsLCwtBAA8L1AEBAX4gADUCACABNQIAfCEDIAIgAz4CACAANQIEIAE1AgR8IANCIIh8IQMgAiADPgIEIAA1AgggATUCCHwgA0IgiHwhAyACIAM+AgggADUCDCABNQIMfCADQiCIfCEDIAIgAz4CDCAANQIQIAE1AhB8IANCIIh8IQMgAiADPgIQIAA1AhQgATUCFHwgA0IgiHwhAyACIAM+AhQgADUCGCABNQIYfCADQiCIfCEDIAIgAz4CGCAANQIcIAE1Ahx8IANCIIh8IQMgAiADPgIcIANCIIinC4wCAQF+IAA1AgAgATUCAH0hAyACIANC/////w+DPgIAIAA1AgQgATUCBH0gA0Igh3whAyACIANC/////w+DPgIEIAA1AgggATUCCH0gA0Igh3whAyACIANC/////w+DPgIIIAA1AgwgATUCDH0gA0Igh3whAyACIANC/////w+DPgIMIAA1AhAgATUCEH0gA0Igh3whAyACIANC/////w+DPgIQIAA1AhQgATUCFH0gA0Igh3whAyACIANC/////w+DPgIUIAA1AhggATUCGH0gA0Igh3whAyACIANC/////w+DPgIYIAA1AhwgATUCHH0gA0Igh3whAyACIANC/////w+DPgIcIANCIIenC48QEgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfiADQv////8PgyAANQIAIgUgATUCACIGfnwhAyAEIANCIIh8IQQgAiADPgIAIARCIIghAyAEQv////8PgyAFIAE1AgQiCH58IQQgAyAEQiCIfCEDIARC/////w+DIAA1AgQiByAGfnwhBCADIARCIIh8IQMgAiAEPgIEIANCIIghBCADQv////8PgyAFIAE1AggiCn58IQMgBCADQiCIfCEEIANC/////w+DIAcgCH58IQMgBCADQiCIfCEEIANC/////w+DIAA1AggiCSAGfnwhAyAEIANCIIh8IQQgAiADPgIIIARCIIghAyAEQv////8PgyAFIAE1AgwiDH58IQQgAyAEQiCIfCEDIARC/////w+DIAcgCn58IQQgAyAEQiCIfCEDIARC/////w+DIAkgCH58IQQgAyAEQiCIfCEDIARC/////w+DIAA1AgwiCyAGfnwhBCADIARCIIh8IQMgAiAEPgIMIANCIIghBCADQv////8PgyAFIAE1AhAiDn58IQMgBCADQiCIfCEEIANC/////w+DIAcgDH58IQMgBCADQiCIfCEEIANC/////w+DIAkgCn58IQMgBCADQiCIfCEEIANC/////w+DIAsgCH58IQMgBCADQiCIfCEEIANC/////w+DIAA1AhAiDSAGfnwhAyAEIANCIIh8IQQgAiADPgIQIARCIIghAyAEQv////8PgyAFIAE1AhQiEH58IQQgAyAEQiCIfCEDIARC/////w+DIAcgDn58IQQgAyAEQiCIfCEDIARC/////w+DIAkgDH58IQQgAyAEQiCIfCEDIARC/////w+DIAsgCn58IQQgAyAEQiCIfCEDIARC/////w+DIA0gCH58IQQgAyAEQiCIfCEDIARC/////w+DIAA1AhQiDyAGfnwhBCADIARCIIh8IQMgAiAEPgIUIANCIIghBCADQv////8PgyAFIAE1AhgiEn58IQMgBCADQiCIfCEEIANC/////w+DIAcgEH58IQMgBCADQiCIfCEEIANC/////w+DIAkgDn58IQMgBCADQiCIfCEEIANC/////w+DIAsgDH58IQMgBCADQiCIfCEEIANC/////w+DIA0gCn58IQMgBCADQiCIfCEEIANC/////w+DIA8gCH58IQMgBCADQiCIfCEEIANC/////w+DIAA1AhgiESAGfnwhAyAEIANCIIh8IQQgAiADPgIYIARCIIghAyAEQv////8PgyAFIAE1AhwiFH58IQQgAyAEQiCIfCEDIARC/////w+DIAcgEn58IQQgAyAEQiCIfCEDIARC/////w+DIAkgEH58IQQgAyAEQiCIfCEDIARC/////w+DIAsgDn58IQQgAyAEQiCIfCEDIARC/////w+DIA0gDH58IQQgAyAEQiCIfCEDIARC/////w+DIA8gCn58IQQgAyAEQiCIfCEDIARC/////w+DIBEgCH58IQQgAyAEQiCIfCEDIARC/////w+DIAA1AhwiEyAGfnwhBCADIARCIIh8IQMgAiAEPgIcIANCIIghBCADQv////8PgyAHIBR+fCEDIAQgA0IgiHwhBCADQv////8PgyAJIBJ+fCEDIAQgA0IgiHwhBCADQv////8PgyALIBB+fCEDIAQgA0IgiHwhBCADQv////8PgyANIA5+fCEDIAQgA0IgiHwhBCADQv////8PgyAPIAx+fCEDIAQgA0IgiHwhBCADQv////8PgyARIAp+fCEDIAQgA0IgiHwhBCADQv////8PgyATIAh+fCEDIAQgA0IgiHwhBCACIAM+AiAgBEIgiCEDIARC/////w+DIAkgFH58IQQgAyAEQiCIfCEDIARC/////w+DIAsgEn58IQQgAyAEQiCIfCEDIARC/////w+DIA0gEH58IQQgAyAEQiCIfCEDIARC/////w+DIA8gDn58IQQgAyAEQiCIfCEDIARC/////w+DIBEgDH58IQQgAyAEQiCIfCEDIARC/////w+DIBMgCn58IQQgAyAEQiCIfCEDIAIgBD4CJCADQiCIIQQgA0L/////D4MgCyAUfnwhAyAEIANCIIh8IQQgA0L/////D4MgDSASfnwhAyAEIANCIIh8IQQgA0L/////D4MgDyAQfnwhAyAEIANCIIh8IQQgA0L/////D4MgESAOfnwhAyAEIANCIIh8IQQgA0L/////D4MgEyAMfnwhAyAEIANCIIh8IQQgAiADPgIoIARCIIghAyAEQv////8PgyANIBR+fCEEIAMgBEIgiHwhAyAEQv////8PgyAPIBJ+fCEEIAMgBEIgiHwhAyAEQv////8PgyARIBB+fCEEIAMgBEIgiHwhAyAEQv////8PgyATIA5+fCEEIAMgBEIgiHwhAyACIAQ+AiwgA0IgiCEEIANC/////w+DIA8gFH58IQMgBCADQiCIfCEEIANC/////w+DIBEgEn58IQMgBCADQiCIfCEEIANC/////w+DIBMgEH58IQMgBCADQiCIfCEEIAIgAz4CMCAEQiCIIQMgBEL/////D4MgESAUfnwhBCADIARCIIh8IQMgBEL/////D4MgEyASfnwhBCADIARCIIh8IQMgAiAEPgI0IANCIIghBCADQv////8PgyATIBR+fCEDIAQgA0IgiHwhBCACIAM+AjggBEIgiCEDIAIgBD4CPAuMEgwBfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX5CACECQgAhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAANQIAIgYgBn58IQIgAyACQiCIfCEDIAEgAj4CACADIQQgBEIgiCEFQgAhAkIAIQMgAkL/////D4MgBiAANQIEIgd+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgASACPgIEIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyAGIAA1AggiCH58IQIgAyACQiCIfCEDIAJC/////w+DQgGGIQIgA0IBhiACQiCIfCEDIAJC/////w+DIAcgB358IQIgAyACQiCIfCEDIAJC/////w+DIARC/////w+DfCECIAMgAkIgiHwgBXwhAyABIAI+AgggAyEEIARCIIghBUIAIQJCACEDIAJC/////w+DIAYgADUCDCIJfnwhAiADIAJCIIh8IQMgAkL/////D4MgByAIfnwhAiADIAJCIIh8IQMgAkL/////D4NCAYYhAiADQgGGIAJCIIh8IQMgAkL/////D4MgBEL/////D4N8IQIgAyACQiCIfCAFfCEDIAEgAj4CDCADIQQgBEIgiCEFQgAhAkIAIQMgAkL/////D4MgBiAANQIQIgp+fCECIAMgAkIgiHwhAyACQv////8PgyAHIAl+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAIIAh+fCECIAMgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgASACPgIQIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyAGIAA1AhQiC358IQIgAyACQiCIfCEDIAJC/////w+DIAcgCn58IQIgAyACQiCIfCEDIAJC/////w+DIAggCX58IQIgAyACQiCIfCEDIAJC/////w+DQgGGIQIgA0IBhiACQiCIfCEDIAJC/////w+DIARC/////w+DfCECIAMgAkIgiHwgBXwhAyABIAI+AhQgAyEEIARCIIghBUIAIQJCACEDIAJC/////w+DIAYgADUCGCIMfnwhAiADIAJCIIh8IQMgAkL/////D4MgByALfnwhAiADIAJCIIh8IQMgAkL/////D4MgCCAKfnwhAiADIAJCIIh8IQMgAkL/////D4NCAYYhAiADQgGGIAJCIIh8IQMgAkL/////D4MgCSAJfnwhAiADIAJCIIh8IQMgAkL/////D4MgBEL/////D4N8IQIgAyACQiCIfCAFfCEDIAEgAj4CGCADIQQgBEIgiCEFQgAhAkIAIQMgAkL/////D4MgBiAANQIcIg1+fCECIAMgAkIgiHwhAyACQv////8PgyAHIAx+fCECIAMgAkIgiHwhAyACQv////8PgyAIIAt+fCECIAMgAkIgiHwhAyACQv////8PgyAJIAp+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgASACPgIcIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyAHIA1+fCECIAMgAkIgiHwhAyACQv////8PgyAIIAx+fCECIAMgAkIgiHwhAyACQv////8PgyAJIAt+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAKIAp+fCECIAMgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgASACPgIgIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyAIIA1+fCECIAMgAkIgiHwhAyACQv////8PgyAJIAx+fCECIAMgAkIgiHwhAyACQv////8PgyAKIAt+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgASACPgIkIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyAJIA1+fCECIAMgAkIgiHwhAyACQv////8PgyAKIAx+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyALIAt+fCECIAMgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgASACPgIoIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyAKIA1+fCECIAMgAkIgiHwhAyACQv////8PgyALIAx+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgASACPgIsIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyALIA1+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAMIAx+fCECIAMgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgASACPgIwIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyAMIA1+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgASACPgI0IAMhBCAEQiCIIQVCACECQgAhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyANIA1+fCECIAMgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgASACPgI4IAMhBCAEQiCIIQUgASAEPgI8CwoAIAAgACABEAgLtgEBAX4gADUAACABfiEDIAIgAz4AACAANQAEIAF+IANCIIh8IQMgAiADPgAEIAA1AAggAX4gA0IgiHwhAyACIAM+AAggADUADCABfiADQiCIfCEDIAIgAz4ADCAANQAQIAF+IANCIIh8IQMgAiADPgAQIAA1ABQgAX4gA0IgiHwhAyACIAM+ABQgADUAGCABfiADQiCIfCEDIAIgAz4AGCAANQAcIAF+IANCIIh8IQMgAiADPgAcC04CAX4BfyAAIQMgAzUAACABfCECIAMgAj4AACACQiCIIQICQANAIAJQDQEgA0EEaiEDIAM1AAAgAnwhAiADIAI+AAAgAkIgiCECDAALCwurAgcBfwF/AX8BfwF+AX4BfyACBEAgAiEFBUHIACEFCyADBEAgAyEEBUHoACEECyAAIAQQACABQSgQACAFEAFBiAEQAUEf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LCADQiCIfEHoAzUCECAEfnwhAyAAIAM+AiwgADUCMCADQiCIfEHoAzUCFCAEfnwhAyAAIAM+AjAgADUCNCADQiCIfEHoAzUCGCAEfnwhAyAAIAM+AjQgADUCOCADQiCIfEHoAzUCHCAEfnwhAyAAIAM+AjhBiAYgA0IgiD4CHEGIBiAAQSBqIAEQEAu+HyMBfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+QonHmaQOIQUgA0L/////D4MgADUCACIGIAE1AgAiB358IQMgBCADQiCIfCEEIANC/////w+DIAV+Qv////8PgyEIIANC/////w+DQQA1AugDIgkgCH58IQMgBCADQiCIfCEEIARCIIghAyAEQv////8PgyAGIAE1AgQiC358IQQgAyAEQiCIfCEDIARC/////w+DIAA1AgQiCiAHfnwhBCADIARCIIh8IQMgBEL/////D4NBADUC7AMiDSAIfnwhBCADIARCIIh8IQMgBEL/////D4MgBX5C/////w+DIQwgBEL/////D4MgCSAMfnwhBCADIARCIIh8IQMgA0IgiCEEIANC/////w+DIAYgATUCCCIPfnwhAyAEIANCIIh8IQQgA0L/////D4MgCiALfnwhAyAEIANCIIh8IQQgA0L/////D4MgADUCCCIOIAd+fCEDIAQgA0IgiHwhBCADQv////8PgyANIAx+fCEDIAQgA0IgiHwhBCADQv////8Pg0EANQLwAyIRIAh+fCEDIAQgA0IgiHwhBCADQv////8PgyAFfkL/////D4MhECADQv////8PgyAJIBB+fCEDIAQgA0IgiHwhBCAEQiCIIQMgBEL/////D4MgBiABNQIMIhN+fCEEIAMgBEIgiHwhAyAEQv////8PgyAKIA9+fCEEIAMgBEIgiHwhAyAEQv////8PgyAOIAt+fCEEIAMgBEIgiHwhAyAEQv////8PgyAANQIMIhIgB358IQQgAyAEQiCIfCEDIARC/////w+DIA0gEH58IQQgAyAEQiCIfCEDIARC/////w+DIBEgDH58IQQgAyAEQiCIfCEDIARC/////w+DQQA1AvQDIhUgCH58IQQgAyAEQiCIfCEDIARC/////w+DIAV+Qv////8PgyEUIARC/////w+DIAkgFH58IQQgAyAEQiCIfCEDIANCIIghBCADQv////8PgyAGIAE1AhAiF358IQMgBCADQiCIfCEEIANC/////w+DIAogE358IQMgBCADQiCIfCEEIANC/////w+DIA4gD358IQMgBCADQiCIfCEEIANC/////w+DIBIgC358IQMgBCADQiCIfCEEIANC/////w+DIAA1AhAiFiAHfnwhAyAEIANCIIh8IQQgA0L/////D4MgDSAUfnwhAyAEIANCIIh8IQQgA0L/////D4MgESAQfnwhAyAEIANCIIh8IQQgA0L/////D4MgFSAMfnwhAyAEIANCIIh8IQQgA0L/////D4NBADUC+AMiGSAIfnwhAyAEIANCIIh8IQQgA0L/////D4MgBX5C/////w+DIRggA0L/////D4MgCSAYfnwhAyAEIANCIIh8IQQgBEIgiCEDIARC/////w+DIAYgATUCFCIbfnwhBCADIARCIIh8IQMgBEL/////D4MgCiAXfnwhBCADIARCIIh8IQMgBEL/////D4MgDiATfnwhBCADIARCIIh8IQMgBEL/////D4MgEiAPfnwhBCADIARCIIh8IQMgBEL/////D4MgFiALfnwhBCADIARCIIh8IQMgBEL/////D4MgADUCFCIaIAd+fCEEIAMgBEIgiHwhAyAEQv////8PgyANIBh+fCEEIAMgBEIgiHwhAyAEQv////8PgyARIBR+fCEEIAMgBEIgiHwhAyAEQv////8PgyAVIBB+fCEEIAMgBEIgiHwhAyAEQv////8PgyAZIAx+fCEEIAMgBEIgiHwhAyAEQv////8Pg0EANQL8AyIdIAh+fCEEIAMgBEIgiHwhAyAEQv////8PgyAFfkL/////D4MhHCAEQv////8PgyAJIBx+fCEEIAMgBEIgiHwhAyADQiCIIQQgA0L/////D4MgBiABNQIYIh9+fCEDIAQgA0IgiHwhBCADQv////8PgyAKIBt+fCEDIAQgA0IgiHwhBCADQv////8PgyAOIBd+fCEDIAQgA0IgiHwhBCADQv////8PgyASIBN+fCEDIAQgA0IgiHwhBCADQv////8PgyAWIA9+fCEDIAQgA0IgiHwhBCADQv////8PgyAaIAt+fCEDIAQgA0IgiHwhBCADQv////8PgyAANQIYIh4gB358IQMgBCADQiCIfCEEIANC/////w+DIA0gHH58IQMgBCADQiCIfCEEIANC/////w+DIBEgGH58IQMgBCADQiCIfCEEIANC/////w+DIBUgFH58IQMgBCADQiCIfCEEIANC/////w+DIBkgEH58IQMgBCADQiCIfCEEIANC/////w+DIB0gDH58IQMgBCADQiCIfCEEIANC/////w+DQQA1AoAEIiEgCH58IQMgBCADQiCIfCEEIANC/////w+DIAV+Qv////8PgyEgIANC/////w+DIAkgIH58IQMgBCADQiCIfCEEIARCIIghAyAEQv////8PgyAGIAE1AhwiI358IQQgAyAEQiCIfCEDIARC/////w+DIAogH358IQQgAyAEQiCIfCEDIARC/////w+DIA4gG358IQQgAyAEQiCIfCEDIARC/////w+DIBIgF358IQQgAyAEQiCIfCEDIARC/////w+DIBYgE358IQQgAyAEQiCIfCEDIARC/////w+DIBogD358IQQgAyAEQiCIfCEDIARC/////w+DIB4gC358IQQgAyAEQiCIfCEDIARC/////w+DIAA1AhwiIiAHfnwhBCADIARCIIh8IQMgBEL/////D4MgDSAgfnwhBCADIARCIIh8IQMgBEL/////D4MgESAcfnwhBCADIARCIIh8IQMgBEL/////D4MgFSAYfnwhBCADIARCIIh8IQMgBEL/////D4MgGSAUfnwhBCADIARCIIh8IQMgBEL/////D4MgHSAQfnwhBCADIARCIIh8IQMgBEL/////D4MgISAMfnwhBCADIARCIIh8IQMgBEL/////D4NBADUChAQiJSAIfnwhBCADIARCIIh8IQMgBEL/////D4MgBX5C/////w+DISQgBEL/////D4MgCSAkfnwhBCADIARCIIh8IQMgA0IgiCEEIANC/////w+DIAogI358IQMgBCADQiCIfCEEIANC/////w+DIA4gH358IQMgBCADQiCIfCEEIANC/////w+DIBIgG358IQMgBCADQiCIfCEEIANC/////w+DIBYgF358IQMgBCADQiCIfCEEIANC/////w+DIBogE358IQMgBCADQiCIfCEEIANC/////w+DIB4gD358IQMgBCADQiCIfCEEIANC/////w+DICIgC358IQMgBCADQiCIfCEEIANC/////w+DIA0gJH58IQMgBCADQiCIfCEEIANC/////w+DIBEgIH58IQMgBCADQiCIfCEEIANC/////w+DIBUgHH58IQMgBCADQiCIfCEEIANC/////w+DIBkgGH58IQMgBCADQiCIfCEEIANC/////w+DIB0gFH58IQMgBCADQiCIfCEEIANC/////w+DICEgEH58IQMgBCADQiCIfCEEIANC/////w+DICUgDH58IQMgBCADQiCIfCEEIAIgAz4CACAEQiCIIQMgBEL/////D4MgDiAjfnwhBCADIARCIIh8IQMgBEL/////D4MgEiAffnwhBCADIARCIIh8IQMgBEL/////D4MgFiAbfnwhBCADIARCIIh8IQMgBEL/////D4MgGiAXfnwhBCADIARCIIh8IQMgBEL/////D4MgHiATfnwhBCADIARCIIh8IQMgBEL/////D4MgIiAPfnwhBCADIARCIIh8IQMgBEL/////D4MgESAkfnwhBCADIARCIIh8IQMgBEL/////D4MgFSAgfnwhBCADIARCIIh8IQMgBEL/////D4MgGSAcfnwhBCADIARCIIh8IQMgBEL/////D4MgHSAYfnwhBCADIARCIIh8IQMgBEL/////D4MgISAUfnwhBCADIARCIIh8IQMgBEL/////D4MgJSAQfnwhBCADIARCIIh8IQMgAiAEPgIEIANCIIghBCADQv////8PgyASICN+fCEDIAQgA0IgiHwhBCADQv////8PgyAWIB9+fCEDIAQgA0IgiHwhBCADQv////8PgyAaIBt+fCEDIAQgA0IgiHwhBCADQv////8PgyAeIBd+fCEDIAQgA0IgiHwhBCADQv////8PgyAiIBN+fCEDIAQgA0IgiHwhBCADQv////8PgyAVICR+fCEDIAQgA0IgiHwhBCADQv////8PgyAZICB+fCEDIAQgA0IgiHwhBCADQv////8PgyAdIBx+fCEDIAQgA0IgiHwhBCADQv////8PgyAhIBh+fCEDIAQgA0IgiHwhBCADQv////8PgyAlIBR+fCEDIAQgA0IgiHwhBCACIAM+AgggBEIgiCEDIARC/////w+DIBYgI358IQQgAyAEQiCIfCEDIARC/////w+DIBogH358IQQgAyAEQiCIfCEDIARC/////w+DIB4gG358IQQgAyAEQiCIfCEDIARC/////w+DICIgF358IQQgAyAEQiCIfCEDIARC/////w+DIBkgJH58IQQgAyAEQiCIfCEDIARC/////w+DIB0gIH58IQQgAyAEQiCIfCEDIARC/////w+DICEgHH58IQQgAyAEQiCIfCEDIARC/////w+DICUgGH58IQQgAyAEQiCIfCEDIAIgBD4CDCADQiCIIQQgA0L/////D4MgGiAjfnwhAyAEIANCIIh8IQQgA0L/////D4MgHiAffnwhAyAEIANCIIh8IQQgA0L/////D4MgIiAbfnwhAyAEIANCIIh8IQQgA0L/////D4MgHSAkfnwhAyAEIANCIIh8IQQgA0L/////D4MgISAgfnwhAyAEIANCIIh8IQQgA0L/////D4MgJSAcfnwhAyAEIANCIIh8IQQgAiADPgIQIARCIIghAyAEQv////8PgyAeICN+fCEEIAMgBEIgiHwhAyAEQv////8PgyAiIB9+fCEEIAMgBEIgiHwhAyAEQv////8PgyAhICR+fCEEIAMgBEIgiHwhAyAEQv////8PgyAlICB+fCEEIAMgBEIgiHwhAyACIAQ+AhQgA0IgiCEEIANC/////w+DICIgI358IQMgBCADQiCIfCEEIANC/////w+DICUgJH58IQMgBCADQiCIfCEEIAIgAz4CGCAEQiCIIQMgAiAEPgIcIAOnBEAgAkHoAyACEAcaBSACQegDEAUEQCACQegDIAIQBxoLCwu7IR0BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+QonHmaQOIQZCACECQgAhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAANQIAIgcgB358IQIgAyACQiCIfCEDIAJC/////w+DIAZ+Qv////8PgyEIIAJC/////w+DQQA1AugDIgkgCH58IQIgAyACQiCIfCEDIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyAHIAA1AgQiCn58IQIgAyACQiCIfCEDIAJC/////w+DQgGGIQIgA0IBhiACQiCIfCEDIAJC/////w+DIARC/////w+DfCECIAMgAkIgiHwgBXwhAyACQv////8Pg0EANQLsAyIMIAh+fCECIAMgAkIgiHwhAyACQv////8PgyAGfkL/////D4MhCyACQv////8PgyAJIAt+fCECIAMgAkIgiHwhAyADIQQgBEIgiCEFQgAhAkIAIQMgAkL/////D4MgByAANQIIIg1+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAKIAp+fCECIAMgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgAkL/////D4MgDCALfnwhAiADIAJCIIh8IQMgAkL/////D4NBADUC8AMiDyAIfnwhAiADIAJCIIh8IQMgAkL/////D4MgBn5C/////w+DIQ4gAkL/////D4MgCSAOfnwhAiADIAJCIIh8IQMgAyEEIARCIIghBUIAIQJCACEDIAJC/////w+DIAcgADUCDCIQfnwhAiADIAJCIIh8IQMgAkL/////D4MgCiANfnwhAiADIAJCIIh8IQMgAkL/////D4NCAYYhAiADQgGGIAJCIIh8IQMgAkL/////D4MgBEL/////D4N8IQIgAyACQiCIfCAFfCEDIAJC/////w+DIAwgDn58IQIgAyACQiCIfCEDIAJC/////w+DIA8gC358IQIgAyACQiCIfCEDIAJC/////w+DQQA1AvQDIhIgCH58IQIgAyACQiCIfCEDIAJC/////w+DIAZ+Qv////8PgyERIAJC/////w+DIAkgEX58IQIgAyACQiCIfCEDIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyAHIAA1AhAiE358IQIgAyACQiCIfCEDIAJC/////w+DIAogEH58IQIgAyACQiCIfCEDIAJC/////w+DQgGGIQIgA0IBhiACQiCIfCEDIAJC/////w+DIA0gDX58IQIgAyACQiCIfCEDIAJC/////w+DIARC/////w+DfCECIAMgAkIgiHwgBXwhAyACQv////8PgyAMIBF+fCECIAMgAkIgiHwhAyACQv////8PgyAPIA5+fCECIAMgAkIgiHwhAyACQv////8PgyASIAt+fCECIAMgAkIgiHwhAyACQv////8Pg0EANQL4AyIVIAh+fCECIAMgAkIgiHwhAyACQv////8PgyAGfkL/////D4MhFCACQv////8PgyAJIBR+fCECIAMgAkIgiHwhAyADIQQgBEIgiCEFQgAhAkIAIQMgAkL/////D4MgByAANQIUIhZ+fCECIAMgAkIgiHwhAyACQv////8PgyAKIBN+fCECIAMgAkIgiHwhAyACQv////8PgyANIBB+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgAkL/////D4MgDCAUfnwhAiADIAJCIIh8IQMgAkL/////D4MgDyARfnwhAiADIAJCIIh8IQMgAkL/////D4MgEiAOfnwhAiADIAJCIIh8IQMgAkL/////D4MgFSALfnwhAiADIAJCIIh8IQMgAkL/////D4NBADUC/AMiGCAIfnwhAiADIAJCIIh8IQMgAkL/////D4MgBn5C/////w+DIRcgAkL/////D4MgCSAXfnwhAiADIAJCIIh8IQMgAyEEIARCIIghBUIAIQJCACEDIAJC/////w+DIAcgADUCGCIZfnwhAiADIAJCIIh8IQMgAkL/////D4MgCiAWfnwhAiADIAJCIIh8IQMgAkL/////D4MgDSATfnwhAiADIAJCIIh8IQMgAkL/////D4NCAYYhAiADQgGGIAJCIIh8IQMgAkL/////D4MgECAQfnwhAiADIAJCIIh8IQMgAkL/////D4MgBEL/////D4N8IQIgAyACQiCIfCAFfCEDIAJC/////w+DIAwgF358IQIgAyACQiCIfCEDIAJC/////w+DIA8gFH58IQIgAyACQiCIfCEDIAJC/////w+DIBIgEX58IQIgAyACQiCIfCEDIAJC/////w+DIBUgDn58IQIgAyACQiCIfCEDIAJC/////w+DIBggC358IQIgAyACQiCIfCEDIAJC/////w+DQQA1AoAEIhsgCH58IQIgAyACQiCIfCEDIAJC/////w+DIAZ+Qv////8PgyEaIAJC/////w+DIAkgGn58IQIgAyACQiCIfCEDIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyAHIAA1AhwiHH58IQIgAyACQiCIfCEDIAJC/////w+DIAogGX58IQIgAyACQiCIfCEDIAJC/////w+DIA0gFn58IQIgAyACQiCIfCEDIAJC/////w+DIBAgE358IQIgAyACQiCIfCEDIAJC/////w+DQgGGIQIgA0IBhiACQiCIfCEDIAJC/////w+DIARC/////w+DfCECIAMgAkIgiHwgBXwhAyACQv////8PgyAMIBp+fCECIAMgAkIgiHwhAyACQv////8PgyAPIBd+fCECIAMgAkIgiHwhAyACQv////8PgyASIBR+fCECIAMgAkIgiHwhAyACQv////8PgyAVIBF+fCECIAMgAkIgiHwhAyACQv////8PgyAYIA5+fCECIAMgAkIgiHwhAyACQv////8PgyAbIAt+fCECIAMgAkIgiHwhAyACQv////8Pg0EANQKEBCIeIAh+fCECIAMgAkIgiHwhAyACQv////8PgyAGfkL/////D4MhHSACQv////8PgyAJIB1+fCECIAMgAkIgiHwhAyADIQQgBEIgiCEFQgAhAkIAIQMgAkL/////D4MgCiAcfnwhAiADIAJCIIh8IQMgAkL/////D4MgDSAZfnwhAiADIAJCIIh8IQMgAkL/////D4MgECAWfnwhAiADIAJCIIh8IQMgAkL/////D4NCAYYhAiADQgGGIAJCIIh8IQMgAkL/////D4MgEyATfnwhAiADIAJCIIh8IQMgAkL/////D4MgBEL/////D4N8IQIgAyACQiCIfCAFfCEDIAJC/////w+DIAwgHX58IQIgAyACQiCIfCEDIAJC/////w+DIA8gGn58IQIgAyACQiCIfCEDIAJC/////w+DIBIgF358IQIgAyACQiCIfCEDIAJC/////w+DIBUgFH58IQIgAyACQiCIfCEDIAJC/////w+DIBggEX58IQIgAyACQiCIfCEDIAJC/////w+DIBsgDn58IQIgAyACQiCIfCEDIAJC/////w+DIB4gC358IQIgAyACQiCIfCEDIAEgAj4CACADIQQgBEIgiCEFQgAhAkIAIQMgAkL/////D4MgDSAcfnwhAiADIAJCIIh8IQMgAkL/////D4MgECAZfnwhAiADIAJCIIh8IQMgAkL/////D4MgEyAWfnwhAiADIAJCIIh8IQMgAkL/////D4NCAYYhAiADQgGGIAJCIIh8IQMgAkL/////D4MgBEL/////D4N8IQIgAyACQiCIfCAFfCEDIAJC/////w+DIA8gHX58IQIgAyACQiCIfCEDIAJC/////w+DIBIgGn58IQIgAyACQiCIfCEDIAJC/////w+DIBUgF358IQIgAyACQiCIfCEDIAJC/////w+DIBggFH58IQIgAyACQiCIfCEDIAJC/////w+DIBsgEX58IQIgAyACQiCIfCEDIAJC/////w+DIB4gDn58IQIgAyACQiCIfCEDIAEgAj4CBCADIQQgBEIgiCEFQgAhAkIAIQMgAkL/////D4MgECAcfnwhAiADIAJCIIh8IQMgAkL/////D4MgEyAZfnwhAiADIAJCIIh8IQMgAkL/////D4NCAYYhAiADQgGGIAJCIIh8IQMgAkL/////D4MgFiAWfnwhAiADIAJCIIh8IQMgAkL/////D4MgBEL/////D4N8IQIgAyACQiCIfCAFfCEDIAJC/////w+DIBIgHX58IQIgAyACQiCIfCEDIAJC/////w+DIBUgGn58IQIgAyACQiCIfCEDIAJC/////w+DIBggF358IQIgAyACQiCIfCEDIAJC/////w+DIBsgFH58IQIgAyACQiCIfCEDIAJC/////w+DIB4gEX58IQIgAyACQiCIfCEDIAEgAj4CCCADIQQgBEIgiCEFQgAhAkIAIQMgAkL/////D4MgEyAcfnwhAiADIAJCIIh8IQMgAkL/////D4MgFiAZfnwhAiADIAJCIIh8IQMgAkL/////D4NCAYYhAiADQgGGIAJCIIh8IQMgAkL/////D4MgBEL/////D4N8IQIgAyACQiCIfCAFfCEDIAJC/////w+DIBUgHX58IQIgAyACQiCIfCEDIAJC/////w+DIBggGn58IQIgAyACQiCIfCEDIAJC/////w+DIBsgF358IQIgAyACQiCIfCEDIAJC/////w+DIB4gFH58IQIgAyACQiCIfCEDIAEgAj4CDCADIQQgBEIgiCEFQgAhAkIAIQMgAkL/////D4MgFiAcfnwhAiADIAJCIIh8IQMgAkL/////D4NCAYYhAiADQgGGIAJCIIh8IQMgAkL/////D4MgGSAZfnwhAiADIAJCIIh8IQMgAkL/////D4MgBEL/////D4N8IQIgAyACQiCIfCAFfCEDIAJC/////w+DIBggHX58IQIgAyACQiCIfCEDIAJC/////w+DIBsgGn58IQIgAyACQiCIfCEDIAJC/////w+DIB4gF358IQIgAyACQiCIfCEDIAEgAj4CECADIQQgBEIg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AhAgA0IgiHxB6A01AgggBH58IQMgACADPgIQIAA1AhQgA0IgiHxB6A01AgwgBH58IQMgACADPgIUIAA1AhggA0IgiHxB6A01AhAgBH58IQMgACADPgIYIAA1AhwgA0IgiHxB6A01AhQgBH58IQMgACADPgIcIAA1AiAgA0IgiHxB6A01AhggBH58IQMgACADPgIgIAA1AiQgA0IgiHxB6A01AhwgBH58IQMgACADPgIkQYgQIANCIIg+AghCACEDIAA1AgwgAn5C/////w+DIQQgADUCDCADQiCIfEHoDTUCACAEfnwhAyAAIAM+AgwgADUCECADQiCIfEHoDTUCBCAEfnwhAyAAIAM+AhAgADUCFCADQiCIfEHoDTUCCCAEfnwhAyAAIAM+AhQgADUCGCADQiCIfEHoDTUCDCAEfnwhAyAAIAM+AhggADUCHCADQiCIfEHoDTUCECAEfnwhAyAAIAM+AhwgADUCICADQiCIfEHoDTUCFCAEfnwhAyAAIAM+AiAgADUCJCADQiCIfEHoDTUCGCAEfnwhAyAAIAM+AiQgADUCKCADQiCIfEHoDTUCHCAEfnwhAyAAIAM+AihBiBAgA0IgiD4CDEIAIQMgADUCECACfkL/////D4MhBCAANQIQIANCIIh8QegNNQIAIAR+fCEDIAAgAz4CECAANQIUIANCIIh8QegNNQIEIAR+fCEDIAAgAz4CFCAANQIYIANCIIh8QegNNQIIIAR+fCEDIAAgAz4CGCAANQIcIANCIIh8QegNNQIMIAR+fCEDIAAgAz4CHCAANQIgIANCIIh8QegNNQIQIAR+fCEDIAAgAz4CICAANQIkIANCIIh8QegNNQIUIAR+fCEDIAAgAz4CJCAANQIoIANCIIh8QegNNQIYIAR+fCEDIAAgAz4CKCAANQIsIANCIIh8QegNNQIcIAR+fCEDIAAgAz4CLEGIECADQiCIPgIQQgAhAyAANQIUIAJ+Qv////8PgyEEIAA1AhQgA0IgiHxB6A01AgAgBH58IQMgACADPgIUIAA1AhggA0IgiHxB6A01AgQgBH58IQMgACADPgIYIAA1AhwgA0IgiHxB6A01AgggBH58IQMgACADPgIcIAA1AiAgA0IgiHxB6A01AgwgBH58IQMgACADPgIgIAA1AiQgA0IgiHxB6A01AhAgBH58IQMgACADPgIkIAA1AiggA0IgiHxB6A01AhQgBH58IQMgACADPgIoIAA1AiwgA0IgiHxB6A01AhggBH58IQMgACADPgIsIAA1AjAgA0IgiHxB6A01AhwgBH58IQMgACADPgIwQYgQIANCIIg+AhRCACEDIAA1AhggAn5C/////w+DIQQgADUCGCADQiCIfEHoDTUCACAEfnwhAyAAIAM+AhggADUCHCADQiCIfEHoDTUCBCAEfnwhAyAAIAM+AhwgADUCICADQiCIfEHoDTUCCCAEfnwhAyAAIAM+AiAgADUCJCADQiCIfEHoDTUCDCAEfnwhAyAAIAM+AiQgADUCKCADQiCIfEHoDTUCECAEfnwhAyAAIAM+AiggADUCLCADQiCIfEHoDTUCFCAEfnwhAyAAIAM+AiwgADUCMCADQiCIfEHoDTUCGCAEfnwhAyAAIAM+AjAgADUCNCADQiCIfEHoDTUCHCAEfnwhAyAAIAM+AjRBiBAgA0IgiD4CGEIAIQMgADUCHCACfkL/////D4MhBCAANQIcIANCIIh8QegNNQIAIAR+fCEDIAAgAz4CHCAANQIgIANCIIh8QegNNQIEIAR+fCEDIAAgAz4CICAANQIkIANCIIh8QegNNQIIIAR+fCEDIAAgAz4CJCAANQIoIANCIIh8QegNNQIMIAR+fCEDIAAgAz4CKCAANQIsIANCIIh8QegNNQIQIAR+fCEDIAAgAz4CLCAANQIwIANCIIh8QegNNQIUIAR+fCEDIAAgAz4CMCAANQI0IANCIIh8QegNNQIYIAR+fCEDIAAgAz4CNCAANQI4IANCIIh8QegNNQIcIAR+fCEDIAAgAz4COEGIECADQiCIPgIcQYgQIABBIGogARAqC74fIwF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX5C/////w4hBSADQv////8PgyAANQIAIgYgATUCACIHfnwhAyAEIANCIIh8IQQgA0L/////D4MgBX5C/////w+DIQggA0L/////D4NBADUC6A0iCSAIfnwhAyAEIANCIIh8IQQgBEIgiCEDIARC/////w+DIAYgATUCBCILfnwhBCADIARCIIh8IQMgBEL/////D4MgADUCBCIKIAd+fCEEIAMgBEIgiHwhAyAEQv////8Pg0EANQLsDSINIAh+fCEEIAMgBEIgiHwhAyAEQv////8PgyAFfkL/////D4MhDCAEQv////8PgyAJIAx+fCEEIAMgBEIgiHwhAyADQiCIIQQgA0L/////D4MgBiABNQIIIg9+fCEDIAQgA0IgiHwhBCADQv////8PgyAKIAt+fCEDIAQgA0IgiHwhBCADQv////8PgyAANQIIIg4gB358IQMgBCADQiCIfCEEIANC/////w+DIA0gDH58IQMgBCADQiCIfCEEIANC/////w+DQQA1AvANIhEgCH58IQMgBCADQiCIfCEEIANC/////w+DIAV+Qv////8PgyEQIANC/////w+DIAkgEH58IQMgBCADQiCIfCEEIARCIIghAyAEQv////8PgyAGIAE1AgwiE358IQQgAyAEQiCIfCEDIARC/////w+DIAogD358IQQgAyAEQiCIfCEDIARC/////w+DIA4gC358IQQgAyAEQiCIfCEDIARC/////w+DIAA1AgwiEiAHfnwhBCADIARCIIh8IQMgBEL/////D4MgDSAQfnwhBCADIARCIIh8IQMgBEL/////D4MgESAMfnwhBCADIARCIIh8IQMgBEL/////D4NBADUC9A0iFSAIfnwhBCADIARCIIh8IQMgBEL/////D4MgBX5C/////w+DIRQgBEL/////D4MgCSAUfnwhBCADIARCIIh8IQMgA0IgiCEEIANC/////w+DIAYgATUCECIXfnwhAyAEIANCIIh8IQQgA0L/////D4MgCiATfnwhAyAEIANCIIh8IQQgA0L/////D4MgDiAPfnwhAyAEIANCIIh8IQQgA0L/////D4MgEiALfnwhAyAEIANCIIh8IQQgA0L/////D4MgADUCECIWIAd+fCEDIAQgA0IgiHwhBCADQv////8PgyANIBR+fCEDIAQgA0IgiHwhBCADQv////8PgyARIBB+fCEDIAQgA0IgiHwhBCADQv////8PgyAVIAx+fCEDIAQgA0IgiHwhBCADQv////8Pg0EANQL4DSIZIAh+fCEDIAQgA0IgiHwhBCADQv////8PgyAFfkL/////D4MhGCADQv////8PgyAJIBh+fCEDIAQgA0IgiHwhBCAEQiCIIQMgBEL/////D4MgBiABNQIUIht+fCEEIAMgBEIgiHwhAyAEQv////8PgyAKIBd+fCEEIAMgBEIgiHwhAyAEQv////8PgyAOIBN+fCEEIAMgBEIgiHwhAyAEQv////8PgyASIA9+fCEEIAMgBEIgiHwhAyAEQv////8PgyAWIAt+fCEEIAMgBEIgiHwhAyAEQv////8PgyAANQIUIhogB358IQQgAyAEQiCIfCEDIARC/////w+DIA0gGH58IQQgAyAEQiCIfCEDIARC/////w+DIBEgFH58IQQgAyAEQiCIfCEDIARC/////w+DIBUgEH58IQQgAyAEQiCIfCEDIARC/////w+DIBkgDH58IQQgAyAEQiCIfCEDIARC/////w+DQQA1AvwNIh0gCH58IQQgAyAEQiCIfCEDIARC/////w+DIAV+Qv////8PgyEcIARC/////w+DIAkgHH58IQQgAyAEQiCIfCEDIANCIIghBCADQv////8PgyAGIAE1AhgiH358IQMgBCADQiCIfCEEIANC/////w+DIAogG358IQMgBCADQiCIfCEEIANC/////w+DIA4gF358IQMgBCADQiCIfCEEIANC/////w+DIBIgE358IQMgBCADQiCIfCEEIANC/////w+DIBYgD358IQMgBCADQiCIfCEEIANC/////w+DIBogC358IQMgBCADQiCIfCEEIANC/////w+DIAA1AhgiHiAHfnwhAyAEIANCIIh8IQQgA0L/////D4MgDSAcfnwhAyAEIANCIIh8IQQgA0L/////D4MgESAYfnwhAyAEIANCIIh8IQQgA0L/////D4MgFSAUfnwhAyAEIANCIIh8IQQgA0L/////D4MgGSAQfnwhAyAEIANCIIh8IQQgA0L/////D4MgHSAMfnwhAyAEIANCIIh8IQQgA0L/////D4NBADUCgA4iISAIfnwhAyAEIANCIIh8IQQgA0L/////D4MgBX5C/////w+DISAgA0L/////D4MgCSAgfnwhAyAEIANCIIh8IQQgBEIgiCEDIARC/////w+DIAYgATUCHCIjfnwhBCADIARCIIh8IQMgBEL/////D4MgCiAffnwhBCADIARCIIh8IQMgBEL/////D4MgDiAbfnwhBCADIARCIIh8IQMgBEL/////D4MgEiAXfnwhBCADIARCIIh8IQMgBEL/////D4MgFiATfnwhBCADIARCIIh8IQMgBEL/////D4MgGiAPfnwhBCADIARCIIh8IQMgBEL/////D4MgHiALfnwhBCADIARCIIh8IQMgBEL/////D4MgADUCHCIiIAd+fCEEIAMgBEIgiHwhAyAEQv////8PgyANICB+fCEEIAMgBEIgiHwhAyAEQv////8PgyARIBx+fCEEIAMgBEIgiHwhAyAEQv////8PgyAVIBh+fCEEIAMgBEIgiHwhAyAEQv////8PgyAZIBR+fCEEIAMgBEIgiHwhAyAEQv////8PgyAdIBB+fCEEIAMgBEIgiHwhAyAEQv////8PgyAhIAx+fCEEIAMgBEIgiHwhAyAEQv////8Pg0EANQKEDiIlIAh+fCEEIAMgBEIgiHwhAyAEQv////8PgyAFfkL/////D4MhJCAEQv////8PgyAJICR+fCEEIAMgBEIgiHwhAyADQiCIIQQgA0L/////D4MgCiAjfnwhAyAEIANCIIh8IQQgA0L/////D4MgDiAffnwhAyAEIANCIIh8IQQgA0L/////D4MgEiAbfnwhAyAEIANCIIh8IQQgA0L/////D4MgFiAXfnwhAyAEIANCIIh8IQQgA0L/////D4MgGiATfnwhAyAEIANCIIh8IQQgA0L/////D4MgHiAPfnwhAyAEIANCIIh8IQQgA0L/////D4MgIiALfnwhAyAEIANCIIh8IQQgA0L/////D4MgDSAkfnwhAyAEIANCIIh8IQQgA0L/////D4MgESAgfnwhAyAEIANCIIh8IQQgA0L/////D4MgFSAcfnwhAyAEIANCIIh8IQQgA0L/////D4MgGSAYfnwhAyAEIANCIIh8IQQgA0L/////D4MgHSAUfnwhAyAEIANCIIh8IQQgA0L/////D4MgISAQfnwhAyAEIANCIIh8IQQgA0L/////D4MgJSAMfnwhAyAEIANCIIh8IQQgAiADPgIAIARCIIghAyAEQv////8PgyAOICN+fCEEIAMgBEIgiHwhAyAEQv////8PgyASIB9+fCEEIAMgBEIgiHwhAyAEQv////8PgyAWIBt+fCEEIAMgBEIgiHwhAyAEQv////8PgyAaIBd+fCEEIAMgBEIgiHwhAyAEQv////8PgyAeIBN+fCEEIAMgBEIgiHwhAyAEQv////8PgyAiIA9+fCEEIAMgBEIgiHwhAyAEQv////8PgyARICR+fCEEIAMgBEIgiHwhAyAEQv////8PgyAVICB+fCEEIAMgBEIgiHwhAyAEQv////8PgyAZIBx+fCEEIAMgBEIgiHwhAyAEQv////8PgyAdIBh+fCEEIAMgBEIgiHwhAyAEQv////8PgyAhIBR+fCEEIAMgBEIgiHwhAyAEQv////8PgyAlIBB+fCEEIAMgBEIgiHwhAyACIAQ+AgQgA0IgiCEEIANC/////w+DIBIgI358IQMgBCADQiCIfCEEIANC/////w+DIBYgH358IQMgBCADQiCIfCEEIANC/////w+DIBogG358IQMgBCADQiCIfCEEIANC/////w+DIB4gF358IQMgBCADQiCIfCEEIANC/////w+DICIgE358IQMgBCADQiCIfCEEIANC/////w+DIBUgJH58IQMgBCADQiCIfCEEIANC/////w+DIBkgIH58IQMgBCADQiCIfCEEIANC/////w+DIB0gHH58IQMgBCADQiCIfCEEIANC/////w+DICEgGH58IQMgBCADQiCIfCEEIANC/////w+DICUgFH58IQMgBCADQiCIfCEEIAIgAz4CCCAEQiCIIQMgBEL/////D4MgFiAjfnwhBCADIARCIIh8IQMgBEL/////D4MgGiAffnwhBCADIARCIIh8IQMgBEL/////D4MgHiAbfnwhBCADIARCIIh8IQMgBEL/////D4MgIiAXfnwhBCADIARCIIh8IQMgBEL/////D4MgGSAkfnwhBCADIARCIIh8IQMgBEL/////D4MgHSAgfnwhBCADIARCIIh8IQMgBEL/////D4MgISAcfnwhBCADIARCIIh8IQMgBEL/////D4MgJSAYfnwhBCADIARCIIh8IQMgAiAEPgIMIANCIIghBCADQv////8PgyAaICN+fCEDIAQgA0IgiHwhBCADQv////8PgyAeIB9+fCEDIAQgA0IgiHwhBCADQv////8PgyAiIBt+fCEDIAQgA0IgiHwhBCADQv////8PgyAdICR+fCEDIAQgA0IgiHwhBCADQv////8PgyAhICB+fCEDIAQgA0IgiHwhBCADQv////8PgyAlIBx+fCEDIAQgA0IgiHwhBCACIAM+AhAgBEIgiCEDIARC/////w+DIB4gI358IQQgAyAEQiCIfCEDIARC/////w+DICIgH358IQQgAyAEQiCIfCEDIARC/////w+DICEgJH58IQQgAyAEQiCIfCEDIARC/////w+DICUgIH58IQQgAyAEQiCIfCEDIAIgBD4CFCADQiCIIQQgA0L/////D4MgIiAjfnwhAyAEIANCIIh8IQQgA0L/////D4MgJSAkfnwhAyAEIANCIIh8IQQgAiADPgIYIARCIIghAyACIAQ+AhwgA6cEQCACQegNIAIQBxoFIAJB6A0QBQRAIAJB6A0gAhAHGgsLC7shHQF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX4BfgF+AX5C/////w4hBkIAIQJCACEDIAJC/////w+DQgGGIQIgA0IBhiACQiCIfCEDIAJC/////w+DIAA1AgAiByAHfnwhAiADIAJCIIh8IQMgAkL/////D4MgBn5C/////w+DIQggAkL/////D4NBADUC6A0iCSAIfnwhAiADIAJCIIh8IQMgAyEEIARCIIghBUIAIQJCACEDIAJC/////w+DIAcgADUCBCIKfnwhAiADIAJCIIh8IQMgAkL/////D4NCAYYhAiADQgGGIAJCIIh8IQMgAkL/////D4MgBEL/////D4N8IQIgAyACQiCIfCAFfCEDIAJC/////w+DQQA1AuwNIgwgCH58IQIgAyACQiCIfCEDIAJC/////w+DIAZ+Qv////8PgyELIAJC/////w+DIAkgC358IQIgAyACQiCIfCEDIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyAHIAA1AggiDX58IQIgAyACQiCIfCEDIAJC/////w+DQgGGIQIgA0IBhiACQiCIfCEDIAJC/////w+DIAogCn58IQIgAyACQiCIfCEDIAJC/////w+DIARC/////w+DfCECIAMgAkIgiHwgBXwhAyACQv////8PgyAMIAt+fCECIAMgAkIgiHwhAyACQv////8Pg0EANQLwDSIPIAh+fCECIAMgAkIgiHwhAyACQv////8PgyAGfkL/////D4MhDiACQv////8PgyAJIA5+fCECIAMgAkIgiHwhAyADIQQgBEIgiCEFQgAhAkIAIQMgAkL/////D4MgByAANQIMIhB+fCECIAMgAkIgiHwhAyACQv////8PgyAKIA1+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgAkL/////D4MgDCAOfnwhAiADIAJCIIh8IQMgAkL/////D4MgDyALfnwhAiADIAJCIIh8IQMgAkL/////D4NBADUC9A0iEiAIfnwhAiADIAJCIIh8IQMgAkL/////D4MgBn5C/////w+DIREgAkL/////D4MgCSARfnwhAiADIAJCIIh8IQMgAyEEIARCIIghBUIAIQJCACEDIAJC/////w+DIAcgADUCECITfnwhAiADIAJCIIh8IQMgAkL/////D4MgCiAQfnwhAiADIAJCIIh8IQMgAkL/////D4NCAYYhAiADQgGGIAJCIIh8IQMgAkL/////D4MgDSANfnwhAiADIAJCIIh8IQMgAkL/////D4MgBEL/////D4N8IQIgAyACQiCIfCAFfCEDIAJC/////w+DIAwgEX58IQIgAyACQiCIfCEDIAJC/////w+DIA8gDn58IQIgAyACQiCIfCEDIAJC/////w+DIBIgC358IQIgAyACQiCIfCEDIAJC/////w+DQQA1AvgNIhUgCH58IQIgAyACQiCIfCEDIAJC/////w+DIAZ+Qv////8PgyEUIAJC/////w+DIAkgFH58IQIgAyACQiCIfCEDIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyAHIAA1AhQiFn58IQIgAyACQiCIfCEDIAJC/////w+DIAogE358IQIgAyACQiCIfCEDIAJC/////w+DIA0gEH58IQIgAyACQiCIfCEDIAJC/////w+DQgGGIQIgA0IBhiACQiCIfCEDIAJC/////w+DIARC/////w+DfCECIAMgAkIgiHwgBXwhAyACQv////8PgyAMIBR+fCECIAMgAkIgiHwhAyACQv////8PgyAPIBF+fCECIAMgAkIgiHwhAyACQv////8PgyASIA5+fCECIAMgAkIgiHwhAyACQv////8PgyAVIAt+fCECIAMgAkIgiHwhAyACQv////8Pg0EANQL8DSIYIAh+fCECIAMgAkIgiHwhAyACQv////8PgyAGfkL/////D4MhFyACQv////8PgyAJIBd+fCECIAMgAkIgiHwhAyADIQQgBEIgiCEFQgAhAkIAIQMgAkL/////D4MgByAANQIYIhl+fCECIAMgAkIgiHwhAyACQv////8PgyAKIBZ+fCECIAMgAkIgiHwhAyACQv////8PgyANIBN+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAQIBB+fCECIAMgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgAkL/////D4MgDCAXfnwhAiADIAJCIIh8IQMgAkL/////D4MgDyAUfnwhAiADIAJCIIh8IQMgAkL/////D4MgEiARfnwhAiADIAJCIIh8IQMgAkL/////D4MgFSAOfnwhAiADIAJCIIh8IQMgAkL/////D4MgGCALfnwhAiADIAJCIIh8IQMgAkL/////D4NBADUCgA4iGyAIfnwhAiADIAJCIIh8IQMgAkL/////D4MgBn5C/////w+DIRogAkL/////D4MgCSAafnwhAiADIAJCIIh8IQMgAyEEIARCIIghBUIAIQJCACEDIAJC/////w+DIAcgADUCHCIcfnwhAiADIAJCIIh8IQMgAkL/////D4MgCiAZfnwhAiADIAJCIIh8IQMgAkL/////D4MgDSAWfnwhAiADIAJCIIh8IQMgAkL/////D4MgECATfnwhAiADIAJCIIh8IQMgAkL/////D4NCAYYhAiADQgGGIAJCIIh8IQMgAkL/////D4MgBEL/////D4N8IQIgAyACQiCIfCAFfCEDIAJC/////w+DIAwgGn58IQIgAyACQiCIfCEDIAJC/////w+DIA8gF358IQIgAyACQiCIfCEDIAJC/////w+DIBIgFH58IQIgAyACQiCIfCEDIAJC/////w+DIBUgEX58IQIgAyACQiCIfCEDIAJC/////w+DIBggDn58IQIgAyACQiCIfCEDIAJC/////w+DIBsgC358IQIgAyACQiCIfCEDIAJC/////w+DQQA1AoQOIh4gCH58IQIgAyACQiCIfCEDIAJC/////w+DIAZ+Qv////8PgyEdIAJC/////w+DIAkgHX58IQIgAyACQiCIfCEDIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyAKIBx+fCECIAMgAkIgiHwhAyACQv////8PgyANIBl+fCECIAMgAkIgiHwhAyACQv////8PgyAQIBZ+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyATIBN+fCECIAMgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgAkL/////D4MgDCAdfnwhAiADIAJCIIh8IQMgAkL/////D4MgDyAafnwhAiADIAJCIIh8IQMgAkL/////D4MgEiAXfnwhAiADIAJCIIh8IQMgAkL/////D4MgFSAUfnwhAiADIAJCIIh8IQMgAkL/////D4MgGCARfnwhAiADIAJCIIh8IQMgAkL/////D4MgGyAOfnwhAiADIAJCIIh8IQMgAkL/////D4MgHiALfnwhAiADIAJCIIh8IQMgASACPgIAIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyANIBx+fCECIAMgAkIgiHwhAyACQv////8PgyAQIBl+fCECIAMgAkIgiHwhAyACQv////8PgyATIBZ+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgAkL/////D4MgDyAdfnwhAiADIAJCIIh8IQMgAkL/////D4MgEiAafnwhAiADIAJCIIh8IQMgAkL/////D4MgFSAXfnwhAiADIAJCIIh8IQMgAkL/////D4MgGCAUfnwhAiADIAJCIIh8IQMgAkL/////D4MgGyARfnwhAiADIAJCIIh8IQMgAkL/////D4MgHiAOfnwhAiADIAJCIIh8IQMgASACPgIEIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyAQIBx+fCECIAMgAkIgiHwhAyACQv////8PgyATIBl+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAWIBZ+fCECIAMgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgAkL/////D4MgEiAdfnwhAiADIAJCIIh8IQMgAkL/////D4MgFSAafnwhAiADIAJCIIh8IQMgAkL/////D4MgGCAXfnwhAiADIAJCIIh8IQMgAkL/////D4MgGyAUfnwhAiADIAJCIIh8IQMgAkL/////D4MgHiARfnwhAiADIAJCIIh8IQMgASACPgIIIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyATIBx+fCECIAMgAkIgiHwhAyACQv////8PgyAWIBl+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgAkL/////D4MgFSAdfnwhAiADIAJCIIh8IQMgAkL/////D4MgGCAafnwhAiADIAJCIIh8IQMgAkL/////D4MgGyAXfnwhAiADIAJCIIh8IQMgAkL/////D4MgHiAUfnwhAiADIAJCIIh8IQMgASACPgIMIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyAWIBx+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAZIBl+fCECIAMgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgAkL/////D4MgGCAdfnwhAiADIAJCIIh8IQMgAkL/////D4MgGyAafnwhAiADIAJCIIh8IQMgAkL/////D4MgHiAXfnwhAiADIAJCIIh8IQMgASACPgIQIAMhBCAEQiCIIQVCACECQgAhAyACQv////8PgyAZIBx+fCECIAMgAkIgiHwhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgAkL/////D4MgGyAdfnwhAiADIAJCIIh8IQMgAkL/////D4MgHiAafnwhAiADIAJCIIh8IQMgASACPgIUIAMhBCAEQiCIIQVCACECQgAhAyACQv////8Pg0IBhiECIANCAYYgAkIgiHwhAyACQv////8PgyAcIBx+fCECIAMgAkIgiHwhAyACQv////8PgyAEQv////8Pg3whAiADIAJCIIh8IAV8IQMgAkL/////D4MgHiAdfnwhAiADIAJCIIh8IQMgASACPgIYIAMhBCAEQiCIIQUgASAEPgIcIAWnBEAgAUHoDSABEAcaBSABQegNEAUEQCABQegNIAEQBxoLCwsKACAAIAAgARAuCwsAIABBiA4gARAuCxUAIABBiBQQAEGoFBABQYgUIAEQLQsRACAAQcgUEDJByBRBiA8QBQskACAAEAIEQEEADwsgAEHoFBAyQegUQYgPEAUEQEF/DwtBAQ8LFwAgACABEDIgAUHoDSABEA4gASABEDELCQBBqA4gABAAC8sBBAF/AX8BfwF/IAIQAUEgIQUgACEDAkADQCAFIAFLDQEgBUEgRgRAQYgVEDYFQYgVQYgOQYgVEC4LIANBiBVBqBUQLiACQagVIAIQKiADQSBqIQMgBUEgaiEFDAALCyABQSBwIQQgBEUEQA8LQagVEAFBACEGAkADQCAGIARGDQEgBiADLQAAOgCoFSADQQFqIQMgBkEBaiEGDAALCyAFQSBGBEBBiBUQNgVBiBVBiA5BiBUQLgtBqBVBiBVBqBUQLiACQagVIAIQKgscACABIAJByBUQN0HIFUHIFRAxIABByBUgAxAuC/gBBAF/AX8BfwF/QQAoAgAhBUEAIAUgAkEBakEgbGo2AgAgBRA2IAAhBiAFQSBqIQVBACEIAkADQCAIIAJGDQEgBhACBEAgBUEgayAFEAAFIAYgBUEgayAFEC4LIAYgAWohBiAFQSBqIQUgCEEBaiEIDAALCyAGIAFrIQYgBUEgayEFIAMgAkEBayAEbGohByAFIAUQNQJAA0AgCEUNASAGEAIEQCAFIAVBIGsQACAHEAEFIAVBIGtB6BUQACAFIAYgBUEgaxAuIAVB6BUgBxAuCyAGIAFrIQYgByAEayEHIAVBIGshBSAIQQFrIQgMAAsLQQAgBTYCAAs+AwF/AX8BfyAAIQQgAiEFQQAhAwJAA0AgAyABRg0BIAQgBRAxIARBIGohBCAFQSBqIQUgA0EBaiEDDAALCws+AwF/AX8BfyAAIQQgAiEFQQAhAwJAA0AgAyABRg0BIAQgBRAyIARBIGohBCAFQSBqIQUgA0EBaiEDDAALCws+AwF/AX8BfyAAIQQgAiEFQQAhAwJAA0AgAyABRg0BIAQgBRAsIARBIGohBCAFQSBqIQUgA0EBaiEDDAALCwtNBAF/AX8BfwF/IAAhBSABIQYgAyEHQQAhBAJAA0AgBCACRg0BIAUgBiAHECogBUEgaiEFIAZBIGohBiAHQSBqIQcgBEEBaiEEDAALCwtNBAF/AX8BfwF/IAAhBSABIQYgAyEHQQAhBAJAA0AgBCACRg0BIAUgBiAHECsgBUEgaiEFIAZBIGohBiAHQSBqIQcgBEEBaiEEDAALCwtNBAF/AX8BfwF/IAAhBSABIQYgAyEHQQAhBAJAA0AgBCACRg0BIAUgBiAHEC4gBUEgaiEFIAZBIGohBiAHQSBqIQcgBEEBaiEEDAALCwuyAgIBfwF/IAJFBEAgAxA2DwsgAEGIFhAAIAMQNiACIQQCQANAIARBAWshBCABIARqLQAAIQUgAyADEC8gBUGAAU8EQCAFQYABayEFIANBiBYgAxAuCyADIAMQLyAFQcAATwRAIAVBwABrIQUgA0GIFiADEC4LIAMgAxAvIAVBIE8EQCAFQSBrIQUgA0GIFiADEC4LIAMgAxAvIAVBEE8EQCAFQRBrIQUgA0GIFiADEC4LIAMgAxAvIAVBCE8EQCAFQQhrIQUgA0GIFiADEC4LIAMgAxAvIAVBBE8EQCAFQQRrIQUgA0GIFiADEC4LIAMgAxAvIAVBAk8EQCAFQQJrIQUgA0GIFiADEC4LIAMgAxAvIAVBAU8EQCAFQQFrIQUgA0GIFiADEC4LIARFDQEMAAsLC94BAwF/AX8BfyAAEAIEQCABEAEPC0EcIQJByA9BqBYQACAAQagPQSBByBYQQCAAQegPQSBB6BYQQAJAA0BByBZBqA4QBA0BQcgWQYgXEC9BASEDAkADQEGIF0GoDhAEDQFBiBdBiBcQLyADQQFqIQMMAAsLQagWQagXEAAgAiADa0EBayEEAkADQCAERQ0BQagXQagXEC8gBEEBayEEDAALCyADIQJBqBdBqBYQL0HIFkGoFkHIFhAuQegWQagXQegWEC4MAAsLQegWEDMEQEHoFiABECwFQegWIAEQAAsLIAAgABACBEBBAQ8LIABB6A5BIEHIFxBAQcgXQagOEAQLFQAgACABQegXEC5B6BdBiA4gAhAuCwoAIAAgACABEEMLCwAgAEHoDSABEA4LCQAgAEGIDxAFCw4AIAAQAiAAQSBqEAJxCwoAIABBwABqEAILDQAgABABIABBIGoQAQsVACAAEAEgAEEgahAcIABBwABqEAELUgAgASAAKQMANwMAIAEgACkDCDcDCCABIAApAxA3AxAgASAAKQMYNwMYIAEgACkDIDcDICABIAApAyg3AyggASAAKQMwNwMwIAEgACkDODcDOAt6ACABIAApAwA3AwAgASAAKQMINwMIIAEgACkDEDcDECABIAApAxg3AxggASAAKQMgNwMgIAEgACkDKDcDKCABIAApAzA3AzAgASAAKQM4NwM4IAEgACkDQDcDQCABIAApA0g3A0ggASAAKQNQNwNQIAEgACkDWDcDWAsoACAAEEcEQCABEEoFIAFBwABqEBwgAEEgaiABQSBqEAAgACABEAALCxgBAX8gACABEAQgAEEgaiABQSBqEARxDwt1AQF/IABBwABqIQIgABBIBEAgARBHDwsgARBHBEBBAA8LIAIQDwRAIAAgARBODwsgAkGoGBAVIAFBqBhByBgQFCACQagYQegYEBQgAUEgakHoGEGIGRAUIABByBgQBARAIABBIGpBiBkQBARAQQEPCwtBAA8LtAECAX8BfyAAQcAAaiECIAFBwABqIQMgABBIBEAgARBIDwsgARBIBEBBAA8LIAIQDwRAIAEgABBPDwsgAxAPBEAgACABEE8PCyACQagZEBUgA0HIGRAVIABByBlB6BkQFCABQagZQYgaEBQgAkGoGUGoGhAUIANByBlByBoQFCAAQSBqQcgaQegaEBQgAUEgakGoGkGIGxAUQegZQYgaEAQEQEHoGkGIGxAEBEBBAQ8LC0EADwvoAQAgABBHBEAgACABEE0PCyAAQagbEBUgAEEgakHIGxAVQcgbQegbEBUgAEHIG0GIHBAQQYgcQYgcEBVBiBxBqBtBiBwQEUGIHEHoG0GIHBARQYgcQYgcQYgcEBBBqBtBqBtBqBwQEEGoHEGoG0GoHBAQIABBIGogAEEgaiABQcAAahAQQagcIAEQFSABQYgcIAEQESABQYgcIAEQEUHoG0HoG0HIHBAQQcgcQcgcQcgcEBBByBxByBxByBwQEEGIHCABIAFBIGoQESABQSBqQagcIAFBIGoQFCABQSBqQcgcIAFBIGoQEQuJAgAgABBIBEAgACABEEwPCyAAQcAAahAPBEAgACABEFEPDwsgAEHoHBAVIABBIGpBiB0QFUGIHUGoHRAVIABBiB1ByB0QEEHIHUHIHRAVQcgdQegcQcgdEBFByB1BqB1ByB0QEUHIHUHIHUHIHRAQQegcQegcQegdEBBB6B1B6BxB6B0QEEHoHUGIHhAVIABBIGogAEHAAGpBqB4QFEHIHUHIHSABEBBBiB4gASABEBFBqB1BqB1ByB4QEEHIHkHIHkHIHhAQQcgeQcgeQcgeEBBByB0gASABQSBqEBEgAUEgakHoHSABQSBqEBQgAUEgakHIHiABQSBqEBFBqB5BqB4gAUHAAGoQEAujAgEBfyAAQcAAaiEDIAAQRwRAIAEgAhBLIAJBwABqEBwPCyABEEcEQCAAIAIQSyACQcAAahAcDwsgACABEAQEQCAAQSBqIAFBIGoQBARAIAEgAhBRDwsLIAEgAEHoHhARIAFBIGogAEEgakGoHxARQegeQYgfEBVBiB9BiB9ByB8QEEHIH0HIH0HIHxAQQegeQcgfQegfEBRBqB9BqB9BiCAQECAAQcgfQcggEBRBiCBBqCAQFUHIIEHIIEHoIBAQQaggQegfIAIQESACQeggIAIQESAAQSBqQegfQYghEBRBiCFBiCFBiCEQEEHIICACIAJBIGoQESACQSBqQYggIAJBIGoQFCACQSBqQYghIAJBIGoQEUHoHkHoHiACQcAAahAQC4ADAQF/IABBwABqIQMgABBIBEAgASACEEsgAkHAAGoQHA8LIAEQRwRAIAAgAhBMDwsgAxAPBEAgACABIAIQUw8LIANBqCEQFSABQaghQcghEBQgA0GoIUHoIRAUIAFBIGpB6CFBiCIQFCAAQcghEAQEQCAAQSBqQYgiEAQEQCABIAIQUQ8LC0HIISAAQagiEBFBiCIgAEEgakHoIhARQagiQcgiEBVByCJByCJBiCMQEEGII0GII0GIIxAQQagiQYgjQagjEBRB6CJB6CJByCMQECAAQYgjQYgkEBRByCNB6CMQFUGIJEGIJEGoJBAQQegjQagjIAIQESACQagkIAIQESAAQSBqQagjQcgkEBRByCRByCRByCQQEEGIJCACIAJBIGoQESACQSBqQcgjIAJBIGoQFCACQSBqQcgkIAJBIGoQESADQagiIAJBwABqEBAgAkHAAGogAkHAAGoQFSACQcAAakGoISACQcAAahARIAJBwABqQcgiIAJBwABqEBELvAMCAX8BfyAAQcAAaiEDIAFBwABqIQQgABBIBEAgASACEEwPCyABEEgEQCAAIAIQTA8LIAMQDwRAIAEgACACEFQPCyAEEA8EQCAAIAEgAhBUDwsgA0HoJBAVIARBiCUQFSAAQYglQaglEBQgAUHoJEHIJRAUIANB6CRB6CUQFCAEQYglQYgmEBQgAEEgakGIJkGoJhAUIAFBIGpB6CVByCYQFEGoJUHIJRAEBEBBqCZByCYQBARAIAAgAhBSDwsLQcglQaglQegmEBFByCZBqCZBiCcQEUHoJkHoJkGoJxAQQagnQagnEBVB6CZBqCdByCcQFEGIJ0GIJ0HoJxAQQaglQagnQagoEBRB6CdBiCgQFUGoKEGoKEHIKBAQQYgoQcgnIAIQESACQcgoIAIQEUGoJkHIJ0HoKBAUQegoQegoQegoEBBBqCggAiACQSBqEBEgAkEgakHoJyACQSBqEBQgAkEgakHoKCACQSBqEBEgAyAEIAJBwABqEBAgAkHAAGogAkHAAGoQFSACQcAAakHoJCACQcAAahARIAJBwABqQYglIAJBwABqEBEgAkHAAGpB6CYgAkHAAGoQFAsUACAAIAEQACAAQSBqIAFBIGoQEgsiACAAIAEQACAAQSBqIAFBIGoQEiAAQcAAaiABQcAAahAACxIAIAFBiCkQViAAQYgpIAIQUwsSACABQegpEFYgAEHoKSACEFQLEgAgAUHIKhBXIABByCogAhBVCxQAIAAgARAYIABBIGogAUEgahAYCyIAIAAgARAYIABBIGogAUEgahAYIABBwABqIAFBwABqEBgLFAAgACABEBcgAEEgaiABQSBqEBcLIgAgACABEBcgAEEgaiABQSBqEBcgAEHAAGogAUHAAGoQFwtLACAAEEgEQCABEAEgAUEgahABBSAAQcAAakGoKxAbQagrQcgrEBVBqCtByCtB6CsQFCAAQcgrIAEQFCAAQSBqQegrIAFBIGoQFAsLMQAgAEEgakGILBAVIABBqCwQFSAAQagsQagsEBRBqCxBiBhBqCwQEEGILEGoLBAEDwsPACAAQcgsEF9ByCwQYA8LrgEFAX8BfwF/AX8Bf0EAKAIAIQNBACADIAFBIGxqNgIAIABBwABqQeAAIAEgA0EgEB8gACEEIAMhBSACIQZBACEHAkADQCAHIAFGDQEgBRACBEAgBhABIAZBIGoQAQUgBSAEQSBqQYgtEBQgBSAFEBUgBSAEIAYQFCAFQYgtIAZBIGoQFAsgBEHgAGohBCAGQcAAaiEGIAVBIGohBSAHQQFqIQcMAAsLQQAgAzYCAAtMACAAEEgEQCABEEoFIABBwABqQagtEBtBqC1ByC0QFUGoLUHILUHoLRAUIABByC0gARAUIABBIGpB6C0gAUEgahAUIAFBwABqEBwLCzsCAX8BfyACIAFqQQFrIQMgACEEAkADQCADIAJIDQEgAyAELQAAOgAAIANBAWshAyAEQQFqIQQMAAsLCyoAIAAQRwRAIAEQSQ8LIABBiC4QW0GILkEgIAEQZEGoLkEgIAFBIGoQZAtBACAAEEcEQCABEAEgAUHAADoAAA8LIABByC4QGEHILkEgIAEQZCAAQSBqEBpBf0YEQCABIAEtAABBgAFyOgAACwsvACAALQAAQcAAcQRAIAEQSQ8LIABBIEHoLhBkIABBIGpBIEGILxBkQeguIAEQXQuyAQIBfwF/IAAtAAAhAiACQcAAcQRAIAEQSQ8LIAJBgAFxIQMgAEHILxAAQcgvIAJBP3E6AABByC9BIEGoLxBkQagvIAEQFyABQcgvEBUgAUHIL0HILxAUQcgvQYgYQcgvEBBByC9ByC8QJ0HIL0GoLxASQcgvEBpBf0YEQCADBEBByC8gAUEgahAABUHILyABQSBqEBILBSADBEBByC8gAUEgahASBUHILyABQSBqEAALCwtAAwF/AX8BfyAAIQQgAiEFQQAhAwJAA0AgAyABRg0BIAQgBRBlIARBwABqIQQgBUHAAGohBSADQQFqIQMMAAsLCz8DAX8BfwF/IAAhBCACIQVBACEDAkADQCADIAFGDQEgBCAFEGYgBEHAAGohBCAFQSBqIQUgA0EBaiEDDAALCwtAAwF/AX8BfyAAIQQgAiEFQQAhAwJAA0AgAyABRg0BIAQgBRBnIARBwABqIQQgBUHAAGohBSADQQFqIQMMAAsLC1IDAX8BfwF/IAAgAUEBa0EgbGohBCACIAFBAWtBwABsaiEFQQAhAwJAA0AgAyABRg0BIAQgBRBoIARBIGshBCAFQcAAayEFIANBAWohAwwACwsLVAMBfwF/AX8gACABQQFrQcAAbGohBCACIAFBAWtB4ABsaiEFQQAhAwJAA0AgAyABRg0BIAQgBRBNIARBwABrIQQgBUHgAGshBSADQQFqIQMMAAsLC0ECAX8BfyABQQhsIAJrIQQgAyAESgRAQQEgBHRBAWshBQVBASADdEEBayEFCyAAIAJBA3ZqKAAAIAJBB3F2IAVxC5UBBAF/AX8BfwF/IAFBAUYEQA8LQQEgAUEBa3QhAiAAIQMgACACQeAAbGohBCAEQeAAayEFAkADQCADIAVGDQEgAyAEIAMQVSAFIAQgBRBVIANB4ABqIQMgBEHgAGohBAwACwsgACABQQFrEG8gAUEBayEBAkADQCABRQ0BIAUgBRBSIAFBAWshAQwACwsgACAFIAAQVQvMAQoBfwF/AX8BfwF/AX8BfwF/AX8BfyADRQRAIAYQSg8LQQEgBXQhDUEAKAIAIQ5BACAOIA1B4ABsajYCAEEAIQwCQANAIAwgDUYNASAOIAxB4ABsahBKIAxBAWohDAwACwsgACEKIAEhCCABIAMgAmxqIQkCQANAIAggCUYNASAIIAIgBCAFEG4hDyAPBEAgDiAPQQFrQeAAbGohECAQIAogEBBVCyAIIAJqIQggCkHgAGohCgwACwsgDiAFEG8gDiAGEExBACAONgIAC6ABDAF/AX8BfwF/AX8BfwF/AX8BfwF/AX8BfyAEEEogA0UEQA8LIANnLQDIMCEFIAJBA3RBAWsgBW5BAWohBiAGQQFrIAVsIQoCQANAIApBAEgNASAEEEhFBEBBACEMAkADQCAMIAVGDQEgBCAEEFIgDEEBaiEMDAALCwsgACABIAIgAyAKIAVB6C8QcCAEQegvIAQQVSAKIAVrIQoMAAsLC0ECAX8BfyABQQhsIAJrIQQgAyAESgRAQQEgBHRBAWshBQVBASADdEEBayEFCyAAIAJBA3ZqKAAAIAJBB3F2IAVxC5UBBAF/AX8BfwF/IAFBAUYEQA8LQQEgAUEBa3QhAiAAIQMgACACQeAAbGohBCAEQeAAayEFAkADQCADIAVGDQEgAyAEIAMQVSAFIAQgBRBVIANB4ABqIQMgBEHgAGohBAwACwsgACABQQFrEHMgAUEBayEBAkADQCABRQ0BIAUgBRBSIAFBAWshAQwACwsgACAFIAAQVQvMAQoBfwF/AX8BfwF/AX8BfwF/AX8BfyADRQRAIAYQSg8LQQEgBXQhDUEAKAIAIQ5BACAOIA1B4ABsajYCAEEAIQwCQANAIAwgDUYNASAOIAxB4ABsahBKIAxBAWohDAwACwsgACEKIAEhCCABIAMgAmxqIQkCQANAIAggCUYNASAIIAIgBCAFEHIhDyAPBEAgDiAPQQFrQeAAbGohECAQIAogEBBUCyAIIAJqIQggCkHAAGohCgwACwsgDiAFEHMgDiAGEExBACAONgIAC6ABDAF/AX8BfwF/AX8BfwF/AX8BfwF/AX8BfyAEEEogA0UEQA8LIANnLQDIMSEFIAJBA3RBAWsgBW5BAWohBiAGQQFrIAVsIQoCQANAIApBAEgNASAEEEhFBEBBACEMAkADQCAMIAVGDQEgBCAEEFIgDEEBaiEMDAALCwsgACABIAIgAyAKIAVB6DAQdCAEQegwIAQQVSAKIAVrIQoMAAsLC6sEBwF/AX8BfwF/AX8BfwF/IAJFBEAgAxBKDwsgAkEDdCEFQQAoAgAhBCAEIQpBACAEQSBqIAVqQXhxNgIAQQEhBiABQQBBA3ZBfHFqKAIAQQBBH3F2QQFxIQdBACEJAkADQCAGIAVGDQEgASAGQQN2QXxxaigCACAGQR9xdkEBcSEIIAcEQCAIBEAgCQRAQQAhB0EBIQkgCkEBOgAAIApBAWohCgVBACEHQQEhCSAKQf8BOgAAIApBAWohCgsFIAkEQEEAIQdBASEJIApB/wE6AAAgCkEBaiEKBUEAIQdBACEJIApBAToAACAKQQFqIQoLCwUgCARAIAkEQEEAIQdBASEJIApBADoAACAKQQFqIQoFQQEhB0EAIQkgCkEAOgAAIApBAWohCgsFIAkEQEEBIQdBACEJIApBADoAACAKQQFqIQoFQQAhB0EAIQkgCkEAOgAAIApBAWohCgsLCyAGQQFqIQYMAAsLIAcEQCAJBEAgCkH/AToAACAKQQFqIQogCkEAOgAAIApBAWohCiAKQQE6AAAgCkEBaiEKBSAKQQE6AAAgCkEBaiEKCwUgCQRAIApBADoAACAKQQFqIQogCkEBOgAAIApBAWohCgsLIApBAWshCiAAQegxEEwgAxBKAkADQCADIAMQUiAKLQAAIQggCARAIAhBAUYEQCADQegxIAMQVQUgA0HoMSADEFoLCyAEIApGDQEgCkEBayEKDAALC0EAIAQ2AgALqwQHAX8BfwF/AX8BfwF/AX8gAkUEQCADEEoPCyACQQN0IQVBACgCACEEIAQhCkEAIARBIGogBWpBeHE2AgBBASEGIAFBAEEDdkF8cWooAgBBAEEfcXZBAXEhB0EAIQkCQANAIAYgBUYNASABIAZBA3ZBfHFqKAIAIAZBH3F2QQFxIQggBwRAIAgEQCAJBEBBACEHQQEhCSAKQQE6AAAgCkEBaiEKBUEAIQdBASEJIApB/wE6AAAgCkEBaiEKCwUgCQRAQQAhB0EBIQkgCkH/AToAACAKQQFqIQoFQQAhB0EAIQkgCkEBOgAAIApBAWohCgsLBSAIBEAgCQRAQQAhB0EBIQkgCkEAOgAAIApBAWohCgVBASEHQQAhCSAKQQA6AAAgCkEBaiEKCwUgCQRAQQEhB0EAIQkgCkEAOgAAIApBAWohCgVBACEHQQAhCSAKQQA6AAAgCkEBaiEKCwsLIAZBAWohBgwACwsgBwRAIAkEQCAKQf8BOgAAIApBAWohCiAKQQA6AAAgCkEBaiEKIApBAToAACAKQQFqIQoFIApBAToAACAKQQFqIQoLBSAJBEAgCkEAOgAAIApBAWohCiAKQQE6AAAgCkEBaiEKCwsgCkEBayEKIABByDIQSyADEEoCQANAIAMgAxBSIAotAAAhCCAIBEAgCEEBRgRAIANByDIgAxBUBSADQcgyIAMQWQsLIAQgCkYNASAKQQFrIQoMAAsLQQAgBDYCAAtCACAAQf8BcS0AiFBBGHQgAEEIdkH/AXEtAIhQQRB0aiAAQRB2Qf8BcS0AiFBBCHQgAEEYdkH/AXEtAIhQamogAXcLZwUBfwF/AX8BfwF/QQEgAXQhAkEAIQMCQANAIAMgAkYNASAAIANBIGxqIQUgAyABEHghBCAAIARBIGxqIQYgAyAESQRAIAVBiNIAEAAgBiAFEABBiNIAIAYQAAsgA0EBaiEDDAALCwvaAQcBfwF/AX8BfwF/AX8BfyACRSADEClxBEAPC0EBIAF0IQQgBEEBayEIQQEhByAEQQF2IQUCQANAIAcgBU8NASAAIAdBIGxqIQkgACAEIAdrQSBsaiEKIAIEQCADECkEQCAJQajSABAAIAogCRAAQajSACAKEAAFIAlBqNIAEAAgCiADIAkQLkGo0gAgAyAKEC4LBSADECkEQAUgCSADIAkQLiAKIAMgChAuCwsgB0EBaiEHDAALCyADECkEQAUgACADIAAQLiAAIAVBIGxqIQogCiADIAoQLgsL5wEJAX8BfwF/AX8BfwF/AX8BfwF/IAAgARB5QQEgAXQhCUEBIQQCQANAIAQgAUsNAUEBIAR0IQdBiDMgBEEgbGohCkEAIQUCQANAIAUgCU8NAUHI0gAQNiAHQQF2IQhBACEGAkADQCAGIAhPDQEgACAFIAZqQSBsaiELIAsgCEEgbGohDCAMQcjSAEHo0gAQLiALQYjTABAAQYjTAEHo0gAgCxAqQYjTAEHo0gAgDBArQcjSACAKQcjSABAuIAZBAWohBgwACwsgBSAHaiEFDAALCyAEQQFqIQQMAAsLIAAgASACIAMQegtDAgF/AX8gAEEBdiECQQAhAQJAA0AgAkUNASACQQF2IQIgAUEBaiEBDAALCyAAQQEgAXRHBEAACyABQRxLBEAACyABCxwBAX8gARB8IQJBqNMAEDYgACACQQBBqNMAEHsLIQIBfwF/IAEQfCECQag6IAJBIGxqIQMgACACQQEgAxB7C3YDAX8BfwF/IANByNMAEABBACEHAkADQCAHIAJGDQEgACAHQSBsaiEFIAEgB0EgbGohBiAGQcjTAEHo0wAQLiAFQYjUABAAQYjUAEHo0wAgBRAqQYjUAEHo0wAgBhArQcjTACAEQcjTABAuIAdBAWohBwwACwsLhAEEAX8BfwF/AX9ByMEAIAVBIGxqIQkgA0Go1AAQAEEAIQgCQANAIAggAkYNASAAIAhBIGxqIQYgASAIQSBsaiEHIAYgB0HI1AAQKiAHIAkgBxAuIAYgByAHECogB0Go1AAgBxAuQcjUACAGEABBqNQAIARBqNQAEC4gCEEBaiEIDAALCwueAQUBfwF/AX8BfwF/QcjBACAFQSBsaiEJQejIACAFQSBsaiEKIANB6NQAEABBACEIAkADQCAIIAJGDQEgACAIQSBsaiEGIAEgCEEgbGohByAHQejUAEGI1QAQLiAGQYjVACAHECsgByAKIAcQLiAGIAkgBhAuQYjVACAGIAYQKyAGIAogBhAuQejUACAEQejUABAuIAhBAWohCAwACwsLxAEJAX8BfwF/AX8BfwF/AX8BfwF/QQEgAnQhBCAEQQF2IQUgASACdiEDIAVBIGwhBkGIMyACQSBsaiELQQAhCQJAA0AgCSADRg0BQajVABA2QQAhCgJAA0AgCiAFRg0BIAAgCSAEbCAKakEgbGohByAHIAZqIQggCEGo1QBByNUAEC4gB0Ho1QAQAEHo1QBByNUAIAcQKkHo1QBByNUAIAgQK0Go1QAgC0Go1QAQLiAKQQFqIQoMAAsLIAlBAWohCQwACwsLewQBfwF/AX8BfyABQQF2IQYgAUEBcQRAIAAgBkEgbGogAiAAIAZBIGxqEC4LQQAhBQJAA0AgBSAGTw0BIAAgBUEgbGohAyAAIAFBAWsgBWtBIGxqIQQgBCACQYjWABAuIAMgAiAEEC5BiNYAIAMQACAFQQFqIQUMAAsLC5gBBQF/AX8BfwF/AX9ByMEAIAVBIGxqIQlB6MgAIAVBIGxqIQogA0Go1gAQAEEAIQgCQANAIAggAkYNASAAIAhBIGxqIQYgASAIQSBsaiEHIAYgCUHI1gAQLiAHQcjWAEHI1gAQKyAGIAcgBxArQcjWACAKIAYQLiAHQajWACAHEC5BqNYAIARBqNYAEC4gCEEBaiEIDAALCwsuAgF/AX8gACEDIAAgAUEgbGohAgJAA0AgAyACRg0BIAMQASADQSBqIQMMAAsLC44BBgF/AX8BfwF/AX8Bf0EAIQQgACEGIAEhBwJAA0AgBCACRg0BIAYoAgAhCSAGQQRqIQZBACEFAkADQCAFIAlGDQEgAyAGKAIAQSBsaiEIIAZBBGohBiAHIAZB6NYAEC5B6NYAIAggCBAqIAZBIGohBiAFQQFqIQUMAAsLIAdBIGohByAEQQFqIQQMAAsLC8gCCAF/AX8BfwF/AX8BfwF/AX8gAyELIAQhDCADIAdBIGxqIQ0CQANAIAsgDUYNASALEAEgDBABIAtBIGohCyAMQSBqIQwMAAsLIAAhCiAAIAFBLGxqIQ0CQANAIAogDUYNASAKKAIIIRAgECAISSAQIAggCWpPcgRAIApBLGohCgwBCyAKKAIAIQ4gDkEARgRAIAMhEQUgDkEBRgRAIAQhEQUgCkEsaiEKDAELCyAKKAIEIQ8gDyAGSSAPIAYgB2pPcgRAIApBLGohCgwBCyARIA8gBmtBIGxqIREgAiAQIAhrQSBsaiAKQQxqQYjXABAuIBFBiNcAIBEQKiAKQSxqIQoMAAsLIAMhCyAEIQwgBSEKIAMgB0EgbGohDQJAA0AgCyANRg0BIAsgDCAKEC4gC0EgaiELIAxBIGohDCAKQSBqIQoMAAsLC2UFAX8BfwF/AX8BfyAAIQUgASEGIAIhByAEIQggACADQSBsaiEJAkADQCAFIAlGDQEgBSAGQajXABAuQajXACAHIAgQKyAFQSBqIQUgBkEgaiEGIAdBIGohByAIQSBqIQgMAAsLC0wEAX8BfwF/AX8gACEEIAEhBSADIQYgACACQSBsaiEHAkADQCAEIAdGDQEgBCAFIAYQKiAEQSBqIQQgBUEgaiEFIAZBIGohBgwACwsLDgAgABACIABBIGoQAnELDwAgABAPIABBIGoQAnEPCw0AIAAQASAAQSBqEAELDQAgABAcIABBIGoQAQsUACAAIAEQACAAQSBqIAFBIGoQAAt1ACAAIAFByNcAEBQgAEEgaiABQSBqQejXABAUIAAgAEEgakGI2AAQECABIAFBIGpBqNgAEBBBiNgAQajYAEGI2AAQFEHo1wAgAhASQcjXACACIAIQEEHI1wBB6NcAIAJBIGoQEEGI2AAgAkEgaiACQSBqEBELGAAgACABIAIQFCAAQSBqIAEgAkEgahAUC3AAIAAgAEEgakHI2AAQFCAAIABBIGpB6NgAEBAgAEEgakGI2QAQEiAAQYjZAEGI2QAQEEHI2ABBqNkAEBJBqNkAQcjYAEGo2QAQEEHo2ABBiNkAIAEQFCABQajZACABEBFByNgAQcjYACABQSBqEBALGwAgACABIAIQECAAQSBqIAFBIGogAkEgahAQCxsAIAAgASACEBEgAEEgaiABQSBqIAJBIGoQEQsUACAAIAEQEiAAQSBqIAFBIGoQEgsUACAAIAEQACAAQSBqIAFBIGoQEgsUACAAIAEQFyAAQSBqIAFBIGoQFwsUACAAIAEQGCAAQSBqIAFBIGoQGAsVACAAIAEQBCAAQSBqIAFBIGoQBHELXQAgAEHI2QAQFSAAQSBqQejZABAVQejZAEGI2gAQEkHI2QBBiNoAQYjaABARQYjaAEGo2gAQGyAAQajaACABEBQgAEEgakGo2gAgAUEgahAUIAFBIGogAUEgahASCxwAIAAgASACIAMQHiAAQSBqIAEgAiADQSBqEB4LGgEBfyAAQSBqEBohASABBEAgAQ8LIAAQGg8LGQAgAEEgahACBEAgABAZDwsgAEEgahAZDwuPAgQBfwF/AX8Bf0EAKAIAIQVBACAFIAJBAWpBwABsajYCACAFEI0BIAAhBiAFQcAAaiEFQQAhCAJAA0AgCCACRg0BIAYQigEEQCAFQcAAayAFEI4BBSAGIAVBwABrIAUQjwELIAYgAWohBiAFQcAAaiEFIAhBAWohCAwACwsgBiABayEGIAVBwABrIQUgAyACQQFrIARsaiEHIAUgBRCZAQJAA0AgCEUNASAGEIoBBEAgBSAFQcAAaxCOASAHEIwBBSAFQcAAa0HI2gAQjgEgBSAGIAVBwABrEI8BIAVByNoAIAcQjwELIAYgAWshBiAHIARrIQcgBUHAAGshBSAIQQFrIQgMAAsLQQAgBTYCAAvOAgIBfwF/IAJFBEAgAxCNAQ8LIABBiNsAEI4BIAMQjQEgAiEEAkADQCAEQQFrIQQgASAEai0AACEFIAMgAxCRASAFQYABTwRAIAVBgAFrIQUgA0GI2wAgAxCPAQsgAyADEJEBIAVBwABPBEAgBUHAAGshBSADQYjbACADEI8BCyADIAMQkQEgBUEgTwRAIAVBIGshBSADQYjbACADEI8BCyADIAMQkQEgBUEQTwRAIAVBEGshBSADQYjbACADEI8BCyADIAMQkQEgBUEITwRAIAVBCGshBSADQYjbACADEI8BCyADIAMQkQEgBUEETwRAIAVBBGshBSADQYjbACADEI8BCyADIAMQkQEgBUECTwRAIAVBAmshBSADQYjbACADEI8BCyADIAMQkQEgBUEBTwRAIAVBAWshBSADQYjbACADEI8BCyAERQ0BDAALCwvNAQBByN0AEI0BQcjdAEHI3QAQlAEgAEHI2wBBIEGI3AAQngFBiNwAQcjcABCRASAAQcjcAEHI3AAQjwFByNwAQYjdABCVAUGI3QBByNwAQYjdABCPAUGI3QBByN0AEJgBBEAAC0GI3AAgAEGI3gAQjwFByNwAQcjdABCYAQRAQcjdABABQejdABAcQcjdAEGI3gAgARCPAQVByN4AEI0BQcjeAEHI3ABByN4AEJIBQcjeAEHo2wBBIEHI3gAQngFByN4AQYjeACABEI8BCwtpAEHo4AAQjQFB6OAAQejgABCUASAAQYjfAEEgQajfABCeAUGo3wBB6N8AEJEBIABB6N8AQejfABCPAUHo3wBBqOAAEJUBQajgAEHo3wBBqOAAEI8BQajgAEHo4AAQmAEEQEEADwtBAQ8LEQAgABCKASAAQcAAahCKAXELCwAgAEGAAWoQigELEAAgABCMASAAQcAAahCMAQsZACAAEIwBIABBwABqEI0BIABBgAFqEIwBC6IBACABIAApAwA3AwAgASAAKQMINwMIIAEgACkDEDcDECABIAApAxg3AxggASAAKQMgNwMgIAEgACkDKDcDKCABIAApAzA3AzAgASAAKQM4NwM4IAEgACkDQDcDQCABIAApA0g3A0ggASAAKQNQNwNQIAEgACkDWDcDWCABIAApA2A3A2AgASAAKQNoNwNoIAEgACkDcDcDcCABIAApA3g3A3gLggIAIAEgACkDADcDACABIAApAwg3AwggASAAKQMQNwMQIAEgACkDGDcDGCABIAApAyA3AyAgASAAKQMoNwMoIAEgACkDMDcDMCABIAApAzg3AzggASAAKQNANwNAIAEgACkDSDcDSCABIAApA1A3A1AgASAAKQNYNwNYIAEgACkDYDcDYCABIAApA2g3A2ggASAAKQNwNwNwIAEgACkDeDcDeCABIAApA4ABNwOAASABIAApA4gBNwOIASABIAApA5ABNwOQASABIAApA5gBNwOYASABIAApA6ABNwOgASABIAApA6gBNwOoASABIAApA7ABNwOwASABIAApA7gBNwO4AQsvACAAEKEBBEAgARCkAQUgAUGAAWoQjQEgAEHAAGogAUHAAGoQjgEgACABEI4BCwscAQF/IAAgARCYASAAQcAAaiABQcAAahCYAXEPC4sBAQF/IABBgAFqIQIgABCiAQRAIAEQoQEPCyABEKEBBEBBAA8LIAIQiwEEQCAAIAEQqAEPCyACQejhABCRASABQejhAEGo4gAQjwEgAkHo4QBB6OIAEI8BIAFBwABqQejiAEGo4wAQjwEgAEGo4gAQmAEEQCAAQcAAakGo4wAQmAEEQEEBDwsLQQAPC9kBAgF/AX8gAEGAAWohAiABQYABaiEDIAAQogEEQCABEKIBDwsgARCiAQRAQQAPCyACEIsBBEAgASAAEKkBDwsgAxCLAQRAIAAgARCpAQ8LIAJB6OMAEJEBIANBqOQAEJEBIABBqOQAQejkABCPASABQejjAEGo5QAQjwEgAkHo4wBB6OUAEI8BIANBqOQAQajmABCPASAAQcAAakGo5gBB6OYAEI8BIAFBwABqQejlAEGo5wAQjwFB6OQAQajlABCYAQRAQejmAEGo5wAQmAEEQEEBDwsLQQAPC6wCACAAEKEBBEAgACABEKcBDwsgAEHo5wAQkQEgAEHAAGpBqOgAEJEBQajoAEHo6AAQkQEgAEGo6ABBqOkAEJIBQajpAEGo6QAQkQFBqOkAQejnAEGo6QAQkwFBqOkAQejoAEGo6QAQkwFBqOkAQajpAEGo6QAQkgFB6OcAQejnAEHo6QAQkgFB6OkAQejnAEHo6QAQkgEgAEHAAGogAEHAAGogAUGAAWoQkgFB6OkAIAEQkQEgAUGo6QAgARCTASABQajpACABEJMBQejoAEHo6ABBqOoAEJIBQajqAEGo6gBBqOoAEJIBQajqAEGo6gBBqOoAEJIBQajpACABIAFBwABqEJMBIAFBwABqQejpACABQcAAahCPASABQcAAakGo6gAgAUHAAGoQkwEL1AIAIAAQogEEQCAAIAEQpgEPCyAAQYABahCLAQRAIAAgARCrAQ8PCyAAQejqABCRASAAQcAAakGo6wAQkQFBqOsAQejrABCRASAAQajrAEGo7AAQkgFBqOwAQajsABCRAUGo7ABB6OoAQajsABCTAUGo7ABB6OsAQajsABCTAUGo7ABBqOwAQajsABCSAUHo6gBB6OoAQejsABCSAUHo7ABB6OoAQejsABCSAUHo7ABBqO0AEJEBIABBwABqIABBgAFqQejtABCPAUGo7ABBqOwAIAEQkgFBqO0AIAEgARCTAUHo6wBB6OsAQajuABCSAUGo7gBBqO4AQajuABCSAUGo7gBBqO4AQajuABCSAUGo7AAgASABQcAAahCTASABQcAAakHo7AAgAUHAAGoQjwEgAUHAAGpBqO4AIAFBwABqEJMBQejtAEHo7QAgAUGAAWoQkgEL7AIBAX8gAEGAAWohAyAAEKEBBEAgASACEKUBIAJBgAFqEI0BDwsgARChAQRAIAAgAhClASACQYABahCNAQ8LIAAgARCYAQRAIABBwABqIAFBwABqEJgBBEAgASACEKsBDwsLIAEgAEHo7gAQkwEgAUHAAGogAEHAAGpB6O8AEJMBQejuAEGo7wAQkQFBqO8AQajvAEGo8AAQkgFBqPAAQajwAEGo8AAQkgFB6O4AQajwAEHo8AAQjwFB6O8AQejvAEGo8QAQkgEgAEGo8ABBqPIAEI8BQajxAEHo8QAQkQFBqPIAQajyAEHo8gAQkgFB6PEAQejwACACEJMBIAJB6PIAIAIQkwEgAEHAAGpB6PAAQajzABCPAUGo8wBBqPMAQajzABCSAUGo8gAgAiACQcAAahCTASACQcAAakGo8QAgAkHAAGoQjwEgAkHAAGpBqPMAIAJBwABqEJMBQejuAEHo7gAgAkGAAWoQkgEL3AMBAX8gAEGAAWohAyAAEKIBBEAgASACEKUBIAJBgAFqEI0BDwsgARChAQRAIAAgAhCmAQ8LIAMQiwEEQCAAIAEgAhCtAQ8LIANB6PMAEJEBIAFB6PMAQaj0ABCPASADQejzAEHo9AAQjwEgAUHAAGpB6PQAQaj1ABCPASAAQaj0ABCYAQRAIABBwABqQaj1ABCYAQRAIAEgAhCrAQ8LC0Go9AAgAEHo9QAQkwFBqPUAIABBwABqQej2ABCTAUHo9QBBqPYAEJEBQaj2AEGo9gBBqPcAEJIBQaj3AEGo9wBBqPcAEJIBQej1AEGo9wBB6PcAEI8BQej2AEHo9gBBqPgAEJIBIABBqPcAQaj5ABCPAUGo+ABB6PgAEJEBQaj5AEGo+QBB6PkAEJIBQej4AEHo9wAgAhCTASACQej5ACACEJMBIABBwABqQej3AEGo+gAQjwFBqPoAQaj6AEGo+gAQkgFBqPkAIAIgAkHAAGoQkwEgAkHAAGpBqPgAIAJBwABqEI8BIAJBwABqQaj6ACACQcAAahCTASADQej1ACACQYABahCSASACQYABaiACQYABahCRASACQYABakHo8wAgAkGAAWoQkwEgAkGAAWpBqPYAIAJBgAFqEJMBC6UEAgF/AX8gAEGAAWohAyABQYABaiEEIAAQogEEQCABIAIQpgEPCyABEKIBBEAgACACEKYBDwsgAxCLAQRAIAEgACACEK4BDwsgBBCLAQRAIAAgASACEK4BDwsgA0Ho+gAQkQEgBEGo+wAQkQEgAEGo+wBB6PsAEI8BIAFB6PoAQaj8ABCPASADQej6AEHo/AAQjwEgBEGo+wBBqP0AEI8BIABBwABqQaj9AEHo/QAQjwEgAUHAAGpB6PwAQaj+ABCPAUHo+wBBqPwAEJgBBEBB6P0AQaj+ABCYAQRAIAAgAhCsAQ8LC0Go/ABB6PsAQej+ABCTAUGo/gBB6P0AQaj/ABCTAUHo/gBB6P4AQej/ABCSAUHo/wBB6P8AEJEBQej+AEHo/wBBqIABEI8BQaj/AEGo/wBB6IABEJIBQej7AEHo/wBB6IEBEI8BQeiAAUGogQEQkQFB6IEBQeiBAUGoggEQkgFBqIEBQaiAASACEJMBIAJBqIIBIAIQkwFB6P0AQaiAAUHoggEQjwFB6IIBQeiCAUHoggEQkgFB6IEBIAIgAkHAAGoQkwEgAkHAAGpB6IABIAJBwABqEI8BIAJBwABqQeiCASACQcAAahCTASADIAQgAkGAAWoQkgEgAkGAAWogAkGAAWoQkQEgAkGAAWpB6PoAIAJBgAFqEJMBIAJBgAFqQaj7ACACQYABahCTASACQYABakHo/gAgAkGAAWoQjwELGAAgACABEI4BIABBwABqIAFBwABqEJQBCycAIAAgARCOASAAQcAAaiABQcAAahCUASAAQYABaiABQYABahCOAQsWACABQaiDARCwASAAQaiDASACEK0BCxYAIAFB6IQBELABIABB6IQBIAIQrgELFgAgAUGohgEQsQEgAEGohgEgAhCvAQsYACAAIAEQlwEgAEHAAGogAUHAAGoQlwELJwAgACABEJcBIABBwABqIAFBwABqEJcBIABBgAFqIAFBgAFqEJcBCxgAIAAgARCWASAAQcAAaiABQcAAahCWAQsnACAAIAEQlgEgAEHAAGogAUHAAGoQlgEgAEGAAWogAUGAAWoQlgELXgAgABCiAQRAIAEQjAEgAUHAAGoQjAEFIABBgAFqQeiHARCZAUHohwFBqIgBEJEBQeiHAUGoiAFB6IgBEI8BIABBqIgBIAEQjwEgAEHAAGpB6IgBIAFBwABqEI8BCwtAACAAQcAAakGoiQEQkQEgAEHoiQEQkQEgAEHoiQFB6IkBEI8BQeiJAUGo4QBB6IkBEJIBQaiJAUHoiQEQmAEPCxMAIABBqIoBELkBQaiKARC6AQ8LvgEFAX8BfwF/AX8Bf0EAKAIAIQNBACADIAFBwABsajYCACAAQYABakHAASABIANBwAAQnQEgACEEIAMhBSACIQZBACEHAkADQCAHIAFGDQEgBRCKAQRAIAYQjAEgBkHAAGoQjAEFIAUgBEHAAGpBqIsBEI8BIAUgBRCRASAFIAQgBhCPASAFQaiLASAGQcAAahCPAQsgBEHAAWohBCAGQYABaiEGIAVBwABqIQUgB0EBaiEHDAALC0EAIAM2AgALXgAgABCiAQRAIAEQpAEFIABBgAFqQeiLARCZAUHoiwFBqIwBEJEBQeiLAUGojAFB6IwBEI8BIABBqIwBIAEQjwEgAEHAAGpB6IwBIAFBwABqEI8BIAFBgAFqEI0BCws7AgF/AX8gAiABakEBayEDIAAhBAJAA0AgAyACSA0BIAMgBC0AADoAACADQQFrIQMgBEEBaiEEDAALCws1ACAAEKEBBEAgARCjAQ8LIABBqI0BELUBQaiNAUHAACABEL4BQeiNAUHAACABQcAAahC+AQtKACAAEKEBBEAgARCMASABQcAAOgAADwsgAEGojgEQlwFBqI4BQcAAIAEQvgEgAEHAAGoQmwFBf0YEQCABIAEtAABBgAFyOgAACws5ACAALQAAQcAAcQRAIAEQowEPCyAAQcAAQeiOARC+ASAAQcAAakHAAEGojwEQvgFB6I4BIAEQtwEL2QECAX8BfyAALQAAIQIgAkHAAHEEQCABEKMBDwsgAkGAAXEhAyAAQaiQARCOAUGokAEgAkE/cToAAEGokAFBwABB6I8BEL4BQeiPASABEJYBIAFBqJABEJEBIAFBqJABQaiQARCPAUGokAFBqOEAQaiQARCSAUGokAFBqJABEJ8BQaiQAUHojwEQlAFBqJABEJsBQX9GBEAgAwRAQaiQASABQcAAahCOAQVBqJABIAFBwABqEJQBCwUgAwRAQaiQASABQcAAahCUAQVBqJABIAFBwABqEI4BCwsLQQMBfwF/AX8gACEEIAIhBUEAIQMCQANAIAMgAUYNASAEIAUQvwEgBEGAAWohBCAFQYABaiEFIANBAWohAwwACwsLQQMBfwF/AX8gACEEIAIhBUEAIQMCQANAIAMgAUYNASAEIAUQwAEgBEGAAWohBCAFQcAAaiEFIANBAWohAwwACwsLQQMBfwF/AX8gACEEIAIhBUEAIQMCQANAIAMgAUYNASAEIAUQwQEgBEGAAWohBCAFQYABaiEFIANBAWohAwwACwsLVQMBfwF/AX8gACABQQFrQcAAbGohBCACIAFBAWtBgAFsaiEFQQAhAwJAA0AgAyABRg0BIAQgBRDCASAEQcAAayEEIAVBgAFrIQUgA0EBaiEDDAALCwtVAwF/AX8BfyAAIAFBAWtBgAFsaiEEIAIgAUEBa0HAAWxqIQVBACEDAkADQCADIAFGDQEgBCAFEKcBIARBgAFrIQQgBUHAAWshBSADQQFqIQMMAAsLC0ECAX8BfyABQQhsIAJrIQQgAyAESgRAQQEgBHRBAWshBQVBASADdEEBayEFCyAAIAJBA3ZqKAAAIAJBB3F2IAVxC5oBBAF/AX8BfwF/IAFBAUYEQA8LQQEgAUEBa3QhAiAAIQMgACACQcABbGohBCAEQcABayEFAkADQCADIAVGDQEgAyAEIAMQrwEgBSAEIAUQrwEgA0HAAWohAyAEQcABaiEEDAALCyAAIAFBAWsQyQEgAUEBayEBAkADQCABRQ0BIAUgBRCsASABQQFrIQEMAAsLIAAgBSAAEK8BC9IBCgF/AX8BfwF/AX8BfwF/AX8BfwF/IANFBEAgBhCkAQ8LQQEgBXQhDUEAKAIAIQ5BACAOIA1BwAFsajYCAEEAIQwCQANAIAwgDUYNASAOIAxBwAFsahCkASAMQQFqIQwMAAsLIAAhCiABIQggASADIAJsaiEJAkADQCAIIAlGDQEgCCACIAQgBRDIASEPIA8EQCAOIA9BAWtBwAFsaiEQIBAgCiAQEK8BCyAIIAJqIQggCkHAAWohCgwACwsgDiAFEMkBIA4gBhCmAUEAIA42AgALqAEMAX8BfwF/AX8BfwF/AX8BfwF/AX8BfwF/IAQQpAEgA0UEQA8LIANnLQCokgEhBSACQQN0QQFrIAVuQQFqIQYgBkEBayAFbCEKAkADQCAKQQBIDQEgBBCiAUUEQEEAIQwCQANAIAwgBUYNASAEIAQQrAEgDEEBaiEMDAALCwsgACABIAIgAyAKIAVB6JABEMoBIARB6JABIAQQrwEgCiAFayEKDAALCwtBAgF/AX8gAUEIbCACayEEIAMgBEoEQEEBIAR0QQFrIQUFQQEgA3RBAWshBQsgACACQQN2aigAACACQQdxdiAFcQuaAQQBfwF/AX8BfyABQQFGBEAPC0EBIAFBAWt0IQIgACEDIAAgAkHAAWxqIQQgBEHAAWshBQJAA0AgAyAFRg0BIAMgBCADEK8BIAUgBCAFEK8BIANBwAFqIQMgBEHAAWohBAwACwsgACABQQFrEM0BIAFBAWshAQJAA0AgAUUNASAFIAUQrAEgAUEBayEBDAALCyAAIAUgABCvAQvSAQoBfwF/AX8BfwF/AX8BfwF/AX8BfyADRQRAIAYQpAEPC0EBIAV0IQ1BACgCACEOQQAgDiANQcABbGo2AgBBACEMAkADQCAMIA1GDQEgDiAMQcABbGoQpAEgDEEBaiEMDAALCyAAIQogASEIIAEgAyACbGohCQJAA0AgCCAJRg0BIAggAiAEIAUQzAEhDyAPBEAgDiAPQQFrQcABbGohECAQIAogEBCuAQsgCCACaiEIIApBgAFqIQoMAAsLIA4gBRDNASAOIAYQpgFBACAONgIAC6gBDAF/AX8BfwF/AX8BfwF/AX8BfwF/AX8BfyAEEKQBIANFBEAPCyADZy0AiJQBIQUgAkEDdEEBayAFbkEBaiEGIAZBAWsgBWwhCgJAA0AgCkEASA0BIAQQogFFBEBBACEMAkADQCAMIAVGDQEgBCAEEKwBIAxBAWohDAwACwsLIAAgASACIAMgCiAFQciSARDOASAEQciSASAEEK8BIAogBWshCgwACwsLtAQHAX8BfwF/AX8BfwF/AX8gAkUEQCADEKQBDwsgAkEDdCEFQQAoAgAhBCAEIQpBACAEQSBqIAVqQXhxNgIAQQEhBiABQQBBA3ZBfHFqKAIAQQBBH3F2QQFxIQdBACEJAkADQCAGIAVGDQEgASAGQQN2QXxxaigCACAGQR9xdkEBcSEIIAcEQCAIBEAgCQRAQQAhB0EBIQkgCkEBOgAAIApBAWohCgVBACEHQQEhCSAKQf8BOgAAIApBAWohCgsFIAkEQEEAIQdBASEJIApB/wE6AAAgCkEBaiEKBUEAIQdBACEJIApBAToAACAKQQFqIQoLCwUgCARAIAkEQEEAIQdBASEJIApBADoAACAKQQFqIQoFQQEhB0EAIQkgCkEAOgAAIApBAWohCgsFIAkEQEEBIQdBACEJIApBADoAACAKQQFqIQoFQQAhB0EAIQkgCkEAOgAAIApBAWohCgsLCyAGQQFqIQYMAAsLIAcEQCAJBEAgCkH/AToAACAKQQFqIQogCkEAOgAAIApBAWohCiAKQQE6AAAgCkEBaiEKBSAKQQE6AAAgCkEBaiEKCwUgCQRAIApBADoAACAKQQFqIQogCkEBOgAAIApBAWohCgsLIApBAWshCiAAQaiUARCmASADEKQBAkADQCADIAMQrAEgCi0AACEIIAgEQCAIQQFGBEAgA0GolAEgAxCvAQUgA0GolAEgAxC0AQsLIAQgCkYNASAKQQFrIQoMAAsLQQAgBDYCAAu0BAcBfwF/AX8BfwF/AX8BfyACRQRAIAMQpAEPCyACQQN0IQVBACgCACEEIAQhCkEAIARBIGogBWpBeHE2AgBBASEGIAFBAEEDdkF8cWooAgBBAEEfcXZBAXEhB0EAIQkCQANAIAYgBUYNASABIAZBA3ZBfHFqKAIAIAZBH3F2QQFxIQggBwRAIAgEQCAJBEBBACEHQQEhCSAKQQE6AAAgCkEBaiEKBUEAIQdBASEJIApB/wE6AAAgCkEBaiEKCwUgCQRAQQAhB0EBIQkgCkH/AToAACAKQQFqIQoFQQAhB0EAIQkgCkEBOgAAIApBAWohCgsLBSAIBEAgCQRAQQAhB0EBIQkgCkEAOgAAIApBAWohCgVBASEHQQAhCSAKQQA6AAAgCkEBaiEKCwUgCQRAQQEhB0EAIQkgCkEAOgAAIApBAWohCgVBACEHQQAhCSAKQQA6AAAgCkEBaiEKCwsLIAZBAWohBgwACwsgBwRAIAkEQCAKQf8BOgAAIApBAWohCiAKQQA6AAAgCkEBaiEKIApBAToAACAKQQFqIQoFIApBAToAACAKQQFqIQoLBSAJBEAgCkEAOgAAIApBAWohCiAKQQE6AAAgCkEBaiEKCwsgCkEBayEKIABB6JUBEKUBIAMQpAECQANAIAMgAxCsASAKLQAAIQggCARAIAhBAUYEQCADQeiVASADEK4BBSADQeiVASADELMBCwsgBCAKRg0BIApBAWshCgwACwtBACAENgIACxYAIAFB6JYBEDIgAEHolgFBICACEHYLRgAgAEH/AXEtAIi0AUEYdCAAQQh2Qf8BcS0AiLQBQRB0aiAAQRB2Qf8BcS0AiLQBQQh0IABBGHZB/wFxLQCItAFqaiABdwtqBQF/AX8BfwF/AX9BASABdCECQQAhAwJAA0AgAyACRg0BIAAgA0HgAGxqIQUgAyABENMBIQQgACAEQeAAbGohBiADIARJBEAgBUGItgEQTCAGIAUQTEGItgEgBhBMCyADQQFqIQMMAAsLC+MBBwF/AX8BfwF/AX8BfwF/IAJFIAMQKXEEQA8LQQEgAXQhBCAEQQFrIQhBASEHIARBAXYhBQJAA0AgByAFTw0BIAAgB0HgAGxqIQkgACAEIAdrQeAAbGohCiACBEAgAxApBEAgCUHotgEQTCAKIAkQTEHotgEgChBMBSAJQei2ARBMIAogAyAJENIBQei2ASADIAoQ0gELBSADECkEQAUgCSADIAkQ0gEgCiADIAoQ0gELCyAHQQFqIQcMAAsLIAMQKQRABSAAIAMgABDSASAAIAVB4ABsaiEKIAogAyAKENIBCwvtAQkBfwF/AX8BfwF/AX8BfwF/AX8gACABENQBQQEgAXQhCUEBIQQCQANAIAQgAUsNAUEBIAR0IQdBiJcBIARBIGxqIQpBACEFAkADQCAFIAlPDQFByLcBEDYgB0EBdiEIQQAhBgJAA0AgBiAITw0BIAAgBSAGakHgAGxqIQsgCyAIQeAAbGohDCAMQci3AUHotwEQ0gEgC0HIuAEQTEHIuAFB6LcBIAsQVUHIuAFB6LcBIAwQWkHItwEgCkHItwEQLiAGQQFqIQYMAAsLIAUgB2ohBQwACwsgBEEBaiEEDAALCyAAIAEgAiADENUBC0MCAX8BfyAAQQF2IQJBACEBAkADQCACRQ0BIAJBAXYhAiABQQFqIQEMAAsLIABBASABdEcEQAALIAFBHEsEQAALIAELHgEBfyABENcBIQJBqLkBEDYgACACQQBBqLkBENYBCyQCAX8BfyABENcBIQJBqJ4BIAJBIGxqIQMgACACQQEgAxDWAQt5AwF/AX8BfyADQci5ARAAQQAhBwJAA0AgByACRg0BIAAgB0HgAGxqIQUgASAHQeAAbGohBiAGQci5AUHouQEQ0gEgBUHIugEQTEHIugFB6LkBIAUQVUHIugFB6LkBIAYQWkHIuQEgBEHIuQEQLiAHQQFqIQcMAAsLC4gBBAF/AX8BfwF/QcilASAFQSBsaiEJIANBqLsBEABBACEIAkADQCAIIAJGDQEgACAIQeAAbGohBiABIAhB4ABsaiEHIAYgB0HIuwEQVSAHIAkgBxDSASAGIAcgBxBVIAdBqLsBIAcQ0gFByLsBIAYQTEGouwEgBEGouwEQLiAIQQFqIQgMAAsLC6QBBQF/AX8BfwF/AX9ByKUBIAVBIGxqIQlB6KwBIAVBIGxqIQogA0GovAEQAEEAIQgCQANAIAggAkYNASAAIAhB4ABsaiEGIAEgCEHgAGxqIQcgB0GovAFByLwBENIBIAZByLwBIAcQWiAHIAogBxDSASAGIAkgBhDSAUHIvAEgBiAGEFogBiAKIAYQ0gFBqLwBIARBqLwBEC4gCEEBaiEIDAALCwvIAQkBfwF/AX8BfwF/AX8BfwF/AX9BASACdCEEIARBAXYhBSABIAJ2IQMgBUHgAGwhBkGIlwEgAkEgbGohC0EAIQkCQANAIAkgA0YNAUGovQEQNkEAIQoCQANAIAogBUYNASAAIAkgBGwgCmpB4ABsaiEHIAcgBmohCCAIQai9AUHIvQEQ0gEgB0GovgEQTEGovgFByL0BIAcQVUGovgFByL0BIAgQWkGovQEgC0GovQEQLiAKQQFqIQoMAAsLIAlBAWohCQwACwsLggEEAX8BfwF/AX8gAUEBdiEGIAFBAXEEQCAAIAZB4ABsaiACIAAgBkHgAGxqENIBC0EAIQUCQANAIAUgBk8NASAAIAVB4ABsaiEDIAAgAUEBayAFa0HgAGxqIQQgBCACQYi/ARDSASADIAIgBBDSAUGIvwEgAxBMIAVBAWohBQwACwsLnQEFAX8BfwF/AX8Bf0HIpQEgBUEgbGohCUHorAEgBUEgbGohCiADQei/ARAAQQAhCAJAA0AgCCACRg0BIAAgCEHgAGxqIQYgASAIQeAAbGohByAGIAlBiMABENIBIAdBiMABQYjAARBaIAYgByAHEFpBiMABIAogBhDSASAHQei/ASAHENIBQei/ASAEQei/ARAuIAhBAWohCAwACwsLFwAgAUHowAEQMiAAQejAAUEgIAIQ0AELRgAgAEH/AXEtAIjeAUEYdCAAQQh2Qf8BcS0AiN4BQRB0aiAAQRB2Qf8BcS0AiN4BQQh0IABBGHZB/wFxLQCI3gFqaiABdwttBQF/AX8BfwF/AX9BASABdCECQQAhAwJAA0AgAyACRg0BIAAgA0HAAWxqIQUgAyABEOEBIQQgACAEQcABbGohBiADIARJBEAgBUGI4AEQpgEgBiAFEKYBQYjgASAGEKYBCyADQQFqIQMMAAsLC+cBBwF/AX8BfwF/AX8BfwF/IAJFIAMQKXEEQA8LQQEgAXQhBCAEQQFrIQhBASEHIARBAXYhBQJAA0AgByAFTw0BIAAgB0HAAWxqIQkgACAEIAdrQcABbGohCiACBEAgAxApBEAgCUHI4QEQpgEgCiAJEKYBQcjhASAKEKYBBSAJQcjhARCmASAKIAMgCRDgAUHI4QEgAyAKEOABCwUgAxApBEAFIAkgAyAJEOABIAogAyAKEOABCwsgB0EBaiEHDAALCyADECkEQAUgACADIAAQ4AEgACAFQcABbGohCiAKIAMgChDgAQsL8AEJAX8BfwF/AX8BfwF/AX8BfwF/IAAgARDiAUEBIAF0IQlBASEEAkADQCAEIAFLDQFBASAEdCEHQYjBASAEQSBsaiEKQQAhBQJAA0AgBSAJTw0BQYjjARA2IAdBAXYhCEEAIQYCQANAIAYgCE8NASAAIAUgBmpBwAFsaiELIAsgCEHAAWxqIQwgDEGI4wFBqOMBEOABIAtB6OQBEKYBQejkAUGo4wEgCxCvAUHo5AFBqOMBIAwQtAFBiOMBIApBiOMBEC4gBkEBaiEGDAALCyAFIAdqIQUMAAsLIARBAWohBAwACwsgACABIAIgAxDjAQtDAgF/AX8gAEEBdiECQQAhAQJAA0AgAkUNASACQQF2IQIgAUEBaiEBDAALCyAAQQEgAXRHBEAACyABQRxLBEAACyABCx4BAX8gARDlASECQajmARA2IAAgAkEAQajmARDkAQskAgF/AX8gARDlASECQajIASACQSBsaiEDIAAgAkEBIAMQ5AELfAMBfwF/AX8gA0HI5gEQAEEAIQcCQANAIAcgAkYNASAAIAdBwAFsaiEFIAEgB0HAAWxqIQYgBkHI5gFB6OYBEOABIAVBqOgBEKYBQajoAUHo5gEgBRCvAUGo6AFB6OYBIAYQtAFByOYBIARByOYBEC4gB0EBaiEHDAALCwuLAQQBfwF/AX8Bf0HIzwEgBUEgbGohCSADQejpARAAQQAhCAJAA0AgCCACRg0BIAAgCEHAAWxqIQYgASAIQcABbGohByAGIAdBiOoBEK8BIAcgCSAHEOABIAYgByAHEK8BIAdB6OkBIAcQ4AFBiOoBIAYQpgFB6OkBIARB6OkBEC4gCEEBaiEIDAALCwumAQUBfwF/AX8BfwF/QcjPASAFQSBsaiEJQejWASAFQSBsaiEKIANByOsBEABBACEIAkADQCAIIAJGDQEgACAIQcABbGohBiABIAhBwAFsaiEHIAdByOsBQejrARDgASAGQejrASAHELQBIAcgCiAHEOABIAYgCSAGEOABQejrASAGIAYQtAEgBiAKIAYQ4AFByOsBIARByOsBEC4gCEEBaiEIDAALCwvLAQkBfwF/AX8BfwF/AX8BfwF/AX9BASACdCEEIARBAXYhBSABIAJ2IQMgBUHAAWwhBkGIwQEgAkEgbGohC0EAIQkCQANAIAkgA0YNAUGo7QEQNkEAIQoCQANAIAogBUYNASAAIAkgBGwgCmpBwAFsaiEHIAcgBmohCCAIQajtAUHI7QEQ4AEgB0GI7wEQpgFBiO8BQcjtASAHEK8BQYjvAUHI7QEgCBC0AUGo7QEgC0Go7QEQLiAKQQFqIQoMAAsLIAlBAWohCQwACwsLgwEEAX8BfwF/AX8gAUEBdiEGIAFBAXEEQCAAIAZBwAFsaiACIAAgBkHAAWxqEOABC0EAIQUCQANAIAUgBk8NASAAIAVBwAFsaiEDIAAgAUEBayAFa0HAAWxqIQQgBCACQcjwARDgASADIAIgBBDgAUHI8AEgAxCmASAFQQFqIQUMAAsLC58BBQF/AX8BfwF/AX9ByM8BIAVBIGxqIQlB6NYBIAVBIGxqIQogA0GI8gEQAEEAIQgCQANAIAggAkYNASAAIAhBwAFsaiEGIAEgCEHAAWxqIQcgBiAJQajyARDgASAHQajyAUGo8gEQtAEgBiAHIAcQtAFBqPIBIAogBhDgASAHQYjyASAHEOABQYjyASAEQYjyARAuIAhBAWohCAwACwsLFgAgAUHo8wEQMiAAQejzAUEgIAIQdwsXACABQYj0ARAyIABBiPQBQSAgAhDRAQtYBAF/AX8BfwF/IAAhByAEIQggAkGo9AEQAEEAIQYCQANAIAYgAUYNASAHQaj0ASAIEC4gB0EgaiEHIAhBIGohCEGo9AEgA0Go9AEQLiAGQQFqIQYMAAsLC1sEAX8BfwF/AX8gACEHIAQhCCACQcj0ARAAQQAhBgJAA0AgBiABRg0BIAdByPQBIAgQ0gEgB0HgAGohByAIQeAAaiEIQcj0ASADQcj0ARAuIAZBAWohBgwACwsLWwQBfwF/AX8BfyAAIQcgBCEIIAJB6PQBEABBACEGAkADQCAGIAFGDQEgB0Ho9AEgCBDuASAHQcAAaiEHIAhB4ABqIQhB6PQBIANB6PQBEC4gBkEBaiEGDAALCwtbBAF/AX8BfwF/IAAhByAEIQggAkGI9QEQAEEAIQYCQANAIAYgAUYNASAHQYj1ASAIEOABIAdBwAFqIQcgCEHAAWohCEGI9QEgA0GI9QEQLiAGQQFqIQYMAAsLC1sEAX8BfwF/AX8gACEHIAQhCCACQaj1ARAAQQAhBgJAA0AgBiABRg0BIAdBqPUBIAgQ7wEgB0GAAWohByAIQcABaiEIQaj1ASADQaj1ARAuIAZBAWohBgwACwsLDQBBiP0BIAAgARCPAQsbACAAEIoBIABBwABqEIoBcSAAQYABahCKAXELHAAgABCLASAAQcAAahCKAXEgAEGAAWoQigFxDwsZACAAEIwBIABBwABqEIwBIABBgAFqEIwBCxkAIAAQjQEgAEHAAGoQjAEgAEGAAWoQjAELJwAgACABEI4BIABBwABqIAFBwABqEI4BIABBgAFqIAFBgAFqEI4BC+UCACAAIAFByP4BEI8BIABBwABqIAFBwABqQYj/ARCPASAAQYABaiABQYABakHI/wEQjwEgACAAQcAAakGIgAIQkgEgASABQcAAakHIgAIQkgEgACAAQYABakGIgQIQkgEgASABQYABakHIgQIQkgEgAEHAAGogAEGAAWpBiIICEJIBIAFBwABqIAFBgAFqQciCAhCSAUHI/gFBiP8BQYiDAhCSAUHI/gFByP8BQciDAhCSAUGI/wFByP8BQYiEAhCSAUGIggJByIICIAIQjwEgAkGIhAIgAhCTASACIAIQ9QFByP4BIAIgAhCSAUGIgAJByIACIAJBwABqEI8BIAJBwABqQYiDAiACQcAAahCTAUHI/wFByIQCEPUBIAJBwABqQciEAiACQcAAahCSAUGIgQJByIECIAJBgAFqEI8BIAJBgAFqQciDAiACQYABahCTASACQYABakGI/wEgAkGAAWoQkgELgQIAIABBiIUCEJEBIAAgAEHAAGpByIUCEI8BQciFAkHIhQJBiIYCEJIBIAAgAEHAAGpByIYCEJMBQciGAiAAQYABakHIhgIQkgFByIYCQciGAhCRASAAQcAAaiAAQYABakGIhwIQjwFBiIcCQYiHAkHIhwIQkgEgAEGAAWpBiIgCEJEBQciHAiABEPUBQYiFAiABIAEQkgFBiIgCIAFBwABqEPUBQYiGAiABQcAAaiABQcAAahCSAUGIhQJBiIgCIAFBgAFqEJIBQciHAiABQYABaiABQYABahCTAUHIhgIgAUGAAWogAUGAAWoQkgFBiIYCIAFBgAFqIAFBgAFqEJIBCzUAIAAgASACEJIBIABBwABqIAFBwABqIAJBwABqEJIBIABBgAFqIAFBgAFqIAJBgAFqEJIBCzUAIAAgASACEJMBIABBwABqIAFBwABqIAJBwABqEJMBIABBgAFqIAFBgAFqIAJBgAFqEJMBCycAIAAgARCUASAAQcAAaiABQcAAahCUASAAQYABaiABQYABahCUAQswAQF/IABBgAFqEJsBIQEgAQRAIAEPCyAAQcAAahCbASEBIAEEQCABDwsgABCbAQ8LJwAgACABEJYBIABBwABqIAFBwABqEJYBIABBgAFqIAFBgAFqEJYBCycAIAAgARCXASAAQcAAaiABQcAAahCX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ASAAQcACakGQiQQgAUHAAmoQjwELigIAIAAgARAAIABBIGogAUEgahASIAFB0IkEIAEQjwEgAEHAAGogAUHAAGoQACAAQeAAaiABQeAAahASIAFBwABqQZCKBCABQcAAahCPASAAQYABaiABQYABahAAIABBoAFqIAFBoAFqEBIgAUGAAWpB0IoEIAFBgAFqEI8BIABBwAFqIAFBwAFqEAAgAEHgAWogAUHgAWoQEiABQcABakGQiwQgAUHAAWoQjwEgAEGAAmogAUGAAmoQACAAQaACaiABQaACahASIAFBgAJqQdCLBCABQYACahCPASAAQcACaiABQcACahAAIABB4AJqIAFB4AJqEBIgAUHAAmpBkIwEIAFBwAJqEI8BC2wAIABB0IwEIAEQjwEgAEHAAGpBkI0EIAFBwABqEI8BIABBgAFqQdCNBCABQYABahCPASAAQcABakGQjgQgAUHAAWoQjwEgAEGAAmpB0I4EIAFBgAJqEI8BIABBwAJqQZCPBCABQcACahCPAQuKAgAgACABEAAgAEEgaiABQSBqEBIgAUHQjwQgARCPASAAQcAAaiABQcAAahAAIABB4ABqIAFB4ABqEBIgAUHAAGpBkJAEIAFBwABqEI8BIABBgAFqIAFBgAFqEAAgAEGgAWogAUGgAWoQEiABQYABakHQkAQgAUGAAWoQjwEgAEHAAWogAUHAAWoQACAAQeABaiABQeABahASIAFBwAFqQZCRBCABQcABahCPASAAQYACaiABQYACahAAIABBoAJqIAFBoAJqEBIgAUGAAmpB0JEEIAFBgAJqEI8BIABBwAJqIAFBwAJqEAAgAEHgAmogAUHgAmoQEiABQcACakGQkgQgAUHAAmoQjwELbAAgAEHQkgQgARCPASAAQcAAakGQkwQgAUHAAGoQjwEgAEGAAWpB0JMEIAFBgAFqEI8BIABBwAFqQZCUBCABQcABahCPASAAQYACakHQlAQgAUGAAmoQjwEgAEHAAmpBkJUEIAFBwAJqEI8BC4oCACAAIAEQACAAQSBqIAFBIGoQEiABQdCVBCABEI8BIABBwABqIAFBwABqEAAgAEHgAGogAUHgAGoQEiABQcAAakGQlgQgAUHAAGoQjwEgAEGAAWogAUGAAWoQACAAQaABaiABQaABahASIAFBgAFqQdCWBCABQYABahCP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', imports)}
2425
-
2426
- /**
2427
- * Cloudflare-Workers-compatible Groth16 ZK proof verifier.
2428
- *
2429
- * Drives the BN128 WASM module's exported pairing functions directly. Does NOT
2430
- * use snarkjs/ffjavascript — those depend on runtime features (most notably
2431
- * `URL.createObjectURL`) that CF Workers don't expose. See ROADMAP / CLAUDE.md.
2432
- *
2433
- * Two ways to initialize:
2434
- * 1. `await initBn128Wasm()` — uses the bundled bn128.wasm (base64-inlined at
2435
- * build time via `@rollup/plugin-wasm`). Works in any modern JS runtime
2436
- * that allows runtime `WebAssembly.compile()` — Node, browsers, most
2437
- * Workers configurations.
2438
- * 2. `await initBn128Wasm(myWasmModule)` — accepts a pre-compiled
2439
- * `WebAssembly.Module`. Lets a CF-Workers consumer keep the native pattern
2440
- * of importing `.wasm` so wrangler precompiles it at deploy time and the
2441
- * worker never pays for runtime compilation.
2442
- */
2443
- // BN128 curve sizing
2444
- const n8q = 32;
2445
- const n8r = 32;
2446
- const f1size = n8q;
2447
- const g1size = f1size * 3;
2448
- const g2size = f1size * 6;
2449
- const ftsize = f1size * 12;
2450
- // Field modulus q (base field) and r (scalar field)
2451
- const q = BigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583");
2452
- const r = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
2453
- // Initial linear memory: 25 * 64KB = 1.6MB
2454
- const MEM_SIZE = 25;
2455
- /**
2456
- * Initialize the BN128 WASM module.
2457
- *
2458
- * @param wasmModule Optional pre-compiled `WebAssembly.Module`. If omitted, the
2459
- * bundled bn128.wasm (base64-inlined by `@rollup/plugin-wasm` at build time)
2460
- * is used. Passing your own module is the recommended path inside CF Workers,
2461
- * where wrangler can precompile a `.wasm` import at deploy time and avoid the
2462
- * runtime compile cost.
2463
- */
2464
- async function initBn128Wasm(wasmModule) {
2465
- const memory = new WebAssembly.Memory({ initial: MEM_SIZE, maximum: 32767 });
2466
- const imports = { env: { memory } };
2467
- let instance;
2468
- if (wasmModule) {
2469
- instance = await WebAssembly.instantiate(wasmModule, imports);
2470
- }
2471
- else {
2472
- // Bundled fallback: the rollup plugin returns a loader function that takes
2473
- // an import object and resolves to an instantiated WebAssembly.Instance.
2474
- instance = await loadBundledBn128(imports);
2475
- }
2476
- // The first u32 in linear memory is the heap free pointer (set by the module
2477
- // during static initialization). Remember it so we can reset between calls.
2478
- const u32 = new Uint32Array(memory.buffer);
2479
- const initialPFree = u32[0];
2480
- return { instance, memory, initialPFree };
2481
- }
2482
- /**
2483
- * Verify a Groth16 proof.
2484
- *
2485
- * Returns `false` (rather than throwing) for any structural problem — malformed
2486
- * proof, out-of-range field elements, off-curve points, or a failed pairing.
2487
- * Throws only for runtime/WASM faults.
2488
- */
2489
- async function verifyGroth16(wasmInstance, memory, initialPFree, verificationKey, proof, publicSignals) {
2490
- try {
2491
- const vk = unstringifyBigInts(verificationKey);
2492
- const p = unstringifyBigInts(proof);
2493
- const signals = unstringifyBigInts(publicSignals);
2494
- // Validate proof coordinates are within the base field
2495
- if (!validateG1InField(p.pi_a))
2496
- return false;
2497
- if (!validateG1InField(p.pi_c))
2498
- return false;
2499
- for (let i = 0; i < 2; i++) {
2500
- for (let j = 0; j < 2; j++) {
2501
- const val = typeof p.pi_b[i][j] === "bigint" ? p.pi_b[i][j] : BigInt(String(p.pi_b[i][j]));
2502
- if (val >= q)
2503
- return false;
2504
- }
2505
- }
2506
- // Validate public signals are within the scalar field
2507
- for (const signal of signals) {
2508
- if (signal >= r)
2509
- return false;
2510
- }
2511
- const exports = wasmInstance.exports;
2512
- const u8 = new Uint8Array(memory.buffer);
2513
- const u32 = new Uint32Array(memory.buffer);
2514
- // Reset the WASM allocator's heap pointer between invocations
2515
- u32[0] = initialPFree;
2516
- const g1m_add = exports["g1m_add"];
2517
- const g1m_timesScalar = exports["g1m_timesScalar"];
2518
- const g1m_neg = exports["g1m_neg"];
2519
- const g1m_inCurve = exports["g1m_inCurve"];
2520
- const g2m_inCurve = exports["g2m_inCurve"];
2521
- const ftm_one = exports["ftm_one"];
2522
- const bn128_pairingEq4 = exports["bn128_pairingEq4"];
2523
- // Compute vk_x = IC[0] + sum(IC[i+1] * signal[i])
2524
- const pVkX = alloc(u32, g1size);
2525
- const pIC0 = alloc(u32, g1size);
2526
- writeG1Point(u8, pIC0, vk.IC[0], exports);
2527
- u8.set(u8.slice(pIC0, pIC0 + g1size), pVkX);
2528
- const pTemp = alloc(u32, g1size);
2529
- const pScalar = alloc(u32, n8r);
2530
- for (let i = 0; i < signals.length; i++) {
2531
- const pICi = alloc(u32, g1size);
2532
- writeG1Point(u8, pICi, vk.IC[i + 1], exports);
2533
- u8.set(bigIntToLE(signals[i], n8r), pScalar);
2534
- g1m_timesScalar(pICi, pScalar, n8r, pTemp);
2535
- const pSum = alloc(u32, g1size);
2536
- g1m_add(pVkX, pTemp, pSum);
2537
- u8.set(u8.slice(pSum, pSum + g1size), pVkX);
2538
- }
2539
- // Allocate proof points
2540
- const pA = alloc(u32, g1size);
2541
- const pNegA = alloc(u32, g1size);
2542
- const pB = alloc(u32, g2size);
2543
- const pC = alloc(u32, g1size);
2544
- writeG1Point(u8, pA, p.pi_a, exports);
2545
- writeG2Point(u8, pB, p.pi_b, exports);
2546
- writeG1Point(u8, pC, p.pi_c, exports);
2547
- // Subgroup / on-curve checks
2548
- if (!g1m_inCurve(pA))
2549
- return false;
2550
- if (!g2m_inCurve(pB))
2551
- return false;
2552
- if (!g1m_inCurve(pC))
2553
- return false;
2554
- g1m_neg(pA, pNegA);
2555
- // Verification key points
2556
- const pAlpha = alloc(u32, g1size);
2557
- const pBeta = alloc(u32, g2size);
2558
- const pGamma = alloc(u32, g2size);
2559
- const pDelta = alloc(u32, g2size);
2560
- writeG1Point(u8, pAlpha, vk.vk_alpha_1, exports);
2561
- writeG2Point(u8, pBeta, vk.vk_beta_2, exports);
2562
- writeG2Point(u8, pGamma, vk.vk_gamma_2, exports);
2563
- writeG2Point(u8, pDelta, vk.vk_delta_2, exports);
2564
- // Target: F12 element representing 1
2565
- const pOne = alloc(u32, ftsize);
2566
- ftm_one(pOne);
2567
- // e(-A, B) * e(alpha, beta) * e(vk_x, gamma) * e(C, delta) == 1
2568
- const result = bn128_pairingEq4(pNegA, pB, pAlpha, pBeta, pVkX, pGamma, pC, pDelta, pOne);
2569
- return result === 1;
2570
- }
2571
- catch {
2572
- return false;
2573
- }
2574
- }
2575
- // ---------------------------------------------------------------------------
2576
- // Internals
2577
- // ---------------------------------------------------------------------------
2578
- function parseToBigInt(value) {
2579
- if (typeof value === "string") {
2580
- if (/^0x[0-9a-fA-F]+$/.test(value))
2581
- return BigInt(value);
2582
- if (/^[0-9a-fA-F]+$/.test(value) && /[a-fA-F]/.test(value))
2583
- return BigInt("0x" + value);
2584
- if (/^[0-9]+$/.test(value))
2585
- return BigInt(value);
2586
- throw new Error(`Cannot convert ${value} to BigInt`);
2587
- }
2588
- if (typeof value === "number")
2589
- return BigInt(value);
2590
- return value;
2591
- }
2592
- function bigIntToLE(value, size) {
2593
- const result = new Uint8Array(size);
2594
- let v = parseToBigInt(value);
2595
- for (let i = 0; i < size; i++) {
2596
- result[i] = Number(v & 0xffn);
2597
- v = v >> 8n;
2598
- }
2599
- return result;
2600
- }
2601
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2602
- function unstringifyBigInts(o) {
2603
- if (typeof o === "string") {
2604
- try {
2605
- if (/^[0-9]+$/.test(o) || /^0x[0-9a-fA-F]+$/.test(o) ||
2606
- (/^[0-9a-fA-F]+$/.test(o) && /[a-fA-F]/.test(o))) {
2607
- return parseToBigInt(o);
2608
- }
2609
- }
2610
- catch {
2611
- // fall through
2612
- }
2613
- return o;
2614
- }
2615
- if (Array.isArray(o))
2616
- return o.map(unstringifyBigInts);
2617
- if (typeof o === "object" && o !== null) {
2618
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2619
- const res = {};
2620
- for (const k of Object.keys(o))
2621
- res[k] = unstringifyBigInts(o[k]);
2622
- return res;
2623
- }
2624
- return o;
2625
- }
2626
- function validateG1InField(point) {
2627
- const x = typeof point[0] === "bigint" ? point[0] : BigInt(String(point[0]));
2628
- const y = typeof point[1] === "bigint" ? point[1] : BigInt(String(point[1]));
2629
- return x < q && y < q;
2630
- }
2631
- function writeG1Point(u8, offset, point, exports) {
2632
- const x = point[0];
2633
- const y = point[1];
2634
- const z = point.length > 2 ? point[2] : 1n;
2635
- u8.set(bigIntToLE(x, f1size), offset);
2636
- u8.set(bigIntToLE(y, f1size), offset + f1size);
2637
- u8.set(bigIntToLE(z, f1size), offset + 2 * f1size);
2638
- const f1m_toMontgomery = exports["f1m_toMontgomery"];
2639
- f1m_toMontgomery(offset, offset);
2640
- f1m_toMontgomery(offset + f1size, offset + f1size);
2641
- f1m_toMontgomery(offset + 2 * f1size, offset + 2 * f1size);
2642
- }
2643
- function writeG2Point(u8, offset, point, exports) {
2644
- const x = point[0];
2645
- const y = point[1];
2646
- const z = point.length > 2 ? point[2] : [1n, 0n];
2647
- u8.set(bigIntToLE(x[0], f1size), offset);
2648
- u8.set(bigIntToLE(x[1], f1size), offset + f1size);
2649
- u8.set(bigIntToLE(y[0], f1size), offset + 2 * f1size);
2650
- u8.set(bigIntToLE(y[1], f1size), offset + 3 * f1size);
2651
- u8.set(bigIntToLE(z[0], f1size), offset + 4 * f1size);
2652
- u8.set(bigIntToLE(z[1], f1size), offset + 5 * f1size);
2653
- const f1m_toMontgomery = exports["f1m_toMontgomery"];
2654
- for (let i = 0; i < 6; i++) {
2655
- f1m_toMontgomery(offset + i * f1size, offset + i * f1size);
2656
- }
2657
- }
2658
- function alloc(u32, size) {
2659
- while (u32[0] & 3)
2660
- u32[0]++;
2661
- const ptr = u32[0];
2662
- u32[0] += size;
2663
- return ptr;
2664
- }
2665
-
2666
- const appLogger$1 = new Logger("connect", 'ERROR');
2667
- globalThis.appLogger = appLogger$1;
2668
-
2669
- export { AES_GCM_IV_BYTES, AES_GCM_KEY_BYTES, AES_GCM_TAG_BYTES, BroadcastChannel, BroadcastChannelEvents, ChunkCipher, DoubleRatchet, EncryptedSession, EventCore, EventCoreEvents, KeyStore, Message, Message as MessageDefault, PBKDF2_DEFAULT_ITERATIONS, PREIMAGE_POK_VERIFICATION_KEY, Packet, SerializeMessage, WSTransport, decorators, decryptAesGcm, deriveAesKeyFromPassphrase, deriveBitsHkdf, encryptAesGcm, getSubtle, initBn128Wasm, randomBytes, unwrapWithPassphrase, verifyGroth16, wrapWithPassphrase };
2670
- //# sourceMappingURL=index.js.map