@api.global/typedsocket 6.0.0 → 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.
Files changed (35) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/classes.clienttagreconciler.d.ts +51 -0
  3. package/dist_ts/classes.clienttagreconciler.js +290 -0
  4. package/dist_ts/classes.nativebyteerror.js +26 -0
  5. package/dist_ts/{nativebytes.manager.d.ts → classes.nativebytemanager.d.ts} +8 -3
  6. package/dist_ts/classes.nativebytemanager.js +2343 -0
  7. package/dist_ts/{typedsocket.classes.typedsocket.d.ts → classes.typedsocket.d.ts} +21 -21
  8. package/dist_ts/classes.typedsocket.js +1733 -0
  9. package/dist_ts/{typedsocket.tags.d.ts → classes.typedsockettagpolicymanager.d.ts} +9 -2
  10. package/dist_ts/classes.typedsockettagpolicymanager.js +549 -0
  11. package/dist_ts/{nativebytes.constants.js → constants.nativebytes.js} +1 -1
  12. package/dist_ts/{nativebytes.codec.d.ts → helpers.nativebytecodec.d.ts} +1 -1
  13. package/dist_ts/helpers.nativebytecodec.js +328 -0
  14. package/dist_ts/helpers.websocket.d.ts +8 -0
  15. package/dist_ts/helpers.websocket.js +13 -0
  16. package/dist_ts/index.d.ts +9 -8
  17. package/dist_ts/index.js +6 -6
  18. package/dist_ts/interfaces.diagnostics.d.ts +73 -0
  19. package/dist_ts/interfaces.diagnostics.js +2 -0
  20. package/dist_ts/{nativebytes.types.d.ts → interfaces.nativebytes.d.ts} +2 -2
  21. package/dist_ts/interfaces.nativebytes.js +2 -0
  22. package/dist_ts/plugins.js +14 -0
  23. package/package.json +1 -1
  24. package/readme.hints.md +26 -1
  25. package/readme.md +120 -55
  26. package/dist_ts/nativebytes.codec.js +0 -328
  27. package/dist_ts/nativebytes.errors.js +0 -26
  28. package/dist_ts/nativebytes.manager.js +0 -2308
  29. package/dist_ts/nativebytes.types.js +0 -2
  30. package/dist_ts/typedsocket.classes.typedsocket.js +0 -1874
  31. package/dist_ts/typedsocket.plugins.js +0 -14
  32. package/dist_ts/typedsocket.tags.js +0 -521
  33. /package/dist_ts/{nativebytes.errors.d.ts → classes.nativebyteerror.d.ts} +0 -0
  34. /package/dist_ts/{nativebytes.constants.d.ts → constants.nativebytes.d.ts} +0 -0
  35. /package/dist_ts/{typedsocket.plugins.d.ts → plugins.d.ts} +0 -0
