@spine-event-engine/storage 2.0.0-snapshot.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 (133) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +160 -0
  3. package/REFERENCE.md +120 -0
  4. package/dist/entity/entity-history-record-spec.d.ts +26 -0
  5. package/dist/entity/entity-history-record-spec.d.ts.map +1 -0
  6. package/dist/entity/entity-history-record-spec.js +77 -0
  7. package/dist/entity/entity-history-record-spec.js.map +1 -0
  8. package/dist/entity/entity-history-storage.d.ts +111 -0
  9. package/dist/entity/entity-history-storage.d.ts.map +1 -0
  10. package/dist/entity/entity-history-storage.js +40 -0
  11. package/dist/entity/entity-history-storage.js.map +1 -0
  12. package/dist/entity/entity-record.d.ts +31 -0
  13. package/dist/entity/entity-record.d.ts.map +1 -0
  14. package/dist/entity/entity-record.js +15 -0
  15. package/dist/entity/entity-record.js.map +1 -0
  16. package/dist/entity/history-conformance.d.ts +55 -0
  17. package/dist/entity/history-conformance.d.ts.map +1 -0
  18. package/dist/entity/history-conformance.js +165 -0
  19. package/dist/entity/history-conformance.js.map +1 -0
  20. package/dist/event/event-store.d.ts +141 -0
  21. package/dist/event/event-store.d.ts.map +1 -0
  22. package/dist/event/event-store.js +407 -0
  23. package/dist/event/event-store.js.map +1 -0
  24. package/dist/index.d.ts +23 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +30 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/internal/delivery-cleanup.d.ts +99 -0
  29. package/dist/internal/delivery-cleanup.d.ts.map +1 -0
  30. package/dist/internal/delivery-cleanup.js +38 -0
  31. package/dist/internal/delivery-cleanup.js.map +1 -0
  32. package/dist/internal/entity-commit.d.ts +108 -0
  33. package/dist/internal/entity-commit.d.ts.map +1 -0
  34. package/dist/internal/entity-commit.js +32 -0
  35. package/dist/internal/entity-commit.js.map +1 -0
  36. package/dist/internal/entity-history.d.ts +12 -0
  37. package/dist/internal/entity-history.d.ts.map +1 -0
  38. package/dist/internal/entity-history.js +17 -0
  39. package/dist/internal/entity-history.js.map +1 -0
  40. package/dist/internal/event-store.d.ts +8 -0
  41. package/dist/internal/event-store.d.ts.map +1 -0
  42. package/dist/internal/event-store.js +21 -0
  43. package/dist/internal/event-store.js.map +1 -0
  44. package/dist/internal/query-values.d.ts +5 -0
  45. package/dist/internal/query-values.d.ts.map +1 -0
  46. package/dist/internal/query-values.js +18 -0
  47. package/dist/internal/query-values.js.map +1 -0
  48. package/dist/internal/tenancy.d.ts +89 -0
  49. package/dist/internal/tenancy.d.ts.map +1 -0
  50. package/dist/internal/tenancy.js +97 -0
  51. package/dist/internal/tenancy.js.map +1 -0
  52. package/dist/memory/canonical-utf8.d.ts +21 -0
  53. package/dist/memory/canonical-utf8.d.ts.map +1 -0
  54. package/dist/memory/canonical-utf8.js +65 -0
  55. package/dist/memory/canonical-utf8.js.map +1 -0
  56. package/dist/memory/in-memory-entity-commit.d.ts +35 -0
  57. package/dist/memory/in-memory-entity-commit.d.ts.map +1 -0
  58. package/dist/memory/in-memory-entity-commit.js +183 -0
  59. package/dist/memory/in-memory-entity-commit.js.map +1 -0
  60. package/dist/memory/in-memory-entity-history.d.ts +379 -0
  61. package/dist/memory/in-memory-entity-history.d.ts.map +1 -0
  62. package/dist/memory/in-memory-entity-history.js +756 -0
  63. package/dist/memory/in-memory-entity-history.js.map +1 -0
  64. package/dist/memory/in-memory-record-storage.d.ts +78 -0
  65. package/dist/memory/in-memory-record-storage.d.ts.map +1 -0
  66. package/dist/memory/in-memory-record-storage.js +127 -0
  67. package/dist/memory/in-memory-record-storage.js.map +1 -0
  68. package/dist/memory/in-memory-storage-backend.d.ts +38 -0
  69. package/dist/memory/in-memory-storage-backend.d.ts.map +1 -0
  70. package/dist/memory/in-memory-storage-backend.js +108 -0
  71. package/dist/memory/in-memory-storage-backend.js.map +1 -0
  72. package/dist/memory/in-memory-storage-factory.d.ts +58 -0
  73. package/dist/memory/in-memory-storage-factory.d.ts.map +1 -0
  74. package/dist/memory/in-memory-storage-factory.js +148 -0
  75. package/dist/memory/in-memory-storage-factory.js.map +1 -0
  76. package/dist/memory/memory-delivery-cleanup.d.ts +32 -0
  77. package/dist/memory/memory-delivery-cleanup.d.ts.map +1 -0
  78. package/dist/memory/memory-delivery-cleanup.js +61 -0
  79. package/dist/memory/memory-delivery-cleanup.js.map +1 -0
  80. package/dist/memory/tenant-records.d.ts +66 -0
  81. package/dist/memory/tenant-records.d.ts.map +1 -0
  82. package/dist/memory/tenant-records.js +573 -0
  83. package/dist/memory/tenant-records.js.map +1 -0
  84. package/dist/query/query-execution.d.ts +50 -0
  85. package/dist/query/query-execution.d.ts.map +1 -0
  86. package/dist/query/query-execution.js +222 -0
  87. package/dist/query/query-execution.js.map +1 -0
  88. package/dist/query/query-policy.d.ts +115 -0
  89. package/dist/query/query-policy.d.ts.map +1 -0
  90. package/dist/query/query-policy.js +294 -0
  91. package/dist/query/query-policy.js.map +1 -0
  92. package/dist/record/column-mapping.d.ts +41 -0
  93. package/dist/record/column-mapping.d.ts.map +1 -0
  94. package/dist/record/column-mapping.js +36 -0
  95. package/dist/record/column-mapping.js.map +1 -0
  96. package/dist/record/column-type.d.ts +75 -0
  97. package/dist/record/column-type.d.ts.map +1 -0
  98. package/dist/record/column-type.js +69 -0
  99. package/dist/record/column-type.js.map +1 -0
  100. package/dist/record/record-column.d.ts +23 -0
  101. package/dist/record/record-column.d.ts.map +1 -0
  102. package/dist/record/record-column.js +41 -0
  103. package/dist/record/record-column.js.map +1 -0
  104. package/dist/record/record-mask.d.ts +11 -0
  105. package/dist/record/record-mask.d.ts.map +1 -0
  106. package/dist/record/record-mask.js +82 -0
  107. package/dist/record/record-mask.js.map +1 -0
  108. package/dist/record/record-query.d.ts +102 -0
  109. package/dist/record/record-query.d.ts.map +1 -0
  110. package/dist/record/record-query.js +44 -0
  111. package/dist/record/record-query.js.map +1 -0
  112. package/dist/record/record-spec.d.ts +101 -0
  113. package/dist/record/record-spec.d.ts.map +1 -0
  114. package/dist/record/record-spec.js +159 -0
  115. package/dist/record/record-spec.js.map +1 -0
  116. package/dist/record/record-storage.d.ts +202 -0
  117. package/dist/record/record-storage.d.ts.map +1 -0
  118. package/dist/record/record-storage.js +234 -0
  119. package/dist/record/record-storage.js.map +1 -0
  120. package/dist/record/storage-group.d.ts +17 -0
  121. package/dist/record/storage-group.d.ts.map +1 -0
  122. package/dist/record/storage-group.js +37 -0
  123. package/dist/record/storage-group.js.map +1 -0
  124. package/dist/storage/storage-factory.d.ts +44 -0
  125. package/dist/storage/storage-factory.d.ts.map +1 -0
  126. package/dist/storage/storage-factory.js +54 -0
  127. package/dist/storage/storage-factory.js.map +1 -0
  128. package/dist/storage/storage.d.ts +62 -0
  129. package/dist/storage/storage.d.ts.map +1 -0
  130. package/dist/storage/storage.js +15 -0
  131. package/dist/storage/storage.js.map +1 -0
  132. package/dist/tsconfig.tsbuildinfo +1 -0
  133. package/package.json +56 -0
