@casual-simulation/aux-common 3.3.11 → 3.3.13

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 (38) hide show
  1. package/bots/BotEvents.d.ts +30 -1
  2. package/bots/BotEvents.js +16 -0
  3. package/bots/BotEvents.js.map +1 -1
  4. package/common/DenialReason.d.ts +4 -1
  5. package/documents/RemoteYjsSharedDocument.d.ts +52 -0
  6. package/documents/RemoteYjsSharedDocument.js +304 -0
  7. package/documents/RemoteYjsSharedDocument.js.map +1 -0
  8. package/documents/SharedDocument.d.ts +449 -0
  9. package/documents/SharedDocument.js +2 -0
  10. package/documents/SharedDocument.js.map +1 -0
  11. package/documents/SharedDocumentConfig.d.ts +65 -0
  12. package/documents/SharedDocumentConfig.js +2 -0
  13. package/documents/SharedDocumentConfig.js.map +1 -0
  14. package/documents/SharedDocumentFactories.d.ts +20 -0
  15. package/documents/SharedDocumentFactories.js +29 -0
  16. package/documents/SharedDocumentFactories.js.map +1 -0
  17. package/documents/YjsSharedDocument.d.ts +152 -0
  18. package/documents/YjsSharedDocument.js +628 -0
  19. package/documents/YjsSharedDocument.js.map +1 -0
  20. package/documents/index.d.ts +6 -0
  21. package/documents/index.js +6 -0
  22. package/documents/index.js.map +1 -0
  23. package/documents/test/DocumentTests.d.ts +6 -0
  24. package/documents/test/DocumentTests.js +497 -0
  25. package/documents/test/DocumentTests.js.map +1 -0
  26. package/package.json +2 -2
  27. package/partitions/AuxPartitionConfig.d.ts +5 -4
  28. package/partitions/PartitionAuthSource.d.ts +4 -0
  29. package/partitions/RemoteYjsPartition.d.ts +8 -50
  30. package/partitions/RemoteYjsPartition.js +65 -364
  31. package/partitions/RemoteYjsPartition.js.map +1 -1
  32. package/partitions/YjsPartition.d.ts +4 -28
  33. package/partitions/YjsPartition.js +7 -93
  34. package/partitions/YjsPartition.js.map +1 -1
  35. package/rpc/ErrorCodes.d.ts +1 -1
  36. package/rpc/ErrorCodes.js.map +1 -1
  37. package/websockets/InstRecordsClient.js +1 -1
  38. package/websockets/InstRecordsClient.js.map +1 -1
