@greatwait/contracts 0.3.0 → 0.3.2

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.
Files changed (104) hide show
  1. package/dist/attempt-diagnostics.d.ts +1 -1
  2. package/dist/attempt-diagnostics.js +13 -1
  3. package/dist/attempt-search.d.ts +2 -0
  4. package/dist/attempt-search.js +22 -19
  5. package/dist/authority.js +9 -9
  6. package/dist/billing.d.ts +46 -0
  7. package/dist/billing.js +29 -0
  8. package/dist/callback-safety.js +5 -1
  9. package/dist/configuration.d.ts +6 -2
  10. package/dist/configuration.js +93 -52
  11. package/dist/delivery.d.ts +13 -1
  12. package/dist/delivery.js +2 -0
  13. package/dist/effective-limits.d.ts +4 -4
  14. package/dist/endpoints.d.ts +29 -0
  15. package/dist/endpoints.js +57 -26
  16. package/dist/forecast.d.ts +2 -2
  17. package/dist/http-request.d.ts +12 -2
  18. package/dist/http-request.js +56 -24
  19. package/dist/identifiers.js +20 -20
  20. package/dist/index.d.ts +8 -7
  21. package/dist/index.js +8 -7
  22. package/dist/mcp.js +1 -0
  23. package/dist/operational-config.d.ts +174 -22
  24. package/dist/operational-config.js +213 -79
  25. package/dist/operations.d.ts +334 -52
  26. package/dist/operations.js +195 -34
  27. package/dist/project-notifications.d.ts +35 -9
  28. package/dist/project-notifications.js +43 -12
  29. package/dist/protocol.d.ts +28 -0
  30. package/dist/protocol.js +56 -33
  31. package/dist/schedule-selection.js +2 -2
  32. package/dist/scheduling-records.d.ts +106 -16
  33. package/dist/scheduling-records.js +36 -12
  34. package/dist/scheduling.d.ts +200 -43
  35. package/dist/scheduling.js +280 -131
  36. package/dist/service-mode.d.ts +88 -0
  37. package/dist/service-mode.js +130 -0
  38. package/dist/signatures.d.ts +6 -6
  39. package/dist/signatures.js +24 -24
  40. package/dist/stored-http.d.ts +18 -0
  41. package/dist/stored-http.js +106 -0
  42. package/dist/tenancy.d.ts +54 -30
  43. package/dist/tenancy.js +35 -17
  44. package/dist/time.js +7 -7
  45. package/dist/timing.d.ts +39 -0
  46. package/dist/timing.js +51 -0
  47. package/dist/zod-values.d.ts +1 -1
  48. package/dist/zod-values.js +1 -1
  49. package/dist/zod.d.ts +1 -1
  50. package/dist/zod.js +1 -1
  51. package/generated/v1/examples/billing.noticesdismiss.request.json +3 -0
  52. package/generated/v1/examples/billing.noticesdismiss.response.json +6 -0
  53. package/generated/v1/examples/billing.reconcile.response.json +12 -0
  54. package/generated/v1/examples/billing.summary.response.json +12 -0
  55. package/generated/v1/examples/executions.list.response.json +1 -0
  56. package/generated/v1/examples/limits.read.response.json +1 -1
  57. package/generated/v1/examples/projectnotifications.rotateSigningKey.response.json +1 -0
  58. package/generated/v1/examples/projects.list.response.json +0 -6
  59. package/generated/v1/examples/projects.read.response.json +14 -0
  60. package/generated/v1/examples/schedules.list.response.json +1 -3
  61. package/generated/v1/examples/schedules.summary.response.json +174 -0
  62. package/generated/v1/examples/timing.summary.response.json +33 -1
  63. package/generated/v1/manifest.json +79 -2
  64. package/generated/v1/openapi.json +4084 -2023
  65. package/generated/v1/policy-matrix.json +22 -1
  66. package/generated/v1/schemas/attempts.list.response.json +10 -0
  67. package/generated/v1/schemas/attempts.read.response.json +10 -0
  68. package/generated/v1/schemas/attempts.search.response.json +4 -0
  69. package/generated/v1/schemas/billing.notices.query.json +4 -0
  70. package/generated/v1/schemas/billing.noticesdismiss.request.json +12 -0
  71. package/generated/v1/schemas/billing.noticesdismiss.response.json +22 -0
  72. package/generated/v1/schemas/billing.reconcile.response.json +43 -0
  73. package/generated/v1/schemas/billing.summary.response.json +43 -0
  74. package/generated/v1/schemas/endpoints.list.query.json +15 -0
  75. package/generated/v1/schemas/executions.list.response.json +4 -0
  76. package/generated/v1/schemas/occurrences.list.response.json +4 -0
  77. package/generated/v1/schemas/occurrences.read.response.json +4 -0
  78. package/generated/v1/schemas/occurrences.redeliver.response.json +10 -0
  79. package/generated/v1/schemas/projectnotifications.read.response.json +4 -0
  80. package/generated/v1/schemas/projectnotifications.rotateSigningKey.response.json +4 -0
  81. package/generated/v1/schemas/projectnotifications.update.request.json +41 -17
  82. package/generated/v1/schemas/projectnotifications.update.response.json +4 -0
  83. package/generated/v1/schemas/projects.list.response.json +0 -27
  84. package/generated/v1/schemas/projects.read.response-headers.json +11 -0
  85. package/generated/v1/schemas/projects.read.response.json +79 -0
  86. package/generated/v1/schemas/schedules.archive.response.json +8 -0
  87. package/generated/v1/schemas/schedules.cancel.response.json +8 -0
  88. package/generated/v1/schemas/schedules.create.request.json +1 -1
  89. package/generated/v1/schemas/schedules.create.response.json +8 -0
  90. package/generated/v1/schemas/schedules.list.query.json +6 -0
  91. package/generated/v1/schemas/schedules.list.response.json +4 -0
  92. package/generated/v1/schemas/schedules.pause.response.json +8 -0
  93. package/generated/v1/schemas/schedules.read.response.json +8 -0
  94. package/generated/v1/schemas/schedules.replace.request.json +1 -1
  95. package/generated/v1/schemas/schedules.replace.response.json +8 -0
  96. package/generated/v1/schemas/schedules.resume.response.json +8 -0
  97. package/generated/v1/schemas/schedules.summary.query.json +11 -0
  98. package/generated/v1/schemas/schedules.summary.response.json +144 -0
  99. package/generated/v1/schemas/timing.summary.response.json +69 -0
  100. package/generated/v1/snippets/billing.noticesdismiss.json +6 -0
  101. package/generated/v1/snippets/projectnotifications.rotateSigningKey.json +1 -1
  102. package/generated/v1/snippets/projects.read.json +6 -0
  103. package/generated/v1/snippets/schedules.summary.json +6 -0
  104. package/package.json +1 -1
