@push.rocks/smartproxy 19.5.4 → 19.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/core/utils/async-utils.d.ts +81 -0
- package/dist_ts/core/utils/async-utils.js +216 -0
- package/dist_ts/core/utils/binary-heap.d.ts +73 -0
- package/dist_ts/core/utils/binary-heap.js +193 -0
- package/dist_ts/core/utils/enhanced-connection-pool.d.ts +110 -0
- package/dist_ts/core/utils/enhanced-connection-pool.js +320 -0
- package/dist_ts/core/utils/fs-utils.d.ts +144 -0
- package/dist_ts/core/utils/fs-utils.js +252 -0
- package/dist_ts/core/utils/index.d.ts +5 -2
- package/dist_ts/core/utils/index.js +6 -3
- package/dist_ts/core/utils/lifecycle-component.d.ts +59 -0
- package/dist_ts/core/utils/lifecycle-component.js +195 -0
- package/dist_ts/plugins.d.ts +2 -1
- package/dist_ts/plugins.js +3 -2
- package/dist_ts/proxies/http-proxy/certificate-manager.d.ts +15 -0
- package/dist_ts/proxies/http-proxy/certificate-manager.js +49 -2
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.d.ts +10 -0
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.js +53 -43
- package/dist_ts/proxies/smart-proxy/cert-store.js +22 -20
- package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +37 -7
- package/dist_ts/proxies/smart-proxy/connection-manager.js +257 -180
- package/package.json +2 -2
- package/readme.hints.md +96 -1
- package/readme.plan.md +1135 -221
- package/readme.problems.md +167 -83
- package/ts/core/utils/async-utils.ts +275 -0
- package/ts/core/utils/binary-heap.ts +225 -0
- package/ts/core/utils/enhanced-connection-pool.ts +420 -0
- package/ts/core/utils/fs-utils.ts +270 -0
- package/ts/core/utils/index.ts +5 -2
- package/ts/core/utils/lifecycle-component.ts +231 -0
- package/ts/plugins.ts +2 -1
- package/ts/proxies/http-proxy/certificate-manager.ts +52 -1
- package/ts/proxies/nftables-proxy/nftables-proxy.ts +64 -79
- package/ts/proxies/smart-proxy/cert-store.ts +26 -20
- package/ts/proxies/smart-proxy/connection-manager.ts +291 -189
- package/readme.plan2.md +0 -764
- package/ts/common/eventUtils.ts +0 -34
- package/ts/common/types.ts +0 -91
- package/ts/core/utils/event-system.ts +0 -376
- package/ts/core/utils/event-utils.ts +0 -25
|
@@ -2,16 +2,30 @@ import * as plugins from '../../plugins.js';
|
|
|
2
2
|
import { SecurityManager } from './security-manager.js';
|
|
3
3
|
import { TimeoutManager } from './timeout-manager.js';
|
|
4
4
|
import { logger } from '../../core/utils/logger.js';
|
|
5
|
+
import { LifecycleComponent } from '../../core/utils/lifecycle-component.js';
|
|
5
6
|
/**
|
|
6
|
-
* Manages connection lifecycle, tracking, and cleanup
|
|
7
|
+
* Manages connection lifecycle, tracking, and cleanup with performance optimizations
|
|
7
8
|
*/
|
|
8
|
-
export class ConnectionManager {
|
|
9
|
+
export class ConnectionManager extends LifecycleComponent {
|
|
9
10
|
constructor(settings, securityManager, timeoutManager) {
|
|
11
|
+
super();
|
|
10
12
|
this.settings = settings;
|
|
11
13
|
this.securityManager = securityManager;
|
|
12
14
|
this.timeoutManager = timeoutManager;
|
|
13
15
|
this.connectionRecords = new Map();
|
|
14
16
|
this.terminationStats = { incoming: {}, outgoing: {} };
|
|
17
|
+
// Performance optimization: Track connections needing inactivity check
|
|
18
|
+
this.nextInactivityCheck = new Map();
|
|
19
|
+
this.cleanupBatchSize = 100;
|
|
20
|
+
// Cleanup queue for batched processing
|
|
21
|
+
this.cleanupQueue = new Set();
|
|
22
|
+
this.cleanupTimer = null;
|
|
23
|
+
// Set reasonable defaults for connection limits
|
|
24
|
+
this.maxConnections = settings.defaults?.security?.maxConnections || 10000;
|
|
25
|
+
// Start inactivity check timer if not disabled
|
|
26
|
+
if (!settings.disableInactivityCheck) {
|
|
27
|
+
this.startInactivityCheckTimer();
|
|
28
|
+
}
|
|
15
29
|
}
|
|
16
30
|
/**
|
|
17
31
|
* Generate a unique connection ID
|
|
@@ -24,15 +38,26 @@ export class ConnectionManager {
|
|
|
24
38
|
* Create and track a new connection
|
|
25
39
|
*/
|
|
26
40
|
createConnection(socket) {
|
|
41
|
+
// Enforce connection limit
|
|
42
|
+
if (this.connectionRecords.size >= this.maxConnections) {
|
|
43
|
+
logger.log('warn', `Connection limit reached (${this.maxConnections}). Rejecting new connection.`, {
|
|
44
|
+
currentConnections: this.connectionRecords.size,
|
|
45
|
+
maxConnections: this.maxConnections,
|
|
46
|
+
component: 'connection-manager'
|
|
47
|
+
});
|
|
48
|
+
socket.destroy();
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
27
51
|
const connectionId = this.generateConnectionId();
|
|
28
52
|
const remoteIP = socket.remoteAddress || '';
|
|
29
53
|
const localPort = socket.localPort || 0;
|
|
54
|
+
const now = Date.now();
|
|
30
55
|
const record = {
|
|
31
56
|
id: connectionId,
|
|
32
57
|
incoming: socket,
|
|
33
58
|
outgoing: null,
|
|
34
|
-
incomingStartTime:
|
|
35
|
-
lastActivity:
|
|
59
|
+
incomingStartTime: now,
|
|
60
|
+
lastActivity: now,
|
|
36
61
|
connectionClosed: false,
|
|
37
62
|
pendingData: [],
|
|
38
63
|
pendingDataSize: 0,
|
|
@@ -59,6 +84,38 @@ export class ConnectionManager {
|
|
|
59
84
|
trackConnection(connectionId, record) {
|
|
60
85
|
this.connectionRecords.set(connectionId, record);
|
|
61
86
|
this.securityManager.trackConnectionByIP(record.remoteIP, connectionId);
|
|
87
|
+
// Schedule inactivity check
|
|
88
|
+
if (!this.settings.disableInactivityCheck) {
|
|
89
|
+
this.scheduleInactivityCheck(connectionId, record);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Schedule next inactivity check for a connection
|
|
94
|
+
*/
|
|
95
|
+
scheduleInactivityCheck(connectionId, record) {
|
|
96
|
+
let timeout = this.settings.inactivityTimeout;
|
|
97
|
+
if (record.hasKeepAlive) {
|
|
98
|
+
if (this.settings.keepAliveTreatment === 'immortal') {
|
|
99
|
+
// Don't schedule check for immortal connections
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
else if (this.settings.keepAliveTreatment === 'extended') {
|
|
103
|
+
const multiplier = this.settings.keepAliveInactivityMultiplier || 6;
|
|
104
|
+
timeout = timeout * multiplier;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const checkTime = Date.now() + timeout;
|
|
108
|
+
this.nextInactivityCheck.set(connectionId, checkTime);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Start the inactivity check timer
|
|
112
|
+
*/
|
|
113
|
+
startInactivityCheckTimer() {
|
|
114
|
+
// Check every 30 seconds for connections that need inactivity check
|
|
115
|
+
this.setInterval(() => {
|
|
116
|
+
this.performOptimizedInactivityCheck();
|
|
117
|
+
}, 30000);
|
|
118
|
+
// Note: LifecycleComponent's setInterval already calls unref()
|
|
62
119
|
}
|
|
63
120
|
/**
|
|
64
121
|
* Get a connection by ID
|
|
@@ -83,14 +140,58 @@ export class ConnectionManager {
|
|
|
83
140
|
*/
|
|
84
141
|
initiateCleanupOnce(record, reason = 'normal') {
|
|
85
142
|
if (this.settings.enableDetailedLogging) {
|
|
86
|
-
logger.log('info', `Connection cleanup initiated`, {
|
|
143
|
+
logger.log('info', `Connection cleanup initiated`, {
|
|
144
|
+
connectionId: record.id,
|
|
145
|
+
remoteIP: record.remoteIP,
|
|
146
|
+
reason,
|
|
147
|
+
component: 'connection-manager'
|
|
148
|
+
});
|
|
87
149
|
}
|
|
88
|
-
if (record.incomingTerminationReason
|
|
89
|
-
record.incomingTerminationReason === undefined) {
|
|
150
|
+
if (record.incomingTerminationReason == null) {
|
|
90
151
|
record.incomingTerminationReason = reason;
|
|
91
152
|
this.incrementTerminationStat('incoming', reason);
|
|
92
153
|
}
|
|
93
|
-
|
|
154
|
+
// Add to cleanup queue for batched processing
|
|
155
|
+
this.queueCleanup(record.id);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Queue a connection for cleanup
|
|
159
|
+
*/
|
|
160
|
+
queueCleanup(connectionId) {
|
|
161
|
+
this.cleanupQueue.add(connectionId);
|
|
162
|
+
// Process immediately if queue is getting large
|
|
163
|
+
if (this.cleanupQueue.size >= this.cleanupBatchSize) {
|
|
164
|
+
this.processCleanupQueue();
|
|
165
|
+
}
|
|
166
|
+
else if (!this.cleanupTimer) {
|
|
167
|
+
// Otherwise, schedule batch processing
|
|
168
|
+
this.cleanupTimer = this.setTimeout(() => {
|
|
169
|
+
this.processCleanupQueue();
|
|
170
|
+
}, 100);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Process the cleanup queue in batches
|
|
175
|
+
*/
|
|
176
|
+
processCleanupQueue() {
|
|
177
|
+
if (this.cleanupTimer) {
|
|
178
|
+
this.clearTimeout(this.cleanupTimer);
|
|
179
|
+
this.cleanupTimer = null;
|
|
180
|
+
}
|
|
181
|
+
const toCleanup = Array.from(this.cleanupQueue).slice(0, this.cleanupBatchSize);
|
|
182
|
+
this.cleanupQueue.clear();
|
|
183
|
+
for (const connectionId of toCleanup) {
|
|
184
|
+
const record = this.connectionRecords.get(connectionId);
|
|
185
|
+
if (record) {
|
|
186
|
+
this.cleanupConnection(record, record.incomingTerminationReason || 'normal');
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// If there are more in queue, schedule next batch
|
|
190
|
+
if (this.cleanupQueue.size > 0) {
|
|
191
|
+
this.cleanupTimer = this.setTimeout(() => {
|
|
192
|
+
this.processCleanupQueue();
|
|
193
|
+
}, 10);
|
|
194
|
+
}
|
|
94
195
|
}
|
|
95
196
|
/**
|
|
96
197
|
* Clean up a connection record
|
|
@@ -98,33 +199,47 @@ export class ConnectionManager {
|
|
|
98
199
|
cleanupConnection(record, reason = 'normal') {
|
|
99
200
|
if (!record.connectionClosed) {
|
|
100
201
|
record.connectionClosed = true;
|
|
202
|
+
// Remove from inactivity check
|
|
203
|
+
this.nextInactivityCheck.delete(record.id);
|
|
101
204
|
// Track connection termination
|
|
102
205
|
this.securityManager.removeConnectionByIP(record.remoteIP, record.id);
|
|
103
206
|
if (record.cleanupTimer) {
|
|
104
207
|
clearTimeout(record.cleanupTimer);
|
|
105
208
|
record.cleanupTimer = undefined;
|
|
106
209
|
}
|
|
107
|
-
//
|
|
210
|
+
// Calculate metrics once
|
|
108
211
|
const duration = Date.now() - record.incomingStartTime;
|
|
109
|
-
const
|
|
110
|
-
|
|
212
|
+
const logData = {
|
|
213
|
+
connectionId: record.id,
|
|
214
|
+
remoteIP: record.remoteIP,
|
|
215
|
+
localPort: record.localPort,
|
|
216
|
+
reason,
|
|
217
|
+
duration: plugins.prettyMs(duration),
|
|
218
|
+
bytes: { in: record.bytesReceived, out: record.bytesSent },
|
|
219
|
+
tls: record.isTLS,
|
|
220
|
+
keepAlive: record.hasKeepAlive,
|
|
221
|
+
usingNetworkProxy: record.usingNetworkProxy,
|
|
222
|
+
domainSwitches: record.domainSwitches || 0,
|
|
223
|
+
component: 'connection-manager'
|
|
224
|
+
};
|
|
111
225
|
// Remove all data handlers to make sure we clean up properly
|
|
112
226
|
if (record.incoming) {
|
|
113
227
|
try {
|
|
114
|
-
// Remove our safe data handler
|
|
115
228
|
record.incoming.removeAllListeners('data');
|
|
116
|
-
// Reset the handler references
|
|
117
229
|
record.renegotiationHandler = undefined;
|
|
118
230
|
}
|
|
119
231
|
catch (err) {
|
|
120
|
-
logger.log('error', `Error removing data handlers
|
|
232
|
+
logger.log('error', `Error removing data handlers: ${err}`, {
|
|
233
|
+
connectionId: record.id,
|
|
234
|
+
error: err,
|
|
235
|
+
component: 'connection-manager'
|
|
236
|
+
});
|
|
121
237
|
}
|
|
122
238
|
}
|
|
123
|
-
// Handle
|
|
124
|
-
this.
|
|
125
|
-
// Handle outgoing socket
|
|
239
|
+
// Handle socket cleanup without delay
|
|
240
|
+
this.cleanupSocketImmediate(record, 'incoming', record.incoming);
|
|
126
241
|
if (record.outgoing) {
|
|
127
|
-
this.
|
|
242
|
+
this.cleanupSocketImmediate(record, 'outgoing', record.outgoing);
|
|
128
243
|
}
|
|
129
244
|
// Clear pendingData to avoid memory leaks
|
|
130
245
|
record.pendingData = [];
|
|
@@ -133,26 +248,11 @@ export class ConnectionManager {
|
|
|
133
248
|
this.connectionRecords.delete(record.id);
|
|
134
249
|
// Log connection details
|
|
135
250
|
if (this.settings.enableDetailedLogging) {
|
|
136
|
-
logger.log('info', `Connection
|
|
137
|
-
|
|
138
|
-
`TLS: ${record.isTLS ? 'Yes' : 'No'}, Keep-Alive: ${record.hasKeepAlive ? 'Yes' : 'No'}` +
|
|
139
|
-
`${record.usingNetworkProxy ? ', Using NetworkProxy' : ''}` +
|
|
140
|
-
`${record.domainSwitches ? `, Domain switches: ${record.domainSwitches}` : ''}`, {
|
|
141
|
-
connectionId: record.id,
|
|
142
|
-
remoteIP: record.remoteIP,
|
|
143
|
-
localPort: record.localPort,
|
|
144
|
-
reason,
|
|
145
|
-
duration: plugins.prettyMs(duration),
|
|
146
|
-
bytes: { in: bytesReceived, out: bytesSent },
|
|
147
|
-
tls: record.isTLS,
|
|
148
|
-
keepAlive: record.hasKeepAlive,
|
|
149
|
-
usingNetworkProxy: record.usingNetworkProxy,
|
|
150
|
-
domainSwitches: record.domainSwitches || 0,
|
|
151
|
-
component: 'connection-manager'
|
|
152
|
-
});
|
|
251
|
+
logger.log('info', `Connection terminated: ${record.remoteIP}:${record.localPort} (${reason}) - ` +
|
|
252
|
+
`${plugins.prettyMs(duration)}, IN: ${record.bytesReceived}B, OUT: ${record.bytesSent}B`, logData);
|
|
153
253
|
}
|
|
154
254
|
else {
|
|
155
|
-
logger.log('info', `Connection
|
|
255
|
+
logger.log('info', `Connection terminated: ${record.remoteIP} (${reason}). Active: ${this.connectionRecords.size}`, {
|
|
156
256
|
connectionId: record.id,
|
|
157
257
|
remoteIP: record.remoteIP,
|
|
158
258
|
reason,
|
|
@@ -163,39 +263,21 @@ export class ConnectionManager {
|
|
|
163
263
|
}
|
|
164
264
|
}
|
|
165
265
|
/**
|
|
166
|
-
* Helper method to clean up a socket
|
|
266
|
+
* Helper method to clean up a socket immediately
|
|
167
267
|
*/
|
|
168
|
-
|
|
268
|
+
cleanupSocketImmediate(record, side, socket) {
|
|
169
269
|
try {
|
|
170
270
|
if (!socket.destroyed) {
|
|
171
|
-
|
|
172
|
-
socket.end();
|
|
173
|
-
const socketTimeout = setTimeout(() => {
|
|
174
|
-
try {
|
|
175
|
-
if (!socket.destroyed) {
|
|
176
|
-
socket.destroy();
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
catch (err) {
|
|
180
|
-
logger.log('error', `Error destroying ${side} socket for connection ${record.id}: ${err}`, { connectionId: record.id, side, error: err, component: 'connection-manager' });
|
|
181
|
-
}
|
|
182
|
-
}, 1000);
|
|
183
|
-
// Ensure the timeout doesn't block Node from exiting
|
|
184
|
-
if (socketTimeout.unref) {
|
|
185
|
-
socketTimeout.unref();
|
|
186
|
-
}
|
|
271
|
+
socket.destroy();
|
|
187
272
|
}
|
|
188
273
|
}
|
|
189
274
|
catch (err) {
|
|
190
|
-
logger.log('error', `Error
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
catch (destroyErr) {
|
|
197
|
-
logger.log('error', `Error destroying ${side} socket for connection ${record.id}: ${destroyErr}`, { connectionId: record.id, side, error: destroyErr, component: 'connection-manager' });
|
|
198
|
-
}
|
|
275
|
+
logger.log('error', `Error destroying ${side} socket: ${err}`, {
|
|
276
|
+
connectionId: record.id,
|
|
277
|
+
side,
|
|
278
|
+
error: err,
|
|
279
|
+
component: 'connection-manager'
|
|
280
|
+
});
|
|
199
281
|
}
|
|
200
282
|
}
|
|
201
283
|
/**
|
|
@@ -208,46 +290,37 @@ export class ConnectionManager {
|
|
|
208
290
|
const now = Date.now();
|
|
209
291
|
const connectionDuration = now - record.incomingStartTime;
|
|
210
292
|
const lastActivityAge = now - record.lastActivity;
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
side,
|
|
216
|
-
remoteIP: record.remoteIP,
|
|
217
|
-
error: err.message,
|
|
218
|
-
duration: plugins.prettyMs(connectionDuration),
|
|
219
|
-
lastActivity: plugins.prettyMs(lastActivityAge),
|
|
220
|
-
component: 'connection-manager'
|
|
221
|
-
});
|
|
293
|
+
// Update activity tracking
|
|
294
|
+
if (side === 'incoming') {
|
|
295
|
+
record.lastActivity = now;
|
|
296
|
+
this.scheduleInactivityCheck(record.id, record);
|
|
222
297
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
component: 'connection-manager'
|
|
244
|
-
});
|
|
298
|
+
const errorData = {
|
|
299
|
+
connectionId: record.id,
|
|
300
|
+
side,
|
|
301
|
+
remoteIP: record.remoteIP,
|
|
302
|
+
error: err.message,
|
|
303
|
+
duration: plugins.prettyMs(connectionDuration),
|
|
304
|
+
lastActivity: plugins.prettyMs(lastActivityAge),
|
|
305
|
+
component: 'connection-manager'
|
|
306
|
+
};
|
|
307
|
+
switch (code) {
|
|
308
|
+
case 'ECONNRESET':
|
|
309
|
+
reason = 'econnreset';
|
|
310
|
+
logger.log('warn', `ECONNRESET on ${side}: ${record.remoteIP}`, errorData);
|
|
311
|
+
break;
|
|
312
|
+
case 'ETIMEDOUT':
|
|
313
|
+
reason = 'etimedout';
|
|
314
|
+
logger.log('warn', `ETIMEDOUT on ${side}: ${record.remoteIP}`, errorData);
|
|
315
|
+
break;
|
|
316
|
+
default:
|
|
317
|
+
logger.log('error', `Error on ${side}: ${record.remoteIP} - ${err.message}`, errorData);
|
|
245
318
|
}
|
|
246
|
-
if (side === 'incoming' && record.incomingTerminationReason
|
|
319
|
+
if (side === 'incoming' && record.incomingTerminationReason == null) {
|
|
247
320
|
record.incomingTerminationReason = reason;
|
|
248
321
|
this.incrementTerminationStat('incoming', reason);
|
|
249
322
|
}
|
|
250
|
-
else if (side === 'outgoing' && record.outgoingTerminationReason
|
|
323
|
+
else if (side === 'outgoing' && record.outgoingTerminationReason == null) {
|
|
251
324
|
record.outgoingTerminationReason = reason;
|
|
252
325
|
this.incrementTerminationStat('outgoing', reason);
|
|
253
326
|
}
|
|
@@ -267,14 +340,13 @@ export class ConnectionManager {
|
|
|
267
340
|
component: 'connection-manager'
|
|
268
341
|
});
|
|
269
342
|
}
|
|
270
|
-
if (side === 'incoming' && record.incomingTerminationReason
|
|
343
|
+
if (side === 'incoming' && record.incomingTerminationReason == null) {
|
|
271
344
|
record.incomingTerminationReason = 'normal';
|
|
272
345
|
this.incrementTerminationStat('incoming', 'normal');
|
|
273
346
|
}
|
|
274
|
-
else if (side === 'outgoing' && record.outgoingTerminationReason
|
|
347
|
+
else if (side === 'outgoing' && record.outgoingTerminationReason == null) {
|
|
275
348
|
record.outgoingTerminationReason = 'normal';
|
|
276
349
|
this.incrementTerminationStat('outgoing', 'normal');
|
|
277
|
-
// Record the time when outgoing socket closed.
|
|
278
350
|
record.outgoingClosedTime = Date.now();
|
|
279
351
|
}
|
|
280
352
|
this.initiateCleanupOnce(record, 'closed_' + side);
|
|
@@ -293,18 +365,22 @@ export class ConnectionManager {
|
|
|
293
365
|
return this.terminationStats;
|
|
294
366
|
}
|
|
295
367
|
/**
|
|
296
|
-
*
|
|
368
|
+
* Optimized inactivity check - only checks connections that are due
|
|
297
369
|
*/
|
|
298
|
-
|
|
370
|
+
performOptimizedInactivityCheck() {
|
|
299
371
|
const now = Date.now();
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
if (
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
372
|
+
const connectionsToCheck = [];
|
|
373
|
+
// Find connections that need checking
|
|
374
|
+
for (const [connectionId, checkTime] of this.nextInactivityCheck) {
|
|
375
|
+
if (checkTime <= now) {
|
|
376
|
+
connectionsToCheck.push(connectionId);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// Process only connections that need checking
|
|
380
|
+
for (const connectionId of connectionsToCheck) {
|
|
381
|
+
const record = this.connectionRecords.get(connectionId);
|
|
382
|
+
if (!record || record.connectionClosed) {
|
|
383
|
+
this.nextInactivityCheck.delete(connectionId);
|
|
308
384
|
continue;
|
|
309
385
|
}
|
|
310
386
|
const inactivityTime = now - record.lastActivity;
|
|
@@ -314,36 +390,36 @@ export class ConnectionManager {
|
|
|
314
390
|
const multiplier = this.settings.keepAliveInactivityMultiplier || 6;
|
|
315
391
|
effectiveTimeout = effectiveTimeout * multiplier;
|
|
316
392
|
}
|
|
317
|
-
if (inactivityTime > effectiveTimeout
|
|
393
|
+
if (inactivityTime > effectiveTimeout) {
|
|
318
394
|
// For keep-alive connections, issue a warning first
|
|
319
395
|
if (record.hasKeepAlive && !record.inactivityWarningIssued) {
|
|
320
|
-
logger.log('warn', `Keep-alive connection
|
|
321
|
-
connectionId
|
|
396
|
+
logger.log('warn', `Keep-alive connection inactive: ${record.remoteIP}`, {
|
|
397
|
+
connectionId,
|
|
322
398
|
remoteIP: record.remoteIP,
|
|
323
399
|
inactiveFor: plugins.prettyMs(inactivityTime),
|
|
324
|
-
closureWarning: '10 minutes',
|
|
325
400
|
component: 'connection-manager'
|
|
326
401
|
});
|
|
327
|
-
// Set warning flag and add grace period
|
|
328
402
|
record.inactivityWarningIssued = true;
|
|
329
|
-
|
|
403
|
+
// Reschedule check for 10 minutes later
|
|
404
|
+
this.nextInactivityCheck.set(connectionId, now + 600000);
|
|
330
405
|
// Try to stimulate activity with a probe packet
|
|
331
406
|
if (record.outgoing && !record.outgoing.destroyed) {
|
|
332
407
|
try {
|
|
333
408
|
record.outgoing.write(Buffer.alloc(0));
|
|
334
|
-
if (this.settings.enableDetailedLogging) {
|
|
335
|
-
logger.log('info', `Sent probe packet to test keep-alive connection ${id}`, { connectionId: id, component: 'connection-manager' });
|
|
336
|
-
}
|
|
337
409
|
}
|
|
338
410
|
catch (err) {
|
|
339
|
-
logger.log('error', `Error sending probe packet
|
|
411
|
+
logger.log('error', `Error sending probe packet: ${err}`, {
|
|
412
|
+
connectionId,
|
|
413
|
+
error: err,
|
|
414
|
+
component: 'connection-manager'
|
|
415
|
+
});
|
|
340
416
|
}
|
|
341
417
|
}
|
|
342
418
|
}
|
|
343
419
|
else {
|
|
344
|
-
//
|
|
345
|
-
logger.log('warn', `Closing inactive connection ${
|
|
346
|
-
connectionId
|
|
420
|
+
// Close the connection
|
|
421
|
+
logger.log('warn', `Closing inactive connection: ${record.remoteIP}`, {
|
|
422
|
+
connectionId,
|
|
347
423
|
remoteIP: record.remoteIP,
|
|
348
424
|
inactiveFor: plugins.prettyMs(inactivityTime),
|
|
349
425
|
hasKeepAlive: record.hasKeepAlive,
|
|
@@ -352,23 +428,17 @@ export class ConnectionManager {
|
|
|
352
428
|
this.cleanupConnection(record, 'inactivity');
|
|
353
429
|
}
|
|
354
430
|
}
|
|
355
|
-
else
|
|
356
|
-
//
|
|
357
|
-
|
|
358
|
-
logger.log('info', `Connection ${id} activity detected after inactivity warning`, {
|
|
359
|
-
connectionId: id,
|
|
360
|
-
component: 'connection-manager'
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
record.inactivityWarningIssued = false;
|
|
431
|
+
else {
|
|
432
|
+
// Reschedule next check
|
|
433
|
+
this.scheduleInactivityCheck(connectionId, record);
|
|
364
434
|
}
|
|
365
435
|
// Parity check: if outgoing socket closed and incoming remains active
|
|
366
436
|
if (record.outgoingClosedTime &&
|
|
367
437
|
!record.incoming.destroyed &&
|
|
368
438
|
!record.connectionClosed &&
|
|
369
439
|
now - record.outgoingClosedTime > 120000) {
|
|
370
|
-
logger.log('warn', `Parity check:
|
|
371
|
-
connectionId
|
|
440
|
+
logger.log('warn', `Parity check failed: ${record.remoteIP}`, {
|
|
441
|
+
connectionId,
|
|
372
442
|
remoteIP: record.remoteIP,
|
|
373
443
|
timeElapsed: plugins.prettyMs(now - record.outgoingClosedTime),
|
|
374
444
|
component: 'connection-manager'
|
|
@@ -377,65 +447,72 @@ export class ConnectionManager {
|
|
|
377
447
|
}
|
|
378
448
|
}
|
|
379
449
|
}
|
|
450
|
+
/**
|
|
451
|
+
* Legacy method for backward compatibility
|
|
452
|
+
*/
|
|
453
|
+
performInactivityCheck() {
|
|
454
|
+
this.performOptimizedInactivityCheck();
|
|
455
|
+
}
|
|
380
456
|
/**
|
|
381
457
|
* Clear all connections (for shutdown)
|
|
382
458
|
*/
|
|
383
|
-
clearConnections() {
|
|
384
|
-
//
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
459
|
+
async clearConnections() {
|
|
460
|
+
// Delegate to LifecycleComponent's cleanup
|
|
461
|
+
await this.cleanup();
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Override LifecycleComponent's onCleanup method
|
|
465
|
+
*/
|
|
466
|
+
async onCleanup() {
|
|
467
|
+
// Process connections in batches to avoid blocking
|
|
468
|
+
const connections = Array.from(this.connectionRecords.values());
|
|
469
|
+
const batchSize = 100;
|
|
470
|
+
let index = 0;
|
|
471
|
+
const processBatch = () => {
|
|
472
|
+
const batch = connections.slice(index, index + batchSize);
|
|
473
|
+
for (const record of batch) {
|
|
390
474
|
try {
|
|
391
|
-
// Clear any timers
|
|
392
475
|
if (record.cleanupTimer) {
|
|
393
476
|
clearTimeout(record.cleanupTimer);
|
|
394
477
|
record.cleanupTimer = undefined;
|
|
395
478
|
}
|
|
396
|
-
//
|
|
397
|
-
if (record.incoming
|
|
398
|
-
record.incoming.
|
|
479
|
+
// Immediate destruction
|
|
480
|
+
if (record.incoming) {
|
|
481
|
+
record.incoming.removeAllListeners();
|
|
482
|
+
if (!record.incoming.destroyed) {
|
|
483
|
+
record.incoming.destroy();
|
|
484
|
+
}
|
|
399
485
|
}
|
|
400
|
-
if (record.outgoing
|
|
401
|
-
record.outgoing.
|
|
486
|
+
if (record.outgoing) {
|
|
487
|
+
record.outgoing.removeAllListeners();
|
|
488
|
+
if (!record.outgoing.destroyed) {
|
|
489
|
+
record.outgoing.destroy();
|
|
490
|
+
}
|
|
402
491
|
}
|
|
403
492
|
}
|
|
404
493
|
catch (err) {
|
|
405
|
-
logger.log('error', `Error during
|
|
494
|
+
logger.log('error', `Error during connection cleanup: ${err}`, {
|
|
495
|
+
connectionId: record.id,
|
|
496
|
+
error: err,
|
|
497
|
+
component: 'connection-manager'
|
|
498
|
+
});
|
|
406
499
|
}
|
|
407
500
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
for (const id of connectionIds) {
|
|
413
|
-
const record = this.connectionRecords.get(id);
|
|
414
|
-
if (record) {
|
|
415
|
-
try {
|
|
416
|
-
// Remove all listeners to prevent memory leaks
|
|
417
|
-
if (record.incoming) {
|
|
418
|
-
record.incoming.removeAllListeners();
|
|
419
|
-
if (!record.incoming.destroyed) {
|
|
420
|
-
record.incoming.destroy();
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
if (record.outgoing) {
|
|
424
|
-
record.outgoing.removeAllListeners();
|
|
425
|
-
if (!record.outgoing.destroyed) {
|
|
426
|
-
record.outgoing.destroy();
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
catch (err) {
|
|
431
|
-
logger.log('error', `Error during forced destruction of connection ${id}: ${err}`, { connectionId: id, error: err, component: 'connection-manager' });
|
|
432
|
-
}
|
|
433
|
-
}
|
|
501
|
+
index += batchSize;
|
|
502
|
+
// Continue with next batch if needed
|
|
503
|
+
if (index < connections.length) {
|
|
504
|
+
setImmediate(processBatch);
|
|
434
505
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
506
|
+
else {
|
|
507
|
+
// Clear all maps
|
|
508
|
+
this.connectionRecords.clear();
|
|
509
|
+
this.nextInactivityCheck.clear();
|
|
510
|
+
this.cleanupQueue.clear();
|
|
511
|
+
this.terminationStats = { incoming: {}, outgoing: {} };
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
// Start batch processing
|
|
515
|
+
setImmediate(processBatch);
|
|
439
516
|
}
|
|
440
517
|
}
|
|
441
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29ubmVjdGlvbi1tYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvcHJveGllcy9zbWFydC1wcm94eS9jb25uZWN0aW9uLW1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxrQkFBa0IsQ0FBQztBQUU1QyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDeEQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUVwRDs7R0FFRztBQUNILE1BQU0sT0FBTyxpQkFBaUI7SUFPNUIsWUFDVSxRQUE0QixFQUM1QixlQUFnQyxFQUNoQyxjQUE4QjtRQUY5QixhQUFRLEdBQVIsUUFBUSxDQUFvQjtRQUM1QixvQkFBZSxHQUFmLGVBQWUsQ0FBaUI7UUFDaEMsbUJBQWMsR0FBZCxjQUFjLENBQWdCO1FBVGhDLHNCQUFpQixHQUFtQyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQzlELHFCQUFnQixHQUdwQixFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUUsUUFBUSxFQUFFLEVBQUUsRUFBRSxDQUFDO0lBTWhDLENBQUM7SUFFSjs7T0FFRztJQUNJLG9CQUFvQjtRQUN6QixPQUFPLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDM0MsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3JELENBQUM7SUFFRDs7T0FFRztJQUNJLGdCQUFnQixDQUFDLE1BQTBCO1FBQ2hELE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO1FBQ2pELE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxhQUFhLElBQUksRUFBRSxDQUFDO1FBQzVDLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxTQUFTLElBQUksQ0FBQyxDQUFDO1FBRXhDLE1BQU0sTUFBTSxHQUFzQjtZQUNoQyxFQUFFLEVBQUUsWUFBWTtZQUNoQixRQUFRLEVBQUUsTUFBTTtZQUNoQixRQUFRLEVBQUUsSUFBSTtZQUNkLGlCQUFpQixFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7WUFDN0IsWUFBWSxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7WUFDeEIsZ0JBQWdCLEVBQUUsS0FBSztZQUN2QixXQUFXLEVBQUUsRUFBRTtZQUNmLGVBQWUsRUFBRSxDQUFDO1lBQ2xCLGFBQWEsRUFBRSxDQUFDO1lBQ2hCLFNBQVMsRUFBRSxDQUFDO1lBQ1osUUFBUTtZQUNSLFNBQVM7WUFDVCxLQUFLLEVBQUUsS0FBSztZQUNaLG9CQUFvQixFQUFFLEtBQUs7WUFDM0Isc0JBQXNCLEVBQUUsS0FBSztZQUM3QixZQUFZLEVBQUUsS0FBSztZQUNuQix5QkFBeUIsRUFBRSxJQUFJO1lBQy9CLHlCQUF5QixFQUFFLElBQUk7WUFDL0IsaUJBQWlCLEVBQUUsS0FBSztZQUN4QixtQkFBbUIsRUFBRSxLQUFLO1lBQzFCLGNBQWMsRUFBRSxDQUFDO1NBQ2xCLENBQUM7UUFFRixJQUFJLENBQUMsZUFBZSxDQUFDLFlBQVksRUFBRSxNQUFNLENBQUMsQ0FBQztRQUMzQyxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQ7O09BRUc7SUFDSSxlQUFlLENBQUMsWUFBb0IsRUFBRSxNQUF5QjtRQUNwRSxJQUFJLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxNQUFNLENBQUMsQ0FBQztRQUNqRCxJQUFJLENBQUMsZUFBZSxDQUFDLG1CQUFtQixDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsWUFBWSxDQUFDLENBQUM7SUFDMUUsQ0FBQztJQUVEOztPQUVHO0lBQ0ksYUFBYSxDQUFDLFlBQW9CO1FBQ3ZDLE9BQU8sSUFBSSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUNsRCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxjQUFjO1FBQ25CLE9BQU8sSUFBSSxDQUFDLGlCQUFpQixDQUFDO0lBQ2hDLENBQUM7SUFFRDs7T0FFRztJQUNJLGtCQUFrQjtRQUN2QixPQUFPLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUM7SUFDckMsQ0FBQztJQUVEOztPQUVHO0lBQ0ksbUJBQW1CLENBQUMsTUFBeUIsRUFBRSxTQUFpQixRQUFRO1FBQzdFLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1lBQ3hDLE1BQU0sQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLDhCQUE4QixFQUFFLEVBQUUsWUFBWSxFQUFFLE1BQU0sQ0FBQyxFQUFFLEVBQUUsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxvQkFBb0IsRUFBRSxDQUFDLENBQUM7UUFDdEosQ0FBQztRQUVELElBQ0UsTUFBTSxDQUFDLHlCQUF5QixLQUFLLElBQUk7WUFDekMsTUFBTSxDQUFDLHlCQUF5QixLQUFLLFNBQVMsRUFDOUMsQ0FBQztZQUNELE1BQU0sQ0FBQyx5QkFBeUIsR0FBRyxNQUFNLENBQUM7WUFDMUMsSUFBSSxDQUFDLHdCQUF3QixDQUFDLFVBQVUsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUNwRCxDQUFDO1FBRUQsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztJQUN6QyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxpQkFBaUIsQ0FBQyxNQUF5QixFQUFFLFNBQWlCLFFBQVE7UUFDM0UsSUFBSSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQzdCLE1BQU0sQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUM7WUFFL0IsK0JBQStCO1lBQy9CLElBQUksQ0FBQyxlQUFlLENBQUMsb0JBQW9CLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7WUFFdEUsSUFBSSxNQUFNLENBQUMsWUFBWSxFQUFFLENBQUM7Z0JBQ3hCLFlBQVksQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUM7Z0JBQ2xDLE1BQU0sQ0FBQyxZQUFZLEdBQUcsU0FBUyxDQUFDO1lBQ2xDLENBQUM7WUFFRCx3QkFBd0I7WUFDeEIsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQztZQUN2RCxNQUFNLGFBQWEsR0FBRyxNQUFNLENBQUMsYUFBYSxDQUFDO1lBQzNDLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUM7WUFFbkMsNkRBQTZEO1lBQzdELElBQUksTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDO2dCQUNwQixJQUFJLENBQUM7b0JBQ0gsK0JBQStCO29CQUMvQixNQUFNLENBQUMsUUFBUSxDQUFDLGtCQUFrQixDQUFDLE1BQU0sQ0FBQyxDQUFDO29CQUMzQywrQkFBK0I7b0JBQy9CLE1BQU0sQ0FBQyxvQkFBb0IsR0FBRyxTQUFTLENBQUM7Z0JBQzFDLENBQUM7Z0JBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztvQkFDYixNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSwrQ0FBK0MsTUFBTSxDQUFDLEVBQUUsS0FBSyxHQUFHLEVBQUUsRUFBRSxFQUFFLFlBQVksRUFBRSxNQUFNLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLG9CQUFvQixFQUFFLENBQUMsQ0FBQztnQkFDcEssQ0FBQztZQUNILENBQUM7WUFFRCx5QkFBeUI7WUFDekIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUV4RCx5QkFBeUI7WUFDekIsSUFBSSxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQ3BCLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDMUQsQ0FBQztZQUVELDBDQUEwQztZQUMxQyxNQUFNLENBQUMsV0FBVyxHQUFHLEVBQUUsQ0FBQztZQUN4QixNQUFNLENBQUMsZUFBZSxHQUFHLENBQUMsQ0FBQztZQUUzQiwwQ0FBMEM7WUFDMUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7WUFFekMseUJBQXlCO1lBQ3pCLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO2dCQUN4QyxNQUFNLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFDZixtQkFBbUIsTUFBTSxDQUFDLFFBQVEsWUFBWSxNQUFNLENBQUMsU0FBUyxnQkFBZ0IsTUFBTSxLQUFLO29CQUN6RixhQUFhLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLGVBQWUsYUFBYSxVQUFVLFNBQVMsSUFBSTtvQkFDMUYsUUFBUSxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksaUJBQWlCLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFO29CQUN4RixHQUFHLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsc0JBQXNCLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRTtvQkFDM0QsR0FBRyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxzQkFBc0IsTUFBTSxDQUFDLGNBQWMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFDL0U7b0JBQ0UsWUFBWSxFQUFFLE1BQU0sQ0FBQyxFQUFFO29CQUN2QixRQUFRLEVBQUUsTUFBTSxDQUFDLFFBQVE7b0JBQ3pCLFNBQVMsRUFBRSxNQUFNLENBQUMsU0FBUztvQkFDM0IsTUFBTTtvQkFDTixRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUM7b0JBQ3BDLEtBQUssRUFBRSxFQUFFLEVBQUUsRUFBRSxhQUFhLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRTtvQkFDNUMsR0FBRyxFQUFFLE1BQU0sQ0FBQyxLQUFLO29CQUNqQixTQUFTLEVBQUUsTUFBTSxDQUFDLFlBQVk7b0JBQzlCLGlCQUFpQixFQUFFLE1BQU0sQ0FBQyxpQkFBaUI7b0JBQzNDLGNBQWMsRUFBRSxNQUFNLENBQUMsY0FBYyxJQUFJLENBQUM7b0JBQzFDLFNBQVMsRUFBRSxvQkFBb0I7aUJBQ2hDLENBQ0YsQ0FBQztZQUNKLENBQUM7aUJBQU0sQ0FBQztnQkFDTixNQUFNLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFDZixtQkFBbUIsTUFBTSxDQUFDLFFBQVEsZ0JBQWdCLE1BQU0sMEJBQTBCLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLEVBQUUsRUFDL0c7b0JBQ0UsWUFBWSxFQUFFLE1BQU0sQ0FBQyxFQUFFO29CQUN2QixRQUFRLEVBQUUsTUFBTSxDQUFDLFFBQVE7b0JBQ3pCLE1BQU07b0JBQ04saUJBQWlCLEVBQUUsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUk7b0JBQzlDLFNBQVMsRUFBRSxvQkFBb0I7aUJBQ2hDLENBQ0YsQ0FBQztZQUNKLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssYUFBYSxDQUFDLE1BQXlCLEVBQUUsSUFBNkIsRUFBRSxNQUEwQjtRQUN4RyxJQUFJLENBQUM7WUFDSCxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxDQUFDO2dCQUN0Qix3RUFBd0U7Z0JBQ3hFLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQztnQkFDYixNQUFNLGFBQWEsR0FBRyxVQUFVLENBQUMsR0FBRyxFQUFFO29CQUNwQyxJQUFJLENBQUM7d0JBQ0gsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQzs0QkFDdEIsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO3dCQUNuQixDQUFDO29CQUNILENBQUM7b0JBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQzt3QkFDYixNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxvQkFBb0IsSUFBSSwwQkFBMEIsTUFBTSxDQUFDLEVBQUUsS0FBSyxHQUFHLEVBQUUsRUFBRSxFQUFFLFlBQVksRUFBRSxNQUFNLENBQUMsRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxvQkFBb0IsRUFBRSxDQUFDLENBQUM7b0JBQzdLLENBQUM7Z0JBQ0gsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDO2dCQUVULHFEQUFxRDtnQkFDckQsSUFBSSxhQUFhLENBQUMsS0FBSyxFQUFFLENBQUM7b0JBQ3hCLGFBQWEsQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDeEIsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO1FBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztZQUNiLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLGlCQUFpQixJQUFJLDBCQUEwQixNQUFNLENBQUMsRUFBRSxLQUFLLEdBQUcsRUFBRSxFQUFFLEVBQUUsWUFBWSxFQUFFLE1BQU0sQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLG9CQUFvQixFQUFFLENBQUMsQ0FBQztZQUN4SyxJQUFJLENBQUM7Z0JBQ0gsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQztvQkFDdEIsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUNuQixDQUFDO1lBQ0gsQ0FBQztZQUFDLE9BQU8sVUFBVSxFQUFFLENBQUM7Z0JBQ3BCLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLG9CQUFvQixJQUFJLDBCQUEwQixNQUFNLENBQUMsRUFBRSxLQUFLLFVBQVUsRUFBRSxFQUFFLEVBQUUsWUFBWSxFQUFFLE1BQU0sQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLG9CQUFvQixFQUFFLENBQUMsQ0FBQztZQUMzTCxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNJLFdBQVcsQ0FBQyxJQUE2QixFQUFFLE1BQXlCO1FBQ3pFLE9BQU8sQ0FBQyxHQUFVLEVBQUUsRUFBRTtZQUNwQixNQUFNLElBQUksR0FBSSxHQUFXLENBQUMsSUFBSSxDQUFDO1lBQy9CLElBQUksTUFBTSxHQUFHLE9BQU8sQ0FBQztZQUVyQixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDdkIsTUFBTSxrQkFBa0IsR0FBRyxHQUFHLEdBQUcsTUFBTSxDQUFDLGlCQUFpQixDQUFDO1lBQzFELE1BQU0sZUFBZSxHQUFHLEdBQUcsR0FBRyxNQUFNLENBQUMsWUFBWSxDQUFDO1lBRWxELElBQUksSUFBSSxLQUFLLFlBQVksRUFBRSxDQUFDO2dCQUMxQixNQUFNLEdBQUcsWUFBWSxDQUFDO2dCQUN0QixNQUFNLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxpQkFBaUIsSUFBSSxvQkFBb0IsTUFBTSxDQUFDLFFBQVEsWUFBWSxHQUFHLENBQUMsT0FBTyxlQUFlLE9BQU8sQ0FBQyxRQUFRLENBQUMsa0JBQWtCLENBQUMsb0JBQW9CLE9BQU8sQ0FBQyxRQUFRLENBQUMsZUFBZSxDQUFDLEVBQUUsRUFBRTtvQkFDNU0sWUFBWSxFQUFFLE1BQU0sQ0FBQyxFQUFFO29CQUN2QixJQUFJO29CQUNKLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUTtvQkFDekIsS0FBSyxFQUFFLEdBQUcsQ0FBQyxPQUFPO29CQUNsQixRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQztvQkFDOUMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxRQUFRLENBQUMsZUFBZSxDQUFDO29CQUMvQyxTQUFTLEVBQUUsb0JBQW9CO2lCQUNoQyxDQUFDLENBQUM7WUFDTCxDQUFDO2lCQUFNLElBQUksSUFBSSxLQUFLLFdBQVcsRUFBRSxDQUFDO2dCQUNoQyxNQUFNLEdBQUcsV0FBVyxDQUFDO2dCQUNyQixNQUFNLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxnQkFBZ0IsSUFBSSxvQkFBb0IsTUFBTSxDQUFDLFFBQVEsWUFBWSxHQUFHLENBQUMsT0FBTyxlQUFlLE9BQU8sQ0FBQyxRQUFRLENBQUMsa0JBQWtCLENBQUMsb0JBQW9CLE9BQU8sQ0FBQyxRQUFRLENBQUMsZUFBZSxDQUFDLEVBQUUsRUFBRTtvQkFDM00sWUFBWSxFQUFFLE1BQU0sQ0FBQyxFQUFFO29CQUN2QixJQUFJO29CQUNKLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUTtvQkFDekIsS0FBSyxFQUFFLEdBQUcsQ0FBQyxPQUFPO29CQUNsQixRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQztvQkFDOUMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxRQUFRLENBQUMsZUFBZSxDQUFDO29CQUMvQyxTQUFTLEVBQUUsb0JBQW9CO2lCQUNoQyxDQUFDLENBQUM7WUFDTCxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsWUFBWSxJQUFJLG9CQUFvQixNQUFNLENBQUMsUUFBUSxLQUFLLEdBQUcsQ0FBQyxPQUFPLGVBQWUsT0FBTyxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQyxvQkFBb0IsT0FBTyxDQUFDLFFBQVEsQ0FBQyxlQUFlLENBQUMsRUFBRSxFQUFFO29CQUNqTSxZQUFZLEVBQUUsTUFBTSxDQUFDLEVBQUU7b0JBQ3ZCLElBQUk7b0JBQ0osUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRO29CQUN6QixLQUFLLEVBQUUsR0FBRyxDQUFDLE9BQU87b0JBQ2xCLFFBQVEsRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLGtCQUFrQixDQUFDO29CQUM5QyxZQUFZLEVBQUUsT0FBTyxDQUFDLFFBQVEsQ0FBQyxlQUFlLENBQUM7b0JBQy9DLFNBQVMsRUFBRSxvQkFBb0I7aUJBQ2hDLENBQUMsQ0FBQztZQUNMLENBQUM7WUFFRCxJQUFJLElBQUksS0FBSyxVQUFVLElBQUksTUFBTSxDQUFDLHlCQUF5QixLQUFLLElBQUksRUFBRSxDQUFDO2dCQUNyRSxNQUFNLENBQUMseUJBQXlCLEdBQUcsTUFBTSxDQUFDO2dCQUMxQyxJQUFJLENBQUMsd0JBQXdCLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQ3BELENBQUM7aUJBQU0sSUFBSSxJQUFJLEtBQUssVUFBVSxJQUFJLE1BQU0sQ0FBQyx5QkFBeUIsS0FBSyxJQUFJLEVBQUUsQ0FBQztnQkFDNUUsTUFBTSxDQUFDLHlCQUF5QixHQUFHLE1BQU0sQ0FBQztnQkFDMUMsSUFBSSxDQUFDLHdCQUF3QixDQUFDLFVBQVUsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUNwRCxDQUFDO1lBRUQsSUFBSSxDQUFDLG1CQUFtQixDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztRQUMzQyxDQUFDLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSSxXQUFXLENBQUMsSUFBNkIsRUFBRSxNQUF5QjtRQUN6RSxPQUFPLEdBQUcsRUFBRTtZQUNWLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO2dCQUN4QyxNQUFNLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSx3QkFBd0IsSUFBSSxPQUFPLEVBQUU7b0JBQ3RELFlBQVksRUFBRSxNQUFNLENBQUMsRUFBRTtvQkFDdkIsSUFBSTtvQkFDSixRQUFRLEVBQUUsTUFBTSxDQUFDLFFBQVE7b0JBQ3pCLFNBQVMsRUFBRSxvQkFBb0I7aUJBQ2hDLENBQUMsQ0FBQztZQUNMLENBQUM7WUFFRCxJQUFJLElBQUksS0FBSyxVQUFVLElBQUksTUFBTSxDQUFDLHlCQUF5QixLQUFLLElBQUksRUFBRSxDQUFDO2dCQUNyRSxNQUFNLENBQUMseUJBQXlCLEdBQUcsUUFBUSxDQUFDO2dCQUM1QyxJQUFJLENBQUMsd0JBQXdCLENBQUMsVUFBVSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBQ3RELENBQUM7aUJBQU0sSUFBSSxJQUFJLEtBQUssVUFBVSxJQUFJLE1BQU0sQ0FBQyx5QkFBeUIsS0FBSyxJQUFJLEVBQUUsQ0FBQztnQkFDNUUsTUFBTSxDQUFDLHlCQUF5QixHQUFHLFFBQVEsQ0FBQztnQkFDNUMsSUFBSSxDQUFDLHdCQUF3QixDQUFDLFVBQVUsRUFBRSxRQUFRLENBQUMsQ0FBQztnQkFDcEQsK0NBQStDO2dCQUMvQyxNQUFNLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ3pDLENBQUM7WUFFRCxJQUFJLENBQUMsbUJBQW1CLENBQUMsTUFBTSxFQUFFLFNBQVMsR0FBRyxJQUFJLENBQUMsQ0FBQztRQUNyRCxDQUFDLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSSx3QkFBd0IsQ0FBQyxJQUE2QixFQUFFLE1BQWM7UUFDM0UsSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN2RixDQUFDO0lBRUQ7O09BRUc7SUFDSSxtQkFBbUI7UUFDeEIsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLENBQUM7SUFDL0IsQ0FBQztJQUVEOztPQUVHO0lBQ0ksc0JBQXNCO1FBQzNCLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUN2QixNQUFNLGFBQWEsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFFekQsS0FBSyxNQUFNLEVBQUUsSUFBSSxhQUFhLEVBQUUsQ0FBQztZQUMvQixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQzlDLElBQUksQ0FBQyxNQUFNO2dCQUFFLFNBQVM7WUFFdEIsMkVBQTJFO1lBQzNFLElBQ0UsSUFBSSxDQUFDLFFBQVEsQ0FBQyxzQkFBc0I7Z0JBQ3BDLENBQUMsTUFBTSxDQUFDLFlBQVksSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLGtCQUFrQixLQUFLLFVBQVUsQ0FBQyxFQUN4RSxDQUFDO2dCQUNELFNBQVM7WUFDWCxDQUFDO1lBRUQsTUFBTSxjQUFjLEdBQUcsR0FBRyxHQUFHLE1BQU0sQ0FBQyxZQUFZLENBQUM7WUFFakQscUVBQXFFO1lBQ3JFLElBQUksZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxpQkFBa0IsQ0FBQztZQUN4RCxJQUFJLE1BQU0sQ0FBQyxZQUFZLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsS0FBSyxVQUFVLEVBQUUsQ0FBQztnQkFDM0UsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyw2QkFBNkIsSUFBSSxDQUFDLENBQUM7Z0JBQ3BFLGdCQUFnQixHQUFHLGdCQUFnQixHQUFHLFVBQVUsQ0FBQztZQUNuRCxDQUFDO1lBRUQsSUFBSSxjQUFjLEdBQUcsZ0JBQWdCLElBQUksQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztnQkFDbEUsb0RBQW9EO2dCQUNwRCxJQUFJLE1BQU0sQ0FBQyxZQUFZLElBQUksQ0FBQyxNQUFNLENBQUMsdUJBQXVCLEVBQUUsQ0FBQztvQkFDM0QsTUFBTSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUseUJBQXlCLEVBQUUsU0FBUyxNQUFNLENBQUMsUUFBUSxpQkFBaUIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsNENBQTRDLEVBQUU7d0JBQ25LLFlBQVksRUFBRSxFQUFFO3dCQUNoQixRQUFRLEVBQUUsTUFBTSxDQUFDLFFBQVE7d0JBQ3pCLFdBQVcsRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQzt3QkFDN0MsY0FBYyxFQUFFLFlBQVk7d0JBQzVCLFNBQVMsRUFBRSxvQkFBb0I7cUJBQ2hDLENBQUMsQ0FBQztvQkFFSCx3Q0FBd0M7b0JBQ3hDLE1BQU0sQ0FBQyx1QkFBdUIsR0FBRyxJQUFJLENBQUM7b0JBQ3RDLE1BQU0sQ0FBQyxZQUFZLEdBQUcsR0FBRyxHQUFHLENBQUMsZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLENBQUM7b0JBRXhELGdEQUFnRDtvQkFDaEQsSUFBSSxNQUFNLENBQUMsUUFBUSxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxTQUFTLEVBQUUsQ0FBQzt3QkFDbEQsSUFBSSxDQUFDOzRCQUNILE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs0QkFFdkMsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLHFCQUFxQixFQUFFLENBQUM7Z0NBQ3hDLE1BQU0sQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLG1EQUFtRCxFQUFFLEVBQUUsRUFBRSxFQUFFLFlBQVksRUFBRSxFQUFFLEVBQUUsU0FBUyxFQUFFLG9CQUFvQixFQUFFLENBQUMsQ0FBQzs0QkFDckksQ0FBQzt3QkFDSCxDQUFDO3dCQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7NEJBQ2IsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsNENBQTRDLEVBQUUsS0FBSyxHQUFHLEVBQUUsRUFBRSxFQUFFLFlBQVksRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsb0JBQW9CLEVBQUUsQ0FBQyxDQUFDO3dCQUNuSixDQUFDO29CQUNILENBQUM7Z0JBQ0gsQ0FBQztxQkFBTSxDQUFDO29CQUNOLDREQUE0RDtvQkFDNUQsTUFBTSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsK0JBQStCLEVBQUUsU0FBUyxNQUFNLENBQUMsUUFBUSxrQkFBa0IsT0FBTyxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsaUJBQWlCLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxHQUFHLEVBQUU7d0JBQ3BMLFlBQVksRUFBRSxFQUFFO3dCQUNoQixRQUFRLEVBQUUsTUFBTSxDQUFDLFFBQVE7d0JBQ3pCLFdBQVcsRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQzt3QkFDN0MsWUFBWSxFQUFFLE1BQU0sQ0FBQyxZQUFZO3dCQUNqQyxTQUFTLEVBQUUsb0JBQW9CO3FCQUNoQyxDQUFDLENBQUM7b0JBQ0gsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sRUFBRSxZQUFZLENBQUMsQ0FBQztnQkFDL0MsQ0FBQztZQUNILENBQUM7aUJBQU0sSUFBSSxjQUFjLElBQUksZ0JBQWdCLElBQUksTUFBTSxDQUFDLHVCQUF1QixFQUFFLENBQUM7Z0JBQ2hGLHdEQUF3RDtnQkFDeEQsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLHFCQUFxQixFQUFFLENBQUM7b0JBQ3hDLE1BQU0sQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLGNBQWMsRUFBRSw2Q0FBNkMsRUFBRTt3QkFDaEYsWUFBWSxFQUFFLEVBQUU7d0JBQ2hCLFNBQVMsRUFBRSxvQkFBb0I7cUJBQ2hDLENBQUMsQ0FBQztnQkFDTCxDQUFDO2dCQUNELE1BQU0sQ0FBQyx1QkFBdUIsR0FBRyxLQUFLLENBQUM7WUFDekMsQ0FBQztZQUVELHNFQUFzRTtZQUN0RSxJQUNFLE1BQU0sQ0FBQyxrQkFBa0I7Z0JBQ3pCLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxTQUFTO2dCQUMxQixDQUFDLE1BQU0sQ0FBQyxnQkFBZ0I7Z0JBQ3hCLEdBQUcsR0FBRyxNQUFNLENBQUMsa0JBQWtCLEdBQUcsTUFBTSxFQUN4QyxDQUFDO2dCQUNELE1BQU0sQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLDRCQUE0QixFQUFFLFNBQVMsTUFBTSxDQUFDLFFBQVEscUNBQXFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRyxHQUFHLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQywrQkFBK0IsRUFBRTtvQkFDOUwsWUFBWSxFQUFFLEVBQUU7b0JBQ2hCLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUTtvQkFDekIsV0FBVyxFQUFFLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRyxHQUFHLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQztvQkFDOUQsU0FBUyxFQUFFLG9CQUFvQjtpQkFDaEMsQ0FBQyxDQUFDO2dCQUNILElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLEVBQUUsY0FBYyxDQUFDLENBQUM7WUFDakQsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxnQkFBZ0I7UUFDckIsbUVBQW1FO1FBQ25FLE1BQU0sYUFBYSxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUV6RCw2Q0FBNkM7UUFDN0MsS0FBSyxNQUFNLEVBQUUsSUFBSSxhQUFhLEVBQUUsQ0FBQztZQUMvQixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQzlDLElBQUksTUFBTSxFQUFFLENBQUM7Z0JBQ1gsSUFBSSxDQUFDO29CQUNILG1CQUFtQjtvQkFDbkIsSUFBSSxNQUFNLENBQUMsWUFBWSxFQUFFLENBQUM7d0JBQ3hCLFlBQVksQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUM7d0JBQ2xDLE1BQU0sQ0FBQyxZQUFZLEdBQUcsU0FBUyxDQUFDO29CQUNsQyxDQUFDO29CQUVELHlCQUF5QjtvQkFDekIsSUFBSSxNQUFNLENBQUMsUUFBUSxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxTQUFTLEVBQUUsQ0FBQzt3QkFDbEQsTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQztvQkFDeEIsQ0FBQztvQkFFRCxJQUFJLE1BQU0sQ0FBQyxRQUFRLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFBRSxDQUFDO3dCQUNsRCxNQUFNLENBQUMsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDO29CQUN4QixDQUFDO2dCQUNILENBQUM7Z0JBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztvQkFDYixNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSwyQ0FBMkMsRUFBRSxLQUFLLEdBQUcsRUFBRSxFQUFFLEVBQUUsWUFBWSxFQUFFLEVBQUUsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxvQkFBb0IsRUFBRSxDQUFDLENBQUM7Z0JBQ2xKLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUVELGdEQUFnRDtRQUNoRCxVQUFVLENBQUMsR0FBRyxFQUFFO1lBQ2Qsd0NBQXdDO1lBQ3hDLEtBQUssTUFBTSxFQUFFLElBQUksYUFBYSxFQUFFLENBQUM7Z0JBQy9CLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7Z0JBQzlDLElBQUksTUFBTSxFQUFFLENBQUM7b0JBQ1gsSUFBSSxDQUFDO3dCQUNILCtDQUErQzt3QkFDL0MsSUFBSSxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUM7NEJBQ3BCLE1BQU0sQ0FBQyxRQUFRLENBQUMsa0JBQWtCLEVBQUUsQ0FBQzs0QkFDckMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsU0FBUyxFQUFFLENBQUM7Z0NBQy9CLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxFQUFFLENBQUM7NEJBQzVCLENBQUM7d0JBQ0gsQ0FBQzt3QkFFRCxJQUFJLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQzs0QkFDcEIsTUFBTSxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsRUFBRSxDQUFDOzRCQUNyQyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQ0FDL0IsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsQ0FBQzs0QkFDNUIsQ0FBQzt3QkFDSCxDQUFDO29CQUNILENBQUM7b0JBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQzt3QkFDYixNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxpREFBaUQsRUFBRSxLQUFLLEdBQUcsRUFBRSxFQUFFLEVBQUUsWUFBWSxFQUFFLEVBQUUsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxvQkFBb0IsRUFBRSxDQUFDLENBQUM7b0JBQ3hKLENBQUM7Z0JBQ0gsQ0FBQztZQUNILENBQUM7WUFFRCxpQkFBaUI7WUFDakIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEtBQUssRUFBRSxDQUFDO1lBQy9CLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUUsUUFBUSxFQUFFLEVBQUUsRUFBRSxDQUFDO1FBQ3pELENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUNWLENBQUM7Q0FDRiJ9
|
|
518
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29ubmVjdGlvbi1tYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvcHJveGllcy9zbWFydC1wcm94eS9jb25uZWN0aW9uLW1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxrQkFBa0IsQ0FBQztBQUU1QyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDeEQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQztBQUU3RTs7R0FFRztBQUNILE1BQU0sT0FBTyxpQkFBa0IsU0FBUSxrQkFBa0I7SUFrQnZELFlBQ1UsUUFBNEIsRUFDNUIsZUFBZ0MsRUFDaEMsY0FBOEI7UUFFdEMsS0FBSyxFQUFFLENBQUM7UUFKQSxhQUFRLEdBQVIsUUFBUSxDQUFvQjtRQUM1QixvQkFBZSxHQUFmLGVBQWUsQ0FBaUI7UUFDaEMsbUJBQWMsR0FBZCxjQUFjLENBQWdCO1FBcEJoQyxzQkFBaUIsR0FBbUMsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUM5RCxxQkFBZ0IsR0FHcEIsRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUUsQ0FBQztRQUVuQyx1RUFBdUU7UUFDL0Qsd0JBQW1CLEdBQXdCLElBQUksR0FBRyxFQUFFLENBQUM7UUFJNUMscUJBQWdCLEdBQVcsR0FBRyxDQUFDO1FBRWhELHVDQUF1QztRQUMvQixpQkFBWSxHQUFnQixJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ3RDLGlCQUFZLEdBQTBCLElBQUksQ0FBQztRQVNqRCxnREFBZ0Q7UUFDaEQsSUFBSSxDQUFDLGNBQWMsR0FBRyxRQUFRLENBQUMsUUFBUSxFQUFFLFFBQVEsRUFBRSxjQUFjLElBQUks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
|