@marcoappio/marco-config 2.0.526 → 2.0.528

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.
@@ -286,9 +286,6 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
286
286
  };
287
287
  };
288
288
  labelPath: string;
289
- labelUnreadCounts?: {
290
- [x: string]: number;
291
- } | undefined;
292
289
  }, {
293
290
  accounts: {
294
291
  [x: string]: {
@@ -296,9 +293,6 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
296
293
  };
297
294
  };
298
295
  labelPath: string;
299
- labelUnreadCounts?: {
300
- [x: string]: number;
301
- } | undefined;
302
296
  }, Context, unknown>;
303
297
  readonly delete: import("@rocicorp/zero").MutatorDefinition<{
304
298
  accounts: {
@@ -306,18 +300,12 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
306
300
  threadIds: string[];
307
301
  };
308
302
  };
309
- labelUnreadCounts?: {
310
- [x: string]: number;
311
- } | undefined;
312
303
  }, {
313
304
  accounts: {
314
305
  [x: string]: {
315
306
  threadIds: string[];
316
307
  };
317
308
  };
318
- labelUnreadCounts?: {
319
- [x: string]: number;
320
- } | undefined;
321
309
  }, Context, unknown>;
322
310
  readonly removeLabel: import("@rocicorp/zero").MutatorDefinition<{
323
311
  accounts: {
@@ -326,9 +314,6 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
326
314
  };
327
315
  };
328
316
  labelPath: string;
329
- labelUnreadCounts?: {
330
- [x: string]: number;
331
- } | undefined;
332
317
  }, {
333
318
  accounts: {
334
319
  [x: string]: {
@@ -336,9 +321,6 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
336
321
  };
337
322
  };
338
323
  labelPath: string;
339
- labelUnreadCounts?: {
340
- [x: string]: number;
341
- } | undefined;
342
324
  }, Context, unknown>;
343
325
  readonly setArchive: import("@rocicorp/zero").MutatorDefinition<{
344
326
  accounts: {
@@ -346,18 +328,12 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
346
328
  threadIds: string[];
347
329
  };
348
330
  };
349
- labelUnreadCounts?: {
350
- [x: string]: number;
351
- } | undefined;
352
331
  }, {
353
332
  accounts: {
354
333
  [x: string]: {
355
334
  threadIds: string[];
356
335
  };
357
336
  };
358
- labelUnreadCounts?: {
359
- [x: string]: number;
360
- } | undefined;
361
337
  }, Context, unknown>;
362
338
  readonly setFlagged: import("@rocicorp/zero").MutatorDefinition<{
363
339
  accounts: {
@@ -380,18 +356,12 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
380
356
  threadIds: string[];
381
357
  };
382
358
  };
383
- labelUnreadCounts?: {
384
- [x: string]: number;
385
- } | undefined;
386
359
  }, {
387
360
  accounts: {
388
361
  [x: string]: {
389
362
  threadIds: string[];
390
363
  };
391
364
  };
392
- labelUnreadCounts?: {
393
- [x: string]: number;
394
- } | undefined;
395
365
  }, Context, unknown>;
396
366
  readonly setSeen: import("@rocicorp/zero").MutatorDefinition<{
397
367
  accounts: {
@@ -399,9 +369,6 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
399
369
  threadIds: string[];
400
370
  };
401
371
  };
402
- labelUnreadCounts?: {
403
- [x: string]: number;
404
- } | undefined;
405
372
  seen: boolean;
406
373
  }, {
407
374
  accounts: {
@@ -409,9 +376,6 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
409
376
  threadIds: string[];
410
377
  };
411
378
  };
412
- labelUnreadCounts?: {
413
- [x: string]: number;
414
- } | undefined;
415
379
  seen: boolean;
416
380
  }, Context, unknown>;
417
381
  readonly setSpam: import("@rocicorp/zero").MutatorDefinition<{
@@ -420,18 +384,12 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
420
384
  threadIds: string[];
421
385
  };
422
386
  };
423
- labelUnreadCounts?: {
424
- [x: string]: number;
425
- } | undefined;
426
387
  }, {
427
388
  accounts: {
428
389
  [x: string]: {
429
390
  threadIds: string[];
430
391
  };
431
392
  };
432
- labelUnreadCounts?: {
433
- [x: string]: number;
434
- } | undefined;
435
393
  }, Context, unknown>;
