@api.global/typedsocket 5.1.2 → 6.1.0
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_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.clienttagreconciler.d.ts +51 -0
- package/dist_ts/classes.clienttagreconciler.js +290 -0
- package/dist_ts/classes.nativebyteerror.d.ts +13 -0
- package/dist_ts/classes.nativebyteerror.js +26 -0
- package/dist_ts/classes.nativebytemanager.d.ts +327 -0
- package/dist_ts/classes.nativebytemanager.js +2343 -0
- package/dist_ts/{typedsocket.classes.typedsocket.d.ts → classes.typedsocket.d.ts} +122 -13
- package/dist_ts/classes.typedsocket.js +1733 -0
- package/dist_ts/classes.typedsockettagpolicymanager.d.ts +112 -0
- package/dist_ts/classes.typedsockettagpolicymanager.js +549 -0
- package/dist_ts/constants.nativebytes.d.ts +59 -0
- package/dist_ts/constants.nativebytes.js +58 -0
- package/dist_ts/helpers.nativebytecodec.d.ts +8 -0
- package/dist_ts/helpers.nativebytecodec.js +328 -0
- package/dist_ts/helpers.websocket.d.ts +8 -0
- package/dist_ts/helpers.websocket.js +13 -0
- package/dist_ts/index.d.ts +9 -1
- package/dist_ts/index.js +6 -2
- package/dist_ts/interfaces.diagnostics.d.ts +73 -0
- package/dist_ts/interfaces.diagnostics.js +2 -0
- package/dist_ts/interfaces.nativebytes.d.ts +187 -0
- package/dist_ts/interfaces.nativebytes.js +2 -0
- package/{ts/typedsocket.plugins.ts → dist_ts/plugins.d.ts} +3 -9
- package/dist_ts/plugins.js +14 -0
- package/{license → license.md} +2 -2
- package/package.json +22 -18
- package/readme.hints.md +60 -19
- package/readme.md +536 -56
- package/dist_ts/typedsocket.classes.typedsocket.js +0 -941
- package/dist_ts/typedsocket.plugins.d.ts +0 -11
- package/dist_ts/typedsocket.plugins.js +0 -13
- package/npmextra.json +0 -35
- package/ts/00_commitinfo_data.ts +0 -8
- package/ts/index.ts +0 -1
- package/ts/typedsocket.classes.typedsocket.ts +0 -1156
|
@@ -0,0 +1,549 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
export const TYPEDSOCKET_MAX_TAG_NAME_BYTES = 128;
|
|
3
|
+
export const TYPEDSOCKET_MAX_TAG_PAYLOAD_BYTES = 4 * 1024;
|
|
4
|
+
export const TYPEDSOCKET_MAX_CLIENT_TAGS_PER_PEER = 16;
|
|
5
|
+
export const TYPEDSOCKET_MAX_CLIENT_TAG_RETAINED_BYTES_PER_PEER = 16 * 1024;
|
|
6
|
+
export const TYPEDSOCKET_MAX_RETAINED_TAG_MUTATIONS_PER_PEER = 8;
|
|
7
|
+
export const TYPEDSOCKET_MAX_RETAINED_TAG_MUTATIONS_PER_RULE = 32;
|
|
8
|
+
export const TYPEDSOCKET_MAX_RETAINED_TAG_MUTATIONS_PER_SERVER = 256;
|
|
9
|
+
export const TYPEDSOCKET_MAX_TAG_AUTHORIZATION_TIMEOUT_MS = 5_000;
|
|
10
|
+
export const TYPEDSOCKET_MAX_SERVER_TAG_NAMES_PER_PEER = 64;
|
|
11
|
+
export const TYPEDSOCKET_MAX_SERVER_TAG_RETAINED_BYTES_PER_PEER = 64 * 1024;
|
|
12
|
+
const TAG_PREFIX = '__typedsocket_tag__';
|
|
13
|
+
const textEncoder = new TextEncoder();
|
|
14
|
+
/**
|
|
15
|
+
* The exhaustive runtime set of denial codes. Clients validate remote denial
|
|
16
|
+
* responses against this set so no server-controlled string can reach typed
|
|
17
|
+
* consumers or the diagnostics channel.
|
|
18
|
+
*/
|
|
19
|
+
export const TYPEDSOCKET_TAG_DENIAL_CODES = Object.freeze([
|
|
20
|
+
'CLIENT_TAGS_DISABLED',
|
|
21
|
+
'INVALID_TAG_NAME',
|
|
22
|
+
'TAG_NAME_TOO_LARGE',
|
|
23
|
+
'TAG_NOT_ALLOWED',
|
|
24
|
+
'INVALID_TAG_PAYLOAD',
|
|
25
|
+
'TAG_PAYLOAD_TOO_LARGE',
|
|
26
|
+
'TAG_AUTHORIZATION_DENIED',
|
|
27
|
+
'TAG_AUTHORIZATION_TIMEOUT',
|
|
28
|
+
'TAG_MUTATION_CAPACITY_EXCEEDED',
|
|
29
|
+
'TAG_COUNT_LIMIT_EXCEEDED',
|
|
30
|
+
'TAG_RETAINED_BYTES_EXCEEDED',
|
|
31
|
+
'TAG_SERVER_OWNED',
|
|
32
|
+
'TAG_CONNECTION_CLOSED',
|
|
33
|
+
'MALFORMED_TAG_RESPONSE',
|
|
34
|
+
]);
|
|
35
|
+
export class TypedSocketClientTagDeniedError extends Error {
|
|
36
|
+
constructor(codeArg, messageArg) {
|
|
37
|
+
super(messageArg);
|
|
38
|
+
this.name = 'TypedSocketClientTagDeniedError';
|
|
39
|
+
this.code = codeArg;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function deny(codeArg, messageArg) {
|
|
43
|
+
return {
|
|
44
|
+
success: false,
|
|
45
|
+
code: codeArg,
|
|
46
|
+
message: messageArg,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export function assertBoundedTextIdentifier(valueArg, labelArg, maximumBytesArg) {
|
|
50
|
+
if (typeof valueArg !== 'string'
|
|
51
|
+
|| valueArg.length === 0
|
|
52
|
+
|| textEncoder.encode(valueArg).byteLength > maximumBytesArg) {
|
|
53
|
+
throw new Error(`TypedSocket ${labelArg} must be a non-empty string of at most ${maximumBytesArg} UTF-8 bytes.`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function validateTagName(nameArg) {
|
|
57
|
+
if (typeof nameArg !== 'string' || nameArg.length === 0) {
|
|
58
|
+
return deny('INVALID_TAG_NAME', 'TypedSocket tag names must be non-empty strings.');
|
|
59
|
+
}
|
|
60
|
+
if (textEncoder.encode(nameArg).byteLength > TYPEDSOCKET_MAX_TAG_NAME_BYTES) {
|
|
61
|
+
return deny('TAG_NAME_TOO_LARGE', `TypedSocket tag names must not exceed ${TYPEDSOCKET_MAX_TAG_NAME_BYTES} UTF-8 bytes.`);
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
export function createTypedSocketTagPayloadSnapshot(payloadArg) {
|
|
66
|
+
let encoded;
|
|
67
|
+
let payload;
|
|
68
|
+
try {
|
|
69
|
+
encoded = plugins.smartjson.stringify({ value: payloadArg });
|
|
70
|
+
const parsed = plugins.smartjson.parse(encoded);
|
|
71
|
+
payload = typeof parsed === 'object' && parsed !== null
|
|
72
|
+
? Reflect.get(parsed, 'value')
|
|
73
|
+
: undefined;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
throw new TypedSocketClientTagDeniedError('INVALID_TAG_PAYLOAD', 'TypedSocket tag payloads must be SmartJSON-serializable.');
|
|
77
|
+
}
|
|
78
|
+
const byteLength = textEncoder.encode(encoded).byteLength;
|
|
79
|
+
if (byteLength > TYPEDSOCKET_MAX_TAG_PAYLOAD_BYTES) {
|
|
80
|
+
throw new TypedSocketClientTagDeniedError('TAG_PAYLOAD_TOO_LARGE', `TypedSocket tag payloads must not exceed ${TYPEDSOCKET_MAX_TAG_PAYLOAD_BYTES} serialized bytes.`);
|
|
81
|
+
}
|
|
82
|
+
return { payload, encoded, byteLength };
|
|
83
|
+
}
|
|
84
|
+
function cloneTagPayload(payloadArg) {
|
|
85
|
+
return createTypedSocketTagPayloadSnapshot(payloadArg).payload;
|
|
86
|
+
}
|
|
87
|
+
export class TypedSocketTagPolicyManager {
|
|
88
|
+
constructor(policyArg) {
|
|
89
|
+
this.rules = new Map();
|
|
90
|
+
this.peerStates = new WeakMap();
|
|
91
|
+
this.ruleStates = new Map();
|
|
92
|
+
this.connectionAuthorityIds = new WeakMap();
|
|
93
|
+
this.routingSurfaceAuthorityIds = new WeakMap();
|
|
94
|
+
this.closedPeers = new WeakSet();
|
|
95
|
+
this.retainedMutationWork = 0;
|
|
96
|
+
this.stopping = false;
|
|
97
|
+
const timeoutMs = policyArg?.authorizationTimeoutMs
|
|
98
|
+
?? TYPEDSOCKET_MAX_TAG_AUTHORIZATION_TIMEOUT_MS;
|
|
99
|
+
if (!Number.isSafeInteger(timeoutMs)
|
|
100
|
+
|| timeoutMs < 1
|
|
101
|
+
|| timeoutMs > TYPEDSOCKET_MAX_TAG_AUTHORIZATION_TIMEOUT_MS) {
|
|
102
|
+
throw new Error(`clientTagPolicy.authorizationTimeoutMs must be an integer from 1 to ${TYPEDSOCKET_MAX_TAG_AUTHORIZATION_TIMEOUT_MS}.`);
|
|
103
|
+
}
|
|
104
|
+
this.authorizationTimeoutMs = timeoutMs;
|
|
105
|
+
for (const rule of policyArg?.rules ?? []) {
|
|
106
|
+
const nameDenial = validateTagName(rule?.name);
|
|
107
|
+
if (nameDenial)
|
|
108
|
+
throw new Error(nameDenial.message);
|
|
109
|
+
if (rule.owner !== 'client' && rule.owner !== 'server') {
|
|
110
|
+
throw new Error(`TypedSocket client tag rule "${rule.name}" has an invalid owner.`);
|
|
111
|
+
}
|
|
112
|
+
if (typeof rule.validateAndAuthorize !== 'function') {
|
|
113
|
+
throw new Error(`TypedSocket client tag rule "${rule.name}" requires validateAndAuthorize().`);
|
|
114
|
+
}
|
|
115
|
+
if (this.rules.has(rule.name)) {
|
|
116
|
+
throw new Error(`TypedSocket client tag rule "${rule.name}" is duplicated.`);
|
|
117
|
+
}
|
|
118
|
+
this.rules.set(rule.name, Object.freeze({ ...rule }));
|
|
119
|
+
this.ruleStates.set(rule.name, { retainedWork: 0, orphanedAuthorizations: 0 });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async setClientTag(peerArg, nameArg, payloadArg) {
|
|
123
|
+
const common = this.validateClientMutation(peerArg, nameArg);
|
|
124
|
+
if ('success' in common)
|
|
125
|
+
return common;
|
|
126
|
+
let payloadSnapshot;
|
|
127
|
+
try {
|
|
128
|
+
payloadSnapshot = createTypedSocketTagPayloadSnapshot(payloadArg);
|
|
129
|
+
}
|
|
130
|
+
catch (errorArg) {
|
|
131
|
+
return errorArg instanceof TypedSocketClientTagDeniedError
|
|
132
|
+
? deny(errorArg.code, errorArg.message)
|
|
133
|
+
: deny('INVALID_TAG_PAYLOAD', 'TypedSocket tag payload validation failed.');
|
|
134
|
+
}
|
|
135
|
+
return this.enqueueMutation(common.peer, common.rule, common.name, async (stateArg, executionArg) => {
|
|
136
|
+
return this.executeSet(common.peer, stateArg, common.rule, common.name, payloadSnapshot, executionArg);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
async removeClientTag(peerArg, nameArg) {
|
|
140
|
+
const common = this.validateClientMutation(peerArg, nameArg);
|
|
141
|
+
if ('success' in common)
|
|
142
|
+
return common;
|
|
143
|
+
return this.enqueueMutation(common.peer, common.rule, common.name, async (stateArg, executionArg) => {
|
|
144
|
+
return this.executeRemove(common.peer, stateArg, common.rule, common.name, executionArg);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
setServerTag(peerArg, nameArg, payloadArg) {
|
|
148
|
+
this.assertServerMutationName(nameArg);
|
|
149
|
+
if (!this.isPeerLive(peerArg)) {
|
|
150
|
+
throw new Error('Cannot set a TypedSocket server tag on a detached or closed connection.');
|
|
151
|
+
}
|
|
152
|
+
const payloadSnapshot = createTypedSocketTagPayloadSnapshot(payloadArg);
|
|
153
|
+
const state = this.getPeerState(peerArg);
|
|
154
|
+
this.retainServerTag(state, nameArg, payloadSnapshot.byteLength);
|
|
155
|
+
this.releaseAdmission(state, nameArg);
|
|
156
|
+
state.protectedServerNames.add(nameArg);
|
|
157
|
+
peerArg.tags.add(nameArg);
|
|
158
|
+
peerArg.data.set(`${TAG_PREFIX}${nameArg}`, payloadSnapshot.payload);
|
|
159
|
+
}
|
|
160
|
+
removeServerTag(peerArg, nameArg) {
|
|
161
|
+
this.assertServerMutationName(nameArg);
|
|
162
|
+
if (!this.isPeerLive(peerArg)) {
|
|
163
|
+
throw new Error('Cannot remove a TypedSocket server tag from a detached or closed connection.');
|
|
164
|
+
}
|
|
165
|
+
const state = this.getPeerState(peerArg);
|
|
166
|
+
this.retainServerTag(state, nameArg, 0);
|
|
167
|
+
this.releaseAdmission(state, nameArg);
|
|
168
|
+
state.protectedServerNames.add(nameArg);
|
|
169
|
+
peerArg.tags.delete(nameArg);
|
|
170
|
+
peerArg.data.delete(`${TAG_PREFIX}${nameArg}`);
|
|
171
|
+
}
|
|
172
|
+
handlePeerClose(peerArg) {
|
|
173
|
+
this.closedPeers.add(peerArg);
|
|
174
|
+
const state = this.peerStates.get(peerArg);
|
|
175
|
+
if (!state)
|
|
176
|
+
return;
|
|
177
|
+
for (const controller of state.authorizationControllers) {
|
|
178
|
+
controller.abort(new Error('TypedSocket connection closed.'));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
setAttachedPeersProvider(providerArg) {
|
|
182
|
+
this.attachedPeersProvider = providerArg;
|
|
183
|
+
}
|
|
184
|
+
stop(peersArg) {
|
|
185
|
+
this.stopping = true;
|
|
186
|
+
for (const peer of peersArg)
|
|
187
|
+
this.handlePeerClose(peer);
|
|
188
|
+
this.attachedPeersProvider = undefined;
|
|
189
|
+
}
|
|
190
|
+
getRetainedMutationWork() {
|
|
191
|
+
return this.retainedMutationWork;
|
|
192
|
+
}
|
|
193
|
+
getRetainedMutationWorkForRule(nameArg) {
|
|
194
|
+
return this.ruleStates.get(nameArg)?.retainedWork ?? 0;
|
|
195
|
+
}
|
|
196
|
+
validateClientMutation(peerArg, nameArg) {
|
|
197
|
+
const nameDenial = validateTagName(nameArg);
|
|
198
|
+
if (nameDenial)
|
|
199
|
+
return nameDenial;
|
|
200
|
+
if (!peerArg) {
|
|
201
|
+
return deny('TAG_CONNECTION_CLOSED', 'TypedSocket tag mutation has no live connection.');
|
|
202
|
+
}
|
|
203
|
+
if (!this.isPeerLive(peerArg)) {
|
|
204
|
+
return deny('TAG_CONNECTION_CLOSED', 'TypedSocket tag mutation connection is not attached and live.');
|
|
205
|
+
}
|
|
206
|
+
if (this.rules.size === 0) {
|
|
207
|
+
return deny('CLIENT_TAGS_DISABLED', 'TypedSocket client tag mutation is disabled.');
|
|
208
|
+
}
|
|
209
|
+
if (typeof nameArg !== 'string') {
|
|
210
|
+
return deny('INVALID_TAG_NAME', 'TypedSocket tag names must be non-empty strings.');
|
|
211
|
+
}
|
|
212
|
+
const rule = this.rules.get(nameArg);
|
|
213
|
+
if (!rule) {
|
|
214
|
+
return deny('TAG_NOT_ALLOWED', 'TypedSocket client tag name is not allowed.');
|
|
215
|
+
}
|
|
216
|
+
return { peer: peerArg, name: nameArg, rule };
|
|
217
|
+
}
|
|
218
|
+
async enqueueMutation(peerArg, ruleArg, nameArg, operationArg) {
|
|
219
|
+
const state = this.getPeerState(peerArg);
|
|
220
|
+
const ruleState = this.ruleStates.get(ruleArg.name);
|
|
221
|
+
if (!ruleState) {
|
|
222
|
+
return deny('TAG_NOT_ALLOWED', 'TypedSocket client tag rule state is unavailable.');
|
|
223
|
+
}
|
|
224
|
+
if (state.activeMutationOperations + state.orphanedAuthorizations
|
|
225
|
+
>= TYPEDSOCKET_MAX_RETAINED_TAG_MUTATIONS_PER_PEER
|
|
226
|
+
|| ruleState.retainedWork >= TYPEDSOCKET_MAX_RETAINED_TAG_MUTATIONS_PER_RULE
|
|
227
|
+
|| this.retainedMutationWork >= TYPEDSOCKET_MAX_RETAINED_TAG_MUTATIONS_PER_SERVER) {
|
|
228
|
+
return deny('TAG_MUTATION_CAPACITY_EXCEEDED', 'TypedSocket client tag mutation capacity is exhausted.');
|
|
229
|
+
}
|
|
230
|
+
state.activeMutationOperations++;
|
|
231
|
+
ruleState.retainedWork++;
|
|
232
|
+
this.retainedMutationWork++;
|
|
233
|
+
const previousTail = state.mutationTails.get(nameArg) ?? Promise.resolve();
|
|
234
|
+
const execution = {};
|
|
235
|
+
const operation = previousTail.then(() => operationArg(state, execution));
|
|
236
|
+
const tail = operation.then(() => undefined, () => undefined);
|
|
237
|
+
state.mutationTails.set(nameArg, tail);
|
|
238
|
+
try {
|
|
239
|
+
return await operation;
|
|
240
|
+
}
|
|
241
|
+
finally {
|
|
242
|
+
state.activeMutationOperations--;
|
|
243
|
+
if (execution.orphanOutcome) {
|
|
244
|
+
state.orphanedAuthorizations++;
|
|
245
|
+
ruleState.orphanedAuthorizations++;
|
|
246
|
+
void execution.orphanOutcome.then(() => {
|
|
247
|
+
state.orphanedAuthorizations--;
|
|
248
|
+
ruleState.orphanedAuthorizations--;
|
|
249
|
+
ruleState.retainedWork--;
|
|
250
|
+
this.retainedMutationWork--;
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
ruleState.retainedWork--;
|
|
255
|
+
this.retainedMutationWork--;
|
|
256
|
+
}
|
|
257
|
+
if (state.mutationTails.get(nameArg) === tail) {
|
|
258
|
+
state.mutationTails.delete(nameArg);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
async executeSet(peerArg, stateArg, ruleArg, nameArg, payloadSnapshotArg, executionArg) {
|
|
263
|
+
if (!this.isPeerLive(peerArg)) {
|
|
264
|
+
return deny('TAG_CONNECTION_CLOSED', 'TypedSocket tag connection is closed.');
|
|
265
|
+
}
|
|
266
|
+
const existing = this.reconcileName(peerArg, stateArg, nameArg);
|
|
267
|
+
if (stateArg.protectedServerNames.has(nameArg) || existing?.owner === 'server') {
|
|
268
|
+
return deny('TAG_SERVER_OWNED', 'TypedSocket server-owned tags cannot be overwritten.');
|
|
269
|
+
}
|
|
270
|
+
if (existing && ruleArg.owner !== 'client') {
|
|
271
|
+
return deny('TAG_SERVER_OWNED', 'TypedSocket server-owned tag proposals are one-time.');
|
|
272
|
+
}
|
|
273
|
+
const fingerprint = this.createFingerprint(existing);
|
|
274
|
+
const routingSurface = peerArg.routingSurface;
|
|
275
|
+
const authorization = await this.authorize(peerArg, stateArg, ruleArg, {
|
|
276
|
+
operation: 'set',
|
|
277
|
+
name: nameArg,
|
|
278
|
+
payload: payloadSnapshotArg.payload,
|
|
279
|
+
existing,
|
|
280
|
+
}, executionArg);
|
|
281
|
+
if (!authorization.allowed)
|
|
282
|
+
return authorization.denial;
|
|
283
|
+
if (!this.isPeerLive(peerArg)) {
|
|
284
|
+
return deny('TAG_CONNECTION_CLOSED', 'TypedSocket tag connection closed during authorization.');
|
|
285
|
+
}
|
|
286
|
+
const current = this.reconcileName(peerArg, stateArg, nameArg);
|
|
287
|
+
if (!routingSurface
|
|
288
|
+
|| peerArg.routingSurface !== routingSurface
|
|
289
|
+
|| stateArg.protectedServerNames.has(nameArg)
|
|
290
|
+
|| this.createFingerprint(current) !== fingerprint) {
|
|
291
|
+
return deny('TAG_SERVER_OWNED', 'TypedSocket tag ownership changed during authorization.');
|
|
292
|
+
}
|
|
293
|
+
const retainedBytes = textEncoder.encode(nameArg).byteLength + payloadSnapshotArg.byteLength;
|
|
294
|
+
const nextCount = stateArg.admissions.size + (current ? 0 : 1);
|
|
295
|
+
const nextBytes = stateArg.admittedBytes - (current?.retainedBytes ?? 0) + retainedBytes;
|
|
296
|
+
if (nextCount > TYPEDSOCKET_MAX_CLIENT_TAGS_PER_PEER) {
|
|
297
|
+
return deny('TAG_COUNT_LIMIT_EXCEEDED', `TypedSocket clients may retain at most ${TYPEDSOCKET_MAX_CLIENT_TAGS_PER_PEER} tags per connection.`);
|
|
298
|
+
}
|
|
299
|
+
if (nextBytes > TYPEDSOCKET_MAX_CLIENT_TAG_RETAINED_BYTES_PER_PEER) {
|
|
300
|
+
return deny('TAG_RETAINED_BYTES_EXCEEDED', `TypedSocket client tags may retain at most ${TYPEDSOCKET_MAX_CLIENT_TAG_RETAINED_BYTES_PER_PEER} bytes per connection.`);
|
|
301
|
+
}
|
|
302
|
+
if (current)
|
|
303
|
+
this.releaseAdmission(stateArg, nameArg);
|
|
304
|
+
const admission = {
|
|
305
|
+
...payloadSnapshotArg,
|
|
306
|
+
owner: ruleArg.owner,
|
|
307
|
+
retainedBytes,
|
|
308
|
+
};
|
|
309
|
+
stateArg.admissions.set(nameArg, admission);
|
|
310
|
+
stateArg.admittedBytes += retainedBytes;
|
|
311
|
+
if (ruleArg.owner === 'server')
|
|
312
|
+
stateArg.protectedServerNames.add(nameArg);
|
|
313
|
+
peerArg.tags.add(nameArg);
|
|
314
|
+
peerArg.data.set(`${TAG_PREFIX}${nameArg}`, payloadSnapshotArg.payload);
|
|
315
|
+
return this.createSuccess(peerArg, stateArg, nameArg);
|
|
316
|
+
}
|
|
317
|
+
async executeRemove(peerArg, stateArg, ruleArg, nameArg, executionArg) {
|
|
318
|
+
if (!this.isPeerLive(peerArg)) {
|
|
319
|
+
return deny('TAG_CONNECTION_CLOSED', 'TypedSocket tag connection is closed.');
|
|
320
|
+
}
|
|
321
|
+
const existing = this.reconcileName(peerArg, stateArg, nameArg);
|
|
322
|
+
if (stateArg.protectedServerNames.has(nameArg) || existing?.owner === 'server') {
|
|
323
|
+
return deny('TAG_SERVER_OWNED', 'TypedSocket server-owned tags cannot be removed.');
|
|
324
|
+
}
|
|
325
|
+
if (!existing)
|
|
326
|
+
return this.createSuccess(peerArg, stateArg, nameArg, false);
|
|
327
|
+
if (ruleArg.owner !== 'client') {
|
|
328
|
+
return deny('TAG_SERVER_OWNED', 'TypedSocket server-owned tags cannot be removed.');
|
|
329
|
+
}
|
|
330
|
+
const fingerprint = this.createFingerprint(existing);
|
|
331
|
+
const routingSurface = peerArg.routingSurface;
|
|
332
|
+
const authorization = await this.authorize(peerArg, stateArg, ruleArg, {
|
|
333
|
+
operation: 'remove',
|
|
334
|
+
name: nameArg,
|
|
335
|
+
payload: existing.payload,
|
|
336
|
+
existing,
|
|
337
|
+
}, executionArg);
|
|
338
|
+
if (!authorization.allowed)
|
|
339
|
+
return authorization.denial;
|
|
340
|
+
if (!this.isPeerLive(peerArg)) {
|
|
341
|
+
return deny('TAG_CONNECTION_CLOSED', 'TypedSocket tag connection closed during authorization.');
|
|
342
|
+
}
|
|
343
|
+
const current = this.reconcileName(peerArg, stateArg, nameArg);
|
|
344
|
+
if (!routingSurface
|
|
345
|
+
|| peerArg.routingSurface !== routingSurface
|
|
346
|
+
|| stateArg.protectedServerNames.has(nameArg)
|
|
347
|
+
|| this.createFingerprint(current) !== fingerprint) {
|
|
348
|
+
return deny('TAG_SERVER_OWNED', 'TypedSocket tag ownership changed during authorization.');
|
|
349
|
+
}
|
|
350
|
+
this.releaseAdmission(stateArg, nameArg);
|
|
351
|
+
peerArg.tags.delete(nameArg);
|
|
352
|
+
peerArg.data.delete(`${TAG_PREFIX}${nameArg}`);
|
|
353
|
+
return this.createSuccess(peerArg, stateArg, nameArg, false);
|
|
354
|
+
}
|
|
355
|
+
async authorize(peerArg, stateArg, ruleArg, contextArg, executionArg) {
|
|
356
|
+
const routingSurface = peerArg.routingSurface;
|
|
357
|
+
if (!routingSurface) {
|
|
358
|
+
return {
|
|
359
|
+
allowed: false,
|
|
360
|
+
denial: deny('TAG_CONNECTION_CLOSED', 'TypedSocket tag authorization requires an exact routing surface.'),
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
const controller = new AbortController();
|
|
364
|
+
stateArg.authorizationControllers.add(controller);
|
|
365
|
+
const authority = Object.freeze({
|
|
366
|
+
connectionId: this.getConnectionAuthorityId(peerArg),
|
|
367
|
+
routingSurfaceId: this.getRoutingSurfaceAuthorityId(routingSurface),
|
|
368
|
+
});
|
|
369
|
+
const existing = contextArg.existing
|
|
370
|
+
? Object.freeze({
|
|
371
|
+
owner: 'client',
|
|
372
|
+
payload: cloneTagPayload(contextArg.existing.payload),
|
|
373
|
+
})
|
|
374
|
+
: undefined;
|
|
375
|
+
const validationContext = Object.freeze({
|
|
376
|
+
operation: contextArg.operation,
|
|
377
|
+
name: contextArg.name,
|
|
378
|
+
payload: cloneTagPayload(contextArg.payload),
|
|
379
|
+
existing,
|
|
380
|
+
authority,
|
|
381
|
+
abortSignal: controller.signal,
|
|
382
|
+
});
|
|
383
|
+
let callbackSettled = false;
|
|
384
|
+
const outcome = Promise.resolve()
|
|
385
|
+
.then(() => ruleArg.validateAndAuthorize(validationContext))
|
|
386
|
+
.then((allowedArg) => {
|
|
387
|
+
callbackSettled = true;
|
|
388
|
+
return allowedArg === true;
|
|
389
|
+
}, () => {
|
|
390
|
+
callbackSettled = true;
|
|
391
|
+
return false;
|
|
392
|
+
});
|
|
393
|
+
let timeout;
|
|
394
|
+
let abortListener;
|
|
395
|
+
const timeoutResult = new Promise((resolveArg) => {
|
|
396
|
+
timeout = setTimeout(() => {
|
|
397
|
+
resolveArg('timeout');
|
|
398
|
+
controller.abort(new Error('TypedSocket tag authorization timed out.'));
|
|
399
|
+
}, this.authorizationTimeoutMs);
|
|
400
|
+
});
|
|
401
|
+
const abortResult = new Promise((resolveArg) => {
|
|
402
|
+
abortListener = () => resolveArg('aborted');
|
|
403
|
+
controller.signal.addEventListener('abort', abortListener, { once: true });
|
|
404
|
+
});
|
|
405
|
+
try {
|
|
406
|
+
const result = await Promise.race([
|
|
407
|
+
outcome.then((allowedArg) => allowedArg ? 'allowed' : 'denied'),
|
|
408
|
+
timeoutResult,
|
|
409
|
+
abortResult,
|
|
410
|
+
]);
|
|
411
|
+
if (result === 'allowed')
|
|
412
|
+
return { allowed: true };
|
|
413
|
+
if (!callbackSettled)
|
|
414
|
+
executionArg.orphanOutcome = outcome;
|
|
415
|
+
if (result === 'timeout') {
|
|
416
|
+
return {
|
|
417
|
+
allowed: false,
|
|
418
|
+
denial: deny('TAG_AUTHORIZATION_TIMEOUT', 'TypedSocket tag authorization timed out.'),
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
if (result === 'aborted') {
|
|
422
|
+
return {
|
|
423
|
+
allowed: false,
|
|
424
|
+
denial: deny('TAG_CONNECTION_CLOSED', 'TypedSocket tag authorization was cancelled.'),
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
return {
|
|
428
|
+
allowed: false,
|
|
429
|
+
denial: deny('TAG_AUTHORIZATION_DENIED', 'TypedSocket tag authorization was denied.'),
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
finally {
|
|
433
|
+
if (timeout)
|
|
434
|
+
clearTimeout(timeout);
|
|
435
|
+
if (abortListener)
|
|
436
|
+
controller.signal.removeEventListener('abort', abortListener);
|
|
437
|
+
stateArg.authorizationControllers.delete(controller);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
reconcileName(peerArg, stateArg, nameArg) {
|
|
441
|
+
const tracked = stateArg.admissions.get(nameArg);
|
|
442
|
+
const dataKey = `${TAG_PREFIX}${nameArg}`;
|
|
443
|
+
const hasTag = peerArg.tags.has(nameArg);
|
|
444
|
+
const hasPayload = peerArg.data.has(dataKey);
|
|
445
|
+
if (tracked) {
|
|
446
|
+
let matches = hasTag && hasPayload;
|
|
447
|
+
if (matches) {
|
|
448
|
+
try {
|
|
449
|
+
matches = createTypedSocketTagPayloadSnapshot(peerArg.data.get(dataKey)).encoded
|
|
450
|
+
=== tracked.encoded;
|
|
451
|
+
}
|
|
452
|
+
catch {
|
|
453
|
+
matches = false;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (matches)
|
|
457
|
+
return tracked;
|
|
458
|
+
this.releaseAdmission(stateArg, nameArg);
|
|
459
|
+
stateArg.protectedServerNames.add(nameArg);
|
|
460
|
+
return undefined;
|
|
461
|
+
}
|
|
462
|
+
if (hasTag || hasPayload)
|
|
463
|
+
stateArg.protectedServerNames.add(nameArg);
|
|
464
|
+
return undefined;
|
|
465
|
+
}
|
|
466
|
+
releaseAdmission(stateArg, nameArg) {
|
|
467
|
+
const existing = stateArg.admissions.get(nameArg);
|
|
468
|
+
if (!existing)
|
|
469
|
+
return;
|
|
470
|
+
stateArg.admissions.delete(nameArg);
|
|
471
|
+
stateArg.admittedBytes -= existing.retainedBytes;
|
|
472
|
+
}
|
|
473
|
+
createFingerprint(admissionArg) {
|
|
474
|
+
return admissionArg ? `${admissionArg.owner}:${admissionArg.encoded}` : 'absent';
|
|
475
|
+
}
|
|
476
|
+
createSuccess(peerArg, stateArg, nameArg, retainRevisionArg = true) {
|
|
477
|
+
const tagRevision = (stateArg.successfulRevisionByName.get(nameArg) ?? 0) + 1;
|
|
478
|
+
if (retainRevisionArg)
|
|
479
|
+
stateArg.successfulRevisionByName.set(nameArg, tagRevision);
|
|
480
|
+
else
|
|
481
|
+
stateArg.successfulRevisionByName.delete(nameArg);
|
|
482
|
+
return {
|
|
483
|
+
success: true,
|
|
484
|
+
connectionId: this.getConnectionAuthorityId(peerArg),
|
|
485
|
+
tagRevision,
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
getPeerState(peerArg) {
|
|
489
|
+
let state = this.peerStates.get(peerArg);
|
|
490
|
+
if (state)
|
|
491
|
+
return state;
|
|
492
|
+
state = {
|
|
493
|
+
admissions: new Map(),
|
|
494
|
+
protectedServerNames: new Set(),
|
|
495
|
+
successfulRevisionByName: new Map(),
|
|
496
|
+
mutationTails: new Map(),
|
|
497
|
+
authorizationControllers: new Set(),
|
|
498
|
+
serverRetainedBytesByName: new Map(),
|
|
499
|
+
activeMutationOperations: 0,
|
|
500
|
+
orphanedAuthorizations: 0,
|
|
501
|
+
admittedBytes: 0,
|
|
502
|
+
serverRetainedBytes: 0,
|
|
503
|
+
};
|
|
504
|
+
this.peerStates.set(peerArg, state);
|
|
505
|
+
return state;
|
|
506
|
+
}
|
|
507
|
+
isPeerLive(peerArg) {
|
|
508
|
+
return !this.stopping
|
|
509
|
+
&& !this.closedPeers.has(peerArg)
|
|
510
|
+
&& peerArg.readyState === 1
|
|
511
|
+
&& (!this.attachedPeersProvider || this.attachedPeersProvider().includes(peerArg));
|
|
512
|
+
}
|
|
513
|
+
getConnectionAuthorityId(peerArg) {
|
|
514
|
+
let id = this.connectionAuthorityIds.get(peerArg);
|
|
515
|
+
if (!id) {
|
|
516
|
+
id = plugins.smartstring.create.createCryptoRandomString();
|
|
517
|
+
this.connectionAuthorityIds.set(peerArg, id);
|
|
518
|
+
}
|
|
519
|
+
return id;
|
|
520
|
+
}
|
|
521
|
+
getRoutingSurfaceAuthorityId(routingSurfaceArg) {
|
|
522
|
+
let id = this.routingSurfaceAuthorityIds.get(routingSurfaceArg);
|
|
523
|
+
if (!id) {
|
|
524
|
+
id = plugins.smartstring.create.createCryptoRandomString();
|
|
525
|
+
this.routingSurfaceAuthorityIds.set(routingSurfaceArg, id);
|
|
526
|
+
}
|
|
527
|
+
return id;
|
|
528
|
+
}
|
|
529
|
+
assertServerMutationName(nameArg) {
|
|
530
|
+
const denial = validateTagName(nameArg);
|
|
531
|
+
if (denial)
|
|
532
|
+
throw new Error(denial.message);
|
|
533
|
+
}
|
|
534
|
+
retainServerTag(stateArg, nameArg, payloadBytesArg) {
|
|
535
|
+
const previousBytes = stateArg.serverRetainedBytesByName.get(nameArg) ?? 0;
|
|
536
|
+
if (previousBytes === 0
|
|
537
|
+
&& stateArg.serverRetainedBytesByName.size >= TYPEDSOCKET_MAX_SERVER_TAG_NAMES_PER_PEER) {
|
|
538
|
+
throw new Error(`TypedSocket servers may protect at most ${TYPEDSOCKET_MAX_SERVER_TAG_NAMES_PER_PEER} tag names per connection.`);
|
|
539
|
+
}
|
|
540
|
+
const retainedBytes = textEncoder.encode(nameArg).byteLength + payloadBytesArg;
|
|
541
|
+
const nextTotal = stateArg.serverRetainedBytes - previousBytes + retainedBytes;
|
|
542
|
+
if (nextTotal > TYPEDSOCKET_MAX_SERVER_TAG_RETAINED_BYTES_PER_PEER) {
|
|
543
|
+
throw new Error(`TypedSocket server tags may retain at most ${TYPEDSOCKET_MAX_SERVER_TAG_RETAINED_BYTES_PER_PEER} bytes per connection.`);
|
|
544
|
+
}
|
|
545
|
+
stateArg.serverRetainedBytesByName.set(nameArg, retainedBytes);
|
|
546
|
+
stateArg.serverRetainedBytes = nextTotal;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy50eXBlZHNvY2tldHRhZ3BvbGljeW1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLnR5cGVkc29ja2V0dGFncG9saWN5bWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUV4QyxNQUFNLENBQUMsTUFBTSw4QkFBOEIsR0FBRyxHQUFHLENBQUM7QUFDbEQsTUFBTSxDQUFDLE1BQU0saUNBQWlDLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQztBQUMxRCxNQUFNLENBQUMsTUFBTSxvQ0FBb0MsR0FBRyxFQUFFLENBQUM7QUFDdkQsTUFBTSxDQUFDLE1BQU0sa0RBQWtELEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUM1RSxNQUFNLENBQUMsTUFBTSwrQ0FBK0MsR0FBRyxDQUFDLENBQUM7QUFDakUsTUFBTSxDQUFDLE1BQU0sK0NBQStDLEdBQUcsRUFBRSxDQUFDO0FBQ2xFLE1BQU0sQ0FBQyxNQUFNLGlEQUFpRCxHQUFHLEdBQUcsQ0FBQztBQUNyRSxNQUFNLENBQUMsTUFBTSw0Q0FBNEMsR0FBRyxLQUFLLENBQUM7QUFDbEUsTUFBTSxDQUFDLE1BQU0seUNBQXlDLEdBQUcsRUFBRSxDQUFDO0FBQzVELE1BQU0sQ0FBQyxNQUFNLGtEQUFrRCxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFFNUUsTUFBTSxVQUFVLEdBQUcscUJBQXFCLENBQUM7QUFDekMsTUFBTSxXQUFXLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztBQUt0Qzs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sNEJBQTRCLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQztJQUN4RCxzQkFBc0I7SUFDdEIsa0JBQWtCO0lBQ2xCLG9CQUFvQjtJQUNwQixpQkFBaUI7SUFDakIscUJBQXFCO0lBQ3JCLHVCQUF1QjtJQUN2QiwwQkFBMEI7SUFDMUIsMkJBQTJCO0lBQzNCLGdDQUFnQztJQUNoQywwQkFBMEI7SUFDMUIsNkJBQTZCO0lBQzdCLGtCQUFrQjtJQUNsQix1QkFBdUI7SUFDdkIsd0JBQXdCO0NBQ2hCLENBQUMsQ0FBQztBQTJEWixNQUFNLE9BQU8sK0JBQWdDLFNBQVEsS0FBSztJQUd4RCxZQUFZLE9BQWtDLEVBQUUsVUFBa0I7UUFDaEUsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2xCLElBQUksQ0FBQyxJQUFJLEdBQUcsaUNBQWlDLENBQUM7UUFDOUMsSUFBSSxDQUFDLElBQUksR0FBRyxPQUFPLENBQUM7SUFDdEIsQ0FBQztDQUNGO0FBdUNELFNBQVMsSUFBSSxDQUNYLE9BQWtDLEVBQ2xDLFVBQWtCO0lBRWxCLE9BQU87UUFDTCxPQUFPLEVBQUUsS0FBSztRQUNkLElBQUksRUFBRSxPQUFPO1FBQ2IsT0FBTyxFQUFFLFVBQVU7S0FDcEIsQ0FBQztBQUNKLENBQUM7QUFFRCxNQUFNLFVBQVUsMkJBQTJCLENBQ3pDLFFBQWlCLEVBQ2pCLFFBQWdCLEVBQ2hCLGVBQXVCO0lBRXZCLElBQ0UsT0FBTyxRQUFRLEtBQUssUUFBUTtXQUN6QixRQUFRLENBQUMsTUFBTSxLQUFLLENBQUM7V0FDckIsV0FBVyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxVQUFVLEdBQUcsZUFBZSxFQUM1RCxDQUFDO1FBQ0QsTUFBTSxJQUFJLEtBQUssQ0FDYixlQUFlLFFBQVEsMENBQTBDLGVBQWUsZUFBZSxDQUNoRyxDQUFDO0lBQ0osQ0FBQztBQUNILENBQUM7QUFFRCxTQUFTLGVBQWUsQ0FBQyxPQUFnQjtJQUN2QyxJQUFJLE9BQU8sT0FBTyxLQUFLLFFBQVEsSUFBSSxPQUFPLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3hELE9BQU8sSUFBSSxDQUFDLGtCQUFrQixFQUFFLGtEQUFrRCxDQUFDLENBQUM7SUFDdEYsQ0FBQztJQUNELElBQUksV0FBVyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxVQUFVLEdBQUcsOEJBQThCLEVBQUUsQ0FBQztRQUM1RSxPQUFPLElBQUksQ0FDVCxvQkFBb0IsRUFDcEIseUNBQXlDLDhCQUE4QixlQUFlLENBQ3ZGLENBQUM7SUFDSixDQUFDO0lBQ0QsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQUVELE1BQU0sVUFBVSxtQ0FBbUMsQ0FBQyxVQUFtQjtJQUNyRSxJQUFJLE9BQWUsQ0FBQztJQUNwQixJQUFJLE9BQWdCLENBQUM7SUFDckIsSUFBSSxDQUFDO1FBQ0gsT0FBTyxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUM7UUFDN0QsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDaEQsT0FBTyxHQUFHLE9BQU8sTUFBTSxLQUFLLFFBQVEsSUFBSSxNQUFNLEtBQUssSUFBSTtZQUNyRCxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDO1lBQzlCLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFDaEIsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE1BQU0sSUFBSSwrQkFBK0IsQ0FDdkMscUJBQXFCLEVBQ3JCLDBEQUEwRCxDQUMzRCxDQUFDO0lBQ0osQ0FBQztJQUNELE1BQU0sVUFBVSxHQUFHLFdBQVcsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsVUFBVSxDQUFDO0lBQzFELElBQUksVUFBVSxHQUFHLGlDQUFpQyxFQUFFLENBQUM7UUFDbkQsTUFBTSxJQUFJLCtCQUErQixDQUN2Qyx1QkFBdUIsRUFDdkIsNENBQTRDLGlDQUFpQyxvQkFBb0IsQ0FDbEcsQ0FBQztJQUNKLENBQUM7SUFDRCxPQUFPLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsQ0FBQztBQUMxQyxDQUFDO0FBRUQsU0FBUyxlQUFlLENBQUMsVUFBbUI7SUFDMUMsT0FBTyxtQ0FBbUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxPQUFPLENBQUM7QUFDakUsQ0FBQztBQUVELE1BQU0sT0FBTywyQkFBMkI7SUFZdEMsWUFBWSxTQUF1QztRQVhsQyxVQUFLLEdBQUcsSUFBSSxHQUFHLEVBQXFDLENBQUM7UUFFckQsZUFBVSxHQUFHLElBQUksT0FBTyxFQUF5QyxDQUFDO1FBQ2xFLGVBQVUsR0FBRyxJQUFJLEdBQUcsRUFBbUMsQ0FBQztRQUN4RCwyQkFBc0IsR0FBRyxJQUFJLE9BQU8sRUFBa0MsQ0FBQztRQUN2RSwrQkFBMEIsR0FBRyxJQUFJLE9BQU8sRUFBNEMsQ0FBQztRQUNyRixnQkFBVyxHQUFHLElBQUksT0FBTyxFQUEwQixDQUFDO1FBRTdELHlCQUFvQixHQUFHLENBQUMsQ0FBQztRQUN6QixhQUFRLEdBQUcsS0FBSyxDQUFDO1FBR3ZCLE1BQU0sU0FBUyxHQUFHLFNBQVMsRUFBRSxzQkFBc0I7ZUFDOUMsNENBQTRDLENBQUM7UUFDbEQsSUFDRSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFDO2VBQzdCLFNBQVMsR0FBRyxDQUFDO2VBQ2IsU0FBUyxHQUFHLDRDQUE0QyxFQUMzRCxDQUFDO1lBQ0QsTUFBTSxJQUFJLEtBQUssQ0FDYix1RUFBdUUsNENBQTRDLEdBQUcsQ0FDdkgsQ0FBQztRQUNKLENBQUM7UUFDRCxJQUFJLENBQUMsc0JBQXNCLEdBQUcsU0FBUyxDQUFDO1FBRXhDLEtBQUssTUFBTSxJQUFJLElBQUksU0FBUyxFQUFFLEtBQUssSUFBSSxFQUFFLEVBQUUsQ0FBQztZQUMxQyxNQUFNLFVBQVUsR0FBRyxlQUFlLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQy9DLElBQUksVUFBVTtnQkFBRSxNQUFNLElBQUksS0FBSyxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNwRCxJQUFJLElBQUksQ0FBQyxLQUFLLEtBQUssUUFBUSxJQUFJLElBQUksQ0FBQyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQ3ZELE1BQU0sSUFBSSxLQUFLLENBQUMsZ0NBQWdDLElBQUksQ0FBQyxJQUFJLHlCQUF5QixDQUFDLENBQUM7WUFDdEYsQ0FBQztZQUNELElBQUksT0FBTyxJQUFJLENBQUMsb0JBQW9CLEtBQUssVUFBVSxFQUFFLENBQUM7Z0JBQ3BELE1BQU0sSUFBSSxLQUFLLENBQ2IsZ0NBQWdDLElBQUksQ0FBQyxJQUFJLG9DQUFvQyxDQUM5RSxDQUFDO1lBQ0osQ0FBQztZQUNELElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQzlCLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0NBQWdDLElBQUksQ0FBQyxJQUFJLGtCQUFrQixDQUFDLENBQUM7WUFDL0UsQ0FBQztZQUNELElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEdBQUcsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQ3RELElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsRUFBRSxZQUFZLEVBQUUsQ0FBQyxFQUFFLHNCQUFzQixFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDakYsQ0FBQztJQUNILENBQUM7SUFFTSxLQUFLLENBQUMsWUFBWSxDQUN2QixPQUEyQyxFQUMzQyxPQUFnQixFQUNoQixVQUFtQjtRQUVuQixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsc0JBQXNCLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzdELElBQUksU0FBUyxJQUFJLE1BQU07WUFBRSxPQUFPLE1BQU0sQ0FBQztRQUV2QyxJQUFJLGVBQW9DLENBQUM7UUFDekMsSUFBSSxDQUFDO1lBQ0gsZUFBZSxHQUFHLG1DQUFtQyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3BFLENBQUM7UUFBQyxPQUFPLFFBQVEsRUFBRSxDQUFDO1lBQ2xCLE9BQU8sUUFBUSxZQUFZLCtCQUErQjtnQkFDeEQsQ0FBQyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxPQUFPLENBQUM7Z0JBQ3ZDLENBQUMsQ0FBQyxJQUFJLENBQUMscUJBQXFCLEVBQUUsNENBQTRDLENBQUMsQ0FBQztRQUNoRixDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsWUFBWSxFQUFFLEVBQUU7WUFDbEcsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUNwQixNQUFNLENBQUMsSUFBSSxFQUNYLFFBQVEsRUFDUixNQUFNLENBQUMsSUFBSSxFQUNYLE1BQU0sQ0FBQyxJQUFJLEVBQ1gsZUFBZSxFQUNmLFlBQVksQ0FDYixDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU0sS0FBSyxDQUFDLGVBQWUsQ0FDMUIsT0FBMkMsRUFDM0MsT0FBZ0I7UUFFaEIsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLHNCQUFzQixDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztRQUM3RCxJQUFJLFNBQVMsSUFBSSxNQUFNO1lBQUUsT0FBTyxNQUFNLENBQUM7UUFFdkMsT0FBTyxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsWUFBWSxFQUFFLEVBQUU7WUFDbEcsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUN2QixNQUFNLENBQUMsSUFBSSxFQUNYLFFBQVEsRUFDUixNQUFNLENBQUMsSUFBSSxFQUNYLE1BQU0sQ0FBQyxJQUFJLEVBQ1gsWUFBWSxDQUNiLENBQUM7UUFDSixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTSxZQUFZLENBQ2pCLE9BQStCLEVBQy9CLE9BQWUsRUFDZixVQUFvQjtRQUVwQixJQUFJLENBQUMsd0JBQXdCLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDdkMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUM5QixNQUFNLElBQUksS0FBSyxDQUFDLHlFQUF5RSxDQUFDLENBQUM7UUFDN0YsQ0FBQztRQUNELE1BQU0sZUFBZSxHQUFHLG1DQUFtQyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3hFLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDekMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLGVBQWUsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNqRSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3RDLEtBQUssQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDeEMsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDMUIsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxVQUFVLEdBQUcsT0FBTyxFQUFFLEVBQUUsZUFBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3ZFLENBQUM7SUFFTSxlQUFlLENBQUMsT0FBK0IsRUFBRSxPQUFlO1FBQ3JFLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN2QyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQzlCLE1BQU0sSUFBSSxLQUFLLENBQUMsOEVBQThFLENBQUMsQ0FBQztRQUNsRyxDQUFDO1FBQ0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN6QyxJQUFJLENBQUMsZUFBZSxDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDeEMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN0QyxLQUFLLENBQUMsb0JBQW9CLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3hDLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzdCLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsVUFBVSxHQUFHLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDakQsQ0FBQztJQUVNLGVBQWUsQ0FBQyxPQUErQjtRQUNwRCxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM5QixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMzQyxJQUFJLENBQUMsS0FBSztZQUFFLE9BQU87UUFDbkIsS0FBSyxNQUFNLFVBQVUsSUFBSSxLQUFLLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztZQUN4RCxVQUFVLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxDQUFDLGdDQUFnQyxDQUFDLENBQUMsQ0FBQztRQUNoRSxDQUFDO0lBQ0gsQ0FBQztJQUVNLHdCQUF3QixDQUM3QixXQUFrRTtRQUVsRSxJQUFJLENBQUMscUJBQXFCLEdBQUcsV0FBVyxDQUFDO0lBQzNDLENBQUM7SUFFTSxJQUFJLENBQUMsUUFBMkM7UUFDckQsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7UUFDckIsS0FBSyxNQUFNLElBQUksSUFBSSxRQUFRO1lBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN4RCxJQUFJLENBQUMscUJBQXFCLEdBQUcsU0FBUyxDQUFDO0lBQ3pDLENBQUM7SUFFTSx1QkFBdUI7UUFDNUIsT0FBTyxJQUFJLENBQUMsb0JBQW9CLENBQUM7SUFDbkMsQ0FBQztJQUVNLDhCQUE4QixDQUFDLE9BQWU7UUFDbkQsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsRUFBRSxZQUFZLElBQUksQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFFTyxzQkFBc0IsQ0FDNUIsT0FBMkMsRUFDM0MsT0FBZ0I7UUFRaEIsTUFBTSxVQUFVLEdBQUcsZUFBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzVDLElBQUksVUFBVTtZQUFFLE9BQU8sVUFBVSxDQUFDO1FBQ2xDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNiLE9BQU8sSUFBSSxDQUFDLHVCQUF1QixFQUFFLGtEQUFrRCxDQUFDLENBQUM7UUFDM0YsQ0FBQztRQUNELElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDOUIsT0FBTyxJQUFJLENBQUMsdUJBQXVCLEVBQUUsK0RBQStELENBQUMsQ0FBQztRQUN4RyxDQUFDO1FBQ0QsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUMxQixPQUFPLElBQUksQ0FBQyxzQkFBc0IsRUFBRSw4Q0FBOEMsQ0FBQyxDQUFDO1FBQ3RGLENBQUM7UUFDRCxJQUFJLE9BQU8sT0FBTyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ2hDLE9BQU8sSUFBSSxDQUFDLGtCQUFrQixFQUFFLGtEQUFrRCxDQUFDLENBQUM7UUFDdEYsQ0FBQztRQUNELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3JDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNWLE9BQU8sSUFBSSxDQUFDLGlCQUFpQixFQUFFLDZDQUE2QyxDQUFDLENBQUM7UUFDaEYsQ0FBQztRQUNELE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLENBQUM7SUFDaEQsQ0FBQztJQUVPLEtBQUssQ0FBQyxlQUFlLENBQzNCLE9BQStCLEVBQy9CLE9BQWtDLEVBQ2xDLE9BQWUsRUFDZixZQUc2QztRQUU3QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3pDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNwRCxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDZixPQUFPLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxtREFBbUQsQ0FBQyxDQUFDO1FBQ3RGLENBQUM7UUFDRCxJQUNFLEtBQUssQ0FBQyx3QkFBd0IsR0FBRyxLQUFLLENBQUMsc0JBQXNCO2VBQ3hELCtDQUErQztlQUNqRCxTQUFTLENBQUMsWUFBWSxJQUFJLCtDQUErQztlQUN6RSxJQUFJLENBQUMsb0JBQW9CLElBQUksaURBQWlELEVBQ2pGLENBQUM7WUFDRCxPQUFPLElBQUksQ0FDVCxnQ0FBZ0MsRUFDaEMsd0RBQXdELENBQ3pELENBQUM7UUFDSixDQUFDO1FBRUQsS0FBSyxDQUFDLHdCQUF3QixFQUFFLENBQUM7UUFDakMsU0FBUyxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO1FBQzVCLE1BQU0sWUFBWSxHQUFHLEtBQUssQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUMzRSxNQUFNLFNBQVMsR0FBdUIsRUFBRSxDQUFDO1FBQ3pDLE1BQU0sU0FBUyxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDO1FBQzFFLE1BQU0sSUFBSSxHQUFHLFNBQVMsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsU0FBUyxFQUFFLEdBQUcsRUFBRSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzlELEtBQUssQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQztRQUV2QyxJQUFJLENBQUM7WUFDSCxPQUFPLE1BQU0sU0FBUyxDQUFDO1FBQ3pCLENBQUM7Z0JBQVMsQ0FBQztZQUNULEtBQUssQ0FBQyx3QkFBd0IsRUFBRSxDQUFDO1lBQ2pDLElBQUksU0FBUyxDQUFDLGFBQWEsRUFBRSxDQUFDO2dCQUM1QixLQUFLLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztnQkFDL0IsU0FBUyxDQUFDLHNCQUFzQixFQUFFLENBQUM7Z0JBQ25DLEtBQUssU0FBUyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFO29CQUNyQyxLQUFLLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztvQkFDL0IsU0FBUyxDQUFDLHNCQUFzQixFQUFFLENBQUM7b0JBQ25DLFNBQVMsQ0FBQyxZQUFZLEVBQUUsQ0FBQztvQkFDekIsSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUM7Z0JBQzlCLENBQUMsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLFNBQVMsQ0FBQyxZQUFZLEVBQUUsQ0FBQztnQkFDekIsSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUM7WUFDOUIsQ0FBQztZQUNELElBQUksS0FBSyxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUM7Z0JBQzlDLEtBQUssQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ3RDLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVPLEtBQUssQ0FBQyxVQUFVLENBQ3RCLE9BQStCLEVBQy9CLFFBQXVCLEVBQ3ZCLE9BQWtDLEVBQ2xDLE9BQWUsRUFDZixrQkFBdUMsRUFDdkMsWUFBZ0M7UUFFaEMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUM5QixPQUFPLElBQUksQ0FBQyx1QkFBdUIsRUFBRSx1Q0FBdUMsQ0FBQyxDQUFDO1FBQ2hGLENBQUM7UUFDRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDaEUsSUFBSSxRQUFRLENBQUMsb0JBQW9CLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLFFBQVEsRUFBRSxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDL0UsT0FBTyxJQUFJLENBQUMsa0JBQWtCLEVBQUUsc0RBQXNELENBQUMsQ0FBQztRQUMxRixDQUFDO1FBQ0QsSUFBSSxRQUFRLElBQUksT0FBTyxDQUFDLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUMzQyxPQUFPLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxzREFBc0QsQ0FBQyxDQUFDO1FBQzFGLENBQUM7UUFDRCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDckQsTUFBTSxjQUFjLEdBQUcsT0FBTyxDQUFDLGNBQWMsQ0FBQztRQUM5QyxNQUFNLGFBQWEsR0FBRyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQ3hDLE9BQU8sRUFDUCxRQUFRLEVBQ1IsT0FBTyxFQUNQO1lBQ0UsU0FBUyxFQUFFLEtBQUs7WUFDaEIsSUFBSSxFQUFFLE9BQU87WUFDYixPQUFPLEVBQUUsa0JBQWtCLENBQUMsT0FBTztZQUNuQyxRQUFRO1NBQ1QsRUFDRCxZQUFZLENBQ2IsQ0FBQztRQUNGLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTztZQUFFLE9BQU8sYUFBYSxDQUFDLE1BQU0sQ0FBQztRQUN4RCxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQzlCLE9BQU8sSUFBSSxDQUFDLHVCQUF1QixFQUFFLHlEQUF5RCxDQUFDLENBQUM7UUFDbEcsQ0FBQztRQUNELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUMvRCxJQUNFLENBQUMsY0FBYztlQUNaLE9BQU8sQ0FBQyxjQUFjLEtBQUssY0FBYztlQUN6QyxRQUFRLENBQUMsb0JBQW9CLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQztlQUMxQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsT0FBTyxDQUFDLEtBQUssV0FBVyxFQUNsRCxDQUFDO1lBQ0QsT0FBTyxJQUFJLENBQUMsa0JBQWtCLEVBQUUseURBQXlELENBQUMsQ0FBQztRQUM3RixDQUFDO1FBRUQsTUFBTSxhQUFhLEdBQUcsV0FBVyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxVQUFVLEdBQUcsa0JBQWtCLENBQUMsVUFBVSxDQUFDO1FBQzdGLE1BQU0sU0FBUyxHQUFHLFFBQVEsQ0FBQyxVQUFVLENBQUMsSUFBSSxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQy9ELE1BQU0sU0FBUyxHQUFHLFFBQVEsQ0FBQyxhQUFhLEdBQUcsQ0FBQyxPQUFPLEVBQUUsYUFBYSxJQUFJLENBQUMsQ0FBQyxHQUFHLGFBQWEsQ0FBQztRQUN6RixJQUFJLFNBQVMsR0FBRyxvQ0FBb0MsRUFBRSxDQUFDO1lBQ3JELE9BQU8sSUFBSSxDQUNULDBCQUEwQixFQUMxQiwwQ0FBMEMsb0NBQW9DLHVCQUF1QixDQUN0RyxDQUFDO1FBQ0osQ0FBQztRQUNELElBQUksU0FBUyxHQUFHLGtEQUFrRCxFQUFFLENBQUM7WUFDbkUsT0FBTyxJQUFJLENBQ1QsNkJBQTZCLEVBQzdCLDhDQUE4QyxrREFBa0Qsd0JBQXdCLENBQ3pILENBQUM7UUFDSixDQUFDO1FBRUQsSUFBSSxPQUFPO1lBQUUsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN0RCxNQUFNLFNBQVMsR0FBOEI7WUFDM0MsR0FBRyxrQkFBa0I7WUFDckIsS0FBSyxFQUFFLE9BQU8sQ0FBQyxLQUFLO1lBQ3BCLGFBQWE7U0FDZCxDQUFDO1FBQ0YsUUFBUSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBQzVDLFFBQVEsQ0FBQyxhQUFhLElBQUksYUFBYSxDQUFDO1FBQ3hDLElBQUksT0FBTyxDQUFDLEtBQUssS0FBSyxRQUFRO1lBQUUsUUFBUSxDQUFDLG9CQUFvQixDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMzRSxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMxQixPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLFVBQVUsR0FBRyxPQUFPLEVBQUUsRUFBRSxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN4RSxPQUFPLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBRU8sS0FBSyxDQUFDLGFBQWEsQ0FDekIsT0FBK0IsRUFDL0IsUUFBdUIsRUFDdkIsT0FBa0MsRUFDbEMsT0FBZSxFQUNmLFlBQWdDO1FBRWhDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDOUIsT0FBTyxJQUFJLENBQUMsdUJBQXVCLEVBQUUsdUNBQXVDLENBQUMsQ0FBQztRQUNoRixDQUFDO1FBQ0QsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ2hFLElBQUksUUFBUSxDQUFDLG9CQUFvQixDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxRQUFRLEVBQUUsS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQy9FLE9BQU8sSUFBSSxDQUFDLGtCQUFrQixFQUFFLGtEQUFrRCxDQUFDLENBQUM7UUFDdEYsQ0FBQztRQUNELElBQUksQ0FBQyxRQUFRO1lBQUUsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzVFLElBQUksT0FBTyxDQUFDLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUMvQixPQUFPLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxrREFBa0QsQ0FBQyxDQUFDO1FBQ3RGLENBQUM7UUFDRCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDckQsTUFBTSxjQUFjLEdBQUcsT0FBTyxDQUFDLGNBQWMsQ0FBQztRQUM5QyxNQUFNLGFBQWEsR0FBRyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQ3hDLE9BQU8sRUFDUCxRQUFRLEVBQ1IsT0FBTyxFQUNQO1lBQ0UsU0FBUyxFQUFFLFFBQVE7WUFDbkIsSUFBSSxFQUFFLE9BQU87WUFDYixPQUFPLEVBQUUsUUFBUSxDQUFDLE9BQU87WUFDekIsUUFBUTtTQUNULEVBQ0QsWUFBWSxDQUNiLENBQUM7UUFDRixJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU87WUFBRSxPQUFPLGFBQWEsQ0FBQyxNQUFNLENBQUM7UUFDeEQsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUM5QixPQUFPLElBQUksQ0FBQyx1QkFBdUIsRUFBRSx5REFBeUQsQ0FBQyxDQUFDO1FBQ2xHLENBQUM7UUFDRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDL0QsSUFDRSxDQUFDLGNBQWM7ZUFDWixPQUFPLENBQUMsY0FBYyxLQUFLLGNBQWM7ZUFDekMsUUFBUSxDQUFDLG9CQUFvQixDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUM7ZUFDMUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxLQUFLLFdBQVcsRUFDbEQsQ0FBQztZQUNELE9BQU8sSUFBSSxDQUFDLGtCQUFrQixFQUFFLHlEQUF5RCxDQUFDLENBQUM7UUFDN0YsQ0FBQztRQUNELElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDekMsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDN0IsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxVQUFVLEdBQUcsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUMvQyxPQUFPLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDL0QsQ0FBQztJQUVPLEtBQUssQ0FBQyxTQUFTLENBQ3JCLE9BQStCLEVBQy9CLFFBQXVCLEVBQ3ZCLE9BQWtDLEVBQ2xDLFVBS0MsRUFDRCxZQUFnQztRQUVoQyxNQUFNLGNBQWMsR0FBRyxPQUFPLENBQUMsY0FBYyxDQUFDO1FBQzlDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUNwQixPQUFPO2dCQUNMLE9BQU8sRUFBRSxLQUFLO2dCQUNkLE1BQU0sRUFBRSxJQUFJLENBQ1YsdUJBQXVCLEVBQ3ZCLGtFQUFrRSxDQUNuRTthQUNGLENBQUM7UUFDSixDQUFDO1FBQ0QsTUFBTSxVQUFVLEdBQUcsSUFBSSxlQUFlLEVBQUUsQ0FBQztRQUN6QyxRQUFRLENBQUMsd0JBQXdCLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2xELE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7WUFDOUIsWUFBWSxFQUFFLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxPQUFPLENBQUM7WUFDcEQsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLDRCQUE0QixDQUFDLGNBQWMsQ0FBQztTQUNwRSxDQUFDLENBQUM7UUFDSCxNQUFNLFFBQVEsR0FBRyxVQUFVLENBQUMsUUFBUTtZQUNsQyxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQztnQkFDWixLQUFLLEVBQUUsUUFBaUI7Z0JBQ3hCLE9BQU8sRUFBRSxlQUFlLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUM7YUFDdEQsQ0FBQztZQUNKLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFDZCxNQUFNLGlCQUFpQixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7WUFDdEMsU0FBUyxFQUFFLFVBQVUsQ0FBQyxTQUFTO1lBQy9CLElBQUksRUFBRSxVQUFVLENBQUMsSUFBSTtZQUNyQixPQUFPLEVBQUUsZUFBZSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUM7WUFDNUMsUUFBUTtZQUNSLFNBQVM7WUFDVCxXQUFXLEVBQUUsVUFBVSxDQUFDLE1BQU07U0FDL0IsQ0FBQyxDQUFDO1FBRUgsSUFBSSxlQUFlLEdBQUcsS0FBSyxDQUFDO1FBQzVCLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLEVBQUU7YUFDOUIsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO2FBQzNELElBQUksQ0FDSCxDQUFDLFVBQVUsRUFBRSxFQUFFO1lBQ2IsZUFBZSxHQUFHLElBQUksQ0FBQztZQUN2QixPQUFPLFVBQVUsS0FBSyxJQUFJLENBQUM7UUFDN0IsQ0FBQyxFQUNELEdBQUcsRUFBRTtZQUNILGVBQWUsR0FBRyxJQUFJLENBQUM7WUFDdkIsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDLENBQ0YsQ0FBQztRQUNKLElBQUksT0FBa0QsQ0FBQztRQUN2RCxJQUFJLGFBQXVDLENBQUM7UUFDNUMsTUFBTSxhQUFhLEdBQUcsSUFBSSxPQUFPLENBQVksQ0FBQyxVQUFVLEVBQUUsRUFBRTtZQUMxRCxPQUFPLEdBQUcsVUFBVSxDQUFDLEdBQUcsRUFBRTtnQkFDeEIsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUN0QixVQUFVLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxDQUFDLDBDQUEwQyxDQUFDLENBQUMsQ0FBQztZQUMxRSxDQUFDLEVBQUUsSUFBSSxDQUFDLHNCQUFzQixDQUFDLENBQUM7UUFDbEMsQ0FBQyxDQUFDLENBQUM7UUFDSCxNQUFNLFdBQVcsR0FBRyxJQUFJLE9BQU8sQ0FBWSxDQUFDLFVBQVUsRUFBRSxFQUFFO1lBQ3hELGFBQWEsR0FBRyxHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDNUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsYUFBYSxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFDN0UsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUM7WUFDSCxNQUFNLE1BQU0sR0FBRyxNQUFNLE9BQU8sQ0FBQyxJQUFJLENBQUM7Z0JBQ2hDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsU0FBa0IsQ0FBQyxDQUFDLENBQUMsUUFBaUIsQ0FBQztnQkFDakYsYUFBYTtnQkFDYixXQUFXO2FBQ1osQ0FBQyxDQUFDO1lBQ0gsSUFBSSxNQUFNLEtBQUssU0FBUztnQkFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxDQUFDO1lBQ25ELElBQUksQ0FBQyxlQUFlO2dCQUFFLFlBQVksQ0FBQyxhQUFhLEdBQUcsT0FBTyxDQUFDO1lBQzNELElBQUksTUFBTSxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUN6QixPQUFPO29CQUNMLE9BQU8sRUFBRSxLQUFLO29CQUNkLE1BQU0sRUFBRSxJQUFJLENBQUMsMkJBQTJCLEVBQUUsMENBQTBDLENBQUM7aUJBQ3RGLENBQUM7WUFDSixDQUFDO1lBQ0QsSUFBSSxNQUFNLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQ3pCLE9BQU87b0JBQ0wsT0FBTyxFQUFFLEtBQUs7b0JBQ2QsTUFBTSxFQUFFLElBQUksQ0FBQyx1QkFBdUIsRUFBRSw4Q0FBOEMsQ0FBQztpQkFDdEYsQ0FBQztZQUNKLENBQUM7WUFDRCxPQUFPO2dCQUNMLE9BQU8sRUFBRSxLQUFLO2dCQUNkLE1BQU0sRUFBRSxJQUFJLENBQUMsMEJBQTBCLEVBQUUsMkNBQTJDLENBQUM7YUFDdEYsQ0FBQztRQUNKLENBQUM7Z0JBQVMsQ0FBQztZQUNULElBQUksT0FBTztnQkFBRSxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDbkMsSUFBSSxhQUFhO2dCQUFFLFVBQVUsQ0FBQyxNQUFNLENBQUMsbUJBQW1CLENBQUMsT0FBTyxFQUFFLGFBQWEsQ0FBQyxDQUFDO1lBQ2pGLFFBQVEsQ0FBQyx3QkFBd0IsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDdkQsQ0FBQztJQUNILENBQUM7SUFFTyxhQUFhLENBQ25CLE9BQStCLEVBQy9CLFFBQXVCLEVBQ3ZCLE9BQWU7UUFFZixNQUFNLE9BQU8sR0FBRyxRQUFRLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNqRCxNQUFNLE9BQU8sR0FBRyxHQUFHLFVBQVUsR0FBRyxPQUFPLEVBQUUsQ0FBQztRQUMxQyxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN6QyxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM3QyxJQUFJLE9BQU8sRUFBRSxDQUFDO1lBQ1osSUFBSSxPQUFPLEdBQUcsTUFBTSxJQUFJLFVBQVUsQ0FBQztZQUNuQyxJQUFJLE9BQU8sRUFBRSxDQUFDO2dCQUNaLElBQUksQ0FBQztvQkFDSCxPQUFPLEdBQUcsbUNBQW1DLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxPQUFPOzRCQUMxRSxPQUFPLENBQUMsT0FBTyxDQUFDO2dCQUN4QixDQUFDO2dCQUFDLE1BQU0sQ0FBQztvQkFDUCxPQUFPLEdBQUcsS0FBSyxDQUFDO2dCQUNsQixDQUFDO1lBQ0gsQ0FBQztZQUNELElBQUksT0FBTztnQkFBRSxPQUFPLE9BQU8sQ0FBQztZQUM1QixJQUFJLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQ3pDLFFBQVEsQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDM0MsT0FBTyxTQUFTLENBQUM7UUFDbkIsQ0FBQztRQUNELElBQUksTUFBTSxJQUFJLFVBQVU7WUFBRSxRQUFRLENBQUMsb0JBQW9CLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3JFLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFFTyxnQkFBZ0IsQ0FBQyxRQUF1QixFQUFFLE9BQWU7UUFDL0QsTUFBTSxRQUFRLEdBQUcsUUFBUSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDbEQsSUFBSSxDQUFDLFFBQVE7WUFBRSxPQUFPO1FBQ3RCLFFBQVEsQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3BDLFFBQVEsQ0FBQyxhQUFhLElBQUksUUFBUSxDQUFDLGFBQWEsQ0FBQztJQUNuRCxDQUFDO0lBRU8saUJBQWlCLENBQUMsWUFBd0M7UUFDaEUsT0FBTyxZQUFZLENBQUMsQ0FBQyxDQUFDLEdBQUcsWUFBWSxDQUFDLEtBQUssSUFBSSxZQUFZLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQztJQUNuRixDQUFDO0lBRU8sYUFBYSxDQUNuQixPQUErQixFQUMvQixRQUF1QixFQUN2QixPQUFlLEVBQ2YsaUJBQWlCLEdBQUcsSUFBSTtRQUV4QixNQUFNLFdBQVcsR0FBRyxDQUFDLFFBQVEsQ0FBQyx3QkFBd0IsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzlFLElBQUksaUJBQWlCO1lBQUUsUUFBUSxDQUFDLHdCQUF3QixDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsV0FBVyxDQUFDLENBQUM7O1lBQzlFLFFBQVEsQ0FBQyx3QkFBd0IsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDdkQsT0FBTztZQUNMLE9BQU8sRUFBRSxJQUFJO1lBQ2IsWUFBWSxFQUFFLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxPQUFPLENBQUM7WUFDcEQsV0FBVztTQUNaLENBQUM7SUFDSixDQUFDO0lBRU8sWUFBWSxDQUFDLE9BQStCO1FBQ2xELElBQUksS0FBSyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3pDLElBQUksS0FBSztZQUFFLE9BQU8sS0FBSyxDQUFDO1FBQ3hCLEtBQUssR0FBRztZQUNOLFVBQVUsRUFBRSxJQUFJLEdBQUcsRUFBRTtZQUNyQixvQkFBb0IsRUFBRSxJQUFJLEdBQUcsRUFBRTtZQUMvQix3QkFBd0IsRUFBRSxJQUFJLEdBQUcsRUFBRTtZQUNuQyxhQUFhLEVBQUUsSUFBSSxHQUFHLEVBQUU7WUFDeEIsd0JBQXdCLEVBQUUsSUFBSSxHQUFHLEVBQUU7WUFDbkMseUJBQXlCLEVBQUUsSUFBSSxHQUFHLEVBQUU7WUFDcEMsd0JBQXdCLEVBQUUsQ0FBQztZQUMzQixzQkFBc0IsRUFBRSxDQUFDO1lBQ3pCLGFBQWEsRUFBRSxDQUFDO1lBQ2hCLG1CQUFtQixFQUFFLENBQUM7U0FDdkIsQ0FBQztRQUNGLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNwQyxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFTyxVQUFVLENBQUMsT0FBK0I7UUFDaEQsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFRO2VBQ2hCLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDO2VBQzlCLE9BQU8sQ0FBQyxVQUFVLEtBQUssQ0FBQztlQUN4QixDQUFDLENBQUMsSUFBSSxDQUFDLHFCQUFxQixJQUFJLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQ3ZGLENBQUM7SUFFTyx3QkFBd0IsQ0FBQyxPQUErQjtRQUM5RCxJQUFJLEVBQUUsR0FBRyxJQUFJLENBQUMsc0JBQXNCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2xELElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNSLEVBQUUsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyx3QkFBd0IsRUFBRSxDQUFDO1lBQzNELElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQy9DLENBQUM7UUFDRCxPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFFTyw0QkFBNEIsQ0FDbEMsaUJBQW1EO1FBRW5ELElBQUksRUFBRSxHQUFHLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxHQUFHLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUNoRSxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDUixFQUFFLEdBQUcsT0FBTyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztZQUMzRCxJQUFJLENBQUMsMEJBQTBCLENBQUMsR0FBRyxDQUFDLGlCQUFpQixFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQzdELENBQUM7UUFDRCxPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFFTyx3QkFBd0IsQ0FBQyxPQUFlO1FBQzlDLE1BQU0sTUFBTSxHQUFHLGVBQWUsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN4QyxJQUFJLE1BQU07WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUM5QyxDQUFDO0lBRU8sZUFBZSxDQUNyQixRQUF1QixFQUN2QixPQUFlLEVBQ2YsZUFBdUI7UUFFdkIsTUFBTSxhQUFhLEdBQUcsUUFBUSxDQUFDLHlCQUF5QixDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDM0UsSUFDRSxhQUFhLEtBQUssQ0FBQztlQUNoQixRQUFRLENBQUMseUJBQXlCLENBQUMsSUFBSSxJQUFJLHlDQUF5QyxFQUN2RixDQUFDO1lBQ0QsTUFBTSxJQUFJLEtBQUssQ0FDYiwyQ0FBMkMseUNBQXlDLDRCQUE0QixDQUNqSCxDQUFDO1FBQ0osQ0FBQztRQUNELE1BQU0sYUFBYSxHQUFHLFdBQVcsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsVUFBVSxHQUFHLGVBQWUsQ0FBQztRQUMvRSxNQUFNLFNBQVMsR0FBRyxRQUFRLENBQUMsbUJBQW1CLEdBQUcsYUFBYSxHQUFHLGFBQWEsQ0FBQztRQUMvRSxJQUFJLFNBQVMsR0FBRyxrREFBa0QsRUFBRSxDQUFDO1lBQ25FLE1BQU0sSUFBSSxLQUFLLENBQ2IsOENBQThDLGtEQUFrRCx3QkFBd0IsQ0FDekgsQ0FBQztRQUNKLENBQUM7UUFDRCxRQUFRLENBQUMseUJBQXlCLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxhQUFhLENBQUMsQ0FBQztRQUMvRCxRQUFRLENBQUMsbUJBQW1CLEdBQUcsU0FBUyxDQUFDO0lBQzNDLENBQUM7Q0FDRiJ9
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export declare const NATIVE_BYTE_PROTOCOL: "native-byte-v1";
|
|
2
|
+
export declare const NATIVE_BYTE_PROTOCOL_MAJOR: 6;
|
|
3
|
+
export declare const NATIVE_BYTE_FRAME_MAGIC: "TSB1";
|
|
4
|
+
export declare const NATIVE_BYTE_FRAME_TYPES: {
|
|
5
|
+
readonly OPEN: 1;
|
|
6
|
+
readonly OPEN_ACK: 2;
|
|
7
|
+
readonly DATA: 3;
|
|
8
|
+
readonly ACK: 4;
|
|
9
|
+
readonly FIN: 5;
|
|
10
|
+
readonly FIN_ACK: 6;
|
|
11
|
+
readonly RESET: 7;
|
|
12
|
+
};
|
|
13
|
+
export declare const NATIVE_BYTE_RESET_CODES: {
|
|
14
|
+
readonly PROTOCOL_ERROR: 1;
|
|
15
|
+
readonly CAPABILITY_REJECTED: 2;
|
|
16
|
+
readonly RESOURCE_LIMIT: 3;
|
|
17
|
+
readonly TIMEOUT: 4;
|
|
18
|
+
readonly ABORTED: 5;
|
|
19
|
+
readonly INTEGRITY_ERROR: 6;
|
|
20
|
+
readonly AUTHORITY_REVOKED: 7;
|
|
21
|
+
readonly INTERNAL_ERROR: 8;
|
|
22
|
+
};
|
|
23
|
+
export declare const NATIVE_BYTE_COMMON_HEADER_BYTES = 32;
|
|
24
|
+
export declare const NATIVE_BYTE_OPEN_FIXED_HEADER_BYTES = 116;
|
|
25
|
+
export declare const NATIVE_BYTE_OPEN_ACK_HEADER_BYTES = 48;
|
|
26
|
+
export declare const NATIVE_BYTE_DATA_HEADER_BYTES = 48;
|
|
27
|
+
export declare const NATIVE_BYTE_ACK_HEADER_BYTES = 48;
|
|
28
|
+
export declare const NATIVE_BYTE_FIN_HEADER_BYTES = 72;
|
|
29
|
+
export declare const NATIVE_BYTE_FIN_ACK_HEADER_BYTES = 72;
|
|
30
|
+
export declare const NATIVE_BYTE_RESET_FIXED_HEADER_BYTES = 40;
|
|
31
|
+
export declare const NATIVE_BYTE_MAX_FRAME_BYTES: number;
|
|
32
|
+
export declare const NATIVE_BYTE_MAX_DATA_PAYLOAD_BYTES: number;
|
|
33
|
+
export declare const NATIVE_BYTE_MAX_STREAM_BYTES: number;
|
|
34
|
+
export declare const NATIVE_BYTE_MAX_CONTENT_TYPE_BYTES = 255;
|
|
35
|
+
export declare const NATIVE_BYTE_MAX_RESET_REASON_BYTES = 256;
|
|
36
|
+
export declare const NATIVE_BYTE_DEFAULT_INITIAL_WINDOW_BYTES: number;
|
|
37
|
+
export declare const NATIVE_BYTE_MAX_WINDOW_BYTES: number;
|
|
38
|
+
export declare const NATIVE_BYTE_MAX_QUEUED_PAYLOAD_BYTES_PER_STREAM: number;
|
|
39
|
+
export declare const NATIVE_BYTE_MAX_QUEUED_PAYLOAD_BYTES_PER_CONNECTION: number;
|
|
40
|
+
export declare const NATIVE_BYTE_MAX_RECEIVE_QUEUE_CHUNKS = 4096;
|
|
41
|
+
export declare const NATIVE_BYTE_MAX_STREAMS_PER_CONNECTION = 32;
|
|
42
|
+
export declare const NATIVE_BYTE_MAX_PENDING_DATA_OPERATIONS_PER_CONNECTION = 64;
|
|
43
|
+
export declare const NATIVE_BYTE_MAX_RAW_QUEUE_FRAMES = 64;
|
|
44
|
+
export declare const NATIVE_BYTE_MAX_RAW_QUEUE_BYTES: number;
|
|
45
|
+
export declare const NATIVE_BYTE_GRANT_OPEN_TIMEOUT_MS = 10000;
|
|
46
|
+
export declare const NATIVE_BYTE_PROGRESS_TIMEOUT_MS = 30000;
|
|
47
|
+
export declare const NATIVE_BYTE_TOMBSTONE_RETENTION_MS = 60000;
|
|
48
|
+
export declare const NATIVE_BYTE_MAX_TOMBSTONES = 64;
|
|
49
|
+
export declare const NATIVE_BYTE_MAX_PRINCIPAL_ID_BYTES = 256;
|
|
50
|
+
export declare const NATIVE_BYTE_MAX_AUTHORITY_REVISION_BYTES = 256;
|
|
51
|
+
export declare const NATIVE_BYTE_REVALIDATION_TIMEOUT_MS = 5000;
|
|
52
|
+
export declare const NATIVE_BYTE_MAX_REVALIDATIONS_PER_PEER = 4;
|
|
53
|
+
export declare const NATIVE_BYTE_MAX_REVALIDATIONS_PER_PRINCIPAL = 16;
|
|
54
|
+
export declare const NATIVE_BYTE_MAX_REVALIDATIONS_PER_SERVER = 128;
|
|
55
|
+
export declare const NATIVE_BYTE_MAX_CONNECTIONS_PER_SERVER = 1024;
|
|
56
|
+
export declare const NATIVE_BYTE_MAX_STREAMS_PER_SERVER = 1024;
|
|
57
|
+
export declare const NATIVE_BYTE_MAX_RETAINED_BYTES_PER_SERVER: number;
|
|
58
|
+
export type TNativeByteFrameType = (typeof NATIVE_BYTE_FRAME_TYPES)[keyof typeof NATIVE_BYTE_FRAME_TYPES];
|
|
59
|
+
export type TNativeByteResetCode = (typeof NATIVE_BYTE_RESET_CODES)[keyof typeof NATIVE_BYTE_RESET_CODES];
|