@raspect/workflow-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +249 -0
- package/dist/activity.d.ts +23 -0
- package/dist/activity.js +44 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +67 -0
- package/dist/types.d.ts +106 -0
- package/dist/types.js +4 -0
- package/dist/worker.d.ts +73 -0
- package/dist/worker.js +615 -0
- package/dist/workflow.d.ts +74 -0
- package/dist/workflow.js +186 -0
- package/package.json +49 -0
package/dist/worker.js
ADDED
|
@@ -0,0 +1,615 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Worker - Node.js implementation for executing workflows and activities
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.Worker = void 0;
|
|
38
|
+
const kafkajs_1 = require("kafkajs");
|
|
39
|
+
const aws_msk_iam_sasl_signer_js_1 = require("aws-msk-iam-sasl-signer-js");
|
|
40
|
+
const os = __importStar(require("os"));
|
|
41
|
+
const workflow_1 = require("./workflow");
|
|
42
|
+
const activity_1 = require("./activity");
|
|
43
|
+
/**
|
|
44
|
+
* Worker that executes workflows and activities.
|
|
45
|
+
*
|
|
46
|
+
* Usage:
|
|
47
|
+
* import { Worker, workflow, activity } from '@inspectica/workflow-sdk';
|
|
48
|
+
*
|
|
49
|
+
* const sayHello = activity.defn(async (input: { name: string }) => {
|
|
50
|
+
* return { message: `Hello, ${input.name}!` };
|
|
51
|
+
* });
|
|
52
|
+
*
|
|
53
|
+
* @workflow.defn
|
|
54
|
+
* class HelloWorldWorkflow {
|
|
55
|
+
* @workflow.run
|
|
56
|
+
* async run(input: { name: string }) {
|
|
57
|
+
* return await workflow.executeActivity(sayHello, input);
|
|
58
|
+
* }
|
|
59
|
+
* }
|
|
60
|
+
*
|
|
61
|
+
* const worker = new Worker({
|
|
62
|
+
* serverUrl: 'https://workflow.example.com',
|
|
63
|
+
* apiKey: 'wk_abc123...',
|
|
64
|
+
* });
|
|
65
|
+
* worker.register({ workflows: [HelloWorldWorkflow], activities: [sayHello] });
|
|
66
|
+
* await worker.run();
|
|
67
|
+
*/
|
|
68
|
+
class Worker {
|
|
69
|
+
config;
|
|
70
|
+
workflows = new Map();
|
|
71
|
+
activities = new Map();
|
|
72
|
+
workerId = null;
|
|
73
|
+
instanceId = null;
|
|
74
|
+
running = false;
|
|
75
|
+
kafka = null;
|
|
76
|
+
consumer = null;
|
|
77
|
+
producer = null;
|
|
78
|
+
heartbeatInterval = null;
|
|
79
|
+
heartbeatIntervalMs = 30000;
|
|
80
|
+
resultTopic = null;
|
|
81
|
+
maxConcurrentWorkflows;
|
|
82
|
+
activeWorkflows = 0;
|
|
83
|
+
constructor(config) {
|
|
84
|
+
this.config = {
|
|
85
|
+
...config,
|
|
86
|
+
serverUrl: config.serverUrl.replace(/\/$/, ''),
|
|
87
|
+
};
|
|
88
|
+
this.maxConcurrentWorkflows = config.maxConcurrentWorkflows || 10;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Register workflows and activities.
|
|
92
|
+
*/
|
|
93
|
+
register(options) {
|
|
94
|
+
for (const wfCls of options.workflows || []) {
|
|
95
|
+
const wfName = (0, workflow_1.getWorkflowName)(wfCls);
|
|
96
|
+
this.workflows.set(wfName, wfCls);
|
|
97
|
+
console.log(`Registered workflow: ${wfName}`);
|
|
98
|
+
}
|
|
99
|
+
for (const activityFn of options.activities || []) {
|
|
100
|
+
const activityName = (0, activity_1.getActivityName)(activityFn);
|
|
101
|
+
this.activities.set(activityName, activityFn);
|
|
102
|
+
console.log(`Registered activity: ${activityName}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Start the worker (blocking).
|
|
107
|
+
*/
|
|
108
|
+
async run() {
|
|
109
|
+
this.running = true;
|
|
110
|
+
// Setup signal handlers
|
|
111
|
+
process.on('SIGINT', () => this.stop());
|
|
112
|
+
process.on('SIGTERM', () => this.stop());
|
|
113
|
+
// Connect to server and get Kafka config
|
|
114
|
+
const serverKafkaConfig = await this.connectToServer();
|
|
115
|
+
const workerTopic = serverKafkaConfig.worker_topic;
|
|
116
|
+
const resultTopic = serverKafkaConfig.result_topic;
|
|
117
|
+
this.resultTopic = resultTopic;
|
|
118
|
+
// Create Kafka client
|
|
119
|
+
this.kafka = this.createKafkaClient(serverKafkaConfig);
|
|
120
|
+
// Create consumer
|
|
121
|
+
const consumerGroupId = this.config.groupId || `workflow-worker-${this.workerId}`;
|
|
122
|
+
this.consumer = this.kafka.consumer({ groupId: consumerGroupId });
|
|
123
|
+
// Create producer
|
|
124
|
+
this.producer = this.kafka.producer();
|
|
125
|
+
try {
|
|
126
|
+
await this.consumer.connect();
|
|
127
|
+
await this.producer.connect();
|
|
128
|
+
await this.consumer.subscribe({ topic: workerTopic, fromBeginning: false });
|
|
129
|
+
console.log(`Worker ${this.workerId} started, consuming from ${workerTopic}`);
|
|
130
|
+
console.log(`Max concurrent workflows: ${this.maxConcurrentWorkflows}`);
|
|
131
|
+
console.log(`Registered workflows: ${Array.from(this.workflows.keys()).join(', ')}`);
|
|
132
|
+
console.log(`Registered activities: ${Array.from(this.activities.keys()).join(', ')}`);
|
|
133
|
+
// Start heartbeat
|
|
134
|
+
this.startHeartbeat();
|
|
135
|
+
// Start consuming messages
|
|
136
|
+
await this.consumer.run({
|
|
137
|
+
eachMessage: async ({ message }) => {
|
|
138
|
+
if (!this.running)
|
|
139
|
+
return;
|
|
140
|
+
try {
|
|
141
|
+
const data = JSON.parse(message.value?.toString() || '{}');
|
|
142
|
+
await this.processMessage(data, resultTopic);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
console.error('Error processing message:', error);
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
// Keep running until stopped
|
|
150
|
+
await new Promise((resolve) => {
|
|
151
|
+
const checkInterval = setInterval(() => {
|
|
152
|
+
if (!this.running) {
|
|
153
|
+
clearInterval(checkInterval);
|
|
154
|
+
resolve();
|
|
155
|
+
}
|
|
156
|
+
}, 100);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
await this.cleanup();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Stop the worker gracefully.
|
|
165
|
+
*/
|
|
166
|
+
async stop() {
|
|
167
|
+
console.log('Stopping worker...');
|
|
168
|
+
this.running = false;
|
|
169
|
+
}
|
|
170
|
+
async connectToServer() {
|
|
171
|
+
const hostname = os.hostname();
|
|
172
|
+
const connectPayload = {
|
|
173
|
+
workflows: Array.from(this.workflows.keys()),
|
|
174
|
+
activities: Array.from(this.activities.keys()),
|
|
175
|
+
hostname,
|
|
176
|
+
};
|
|
177
|
+
const response = await fetch(`${this.config.serverUrl}/workflow/api/v1/workers/connect`, {
|
|
178
|
+
method: 'POST',
|
|
179
|
+
headers: {
|
|
180
|
+
'Content-Type': 'application/json',
|
|
181
|
+
'Authorization': `Bearer ${this.config.apiKey}`,
|
|
182
|
+
},
|
|
183
|
+
body: JSON.stringify(connectPayload),
|
|
184
|
+
});
|
|
185
|
+
if (!response.ok) {
|
|
186
|
+
const error = await response.text();
|
|
187
|
+
throw new Error(`Failed to connect to server: ${response.status} - ${error}`);
|
|
188
|
+
}
|
|
189
|
+
const data = await response.json();
|
|
190
|
+
this.workerId = data.worker_id;
|
|
191
|
+
this.instanceId = data.instance_id;
|
|
192
|
+
this.heartbeatIntervalMs = data.heartbeat_interval_ms || 30000;
|
|
193
|
+
console.log(`Connected to server as worker_id=${this.workerId}, instance_id=${this.instanceId}`);
|
|
194
|
+
return data.kafka;
|
|
195
|
+
}
|
|
196
|
+
createKafkaClient(kafkaConfig) {
|
|
197
|
+
const auth = kafkaConfig.auth;
|
|
198
|
+
// Server returns brokers as comma-separated string, convert to array
|
|
199
|
+
const brokers = typeof kafkaConfig.brokers === 'string'
|
|
200
|
+
? kafkaConfig.brokers.split(',').map(b => b.trim()).filter(b => b)
|
|
201
|
+
: kafkaConfig.brokers;
|
|
202
|
+
const config = {
|
|
203
|
+
clientId: `workflow-worker-${this.workerId}`,
|
|
204
|
+
brokers,
|
|
205
|
+
logLevel: kafkajs_1.logLevel.WARN,
|
|
206
|
+
};
|
|
207
|
+
if (auth?.type === 'msk_iam') {
|
|
208
|
+
config.ssl = true;
|
|
209
|
+
config.sasl = {
|
|
210
|
+
mechanism: 'oauthbearer',
|
|
211
|
+
oauthBearerProvider: async () => {
|
|
212
|
+
const token = await (0, aws_msk_iam_sasl_signer_js_1.generateAuthTokenFromCredentialsProvider)({
|
|
213
|
+
region: auth.region,
|
|
214
|
+
awsCredentialsProvider: async () => ({
|
|
215
|
+
accessKeyId: auth.access_key_id,
|
|
216
|
+
secretAccessKey: auth.secret_access_key,
|
|
217
|
+
}),
|
|
218
|
+
});
|
|
219
|
+
return { value: token.token };
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
else if (auth?.type === 'sasl') {
|
|
224
|
+
if (auth.security_protocol?.includes('SSL')) {
|
|
225
|
+
config.ssl = true;
|
|
226
|
+
}
|
|
227
|
+
if (auth.sasl_mechanism && auth.sasl_username && auth.sasl_password) {
|
|
228
|
+
config.sasl = {
|
|
229
|
+
mechanism: auth.sasl_mechanism.toLowerCase().replace('-', ''),
|
|
230
|
+
username: auth.sasl_username,
|
|
231
|
+
password: auth.sasl_password,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return new kafkajs_1.Kafka(config);
|
|
236
|
+
}
|
|
237
|
+
startHeartbeat() {
|
|
238
|
+
this.heartbeatInterval = setInterval(async () => {
|
|
239
|
+
if (!this.running)
|
|
240
|
+
return;
|
|
241
|
+
try {
|
|
242
|
+
const response = await fetch(`${this.config.serverUrl}/workflow/api/v1/workers/heartbeat`, {
|
|
243
|
+
method: 'POST',
|
|
244
|
+
headers: {
|
|
245
|
+
'Content-Type': 'application/json',
|
|
246
|
+
'Authorization': `Bearer ${this.config.apiKey}`,
|
|
247
|
+
},
|
|
248
|
+
body: JSON.stringify({ instance_id: this.instanceId }),
|
|
249
|
+
});
|
|
250
|
+
if (!response.ok) {
|
|
251
|
+
console.warn(`Heartbeat failed: ${response.status}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
console.warn('Heartbeat error:', error);
|
|
256
|
+
}
|
|
257
|
+
}, this.heartbeatIntervalMs);
|
|
258
|
+
}
|
|
259
|
+
async disconnectFromServer() {
|
|
260
|
+
if (!this.instanceId)
|
|
261
|
+
return;
|
|
262
|
+
try {
|
|
263
|
+
const response = await fetch(`${this.config.serverUrl}/workflow/api/v1/workers/disconnect`, {
|
|
264
|
+
method: 'POST',
|
|
265
|
+
headers: {
|
|
266
|
+
'Content-Type': 'application/json',
|
|
267
|
+
'Authorization': `Bearer ${this.config.apiKey}`,
|
|
268
|
+
},
|
|
269
|
+
body: JSON.stringify({ instance_id: this.instanceId }),
|
|
270
|
+
});
|
|
271
|
+
if (response.ok) {
|
|
272
|
+
console.log('Disconnected from server');
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
console.warn('Failed to disconnect from server:', error);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
async processMessage(data, resultTopic) {
|
|
280
|
+
// Check if this is an activity result (response from another worker via server)
|
|
281
|
+
if (data.status && data.completed_at && !data.task_type) {
|
|
282
|
+
console.debug('Received activity result on worker topic (ignored - using polling)');
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const taskType = data.task_type || 'activity';
|
|
286
|
+
if (taskType === 'workflow') {
|
|
287
|
+
// Process workflow in background (don't block message loop)
|
|
288
|
+
this.processWorkflowTask(data, resultTopic).catch((error) => {
|
|
289
|
+
console.error('Error processing workflow task:', error);
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
// Activity tasks can be processed inline
|
|
294
|
+
await this.processActivityTask(data, resultTopic);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
async processWorkflowTask(data, resultTopic) {
|
|
298
|
+
// Check concurrency limit
|
|
299
|
+
while (this.activeWorkflows >= this.maxConcurrentWorkflows) {
|
|
300
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
301
|
+
}
|
|
302
|
+
this.activeWorkflows++;
|
|
303
|
+
try {
|
|
304
|
+
await this.executeWorkflow(data, resultTopic);
|
|
305
|
+
}
|
|
306
|
+
finally {
|
|
307
|
+
this.activeWorkflows--;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
async executeWorkflow(task, resultTopic) {
|
|
311
|
+
console.log(`Received workflow task ${task.task_id}: ${task.workflow_name}`);
|
|
312
|
+
// Find the workflow class
|
|
313
|
+
const workflowCls = this.workflows.get(task.workflow_name);
|
|
314
|
+
if (!workflowCls) {
|
|
315
|
+
console.warn(`Unknown workflow: ${task.workflow_name}`);
|
|
316
|
+
await this.sendWorkflowResult(task, resultTopic, 'failed', undefined, {
|
|
317
|
+
type: 'UnknownWorkflow',
|
|
318
|
+
message: `Workflow '${task.workflow_name}' not registered`,
|
|
319
|
+
});
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
// Find the run method
|
|
323
|
+
const runMethod = (0, workflow_1.findRunMethod)(workflowCls);
|
|
324
|
+
if (!runMethod) {
|
|
325
|
+
await this.sendWorkflowResult(task, resultTopic, 'failed', undefined, {
|
|
326
|
+
type: 'NoRunMethod',
|
|
327
|
+
message: `Workflow '${task.workflow_name}' has no run method`,
|
|
328
|
+
});
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
// Execute the workflow
|
|
332
|
+
const startedAt = new Date();
|
|
333
|
+
try {
|
|
334
|
+
// Build completed activities map for replay
|
|
335
|
+
const completedActivitiesMap = new Map();
|
|
336
|
+
if (task.completed_activities) {
|
|
337
|
+
for (const ca of task.completed_activities) {
|
|
338
|
+
completedActivitiesMap.set(ca.index, ca.output);
|
|
339
|
+
}
|
|
340
|
+
console.log(`Resuming workflow ${task.workflow_id} with ${completedActivitiesMap.size} completed activities`);
|
|
341
|
+
}
|
|
342
|
+
// Create workflow context
|
|
343
|
+
const ctx = new workflow_1.WorkflowContext(this.activities, task.workflow_id, this, completedActivitiesMap.size > 0 ? completedActivitiesMap : null, task.metadata);
|
|
344
|
+
// Execute within context
|
|
345
|
+
const output = await (0, workflow_1.runWithContext)(ctx, async () => {
|
|
346
|
+
return await Promise.race([
|
|
347
|
+
runMethod(task.input),
|
|
348
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`Workflow timed out after ${task.timeout_ms}ms`)), task.timeout_ms)),
|
|
349
|
+
]);
|
|
350
|
+
});
|
|
351
|
+
const completedAt = new Date();
|
|
352
|
+
const durationMs = completedAt.getTime() - startedAt.getTime();
|
|
353
|
+
console.log(`Workflow ${task.task_id} completed in ${durationMs}ms`);
|
|
354
|
+
await this.sendWorkflowResult(task, resultTopic, 'completed', output, undefined, startedAt, completedAt, durationMs);
|
|
355
|
+
}
|
|
356
|
+
catch (error) {
|
|
357
|
+
const completedAt = new Date();
|
|
358
|
+
const durationMs = completedAt.getTime() - startedAt.getTime();
|
|
359
|
+
const err = error;
|
|
360
|
+
console.error(`Workflow ${task.task_id} failed:`, err.message);
|
|
361
|
+
await this.sendWorkflowResult(task, resultTopic, 'failed', undefined, {
|
|
362
|
+
type: err.name || 'Error',
|
|
363
|
+
message: err.message,
|
|
364
|
+
stack_trace: err.stack,
|
|
365
|
+
}, startedAt, completedAt, durationMs);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
async processActivityTask(data, resultTopic) {
|
|
369
|
+
const task = data;
|
|
370
|
+
console.log(`Received activity task ${task.task_id}: ${task.activity_name} (workflow=${task.workflow_id})`);
|
|
371
|
+
// Find the activity handler
|
|
372
|
+
const activityFn = this.activities.get(task.activity_name);
|
|
373
|
+
if (!activityFn) {
|
|
374
|
+
console.warn(`Unknown activity: ${task.activity_name}`);
|
|
375
|
+
await this.sendActivityResult(task, resultTopic, 'failed', undefined, {
|
|
376
|
+
type: 'UnknownActivity',
|
|
377
|
+
message: `Activity '${task.activity_name}' not registered`,
|
|
378
|
+
});
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
// Execute the activity
|
|
382
|
+
const startedAt = new Date();
|
|
383
|
+
try {
|
|
384
|
+
const output = await Promise.race([
|
|
385
|
+
Promise.resolve(activityFn(task.input)),
|
|
386
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`Activity timed out after ${task.timeout_ms}ms`)), task.timeout_ms)),
|
|
387
|
+
]);
|
|
388
|
+
const completedAt = new Date();
|
|
389
|
+
const durationMs = completedAt.getTime() - startedAt.getTime();
|
|
390
|
+
console.log(`Activity ${task.task_id} completed in ${durationMs}ms`);
|
|
391
|
+
await this.sendActivityResult(task, resultTopic, 'completed', output, undefined, startedAt, completedAt, durationMs);
|
|
392
|
+
}
|
|
393
|
+
catch (error) {
|
|
394
|
+
const completedAt = new Date();
|
|
395
|
+
const durationMs = completedAt.getTime() - startedAt.getTime();
|
|
396
|
+
const err = error;
|
|
397
|
+
console.error(`Activity ${task.task_id} failed:`, err.message);
|
|
398
|
+
await this.sendActivityResult(task, resultTopic, 'failed', undefined, {
|
|
399
|
+
type: err.name || 'Error',
|
|
400
|
+
message: err.message,
|
|
401
|
+
stack_trace: err.stack,
|
|
402
|
+
}, startedAt, completedAt, durationMs);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
async sendWorkflowResult(task, resultTopic, status, output, error, startedAt, completedAt, durationMs = 0) {
|
|
406
|
+
const now = new Date();
|
|
407
|
+
const result = {
|
|
408
|
+
task_id: task.task_id,
|
|
409
|
+
workflow_id: task.workflow_id,
|
|
410
|
+
workflow_name: task.workflow_name,
|
|
411
|
+
status,
|
|
412
|
+
output,
|
|
413
|
+
error,
|
|
414
|
+
started_at: (startedAt || now).toISOString(),
|
|
415
|
+
completed_at: (completedAt || now).toISOString(),
|
|
416
|
+
duration_ms: durationMs,
|
|
417
|
+
worker_id: this.workerId,
|
|
418
|
+
};
|
|
419
|
+
if (this.producer) {
|
|
420
|
+
await this.producer.send({
|
|
421
|
+
topic: resultTopic,
|
|
422
|
+
messages: [
|
|
423
|
+
{
|
|
424
|
+
key: task.workflow_id,
|
|
425
|
+
value: JSON.stringify(result),
|
|
426
|
+
},
|
|
427
|
+
],
|
|
428
|
+
});
|
|
429
|
+
console.debug(`Sent workflow result for task ${task.task_id}`);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
async sendActivityResult(task, resultTopic, status, output, error, startedAt, completedAt, durationMs = 0) {
|
|
433
|
+
const now = new Date();
|
|
434
|
+
const result = {
|
|
435
|
+
task_id: task.task_id,
|
|
436
|
+
workflow_id: task.workflow_id,
|
|
437
|
+
activity_name: task.activity_name,
|
|
438
|
+
activity_index: task.activity_index,
|
|
439
|
+
fan_out_index: task.fan_out_index,
|
|
440
|
+
status,
|
|
441
|
+
output,
|
|
442
|
+
error,
|
|
443
|
+
started_at: (startedAt || now).toISOString(),
|
|
444
|
+
completed_at: (completedAt || now).toISOString(),
|
|
445
|
+
duration_ms: durationMs,
|
|
446
|
+
worker_id: this.workerId,
|
|
447
|
+
requester_worker_id: task.requester_worker_id,
|
|
448
|
+
correlation_id: task.correlation_id,
|
|
449
|
+
};
|
|
450
|
+
if (this.producer) {
|
|
451
|
+
await this.producer.send({
|
|
452
|
+
topic: resultTopic,
|
|
453
|
+
messages: [
|
|
454
|
+
{
|
|
455
|
+
key: task.workflow_id,
|
|
456
|
+
value: JSON.stringify(result),
|
|
457
|
+
},
|
|
458
|
+
],
|
|
459
|
+
});
|
|
460
|
+
console.debug(`Sent activity result for task ${task.task_id}`);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
// WorkerInterface implementation for WorkflowContext
|
|
464
|
+
async reportLocalActivityCompletion(workflowId, activityName, activityIndex, output, durationMs) {
|
|
465
|
+
if (!this.producer || !this.resultTopic) {
|
|
466
|
+
console.debug('Cannot report local activity - producer not initialized');
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
const completedAt = new Date();
|
|
470
|
+
const startedAt = new Date(completedAt.getTime() - durationMs);
|
|
471
|
+
const result = {
|
|
472
|
+
task_id: `local-${workflowId}-${activityIndex}`,
|
|
473
|
+
workflow_id: workflowId,
|
|
474
|
+
activity_name: activityName,
|
|
475
|
+
activity_index: activityIndex,
|
|
476
|
+
status: 'completed',
|
|
477
|
+
output,
|
|
478
|
+
started_at: startedAt.toISOString(),
|
|
479
|
+
completed_at: completedAt.toISOString(),
|
|
480
|
+
duration_ms: durationMs,
|
|
481
|
+
worker_id: this.workerId,
|
|
482
|
+
};
|
|
483
|
+
try {
|
|
484
|
+
await this.producer.send({
|
|
485
|
+
topic: this.resultTopic,
|
|
486
|
+
messages: [{ key: workflowId, value: JSON.stringify(result) }],
|
|
487
|
+
});
|
|
488
|
+
console.debug(`Reported local activity completion: workflow_id=${workflowId}, activity=${activityName}, index=${activityIndex}`);
|
|
489
|
+
}
|
|
490
|
+
catch (error) {
|
|
491
|
+
console.warn('Failed to report local activity completion:', error);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
async reportLocalActivityFailure(workflowId, activityName, activityIndex, error, errorType, durationMs) {
|
|
495
|
+
if (!this.producer || !this.resultTopic) {
|
|
496
|
+
console.debug('Cannot report local activity failure - producer not initialized');
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
const completedAt = new Date();
|
|
500
|
+
const startedAt = new Date(completedAt.getTime() - durationMs);
|
|
501
|
+
const result = {
|
|
502
|
+
task_id: `local-${workflowId}-${activityIndex}`,
|
|
503
|
+
workflow_id: workflowId,
|
|
504
|
+
activity_name: activityName,
|
|
505
|
+
activity_index: activityIndex,
|
|
506
|
+
status: 'failed',
|
|
507
|
+
output: null,
|
|
508
|
+
error: { type: errorType, message: error },
|
|
509
|
+
started_at: startedAt.toISOString(),
|
|
510
|
+
completed_at: completedAt.toISOString(),
|
|
511
|
+
duration_ms: durationMs,
|
|
512
|
+
worker_id: this.workerId,
|
|
513
|
+
};
|
|
514
|
+
try {
|
|
515
|
+
await this.producer.send({
|
|
516
|
+
topic: this.resultTopic,
|
|
517
|
+
messages: [{ key: workflowId, value: JSON.stringify(result) }],
|
|
518
|
+
});
|
|
519
|
+
console.debug(`Reported local activity failure: workflow_id=${workflowId}, activity=${activityName}, index=${activityIndex}`);
|
|
520
|
+
}
|
|
521
|
+
catch (error) {
|
|
522
|
+
console.warn('Failed to report local activity failure:', error);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
async executeRemoteActivity(workflowId, activityName, activityIndex, inputData, timeoutMs) {
|
|
526
|
+
if (!this.producer || !this.resultTopic) {
|
|
527
|
+
throw new Error('Kafka producer not initialized');
|
|
528
|
+
}
|
|
529
|
+
// Send ActivityRequest to server via Kafka
|
|
530
|
+
const requestPayload = {
|
|
531
|
+
request_type: 'activity_request',
|
|
532
|
+
request_id: crypto.randomUUID(),
|
|
533
|
+
workflow_id: workflowId,
|
|
534
|
+
activity_name: activityName,
|
|
535
|
+
activity_index: activityIndex,
|
|
536
|
+
input: inputData,
|
|
537
|
+
timeout_ms: timeoutMs,
|
|
538
|
+
requester_worker_id: this.workerId,
|
|
539
|
+
correlation_id: crypto.randomUUID(),
|
|
540
|
+
created_at: new Date().toISOString(),
|
|
541
|
+
};
|
|
542
|
+
await this.producer.send({
|
|
543
|
+
topic: this.resultTopic,
|
|
544
|
+
messages: [{ key: workflowId, value: JSON.stringify(requestPayload) }],
|
|
545
|
+
});
|
|
546
|
+
console.log(`Activity request sent via Kafka: activity=${activityName}, workflow_id=${workflowId}, activity_index=${activityIndex}`);
|
|
547
|
+
// Poll server for result with exponential backoff
|
|
548
|
+
let pollInterval = 2000; // Start at 2 seconds
|
|
549
|
+
const maxPollInterval = 900000; // Max 15 minutes
|
|
550
|
+
const backoffMultiplier = 1.5;
|
|
551
|
+
const startTime = Date.now();
|
|
552
|
+
const timeoutSeconds = timeoutMs;
|
|
553
|
+
const pollUrl = `${this.config.serverUrl}/workflow/api/v1/workflows/${workflowId}/activities/${activityIndex}/result`;
|
|
554
|
+
const headers = { Authorization: `Bearer ${this.config.apiKey}` };
|
|
555
|
+
while (true) {
|
|
556
|
+
const elapsed = Date.now() - startTime;
|
|
557
|
+
if (elapsed >= timeoutSeconds) {
|
|
558
|
+
throw new Error(`Activity ${activityName} timed out after ${timeoutMs}ms`);
|
|
559
|
+
}
|
|
560
|
+
try {
|
|
561
|
+
const response = await fetch(pollUrl, { headers });
|
|
562
|
+
if (response.status === 200) {
|
|
563
|
+
const result = await response.json();
|
|
564
|
+
if (result.status === 'completed') {
|
|
565
|
+
console.log(`Activity ${activityName} completed for workflow ${workflowId}`);
|
|
566
|
+
return result.output;
|
|
567
|
+
}
|
|
568
|
+
else if (result.status === 'failed') {
|
|
569
|
+
const errorMsg = result.error || 'Activity failed';
|
|
570
|
+
console.error(`Activity ${activityName} failed: ${errorMsg}`);
|
|
571
|
+
throw new Error(errorMsg);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
else if (response.status === 202) {
|
|
575
|
+
// Still pending/running, continue polling
|
|
576
|
+
console.debug(`Activity ${activityName} still running, polling again in ${pollInterval}ms`);
|
|
577
|
+
}
|
|
578
|
+
else if (response.status === 404) {
|
|
579
|
+
// Activity not found yet
|
|
580
|
+
console.debug(`Activity ${activityName} not found yet, polling again in ${pollInterval}ms`);
|
|
581
|
+
}
|
|
582
|
+
else {
|
|
583
|
+
console.warn(`Unexpected response ${response.status} when polling activity result`);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
catch (error) {
|
|
587
|
+
if (error.message.includes('timed out') || error.message.includes('failed')) {
|
|
588
|
+
throw error;
|
|
589
|
+
}
|
|
590
|
+
console.warn('Error polling activity result:', error);
|
|
591
|
+
}
|
|
592
|
+
// Wait with exponential backoff
|
|
593
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
594
|
+
pollInterval = Math.min(pollInterval * backoffMultiplier, maxPollInterval);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
async cleanup() {
|
|
598
|
+
// Stop heartbeat
|
|
599
|
+
if (this.heartbeatInterval) {
|
|
600
|
+
clearInterval(this.heartbeatInterval);
|
|
601
|
+
}
|
|
602
|
+
// Disconnect from server
|
|
603
|
+
await this.disconnectFromServer();
|
|
604
|
+
// Stop Kafka clients
|
|
605
|
+
if (this.consumer) {
|
|
606
|
+
await this.consumer.disconnect();
|
|
607
|
+
}
|
|
608
|
+
if (this.producer) {
|
|
609
|
+
await this.producer.disconnect();
|
|
610
|
+
}
|
|
611
|
+
console.log(`Worker ${this.workerId} stopped`);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
exports.Worker = Worker;
|
|
615
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3dvcmtlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEseUVBQXlFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFekUscUNBQTJFO0FBQzNFLDJFQUFzRjtBQUN0Rix1Q0FBeUI7QUFlekIseUNBQW1IO0FBQ25ILHlDQUE2QztBQUU3Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHO0FBQ0gsTUFBYSxNQUFNO0lBQ1QsTUFBTSxDQUFlO0lBQ3JCLFNBQVMsR0FBK0IsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUNsRCxVQUFVLEdBQWlDLElBQUksR0FBRyxFQUFFLENBQUM7SUFFckQsUUFBUSxHQUFrQixJQUFJLENBQUM7SUFDL0IsVUFBVSxHQUFrQixJQUFJLENBQUM7SUFDakMsT0FBTyxHQUFHLEtBQUssQ0FBQztJQUNoQixLQUFLLEdBQWlCLElBQUksQ0FBQztJQUMzQixRQUFRLEdBQW9CLElBQUksQ0FBQztJQUNqQyxRQUFRLEdBQW9CLElBQUksQ0FBQztJQUNqQyxpQkFBaUIsR0FBMEIsSUFBSSxDQUFDO0lBQ2hELG1CQUFtQixHQUFHLEtBQUssQ0FBQztJQUM1QixXQUFXLEdBQWtCLElBQUksQ0FBQztJQUNsQyxzQkFBc0IsQ0FBUztJQUMvQixlQUFlLEdBQUcsQ0FBQyxDQUFDO0lBRTVCLFlBQVksTUFBb0I7UUFDOUIsSUFBSSxDQUFDLE1BQU0sR0FBRztZQUNaLEdBQUcsTUFBTTtZQUNULFNBQVMsRUFBRSxNQUFNLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDO1NBQy9DLENBQUM7UUFDRixJQUFJLENBQUMsc0JBQXNCLEdBQUcsTUFBTSxDQUFDLHNCQUFzQixJQUFJLEVBQUUsQ0FBQztJQUNwRSxDQUFDO0lBRUQ7O09BRUc7SUFDSCxRQUFRLENBQUMsT0FHUjtRQUNDLEtBQUssTUFBTSxLQUFLLElBQUksT0FBTyxDQUFDLFNBQVMsSUFBSSxFQUFFLEVBQUUsQ0FBQztZQUM1QyxNQUFNLE1BQU0sR0FBRyxJQUFBLDBCQUFlLEVBQUMsS0FBSyxDQUFDLENBQUM7WUFDdEMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ2xDLE9BQU8sQ0FBQyxHQUFHLENBQUMsd0JBQXdCLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDaEQsQ0FBQztRQUVELEtBQUssTUFBTSxVQUFVLElBQUksT0FBTyxDQUFDLFVBQVUsSUFBSSxFQUFFLEVBQUUsQ0FBQztZQUNsRCxNQUFNLFlBQVksR0FBRyxJQUFBLDBCQUFlLEVBQUMsVUFBVSxDQUFDLENBQUM7WUFDakQsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1lBQzlDLE9BQU8sQ0FBQyxHQUFHLENBQUMsd0JBQXdCLFlBQVksRUFBRSxDQUFDLENBQUM7UUFDdEQsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxHQUFHO1FBQ1AsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7UUFFcEIsd0JBQXdCO1FBQ3hCLE9BQU8sQ0FBQyxFQUFFLENBQUMsUUFBUSxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQ3hDLE9BQU8sQ0FBQyxFQUFFLENBQUMsU0FBUyxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBRXpDLHlDQUF5QztRQUN6QyxNQUFNLGlCQUFpQixHQUFHLE1BQU0sSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQ3ZELE1BQU0sV0FBVyxHQUFHLGlCQUFpQixDQUFDLFlBQVksQ0FBQztRQUNuRCxNQUFNLFdBQVcsR0FBRyxpQkFBaUIsQ0FBQyxZQUFZLENBQUM7UUFDbkQsSUFBSSxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUM7UUFFL0Isc0JBQXNCO1FBQ3RCLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLGlCQUFpQixDQUFDLENBQUM7UUFFdkQsa0JBQWtCO1FBQ2xCLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxJQUFJLG1CQUFtQixJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDbEYsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxFQUFFLE9BQU8sRUFBRSxlQUFlLEVBQUUsQ0FBQyxDQUFDO1FBRWxFLGtCQUFrQjtRQUNsQixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUM7UUFFdEMsSUFBSSxDQUFDO1lBQ0gsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQzlCLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUM5QixNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxhQUFhLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUU1RSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsSUFBSSxDQUFDLFFBQVEsNEJBQTRCLFdBQVcsRUFBRSxDQUFDLENBQUM7WUFDOUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyw2QkFBNkIsSUFBSSxDQUFDLHNCQUFzQixFQUFFLENBQUMsQ0FBQztZQUN4RSxPQUFPLENBQUMsR0FBRyxDQUFDLHlCQUF5QixLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ3JGLE9BQU8sQ0FBQyxHQUFHLENBQUMsMEJBQTBCLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7WUFFdkYsa0JBQWtCO1lBQ2xCLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUV0QiwyQkFBMkI7WUFDM0IsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQztnQkFDdEIsV0FBVyxFQUFFLEtBQUssRUFBRSxFQUFFLE9BQU8sRUFBRSxFQUFFLEVBQUU7b0JBQ2pDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTzt3QkFBRSxPQUFPO29CQUUxQixJQUFJLENBQUM7d0JBQ0gsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxJQUFJLElBQUksQ0FBQyxDQUFDO3dCQUMzRCxNQUFNLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxDQUFDO29CQUMvQyxDQUFDO29CQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7d0JBQ2YsT0FBTyxDQUFDLEtBQUssQ0FBQywyQkFBMkIsRUFBRSxLQUFLLENBQUMsQ0FBQztvQkFDcEQsQ0FBQztnQkFDSCxDQUFDO2FBQ0YsQ0FBQyxDQUFDO1lBRUgsNkJBQTZCO1lBQzdCLE1BQU0sSUFBSSxPQUFPLENBQU8sQ0FBQyxPQUFPLEVBQUUsRUFBRTtnQkFDbEMsTUFBTSxhQUFhLEdBQUcsV0FBVyxDQUFDLEdBQUcsRUFBRTtvQkFDckMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQzt3QkFDbEIsYUFBYSxDQUFDLGFBQWEsQ0FBQyxDQUFDO3dCQUM3QixPQUFPLEVBQUUsQ0FBQztvQkFDWixDQUFDO2dCQUNILENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztZQUNWLENBQUMsQ0FBQyxDQUFDO1FBRUwsQ0FBQztnQkFBUyxDQUFDO1lBQ1QsTUFBTSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDdkIsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxJQUFJO1FBQ1IsT0FBTyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBQ2xDLElBQUksQ0FBQyxPQUFPLEdBQUcsS0FBSyxDQUFDO0lBQ3ZCLENBQUM7SUFFTyxLQUFLLENBQUMsZUFBZTtRQUMzQixNQUFNLFFBQVEsR0FBRyxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUM7UUFFL0IsTUFBTSxjQUFjLEdBQUc7WUFDckIsU0FBUyxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUM1QyxVQUFVLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQzlDLFFBQVE7U0FDVCxDQUFDO1FBRUYsTUFBTSxRQUFRLEdBQUcsTUFBTSxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsa0NBQWtDLEVBQUU7WUFDdkYsTUFBTSxFQUFFLE1BQU07WUFDZCxPQUFPLEVBQUU7Z0JBQ1AsY0FBYyxFQUFFLGtCQUFrQjtnQkFDbEMsZUFBZSxFQUFFLFVBQVUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUU7YUFDaEQ7WUFDRCxJQUFJLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLENBQUM7U0FDckMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNqQixNQUFNLEtBQUssR0FBRyxNQUFNLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNwQyxNQUFNLElBQUksS0FBSyxDQUFDLGdDQUFnQyxRQUFRLENBQUMsTUFBTSxNQUFNLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDaEYsQ0FBQztRQUVELE1BQU0sSUFBSSxHQUFHLE1BQU0sUUFBUSxDQUFDLElBQUksRUFBcUIsQ0FBQztRQUV0RCxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUM7UUFDL0IsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDO1FBQ25DLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxJQUFJLENBQUMscUJBQXFCLElBQUksS0FBSyxDQUFDO1FBRS9ELE9BQU8sQ0FBQyxHQUFHLENBQUMsb0NBQW9DLElBQUksQ0FBQyxRQUFRLGlCQUFpQixJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztRQUVqRyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUM7SUFDcEIsQ0FBQztJQUVPLGlCQUFpQixDQUFDLFdBQXdCO1FBQ2hELE1BQU0sSUFBSSxHQUFHLFdBQVcsQ0FBQyxJQUFJLENBQUM7UUFFOUIscUVBQXFFO1FBQ3JFLE1BQU0sT0FBTyxHQUFHLE9BQU8sV0FBVyxDQUFDLE9BQU8sS0FBSyxRQUFRO1lBQ3JELENBQUMsQ0FBRSxXQUFXLENBQUMsT0FBa0IsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQzlFLENBQUMsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDO1FBRXhCLE1BQU0sTUFBTSxHQUFRO1lBQ2xCLFFBQVEsRUFBRSxtQkFBbUIsSUFBSSxDQUFDLFFBQVEsRUFBRTtZQUM1QyxPQUFPO1lBQ1AsUUFBUSxFQUFFLGtCQUFRLENBQUMsSUFBSTtTQUN4QixDQUFDO1FBRUYsSUFBSSxJQUFJLEVBQUUsSUFBSSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQzdCLE1BQU0sQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDO1lBQ2xCLE1BQU0sQ0FBQyxJQUFJLEdBQUc7Z0JBQ1osU0FBUyxFQUFFLGFBQWE7Z0JBQ3hCLG1CQUFtQixFQUFFLEtBQUssSUFBSSxFQUFFO29CQUM5QixNQUFNLEtBQUssR0FBRyxNQUFNLElBQUEscUVBQXdDLEVBQUM7d0JBQzNELE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTzt3QkFDcEIsc0JBQXNCLEVBQUUsS0FBSyxJQUFJLEVBQUUsQ0FBQyxDQUFDOzRCQUNuQyxXQUFXLEVBQUUsSUFBSSxDQUFDLGFBQWM7NEJBQ2hDLGVBQWUsRUFBRSxJQUFJLENBQUMsaUJBQWtCO3lCQUN6QyxDQUFDO3FCQUNILENBQUMsQ0FBQztvQkFDSCxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDaEMsQ0FBQzthQUNhLENBQUM7UUFDbkIsQ0FBQzthQUFNLElBQUksSUFBSSxFQUFFLElBQUksS0FBSyxNQUFNLEVBQUUsQ0FBQztZQUNqQyxJQUFJLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDNUMsTUFBTSxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUM7WUFDcEIsQ0FBQztZQUNELElBQUksSUFBSSxDQUFDLGNBQWMsSUFBSSxJQUFJLENBQUMsYUFBYSxJQUFJLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztnQkFDcEUsTUFBTSxDQUFDLElBQUksR0FBRztvQkFDWixTQUFTLEVBQUUsSUFBSSxDQUFDLGNBQWMsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQztvQkFDN0QsUUFBUSxFQUFFLElBQUksQ0FBQyxhQUFhO29CQUM1QixRQUFRLEVBQUUsSUFBSSxDQUFDLGFBQWE7aUJBQ2QsQ0FBQztZQUNuQixDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU8sSUFBSSxlQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDM0IsQ0FBQztJQUVPLGNBQWM7UUFDcEIsSUFBSSxDQUFDLGlCQUFpQixHQUFHLFdBQVcsQ0FBQyxLQUFLLElBQUksRUFBRTtZQUM5QyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU87Z0JBQUUsT0FBTztZQUUxQixJQUFJLENBQUM7Z0JBQ0gsTUFBTSxRQUFRLEdBQUcsTUFBTSxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsb0NBQW9DLEVBQUU7b0JBQ3pGLE1BQU0sRUFBRSxNQUFNO29CQUNkLE9BQU8sRUFBRTt3QkFDUCxjQUFjLEVBQUUsa0JBQWtCO3dCQUNsQyxlQUFlLEVBQUUsVUFBVSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRTtxQkFDaEQ7b0JBQ0QsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxXQUFXLEVBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO2lCQUN2RCxDQUFDLENBQUM7Z0JBRUgsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUUsQ0FBQztvQkFDakIsT0FBTyxDQUFDLElBQUksQ0FBQyxxQkFBcUIsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7Z0JBQ3ZELENBQUM7WUFDSCxDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixPQUFPLENBQUMsSUFBSSxDQUFDLGtCQUFrQixFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQzFDLENBQUM7UUFDSCxDQUFDLEVBQUUsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDL0IsQ0FBQztJQUVPLEtBQUssQ0FBQyxvQkFBb0I7UUFDaEMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVO1lBQUUsT0FBTztRQUU3QixJQUFJLENBQUM7WUFDSCxNQUFNLFFBQVEsR0FBRyxNQUFNLEtBQUssQ0FBQyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxxQ0FBcUMsRUFBRTtnQkFDMUYsTUFBTSxFQUFFLE1BQU07Z0JBQ2QsT0FBTyxFQUFFO29CQUNQLGNBQWMsRUFBRSxrQkFBa0I7b0JBQ2xDLGVBQWUsRUFBRSxVQUFVLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFO2lCQUNoRDtnQkFDRCxJQUFJLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLFdBQVcsRUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7YUFDdkQsQ0FBQyxDQUFDO1lBRUgsSUFBSSxRQUFRLENBQUMsRUFBRSxFQUFFLENBQUM7Z0JBQ2hCLE9BQU8sQ0FBQyxHQUFHLENBQUMsMEJBQTBCLENBQUMsQ0FBQztZQUMxQyxDQUFDO1FBQ0gsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixPQUFPLENBQUMsSUFBSSxDQUFDLG1DQUFtQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzNELENBQUM7SUFDSCxDQUFDO0lBRU8sS0FBSyxDQUFDLGNBQWMsQ0FBQyxJQUFTLEVBQUUsV0FBbUI7UUFDekQsZ0ZBQWdGO1FBQ2hGLElBQUksSUFBSSxDQUFDLE1BQU0sSUFBSSxJQUFJLENBQUMsWUFBWSxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ3hELE9BQU8sQ0FBQyxLQUFLLENBQUMsb0VBQW9FLENBQUMsQ0FBQztZQUNwRixPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxTQUFTLElBQUksVUFBVSxDQUFDO1FBRTlDLElBQUksUUFBUSxLQUFLLFVBQVUsRUFBRSxDQUFDO1lBQzVCLDREQUE0RDtZQUM1RCxJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFO2dCQUMxRCxPQUFPLENBQUMsS0FBSyxDQUFDLGlDQUFpQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQzFELENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQzthQUFNLENBQUM7WUFDTix5Q0FBeUM7WUFDekMsTUFBTSxJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQ3BELENBQUM7SUFDSCxDQUFDO0lBRU8sS0FBSyxDQUFDLG1CQUFtQixDQUFDLElBQWtCLEVBQUUsV0FBbUI7UUFDdkUsMEJBQTBCO1FBQzFCLE9BQU8sSUFBSSxDQUFDLGVBQWUsSUFBSSxJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztZQUMzRCxNQUFNLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDM0QsQ0FBQztRQUNELElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUV2QixJQUFJLENBQUM7WUFDSCxNQUFNLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQ2hELENBQUM7Z0JBQVMsQ0FBQztZQUNULElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUN6QixDQUFDO0lBQ0gsQ0FBQztJQUVPLEtBQUssQ0FBQyxlQUFlLENBQUMsSUFBa0IsRUFBRSxXQUFtQjtRQUNuRSxPQUFPLENBQUMsR0FBRyxDQUFDLDBCQUEwQixJQUFJLENBQUMsT0FBTyxLQUFLLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBRTdFLDBCQUEwQjtRQUMxQixNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDM0QsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ2pCLE9BQU8sQ0FBQyxJQUFJLENBQUMscUJBQXFCLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDO1lBQ3hELE1BQU0sSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksRUFBRSxXQUFXLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRTtnQkFDcEUsSUFBSSxFQUFFLGlCQUFpQjtnQkFDdkIsT0FBTyxFQUFFLGFBQWEsSUFBSSxDQUFDLGFBQWEsa0JBQWtCO2FBQzNELENBQUMsQ0FBQztZQUNILE9BQU87UUFDVCxDQUFDO1FBRUQsc0JBQXNCO1FBQ3RCLE1BQU0sU0FBUyxHQUFHLElBQUEsd0JBQWEsRUFBQyxXQUFXLENBQUMsQ0FBQztRQUM3QyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDZixNQUFNLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLEVBQUUsV0FBVyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUU7Z0JBQ3BFLElBQUksRUFBRSxhQUFhO2dCQUNuQixPQUFPLEVBQUUsYUFBYSxJQUFJLENBQUMsYUFBYSxxQkFBcUI7YUFDOUQsQ0FBQyxDQUFDO1lBQ0gsT0FBTztRQUNULENBQUM7UUFFRCx1QkFBdUI7UUFDdkIsTUFBTSxTQUFTLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUM3QixJQUFJLENBQUM7WUFDSCw0Q0FBNEM7WUFDNUMsTUFBTSxzQkFBc0IsR0FBRyxJQUFJLEdBQUcsRUFBbUIsQ0FBQztZQUMxRCxJQUFJLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO2dCQUM5QixLQUFLLE1BQU0sRUFBRSxJQUFJLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO29CQUMzQyxzQkFBc0IsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQ2xELENBQUM7Z0JBQ0QsT0FBTyxDQUFDLEdBQUcsQ0FDVCxxQkFBcUIsSUFBSSxDQUFDLFdBQVcsU0FBUyxzQkFBc0IsQ0FBQyxJQUFJLHVCQUF1QixDQUNqRyxDQUFDO1lBQ0osQ0FBQztZQUVELDBCQUEwQjtZQUMxQixNQUFNLEdBQUcsR0FBRyxJQUFJLDBCQUFlLENBQzdCLElBQUksQ0FBQyxVQUFVLEVBQ2YsSUFBSSxDQUFDLFdBQVcsRUFDaEIsSUFBSSxFQUNKLHNCQUFzQixDQUFDLElBQUksR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLHNCQUFzQixDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQy9ELElBQUksQ0FBQyxRQUFRLENBQ2QsQ0FBQztZQUVGLHlCQUF5QjtZQUN6QixNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUEseUJBQWMsRUFBQyxHQUFHLEVBQUUsS0FBSyxJQUFJLEVBQUU7Z0JBQ2xELE9BQU8sTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDO29CQUN4QixTQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQztvQkFDckIsSUFBSSxPQUFPLENBQVEsQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLEVBQUUsQ0FDL0IsVUFBVSxDQUNSLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyw0QkFBNEIsSUFBSSxDQUFDLFVBQVUsSUFBSSxDQUFDLENBQUMsRUFDeEUsSUFBSSxDQUFDLFVBQVUsQ0FDaEIsQ0FDRjtpQkFDRixDQUFDLENBQUM7WUFDTCxDQUFDLENBQUMsQ0FBQztZQUVILE1BQU0sV0FBVyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7WUFDL0IsTUFBTSxVQUFVLEdBQUcsV0FBVyxDQUFDLE9BQU8sRUFBRSxHQUFHLFNBQVMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUUvRCxPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksSUFBSSxDQUFDLE9BQU8saUJBQWlCLFVBQVUsSUFBSSxDQUFDLENBQUM7WUFFckUsTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQzNCLElBQUksRUFDSixXQUFXLEVBQ1gsV0FBVyxFQUNYLE1BQU0sRUFDTixTQUFTLEVBQ1QsU0FBUyxFQUNULFdBQVcsRUFDWCxVQUFVLENBQ1gsQ0FBQztRQUNKLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxXQUFXLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztZQUMvQixNQUFNLFVBQVUsR0FBRyxXQUFXLENBQUMsT0FBTyxFQUFFLEdBQUcsU0FBUyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQy9ELE1BQU0sR0FBRyxHQUFHLEtBQWMsQ0FBQztZQUUzQixPQUFPLENBQUMsS0FBSyxDQUFDLFlBQVksSUFBSSxDQUFDLE9BQU8sVUFBVSxFQUFFLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUUvRCxNQUFNLElBQUksQ0FBQyxrQkFBa0IsQ0FDM0IsSUFBSSxFQUNKLFdBQVcsRUFDWCxRQUFRLEVBQ1IsU0FBUyxFQUNUO2dCQUNFLElBQUksRUFBRSxHQUFHLENBQUMsSUFBSSxJQUFJLE9BQU87Z0JBQ3pCLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTztnQkFDcEIsV0FBVyxFQUFFLEdBQUcsQ0FBQyxLQUFLO2FBQ3ZCLEVBQ0QsU0FBUyxFQUNULFdBQVcsRUFDWCxVQUFVLENBQ1gsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRU8sS0FBSyxDQUFDLG1CQUFtQixDQUFDLElBQWtCLEVBQUUsV0FBbUI7UUFDdkUsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBQ2xCLE9BQU8sQ0FBQyxHQUFHLENBQ1QsMEJBQTBCLElBQUksQ0FBQyxPQUFPLEtBQUssSUFBSSxDQUFDLGFBQWEsY0FBYyxJQUFJLENBQUMsV0FBVyxHQUFHLENBQy9GLENBQUM7UUFFRiw0QkFBNEI7UUFDNUIsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQzNELElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUNoQixPQUFPLENBQUMsSUFBSSxDQUFDLHFCQUFxQixJQUFJLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQztZQUN4RCxNQUFNLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLEVBQUUsV0FBVyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUU7Z0JBQ3BFLElBQUksRUFBRSxpQkFBaUI7Z0JBQ3ZCLE9BQU8sRUFBRSxhQUFhLElBQUksQ0FBQyxhQUFhLGtCQUFrQjthQUMzRCxDQUFDLENBQUM7WUFDSCxPQUFPO1FBQ1QsQ0FBQztRQUVELHVCQUF1QjtRQUN2QixNQUFNLFNBQVMsR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1FBQzdCLElBQUksQ0FBQztZQUNILE1BQU0sTUFBTSxHQUFHLE1BQU0sT0FBTyxDQUFDLElBQUksQ0FBQztnQkFDaEMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUN2QyxJQUFJLE9BQU8sQ0FBUSxDQUFDLENBQUMsRUFBRSxNQUFNLEVBQUUsRUFBRSxDQUMvQixVQUFVLENBQ1IsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLDRCQUE0QixJQUFJLENBQUMsVUFBVSxJQUFJLENBQUMsQ0FBQyxFQUN4RSxJQUFJLENBQUMsVUFBVSxDQUNoQixDQUNGO2FBQ0YsQ0FBQyxDQUFDO1lBRUgsTUFBTSxXQUFXLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztZQUMvQixNQUFNLFVBQVUsR0FBRyxXQUFXLENBQUMsT0FBTyxFQUFFLEdBQUcsU0FBUyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBRS9ELE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxJQUFJLENBQUMsT0FBTyxpQkFBaUIsVUFBVSxJQUFJLENBQUMsQ0FBQztZQUVyRSxNQUFNLElBQUksQ0FBQyxrQkFBa0IsQ0FDM0IsSUFBSSxFQUNKLFdBQVcsRUFDWCxXQUFXLEVBQ1gsTUFBTSxFQUNOLFNBQVMsRUFDVCxTQUFTLEVBQ1QsV0FBVyxFQUNYLFVBQVUsQ0FDWCxDQUFDO1FBQ0osQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLFdBQVcsR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1lBQy9CLE1BQU0sVUFBVSxHQUFHLFdBQVcsQ0FBQyxPQUFPLEVBQUUsR0FBRyxTQUFTLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDL0QsTUFBTSxHQUFHLEdBQUcsS0FBYyxDQUFDO1lBRTNCLE9BQU8sQ0FBQyxLQUFLLENBQUMsWUFBWSxJQUFJLENBQUMsT0FBTyxVQUFVLEVBQUUsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBRS9ELE1BQU0sSUFBSSxDQUFDLGtCQUFrQixDQUMzQixJQUFJLEVBQ0osV0FBVyxFQUNYLFFBQVEsRUFDUixTQUFTLEVBQ1Q7Z0JBQ0UsSUFBSSxFQUFFLEdBQUcsQ0FBQyxJQUFJLElBQUksT0FBTztnQkFDekIsT0FBTyxFQUFFLEdBQUcsQ0FBQyxPQUFPO2dCQUNwQixXQUFXLEVBQUUsR0FBRyxDQUFDLEtBQUs7YUFDdkIsRUFDRCxTQUFTLEVBQ1QsV0FBVyxFQUNYLFVBQVUsQ0FDWCxDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFTyxLQUFLLENBQUMsa0JBQWtCLENBQzlCLElBQWtCLEVBQ2xCLFdBQW1CLEVBQ25CLE1BQThCLEVBQzlCLE1BQWdCLEVBQ2hCLEtBQXFCLEVBQ3JCLFNBQWdCLEVBQ2hCLFdBQWtCLEVBQ2xCLFVBQVUsR0FBRyxDQUFDO1FBRWQsTUFBTSxHQUFHLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUN2QixNQUFNLE1BQU0sR0FBbUI7WUFDN0IsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPO1lBQ3JCLFdBQVcsRUFBRSxJQUFJLENBQUMsV0FBVztZQUM3QixhQUFhLEVBQUUsSUFBSSxDQUFDLGFBQWE7WUFDakMsTUFBTTtZQUNOLE1BQU07WUFDTixLQUFLO1lBQ0wsVUFBVSxFQUFFLENBQUMsU0FBUyxJQUFJLEdBQUcsQ0FBQyxDQUFDLFdBQVcsRUFBRTtZQUM1QyxZQUFZLEVBQUUsQ0FBQyxXQUFXLElBQUksR0FBRyxDQUFDLENBQUMsV0FBVyxFQUFFO1lBQ2hELFdBQVcsRUFBRSxVQUFVO1lBQ3ZCLFNBQVMsRUFBRSxJQUFJLENBQUMsUUFBUztTQUMxQixDQUFDO1FBRUYsSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDbEIsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQztnQkFDdkIsS0FBSyxFQUFFLFdBQVc7Z0JBQ2xCLFFBQVEsRUFBRTtvQkFDUjt3QkFDRSxHQUFHLEVBQUUsSUFBSSxDQUFDLFdBQVc7d0JBQ3JCLEtBQUssRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQztxQkFDOUI7aUJBQ0Y7YUFDRixDQUFDLENBQUM7WUFDSCxPQUFPLENBQUMsS0FBSyxDQUFDLGlDQUFpQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUNqRSxDQUFDO0lBQ0gsQ0FBQztJQUVPLEtBQUssQ0FBQyxrQkFBa0IsQ0FDOUIsSUFBa0IsRUFDbEIsV0FBbUIsRUFDbkIsTUFBOEIsRUFDOUIsTUFBZ0IsRUFDaEIsS0FBcUIsRUFDckIsU0FBZ0IsRUFDaEIsV0FBa0IsRUFDbEIsVUFBVSxHQUFHLENBQUM7UUFFZCxNQUFNLEdBQUcsR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1FBQ3ZCLE1BQU0sTUFBTSxHQUFtQjtZQUM3QixPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU87WUFDckIsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXO1lBQzdCLGFBQWEsRUFBRSxJQUFJLENBQUMsYUFBYTtZQUNqQyxjQUFjLEVBQUUsSUFBSSxDQUFDLGNBQWM7WUFDbkMsYUFBYSxFQUFFLElBQUksQ0FBQyxhQUFhO1lBQ2pDLE1BQU07WUFDTixNQUFNO1lBQ04sS0FBSztZQUNMLFVBQVUsRUFBRSxDQUFDLFNBQVMsSUFBSSxHQUFHLENBQUMsQ0FBQyxXQUFXLEVBQUU7WUFDNUMsWUFBWSxFQUFFLENBQUMsV0FBVyxJQUFJLEdBQUcsQ0FBQyxDQUFDLFdBQVcsRUFBRTtZQUNoRCxXQUFXLEVBQUUsVUFBVTtZQUN2QixTQUFTLEVBQUUsSUFBSSxDQUFDLFFBQVM7WUFDekIsbUJBQW1CLEVBQUUsSUFBSSxDQUFDLG1CQUFtQjtZQUM3QyxjQUFjLEVBQUUsSUFBSSxDQUFDLGNBQWM7U0FDcEMsQ0FBQztRQUVGLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ2xCLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUM7Z0JBQ3ZCLEtBQUssRUFBRSxXQUFXO2dCQUNsQixRQUFRLEVBQUU7b0JBQ1I7d0JBQ0UsR0FBRyxFQUFFLElBQUksQ0FBQyxXQUFXO3dCQUNyQixLQUFLLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7cUJBQzlCO2lCQUNGO2FBQ0YsQ0FBQyxDQUFDO1lBQ0gsT0FBTyxDQUFDLEtBQUssQ0FBQyxpQ0FBaUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7UUFDakUsQ0FBQztJQUNILENBQUM7SUFFRCxxREFBcUQ7SUFFckQsS0FBSyxDQUFDLDZCQUE2QixDQUNqQyxVQUFrQixFQUNsQixZQUFvQixFQUNwQixhQUFxQixFQUNyQixNQUFlLEVBQ2YsVUFBa0I7UUFFbEIsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDeEMsT0FBTyxDQUFDLEtBQUssQ0FBQyx5REFBeUQsQ0FBQyxDQUFDO1lBQ3pFLE9BQU87UUFDVCxDQUFDO1FBRUQsTUFBTSxXQUFXLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUMvQixNQUFNLFNBQVMsR0FBRyxJQUFJLElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxFQUFFLEdBQUcsVUFBVSxDQUFDLENBQUM7UUFFL0QsTUFBTSxNQUFNLEdBQUc7WUFDYixPQUFPLEVBQUUsU0FBUyxVQUFVLElBQUksYUFBYSxFQUFFO1lBQy9DLFdBQVcsRUFBRSxVQUFVO1lBQ3ZCLGFBQWEsRUFBRSxZQUFZO1lBQzNCLGNBQWMsRUFBRSxhQUFhO1lBQzdCLE1BQU0sRUFBRSxXQUFXO1lBQ25CLE1BQU07WUFDTixVQUFVLEVBQUUsU0FBUyxDQUFDLFdBQVcsRUFBRTtZQUNuQyxZQUFZLEVBQUUsV0FBVyxDQUFDLFdBQVcsRUFBRTtZQUN2QyxXQUFXLEVBQUUsVUFBVTtZQUN2QixTQUFTLEVBQUUsSUFBSSxDQUFDLFFBQVE7U0FDekIsQ0FBQztRQUVGLElBQUksQ0FBQztZQUNILE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUM7Z0JBQ3ZCLEtBQUssRUFBRSxJQUFJLENBQUMsV0FBVztnQkFDdkIsUUFBUSxFQUFFLENBQUMsRUFBRSxHQUFHLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7YUFDL0QsQ0FBQyxDQUFDO1lBQ0gsT0FBTyxDQUFDLEtBQUssQ0FDWCxtREFBbUQsVUFBVSxjQUFjLFlBQVksV0FBVyxhQUFhLEVBQUUsQ0FDbEgsQ0FBQztRQUNKLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsT0FBTyxDQUFDLElBQUksQ0FBQyw2Q0FBNkMsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNyRSxDQUFDO0lBQ0gsQ0FBQztJQUVELEtBQUssQ0FBQywwQkFBMEIsQ0FDOUIsVUFBa0IsRUFDbEIsWUFBb0IsRUFDcEIsYUFBcUIsRUFDckIsS0FBYSxFQUNiLFNBQWlCLEVBQ2pCLFVBQWtCO1FBRWxCLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ3hDLE9BQU8sQ0FBQyxLQUFLLENBQUMsaUVBQWlFLENBQUMsQ0FBQztZQUNqRixPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0sV0FBVyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7UUFDL0IsTUFBTSxTQUFTLEdBQUcsSUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sRUFBRSxHQUFHLFVBQVUsQ0FBQyxDQUFDO1FBRS9ELE1BQU0sTUFBTSxHQUFHO1lBQ2IsT0FBTyxFQUFFLFNBQVMsVUFBVSxJQUFJLGFBQWEsRUFBRTtZQUMvQyxXQUFXLEVBQUUsVUFBVTtZQUN2QixhQUFhLEVBQUUsWUFBWTtZQUMzQixjQUFjLEVBQUUsYUFBYTtZQUM3QixNQUFNLEVBQUUsUUFBUTtZQUNoQixNQUFNLEVBQUUsSUFBSTtZQUNaLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRTtZQUMxQyxVQUFVLEVBQUUsU0FBUyxDQUFDLFdBQVcsRUFBRTtZQUNuQyxZQUFZLEVBQUUsV0FBVyxDQUFDLFdBQVcsRUFBRTtZQUN2QyxXQUFXLEVBQUUsVUFBVTtZQUN2QixTQUFTLEVBQUUsSUFBSSxDQUFDLFFBQVE7U0FDekIsQ0FBQztRQUVGLElBQUksQ0FBQztZQUNILE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUM7Z0JBQ3ZCLEtBQUssRUFBRSxJQUFJLENBQUMsV0FBVztnQkFDdkIsUUFBUSxFQUFFLENBQUMsRUFBRSxHQUFHLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7YUFDL0QsQ0FBQyxDQUFDO1lBQ0gsT0FBTyxDQUFDLEtBQUssQ0FDWCxnREFBZ0QsVUFBVSxjQUFjLFlBQVksV0FBVyxhQUFhLEVBQUUsQ0FDL0csQ0FBQztRQUNKLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsT0FBTyxDQUFDLElBQUksQ0FBQywwQ0FBMEMsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNsRSxDQUFDO0lBQ0gsQ0FBQztJQUVELEtBQUssQ0FBQyxxQkFBcUIsQ0FDekIsVUFBa0IsRUFDbEIsWUFBb0IsRUFDcEIsYUFBcUIsRUFDckIsU0FBa0IsRUFDbEIsU0FBaUI7UUFFakIsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDeEMsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO1FBQ3BELENBQUM7UUFFRCwyQ0FBMkM7UUFDM0MsTUFBTSxjQUFjLEdBQUc7WUFDckIsWUFBWSxFQUFFLGtCQUFrQjtZQUNoQyxVQUFVLEVBQUUsTUFBTSxDQUFDLFVBQVUsRUFBRTtZQUMvQixXQUFXLEVBQUUsVUFBVTtZQUN2QixhQUFhLEVBQUUsWUFBWTtZQUMzQixjQUFjLEVBQUUsYUFBYTtZQUM3QixLQUFLLEVBQUUsU0FBUztZQUNoQixVQUFVLEVBQUUsU0FBUztZQUNyQixtQkFBbUIsRUFBRSxJQUFJLENBQUMsUUFBUTtZQUNsQyxjQUFjLEVBQUUsTUFBTSxDQUFDLFVBQVUsRUFBRTtZQUNuQyxVQUFVLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUU7U0FDckMsQ0FBQztRQUVGLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUM7WUFDdkIsS0FBSyxFQUFFLElBQUksQ0FBQyxXQUFXO1lBQ3ZCLFFBQVEsRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDO1NBQ3ZFLENBQUMsQ0FBQztRQUVILE9BQU8sQ0FBQyxHQUFHLENBQ1QsNkNBQTZDLFlBQVksaUJBQWlCLFVBQVUsb0JBQW9CLGFBQWEsRUFBRSxDQUN4SCxDQUFDO1FBRUYsa0RBQWtEO1FBQ2xELElBQUksWUFBWSxHQUFHLElBQUksQ0FBQyxDQUFDLHFCQUFxQjtRQUM5QyxNQUFNLGVBQWUsR0FBRyxNQUFNLENBQUMsQ0FBQyxpQkFBaUI7UUFDakQsTUFBTSxpQkFBaUIsR0FBRyxHQUFHLENBQUM7UUFDOUIsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQzdCLE1BQU0sY0FBYyxHQUFHLFNBQVMsQ0FBQztRQUVqQyxNQUFNLE9BQU8sR0FBRyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyw4QkFBOEIsVUFBVSxlQUFlLGFBQWEsU0FBUyxDQUFDO1FBQ3RILE1BQU0sT0FBTyxHQUFHLEVBQUUsYUFBYSxFQUFFLFVBQVUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDO1FBRWxFLE9BQU8sSUFBSSxFQUFFLENBQUM7WUFDWixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsU0FBUyxDQUFDO1lBQ3ZDLElBQUksT0FBTyxJQUFJLGNBQWMsRUFBRSxDQUFDO2dCQUM5QixNQUFNLElBQUksS0FBSyxDQUFDLFlBQVksWUFBWSxvQkFBb0IsU0FBUyxJQUFJLENBQUMsQ0FBQztZQUM3RSxDQUFDO1lBRUQsSUFBSSxDQUFDO2dCQUNILE1BQU0sUUFBUSxHQUFHLE1BQU0sS0FBSyxDQUFDLE9BQU8sRUFBRSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7Z0JBRW5ELElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxHQUFHLEVBQUUsQ0FBQztvQkFDNUIsTUFBTSxNQUFNLEdBQUcsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUEwRCxDQUFDO29CQUM3RixJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssV0FBVyxFQUFFLENBQUM7d0JBQ2xDLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxZQUFZLDJCQUEyQixVQUFVLEVBQUUsQ0FBQyxDQUFDO3dCQUM3RSxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUM7b0JBQ3ZCLENBQUM7eUJBQU0sSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLFFBQVEsRUFBRSxDQUFDO3dCQUN0QyxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsS0FBSyxJQUFJLGlCQUFpQixDQUFDO3dCQUNuRCxPQUFPLENBQUMsS0FBSyxDQUFDLFlBQVksWUFBWSxZQUFZLFFBQVEsRUFBRSxDQUFDLENBQUM7d0JBQzlELE1BQU0sSUFBSSxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7b0JBQzVCLENBQUM7Z0JBQ0gsQ0FBQztxQkFBTSxJQUFJLFFBQVEsQ0FBQyxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUM7b0JBQ25DLDBDQUEwQztvQkFDMUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxZQUFZLFlBQVksb0NBQW9DLFlBQVksSUFBSSxDQUFDLENBQUM7Z0JBQzlGLENBQUM7cUJBQU0sSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDO29CQUNuQyx5QkFBeUI7b0JBQ3pCLE9BQU8sQ0FBQyxLQUFLLENBQUMsWUFBWSxZQUFZLG9DQUFvQyxZQUFZLElBQUksQ0FBQyxDQUFDO2dCQUM5RixDQUFDO3FCQUFNLENBQUM7b0JBQ04sT0FBTyxDQUFDLElBQUksQ0FBQyx1QkFBdUIsUUFBUSxDQUFDLE1BQU0sK0JBQStCLENBQUMsQ0FBQztnQkFDdEYsQ0FBQztZQUNILENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNmLElBQUssS0FBZSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLElBQUssS0FBZSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztvQkFDbEcsTUFBTSxLQUFLLENBQUM7Z0JBQ2QsQ0FBQztnQkFDRCxPQUFPLENBQUMsSUFBSSxDQUFDLGdDQUFnQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ3hELENBQUM7WUFFRCxnQ0FBZ0M7WUFDaEMsTUFBTSxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxZQUFZLENBQUMsQ0FBQyxDQUFDO1lBQ2xFLFlBQVksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksR0FBRyxpQkFBaUIsRUFBRSxlQUFlLENBQUMsQ0FBQztRQUM3RSxDQUFDO0lBQ0gsQ0FBQztJQUVPLEtBQUssQ0FBQyxPQUFPO1FBQ25CLGlCQUFpQjtRQUNqQixJQUFJLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQzNCLGFBQWEsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUN4QyxDQUFDO1FBRUQseUJBQXlCO1FBQ3pCLE1BQU0sSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUM7UUFFbEMscUJBQXFCO1FBQ3JCLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ2xCLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNuQyxDQUFDO1FBQ0QsSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDbEIsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ25DLENBQUM7UUFFRCxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsSUFBSSxDQUFDLFFBQVEsVUFBVSxDQUFDLENBQUM7SUFDakQsQ0FBQztDQUNGO0FBNXNCRCx3QkE0c0JDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gV29ya2VyIC0gTm9kZS5qcyBpbXBsZW1lbnRhdGlvbiBmb3IgZXhlY3V0aW5nIHdvcmtmbG93cyBhbmQgYWN0aXZpdGllc1xuXG5pbXBvcnQgeyBLYWZrYSwgQ29uc3VtZXIsIFByb2R1Y2VyLCBTQVNMT3B0aW9ucywgbG9nTGV2ZWwgfSBmcm9tICdrYWZrYWpzJztcbmltcG9ydCB7IGdlbmVyYXRlQXV0aFRva2VuRnJvbUNyZWRlbnRpYWxzUHJvdmlkZXIgfSBmcm9tICdhd3MtbXNrLWlhbS1zYXNsLXNpZ25lci1qcyc7XG5pbXBvcnQgKiBhcyBvcyBmcm9tICdvcyc7XG5pbXBvcnQgdHlwZSB7XG4gIFdvcmtlckNvbmZpZyxcbiAgQWN0aXZpdHlIYW5kbGVyLFxuICBEZWNvcmF0ZWRBY3Rpdml0eSxcbiAgV29ya2Zsb3dDbGFzcyxcbiAgV29ya2Zsb3dUYXNrLFxuICBBY3Rpdml0eVRhc2ssXG4gIFdvcmtmbG93UmVzdWx0LFxuICBBY3Rpdml0eVJlc3VsdCxcbiAgV29ya2Zsb3dFcnJvcixcbiAgQWN0aXZpdHlFcnJvcixcbiAgS2Fma2FDb25maWcsXG4gIENvbm5lY3RSZXNwb25zZSxcbn0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBXb3JrZmxvd0NvbnRleHQsIHJ1bldpdGhDb250ZXh0LCBnZXRXb3JrZmxvd05hbWUsIGZpbmRSdW5NZXRob2QsIHR5cGUgV29ya2VySW50ZXJmYWNlIH0gZnJvbSAnLi93b3JrZmxvdyc7XG5pbXBvcnQgeyBnZXRBY3Rpdml0eU5hbWUgfSBmcm9tICcuL2FjdGl2aXR5JztcblxuLyoqXG4gKiBXb3JrZXIgdGhhdCBleGVjdXRlcyB3b3JrZmxvd3MgYW5kIGFjdGl2aXRpZXMuXG4gKiBcbiAqIFVzYWdlOlxuICogICBpbXBvcnQgeyBXb3JrZXIsIHdvcmtmbG93LCBhY3Rpdml0eSB9IGZyb20gJ0BpbnNwZWN0aWNhL3dvcmtmbG93LXNkayc7XG4gKiAgIFxuICogICBjb25zdCBzYXlIZWxsbyA9IGFjdGl2aXR5LmRlZm4oYXN5bmMgKGlucHV0OiB7IG5hbWU6IHN0cmluZyB9KSA9PiB7XG4gKiAgICAgcmV0dXJuIHsgbWVzc2FnZTogYEhlbGxvLCAke2lucHV0Lm5hbWV9IWAgfTtcbiAqICAgfSk7XG4gKiAgIFxuICogICBAd29ya2Zsb3cuZGVmblxuICogICBjbGFzcyBIZWxsb1dvcmxkV29ya2Zsb3cge1xuICogICAgIEB3b3JrZmxvdy5ydW5cbiAqICAgICBhc3luYyBydW4oaW5wdXQ6IHsgbmFtZTogc3RyaW5nIH0pIHtcbiAqICAgICAgIHJldHVybiBhd2FpdCB3b3JrZmxvdy5leGVjdXRlQWN0aXZpdHkoc2F5SGVsbG8sIGlucHV0KTtcbiAqICAgICB9XG4gKiAgIH1cbiAqICAgXG4gKiAgIGNvbnN0IHdvcmtlciA9IG5ldyBXb3JrZXIoe1xuICogICAgIHNlcnZlclVybDogJ2h0dHBzOi8vd29ya2Zsb3cuZXhhbXBsZS5jb20nLFxuICogICAgIGFwaUtleTogJ3drX2FiYzEyMy4uLicsXG4gKiAgIH0pO1xuICogICB3b3JrZXIucmVnaXN0ZXIoeyB3b3JrZmxvd3M6IFtIZWxsb1dvcmxkV29ya2Zsb3ddLCBhY3Rpdml0aWVzOiBbc2F5SGVsbG9dIH0pO1xuICogICBhd2FpdCB3b3JrZXIucnVuKCk7XG4gKi9cbmV4cG9ydCBjbGFzcyBXb3JrZXIgaW1wbGVtZW50cyBXb3JrZXJJbnRlcmZhY2Uge1xuICBwcml2YXRlIGNvbmZpZzogV29ya2VyQ29uZmlnO1xuICBwcml2YXRlIHdvcmtmbG93czogTWFwPHN0cmluZywgV29ya2Zsb3dDbGFzcz4gPSBuZXcgTWFwKCk7XG4gIHByaXZhdGUgYWN0aXZpdGllczogTWFwPHN0cmluZywgQWN0aXZpdHlIYW5kbGVyPiA9IG5ldyBNYXAoKTtcbiAgXG4gIHByaXZhdGUgd29ya2VySWQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGluc3RhbmNlSWQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHJ1bm5pbmcgPSBmYWxzZTtcbiAgcHJpdmF0ZSBrYWZrYTogS2Fma2EgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBjb25zdW1lcjogQ29uc3VtZXIgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBwcm9kdWNlcjogUHJvZHVjZXIgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBoZWFydGJlYXRJbnRlcnZhbDogTm9kZUpTLlRpbWVvdXQgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBoZWFydGJlYXRJbnRlcnZhbE1zID0gMzAwMDA7XG4gIHByaXZhdGUgcmVzdWx0VG9waWM6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIG1heENvbmN1cnJlbnRXb3JrZmxvd3M6IG51bWJlcjtcbiAgcHJpdmF0ZSBhY3RpdmVXb3JrZmxvd3MgPSAwO1xuXG4gIGNvbnN0cnVjdG9yKGNvbmZpZzogV29ya2VyQ29uZmlnKSB7XG4gICAgdGhpcy5jb25maWcgPSB7XG4gICAgICAuLi5jb25maWcsXG4gICAgICBzZXJ2ZXJVcmw6IGNvbmZpZy5zZXJ2ZXJVcmwucmVwbGFjZSgvXFwvJC8sICcnKSxcbiAgICB9O1xuICAgIHRoaXMubWF4Q29uY3VycmVudFdvcmtmbG93cyA9IGNvbmZpZy5tYXhDb25jdXJyZW50V29ya2Zsb3dzIHx8IDEwO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVyIHdvcmtmbG93cyBhbmQgYWN0aXZpdGllcy5cbiAgICovXG4gIHJlZ2lzdGVyKG9wdGlvbnM6IHtcbiAgICB3b3JrZmxvd3M/OiBXb3JrZmxvd0NsYXNzW107XG4gICAgYWN0aXZpdGllcz86IERlY29yYXRlZEFjdGl2aXR5W107XG4gIH0pOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IHdmQ2xzIG9mIG9wdGlvbnMud29ya2Zsb3dzIHx8IFtdKSB7XG4gICAgICBjb25zdCB3Zk5hbWUgPSBnZXRXb3JrZmxvd05hbWUod2ZDbHMpO1xuICAgICAgdGhpcy53b3JrZmxvd3Muc2V0KHdmTmFtZSwgd2ZDbHMpO1xuICAgICAgY29uc29sZS5sb2coYFJlZ2lzdGVyZWQgd29ya2Zsb3c6ICR7d2ZOYW1lfWApO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgYWN0aXZpdHlGbiBvZiBvcHRpb25zLmFjdGl2aXRpZXMgfHwgW10pIHtcbiAgICAgIGNvbnN0IGFjdGl2aXR5TmFtZSA9IGdldEFjdGl2aXR5TmFtZShhY3Rpdml0eUZuKTtcbiAgICAgIHRoaXMuYWN0aXZpdGllcy5zZXQoYWN0aXZpdHlOYW1lLCBhY3Rpdml0eUZuKTtcbiAgICAgIGNvbnNvbGUubG9nKGBSZWdpc3RlcmVkIGFjdGl2aXR5OiAke2FjdGl2aXR5TmFtZX1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU3RhcnQgdGhlIHdvcmtlciAoYmxvY2tpbmcpLlxuICAgKi9cbiAgYXN5bmMgcnVuKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMucnVubmluZyA9IHRydWU7XG5cbiAgICAvLyBTZXR1cCBzaWduYWwgaGFuZGxlcnNcbiAgICBwcm9jZXNzLm9uKCdTSUdJTlQnLCAoKSA9PiB0aGlzLnN0b3AoKSk7XG4gICAgcHJvY2Vzcy5vbignU0lHVEVSTScsICgpID0+IHRoaXMuc3RvcCgpKTtcblxuICAgIC8vIENvbm5lY3QgdG8gc2VydmVyIGFuZCBnZXQgS2Fma2EgY29uZmlnXG4gICAgY29uc3Qgc2VydmVyS2Fma2FDb25maWcgPSBhd2FpdCB0aGlzLmNvbm5lY3RUb1NlcnZlcigpO1xuICAgIGNvbnN0IHdvcmtlclRvcGljID0gc2VydmVyS2Fma2FDb25maWcud29ya2VyX3RvcGljO1xuICAgIGNvbnN0IHJlc3VsdFRvcGljID0gc2VydmVyS2Fma2FDb25maWcucmVzdWx0X3RvcGljO1xuICAgIHRoaXMucmVzdWx0VG9waWMgPSByZXN1bHRUb3BpYztcblxuICAgIC8vIENyZWF0ZSBLYWZrYSBjbGllbnRcbiAgICB0aGlzLmthZmthID0gdGhpcy5jcmVhdGVLYWZrYUNsaWVudChzZXJ2ZXJLYWZrYUNvbmZpZyk7XG4gICAgXG4gICAgLy8gQ3JlYXRlIGNvbnN1bWVyXG4gICAgY29uc3QgY29uc3VtZXJHcm91cElkID0gdGhpcy5jb25maWcuZ3JvdXBJZCB8fCBgd29ya2Zsb3ctd29ya2VyLSR7dGhpcy53b3JrZXJJZH1gO1xuICAgIHRoaXMuY29uc3VtZXIgPSB0aGlzLmthZmthLmNvbnN1bWVyKHsgZ3JvdXBJZDogY29uc3VtZXJHcm91cElkIH0pO1xuICAgIFxuICAgIC8vIENyZWF0ZSBwcm9kdWNlclxuICAgIHRoaXMucHJvZHVjZXIgPSB0aGlzLmthZmthLnByb2R1Y2VyKCk7XG5cbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5jb25zdW1lci5jb25uZWN0KCk7XG4gICAgICBhd2FpdCB0aGlzLnByb2R1Y2VyLmNvbm5lY3QoKTtcbiAgICAgIGF3YWl0IHRoaXMuY29uc3VtZXIuc3Vic2NyaWJlKHsgdG9waWM6IHdvcmtlclRvcGljLCBmcm9tQmVnaW5uaW5nOiBmYWxzZSB9KTtcblxuICAgICAgY29uc29sZS5sb2coYFdvcmtlciAke3RoaXMud29ya2VySWR9IHN0YXJ0ZWQsIGNvbnN1bWluZyBmcm9tICR7d29ya2VyVG9waWN9YCk7XG4gICAgICBjb25zb2xlLmxvZyhgTWF4IGNvbmN1cnJlbnQgd29ya2Zsb3dzOiAke3RoaXMubWF4Q29uY3VycmVudFdvcmtmbG93c31gKTtcbiAgICAgIGNvbnNvbGUubG9nKGBSZWdpc3RlcmVkIHdvcmtmbG93czogJHtBcnJheS5mcm9tKHRoaXMud29ya2Zsb3dzLmtleXMoKSkuam9pbignLCAnKX1gKTtcbiAgICAgIGNvbnNvbGUubG9nKGBSZWdpc3RlcmVkIGFjdGl2aXRpZXM6ICR7QXJyYXkuZnJvbSh0aGlzLmFjdGl2aXRpZXMua2V5cygpKS5qb2luKCcsICcpfWApO1xuXG4gICAgICAvLyBTdGFydCBoZWFydGJlYXRcbiAgICAgIHRoaXMuc3RhcnRIZWFydGJlYXQoKTtcblxuICAgICAgLy8gU3RhcnQgY29uc3VtaW5nIG1lc3NhZ2VzXG4gICAgICBhd2FpdCB0aGlzLmNvbnN1bWVyLnJ1bih7XG4gICAgICAgIGVhY2hNZXNzYWdlOiBhc3luYyAoeyBtZXNzYWdlIH0pID0+IHtcbiAgICAgICAgICBpZiAoIXRoaXMucnVubmluZykgcmV0dXJuO1xuICAgICAgICAgIFxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBkYXRhID0gSlNPTi5wYXJzZShtZXNzYWdlLnZhbHVlPy50b1N0cmluZygpIHx8ICd7fScpO1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5wcm9jZXNzTWVzc2FnZShkYXRhLCByZXN1bHRUb3BpYyk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIHByb2Nlc3NpbmcgbWVzc2FnZTonLCBlcnJvcik7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgfSk7XG5cbiAgICAgIC8vIEtlZXAgcnVubmluZyB1bnRpbCBzdG9wcGVkXG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4ge1xuICAgICAgICBjb25zdCBjaGVja0ludGVydmFsID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgICAgICAgIGlmICghdGhpcy5ydW5uaW5nKSB7XG4gICAgICAgICAgICBjbGVhckludGVydmFsKGNoZWNrSW50ZXJ2YWwpO1xuICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSwgMTAwKTtcbiAgICAgIH0pO1xuXG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGF3YWl0IHRoaXMuY2xlYW51cCgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTdG9wIHRoZSB3b3JrZXIgZ3JhY2VmdWxseS5cbiAgICovXG4gIGFzeW5jIHN0b3AoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc29sZS5sb2coJ1N0b3BwaW5nIHdvcmtlci4uLicpO1xuICAgIHRoaXMucnVubmluZyA9IGZhbHNlO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjb25uZWN0VG9TZXJ2ZXIoKTogUHJvbWlzZTxLYWZrYUNvbmZpZz4ge1xuICAgIGNvbnN0IGhvc3RuYW1lID0gb3MuaG9zdG5hbWUoKTtcbiAgICBcbiAgICBjb25zdCBjb25uZWN0UGF5bG9hZCA9IHtcbiAgICAgIHdvcmtmbG93czogQXJyYXkuZnJvbSh0aGlzLndvcmtmbG93cy5rZXlzKCkpLFxuICAgICAgYWN0aXZpdGllczogQXJyYXkuZnJvbSh0aGlzLmFjdGl2aXRpZXMua2V5cygpKSxcbiAgICAgIGhvc3RuYW1lLFxuICAgIH07XG5cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke3RoaXMuY29uZmlnLnNlcnZlclVybH0vd29ya2Zsb3cvYXBpL3YxL3dvcmtlcnMvY29ubmVjdGAsIHtcbiAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAnQXV0aG9yaXphdGlvbic6IGBCZWFyZXIgJHt0aGlzLmNvbmZpZy5hcGlLZXl9YCxcbiAgICAgIH0sXG4gICAgICBib2R5OiBKU09OLnN0cmluZ2lmeShjb25uZWN0UGF5bG9hZCksXG4gICAgfSk7XG5cbiAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICBjb25zdCBlcnJvciA9IGF3YWl0IHJlc3BvbnNlLnRleHQoKTtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIGNvbm5lY3QgdG8gc2VydmVyOiAke3Jlc3BvbnNlLnN0YXR1c30gLSAke2Vycm9yfWApO1xuICAgIH1cblxuICAgIGNvbnN0IGRhdGEgPSBhd2FpdCByZXNwb25zZS5qc29uKCkgYXMgQ29ubmVjdFJlc3BvbnNlO1xuICAgIFxuICAgIHRoaXMud29ya2VySWQgPSBkYXRhLndvcmtlcl9pZDtcbiAgICB0aGlzLmluc3RhbmNlSWQgPSBkYXRhLmluc3RhbmNlX2lkO1xuICAgIHRoaXMuaGVhcnRiZWF0SW50ZXJ2YWxNcyA9IGRhdGEuaGVhcnRiZWF0X2ludGVydmFsX21zIHx8IDMwMDAwO1xuXG4gICAgY29uc29sZS5sb2coYENvbm5lY3RlZCB0byBzZXJ2ZXIgYXMgd29ya2VyX2lkPSR7dGhpcy53b3JrZXJJZH0sIGluc3RhbmNlX2lkPSR7dGhpcy5pbnN0YW5jZUlkfWApO1xuXG4gICAgcmV0dXJuIGRhdGEua2Fma2E7XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZUthZmthQ2xpZW50KGthZmthQ29uZmlnOiBLYWZrYUNvbmZpZyk6IEthZmthIHtcbiAgICBjb25zdCBhdXRoID0ga2Fma2FDb25maWcuYXV0aDtcbiAgICBcbiAgICAvLyBTZXJ2ZXIgcmV0dXJucyBicm9rZXJzIGFzIGNvbW1hLXNlcGFyYXRlZCBzdHJpbmcsIGNvbnZlcnQgdG8gYXJyYXlcbiAgICBjb25zdCBicm9rZXJzID0gdHlwZW9mIGthZmthQ29uZmlnLmJyb2tlcnMgPT09ICdzdHJpbmcnXG4gICAgICA/IChrYWZrYUNvbmZpZy5icm9rZXJzIGFzIHN0cmluZykuc3BsaXQoJywnKS5tYXAoYiA9PiBiLnRyaW0oKSkuZmlsdGVyKGIgPT4gYilcbiAgICAgIDoga2Fma2FDb25maWcuYnJva2VycztcbiAgICBcbiAgICBjb25zdCBjb25maWc6IGFueSA9IHtcbiAgICAgIGNsaWVudElkOiBgd29ya2Zsb3ctd29ya2VyLSR7dGhpcy53b3JrZXJJZH1gLFxuICAgICAgYnJva2VycyxcbiAgICAgIGxvZ0xldmVsOiBsb2dMZXZlbC5XQVJOLFxuICAgIH07XG5cbiAgICBpZiAoYXV0aD8udHlwZSA9PT0gJ21za19pYW0nKSB7XG4gICAgICBjb25maWcuc3NsID0gdHJ1ZTtcbiAgICAgIGNvbmZpZy5zYXNsID0ge1xuICAgICAgICBtZWNoYW5pc206ICdvYXV0aGJlYXJlcicsXG4gICAgICAgIG9hdXRoQmVhcmVyUHJvdmlkZXI6IGFzeW5jICgpID0+IHtcbiAgICAgICAgICBjb25zdCB0b2tlbiA9IGF3YWl0IGdlbmVyYXRlQXV0aFRva2VuRnJvbUNyZWRlbnRpYWxzUHJvdmlkZXIoe1xuICAgICAgICAgICAgcmVnaW9uOiBhdXRoLnJlZ2lvbiEsXG4gICAgICAgICAgICBhd3NDcmVkZW50aWFsc1Byb3ZpZGVyOiBhc3luYyAoKSA9PiAoe1xuICAgICAgICAgICAgICBhY2Nlc3NLZXlJZDogYXV0aC5hY2Nlc3Nfa2V5X2lkISxcbiAgICAgICAgICAgICAgc2VjcmV0QWNjZXNzS2V5OiBhdXRoLnNlY3JldF9hY2Nlc3Nfa2V5ISxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHJldHVybiB7IHZhbHVlOiB0b2tlbi50b2tlbiB9O1xuICAgICAgICB9LFxuICAgICAgfSBhcyBTQVNMT3B0aW9ucztcbiAgICB9IGVsc2UgaWYgKGF1dGg/LnR5cGUgPT09ICdzYXNsJykge1xuICAgICAgaWYgKGF1dGguc2VjdXJpdHlfcHJvdG9jb2w/LmluY2x1ZGVzKCdTU0wnKSkge1xuICAgICAgICBjb25maWcuc3NsID0gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIGlmIChhdXRoLnNhc2xfbWVjaGFuaXNtICYmIGF1dGguc2FzbF91c2VybmFtZSAmJiBhdXRoLnNhc2xfcGFzc3dvcmQpIHtcbiAgICAgICAgY29uZmlnLnNhc2wgPSB7XG4gICAgICAgICAgbWVjaGFuaXNtOiBhdXRoLnNhc2xfbWVjaGFuaXNtLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgnLScsICcnKSxcbiAgICAgICAgICB1c2VybmFtZTogYXV0aC5zYXNsX3VzZXJuYW1lLFxuICAgICAgICAgIHBhc3N3b3JkOiBhdXRoLnNhc2xfcGFzc3dvcmQsXG4gICAgICAgIH0gYXMgU0FTTE9wdGlvbnM7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBLYWZrYShjb25maWcpO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGFydEhlYXJ0YmVhdCgpOiB2b2lkIHtcbiAgICB0aGlzLmhlYXJ0YmVhdEludGVydmFsID0gc2V0SW50ZXJ2YWwoYXN5bmMgKCkgPT4ge1xuICAgICAgaWYgKCF0aGlzLnJ1bm5pbmcpIHJldHVybjtcbiAgICAgIFxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHt0aGlzLmNvbmZpZy5zZXJ2ZXJVcmx9L3dvcmtmbG93L2FwaS92MS93b3JrZXJzL2hlYXJ0YmVhdGAsIHtcbiAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiBgQmVhcmVyICR7dGhpcy5jb25maWcuYXBpS2V5fWAsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7IGluc3RhbmNlX2lkOiB0aGlzLmluc3RhbmNlSWQgfSksXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgICAgICBjb25zb2xlLndhcm4oYEhlYXJ0YmVhdCBmYWlsZWQ6ICR7cmVzcG9uc2Uuc3RhdHVzfWApO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zb2xlLndhcm4oJ0hlYXJ0YmVhdCBlcnJvcjonLCBlcnJvcik7XG4gICAgICB9XG4gICAgfSwgdGhpcy5oZWFydGJlYXRJbnRlcnZhbE1zKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZGlzY29ubmVjdEZyb21TZXJ2ZXIoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKCF0aGlzLmluc3RhbmNlSWQpIHJldHVybjtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke3RoaXMuY29uZmlnLnNlcnZlclVybH0vd29ya2Zsb3cvYXBpL3YxL3dvcmtlcnMvZGlzY29ubmVjdGAsIHtcbiAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICdBdXRob3JpemF0aW9uJzogYEJlYXJlciAke3RoaXMuY29uZmlnLmFwaUtleX1gLFxuICAgICAgICB9LFxuICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7IGluc3RhbmNlX2lkOiB0aGlzLmluc3RhbmNlSWQgfSksXG4gICAgICB9KTtcblxuICAgICAgaWYgKHJlc3BvbnNlLm9rKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdEaXNjb25uZWN0ZWQgZnJvbSBzZXJ2ZXInKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS53YXJuKCdGYWlsZWQgdG8gZGlzY29ubmVjdCBmcm9tIHNlcnZlcjonLCBlcnJvcik7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBwcm9jZXNzTWVzc2FnZShkYXRhOiBhbnksIHJlc3VsdFRvcGljOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAvLyBDaGVjayBpZiB0aGlzIGlzIGFuIGFjdGl2aXR5IHJlc3VsdCAocmVzcG9uc2UgZnJvbSBhbm90aGVyIHdvcmtlciB2aWEgc2VydmVyKVxuICAgIGlmIChkYXRhLnN0YXR1cyAmJiBkYXRhLmNvbXBsZXRlZF9hdCAmJiAhZGF0YS50YXNrX3R5cGUpIHtcbiAgICAgIGNvbnNvbGUuZGVidWcoJ1JlY2VpdmVkIGFjdGl2aXR5IHJlc3VsdCBvbiB3b3JrZXIgdG9waWMgKGlnbm9yZWQgLSB1c2luZyBwb2xsaW5nKScpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHRhc2tUeXBlID0gZGF0YS50YXNrX3R5cGUgfHwgJ2FjdGl2aXR5JztcblxuICAgIGlmICh0YXNrVHlwZSA9PT0gJ3dvcmtmbG93Jykge1xuICAgICAgLy8gUHJvY2VzcyB3b3JrZmxvdyBpbiBiYWNrZ3JvdW5kIChkb24ndCBibG9jayBtZXNzYWdlIGxvb3ApXG4gICAgICB0aGlzLnByb2Nlc3NXb3JrZmxvd1Rhc2soZGF0YSwgcmVzdWx0VG9waWMpLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBwcm9jZXNzaW5nIHdvcmtmbG93IHRhc2s6JywgZXJyb3IpO1xuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIEFjdGl2aXR5IHRhc2tzIGNhbiBiZSBwcm9jZXNzZWQgaW5saW5lXG4gICAgICBhd2FpdCB0aGlzLnByb2Nlc3NBY3Rpdml0eVRhc2soZGF0YSwgcmVzdWx0VG9waWMpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcHJvY2Vzc1dvcmtmbG93VGFzayhkYXRhOiBXb3JrZmxvd1Rhc2ssIHJlc3VsdFRvcGljOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAvLyBDaGVjayBjb25jdXJyZW5jeSBsaW1pdFxuICAgIHdoaWxlICh0aGlzLmFjdGl2ZVdvcmtmbG93cyA+PSB0aGlzLm1heENvbmN1cnJlbnRXb3JrZmxvd3MpIHtcbiAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIDEwMCkpO1xuICAgIH1cbiAgICB0aGlzLmFjdGl2ZVdvcmtmbG93cysrO1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuZXhlY3V0ZVdvcmtmbG93KGRhdGEsIHJlc3VsdFRvcGljKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5hY3RpdmVXb3JrZmxvd3MtLTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGV4ZWN1dGVXb3JrZmxvdyh0YXNrOiBXb3JrZmxvd1Rhc2ssIHJlc3VsdFRvcGljOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zb2xlLmxvZyhgUmVjZWl2ZWQgd29ya2Zsb3cgdGFzayAke3Rhc2sudGFza19pZH06ICR7dGFzay53b3JrZmxvd19uYW1lfWApO1xuXG4gICAgLy8gRmluZCB0aGUgd29ya2Zsb3cgY2xhc3NcbiAgICBjb25zdCB3b3JrZmxvd0NscyA9IHRoaXMud29ya2Zsb3dzLmdldCh0YXNrLndvcmtmbG93X25hbWUpO1xuICAgIGlmICghd29ya2Zsb3dDbHMpIHtcbiAgICAgIGNvbnNvbGUud2FybihgVW5rbm93biB3b3JrZmxvdzogJHt0YXNrLndvcmtmbG93X25hbWV9YCk7XG4gICAgICBhd2FpdCB0aGlzLnNlbmRXb3JrZmxvd1Jlc3VsdCh0YXNrLCByZXN1bHRUb3BpYywgJ2ZhaWxlZCcsIHVuZGVmaW5lZCwge1xuICAgICAgICB0eXBlOiAnVW5rbm93bldvcmtmbG93JyxcbiAgICAgICAgbWVzc2FnZTogYFdvcmtmbG93ICcke3Rhc2sud29ya2Zsb3dfbmFtZX0nIG5vdCByZWdpc3RlcmVkYCxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIEZpbmQgdGhlIHJ1biBtZXRob2RcbiAgICBjb25zdCBydW5NZXRob2QgPSBmaW5kUnVuTWV0aG9kKHdvcmtmbG93Q2xzKTtcbiAgICBpZiAoIXJ1bk1ldGhvZCkge1xuICAgICAgYXdhaXQgdGhpcy5zZW5kV29ya2Zsb3dSZXN1bHQodGFzaywgcmVzdWx0VG9waWMsICdmYWlsZWQnLCB1bmRlZmluZWQsIHtcbiAgICAgICAgdHlwZTogJ05vUnVuTWV0aG9kJyxcbiAgICAgICAgbWVzc2FnZTogYFdvcmtmbG93ICcke3Rhc2sud29ya2Zsb3dfbmFtZX0nIGhhcyBubyBydW4gbWV0aG9kYCxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIEV4ZWN1dGUgdGhlIHdvcmtmbG93XG4gICAgY29uc3Qgc3RhcnRlZEF0ID0gbmV3IERhdGUoKTtcbiAgICB0cnkge1xuICAgICAgLy8gQnVpbGQgY29tcGxldGVkIGFjdGl2aXRpZXMgbWFwIGZvciByZXBsYXlcbiAgICAgIGNvbnN0IGNvbXBsZXRlZEFjdGl2aXRpZXNNYXAgPSBuZXcgTWFwPG51bWJlciwgdW5rbm93bj4oKTtcbiAgICAgIGlmICh0YXNrLmNvbXBsZXRlZF9hY3Rpdml0aWVzKSB7XG4gICAgICAgIGZvciAoY29uc3QgY2Egb2YgdGFzay5jb21wbGV0ZWRfYWN0aXZpdGllcykge1xuICAgICAgICAgIGNvbXBsZXRlZEFjdGl2aXRpZXNNYXAuc2V0KGNhLmluZGV4LCBjYS5vdXRwdXQpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgIGBSZXN1bWluZyB3b3JrZmxvdyAke3Rhc2sud29ya2Zsb3dfaWR9IHdpdGggJHtjb21wbGV0ZWRBY3Rpdml0aWVzTWFwLnNpemV9IGNvbXBsZXRlZCBhY3Rpdml0aWVzYFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBDcmVhdGUgd29ya2Zsb3cgY29udGV4dFxuICAgICAgY29uc3QgY3R4ID0gbmV3IFdvcmtmbG93Q29udGV4dChcbiAgICAgICAgdGhpcy5hY3Rpdml0aWVzLFxuICAgICAgICB0YXNrLndvcmtmbG93X2lkLFxuICAgICAgICB0aGlzLFxuICAgICAgICBjb21wbGV0ZWRBY3Rpdml0aWVzTWFwLnNpemUgPiAwID8gY29tcGxldGVkQWN0aXZpdGllc01hcCA6IG51bGwsXG4gICAgICAgIHRhc2subWV0YWRhdGFcbiAgICAgICk7XG5cbiAgICAgIC8vIEV4ZWN1dGUgd2l0aGluIGNvbnRleHRcbiAgICAgIGNvbnN0IG91dHB1dCA9IGF3YWl0IHJ1bldpdGhDb250ZXh0KGN0eCwgYXN5bmMgKCkgPT4ge1xuICAgICAgICByZXR1cm4gYXdhaXQgUHJvbWlzZS5yYWNlKFtcbiAgICAgICAgICBydW5NZXRob2QodGFzay5pbnB1dCksXG4gICAgICAgICAgbmV3IFByb21pc2U8bmV2ZXI+KChfLCByZWplY3QpID0+XG4gICAgICAgICAgICBzZXRUaW1lb3V0KFxuICAgICAgICAgICAgICAoKSA9PiByZWplY3QobmV3IEVycm9yKGBXb3JrZmxvdyB0aW1lZCBvdXQgYWZ0ZXIgJHt0YXNrLnRpbWVvdXRfbXN9bXNgKSksXG4gICAgICAgICAgICAgIHRhc2sudGltZW91dF9tc1xuICAgICAgICAgICAgKVxuICAgICAgICAgICksXG4gICAgICAgIF0pO1xuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IGNvbXBsZXRlZEF0ID0gbmV3IERhdGUoKTtcbiAgICAgIGNvbnN0IGR1cmF0aW9uTXMgPSBjb21wbGV0ZWRBdC5nZXRUaW1lKCkgLSBzdGFydGVkQXQuZ2V0VGltZSgpO1xuXG4gICAgICBjb25zb2xlLmxvZyhgV29ya2Zsb3cgJHt0YXNrLnRhc2tfaWR9IGNvbXBsZXRlZCBpbiAke2R1cmF0aW9uTXN9bXNgKTtcblxuICAgICAgYXdhaXQgdGhpcy5zZW5kV29ya2Zsb3dSZXN1bHQoXG4gICAgICAgIHRhc2ssXG4gICAgICAgIHJlc3VsdFRvcGljLFxuICAgICAgICAnY29tcGxldGVkJyxcbiAgICAgICAgb3V0cHV0LFxuICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgIHN0YXJ0ZWRBdCxcbiAgICAgICAgY29tcGxldGVkQXQsXG4gICAgICAgIGR1cmF0aW9uTXNcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnN0IGNvbXBsZXRlZEF0ID0gbmV3IERhdGUoKTtcbiAgICAgIGNvbnN0IGR1cmF0aW9uTXMgPSBjb21wbGV0ZWRBdC5nZXRUaW1lKCkgLSBzdGFydGVkQXQuZ2V0VGltZSgpO1xuICAgICAgY29uc3QgZXJyID0gZXJyb3IgYXMgRXJyb3I7XG5cbiAgICAgIGNvbnNvbGUuZXJyb3IoYFdvcmtmbG93ICR7dGFzay50YXNrX2lkfSBmYWlsZWQ6YCwgZXJyLm1lc3NhZ2UpO1xuXG4gICAgICBhd2FpdCB0aGlzLnNlbmRXb3JrZmxvd1Jlc3VsdChcbiAgICAgICAgdGFzayxcbiAgICAgICAgcmVzdWx0VG9waWMsXG4gICAgICAgICdmYWlsZWQnLFxuICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgIHtcbiAgICAgICAgICB0eXBlOiBlcnIubmFtZSB8fCAnRXJyb3InLFxuICAgICAgICAgIG1lc3NhZ2U6IGVyci5tZXNzYWdlLFxuICAgICAgICAgIHN0YWNrX3RyYWNlOiBlcnIuc3RhY2ssXG4gICAgICAgIH0sXG4gICAgICAgIHN0YXJ0ZWRBdCxcbiAgICAgICAgY29tcGxldGVkQXQsXG4gICAgICAgIGR1cmF0aW9uTXNcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBwcm9jZXNzQWN0aXZpdHlUYXNrKGRhdGE6IEFjdGl2aXR5VGFzaywgcmVzdWx0VG9waWM6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHRhc2sgPSBkYXRhO1xuICAgIGNvbnNvbGUubG9nKFxuICAgICAgYFJlY2VpdmVkIGFjdGl2aXR5IHRhc2sgJHt0YXNrLnRhc2tfaWR9OiAke3Rhc2suYWN0aXZpdHlfbmFtZX0gKHdvcmtmbG93PSR7dGFzay53b3JrZmxvd19pZH0pYFxuICAgICk7XG5cbiAgICAvLyBGaW5kIHRoZSBhY3Rpdml0eSBoYW5kbGVyXG4gICAgY29uc3QgYWN0aXZpdHlGbiA9IHRoaXMuYWN0aXZpdGllcy5nZXQodGFzay5hY3Rpdml0eV9uYW1lKTtcbiAgICBpZiAoIWFjdGl2aXR5Rm4pIHtcbiAgICAgIGNvbnNvbGUud2FybihgVW5rbm93biBhY3Rpdml0eTogJHt0YXNrLmFjdGl2aXR5X25hbWV9YCk7XG4gICAgICBhd2FpdCB0aGlzLnNlbmRBY3Rpdml0eVJlc3VsdCh0YXNrLCByZXN1bHRUb3BpYywgJ2ZhaWxlZCcsIHVuZGVmaW5lZCwge1xuICAgICAgICB0eXBlOiAnVW5rbm93bkFjdGl2aXR5JyxcbiAgICAgICAgbWVzc2FnZTogYEFjdGl2aXR5ICcke3Rhc2suYWN0aXZpdHlfbmFtZX0nIG5vdCByZWdpc3RlcmVkYCxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIEV4ZWN1dGUgdGhlIGFjdGl2aXR5XG4gICAgY29uc3Qgc3RhcnRlZEF0ID0gbmV3IERhdGUoKTtcbiAgICB0cnkge1xuICAgICAgY29uc3Qgb3V0cHV0ID0gYXdhaXQgUHJvbWlzZS5yYWNlKFtcbiAgICAgICAgUHJvbWlzZS5yZXNvbHZlKGFjdGl2aXR5Rm4odGFzay5pbnB1dCkpLFxuICAgICAgICBuZXcgUHJvbWlzZTxuZXZlcj4oKF8sIHJlamVjdCkgPT5cbiAgICAgICAgICBzZXRUaW1lb3V0KFxuICAgICAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFcnJvcihgQWN0aXZpdHkgdGltZWQgb3V0IGFmdGVyICR7dGFzay50aW1lb3V0X21zfW1zYCkpLFxuICAgICAgICAgICAgdGFzay50aW1lb3V0X21zXG4gICAgICAgICAgKVxuICAgICAgICApLFxuICAgICAgXSk7XG5cbiAgICAgIGNvbnN0IGNvbXBsZXRlZEF0ID0gbmV3IERhdGUoKTtcbiAgICAgIGNvbnN0IGR1cmF0aW9uTXMgPSBjb21wbGV0ZWRBdC5nZXRUaW1lKCkgLSBzdGFydGVkQXQuZ2V0VGltZSgpO1xuXG4gICAgICBjb25zb2xlLmxvZyhgQWN0aXZpdHkgJHt0YXNrLnRhc2tfaWR9IGNvbXBsZXRlZCBpbiAke2R1cmF0aW9uTXN9bXNgKTtcblxuICAgICAgYXdhaXQgdGhpcy5zZW5kQWN0aXZpdHlSZXN1bHQoXG4gICAgICAgIHRhc2ssXG4gICAgICAgIHJlc3VsdFRvcGljLFxuICAgICAgICAnY29tcGxldGVkJyxcbiAgICAgICAgb3V0cHV0LFxuICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgIHN0YXJ0ZWRBdCxcbiAgICAgICAgY29tcGxldGVkQXQsXG4gICAgICAgIGR1cmF0aW9uTXNcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnN0IGNvbXBsZXRlZEF0ID0gbmV3IERhdGUoKTtcbiAgICAgIGNvbnN0IGR1cmF0aW9uTXMgPSBjb21wbGV0ZWRBdC5nZXRUaW1lKCkgLSBzdGFydGVkQXQuZ2V0VGltZSgpO1xuICAgICAgY29uc3QgZXJyID0gZXJyb3IgYXMgRXJyb3I7XG5cbiAgICAgIGNvbnNvbGUuZXJyb3IoYEFjdGl2aXR5ICR7dGFzay50YXNrX2lkfSBmYWlsZWQ6YCwgZXJyLm1lc3NhZ2UpO1xuXG4gICAgICBhd2FpdCB0aGlzLnNlbmRBY3Rpdml0eVJlc3VsdChcbiAgICAgICAgdGFzayxcbiAgICAgICAgcmVzdWx0VG9waWMsXG4gICAgICAgICdmYWlsZWQnLFxuICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgIHtcbiAgICAgICAgICB0eXBlOiBlcnIubmFtZSB8fCAnRXJyb3InLFxuICAgICAgICAgIG1lc3NhZ2U6IGVyci5tZXNzYWdlLFxuICAgICAgICAgIHN0YWNrX3RyYWNlOiBlcnIuc3RhY2ssXG4gICAgICAgIH0sXG4gICAgICAgIHN0YXJ0ZWRBdCxcbiAgICAgICAgY29tcGxldGVkQXQsXG4gICAgICAgIGR1cmF0aW9uTXNcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBzZW5kV29ya2Zsb3dSZXN1bHQoXG4gICAgdGFzazogV29ya2Zsb3dUYXNrLFxuICAgIHJlc3VsdFRvcGljOiBzdHJpbmcsXG4gICAgc3RhdHVzOiAnY29tcGxldGVkJyB8ICdmYWlsZWQnLFxuICAgIG91dHB1dD86IHVua25vd24sXG4gICAgZXJyb3I/OiBXb3JrZmxvd0Vycm9yLFxuICAgIHN0YXJ0ZWRBdD86IERhdGUsXG4gICAgY29tcGxldGVkQXQ/OiBEYXRlLFxuICAgIGR1cmF0aW9uTXMgPSAwXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IG5vdyA9IG5ldyBEYXRlKCk7XG4gICAgY29uc3QgcmVzdWx0OiBXb3JrZmxvd1Jlc3VsdCA9IHtcbiAgICAgIHRhc2tfaWQ6IHRhc2sudGFza19pZCxcbiAgICAgIHdvcmtmbG93X2lkOiB0YXNrLndvcmtmbG93X2lkLFxuICAgICAgd29ya2Zsb3dfbmFtZTogdGFzay53b3JrZmxvd19uYW1lLFxuICAgICAgc3RhdHVzLFxuICAgICAgb3V0cHV0LFxuICAgICAgZXJyb3IsXG4gICAgICBzdGFydGVkX2F0OiAoc3RhcnRlZEF0IHx8IG5vdykudG9JU09TdHJpbmcoKSxcbiAgICAgIGNvbXBsZXRlZF9hdDogKGNvbXBsZXRlZEF0IHx8IG5vdykudG9JU09TdHJpbmcoKSxcbiAgICAgIGR1cmF0aW9uX21zOiBkdXJhdGlvbk1zLFxuICAgICAgd29ya2VyX2lkOiB0aGlzLndvcmtlcklkISxcbiAgICB9O1xuXG4gICAgaWYgKHRoaXMucHJvZHVjZXIpIHtcbiAgICAgIGF3YWl0IHRoaXMucHJvZHVjZXIuc2VuZCh7XG4gICAgICAgIHRvcGljOiByZXN1bHRUb3BpYyxcbiAgICAgICAgbWVzc2FnZXM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBrZXk6IHRhc2sud29ya2Zsb3dfaWQsXG4gICAgICAgICAgICB2YWx1ZTogSlNPTi5zdHJpbmdpZnkocmVzdWx0KSxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgfSk7XG4gICAgICBjb25zb2xlLmRlYnVnKGBTZW50IHdvcmtmbG93IHJlc3VsdCBmb3IgdGFzayAke3Rhc2sudGFza19pZH1gKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHNlbmRBY3Rpdml0eVJlc3VsdChcbiAgICB0YXNrOiBBY3Rpdml0eVRhc2ssXG4gICAgcmVzdWx0VG9waWM6IHN0cmluZyxcbiAgICBzdGF0dXM6ICdjb21wbGV0ZWQnIHwgJ2ZhaWxlZCcsXG4gICAgb3V0cHV0PzogdW5rbm93bixcbiAgICBlcnJvcj86IEFjdGl2aXR5RXJyb3IsXG4gICAgc3RhcnRlZEF0PzogRGF0ZSxcbiAgICBjb21wbGV0ZWRBdD86IERhdGUsXG4gICAgZHVyYXRpb25NcyA9IDBcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3Qgbm93ID0gbmV3IERhdGUoKTtcbiAgICBjb25zdCByZXN1bHQ6IEFjdGl2aXR5UmVzdWx0ID0ge1xuICAgICAgdGFza19pZDogdGFzay50YXNrX2lkLFxuICAgICAgd29ya2Zsb3dfaWQ6IHRhc2sud29ya2Zsb3dfaWQsXG4gICAgICBhY3Rpdml0eV9uYW1lOiB0YXNrLmFjdGl2aXR5X25hbWUsXG4gICAgICBhY3Rpdml0eV9pbmRleDogdGFzay5hY3Rpdml0eV9pbmRleCxcbiAgICAgIGZhbl9vdXRfaW5kZXg6IHRhc2suZmFuX291dF9pbmRleCxcbiAgICAgIHN0YXR1cyxcbiAgICAgIG91dHB1dCxcbiAgICAgIGVycm9yLFxuICAgICAgc3RhcnRlZF9hdDogKHN0YXJ0ZWRBdCB8fCBub3cpLnRvSVNPU3RyaW5nKCksXG4gICAgICBjb21wbGV0ZWRfYXQ6IChjb21wbGV0ZWRBdCB8fCBub3cpLnRvSVNPU3RyaW5nKCksXG4gICAgICBkdXJhdGlvbl9tczogZHVyYXRpb25NcyxcbiAgICAgIHdvcmtlcl9pZDogdGhpcy53b3JrZXJJZCEsXG4gICAgICByZXF1ZXN0ZXJfd29ya2VyX2lkOiB0YXNrLnJlcXVlc3Rlcl93b3JrZXJfaWQsXG4gICAgICBjb3JyZWxhdGlvbl9pZDogdGFzay5jb3JyZWxhdGlvbl9pZCxcbiAgICB9O1xuXG4gICAgaWYgKHRoaXMucHJvZHVjZXIpIHtcbiAgICAgIGF3YWl0IHRoaXMucHJvZHVjZXIuc2VuZCh7XG4gICAgICAgIHRvcGljOiByZXN1bHRUb3BpYyxcbiAgICAgICAgbWVzc2FnZXM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBrZXk6IHRhc2sud29ya2Zsb3dfaWQsXG4gICAgICAgICAgICB2YWx1ZTogSlNPTi5zdHJpbmdpZnkocmVzdWx0KSxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgfSk7XG4gICAgICBjb25zb2xlLmRlYnVnKGBTZW50IGFjdGl2aXR5IHJlc3VsdCBmb3IgdGFzayAke3Rhc2sudGFza19pZH1gKTtcbiAgICB9XG4gIH1cblxuICAvLyBXb3JrZXJJbnRlcmZhY2UgaW1wbGVtZW50YXRpb24gZm9yIFdvcmtmbG93Q29udGV4dFxuXG4gIGFzeW5jIHJlcG9ydExvY2FsQWN0aXZpdHlDb21wbGV0aW9uKFxuICAgIHdvcmtmbG93SWQ6IHN0cmluZyxcbiAgICBhY3Rpdml0eU5hbWU6IHN0cmluZyxcbiAgICBhY3Rpdml0eUluZGV4OiBudW1iZXIsXG4gICAgb3V0cHV0OiB1bmtub3duLFxuICAgIGR1cmF0aW9uTXM6IG51bWJlclxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMucHJvZHVjZXIgfHwgIXRoaXMucmVzdWx0VG9waWMpIHtcbiAgICAgIGNvbnNvbGUuZGVidWcoJ0Nhbm5vdCByZXBvcnQgbG9jYWwgYWN0aXZpdHkgLSBwcm9kdWNlciBub3QgaW5pdGlhbGl6ZWQnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBjb21wbGV0ZWRBdCA9IG5ldyBEYXRlKCk7XG4gICAgY29uc3Qgc3RhcnRlZEF0ID0gbmV3IERhdGUoY29tcGxldGVkQXQuZ2V0VGltZSgpIC0gZHVyYXRpb25Ncyk7XG5cbiAgICBjb25zdCByZXN1bHQgPSB7XG4gICAgICB0YXNrX2lkOiBgbG9jYWwtJHt3b3JrZmxvd0lkfS0ke2FjdGl2aXR5SW5kZXh9YCxcbiAgICAgIHdvcmtmbG93X2lkOiB3b3JrZmxvd0lkLFxuICAgICAgYWN0aXZpdHlfbmFtZTogYWN0aXZpdHlOYW1lLFxuICAgICAgYWN0aXZpdHlfaW5kZXg6IGFjdGl2aXR5SW5kZXgsXG4gICAgICBzdGF0dXM6ICdjb21wbGV0ZWQnLFxuICAgICAgb3V0cHV0LFxuICAgICAgc3RhcnRlZF9hdDogc3RhcnRlZEF0LnRvSVNPU3RyaW5nKCksXG4gICAgICBjb21wbGV0ZWRfYXQ6IGNvbXBsZXRlZEF0LnRvSVNPU3RyaW5nKCksXG4gICAgICBkdXJhdGlvbl9tczogZHVyYXRpb25NcyxcbiAgICAgIHdvcmtlcl9pZDogdGhpcy53b3JrZXJJZCxcbiAgICB9O1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMucHJvZHVjZXIuc2VuZCh7XG4gICAgICAgIHRvcGljOiB0aGlzLnJlc3VsdFRvcGljLFxuICAgICAgICBtZXNzYWdlczogW3sga2V5OiB3b3JrZmxvd0lkLCB2YWx1ZTogSlNPTi5zdHJpbmdpZnkocmVzdWx0KSB9XSxcbiAgICAgIH0pO1xuICAgICAgY29uc29sZS5kZWJ1ZyhcbiAgICAgICAgYFJlcG9ydGVkIGxvY2FsIGFjdGl2aXR5IGNvbXBsZXRpb246IHdvcmtmbG93X2lkPSR7d29ya2Zsb3dJZH0sIGFjdGl2aXR5PSR7YWN0aXZpdHlOYW1lfSwgaW5kZXg9JHthY3Rpdml0eUluZGV4fWBcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUud2FybignRmFpbGVkIHRvIHJlcG9ydCBsb2NhbCBhY3Rpdml0eSBjb21wbGV0aW9uOicsIGVycm9yKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyByZXBvcnRMb2NhbEFjdGl2aXR5RmFpbHVyZShcbiAgICB3b3JrZmxvd0lkOiBzdHJpbmcsXG4gICAgYWN0aXZpdHlOYW1lOiBzdHJpbmcsXG4gICAgYWN0aXZpdHlJbmRleDogbnVtYmVyLFxuICAgIGVycm9yOiBzdHJpbmcsXG4gICAgZXJyb3JUeXBlOiBzdHJpbmcsXG4gICAgZHVyYXRpb25NczogbnVtYmVyXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICghdGhpcy5wcm9kdWNlciB8fCAhdGhpcy5yZXN1bHRUb3BpYykge1xuICAgICAgY29uc29sZS5kZWJ1ZygnQ2Fubm90IHJlcG9ydCBsb2NhbCBhY3Rpdml0eSBmYWlsdXJlIC0gcHJvZHVjZXIgbm90IGluaXRpYWxpemVkJyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgY29tcGxldGVkQXQgPSBuZXcgRGF0ZSgpO1xuICAgIGNvbnN0IHN0YXJ0ZWRBdCA9IG5ldyBEYXRlKGNvbXBsZXRlZEF0LmdldFRpbWUoKSAtIGR1cmF0aW9uTXMpO1xuXG4gICAgY29uc3QgcmVzdWx0ID0ge1xuICAgICAgdGFza19pZDogYGxvY2FsLSR7d29ya2Zsb3dJZH0tJHthY3Rpdml0eUluZGV4fWAsXG4gICAgICB3b3JrZmxvd19pZDogd29ya2Zsb3dJZCxcbiAgICAgIGFjdGl2aXR5X25hbWU6IGFjdGl2aXR5TmFtZSxcbiAgICAgIGFjdGl2aXR5X2luZGV4OiBhY3Rpdml0eUluZGV4LFxuICAgICAgc3RhdHVzOiAnZmFpbGVkJyxcbiAgICAgIG91dHB1dDogbnVsbCxcbiAgICAgIGVycm9yOiB7IHR5cGU6IGVycm9yVHlwZSwgbWVzc2FnZTogZXJyb3IgfSxcbiAgICAgIHN0YXJ0ZWRfYXQ6IHN0YXJ0ZWRBdC50b0lTT1N0cmluZygpLFxuICAgICAgY29tcGxldGVkX2F0OiBjb21wbGV0ZWRBdC50b0lTT1N0cmluZygpLFxuICAgICAgZHVyYXRpb25fbXM6IGR1cmF0aW9uTXMsXG4gICAgICB3b3JrZXJfaWQ6IHRoaXMud29ya2VySWQsXG4gICAgfTtcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLnByb2R1Y2VyLnNlbmQoe1xuICAgICAgICB0b3BpYzogdGhpcy5yZXN1bHRUb3BpYyxcbiAgICAgICAgbWVzc2FnZXM6IFt7IGtleTogd29ya2Zsb3dJZCwgdmFsdWU6IEpTT04uc3RyaW5naWZ5KHJlc3VsdCkgfV0sXG4gICAgICB9KTtcbiAgICAgIGNvbnNvbGUuZGVidWcoXG4gICAgICAgIGBSZXBvcnRlZCBsb2NhbCBhY3Rpdml0eSBmYWlsdXJlOiB3b3JrZmxvd19pZD0ke3dvcmtmbG93SWR9LCBhY3Rpdml0eT0ke2FjdGl2aXR5TmFtZX0sIGluZGV4PSR7YWN0aXZpdHlJbmRleH1gXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ0ZhaWxlZCB0byByZXBvcnQgbG9jYWwgYWN0aXZpdHkgZmFpbHVyZTonLCBlcnJvcik7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgZXhlY3V0ZVJlbW90ZUFjdGl2aXR5KFxuICAgIHdvcmtmbG93SWQ6IHN0cmluZyxcbiAgICBhY3Rpdml0eU5hbWU6IHN0cmluZyxcbiAgICBhY3Rpdml0eUluZGV4OiBudW1iZXIsXG4gICAgaW5wdXREYXRhOiB1bmtub3duLFxuICAgIHRpbWVvdXRNczogbnVtYmVyXG4gICk6IFByb21pc2U8dW5rbm93bj4ge1xuICAgIGlmICghdGhpcy5wcm9kdWNlciB8fCAhdGhpcy5yZXN1bHRUb3BpYykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdLYWZrYSBwcm9kdWNlciBub3QgaW5pdGlhbGl6ZWQnKTtcbiAgICB9XG5cbiAgICAvLyBTZW5kIEFjdGl2aXR5UmVxdWVzdCB0byBzZXJ2ZXIgdmlhIEthZmthXG4gICAgY29uc3QgcmVxdWVzdFBheWxvYWQgPSB7XG4gICAgICByZXF1ZXN0X3R5cGU6ICdhY3Rpdml0eV9yZXF1ZXN0JyxcbiAgICAgIHJlcXVlc3RfaWQ6IGNyeXB0by5yYW5kb21VVUlEKCksXG4gICAgICB3b3JrZmxvd19pZDogd29ya2Zsb3dJZCxcbiAgICAgIGFjdGl2aXR5X25hbWU6IGFjdGl2aXR5TmFtZSxcbiAgICAgIGFjdGl2aXR5X2luZGV4OiBhY3Rpdml0eUluZGV4LFxuICAgICAgaW5wdXQ6IGlucHV0RGF0YSxcbiAgICAgIHRpbWVvdXRfbXM6IHRpbWVvdXRNcyxcbiAgICAgIHJlcXVlc3Rlcl93b3JrZXJfaWQ6IHRoaXMud29ya2VySWQsXG4gICAgICBjb3JyZWxhdGlvbl9pZDogY3J5cHRvLnJhbmRvbVVVSUQoKSxcbiAgICAgIGNyZWF0ZWRfYXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICB9O1xuXG4gICAgYXdhaXQgdGhpcy5wcm9kdWNlci5zZW5kKHtcbiAgICAgIHRvcGljOiB0aGlzLnJlc3VsdFRvcGljLFxuICAgICAgbWVzc2FnZXM6IFt7IGtleTogd29ya2Zsb3dJZCwgdmFsdWU6IEpTT04uc3RyaW5naWZ5KHJlcXVlc3RQYXlsb2FkKSB9XSxcbiAgICB9KTtcblxuICAgIGNvbnNvbGUubG9nKFxuICAgICAgYEFjdGl2aXR5IHJlcXVlc3Qgc2VudCB2aWEgS2Fma2E6IGFjdGl2aXR5PSR7YWN0aXZpdHlOYW1lfSwgd29ya2Zsb3dfaWQ9JHt3b3JrZmxvd0lkfSwgYWN0aXZpdHlfaW5kZXg9JHthY3Rpdml0eUluZGV4fWBcbiAgICApO1xuXG4gICAgLy8gUG9sbCBzZXJ2ZXIgZm9yIHJlc3VsdCB3aXRoIGV4cG9uZW50aWFsIGJhY2tvZmZcbiAgICBsZXQgcG9sbEludGVydmFsID0gMjAwMDsgLy8gU3RhcnQgYXQgMiBzZWNvbmRzXG4gICAgY29uc3QgbWF4UG9sbEludGVydmFsID0gOTAwMDAwOyAvLyBNYXggMTUgbWludXRlc1xuICAgIGNvbnN0IGJhY2tvZmZNdWx0aXBsaWVyID0gMS41O1xuICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgY29uc3QgdGltZW91dFNlY29uZHMgPSB0aW1lb3V0TXM7XG5cbiAgICBjb25zdCBwb2xsVXJsID0gYCR7dGhpcy5jb25maWcuc2VydmVyVXJsfS93b3JrZmxvdy9hcGkvdjEvd29ya2Zsb3dzLyR7d29ya2Zsb3dJZH0vYWN0aXZpdGllcy8ke2FjdGl2aXR5SW5kZXh9L3Jlc3VsdGA7XG4gICAgY29uc3QgaGVhZGVycyA9IHsgQXV0aG9yaXphdGlvbjogYEJlYXJlciAke3RoaXMuY29uZmlnLmFwaUtleX1gIH07XG5cbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgY29uc3QgZWxhcHNlZCA9IERhdGUubm93KCkgLSBzdGFydFRpbWU7XG4gICAgICBpZiAoZWxhcHNlZCA+PSB0aW1lb3V0U2Vjb25kcykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEFjdGl2aXR5ICR7YWN0aXZpdHlOYW1lfSB0aW1lZCBvdXQgYWZ0ZXIgJHt0aW1lb3V0TXN9bXNgKTtcbiAgICAgIH1cblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChwb2xsVXJsLCB7IGhlYWRlcnMgfSk7XG5cbiAgICAgICAgaWYgKHJlc3BvbnNlLnN0YXR1cyA9PT0gMjAwKSB7XG4gICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcmVzcG9uc2UuanNvbigpIGFzIHsgc3RhdHVzOiBzdHJpbmc7IG91dHB1dD86IHVua25vd247IGVycm9yPzogc3RyaW5nIH07XG4gICAgICAgICAgaWYgKHJlc3VsdC5zdGF0dXMgPT09ICdjb21wbGV0ZWQnKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgQWN0aXZpdHkgJHthY3Rpdml0eU5hbWV9IGNvbXBsZXRlZCBmb3Igd29ya2Zsb3cgJHt3b3JrZmxvd0lkfWApO1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdC5vdXRwdXQ7XG4gICAgICAgICAgfSBlbHNlIGlmIChyZXN1bHQuc3RhdHVzID09PSAnZmFpbGVkJykge1xuICAgICAgICAgICAgY29uc3QgZXJyb3JNc2cgPSByZXN1bHQuZXJyb3IgfHwgJ0FjdGl2aXR5IGZhaWxlZCc7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGBBY3Rpdml0eSAke2FjdGl2aXR5TmFtZX0gZmFpbGVkOiAke2Vycm9yTXNnfWApO1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGVycm9yTXNnKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAocmVzcG9uc2Uuc3RhdHVzID09PSAyMDIpIHtcbiAgICAgICAgICAvLyBTdGlsbCBwZW5kaW5nL3J1bm5pbmcsIGNvbnRpbnVlIHBvbGxpbmdcbiAgICAgICAgICBjb25zb2xlLmRlYnVnKGBBY3Rpdml0eSAke2FjdGl2aXR5TmFtZX0gc3RpbGwgcnVubmluZywgcG9sbGluZyBhZ2FpbiBpbiAke3BvbGxJbnRlcnZhbH1tc2ApO1xuICAgICAgICB9IGVsc2UgaWYgKHJlc3BvbnNlLnN0YXR1cyA9PT0gNDA0KSB7XG4gICAgICAgICAgLy8gQWN0aXZpdHkgbm90IGZvdW5kIHlldFxuICAgICAgICAgIGNvbnNvbGUuZGVidWcoYEFjdGl2aXR5ICR7YWN0aXZpdHlOYW1lfSBub3QgZm91bmQgeWV0LCBwb2xsaW5nIGFnYWluIGluICR7cG9sbEludGVydmFsfW1zYCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc29sZS53YXJuKGBVbmV4cGVjdGVkIHJlc3BvbnNlICR7cmVzcG9uc2Uuc3RhdHVzfSB3aGVuIHBvbGxpbmcgYWN0aXZpdHkgcmVzdWx0YCk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGlmICgoZXJyb3IgYXMgRXJyb3IpLm1lc3NhZ2UuaW5jbHVkZXMoJ3RpbWVkIG91dCcpIHx8IChlcnJvciBhcyBFcnJvcikubWVzc2FnZS5pbmNsdWRlcygnZmFpbGVkJykpIHtcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgfVxuICAgICAgICBjb25zb2xlLndhcm4oJ0Vycm9yIHBvbGxpbmcgYWN0aXZpdHkgcmVzdWx0OicsIGVycm9yKTtcbiAgICAgIH1cblxuICAgICAgLy8gV2FpdCB3aXRoIGV4cG9uZW50aWFsIGJhY2tvZmZcbiAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIHBvbGxJbnRlcnZhbCkpO1xuICAgICAgcG9sbEludGVydmFsID0gTWF0aC5taW4ocG9sbEludGVydmFsICogYmFja29mZk11bHRpcGxpZXIsIG1heFBvbGxJbnRlcnZhbCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjbGVhbnVwKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIFN0b3AgaGVhcnRiZWF0XG4gICAgaWYgKHRoaXMuaGVhcnRiZWF0SW50ZXJ2YWwpIHtcbiAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy5oZWFydGJlYXRJbnRlcnZhbCk7XG4gICAgfVxuXG4gICAgLy8gRGlzY29ubmVjdCBmcm9tIHNlcnZlclxuICAgIGF3YWl0IHRoaXMuZGlzY29ubmVjdEZyb21TZXJ2ZXIoKTtcblxuICAgIC8vIFN0b3AgS2Fma2EgY2xpZW50c1xuICAgIGlmICh0aGlzLmNvbnN1bWVyKSB7XG4gICAgICBhd2FpdCB0aGlzLmNvbnN1bWVyLmRpc2Nvbm5lY3QoKTtcbiAgICB9XG4gICAgaWYgKHRoaXMucHJvZHVjZXIpIHtcbiAgICAgIGF3YWl0IHRoaXMucHJvZHVjZXIuZGlzY29ubmVjdCgpO1xuICAgIH1cblxuICAgIGNvbnNvbGUubG9nKGBXb3JrZXIgJHt0aGlzLndvcmtlcklkfSBzdG9wcGVkYCk7XG4gIH1cbn1cbiJdfQ==
|