436
394
  readonly setTrash: import("@rocicorp/zero").MutatorDefinition<{
437
395
  accounts: {
@@ -439,18 +397,12 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
439
397
  threadIds: string[];
440
398
  };
441
399
  };
442
- labelUnreadCounts?: {
443
- [x: string]: number;
444
- } | undefined;
445
400
  }, {
446
401
  accounts: {
447
402
  [x: string]: {
448
403
  threadIds: string[];
449
404
  };
450
405
  };
451
- labelUnreadCounts?: {
452
- [x: string]: number;
453
- } | undefined;
454
406
  }, Context, unknown>;
455
407
  };
456
408
  readonly user: {
@@ -1159,6 +1111,15 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
1159
1111
  } & {
1160
1112
  serverName: string;
1161
1113
  };
1114
+ readonly unsubscribeUrl: Omit<{
1115
+ type: "string";
1116
+ optional: false;
1117
+ customType: string;
1118
+ }, "optional"> & {
1119
+ optional: true;
1120
+ } & {
1121
+ serverName: string;
1122
+ };
1162
1123
  };
1163
1124
  primaryKey: readonly [string, ...string[]];
1164
1125
  } & {
@@ -1405,7 +1366,7 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
1405
1366
  }];
1406
1367
  messages: [{
1407
1368
  readonly sourceField: readonly ("id" | "userId" | "accountId" | "subject" | "flagged" | "hasAttachments" | "labelIdList" | "latestMessageDate" | "latestMessageId" | "messageCount" | "previewText" | "seen" | "senderEmail" | "senderName" | "words")[];
1408
- readonly destField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject")[];
1369
+ readonly destField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject" | "unsubscribeUrl")[];
1409
1370
  readonly destSchema: "threadMessage";
1410
1371
  readonly cardinality: "many";
1411
1372
  }];
@@ -1431,7 +1392,7 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
1431
1392
  }];
1432
1393
  message: [{
1433
1394
  readonly sourceField: readonly ("accountId" | "uidValidity" | "labelId" | "lastSyncedAt" | "threadId" | "threadMessageId" | "uid")[];
1434
- readonly destField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject")[];
1395
+ readonly destField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject" | "unsubscribeUrl")[];
1435
1396
  readonly destSchema: "threadMessage";
1436
1397
  readonly cardinality: "one";
1437
1398
  }];
@@ -1458,13 +1419,13 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
1458
1419
  };