@@ -0,0 +1,32 @@
1
+ import type { Message } from "@bufbuild/protobuf";
2
+ import { type DeliveryCleanupInput, type DeliveryCleanupStorage } from "../internal/delivery-cleanup.js";
3
+ import type { RecordSpec } from "../record/record-spec.js";
4
+ import type { StorageContext } from "../storage/storage.js";
5
+ import type { StorageGroup } from "../record/storage-group.js";
6
+ import { TenantRecords } from "./tenant-records.js";
7
+ /**
8
+ * Provides an in-memory critical section for fenced delivery cleanup.
9
+ */
10
+ export declare class MemoryDeliveryCleanupStorage implements DeliveryCleanupStorage {
11
+ #private;
12
+ private readonly records;
13
+ /**
14
+ * Creates an in-memory cleanup handle.
15
+ *
16
+ * @param records Resolves a tenant-scoped record family.
17
+ */
18
+ constructor(records: <I, R extends Message>(context: StorageContext, spec: RecordSpec<I, R>, group?: StorageGroup) => TenantRecords<I, R>);
19
+ /**
20
+ * Removes an exact Inbox record while its session record remains current.
21
+ *
22
+ * @param input Describes the records and ownership predicate for deletion.
23
+ * @returns Whether the exact Inbox record was removed.
24
+ */
25
+ remove<InboxId, InboxRecord extends Message, SessionId, SessionRecord extends Message>(input: DeliveryCleanupInput<InboxId, InboxRecord, SessionId, SessionRecord>): Promise<boolean>;
26
+ /**
27
+ * Closes this cleanup handle to further removal operations.
28
+ */
29
+ close(): void;
30
+ private static active;
31
+ }
32
+ //# sourceMappingURL=memory-delivery-cleanup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-delivery-cleanup.d.ts","sourceRoot":"","sources":["../../src/memory/memory-delivery-cleanup.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAGL,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC5B,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;GAEG;AACH,qBAAa,4BAA6B,YAAW,sBAAsB;;IASvE,OAAO,CAAC,QAAQ,CAAC,OAAO;IAN1B;;;;OAIG;gBAEgB,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,SAAS,OAAO,EAC7C,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,EACtB,KAAK,CAAC,EAAE,YAAY,KACjB,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC;IAG1B;;;;;OAKG;IACH,MAAM,CAAC,OAAO,EAAE,WAAW,SAAS,OAAO,EAAE,SAAS,EAAE,aAAa,SAAS,OAAO,EACnF,KAAK,EAAE,oBAAoB,CAAC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,CAAC,GAC1E,OAAO,CAAC,OAAO,CAAC;IAmBnB;;OAEG;IACH,KAAK,IAAI,IAAI;IAGb,OAAO,CAAC,MAAM,CAAC,MAAM;CAGtB"}
@@ -0,0 +1,61 @@
1
+ /*
2
+ * Copyright 2026, CodeMatters. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5
+ * in compliance with the License. You may obtain a copy of the License at
6
+ *
7
+ * https://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
10
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11
+ * or implied. See the License for the specific language governing permissions and limitations under
12
+ * the License.
13
+ */
14
+ import { cleanupOperationActive, } from "../internal/delivery-cleanup.js";
15
+ import { TenantRecords } from "./tenant-records.js";
16
+ /**
17
+ * Provides an in-memory critical section for fenced delivery cleanup.
18
+ */
19
+ export class MemoryDeliveryCleanupStorage {
20
+ records;
21
+ #open = true;
22
+ /**
23
+ * Creates an in-memory cleanup handle.
24
+ *
25
+ * @param records Resolves a tenant-scoped record family.
26
+ */
27
+ constructor(records) {
28
+ this.records = records;
29
+ }
30
+ /**
31
+ * Removes an exact Inbox record while its session record remains current.
32
+ *
33
+ * @param input Describes the records and ownership predicate for deletion.
34
+ * @returns Whether the exact Inbox record was removed.
35
+ */
36
+ remove(input) {
37
+ if (!this.#open)
38
+ return Promise.reject(new Error("Delivery cleanup storage is closed."));
39
+ if (!MemoryDeliveryCleanupStorage.active(input))
40
+ return Promise.resolve(false);
41
+ const sessions = this.records(input.context, input.session.spec);
42
+ const current = sessions.read(input.session.id);
43
+ if (current === undefined || !input.session.isCurrent(current))
44
+ return Promise.resolve(false);
45
+ const expectedSession = input.session.spec.materialize(input.session.expected);
46
+ if (!sessions.compareAndSet(input.session.id, expectedSession, expectedSession))
47
+ return Promise.resolve(false);
48
+ const inbox = this.records(input.context, input.inbox.spec);
49
+ return Promise.resolve(inbox.compareAndSet(input.inbox.id, input.inbox.spec.materialize(input.inbox.expected), undefined));
50
+ }
51
+ /**
52
+ * Closes this cleanup handle to further removal operations.
53
+ */
54
+ close() {
55
+ this.#open = false;
56
+ }
57
+ static active(input) {
58
+ return cleanupOperationActive(input.operation);
59
+ }
60
+ }
61
+ //# sourceMappingURL=memory-delivery-cleanup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-delivery-cleanup.js","sourceRoot":"","sources":["../../src/memory/memory-delivery-cleanup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EACL,sBAAsB,GAIvB,MAAM,iCAAiC,CAAC;AAIzC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;GAEG;AACH,MAAM,OAAO,4BAA4B;IASpB;IARnB,KAAK,GAAG,IAAI,CAAC;IAEb;;;;OAIG;IACH,YACmB,OAIO;QAJP,YAAO,GAAP,OAAO,CAIA;IACvB,CAAC;IAEJ;;;;;OAKG;IACH,MAAM,CACJ,KAA2E;QAE3E,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC,CAAC;QACzF,IAAI,CAAC,4BAA4B,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC/E,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACjE,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAChD,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9F,MAAM,eAAe,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC/E,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,eAAe,EAAE,eAAe,CAAC;YAC7E,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5D,OAAO,OAAO,CAAC,OAAO,CACpB,KAAK,CAAC,aAAa,CACjB,KAAK,CAAC,KAAK,CAAC,EAAE,EACd,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAClD,SAAS,CACV,CACF,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IACO,MAAM,CAAC,MAAM,CAAC,KAAgD;QACpE,OAAO,sBAAsB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACjD,CAAC;CACF"}
@@ -0,0 +1,66 @@
1
+ import type { Message } from "@bufbuild/protobuf";
2
+ import type { RecordQuery } from "../record/record-query.js";
3
+ import type { RecordSpec } from "../record/record-spec.js";
4
+ import type { RecordEntry } from "../record/record-storage.js";
5
+ /**
6
+ * Record slice owned by one tenant of an in-memory record storage.
7
+ */
8
+ export declare class TenantRecords<I, R extends Message> {
9
+ #private;
10
+ /**
11
+ * Compares and replaces an expected materialized record in this tenant slice.
12
+ * @param id Identifies the storage slot to compare and replace.
13
+ * @param expected Specifies the materialized record required at the slot.
14
+ * @param next Specifies the replacement record, or removes the slot when absent.
15
+ * @returns Whether the expected record matched and the mutation was applied.
16
+ */
17
+ compareAndSet(id: I, expected: StoredRecord<I, R> | undefined, next: StoredRecord<I, R> | undefined): boolean;
18
+ /**
19
+ * Removes one storage slot from this tenant slice.
20
+ * @param id Identifies the storage slot to remove.
21
+ * @returns Whether a record occupied the slot.
22
+ */
23
+ delete(id: I): boolean;
24
+ /**
25
+ * Returns materialized records matching a tenant-scoped query.
26
+ * @param spec Supplies record identity cloning and materialized columns.
27
+ * @param query Specifies filters, ordering, continuation, and windowing.
28
+ * @returns The matching logical record entries in query order.
29
+ */
30
+ queryEntries(spec: RecordSpec<I, R>, query: RecordQuery<I>): readonly RecordEntry<I, R>[];
31
+ /**
32
+ * Reads one record from this tenant slice.
33
+ * @param id Identifies the storage slot to read.
34
+ * @returns The stored record, or undefined when the slot is empty.
35
+ */
36
+ read(id: I): R | undefined;
37
+ /**
38
+ * Stores one materialized record in this tenant slice.
39
+ * @param record Supplies the materialized record and storage identity.
40
+ */
41
+ write(record: StoredRecord<I, R>): void;
42
+ /**
43
+ * Stores all materialized records in this tenant slice.
44
+ * @param records Supplies the materialized records to store.
45
+ */
46
+ writeAll(records: readonly StoredRecord<I, R>[]): void;
47
+ /**
48
+ * Copies the materialized rows for a provider-owned staged commit.
49
+ *
50
+ * @returns An independent snapshot of the current rows.
51
+ */
52
+ snapshot(): Map<string, StoredEntry<I, R>>;
53
+ /**
54
+ * Replaces all rows from a fully validated staged snapshot.
55
+ *
56
+ * @param snapshot Supplies the staged materialized rows.
57
+ */
58
+ replace(snapshot: Map<string, StoredEntry<I, R>>): void;
59
+ }
60
+ type StoredRecord<I, R extends Message> = ReturnType<RecordSpec<I, R>["materialize"]>;
61
+ interface StoredEntry<I, R extends Message> {
62
+ readonly slotId: I;
63
+ readonly stored: StoredRecord<I, R>;
64
+ }
65
+ export {};
66
+ //# sourceMappingURL=tenant-records.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-records.d.ts","sourceRoot":"","sources":["../../src/memory/tenant-records.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,KAAK,EAIV,WAAW,EACZ,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAO/D;;GAEG;AACH,qBAAa,aAAa,CAAC,CAAC,EAAE,CAAC,SAAS,OAAO;;IAG7C;;;;;;OAMG;IACH,aAAa,CACX,EAAE,EAAE,CAAC,EACL,QAAQ,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,EACxC,IAAI,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,GACnC,OAAO;IAoBV;;;;OAIG;IACH,MAAM,CAAC,EAAE,EAAE,CAAC,GAAG,OAAO;IAItB;;;;;OAKG;IACH,YAAY,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;IAIzF;;;;OAIG;IACH,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IAI1B;;;OAGG;IACH,KAAK,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI;IAOvC;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI;IAMtD;;;;OAIG;IACH,QAAQ,IAAI,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAI1C;;;;OAIG;IACH,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI;CAIxD;AAED,KAAK,YAAY,CAAC,CAAC,EAAE,CAAC,SAAS,OAAO,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AAEtF,UAAU,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,OAAO;IACxC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CACrC"}