orez-sync-executor 0.11.1 → 0.11.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.
- package/dist/realtime/host.d.ts +7 -0
- package/dist/realtime/host.d.ts.map +1 -0
- package/dist/realtime/host.js +77 -0
- package/dist/realtime/host.js.map +1 -0
- package/dist/realtime/hub.d.ts +67 -0
- package/dist/realtime/hub.d.ts.map +1 -0
- package/dist/realtime/hub.js +456 -0
- package/dist/realtime/hub.js.map +1 -0
- package/dist/realtime/index.d.ts +24 -0
- package/dist/realtime/index.d.ts.map +1 -0
- package/dist/realtime/index.js +27 -0
- package/dist/realtime/index.js.map +1 -0
- package/dist/realtime/local.d.ts +15 -0
- package/dist/realtime/local.d.ts.map +1 -0
- package/dist/realtime/local.js +63 -0
- package/dist/realtime/local.js.map +1 -0
- package/dist/realtime/manifest.d.ts +51 -0
- package/dist/realtime/manifest.d.ts.map +1 -0
- package/dist/realtime/manifest.js +110 -0
- package/dist/realtime/manifest.js.map +1 -0
- package/dist/realtime/message-port.d.ts +34 -0
- package/dist/realtime/message-port.d.ts.map +1 -0
- package/dist/realtime/message-port.js +141 -0
- package/dist/realtime/message-port.js.map +1 -0
- package/dist/realtime/producer-socket.d.ts +10 -0
- package/dist/realtime/producer-socket.d.ts.map +1 -0
- package/dist/realtime/producer-socket.js +90 -0
- package/dist/realtime/producer-socket.js.map +1 -0
- package/dist/realtime/producer.d.ts +16 -0
- package/dist/realtime/producer.d.ts.map +1 -0
- package/dist/realtime/producer.js +51 -0
- package/dist/realtime/producer.js.map +1 -0
- package/dist/realtime/protocol.d.ts +99 -0
- package/dist/realtime/protocol.d.ts.map +1 -0
- package/dist/realtime/protocol.js +191 -0
- package/dist/realtime/protocol.js.map +1 -0
- package/dist/realtime/publisher.d.ts +28 -0
- package/dist/realtime/publisher.d.ts.map +1 -0
- package/dist/realtime/publisher.js +309 -0
- package/dist/realtime/publisher.js.map +1 -0
- package/dist/realtime/socket-host.d.ts +25 -0
- package/dist/realtime/socket-host.d.ts.map +1 -0
- package/dist/realtime/socket-host.js +105 -0
- package/dist/realtime/socket-host.js.map +1 -0
- package/dist/realtime/store.d.ts +28 -0
- package/dist/realtime/store.d.ts.map +1 -0
- package/dist/realtime/store.js +0 -0
- package/dist/realtime/store.js.map +1 -0
- package/dist/realtime/writer.d.ts +17 -0
- package/dist/realtime/writer.d.ts.map +1 -0
- package/dist/realtime/writer.js +138 -0
- package/dist/realtime/writer.js.map +1 -0
- package/package.json +5 -1
- package/dist/adapters.d.ts +0 -25
- package/dist/adapters.d.ts.map +0 -1
- package/dist/adapters.js +0 -116
- package/dist/adapters.js.map +0 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RealtimeHub, HubConnection, HubProducer } from './hub.js';
|
|
2
|
+
import type { ClientFrame, HostFrame, ProducerFrame } from './protocol.js';
|
|
3
|
+
import type { RealtimeStore } from './store.js';
|
|
4
|
+
export declare function applyClientFrame(hub: RealtimeHub, connection: HubConnection, frame: ClientFrame): Promise<void>;
|
|
5
|
+
export declare function applyProducerFrame(hub: RealtimeHub, producer: HubProducer, frame: ProducerFrame): void;
|
|
6
|
+
export declare function applyHostFrame(store: RealtimeStore, frame: HostFrame): void;
|
|
7
|
+
//# sourceMappingURL=host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/realtime/host.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACvE,OAAO,KAAK,EAAE,WAAW,EAAe,SAAS,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AACvF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAK/C,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,WAAW,EAChB,UAAU,EAAE,aAAa,EACzB,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,IAAI,CAAC,CAIf;AAQD,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,WAAW,EACrB,KAAK,EAAE,aAAa,GACnB,IAAI,CAuBN;AASD,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAc3E"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Frame routing. Every realtime surface is built from these three functions.
|
|
2
|
+
//
|
|
3
|
+
// A stream has exactly three directions, and there is one applier for each:
|
|
4
|
+
//
|
|
5
|
+
// applyClientFrame subscriber -> hub subscribe, unsubscribe
|
|
6
|
+
// applyProducerFrame producer -> hub begin, publish
|
|
7
|
+
// applyHostFrame hub -> store subscribed, field, subscribe-error
|
|
8
|
+
//
|
|
9
|
+
// Everything else in a surface is channel plumbing: a MessagePort, a
|
|
10
|
+
// WebSocket, or a direct call. Keeping the routing here is what lets a new
|
|
11
|
+
// transport be written without re-deriving which frame maps to which call, and
|
|
12
|
+
// it is why adding one cannot quietly disagree with the others.
|
|
13
|
+
//
|
|
14
|
+
// Subscribers and producers are deliberately separate roles with separate
|
|
15
|
+
// frames. A subscriber socket can never publish, so a leaked streamID buys an
|
|
16
|
+
// attacker nothing: the hub checks the producer HANDLE, and a subscriber does
|
|
17
|
+
// not have one.
|
|
18
|
+
// Apply one subscriber frame. The returned promise resolves when the frame has
|
|
19
|
+
// been applied, which an adapter awaits before processing the next frame from
|
|
20
|
+
// the same socket so a subscribe/unsubscribe pair cannot land out of order.
|
|
21
|
+
export function applyClientFrame(hub, connection, frame) {
|
|
22
|
+
return frame[0] === 'subscribe'
|
|
23
|
+
? hub.subscribe(connection, frame[1].topic)
|
|
24
|
+
: hub.unsubscribe(connection, frame[1].topic);
|
|
25
|
+
}
|
|
26
|
+
// Apply one producer frame.
|
|
27
|
+
//
|
|
28
|
+
// `begin` is answered either way: the producer cannot start streaming until it
|
|
29
|
+
// knows the host accepted the generation. Updates are answered only when
|
|
30
|
+
// rejected, so a token stream costs one frame per token rather than a round
|
|
31
|
+
// trip per token.
|
|
32
|
+
export function applyProducerFrame(hub, producer, frame) {
|
|
33
|
+
if (frame[0] === 'begin') {
|
|
34
|
+
const { topic, streamID } = frame[1];
|
|
35
|
+
const result = hub.beginGeneration(producer, topic, streamID);
|
|
36
|
+
producer.send([
|
|
37
|
+
'begin-result',
|
|
38
|
+
{
|
|
39
|
+
streamID,
|
|
40
|
+
topic: result.ok ? result.topicID : null,
|
|
41
|
+
reason: result.ok ? null : result.reason,
|
|
42
|
+
},
|
|
43
|
+
]);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const { update } = frame[1];
|
|
47
|
+
const result = hub.publish(producer, update);
|
|
48
|
+
if (!result.ok) {
|
|
49
|
+
producer.send([
|
|
50
|
+
'publish-rejected',
|
|
51
|
+
{ topic: update.topic, streamID: update.streamID, reason: result.reason },
|
|
52
|
+
]);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Apply one frame the host sent back to a subscriber. Every client transport
|
|
56
|
+
// ends in this call, so a MessagePort client and a WebSocket client cannot drift
|
|
57
|
+
// apart in how they interpret the same frame.
|
|
58
|
+
//
|
|
59
|
+
// A `wake` frame is deliberately ignored here: it belongs to the Zero pull path,
|
|
60
|
+
// not to the field overlay, and a client that shares one socket for both routes
|
|
61
|
+
// it before reaching this.
|
|
62
|
+
export function applyHostFrame(store, frame) {
|
|
63
|
+
switch (frame[0]) {
|
|
64
|
+
case 'field':
|
|
65
|
+
store.applyUpdates(frame[1].updates);
|
|
66
|
+
return;
|
|
67
|
+
case 'subscribed':
|
|
68
|
+
store.handleSubscribed(frame[1].topic, frame[1].status);
|
|
69
|
+
return;
|
|
70
|
+
case 'subscribe-error':
|
|
71
|
+
store.handleSubscribeError(frame[1].topic, frame[1].reason);
|
|
72
|
+
return;
|
|
73
|
+
case 'wake':
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/realtime/host.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { StreamingFieldSpec, StreamingManifest } from './manifest.js';
|
|
2
|
+
import type { FieldUpdate, RealtimeTopic } from './protocol.js';
|
|
3
|
+
export type RealtimeIdentity = {
|
|
4
|
+
readonly userID: string;
|
|
5
|
+
readonly clientID: string;
|
|
6
|
+
readonly clientGroupID: string;
|
|
7
|
+
};
|
|
8
|
+
export interface HubConnection {
|
|
9
|
+
readonly id: string;
|
|
10
|
+
readonly identity: RealtimeIdentity;
|
|
11
|
+
send(frame: unknown): void;
|
|
12
|
+
}
|
|
13
|
+
export interface HubProducer {
|
|
14
|
+
readonly id: string;
|
|
15
|
+
send(frame: unknown): void;
|
|
16
|
+
}
|
|
17
|
+
export type SubscribeAuthorization = {
|
|
18
|
+
readonly status: 'active' | 'pending';
|
|
19
|
+
} | {
|
|
20
|
+
readonly status: 'denied';
|
|
21
|
+
readonly reason: string;
|
|
22
|
+
};
|
|
23
|
+
export type HubLimits = {
|
|
24
|
+
readonly maxTopicsPerConnection: number;
|
|
25
|
+
readonly maxSubscribersPerTopic: number;
|
|
26
|
+
readonly maxTopicsPerNamespace: number;
|
|
27
|
+
readonly maxBatchBytes: number;
|
|
28
|
+
readonly batchWindowMs: number;
|
|
29
|
+
};
|
|
30
|
+
export declare const DEFAULT_HUB_LIMITS: HubLimits;
|
|
31
|
+
export type HubOptions = {
|
|
32
|
+
readonly manifest: StreamingManifest;
|
|
33
|
+
readonly authorizeSubscribe: (identity: RealtimeIdentity, topic: RealtimeTopic, spec: StreamingFieldSpec) => Promise<SubscribeAuthorization> | SubscribeAuthorization;
|
|
34
|
+
readonly limits?: Partial<HubLimits>;
|
|
35
|
+
readonly scheduleFlush?: (flush: () => void, ms: number) => void;
|
|
36
|
+
};
|
|
37
|
+
export declare class RealtimeHub {
|
|
38
|
+
#private;
|
|
39
|
+
constructor(options: HubOptions);
|
|
40
|
+
subscribe(connection: HubConnection, topic: RealtimeTopic): Promise<void>;
|
|
41
|
+
unsubscribe(connection: HubConnection, topic: RealtimeTopic): Promise<void>;
|
|
42
|
+
dropConnection(connectionID: string): void;
|
|
43
|
+
revokeMembership(clientGroupID: string, removed: readonly RealtimeTopic[]): void;
|
|
44
|
+
revokeAllForGroup(clientGroupID: string): void;
|
|
45
|
+
beginGeneration(producer: HubProducer, topic: RealtimeTopic, streamID: string): {
|
|
46
|
+
readonly ok: true;
|
|
47
|
+
readonly topicID: string;
|
|
48
|
+
} | {
|
|
49
|
+
readonly ok: false;
|
|
50
|
+
readonly reason: string;
|
|
51
|
+
};
|
|
52
|
+
publish(producer: HubProducer, update: FieldUpdate): {
|
|
53
|
+
readonly ok: true;
|
|
54
|
+
} | {
|
|
55
|
+
readonly ok: false;
|
|
56
|
+
readonly reason: string;
|
|
57
|
+
};
|
|
58
|
+
dropProducer(producerID: string): void;
|
|
59
|
+
flush(): void;
|
|
60
|
+
get activeTopics(): number;
|
|
61
|
+
get subscribedTopics(): number;
|
|
62
|
+
generationFor(topicID: string): {
|
|
63
|
+
readonly streamID: string;
|
|
64
|
+
readonly seq: number;
|
|
65
|
+
} | undefined;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=hub.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hub.d.ts","sourceRoot":"","sources":["../../src/realtime/hub.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
// The host-side realtime hub: one pure state machine shared by every
|
|
2
|
+
// TypeScript host (the Cloudflare Durable Object and the browser worker).
|
|
3
|
+
//
|
|
4
|
+
// It owns no I/O. Connections are opaque handles with a `send`, so the same
|
|
5
|
+
// logic drives a hibernatable WebSocket, a MessagePort, and a test harness. A
|
|
6
|
+
// host adapter is then only socket lifecycle plus authentication.
|
|
7
|
+
//
|
|
8
|
+
// The hub ACCUMULATES each generation's value. That is what makes append-mode
|
|
9
|
+
// frames safe: a subscriber arriving at token 900 gets one snapshot of what the
|
|
10
|
+
// hub has, then appends, and no client ever needs a replay buffer. It is also
|
|
11
|
+
// why a lost frame cannot produce a wrong value, since the next snapshot after
|
|
12
|
+
// any reconnect is authoritative.
|
|
13
|
+
import { resolveTopic } from './manifest.js';
|
|
14
|
+
import { canonicalEncode } from './store.js';
|
|
15
|
+
export const DEFAULT_HUB_LIMITS = {
|
|
16
|
+
maxTopicsPerConnection: 256,
|
|
17
|
+
maxSubscribersPerTopic: 512,
|
|
18
|
+
maxTopicsPerNamespace: 4096,
|
|
19
|
+
maxBatchBytes: 512 * 1024,
|
|
20
|
+
batchWindowMs: 25,
|
|
21
|
+
};
|
|
22
|
+
export class RealtimeHub {
|
|
23
|
+
#manifest;
|
|
24
|
+
#authorize;
|
|
25
|
+
#limits;
|
|
26
|
+
#schedule;
|
|
27
|
+
#generations = new Map();
|
|
28
|
+
#subscribers = new Map();
|
|
29
|
+
#connectionTopics = new Map();
|
|
30
|
+
#connections = new Map();
|
|
31
|
+
// producer id -> every generation it currently leases. An application server
|
|
32
|
+
// streaming twenty agent sessions holds one connection, not twenty, so the
|
|
33
|
+
// lease is a set: the socket closing releases all of them at once.
|
|
34
|
+
#producerGenerations = new Map();
|
|
35
|
+
// per-connection outbound batch, flushed on the batching window
|
|
36
|
+
#outbox = new Map();
|
|
37
|
+
#flushScheduled = false;
|
|
38
|
+
// One chain per connection so its subscribe and unsubscribe frames apply in
|
|
39
|
+
// arrival order even though authorization may await. Without it, a
|
|
40
|
+
// subscribe/unsubscribe pair sent back to back could resolve out of order and
|
|
41
|
+
// leave a connection subscribed to a topic it had already dropped.
|
|
42
|
+
#connectionQueue = new Map();
|
|
43
|
+
// Bumped by dropConnection. A subscribe captures the epoch when the frame
|
|
44
|
+
// ARRIVES, not when its queued task runs, so a socket that closes while its
|
|
45
|
+
// authorization is still in flight abandons the subscription instead of
|
|
46
|
+
// completing it against a connection nobody is reading from.
|
|
47
|
+
#connectionEpoch = new Map();
|
|
48
|
+
constructor(options) {
|
|
49
|
+
this.#manifest = options.manifest;
|
|
50
|
+
this.#authorize = options.authorizeSubscribe;
|
|
51
|
+
this.#limits = { ...DEFAULT_HUB_LIMITS, ...options.limits };
|
|
52
|
+
this.#schedule =
|
|
53
|
+
options.scheduleFlush ??
|
|
54
|
+
((flush, ms) => {
|
|
55
|
+
setTimeout(flush, ms);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// ---- subscribers --------------------------------------------------------
|
|
59
|
+
// Queued per connection: the returned promise resolves once this frame has
|
|
60
|
+
// been applied, which is what a host adapter awaits before processing the
|
|
61
|
+
// next frame from the same socket.
|
|
62
|
+
subscribe(connection, topic) {
|
|
63
|
+
const epoch = this.#connectionEpoch.get(connection.id) ?? 0;
|
|
64
|
+
return this.#enqueue(connection.id, () => this.#subscribe(connection, topic, epoch));
|
|
65
|
+
}
|
|
66
|
+
unsubscribe(connection, topic) {
|
|
67
|
+
return this.#enqueue(connection.id, () => {
|
|
68
|
+
const resolved = resolveTopic(this.#manifest, topic);
|
|
69
|
+
if ('reason' in resolved)
|
|
70
|
+
return;
|
|
71
|
+
this.#removeSubscription(connection.id, resolved.id);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
#enqueue(connectionID, task) {
|
|
75
|
+
const previous = this.#connectionQueue.get(connectionID) ?? Promise.resolve();
|
|
76
|
+
// a rejected task must not poison the chain for later frames
|
|
77
|
+
const next = previous.then(task).catch(() => { });
|
|
78
|
+
this.#connectionQueue.set(connectionID, next);
|
|
79
|
+
return next;
|
|
80
|
+
}
|
|
81
|
+
#isCurrent(connectionID, epoch) {
|
|
82
|
+
return (this.#connectionEpoch.get(connectionID) ?? 0) === epoch;
|
|
83
|
+
}
|
|
84
|
+
async #subscribe(connection, topic, epoch) {
|
|
85
|
+
if (!this.#isCurrent(connection.id, epoch))
|
|
86
|
+
return;
|
|
87
|
+
this.#connections.set(connection.id, connection);
|
|
88
|
+
const resolved = resolveTopic(this.#manifest, topic);
|
|
89
|
+
if ('reason' in resolved) {
|
|
90
|
+
connection.send([
|
|
91
|
+
'subscribe-error',
|
|
92
|
+
{ topic: describe(topic), reason: resolved.reason },
|
|
93
|
+
]);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const { spec, id } = resolved;
|
|
97
|
+
const owned = this.#connectionTopics.get(connection.id) ?? new Set();
|
|
98
|
+
// a resubscribe after reconnect is not a new subscription
|
|
99
|
+
if (!owned.has(id)) {
|
|
100
|
+
if (owned.size >= this.#limits.maxTopicsPerConnection) {
|
|
101
|
+
connection.send([
|
|
102
|
+
'subscribe-error',
|
|
103
|
+
{ topic: id, reason: 'connection is at its subscription limit' },
|
|
104
|
+
]);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (!this.#subscribers.has(id) &&
|
|
108
|
+
this.#subscribers.size >= this.#limits.maxTopicsPerNamespace) {
|
|
109
|
+
connection.send([
|
|
110
|
+
'subscribe-error',
|
|
111
|
+
{ topic: id, reason: 'namespace is at its active topic limit' },
|
|
112
|
+
]);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const existing = this.#subscribers.get(id);
|
|
116
|
+
if (existing && existing.size >= this.#limits.maxSubscribersPerTopic) {
|
|
117
|
+
connection.send([
|
|
118
|
+
'subscribe-error',
|
|
119
|
+
{ topic: id, reason: 'topic is at its subscriber limit' },
|
|
120
|
+
]);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const authorization = await this.#authorize(connection.identity, topic, spec);
|
|
125
|
+
// the socket can close while authorization is in flight
|
|
126
|
+
if (!this.#isCurrent(connection.id, epoch))
|
|
127
|
+
return;
|
|
128
|
+
if (authorization.status === 'denied') {
|
|
129
|
+
connection.send(['subscribe-error', { topic: id, reason: authorization.reason }]);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
owned.add(id);
|
|
133
|
+
this.#connectionTopics.set(connection.id, owned);
|
|
134
|
+
if (authorization.status === 'active') {
|
|
135
|
+
let subscribers = this.#subscribers.get(id);
|
|
136
|
+
if (!subscribers) {
|
|
137
|
+
subscribers = new Set();
|
|
138
|
+
this.#subscribers.set(id, subscribers);
|
|
139
|
+
}
|
|
140
|
+
subscribers.add(connection);
|
|
141
|
+
}
|
|
142
|
+
connection.send(['subscribed', { topic: id, status: authorization.status }]);
|
|
143
|
+
// catch a new subscriber up on a generation already in flight. This is what
|
|
144
|
+
// lets append-mode frames be safe for late joiners, and it is sent
|
|
145
|
+
// immediately rather than batched so a mid-stream mount paints at once.
|
|
146
|
+
const generation = this.#generations.get(id);
|
|
147
|
+
if (authorization.status === 'active' && generation) {
|
|
148
|
+
connection.send([
|
|
149
|
+
'field',
|
|
150
|
+
{
|
|
151
|
+
updates: [
|
|
152
|
+
{
|
|
153
|
+
topic: id,
|
|
154
|
+
streamID: generation.streamID,
|
|
155
|
+
seq: generation.seq,
|
|
156
|
+
op: 'snapshot',
|
|
157
|
+
value: generation.value,
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
]);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
dropConnection(connectionID) {
|
|
165
|
+
this.#connectionEpoch.set(connectionID, (this.#connectionEpoch.get(connectionID) ?? 0) + 1);
|
|
166
|
+
this.#connectionQueue.delete(connectionID);
|
|
167
|
+
for (const topicID of this.#connectionTopics.get(connectionID) ?? []) {
|
|
168
|
+
this.#subscribers.get(topicID)?.forEach((connection) => {
|
|
169
|
+
if (connection.id === connectionID)
|
|
170
|
+
this.#subscribers.get(topicID).delete(connection);
|
|
171
|
+
});
|
|
172
|
+
if (this.#subscribers.get(topicID)?.size === 0)
|
|
173
|
+
this.#subscribers.delete(topicID);
|
|
174
|
+
}
|
|
175
|
+
this.#connectionTopics.delete(connectionID);
|
|
176
|
+
this.#connections.delete(connectionID);
|
|
177
|
+
this.#outbox.delete(connectionID);
|
|
178
|
+
}
|
|
179
|
+
#removeSubscription(connectionID, topicID) {
|
|
180
|
+
this.#connectionTopics.get(connectionID)?.delete(topicID);
|
|
181
|
+
const subscribers = this.#subscribers.get(topicID);
|
|
182
|
+
if (!subscribers)
|
|
183
|
+
return;
|
|
184
|
+
for (const connection of subscribers) {
|
|
185
|
+
if (connection.id === connectionID)
|
|
186
|
+
subscribers.delete(connection);
|
|
187
|
+
}
|
|
188
|
+
if (subscribers.size === 0)
|
|
189
|
+
this.#subscribers.delete(topicID);
|
|
190
|
+
}
|
|
191
|
+
// A pull removed rows from a client group's query membership. The client is
|
|
192
|
+
// about to learn the row left its query, so its field subscriptions for those
|
|
193
|
+
// rows go with it, in the same update rather than on a later sweep.
|
|
194
|
+
revokeMembership(clientGroupID, removed) {
|
|
195
|
+
for (const topic of removed) {
|
|
196
|
+
const resolved = resolveTopic(this.#manifest, topic);
|
|
197
|
+
if ('reason' in resolved)
|
|
198
|
+
continue;
|
|
199
|
+
const subscribers = this.#subscribers.get(resolved.id);
|
|
200
|
+
if (!subscribers)
|
|
201
|
+
continue;
|
|
202
|
+
for (const connection of [...subscribers]) {
|
|
203
|
+
if (connection.identity.clientGroupID !== clientGroupID)
|
|
204
|
+
continue;
|
|
205
|
+
this.#removeSubscription(connection.id, resolved.id);
|
|
206
|
+
connection.send([
|
|
207
|
+
'subscribe-error',
|
|
208
|
+
{ topic: resolved.id, reason: 'row left your authorized query membership' },
|
|
209
|
+
]);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// Every row a client group can currently subscribe to left its membership.
|
|
214
|
+
// Cheaper than enumerating rows when a whole query is dropped.
|
|
215
|
+
revokeAllForGroup(clientGroupID) {
|
|
216
|
+
for (const [topicID, subscribers] of [...this.#subscribers]) {
|
|
217
|
+
for (const connection of [...subscribers]) {
|
|
218
|
+
if (connection.identity.clientGroupID !== clientGroupID)
|
|
219
|
+
continue;
|
|
220
|
+
this.#removeSubscription(connection.id, topicID);
|
|
221
|
+
connection.send([
|
|
222
|
+
'subscribe-error',
|
|
223
|
+
{ topic: topicID, reason: 'row left your authorized query membership' },
|
|
224
|
+
]);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// ---- producers ----------------------------------------------------------
|
|
229
|
+
// Open a generation. A newer generation always supersedes an older one for
|
|
230
|
+
// the same topic, matching how an LLM retry replaces its predecessor. The
|
|
231
|
+
// application still owns final-write fencing in the database; this only
|
|
232
|
+
// decides who may deliver display values.
|
|
233
|
+
beginGeneration(producer, topic, streamID) {
|
|
234
|
+
const resolved = resolveTopic(this.#manifest, topic);
|
|
235
|
+
if ('reason' in resolved)
|
|
236
|
+
return { ok: false, reason: resolved.reason };
|
|
237
|
+
const { spec, id } = resolved;
|
|
238
|
+
const previous = this.#generations.get(id);
|
|
239
|
+
if (previous && previous.streamID !== streamID) {
|
|
240
|
+
if (previous.producer) {
|
|
241
|
+
this.#releaseLease(previous.producer.id, id);
|
|
242
|
+
previous.producer.send(['superseded', { topic: id, streamID: previous.streamID }]);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
this.#generations.set(id, {
|
|
246
|
+
topicID: id,
|
|
247
|
+
spec,
|
|
248
|
+
streamID,
|
|
249
|
+
seq: -1,
|
|
250
|
+
value: spec.mode === 'append' ? '' : null,
|
|
251
|
+
producer,
|
|
252
|
+
});
|
|
253
|
+
const leases = this.#producerGenerations.get(producer.id);
|
|
254
|
+
if (leases)
|
|
255
|
+
leases.add(id);
|
|
256
|
+
else
|
|
257
|
+
this.#producerGenerations.set(producer.id, new Set([id]));
|
|
258
|
+
return { ok: true, topicID: id };
|
|
259
|
+
}
|
|
260
|
+
// Accept one update from a producer, accumulate it, and fan it out. The
|
|
261
|
+
// rejection REASON is returned rather than a bare false: a producer that is
|
|
262
|
+
// told only "refused" has to guess between supersession, a stale sequence, and
|
|
263
|
+
// a manifest bound, and every adapter was inventing the same vague guess.
|
|
264
|
+
publish(producer, update) {
|
|
265
|
+
const generation = this.#generations.get(update.topic);
|
|
266
|
+
if (!generation) {
|
|
267
|
+
return { ok: false, reason: `no open generation for '${update.topic}'` };
|
|
268
|
+
}
|
|
269
|
+
// Only the producer holding this generation may publish. A subscriber
|
|
270
|
+
// socket is never a producer, so a leaked streamID grants nothing: the check
|
|
271
|
+
// is on the producer handle, not the frame contents. A superseded generation
|
|
272
|
+
// needs no flag of its own, because beginGeneration REPLACED it in this map;
|
|
273
|
+
// its old producer falls out here, and its old stream id falls out below.
|
|
274
|
+
if (generation.producer?.id !== producer.id) {
|
|
275
|
+
return { ok: false, reason: `another producer holds '${update.topic}'` };
|
|
276
|
+
}
|
|
277
|
+
if (generation.streamID !== update.streamID) {
|
|
278
|
+
return {
|
|
279
|
+
ok: false,
|
|
280
|
+
reason: `stream ${update.streamID} is not the current generation for '${update.topic}'`,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
if (update.seq <= generation.seq) {
|
|
284
|
+
return {
|
|
285
|
+
ok: false,
|
|
286
|
+
reason: `seq ${update.seq} is not newer than the delivered ${generation.seq}`,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
switch (update.op) {
|
|
290
|
+
case 'snapshot': {
|
|
291
|
+
if (!this.#validate(generation.spec, update.value)) {
|
|
292
|
+
return {
|
|
293
|
+
ok: false,
|
|
294
|
+
reason: `value failed the manifest bounds for '${update.topic}'`,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
generation.value = update.value;
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
case 'append': {
|
|
301
|
+
if (generation.spec.mode !== 'append') {
|
|
302
|
+
return {
|
|
303
|
+
ok: false,
|
|
304
|
+
reason: `'${update.topic}' is replace mode and takes no appends`,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
const next = generation.value + update.text;
|
|
308
|
+
if (byteLength(next) > generation.spec.maxBytes) {
|
|
309
|
+
return {
|
|
310
|
+
ok: false,
|
|
311
|
+
reason: `append would exceed maxBytes for '${update.topic}'`,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
generation.value = next;
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
case 'end':
|
|
318
|
+
case 'abort':
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
generation.seq = update.seq;
|
|
322
|
+
this.#fanOut(update);
|
|
323
|
+
if (update.op === 'end' || update.op === 'abort') {
|
|
324
|
+
this.#generations.delete(update.topic);
|
|
325
|
+
this.#releaseLease(producer.id, update.topic);
|
|
326
|
+
}
|
|
327
|
+
return { ok: true };
|
|
328
|
+
}
|
|
329
|
+
#releaseLease(producerID, topicID) {
|
|
330
|
+
const leases = this.#producerGenerations.get(producerID);
|
|
331
|
+
if (!leases)
|
|
332
|
+
return;
|
|
333
|
+
leases.delete(topicID);
|
|
334
|
+
if (leases.size === 0)
|
|
335
|
+
this.#producerGenerations.delete(producerID);
|
|
336
|
+
}
|
|
337
|
+
// A producer socket closed without a terminal frame (a crash, or a lost
|
|
338
|
+
// connection). The generation's lease is released so the next `begin` is
|
|
339
|
+
// clean; subscribers fall back to their inactivity deadline, which reveals
|
|
340
|
+
// the durable value rather than inventing a recovery value here.
|
|
341
|
+
dropProducer(producerID) {
|
|
342
|
+
const leases = this.#producerGenerations.get(producerID);
|
|
343
|
+
this.#producerGenerations.delete(producerID);
|
|
344
|
+
if (!leases)
|
|
345
|
+
return;
|
|
346
|
+
for (const topicID of leases) {
|
|
347
|
+
const generation = this.#generations.get(topicID);
|
|
348
|
+
if (generation?.producer?.id === producerID)
|
|
349
|
+
this.#generations.delete(topicID);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
#validate(spec, value) {
|
|
353
|
+
if (spec.mode === 'append' && typeof value !== 'string')
|
|
354
|
+
return false;
|
|
355
|
+
if (spec.validate && !spec.validate(value))
|
|
356
|
+
return false;
|
|
357
|
+
return byteLength(canonicalEncode(value)) <= spec.maxBytes;
|
|
358
|
+
}
|
|
359
|
+
#fanOut(update) {
|
|
360
|
+
const subscribers = this.#subscribers.get(update.topic);
|
|
361
|
+
if (!subscribers || subscribers.size === 0)
|
|
362
|
+
return;
|
|
363
|
+
for (const connection of subscribers) {
|
|
364
|
+
const batch = this.#outbox.get(connection.id);
|
|
365
|
+
if (batch)
|
|
366
|
+
batch.push(update);
|
|
367
|
+
else
|
|
368
|
+
this.#outbox.set(connection.id, [update]);
|
|
369
|
+
}
|
|
370
|
+
this.#scheduleFlush();
|
|
371
|
+
}
|
|
372
|
+
// The "is a flush already pending" flag is separate from the cancel handle
|
|
373
|
+
// because a scheduler is allowed to run its callback SYNCHRONOUSLY, which the
|
|
374
|
+
// local in-process host does (there is no socket, so there is nothing to
|
|
375
|
+
// batch for). In that case flush() completes during the schedule call and
|
|
376
|
+
// clears its state before the handle could be assigned, so guarding on the
|
|
377
|
+
// handle alone left it permanently set and no later batch was ever scheduled.
|
|
378
|
+
#scheduleFlush() {
|
|
379
|
+
if (this.#flushScheduled)
|
|
380
|
+
return;
|
|
381
|
+
this.#flushScheduled = true;
|
|
382
|
+
this.#schedule(() => this.flush(), this.#limits.batchWindowMs);
|
|
383
|
+
}
|
|
384
|
+
// Deliver every pending batch. Public so an adapter can force a flush before
|
|
385
|
+
// it lets its runtime go idle.
|
|
386
|
+
flush() {
|
|
387
|
+
this.#flushScheduled = false;
|
|
388
|
+
if (this.#outbox.size === 0)
|
|
389
|
+
return;
|
|
390
|
+
const outbox = [...this.#outbox];
|
|
391
|
+
this.#outbox.clear();
|
|
392
|
+
let requeued = false;
|
|
393
|
+
for (const [connectionID, updates] of outbox) {
|
|
394
|
+
const connection = this.#connections.get(connectionID);
|
|
395
|
+
if (!connection)
|
|
396
|
+
continue;
|
|
397
|
+
// Stop a batch before it exceeds the frame ceiling; the rest goes in the
|
|
398
|
+
// next frame rather than being dropped or sent as one oversized frame.
|
|
399
|
+
let bytes = 0;
|
|
400
|
+
let cut = updates.length;
|
|
401
|
+
for (let index = 0; index < updates.length; index++) {
|
|
402
|
+
bytes += updateBytes(updates[index]);
|
|
403
|
+
if (bytes > this.#limits.maxBatchBytes && index > 0) {
|
|
404
|
+
cut = index;
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
connection.send(['field', { updates: updates.slice(0, cut) }]);
|
|
409
|
+
if (cut < updates.length) {
|
|
410
|
+
this.#outbox.set(connectionID, updates.slice(cut));
|
|
411
|
+
requeued = true;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (requeued)
|
|
415
|
+
this.#scheduleFlush();
|
|
416
|
+
}
|
|
417
|
+
// ---- introspection for adapters and tests -------------------------------
|
|
418
|
+
get activeTopics() {
|
|
419
|
+
return this.#generations.size;
|
|
420
|
+
}
|
|
421
|
+
get subscribedTopics() {
|
|
422
|
+
return this.#subscribers.size;
|
|
423
|
+
}
|
|
424
|
+
generationFor(topicID) {
|
|
425
|
+
const generation = this.#generations.get(topicID);
|
|
426
|
+
return generation ? { streamID: generation.streamID, seq: generation.seq } : undefined;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
function describe(topic) {
|
|
430
|
+
return `${topic.table}.${topic.field}`;
|
|
431
|
+
}
|
|
432
|
+
function updateBytes(update) {
|
|
433
|
+
if (update.op === 'append')
|
|
434
|
+
return byteLength(update.text) + 96;
|
|
435
|
+
if (update.op === 'snapshot')
|
|
436
|
+
return byteLength(canonicalEncode(update.value)) + 96;
|
|
437
|
+
return 96;
|
|
438
|
+
}
|
|
439
|
+
function byteLength(value) {
|
|
440
|
+
let bytes = 0;
|
|
441
|
+
for (let index = 0; index < value.length; index++) {
|
|
442
|
+
const code = value.charCodeAt(index);
|
|
443
|
+
if (code < 0x80)
|
|
444
|
+
bytes += 1;
|
|
445
|
+
else if (code < 0x800)
|
|
446
|
+
bytes += 2;
|
|
447
|
+
else if (code >= 0xd800 && code < 0xdc00) {
|
|
448
|
+
bytes += 4;
|
|
449
|
+
index++;
|
|
450
|
+
}
|
|
451
|
+
else
|
|
452
|
+
bytes += 3;
|
|
453
|
+
}
|
|
454
|
+
return bytes;
|
|
455
|
+
}
|
|
456
|
+
//# sourceMappingURL=hub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hub.js","sourceRoot":"","sources":["../../src/realtime/hub.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,0EAA0E;AAC1E,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,kEAAkE;AAClE,EAAE;AACF,8EAA8E;AAC9E,gFAAgF;AAChF,8EAA8E;AAC9E,+EAA+E;AAC/E,kCAAkC;AAElC,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAuC5C,MAAM,CAAC,MAAM,kBAAkB,GAAc;IAC3C,sBAAsB,EAAE,GAAG;IAC3B,sBAAsB,EAAE,GAAG;IAC3B,qBAAqB,EAAE,IAAI;IAC3B,aAAa,EAAE,GAAG,GAAG,IAAI;IACzB,aAAa,EAAE,EAAE;CAClB,CAAA;AA6BD,MAAM,OAAO,WAAW;IACb,SAAS,CAAmB;IAC5B,UAAU,CAAkC;IAC5C,OAAO,CAAW;IAClB,SAAS,CAAyC;IAElD,YAAY,GAAG,IAAI,GAAG,EAAsB,CAAA;IAC5C,YAAY,GAAG,IAAI,GAAG,EAA8B,CAAA;IACpD,iBAAiB,GAAG,IAAI,GAAG,EAAuB,CAAA;IAClD,YAAY,GAAG,IAAI,GAAG,EAAyB,CAAA;IACxD,6EAA6E;IAC7E,2EAA2E;IAC3E,mEAAmE;IAC1D,oBAAoB,GAAG,IAAI,GAAG,EAAuB,CAAA;IAE9D,gEAAgE;IACvD,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAA;IACnD,eAAe,GAAG,KAAK,CAAA;IAEvB,4EAA4E;IAC5E,mEAAmE;IACnE,8EAA8E;IAC9E,mEAAmE;IAC1D,gBAAgB,GAAG,IAAI,GAAG,EAAyB,CAAA;IAE5D,0EAA0E;IAC1E,4EAA4E;IAC5E,wEAAwE;IACxE,6DAA6D;IACpD,gBAAgB,GAAG,IAAI,GAAG,EAAkB,CAAA;IAErD,YAAY,OAAmB;QAC7B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAA;QACjC,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,kBAAkB,CAAA;QAC5C,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,kBAAkB,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAA;QAC3D,IAAI,CAAC,SAAS;YACZ,OAAO,CAAC,aAAa;gBACrB,CAAC,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;oBACb,UAAU,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;gBACvB,CAAC,CAAC,CAAA;IACN,CAAC;IAED,4EAA4E;IAE5E,2EAA2E;IAC3E,0EAA0E;IAC1E,mCAAmC;IACnC,SAAS,CAAC,UAAyB,EAAE,KAAoB;QACvD,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,CAAA;QAC3D,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAA;IACtF,CAAC;IAED,WAAW,CAAC,UAAyB,EAAE,KAAoB;QACzD,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,EAAE,GAAG,EAAE;YACvC,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;YACpD,IAAI,QAAQ,IAAI,QAAQ;gBAAE,OAAM;YAChC,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAA;QACtD,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,QAAQ,CAAC,YAAoB,EAAE,IAAgC;QAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAA;QAC7E,6DAA6D;QAC7D,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QAChD,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;QAC7C,OAAO,IAAI,CAAA;IACb,CAAC;IAED,UAAU,CAAC,YAAoB,EAAE,KAAa;QAC5C,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,CAAA;IACjE,CAAC;IAED,KAAK,CAAC,UAAU,CACd,UAAyB,EACzB,KAAoB,EACpB,KAAa;QAEb,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC;YAAE,OAAM;QAClD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,UAAU,CAAC,CAAA;QAChD,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;QACpD,IAAI,QAAQ,IAAI,QAAQ,EAAE,CAAC;YACzB,UAAU,CAAC,IAAI,CAAC;gBACd,iBAAiB;gBACjB,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE;aACpD,CAAC,CAAA;YACF,OAAM;QACR,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,QAAQ,CAAA;QAE7B,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,IAAI,GAAG,EAAU,CAAA;QAC5E,0DAA0D;QAC1D,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACnB,IAAI,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE,CAAC;gBACtD,UAAU,CAAC,IAAI,CAAC;oBACd,iBAAiB;oBACjB,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,yCAAyC,EAAE;iBACjE,CAAC,CAAA;gBACF,OAAM;YACR,CAAC;YACD,IACE,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC1B,IAAI,CAAC,YAAY,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAC5D,CAAC;gBACD,UAAU,CAAC,IAAI,CAAC;oBACd,iBAAiB;oBACjB,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,wCAAwC,EAAE;iBAChE,CAAC,CAAA;gBACF,OAAM;YACR,CAAC;YACD,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YAC1C,IAAI,QAAQ,IAAI,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE,CAAC;gBACrE,UAAU,CAAC,IAAI,CAAC;oBACd,iBAAiB;oBACjB,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,kCAAkC,EAAE;iBAC1D,CAAC,CAAA;gBACF,OAAM;YACR,CAAC;QACH,CAAC;QAED,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;QAC7E,wDAAwD;QACxD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC;YAAE,OAAM;QAClD,IAAI,aAAa,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACtC,UAAU,CAAC,IAAI,CAAC,CAAC,iBAAiB,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;YACjF,OAAM;QACR,CAAC;QAED,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACb,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;QAChD,IAAI,aAAa,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACtC,IAAI,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YAC3C,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,WAAW,GAAG,IAAI,GAAG,EAAE,CAAA;gBACvB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,WAAW,CAAC,CAAA;YACxC,CAAC;YACD,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;QAC7B,CAAC;QAED,UAAU,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QAE5E,4EAA4E;QAC5E,mEAAmE;QACnE,wEAAwE;QACxE,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC5C,IAAI,aAAa,CAAC,MAAM,KAAK,QAAQ,IAAI,UAAU,EAAE,CAAC;YACpD,UAAU,CAAC,IAAI,CAAC;gBACd,OAAO;gBACP;oBACE,OAAO,EAAE;wBACP;4BACE,KAAK,EAAE,EAAE;4BACT,QAAQ,EAAE,UAAU,CAAC,QAAQ;4BAC7B,GAAG,EAAE,UAAU,CAAC,GAAG;4BACnB,EAAE,EAAE,UAAU;4BACd,KAAK,EAAE,UAAU,CAAC,KAAK;yBACxB;qBACF;iBACF;aACF,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,cAAc,CAAC,YAAoB;QACjC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CACvB,YAAY,EACZ,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CACnD,CAAA;QACD,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;QAC1C,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC;YACrE,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE;gBACrD,IAAI,UAAU,CAAC,EAAE,KAAK,YAAY;oBAChC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;YACtD,CAAC,CAAC,CAAA;YACF,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,KAAK,CAAC;gBAAE,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QACnF,CAAC;QACD,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;QAC3C,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;QACtC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;IACnC,CAAC;IAED,mBAAmB,CAAC,YAAoB,EAAE,OAAe;QACvD,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;QACzD,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QAClD,IAAI,CAAC,WAAW;YAAE,OAAM;QACxB,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;YACrC,IAAI,UAAU,CAAC,EAAE,KAAK,YAAY;gBAAE,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;QACpE,CAAC;QACD,IAAI,WAAW,CAAC,IAAI,KAAK,CAAC;YAAE,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC/D,CAAC;IAED,4EAA4E;IAC5E,8EAA8E;IAC9E,oEAAoE;IACpE,gBAAgB,CAAC,aAAqB,EAAE,OAAiC;QACvE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;YACpD,IAAI,QAAQ,IAAI,QAAQ;gBAAE,SAAQ;YAClC,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;YACtD,IAAI,CAAC,WAAW;gBAAE,SAAQ;YAC1B,KAAK,MAAM,UAAU,IAAI,CAAC,GAAG,WAAW,CAAC,EAAE,CAAC;gBAC1C,IAAI,UAAU,CAAC,QAAQ,CAAC,aAAa,KAAK,aAAa;oBAAE,SAAQ;gBACjE,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAA;gBACpD,UAAU,CAAC,IAAI,CAAC;oBACd,iBAAiB;oBACjB,EAAE,KAAK,EAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,2CAA2C,EAAE;iBAC5E,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,+DAA+D;IAC/D,iBAAiB,CAAC,aAAqB;QACrC,KAAK,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;YAC5D,KAAK,MAAM,UAAU,IAAI,CAAC,GAAG,WAAW,CAAC,EAAE,CAAC;gBAC1C,IAAI,UAAU,CAAC,QAAQ,CAAC,aAAa,KAAK,aAAa;oBAAE,SAAQ;gBACjE,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;gBAChD,UAAU,CAAC,IAAI,CAAC;oBACd,iBAAiB;oBACjB,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,2CAA2C,EAAE;iBACxE,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,4EAA4E;IAE5E,2EAA2E;IAC3E,0EAA0E;IAC1E,wEAAwE;IACxE,0CAA0C;IAC1C,eAAe,CACb,QAAqB,EACrB,KAAoB,EACpB,QAAgB;QAIhB,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;QACpD,IAAI,QAAQ,IAAI,QAAQ;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAA;QACvE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,QAAQ,CAAA;QAE7B,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC1C,IAAI,QAAQ,IAAI,QAAQ,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC/C,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;gBACtB,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;gBAC5C,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;YACpF,CAAC;QACH,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE;YACxB,OAAO,EAAE,EAAE;YACX,IAAI;YACJ,QAAQ;YACR,GAAG,EAAE,CAAC,CAAC;YACP,KAAK,EAAE,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;YACzC,QAAQ;SACT,CAAC,CAAA;QACF,MAAM,MAAM,GAAG,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;QACzD,IAAI,MAAM;YAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;;YACrB,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAC9D,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAA;IAClC,CAAC;IAED,wEAAwE;IACxE,4EAA4E;IAC5E,+EAA+E;IAC/E,0EAA0E;IAC1E,OAAO,CACL,QAAqB,EACrB,MAAmB;QAEnB,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACtD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,2BAA2B,MAAM,CAAC,KAAK,GAAG,EAAE,CAAA;QAC1E,CAAC;QACD,sEAAsE;QACtE,6EAA6E;QAC7E,6EAA6E;QAC7E,6EAA6E;QAC7E,0EAA0E;QAC1E,IAAI,UAAU,CAAC,QAAQ,EAAE,EAAE,KAAK,QAAQ,CAAC,EAAE,EAAE,CAAC;YAC5C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,2BAA2B,MAAM,CAAC,KAAK,GAAG,EAAE,CAAA;QAC1E,CAAC;QACD,IAAI,UAAU,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ,EAAE,CAAC;YAC5C,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,UAAU,MAAM,CAAC,QAAQ,uCAAuC,MAAM,CAAC,KAAK,GAAG;aACxF,CAAA;QACH,CAAC;QACD,IAAI,MAAM,CAAC,GAAG,IAAI,UAAU,CAAC,GAAG,EAAE,CAAC;YACjC,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,OAAO,MAAM,CAAC,GAAG,oCAAoC,UAAU,CAAC,GAAG,EAAE;aAC9E,CAAA;QACH,CAAC;QAED,QAAQ,MAAM,CAAC,EAAE,EAAE,CAAC;YAClB,KAAK,UAAU,CAAC,CAAC,CAAC;gBAChB,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;oBACnD,OAAO;wBACL,EAAE,EAAE,KAAK;wBACT,MAAM,EAAE,yCAAyC,MAAM,CAAC,KAAK,GAAG;qBACjE,CAAA;gBACH,CAAC;gBACD,UAAU,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAA;gBAC/B,MAAK;YACP,CAAC;YACD,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACtC,OAAO;wBACL,EAAE,EAAE,KAAK;wBACT,MAAM,EAAE,IAAI,MAAM,CAAC,KAAK,wCAAwC;qBACjE,CAAA;gBACH,CAAC;gBACD,MAAM,IAAI,GAAI,UAAU,CAAC,KAAgB,GAAG,MAAM,CAAC,IAAI,CAAA;gBACvD,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAChD,OAAO;wBACL,EAAE,EAAE,KAAK;wBACT,MAAM,EAAE,qCAAqC,MAAM,CAAC,KAAK,GAAG;qBAC7D,CAAA;gBACH,CAAC;gBACD,UAAU,CAAC,KAAK,GAAG,IAAI,CAAA;gBACvB,MAAK;YACP,CAAC;YACD,KAAK,KAAK,CAAC;YACX,KAAK,OAAO;gBACV,MAAK;QACT,CAAC;QACD,UAAU,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAA;QAC3B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QAEpB,IAAI,MAAM,CAAC,EAAE,KAAK,KAAK,IAAI,MAAM,CAAC,EAAE,KAAK,OAAO,EAAE,CAAC;YACjD,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACtC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;QAC/C,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;IACrB,CAAC;IAED,aAAa,CAAC,UAAkB,EAAE,OAAe;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;QACxD,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QACtB,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;YAAE,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;IACrE,CAAC;IAED,wEAAwE;IACxE,yEAAyE;IACzE,2EAA2E;IAC3E,iEAAiE;IACjE,YAAY,CAAC,UAAkB;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;QACxD,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;QAC5C,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,KAAK,MAAM,OAAO,IAAI,MAAM,EAAE,CAAC;YAC7B,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;YACjD,IAAI,UAAU,EAAE,QAAQ,EAAE,EAAE,KAAK,UAAU;gBAAE,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QAChF,CAAC;IACH,CAAC;IAED,SAAS,CAAC,IAAwB,EAAE,KAAc;QAChD,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAA;QACrE,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAA;QACxD,OAAO,UAAU,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAA;IAC5D,CAAC;IAED,OAAO,CAAC,MAAmB;QACzB,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACvD,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,IAAI,KAAK,CAAC;YAAE,OAAM;QAClD,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;YAC7C,IAAI,KAAK;gBAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;;gBACxB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;QAChD,CAAC;QACD,IAAI,CAAC,cAAc,EAAE,CAAA;IACvB,CAAC;IAED,2EAA2E;IAC3E,8EAA8E;IAC9E,yEAAyE;IACzE,0EAA0E;IAC1E,2EAA2E;IAC3E,8EAA8E;IAC9E,cAAc;QACZ,IAAI,IAAI,CAAC,eAAe;YAAE,OAAM;QAChC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAA;QAC3B,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAA;IAChE,CAAC;IAED,6EAA6E;IAC7E,+BAA+B;IAC/B,KAAK;QACH,IAAI,CAAC,eAAe,GAAG,KAAK,CAAA;QAC5B,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC;YAAE,OAAM;QACnC,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAA;QAChC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;QACpB,IAAI,QAAQ,GAAG,KAAK,CAAA;QACpB,KAAK,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,IAAI,MAAM,EAAE,CAAC;YAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;YACtD,IAAI,CAAC,UAAU;gBAAE,SAAQ;YACzB,yEAAyE;YACzE,uEAAuE;YACvE,IAAI,KAAK,GAAG,CAAC,CAAA;YACb,IAAI,GAAG,GAAG,OAAO,CAAC,MAAM,CAAA;YACxB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;gBACpD,KAAK,IAAI,WAAW,CAAC,OAAO,CAAC,KAAK,CAAE,CAAC,CAAA;gBACrC,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;oBACpD,GAAG,GAAG,KAAK,CAAA;oBACX,MAAK;gBACP,CAAC;YACH,CAAC;YACD,UAAU,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;YAC9D,IAAI,GAAG,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;gBACzB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA;gBAClD,QAAQ,GAAG,IAAI,CAAA;YACjB,CAAC;QACH,CAAC;QACD,IAAI,QAAQ;YAAE,IAAI,CAAC,cAAc,EAAE,CAAA;IACrC,CAAC;IAED,4EAA4E;IAE5E,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAA;IAC/B,CAAC;IAED,IAAI,gBAAgB;QAClB,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAA;IAC/B,CAAC;IAED,aAAa,CACX,OAAe;QAEf,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QACjD,OAAO,UAAU,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;IACxF,CAAC;CACF;AAED,SAAS,QAAQ,CAAC,KAAoB;IACpC,OAAO,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE,CAAA;AACxC,CAAC;AAED,SAAS,WAAW,CAAC,MAAmB;IACtC,IAAI,MAAM,CAAC,EAAE,KAAK,QAAQ;QAAE,OAAO,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAA;IAC/D,IAAI,MAAM,CAAC,EAAE,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAA;IACnF,OAAO,EAAE,CAAA;AACX,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QAClD,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;QACpC,IAAI,IAAI,GAAG,IAAI;YAAE,KAAK,IAAI,CAAC,CAAA;aACtB,IAAI,IAAI,GAAG,KAAK;YAAE,KAAK,IAAI,CAAC,CAAA;aAC5B,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,GAAG,MAAM,EAAE,CAAC;YACzC,KAAK,IAAI,CAAC,CAAA;YACV,KAAK,EAAE,CAAA;QACT,CAAC;;YAAM,KAAK,IAAI,CAAC,CAAA;IACnB,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
|