@@ -34,11 +34,21 @@ export declare const portableScheduleRecordSchema: import("zod").ZodObject<{
34
34
  name: import("zod").ZodString;
35
35
  suppressed: import("zod").ZodLiteral<true>;
36
36
  }, import("zod/v4/core").$strict>]>>;
37
- encryptedTemplate: import("zod").ZodOptional<import("zod").ZodObject<{
37
+ encryptedTemplate: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodObject<{
38
38
  keyId: import("zod").ZodLiteral<"v1">;
39
39
  nonce: import("zod").ZodString;
40
40
  ciphertext: import("zod").ZodString;
41
- }, import("zod/v4/core").$strict>>;
41
+ }, import("zod/v4/core").$strict>, import("zod").ZodObject<{
42
+ keyId: import("zod").ZodLiteral<"v1">;
43
+ nonce: import("zod").ZodString;
44
+ ciphertext: import("zod").ZodString;
45
+ version: import("zod").ZodLiteral<2>;
46
+ codec: import("zod").ZodEnum<{
47
+ identity: "identity";
48
+ gzip: "gzip";
49
+ }>;
50
+ originalBytes: import("zod").ZodNumber;
51
+ }, import("zod/v4/core").$strict>]>>;
42
52
  }, import("zod/v4/core").$strict>>;
43
53
  httpTemplateRetentionDueAt: import("zod").ZodOptional<import("zod").ZodString>;