@@ -1,1874 +0,0 @@
1
- import * as plugins from './typedsocket.plugins.js';
2
- import { NATIVE_BYTE_PROTOCOL, NATIVE_BYTE_PROTOCOL_MAJOR } from './nativebytes.constants.js';
3
- import { NativeByteCapabilityError } from './nativebytes.errors.js';
4
- import { NativeByteManager } from './nativebytes.manager.js';
5
- import { createTypedSocketTagPayloadSnapshot, TYPEDSOCKET_MAX_CLIENT_TAG_RETAINED_BYTES_PER_PEER, TYPEDSOCKET_MAX_CLIENT_TAGS_PER_PEER, TYPEDSOCKET_MAX_TAG_NAME_BYTES, TypedSocketClientTagDeniedError, TypedSocketTagPolicyManager, } from './typedsocket.tags.js';
6
- const TAG_PREFIX = '__typedsocket_tag__';
7
- const textEncoder = new TextEncoder();
8
- export const TYPEDSOCKET_MAX_TEXT_FRAME_BYTES = 1024 * 1024;
9
- export const TYPEDSOCKET_MAX_QUEUED_TEXT_FRAMES = 64;
10
- export const TYPEDSOCKET_MAX_QUEUED_TEXT_BYTES = 4 * 1024 * 1024;
11
- export const TYPEDSOCKET_MAX_CONCURRENT_CLIENT_HANDLERS = 16;
12
- export const TYPEDSOCKET_MAX_RETAINED_CLIENT_CALLBACKS = 64;
13
- export const TYPEDSOCKET_MAX_PENDING_CLIENT_REQUESTS = 1024;
14
- export const TYPEDSOCKET_MAX_OUTBOUND_BUFFERED_BYTES = 4 * 1024 * 1024;
15
- export const TYPEDSOCKET_MAX_METHOD_NAME_BYTES = 256;
16
- export const TYPEDSOCKET_MAX_CORRELATION_ID_BYTES = 256;
17
- export const TYPEDSOCKET_MAX_REQUEST_TIMEOUT_MS = 5 * 60 * 1000;
18
- export const TYPEDSOCKET_MAX_CONNECTION_RESTORE_TIMEOUT_MS = 10_000;
19
- export const TYPEDSOCKET_MAX_RECONNECT_RETRIES = 100;
20
- export const TYPEDSOCKET_MAX_RECONNECT_BACKOFF_MS = 60_000;
21
- export const TYPEDSOCKET_MAX_RETAINED_CLIENT_TAG_MUTATIONS_PER_NAME = 8;
22
- export const TYPEDSOCKET_MAX_RETAINED_CLIENT_TAG_MUTATIONS = 64;
23
- export const TYPEDSOCKET_MAX_PENDING_SERVER_REQUESTS_PER_PEER = 64;
24
- export const TYPEDSOCKET_MAX_PENDING_SERVER_REQUESTS = 1024;
25
- export const TYPEDSOCKET_MAX_RETAINED_SERVER_INTERESTS_PER_PEER = 8;
26
- export const TYPEDSOCKET_MAX_RETAINED_SERVER_INTERESTS = 64;
27
- export class TypedSocketConnectionRestoreDeniedError extends Error {
28
- constructor(messageArg) {
29
- super(messageArg);
30
- this.name = 'TypedSocketConnectionRestoreDeniedError';
31
- }
32
- }
33
- /**
34
- * Creates a typed connection wrapper around one IWebSocketPeer.
35
- */
36
- function wrapSmartServePeer(peer) {
37
- return {
38
- peer,
39
- async getTagById(tagId) {
40
- if (!peer.tags.has(tagId)) {
41
- return undefined;
42
- }
43
- const payload = peer.data.get(`${TAG_PREFIX}${tagId}`);
44
- return { id: tagId, payload };
45
- },
46
- };
47
- }
48
- function composeAbortSignals(configuredSignalArg, requestSignalArg) {
49
- if (!configuredSignalArg || configuredSignalArg === requestSignalArg) {
50
- return {
51
- signal: requestSignalArg ?? configuredSignalArg,
52
- cleanup: () => { },
53
- };
54
- }
55
- if (!requestSignalArg) {
56
- return {
57
- signal: configuredSignalArg,
58
- cleanup: () => { },
59
- };
60
- }
61
- const abortController = new AbortController();
62
- const configuredAbortListener = () => {
63
- abortController.abort(configuredSignalArg.reason);
64
- };
65
- const requestAbortListener = () => {
66
- abortController.abort(requestSignalArg.reason);
67
- };
68
- const cleanup = () => {
69
- configuredSignalArg.removeEventListener('abort', configuredAbortListener);
70
- requestSignalArg.removeEventListener('abort', requestAbortListener);
71
- };
72
- if (configuredSignalArg.aborted) {
73
- configuredAbortListener();
74
- }
75
- else if (requestSignalArg.aborted) {
76
- requestAbortListener();
77
- }
78
- else {
79
- configuredSignalArg.addEventListener('abort', configuredAbortListener, { once: true });
80
- requestSignalArg.addEventListener('abort', requestAbortListener, { once: true });
81
- }
82
- return {
83
- signal: abortController.signal,
84
- cleanup,
85
- };
86
- }
87
- const packageClientLimits = Object.freeze({
88
- textFrameBytes: TYPEDSOCKET_MAX_TEXT_FRAME_BYTES,
89
- queuedTextFrames: TYPEDSOCKET_MAX_QUEUED_TEXT_FRAMES,
90
- queuedTextBytes: TYPEDSOCKET_MAX_QUEUED_TEXT_BYTES,
91
- concurrentHandlers: TYPEDSOCKET_MAX_CONCURRENT_CLIENT_HANDLERS,
92
- retainedCallbacks: TYPEDSOCKET_MAX_RETAINED_CLIENT_CALLBACKS,
93
- pendingRequests: TYPEDSOCKET_MAX_PENDING_CLIENT_REQUESTS,
94
- outboundBufferedBytes: TYPEDSOCKET_MAX_OUTBOUND_BUFFERED_BYTES,
95
- requestTimeoutMs: TYPEDSOCKET_MAX_REQUEST_TIMEOUT_MS,
96
- connectionRestoreTimeoutMs: TYPEDSOCKET_MAX_CONNECTION_RESTORE_TIMEOUT_MS,
97
- });
98
- function normalizeClientLimits(limitsArg) {
99
- const lower = (nameArg, valueArg, maximumArg) => {
100
- const value = valueArg ?? maximumArg;
101
- if (!Number.isSafeInteger(value) || value < 1 || value > maximumArg) {
102
- throw new RangeError(`TypedSocket client limit ${nameArg} must be a positive safe integer no greater than ${maximumArg}.`);
103
- }
104
- return value;
105
- };
106
- const normalized = {
107
- textFrameBytes: lower('textFrameBytes', limitsArg?.textFrameBytes, packageClientLimits.textFrameBytes),
108
- queuedTextFrames: lower('queuedTextFrames', limitsArg?.queuedTextFrames, packageClientLimits.queuedTextFrames),
109
- queuedTextBytes: lower('queuedTextBytes', limitsArg?.queuedTextBytes, packageClientLimits.queuedTextBytes),
110
- concurrentHandlers: lower('concurrentHandlers', limitsArg?.concurrentHandlers, packageClientLimits.concurrentHandlers),
111
- retainedCallbacks: lower('retainedCallbacks', limitsArg?.retainedCallbacks, packageClientLimits.retainedCallbacks),
112
- pendingRequests: lower('pendingRequests', limitsArg?.pendingRequests, packageClientLimits.pendingRequests),
113
- outboundBufferedBytes: lower('outboundBufferedBytes', limitsArg?.outboundBufferedBytes, packageClientLimits.outboundBufferedBytes),
114
- requestTimeoutMs: lower('requestTimeoutMs', limitsArg?.requestTimeoutMs, packageClientLimits.requestTimeoutMs),
115
- connectionRestoreTimeoutMs: lower('connectionRestoreTimeoutMs', limitsArg?.connectionRestoreTimeoutMs, packageClientLimits.connectionRestoreTimeoutMs),
116
- };
117
- if (normalized.queuedTextBytes < normalized.textFrameBytes) {
118
- throw new RangeError('TypedSocket queuedTextBytes must be at least textFrameBytes.');
119
- }
120
- return Object.freeze(normalized);
121
- }
122
- function normalizeReconnectInteger(nameArg, valueArg, defaultArg, maximumArg, allowZeroArg) {
123
- const value = valueArg ?? defaultArg;
124
- if (!Number.isSafeInteger(value)
125
- || value < (allowZeroArg ? 0 : 1)
126
- || value > maximumArg) {
127
- throw new RangeError(`TypedSocket ${nameArg} must be ${allowZeroArg ? 'a non-negative' : 'a positive'} safe integer no greater than ${maximumArg}.`);
128
- }
129
- return value;
130
- }
131
- function isPlainRecord(valueArg) {
132
- if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg))
133
- return false;
134
- const prototype = Object.getPrototypeOf(valueArg);
135
- return prototype === Object.prototype || prototype === null;
136
- }
137
- function isLoopbackHostname(hostnameArg) {
138
- const hostname = hostnameArg.toLowerCase().replace(/^\[(.*)\]$/, '$1');
139
- if (hostname === 'localhost' || hostname.endsWith('.localhost') || hostname === '::1') {
140
- return true;
141
- }
142
- const octets = hostname.split('.');
143
- return octets.length === 4
144
- && octets.every((octetArg) => /^\d{1,3}$/.test(octetArg) && Number(octetArg) <= 255)
145
- && Number(octets[0]) === 127;
146
- }
147
- function assertBoundedTextIdentifier(valueArg, labelArg, maximumBytesArg) {
148
- if (typeof valueArg !== 'string'
149
- || valueArg.length === 0
150
- || textEncoder.encode(valueArg).byteLength > maximumBytesArg) {
151
- throw new Error(`TypedSocket ${labelArg} must be a non-empty string of at most ${maximumBytesArg} UTF-8 bytes.`);
152
- }
153
- }
154
- export class TypedSocket {
155
- // ============================================================================
156
- // STATIC METHODS
157
- // ============================================================================
158
- /**
159
- * Creates a TypedSocket client using native WebSocket.
160
- * Works in both browser and Node.js environments.
161
- *
162
- * @param typedrouterArg - TypedRouter for handling server-initiated requests
163
- * @param serverUrlArg - Server URL (e.g., 'http://localhost:3000' or 'wss://example.com')
164
- * @param options - Connection options
165
- *
166
- * @example
167
- * ```typescript
168
- * const typedRouter = new TypedRouter();
169
- * const client = await TypedSocket.createClient(
170
- * typedRouter,
171
- * 'http://localhost:3000',
172
- * { autoReconnect: true }
173
- * );
174
- * ```
175
- */
176
- static async createClient(typedrouterArg, serverUrlArg, options = {}) {
177
- if (options.autoReconnect !== undefined && typeof options.autoReconnect !== 'boolean') {
178
- throw new TypeError('TypedSocket autoReconnect must be a boolean.');
179
- }
180
- const maxRetries = normalizeReconnectInteger('maxRetries', options.maxRetries, TYPEDSOCKET_MAX_RECONNECT_RETRIES, TYPEDSOCKET_MAX_RECONNECT_RETRIES, true);
181
- const initialBackoffMs = normalizeReconnectInteger('initialBackoffMs', options.initialBackoffMs, 1000, TYPEDSOCKET_MAX_RECONNECT_BACKOFF_MS, false);
182
- const maxBackoffMs = normalizeReconnectInteger('maxBackoffMs', options.maxBackoffMs, TYPEDSOCKET_MAX_RECONNECT_BACKOFF_MS, TYPEDSOCKET_MAX_RECONNECT_BACKOFF_MS, false);
183
- if (initialBackoffMs > maxBackoffMs) {
184
- throw new RangeError('TypedSocket initialBackoffMs must not exceed maxBackoffMs.');
185
- }
186
- const opts = {
187
- autoReconnect: options.autoReconnect ?? true,
188
- maxRetries,
189
- initialBackoffMs,
190
- maxBackoffMs,
191
- abortSignal: options.abortSignal,
192
- nativeByteCapabilityMode: options.nativeByteCapabilityMode ?? 'optional',
193
- limits: normalizeClientLimits(options.limits),
194
- restoreConnection: options.restoreConnection,
195
- };
196
- const typedSocket = new TypedSocket('client', typedrouterArg, opts.nativeByteCapabilityMode);
197
- typedSocket.clientOptions = opts;
198
- typedSocket.serverUrl = serverUrlArg;
199
- typedSocket.currentBackoff = opts.initialBackoffMs;
200
- if (opts.abortSignal?.aborted) {
201
- await typedSocket.stop();
202
- throw typedSocket.createAbortError();
203
- }
204
- if (opts.abortSignal) {
205
- typedSocket.abortSignalListener = () => {
206
- void typedSocket.stop();
207
- };
208
- opts.abortSignal.addEventListener('abort', typedSocket.abortSignalListener, { once: true });
209
- }
210
- try {
211
- await typedSocket.connect();
212
- }
213
- catch (error) {
214
- await typedSocket.stop();
215
- throw error;
216
- }
217
- return typedSocket;
218
- }
219
- /**
220
- * Returns the current window location origin URL.
221
- * Useful in browser environments for connecting to the same origin.
222
- */
223
- static { this.useWindowLocationOriginUrl = () => {
224
- return plugins.smarturl.Smarturl.createFromUrl(globalThis.location.origin).toString();
225
- }; }
226
- /**
227
- * Creates a server-side TypedSocket and composes its private protocol
228
- * handlers into one or more isolated application routers.
229
- *
230
- * Call attachSmartServe() after constructing the SmartServe transport.
231
- */
232
- static createServer(typedRouterOrRoutersArg, optionsArg = {}) {
233
- const typedRouters = Array.isArray(typedRouterOrRoutersArg)
234
- ? [...typedRouterOrRoutersArg]
235
- : [typedRouterOrRoutersArg];
236
- if (typedRouters.length === 0) {
237
- throw new Error('TypedSocket.createServer requires at least one TypedRouter.');
238
- }
239
- if (new Set(typedRouters).size !== typedRouters.length) {
240
- throw new Error('TypedSocket.createServer received the same TypedRouter more than once.');
241
- }
242
- const typedSocket = new TypedSocket('server', typedRouters[0], optionsArg.nativeByteCapabilityMode ?? 'optional', optionsArg.nativeByteAuthorizationAdapter, optionsArg.clientTagPolicy);
243
- const protocolRouter = new plugins.typedrequest.TypedRouter();
244
- TypedSocket.registerProtocolHandlers(protocolRouter, typedSocket);
245
- const protocolMethods = new Set(protocolRouter.getMethodNames());
246
- for (const typedRouter of typedRouters) {
247
- const collision = typedRouter
248
- .getMethodNames()
249
- .find((methodArg) => protocolMethods.has(methodArg));
250
- if (collision) {
251
- throw new Error(`TypedSocket protocol handler collides with application method "${collision}".`);
252
- }
253
- }
254
- const detachProtocolRouters = [];
255
- const detachLegacyPolicies = [];
256
- try {
257
- for (const typedRouter of typedRouters) {
258
- detachProtocolRouters.push(typedRouter.addFallbackRouter(protocolRouter));
259
- detachLegacyPolicies.push(typedRouter.registerLegacyVirtualStreamPolicy('deny'));
260
- }
261
- }
262
- catch (error) {
263
- for (const detachLegacyPolicy of detachLegacyPolicies.reverse()) {
264
- detachLegacyPolicy();
265
- }
266
- for (const detachProtocolRouter of detachProtocolRouters.reverse()) {
267
- detachProtocolRouter();
268
- }
269
- throw error;
270
- }
271
- typedSocket.serverTypedRouters = typedRouters;
272
- typedSocket.detachProtocolRouters = detachProtocolRouters;
273
- typedSocket.detachLegacyVirtualStreamPolicies = detachLegacyPolicies;
274
- return typedSocket;
275
- }
276
- /**
277
- * Creates and attaches a TypedSocket server to an existing SmartServe
278
- * instance. Prefer createServer() plus attachSmartServe() when transport
279
- * construction needs the composed routers first.
280
- *
281
- * @param smartServeArg - SmartServe instance configured with the application router
282
- * @param typedRouterArg - Application TypedRouter used by SmartServe
283
- *
284
- * @example
285
- * ```typescript
286
- * const typedRouter = new TypedRouter();
287
- * const smartServe = new SmartServe({
288
- * port: 3000,
289
- * websocket: {
290
- * typedRouter
291
- * }
292
- * });
293
- * await smartServe.start();
294
- * const typedSocket = TypedSocket.fromSmartServe(smartServe, typedRouter);
295
- * // Authenticated server handlers assign protected connection metadata with:
296
- * // typedSocket.setServerTag(peer, 'authenticated', { userId });
297
- * ```
298
- */
299
- static fromSmartServe(smartServeArg, typedRouterArg, optionsArg = {}) {
300
- const typedSocket = TypedSocket.createServer(typedRouterArg, optionsArg);
301
- try {
302
- return typedSocket.attachSmartServe(smartServeArg);
303
- }
304
- catch (errorArg) {
305
- typedSocket.releaseServerComposition();
306
- throw errorArg;
307
- }
308
- }
309
- /**
310
- * Registers built-in TypedHandlers for tag management
311
- */
312
- static registerProtocolHandlers(typedRouter, typedSocketArg) {
313
- typedRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('__typedsocket_setTag', async (data, meta) => {
314
- const peer = typedSocketArg.findServerPeerFromRequest(meta);
315
- return typedSocketArg.tagPolicyManager.setClientTag(peer, data?.name, data?.payload);
316
- }));
317
- typedRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('__typedsocket_removeTag', async (data, meta) => {
318
- const peer = typedSocketArg.findServerPeerFromRequest(meta);
319
- return typedSocketArg.tagPolicyManager.removeClientTag(peer, data?.name);
320
- }));
321
- typedRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('__typedsocket_negotiateCapabilities', async (data, meta) => {
322
- const peer = typedSocketArg.findServerPeerFromRequest(meta);
323
- if (!peer || !Array.isArray(data.capabilities)) {
324
- return {
325
- protocolMajor: NATIVE_BYTE_PROTOCOL_MAJOR,
326
- capabilities: [],
327
- required: false,
328
- };
329
- }
330
- const response = typedSocketArg.nativeBytes.negotiateServerPeer(peer, {
331
- protocolMajor: data.protocolMajor,
332
- capabilities: data.capabilities,
333
- });
334
- return {
335
- protocolMajor: response.protocolMajor,
336
- capabilities: [...response.capabilities],
337
- required: response.required,
338
- };
339
- }));
340
- }
341
- // ============================================================================
342
- // CONSTRUCTOR
343
- // ============================================================================
344
- constructor(sideArg, typedrouterArg, nativeByteCapabilityModeArg = 'optional', nativeByteAuthorizationAdapterArg, clientTagPolicyArg) {
345
- // Connection status observable
346
- this.statusSubject = new plugins.smartrx.rxjs.Subject();
347
- this.connectionStatus = 'new';
348
- // Client-specific properties
349
- this.websocket = null;
350
- this.connectionGeneration = 0;
351
- this.clientConnectionState = null;
352
- this.retainedClientCallbacks = 0;
353
- this.clientOptions = null;
354
- this.serverUrl = '';
355
- this.retryCount = 0;
356
- this.currentBackoff = 1000;
357
- this.stopped = false;
358
- this.stopListeners = new Set();
359
- this.pendingRequests = new Map();
360
- // Acknowledged state is diagnostic state for the current server connection.
361
- this.clientTags = new Map();
362
- this.clientTagRevisions = new Map();
363
- // Desired state survives transport failure and is reconciled on every connection.
364
- this.desiredClientTags = new Map();
365
- this.clientTagDesiredMutationQueues = new Map();
366
- this.clientTagMutationSequence = 0;
367
- this.clientTagMutationTails = new Map();
368
- this.retainedClientTagMutations = 0;
369
- this.retainedClientTagMutationsByName = new Map();
370
- // Server-specific properties (SmartServe mode)
371
- this.smartServeRef = null;
372
- this.serverTypedRouters = [];
373
- this.detachProtocolRouters = [];
374
- this.detachLegacyVirtualStreamPolicies = [];
375
- this.serverStopping = false;
376
- this.serverLifecycleGeneration = 0;
377
- this.unsubscribeSmartServeConnectionClose = null;
378
- this.detachNativeStreamResolvers = [];
379
- this.detachResponseAuthorityGuards = [];
380
- this.pendingServerRequests = new Map();
381
- this.pendingServerRequestIdsByPeer = new Map();
382
- this.retainedServerInterests = 0;
383
- this.retainedServerInterestsByPeer = new Map();
384
- this.side = sideArg;
385
- this.typedrouter = typedrouterArg;
386
- this.nativeBytes = new NativeByteManager({
387
- side: sideArg,
388
- capabilityMode: nativeByteCapabilityModeArg,
389
- });
390
- this.nativeByteAuthorizationAdapter = nativeByteAuthorizationAdapterArg;
391
- this.tagPolicyManager = new TypedSocketTagPolicyManager(clientTagPolicyArg);
392
- this.webSocketTransportOwner = this.nativeBytes.webSocketTransportOwner;
393
- if (sideArg === 'client') {
394
- let detachLegacyPolicy;
395
- let detachNativeStreamResolver;
396
- try {
397
- detachLegacyPolicy = typedrouterArg.registerLegacyVirtualStreamPolicy('deny');
398
- detachNativeStreamResolver = typedrouterArg.registerNativeStreamTransportResolver(() => this.nativeBytes.getClientNativeStreamTransport());
399
- this.detachLegacyVirtualStreamPolicies.push(detachLegacyPolicy);
400
- this.detachNativeStreamResolvers.push(detachNativeStreamResolver);
401
- }
402
- catch (errorArg) {
403
- detachNativeStreamResolver?.();
404
- detachLegacyPolicy?.();
405
- throw errorArg;
406
- }
407
- }
408
- }
409
- /**
410
- * Attaches the SmartServe transport after server router composition.
411
- */
412
- attachSmartServe(smartServeArg) {
413
- if (this.side !== 'server') {
414
- throw new Error('attachSmartServe is only available on servers.');
415
- }
416
- if (this.serverStopping) {
417
- throw new Error('Cannot attach SmartServe after the TypedSocket server has stopped.');
418
- }
419
- if (this.smartServeRef) {
420
- if (this.smartServeRef === smartServeArg) {
421
- return this;
422
- }
423
- throw new Error('TypedSocket server is already attached to a SmartServe instance.');
424
- }
425
- const detachResolvers = [];
426
- const detachResponseGuards = [];
427
- let unsubscribe;
428
- let nativeServerAttached = false;
429
- try {
430
- for (const typedRouter of this.serverTypedRouters) {
431
- detachResponseGuards.push(typedRouter.registerIncomingResponseAuthorityGuard((responseArg, contextArg) => {
432
- return this.authorizeIncomingServerResponse(responseArg, contextArg.typedRouter, contextArg.trustedLocalData);
433
- }));
434
- detachResolvers.push(typedRouter.registerNativeStreamTransportResolver((trustedLocalDataArg) => {
435
- const peer = this.smartServeRef
436
- ?.getWebSocketConnections()
437
- .find((peerArg) => peerArg === trustedLocalDataArg.peer);
438
- return peer ? this.nativeBytes.getServerNativeStreamTransport(peer) : undefined;
439
- }));
440
- }
441
- unsubscribe = smartServeArg.subscribeWebSocketConnectionClose((peerArg) => {
442
- this.tagPolicyManager.handlePeerClose(peerArg);
443
- this.cancelPendingServerRequestsForPeer(peerArg, new Error(`TypedSocket target connection closed: ${peerArg.id}`));
444
- });
445
- this.nativeBytes.attachServer();
446
- nativeServerAttached = true;
447
- this.serverLifecycleGeneration++;
448
- this.tagPolicyManager.setAttachedPeersProvider(() => smartServeArg.getWebSocketConnections().filter((peerArg) => {
449
- const routingSurface = peerArg.routingSurface;
450
- return Boolean(routingSurface && this.serverTypedRouters.includes(routingSurface));
451
- }));
452
- this.smartServeRef = smartServeArg;
453
- this.detachNativeStreamResolvers = detachResolvers;
454
- this.detachResponseAuthorityGuards = detachResponseGuards;
455
- this.unsubscribeSmartServeConnectionClose = unsubscribe;
456
- return this;
457
- }
458
- catch (errorArg) {
459
- unsubscribe?.();
460
- if (nativeServerAttached) {
461
- this.nativeBytes.detachServer();
462
- }
463
- this.tagPolicyManager.setAttachedPeersProvider(undefined);
464
- for (const detachResponseGuard of detachResponseGuards.reverse())
465
- detachResponseGuard();
466
- for (const detachResolver of detachResolvers.reverse())
467
- detachResolver();
468
- throw errorArg;
469
- }
470
- }
471
- // ============================================================================
472
- // CLIENT METHODS
473
- // ============================================================================
474
- /**
475
- * Connects the client to the server using native WebSocket
476
- */
477
- async connect() {
478
- if (this.stopped || this.clientOptions?.abortSignal?.aborted) {
479
- throw this.createAbortError();
480
- }
481
- const done = plugins.smartpromise.defer();
482
- let connectionSettled = false;
483
- let connectionTimeout;
484
- let abortConnection;
485
- const settleConnection = (errorArg) => {
486
- if (connectionSettled) {
487
- return;
488
- }
489
- connectionSettled = true;
490
- if (connectionTimeout) {
491
- clearTimeout(connectionTimeout);
492
- }
493
- if (abortConnection) {
494
- this.stopListeners.delete(abortConnection);
495
- this.clientOptions?.abortSignal?.removeEventListener('abort', abortConnection);
496
- }
497
- if (errorArg) {
498
- done.reject(errorArg);
499
- }
500
- else {
501
- done.resolve();
502
- }
503
- };
504
- this.updateStatus('connecting');
505
- const wsUrl = this.toWebSocketUrl(this.serverUrl);
506
- const logEndpoint = this.toRedactedLogEndpoint(wsUrl);
507
- this.logDebug(`TypedSocket connecting to ${logEndpoint}...`);
508
- if (this.clientConnectionState) {
509
- this.abortClientConnectionState(this.clientConnectionState, new Error('TypedSocket connection replaced'));
510
- }
511
- const generation = ++this.connectionGeneration;
512
- const websocket = new WebSocket(wsUrl);
513
- websocket.binaryType = 'arraybuffer';
514
- this.websocket = websocket;
515
- const connectionState = {
516
- generation,
517
- connectionId: plugins.smartstring.create.createCryptoRandomString(),
518
- websocket,
519
- abortController: new AbortController(),
520
- queuedTextFrames: [],
521
- queuedTextBytes: 0,
522
- activeHandlers: 0,
523
- };
524
- this.clientConnectionState = connectionState;
525
- this.nativeBytes.bindClientConnection(websocket, generation);
526
- abortConnection = () => {
527
- if (this.websocket === websocket && this.connectionGeneration === generation) {
528
- websocket.close();
529
- }
530
- settleConnection(this.createAbortError());
531
- };
532
- this.stopListeners.add(abortConnection);
533
- this.clientOptions?.abortSignal?.addEventListener('abort', abortConnection, { once: true });
534
- connectionTimeout = setTimeout(() => {
535
- if (this.connectionStatus !== 'connected') {
536
- this.logTransient(`TypedSocket connection timeout for ${logEndpoint}`);
537
- if (this.websocket === websocket && this.connectionGeneration === generation) {
538
- websocket.close();
539
- }
540
- settleConnection(new Error('Connection timeout'));
541
- }
542
- }, 10000);
543
- websocket.onopen = async () => {
544
- try {
545
- if (this.websocket !== websocket || this.connectionGeneration !== generation)
546
- return;
547
- await this.negotiateClientCapabilities(websocket, generation);
548
- if (this.websocket !== websocket || this.connectionGeneration !== generation)
549
- return;
550
- await this.restoreClientConnection(connectionState);
551
- if (this.websocket !== websocket || this.connectionGeneration !== generation)
552
- return;
553
- await this.reapplyClientTags(connectionState);
554
- if (this.websocket !== websocket
555
- || this.connectionGeneration !== generation
556
- || websocket.readyState !== WebSocket.OPEN) {
557
- throw new Error('TypedSocket connection changed while restoring client tags');
558
- }
559
- this.logDebug('TypedSocket connected and client registration restored!');
560
- this.retryCount = 0;
561
- this.currentBackoff = this.clientOptions?.initialBackoffMs ?? 1000;
562
- this.updateStatus('connected');
563
- settleConnection();
564
- }
565
- catch (error) {
566
- const restorationError = error instanceof Error
567
- ? error
568
- : new Error(String(error));
569
- this.logTransient('TypedSocket client registration restoration failed.');
570
- settleConnection(restorationError);
571
- websocket.close();
572
- }
573
- };
574
- websocket.onmessage = (event) => {
575
- if (this.websocket !== websocket || this.connectionGeneration !== generation)
576
- return;
577
- if (typeof event.data === 'string') {
578
- this.enqueueClientTextFrame(connectionState, event.data);
579
- return;
580
- }
581
- if (event.data instanceof ArrayBuffer || ArrayBuffer.isView(event.data)) {
582
- this.nativeBytes.enqueueClientRawFrame(websocket, generation, event.data);
583
- return;
584
- }
585
- websocket.close(1003, 'Unsupported WebSocket payload');
586
- };
587
- websocket.onclose = () => {
588
- if (this.websocket !== websocket || this.connectionGeneration !== generation)
589
- return;
590
- this.abortClientConnectionState(connectionState, new Error('TypedSocket disconnected'));
591
- this.nativeBytes.unbindClientConnection(websocket, generation, new Error('TypedSocket disconnected'));
592
- if (this.connectionStatus === 'connected') {
593
- this.handleDisconnect();
594
- }
595
- else {
596
- this.rejectPendingClientRequests(new Error('TypedSocket disconnected'));
597
- settleConnection(this.stopped || this.clientOptions?.abortSignal?.aborted
598
- ? this.createAbortError()
599
- : new Error('TypedSocket connection closed before it opened'));
600
- }
601
- };
602
- websocket.onerror = () => {
603
- if (this.websocket !== websocket || this.connectionGeneration !== generation)
604
- return;
605
- // transient socket errors (network blips, proxy TLS hiccups) are expected
606
- // and handled by reconnection; only exhausted retries surface as errors
607
- this.logTransient(`TypedSocket websocket error on ${logEndpoint}`);
608
- };
609
- try {
610
- await done.promise;
611
- }
612
- catch (err) {
613
- if (connectionTimeout) {
614
- clearTimeout(connectionTimeout);
615
- }
616
- if (!(err instanceof NativeByteCapabilityError)
617
- && !(err instanceof TypedSocketClientTagDeniedError)
618
- && !(err instanceof TypedSocketConnectionRestoreDeniedError)
619
- && this.shouldReconnect()) {
620
- await this.scheduleReconnect();
621
- if (this.connectionStatus !== 'connected') {
622
- throw this.stopped || this.clientOptions?.abortSignal?.aborted ? this.createAbortError() : err;
623
- }
624
- }
625
- else {
626
- throw err;
627
- }
628
- }
629
- }
630
- async negotiateClientCapabilities(websocketArg, generationArg) {
631
- const advertisement = this.nativeBytes.getClientNegotiationAdvertisement();
632
- let negotiatedResponse;
633
- try {
634
- const request = {
635
- method: '__typedsocket_negotiateCapabilities',
636
- request: {
637
- protocolMajor: advertisement.protocolMajor,
638
- capabilities: [...advertisement.capabilities],
639
- },
640
- response: {
641
- protocolMajor: 0,
642
- capabilities: [],
643
- required: false,
644
- },
645
- };
646
- const response = await this.sendRequest(request, {
647
- timeoutMs: Math.min(10_000, this.requireClientOptions().limits.requestTimeoutMs),
648
- });
649
- if (response.error)
650
- throw new NativeByteCapabilityError(response.error.text);
651
- if (!response.response
652
- || !Number.isSafeInteger(response.response.protocolMajor)
653
- || !Array.isArray(response.response.capabilities)
654
- || response.response.capabilities.some((capabilityArg) => typeof capabilityArg !== 'string')
655
- || typeof response.response.required !== 'boolean') {
656
- throw new NativeByteCapabilityError('TypedSocket server returned malformed capabilities');
657
- }
658
- negotiatedResponse = response.response;
659
- }
660
- catch (errorArg) {
661
- if (this.clientOptions?.nativeByteCapabilityMode === 'required') {
662
- throw errorArg instanceof NativeByteCapabilityError
663
- ? errorArg
664
- : new NativeByteCapabilityError('Required native-byte-v1 negotiation failed', {
665
- cause: errorArg,
666
- });
667
- }
668
- this.nativeBytes.failOptionalClientNegotiation(websocketArg, generationArg);
669
- return;
670
- }
671
- if (negotiatedResponse.required
672
- && (negotiatedResponse.protocolMajor !== NATIVE_BYTE_PROTOCOL_MAJOR
673
- || negotiatedResponse.capabilities.length !== 1
674
- || negotiatedResponse.capabilities[0] !== NATIVE_BYTE_PROTOCOL
675
- || this.clientOptions?.nativeByteCapabilityMode === 'disabled')) {
676
- throw new NativeByteCapabilityError('TypedSocket server requires native-byte-v1');
677
- }
678
- this.nativeBytes.completeClientNegotiation(websocketArg, generationArg, negotiatedResponse);
679
- }
680
- async restoreClientConnection(stateArg) {
681
- const restoreConnection = this.clientOptions?.restoreConnection;
682
- if (!restoreConnection)
683
- return;
684
- const limits = this.requireClientOptions().limits;
685
- if (this.retainedClientCallbacks >= limits.retainedCallbacks) {
686
- throw new TypedSocketConnectionRestoreDeniedError('TypedSocket connection restoration callback capacity exhausted.');
687
- }
688
- const timeoutMs = limits.connectionRestoreTimeoutMs;
689
- const deadline = Date.now() + timeoutMs;
690
- const restorationAbortController = new AbortController();
691
- const interruptRestoration = () => {
692
- restorationAbortController.abort(new TypedSocketConnectionRestoreDeniedError('TypedSocket connection restoration was interrupted.'));
693
- };
694
- stateArg.abortController.signal.addEventListener('abort', interruptRestoration, { once: true });
695
- if (stateArg.abortController.signal.aborted)
696
- interruptRestoration();
697
- const createTypedRequest = (methodNameArg) => {
698
- if (restorationAbortController.signal.aborted) {
699
- throw new TypedSocketConnectionRestoreDeniedError('TypedSocket connection restoration request was interrupted.');
700
- }
701
- const remainingMs = deadline - Date.now();
702
- if (!Number.isSafeInteger(remainingMs) || remainingMs < 1) {
703
- throw new TypedSocketConnectionRestoreDeniedError('TypedSocket connection restoration request exceeded its deadline.');
704
- }
705
- return this.createTypedRequest(methodNameArg, undefined, {
706
- timeoutMs: Math.min(remainingMs + 1, limits.requestTimeoutMs),
707
- abortSignal: restorationAbortController.signal,
708
- });
709
- };
710
- this.retainedClientCallbacks++;
711
- const callbackOutcome = Promise.resolve().then(() => restoreConnection(Object.freeze({
712
- connectionId: stateArg.connectionId,
713
- abortSignal: restorationAbortController.signal,
714
- deadline,
715
- createTypedRequest,
716
- })));
717
- void callbackOutcome.then(() => { this.retainedClientCallbacks--; }, () => { this.retainedClientCallbacks--; });
718
- let timeout;
719
- let abortListener;
720
- const interrupted = new Promise((_resolveArg, rejectArg) => {
721
- timeout = setTimeout(() => {
722
- const error = new TypedSocketConnectionRestoreDeniedError('TypedSocket connection restoration timed out.');
723
- restorationAbortController.abort(error);
724
- rejectArg(error);
725
- }, timeoutMs);
726
- abortListener = () => {
727
- const reason = restorationAbortController.signal.reason;
728
- rejectArg(reason instanceof TypedSocketConnectionRestoreDeniedError
729
- ? reason
730
- : new TypedSocketConnectionRestoreDeniedError('TypedSocket connection restoration was interrupted.'));
731
- };
732
- restorationAbortController.signal.addEventListener('abort', abortListener, { once: true });
733
- if (restorationAbortController.signal.aborted)
734
- abortListener();
735
- });
736
- try {
737
- await Promise.race([callbackOutcome, interrupted]);
738
- }
739
- catch (errorArg) {
740
- if (errorArg instanceof TypedSocketConnectionRestoreDeniedError)
741
- throw errorArg;
742
- throw new TypedSocketConnectionRestoreDeniedError('TypedSocket connection restoration was denied.');
743
- }
744
- finally {
745
- if (timeout)
746
- clearTimeout(timeout);
747
- if (abortListener) {
748
- restorationAbortController.signal.removeEventListener('abort', abortListener);
749
- }
750
- stateArg.abortController.signal.removeEventListener('abort', interruptRestoration);
751
- restorationAbortController.abort(new TypedSocketConnectionRestoreDeniedError('TypedSocket connection restoration callback completed.'));
752
- }
753
- if (!this.isCurrentClientConnection(stateArg)) {
754
- throw new TypedSocketConnectionRestoreDeniedError('TypedSocket connection changed during restoration.');
755
- }
756
- }
757
- /**
758
- * Converts an HTTP(S) URL to a WebSocket URL
759
- */
760
- toWebSocketUrl(url) {
761
- const parsed = new URL(url);
762
- if (parsed.username || parsed.password) {
763
- throw new Error('TypedSocket server URL must not contain userinfo.');
764
- }
765
- if (parsed.hash) {
766
- throw new Error('TypedSocket server URL must not contain a fragment.');
767
- }
768
- const wsProtocol = (() => {
769
- switch (parsed.protocol) {
770
- case 'http:':
771
- case 'ws:':
772
- return 'ws:';
773
- case 'https:':
774
- case 'wss:':
775
- return 'wss:';
776
- default:
777
- throw new Error('TypedSocket server URL must use http, https, ws, or wss.');
778
- }
779
- })();
780
- if (wsProtocol === 'ws:' && !isLoopbackHostname(parsed.hostname)) {
781
- throw new Error('TypedSocket insecure WebSocket transport is restricted to loopback hosts.');
782
- }
783
- parsed.protocol = wsProtocol;
784
- return parsed.toString();
785
- }
786
- toRedactedLogEndpoint(urlArg) {
787
- const parsed = new URL(urlArg);
788
- return `${parsed.protocol}//${parsed.host}`;
789
- }
790
- enqueueClientTextFrame(stateArg, textArg) {
791
- if (!this.isCurrentClientConnection(stateArg))
792
- return;
793
- const limits = this.requireClientOptions().limits;
794
- const byteLength = textEncoder.encode(textArg).byteLength;
795
- if (byteLength > limits.textFrameBytes) {
796
- stateArg.websocket.close(1009, 'TypedSocket text frame exceeds package limit');
797
- return;
798
- }
799
- if (stateArg.queuedTextFrames.length >= limits.queuedTextFrames
800
- || stateArg.queuedTextBytes + byteLength > limits.queuedTextBytes) {
801
- stateArg.websocket.close(1008, 'TypedSocket text queue exceeds package limit');
802
- return;
803
- }
804
- stateArg.queuedTextFrames.push({ text: textArg, byteLength });
805
- stateArg.queuedTextBytes += byteLength;
806
- this.drainClientTextFrames(stateArg);
807
- }
808
- drainClientTextFrames(stateArg) {
809
- const limits = this.requireClientOptions().limits;
810
- while (this.isCurrentClientConnection(stateArg)
811
- && !stateArg.abortController.signal.aborted
812
- && stateArg.queuedTextFrames.length > 0
813
- && stateArg.activeHandlers < limits.concurrentHandlers) {
814
- if (this.retainedClientCallbacks >= limits.retainedCallbacks) {
815
- stateArg.websocket.close(1013, 'TypedSocket callback capacity exhausted');
816
- return;
817
- }
818
- const frame = stateArg.queuedTextFrames.shift();
819
- if (!frame)
820
- return;
821
- stateArg.queuedTextBytes -= frame.byteLength;
822
- stateArg.activeHandlers++;
823
- this.retainedClientCallbacks++;
824
- void this.handleMessage(frame.text, stateArg)
825
- .catch(() => {
826
- if (this.isCurrentClientConnection(stateArg)) {
827
- stateArg.websocket.close(1008, 'TypedSocket rejected malformed text envelope');
828
- }
829
- })
830
- .finally(() => {
831
- stateArg.activeHandlers--;
832
- this.retainedClientCallbacks--;
833
- this.drainClientTextFrames(stateArg);
834
- });
835
- }
836
- }
837
- assertClientEnvelope(valueArg) {
838
- if (!isPlainRecord(valueArg) || Object.hasOwn(valueArg, 'localData')) {
839
- throw new Error('TypedSocket received an invalid text envelope.');
840
- }
841
- assertBoundedTextIdentifier(valueArg.method, 'method', TYPEDSOCKET_MAX_METHOD_NAME_BYTES);
842
- const correlation = valueArg.correlation;
843
- if (!isPlainRecord(correlation)) {
844
- throw new Error('TypedSocket received an invalid correlation envelope.');
845
- }
846
- assertBoundedTextIdentifier(correlation.id, 'correlation ID', TYPEDSOCKET_MAX_CORRELATION_ID_BYTES);
847
- if (correlation.phase !== 'request' && correlation.phase !== 'response') {
848
- throw new Error('TypedSocket received an invalid correlation phase.');
849
- }
850
- if (correlation.phase === 'request' && !Object.hasOwn(valueArg, 'request')) {
851
- throw new Error('TypedSocket request envelope has no request payload.');
852
- }
853
- if (correlation.phase === 'response'
854
- && !Object.hasOwn(valueArg, 'response')
855
- && !Object.hasOwn(valueArg, 'error')) {
856
- throw new Error('TypedSocket response envelope has no response or error payload.');
857
- }
858
- }
859
- async handleMessage(dataArg, stateArg = this.clientConnectionState) {
860
- if (!stateArg || !this.isCurrentClientConnection(stateArg))
861
- return;
862
- const message = plugins.smartjson.parse(dataArg);
863
- this.assertClientEnvelope(message);
864
- const correlation = message.correlation;
865
- if (correlation.phase === 'response') {
866
- const pending = this.pendingRequests.get(correlation.id);
867
- if (!pending)
868
- return;
869
- if (pending.connectionGeneration !== stateArg.generation
870
- || pending.expectedMethod !== message.method) {
871
- throw new Error('TypedSocket response authority mismatch.');
872
- }
873
- this.pendingRequests.delete(correlation.id);
874
- pending.resolve(message);
875
- return;
876
- }
877
- const response = await this.typedrouter.routeAndAddResponse(message);
878
- if (!response || !this.isCurrentClientConnection(stateArg))
879
- return;
880
- this.sendClientTextEnvelope(response, stateArg);
881
- }
882
- sendClientTextEnvelope(envelopeArg, stateArg) {
883
- if (!this.isCurrentClientConnection(stateArg)) {
884
- throw new Error('TypedSocket connection changed before text send.');
885
- }
886
- const encoded = plugins.smartjson.stringify(envelopeArg);
887
- const byteLength = textEncoder.encode(encoded).byteLength;
888
- const limits = this.requireClientOptions().limits;
889
- if (byteLength > limits.textFrameBytes) {
890
- throw new Error(`TypedSocket outbound envelope exceeds ${limits.textFrameBytes} UTF-8 bytes.`);
891
- }
892
- if (stateArg.websocket.bufferedAmount + byteLength > limits.outboundBufferedBytes) {
893
- throw new Error('TypedSocket outbound WebSocket buffer capacity exceeded.');
894
- }
895
- stateArg.websocket.send(encoded);
896
- }
897
- isCurrentClientConnection(stateArg) {
898
- return Boolean(this.clientConnectionState === stateArg
899
- && this.websocket === stateArg.websocket
900
- && this.connectionGeneration === stateArg.generation
901
- && stateArg.websocket.readyState === WebSocket.OPEN);
902
- }
903
- abortClientConnectionState(stateArg, reasonArg) {
904
- if (!stateArg.abortController.signal.aborted) {
905
- stateArg.abortController.abort(reasonArg);
906
- }
907
- stateArg.queuedTextFrames.length = 0;
908
- stateArg.queuedTextBytes = 0;
909
- if (this.clientConnectionState === stateArg) {
910
- this.clientConnectionState = null;
911
- }
912
- }
913
- /**
914
- * Handles WebSocket disconnection
915
- */
916
- handleDisconnect() {
917
- if (this.connectionStatus === 'disconnected') {
918
- return; // Already handled
919
- }
920
- this.updateStatus('disconnected');
921
- // Reject all pending requests — the connection is gone and they'll never receive a response
922
- this.rejectPendingClientRequests(new Error('TypedSocket disconnected'));
923
- if (this.shouldReconnect()) {
924
- this.scheduleReconnect();
925
- }
926
- }
927
- /**
928
- * Schedules a reconnection attempt with exponential backoff
929
- */
930
- async scheduleReconnect() {
931
- if (!this.shouldReconnect())
932
- return;
933
- const clientOptions = this.requireClientOptions();
934
- this.updateStatus('reconnecting');
935
- this.retryCount++;
936
- // Exponential backoff with jitter
937
- const jitter = this.currentBackoff * 0.2 * (Math.random() * 2 - 1);
938
- const delay = Math.min(this.currentBackoff + jitter, clientOptions.maxBackoffMs);
939
- this.logDebug(`TypedSocket reconnecting in ${Math.round(delay)}ms (attempt ${this.retryCount}/${clientOptions.maxRetries})`);
940
- await this.waitForReconnectDelay(delay);
941
- if (!this.shouldReconnect())
942
- return;
943
- // Increase backoff for next time
944
- this.currentBackoff = Math.min(this.currentBackoff * 2, clientOptions.maxBackoffMs);
945
- try {
946
- await this.connect();
947
- }
948
- catch {
949
- if (this.shouldReconnect()) {
950
- this.logDebug('TypedSocket reconnection attempt failed.');
951
- }
952
- else if (!this.stopped && !this.clientOptions?.abortSignal?.aborted) {
953
- const endpoint = this.toRedactedLogEndpoint(this.toWebSocketUrl(this.serverUrl));
954
- console.error(`TypedSocket giving up on ${endpoint} after ${this.retryCount} attempts.`);
955
- }
956
- }
957
- }
958
- /**
959
- * Lifecycle chatter: hidden by default in browser devtools (verbose level)
960
- * and irrelevant for servers, but available when debugging.
961
- */
962
- logDebug(messageArg) {
963
- console.debug(messageArg);
964
- }
965
- /**
966
- * Failures that reconnection is expected to recover from. Logged as debug
967
- * while retries remain; the final failure is reported by scheduleReconnect.
968
- */
969
- logTransient(messageArg) {
970
- if (this.shouldReconnect()) {
971
- this.logDebug(messageArg);
972
- }
973
- else if (!this.stopped && !this.clientOptions?.abortSignal?.aborted) {
974
- console.warn(messageArg);
975
- }
976
- }
977
- shouldReconnect() {
978
- return Boolean(this.clientOptions?.autoReconnect &&
979
- !this.stopped &&
980
- !this.clientOptions.abortSignal?.aborted &&
981
- this.retryCount < this.clientOptions.maxRetries);
982
- }
983
- async waitForReconnectDelay(delayMsArg) {
984
- await new Promise((resolve) => {
985
- let timeout;
986
- let finished = false;
987
- const finish = () => {
988
- if (finished)
989
- return;
990
- finished = true;
991
- if (timeout) {
992
- clearTimeout(timeout);
993
- }
994
- this.stopListeners.delete(finish);
995
- this.clientOptions?.abortSignal?.removeEventListener('abort', finish);
996
- resolve();
997
- };
998
- if (this.clientOptions?.abortSignal?.aborted) {
999
- finish();
1000
- return;
1001
- }
1002
- if (this.stopped) {
1003
- finish();
1004
- return;
1005
- }
1006
- timeout = setTimeout(finish, delayMsArg);
1007
- this.stopListeners.add(finish);
1008
- this.clientOptions?.abortSignal?.addEventListener('abort', finish, { once: true });
1009
- });
1010
- }
1011
- createAbortError() {
1012
- return new Error('TypedSocket client startup aborted');
1013
- }
1014
- rejectPendingClientRequests(errorArg) {
1015
- for (const pending of this.pendingRequests.values()) {
1016
- pending.reject(errorArg);
1017
- }
1018
- this.pendingRequests.clear();
1019
- }
1020
- /**
1021
- * Updates connection status and notifies subscribers
1022
- */
1023
- updateStatus(status) {
1024
- if (this.connectionStatus !== status) {
1025
- this.connectionStatus = status;
1026
- this.statusSubject.next(status);
1027
- }
1028
- }
1029
- /**
1030
- * Sends a request to the server and waits for response (client-side)
1031
- */
1032
- async sendRequest(request, optionsArg = {}) {
1033
- if (request.method === '##VirtualStream##') {
1034
- throw new Error('Legacy VirtualStream control request rejected by transport policy');
1035
- }
1036
- const state = this.clientConnectionState;
1037
- if (!state || !this.isCurrentClientConnection(state)) {
1038
- throw new Error('WebSocket not connected');
1039
- }
1040
- const timeoutMs = this.normalizeRequestTimeout(optionsArg.timeoutMs);
1041
- if (optionsArg.abortSignal?.aborted) {
1042
- throw new Error('TypedSocket request aborted');
1043
- }
1044
- request.correlation ||= {
1045
- id: plugins.smartstring.create.createCryptoRandomString(),
1046
- phase: 'request',
1047
- };
1048
- assertBoundedTextIdentifier(request.method, 'method', TYPEDSOCKET_MAX_METHOD_NAME_BYTES);
1049
- assertBoundedTextIdentifier(request.correlation.id, 'correlation ID', TYPEDSOCKET_MAX_CORRELATION_ID_BYTES);
1050
- if (request.correlation.phase !== 'request') {
1051
- throw new Error('TypedSocket outbound requests require request correlation phase.');
1052
- }
1053
- const correlationId = request.correlation.id;
1054
- if (this.pendingRequests.has(correlationId)) {
1055
- throw new Error(`Duplicate in-flight TypedSocket correlation ID: ${correlationId}`);
1056
- }
1057
- if (this.pendingRequests.size >= this.requireClientOptions().limits.pendingRequests) {
1058
- throw new Error('TypedSocket pending client request capacity exceeded.');
1059
- }
1060
- return new Promise((resolve, reject) => {
1061
- let settled = false;
1062
- const cleanup = () => {
1063
- clearTimeout(timeout);
1064
- optionsArg.abortSignal?.removeEventListener('abort', onAbort);
1065
- this.pendingRequests.delete(correlationId);
1066
- };
1067
- const settle = (errorArg, responseArg) => {
1068
- if (settled) {
1069
- return;
1070
- }
1071
- settled = true;
1072
- cleanup();
1073
- if (errorArg) {
1074
- reject(errorArg);
1075
- }
1076
- else if (!responseArg) {
1077
- reject(new Error('TypedSocket request settled without a response.'));
1078
- }
1079
- else {
1080
- resolve(responseArg);
1081
- }
1082
- };
1083
- const onAbort = () => settle(new Error('TypedSocket request aborted'));
1084
- const timeout = setTimeout(() => {
1085
- settle(new Error('TypedSocket request timed out'));
1086
- }, timeoutMs);
1087
- this.pendingRequests.set(correlationId, {
1088
- expectedMethod: request.method,
1089
- connectionGeneration: state.generation,
1090
- resolve: (response) => {
1091
- request.response = response.response;
1092
- request.correlation = response.correlation;
1093
- if (response.error)
1094
- request.error = response.error;
1095
- else
1096
- delete request.error;
1097
- if (response.retry)
1098
- request.retry = response.retry;
1099
- else
1100
- delete request.retry;
1101
- settle(undefined, request);
1102
- },
1103
- reject: (error) => {
1104
- settle(error);
1105
- },
1106
- });
1107
- optionsArg.abortSignal?.addEventListener('abort', onAbort, { once: true });
1108
- if (optionsArg.abortSignal?.aborted) {
1109
- onAbort();
1110
- return;
1111
- }
1112
- try {
1113
- this.sendClientTextEnvelope(request, state);
1114
- }
1115
- catch (error) {
1116
- settle(error instanceof Error ? error : new Error(String(error)));
1117
- }
1118
- });
1119
- }
1120
- normalizeRequestTimeout(timeoutMsArg) {
1121
- const maximum = this.clientOptions?.limits.requestTimeoutMs
1122
- ?? TYPEDSOCKET_MAX_REQUEST_TIMEOUT_MS;
1123
- const timeoutMs = timeoutMsArg ?? Math.min(30_000, maximum);
1124
- if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > maximum) {
1125
- throw new Error(`TypedSocket request timeout must be a positive safe integer no greater than ${maximum}.`);
1126
- }
1127
- return timeoutMs;
1128
- }
1129
- requireClientOptions() {
1130
- if (!this.clientOptions) {
1131
- throw new Error('TypedSocket client options are unavailable on this instance.');
1132
- }
1133
- return this.clientOptions;
1134
- }
1135
- cancelPendingServerRequestsForPeer(peerArg, errorArg) {
1136
- const correlationIds = this.pendingServerRequestIdsByPeer.get(peerArg);
1137
- if (!correlationIds) {
1138
- return;
1139
- }
1140
- for (const correlationId of Array.from(correlationIds)) {
1141
- this.pendingServerRequests.get(correlationId)?.cancel(errorArg);
1142
- }
1143
- }
1144
- retainServerInterestRegistration(peerArg) {
1145
- const retainedForPeer = this.retainedServerInterestsByPeer.get(peerArg) ?? 0;
1146
- if (retainedForPeer >= TYPEDSOCKET_MAX_RETAINED_SERVER_INTERESTS_PER_PEER
1147
- || this.retainedServerInterests >= TYPEDSOCKET_MAX_RETAINED_SERVER_INTERESTS) {
1148
- throw new Error('TypedSocket server interest registration capacity exceeded.');
1149
- }
1150
- this.retainedServerInterests++;
1151
- this.retainedServerInterestsByPeer.set(peerArg, retainedForPeer + 1);
1152
- let released = false;
1153
- return () => {
1154
- if (released)
1155
- return;
1156
- released = true;
1157
- this.retainedServerInterests--;
1158
- const currentForPeer = this.retainedServerInterestsByPeer.get(peerArg);
1159
- if (currentForPeer === undefined || currentForPeer < 1) {
1160
- throw new Error('TypedSocket server interest registration accounting underflow.');
1161
- }
1162
- if (currentForPeer === 1) {
1163
- this.retainedServerInterestsByPeer.delete(peerArg);
1164
- }
1165
- else {
1166
- this.retainedServerInterestsByPeer.set(peerArg, currentForPeer - 1);
1167
- }
1168
- };
1169
- }
1170
- authorizeIncomingServerResponse(responseArg, routingSurfaceArg, trustedLocalDataArg) {
1171
- if (this.serverStopping
1172
- || !this.smartServeRef
1173
- || responseArg.correlation?.phase !== 'response'
1174
- || typeof responseArg.correlation.id !== 'string'
1175
- || typeof responseArg.method !== 'string') {
1176
- return false;
1177
- }
1178
- const peer = trustedLocalDataArg.peer;
1179
- if (!peer || typeof peer !== 'object')
1180
- return false;
1181
- const pending = this.pendingServerRequests.get(responseArg.correlation.id);
1182
- return Boolean(pending
1183
- && pending.peer === peer
1184
- && pending.routingSurface === routingSurfaceArg
1185
- && pending.expectedMethod === responseArg.method
1186
- && pending.lifecycleGeneration === this.serverLifecycleGeneration
1187
- && pending.peer.routingSurface === routingSurfaceArg
1188
- && this.isAttachedServerPeer(pending.peer));
1189
- }
1190
- isAttachedServerPeer(peerArg) {
1191
- return Boolean(!this.serverStopping
1192
- && this.smartServeRef
1193
- && peerArg.readyState === 1
1194
- && peerArg.routingSurface
1195
- && this.serverTypedRouters.includes(peerArg.routingSurface)
1196
- && this.smartServeRef.getWebSocketConnections().includes(peerArg));
1197
- }
1198
- findServerPeerFromRequest(typedToolsArg) {
1199
- const candidate = typedToolsArg?.localData?.peer;
1200
- const peer = this.smartServeRef
1201
- ?.getWebSocketConnections()
1202
- .find((peerArg) => peerArg === candidate);
1203
- return peer && this.isAttachedServerPeer(peer) ? peer : undefined;
1204
- }
1205
- async sendServerRequest(typedRequestDataArg, targetArg, optionsArg) {
1206
- const timeoutMs = this.normalizeRequestTimeout(optionsArg.timeoutMs);
1207
- if (this.serverStopping || !this.smartServeRef) {
1208
- throw new Error('TypedSocket server stopped');
1209
- }
1210
- if (optionsArg.abortSignal?.aborted) {
1211
- throw new Error('TypedSocket request aborted');
1212
- }
1213
- typedRequestDataArg.correlation ||= {
1214
- id: plugins.smartstring.create.createCryptoRandomString(),
1215
- phase: 'request',
1216
- };
1217
- assertBoundedTextIdentifier(typedRequestDataArg.method, 'method', TYPEDSOCKET_MAX_METHOD_NAME_BYTES);
1218
- assertBoundedTextIdentifier(typedRequestDataArg.correlation.id, 'correlation ID', TYPEDSOCKET_MAX_CORRELATION_ID_BYTES);
1219
- if (typedRequestDataArg.correlation.phase !== 'request') {
1220
- throw new Error('TypedSocket outbound requests require request correlation phase.');
1221
- }
1222
- const correlationId = typedRequestDataArg.correlation.id;
1223
- const peer = targetArg.peer;
1224
- const peerId = targetArg.peer.id;
1225
- const routingSurface = peer.routingSurface;
1226
- if (!routingSurface || !this.serverTypedRouters.includes(routingSurface)) {
1227
- throw new Error('TypedSocket target connection is not bound to this server routing surface');
1228
- }
1229
- if (!this.isAttachedServerPeer(peer)) {
1230
- throw new Error(`TypedSocket target connection is detached or closed: ${peerId}`);
1231
- }
1232
- if (this.pendingServerRequests.has(correlationId)) {
1233
- throw new Error(`Duplicate in-flight TypedSocket correlation ID: ${correlationId}`);
1234
- }
1235
- const requestsForPeer = this.pendingServerRequestIdsByPeer.get(peer) ?? new Set();
1236
- if (requestsForPeer.size >= TYPEDSOCKET_MAX_PENDING_SERVER_REQUESTS_PER_PEER
1237
- || this.pendingServerRequests.size >= TYPEDSOCKET_MAX_PENDING_SERVER_REQUESTS) {
1238
- throw new Error('TypedSocket pending server request capacity exceeded.');
1239
- }
1240
- if ((this.retainedServerInterestsByPeer.get(peer) ?? 0)
1241
- >= TYPEDSOCKET_MAX_RETAINED_SERVER_INTERESTS_PER_PEER
1242
- || this.retainedServerInterests >= TYPEDSOCKET_MAX_RETAINED_SERVER_INTERESTS) {
1243
- throw new Error('TypedSocket server interest registration capacity exceeded.');
1244
- }
1245
- const cancellation = plugins.smartpromise.defer();
1246
- // A stop/abort may happen while InterestMap.addInterest is yielding. Attach
1247
- // a rejection handler immediately; Promise.race below still receives the
1248
- // original rejection once the interest exists.
1249
- void cancellation.promise.catch(() => { });
1250
- const cleanup = plugins.smartpromise.defer();
1251
- let cancellationRequested = false;
1252
- const cancel = (errorArg) => {
1253
- if (cancellationRequested) {
1254
- return;
1255
- }
1256
- cancellationRequested = true;
1257
- cancellation.reject(errorArg);
1258
- };
1259
- const pendingRequest = {
1260
- peer,
1261
- peerId,
1262
- routingSurface,
1263
- expectedMethod: typedRequestDataArg.method,
1264
- lifecycleGeneration: this.serverLifecycleGeneration,
1265
- cancel,
1266
- cleanupComplete: cleanup.promise,
1267
- };
1268
- this.pendingServerRequests.set(correlationId, pendingRequest);
1269
- requestsForPeer.add(correlationId);
1270
- this.pendingServerRequestIdsByPeer.set(peer, requestsForPeer);
1271
- const onAbort = () => cancel(new Error('TypedSocket request aborted'));
1272
- const timeout = setTimeout(() => cancel(new Error(`TypedSocket request timed out after ${timeoutMs}ms`)), timeoutMs);
1273
- optionsArg.abortSignal?.addEventListener('abort', onAbort, { once: true });
1274
- if (optionsArg.abortSignal?.aborted) {
1275
- onAbort();
1276
- }
1277
- const destroyInterests = [];
1278
- try {
1279
- const releaseInterestRegistration = this.retainServerInterestRegistration(peer);
1280
- const interestRegistration = Promise.resolve()
1281
- .then(() => routingSurface.fireEventInterestMap.addInterest(correlationId, typedRequestDataArg))
1282
- .then((interestArg) => {
1283
- if (cancellationRequested || this.serverStopping) {
1284
- interestArg.destroy();
1285
- }
1286
- return interestArg;
1287
- })
1288
- .finally(releaseInterestRegistration);
1289
- const interest = await Promise.race([
1290
- interestRegistration,
1291
- cancellation.promise,
1292
- ]);
1293
- if (cancellationRequested || this.serverStopping) {
1294
- interest.destroy();
1295
- await cancellation.promise;
1296
- }
1297
- destroyInterests.push(() => interest.destroy());
1298
- // Establish the rejecting race before send so synchronous close/abort and
1299
- // send failures all use the same cleanup path.
1300
- const response = Promise.race([
1301
- interest.interestFullfilled,
1302
- cancellation.promise,
1303
- ]);
1304
- const targetIsStillConnected = this.smartServeRef
1305
- ?.getWebSocketConnections()
1306
- .some((peerArg) => peerArg === peer) ?? false;
1307
- if (!targetIsStillConnected) {
1308
- cancel(new Error(`TypedSocket target connection closed: ${peerId}`));
1309
- }
1310
- if (this.serverStopping) {
1311
- cancel(new Error('TypedSocket server stopped'));
1312
- }
1313
- if (!cancellationRequested && targetIsStillConnected && !this.serverStopping) {
1314
- targetArg.peer.send(plugins.smartjson.stringify(typedRequestDataArg));
1315
- }
1316
- const routedResponse = await response;
1317
- typedRequestDataArg.response = routedResponse.response;
1318
- typedRequestDataArg.correlation = routedResponse.correlation;
1319
- if (routedResponse.error)
1320
- typedRequestDataArg.error = routedResponse.error;
1321
- else
1322
- delete typedRequestDataArg.error;
1323
- if (routedResponse.retry)
1324
- typedRequestDataArg.retry = routedResponse.retry;
1325
- else
1326
- delete typedRequestDataArg.retry;
1327
- return typedRequestDataArg;
1328
- }
1329
- finally {
1330
- clearTimeout(timeout);
1331
- optionsArg.abortSignal?.removeEventListener('abort', onAbort);
1332
- this.pendingServerRequests.delete(correlationId);
1333
- const remainingRequestsForPeer = this.pendingServerRequestIdsByPeer.get(peer);
1334
- remainingRequestsForPeer?.delete(correlationId);
1335
- if (remainingRequestsForPeer?.size === 0) {
1336
- this.pendingServerRequestIdsByPeer.delete(peer);
1337
- }
1338
- for (const destroyInterest of destroyInterests) {
1339
- destroyInterest();
1340
- }
1341
- cleanup.resolve();
1342
- }
1343
- }
1344
- // ============================================================================
1345
- // PUBLIC API - SHARED
1346
- // ============================================================================
1347
- /**
1348
- * Creates a TypedRequest for the specified method.
1349
- * On clients, sends to the server.
1350
- * On servers, sends to the specified target connection.
1351
- */
1352
- createTypedRequest(methodName, targetConnection, optionsArg = {}) {
1353
- const postMethod = async (requestDataArg, postOptionsArg = {}) => {
1354
- const composedAbortSignal = composeAbortSignals(optionsArg.abortSignal, postOptionsArg.signal);
1355
- const requestOptions = {
1356
- ...optionsArg,
1357
- abortSignal: composedAbortSignal.signal,
1358
- };
1359
- try {
1360
- if (this.side === 'client') {
1361
- return await this.sendRequest(requestDataArg, requestOptions);
1362
- }
1363
- // Server-side: send to target connection
1364
- if (!this.smartServeRef) {
1365
- throw new Error('Server not initialized');
1366
- }
1367
- let target = targetConnection;
1368
- if (!target) {
1369
- if (this.serverTypedRouters.length > 1) {
1370
- throw new Error('TypedSocket multi-router servers require an explicit targetConnection');
1371
- }
1372
- const routingSurface = this.serverTypedRouters[0];
1373
- const allConnections = this.smartServeRef.getWebSocketConnections().filter((peerArg) => peerArg.routingSurface === routingSurface);
1374
- if (allConnections.length === 1) {
1375
- const peer = allConnections[0];
1376
- target = wrapSmartServePeer(peer);
1377
- }
1378
- else if (allConnections.length === 0) {
1379
- throw new Error('No WebSocket connections available');
1380
- }
1381
- else {
1382
- throw new Error('Multiple connections available - specify targetConnection');
1383
- }
1384
- }
1385
- return await this.sendServerRequest(requestDataArg, target, requestOptions);
1386
- }
1387
- finally {
1388
- composedAbortSignal.cleanup();
1389
- }
1390
- };
1391
- const nativeStreamTransport = this.side === 'client'
1392
- ? this.nativeBytes.getClientNativeStreamTransport()
1393
- : targetConnection
1394
- ? this.nativeBytes.getServerNativeStreamTransport(targetConnection.peer)
1395
- : undefined;
1396
- return new plugins.typedrequest.TypedRequest(new plugins.typedrequest.TypedTarget({
1397
- postMethod,
1398
- supportsAbortSignal: true,
1399
- nativeStreamTransport,
1400
- legacyVirtualStreams: 'deny',
1401
- }), methodName);
1402
- }
1403
- /**
1404
- * Creates an exact authorized native-byte receive facade for one server peer.
1405
- * TypedRequest carries its opaque descriptor when the facade enters a DTO.
1406
- */
1407
- createVirtualStream(optionsArg) {
1408
- if (this.side !== 'server') {
1409
- throw new Error('createVirtualStream is only available on servers');
1410
- }
1411
- if (optionsArg.protocol !== NATIVE_BYTE_PROTOCOL
1412
- || optionsArg.direction !== 'receive') {
1413
- throw new TypeError('createVirtualStream requires native-byte-v1 receive direction');
1414
- }
1415
- const authorizationAdapter = this.nativeByteAuthorizationAdapter;
1416
- if (!authorizationAdapter) {
1417
- throw new NativeByteCapabilityError('createVirtualStream requires a nativeByteAuthorizationAdapter');
1418
- }
1419
- const peer = 'peer' in optionsArg.target
1420
- ? optionsArg.target.peer
1421
- : optionsArg.target;
1422
- const transport = this.nativeBytes.getServerNativeStreamTransport(peer);
1423
- if (!transport) {
1424
- throw new NativeByteCapabilityError('createVirtualStream target is not an active native-byte-v1 peer');
1425
- }
1426
- transport.requireCapability({ capability: NATIVE_BYTE_PROTOCOL });
1427
- const manifest = this.nativeBytes.normalizeManifest({
1428
- byteLength: optionsArg.byteLength,
1429
- sha256: optionsArg.sha256,
1430
- contentType: optionsArg.contentType,
1431
- });
1432
- const authorizationBinding = authorizationAdapter.bind(optionsArg.authorization, Object.freeze({ target: peer, manifest }));
1433
- if (!authorizationBinding
1434
- || typeof authorizationBinding !== 'object'
1435
- || typeof Reflect.get(authorizationBinding, 'then') === 'function') {
1436
- throw new TypeError('nativeByteAuthorizationAdapter.bind() must return a synchronous binding');
1437
- }
1438
- const registration = this.nativeBytes.createReceiveRegistration({
1439
- target: peer,
1440
- ...manifest,
1441
- initialWindowBytes: optionsArg.initialWindowBytes,
1442
- principalId: authorizationBinding.principalId,
1443
- credentialRevision: authorizationBinding.credentialRevision,
1444
- configRevision: authorizationBinding.configRevision,
1445
- bindingRevision: authorizationBinding.bindingRevision,
1446
- revalidate: authorizationBinding.revalidate,
1447
- });
1448
- return plugins.typedrequest.VirtualStream.fromNativeByteRegistration({
1449
- transport,
1450
- registration,
1451
- });
1452
- }
1453
- /**
1454
- * Gets the current connection status
1455
- */
1456
- getStatus() {
1457
- return this.connectionStatus;
1458
- }
1459
- /**
1460
- * Stops the TypedSocket client or cleans up server state
1461
- */
1462
- async stop() {
1463
- if (this.side === 'client') {
1464
- this.stopped = true;
1465
- for (const stopListener of Array.from(this.stopListeners)) {
1466
- stopListener();
1467
- }
1468
- this.stopListeners.clear();
1469
- if (this.clientOptions) {
1470
- this.clientOptions.autoReconnect = false;
1471
- if (this.clientOptions.abortSignal && this.abortSignalListener) {
1472
- this.clientOptions.abortSignal.removeEventListener('abort', this.abortSignalListener);
1473
- }
1474
- }
1475
- this.abortSignalListener = undefined;
1476
- if (this.websocket) {
1477
- const websocket = this.websocket;
1478
- const generation = this.connectionGeneration;
1479
- if (this.clientConnectionState) {
1480
- this.abortClientConnectionState(this.clientConnectionState, new Error('TypedSocket stopped'));
1481
- }
1482
- this.nativeBytes.unbindClientConnection(websocket, generation, new Error('TypedSocket stopped'));
1483
- websocket.close();
1484
- this.websocket = null;
1485
- }
1486
- for (const pendingRequest of this.pendingRequests.values()) {
1487
- pendingRequest.reject(new Error('TypedSocket stopped'));
1488
- }
1489
- this.pendingRequests.clear();
1490
- }
1491
- else {
1492
- this.serverStopping = true;
1493
- this.serverLifecycleGeneration++;
1494
- this.tagPolicyManager.stop(this.smartServeRef?.getWebSocketConnections() ?? []);
1495
- const pendingRequests = Array.from(this.pendingServerRequests.values());
1496
- for (const pendingRequest of pendingRequests) {
1497
- pendingRequest.cancel(new Error('TypedSocket server stopped'));
1498
- }
1499
- await Promise.all(pendingRequests.map((pendingRequest) => pendingRequest.cleanupComplete));
1500
- this.unsubscribeSmartServeConnectionClose?.();
1501
- this.unsubscribeSmartServeConnectionClose = null;
1502
- this.nativeBytes.detachServer();
1503
- this.tagPolicyManager.setAttachedPeersProvider(undefined);
1504
- this.smartServeRef = null;
1505
- this.pendingServerRequestIdsByPeer.clear();
1506
- }
1507
- for (const detachNativeStreamResolver of this.detachNativeStreamResolvers.reverse()) {
1508
- detachNativeStreamResolver();
1509
- }
1510
- this.detachNativeStreamResolvers = [];
1511
- for (const detachResponseAuthorityGuard of this.detachResponseAuthorityGuards.reverse()) {
1512
- detachResponseAuthorityGuard();
1513
- }
1514
- this.detachResponseAuthorityGuards = [];
1515
- if (this.side === 'server') {
1516
- this.releaseServerComposition();
1517
- }
1518
- }
1519
- releaseServerComposition() {
1520
- for (const detachLegacyPolicy of this.detachLegacyVirtualStreamPolicies.reverse()) {
1521
- detachLegacyPolicy();
1522
- }
1523
- this.detachLegacyVirtualStreamPolicies = [];
1524
- for (const detachProtocolRouter of this.detachProtocolRouters.reverse()) {
1525
- detachProtocolRouter();
1526
- }
1527
- this.detachProtocolRouters = [];
1528
- }
1529
- // ============================================================================
1530
- // CLIENT-ONLY METHODS
1531
- // ============================================================================
1532
- /**
1533
- * Sets a tag on this client connection.
1534
- * Tags are stored on the server and can be used for filtering.
1535
- * @client-only
1536
- */
1537
- async setTag(name, payload) {
1538
- if (this.side !== 'client') {
1539
- throw new Error('setTag is only available on clients');
1540
- }
1541
- const releaseMutation = this.retainClientTagMutation(name);
1542
- try {
1543
- const snapshot = createTypedSocketTagPayloadSnapshot(payload);
1544
- const desired = this.setDesiredClientTag(name, 'set', snapshot.payload, snapshot.byteLength);
1545
- return await this.serializeClientTagMutation(name, async () => {
1546
- let applied;
1547
- try {
1548
- applied = await this.submitDesiredClientTag(name, desired);
1549
- }
1550
- catch (errorArg) {
1551
- this.settleDesiredClientTag(name, desired, errorArg instanceof TypedSocketClientTagDeniedError ? 'denied' : 'retained');
1552
- throw errorArg;
1553
- }
1554
- this.settleDesiredClientTag(name, desired, applied ? 'accepted' : 'retained');
1555
- });
1556
- }
1557
- finally {
1558
- releaseMutation();
1559
- }
1560
- }
1561
- /**
1562
- * Re-applies all client tags after a reconnect, since server-side tags are
1563
- * bound to the previous connection.
1564
- */
1565
- async reapplyClientTags(stateArg = this.clientConnectionState) {
1566
- if (!stateArg || !this.isCurrentClientConnection(stateArg)) {
1567
- throw new Error('TypedSocket has no active connection for tag restoration.');
1568
- }
1569
- this.clientTags.clear();
1570
- this.clientTagRevisions.clear();
1571
- while (this.isCurrentClientConnection(stateArg)) {
1572
- const snapshot = Array.from(this.desiredClientTags.entries());
1573
- for (const [name, desired] of snapshot) {
1574
- try {
1575
- const applied = await this.submitDesiredClientTag(name, desired, stateArg);
1576
- if (applied
1577
- && desired.operation === 'remove'
1578
- && this.desiredClientTags.get(name)?.sequence === desired.sequence) {
1579
- this.desiredClientTags.delete(name);
1580
- }
1581
- }
1582
- catch (errorArg) {
1583
- if (errorArg instanceof TypedSocketClientTagDeniedError
1584
- && this.desiredClientTags.get(name)?.sequence === desired.sequence) {
1585
- this.desiredClientTags.delete(name);
1586
- }
1587
- throw errorArg;
1588
- }
1589
- }
1590
- const stable = snapshot.length === this.desiredClientTags.size
1591
- && snapshot.every(([name, desired]) => {
1592
- return this.desiredClientTags.get(name)?.sequence === desired.sequence;
1593
- });
1594
- if (stable)
1595
- return;
1596
- }
1597
- throw new Error('TypedSocket connection changed while restoring client tags.');
1598
- }
1599
- /**
1600
- * Removes a tag from this client connection.
1601
- * @client-only
1602
- */
1603
- async removeTag(name) {
1604
- if (this.side !== 'client') {
1605
- throw new Error('removeTag is only available on clients');
1606
- }
1607
- const releaseMutation = this.retainClientTagMutation(name);
1608
- try {
1609
- const desired = this.setDesiredClientTag(name, 'remove', undefined, 0);
1610
- return await this.serializeClientTagMutation(name, async () => {
1611
- let applied;
1612
- try {
1613
- applied = await this.submitDesiredClientTag(name, desired);
1614
- }
1615
- catch (errorArg) {
1616
- this.settleDesiredClientTag(name, desired, errorArg instanceof TypedSocketClientTagDeniedError ? 'denied' : 'retained');
1617
- throw errorArg;
1618
- }
1619
- this.settleDesiredClientTag(name, desired, applied ? 'accepted' : 'retained');
1620
- });
1621
- }
1622
- finally {
1623
- releaseMutation();
1624
- }
1625
- }
1626
- retainClientTagMutation(nameArg) {
1627
- assertBoundedTextIdentifier(nameArg, 'tag name', TYPEDSOCKET_MAX_TAG_NAME_BYTES);
1628
- const retainedForName = this.retainedClientTagMutationsByName.get(nameArg) ?? 0;
1629
- if (retainedForName >= TYPEDSOCKET_MAX_RETAINED_CLIENT_TAG_MUTATIONS_PER_NAME
1630
- || this.retainedClientTagMutations >= TYPEDSOCKET_MAX_RETAINED_CLIENT_TAG_MUTATIONS) {
1631
- throw new TypedSocketClientTagDeniedError('TAG_MUTATION_CAPACITY_EXCEEDED', 'TypedSocket retained client tag mutation capacity exceeded.');
1632
- }
1633
- this.retainedClientTagMutations++;
1634
- this.retainedClientTagMutationsByName.set(nameArg, retainedForName + 1);
1635
- let released = false;
1636
- return () => {
1637
- if (released)
1638
- return;
1639
- released = true;
1640
- this.retainedClientTagMutations--;
1641
- const currentForName = this.retainedClientTagMutationsByName.get(nameArg);
1642
- if (currentForName === undefined || currentForName < 1) {
1643
- throw new Error('TypedSocket client tag mutation accounting underflow.');
1644
- }
1645
- if (currentForName === 1) {
1646
- this.retainedClientTagMutationsByName.delete(nameArg);
1647
- }
1648
- else {
1649
- this.retainedClientTagMutationsByName.set(nameArg, currentForName - 1);
1650
- }
1651
- };
1652
- }
1653
- setDesiredClientTag(nameArg, operationArg, payloadArg, payloadBytesArg) {
1654
- assertBoundedTextIdentifier(nameArg, 'tag name', TYPEDSOCKET_MAX_TAG_NAME_BYTES);
1655
- const retainedBytes = textEncoder.encode(nameArg).byteLength + payloadBytesArg;
1656
- const desired = Object.freeze({
1657
- sequence: ++this.clientTagMutationSequence,
1658
- operation: operationArg,
1659
- payload: operationArg === 'set' ? payloadArg : undefined,
1660
- retainedBytes,
1661
- });
1662
- const alreadyPresent = this.desiredClientTags.has(nameArg);
1663
- if (!alreadyPresent && this.desiredClientTags.size >= TYPEDSOCKET_MAX_CLIENT_TAGS_PER_PEER) {
1664
- throw new TypedSocketClientTagDeniedError('TAG_COUNT_LIMIT_EXCEEDED', 'TypedSocket desired client tag count limit exceeded.');
1665
- }
1666
- let retainedTotal = retainedBytes;
1667
- for (const [name, entry] of this.desiredClientTags) {
1668
- if (name !== nameArg)
1669
- retainedTotal += entry.retainedBytes;
1670
- }
1671
- if (retainedTotal > TYPEDSOCKET_MAX_CLIENT_TAG_RETAINED_BYTES_PER_PEER) {
1672
- throw new TypedSocketClientTagDeniedError('TAG_RETAINED_BYTES_EXCEEDED', 'TypedSocket desired client tag retained-byte limit exceeded.');
1673
- }
1674
- let queue = this.clientTagDesiredMutationQueues.get(nameArg);
1675
- if (!queue) {
1676
- queue = {
1677
- baseline: this.desiredClientTags.get(nameArg),
1678
- pending: [],
1679
- };
1680
- this.clientTagDesiredMutationQueues.set(nameArg, queue);
1681
- }
1682
- queue.pending.push(desired);
1683
- this.desiredClientTags.set(nameArg, desired);
1684
- return desired;
1685
- }
1686
- settleDesiredClientTag(nameArg, desiredArg, outcomeArg) {
1687
- const queue = this.clientTagDesiredMutationQueues.get(nameArg);
1688
- const settled = queue?.pending.shift();
1689
- if (!queue || settled !== desiredArg) {
1690
- throw new Error('TypedSocket desired client tag mutation order changed unexpectedly.');
1691
- }
1692
- if (outcomeArg === 'accepted') {
1693
- queue.baseline = desiredArg.operation === 'set' ? desiredArg : undefined;
1694
- }
1695
- else if (outcomeArg === 'retained') {
1696
- queue.baseline = desiredArg;
1697
- }
1698
- const current = queue.pending.at(-1) ?? queue.baseline;
1699
- if (current)
1700
- this.desiredClientTags.set(nameArg, current);
1701
- else
1702
- this.desiredClientTags.delete(nameArg);
1703
- if (queue.pending.length === 0)
1704
- this.clientTagDesiredMutationQueues.delete(nameArg);
1705
- }
1706
- async serializeClientTagMutation(nameArg, mutationArg) {
1707
- const previous = this.clientTagMutationTails.get(nameArg) ?? Promise.resolve();
1708
- const operation = previous.catch(() => { }).then(mutationArg);
1709
- const tail = operation.then(() => { }, () => { });
1710
- this.clientTagMutationTails.set(nameArg, tail);
1711
- try {
1712
- await operation;
1713
- }
1714
- finally {
1715
- if (this.clientTagMutationTails.get(nameArg) === tail) {
1716
- this.clientTagMutationTails.delete(nameArg);
1717
- }
1718
- }
1719
- }
1720
- async submitDesiredClientTag(nameArg, desiredArg, stateArg = this.clientConnectionState) {
1721
- if (!stateArg || !this.isCurrentClientConnection(stateArg)) {
1722
- throw new Error('WebSocket not connected');
1723
- }
1724
- const connectionGeneration = stateArg.generation;
1725
- const response = desiredArg.operation === 'set'
1726
- ? this.requireTagMutationSuccess(await this
1727
- .createTypedRequest('__typedsocket_setTag')
1728
- .fire({ name: nameArg, payload: desiredArg.payload }))
1729
- : this.requireTagMutationSuccess(await this
1730
- .createTypedRequest('__typedsocket_removeTag')
1731
- .fire({ name: nameArg }));
1732
- const applied = this.applyClientTagMutation(nameArg, desiredArg.payload, response, connectionGeneration, desiredArg.operation);
1733
- return applied;
1734
- }
1735
- requireTagMutationSuccess(responseArg) {
1736
- if (!responseArg || typeof responseArg.success !== 'boolean') {
1737
- throw new TypedSocketClientTagDeniedError('MALFORMED_TAG_RESPONSE', 'TypedSocket server returned a malformed tag mutation response.');
1738
- }
1739
- if (!responseArg.success) {
1740
- if (typeof responseArg.code !== 'string' || typeof responseArg.message !== 'string') {
1741
- throw new TypedSocketClientTagDeniedError('MALFORMED_TAG_RESPONSE', 'TypedSocket server returned a malformed tag denial response.');
1742
- }
1743
- throw new TypedSocketClientTagDeniedError(responseArg.code, responseArg.message);
1744
- }
1745
- if (typeof responseArg.connectionId !== 'string'
1746
- || responseArg.connectionId.length === 0
1747
- || !Number.isSafeInteger(responseArg.tagRevision)
1748
- || responseArg.tagRevision < 1) {
1749
- throw new TypedSocketClientTagDeniedError('MALFORMED_TAG_RESPONSE', 'TypedSocket server returned malformed tag mutation ordering metadata.');
1750
- }
1751
- return responseArg;
1752
- }
1753
- applyClientTagMutation(nameArg, payloadArg, responseArg, connectionGenerationArg, operationArg) {
1754
- if (connectionGenerationArg !== this.connectionGeneration)
1755
- return false;
1756
- const current = this.clientTagRevisions.get(nameArg);
1757
- if (current) {
1758
- if (connectionGenerationArg < current.connectionGeneration)
1759
- return false;
1760
- if (connectionGenerationArg === current.connectionGeneration) {
1761
- if (responseArg.connectionId !== current.connectionId) {
1762
- throw new TypedSocketClientTagDeniedError('MALFORMED_TAG_RESPONSE', 'TypedSocket server changed tag mutation connection identity within one connection generation.');
1763
- }
1764
- if (responseArg.tagRevision <= current.tagRevision)
1765
- return false;
1766
- }
1767
- }
1768
- if (operationArg === 'set') {
1769
- this.clientTagRevisions.set(nameArg, {
1770
- connectionGeneration: connectionGenerationArg,
1771
- connectionId: responseArg.connectionId,
1772
- tagRevision: responseArg.tagRevision,
1773
- });
1774
- this.clientTags.set(nameArg, createTypedSocketTagPayloadSnapshot(payloadArg).payload);
1775
- }
1776
- else {
1777
- this.clientTags.delete(nameArg);
1778
- this.clientTagRevisions.delete(nameArg);
1779
- }
1780
- return true;
1781
- }
1782
- // ============================================================================
1783
- // SERVER-ONLY METHODS
1784
- // ============================================================================
1785
- /**
1786
- * Resolves the exact SmartServe transport peer for one incoming TypedRequest.
1787
- * Server handlers can pass their TypedTools argument without type assertions.
1788
- */
1789
- getServerConnectionForRequest(typedToolsArg) {
1790
- if (this.side !== 'server') {
1791
- throw new Error('getServerConnectionForRequest is only available on servers');
1792
- }
1793
- const peer = this.findServerPeerFromRequest(typedToolsArg);
1794
- if (!peer) {
1795
- throw new Error('TypedSocket request is not bound to an attached transport peer');
1796
- }
1797
- return wrapSmartServePeer(peer);
1798
- }
1799
- /** Assigns a protected server-owned tag to one connection. */
1800
- setServerTag(connectionArg, nameArg, payloadArg) {
1801
- if (this.side !== 'server') {
1802
- throw new Error('setServerTag is only available on servers');
1803
- }
1804
- this.tagPolicyManager.setServerTag('peer' in connectionArg ? connectionArg.peer : connectionArg, nameArg, payloadArg);
1805
- }
1806
- /** Removes a server-owned tag while keeping its name protected from clients. */
1807
- removeServerTag(connectionArg, nameArg) {
1808
- if (this.side !== 'server') {
1809
- throw new Error('removeServerTag is only available on servers');
1810
- }
1811
- this.tagPolicyManager.removeServerTag('peer' in connectionArg ? connectionArg.peer : connectionArg, nameArg);
1812
- }
1813
- /**
1814
- * Finds all connections matching the filter function.
1815
- * @server-only
1816
- */
1817
- async findAllTargetConnections(asyncFindFuncArg) {
1818
- if (this.side !== 'server' || !this.smartServeRef) {
1819
- throw new Error('findAllTargetConnections is only available on servers');
1820
- }
1821
- const matchingConnections = [];
1822
- for (const peer of this.smartServeRef.getWebSocketConnections()) {
1823
- if (!this.isAttachedServerPeer(peer))
1824
- continue;
1825
- const wrapper = wrapSmartServePeer(peer);
1826
- if (await asyncFindFuncArg(wrapper)) {
1827
- matchingConnections.push(wrapper);
1828
- }
1829
- }
1830
- return matchingConnections;
1831
- }
1832
- /**
1833
- * Finds the first connection matching the filter function.
1834
- * @server-only
1835
- */
1836
- async findTargetConnection(asyncFindFuncArg) {
1837
- const allMatching = await this.findAllTargetConnections(asyncFindFuncArg);
1838
- return allMatching[0];
1839
- }
1840
- /**
1841
- * Finds all connections with the specified tag.
1842
- * @server-only
1843
- */
1844
- async findAllTargetConnectionsByTag(keyArg, payloadArg) {
1845
- if (this.side !== 'server' || !this.smartServeRef) {
1846
- throw new Error('findAllTargetConnectionsByTag is only available on servers');
1847
- }
1848
- const peers = this.smartServeRef
1849
- .getWebSocketConnectionsByTag(keyArg)
1850
- .filter((peerArg) => this.isAttachedServerPeer(peerArg));
1851
- const results = [];
1852
- for (const peer of peers) {
1853
- const wrapper = wrapSmartServePeer(peer);
1854
- // If payload specified, also filter by payload
1855
- if (payloadArg !== undefined) {
1856
- const tag = await wrapper.getTagById(keyArg);
1857
- if (plugins.smartjson.stringify(tag?.payload) !== plugins.smartjson.stringify(payloadArg)) {
1858
- continue;
1859
- }
1860
- }
1861
- results.push(wrapper);
1862
- }
1863
- return results;
1864
- }
1865
- /**
1866
- * Finds the first connection with the specified tag.
1867
- * @server-only
1868
- */
1869
- async findTargetConnectionByTag(keyArg, payloadArg) {
1870
- const allResults = await this.findAllTargetConnectionsByTag(keyArg, payloadArg);
1871
- return allResults[0];
1872
- }
1873
- }
1874
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZWRzb2NrZXQuY2xhc3Nlcy50eXBlZHNvY2tldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3R5cGVkc29ja2V0LmNsYXNzZXMudHlwZWRzb2NrZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUM5RixPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNwRSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUM3RCxPQUFPLEVBQ0wsbUNBQW1DLEVBQ25DLGtEQUFrRCxFQUNsRCxvQ0FBb0MsRUFDcEMsOEJBQThCLEVBQzlCLCtCQUErQixFQUMvQiwyQkFBMkIsR0FDNUIsTUFBTSx1QkFBdUIsQ0FBQztBQWUvQixNQUFNLFVBQVUsR0FBRyxxQkFBcUIsQ0FBQztBQUN6QyxNQUFNLFdBQVcsR0FBRyxJQUFJLFdBQVcsRUFBRSxDQUFDO0FBRXRDLE1BQU0sQ0FBQyxNQUFNLGdDQUFnQyxHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7QUFDNUQsTUFBTSxDQUFDLE1BQU0sa0NBQWtDLEdBQUcsRUFBRSxDQUFDO0FBQ3JELE1BQU0sQ0FBQyxNQUFNLGlDQUFpQyxHQUFHLENBQUMsR0FBRyxJQUFJLEdBQUcsSUFBSSxDQUFDO0FBQ2pFLE1BQU0sQ0FBQyxNQUFNLDBDQUEwQyxHQUFHLEVBQUUsQ0FBQztBQUM3RCxNQUFNLENBQUMsTUFBTSx5Q0FBeUMsR0FBRyxFQUFFLENBQUM7QUFDNUQsTUFBTSxDQUFDLE1BQU0sdUNBQXVDLEdBQUcsSUFBSSxDQUFDO0FBQzVELE1BQU0sQ0FBQyxNQUFNLHVDQUF1QyxHQUFHLENBQUMsR0FBRyxJQUFJLEdBQUcsSUFBSSxDQUFDO0FBQ3ZFLE1BQU0sQ0FBQyxNQUFNLGlDQUFpQyxHQUFHLEdBQUcsQ0FBQztBQUNyRCxNQUFNLENBQUMsTUFBTSxvQ0FBb0MsR0FBRyxHQUFHLENBQUM7QUFDeEQsTUFBTSxDQUFDLE1BQU0sa0NBQWtDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFDaEUsTUFBTSxDQUFDLE1BQU0sNkNBQTZDLEdBQUcsTUFBTSxDQUFDO0FBQ3BFLE1BQU0sQ0FBQyxNQUFNLGlDQUFpQyxHQUFHLEdBQUcsQ0FBQztBQUNyRCxNQUFNLENBQUMsTUFBTSxvQ0FBb0MsR0FBRyxNQUFNLENBQUM7QUFDM0QsTUFBTSxDQUFDLE1BQU0sc0RBQXNELEdBQUcsQ0FBQyxDQUFDO0FBQ3hFLE1BQU0sQ0FBQyxNQUFNLDZDQUE2QyxHQUFHLEVBQUUsQ0FBQztBQUNoRSxNQUFNLENBQUMsTUFBTSxnREFBZ0QsR0FBRyxFQUFFLENBQUM7QUFDbkUsTUFBTSxDQUFDLE1BQU0sdUNBQXVDLEdBQUcsSUFBSSxDQUFDO0FBQzVELE1BQU0sQ0FBQyxNQUFNLGtEQUFrRCxHQUFHLENBQUMsQ0FBQztBQUNwRSxNQUFNLENBQUMsTUFBTSx5Q0FBeUMsR0FBRyxFQUFFLENBQUM7QUE2QjVELE1BQU0sT0FBTyx1Q0FBd0MsU0FBUSxLQUFLO0lBQ2hFLFlBQVksVUFBa0I7UUFDNUIsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2xCLElBQUksQ0FBQyxJQUFJLEdBQUcseUNBQXlDLENBQUM7SUFDeEQsQ0FBQztDQUNGO0FBeUpEOztHQUVHO0FBQ0gsU0FBUyxrQkFBa0IsQ0FBQyxJQUE0QjtJQUN0RCxPQUFPO1FBQ0wsSUFBSTtRQUNKLEtBQUssQ0FBQyxVQUFVLENBQUMsS0FBYTtZQUM1QixJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDMUIsT0FBTyxTQUFTLENBQUM7WUFDbkIsQ0FBQztZQUNELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsVUFBVSxHQUFHLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDdkQsT0FBTyxFQUFFLEVBQUUsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUM7UUFDaEMsQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDO0FBRUQsU0FBUyxtQkFBbUIsQ0FDMUIsbUJBQWlDLEVBQ2pDLGdCQUE4QjtJQUU5QixJQUFJLENBQUMsbUJBQW1CLElBQUksbUJBQW1CLEtBQUssZ0JBQWdCLEVBQUUsQ0FBQztRQUNyRSxPQUFPO1lBQ0wsTUFBTSxFQUFFLGdCQUFnQixJQUFJLG1CQUFtQjtZQUMvQyxPQUFPLEVBQUUsR0FBRyxFQUFFLEdBQUUsQ0FBQztTQUNsQixDQUFDO0lBQ0osQ0FBQztJQUNELElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3RCLE9BQU87WUFDTCxNQUFNLEVBQUUsbUJBQW1CO1lBQzNCLE9BQU8sRUFBRSxHQUFHLEVBQUUsR0FBRSxDQUFDO1NBQ2xCLENBQUM7SUFDSixDQUFDO0lBRUQsTUFBTSxlQUFlLEdBQUcsSUFBSSxlQUFlLEVBQUUsQ0FBQztJQUM5QyxNQUFNLHVCQUF1QixHQUFHLEdBQUcsRUFBRTtRQUNuQyxlQUFlLENBQUMsS0FBSyxDQUFDLG1CQUFtQixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3BELENBQUMsQ0FBQztJQUNGLE1BQU0sb0JBQW9CLEdBQUcsR0FBRyxFQUFFO1FBQ2hDLGVBQWUsQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDakQsQ0FBQyxDQUFDO0lBQ0YsTUFBTSxPQUFPLEdBQUcsR0FBRyxFQUFFO1FBQ25CLG1CQUFtQixDQUFDLG1CQUFtQixDQUFDLE9BQU8sRUFBRSx1QkFBdUIsQ0FBQyxDQUFDO1FBQzFFLGdCQUFnQixDQUFDLG1CQUFtQixDQUFDLE9BQU8sRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO0lBQ3RFLENBQUMsQ0FBQztJQUVGLElBQUksbUJBQW1CLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDaEMsdUJBQXVCLEVBQUUsQ0FBQztJQUM1QixDQUFDO1NBQU0sSUFBSSxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNwQyxvQkFBb0IsRUFBRSxDQUFDO0lBQ3pCLENBQUM7U0FBTSxDQUFDO1FBQ04sbUJBQW1CLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLHVCQUF1QixFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFDdkYsZ0JBQWdCLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLG9CQUFvQixFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDbkYsQ0FBQztJQUVELE9BQU87UUFDTCxNQUFNLEVBQUUsZUFBZSxDQUFDLE1BQU07UUFDOUIsT0FBTztLQUNSLENBQUM7QUFDSixDQUFDO0FBRUQsTUFBTSxtQkFBbUIsR0FBNkIsTUFBTSxDQUFDLE1BQU0sQ0FBQztJQUNsRSxjQUFjLEVBQUUsZ0NBQWdDO0lBQ2hELGdCQUFnQixFQUFFLGtDQUFrQztJQUNwRCxlQUFlLEVBQUUsaUNBQWlDO0lBQ2xELGtCQUFrQixFQUFFLDBDQUEwQztJQUM5RCxpQkFBaUIsRUFBRSx5Q0FBeUM7SUFDNUQsZUFBZSxFQUFFLHVDQUF1QztJQUN4RCxxQkFBcUIsRUFBRSx1Q0FBdUM7SUFDOUQsZ0JBQWdCLEVBQUUsa0NBQWtDO0lBQ3BELDBCQUEwQixFQUFFLDZDQUE2QztDQUMxRSxDQUFDLENBQUM7QUFFSCxTQUFTLHFCQUFxQixDQUM1QixTQUF3RDtJQUV4RCxNQUFNLEtBQUssR0FBRyxDQUFDLE9BQWUsRUFBRSxRQUE0QixFQUFFLFVBQWtCLEVBQVUsRUFBRTtRQUMxRixNQUFNLEtBQUssR0FBRyxRQUFRLElBQUksVUFBVSxDQUFDO1FBQ3JDLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssR0FBRyxDQUFDLElBQUksS0FBSyxHQUFHLFVBQVUsRUFBRSxDQUFDO1lBQ3BFLE1BQU0sSUFBSSxVQUFVLENBQ2xCLDRCQUE0QixPQUFPLG9EQUFvRCxVQUFVLEdBQUcsQ0FDckcsQ0FBQztRQUNKLENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUMsQ0FBQztJQUNGLE1BQU0sVUFBVSxHQUE2QjtRQUMzQyxjQUFjLEVBQUUsS0FBSyxDQUNuQixnQkFBZ0IsRUFBRSxTQUFTLEVBQUUsY0FBYyxFQUFFLG1CQUFtQixDQUFDLGNBQWMsQ0FDaEY7UUFDRCxnQkFBZ0IsRUFBRSxLQUFLLENBQ3JCLGtCQUFrQixFQUFFLFNBQVMsRUFBRSxnQkFBZ0IsRUFBRSxtQkFBbUIsQ0FBQyxnQkFBZ0IsQ0FDdEY7UUFDRCxlQUFlLEVBQUUsS0FBSyxDQUNwQixpQkFBaUIsRUFBRSxTQUFTLEVBQUUsZUFBZSxFQUFFLG1CQUFtQixDQUFDLGVBQWUsQ0FDbkY7UUFDRCxrQkFBa0IsRUFBRSxLQUFLLENBQ3ZCLG9CQUFvQixFQUFFLFNBQVMsRUFBRSxrQkFBa0IsRUFBRSxtQkFBbUIsQ0FBQyxrQkFBa0IsQ0FDNUY7UUFDRCxpQkFBaUIsRUFBRSxLQUFLLENBQ3RCLG1CQUFtQixFQUFFLFNBQVMsRUFBRSxpQkFBaUIsRUFBRSxtQkFBbUIsQ0FBQyxpQkFBaUIsQ0FDekY7UUFDRCxlQUFlLEVBQUUsS0FBSyxDQUNwQixpQkFBaUIsRUFBRSxTQUFTLEVBQUUsZUFBZSxFQUFFLG1CQUFtQixDQUFDLGVBQWUsQ0FDbkY7UUFDRCxxQkFBcUIsRUFBRSxLQUFLLENBQzFCLHVCQUF1QixFQUN2QixTQUFTLEVBQUUscUJBQXFCLEVBQ2hDLG1CQUFtQixDQUFDLHFCQUFxQixDQUMxQztRQUNELGdCQUFnQixFQUFFLEtBQUssQ0FDckIsa0JBQWtCLEVBQUUsU0FBUyxFQUFFLGdCQUFnQixFQUFFLG1CQUFtQixDQUFDLGdCQUFnQixDQUN0RjtRQUNELDBCQUEwQixFQUFFLEtBQUssQ0FDL0IsNEJBQTRCLEVBQzVCLFNBQVMsRUFBRSwwQkFBMEIsRUFDckMsbUJBQW1CLENBQUMsMEJBQTBCLENBQy9DO0tBQ0YsQ0FBQztJQUNGLElBQUksVUFBVSxDQUFDLGVBQWUsR0FBRyxVQUFVLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDM0QsTUFBTSxJQUFJLFVBQVUsQ0FBQyw4REFBOEQsQ0FBQyxDQUFDO0lBQ3ZGLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7QUFDbkMsQ0FBQztBQUVELFNBQVMseUJBQXlCLENBQ2hDLE9BQWUsRUFDZixRQUE0QixFQUM1QixVQUFrQixFQUNsQixVQUFrQixFQUNsQixZQUFxQjtJQUVyQixNQUFNLEtBQUssR0FBRyxRQUFRLElBQUksVUFBVSxDQUFDO0lBQ3JDLElBQ0UsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQztXQUN6QixLQUFLLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1dBQzlCLEtBQUssR0FBRyxVQUFVLEVBQ3JCLENBQUM7UUFDRCxNQUFNLElBQUksVUFBVSxDQUNsQixlQUFlLE9BQU8sWUFBWSxZQUFZLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxZQUFZLGlDQUFpQyxVQUFVLEdBQUcsQ0FDL0gsQ0FBQztJQUNKLENBQUM7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRCxTQUFTLGFBQWEsQ0FBQyxRQUFpQjtJQUN0QyxJQUFJLENBQUMsUUFBUSxJQUFJLE9BQU8sUUFBUSxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQztRQUFFLE9BQU8sS0FBSyxDQUFDO0lBQ3ZGLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDbEQsT0FBTyxTQUFTLEtBQUssTUFBTSxDQUFDLFNBQVMsSUFBSSxTQUFTLEtBQUssSUFBSSxDQUFDO0FBQzlELENBQUM7QUFFRCxTQUFTLGtCQUFrQixDQUFDLFdBQW1CO0lBQzdDLE1BQU0sUUFBUSxHQUFHLFdBQVcsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3ZFLElBQUksUUFBUSxLQUFLLFdBQVcsSUFBSSxRQUFRLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxJQUFJLFFBQVEsS0FBSyxLQUFLLEVBQUUsQ0FBQztRQUN0RixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFDRCxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ25DLE9BQU8sTUFBTSxDQUFDLE1BQU0sS0FBSyxDQUFDO1dBQ3JCLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEdBQUcsQ0FBQztXQUNqRixNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssR0FBRyxDQUFDO0FBQ2pDLENBQUM7QUFFRCxTQUFTLDJCQUEyQixDQUNsQyxRQUFpQixFQUNqQixRQUFnQixFQUNoQixlQUF1QjtJQUV2QixJQUNFLE9BQU8sUUFBUSxLQUFLLFFBQVE7V0FDekIsUUFBUSxDQUFDLE1BQU0sS0FBSyxDQUFDO1dBQ3JCLFdBQVcsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsVUFBVSxHQUFHLGVBQWUsRUFDNUQsQ0FBQztRQUNELE1BQU0sSUFBSSxLQUFLLENBQ2IsZUFBZSxRQUFRLDBDQUEwQyxlQUFlLGVBQWUsQ0FDaEcsQ0FBQztJQUNKLENBQUM7QUFDSCxDQUFDO0FBRUQsTUFBTSxPQUFPLFdBQVc7SUFDdEIsK0VBQStFO0lBQy9FLGlCQUFpQjtJQUNqQiwrRUFBK0U7SUFFL0U7Ozs7Ozs7Ozs7Ozs7Ozs7O09BaUJHO0lBQ0ksTUFBTSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQzlCLGNBQWdELEVBQ2hELFlBQW9CLEVBQ3BCLFVBQXFDLEVBQUU7UUFFdkMsSUFBSSxPQUFPLENBQUMsYUFBYSxLQUFLLFNBQVMsSUFBSSxPQUFPLE9BQU8sQ0FBQyxhQUFhLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDdEYsTUFBTSxJQUFJLFNBQVMsQ0FBQyw4Q0FBOEMsQ0FBQyxDQUFDO1FBQ3RFLENBQUM7UUFDRCxNQUFNLFVBQVUsR0FBRyx5QkFBeUIsQ0FDMUMsWUFBWSxFQUNaLE9BQU8sQ0FBQyxVQUFVLEVBQ2xCLGlDQUFpQyxFQUNqQyxpQ0FBaUMsRUFDakMsSUFBSSxDQUNMLENBQUM7UUFDRixNQUFNLGdCQUFnQixHQUFHLHlCQUF5QixDQUNoRCxrQkFBa0IsRUFDbEIsT0FBTyxDQUFDLGdCQUFnQixFQUN4QixJQUFJLEVBQ0osb0NBQW9DLEVBQ3BDLEtBQUssQ0FDTixDQUFDO1FBQ0YsTUFBTSxZQUFZLEdBQUcseUJBQXlCLENBQzVDLGNBQWMsRUFDZCxPQUFPLENBQUMsWUFBWSxFQUNwQixvQ0FBb0MsRUFDcEMsb0NBQW9DLEVBQ3BDLEtBQUssQ0FDTixDQUFDO1FBQ0YsSUFBSSxnQkFBZ0IsR0FBRyxZQUFZLEVBQUUsQ0FBQztZQUNwQyxNQUFNLElBQUksVUFBVSxDQUFDLDREQUE0RCxDQUFDLENBQUM7UUFDckYsQ0FBQztRQUNELE1BQU0sSUFBSSxHQUE2QjtZQUNyQyxhQUFhLEVBQUUsT0FBTyxDQUFDLGFBQWEsSUFBSSxJQUFJO1lBQzVDLFVBQVU7WUFDVixnQkFBZ0I7WUFDaEIsWUFBWTtZQUNaLFdBQVcsRUFBRSxPQUFPLENBQUMsV0FBVztZQUNoQyx3QkFBd0IsRUFBRSxPQUFPLENBQUMsd0JBQXdCLElBQUksVUFBVTtZQUN4RSxNQUFNLEVBQUUscUJBQXFCLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQztZQUM3QyxpQkFBaUIsRUFBRSxPQUFPLENBQUMsaUJBQWlCO1NBQzdDLENBQUM7UUFFRixNQUFNLFdBQVcsR0FBRyxJQUFJLFdBQVcsQ0FDakMsUUFBUSxFQUNSLGNBQWMsRUFDZCxJQUFJLENBQUMsd0JBQXdCLENBQzlCLENBQUM7UUFDRixXQUFXLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQztRQUNqQyxXQUFXLENBQUMsU0FBUyxHQUFHLFlBQVksQ0FBQztRQUNyQyxXQUFXLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztRQUVuRCxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUUsT0FBTyxFQUFFLENBQUM7WUFDOUIsTUFBTSxXQUFXLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDekIsTUFBTSxXQUFXLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztRQUN2QyxDQUFDO1FBQ0QsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDckIsV0FBVyxDQUFDLG1CQUFtQixHQUFHLEdBQUcsRUFBRTtnQkFDckMsS0FBSyxXQUFXLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDMUIsQ0FBQyxDQUFDO1lBQ0YsSUFBSSxDQUFDLFdBQVcsQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsV0FBVyxDQUFDLG1CQUFtQixFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFDOUYsQ0FBQztRQUVELElBQUksQ0FBQztZQUNILE1BQU0sV0FBVyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQzlCLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxXQUFXLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDekIsTUFBTSxLQUFLLENBQUM7UUFDZCxDQUFDO1FBRUQsT0FBTyxXQUFXLENBQUM7SUFDckIsQ0FBQztJQUVEOzs7T0FHRzthQUNXLCtCQUEwQixHQUFHLEdBQVcsRUFBRTtRQUN0RCxPQUFPLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQ3hGLENBQUMsQUFGdUMsQ0FFdEM7SUFFRjs7Ozs7T0FLRztJQUNJLE1BQU0sQ0FBQyxZQUFZLENBQ3hCLHVCQUFzRCxFQUN0RCxhQUF3QyxFQUFFO1FBRTFDLE1BQU0sWUFBWSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsdUJBQXVCLENBQUM7WUFDekQsQ0FBQyxDQUFDLENBQUMsR0FBRyx1QkFBdUIsQ0FBQztZQUM5QixDQUFDLENBQUMsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO1FBQzlCLElBQUksWUFBWSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUM5QixNQUFNLElBQUksS0FBSyxDQUFDLDZEQUE2RCxDQUFDLENBQUM7UUFDakYsQ0FBQztRQUNELElBQUksSUFBSSxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUMsSUFBSSxLQUFLLFlBQVksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUN2RCxNQUFNLElBQUksS0FBSyxDQUFDLHdFQUF3RSxDQUFDLENBQUM7UUFDNUYsQ0FBQztRQUVELE1BQU0sV0FBVyxHQUFHLElBQUksV0FBVyxDQUNqQyxRQUFRLEVBQ1IsWUFBWSxDQUFDLENBQUMsQ0FBQyxFQUNmLFVBQVUsQ0FBQyx3QkFBd0IsSUFBSSxVQUFVLEVBQ2pELFVBQVUsQ0FBQyw4QkFBOEIsRUFDekMsVUFBVSxDQUFDLGVBQWUsQ0FDM0IsQ0FBQztRQUNGLE1BQU0sY0FBYyxHQUFHLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUM5RCxXQUFXLENBQUMsd0JBQXdCLENBQUMsY0FBYyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQ2xFLE1BQU0sZUFBZSxHQUFHLElBQUksR0FBRyxDQUFDLGNBQWMsQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDO1FBQ2pFLEtBQUssTUFBTSxXQUFXLElBQUksWUFBWSxFQUFFLENBQUM7WUFDdkMsTUFBTSxTQUFTLEdBQUcsV0FBVztpQkFDMUIsY0FBYyxFQUFFO2lCQUNoQixJQUFJLENBQUMsQ0FBQyxTQUFpQixFQUFFLEVBQUUsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7WUFDL0QsSUFBSSxTQUFTLEVBQUUsQ0FBQztnQkFDZCxNQUFNLElBQUksS0FBSyxDQUNiLGtFQUFrRSxTQUFTLElBQUksQ0FDaEYsQ0FBQztZQUNKLENBQUM7UUFDSCxDQUFDO1FBQ0QsTUFBTSxxQkFBcUIsR0FBc0IsRUFBRSxDQUFDO1FBQ3BELE1BQU0sb0JBQW9CLEdBQXNCLEVBQUUsQ0FBQztRQUNuRCxJQUFJLENBQUM7WUFDSCxLQUFLLE1BQU0sV0FBVyxJQUFJLFlBQVksRUFBRSxDQUFDO2dCQUN2QyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLGlCQUFpQixDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUM7Z0JBQzFFLG9CQUFvQixDQUFDLElBQUksQ0FDdkIsV0FBVyxDQUFDLGlDQUFpQyxDQUMzQyxNQUFNLENBQ1AsQ0FDRixDQUFDO1lBQ0osQ0FBQztRQUNILENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsS0FBSyxNQUFNLGtCQUFrQixJQUFJLG9CQUFvQixDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUM7Z0JBQ2hFLGtCQUFrQixFQUFFLENBQUM7WUFDdkIsQ0FBQztZQUNELEtBQUssTUFBTSxvQkFBb0IsSUFBSSxxQkFBcUIsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO2dCQUNuRSxvQkFBb0IsRUFBRSxDQUFDO1lBQ3pCLENBQUM7WUFDRCxNQUFNLEtBQUssQ0FBQztRQUNkLENBQUM7UUFFRCxXQUFXLENBQUMsa0JBQWtCLEdBQUcsWUFBWSxDQUFDO1FBQzlDLFdBQVcsQ0FBQyxxQkFBcUIsR0FBRyxxQkFBcUIsQ0FBQztRQUMxRCxXQUFXLENBQUMsaUNBQWlDLEdBQUcsb0JBQW9CLENBQUM7UUFDckUsT0FBTyxXQUFXLENBQUM7SUFDckIsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O09Bc0JHO0lBQ0ksTUFBTSxDQUFDLGNBQWMsQ0FDMUIsYUFBaUMsRUFDakMsY0FBNkMsRUFDN0MsYUFBd0MsRUFBRTtRQUUxQyxNQUFNLFdBQVcsR0FBRyxXQUFXLENBQUMsWUFBWSxDQUFDLGNBQWMsRUFBRSxVQUFVLENBQUMsQ0FBQztRQUN6RSxJQUFJLENBQUM7WUFDSCxPQUFPLFdBQVcsQ0FBQyxnQkFBZ0IsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUNyRCxDQUFDO1FBQUMsT0FBTyxRQUFRLEVBQUUsQ0FBQztZQUNsQixXQUFXLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztZQUN2QyxNQUFNLFFBQVEsQ0FBQztRQUNqQixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssTUFBTSxDQUFDLHdCQUF3QixDQUNyQyxXQUE2QyxFQUM3QyxjQUEyQjtRQUUzQixXQUFXLENBQUMsZUFBZSxDQUN6QixJQUFJLE9BQU8sQ0FBQyxZQUFZLENBQUMsWUFBWSxDQUFDLHNCQUFzQixFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLEVBQUU7WUFDakYsTUFBTSxJQUFJLEdBQUcsY0FBYyxDQUFDLHlCQUF5QixDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzVELE9BQU8sY0FBYyxDQUFDLGdCQUFnQixDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDdkYsQ0FBQyxDQUFDLENBQ0gsQ0FBQztRQUVGLFdBQVcsQ0FBQyxlQUFlLENBQ3pCLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMseUJBQXlCLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsRUFBRTtZQUNwRixNQUFNLElBQUksR0FBRyxjQUFjLENBQUMseUJBQXlCLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDNUQsT0FBTyxjQUFjLENBQUMsZ0JBQWdCLENBQUMsZUFBZSxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDM0UsQ0FBQyxDQUFDLENBQ0gsQ0FBQztRQUVGLFdBQVcsQ0FBQyxlQUFlLENBQ3pCLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQ25DLHFDQUFxQyxFQUNyQyxLQUFLLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxFQUFFO1lBQ25CLE1BQU0sSUFBSSxHQUFHLGNBQWMsQ0FBQyx5QkFBeUIsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUM1RCxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQztnQkFDL0MsT0FBTztvQkFDTCxhQUFhLEVBQUUsMEJBQTBCO29CQUN6QyxZQUFZLEVBQUUsRUFBRTtvQkFDaEIsUUFBUSxFQUFFLEtBQUs7aUJBQ2hCLENBQUM7WUFDSixDQUFDO1lBQ0QsTUFBTSxRQUFRLEdBQUcsY0FBYyxDQUFDLFdBQVcsQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLEVBQUU7Z0JBQ3BFLGFBQWEsRUFBRSxJQUFJLENBQUMsYUFBYTtnQkFDakMsWUFBWSxFQUFFLElBQUksQ0FBQyxZQUFZO2FBQ2hDLENBQUMsQ0FBQztZQUNILE9BQU87Z0JBQ0wsYUFBYSxFQUFFLFFBQVEsQ0FBQyxhQUFhO2dCQUNyQyxZQUFZLEVBQUUsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxZQUFZLENBQUM7Z0JBQ3hDLFFBQVEsRUFBRSxRQUFRLENBQUMsUUFBUTthQUM1QixDQUFDO1FBQ0osQ0FBQyxDQUNGLENBQ0YsQ0FBQztJQUNKLENBQUM7SUEwREQsK0VBQStFO0lBQy9FLGNBQWM7SUFDZCwrRUFBK0U7SUFFL0UsWUFDRSxPQUF5QixFQUN6QixjQUFnRCxFQUNoRCw4QkFBeUQsVUFBVSxFQUNuRSxpQ0FBbUUsRUFDbkUsa0JBQWdEO1FBeERsRCwrQkFBK0I7UUFDeEIsa0JBQWEsR0FBRyxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBcUIsQ0FBQztRQUNyRSxxQkFBZ0IsR0FBc0IsS0FBSyxDQUFDO1FBRXBELDZCQUE2QjtRQUNyQixjQUFTLEdBQXFCLElBQUksQ0FBQztRQUNuQyx5QkFBb0IsR0FBRyxDQUFDLENBQUM7UUFDekIsMEJBQXFCLEdBQWtDLElBQUksQ0FBQztRQUM1RCw0QkFBdUIsR0FBRyxDQUFDLENBQUM7UUFDNUIsa0JBQWEsR0FBb0MsSUFBSSxDQUFDO1FBQ3RELGNBQVMsR0FBVyxFQUFFLENBQUM7UUFDdkIsZUFBVSxHQUFHLENBQUMsQ0FBQztRQUNmLG1CQUFjLEdBQUcsSUFBSSxDQUFDO1FBQ3RCLFlBQU8sR0FBRyxLQUFLLENBQUM7UUFFaEIsa0JBQWEsR0FBRyxJQUFJLEdBQUcsRUFBYyxDQUFDO1FBQ3RDLG9CQUFlLEdBQUcsSUFBSSxHQUFHLEVBQWlDLENBQUM7UUFDbkUsNEVBQTRFO1FBQ3BFLGVBQVUsR0FBRyxJQUFJLEdBQUcsRUFBbUIsQ0FBQztRQUN4Qyx1QkFBa0IsR0FBRyxJQUFJLEdBQUcsRUFBOEIsQ0FBQztRQUNuRSxrRkFBa0Y7UUFDMUUsc0JBQWlCLEdBQUcsSUFBSSxHQUFHLEVBQXFDLENBQUM7UUFDakUsbUNBQThCLEdBQUcsSUFBSSxHQUFHLEVBQTBDLENBQUM7UUFDbkYsOEJBQXlCLEdBQUcsQ0FBQyxDQUFDO1FBQzlCLDJCQUFzQixHQUFHLElBQUksR0FBRyxFQUF5QixDQUFDO1FBQzFELCtCQUEwQixHQUFHLENBQUMsQ0FBQztRQUMvQixxQ0FBZ0MsR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztRQUVyRSwrQ0FBK0M7UUFDdkMsa0JBQWEsR0FBOEIsSUFBSSxDQUFDO1FBQ2hELHVCQUFrQixHQUF1QyxFQUFFLENBQUM7UUFDNUQsMEJBQXFCLEdBQXNCLEVBQUUsQ0FBQztRQUM5QyxzQ0FBaUMsR0FBc0IsRUFBRSxDQUFDO1FBQzFELG1CQUFjLEdBQUcsS0FBSyxDQUFDO1FBQ3ZCLDhCQUF5QixHQUFHLENBQUMsQ0FBQztRQUM5Qix5Q0FBb0MsR0FBd0IsSUFBSSxDQUFDO1FBQ2pFLGdDQUEyQixHQUFzQixFQUFFLENBQUM7UUFDcEQsa0NBQTZCLEdBQXNCLEVBQUUsQ0FBQztRQUN0RCwwQkFBcUIsR0FBRyxJQUFJLEdBQUcsRUFBaUMsQ0FBQztRQUNqRSxrQ0FBNkIsR0FBRyxJQUFJLEdBQUcsRUFBdUMsQ0FBQztRQUMvRSw0QkFBdUIsR0FBRyxDQUFDLENBQUM7UUFDNUIsa0NBQTZCLEdBQUcsSUFBSSxHQUFHLEVBQWtDLENBQUM7UUFpQmhGLElBQUksQ0FBQyxJQUFJLEdBQUcsT0FBTyxDQUFDO1FBQ3BCLElBQUksQ0FBQyxXQUFXLEdBQUcsY0FBYyxDQUFDO1FBQ2xDLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxpQkFBaUIsQ0FBQztZQUN2QyxJQUFJLEVBQUUsT0FBTztZQUNiLGNBQWMsRUFBRSwyQkFBMkI7U0FDNUMsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLDhCQUE4QixHQUFHLGlDQUFpQyxDQUFDO1FBQ3hFLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLDJCQUEyQixDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFDNUUsSUFBSSxDQUFDLHVCQUF1QixHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsdUJBQXVCLENBQUM7UUFDeEUsSUFBSSxPQUFPLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDekIsSUFBSSxrQkFBNEMsQ0FBQztZQUNqRCxJQUFJLDBCQUFvRCxDQUFDO1lBQ3pELElBQUksQ0FBQztnQkFDSCxrQkFBa0IsR0FBRyxjQUFjLENBQUMsaUNBQWlDLENBQ25FLE1BQU0sQ0FDUCxDQUFDO2dCQUNGLDBCQUEwQixHQUFHLGNBQWMsQ0FBQyxxQ0FBcUMsQ0FDL0UsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyw4QkFBOEIsRUFBRSxDQUN4RCxDQUFDO2dCQUNGLElBQUksQ0FBQyxpQ0FBaUMsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsQ0FBQztnQkFDaEUsSUFBSSxDQUFDLDJCQUEyQixDQUFDLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO1lBQ3BFLENBQUM7WUFBQyxPQUFPLFFBQVEsRUFBRSxDQUFDO2dCQUNsQiwwQkFBMEIsRUFBRSxFQUFFLENBQUM7Z0JBQy9CLGtCQUFrQixFQUFFLEVBQUUsQ0FBQztnQkFDdkIsTUFBTSxRQUFRLENBQUM7WUFDakIsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxnQkFBZ0IsQ0FBQyxhQUFpQztRQUN2RCxJQUFJLElBQUksQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDM0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxnREFBZ0QsQ0FBQyxDQUFDO1FBQ3BFLENBQUM7UUFDRCxJQUFJLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN4QixNQUFNLElBQUksS0FBSyxDQUFDLG9FQUFvRSxDQUFDLENBQUM7UUFDeEYsQ0FBQztRQUNELElBQUksSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQ3ZCLElBQUksSUFBSSxDQUFDLGFBQWEsS0FBSyxhQUFhLEVBQUUsQ0FBQztnQkFDekMsT0FBTyxJQUFJLENBQUM7WUFDZCxDQUFDO1lBQ0QsTUFBTSxJQUFJLEtBQUssQ0FBQyxrRUFBa0UsQ0FBQyxDQUFDO1FBQ3RGLENBQUM7UUFFRCxNQUFNLGVBQWUsR0FBc0IsRUFBRSxDQUFDO1FBQzlDLE1BQU0sb0JBQW9CLEdBQXNCLEVBQUUsQ0FBQztRQUNuRCxJQUFJLFdBQXFDLENBQUM7UUFDMUMsSUFBSSxvQkFBb0IsR0FBRyxLQUFLLENBQUM7UUFDakMsSUFBSSxDQUFDO1lBQ0gsS0FBSyxNQUFNLFdBQVcsSUFBSSxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztnQkFDbEQsb0JBQW9CLENBQUMsSUFBSSxDQUN2QixXQUFXLENBQUMsc0NBQXNDLENBQUMsQ0FBQyxXQUFXLEVBQUUsVUFBVSxFQUFFLEVBQUU7b0JBQzdFLE9BQU8sSUFBSSxDQUFDLCtCQUErQixDQUN6QyxXQUFXLEVBQ1gsVUFBVSxDQUFDLFdBQVcsRUFDdEIsVUFBVSxDQUFDLGdCQUFnQixDQUM1QixDQUFDO2dCQUNKLENBQUMsQ0FBQyxDQUNILENBQUM7Z0JBQ0YsZUFBZSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMscUNBQXFDLENBQUMsQ0FBQyxtQkFBbUIsRUFBRSxFQUFFO29CQUM3RixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsYUFBYTt3QkFDN0IsRUFBRSx1QkFBdUIsRUFBRTt5QkFDMUIsSUFBSSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxPQUFPLEtBQUssbUJBQW1CLENBQUMsSUFBSSxDQUFDLENBQUM7b0JBQzNELE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLDhCQUE4QixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7Z0JBQ2xGLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDTixDQUFDO1lBQ0QsV0FBVyxHQUFHLGFBQWEsQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFO2dCQUN4RSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUMvQyxJQUFJLENBQUMsa0NBQWtDLENBQ3JDLE9BQU8sRUFDUCxJQUFJLEtBQUssQ0FBQyx5Q0FBeUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQ2pFLENBQUM7WUFDSixDQUFDLENBQUMsQ0FBQztZQUNILElBQUksQ0FBQyxXQUFXLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDaEMsb0JBQW9CLEdBQUcsSUFBSSxDQUFDO1lBQzVCLElBQUksQ0FBQyx5QkFBeUIsRUFBRSxDQUFDO1lBQ2pDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyx3QkFBd0IsQ0FDNUMsR0FBRyxFQUFFLENBQUMsYUFBYSxDQUFDLHVCQUF1QixFQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7Z0JBQy9ELE1BQU0sY0FBYyxHQUFHLE9BQU8sQ0FBQyxjQUFjLENBQUM7Z0JBQzlDLE9BQU8sT0FBTyxDQUFDLGNBQWMsSUFBSSxJQUFJLENBQUMsa0JBQWtCLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUM7WUFDckYsQ0FBQyxDQUFDLENBQ0gsQ0FBQztZQUNGLElBQUksQ0FBQyxhQUFhLEdBQUcsYUFBYSxDQUFDO1lBQ25DLElBQUksQ0FBQywyQkFBMkIsR0FBRyxlQUFlLENBQUM7WUFDbkQsSUFBSSxDQUFDLDZCQUE2QixHQUFHLG9CQUFvQixDQUFDO1lBQzFELElBQUksQ0FBQyxvQ0FBb0MsR0FBRyxXQUFXLENBQUM7WUFDeEQsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBQUMsT0FBTyxRQUFRLEVBQUUsQ0FBQztZQUNsQixXQUFXLEVBQUUsRUFBRSxDQUFDO1lBQ2hCLElBQUksb0JBQW9CLEVBQUUsQ0FBQztnQkFDekIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUNsQyxDQUFDO1lBQ0QsSUFBSSxDQUFDLGdCQUFnQixDQUFDLHdCQUF3QixDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQzFELEtBQUssTUFBTSxtQkFBbUIsSUFBSSxvQkFBb0IsQ0FBQyxPQUFPLEVBQUU7Z0JBQUUsbUJBQW1CLEVBQUUsQ0FBQztZQUN4RixLQUFLLE1BQU0sY0FBYyxJQUFJLGVBQWUsQ0FBQyxPQUFPLEVBQUU7Z0JBQUUsY0FBYyxFQUFFLENBQUM7WUFDekUsTUFBTSxRQUFRLENBQUM7UUFDakIsQ0FBQztJQUNILENBQUM7SUFFRCwrRUFBK0U7SUFDL0UsaUJBQWlCO0lBQ2pCLCtFQUErRTtJQUUvRTs7T0FFRztJQUNLLEtBQUssQ0FBQyxPQUFPO1FBQ25CLElBQUksSUFBSSxDQUFDLE9BQU8sSUFBSSxJQUFJLENBQUMsYUFBYSxFQUFFLFdBQVcsRUFBRSxPQUFPLEVBQUUsQ0FBQztZQUM3RCxNQUFNLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBQ2hDLENBQUM7UUFFRCxNQUFNLElBQUksR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBUSxDQUFDO1FBQ2hELElBQUksaUJBQWlCLEdBQUcsS0FBSyxDQUFDO1FBQzlCLElBQUksaUJBQTRELENBQUM7UUFDakUsSUFBSSxlQUF5QyxDQUFDO1FBRTlDLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxRQUFnQixFQUFFLEVBQUU7WUFDNUMsSUFBSSxpQkFBaUIsRUFBRSxDQUFDO2dCQUN0QixPQUFPO1lBQ1QsQ0FBQztZQUNELGlCQUFpQixHQUFHLElBQUksQ0FBQztZQUN6QixJQUFJLGlCQUFpQixFQUFFLENBQUM7Z0JBQ3RCLFlBQVksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1lBQ2xDLENBQUM7WUFDRCxJQUFJLGVBQWUsRUFBRSxDQUFDO2dCQUNwQixJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQztnQkFDM0MsSUFBSSxDQUFDLGFBQWEsRUFBRSxXQUFXLEVBQUUsbUJBQW1CLENBQUMsT0FBTyxFQUFFLGVBQWUsQ0FBQyxDQUFDO1lBQ2pGLENBQUM7WUFDRCxJQUFJLFFBQVEsRUFBRSxDQUFDO2dCQUNiLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDeEIsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNqQixDQUFDO1FBQ0gsQ0FBQyxDQUFDO1FBRUYsSUFBSSxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUVoQyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNsRCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDdEQsSUFBSSxDQUFDLFFBQVEsQ0FBQyw2QkFBNkIsV0FBVyxLQUFLLENBQUMsQ0FBQztRQUU3RCxJQUFJLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1lBQy9CLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxJQUFJLENBQUMscUJBQXFCLEVBQUUsSUFBSSxLQUFLLENBQUMsaUNBQWlDLENBQUMsQ0FBQyxDQUFDO1FBQzVHLENBQUM7UUFDRCxNQUFNLFVBQVUsR0FBRyxFQUFFLElBQUksQ0FBQyxvQkFBb0IsQ0FBQztRQUMvQyxNQUFNLFNBQVMsR0FBRyxJQUFJLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN2QyxTQUFTLENBQUMsVUFBVSxHQUFHLGFBQWEsQ0FBQztRQUNyQyxJQUFJLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQztRQUMzQixNQUFNLGVBQWUsR0FBMkI7WUFDOUMsVUFBVTtZQUNWLFlBQVksRUFBRSxPQUFPLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyx3QkFBd0IsRUFBRTtZQUNuRSxTQUFTO1lBQ1QsZUFBZSxFQUFFLElBQUksZUFBZSxFQUFFO1lBQ3RDLGdCQUFnQixFQUFFLEVBQUU7WUFDcEIsZUFBZSxFQUFFLENBQUM7WUFDbEIsY0FBYyxFQUFFLENBQUM7U0FDbEIsQ0FBQztRQUNGLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxlQUFlLENBQUM7UUFDN0MsSUFBSSxDQUFDLFdBQVcsQ0FBQyxvQkFBb0IsQ0FBQyxTQUFTLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFFN0QsZUFBZSxHQUFHLEdBQUcsRUFBRTtZQUNyQixJQUFJLElBQUksQ0FBQyxTQUFTLEtBQUssU0FBUyxJQUFJLElBQUksQ0FBQyxvQkFBb0IsS0FBSyxVQUFVLEVBQUUsQ0FBQztnQkFDN0UsU0FBUyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3BCLENBQUM7WUFDRCxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxDQUFDO1FBQzVDLENBQUMsQ0FBQztRQUNGLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQ3hDLElBQUksQ0FBQyxhQUFhLEVBQUUsV0FBVyxFQUFFLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxlQUFlLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUU1RixpQkFBaUIsR0FBRyxVQUFVLENBQUMsR0FBRyxFQUFFO1lBQ2xDLElBQUksSUFBSSxDQUFDLGdCQUFnQixLQUFLLFdBQVcsRUFBRSxDQUFDO2dCQUMxQyxJQUFJLENBQUMsWUFBWSxDQUFDLHNDQUFzQyxXQUFXLEVBQUUsQ0FBQyxDQUFDO2dCQUN2RSxJQUFJLElBQUksQ0FBQyxTQUFTLEtBQUssU0FBUyxJQUFJLElBQUksQ0FBQyxvQkFBb0IsS0FBSyxVQUFVLEVBQUUsQ0FBQztvQkFDN0UsU0FBUyxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUNwQixDQUFDO2dCQUNELGdCQUFnQixDQUFDLElBQUksS0FBSyxDQUFDLG9CQUFvQixDQUFDLENBQUMsQ0FBQztZQUNwRCxDQUFDO1FBQ0gsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRVYsU0FBUyxDQUFDLE1BQU0sR0FBRyxLQUFLLElBQUksRUFBRTtZQUM1QixJQUFJLENBQUM7Z0JBQ0gsSUFBSSxJQUFJLENBQUMsU0FBUyxLQUFLLFNBQVMsSUFBSSxJQUFJLENBQUMsb0JBQW9CLEtBQUssVUFBVTtvQkFBRSxPQUFPO2dCQUNyRixNQUFNLElBQUksQ0FBQywyQkFBMkIsQ0FBQyxTQUFTLEVBQUUsVUFBVSxDQUFDLENBQUM7Z0JBQzlELElBQUksSUFBSSxDQUFDLFNBQVMsS0FBSyxTQUFTLElBQUksSUFBSSxDQUFDLG9CQUFvQixLQUFLLFVBQVU7b0JBQUUsT0FBTztnQkFDckYsTUFBTSxJQUFJLENBQUMsdUJBQXVCLENBQUMsZUFBZSxDQUFDLENBQUM7Z0JBQ3BELElBQUksSUFBSSxDQUFDLFNBQVMsS0FBSyxTQUFTLElBQUksSUFBSSxDQUFDLG9CQUFvQixLQUFLLFVBQVU7b0JBQUUsT0FBTztnQkFDckYsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMsZUFBZSxDQUFDLENBQUM7Z0JBQzlDLElBQ0UsSUFBSSxDQUFDLFNBQVMsS0FBSyxTQUFTO3VCQUN6QixJQUFJLENBQUMsb0JBQW9CLEtBQUssVUFBVTt1QkFDeEMsU0FBUyxDQUFDLFVBQVUsS0FBSyxTQUFTLENBQUMsSUFBSSxFQUMxQyxDQUFDO29CQUNELE1BQU0sSUFBSSxLQUFLLENBQUMsNERBQTRELENBQUMsQ0FBQztnQkFDaEYsQ0FBQztnQkFDRCxJQUFJLENBQUMsUUFBUSxDQUFDLHlEQUF5RCxDQUFDLENBQUM7Z0JBQ3pFLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxDQUFDO2dCQUNwQixJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxhQUFhLEVBQUUsZ0JBQWdCLElBQUksSUFBSSxDQUFDO2dCQUNuRSxJQUFJLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxDQUFDO2dCQUMvQixnQkFBZ0IsRUFBRSxDQUFDO1lBQ3JCLENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNmLE1BQU0sZ0JBQWdCLEdBQUcsS0FBSyxZQUFZLEtBQUs7b0JBQzdDLENBQUMsQ0FBQyxLQUFLO29CQUNQLENBQUMsQ0FBQyxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztnQkFDN0IsSUFBSSxDQUFDLFlBQVksQ0FBQyxxREFBcUQsQ0FBQyxDQUFDO2dCQUN6RSxnQkFBZ0IsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO2dCQUNuQyxTQUFTLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDcEIsQ0FBQztRQUNILENBQUMsQ0FBQztRQUVGLFNBQVMsQ0FBQyxTQUFTLEdBQUcsQ0FBQyxLQUFLLEVBQUUsRUFBRTtZQUM5QixJQUFJLElBQUksQ0FBQyxTQUFTLEtBQUssU0FBUyxJQUFJLElBQUksQ0FBQyxvQkFBb0IsS0FBSyxVQUFVO2dCQUFFLE9BQU87WUFDckYsSUFBSSxPQUFPLEtBQUssQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQ25DLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxlQUFlLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUN6RCxPQUFPO1lBQ1QsQ0FBQztZQUNELElBQUksS0FBSyxDQUFDLElBQUksWUFBWSxXQUFXLElBQUksV0FBVyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztnQkFDeEUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxxQkFBcUIsQ0FBQyxTQUFTLEVBQUUsVUFBVSxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDMUUsT0FBTztZQUNULENBQUM7WUFDRCxTQUFTLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSwrQkFBK0IsQ0FBQyxDQUFDO1FBQ3pELENBQUMsQ0FBQztRQUVGLFNBQVMsQ0FBQyxPQUFPLEdBQUcsR0FBRyxFQUFFO1lBQ3ZCLElBQUksSUFBSSxDQUFDLFNBQVMsS0FBSyxTQUFTLElBQUksSUFBSSxDQUFDLG9CQUFvQixLQUFLLFVBQVU7Z0JBQUUsT0FBTztZQUNyRixJQUFJLENBQUMsMEJBQTBCLENBQUMsZUFBZSxFQUFFLElBQUksS0FBSyxDQUFDLDBCQUEwQixDQUFDLENBQUMsQ0FBQztZQUN4RixJQUFJLENBQUMsV0FBVyxDQUFDLHNCQUFzQixDQUFDLFNBQVMsRUFBRSxVQUFVLEVBQUUsSUFBSSxLQUFLLENBQUMsMEJBQTBCLENBQUMsQ0FBQyxDQUFDO1lBQ3RHLElBQUksSUFBSSxDQUFDLGdCQUFnQixLQUFLLFdBQVcsRUFBRSxDQUFDO2dCQUMxQyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUMxQixDQUFDO2lCQUFNLENBQUM7Z0JBQ04sSUFBSSxDQUFDLDJCQUEyQixDQUFDLElBQUksS0FBSyxDQUFDLDBCQUEwQixDQUFDLENBQUMsQ0FBQztnQkFDeEUsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLE9BQU8sSUFBSSxJQUFJLENBQUMsYUFBYSxFQUFFLFdBQVcsRUFBRSxPQUFPO29CQUN2RSxDQUFDLENBQUMsSUFBSSxDQUFDLGdCQUFnQixFQUFFO29CQUN6QixDQUFDLENBQUMsSUFBSSxLQUFLLENBQUMsZ0RBQWdELENBQUMsQ0FBQyxDQUFDO1lBQ25FLENBQUM7UUFDSCxDQUFDLENBQUM7UUFFRixTQUFTLENBQUMsT0FBTyxHQUFHLEdBQUcsRUFBRTtZQUN2QixJQUFJLElBQUksQ0FBQyxTQUFTLEtBQUssU0FBUyxJQUFJLElBQUksQ0FBQyxvQkFBb0IsS0FBSyxVQUFVO2dCQUFFLE9BQU87WUFDckYsMEVBQTBFO1lBQzFFLHdFQUF3RTtZQUN4RSxJQUFJLENBQUMsWUFBWSxDQUFDLGtDQUFrQyxXQUFXLEVBQUUsQ0FBQyxDQUFDO1FBQ3JFLENBQUMsQ0FBQztRQUVGLElBQUksQ0FBQztZQUNILE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQztRQUNyQixDQUFDO1FBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztZQUNiLElBQUksaUJBQWlCLEVBQUUsQ0FBQztnQkFDdEIsWUFBWSxDQUFDLGlCQUFpQixDQUFDLENBQUM7WUFDbEMsQ0FBQztZQUNELElBQ0UsQ0FBQyxDQUFDLEdBQUcsWUFBWSx5QkFBeUIsQ0FBQzttQkFDeEMsQ0FBQyxDQUFDLEdBQUcsWUFBWSwrQkFBK0IsQ0FBQzttQkFDakQsQ0FBQyxDQUFDLEdBQUcsWUFBWSx1Q0FBdUMsQ0FBQzttQkFDekQsSUFBSSxDQUFDLGVBQWUsRUFBRSxFQUN6QixDQUFDO2dCQUNELE1BQU0sSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7Z0JBQy9CLElBQUksSUFBSSxDQUFDLGdCQUFnQixLQUFLLFdBQVcsRUFBRSxDQUFDO29CQUMxQyxNQUFNLElBQUksQ0FBQyxPQUFPLElBQUksSUFBSSxDQUFDLGFBQWEsRUFBRSxXQUFXLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO2dCQUNqRyxDQUFDO1lBQ0gsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLE1BQU0sR0FBRyxDQUFDO1lBQ1osQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRU8sS0FBSyxDQUFDLDJCQUEyQixDQUN2QyxZQUF1QixFQUN2QixhQUFxQjtRQUVyQixNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLGlDQUFpQyxFQUFFLENBQUM7UUFDM0UsSUFBSSxrQkFBMEQsQ0FBQztRQUMvRCxJQUFJLENBQUM7WUFDSCxNQUFNLE9BQU8sR0FBK0I7Z0JBQzFDLE1BQU0sRUFBRSxxQ0FBcUM7Z0JBQzdDLE9BQU8sRUFBRTtvQkFDUCxhQUFhLEVBQUUsYUFBYSxDQUFDLGFBQWE7b0JBQzFDLFlBQVksRUFBRSxDQUFDLEdBQUcsYUFBYSxDQUFDLFlBQVksQ0FBQztpQkFDOUM7Z0JBQ0QsUUFBUSxFQUFFO29CQUNSLGFBQWEsRUFBRSxDQUFDO29CQUNoQixZQUFZLEVBQUUsRUFBRTtvQkFDaEIsUUFBUSxFQUFFLEtBQUs7aUJBQ2hCO2FBQ0YsQ0FBQztZQUNGLE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLEVBQUU7Z0JBQy9DLFNBQVMsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUM7YUFDakYsQ0FBQyxDQUFDO1lBQ0gsSUFBSSxRQUFRLENBQUMsS0FBSztnQkFBRSxNQUFNLElBQUkseUJBQXlCLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUM3RSxJQUNFLENBQUMsUUFBUSxDQUFDLFFBQVE7bUJBQ2YsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDO21CQUN0RCxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUM7bUJBQzlDLFFBQVEsQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDLGFBQWEsRUFBRSxFQUFFLENBQUMsT0FBTyxhQUFhLEtBQUssUUFBUSxDQUFDO21CQUN6RixPQUFPLFFBQVEsQ0FBQyxRQUFRLENBQUMsUUFBUSxLQUFLLFNBQVMsRUFDbEQsQ0FBQztnQkFDRCxNQUFNLElBQUkseUJBQXlCLENBQUMsb0RBQW9ELENBQUMsQ0FBQztZQUM1RixDQUFDO1lBQ0Qsa0JBQWtCLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQztRQUN6QyxDQUFDO1FBQUMsT0FBTyxRQUFRLEVBQUUsQ0FBQztZQUNsQixJQUFJLElBQUksQ0FBQyxhQUFhLEVBQUUsd0JBQXdCLEtBQUssVUFBVSxFQUFFLENBQUM7Z0JBQ2hFLE1BQU0sUUFBUSxZQUFZLHlCQUF5QjtvQkFDakQsQ0FBQyxDQUFDLFFBQVE7b0JBQ1YsQ0FBQyxDQUFDLElBQUkseUJBQXlCLENBQUMsNENBQTRDLEVBQUU7d0JBQzFFLEtBQUssRUFBRSxRQUFRO3FCQUNoQixDQUFDLENBQUM7WUFDVCxDQUFDO1lBQ0QsSUFBSSxDQUFDLFdBQVcsQ0FBQyw2QkFBNkIsQ0FBQyxZQUFZLEVBQUUsYUFBYSxDQUFDLENBQUM7WUFDNUUsT0FBTztRQUNULENBQUM7UUFDRCxJQUNFLGtCQUFrQixDQUFDLFFBQVE7ZUFDeEIsQ0FDRCxrQkFBa0IsQ0FBQyxhQUFhLEtBQUssMEJBQTBCO21CQUM1RCxrQkFBa0IsQ0FBQyxZQUFZLENBQUMsTUFBTSxLQUFLLENBQUM7bUJBQzVDLGtCQUFrQixDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsS0FBSyxvQkFBb0I7bUJBQzNELElBQUksQ0FBQyxhQUFhLEVBQUUsd0JBQXdCLEtBQUssVUFBVSxDQUMvRCxFQUNELENBQUM7WUFDRCxNQUFNLElBQUkseUJBQXlCLENBQUMsNENBQTRDLENBQUMsQ0FBQztRQUNwRixDQUFDO1FBQ0QsSUFBSSxDQUFDLFdBQVcsQ0FBQyx5QkFBeUIsQ0FBQyxZQUFZLEVBQUUsYUFBYSxFQUFFLGtCQUFrQixDQUFDLENBQUM7SUFDOUYsQ0FBQztJQUVPLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxRQUFnQztRQUNwRSxNQUFNLGlCQUFpQixHQUFHLElBQUksQ0FBQyxhQUFhLEVBQUUsaUJBQWlCLENBQUM7UUFDaEUsSUFBSSxDQUFDLGlCQUFpQjtZQUFFLE9BQU87UUFDL0IsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUMsTUFBTSxDQUFDO1FBQ2xELElBQUksSUFBSSxDQUFDLHVCQUF1QixJQUFJLE1BQU0sQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQzdELE1BQU0sSUFBSSx1Q0FBdUMsQ0FDL0MsaUVBQWlFLENBQ2xFLENBQUM7UUFDSixDQUFDO1FBRUQsTUFBTSxTQUFTLEdBQUcsTUFBTSxDQUFDLDBCQUEwQixDQUFDO1FBQ3BELE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxTQUFTLENBQUM7UUFDeEMsTUFBTSwwQkFBMEIsR0FBRyxJQUFJLGVBQWUsRUFBRSxDQUFDO1FBQ3pELE1BQU0sb0JBQW9CLEdBQUcsR0FBRyxFQUFFO1lBQ2hDLDBCQUEwQixDQUFDLEtBQUssQ0FBQyxJQUFJLHVDQUF1QyxDQUMxRSxxREFBcUQsQ0FDdEQsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDO1FBQ0YsUUFBUSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLG9CQUFvQixFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFDaEcsSUFBSSxRQUFRLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxPQUFPO1lBQUUsb0JBQW9CLEVBQUUsQ0FBQztRQUNwRSxNQUFNLGtCQUFrQixHQUFzQyxDQUU1RCxhQUEwQixFQUF3QyxFQUFFO1lBQ3BFLElBQUksMEJBQTBCLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUM5QyxNQUFNLElBQUksdUNBQXVDLENBQy9DLDZEQUE2RCxDQUM5RCxDQUFDO1lBQ0osQ0FBQztZQUNELE1BQU0sV0FBVyxHQUFHLFFBQVEsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDMUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLElBQUksV0FBVyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUMxRCxNQUFNLElBQUksdUNBQXVDLENBQy9DLG1FQUFtRSxDQUNwRSxDQUFDO1lBQ0osQ0FBQztZQUNELE9BQU8sSUFBSSxDQUFDLGtCQUFrQixDQUFJLGFBQWEsRUFBRSxTQUFTLEVBQUU7Z0JBQzFELFNBQVMsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLFdBQVcsR0FBRyxDQUFDLEVBQUUsTUFBTSxDQUFDLGdCQUFnQixDQUFDO2dCQUM3RCxXQUFXLEVBQUUsMEJBQTBCLENBQUMsTUFBTTthQUMvQyxDQUFDLENBQUM7UUFDTCxDQUFDLENBQUM7UUFDRixJQUFJLENBQUMsdUJBQXVCLEVBQUUsQ0FBQztRQUMvQixNQUFNLGVBQWUsR0FBRyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUM7WUFDbkYsWUFBWSxFQUFFLFFBQVEsQ0FBQyxZQUFZO1lBQ25DLFdBQVcsRUFBRSwwQkFBMEIsQ0FBQyxNQUFNO1lBQzlDLFFBQVE7WUFDUixrQkFBa0I7U0FDbkIsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNMLEtBQUssZUFBZSxDQUFDLElBQUksQ0FDdkIsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLHVCQUF1QixFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQ3pDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUMxQyxDQUFDO1FBRUYsSUFBSSxPQUFrRCxDQUFDO1FBQ3ZELElBQUksYUFBdUMsQ0FBQztRQUM1QyxNQUFNLFdBQVcsR0FBRyxJQUFJLE9BQU8sQ0FBUSxDQUFDLFdBQVcsRUFBRSxTQUFTLEVBQUUsRUFBRTtZQUNoRSxPQUFPLEdBQUcsVUFBVSxDQUFDLEdBQUcsRUFBRTtnQkFDeEIsTUFBTSxLQUFLLEdBQUcsSUFBSSx1Q0FBdUMsQ0FDdkQsK0NBQStDLENBQ2hELENBQUM7Z0JBQ0YsMEJBQTBCLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUN4QyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDbkIsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1lBQ2QsYUFBYSxHQUFHLEdBQUcsRUFBRTtnQkFDbkIsTUFBTSxNQUFNLEdBQUcsMEJBQTBCLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQztnQkFDeEQsU0FBUyxDQUFDLE1BQU0sWUFBWSx1Q0FBdUM7b0JBQ2pFLENBQUMsQ0FBQyxNQUFNO29CQUNSLENBQUMsQ0FBQyxJQUFJLHVDQUF1QyxDQUN6QyxxREFBcUQsQ0FDdEQsQ0FBQyxDQUFDO1lBQ1QsQ0FBQyxDQUFDO1lBQ0YsMEJBQTBCLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxhQUFhLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztZQUMzRixJQUFJLDBCQUEwQixDQUFDLE1BQU0sQ0FBQyxPQUFPO2dCQUFFLGFBQWEsRUFBRSxDQUFDO1FBQ2pFLENBQUMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDO1lBQ0gsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsZUFBZSxFQUFFLFdBQVcsQ0FBQyxDQUFDLENBQUM7UUFDckQsQ0FBQztRQUFDLE9BQU8sUUFBUSxFQUFFLENBQUM7WUFDbEIsSUFBSSxRQUFRLFlBQVksdUNBQXVDO2dCQUFFLE1BQU0sUUFBUSxDQUFDO1lBQ2hGLE1BQU0sSUFBSSx1Q0FBdUMsQ0FDL0MsZ0RBQWdELENBQ2pELENBQUM7UUFDSixDQUFDO2dCQUFTLENBQUM7WUFDVCxJQUFJLE9BQU87Z0JBQUUsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ25DLElBQUksYUFBYSxFQUFFLENBQUM7Z0JBQ2xCLDBCQUEwQixDQUFDLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxPQUFPLEVBQUUsYUFBYSxDQUFDLENBQUM7WUFDaEYsQ0FBQztZQUNELFFBQVEsQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLG1CQUFtQixDQUFDLE9BQU8sRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO1lBQ25GLDBCQUEwQixDQUFDLEtBQUssQ0FBQyxJQUFJLHVDQUF1QyxDQUMxRSx3REFBd0QsQ0FDekQsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUNELElBQUksQ0FBQyxJQUFJLENBQUMseUJBQXlCLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUM5QyxNQUFNLElBQUksdUNBQXVDLENBQy9DLG9EQUFvRCxDQUNyRCxDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNLLGNBQWMsQ0FBQyxHQUFXO1FBQ2hDLE1BQU0sTUFBTSxHQUFHLElBQUksR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzVCLElBQUksTUFBTSxDQUFDLFFBQVEsSUFBSSxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDdkMsTUFBTSxJQUFJLEtBQUssQ0FBQyxtREFBbUQsQ0FBQyxDQUFDO1FBQ3ZFLENBQUM7UUFDRCxJQUFJLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNoQixNQUFNLElBQUksS0FBSyxDQUFDLHFEQUFxRCxDQUFDLENBQUM7UUFDekUsQ0FBQztRQUNELE1BQU0sVUFBVSxHQUFHLENBQUMsR0FBRyxFQUFFO1lBQ3ZCLFFBQVEsTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDO2dCQUN4QixLQUFLLE9BQU8sQ0FBQztnQkFDYixLQUFLLEtBQUs7b0JBQ1IsT0FBTyxLQUFLLENBQUM7Z0JBQ2YsS0FBSyxRQUFRLENBQUM7Z0JBQ2QsS0FBSyxNQUFNO29CQUNULE9BQU8sTUFBTSxDQUFDO2dCQUNoQjtvQkFDRSxNQUFNLElBQUksS0FBSyxDQUFDLDBEQUEwRCxDQUFDLENBQUM7WUFDaEYsQ0FBQztRQUNILENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDTCxJQUFJLFVBQVUsS0FBSyxLQUFLLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUNqRSxNQUFNLElBQUksS0FBSyxDQUFDLDJFQUEyRSxDQUFDLENBQUM7UUFDL0YsQ0FBQztRQUNELE1BQU0sQ0FBQyxRQUFRLEdBQUcsVUFBVSxDQUFDO1FBQzdCLE9BQU8sTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQzNCLENBQUM7SUFFTyxxQkFBcUIsQ0FBQyxNQUFjO1FBQzFDLE1BQU0sTUFBTSxHQUFHLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQy9CLE9BQU8sR0FBRyxNQUFNLENBQUMsUUFBUSxLQUFLLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUM5QyxDQUFDO0lBRU8sc0JBQXNCLENBQzVCLFFBQWdDLEVBQ2hDLE9BQWU7UUFFZixJQUFJLENBQUMsSUFBSSxDQUFDLHlCQUF5QixDQUFDLFFBQVEsQ0FBQztZQUFFLE9BQU87UUFDdEQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUMsTUFBTSxDQUFDO1FBQ2xELE1BQU0sVUFBVSxHQUFHLFdBQVcsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsVUFBVSxDQUFDO1FBQzFELElBQUksVUFBVSxHQUFHLE1BQU0sQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN2QyxRQUFRLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsOENBQThDLENBQUMsQ0FBQztZQUMvRSxPQUFPO1FBQ1QsQ0FBQztRQUNELElBQ0UsUUFBUSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sSUFBSSxNQUFNLENBQUMsZ0JBQWdCO2VBQ3hELFFBQVEsQ0FBQyxlQUFlLEdBQUcsVUFBVSxHQUFHLE1BQU0sQ0FBQyxlQUFlLEVBQ2pFLENBQUM7WUFDRCxRQUFRLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsOENBQThDLENBQUMsQ0FBQztZQUMvRSxPQUFPO1FBQ1QsQ0FBQztRQUNELFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUM7UUFDOUQsUUFBUSxDQUFDLGVBQWUsSUFBSSxVQUFVLENBQUM7UUFDdkMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ3ZDLENBQUM7SUFFTyxxQkFBcUIsQ0FBQyxRQUFnQztRQUM1RCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQyxNQUFNLENBQUM7UUFDbEQsT0FDRSxJQUFJLENBQUMseUJBQXlCLENBQUMsUUFBUSxDQUFDO2VBQ3JDLENBQUMsUUFBUSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsT0FBTztlQUN4QyxRQUFRLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxHQUFHLENBQUM7ZUFDcEMsUUFBUSxDQUFDLGNBQWMsR0FBRyxNQUFNLENBQUMsa0JBQWtCLEVBQ3RELENBQUM7WUFDRCxJQUFJLElBQUksQ0FBQyx1QkFBdUIsSUFBSSxNQUFNLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztnQkFDN0QsUUFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLHlDQUF5QyxDQUFDLENBQUM7Z0JBQzFFLE9BQU87WUFDVCxDQUFDO1lBQ0QsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLGdCQUFnQixDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2hELElBQUksQ0FBQyxLQUFLO2dCQUFFLE9BQU87WUFDbkIsUUFBUSxDQUFDLGVBQWUsSUFBSSxLQUFLLENBQUMsVUFBVSxDQUFDO1lBQzdDLFFBQVEsQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUMxQixJQUFJLENBQUMsdUJBQXVCLEVBQUUsQ0FBQztZQUMvQixLQUFLLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxRQUFRLENBQUM7aUJBQzFDLEtBQUssQ0FBQyxHQUFHLEVBQUU7Z0JBQ1YsSUFBSSxJQUFJLENBQUMseUJBQXlCLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztvQkFDN0MsUUFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLDhDQUE4QyxDQUFDLENBQUM7Z0JBQ2pGLENBQUM7WUFDSCxDQUFDLENBQUM7aUJBQ0QsT0FBTyxDQUFDLEdBQUcsRUFBRTtnQkFDWixRQUFRLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQzFCLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO2dCQUMvQixJQUFJLENBQUMscUJBQXFCLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDdkMsQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDO0lBQ0gsQ0FBQztJQUVPLG9CQUFvQixDQUMxQixRQUFpQjtRQU9qQixJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLFdBQVcsQ0FBQyxFQUFFLENBQUM7WUFDckUsTUFBTSxJQUFJLEtBQUssQ0FBQyxnREFBZ0QsQ0FBQyxDQUFDO1FBQ3BFLENBQUM7UUFDRCwyQkFBMkIsQ0FDekIsUUFBUSxDQUFDLE1BQU0sRUFDZixRQUFRLEVBQ1IsaUNBQWlDLENBQ2xDLENBQUM7UUFDRixNQUFNLFdBQVcsR0FBRyxRQUFRLENBQUMsV0FBVyxDQUFDO1FBQ3pDLElBQUksQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztZQUNoQyxNQUFNLElBQUksS0FBSyxDQUFDLHVEQUF1RCxDQUFDLENBQUM7UUFDM0UsQ0FBQztRQUNELDJCQUEyQixDQUN6QixXQUFXLENBQUMsRUFBRSxFQUNkLGdCQUFnQixFQUNoQixvQ0FBb0MsQ0FDckMsQ0FBQztRQUNGLElBQUksV0FBVyxDQUFDLEtBQUssS0FBSyxTQUFTLElBQUksV0FBVyxDQUFDLEtBQUssS0FBSyxVQUFVLEVBQUUsQ0FBQztZQUN4RSxNQUFNLElBQUksS0FBSyxDQUFDLG9EQUFvRCxDQUFDLENBQUM7UUFDeEUsQ0FBQztRQUNELElBQUksV0FBVyxDQUFDLEtBQUssS0FBSyxTQUFTLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxTQUFTLENBQUMsRUFBRSxDQUFDO1lBQzNFLE1BQU0sSUFBSSxLQUFLLENBQUMsc0RBQXNELENBQUMsQ0FBQztRQUMxRSxDQUFDO1FBQ0QsSUFDRSxXQUFXLENBQUMsS0FBSyxLQUFLLFVBQVU7ZUFDN0IsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxVQUFVLENBQUM7ZUFDcEMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsRUFDcEMsQ0FBQztZQUNELE1BQU0sSUFBSSxLQUFLLENBQUMsaUVBQWlFLENBQUMsQ0FBQztRQUNyRixDQUFDO0lBQ0gsQ0FBQztJQUVPLEtBQUssQ0FBQyxhQUFhLENBQ3pCLE9BQWUsRUFDZixXQUEwQyxJQUFJLENBQUMscUJBQXFCO1FBRXBFLElBQUksQ0FBQyxRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMseUJBQXlCLENBQUMsUUFBUSxDQUFDO1lBQUUsT0FBTztRQUNuRSxNQUFNLE9BQU8sR0FBWSxPQUFPLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMxRCxJQUFJLENBQUMsb0JBQW9CLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDbkMsTUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLFdBQVcsQ0FBQztRQUV4QyxJQUFJLFdBQVcsQ0FBQyxLQUFLLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDckMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ3pELElBQUksQ0FBQyxPQUFPO2dCQUFFLE9BQU87WUFDckIsSUFDRSxPQUFPLENBQUMsb0JBQW9CLEtBQUssUUFBUSxDQUFDLFVBQVU7bUJBQ2pELE9BQU8sQ0FBQyxjQUFjLEtBQUssT0FBTyxDQUFDLE1BQU0sRUFDNUMsQ0FBQztnQkFDRCxNQUFNLElBQUksS0FBSyxDQUFDLDBDQUEwQyxDQUFDLENBQUM7WUFDOUQsQ0FBQztZQUNELElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUM1QyxPQUFPLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ3pCLE9BQU87UUFDVCxDQUFDO1FBRUQsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDLG1CQUFtQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3JFLElBQUksQ0FBQyxRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMseUJBQXlCLENBQUMsUUFBUSxDQUFDO1lBQUUsT0FBTztRQUNuRSxJQUFJLENBQUMsc0JBQXNCLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ2xELENBQUM7SUFFTyxzQkFBc0IsQ0FDNUIsV0FBeUQsRUFDekQsUUFBZ0M7UUFFaEMsSUFBSSxDQUFDLElBQUksQ0FBQyx5QkFBeUIsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQzlDLE1BQU0sSUFBSSxLQUFLLENBQUMsa0RBQWtELENBQUMsQ0FBQztRQUN0RSxDQUFDO1FBQ0QsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDekQsTUFBTSxVQUFVLEdBQUcsV0FBVyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxVQUFVLENBQUM7UUFDMUQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUMsTUFBTSxDQUFDO1FBQ2xELElBQUksVUFBVSxHQUFHLE1BQU0sQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN2QyxNQUFNLElBQUksS0FBSyxDQUFDLHlDQUF5QyxNQUFNLENBQUMsY0FBYyxlQUFlLENBQUMsQ0FBQztRQUNqRyxDQUFDO1FBQ0QsSUFBSSxRQUFRLENBQUMsU0FBUyxDQUFDLGNBQWMsR0FBRyxVQUFVLEdBQUcsTUFBTSxDQUFDLHFCQUFxQixFQUFFLENBQUM7WUFDbEYsTUFBTSxJQUFJLEtBQUssQ0FBQywwREFBMEQsQ0FBQyxDQUFDO1FBQzlFLENBQUM7UUFDRCxRQUFRLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNuQyxDQUFDO0lBRU8seUJBQXlCLENBQUMsUUFBZ0M7UUFDaEUsT0FBTyxPQUFPLENBQ1osSUFBSSxDQUFDLHFCQUFxQixLQUFLLFFBQVE7ZUFDcEMsSUFBSSxDQUFDLFNBQVMsS0FBSyxRQUFRLENBQUMsU0FBUztlQUNyQyxJQUFJLENBQUMsb0JBQW9CLEtBQUssUUFBUSxDQUFDLFVBQVU7ZUFDakQsUUFBUSxDQUFDLFNBQVMsQ0FBQyxVQUFVLEtBQUssU0FBUyxDQUFDLElBQUksQ0FDcEQsQ0FBQztJQUNKLENBQUM7SUFFTywwQkFBMEIsQ0FDaEMsUUFBZ0MsRUFDaEMsU0FBZ0I7UUFFaEIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQzdDLFFBQVEsQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzVDLENBQUM7UUFDRCxRQUFRLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztRQUNyQyxRQUFRLENBQUMsZUFBZSxHQUFHLENBQUMsQ0FBQztRQUM3QixJQUFJLElBQUksQ0FBQyxxQkFBcUIsS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUM1QyxJQUFJLENBQUMscUJBQXFCLEdBQUcsSUFBSSxDQUFDO1FBQ3BDLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxnQkFBZ0I7UUFDdEIsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLEtBQUssY0FBYyxFQUFFLENBQUM7WUFDN0MsT0FBTyxDQUFDLGtCQUFrQjtRQUM1QixDQUFDO1FBRUQsSUFBSSxDQUFDLFlBQVksQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUVsQyw0RkFBNEY7UUFDNUYsSUFBSSxDQUFDLDJCQUEyQixDQUFDLElBQUksS0FBSyxDQUFDLDBCQUEwQixDQUFDLENBQUMsQ0FBQztRQUV4RSxJQUFJLElBQUksQ0FBQyxlQUFlLEVBQUUsRUFBRSxDQUFDO1lBQzNCLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQzNCLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxLQUFLLENBQUMsaUJBQWlCO1FBQzdCLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFO1lBQUUsT0FBTztRQUNwQyxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztRQUVsRCxJQUFJLENBQUMsWUFBWSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ2xDLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUVsQixrQ0FBa0M7UUFDbEMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLGNBQWMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ25FLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLGNBQWMsR0FBRyxNQUFNLEVBQUUsYUFBYSxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBRWpGLElBQUksQ0FBQyxRQUFRLENBQUMsK0JBQStCLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLGVBQWUsSUFBSSxDQUFDLFVBQVUsSUFBSSxhQUFhLENBQUMsVUFBVSxHQUFHLENBQUMsQ0FBQztRQUU3SCxNQUFNLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUV4QyxJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRTtZQUFFLE9BQU87UUFFcEMsaUNBQWlDO1FBQ2pDLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsY0FBYyxHQUFHLENBQUMsRUFBRSxhQUFhLENBQUMsWUFBWSxDQUFDLENBQUM7UUFFcEYsSUFBSSxDQUFDO1lBQ0gsTUFBTSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDdkIsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLElBQUksSUFBSSxDQUFDLGVBQWUsRUFBRSxFQUFFLENBQUM7Z0JBQzNCLElBQUksQ0FBQyxRQUFRLENBQUMsMENBQTBDLENBQUMsQ0FBQztZQUM1RCxDQUFDO2lCQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxXQUFXLEVBQUUsT0FBTyxFQUFFLENBQUM7Z0JBQ3RFLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO2dCQUNqRixPQUFPLENBQUMsS0FBSyxDQUFDLDRCQUE0QixRQUFRLFVBQVUsSUFBSSxDQUFDLFVBQVUsWUFBWSxDQUFDLENBQUM7WUFDM0YsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssUUFBUSxDQUFDLFVBQWtCO1FBQ2pDLE9BQU8sQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDNUIsQ0FBQztJQUVEOzs7T0FHRztJQUNLLFlBQVksQ0FBQyxVQUFrQjtRQUNyQyxJQUFJLElBQUksQ0FBQyxlQUFlLEVBQUUsRUFBRSxDQUFDO1lBQzNCLElBQUksQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDNUIsQ0FBQzthQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxXQUFXLEVBQUUsT0FBTyxFQUFFLENBQUM7WUFDdEUsT0FBTyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUMzQixDQUFDO0lBQ0gsQ0FBQztJQUVPLGVBQWU7UUFDckIsT0FBTyxPQUFPLENBQ1osSUFBSSxDQUFDLGFBQWEsRUFBRSxhQUFhO1lBQ2pDLENBQUMsSUFBSSxDQUFDLE9BQU87WUFDYixDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsV0FBVyxFQUFFLE9BQU87WUFDeEMsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FDaEQsQ0FBQztJQUNKLENBQUM7SUFFTyxLQUFLLENBQUMscUJBQXFCLENBQUMsVUFBa0I7UUFDcEQsTUFBTSxJQUFJLE9BQU8sQ0FBTyxDQUFDLE9BQU8sRUFBRSxFQUFFO1lBQ2xDLElBQUksT0FBa0QsQ0FBQztZQUN2RCxJQUFJLFFBQVEsR0FBRyxLQUFLLENBQUM7WUFDckIsTUFBTSxNQUFNLEdBQUcsR0FBRyxFQUFFO2dCQUNsQixJQUFJLFFBQVE7b0JBQUUsT0FBTztnQkFDckIsUUFBUSxHQUFHLElBQUksQ0FBQztnQkFDaEIsSUFBSSxPQUFPLEVBQUUsQ0FBQztvQkFDWixZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ3hCLENBQUM7Z0JBQ0QsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQ2xDLElBQUksQ0FBQyxhQUFhLEVBQUUsV0FBVyxFQUFFLG1CQUFtQixDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQztnQkFDdEUsT0FBTyxFQUFFLENBQUM7WUFDWixDQUFDLENBQUM7WUFDRixJQUFJLElBQUksQ0FBQyxhQUFhLEVBQUUsV0FBVyxFQUFFLE9BQU8sRUFBRSxDQUFDO2dCQUM3QyxNQUFNLEVBQUUsQ0FBQztnQkFDVCxPQUFPO1lBQ1QsQ0FBQztZQUNELElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUNqQixNQUFNLEVBQUUsQ0FBQztnQkFDVCxPQUFPO1lBQ1QsQ0FBQztZQUNELE9BQU8sR0FBRyxVQUFVLENBQUMsTUFBTSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1lBQ3pDLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQy9CLElBQUksQ0FBQyxhQUFhLEVBQUUsV0FBVyxFQUFFLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUNyRixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTyxnQkFBZ0I7UUFDdEIsT0FBTyxJQUFJLEtBQUssQ0FBQyxvQ0FBb0MsQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFFTywyQkFBMkIsQ0FBQyxRQUFlO1FBQ2pELEtBQUssTUFBTSxPQUFPLElBQUksSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDO1lBQ3BELE9BQU8sQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDM0IsQ0FBQztRQUNELElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDL0IsQ0FBQztJQUVEOztPQUVHO0lBQ0ssWUFBWSxDQUFDLE1BQXlCO1FBQzVDLElBQUksSUFBSSxDQUFDLGdCQUFnQixLQUFLLE1BQU0sRUFBRSxDQUFDO1lBQ3JDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxNQUFNLENBQUM7WUFDL0IsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDbEMsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNLLEtBQUssQ0FBQyxXQUFXLENBQ3ZCLE9BQVUsRUFDVixhQUF5QyxFQUFFO1FBRTNDLElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxtQkFBbUIsRUFBRSxDQUFDO1lBQzNDLE1BQU0sSUFBSSxLQUFLLENBQUMsbUVBQW1FLENBQUMsQ0FBQztRQUN2RixDQUFDO1FBQ0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixDQUFDO1FBQ3pDLElBQUksQ0FBQyxLQUFLLElBQUksQ0FBQyxJQUFJLENBQUMseUJBQXlCLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNyRCxNQUFNLElBQUksS0FBSyxDQUFDLHlCQUF5QixDQUFDLENBQUM7UUFDN0MsQ0FBQztRQUVELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDckUsSUFBSSxVQUFVLENBQUMsV0FBVyxFQUFFLE9BQU8sRUFBRSxDQUFDO1lBQ3BDLE1BQU0sSUFBSSxLQUFLLENBQUMsNkJBQTZCLENBQUMsQ0FBQztRQUNqRCxDQUFDO1FBRUQsT0FBTyxDQUFDLFdBQVcsS0FBSztZQUN0QixFQUFFLEVBQUUsT0FBTyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsd0JBQXdCLEVBQUU7WUFDekQsS0FBSyxFQUFFLFNBQVM7U0FDakIsQ0FBQztRQUNGLDJCQUEyQixDQUN6QixPQUFPLENBQUMsTUFBTSxFQUNkLFFBQVEsRUFDUixpQ0FBaUMsQ0FDbEMsQ0FBQztRQUNGLDJCQUEyQixDQUN6QixPQUFPLENBQUMsV0FBVyxDQUFDLEVBQUUsRUFDdEIsZ0JBQWdCLEVBQ2hCLG9DQUFvQyxDQUNyQyxDQUFDO1FBQ0YsSUFBSSxPQUFPLENBQUMsV0FBVyxDQUFDLEtBQUssS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUM1QyxNQUFNLElBQUksS0FBSyxDQUFDLGtFQUFrRSxDQUFDLENBQUM7UUFDdEYsQ0FBQztRQUNELE1BQU0sYUFBYSxHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO1FBQzdDLElBQUksSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQztZQUM1QyxNQUFNLElBQUksS0FBSyxDQUFDLG1EQUFtRCxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBQ3RGLENBQUM7UUFDRCxJQUFJLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDLE1BQU0sQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUNwRixNQUFNLElBQUksS0FBSyxDQUFDLHVEQUF1RCxDQUFDLENBQUM7UUFDM0UsQ0FBQztRQUVELE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDckMsSUFBSSxPQUFPLEdBQUcsS0FBSyxDQUFDO1lBQ3BCLE1BQU0sT0FBTyxHQUFHLEdBQUcsRUFBRTtnQkFDbkIsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUN0QixVQUFVLENBQUMsV0FBVyxFQUFFLG1CQUFtQixDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztnQkFDOUQsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUM7WUFDN0MsQ0FBQyxDQUFDO1lBQ0YsTUFBTSxNQUFNLEdBQUcsQ0FBQyxRQUFnQixFQUFFLFdBQWUsRUFBRSxFQUFFO2dCQUNuRCxJQUFJLE9BQU8sRUFBRSxDQUFDO29CQUNaLE9BQU87Z0JBQ1QsQ0FBQztnQkFDRCxPQUFPLEdBQUcsSUFBSSxDQUFDO2dCQUNmLE9BQU8sRUFBRSxDQUFDO2dCQUNWLElBQUksUUFBUSxFQUFFLENBQUM7b0JBQ2IsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO2dCQUNuQixDQUFDO3FCQUFNLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztvQkFDeEIsTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLGlEQUFpRCxDQUFDLENBQUMsQ0FBQztnQkFDdkUsQ0FBQztxQkFBTSxDQUFDO29CQUNOLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztnQkFDdkIsQ0FBQztZQUNILENBQUMsQ0FBQztZQUNGLE1BQU0sT0FBTyxHQUFHLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDLENBQUM7WUFDdkUsTUFBTSxPQUFPLEdBQUcsVUFBVSxDQUFDLEdBQUcsRUFBRTtnQkFDOUIsTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLCtCQUErQixDQUFDLENBQUMsQ0FBQztZQUNyRCxDQUFDLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFFZCxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxhQUFhLEVBQUU7Z0JBQ3RDLGNBQWMsRUFBRSxPQUFPLENBQUMsTUFBTTtnQkFDOUIsb0JBQW9CLEVBQUUsS0FBSyxDQUFDLFVBQVU7Z0JBQ3RDLE9BQU8sRUFBRSxDQUFDLFFBQVEsRUFBRSxFQUFFO29CQUNwQixPQUFPLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUM7b0JBQ3JDLE9BQU8sQ0FBQyxXQUFXLEdBQUcsUUFBUSxDQUFDLFdBQVcsQ0FBQztvQkFDM0MsSUFBSSxRQUFRLENBQUMsS0FBSzt3QkFBRSxPQUFPLENBQUMsS0FBSyxHQUFHLFFBQVEsQ0FBQyxLQUFLLENBQUM7O3dCQUM5QyxPQUFPLE9BQU8sQ0FBQyxLQUFLLENBQUM7b0JBQzFCLElBQUksUUFBUSxDQUFDLEtBQUs7d0JBQUUsT0FBTyxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDOzt3QkFDOUMsT0FBTyxPQUFPLENBQUMsS0FBSyxDQUFDO29CQUMxQixNQUFNLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxDQUFDO2dCQUM3QixDQUFDO2dCQUNELE1BQU0sRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFO29CQUNoQixNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQ2hCLENBQUM7YUFDRixDQUFDLENBQUM7WUFDSCxVQUFVLENBQUMsV0FBVyxFQUFFLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztZQUMzRSxJQUFJLFVBQVUsQ0FBQyxXQUFXLEVBQUUsT0FBTyxFQUFFLENBQUM7Z0JBQ3BDLE9BQU8sRUFBRSxDQUFDO2dCQUNWLE9BQU87WUFDVCxDQUFDO1lBRUQsSUFBSSxDQUFDO2dCQUNILElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDOUMsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsTUFBTSxDQUFDLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNwRSxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU8sdUJBQXVCLENBQUMsWUFBZ0M7UUFDOUQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGFBQWEsRUFBRSxNQUFNLENBQUMsZ0JBQWdCO2VBQ3RELGtDQUFrQyxDQUFDO1FBQ3hDLE1BQU0sU0FBUyxHQUFHLFlBQVksSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztRQUM1RCxJQUFJLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxTQUFTLENBQUMsSUFBSSxTQUFTLEdBQUcsQ0FBQyxJQUFJLFNBQVMsR0FBRyxPQUFPLEVBQUUsQ0FBQztZQUM3RSxNQUFNLElBQUksS0FBSyxDQUNiLCtFQUErRSxPQUFPLEdBQUcsQ0FDMUYsQ0FBQztRQUNKLENBQUM7UUFDRCxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBRU8sb0JBQW9CO1FBQzFCLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDeEIsTUFBTSxJQUFJLEtBQUssQ0FBQyw4REFBOEQsQ0FBQyxDQUFDO1FBQ2xGLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxhQUFhLENBQUM7SUFDNUIsQ0FBQztJQUVPLGtDQUFrQyxDQUN4QyxPQUErQixFQUMvQixRQUFlO1FBRWYsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLDZCQUE2QixDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN2RSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDcEIsT0FBTztRQUNULENBQUM7UUFDRCxLQUFLLE1BQU0sYUFBYSxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQztZQUN2RCxJQUFJLENBQUMscUJBQXFCLENBQUMsR0FBRyxDQUFDLGFBQWEsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNsRSxDQUFDO0lBQ0gsQ0FBQztJQUVPLGdDQUFnQyxDQUFDLE9BQStCO1FBQ3RFLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzdFLElBQ0UsZUFBZSxJQUFJLGtEQUFrRDtlQUNsRSxJQUFJLENBQUMsdUJBQXVCLElBQUkseUNBQXlDLEVBQzVFLENBQUM7WUFDRCxNQUFNLElBQUksS0FBSyxDQUFDLDZEQUE2RCxDQUFDLENBQUM7UUFDakYsQ0FBQztRQUNELElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1FBQy9CLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLGVBQWUsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNyRSxJQUFJLFFBQVEsR0FBRyxLQUFLLENBQUM7UUFDckIsT0FBTyxHQUFHLEVBQUU7WUFDVixJQUFJLFFBQVE7Z0JBQUUsT0FBTztZQUNyQixRQUFRLEdBQUcsSUFBSSxDQUFDO1lBQ2hCLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1lBQy9CLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDdkUsSUFBSSxjQUFjLEtBQUssU0FBUyxJQUFJLGNBQWMsR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDdkQsTUFBTSxJQUFJLEtBQUssQ0FBQyxnRUFBZ0UsQ0FBQyxDQUFDO1lBQ3BGLENBQUM7WUFDRCxJQUFJLGNBQWMsS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDekIsSUFBSSxDQUFDLDZCQUE2QixDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNyRCxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sSUFBSSxDQUFDLDZCQUE2QixDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsY0FBYyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ3RFLENBQUM7UUFDSCxDQUFDLENBQUM7SUFDSixDQUFDO0lBRU8sK0JBQStCLENBQ3JDLFdBQW1FLEVBQ25FLGlCQUFtRCxFQUNuRCxtQkFBc0Q7UUFFdEQsSUFDRSxJQUFJLENBQUMsY0FBYztlQUNoQixDQUFDLElBQUksQ0FBQyxhQUFhO2VBQ25CLFdBQVcsQ0FBQyxXQUFXLEVBQUUsS0FBSyxLQUFLLFVBQVU7ZUFDN0MsT0FBTyxXQUFXLENBQUMsV0FBVyxDQUFDLEVBQUUsS0FBSyxRQUFRO2VBQzlDLE9BQU8sV0FBVyxDQUFDLE1BQU0sS0FBSyxRQUFRLEVBQ3pDLENBQUM7WUFDRCxPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFDRCxNQUFNLElBQUksR0FBRyxtQkFBbUIsQ0FBQyxJQUFJLENBQUM7UUFDdEMsSUFBSSxDQUFDLElBQUksSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRO1lBQUUsT0FBTyxLQUFLLENBQUM7UUFDcEQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzNFLE9BQU8sT0FBTyxDQUNaLE9BQU87ZUFDSixPQUFPLENBQUMsSUFBSSxLQUFLLElBQUk7ZUFDckIsT0FBTyxDQUFDLGNBQWMsS0FBSyxpQkFBaUI7ZUFDNUMsT0FBTyxDQUFDLGNBQWMsS0FBSyxXQUFXLENBQUMsTUFBTTtlQUM3QyxPQUFPLENBQUMsbUJBQW1CLEtBQUssSUFBSSxDQUFDLHlCQUF5QjtlQUM5RCxPQUFPLENBQUMsSUFBSSxDQUFDLGNBQWMsS0FBSyxpQkFBaUI7ZUFDakQsSUFBSSxDQUFDLG9CQUFvQixDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FDM0MsQ0FBQztJQUNKLENBQUM7SUFFTyxvQkFBb0IsQ0FBQyxPQUErQjtRQUMxRCxPQUFPLE9BQU8sQ0FDWixDQUFDLElBQUksQ0FBQyxjQUFjO2VBQ2pCLElBQUksQ0FBQyxhQUFhO2VBQ2xCLE9BQU8sQ0FBQyxVQUFVLEtBQUssQ0FBQztlQUN4QixPQUFPLENBQUMsY0FBYztlQUN0QixJQUFJLENBQUMsa0JBQWtCLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUM7ZUFDeEQsSUFBSSxDQUFDLGFBQWEsQ0FBQyx1QkFBdUIsRUFBRSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FDbEUsQ0FBQztJQUNKLENBQUM7SUFFTyx5QkFBeUIsQ0FDL0IsYUFBcUQ7UUFFckQsTUFBTSxTQUFTLEdBQUcsYUFBYSxFQUFFLFNBQVMsRUFBRSxJQUFJLENBQUM7UUFDakQsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLGFBQWE7WUFDN0IsRUFBRSx1QkFBdUIsRUFBRTthQUMxQixJQUFJLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLE9BQU8sS0FBSyxTQUFTLENBQUMsQ0FBQztRQUM1QyxPQUFPLElBQUksSUFBSSxJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ3BFLENBQUM7SUFFTyxLQUFLLENBQUMsaUJBQWlCLENBQzdCLG1CQUFzQixFQUN0QixTQUF1QyxFQUN2QyxVQUFzQztRQUV0QyxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsdUJBQXVCLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ3JFLElBQUksSUFBSSxDQUFDLGNBQWMsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUMvQyxNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixDQUFDLENBQUM7UUFDaEQsQ0FBQztRQUNELElBQUksVUFBVSxDQUFDLFdBQVcsRUFBRSxPQUFPLEVBQUUsQ0FBQztZQUNwQyxNQUFNLElBQUksS0FBSyxDQUFDLDZCQUE2QixDQUFDLENBQUM7UUFDakQsQ0FBQztRQUVELG1CQUFtQixDQUFDLFdBQVcsS0FBSztZQUNsQyxFQUFFLEVBQUUsT0FBTyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsd0JBQXdCLEVBQUU7WUFDekQsS0FBSyxFQUFFLFNBQVM7U0FDakIsQ0FBQztRQUNGLDJCQUEyQixDQUN6QixtQkFBbUIsQ0FBQyxNQUFNLEVBQzFCLFFBQVEsRUFDUixpQ0FBaUMsQ0FDbEMsQ0FBQztRQUNGLDJCQUEyQixDQUN6QixtQkFBbUIsQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUNsQyxnQkFBZ0IsRUFDaEIsb0NBQW9DLENBQ3JDLENBQUM7UUFDRixJQUFJLG1CQUFtQixDQUFDLFdBQVcsQ0FBQyxLQUFLLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDeEQsTUFBTSxJQUFJLEtBQUssQ0FBQyxrRUFBa0UsQ0FBQyxDQUFDO1FBQ3RGLENBQUM7UUFDRCxNQUFNLGFBQWEsR0FBRyxtQkFBbUIsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO1FBQ3pELE1BQU0sSUFBSSxHQUFHLFNBQVMsQ0FBQyxJQUFJLENBQUM7UUFDNUIsTUFBTSxNQUFNLEdBQUcsU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDakMsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQztRQUMzQyxJQUFJLENBQUMsY0FBYyxJQUFJLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDO1lBQ3pFLE1BQU0sSUFBSSxLQUFLLENBQUMsMkVBQTJFLENBQUMsQ0FBQztRQUMvRixDQUFDO1FBQ0QsSUFBSSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ3JDLE1BQU0sSUFBSSxLQUFLLENBQUMsd0RBQXdELE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDcEYsQ0FBQztRQUNELElBQUksSUFBSSxDQUFDLHFCQUFxQixDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDO1lBQ2xELE1BQU0sSUFBSSxLQUFLLENBQUMsbURBQW1ELGFBQWEsRUFBRSxDQUFDLENBQUM7UUFDdEYsQ0FBQztRQUNELE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksSUFBSSxHQUFHLEVBQVUsQ0FBQztRQUMxRixJQUNFLGVBQWUsQ0FBQyxJQUFJLElBQUksZ0RBQWdEO2VBQ3JFLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLElBQUksdUNBQXVDLEVBQzdFLENBQUM7WUFDRCxNQUFNLElBQUksS0FBSyxDQUFDLHVEQUF1RCxDQUFDLENBQUM7UUFDM0UsQ0FBQztRQUNELElBQ0UsQ0FBQyxJQUFJLENBQUMsNkJBQTZCLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztlQUM5QyxrREFBa0Q7ZUFDcEQsSUFBSSxDQUFDLHVCQUF1QixJQUFJLHlDQUF5QyxFQUM1RSxDQUFDO1lBQ0QsTUFBTSxJQUFJLEtBQUssQ0FBQyw2REFBNkQsQ0FBQyxDQUFDO1FBQ2pGLENBQUM7UUFDRCxNQUFNLFlBQVksR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBUyxDQUFDO1FBQ3pELDRFQUE0RTtRQUM1RSx5RUFBeUU7UUFDekUsK0NBQStDO1FBQy9DLEtBQUssWUFBWSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7UUFDMUMsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxLQUFLLEVBQVEsQ0FBQztRQUNuRCxJQUFJLHFCQUFxQixHQUFHLEtBQUssQ0FBQztRQUNsQyxNQUFNLE1BQU0sR0FBRyxDQUFDLFFBQWUsRUFBRSxFQUFFO1lBQ2pDLElBQUkscUJBQXFCLEVBQUUsQ0FBQztnQkFDMUIsT0FBTztZQUNULENBQUM7WUFDRCxxQkFBcUIsR0FBRyxJQUFJLENBQUM7WUFDN0IsWUFBWSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNoQyxDQUFDLENBQUM7UUFDRixNQUFNLGNBQWMsR0FBMEI7WUFDNUMsSUFBSTtZQUNKLE1BQU07WUFDTixjQUFjO1lBQ2QsY0FBYyxFQUFFLG1CQUFtQixDQUFDLE1BQU07WUFDMUMsbUJBQW1CLEVBQUUsSUFBSSxDQUFDLHlCQUF5QjtZQUNuRCxNQUFNO1lBQ04sZUFBZSxFQUFFLE9BQU8sQ0FBQyxPQUFPO1NBQ2pDLENBQUM7UUFDRixJQUFJLENBQUMscUJBQXFCLENBQUMsR0FBRyxDQUFDLGFBQWEsRUFBRSxjQUFjLENBQUMsQ0FBQztRQUM5RCxlQUFlLENBQUMsR0FBRyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQ25DLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLGVBQWUsQ0FBQyxDQUFDO1FBRTlELE1BQU0sT0FBTyxHQUFHLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDLENBQUM7UUFDdkUsTUFBTSxPQUFPLEdBQUcsVUFBVSxDQUN4QixHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMsdUNBQXVDLFNBQVMsSUFBSSxDQUFDLENBQUMsRUFDN0UsU0FBUyxDQUNWLENBQUM7UUFDRixVQUFVLENBQUMsV0FBVyxFQUFFLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUMzRSxJQUFJLFVBQVUsQ0FBQyxXQUFXLEVBQUUsT0FBTyxFQUFFLENBQUM7WUFDcEMsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDO1FBRUQsTUFBTSxnQkFBZ0IsR0FBc0IsRUFBRSxDQUFDO1FBQy9DLElBQUksQ0FBQztZQUNILE1BQU0sMkJBQTJCLEdBQUcsSUFBSSxDQUFDLGdDQUFnQyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ2hGLE1BQU0sb0JBQW9CLEdBQUcsT0FBTyxDQUFDLE9BQU8sRUFBRTtpQkFDM0MsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLGNBQWMsQ0FBQyxvQkFBb0IsQ0FBQyxXQUFXLENBQ3pELGFBQWEsRUFDYixtQkFBbUIsQ0FDcEIsQ0FBQztpQkFDRCxJQUFJLENBQUMsQ0FBQyxXQUFXLEVBQUUsRUFBRTtnQkFDcEIsSUFBSSxxQkFBcUIsSUFBSSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7b0JBQ2pELFdBQVcsQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDeEIsQ0FBQztnQkFDRCxPQUFPLFdBQVcsQ0FBQztZQUNyQixDQUFDLENBQUM7aUJBQ0QsT0FBTyxDQUFDLDJCQUEyQixDQUFDLENBQUM7WUFDeEMsTUFBTSxRQUFRLEdBQUcsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDO2dCQUNsQyxvQkFBb0I7Z0JBQ3BCLFlBQVksQ0FBQyxPQUFPO2FBQ3JCLENBQUMsQ0FBQztZQUNILElBQUkscUJBQXFCLElBQUksSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO2dCQUNqRCxRQUFRLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ25CLE1BQU0sWUFBWSxDQUFDLE9BQU8sQ0FBQztZQUM3QixDQUFDO1lBQ0QsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQ2hELDBFQUEwRTtZQUMxRSwrQ0FBK0M7WUFDL0MsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztnQkFDNUIsUUFBUSxDQUFDLGtCQUFrQjtnQkFDM0IsWUFBWSxDQUFDLE9BQU87YUFDckIsQ0FBQyxDQUFDO1lBQ0gsTUFBTSxzQkFBc0IsR0FBRyxJQUFJLENBQUMsYUFBYTtnQkFDL0MsRUFBRSx1QkFBdUIsRUFBRTtpQkFDMUIsSUFBSSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxPQUFPLEtBQUssSUFBSSxDQUFDLElBQUksS0FBSyxDQUFDO1lBQ2hELElBQUksQ0FBQyxzQkFBc0IsRUFBRSxDQUFDO2dCQUM1QixNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMseUNBQXlDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQztZQUN2RSxDQUFDO1lBQ0QsSUFBSSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ3hCLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDLENBQUM7WUFDbEQsQ0FBQztZQUNELElBQUksQ0FBQyxxQkFBcUIsSUFBSSxzQkFBc0IsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDN0UsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxDQUFDO1lBQ3hFLENBQUM7WUFDRCxNQUFNLGNBQWMsR0FBRyxNQUFNLFFBQVEsQ0FBQztZQUN0QyxtQkFBbUIsQ0FBQyxRQUFRLEdBQUcsY0FBYyxDQUFDLFFBQVEsQ0FBQztZQUN2RCxtQkFBbUIsQ0FBQyxXQUFXLEdBQUcsY0FBYyxDQUFDLFdBQVcsQ0FBQztZQUM3RCxJQUFJLGNBQWMsQ0FBQyxLQUFLO2dCQUFFLG1CQUFtQixDQUFDLEtBQUssR0FBRyxjQUFjLENBQUMsS0FBSyxDQUFDOztnQkFDdEUsT0FBTyxtQkFBbUIsQ0FBQyxLQUFLLENBQUM7WUFDdEMsSUFBSSxjQUFjLENBQUMsS0FBSztnQkFBRSxtQkFBbUIsQ0FBQyxLQUFLLEdBQUcsY0FBYyxDQUFDLEtBQUssQ0FBQzs7Z0JBQ3RFLE9BQU8sbUJBQW1CLENBQUMsS0FBSyxDQUFDO1lBQ3RDLE9BQU8sbUJBQW1CLENBQUM7UUFDN0IsQ0FBQztnQkFBUyxDQUFDO1lBQ1QsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ3RCLFVBQVUsQ0FBQyxXQUFXLEVBQUUsbUJBQW1CLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQzlELElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUM7WUFDakQsTUFBTSx3QkFBd0IsR0FBRyxJQUFJLENBQUMsNkJBQTZCLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzlFLHdCQUF3QixFQUFFLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUNoRCxJQUFJLHdCQUF3QixFQUFFLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDekMsSUFBSSxDQUFDLDZCQUE2QixDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUNsRCxDQUFDO1lBQ0QsS0FBSyxNQUFNLGVBQWUsSUFBSSxnQkFBZ0IsRUFBRSxDQUFDO2dCQUMvQyxlQUFlLEVBQUUsQ0FBQztZQUNwQixDQUFDO1lBQ0QsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3BCLENBQUM7SUFDSCxDQUFDO0lBRUQsK0VBQStFO0lBQy9FLHNCQUFzQjtJQUN0QiwrRUFBK0U7SUFFL0U7Ozs7T0FJRztJQUNJLGtCQUFrQixDQUN2QixVQUF1QixFQUN2QixnQkFBK0MsRUFDL0MsYUFBeUMsRUFBRTtRQUUzQyxNQUFNLFVBQVUsR0FBRyxLQUFLLEVBQ3RCLGNBQTRELEVBQzVELGlCQUErRCxFQUFFLEVBQ1YsRUFBRTtZQUN6RCxNQUFNLG1CQUFtQixHQUFHLG1CQUFtQixDQUM3QyxVQUFVLENBQUMsV0FBVyxFQUN0QixjQUFjLENBQUMsTUFBTSxDQUN0QixDQUFDO1lBQ0YsTUFBTSxjQUFjLEdBQStCO2dCQUNqRCxHQUFHLFVBQVU7Z0JBQ2IsV0FBVyxFQUFFLG1CQUFtQixDQUFDLE1BQU07YUFDeEMsQ0FBQztZQUVGLElBQUksQ0FBQztnQkFDSCxJQUFJLElBQUksQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7b0JBQzNCLE9BQU8sTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDLGNBQWMsRUFBRSxjQUFjLENBQUMsQ0FBQztnQkFDaEUsQ0FBQztnQkFFRCx5Q0FBeUM7Z0JBQ3pDLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7b0JBQ3hCLE1BQU0sSUFBSSxLQUFLLENBQUMsd0JBQXdCLENBQUMsQ0FBQztnQkFDNUMsQ0FBQztnQkFFRCxJQUFJLE1BQU0sR0FBRyxnQkFBZ0IsQ0FBQztnQkFDOUIsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO29CQUNaLElBQUksSUFBSSxDQUFDLGtCQUFrQixDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQzt3QkFDdkMsTUFBTSxJQUFJLEtBQUssQ0FBQyx1RUFBdUUsQ0FBQyxDQUFDO29CQUMzRixDQUFDO29CQUNELE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFDbEQsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyx1QkFBdUIsRUFBRSxDQUFDLE1BQU0sQ0FDeEUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxjQUFjLEtBQUssY0FBYyxDQUN2RCxDQUFDO29CQUNGLElBQUksY0FBYyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQzt3QkFDaEMsTUFBTSxJQUFJLEdBQUcsY0FBYyxDQUFDLENBQUMsQ0FBQyxDQUFDO3dCQUMvQixNQUFNLEdBQUcsa0JBQWtCLENBQUMsSUFBSSxDQUFDLENBQUM7b0JBQ3BDLENBQUM7eUJBQU0sSUFBSSxjQUFjLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO3dCQUN2QyxNQUFNLElBQUksS0FBSyxDQUFDLG9DQUFvQyxDQUFDLENBQUM7b0JBQ3hELENBQUM7eUJBQU0sQ0FBQzt3QkFDTixNQUFNLElBQUksS0FBSyxDQUFDLDJEQUEyRCxDQUFDLENBQUM7b0JBQy9FLENBQUM7Z0JBQ0gsQ0FBQztnQkFFRCxPQUFPLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLGNBQWMsRUFBRSxNQUFNLEVBQUUsY0FBYyxDQUFDLENBQUM7WUFDOUUsQ0FBQztvQkFBUyxDQUFDO2dCQUNULG1CQUFtQixDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2hDLENBQUM7UUFDSCxDQUFDLENBQUM7UUFFRixNQUFNLHFCQUFxQixHQUFHLElBQUksQ0FBQyxJQUFJLEtBQUssUUFBUTtZQUNsRCxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyw4QkFBOEIsRUFBRTtZQUNuRCxDQUFDLENBQUMsZ0JBQWdCO2dCQUNoQixDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyw4QkFBOEIsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUM7Z0JBQ3hFLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFFaEIsT0FBTyxJQUFJLE9BQU8sQ0FBQyxZQUFZLENBQUMsWUFBWSxDQUMxQyxJQUFJLE9BQU8sQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDO1lBQ25DLFVBQVU7WUFDVixtQkFBbUIsRUFBRSxJQUFJO1lBQ3pCLHFCQUFxQjtZQUNyQixvQkFBb0IsRUFBRSxNQUFNO1NBQzdCLENBQUMsRUFDRixVQUFVLENBQ1gsQ0FBQztJQUNKLENBQUM7SUFFRDs7O09BR0c7SUFDSSxtQkFBbUIsQ0FDeEIsVUFBaUQ7UUFFakQsSUFBSSxJQUFJLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzNCLE1BQU0sSUFBSSxLQUFLLENBQUMsa0RBQWtELENBQUMsQ0FBQztRQUN0RSxDQUFDO1FBQ0QsSUFDRSxVQUFVLENBQUMsUUFBUSxLQUFLLG9CQUFvQjtlQUN6QyxVQUFVLENBQUMsU0FBUyxLQUFLLFNBQVMsRUFDckMsQ0FBQztZQUNELE1BQU0sSUFBSSxTQUFTLENBQ2pCLCtEQUErRCxDQUNoRSxDQUFDO1FBQ0osQ0FBQztRQUNELE1BQU0sb0JBQW9CLEdBQUcsSUFBSSxDQUFDLDhCQUE4QixDQUFDO1FBQ2pFLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO1lBQzFCLE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsK0RBQStELENBQ2hFLENBQUM7UUFDSixDQUFDO1FBQ0QsTUFBTSxJQUFJLEdBQUcsTUFBTSxJQUFJLFVBQVUsQ0FBQyxNQUFNO1lBQ3RDLENBQUMsQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLElBQUk7WUFDeEIsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUM7UUFDdEIsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyw4QkFBOEIsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN4RSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDZixNQUFNLElBQUkseUJBQXlCLENBQ2pDLGlFQUFpRSxDQUNsRSxDQUFDO1FBQ0osQ0FBQztRQUNELFNBQVMsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLFVBQVUsRUFBRSxvQkFBb0IsRUFBRSxDQUFDLENBQUM7UUFDbEUsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxpQkFBaUIsQ0FBQztZQUNsRCxVQUFVLEVBQUUsVUFBVSxDQUFDLFVBQVU7WUFDakMsTUFBTSxFQUFFLFVBQVUsQ0FBQyxNQUFNO1lBQ3pCLFdBQVcsRUFBRSxVQUFVLENBQUMsV0FBVztTQUNwQyxDQUFDLENBQUM7UUFDSCxNQUFNLG9CQUFvQixHQUFHLG9CQUFvQixDQUFDLElBQUksQ0FDcEQsVUFBVSxDQUFDLGFBQWEsRUFDeEIsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FDMUMsQ0FBQztRQUNGLElBQ0UsQ0FBQyxvQkFBb0I7ZUFDbEIsT0FBTyxvQkFBb0IsS0FBSyxRQUFRO2VBQ3hDLE9BQU8sT0FBTyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsRUFBRSxNQUFNLENBQUMsS0FBSyxVQUFVLEVBQ2xFLENBQUM7WUFDRCxNQUFNLElBQUksU0FBUyxDQUNqQix5RUFBeUUsQ0FDMUUsQ0FBQztRQUNKLENBQUM7UUFDRCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLHlCQUF5QixDQUFDO1lBQzlELE1BQU0sRUFBRSxJQUFJO1lBQ1osR0FBRyxRQUFRO1lBQ1gsa0JBQWtCLEVBQUUsVUFBVSxDQUFDLGtCQUFrQjtZQUNqRCxXQUFXLEVBQUUsb0JBQW9CLENBQUMsV0FBVztZQUM3QyxrQkFBa0IsRUFBRSxvQkFBb0IsQ0FBQyxrQkFBa0I7WUFDM0QsY0FBYyxFQUFFLG9CQUFvQixDQUFDLGNBQWM7WUFDbkQsZUFBZSxFQUFFLG9CQUFvQixDQUFDLGVBQWU7WUFDckQsVUFBVSxFQUFFLG9CQUFvQixDQUFDLFVBQVU7U0FDNUMsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxPQUFPLENBQUMsWUFBWSxDQUFDLGFBQWEsQ0FBQywwQkFBMEIsQ0FBQztZQUNuRSxTQUFTO1lBQ1QsWUFBWTtTQUNiLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNJLFNBQVM7UUFDZCxPQUFPLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztJQUMvQixDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsSUFBSTtRQUNmLElBQUksSUFBSSxDQUFDLElBQUksS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUMzQixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQztZQUNwQixLQUFLLE1BQU0sWUFBWSxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxFQUFFLENBQUM7Z0JBQzFELFlBQVksRUFBRSxDQUFDO1lBQ2pCLENBQUM7WUFDRCxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQzNCLElBQUksSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO2dCQUN2QixJQUFJLENBQUMsYUFBYSxDQUFDLGFBQWEsR0FBRyxLQUFLLENBQUM7Z0JBQ3pDLElBQUksSUFBSSxDQUFDLGFBQWEsQ0FBQyxXQUFXLElBQUksSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7b0JBQy9ELElBQUksQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLG1CQUFtQixDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsbUJBQW1CLENBQUMsQ0FBQztnQkFDeEYsQ0FBQztZQUNILENBQUM7WUFDRCxJQUFJLENBQUMsbUJBQW1CLEdBQUcsU0FBUyxDQUFDO1lBQ3JDLElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO2dCQUNuQixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDO2dCQUNqQyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsb0JBQW9CLENBQUM7Z0JBQzdDLElBQUksSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUM7b0JBQy9CLElBQUksQ0FBQywwQkFBMEIsQ0FDN0IsSUFBSSxDQUFDLHFCQUFxQixFQUMxQixJQUFJLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxDQUNqQyxDQUFDO2dCQUNKLENBQUM7Z0JBQ0QsSUFBSSxDQUFDLFdBQVcsQ0FBQyxzQkFBc0IsQ0FDckMsU0FBUyxFQUNULFVBQVUsRUFDVixJQUFJLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxDQUNqQyxDQUFDO2dCQUNGLFNBQVMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDbEIsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUM7WUFDeEIsQ0FBQztZQUNELEtBQUssTUFBTSxjQUFjLElBQUksSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDO2dCQUMzRCxjQUFjLENBQUMsTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQztZQUMxRCxDQUFDO1lBQ0QsSUFBSSxDQUFDLGVBQWUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUMvQixDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDO1lBQzNCLElBQUksQ0FBQyx5QkFBeUIsRUFBRSxDQUFDO1lBQ2pDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSx1QkFBdUIsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1lBQ2hGLE1BQU0sZUFBZSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7WUFDeEUsS0FBSyxNQUFNLGNBQWMsSUFBSSxlQUFlLEVBQUUsQ0FBQztnQkFDN0MsY0FBYyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDLENBQUM7WUFDakUsQ0FBQztZQUNELE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLENBQUMsY0FBYyxFQUFFLEVBQUUsQ0FBQyxjQUFjLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQztZQUMzRixJQUFJLENBQUMsb0NBQW9DLEVBQUUsRUFBRSxDQUFDO1lBQzlDLElBQUksQ0FBQyxvQ0FBb0MsR0FBRyxJQUFJLENBQUM7WUFDakQsSUFBSSxDQUFDLFdBQVcsQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUNoQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsd0JBQXdCLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDMUQsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUM7WUFDMUIsSUFBSSxDQUFDLDZCQUE2QixDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzdDLENBQUM7UUFDRCxLQUFLLE1BQU0sMEJBQTBCLElBQUksSUFBSSxDQUFDLDJCQUEyQixDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUM7WUFDcEYsMEJBQTBCLEVBQUUsQ0FBQztRQUMvQixDQUFDO1FBQ0QsSUFBSSxDQUFDLDJCQUEyQixHQUFHLEVBQUUsQ0FBQztRQUN0QyxLQUFLLE1BQU0sNEJBQTRCLElBQUksSUFBSSxDQUFDLDZCQUE2QixDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUM7WUFDeEYsNEJBQTRCLEVBQUUsQ0FBQztRQUNqQyxDQUFDO1FBQ0QsSUFBSSxDQUFDLDZCQUE2QixHQUFHLEVBQUUsQ0FBQztRQUN4QyxJQUFJLElBQUksQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDM0IsSUFBSSxDQUFDLHdCQUF3QixFQUFFLENBQUM7UUFDbEMsQ0FBQztJQUNILENBQUM7SUFFTyx3QkFBd0I7UUFDOUIsS0FBSyxNQUFNLGtCQUFrQixJQUFJLElBQUksQ0FBQyxpQ0FBaUMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO1lBQ2xGLGtCQUFrQixFQUFFLENBQUM7UUFDdkIsQ0FBQztRQUNELElBQUksQ0FBQyxpQ0FBaUMsR0FBRyxFQUFFLENBQUM7UUFDNUMsS0FBSyxNQUFNLG9CQUFvQixJQUFJLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO1lBQ3hFLG9CQUFvQixFQUFFLENBQUM7UUFDekIsQ0FBQztRQUNELElBQUksQ0FBQyxxQkFBcUIsR0FBRyxFQUFFLENBQUM7SUFDbEMsQ0FBQztJQUVELCtFQUErRTtJQUMvRSxzQkFBc0I7SUFDdEIsK0VBQStFO0lBRS9FOzs7O09BSUc7SUFDSSxLQUFLLENBQUMsTUFBTSxDQUNqQixJQUFlLEVBQ2YsT0FBcUI7UUFFckIsSUFBSSxJQUFJLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzNCLE1BQU0sSUFBSSxLQUFLLENBQUMscUNBQXFDLENBQUMsQ0FBQztRQUN6RCxDQUFDO1FBRUQsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLHVCQUF1QixDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzNELElBQUksQ0FBQztZQUNILE1BQU0sUUFBUSxHQUFHLG1DQUFtQyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQzlELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLFFBQVEsQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQzdGLE9BQU8sTUFBTSxJQUFJLENBQUMsMEJBQTBCLENBQUMsSUFBSSxFQUFFLEtBQUssSUFBSSxFQUFFO2dCQUM1RCxJQUFJLE9BQWdCLENBQUM7Z0JBQ3JCLElBQUksQ0FBQztvQkFDSCxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsc0JBQXNCLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDO2dCQUM3RCxDQUFDO2dCQUFDLE9BQU8sUUFBUSxFQUFFLENBQUM7b0JBQ2xCLElBQUksQ0FBQyxzQkFBc0IsQ0FDekIsSUFBSSxFQUNKLE9BQU8sRUFDUCxRQUFRLFlBQVksK0JBQStCLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUM1RSxDQUFDO29CQUNGLE1BQU0sUUFBUSxDQUFDO2dCQUNqQixDQUFDO2dCQUNELElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUNoRixDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7Z0JBQVMsQ0FBQztZQUNULGVBQWUsRUFBRSxDQUFDO1FBQ3BCLENBQUM7SUFDSCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssS0FBSyxDQUFDLGlCQUFpQixDQUM3QixXQUEwQyxJQUFJLENBQUMscUJBQXFCO1FBRXBFLElBQUksQ0FBQyxRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMseUJBQXlCLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUMzRCxNQUFNLElBQUksS0FBSyxDQUFDLDJEQUEyRCxDQUFDLENBQUM7UUFDL0UsQ0FBQztRQUNELElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLHlCQUF5QixDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7WUFDaEQsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUM5RCxLQUFLLE1BQU0sQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUksUUFBUSxFQUFFLENBQUM7Z0JBQ3ZDLElBQUksQ0FBQztvQkFDSCxNQUFNLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO29CQUMzRSxJQUNFLE9BQU87MkJBQ0osT0FBTyxDQUFDLFNBQVMsS0FBSyxRQUFROzJCQUM5QixJQUFJLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLFFBQVEsS0FBSyxPQUFPLENBQUMsUUFBUSxFQUNsRSxDQUFDO3dCQUNELElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7b0JBQ3RDLENBQUM7Z0JBQ0gsQ0FBQztnQkFBQyxPQUFPLFFBQVEsRUFBRSxDQUFDO29CQUNsQixJQUNFLFFBQVEsWUFBWSwrQkFBK0I7MkJBQ2hELElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsUUFBUSxLQUFLLE9BQU8sQ0FBQyxRQUFRLEVBQ2xFLENBQUM7d0JBQ0QsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDdEMsQ0FBQztvQkFDRCxNQUFNLFFBQVEsQ0FBQztnQkFDakIsQ0FBQztZQUNILENBQUM7WUFDRCxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsTUFBTSxLQUFLLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJO21CQUN6RCxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLEVBQUUsRUFBRTtvQkFDcEMsT0FBTyxJQUFJLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLFFBQVEsS0FBSyxPQUFPLENBQUMsUUFBUSxDQUFDO2dCQUN6RSxDQUFDLENBQUMsQ0FBQztZQUNMLElBQUksTUFBTTtnQkFBRSxPQUFPO1FBQ3JCLENBQUM7UUFDRCxNQUFNLElBQUksS0FBSyxDQUFDLDZEQUE2RCxDQUFDLENBQUM7SUFDakYsQ0FBQztJQUVEOzs7T0FHRztJQUNJLEtBQUssQ0FBQyxTQUFTLENBQUMsSUFBWTtRQUNqQyxJQUFJLElBQUksQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDM0IsTUFBTSxJQUFJLEtBQUssQ0FBQyx3Q0FBd0MsQ0FBQyxDQUFDO1FBQzVELENBQUM7UUFFRCxNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsdUJBQXVCLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDM0QsSUFBSSxDQUFDO1lBQ0gsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLElBQUksRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQ3ZFLE9BQU8sTUFBTSxJQUFJLENBQUMsMEJBQTBCLENBQUMsSUFBSSxFQUFFLEtBQUssSUFBSSxFQUFFO2dCQUM1RCxJQUFJLE9BQWdCLENBQUM7Z0JBQ3JCLElBQUksQ0FBQztvQkFDSCxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsc0JBQXNCLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDO2dCQUM3RCxDQUFDO2dCQUFDLE9BQU8sUUFBUSxFQUFFLENBQUM7b0JBQ2xCLElBQUksQ0FBQyxzQkFBc0IsQ0FDekIsSUFBSSxFQUNKLE9BQU8sRUFDUCxRQUFRLFlBQVksK0JBQStCLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUM1RSxDQUFDO29CQUNGLE1BQU0sUUFBUSxDQUFDO2dCQUNqQixDQUFDO2dCQUNELElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUNoRixDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7Z0JBQVMsQ0FBQztZQUNULGVBQWUsRUFBRSxDQUFDO1FBQ3BCLENBQUM7SUFDSCxDQUFDO0lBRU8sdUJBQXVCLENBQUMsT0FBZTtRQUM3QywyQkFBMkIsQ0FBQyxPQUFPLEVBQUUsVUFBVSxFQUFFLDhCQUE4QixDQUFDLENBQUM7UUFDakYsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLGdDQUFnQyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEYsSUFDRSxlQUFlLElBQUksc0RBQXNEO2VBQ3RFLElBQUksQ0FBQywwQkFBMEIsSUFBSSw2Q0FBNkMsRUFDbkYsQ0FBQztZQUNELE1BQU0sSUFBSSwrQkFBK0IsQ0FDdkMsZ0NBQWdDLEVBQ2hDLDZEQUE2RCxDQUM5RCxDQUFDO1FBQ0osQ0FBQztRQUNELElBQUksQ0FBQywwQkFBMEIsRUFBRSxDQUFDO1FBQ2xDLElBQUksQ0FBQyxnQ0FBZ0MsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLGVBQWUsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUN4RSxJQUFJLFFBQVEsR0FBRyxLQUFLLENBQUM7UUFDckIsT0FBTyxHQUFHLEVBQUU7WUFDVixJQUFJLFFBQVE7Z0JBQUUsT0FBTztZQUNyQixRQUFRLEdBQUcsSUFBSSxDQUFDO1lBQ2hCLElBQUksQ0FBQywwQkFBMEIsRUFBRSxDQUFDO1lBQ2xDLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxnQ0FBZ0MsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDMUUsSUFBSSxjQUFjLEtBQUssU0FBUyxJQUFJLGNBQWMsR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDdkQsTUFBTSxJQUFJLEtBQUssQ0FBQyx1REFBdUQsQ0FBQyxDQUFDO1lBQzNFLENBQUM7WUFDRCxJQUFJLGNBQWMsS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDekIsSUFBSSxDQUFDLGdDQUFnQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUN4RCxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sSUFBSSxDQUFDLGdDQUFnQyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsY0FBYyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ3pFLENBQUM7UUFDSCxDQUFDLENBQUM7SUFDSixDQUFDO0lBRU8sbUJBQW1CLENBQ3pCLE9BQWUsRUFDZixZQUE4QixFQUM5QixVQUFtQixFQUNuQixlQUF1QjtRQUV2QiwyQkFBMkIsQ0FBQyxPQUFPLEVBQUUsVUFBVSxFQUFFLDhCQUE4QixDQUFDLENBQUM7UUFDakYsTUFBTSxhQUFhLEdBQUcsV0FBVyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxVQUFVLEdBQUcsZUFBZSxDQUFDO1FBQy9FLE1BQU0sT0FBTyxHQUE4QixNQUFNLENBQUMsTUFBTSxDQUFDO1lBQ3ZELFFBQVEsRUFBRSxFQUFFLElBQUksQ0FBQyx5QkFBeUI7WUFDMUMsU0FBUyxFQUFFLFlBQVk7WUFDdkIsT0FBTyxFQUFFLFlBQVksS0FBSyxLQUFLLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsU0FBUztZQUN4RCxhQUFhO1NBQ2QsQ0FBQyxDQUFDO1FBQ0gsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMzRCxJQUFJLENBQUMsY0FBYyxJQUFJLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLElBQUksb0NBQW9DLEVBQUUsQ0FBQztZQUMzRixNQUFNLElBQUksK0JBQStCLENBQ3ZDLDBCQUEwQixFQUMxQixzREFBc0QsQ0FDdkQsQ0FBQztRQUNKLENBQUM7UUFDRCxJQUFJLGFBQWEsR0FBRyxhQUFhLENBQUM7UUFDbEMsS0FBSyxNQUFNLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQ25ELElBQUksSUFBSSxLQUFLLE9BQU87Z0JBQUUsYUFBYSxJQUFJLEtBQUssQ0FBQyxhQUFhLENBQUM7UUFDN0QsQ0FBQztRQUNELElBQUksYUFBYSxHQUFHLGtEQUFrRCxFQUFFLENBQUM7WUFDdkUsTUFBTSxJQUFJLCtCQUErQixDQUN2Qyw2QkFBNkIsRUFDN0IsOERBQThELENBQy9ELENBQUM7UUFDSixDQUFDO1FBQ0QsSUFBSSxLQUFLLEdBQUcsSUFBSSxDQUFDLDhCQUE4QixDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM3RCxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDWCxLQUFLLEdBQUc7Z0JBQ04sUUFBUSxFQUFFLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDO2dCQUM3QyxPQUFPLEVBQUUsRUFBRTthQUNaLENBQUM7WUFDRixJQUFJLENBQUMsOEJBQThCLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUMxRCxDQUFDO1FBQ0QsS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDNUIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDN0MsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQztJQUVPLHNCQUFzQixDQUM1QixPQUFlLEVBQ2YsVUFBcUMsRUFDckMsVUFBOEM7UUFFOUMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLDhCQUE4QixDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMvRCxNQUFNLE9BQU8sR0FBRyxLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ3ZDLElBQUksQ0FBQyxLQUFLLElBQUksT0FBTyxLQUFLLFVBQVUsRUFBRSxDQUFDO1lBQ3JDLE1BQU0sSUFBSSxLQUFLLENBQUMscUVBQXFFLENBQUMsQ0FBQztRQUN6RixDQUFDO1FBQ0QsSUFBSSxVQUFVLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDOUIsS0FBSyxDQUFDLFFBQVEsR0FBRyxVQUFVLENBQUMsU0FBUyxLQUFLLEtBQUssQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFDM0UsQ0FBQzthQUFNLElBQUksVUFBVSxLQUFLLFVBQVUsRUFBRSxDQUFDO1lBQ3JDLEtBQUssQ0FBQyxRQUFRLEdBQUcsVUFBVSxDQUFDO1FBQzlCLENBQUM7UUFDRCxNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssQ0FBQyxRQUFRLENBQUM7UUFDdkQsSUFBSSxPQUFPO1lBQUUsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUM7O1lBQ3JELElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDNUMsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sS0FBSyxDQUFDO1lBQUUsSUFBSSxDQUFDLDhCQUE4QixDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN0RixDQUFDO0lBRU8sS0FBSyxDQUFDLDBCQUEwQixDQUN0QyxPQUFlLEVBQ2YsV0FBZ0M7UUFFaEMsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLHNCQUFzQixDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDL0UsTUFBTSxTQUFTLEdBQUcsUUFBUSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsR0FBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDN0QsTUFBTSxJQUFJLEdBQUcsU0FBUyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7UUFDaEQsSUFBSSxDQUFDLHNCQUFzQixDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDL0MsSUFBSSxDQUFDO1lBQ0gsTUFBTSxTQUFTLENBQUM7UUFDbEIsQ0FBQztnQkFBUyxDQUFDO1lBQ1QsSUFBSSxJQUFJLENBQUMsc0JBQXNCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDO2dCQUN0RCxJQUFJLENBQUMsc0JBQXNCLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQzlDLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVPLEtBQUssQ0FBQyxzQkFBc0IsQ0FDbEMsT0FBZSxFQUNmLFVBQXFDLEVBQ3JDLFdBQTBDLElBQUksQ0FBQyxxQkFBcUI7UUFFcEUsSUFBSSxDQUFDLFFBQVEsSUFBSSxDQUFDLElBQUksQ0FBQyx5QkFBeUIsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQzNELE1BQU0sSUFBSSxLQUFLLENBQUMseUJBQXlCLENBQUMsQ0FBQztRQUM3QyxDQUFDO1FBQ0QsTUFBTSxvQkFBb0IsR0FBRyxRQUFRLENBQUMsVUFBVSxDQUFDO1FBQ2pELE1BQU0sUUFBUSxHQUFHLFVBQVUsQ0FBQyxTQUFTLEtBQUssS0FBSztZQUM3QyxDQUFDLENBQUMsSUFBSSxDQUFDLHlCQUF5QixDQUFDLE1BQU0sSUFBSTtpQkFDdEMsa0JBQWtCLENBQW9CLHNCQUFzQixDQUFDO2lCQUM3RCxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxVQUFVLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUMxRCxDQUFDLENBQUMsSUFBSSxDQUFDLHlCQUF5QixDQUFDLE1BQU0sSUFBSTtpQkFDdEMsa0JBQWtCLENBQXVCLHlCQUF5QixDQUFDO2lCQUNuRSxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ2hDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxzQkFBc0IsQ0FDekMsT0FBTyxFQUNQLFVBQVUsQ0FBQyxPQUFPLEVBQ2xCLFFBQVEsRUFDUixvQkFBb0IsRUFDcEIsVUFBVSxDQUFDLFNBQVMsQ0FDckIsQ0FBQztRQUNGLE9BQU8sT0FBTyxDQUFDO0lBQ2pCLENBQUM7SUFFTyx5QkFBeUIsQ0FDL0IsV0FBNEM7UUFFNUMsSUFBSSxDQUFDLFdBQVcsSUFBSSxPQUFPLFdBQVcsQ0FBQyxPQUFPLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDN0QsTUFBTSxJQUFJLCtCQUErQixDQUN2Qyx3QkFBd0IsRUFDeEIsZ0VBQWdFLENBQ2pFLENBQUM7UUFDSixDQUFDO1FBQ0QsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUN6QixJQUFJLE9BQU8sV0FBVyxDQUFDLElBQUksS0FBSyxRQUFRLElBQUksT0FBTyxXQUFXLENBQUMsT0FBTyxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUNwRixNQUFNLElBQUksK0JBQStCLENBQ3ZDLHdCQUF3QixFQUN4Qiw4REFBOEQsQ0FDL0QsQ0FBQztZQUNKLENBQUM7WUFDRCxNQUFNLElBQUksK0JBQStCLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDbkYsQ0FBQztRQUNELElBQ0UsT0FBTyxXQUFXLENBQUMsWUFBWSxLQUFLLFFBQVE7ZUFDekMsV0FBVyxDQUFDLFlBQVksQ0FBQyxNQUFNLEtBQUssQ0FBQztlQUNyQyxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLFdBQVcsQ0FBQztlQUM5QyxXQUFXLENBQUMsV0FBVyxHQUFHLENBQUMsRUFDOUIsQ0FBQztZQUNELE1BQU0sSUFBSSwrQkFBK0IsQ0FDdkMsd0JBQXdCLEVBQ3hCLHVFQUF1RSxDQUN4RSxDQUFDO1FBQ0osQ0FBQztRQUNELE9BQU8sV0FBVyxDQUFDO0lBQ3JCLENBQUM7SUFFTyxzQkFBc0IsQ0FDNUIsT0FBZSxFQUNmLFVBQW1CLEVBQ25CLFdBQTJDLEVBQzNDLHVCQUErQixFQUMvQixZQUE4QjtRQUU5QixJQUFJLHVCQUF1QixLQUFLLElBQUksQ0FBQyxvQkFBb0I7WUFBRSxPQUFPLEtBQUssQ0FBQztRQUN4RSxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3JELElBQUksT0FBTyxFQUFFLENBQUM7WUFDWixJQUFJLHVCQUF1QixHQUFHLE9BQU8sQ0FBQyxvQkFBb0I7Z0JBQUUsT0FBTyxLQUFLLENBQUM7WUFDekUsSUFBSSx1QkFBdUIsS0FBSyxPQUFPLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztnQkFDN0QsSUFBSSxXQUFXLENBQUMsWUFBWSxLQUFLLE9BQU8sQ0FBQyxZQUFZLEVBQUUsQ0FBQztvQkFDdEQsTUFBTSxJQUFJLCtCQUErQixDQUN2Qyx3QkFBd0IsRUFDeEIsK0ZBQStGLENBQ2hHLENBQUM7Z0JBQ0osQ0FBQztnQkFDRCxJQUFJLFdBQVcsQ0FBQyxXQUFXLElBQUksT0FBTyxDQUFDLFdBQVc7b0JBQUUsT0FBTyxLQUFLLENBQUM7WUFDbkUsQ0FBQztRQUNILENBQUM7UUFDRCxJQUFJLFlBQVksS0FBSyxLQUFLLEVBQUUsQ0FBQztZQUMzQixJQUFJLENBQUMsa0JBQWtCLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRTtnQkFDbkMsb0JBQW9CLEVBQUUsdUJBQXVCO2dCQUM3QyxZQUFZLEVBQUUsV0FBVyxDQUFDLFlBQVk7Z0JBQ3RDLFdBQVcsRUFBRSxXQUFXLENBQUMsV0FBVzthQUNyQyxDQUFDLENBQUM7WUFDSCxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsbUNBQW1DLENBQUMsVUFBVSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDeEYsQ0FBQzthQUFNLENBQUM7WUFDTixJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNoQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzFDLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCwrRUFBK0U7SUFDL0Usc0JBQXNCO0lBQ3RCLCtFQUErRTtJQUUvRTs7O09BR0c7SUFDSSw2QkFBNkIsQ0FDbEMsYUFBcUQ7UUFFckQsSUFBSSxJQUFJLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzNCLE1BQU0sSUFBSSxLQUFLLENBQUMsNERBQTRELENBQUMsQ0FBQztRQUNoRixDQUFDO1FBQ0QsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLHlCQUF5QixDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQzNELElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNWLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0VBQWdFLENBQUMsQ0FBQztRQUNwRixDQUFDO1FBQ0QsT0FBTyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNsQyxDQUFDO0lBRUQsOERBQThEO0lBQ3ZELFlBQVksQ0FDakIsYUFBb0UsRUFDcEUsT0FBZSxFQUNmLFVBQW9CO1FBRXBCLElBQUksSUFBSSxDQUFDLElBQUksS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUMzQixNQUFNLElBQUksS0FBSyxDQUFDLDJDQUEyQyxDQUFDLENBQUM7UUFDL0QsQ0FBQztRQUNELElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxZQUFZLENBQ2hDLE1BQU0sSUFBSSxhQUFhLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLGFBQWEsRUFDNUQsT0FBTyxFQUNQLFVBQVUsQ0FDWCxDQUFDO0lBQ0osQ0FBQztJQUVELGdGQUFnRjtJQUN6RSxlQUFlLENBQ3BCLGFBQW9FLEVBQ3BFLE9BQWU7UUFFZixJQUFJLElBQUksQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDM0IsTUFBTSxJQUFJLEtBQUssQ0FBQyw4Q0FBOEMsQ0FBQyxDQUFDO1FBQ2xFLENBQUM7UUFDRCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsZUFBZSxDQUNuQyxNQUFNLElBQUksYUFBYSxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxhQUFhLEVBQzVELE9BQU8sQ0FDUixDQUFDO0lBQ0osQ0FBQztJQUVEOzs7T0FHRztJQUNJLEtBQUssQ0FBQyx3QkFBd0IsQ0FDbkMsZ0JBQW1GO1FBRW5GLElBQUksSUFBSSxDQUFDLElBQUksS0FBSyxRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDbEQsTUFBTSxJQUFJLEtBQUssQ0FBQyx1REFBdUQsQ0FBQyxDQUFDO1FBQzNFLENBQUM7UUFFRCxNQUFNLG1CQUFtQixHQUFtQyxFQUFFLENBQUM7UUFDL0QsS0FBSyxNQUFNLElBQUksSUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLHVCQUF1QixFQUFFLEVBQUUsQ0FBQztZQUNoRSxJQUFJLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLElBQUksQ0FBQztnQkFBRSxTQUFTO1lBQy9DLE1BQU0sT0FBTyxHQUFHLGtCQUFrQixDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3pDLElBQUksTUFBTSxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO2dCQUNwQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDcEMsQ0FBQztRQUNILENBQUM7UUFDRCxPQUFPLG1CQUFtQixDQUFDO0lBQzdCLENBQUM7SUFFRDs7O09BR0c7SUFDSSxLQUFLLENBQUMsb0JBQW9CLENBQy9CLGdCQUFtRjtRQUVuRixNQUFNLFdBQVcsR0FBRyxNQUFNLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQzFFLE9BQU8sV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hCLENBQUM7SUFFRDs7O09BR0c7SUFDSSxLQUFLLENBQUMsNkJBQTZCLENBQ3hDLE1BQW9CLEVBQ3BCLFVBQTRCO1FBRTVCLElBQUksSUFBSSxDQUFDLElBQUksS0FBSyxRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDbEQsTUFBTSxJQUFJLEtBQUssQ0FBQyw0REFBNEQsQ0FBQyxDQUFDO1FBQ2hGLENBQUM7UUFFRCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsYUFBYTthQUM3Qiw0QkFBNEIsQ0FBQyxNQUFNLENBQUM7YUFDcEMsTUFBTSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztRQUMzRCxNQUFNLE9BQU8sR0FBbUMsRUFBRSxDQUFDO1FBRW5ELEtBQUssTUFBTSxJQUFJLElBQUksS0FBSyxFQUFFLENBQUM7WUFDekIsTUFBTSxPQUFPLEdBQUcsa0JBQWtCLENBQUMsSUFBSSxDQUFDLENBQUM7WUFFekMsK0NBQStDO1lBQy9DLElBQUksVUFBVSxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUM3QixNQUFNLEdBQUcsR0FBRyxNQUFNLE9BQU8sQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQzdDLElBQUksT0FBTyxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFLE9BQU8sQ0FBQyxLQUFLLE9BQU8sQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7b0JBQzFGLFNBQVM7Z0JBQ1gsQ0FBQztZQUNILENBQUM7WUFDRCxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3hCLENBQUM7UUFDRCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksS0FBSyxDQUFDLHlCQUF5QixDQUNwQyxNQUFvQixFQUNwQixVQUE0QjtRQUU1QixNQUFNLFVBQVUsR0FBRyxNQUFNLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxNQUFNLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDaEYsT0FBTyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdkIsQ0FBQyJ9