@@ -0,0 +1,449 @@
1
+ import { ClientError } from '../websockets';
2
+ import { Action, CurrentVersion, StatusUpdate } from '../common';
3
+ import { Observable, SubscriptionLike } from 'rxjs';
4
+ import { InstUpdate } from '../bots';
5
+ /**
6
+ * Defines an interface for objects that are able to synchronize data between multiple clients.
7
+ */
8
+ export interface SharedDocument extends SubscriptionLike {
9
+ /**
10
+ * The name of the record that the document is stored under.
11
+ * If null, then the document is public.
12
+ */
13
+ recordName: string | null;
14
+ /**
15
+ * The address of the document.
16
+ * If null, then the document is stored locally.
17
+ */
18
+ address: string | null;
19
+ /**
20
+ * The branch that was loaded for the document.
21
+ */
22
+ branch: string;
23
+ /**
24
+ * The ID of the remote client that the document is associated with.
25
+ */
26
+ clientId: number;
27
+ /**
28
+ * Gets an observable list that resolves whenever the partition state version is updated.
29
+ */
30
+ onVersionUpdated: Observable<CurrentVersion>;
31
+ /**
32
+ * Gets an observable list of errors from the partition.
33
+ * That is, errors that the client cannot handle.
34
+ */
35
+ onError: Observable<any>;
36
+ /**
37
+ * Gets the observable list of remote events from the partition.
38
+ */
39
+ onEvents: Observable<Action[]>;
40
+ /**
41
+ * Gets the observable list of status updates from the partition.
42
+ */
43
+ onStatusUpdated: Observable<StatusUpdate>;
44
+ /**
45
+ * Gets the observable list of client errors from the document.
46
+ * That is, errors that were caused by the client's behavior.
47
+ */
48
+ onClientError: Observable<ClientError>;
49
+ /**
50
+ * Tells the document to connect to its backing store.
51
+ */
52
+ connect(): void;
53
+ /**
54
+ * Gets a top-level map that can be used to store key/value data.
55
+ * @param name The name of the map.
56
+ */
57
+ getMap<T = any>(name: string): SharedMap<T>;
58
+ /**
59
+ * Gets a top-level array that can be used to store a list of items.
60
+ * @param name The name of the array.
61
+ */
62
+ getArray<T = any>(name: string): SharedArray<T>;
63
+ /**
64
+ * Gets a top-level text object that can be used to store rich text.
65
+ * @param name The name of the text.
66
+ */
67
+ getText(name: string): SharedText;
68
+ /**
69
+ * Creates a new map that can be shared between multiple clients.
70
+ */
71
+ createMap<T = any>(): SharedMap<T>;
72
+ /**
73
+ * Creates a new array that can be shared between multiple clients.
74
+ */
75
+ createArray<T = any>(): SharedArray<T>;
76
+ /**
77
+ * Batches changes that occur within the given callback function into a single transaction.
78
+ * This makes multiple updates more efficient.
79
+ * @param callback The function to execute.
80
+ */
81
+ transact(callback: () => void): void;
82
+ /**
83
+ * Gets the update that represents the current state of the document.
84
+ */
85
+ getStateUpdate(): InstUpdate;
86
+ /**
87
+ * Applies the given updates to the document.
88
+ * @param updates The updates to apply.
89
+ */
90
+ applyStateUpdates(updates: InstUpdate[]): void;
91
+ }
92
+ export type SharedType = SharedMap | SharedArray | SharedText;
93
+ export type SharedTypeChanges = SharedMapChanges<any> | SharedArrayChanges<any> | SharedTextChanges;
94
+ export interface SharedTypeBase {
95
+ /**
96
+ * The document that the map is associated with.
97
+ */
98
+ readonly doc: SharedDocument;
99
+ /**
100
+ * The type that this map is stored in.
101
+ */
102
+ readonly parent: SharedType | null;
103
+ }
104
+ /**
105
+ * Defines a map that can be shared between multiple clients.
106
+ */
107
+ export interface SharedMap<T = any> extends SharedTypeBase {
108
+ /**
109
+ * Gets the number of keys that are in the map.
110
+ */
111
+ readonly size: number;
112
+ /**
113
+ * Sets the given key to the given value.
114
+ * @param key The key to set.
115
+ * @param value The value to set.
116
+ */
117
+ set(key: string, value: T): void;
118
+ /**
119
+ * Gets the value for the given key.
120
+ * @param key The key to get.
121
+ */
122
+ get(key: string): T;
123
+ /**
124
+ * Deletes the given key from the map.
125
+ * @param key Deletes the given key.
126
+ */
127
+ delete(key: string): void;
128
+ /**
129
+ * Determines if the given key exists in the map.
130
+ * @param key The key.
131
+ */
132
+ has(key: string): boolean;
133
+ /**
134
+ * Clears the map.
135
+ */
136
+ clear(): void;
137
+ /**
138
+ * Creates a new map that is a clone of this map.
139
+ */
140
+ clone(): SharedMap;
141
+ /**
142
+ * Transforms this map into an object that can be serialized to JSON.
143
+ */
144
+ toJSON(): {
145
+ [key: string]: T;
146
+ };
147
+ /**
148
+ * Execute the provided function once on every key/value pair.
149
+ * @param callback The function to execute.
150
+ */
151
+ forEach(callback: (value: T, key: string, map: SharedMap<T>) => void): void;
152
+ /**
153
+ * Gets an iterator for the key/value pairs stored in the map.
154
+ */
155
+ [Symbol.iterator](): IterableIterator<[string, T]>;
156
+ /**
157
+ * Gets an iterator for the key/value pairs stored in the map.
158
+ */
159
+ entries(): IterableIterator<[string, T]>;
160
+ /**
161
+ * Gets an iterator for the keys stored in the map.
162
+ */
163
+ keys(): IterableIterator<string>;
164
+ /**
165
+ * Gets an iterator for the values stored in the map.
166
+ */
167
+ values(): IterableIterator<T>;
168
+ /**
169
+ * Gets an observable that resolves whenever the map is changed.
170
+ */
171
+ readonly changes: Observable<SharedMapChanges<T>>;
172
+ /**
173
+ * Gets an observable that resolves whenever this map or any children are changed.
174
+ */
175
+ readonly deepChanges: Observable<SharedTypeChanges[]>;
176
+ }
177
+ /**
178
+ * Defines an array that can be shared between multiple clients.
179
+ */
180
+ export interface SharedArray<T = any> extends SharedTypeBase {
181
+ /**
182
+ * Gets the number of elements in the array.
183
+ */
184
+ readonly length: number;
185
+ /**
186
+ * Gets the number of elements in the array.
187
+ */
188
+ readonly size: number;
189
+ /**
190
+ * Insert items at the given index.
191
+ * @param index The index to insert the items at. Items at or after this index will be pushed back to make space for the new items. If the index is greater than the length of the array, then the items are appended to the end of the array.
192
+ * @param items The items to insert.
193
+ */
194
+ insert(index: number, items: T[]): void;
195
+ /**
196
+ * Deletes the given number of items, starting at the given index.
197
+ * @param index The index of the first item to be deleted.
198
+ * @param count The number of items to delete.
199
+ */
200
+ delete(index: number, count: number): void;
201
+ /**
202
+ * Applies the given delta to the array.
203
+ * @param delta The delta to apply.
204
+ */
205
+ applyDelta(delta: SharedArrayDelta<T>): void;
206
+ /**
207
+ * Append items to the end of the array.
208
+ * @param items The items to add.
209
+ */
210
+ push(...items: T[]): void;
211
+ /**
212
+ * Removes the last item from the array and returns it.
213
+ */
214
+ pop(): T | undefined;
215
+ /**
216
+ * Prepend items to the beginning of the array.
217
+ * @param items The items to add.
218
+ */
219
+ unshift(...items: T[]): void;
220
+ /**
221
+ * Removes the first item from the array and returns it.
222
+ */
223
+ shift(): T | undefined;
224
+ /**
225
+ * Gets the item at the given index.
226
+ * @param index The index to get.
227
+ */
228
+ get(index: number): T;
229
+ /**
230
+ * Gets a range of items from the array.
231
+ * Negative indexes can be used to start from the end of the array.
232
+ * @param start The index of the first item to retrieve.
233
+ * @param end The index of the last item to retrieve.
234
+ */
235
+ slice(start?: number, end?: number): T[];
236
+ /**
237
+ * Changes the contents of the array by removing or replacing existing elements and/or adding new elements.
238
+ * Returns a JavaScript array containing the removed elements.
239
+ * @param start The index at which to start changing the array.
240
+ * @param deleteCount The number of elements in the array to remove from start.
241
+ * @param items The elements to add to the array.
242
+ */
243
+ splice(start: number, deleteCount: number, ...items: T[]): T[];
244
+ /**
245
+ * Creates a new JavaScript array that is a clone of this array.
246
+ */
247
+ toArray(): T[];
248
+ /**
249
+ * Transforms this map into an array that can be serialized to JSON.
250
+ */
251
+ toJSON(): T[];
252
+ /**
253
+ * Execute the given callback function for each item in the array.
254
+ * @param callback The function to execute.
255
+ */
256
+ forEach(callback: (value: T, index: number, array: SharedArray<T>) => void): void;
257
+ /**
258
+ * Creates a new JavaScript array with the results of calling a provided function on every element in this array.
259
+ * @param callback The function to execute.
260
+ */
261
+ map(callback: (value: T, index: number, array: SharedArray<T>) => T): T[];
262
+ /**
263
+ * Creates a new JavaScript array with all elements that pass the test implemented by the provided function.
264
+ * @param predicate The function to execute.
265
+ */
266
+ filter(predicate: (value: T, index: number, array: SharedArray<T>) => boolean): T[];
267
+ /**
268
+ * Gets an iterator for the items in the array.
269
+ */
270
+ [Symbol.iterator](): IterableIterator<T>;
271
+ /**
272
+ * Creates a new shared array that is a clone of this array.
273
+ */
274
+ clone(): SharedArray<T>;
275
+ /**
276
+ * Gets an observable that resolves whenever the array is changed.
277
+ */
278
+ readonly changes: Observable<SharedArrayChanges<T>>;
279
+ /**
280
+ * Gets an observable that resolves whenever this array or any children are changed.
281
+ */
282
+ readonly deepChanges: Observable<SharedTypeChanges[]>;
283
+ }
284
+ /**
285
+ * Defines an object that represents rich text that can be shared between multiple clients.
286
+ */
287
+ export interface SharedText extends SharedTypeBase {
288
+ /**
289
+ * Gets the length of the string in UTF-16 code units.
290
+ */
291
+ readonly length: number;
292
+ /**
293
+ * Insert text at the given index.
294
+ * Optionally apply formatting to the inserted text.
295
+ * @param index The index to insert the text at.
296
+ * @param text The text to insert.
297
+ * @param attribtues The formatting attributes to apply to the inserted text.
298
+ */
299
+ insert(index: number, text: string, attribtues?: Record<string, any>): void;
300
+ /**
301
+ * Deletes the given number of items, starting at the given index.
302
+ * @param index The index of the first item to be deleted.
303
+ * @param count The number of items to delete.
304
+ */
305
+ delete(index: number, count: number): void;
306
+ /**
307
+ * Applies the given delta to the text.
308
+ * @param delta The delta to apply.
309
+ */
310
+ applyDelta(delta: SharedTextDelta): void;
311
+ /**
312
+ * Converts this text into a delta that can be applied to another text object.
313
+ */
314
+ toDelta(): SharedTextDelta;
315
+ /**
316
+ * Creates a relative position that is fixed to the code point at the given index.
317
+ * @param index The index of the character to create the relative position for.
318
+ * @param assoc The association of the relative position to the character. < 0 is before, >= 0 is after.
319
+ */
320
+ encodeRelativePosition(index: number, assoc?: number): RelativePosition;
321
+ /**
322
+ * Gets the index that the given relative position is associated with.
323
+ * @param position The relative position to decode.
324
+ */
325
+ decodeRelativePosition(position: RelativePosition): number;
326
+ /**
327
+ * Gets a range of text from this object.
328
+ * Negative indexes can be used to start from the end of the string.
329
+ * @param start The index of the first code point to retrieve.
330
+ * @param end The index of the last code point to retrieve.
331
+ */
332
+ slice(start?: number, end?: number): string;
333
+ /**
334
+ * Creates a new JavaScript string that is a clone of this text.
335
+ */
336
+ toString(): string;
337
+ /**
338
+ * Transforms this text into a string that can be serialized to JSON.
339
+ */
340
+ toJSON(): string;
341
+ /**
342
+ * Creates a new shared array that is a clone of this array.
343
+ */
344
+ clone(): SharedText;
345
+ /**
346
+ * Gets an observable that resolves whenever the array is changed.
347
+ */
348
+ readonly changes: Observable<SharedTextChanges>;
349
+ /**
350
+ * Gets an observable that resolves whenever this array or any children are changed.
351
+ */
352
+ readonly deepChanges: Observable<SharedTextChanges[]>;
353
+ }
354
+ export interface SharedMapChanges<T> {
355
+ type: 'map';
356
+ /**
357
+ * The map that was changed.
358
+ */
359
+ target: SharedMap<T>;
360
+ /**
361
+ * The keys that were changed, along with their old values.
362
+ */
363
+ changes: Map<string, SharedMapChange<T>>;
364
+ }
365
+ export interface SharedMapChange<T> {
366
+ /**
367
+ * The action that caused this change.
368
+ */
369
+ action: 'add' | 'update' | 'delete';
370
+ /**
371
+ * The old value of the key.
372
+ */
373
+ oldValue: T | undefined;
374
+ }
375
+ export interface SharedArrayChanges<T> {
376
+ type: 'array';
377
+ /**
378
+ * The array that was changed.
379
+ */
380
+ target: SharedArray<T>;
381
+ /**
382
+ * The changes that were made to the array.
383
+ */
384
+ delta: SharedArrayDelta<T>;
385
+ }
386
+ export type SharedArrayDelta<T> = SharedArrayOp<T>[];
387
+ export type SharedArrayOp<T> = SharedArrayPreserveOp | SharedArrayInsertOp<T> | SharedArrayDeleteOp<T>;
388
+ export interface SharedArrayPreserveOp {
389
+ type: 'preserve';
390
+ /**
391
+ * The number of items that were preserved.
392
+ */
393
+ count: number;
394
+ }
395
+ export interface SharedArrayInsertOp<T> {
396
+ type: 'insert';
397
+ /**
398
+ * The values that were inserted.
399
+ */
400
+ values: T[];
401
+ }
402
+ export interface SharedArrayDeleteOp<T> {
403
+ type: 'delete';
404
+ /**
405
+ * The number of items that were deleted.
406
+ */
407
+ count: number;
408
+ }
409
+ export interface SharedTextChanges {
410
+ type: 'text';
411
+ /**
412
+ * The text that was changed.
413
+ */
414
+ target: SharedText;
415
+ /**
416
+ * The changes that were made to the array.
417
+ */
418
+ delta: SharedTextDelta;
419
+ }
420
+ export type SharedTextDelta = SharedTextOp[];
421
+ export type SharedTextOp = SharedTextPreserveOp | SharedTextInsertOp | SharedTextDeleteOp;
422
+ export interface SharedTextPreserveOp {
423
+ type: 'preserve';
424
+ /**
425
+ * The number of characters that were preserved.
426
+ */
427
+ count: number;
428
+ }
429
+ export interface SharedTextInsertOp {
430
+ type: 'insert';
431
+ /**
432
+ * The text that was inserted.
433
+ */
434
+ text: string;
435
+ /**
436
+ * The formatting that was applied to the inserted text.
437
+ */
438
+ attributes: Record<string, any>;
439
+ }
440
+ export interface SharedTextDeleteOp {
441
+ type: 'delete';
442
+ /**
443
+ * The number of items that were deleted.
444
+ */
445
+ count: number;
446
+ }
447
+ export interface RelativePosition {
448
+ }
449
+ //# sourceMappingURL=SharedDocument.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=SharedDocument.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SharedDocument.js","sourceRoot":"","sources":["SharedDocument.ts"],"names":[],"mappings":""}
@@ -0,0 +1,65 @@
1
+ import { RemoteCausalRepoProtocol } from '../partitions/AuxPartitionConfig';
2
+ /**
3
+ * Defines a config for a shared document that is stored locally.
4
+ */
5
+ export interface SharedDocumentConfig {
6
+ /**
7
+ * The name of the record that the document is stored under.
8
+ * If null, then the document will either be stored in a public inst or on the device.
9
+ */
10
+ recordName?: string | null;
11
+ /**
12
+ * The inst that the document is stored in.
13
+ * If omitted or null, then the document will only be stored on the device.
14
+ */
15
+ inst?: string | null;
16
+ /**
17
+ * The branch of the document to load.
18
+ * If omitted, then local persistence will not be supported.
19
+ */
20
+ branch?: string;
21
+ /**
22
+ * Whether the doc should be loaded in read-only mode.
23
+ */
24
+ readOnly?: boolean;
25
+ /**
26
+ * Whether the doc should be loaded without realtime updates and in a read-only mode.
27
+ * Basically this means that all you get is the initial state.
28
+ */
29
+ static?: boolean;
30
+ /**
31
+ * Whether the doc should skip the initial load until the doc is upgraded to a realtime connection.
32
+ */
33
+ skipInitialLoad?: boolean;
34
+ /**
35
+ * Whether the doc should be temporary.
36
+ */
37
+ temporary?: boolean;
38
+ /**
39
+ * The options for local persistence of the document.
40
+ * If not provided, then the document will not be persisted locally.
41
+ */
42
+ localPersistence?: {
43
+ /**
44
+ * Whether to save the document to indexed db.
45
+ */
46
+ saveToIndexedDb?: boolean;
47
+ /**
48
+ * The key to use for encryption.
49
+ */
50
+ encryptionKey?: string;
51
+ };
52
+ }
53
+ export interface RemoteSharedDocumentConfig extends SharedDocumentConfig {
54
+ /**
55
+ * The host to connect to.
56
+ * If omitted, then connecting to remote servers will not be supported.
57
+ */
58
+ host?: string;
59
+ /**
60
+ * The protocol to use for the document.
61
+ * Currently, only "updates" is supported.
62
+ */
63
+ connectionProtocol?: RemoteCausalRepoProtocol;
64
+ }
65
+ //# sourceMappingURL=SharedDocumentConfig.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=SharedDocumentConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SharedDocumentConfig.js","sourceRoot":"","sources":["SharedDocumentConfig.ts"],"names":[],"mappings":""}
@@ -0,0 +1,20 @@
1
+ import { PartitionAuthSource } from '../partitions/PartitionAuthSource';
2
+ import { SharedDocument } from './SharedDocument';
3
+ import { RemoteSharedDocumentConfig } from './SharedDocumentConfig';
4
+ export interface SharedDocumentServices {
5
+ /**
6
+ * The auth source that should be used for the partition, if needed.
7
+ */
8
+ authSource: PartitionAuthSource;
9
+ }
10
+ export type SharedDocumentFactory = (config: RemoteSharedDocumentConfig, services: SharedDocumentServices) => Promise<SharedDocument> | SharedDocument;
11
+ /**
12
+ * Creates a shared document from the given list of factory functions.
13
+ * The first factory function that returns a doc is the document
14
+ * that gets returned.
15
+ * @param config The config which indicates the type of document to create.
16
+ * @param services The services which should be used by the document.
17
+ * @param factories The factory functions.
18
+ */
19
+ export declare function createSharedDocument(config: RemoteSharedDocumentConfig, services: SharedDocumentServices, ...factories: SharedDocumentFactory[]): Promise<SharedDocument>;
20
+ //# sourceMappingURL=SharedDocumentFactories.d.ts.map
@@ -0,0 +1,29 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ /**
11
+ * Creates a shared document from the given list of factory functions.
12
+ * The first factory function that returns a doc is the document
13
+ * that gets returned.
14
+ * @param config The config which indicates the type of document to create.
15
+ * @param services The services which should be used by the document.
16
+ * @param factories The factory functions.
17
+ */
18
+ export function createSharedDocument(config, services, ...factories) {
19
+ return __awaiter(this, void 0, void 0, function* () {
20
+ for (let factory of factories) {
21
+ let result = yield factory(config, services);
22
+ if (result) {
23
+ return result;
24
+ }
25
+ }
26
+ return undefined;
27
+ });
28
+ }
29
+ //# sourceMappingURL=SharedDocumentFactories.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SharedDocumentFactories.js","sourceRoot":"","sources":["SharedDocumentFactories.ts"],"names":[],"mappings":";;;;;;;;;AAgBA;;;;;;;GAOG;AACH,MAAM,UAAgB,oBAAoB,CACtC,MAAkC,EAClC,QAAgC,EAChC,GAAG,SAAkC;;QAErC,KAAK,IAAI,OAAO,IAAI,SAAS,EAAE,CAAC;YAC5B,IAAI,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC7C,IAAI,MAAM,EAAE,CAAC;gBACT,OAAO,MAAM,CAAC;YAClB,CAAC;QACL,CAAC;QAED,OAAO,SAAS,CAAC;IACrB,CAAC;CAAA"}