44
54
  authority: import("zod").ZodObject<{
@@ -106,9 +116,14 @@ export declare const portableScheduleRecordSchema: import("zod").ZodObject<{
106
116
  generation: import("zod").ZodNumber;
107
117
  id: import("zod").ZodString;
108
118
  latencyClass: import("zod").ZodEnum<{
109
- realtime: "realtime";
110
119
  bulk: "bulk";
120
+ realtime: "realtime";
111
121
  }>;
122
+ requestedLatencyClass: import("zod").ZodOptional<import("zod").ZodEnum<{
123
+ bulk: "bulk";
124
+ realtime: "realtime";
125
+ auto: "auto";
126
+ }>>;
112
127
  lateness: import("zod").ZodObject<{
113
128
  maxStalenessSeconds: import("zod").ZodOptional<import("zod").ZodNumber>;
114
129
  policy: import("zod").ZodEnum<{
@@ -169,6 +184,7 @@ export declare const portableOccurrenceRecordSchema: import("zod").ZodObject<{
169
184
  id: import("zod").ZodString;
170
185
  plannedFor: import("zod").ZodString;
171
186
  schedule: import("zod").ZodString;
187
+ scheduleName: import("zod").ZodOptional<import("zod").ZodString>;
172
188
  sequence: import("zod").ZodNumber;
173
189
  settledAt: import("zod").ZodOptional<import("zod").ZodString>;
174
190
  state: import("zod").ZodEnum<{
@@ -269,6 +285,12 @@ export declare const portableAttemptRecordSchema: import("zod").ZodObject<{
269
285
  expired: "expired";
270
286
  not_captured: "not_captured";
271
287
  }>>;
288
+ requestUnavailable: import("zod").ZodOptional<import("zod").ZodEnum<{
289
+ schedule_changed: "schedule_changed";
290
+ endpoint_changed: "endpoint_changed";
291
+ endpoint_deleted: "endpoint_deleted";
292
+ payload_deleted: "payload_deleted";
293
+ }>>;
272
294
  responseHeaders: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
273
295
  name: import("zod").ZodString;
274
296
  value: import("zod").ZodString;
@@ -349,11 +371,21 @@ export declare const portableAttemptRecordSchema: import("zod").ZodObject<{
349
371
  name: import("zod").ZodString;
350
372
  suppressed: import("zod").ZodLiteral<true>;
351
373
  }, import("zod/v4/core").$strict>]>>;
352
- encryptedTemplate: import("zod").ZodOptional<import("zod").ZodObject<{
374
+ encryptedTemplate: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodObject<{
353
375
  keyId: import("zod").ZodLiteral<"v1">;
354
376
  nonce: import("zod").ZodString;
355
377
  ciphertext: import("zod").ZodString;
356
- }, import("zod/v4/core").$strict>>;
378
+ }, import("zod/v4/core").$strict>, import("zod").ZodObject<{
379
+ keyId: import("zod").ZodLiteral<"v1">;
380
+ nonce: import("zod").ZodString;
381
+ ciphertext: import("zod").ZodString;
382
+ version: import("zod").ZodLiteral<2>;
383
+ codec: import("zod").ZodEnum<{
384
+ identity: "identity";
385
+ gzip: "gzip";
386
+ }>;
387
+ originalBytes: import("zod").ZodNumber;
388
+ }, import("zod/v4/core").$strict>]>>;
357
389
  }, import("zod/v4/core").$strict>>;
358
390
  httpPayloadRetentionDueAt: import("zod").ZodOptional<import("zod").ZodString>;
359
391
  authority: import("zod").ZodObject<{
@@ -371,7 +403,10 @@ export declare const portableAttemptRecordSchema: import("zod").ZodObject<{
371
403
  }, import("zod/v4/core").$strict>;
372
404
  export type PortableAttemptRecord = z.infer<typeof portableAttemptRecordSchema>;
373
405
  export declare const portableEncryptedPayloadRecordSchema: import("zod").ZodObject<{
374
- aadVersion: import("zod").ZodLiteral<"greatwait.schedule-payload.v1">;
406
+ aadVersion: import("zod").ZodEnum<{
407
+ "greatwait.schedule-payload.v1": "greatwait.schedule-payload.v1";
408
+ "greatwait.schedule-payload.v2": "greatwait.schedule-payload.v2";
409
+ }>;
375
410
  authority: import("zod").ZodObject<{
376
411
  environment: import("zod").ZodString;
377
412
  environmentKind: import("zod").ZodEnum<{
@@ -381,11 +416,21 @@ export declare const portableEncryptedPayloadRecordSchema: import("zod").ZodObje
381
416
  organization: import("zod").ZodString;
382
417
  project: import("zod").ZodString;
383
418
  }, import("zod/v4/core").$strict>;
384
- envelope: import("zod").ZodObject<{
419
+ envelope: import("zod").ZodUnion<readonly [import("zod").ZodObject<{
385
420
  ciphertext: import("zod").ZodString;
386
421
  keyId: import("zod").ZodString;
387
422
  nonce: import("zod").ZodString;
388
- }, import("zod/v4/core").$strict>;
423
+ }, import("zod/v4/core").$strict>, import("zod").ZodObject<{
424
+ ciphertext: import("zod").ZodString;
425
+ keyId: import("zod").ZodString;
426
+ nonce: import("zod").ZodString;
427
+ version: import("zod").ZodLiteral<2>;
428
+ codec: import("zod").ZodEnum<{
429
+ identity: "identity";
430
+ gzip: "gzip";
431
+ }>;
432
+ originalBytes: import("zod").ZodNumber;
433
+ }, import("zod/v4/core").$strict>]>;
389
434
  plaintextBytes: import("zod").ZodNumber;
390
435
  retentionDueAt: import("zod").ZodOptional<import("zod").ZodString>;
391
436
  schedule: import("zod").ZodString;
@@ -457,6 +502,12 @@ export declare const portableSchedulingRecordSetSchema: import("zod").ZodObject<
457
502
  expired: "expired";
458
503
  not_captured: "not_captured";
459
504
  }>>;
505
+ requestUnavailable: import("zod").ZodOptional<import("zod").ZodEnum<{
506
+ schedule_changed: "schedule_changed";
507
+ endpoint_changed: "endpoint_changed";
508
+ endpoint_deleted: "endpoint_deleted";
509
+ payload_deleted: "payload_deleted";
510
+ }>>;
460
511
  responseHeaders: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
461
512
  name: import("zod").ZodString;
462
513
  value: import("zod").ZodString;
@@ -537,11 +588,21 @@ export declare const portableSchedulingRecordSetSchema: import("zod").ZodObject<
537
588
  name: import("zod").ZodString;
538
589
  suppressed: import("zod").ZodLiteral<true>;
539
590
  }, import("zod/v4/core").$strict>]>>;
540
- encryptedTemplate: import("zod").ZodOptional<import("zod").ZodObject<{
591
+ encryptedTemplate: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodObject<{
541
592
  keyId: import("zod").ZodLiteral<"v1">;
542
593
  nonce: import("zod").ZodString;
543
594
  ciphertext: import("zod").ZodString;
544
- }, import("zod/v4/core").$strict>>;
595
+ }, import("zod/v4/core").$strict>, import("zod").ZodObject<{
596
+ keyId: import("zod").ZodLiteral<"v1">;
597
+ nonce: import("zod").ZodString;
598
+ ciphertext: import("zod").ZodString;
599
+ version: import("zod").ZodLiteral<2>;
600
+ codec: import("zod").ZodEnum<{
601
+ identity: "identity";
602
+ gzip: "gzip";
603
+ }>;
604
+ originalBytes: import("zod").ZodNumber;
605
+ }, import("zod/v4/core").$strict>]>>;
545
606
  }, import("zod/v4/core").$strict>>;
546
607
  httpPayloadRetentionDueAt: import("zod").ZodOptional<import("zod").ZodString>;
547
608
  authority: import("zod").ZodObject<{
@@ -562,6 +623,7 @@ export declare const portableSchedulingRecordSetSchema: import("zod").ZodObject<
562
623
  id: import("zod").ZodString;
563
624
  plannedFor: import("zod").ZodString;
564
625
  schedule: import("zod").ZodString;
626
+ scheduleName: import("zod").ZodOptional<import("zod").ZodString>;
565
627
  sequence: import("zod").ZodNumber;
566
628
  settledAt: import("zod").ZodOptional<import("zod").ZodString>;
567
629
  state: import("zod").ZodEnum<{
@@ -599,7 +661,10 @@ export declare const portableSchedulingRecordSetSchema: import("zod").ZodObject<
599
661
  updatedAt: import("zod").ZodString;
600
662
  }, import("zod/v4/core").$strict>>;
601
663
  payload: import("zod").ZodOptional<import("zod").ZodObject<{
602
- aadVersion: import("zod").ZodLiteral<"greatwait.schedule-payload.v1">;
664
+ aadVersion: import("zod").ZodEnum<{
665
+ "greatwait.schedule-payload.v1": "greatwait.schedule-payload.v1";
666
+ "greatwait.schedule-payload.v2": "greatwait.schedule-payload.v2";
667
+ }>;
603
668
  authority: import("zod").ZodObject<{
604
669
  environment: import("zod").ZodString;
605
670
  environmentKind: import("zod").ZodEnum<{
@@ -609,11 +674,21 @@ export declare const portableSchedulingRecordSetSchema: import("zod").ZodObject<
609
674
  organization: import("zod").ZodString;
610
675
  project: import("zod").ZodString;
611
676
  }, import("zod/v4/core").$strict>;
612
- envelope: import("zod").ZodObject<{
677
+ envelope: import("zod").ZodUnion<readonly [import("zod").ZodObject<{
613
678
  ciphertext: import("zod").ZodString;
614
679
  keyId: import("zod").ZodString;
615
680
  nonce: import("zod").ZodString;
616
- }, import("zod/v4/core").$strict>;
681
+ }, import("zod/v4/core").$strict>, import("zod").ZodObject<{
682
+ ciphertext: import("zod").ZodString;
683
+ keyId: import("zod").ZodString;
684
+ nonce: import("zod").ZodString;
685
+ version: import("zod").ZodLiteral<2>;
686
+ codec: import("zod").ZodEnum<{
687
+ identity: "identity";
688
+ gzip: "gzip";
689
+ }>;
690
+ originalBytes: import("zod").ZodNumber;
691
+ }, import("zod/v4/core").$strict>]>;
617
692
  plaintextBytes: import("zod").ZodNumber;
618
693
  retentionDueAt: import("zod").ZodOptional<import("zod").ZodString>;
619
694
  schedule: import("zod").ZodString;
@@ -677,11 +752,21 @@ export declare const portableSchedulingRecordSetSchema: import("zod").ZodObject<
677
752
  name: import("zod").ZodString;
678
753
  suppressed: import("zod").ZodLiteral<true>;
679
754
  }, import("zod/v4/core").$strict>]>>;
680
- encryptedTemplate: import("zod").ZodOptional<import("zod").ZodObject<{
755
+ encryptedTemplate: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodObject<{
756
+ keyId: import("zod").ZodLiteral<"v1">;
757
+ nonce: import("zod").ZodString;
758
+ ciphertext: import("zod").ZodString;
759
+ }, import("zod/v4/core").$strict>, import("zod").ZodObject<{
681
760
  keyId: import("zod").ZodLiteral<"v1">;
682
761
  nonce: import("zod").ZodString;
683
762
  ciphertext: import("zod").ZodString;
684
- }, import("zod/v4/core").$strict>>;
763
+ version: import("zod").ZodLiteral<2>;
764
+ codec: import("zod").ZodEnum<{
765
+ identity: "identity";
766
+ gzip: "gzip";
767
+ }>;
768
+ originalBytes: import("zod").ZodNumber;
769
+ }, import("zod/v4/core").$strict>]>>;
685
770
  }, import("zod/v4/core").$strict>>;
