@agent-native/core 0.45.1 → 0.47.1
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.
- package/README.md +1 -0
- package/dist/agent/production-agent.d.ts +28 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +14 -7
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/cli/skills.d.ts +2 -2
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +33 -0
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/components/LiveCursorOverlay.d.ts +46 -0
- package/dist/client/components/LiveCursorOverlay.d.ts.map +1 -0
- package/dist/client/components/LiveCursorOverlay.js +137 -0
- package/dist/client/components/LiveCursorOverlay.js.map +1 -0
- package/dist/client/components/PresenceBar.d.ts +11 -1
- package/dist/client/components/PresenceBar.d.ts.map +1 -1
- package/dist/client/components/PresenceBar.js +39 -7
- package/dist/client/components/PresenceBar.js.map +1 -1
- package/dist/client/components/RemoteSelectionRings.d.ts +43 -0
- package/dist/client/components/RemoteSelectionRings.d.ts.map +1 -0
- package/dist/client/components/RemoteSelectionRings.js +116 -0
- package/dist/client/components/RemoteSelectionRings.js.map +1 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +5 -0
- package/dist/client/index.js.map +1 -1
- package/dist/coding-tools/run-code.d.ts +40 -0
- package/dist/coding-tools/run-code.d.ts.map +1 -0
- package/dist/coding-tools/run-code.js +511 -0
- package/dist/coding-tools/run-code.js.map +1 -0
- package/dist/collab/awareness.d.ts +25 -0
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/awareness.js +42 -5
- package/dist/collab/awareness.js.map +1 -1
- package/dist/collab/client.d.ts +19 -1
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +362 -57
- package/dist/collab/client.js.map +1 -1
- package/dist/collab/follow-mode.d.ts +56 -0
- package/dist/collab/follow-mode.d.ts.map +1 -0
- package/dist/collab/follow-mode.js +54 -0
- package/dist/collab/follow-mode.js.map +1 -0
- package/dist/collab/index.d.ts +3 -1
- package/dist/collab/index.d.ts.map +1 -1
- package/dist/collab/index.js +5 -1
- package/dist/collab/index.js.map +1 -1
- package/dist/collab/presence.d.ts +56 -0
- package/dist/collab/presence.d.ts.map +1 -0
- package/dist/collab/presence.js +98 -0
- package/dist/collab/presence.js.map +1 -0
- package/dist/collab/routes.d.ts.map +1 -1
- package/dist/collab/routes.js +33 -6
- package/dist/collab/routes.js.map +1 -1
- package/dist/collab/struct-routes.d.ts.map +1 -1
- package/dist/collab/struct-routes.js +24 -4
- package/dist/collab/struct-routes.js.map +1 -1
- package/dist/collab/ydoc-manager.d.ts +13 -0
- package/dist/collab/ydoc-manager.d.ts.map +1 -1
- package/dist/collab/ydoc-manager.js +51 -15
- package/dist/collab/ydoc-manager.js.map +1 -1
- package/dist/extensions/fetch-tool.d.ts.map +1 -1
- package/dist/extensions/fetch-tool.js +62 -7
- package/dist/extensions/fetch-tool.js.map +1 -1
- package/dist/extensions/web-search-tool.d.ts +41 -0
- package/dist/extensions/web-search-tool.d.ts.map +1 -0
- package/dist/extensions/web-search-tool.js +200 -0
- package/dist/extensions/web-search-tool.js.map +1 -0
- package/dist/provider-api/custom-registry.d.ts +92 -0
- package/dist/provider-api/custom-registry.d.ts.map +1 -0
- package/dist/provider-api/custom-registry.js +289 -0
- package/dist/provider-api/custom-registry.js.map +1 -0
- package/dist/provider-api/index.d.ts +80 -44
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +569 -18
- package/dist/provider-api/index.js.map +1 -1
- package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
- package/dist/secrets/register-framework-secrets.js +36 -3
- package/dist/secrets/register-framework-secrets.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +36 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +119 -0
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/collab-plugin.d.ts +6 -0
- package/dist/server/collab-plugin.d.ts.map +1 -1
- package/dist/server/collab-plugin.js +105 -5
- package/dist/server/collab-plugin.js.map +1 -1
- package/dist/server/poll-events.d.ts +5 -0
- package/dist/server/poll-events.d.ts.map +1 -1
- package/dist/server/poll-events.js +27 -4
- package/dist/server/poll-events.js.map +1 -1
- package/dist/templates/default/.agents/skills/real-time-collab/SKILL.md +185 -37
- package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +12 -2
- package/dist/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +185 -37
- package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +12 -2
- package/dist/workspace-files/index.d.ts +4 -0
- package/dist/workspace-files/index.d.ts.map +1 -0
- package/dist/workspace-files/index.js +4 -0
- package/dist/workspace-files/index.js.map +1 -0
- package/dist/workspace-files/schema.d.ts +195 -0
- package/dist/workspace-files/schema.d.ts.map +1 -0
- package/dist/workspace-files/schema.js +48 -0
- package/dist/workspace-files/schema.js.map +1 -0
- package/dist/workspace-files/store.d.ts +89 -0
- package/dist/workspace-files/store.d.ts.map +1 -0
- package/dist/workspace-files/store.js +298 -0
- package/dist/workspace-files/store.js.map +1 -0
- package/dist/workspace-files/tool.d.ts +15 -0
- package/dist/workspace-files/tool.d.ts.map +1 -0
- package/dist/workspace-files/tool.js +226 -0
- package/dist/workspace-files/tool.js.map +1 -0
- package/docs/content/real-time-collaboration.md +481 -97
- package/package.json +2 -1
- package/src/templates/default/.agents/skills/real-time-collab/SKILL.md +185 -37
- package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +12 -2
- package/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +185 -37
- package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +12 -2
package/dist/collab/awareness.js
CHANGED
|
@@ -4,10 +4,36 @@
|
|
|
4
4
|
* Stores per-client awareness state (cursor positions, user info) in memory.
|
|
5
5
|
* Clients POST their state and receive other clients' states via polling.
|
|
6
6
|
* States expire after 30 seconds of no updates.
|
|
7
|
+
*
|
|
8
|
+
* Fast-path: when a client POSTs new awareness state, the server emits an
|
|
9
|
+
* event on the awareness emitter so SSE-connected peers receive cursor moves
|
|
10
|
+
* push-style instead of waiting for the next poll cycle.
|
|
7
11
|
*/
|
|
12
|
+
import { EventEmitter } from "node:events";
|
|
8
13
|
import { defineEventHandler, setResponseStatus, getRouterParam } from "h3";
|
|
9
14
|
import { readBody } from "../server/h3-helpers.js";
|
|
10
15
|
const AWARENESS_TIMEOUT = 30_000; // 30 seconds
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Awareness event emitter — fast-path for push delivery to SSE-connected peers.
|
|
18
|
+
// The SSE handler (poll-events) subscribes and forwards events to its stream.
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
export const AWARENESS_CHANGE_EVENT = "awareness-change";
|
|
21
|
+
const _awarenessEmitter = new EventEmitter();
|
|
22
|
+
_awarenessEmitter.setMaxListeners(0);
|
|
23
|
+
export function getAwarenessEmitter() {
|
|
24
|
+
return _awarenessEmitter;
|
|
25
|
+
}
|
|
26
|
+
export function emitAwarenessChange(docId, states, owner, orgId) {
|
|
27
|
+
const event = {
|
|
28
|
+
source: "awareness",
|
|
29
|
+
type: "awareness-change",
|
|
30
|
+
docId,
|
|
31
|
+
states,
|
|
32
|
+
...(owner && { owner }),
|
|
33
|
+
...(orgId && { orgId }),
|
|
34
|
+
};
|
|
35
|
+
_awarenessEmitter.emit(AWARENESS_CHANGE_EVENT, event);
|
|
36
|
+
}
|
|
11
37
|
// docId → Map<clientId, AwarenessEntry>
|
|
12
38
|
const _awarenessMap = new Map();
|
|
13
39
|
export function getDocAwareness(docId) {
|
|
@@ -58,16 +84,27 @@ export const postAwareness = defineEventHandler(async (event) => {
|
|
|
58
84
|
const map = getDocAwareness(docId);
|
|
59
85
|
// Store this client's state
|
|
60
86
|
map.set(clientId, { clientId, state, lastSeen: Date.now() });
|
|
61
|
-
// Clean expired entries
|
|
87
|
+
// Clean expired entries, then prune the outer-map entry if it becomes empty.
|
|
88
|
+
// Without pruning, a deployment with many transient docIds (e.g. one per
|
|
89
|
+
// session) would grow _awarenessMap without bound.
|
|
62
90
|
cleanExpired(map);
|
|
63
|
-
//
|
|
64
|
-
|
|
91
|
+
// map has at least the sender's entry so size >= 1 here; pruneIfEmpty is a
|
|
92
|
+
// no-op in the normal path but guards against edge cases (e.g. clientId 0
|
|
93
|
+
// that was immediately evicted by a concurrent cleanExpired run).
|
|
94
|
+
pruneIfEmpty(docId, map);
|
|
95
|
+
// Build the full list of current states (all clients including sender).
|
|
96
|
+
const allStates = [];
|
|
97
|
+
const otherStates = [];
|
|
65
98
|
for (const [id, entry] of map) {
|
|
99
|
+
allStates.push({ clientId: id, state: entry.state });
|
|
66
100
|
if (id !== clientId) {
|
|
67
|
-
|
|
101
|
+
otherStates.push({ clientId: id, state: entry.state });
|
|
68
102
|
}
|
|
69
103
|
}
|
|
70
|
-
|
|
104
|
+
// Fast-path: push the updated state set to SSE-connected peers so they
|
|
105
|
+
// don't have to wait for the next poll cycle for cursor/selection updates.
|
|
106
|
+
emitAwarenessChange(docId, allStates);
|
|
107
|
+
return { states: otherStates };
|
|
71
108
|
});
|
|
72
109
|
/**
|
|
73
110
|
* GET /_agent-native/collab/:docId/users
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"awareness.js","sourceRoot":"","sources":["../../src/collab/awareness.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"awareness.js","sourceRoot":"","sources":["../../src/collab/awareness.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Server-side awareness state management for collaborative editing.\n *\n * Stores per-client awareness state (cursor positions, user info) in memory.\n * Clients POST their state and receive other clients' states via polling.\n * States expire after 30 seconds of no updates.\n *\n * Fast-path: when a client POSTs new awareness state, the server emits an\n * event on the awareness emitter so SSE-connected peers receive cursor moves\n * push-style instead of waiting for the next poll cycle.\n */\n\nimport { EventEmitter } from \"node:events\";\nimport { defineEventHandler, setResponseStatus, getRouterParam } from \"h3\";\nimport type { H3Event } from \"h3\";\nimport { readBody } from \"../server/h3-helpers.js\";\n\nconst AWARENESS_TIMEOUT = 30_000; // 30 seconds\n\nexport interface AwarenessEntry {\n clientId: number;\n state: string; // JSON-encoded awareness state object\n lastSeen: number;\n}\n\n// ---------------------------------------------------------------------------\n// Awareness event emitter — fast-path for push delivery to SSE-connected peers.\n// The SSE handler (poll-events) subscribes and forwards events to its stream.\n// ---------------------------------------------------------------------------\n\nexport const AWARENESS_CHANGE_EVENT = \"awareness-change\" as const;\n\nexport interface AwarenessChangeEvent {\n source: \"awareness\";\n type: \"awareness-change\";\n docId: string;\n /** Array of updated states for this document (all non-expired clients). */\n states: Array<{ clientId: number; state: string }>;\n /** Owner email for access-scoped delivery (taken from session if available). */\n owner?: string;\n /** Org ID for org-scoped delivery. */\n orgId?: string;\n}\n\nconst _awarenessEmitter = new EventEmitter();\n_awarenessEmitter.setMaxListeners(0);\n\nexport function getAwarenessEmitter(): EventEmitter {\n return _awarenessEmitter;\n}\n\nexport function emitAwarenessChange(\n docId: string,\n states: Array<{ clientId: number; state: string }>,\n owner?: string,\n orgId?: string,\n): void {\n const event: AwarenessChangeEvent = {\n source: \"awareness\",\n type: \"awareness-change\",\n docId,\n states,\n ...(owner && { owner }),\n ...(orgId && { orgId }),\n };\n _awarenessEmitter.emit(AWARENESS_CHANGE_EVENT, event);\n}\n\n// docId → Map<clientId, AwarenessEntry>\nconst _awarenessMap = new Map<string, Map<number, AwarenessEntry>>();\n\nexport function getDocAwareness(docId: string): Map<number, AwarenessEntry> {\n let map = _awarenessMap.get(docId);\n if (!map) {\n map = new Map();\n _awarenessMap.set(docId, map);\n }\n return map;\n}\n\nexport function cleanExpired(map: Map<number, AwarenessEntry>): void {\n const now = Date.now();\n for (const [clientId, entry] of map) {\n if (now - entry.lastSeen > AWARENESS_TIMEOUT) {\n map.delete(clientId);\n }\n }\n}\n\n// Drop the per-document map from the registry once it has no entries left,\n// so the outer map does not grow unbounded with every docId ever touched.\nfunction pruneIfEmpty(docId: string, map: Map<number, AwarenessEntry>): void {\n if (map.size === 0) {\n _awarenessMap.delete(docId);\n }\n}\n\n/**\n * POST /_agent-native/collab/:docId/awareness\n *\n * Client sends its awareness state and receives other clients' states.\n *\n * Body: { clientId: number, state: string (base64) }\n * Response: { states: Array<{ clientId: number, state: string }> }\n */\nexport const postAwareness = defineEventHandler(async (event: H3Event) => {\n const docId = getRouterParam(event, \"docId\");\n if (!docId) {\n setResponseStatus(event, 400);\n return { error: \"docId required\" };\n }\n\n const body = await readBody(event);\n const { clientId, state } = body as {\n clientId?: number;\n state?: string;\n };\n\n if (clientId == null || !state) {\n // `!clientId` would wrongly reject clientId === 0, which is a valid\n // (if rare) Yjs client id. Only reject missing/null ids here.\n setResponseStatus(event, 400);\n return { error: \"clientId and state required\" };\n }\n\n const map = getDocAwareness(docId);\n\n // Store this client's state\n map.set(clientId, { clientId, state, lastSeen: Date.now() });\n\n // Clean expired entries, then prune the outer-map entry if it becomes empty.\n // Without pruning, a deployment with many transient docIds (e.g. one per\n // session) would grow _awarenessMap without bound.\n cleanExpired(map);\n // map has at least the sender's entry so size >= 1 here; pruneIfEmpty is a\n // no-op in the normal path but guards against edge cases (e.g. clientId 0\n // that was immediately evicted by a concurrent cleanExpired run).\n pruneIfEmpty(docId, map);\n\n // Build the full list of current states (all clients including sender).\n const allStates: Array<{ clientId: number; state: string }> = [];\n const otherStates: Array<{ clientId: number; state: string }> = [];\n for (const [id, entry] of map) {\n allStates.push({ clientId: id, state: entry.state });\n if (id !== clientId) {\n otherStates.push({ clientId: id, state: entry.state });\n }\n }\n\n // Fast-path: push the updated state set to SSE-connected peers so they\n // don't have to wait for the next poll cycle for cursor/selection updates.\n emitAwarenessChange(docId, allStates);\n\n return { states: otherStates };\n});\n\n/**\n * GET /_agent-native/collab/:docId/users\n *\n * Returns the list of active users for a document (for presence bar).\n */\nexport const getActiveUsers = defineEventHandler(async (event: H3Event) => {\n const docId = getRouterParam(event, \"docId\");\n if (!docId) {\n setResponseStatus(event, 400);\n return { error: \"docId required\" };\n }\n\n const map = getDocAwareness(docId);\n cleanExpired(map);\n pruneIfEmpty(docId, map);\n\n const users: Array<{ clientId: number; lastSeen: number }> = [];\n for (const [, entry] of map) {\n users.push({ clientId: entry.clientId, lastSeen: entry.lastSeen });\n }\n\n return { users };\n});\n"]}
|
package/dist/collab/client.d.ts
CHANGED
|
@@ -7,6 +7,22 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Also manages Yjs Awareness for cursor positions and user presence,
|
|
9
9
|
* synced via polling to the server's awareness endpoint.
|
|
10
|
+
*
|
|
11
|
+
* Transport improvements (vs previous version):
|
|
12
|
+
* - Local update POSTs are debounced and coalesced with Y.mergeUpdates (~80ms)
|
|
13
|
+
* to avoid per-keystroke requests. The batch is flushed immediately on
|
|
14
|
+
* visibilitychange/pagehide and before each poll/awareness cycle.
|
|
15
|
+
* - GET state?stateVector= is NOT fetched on every poll cycle. It is fetched:
|
|
16
|
+
* (a) on (re)connect / initial load, (b) when a poll response indicates a
|
|
17
|
+
* gap (version jump > ring-buffer size), (c) after applying an update fails,
|
|
18
|
+
* and (d) as a low-frequency safety net every STATE_VECTOR_FETCH_INTERVAL
|
|
19
|
+
* poll cycles (~15×).
|
|
20
|
+
* - Network errors use exponential backoff with jitter (cap ~15s), reset on
|
|
21
|
+
* success.
|
|
22
|
+
* - SSE fast-path: collab events are received push-style from
|
|
23
|
+
* /_agent-native/poll-events (the existing SSE stream). While SSE is
|
|
24
|
+
* healthy the poll loop relaxes to a slow cadence (10–15s). If SSE is
|
|
25
|
+
* unavailable the 2s poll resumes automatically.
|
|
10
26
|
*/
|
|
11
27
|
import * as Y from "yjs";
|
|
12
28
|
import { Awareness } from "y-protocols/awareness";
|
|
@@ -18,8 +34,10 @@ export interface CollabUser {
|
|
|
18
34
|
export interface UseCollaborativeDocOptions {
|
|
19
35
|
/** Document ID to collaborate on. Pass null to disable. */
|
|
20
36
|
docId: string | null;
|
|
21
|
-
/** Poll interval in ms. Default: 2000 */
|
|
37
|
+
/** Poll interval in ms when SSE is unavailable. Default: 2000 */
|
|
22
38
|
pollInterval?: number;
|
|
39
|
+
/** Poll interval in ms while SSE is healthy. Default: 12000 */
|
|
40
|
+
pollIntervalWithSse?: number;
|
|
23
41
|
/** Pause remote update/presence polling while the tab is hidden. Default: true */
|
|
24
42
|
pauseWhenHidden?: boolean;
|
|
25
43
|
/** Base URL for collab endpoints. Default: "/_agent-native/collab" */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/collab/client.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/collab/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAIlD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,0BAA0B;IACzC,2DAA2D;IAC3D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kFAAkF;IAClF,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,4EAA4E;IAC5E,IAAI,EAAE,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC;IACnB,uDAAuD;IACvD,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,kEAAkE;IAClE,SAAS,EAAE,OAAO,CAAC;IACnB,iDAAiD;IACjD,QAAQ,EAAE,OAAO,CAAC;IAClB,sDAAsD;IACtD,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,6EAA6E;IAC7E,WAAW,EAAE,OAAO,CAAC;IACrB,+EAA+E;IAC/E,YAAY,EAAE,OAAO,CAAC;CACvB;AAgBD,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGjD;AAYD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAY1E;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,EACvC,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACvC,OAAO,CA6BT;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,uBAAuB,EAAE,GACtC;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CA2B3D;AA2ED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,0BAA0B,GAClC,yBAAyB,CAgpB3B"}
|