1459
1420
  readonly threadMessage: {
1460
1421
  attachments: [{
1461
- readonly sourceField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject")[];
1422
+ readonly sourceField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject" | "unsubscribeUrl")[];
1462
1423
  readonly destField: readonly ("id" | "fileName" | "mimeType" | "threadMessageId" | "size")[];
1463
1424
  readonly destSchema: "threadMessageAttachment";
1464
1425
  readonly cardinality: "many";
1465
1426
  }];
1466
1427
  labels: [{
1467
- readonly sourceField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject")[];
1428
+ readonly sourceField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject" | "unsubscribeUrl")[];
1468
1429
  readonly destField: readonly ("accountId" | "uidValidity" | "labelId" | "lastSyncedAt" | "threadId" | "threadMessageId" | "uid")[];
1469
1430
  readonly destSchema: "threadLabel";
1470
1431
  readonly cardinality: "many";
@@ -1475,13 +1436,13 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
1475
1436
  readonly cardinality: "many";
1476
1437
  }];
1477
1438
  recipients: [{
1478
- readonly sourceField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject")[];
1439
+ readonly sourceField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject" | "unsubscribeUrl")[];
1479
1440
  readonly destField: readonly ("type" | "id" | "name" | "emailAddress" | "threadMessageId")[];
1480
1441
  readonly destSchema: "threadMessageRecipient";
1481
1442
  readonly cardinality: "many";
1482
1443
  }];
1483
1444
  thread: [{
1484
- readonly sourceField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject")[];
1445
+ readonly sourceField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject" | "unsubscribeUrl")[];
1485
1446
  readonly destField: readonly ("id" | "userId" | "accountId" | "subject" | "flagged" | "hasAttachments" | "labelIdList" | "latestMessageDate" | "latestMessageId" | "messageCount" | "previewText" | "seen" | "senderEmail" | "senderName" | "words")[];
1486
1447
  readonly destSchema: "thread";
1487
1448
  readonly cardinality: "one";
@@ -1490,7 +1451,7 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
1490
1451
  readonly threadMessageRecipient: {
1491
1452
  message: [{
1492
1453
  readonly sourceField: readonly ("type" | "id" | "name" | "emailAddress" | "threadMessageId")[];
1493
- readonly destField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject")[];
1454
+ readonly destField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject" | "unsubscribeUrl")[];
1494
1455
  readonly destSchema: "threadMessage";
1495
1456
  readonly cardinality: "one";
1496
1457
  }];
@@ -1498,7 +1459,7 @@ export declare const mutators: import("@rocicorp/zero").MutatorRegistry<{
1498
1459
  readonly threadMessageAttachment: {
1499
1460
  message: [{
1500
1461
  readonly sourceField: readonly ("id" | "fileName" | "mimeType" | "threadMessageId" | "size")[];
1501
- readonly destField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject")[];
1462
+ readonly destField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject" | "unsubscribeUrl")[];
1502
1463
  readonly destSchema: "threadMessage";
1503
1464
  readonly cardinality: "one";
1504
1465
  }];
@@ -1 +1 @@
1
- {"version":3,"file":"mutators.d.ts","sourceRoot":"","sources":["../../src/zero/mutators.ts"],"names":[],"mappings":"AAQA,KAAK,OAAO,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAmHjC,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiiBnB,CAAA"}
1
+ {"version":3,"file":"mutators.d.ts","sourceRoot":"","sources":["../../src/zero/mutators.ts"],"names":[],"mappings":"AAQA,KAAK,OAAO,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAqGjC,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6fnB,CAAA"}
@@ -6,7 +6,7 @@ import { schema } from '../zero/schema';
6
6
  const zql = createBuilder(schema);
7
7
  const defineMutator = defineMutatorWithType();
8
8
  const buildLabelIdList = (x) => (x.length === 0 ? '' : ` ${[...new Set(x)].join(' ')} `);
9
- const setSystemLabel = async (tx, builder, threadId, targetSpecialUse, labelUnreadCounts) => {
9
+ const setSystemLabel = async (tx, builder, threadId, targetSpecialUse) => {
10
10
  const thread = await tx.run(builder.thread.where('id', threadId).one());
11
11
  if (thread) {
12
12
  const [targetLabel, messages] = await Promise.all([
@@ -33,19 +33,11 @@ const setSystemLabel = async (tx, builder, threadId, targetSpecialUse, labelUnre
33
33
  ...[...labelIdsToRemove].map(labelId => tx.mutate.threadByLabel.delete({ labelId, threadId })),
34
34
  ]);
35
35
  if (thread.seen === false && labelIdsToRemove.size > 0) {
36
- if (labelUnreadCounts) {
37
- await Promise.all([...labelIdsToRemove].map(labelId => tx.mutate.accountLabel.update({
38
- id: labelId,
39
- unreadCount: labelUnreadCounts[labelId] ?? 0,
40
- })));
41
- }
42
- else {
43
- const labelsToUpdate = await tx.run(builder.accountLabel.where('id', 'IN', [...labelIdsToRemove]));
44
- await Promise.all(labelsToUpdate.map(label => tx.mutate.accountLabel.update({
45
- id: label.id,
46
- unreadCount: Math.max(0, (label.unreadCount ?? 0) - 1),
47
- })));
48
- }
36
+ const labelsToUpdate = await tx.run(builder.accountLabel.where('id', 'IN', [...labelIdsToRemove]));
37
+ await Promise.all(labelsToUpdate.map(label => tx.mutate.accountLabel.update({
38
+ id: label.id,
39
+ unreadCount: Math.max(0, (label.unreadCount ?? 0) - 1),
40
+ })));
49
41
  }
50
42
  if (!hasTarget) {
51
43
  const baseTimestamp = Date.now();
@@ -68,9 +60,7 @@ const setSystemLabel = async (tx, builder, threadId, targetSpecialUse, labelUnre
68
60
  ? [
69
61
  tx.mutate.accountLabel.update({
70
62
  id: targetLabel.id,
71
- unreadCount: labelUnreadCounts
72
- ? (labelUnreadCounts[targetLabel.id] ?? 0)
73
- : (targetLabel.unreadCount ?? 0) + 1,
63
+ unreadCount: (targetLabel.unreadCount ?? 0) + 1,
74
64
  }),
75
65
  ]
76
66
  : []),
@@ -339,9 +329,7 @@ export const mutators = defineMutators({
339
329
  ? [
340
330
  tx.mutate.accountLabel.update({
341
331
  id: label.id,
342
- unreadCount: args.labelUnreadCounts
343
- ? (args.labelUnreadCounts[label.id] ?? 0)
344
- : (label.unreadCount ?? 0) + 1,
332
+ unreadCount: (label.unreadCount ?? 0) + 1,
345
333
  }),
346
334
  ]
347
335
  : []),
@@ -379,19 +367,11 @@ export const mutators = defineMutators({
379
367
  if (thread.seen === false) {
380
368
  const labelIds = threadsUtils.parseLabelIdList(thread.labelIdList);
381
369
  if (labelIds.length > 0) {
382
- if (args.labelUnreadCounts) {
383
- await Promise.all(labelIds.map(labelId => tx.mutate.accountLabel.update({
384
- id: labelId,
385
- unreadCount: args.labelUnreadCounts?.[labelId] ?? 0,
386
- })));
387
- }
388
- else {
389
- const labels = await tx.run(zql.accountLabel.where('id', 'IN', labelIds));
390
- await Promise.all(labels.map(x => tx.mutate.accountLabel.update({
391
- id: x.id,
392
- unreadCount: Math.max(0, (x.unreadCount ?? 0) - 1),
393
- })));
394
- }
370
+ const labels = await tx.run(zql.accountLabel.where('id', 'IN', labelIds));
371
+ await Promise.all(labels.map(x => tx.mutate.accountLabel.update({
372
+ id: x.id,
373
+ unreadCount: Math.max(0, (x.unreadCount ?? 0) - 1),
374
+ })));
395
375
  }
396
376
  }
397
377
  await tx.mutate.thread.delete({
@@ -428,9 +408,7 @@ export const mutators = defineMutators({
428
408
  ? [
429
409
  tx.mutate.accountLabel.update({
430
410
  id: label.id,
431
- unreadCount: args.labelUnreadCounts
432
- ? (args.labelUnreadCounts[label.id] ?? 0)
433
- : Math.max(0, (label.unreadCount ?? 0) - 1),
411
+ unreadCount: Math.max(0, (label.unreadCount ?? 0) - 1),
434
412
  }),
435
413
  ]
436
414
  : []),
@@ -448,7 +426,7 @@ export const mutators = defineMutators({
448
426
  setArchive: defineMutator(mutatorSchemas.thread.setArchive, async ({ tx, args }) => {
449
427
  for (const [, { threadIds }] of Object.entries(args.accounts)) {
450
428
  for (const threadId of threadIds) {
451
- await setSystemLabel(tx, zql, threadId, 'ARCHIVE', args.labelUnreadCounts);
429
+ await setSystemLabel(tx, zql, threadId, 'ARCHIVE');
452
430
  }
453
431
  }
454
432
  }),
@@ -463,46 +441,30 @@ export const mutators = defineMutators({
463
441
  setInbox: defineMutator(mutatorSchemas.thread.setInbox, async ({ tx, args }) => {
464
442
  for (const [, { threadIds }] of Object.entries(args.accounts)) {
465
443
  for (const threadId of threadIds) {
466
- await setSystemLabel(tx, zql, threadId, 'INBOX', args.labelUnreadCounts);
444
+ await setSystemLabel(tx, zql, threadId, 'INBOX');
467
445
  }
468
446
  }
469
447
  }),
470
448
  setSeen: defineMutator(mutatorSchemas.thread.setSeen, async ({ tx, args }) => {
471
449
  const allThreadIds = Object.values(args.accounts).flatMap(x => x.threadIds);
472
450
  const threads = await tx.run(zql.thread.where('id', 'IN', allThreadIds));
473
- const affectedLabelIds = new Set();
451
+ const labelCounts = new Map();
474
452
  for (const thread of threads) {
475
453
  if (thread.seen !== args.seen) {
476
454
  for (const labelId of threadsUtils.parseLabelIdList(thread.labelIdList)) {
477
- affectedLabelIds.add(labelId);
455
+ labelCounts.set(labelId, (labelCounts.get(labelId) ?? 0) + 1);
478
456
  }
479
457
  }
480
458
  }
481
- if (affectedLabelIds.size > 0) {
482
- if (args.labelUnreadCounts) {
483
- await Promise.all([...affectedLabelIds].map(labelId => tx.mutate.accountLabel.update({
484
- id: labelId,
485
- unreadCount: args.labelUnreadCounts?.[labelId] ?? 0,
486
- })));
487
- }
488
- else {
489
- const labelCounts = new Map();
490
- for (const thread of threads) {
491
- if (thread.seen !== args.seen) {
492
- for (const labelId of threadsUtils.parseLabelIdList(thread.labelIdList)) {
493
- labelCounts.set(labelId, (labelCounts.get(labelId) ?? 0) + 1);
494
- }
495
- }
496
- }
497
- const labels = await tx.run(zql.accountLabel.where('id', 'IN', [...labelCounts.keys()]));
498
- const delta = args.seen ? -1 : 1;
499
- await Promise.all(labels
500
- .filter(x => labelCounts.has(x.id))
501
- .map(x => tx.mutate.accountLabel.update({
502
- id: x.id,
503
- unreadCount: Math.max(0, (x.unreadCount ?? 0) + delta * (labelCounts.get(x.id) ?? 0)),
504
- })));
505
- }
459
+ if (labelCounts.size > 0) {
460
+ const labels = await tx.run(zql.accountLabel.where('id', 'IN', [...labelCounts.keys()]));
461
+ const delta = args.seen ? -1 : 1;
462
+ await Promise.all(labels
463
+ .filter(x => labelCounts.has(x.id))
464
+ .map(x => tx.mutate.accountLabel.update({
465
+ id: x.id,
466
+ unreadCount: Math.max(0, (x.unreadCount ?? 0) + delta * (labelCounts.get(x.id) ?? 0)),
467
+ })));
506
468
  }
507
469
  await Promise.all(allThreadIds.map(threadId => tx.mutate.thread.update({
508
470
  id: threadId,
@@ -512,14 +474,14 @@ export const mutators = defineMutators({
512
474
  setSpam: defineMutator(mutatorSchemas.thread.setSpam, async ({ tx, args }) => {
513
475
  for (const [, { threadIds }] of Object.entries(args.accounts)) {
514
476
  for (const threadId of threadIds) {
515
- await setSystemLabel(tx, zql, threadId, 'SPAM', args.labelUnreadCounts);
477
+ await setSystemLabel(tx, zql, threadId, 'SPAM');
516
478
  }
517
479
  }
518
480
  }),
519
481
  setTrash: defineMutator(mutatorSchemas.thread.setTrash, async ({ tx, args }) => {
520
482
  for (const [, { threadIds }] of Object.entries(args.accounts)) {
521
483
  for (const threadId of threadIds) {
522
- await setSystemLabel(tx, zql, threadId, 'TRASH', args.labelUnreadCounts);
484
+ await setSystemLabel(tx, zql, threadId, 'TRASH');
523
485
  }
524
486
  }
525
487
  }),
@@ -440,25 +440,6 @@ describe('mutators', () => {
440
440
  expect(tx.mutate.thread.update).not.toHaveBeenCalled();
441
441
  expect(tx.mutate.threadByLabel.insert).not.toHaveBeenCalled();
442
442
  });
443
- it('uses pre-computed labelUnreadCounts when provided', async () => {
444
- tx.run = mock()
445
- .mockResolvedValueOnce({ id: 'label-1', uidValidity: 1, unreadCount: 0 })
446
- .mockResolvedValueOnce({
447
- id: 'thread-1',
448
- labelIdList: ' label-2 ',
449
- latestMessageDate: 1234567890,
450
- seen: false,
451
- })
452
- .mockResolvedValueOnce([{ id: 'message-1' }])
453
- .mockResolvedValueOnce(null);
454
- const args = {
455
- accounts: { 'account-1': { threadIds: ['thread-1'] } },
456
- labelPath: 'INBOX',
457
- labelUnreadCounts: { 'label-1': 42 },
458
- };
459
- await mutators.thread.addLabel.fn({ args, ctx, tx: tx });
460
- expect(tx.mutate.accountLabel.update).toHaveBeenCalledWith({ id: 'label-1', unreadCount: 42 });
461
- });
462
443
  });
463
444
  describe('delete', () => {
464
445
  it('deletes threads and updates unread counts', async () => {
@@ -477,16 +458,6 @@ describe('mutators', () => {
477
458
  expect(tx.mutate.accountLabel.update).not.toHaveBeenCalled();
478
459
  expect(tx.mutate.thread.delete).toHaveBeenCalledWith({ id: 'thread-1' });
479
460
  });
480
- it('uses pre-computed labelUnreadCounts when provided', async () => {
481
- tx.run = mock().mockResolvedValueOnce({ id: 'thread-1', labelIdList: ' label-1 ', seen: false });
482
- const args = {
483
- accounts: { 'account-1': { threadIds: ['thread-1'] } },
484
- labelUnreadCounts: { 'label-1': 42 },
485
- };
486
- await mutators.thread.delete.fn({ args, ctx, tx: tx });
487
- expect(tx.mutate.accountLabel.update).toHaveBeenCalledWith({ id: 'label-1', unreadCount: 42 });
488
- expect(tx.run).toHaveBeenCalledTimes(1);
489
- });
490
461
  });
491
462
  describe('removeLabel', () => {
492
463
  it('removes a label from threads', async () => {
@@ -523,19 +494,6 @@ describe('mutators', () => {
523
494
  expect(tx.mutate.threadLabel.delete).not.toHaveBeenCalled();
524
495
  expect(tx.mutate.threadByLabel.delete).not.toHaveBeenCalled();
525
496
  });
526
- it('uses pre-computed labelUnreadCounts when provided', async () => {
527
- tx.run = mock()
528
- .mockResolvedValueOnce({ id: 'label-1', unreadCount: 5 })
529
- .mockResolvedValueOnce({ id: 'thread-1', labelIdList: ' label-1 label-2 ', seen: false })
530
- .mockResolvedValueOnce([{ id: 'message-1' }]);
531
- const args = {
532
- accounts: { 'account-1': { threadIds: ['thread-1'] } },
533
- labelPath: 'INBOX',
534
- labelUnreadCounts: { 'label-1': 42 },
535
- };
536
- await mutators.thread.removeLabel.fn({ args, ctx, tx: tx });
537
- expect(tx.mutate.accountLabel.update).toHaveBeenCalledWith({ id: 'label-1', unreadCount: 42 });
538
- });
539
497
  });
540
498
  describe('setFlagged', () => {
541
499
  it('sets flagged status', async () => {
@@ -570,17 +528,6 @@ describe('mutators', () => {
570
528
  await mutators.thread.setSeen.fn({ args, ctx, tx: tx });
571
529
  expect(tx.mutate.accountLabel.update).not.toHaveBeenCalled();
572
530
  });
573
- it('uses pre-computed labelUnreadCounts when provided', async () => {
574
- tx.run = mock().mockResolvedValueOnce([{ id: 'thread-1', labelIdList: ' label-1 ', seen: false }]);
575
- const args = {
576
- accounts: { 'account-1': { threadIds: ['thread-1'] } },
577
- labelUnreadCounts: { 'label-1': 42 },
578
- seen: true,
579
- };
580
- await mutators.thread.setSeen.fn({ args, ctx, tx: tx });
581
- expect(tx.mutate.accountLabel.update).toHaveBeenCalledWith({ id: 'label-1', unreadCount: 42 });
582
- expect(tx.run).toHaveBeenCalledTimes(1);
583
- });
584
531
  });
585
532
  const systemLabelTestCases = [
586
533
  { mutatorName: 'setArchive', specialUse: 'ARCHIVE' },
@@ -615,25 +562,6 @@ describe('mutators', () => {
615
562
  labelIdList: expect.stringContaining('new-label'),
616
563
  });
617
564
  });
618
- it(`uses pre-computed labelUnreadCounts when moving unread thread to ${specialUse}`, async () => {
619
- tx.run = mock()
620
- .mockResolvedValueOnce({
621
- accountId: 'account-1',
622
- id: 'thread-1',
623
- labelIdList: ' old-label ',
624
- latestMessageDate: 1234567890,
625
- seen: false,
626
- })
627
- .mockResolvedValueOnce({ id: 'new-label', uidValidity: 1, unreadCount: 0 })
628
- .mockResolvedValueOnce([{ id: 'message-1' }]);
629
- const args = {
630
- accounts: { 'account-1': { threadIds: ['thread-1'] } },
631
- labelUnreadCounts: { 'new-label': 10, 'old-label': 5 },
632
- };
633
- await mutators.thread[mutatorName].fn({ args, ctx, tx: tx });
634
- expect(tx.mutate.accountLabel.update).toHaveBeenCalledWith({ id: 'old-label', unreadCount: 5 });
635
- expect(tx.mutate.accountLabel.update).toHaveBeenCalledWith({ id: 'new-label', unreadCount: 10 });
636
- });
637
565
  });
638
566
  }
639
567
  });
@@ -92,6 +92,7 @@ export declare const queries: import("@rocicorp/zero").QueryRegistry<{
92
92
  readonly senderEmail: string;
93
93
  readonly senderName: string | null;
94
94
  readonly threadId: string;
95
+ readonly unsubscribeUrl: string | null;
95
96
  } & {
96
97
  readonly recipients: readonly {
97
98
  readonly emailAddress: string;
@@ -123,6 +124,7 @@ export declare const queries: import("@rocicorp/zero").QueryRegistry<{
123
124
  readonly senderEmail: string;
124
125
  readonly senderName: string | null;
125
126
  readonly threadId: string;
127
+ readonly unsubscribeUrl: string | null;
126
128
  } & {
127
129
  readonly thread: {
128
130
  readonly accountId: string;
@@ -240,6 +242,7 @@ export declare const queries: import("@rocicorp/zero").QueryRegistry<{
240
242
  readonly senderEmail: string;
241
243
  readonly senderName: string | null;
242
244
  readonly threadId: string;
245
+ readonly unsubscribeUrl: string | null;
243
246
  } & {
244
247
  readonly recipients: readonly {
245
248
  readonly emailAddress: string;
@@ -984,6 +987,15 @@ export declare const queries: import("@rocicorp/zero").QueryRegistry<{
984
987
  } & {
985
988
  serverName: string;
986
989
  };
990
+ readonly unsubscribeUrl: Omit<{
991
+ type: "string";
992
+ optional: false;
993
+ customType: string;
994
+ }, "optional"> & {
995
+ optional: true;
996
+ } & {
997
+ serverName: string;
998
+ };
987
999
  };
988
1000
  primaryKey: readonly [string, ...string[]];
989
1001
  } & {
@@ -1230,7 +1242,7 @@ export declare const queries: import("@rocicorp/zero").QueryRegistry<{
1230
1242
  }];
1231
1243
  messages: [{
1232
1244
  readonly sourceField: readonly ("id" | "userId" | "accountId" | "subject" | "flagged" | "hasAttachments" | "labelIdList" | "latestMessageDate" | "latestMessageId" | "messageCount" | "previewText" | "seen" | "senderEmail" | "senderName" | "words")[];
1233
- readonly destField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject")[];
1245
+ readonly destField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject" | "unsubscribeUrl")[];
1234
1246
  readonly destSchema: "threadMessage";
1235
1247
  readonly cardinality: "many";
1236
1248
  }];
@@ -1256,7 +1268,7 @@ export declare const queries: import("@rocicorp/zero").QueryRegistry<{
1256
1268
  }];
1257
1269
  message: [{
1258
1270
  readonly sourceField: readonly ("accountId" | "uidValidity" | "labelId" | "lastSyncedAt" | "threadId" | "threadMessageId" | "uid")[];
1259
- readonly destField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject")[];
1271
+ readonly destField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject" | "unsubscribeUrl")[];
1260
1272
  readonly destSchema: "threadMessage";
1261
1273
  readonly cardinality: "one";
1262
1274
  }];
@@ -1283,13 +1295,13 @@ export declare const queries: import("@rocicorp/zero").QueryRegistry<{
1283
1295
  };
1284
1296
  readonly threadMessage: {
1285
1297
  attachments: [{
1286
- readonly sourceField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject")[];
1298
+ readonly sourceField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject" | "unsubscribeUrl")[];
1287
1299
  readonly destField: readonly ("id" | "fileName" | "mimeType" | "threadMessageId" | "size")[];
1288
1300
  readonly destSchema: "threadMessageAttachment";
1289
1301
  readonly cardinality: "many";
1290
1302
  }];
1291
1303
  labels: [{
1292
- readonly sourceField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject")[];
1304
+ readonly sourceField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject" | "unsubscribeUrl")[];
1293
1305
  readonly destField: readonly ("accountId" | "uidValidity" | "labelId" | "lastSyncedAt" | "threadId" | "threadMessageId" | "uid")[];
1294
1306
  readonly destSchema: "threadLabel";
1295
1307
  readonly cardinality: "many";
@@ -1300,13 +1312,13 @@ export declare const queries: import("@rocicorp/zero").QueryRegistry<{
1300
1312
  readonly cardinality: "many";
1301
1313
  }];
1302
1314
  recipients: [{
1303
- readonly sourceField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject")[];
1315
+ readonly sourceField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject" | "unsubscribeUrl")[];
1304
1316
  readonly destField: readonly ("type" | "id" | "name" | "emailAddress" | "threadMessageId")[];
1305
1317
  readonly destSchema: "threadMessageRecipient";
1306
1318
  readonly cardinality: "many";
1307
1319
  }];
1308
1320
  thread: [{
1309
- readonly sourceField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject")[];
1321
+ readonly sourceField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject" | "unsubscribeUrl")[];
1310
1322
  readonly destField: readonly ("id" | "userId" | "accountId" | "subject" | "flagged" | "hasAttachments" | "labelIdList" | "latestMessageDate" | "latestMessageId" | "messageCount" | "previewText" | "seen" | "senderEmail" | "senderName" | "words")[];
1311
1323
  readonly destSchema: "thread";
1312
1324
  readonly cardinality: "one";
@@ -1315,7 +1327,7 @@ export declare const queries: import("@rocicorp/zero").QueryRegistry<{
1315
1327
  readonly threadMessageRecipient: {
1316
1328
  message: [{
1317
1329
  readonly sourceField: readonly ("type" | "id" | "name" | "emailAddress" | "threadMessageId")[];
1318
- readonly destField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject")[];
1330
+ readonly destField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject" | "unsubscribeUrl")[];
1319
1331
  readonly destSchema: "threadMessage";
1320
1332
  readonly cardinality: "one";
1321
1333
  }];
@@ -1323,7 +1335,7 @@ export declare const queries: import("@rocicorp/zero").QueryRegistry<{
1323
1335
  readonly threadMessageAttachment: {
1324
1336
  message: [{
1325
1337
  readonly sourceField: readonly ("id" | "fileName" | "mimeType" | "threadMessageId" | "size")[];
1326
- readonly destField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject")[];
1338
+ readonly destField: readonly ("id" | "accountId" | "previewText" | "senderEmail" | "senderName" | "threadId" | "envelopeDate" | "envelopeSubject" | "unsubscribeUrl")[];
1327
1339
  readonly destSchema: "threadMessage";
1328
1340
  readonly cardinality: "one";
1329
1341
  }];
@@ -1 +1 @@
1
- {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/zero/queries.ts"],"names":[],"mappings":"AAOA,KAAK,OAAO,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAQjC,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoOlB,CAAA"}
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/zero/queries.ts"],"names":[],"mappings":"AAOA,KAAK,OAAO,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAQjC,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoOlB,CAAA"}