686
771
  httpTemplateRetentionDueAt: import("zod").ZodOptional<import("zod").ZodString>;
687
772
  authority: import("zod").ZodObject<{
@@ -749,9 +834,14 @@ export declare const portableSchedulingRecordSetSchema: import("zod").ZodObject<
749
834
  generation: import("zod").ZodNumber;
750
835
  id: import("zod").ZodString;
751
836
  latencyClass: import("zod").ZodEnum<{
752
- realtime: "realtime";
753
837
  bulk: "bulk";
838
+ realtime: "realtime";
754
839
  }>;
840
+ requestedLatencyClass: import("zod").ZodOptional<import("zod").ZodEnum<{
841
+ bulk: "bulk";
842
+ realtime: "realtime";
843
+ auto: "auto";
844
+ }>>;
755
845
  lateness: import("zod").ZodObject<{
756
846
  maxStalenessSeconds: import("zod").ZodOptional<import("zod").ZodNumber>;
757
847
  policy: import("zod").ZodEnum<{
@@ -116,19 +116,35 @@ const base64UrlBytesSchema = z
116
116
  .refine((value) => decodeBase64UrlBytes(value) !== undefined, {
117
117
  message: "must canonically encode base64url bytes",
118
118
  });
119
+ const portableLegacyPayloadEnvelopeSchema = z.strictObject({
120
+ ciphertext: base64UrlBytesSchema,
121
+ keyId: z
122
+ .string()
123
+ .min(1)
124
+ .max(128)
125
+ .regex(/^[A-Za-z0-9._:-]+$/u, "must be a safe key identifier"),
126
+ nonce: base64UrlBytesSchema.refine((value) => decodeBase64UrlBytes(value)?.length === 12, { message: "must encode exactly 12 bytes" }),
127
+ });
128
+ const portableV2PayloadEnvelopeSchema = portableLegacyPayloadEnvelopeSchema.extend({
129
+ version: z.literal(2),
130
+ codec: z.enum(["identity", "gzip"]),
131
+ originalBytes: z
132
+ .number()
133
+ .int()
134
+ .nonnegative()
135
+ .max(SCHEDULING_BOUNDS.payloadBytes),
136
+ });
119
137
  export const portableEncryptedPayloadRecordSchema = z
120
138
  .strictObject({
121
- aadVersion: z.literal(SCHEDULE_PAYLOAD_AAD_VERSION),
139
+ aadVersion: z.enum([
140
+ SCHEDULE_PAYLOAD_AAD_VERSION,
141
+ "greatwait.schedule-payload.v2",
142
+ ]),
122
143
  authority: portableAuthoritySchema,
123
- envelope: z.strictObject({
124
- ciphertext: base64UrlBytesSchema,
125
- keyId: z
126
- .string()
127
- .min(1)
128
- .max(128)
129
- .regex(/^[A-Za-z0-9._:-]+$/u, "must be a safe key identifier"),
130
- nonce: base64UrlBytesSchema.refine((value) => decodeBase64UrlBytes(value)?.length === 12, { message: "must encode exactly 12 bytes" }),
131
- }),
144
+ envelope: z.union([
145
+ portableLegacyPayloadEnvelopeSchema,
146
+ portableV2PayloadEnvelopeSchema,
147
+ ]),
132
148
  plaintextBytes: z
133
149
  .number()
134
150
  .int()
@@ -142,10 +158,18 @@ export const portableEncryptedPayloadRecordSchema = z
142
158
  .superRefine((payload, context) => {
143
159
  const ciphertext = decodeBase64UrlBytes(payload.envelope.ciphertext);
144
160
  if (ciphertext !== undefined &&
145
- ciphertext.length !== payload.plaintextBytes + 16) {
161
+ ("version" in payload.envelope
162
+ ? payload.aadVersion !== "greatwait.schedule-payload.v2" ||
163
+ payload.envelope.originalBytes !== payload.plaintextBytes ||
164
+ ciphertext.length < 16 ||
165
+ ciphertext.length > payload.plaintextBytes + 16 ||
166
+ (payload.envelope.codec === "identity" &&
167
+ ciphertext.length !== payload.plaintextBytes + 16)
168
+ : payload.aadVersion !== SCHEDULE_PAYLOAD_AAD_VERSION ||
169
+ ciphertext.length !== payload.plaintextBytes + 16)) {
146
170
  context.addIssue({
147
171
  code: "custom",
148
- message: "ciphertext must contain the plaintext bytes and a 16-byte AES-GCM tag",
172
+ message: "ciphertext and authenticated envelope metadata must match the payload version and size",
149
173
  path: ["envelope", "ciphertext"],
150
174
  });
151
175
  }