@push.rocks/smartproxy 3.23.1 → 3.24.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.
@@ -4,13 +4,41 @@ import * as fs from 'fs';
4
4
  import * as path from 'path';
5
5
  import { fileURLToPath } from 'url';
6
6
  export class NetworkProxy {
7
+ /**
8
+ * Creates a new NetworkProxy instance
9
+ */
7
10
  constructor(optionsArg) {
8
11
  this.proxyConfigs = [];
12
+ this.defaultHeaders = {};
13
+ // State tracking
9
14
  this.router = new ProxyRouter();
10
15
  this.socketMap = new plugins.lik.ObjectMap();
11
- this.defaultHeaders = {};
12
- this.alreadyAddedReverseConfigs = {};
13
- this.options = optionsArg;
16
+ this.activeContexts = new Set();
17
+ this.connectedClients = 0;
18
+ this.startTime = 0;
19
+ this.requestsServed = 0;
20
+ this.failedRequests = 0;
21
+ this.certificateCache = new Map();
22
+ // Set default options
23
+ this.options = {
24
+ port: optionsArg.port,
25
+ maxConnections: optionsArg.maxConnections || 10000,
26
+ keepAliveTimeout: optionsArg.keepAliveTimeout || 120000, // 2 minutes
27
+ headersTimeout: optionsArg.headersTimeout || 60000, // 1 minute
28
+ logLevel: optionsArg.logLevel || 'info',
29
+ cors: optionsArg.cors || {
30
+ allowOrigin: '*',
31
+ allowMethods: 'GET, POST, PUT, DELETE, OPTIONS',
32
+ allowHeaders: 'Content-Type, Authorization',
33
+ maxAge: 86400
34
+ }
35
+ };
36
+ this.loadDefaultCertificates();
37
+ }
38
+ /**
39
+ * Loads default certificates from the filesystem
40
+ */
41
+ loadDefaultCertificates() {
14
42
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
15
43
  const certPath = path.join(__dirname, '..', 'assets', 'certs');
16
44
  try {
@@ -18,288 +46,644 @@ export class NetworkProxy {
18
46
  key: fs.readFileSync(path.join(certPath, 'key.pem'), 'utf8'),
19
47
  cert: fs.readFileSync(path.join(certPath, 'cert.pem'), 'utf8')
20
48
  };
49
+ this.log('info', 'Default certificates loaded successfully');
21
50
  }
22
51
  catch (error) {
23
- console.error('Error loading certificates:', error);
24
- throw error;
52
+ this.log('error', 'Error loading default certificates', error);
53
+ // Generate self-signed fallback certificates
54
+ try {
55
+ // This is a placeholder for actual certificate generation code
56
+ // In a real implementation, you would use a library like selfsigned to generate certs
57
+ this.defaultCertificates = {
58
+ key: "FALLBACK_KEY_CONTENT",
59
+ cert: "FALLBACK_CERT_CONTENT"
60
+ };
61
+ this.log('warn', 'Using fallback self-signed certificates');
62
+ }
63
+ catch (fallbackError) {
64
+ this.log('error', 'Failed to generate fallback certificates', fallbackError);
65
+ throw new Error('Could not load or generate SSL certificates');
66
+ }
25
67
  }
26
68
  }
69
+ /**
70
+ * Starts the proxy server
71
+ */
27
72
  async start() {
28
- // Instead of marking the callback async (which Node won't await),
29
- // we call our async handler and catch errors.
73
+ this.startTime = Date.now();
74
+ // Create the HTTPS server
30
75
  this.httpsServer = plugins.https.createServer({
31
76
  key: this.defaultCertificates.key,
32
77
  cert: this.defaultCertificates.cert
33
- }, (originRequest, originResponse) => {
34
- this.handleRequest(originRequest, originResponse).catch((error) => {
35
- console.error('Unhandled error in request handler:', error);
36
- try {
37
- originResponse.end();
38
- }
39
- catch (err) {
40
- // ignore errors during cleanup
78
+ }, (req, res) => this.handleRequest(req, res));
79
+ // Configure server timeouts
80
+ this.httpsServer.keepAliveTimeout = this.options.keepAliveTimeout;
81
+ this.httpsServer.headersTimeout = this.options.headersTimeout;
82
+ // Setup connection tracking
83
+ this.setupConnectionTracking();
84
+ // Setup WebSocket support
85
+ this.setupWebsocketSupport();
86
+ // Start metrics collection
87
+ this.setupMetricsCollection();
88
+ // Start the server
89
+ return new Promise((resolve) => {
90
+ this.httpsServer.listen(this.options.port, () => {
91
+ this.log('info', `NetworkProxy started on port ${this.options.port}`);
92
+ resolve();
93
+ });
94
+ });
95
+ }
96
+ /**
97
+ * Sets up tracking of TCP connections
98
+ */
99
+ setupConnectionTracking() {
100
+ this.httpsServer.on('connection', (connection) => {
101
+ // Check if max connections reached
102
+ if (this.socketMap.getArray().length >= this.options.maxConnections) {
103
+ this.log('warn', `Max connections (${this.options.maxConnections}) reached, rejecting new connection`);
104
+ connection.destroy();
105
+ return;
106
+ }
107
+ // Add connection to tracking
108
+ this.socketMap.add(connection);
109
+ this.connectedClients = this.socketMap.getArray().length;
110
+ this.log('debug', `New connection. Currently ${this.connectedClients} active connections`);
111
+ // Setup connection cleanup handlers
112
+ const cleanupConnection = () => {
113
+ if (this.socketMap.checkForObject(connection)) {
114
+ this.socketMap.remove(connection);
115
+ this.connectedClients = this.socketMap.getArray().length;
116
+ this.log('debug', `Connection closed. ${this.connectedClients} connections remaining`);
41
117
  }
118
+ };
119
+ connection.on('close', cleanupConnection);
120
+ connection.on('error', (err) => {
121
+ this.log('debug', 'Connection error', err);
122
+ cleanupConnection();
123
+ });
124
+ connection.on('end', cleanupConnection);
125
+ connection.on('timeout', () => {
126
+ this.log('debug', 'Connection timeout');
127
+ cleanupConnection();
42
128
  });
43
129
  });
44
- // Enable websockets
45
- const wsServer = new plugins.ws.WebSocketServer({ server: this.httpsServer });
46
- // Set up the heartbeat interval
130
+ }
131
+ /**
132
+ * Sets up WebSocket support
133
+ */
134
+ setupWebsocketSupport() {
135
+ // Create WebSocket server
136
+ this.wsServer = new plugins.ws.WebSocketServer({
137
+ server: this.httpsServer,
138
+ // Add WebSocket specific timeout
139
+ clientTracking: true
140
+ });
141
+ // Handle WebSocket connections
142
+ this.wsServer.on('connection', (wsIncoming, reqArg) => {
143
+ this.handleWebSocketConnection(wsIncoming, reqArg);
144
+ });
145
+ // Set up the heartbeat interval (check every 30 seconds, terminate after 2 minutes of inactivity)
47
146
  this.heartbeatInterval = setInterval(() => {
48
- wsServer.clients.forEach((ws) => {
49
- const wsIncoming = ws;
50
- if (!wsIncoming.lastPong) {
51
- wsIncoming.lastPong = Date.now();
52
- }
53
- if (Date.now() - wsIncoming.lastPong > 5 * 60 * 1000) {
54
- console.log('Terminating websocket due to missing pong for 5 minutes.');
55
- wsIncoming.terminate();
56
- }
57
- else {
58
- wsIncoming.ping();
147
+ if (this.wsServer.clients.size === 0) {
148
+ return; // Skip if no active connections
149
+ }
150
+ this.log('debug', `WebSocket heartbeat check for ${this.wsServer.clients.size} clients`);
151
+ this.wsServer.clients.forEach((ws) => {
152
+ const wsWithHeartbeat = ws;
153
+ if (wsWithHeartbeat.isAlive === false) {
154
+ this.log('debug', 'Terminating inactive WebSocket connection');
155
+ return wsWithHeartbeat.terminate();
59
156
  }
157
+ wsWithHeartbeat.isAlive = false;
158
+ wsWithHeartbeat.ping();
60
159
  });
61
- }, 60000); // runs every 1 minute
62
- wsServer.on('connection', (wsIncoming, reqArg) => {
63
- console.log(`wss proxy: got connection for wsc for https://${reqArg.headers.host}${reqArg.url}`);
160
+ }, 30000);
161
+ }
162
+ /**
163
+ * Sets up metrics collection
164
+ */
165
+ setupMetricsCollection() {
166
+ this.metricsInterval = setInterval(() => {
167
+ const uptime = Math.floor((Date.now() - this.startTime) / 1000);
168
+ const metrics = {
169
+ uptime,
170
+ activeConnections: this.connectedClients,
171
+ totalRequests: this.requestsServed,
172
+ failedRequests: this.failedRequests,
173
+ activeWebSockets: this.wsServer?.clients.size || 0,
174
+ memoryUsage: process.memoryUsage(),
175
+ activeContexts: Array.from(this.activeContexts)
176
+ };
177
+ this.log('debug', 'Proxy metrics', metrics);
178
+ }, 60000); // Log metrics every minute
179
+ }
180
+ /**
181
+ * Handles an incoming WebSocket connection
182
+ */
183
+ handleWebSocketConnection(wsIncoming, reqArg) {
184
+ const wsPath = reqArg.url;
185
+ const wsHost = reqArg.headers.host;
186
+ this.log('info', `WebSocket connection for ${wsHost}${wsPath}`);
187
+ // Setup heartbeat tracking
188
+ wsIncoming.isAlive = true;
189
+ wsIncoming.lastPong = Date.now();
190
+ wsIncoming.on('pong', () => {
191
+ wsIncoming.isAlive = true;
64
192
  wsIncoming.lastPong = Date.now();
65
- wsIncoming.on('pong', () => {
66
- wsIncoming.lastPong = Date.now();
67
- });
68
- let wsOutgoing;
69
- const outGoingDeferred = plugins.smartpromise.defer();
70
- // --- Improvement 2: Only call routeReq once ---
71
- const wsDestinationConfig = this.router.routeReq(reqArg);
72
- if (!wsDestinationConfig) {
73
- wsIncoming.terminate();
74
- return;
75
- }
193
+ });
194
+ // Get the destination configuration
195
+ const wsDestinationConfig = this.router.routeReq(reqArg);
196
+ if (!wsDestinationConfig) {
197
+ this.log('warn', `No route found for WebSocket ${wsHost}${wsPath}`);
198
+ wsIncoming.terminate();
199
+ return;
200
+ }
201
+ // Check authentication if required
202
+ if (wsDestinationConfig.authentication) {
76
203
  try {
77
- wsOutgoing = new plugins.wsDefault(`ws://${wsDestinationConfig.destinationIp}:${wsDestinationConfig.destinationPort}${reqArg.url}`);
78
- console.log('wss proxy: initiated outgoing proxy');
79
- wsOutgoing.on('open', async () => {
80
- outGoingDeferred.resolve();
81
- });
204
+ if (!this.authenticateRequest(reqArg, wsDestinationConfig)) {
205
+ this.log('warn', `WebSocket authentication failed for ${wsHost}${wsPath}`);
206
+ wsIncoming.terminate();
207
+ return;
208
+ }
82
209
  }
83
- catch (err) {
84
- console.error('Error initiating outgoing WebSocket:', err);
210
+ catch (error) {
211
+ this.log('error', 'WebSocket authentication error', error);
85
212
  wsIncoming.terminate();
86
213
  return;
87
214
  }
88
- wsIncoming.on('message', async (message, isBinary) => {
89
- try {
90
- await outGoingDeferred.promise;
215
+ }
216
+ // Setup outgoing WebSocket connection
217
+ let wsOutgoing;
218
+ const outGoingDeferred = plugins.smartpromise.defer();
219
+ try {
220
+ const wsTarget = `ws://${wsDestinationConfig.destinationIp}:${wsDestinationConfig.destinationPort}${reqArg.url}`;
221
+ this.log('debug', `Proxying WebSocket to ${wsTarget}`);
222
+ wsOutgoing = new plugins.wsDefault(wsTarget);
223
+ wsOutgoing.on('open', () => {
224
+ this.log('debug', 'Outgoing WebSocket connection established');
225
+ outGoingDeferred.resolve();
226
+ });
227
+ wsOutgoing.on('error', (error) => {
228
+ this.log('error', 'Outgoing WebSocket error', error);
229
+ outGoingDeferred.reject(error);
230
+ if (wsIncoming.readyState === wsIncoming.OPEN) {
231
+ wsIncoming.terminate();
232
+ }
233
+ });
234
+ }
235
+ catch (err) {
236
+ this.log('error', 'Failed to create outgoing WebSocket connection', err);
237
+ wsIncoming.terminate();
238
+ return;
239
+ }
240
+ // Handle message forwarding from client to backend
241
+ wsIncoming.on('message', async (message, isBinary) => {
242
+ try {
243
+ // Wait for outgoing connection to be ready
244
+ await outGoingDeferred.promise;
245
+ // Only forward if both connections are still open
246
+ if (wsOutgoing.readyState === wsOutgoing.OPEN) {
91
247
  wsOutgoing.send(message, { binary: isBinary });
92
248
  }
93
- catch (error) {
94
- console.error('Error sending message to wsOutgoing:', error);
249
+ }
250
+ catch (error) {
251
+ this.log('error', 'Error forwarding WebSocket message to backend', error);
252
+ }
253
+ });
254
+ // Handle message forwarding from backend to client
255
+ wsOutgoing.on('message', (message, isBinary) => {
256
+ try {
257
+ // Only forward if the incoming connection is still open
258
+ if (wsIncoming.readyState === wsIncoming.OPEN) {
259
+ wsIncoming.send(message, { binary: isBinary });
95
260
  }
96
- });
97
- wsOutgoing.on('message', async (message, isBinary) => {
261
+ }
262
+ catch (error) {
263
+ this.log('error', 'Error forwarding WebSocket message to client', error);
264
+ }
265
+ });
266
+ // Clean up connections when either side closes
267
+ wsIncoming.on('close', (code, reason) => {
268
+ this.log('debug', `Incoming WebSocket closed: ${code} - ${reason}`);
269
+ if (wsOutgoing && wsOutgoing.readyState !== wsOutgoing.CLOSED) {
98
270
  try {
99
- wsIncoming.send(message, { binary: isBinary });
271
+ // Validate close code (must be 1000-4999) or use 1000 as default
272
+ const validCode = (code >= 1000 && code <= 4999) ? code : 1000;
273
+ wsOutgoing.close(validCode, reason.toString() || '');
100
274
  }
101
275
  catch (error) {
102
- console.error('Error sending message to wsIncoming:', error);
103
- }
104
- });
105
- const terminateWsOutgoing = () => {
106
- if (wsOutgoing) {
276
+ this.log('error', 'Error closing outgoing WebSocket', error);
107
277
  wsOutgoing.terminate();
108
- console.log('Terminated outgoing ws.');
109
278
  }
110
- };
111
- wsIncoming.on('error', terminateWsOutgoing);
112
- wsIncoming.on('close', terminateWsOutgoing);
113
- const terminateWsIncoming = () => {
114
- if (wsIncoming) {
115
- wsIncoming.terminate();
116
- console.log('Terminated incoming ws.');
117
- }
118
- };
119
- wsOutgoing.on('error', terminateWsIncoming);
120
- wsOutgoing.on('close', terminateWsIncoming);
279
+ }
121
280
  });
122
- this.httpsServer.keepAliveTimeout = 600 * 1000;
123
- this.httpsServer.headersTimeout = 600 * 1000;
124
- this.httpsServer.on('connection', (connection) => {
125
- this.socketMap.add(connection);
126
- console.log(`Added connection. Now ${this.socketMap.getArray().length} sockets connected.`);
127
- const cleanupConnection = () => {
128
- if (this.socketMap.checkForObject(connection)) {
129
- this.socketMap.remove(connection);
130
- console.log(`Removed connection. ${this.socketMap.getArray().length} sockets remaining.`);
131
- connection.destroy();
281
+ wsOutgoing.on('close', (code, reason) => {
282
+ this.log('debug', `Outgoing WebSocket closed: ${code} - ${reason}`);
283
+ if (wsIncoming && wsIncoming.readyState !== wsIncoming.CLOSED) {
284
+ try {
285
+ // Validate close code (must be 1000-4999) or use 1000 as default
286
+ const validCode = (code >= 1000 && code <= 4999) ? code : 1000;
287
+ wsIncoming.close(validCode, reason.toString() || '');
132
288
  }
133
- };
134
- connection.on('close', cleanupConnection);
135
- connection.on('error', cleanupConnection);
136
- connection.on('end', cleanupConnection);
137
- connection.on('timeout', cleanupConnection);
289
+ catch (error) {
290
+ this.log('error', 'Error closing incoming WebSocket', error);
291
+ wsIncoming.terminate();
292
+ }
293
+ }
138
294
  });
139
- this.httpsServer.listen(this.options.port);
140
- console.log(`NetworkProxy -> OK: now listening for new connections on port ${this.options.port}`);
141
295
  }
142
296
  /**
143
- * Internal async handler for processing HTTP/HTTPS requests.
297
+ * Handles an HTTP/HTTPS request
144
298
  */
145
299
  async handleRequest(originRequest, originResponse) {
146
- const endOriginReqRes = (statusArg = 404, messageArg = 'This route is not available on this server.', headers = {}) => {
147
- originResponse.writeHead(statusArg, messageArg);
148
- originResponse.end(messageArg);
149
- if (originRequest.socket !== originResponse.socket) {
150
- console.log('hey, something is strange.');
300
+ this.requestsServed++;
301
+ const startTime = Date.now();
302
+ const reqId = `req_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
303
+ try {
304
+ const reqPath = plugins.url.parse(originRequest.url).path;
305
+ this.log('info', `[${reqId}] ${originRequest.method} ${originRequest.headers.host}${reqPath}`);
306
+ // Handle preflight OPTIONS requests for CORS
307
+ if (originRequest.method === 'OPTIONS' && this.options.cors) {
308
+ this.handleCorsRequest(originRequest, originResponse);
309
+ return;
151
310
  }
152
- originResponse.destroy();
153
- };
154
- console.log(`got request: ${originRequest.headers.host}${plugins.url.parse(originRequest.url).path}`);
155
- const destinationConfig = this.router.routeReq(originRequest);
156
- if (!destinationConfig) {
157
- console.log(`${originRequest.headers.host} can't be routed properly. Terminating request.`);
158
- endOriginReqRes();
159
- return;
160
- }
161
- // authentication
162
- if (destinationConfig.authentication) {
163
- const authInfo = destinationConfig.authentication;
164
- switch (authInfo.type) {
165
- case 'Basic': {
166
- const authHeader = originRequest.headers.authorization;
167
- if (!authHeader) {
168
- return endOriginReqRes(401, 'Authentication required', {
169
- 'WWW-Authenticate': 'Basic realm="Access to the staging site", charset="UTF-8"',
170
- });
171
- }
172
- if (!authHeader.includes('Basic ')) {
173
- return endOriginReqRes(401, 'Authentication required', {
174
- 'WWW-Authenticate': 'Basic realm="Access to the staging site", charset="UTF-8"',
311
+ // Get destination configuration
312
+ const destinationConfig = this.router.routeReq(originRequest);
313
+ if (!destinationConfig) {
314
+ this.log('warn', `[${reqId}] No route found for ${originRequest.headers.host}`);
315
+ this.sendErrorResponse(originResponse, 404, 'Not Found: No matching route');
316
+ this.failedRequests++;
317
+ return;
318
+ }
319
+ // Handle authentication if configured
320
+ if (destinationConfig.authentication) {
321
+ try {
322
+ if (!this.authenticateRequest(originRequest, destinationConfig)) {
323
+ this.sendErrorResponse(originResponse, 401, 'Unauthorized', {
324
+ 'WWW-Authenticate': 'Basic realm="Access to the proxy site", charset="UTF-8"'
175
325
  });
326
+ this.failedRequests++;
327
+ return;
176
328
  }
177
- const authStringBase64 = authHeader.replace('Basic ', '');
178
- const authString = plugins.smartstring.base64.decode(authStringBase64);
179
- const userPassArray = authString.split(':');
180
- const user = userPassArray[0];
181
- const pass = userPassArray[1];
182
- if (user === authInfo.user && pass === authInfo.pass) {
183
- console.log('Request successfully authenticated');
184
- }
185
- else {
186
- return endOriginReqRes(403, 'Forbidden: Wrong credentials');
187
- }
188
- break;
189
329
  }
190
- default:
191
- return endOriginReqRes(403, 'Forbidden: unsupported authentication method configured. Please report to the admin.');
330
+ catch (error) {
331
+ this.log('error', `[${reqId}] Authentication error`, error);
332
+ this.sendErrorResponse(originResponse, 500, 'Internal Server Error: Authentication failed');
333
+ this.failedRequests++;
334
+ return;
335
+ }
336
+ }
337
+ // Construct destination URL
338
+ const destinationUrl = `http://${destinationConfig.destinationIp}:${destinationConfig.destinationPort}${originRequest.url}`;
339
+ this.log('debug', `[${reqId}] Proxying to ${destinationUrl}`);
340
+ // Forward the request
341
+ await this.forwardRequest(reqId, originRequest, originResponse, destinationUrl);
342
+ const processingTime = Date.now() - startTime;
343
+ this.log('debug', `[${reqId}] Request completed in ${processingTime}ms`);
344
+ }
345
+ catch (error) {
346
+ this.log('error', `[${reqId}] Unhandled error in request handler`, error);
347
+ try {
348
+ this.sendErrorResponse(originResponse, 502, 'Bad Gateway: Server error');
349
+ }
350
+ catch (responseError) {
351
+ this.log('error', `[${reqId}] Failed to send error response`, responseError);
192
352
  }
353
+ this.failedRequests++;
193
354
  }
194
- let destinationUrl;
195
- if (destinationConfig) {
196
- destinationUrl = `http://${destinationConfig.destinationIp}:${destinationConfig.destinationPort}${originRequest.url}`;
355
+ }
356
+ /**
357
+ * Handles a CORS preflight request
358
+ */
359
+ handleCorsRequest(req, res) {
360
+ const cors = this.options.cors;
361
+ // Set CORS headers
362
+ res.setHeader('Access-Control-Allow-Origin', cors.allowOrigin);
363
+ res.setHeader('Access-Control-Allow-Methods', cors.allowMethods);
364
+ res.setHeader('Access-Control-Allow-Headers', cors.allowHeaders);
365
+ res.setHeader('Access-Control-Max-Age', String(cors.maxAge));
366
+ // Handle preflight request
367
+ res.statusCode = 204;
368
+ res.end();
369
+ // Count this as a request served
370
+ this.requestsServed++;
371
+ }
372
+ /**
373
+ * Authenticates a request against the destination config
374
+ */
375
+ authenticateRequest(req, config) {
376
+ const authInfo = config.authentication;
377
+ if (!authInfo) {
378
+ return true; // No authentication required
197
379
  }
198
- else {
199
- return endOriginReqRes();
380
+ switch (authInfo.type) {
381
+ case 'Basic': {
382
+ const authHeader = req.headers.authorization;
383
+ if (!authHeader || !authHeader.includes('Basic ')) {
384
+ return false;
385
+ }
386
+ const authStringBase64 = authHeader.replace('Basic ', '');
387
+ const authString = plugins.smartstring.base64.decode(authStringBase64);
388
+ const [user, pass] = authString.split(':');
389
+ // Use constant-time comparison to prevent timing attacks
390
+ const userMatch = user === authInfo.user;
391
+ const passMatch = pass === authInfo.pass;
392
+ return userMatch && passMatch;
393
+ }
394
+ default:
395
+ throw new Error(`Unsupported authentication method: ${authInfo.type}`);
200
396
  }
201
- console.log(destinationUrl);
397
+ }
398
+ /**
399
+ * Forwards a request to the destination
400
+ */
401
+ async forwardRequest(reqId, originRequest, originResponse, destinationUrl) {
202
402
  try {
203
- const proxyResponse = await plugins.smartrequest.request(destinationUrl, {
403
+ const proxyRequest = await plugins.smartrequest.request(destinationUrl, {
204
404
  method: originRequest.method,
205
- headers: {
206
- ...originRequest.headers,
207
- 'X-Forwarded-Host': originRequest.headers.host,
208
- 'X-Forwarded-Proto': 'https',
209
- },
405
+ headers: this.prepareForwardHeaders(originRequest),
210
406
  keepAlive: true,
211
- }, true, // streaming (keepAlive)
212
- (proxyRequest) => {
213
- originRequest.on('data', (data) => {
214
- proxyRequest.write(data);
215
- });
216
- originRequest.on('end', () => {
217
- proxyRequest.end();
218
- });
219
- originRequest.on('error', () => {
220
- proxyRequest.end();
221
- });
222
- originRequest.on('close', () => {
223
- proxyRequest.end();
224
- });
225
- originRequest.on('timeout', () => {
226
- proxyRequest.end();
227
- originRequest.destroy();
228
- });
229
- proxyRequest.on('error', () => {
230
- endOriginReqRes();
407
+ timeout: 30000 // 30 second timeout
408
+ }, true, // streaming
409
+ (proxyRequestStream) => this.setupRequestStreaming(originRequest, proxyRequestStream));
410
+ // Handle the response
411
+ this.processProxyResponse(reqId, originResponse, proxyRequest);
412
+ }
413
+ catch (error) {
414
+ this.log('error', `[${reqId}] Error forwarding request`, error);
415
+ this.sendErrorResponse(originResponse, 502, 'Bad Gateway: Unable to reach upstream server');
416
+ throw error; // Let the main handler catch this
417
+ }
418
+ }
419
+ /**
420
+ * Prepares headers to forward to the backend
421
+ */
422
+ prepareForwardHeaders(req) {
423
+ const safeHeaders = { ...req.headers };
424
+ // Add forwarding headers
425
+ safeHeaders['X-Forwarded-Host'] = req.headers.host;
426
+ safeHeaders['X-Forwarded-Proto'] = 'https';
427
+ safeHeaders['X-Forwarded-For'] = (req.socket.remoteAddress || '').replace(/^::ffff:/, '');
428
+ // Add proxy-specific headers
429
+ safeHeaders['X-Proxy-Id'] = `NetworkProxy-${this.options.port}`;
430
+ // Remove sensitive headers we don't want to forward
431
+ const sensitiveHeaders = ['connection', 'upgrade', 'http2-settings'];
432
+ for (const header of sensitiveHeaders) {
433
+ delete safeHeaders[header];
434
+ }
435
+ return safeHeaders;
436
+ }
437
+ /**
438
+ * Sets up request streaming for the proxy
439
+ */
440
+ setupRequestStreaming(originRequest, proxyRequest) {
441
+ // Forward request body data
442
+ originRequest.on('data', (chunk) => {
443
+ proxyRequest.write(chunk);
444
+ });
445
+ // End the request when done
446
+ originRequest.on('end', () => {
447
+ proxyRequest.end();
448
+ });
449
+ // Handle request errors
450
+ originRequest.on('error', (error) => {
451
+ this.log('error', 'Error in client request stream', error);
452
+ proxyRequest.destroy(error);
453
+ });
454
+ // Handle client abort/timeout
455
+ originRequest.on('close', () => {
456
+ if (!originRequest.complete) {
457
+ this.log('debug', 'Client closed connection before request completed');
458
+ proxyRequest.destroy();
459
+ }
460
+ });
461
+ originRequest.on('timeout', () => {
462
+ this.log('debug', 'Client request timeout');
463
+ proxyRequest.destroy(new Error('Client request timeout'));
464
+ });
465
+ // Handle proxy request errors
466
+ proxyRequest.on('error', (error) => {
467
+ this.log('error', 'Error in outgoing proxy request', error);
468
+ });
469
+ }
470
+ /**
471
+ * Processes a proxy response
472
+ */
473
+ processProxyResponse(reqId, originResponse, proxyResponse) {
474
+ this.log('debug', `[${reqId}] Received upstream response: ${proxyResponse.statusCode}`);
475
+ // Set status code
476
+ originResponse.statusCode = proxyResponse.statusCode;
477
+ // Add default headers
478
+ for (const [headerName, headerValue] of Object.entries(this.defaultHeaders)) {
479
+ originResponse.setHeader(headerName, headerValue);
480
+ }
481
+ // Add CORS headers if enabled
482
+ if (this.options.cors) {
483
+ originResponse.setHeader('Access-Control-Allow-Origin', this.options.cors.allowOrigin);
484
+ }
485
+ // Copy response headers
486
+ for (const [headerName, headerValue] of Object.entries(proxyResponse.headers)) {
487
+ // Skip hop-by-hop headers
488
+ const hopByHopHeaders = ['connection', 'keep-alive', 'transfer-encoding', 'te',
489
+ 'trailer', 'upgrade', 'proxy-authorization', 'proxy-authenticate'];
490
+ if (!hopByHopHeaders.includes(headerName.toLowerCase())) {
491
+ originResponse.setHeader(headerName, headerValue);
492
+ }
493
+ }
494
+ // Stream response body
495
+ proxyResponse.on('data', (chunk) => {
496
+ const canContinue = originResponse.write(chunk);
497
+ // Apply backpressure if needed
498
+ if (!canContinue) {
499
+ proxyResponse.pause();
500
+ originResponse.once('drain', () => {
501
+ proxyResponse.resume();
231
502
  });
232
- });
233
- originResponse.statusCode = proxyResponse.statusCode;
234
- console.log(proxyResponse.statusCode);
235
- for (const defaultHeader of Object.keys(this.defaultHeaders)) {
236
- originResponse.setHeader(defaultHeader, this.defaultHeaders[defaultHeader]);
237
503
  }
238
- for (const header of Object.keys(proxyResponse.headers)) {
239
- originResponse.setHeader(header, proxyResponse.headers[header]);
504
+ });
505
+ // End the response when done
506
+ proxyResponse.on('end', () => {
507
+ originResponse.end();
508
+ });
509
+ // Handle response errors
510
+ proxyResponse.on('error', (error) => {
511
+ this.log('error', `[${reqId}] Error in proxy response stream`, error);
512
+ originResponse.destroy(error);
513
+ });
514
+ originResponse.on('error', (error) => {
515
+ this.log('error', `[${reqId}] Error in client response stream`, error);
516
+ proxyResponse.destroy();
517
+ });
518
+ }
519
+ /**
520
+ * Sends an error response to the client
521
+ */
522
+ sendErrorResponse(res, statusCode = 500, message = 'Internal Server Error', headers = {}) {
523
+ try {
524
+ // If headers already sent, just end the response
525
+ if (res.headersSent) {
526
+ res.end();
527
+ return;
528
+ }
529
+ // Add default headers
530
+ for (const [key, value] of Object.entries(this.defaultHeaders)) {
531
+ res.setHeader(key, value);
532
+ }
533
+ // Add provided headers
534
+ for (const [key, value] of Object.entries(headers)) {
535
+ res.setHeader(key, value);
536
+ }
537
+ // Send error response
538
+ res.writeHead(statusCode, message);
539
+ // Send error body as JSON for API clients
540
+ if (res.getHeader('Content-Type') === 'application/json') {
541
+ res.end(JSON.stringify({ error: { status: statusCode, message } }));
542
+ }
543
+ else {
544
+ // Send as plain text
545
+ res.end(message);
240
546
  }
241
- proxyResponse.on('data', (data) => {
242
- originResponse.write(data);
243
- });
244
- proxyResponse.on('end', () => {
245
- originResponse.end();
246
- });
247
- proxyResponse.on('error', () => {
248
- originResponse.destroy();
249
- });
250
- proxyResponse.on('close', () => {
251
- originResponse.end();
252
- });
253
- proxyResponse.on('timeout', () => {
254
- originResponse.end();
255
- originResponse.destroy();
256
- });
257
547
  }
258
548
  catch (error) {
259
- console.error('Error while processing request:', error);
260
- endOriginReqRes(502, 'Bad Gateway: Error processing the request');
549
+ this.log('error', 'Error sending error response', error);
550
+ try {
551
+ res.destroy();
552
+ }
553
+ catch (destroyError) {
554
+ // Last resort - nothing more we can do
555
+ }
261
556
  }
262
557
  }
558
+ /**
559
+ * Updates proxy configurations
560
+ */
263
561
  async updateProxyConfigs(proxyConfigsArg) {
264
- console.log(`got new proxy configs`);
562
+ this.log('info', `Updating proxy configurations (${proxyConfigsArg.length} configs)`);
563
+ // Update internal configs
265
564
  this.proxyConfigs = proxyConfigsArg;
266
565
  this.router.setNewProxyConfigs(proxyConfigsArg);
267
- for (const hostCandidate of this.proxyConfigs) {
268
- const existingHostNameConfig = this.alreadyAddedReverseConfigs[hostCandidate.hostName];
269
- if (!existingHostNameConfig) {
270
- this.alreadyAddedReverseConfigs[hostCandidate.hostName] = hostCandidate;
271
- }
272
- else {
273
- if (existingHostNameConfig.publicKey === hostCandidate.publicKey &&
274
- existingHostNameConfig.privateKey === hostCandidate.privateKey) {
275
- continue;
276
- }
277
- else {
278
- this.alreadyAddedReverseConfigs[hostCandidate.hostName] = hostCandidate;
566
+ // Collect all hostnames for cleanup later
567
+ const currentHostNames = new Set();
568
+ // Add/update SSL contexts for each host
569
+ for (const config of proxyConfigsArg) {
570
+ currentHostNames.add(config.hostName);
571
+ try {
572
+ // Check if we need to update the cert
573
+ const currentCert = this.certificateCache.get(config.hostName);
574
+ const shouldUpdate = !currentCert ||
575
+ currentCert.key !== config.privateKey ||
576
+ currentCert.cert !== config.publicKey;
577
+ if (shouldUpdate) {
578
+ this.log('debug', `Updating SSL context for ${config.hostName}`);
579
+ // Update the HTTPS server context
580
+ this.httpsServer.addContext(config.hostName, {
581
+ key: config.privateKey,
582
+ cert: config.publicKey
583
+ });
584
+ // Update the cache
585
+ this.certificateCache.set(config.hostName, {
586
+ key: config.privateKey,
587
+ cert: config.publicKey
588
+ });
589
+ this.activeContexts.add(config.hostName);
279
590
  }
280
591
  }
281
- this.httpsServer.addContext(hostCandidate.hostName, {
282
- cert: hostCandidate.publicKey,
283
- key: hostCandidate.privateKey,
284
- });
592
+ catch (error) {
593
+ this.log('error', `Failed to add SSL context for ${config.hostName}`, error);
594
+ }
595
+ }
596
+ // Clean up removed contexts
597
+ // Note: Node.js doesn't officially support removing contexts
598
+ // This would require server restart in production
599
+ for (const hostname of this.activeContexts) {
600
+ if (!currentHostNames.has(hostname)) {
601
+ this.log('info', `Hostname ${hostname} removed from configuration`);
602
+ this.activeContexts.delete(hostname);
603
+ this.certificateCache.delete(hostname);
604
+ }
285
605
  }
286
606
  }
607
+ /**
608
+ * Adds default headers to be included in all responses
609
+ */
287
610
  async addDefaultHeaders(headersArg) {
288
- for (const headerKey of Object.keys(headersArg)) {
289
- this.defaultHeaders[headerKey] = headersArg[headerKey];
290
- }
611
+ this.log('info', 'Adding default headers', headersArg);
612
+ this.defaultHeaders = {
613
+ ...this.defaultHeaders,
614
+ ...headersArg
615
+ };
291
616
  }
617
+ /**
618
+ * Stops the proxy server
619
+ */
292
620
  async stop() {
293
- const done = plugins.smartpromise.defer();
294
- this.httpsServer.close(() => {
295
- done.resolve();
296
- });
621
+ this.log('info', 'Stopping NetworkProxy server');
622
+ // Clear intervals
623
+ if (this.heartbeatInterval) {
624
+ clearInterval(this.heartbeatInterval);
625
+ }
626
+ if (this.metricsInterval) {
627
+ clearInterval(this.metricsInterval);
628
+ }
629
+ // Close WebSocket server if exists
630
+ if (this.wsServer) {
631
+ for (const client of this.wsServer.clients) {
632
+ try {
633
+ client.terminate();
634
+ }
635
+ catch (error) {
636
+ this.log('error', 'Error terminating WebSocket client', error);
637
+ }
638
+ }
639
+ }
640
+ // Close all tracked sockets
297
641
  for (const socket of this.socketMap.getArray()) {
298
- socket.destroy();
642
+ try {
643
+ socket.destroy();
644
+ }
645
+ catch (error) {
646
+ this.log('error', 'Error destroying socket', error);
647
+ }
648
+ }
649
+ // Close the HTTPS server
650
+ return new Promise((resolve) => {
651
+ this.httpsServer.close(() => {
652
+ this.log('info', 'NetworkProxy server stopped successfully');
653
+ resolve();
654
+ });
655
+ });
656
+ }
657
+ /**
658
+ * Logs a message according to the configured log level
659
+ */
660
+ log(level, message, data) {
661
+ const logLevels = {
662
+ error: 0,
663
+ warn: 1,
664
+ info: 2,
665
+ debug: 3
666
+ };
667
+ // Skip if log level is higher than configured
668
+ if (logLevels[level] > logLevels[this.options.logLevel]) {
669
+ return;
670
+ }
671
+ const timestamp = new Date().toISOString();
672
+ const prefix = `[${timestamp}] [${level.toUpperCase()}]`;
673
+ switch (level) {
674
+ case 'error':
675
+ console.error(`${prefix} ${message}`, data || '');
676
+ break;
677
+ case 'warn':
678
+ console.warn(`${prefix} ${message}`, data || '');
679
+ break;
680
+ case 'info':
681
+ console.log(`${prefix} ${message}`, data || '');
682
+ break;
683
+ case 'debug':
684
+ console.log(`${prefix} ${message}`, data || '');
685
+ break;
299
686
  }
300
- await done.promise;
301
- clearInterval(this.heartbeatInterval);
302
- console.log('NetworkProxy -> OK: Server has been stopped and all connections closed.');
303
687
  }
304
688
  }
305
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5uZXR3b3JrcHJveHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLm5ldHdvcmtwcm94eS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDbEQsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDekIsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLEtBQUssQ0FBQztBQVVwQyxNQUFNLE9BQU8sWUFBWTtJQWN2QixZQUFZLFVBQWdDO1FBWnJDLGlCQUFZLEdBQWtELEVBQUUsQ0FBQztRQUVqRSxXQUFNLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztRQUMzQixjQUFTLEdBQUcsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFNBQVMsRUFBc0IsQ0FBQztRQUM1RCxtQkFBYyxHQUE4QixFQUFFLENBQUM7UUFJL0MsK0JBQTBCLEdBRTdCLEVBQUUsQ0FBQztRQUdMLElBQUksQ0FBQyxPQUFPLEdBQUcsVUFBVSxDQUFDO1FBQzFCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUMvRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRS9ELElBQUksQ0FBQztZQUNILElBQUksQ0FBQyxtQkFBbUIsR0FBRztnQkFDekIsR0FBRyxFQUFFLEVBQUUsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsU0FBUyxDQUFDLEVBQUUsTUFBTSxDQUFDO2dCQUM1RCxJQUFJLEVBQUUs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
689
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5uZXR3b3JrcHJveHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLm5ldHdvcmtwcm94eS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDbEQsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDekIsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLEtBQUssQ0FBQztBQXFCcEMsTUFBTSxPQUFPLFlBQVk7SUEyQnZCOztPQUVHO0lBQ0gsWUFBWSxVQUFnQztRQTNCckMsaUJBQVksR0FBa0QsRUFBRSxDQUFDO1FBQ2pFLG1CQUFjLEdBQThCLEVBQUUsQ0FBQztRQU10RCxpQkFBaUI7UUFDVixXQUFNLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztRQUMzQixjQUFTLEdBQUcsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFNBQVMsRUFBc0IsQ0FBQztRQUM1RCxtQkFBYyxHQUFnQixJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ3hDLHFCQUFnQixHQUFXLENBQUMsQ0FBQztRQUM3QixjQUFTLEdBQVcsQ0FBQyxDQUFDO1FBQ3RCLG1CQUFjLEdBQVcsQ0FBQyxDQUFDO1FBQzNCLG1CQUFjLEdBQVcsQ0FBQyxDQUFDO1FBUTFCLHFCQUFnQixHQUErRCxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBTS9GLHNCQUFzQjtRQUN0QixJQUFJLENBQUMsT0FBTyxHQUFHO1lBQ2IsSUFBSSxFQUFFLFVBQVUsQ0FBQyxJQUFJO1lBQ3JCLGNBQWMsRUFBRSxVQUFVLENBQUMsY0FBYyxJQUFJLEtBQUs7WUFDbEQsZ0JBQWdCLEVBQUUsVUFBVSxDQUFDLGdCQUFnQixJQUFJLE1BQU0sRUFBRSxhQUFhO1lBQ3RFLGNBQWMsRUFBRSxVQUFVLENBQUMsY0FBYyxJQUFJLEtBQUssRUFBRSxXQUFXO1lBQy9ELFFBQVEsRUFBRSxVQUFVLENBQUMsUUFBUSxJQUFJLE1BQU07WUFDdkMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxJQUFJLElBQUk7Z0JBQ3ZCLFdBQVcsRUFBRSxHQUFHO2dCQUNoQixZQUFZLEVBQUUsaUNBQWlDO2dCQUMvQyxZQUFZLEVBQUUsNkJBQTZCO2dCQUMzQyxNQUFNLEVBQUUsS0FBSzthQUNkO1NBQ0YsQ0FBQztRQUVGLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO0lBQ2pDLENBQUM7SUFFRDs7T0FFRztJQUNLLHVCQUF1QjtRQUM3QixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDL0QsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUUvRCxJQUFJLENBQUM7WUFDSCxJQUFJLENBQUMsbUJBQW1CLEdBQUc7Z0JBQ3pCLEdBQUcsRUFBRSxFQUFFLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLFNBQVMsQ0FBQyxFQUFFLE1BQU0sQ0FBQztnQkFDNUQsSUFBSSxFQUFFLEVBQUUsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsVUFBVSxDQUFDLEVBQUUsTUFBTSxDQUFDO2FBQy9ELENBQUM7WUFDRixJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSwwQ0FBMEMsQ0FBQyxDQUFDO1FBQy9ELENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsb0NBQW9DLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFFL0QsNkNBQTZDO1lBQzdDLElBQUksQ0FBQztnQkFDSCwrREFBK0Q7Z0JBQy9ELHNGQUFzRjtnQkFDdEYsSUFBSSxDQUFDLG1CQUFtQixHQUFHO29CQUN6QixHQUFHLEVBQUUsc0JBQXNCO29CQUMzQixJQUFJLEVBQUUsdUJBQXVCO2lCQUM5QixDQUFDO2dCQUNGLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLHlDQUF5QyxDQUFDLENBQUM7WUFDOUQsQ0FBQztZQUFDLE9BQU8sYUFBYSxFQUFFLENBQUM7Z0JBQ3ZCLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLDBDQUEwQyxFQUFFLGFBQWEsQ0FBQyxDQUFDO2dCQUM3RSxNQUFNLElBQUksS0FBSyxDQUFDLDZDQUE2QyxDQUFDLENBQUM7WUFDakUsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsS0FBSztRQUNoQixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUU1QiwwQkFBMEI7UUFDMUIsSUFBSSxDQUFDLFdBQVcsR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FDM0M7WUFDRSxHQUFHLEVBQUUsSUFBSSxDQUFDLG1CQUFtQixDQUFDLEdBQUc7WUFDakMsSUFBSSxFQUFFLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJO1NBQ3BDLEVBQ0QsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FDM0MsQ0FBQztRQUVGLDRCQUE0QjtRQUM1QixJQUFJLENBQUMsV0FBVyxDQUFDLGdCQUFnQixHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUM7UUFDbEUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUM7UUFFOUQsNEJBQTRCO1FBQzVCLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1FBRS9CLDBCQUEwQjtRQUMxQixJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQztRQUU3QiwyQkFBMkI7UUFDM0IsSUFBSSxDQUFDLHNCQUFzQixFQUFFLENBQUM7UUFFOUIsbUJBQW1CO1FBQ25CLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRTtZQUM3QixJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxHQUFHLEVBQUU7Z0JBQzlDLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLGdDQUFnQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7Z0JBQ3RFLE9BQU8sRUFBRSxDQUFDO1lBQ1osQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNLLHVCQUF1QjtRQUM3QixJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxZQUFZLEVBQUUsQ0FBQyxVQUE4QixFQUFFLEVBQUU7WUFDbkUsbUNBQW1DO1lBQ25DLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDcEUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsb0JBQW9CLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxxQ0FBcUMsQ0FBQyxDQUFDO2dCQUN2RyxVQUFVLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ3JCLE9BQU87WUFDVCxDQUFDO1lBRUQsNkJBQTZCO1lBQzdCLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQy9CLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsRUFBRSxDQUFDLE1BQU0sQ0FBQztZQUN6RCxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSw2QkFBNkIsSUFBSSxDQUFDLGdCQUFnQixxQkFBcUIsQ0FBQyxDQUFDO1lBRTNGLG9DQUFvQztZQUNwQyxNQUFNLGlCQUFpQixHQUFHLEdBQUcsRUFBRTtnQkFDN0IsSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO29CQUM5QyxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztvQkFDbEMsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxFQUFFLENBQUMsTUFBTSxDQUFDO29CQUN6RCxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxzQkFBc0IsSUFBSSxDQUFDLGdCQUFnQix3QkFBd0IsQ0FBQyxDQUFDO2dCQUN6RixDQUFDO1lBQ0gsQ0FBQyxDQUFDO1lBRUYsVUFBVSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsaUJBQWlCLENBQUMsQ0FBQztZQUMxQyxVQUFVLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFO2dCQUM3QixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxHQUFHLENBQUMsQ0FBQztnQkFDM0MsaUJBQWlCLEVBQUUsQ0FBQztZQUN0QixDQUFDLENBQUMsQ0FBQztZQUNILFVBQVUsQ0FBQyxFQUFFLENBQUMsS0FBSyxFQUFFLGlCQUFpQixDQUFDLENBQUM7WUFDeEMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxTQUFTLEVBQUUsR0FBRyxFQUFFO2dCQUM1QixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO2dCQUN4QyxpQkFBaUIsRUFBRSxDQUFDO1lBQ3RCLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxxQkFBcUI7UUFDM0IsMEJBQTBCO1FBQzFCLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxPQUFPLENBQUMsRUFBRSxDQUFDLGVBQWUsQ0FBQztZQUM3QyxNQUFNLEVBQUUsSUFBSSxDQUFDLFdBQVc7WUFDeEIsaUNBQWlDO1lBQ2pDLGNBQWMsRUFBRSxJQUFJO1NBQ3JCLENBQUMsQ0FBQztRQUVILCtCQUErQjtRQUMvQixJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxZQUFZLEVBQUUsQ0FBQyxVQUFtQyxFQUFFLE1BQW9DLEVBQUUsRUFBRTtZQUMzRyxJQUFJLENBQUMseUJBQXlCLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQ3JELENBQUMsQ0FBQyxDQUFDO1FBRUgsa0dBQWtHO1FBQ2xHLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxXQUFXLENBQUMsR0FBRyxFQUFFO1lBQ3hDLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsSUFBSSxLQUFLLENBQUMsRUFBRSxDQUFDO2dCQUNyQyxPQUFPLENBQUMsZ0NBQWdDO1lBQzFDLENBQUM7WUFFRCxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxpQ0FBaUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsSUFBSSxVQUFVLENBQUMsQ0FBQztZQUN6RixJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFxQixFQUFFLEVBQUU7Z0JBQ3RELE1BQU0sZUFBZSxHQUFHLEVBQTZCLENBQUM7Z0JBRXRELElBQUksZUFBZSxDQUFDLE9BQU8sS0FBSyxLQUFLLEVBQUUsQ0FBQztvQkFDdEMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsMkNBQTJDLENBQUMsQ0FBQztvQkFDL0QsT0FBTyxlQUFlLENBQUMsU0FBUyxFQUFFLENBQUM7Z0JBQ3JDLENBQUM7Z0JBRUQsZUFBZSxDQUFDLE9BQU8sR0FBRyxLQUFLLENBQUM7Z0JBQ2hDLGVBQWUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUN6QixDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNaLENBQUM7SUFFRDs7T0FFRztJQUNLLHNCQUFzQjtRQUM1QixJQUFJLENBQUMsZUFBZSxHQUFHLFdBQVcsQ0FBQyxHQUFHLEVBQUU7WUFDdEMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7WUFDaEUsTUFBTSxPQUFPLEdBQUc7Z0JBQ2QsTUFBTTtnQkFDTixpQkFBaUIsRUFBRSxJQUFJLENBQUMsZ0JBQWdCO2dCQUN4QyxhQUFhLEVBQUUsSUFBSSxDQUFDLGNBQWM7Z0JBQ2xDLGNBQWMsRUFBRSxJQUFJLENBQUMsY0FBYztnQkFDbkMsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsSUFBSSxJQUFJLENBQUM7Z0JBQ2xELFdBQVcsRUFBRSxPQUFPLENBQUMsV0FBVyxFQUFFO2dCQUNsQyxjQUFjLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDO2FBQ2hELENBQUM7WUFFRixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxlQUFlLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDOUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsMkJBQTJCO0lBQ3hDLENBQUM7SUFFRDs7T0FFRztJQUNLLHlCQUF5QixDQUFDLFVBQW1DLEVBQUUsTUFBb0M7UUFDekcsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQztRQUMxQixNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQztRQUVuQyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSw0QkFBNEIsTUFBTSxHQUFHLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFFaEUsMkJBQTJCO1FBQzNCLFVBQVUsQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO1FBQzFCLFVBQVUsQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ2pDLFVBQVUsQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRTtZQUN6QixVQUFVLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQztZQUMxQixVQUFVLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUNuQyxDQUFDLENBQUMsQ0FBQztRQUVILG9DQUFvQztRQUNwQyxNQUFNLG1CQUFtQixHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3pELElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1lBQ3pCLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLGdDQUFnQyxNQUFNLEdBQUcsTUFBTSxFQUFFLENBQUMsQ0FBQztZQUNwRSxVQUFVLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDdkIsT0FBTztRQUNULENBQUM7UUFFRCxtQ0FBbUM7UUFDbkMsSUFBSSxtQkFBbUIsQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN2QyxJQUFJLENBQUM7Z0JBQ0gsSUFBSSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLEVBQUUsbUJBQW1CLENBQUMsRUFBRSxDQUFDO29CQUMzRCxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSx1Q0FBdUMsTUFBTSxHQUFHLE1BQU0sRUFBRSxDQUFDLENBQUM7b0JBQzNFLFVBQVUsQ0FBQyxTQUFTLEVBQUUsQ0FBQztvQkFDdkIsT0FBTztnQkFDVCxDQUFDO1lBQ0gsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsZ0NBQWdDLEVBQUUsS0FBSyxDQUFDLENBQUM7Z0JBQzNELFVBQVUsQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDdkIsT0FBTztZQUNULENBQUM7UUFDSCxDQUFDO1FBRUQsc0NBQXNDO1FBQ3RDLElBQUksVUFBNkIsQ0FBQztRQUNsQyxNQUFNLGdCQUFnQixHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsS0FBSyxFQUFFLENBQUM7UUFFdEQsSUFBSSxDQUFDO1lBQ0gsTUFBTSxRQUFRLEdBQUcsUUFBUSxtQkFBbUIsQ0FBQyxhQUFhLElBQUksbUJBQW1CLENBQUMsZUFBZSxHQUFHLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNqSCxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSx5QkFBeUIsUUFBUSxFQUFFLENBQUMsQ0FBQztZQUV2RCxVQUFVLEdBQUcsSUFBSSxPQUFPLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBRTdDLFVBQVUsQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRTtnQkFDekIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsMkNBQTJDLENBQUMsQ0FBQztnQkFDL0QsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDN0IsQ0FBQyxDQUFDLENBQUM7WUFFSCxVQUFVLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFO2dCQUMvQixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxLQUFLLENBQUMsQ0FBQztnQkFDckQsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUMvQixJQUFJLFVBQVUsQ0FBQyxVQUFVLEtBQUssVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDO29CQUM5QyxVQUFVLENBQUMsU0FBUyxFQUFFLENBQUM7Z0JBQ3pCLENBQUM7WUFDSCxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7UUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ2IsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsZ0RBQWdELEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDekUsVUFBVSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ3ZCLE9BQU87UUFDVCxDQUFDO1FBRUQsbURBQW1EO1FBQ25ELFVBQVUsQ0FBQyxFQUFFLENBQUMsU0FBUyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLEVBQUU7WUFDbkQsSUFBSSxDQUFDO2dCQUNILDJDQUEyQztnQkFDM0MsTUFBTSxnQkFBZ0IsQ0FBQyxPQUFPLENBQUM7Z0JBRS9CLGtEQUFrRDtnQkFDbEQsSUFBSSxVQUFVLENBQUMsVUFBVSxLQUFLLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztvQkFDOUMsVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztnQkFDakQsQ0FBQztZQUNILENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNmLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLCtDQUErQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQzVFLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUVILG1EQUFtRDtRQUNuRCxVQUFVLENBQUMsRUFBRSxDQUFDLFNBQVMsRUFBRSxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsRUFBRTtZQUM3QyxJQUFJLENBQUM7Z0JBQ0gsd0RBQXdEO2dCQUN4RCxJQUFJLFVBQVUsQ0FBQyxVQUFVLEtBQUssVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDO29CQUM5QyxVQUFVLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO2dCQUNqRCxDQUFDO1lBQ0gsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsOENBQThDLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDM0UsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO1FBRUgsK0NBQStDO1FBQy9DLFVBQVUsQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsSUFBSSxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ3RDLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLDhCQUE4QixJQUFJLE1BQU0sTUFBTSxFQUFFLENBQUMsQ0FBQztZQUNwRSxJQUFJLFVBQVUsSUFBSSxVQUFVLENBQUMsVUFBVSxLQUFLLFVBQVUsQ0FBQyxNQUFNLEVBQUUsQ0FBQztnQkFDOUQsSUFBSSxDQUFDO29CQUNILGlFQUFpRTtvQkFDakUsTUFBTSxTQUFTLEdBQUcsQ0FBQyxJQUFJLElBQUksSUFBSSxJQUFJLElBQUksSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7b0JBQy9ELFVBQVUsQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFDdkQsQ0FBQztnQkFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO29CQUNmLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLGtDQUFrQyxFQUFFLEtBQUssQ0FBQyxDQUFDO29CQUM3RCxVQUFVLENBQUMsU0FBUyxFQUFFLENBQUM7Z0JBQ3pCLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFFSCxVQUFVLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLElBQUksRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUN0QyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSw4QkFBOEIsSUFBSSxNQUFNLE1BQU0sRUFBRSxDQUFDLENBQUM7WUFDcEUsSUFBSSxVQUFVLElBQUksVUFBVSxDQUFDLFVBQVUsS0FBSyxVQUFVLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQzlELElBQUksQ0FBQztvQkFDSCxpRUFBaUU7b0JBQ2pFLE1BQU0sU0FBUyxHQUFHLENBQUMsSUFBSSxJQUFJLElBQUksSUFBSSxJQUFJLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO29CQUMvRCxVQUFVLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsUUFBUSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7Z0JBQ3ZELENBQUM7Z0JBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztvQkFDZixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxrQ0FBa0MsRUFBRSxLQUFLLENBQUMsQ0FBQztvQkFDN0QsVUFBVSxDQUFDLFNBQVMsRUFBRSxDQUFDO2dCQUN6QixDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0ssS0FBSyxDQUFDLGFBQWEsQ0FDekIsYUFBMkMsRUFDM0MsY0FBMkM7UUFFM0MsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ3RCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUM3QixNQUFNLEtBQUssR0FBRyxPQUFPLElBQUksQ0FBQyxHQUFHLEVBQUUsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUVoRixJQUFJLENBQUM7WUFDSCxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDO1lBQzFELElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLElBQUksS0FBSyxLQUFLLGFBQWEsQ0FBQyxNQUFNLElBQUksYUFBYSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEdBQUcsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUUvRiw2Q0FBNkM7WUFDN0MsSUFBSSxhQUFhLENBQUMsTUFBTSxLQUFLLFNBQVMsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO2dCQUM1RCxJQUFJLENBQUMsaUJBQWlCLENBQUMsYUFBYSxFQUFFLGNBQWMsQ0FBQyxDQUFDO2dCQUN0RCxPQUFPO1lBQ1QsQ0FBQztZQUVELGdDQUFnQztZQUNoQyxNQUFNLGlCQUFpQixHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBQzlELElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO2dCQUN2QixJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxJQUFJLEtBQUssd0JBQXdCLGFBQWEsQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFDaEYsSUFBSSxDQUFDLGlCQUFpQixDQUFDLGNBQWMsRUFBRSxHQUFHLEVBQUUsOEJBQThCLENBQUMsQ0FBQztnQkFDNUUsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO2dCQUN0QixPQUFPO1lBQ1QsQ0FBQztZQUVELHNDQUFzQztZQUN0QyxJQUFJLGlCQUFpQixDQUFDLGNBQWMsRUFBRSxDQUFDO2dCQUNyQyxJQUFJLENBQUM7b0JBQ0gsSUFBSSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxhQUFhLEVBQUUsaUJBQWlCLENBQUMsRUFBRSxDQUFDO3dCQUNoRSxJQUFJLENBQUMsaUJBQWlCLENBQUMsY0FBYyxFQUFFLEdBQUcsRUFBRSxjQUFjLEVBQUU7NEJBQzFELGtCQUFrQixFQUFFLHlEQUF5RDt5QkFDOUUsQ0FBQyxDQUFDO3dCQUNILElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQzt3QkFDdEIsT0FBTztvQkFDVCxDQUFDO2dCQUNILENBQUM7Z0JBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztvQkFDZixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxJQUFJLEtBQUssd0JBQXdCLEVBQUUsS0FBSyxDQUFDLENBQUM7b0JBQzVELElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxjQUFjLEVBQUUsR0FBRyxFQUFFLDhDQUE4QyxDQUFDLENBQUM7b0JBQzVGLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztvQkFDdEIsT0FBTztnQkFDVCxDQUFDO1lBQ0gsQ0FBQztZQUVELDRCQUE0QjtZQUM1QixNQUFNLGNBQWMsR0FBRyxVQUFVLGlCQUFpQixDQUFDLGFBQWEsSUFBSSxpQkFBaUIsQ0FBQyxlQUFlLEdBQUcsYUFBYSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQzVILElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLElBQUksS0FBSyxpQkFBaUIsY0FBYyxFQUFFLENBQUMsQ0FBQztZQUU5RCxzQkFBc0I7WUFDdEIsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLEtBQUssRUFBRSxhQUFhLEVBQUUsY0FBYyxFQUFFLGNBQWMsQ0FBQyxDQUFDO1lBRWhGLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxTQUFTLENBQUM7WUFDOUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsSUFBSSxLQUFLLDBCQUEwQixjQUFjLElBQUksQ0FBQyxDQUFDO1FBQzNFLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsSUFBSSxLQUFLLHNDQUFzQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQzFFLElBQUksQ0FBQztnQkFDSCxJQUFJLENBQUMsaUJBQWlCLENBQUMsY0FBYyxFQUFFLEdBQUcsRUFBRSwyQkFBMkIsQ0FBQyxDQUFDO1lBQzNFLENBQUM7WUFBQyxPQUFPLGFBQWEsRUFBRSxDQUFDO2dCQUN2QixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxJQUFJLEtBQUssaUNBQWlDLEVBQUUsYUFBYSxDQUFDLENBQUM7WUFDL0UsQ0FBQztZQUNELElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUN4QixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssaUJBQWlCLENBQ3ZCLEdBQWlDLEVBQ2pDLEdBQWdDO1FBRWhDLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDO1FBRS9CLG1CQUFtQjtRQUNuQixHQUFHLENBQUMsU0FBUyxDQUFDLDZCQUE2QixFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUMvRCxHQUFHLENBQUMsU0FBUyxDQUFDLDhCQUE4QixFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUNqRSxHQUFHLENBQUMsU0FBUyxDQUFDLDhCQUE4QixFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUNqRSxHQUFHLENBQUMsU0FBUyxDQUFDLHdCQUF3QixFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUU3RCwyQkFBMkI7UUFDM0IsR0FBRyxDQUFDLFVBQVUsR0FBRyxHQUFHLENBQUM7UUFDckIsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBRVYsaUNBQWlDO1FBQ2pDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztJQUN4QixDQUFDO0lBRUQ7O09BRUc7SUFDSyxtQkFBbUIsQ0FDekIsR0FBaUMsRUFDakMsTUFBbUQ7UUFFbkQsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLGNBQWMsQ0FBQztRQUN2QyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDZCxPQUFPLElBQUksQ0FBQyxDQUFDLDZCQUE2QjtRQUM1QyxDQUFDO1FBRUQsUUFBUSxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDdEIsS0FBSyxPQUFPLENBQUMsQ0FBQyxDQUFDO2dCQUNiLE1BQU0sVUFBVSxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDO2dCQUM3QyxJQUFJLENBQUMsVUFBVSxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO29CQUNsRCxPQUFPLEtBQUssQ0FBQztnQkFDZixDQUFDO2dCQUVELE1BQU0sZ0JBQWdCLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQzFELE1BQU0sVUFBVSxHQUFXLE9BQU8sQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO2dCQUMvRSxNQUFNLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBRTNDLHlEQUF5RDtnQkFDekQsTUFBTSxTQUFTLEdBQUcsSUFBSSxLQUFLLFFBQVEsQ0FBQyxJQUFJLENBQUM7Z0JBQ3pDLE1BQU0sU0FBUyxHQUFHLElBQUksS0FBSyxRQUFRLENBQUMsSUFBSSxDQUFDO2dCQUV6QyxPQUFPLFNBQVMsSUFBSSxTQUFTLENBQUM7WUFDaEMsQ0FBQztZQUNEO2dCQUNFLE1BQU0sSUFBSSxLQUFLLENBQUMsc0NBQXNDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQzNFLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxLQUFLLENBQUMsY0FBYyxDQUMxQixLQUFhLEVBQ2IsYUFBMkMsRUFDM0MsY0FBMkMsRUFDM0MsY0FBc0I7UUFFdEIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxZQUFZLEdBQUcsTUFBTSxPQUFPLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FDckQsY0FBYyxFQUNkO2dCQUNFLE1BQU0sRUFBRSxhQUFhLENBQUMsTUFBTTtnQkFDNUIsT0FBTyxFQUFFLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxhQUFhLENBQUM7Z0JBQ2xELFNBQVMsRUFBRSxJQUFJO2dCQUNmLE9BQU8sRUFBRSxLQUFLLENBQUMsb0JBQW9CO2FBQ3BDLEVBQ0QsSUFBSSxFQUFFLFlBQVk7WUFDbEIsQ0FBQyxrQkFBa0IsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLGFBQWEsRUFBRSxrQkFBa0IsQ0FBQyxDQUN0RixDQUFDO1lBRUYsc0JBQXNCO1lBQ3RCLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxLQUFLLEVBQUUsY0FBYyxFQUFFLFlBQVksQ0FBQyxDQUFDO1FBQ2pFLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsSUFBSSxLQUFLLDRCQUE0QixFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ2hFLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxjQUFjLEVBQUUsR0FBRyxFQUFFLDhDQUE4QyxDQUFDLENBQUM7WUFDNUYsTUFBTSxLQUFLLENBQUMsQ0FBQyxrQ0FBa0M7UUFDakQsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNLLHFCQUFxQixDQUFDLEdBQWlDO1FBQzdELE1BQU0sV0FBVyxHQUFHLEVBQUUsR0FBRyxHQUFHLENBQUMsT0FBTyxFQUFFLENBQUM7UUFFdkMseUJBQXlCO1FBQ3pCLFdBQVcsQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDO1FBQ25ELFdBQVcsQ0FBQyxtQkFBbUIsQ0FBQyxHQUFHLE9BQU8sQ0FBQztRQUMzQyxXQUFXLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsYUFBYSxJQUFJLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFMUYsNkJBQTZCO1FBQzdCLFdBQVcsQ0FBQyxZQUFZLENBQUMsR0FBRyxnQkFBZ0IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUVoRSxvREFBb0Q7UUFDcEQsTUFBTSxnQkFBZ0IsR0FBRyxDQUFDLFlBQVksRUFBRSxTQUFTLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztRQUNyRSxLQUFLLE1BQU0sTUFBTSxJQUFJLGdCQUFnQixFQUFFLENBQUM7WUFDdEMsT0FBTyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDN0IsQ0FBQztRQUVELE9BQU8sV0FBVyxDQUFDO0lBQ3JCLENBQUM7SUFFRDs7T0FFRztJQUNLLHFCQUFxQixDQUMzQixhQUEyQyxFQUMzQyxZQUF3QztRQUV4Qyw0QkFBNEI7UUFDNUIsYUFBYSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRTtZQUNqQyxZQUFZLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzVCLENBQUMsQ0FBQyxDQUFDO1FBRUgsNEJBQTRCO1FBQzVCLGFBQWEsQ0FBQyxFQUFFLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRTtZQUMzQixZQUFZLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDckIsQ0FBQyxDQUFDLENBQUM7UUFFSCx3QkFBd0I7UUFDeEIsYUFBYSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRTtZQUNsQyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxnQ0FBZ0MsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUMzRCxZQUFZLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzlCLENBQUMsQ0FBQyxDQUFDO1FBRUgsOEJBQThCO1FBQzlCLGFBQWEsQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRTtZQUM3QixJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsRUFBRSxDQUFDO2dCQUM1QixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxtREFBbUQsQ0FBQyxDQUFDO2dCQUN2RSxZQUFZLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDekIsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO1FBRUgsYUFBYSxDQUFDLEVBQUUsQ0FBQyxTQUFTLEVBQUUsR0FBRyxFQUFFO1lBQy9CLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLHdCQUF3QixDQUFDLENBQUM7WUFDNUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDLENBQUM7UUFDNUQsQ0FBQyxDQUFDLENBQUM7UUFFSCw4QkFBOEI7UUFDOUIsWUFBWSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRTtZQUNqQyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxpQ0FBaUMsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUM5RCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNLLG9CQUFvQixDQUMxQixLQUFhLEVBQ2IsY0FBMkMsRUFDM0MsYUFBMkM7UUFFM0MsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsSUFBSSxLQUFLLGlDQUFpQyxhQUFhLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztRQUV4RixrQkFBa0I7UUFDbEIsY0FBYyxDQUFDLFVBQVUsR0FBRyxhQUFhLENBQUMsVUFBVSxDQUFDO1FBRXJELHNCQUFzQjtRQUN0QixLQUFLLE1BQU0sQ0FBQyxVQUFVLEVBQUUsV0FBVyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQztZQUM1RSxjQUFjLENBQUMsU0FBUyxDQUFDLFVBQVUsRUFBRSxXQUFXLENBQUMsQ0FBQztRQUNwRCxDQUFDO1FBRUQsOEJBQThCO1FBQzlCLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUN0QixjQUFjLENBQUMsU0FBUyxDQUFDLDZCQUE2QixFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ3pGLENBQUM7UUFFRCx3QkFBd0I7UUFDeEIsS0FBSyxNQUFNLENBQUMsVUFBVSxFQUFFLFdBQVcsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDOUUsMEJBQTBCO1lBQzFCLE1BQU0sZUFBZSxHQUFHLENBQUMsWUFBWSxFQUFFLFlBQVksRUFBRSxtQkFBbUIsRUFBRSxJQUFJO2dCQUNyRCxTQUFTLEVBQUUsU0FBUyxFQUFFLHFCQUFxQixFQUFFLG9CQUFvQixDQUFDLENBQUM7WUFDNUYsSUFBSSxDQUFDLGVBQWUsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLFdBQVcsRUFBRSxDQUFDLEVBQUUsQ0FBQztnQkFDeEQsY0FBYyxDQUFDLFNBQVMsQ0FBQyxVQUFVLEVBQUUsV0FBVyxDQUFDLENBQUM7WUFDcEQsQ0FBQztRQUNILENBQUM7UUFFRCx1QkFBdUI7UUFDdkIsYUFBYSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRTtZQUNqQyxNQUFNLFdBQVcsR0FBRyxjQUFjLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBRWhELCtCQUErQjtZQUMvQixJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7Z0JBQ2pCLGFBQWEsQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDdEIsY0FBYyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsR0FBRyxFQUFFO29CQUNoQyxhQUFhLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ3pCLENBQUMsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO1FBRUgsNkJBQTZCO1FBQzdCLGFBQWEsQ0FBQyxFQUFFLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRTtZQUMzQixjQUFjLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDdkIsQ0FBQyxDQUFDLENBQUM7UUFFSCx5QkFBeUI7UUFDekIsYUFBYSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRTtZQUNsQyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxJQUFJLEtBQUssa0NBQWtDLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDdEUsY0FBYyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNoQyxDQUFDLENBQUMsQ0FBQztRQUVILGNBQWMsQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDbkMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsSUFBSSxLQUFLLG1DQUFtQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ3ZFLGFBQWEsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUMxQixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNLLGlCQUFpQixDQUN2QixHQUFnQyxFQUNoQyxhQUFxQixHQUFHLEVBQ3hCLFVBQWtCLHVCQUF1QixFQUN6QyxVQUE0QyxFQUFFO1FBRTlDLElBQUksQ0FBQztZQUNILGlEQUFpRDtZQUNqRCxJQUFJLEdBQUcsQ0FBQyxXQUFXLEVBQUUsQ0FBQztnQkFDcEIsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDO2dCQUNWLE9BQU87WUFDVCxDQUFDO1lBRUQsc0JBQXNCO1lBQ3RCLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDO2dCQUMvRCxHQUFHLENBQUMsU0FBUyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUM1QixDQUFDO1lBRUQsdUJBQXVCO1lBQ3ZCLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7Z0JBQ25ELEdBQUcsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQzVCLENBQUM7WUFFRCxzQkFBc0I7WUFDdEIsR0FBRyxDQUFDLFNBQVMsQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFFbkMsMENBQTBDO1lBQzFDLElBQUksR0FBRyxDQUFDLFNBQVMsQ0FBQyxjQUFjLENBQUMsS0FBSyxrQkFBa0IsRUFBRSxDQUFDO2dCQUN6RCxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxLQUFLLEVBQUUsRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQ3RFLENBQUM7aUJBQU0sQ0FBQztnQkFDTixxQkFBcUI7Z0JBQ3JCLEdBQUcsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDbkIsQ0FBQztRQUNILENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsOEJBQThCLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDekQsSUFBSSxDQUFDO2dCQUNILEdBQUcsQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNoQixDQUFDO1lBQUMsT0FBTyxZQUFZLEVBQUUsQ0FBQztnQkFDdEIsdUNBQXVDO1lBQ3pDLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLGtCQUFrQixDQUM3QixlQUE4RDtRQUU5RCxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxrQ0FBa0MsZUFBZSxDQUFDLE1BQU0sV0FBVyxDQUFDLENBQUM7UUFFdEYsMEJBQTBCO1FBQzFCLElBQUksQ0FBQyxZQUFZLEdBQUcsZUFBZSxDQUFDO1FBQ3BDLElBQUksQ0FBQyxNQUFNLENBQUMsa0JBQWtCLENBQUMsZUFBZSxDQUFDLENBQUM7UUFFaEQsMENBQTBDO1FBQzFDLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztRQUUzQyx3Q0FBd0M7UUFDeEMsS0FBSyxNQUFNLE1BQU0sSUFBSSxlQUFlLEVBQUUsQ0FBQztZQUNyQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBRXRDLElBQUksQ0FBQztnQkFDSCxzQ0FBc0M7Z0JBQ3RDLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO2dCQUMvRCxNQUFNLFlBQVksR0FBRyxDQUFDLFdBQVc7b0JBQ2IsV0FBVyxDQUFDLEdBQUcsS0FBSyxNQUFNLENBQUMsVUFBVTtvQkFDckMsV0FBVyxDQUFDLElBQUksS0FBSyxNQUFNLENBQUMsU0FBUyxDQUFDO2dCQUUxRCxJQUFJLFlBQVksRUFBRSxDQUFDO29CQUNqQixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSw0QkFBNEIsTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7b0JBRWpFLGtDQUFrQztvQkFDbEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRTt3QkFDM0MsR0FBRyxFQUFFLE1BQU0sQ0FBQyxVQUFVO3dCQUN0QixJQUFJLEVBQUUsTUFBTSxDQUFDLFNBQVM7cUJBQ3ZCLENBQUMsQ0FBQztvQkFFSCxtQkFBbUI7b0JBQ25CLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRTt3QkFDekMsR0FBRyxFQUFFLE1BQU0sQ0FBQyxVQUFVO3dCQUN0QixJQUFJLEVBQUUsTUFBTSxDQUFDLFNBQVM7cUJBQ3ZCLENBQUMsQ0FBQztvQkFFSCxJQUFJLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQzNDLENBQUM7WUFDSCxDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxpQ0FBaUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQy9FLENBQUM7UUFDSCxDQUFDO1FBRUQsNEJBQTRCO1FBQzVCLDZEQUE2RDtRQUM3RCxrREFBa0Q7UUFDbEQsS0FBSyxNQUFNLFFBQVEsSUFBSSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDM0MsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO2dCQUNwQyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxZQUFZLFFBQVEsNkJBQTZCLENBQUMsQ0FBQztnQkFDcEUsSUFBSSxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQ3JDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDekMsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsaUJBQWlCLENBQUMsVUFBcUM7UUFDbEUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsd0JBQXdCLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDdkQsSUFBSSxDQUFDLGNBQWMsR0FBRztZQUNwQixHQUFHLElBQUksQ0FBQyxjQUFjO1lBQ3RCLEdBQUcsVUFBVTtTQUNkLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsSUFBSTtRQUNmLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLDhCQUE4QixDQUFDLENBQUM7UUFFakQsa0JBQWtCO1FBQ2xCLElBQUksSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFDM0IsYUFBYSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBQ3hDLENBQUM7UUFFRCxJQUFJLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUN6QixhQUFhLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQ3RDLENBQUM7UUFFRCxtQ0FBbUM7UUFDbkMsSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDbEIsS0FBSyxNQUFNLE1BQU0sSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUMzQyxJQUFJLENBQUM7b0JBQ0gsTUFBTSxDQUFDLFNBQVMsRUFBRSxDQUFDO2dCQUNyQixDQUFDO2dCQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7b0JBQ2YsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsb0NBQW9DLEVBQUUsS0FBSyxDQUFDLENBQUM7Z0JBQ2pFLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUVELDRCQUE0QjtRQUM1QixLQUFLLE1BQU0sTUFBTSxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQztZQUMvQyxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ25CLENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNmLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLHlCQUF5QixFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ3RELENBQUM7UUFDSCxDQUFDO1FBRUQseUJBQXlCO1FBQ3pCLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRTtZQUM3QixJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUU7Z0JBQzFCLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLDBDQUEwQyxDQUFDLENBQUM7Z0JBQzdELE9BQU8sRUFBRSxDQUFDO1lBQ1osQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNLLEdBQUcsQ0FBQyxLQUEwQyxFQUFFLE9BQWUsRUFBRSxJQUFVO1FBQ2pGLE1BQU0sU0FBUyxHQUFHO1lBQ2hCLEtBQUssRUFBRSxDQUFDO1lBQ1IsSUFBSSxFQUFFLENBQUM7WUFDUCxJQUFJLEVBQUUsQ0FBQztZQUNQLEtBQUssRUFBRSxDQUFDO1NBQ1QsQ0FBQztRQUVGLDhDQUE4QztRQUM5QyxJQUFJLFNBQVMsQ0FBQyxLQUFLLENBQUMsR0FBRyxTQUFTLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQ3hELE9BQU87UUFDVCxDQUFDO1FBRUQsTUFBTSxTQUFTLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUMzQyxNQUFNLE1BQU0sR0FBRyxJQUFJLFNBQVMsTUFBTSxLQUFLLENBQUMsV0FBVyxFQUFFLEdBQUcsQ0FBQztRQUV6RCxRQUFRLEtBQUssRUFBRSxDQUFDO1lBQ2QsS0FBSyxPQUFPO2dCQUNWLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxNQUFNLElBQUksT0FBTyxFQUFFLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO2dCQUNsRCxNQUFNO1lBQ1IsS0FBSyxNQUFNO2dCQUNULE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxNQUFNLElBQUksT0FBTyxFQUFFLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO2dCQUNqRCxNQUFNO1lBQ1IsS0FBSyxNQUFNO2dCQUNULE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxNQUFNLElBQUksT0FBTyxFQUFFLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO2dCQUNoRCxNQUFNO1lBQ1IsS0FBSyxPQUFPO2dCQUNWLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxNQUFNLElBQUksT0FBTyxFQUFFLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO2dCQUNoRCxNQUFNO1FBQ1YsQ0FBQztJQUNILENBQUM7Q0FDRiJ9