@ruvector/ruvllm 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +406 -0
  2. package/bin/cli.js +387 -0
  3. package/dist/cjs/engine.d.ts +90 -0
  4. package/dist/cjs/engine.d.ts.map +1 -0
  5. package/dist/cjs/engine.js +301 -0
  6. package/dist/cjs/export.d.ts +182 -0
  7. package/dist/cjs/export.d.ts.map +1 -0
  8. package/dist/cjs/export.js +422 -0
  9. package/dist/cjs/federated.d.ts +233 -0
  10. package/dist/cjs/federated.d.ts.map +1 -0
  11. package/dist/cjs/federated.js +525 -0
  12. package/dist/cjs/index.d.ts +64 -0
  13. package/dist/cjs/index.d.ts.map +1 -0
  14. package/dist/cjs/index.js +96 -0
  15. package/dist/cjs/lora.d.ts +240 -0
  16. package/dist/cjs/lora.d.ts.map +1 -0
  17. package/dist/cjs/lora.js +494 -0
  18. package/dist/cjs/native.d.ts +83 -0
  19. package/dist/cjs/native.d.ts.map +1 -0
  20. package/dist/cjs/native.js +70 -0
  21. package/dist/cjs/session.d.ts +80 -0
  22. package/dist/cjs/session.d.ts.map +1 -0
  23. package/dist/cjs/session.js +203 -0
  24. package/dist/cjs/simd.d.ts +90 -0
  25. package/dist/cjs/simd.d.ts.map +1 -0
  26. package/dist/cjs/simd.js +209 -0
  27. package/dist/cjs/sona.d.ts +187 -0
  28. package/dist/cjs/sona.d.ts.map +1 -0
  29. package/dist/cjs/sona.js +500 -0
  30. package/dist/cjs/streaming.d.ts +55 -0
  31. package/dist/cjs/streaming.d.ts.map +1 -0
  32. package/dist/cjs/streaming.js +131 -0
  33. package/dist/cjs/training.d.ts +254 -0
  34. package/dist/cjs/training.d.ts.map +1 -0
  35. package/dist/cjs/training.js +480 -0
  36. package/dist/cjs/types.d.ts +599 -0
  37. package/dist/cjs/types.d.ts.map +1 -0
  38. package/dist/cjs/types.js +6 -0
  39. package/dist/esm/engine.d.ts +90 -0
  40. package/dist/esm/engine.d.ts.map +1 -0
  41. package/dist/esm/engine.js +297 -0
  42. package/dist/esm/export.d.ts +182 -0
  43. package/dist/esm/export.d.ts.map +1 -0
  44. package/dist/esm/export.js +414 -0
  45. package/dist/esm/federated.d.ts +233 -0
  46. package/dist/esm/federated.d.ts.map +1 -0
  47. package/dist/esm/federated.js +520 -0
  48. package/dist/esm/index.d.ts +64 -0
  49. package/dist/esm/index.d.ts.map +1 -0
  50. package/dist/esm/index.js +76 -0
  51. package/dist/esm/lora.d.ts +240 -0
  52. package/dist/esm/lora.d.ts.map +1 -0
  53. package/dist/esm/lora.js +489 -0
  54. package/dist/esm/native.d.ts +83 -0
  55. package/dist/esm/native.d.ts.map +1 -0
  56. package/dist/esm/native.js +65 -0
  57. package/dist/esm/session.d.ts +80 -0
  58. package/dist/esm/session.d.ts.map +1 -0
  59. package/dist/esm/session.js +199 -0
  60. package/dist/esm/simd.d.ts +90 -0
  61. package/dist/esm/simd.d.ts.map +1 -0
  62. package/dist/esm/simd.js +205 -0
  63. package/dist/esm/sona.d.ts +187 -0
  64. package/dist/esm/sona.d.ts.map +1 -0
  65. package/dist/esm/sona.js +494 -0
  66. package/dist/esm/streaming.d.ts +55 -0
  67. package/dist/esm/streaming.d.ts.map +1 -0
  68. package/dist/esm/streaming.js +126 -0
  69. package/dist/esm/training.d.ts +254 -0
  70. package/dist/esm/training.d.ts.map +1 -0
  71. package/dist/esm/training.js +473 -0
  72. package/dist/esm/types.d.ts +599 -0
  73. package/dist/esm/types.d.ts.map +1 -0
  74. package/dist/esm/types.js +5 -0
  75. package/package.json +121 -0
@@ -0,0 +1,473 @@
1
+ /**
2
+ * Training Pipeline for SONA
3
+ *
4
+ * Comprehensive training infrastructure with metrics tracking,
5
+ * learning rate scheduling, and checkpoint management.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { TrainingPipeline, TrainingConfig } from '@ruvector/ruvllm';
10
+ *
11
+ * const pipeline = new TrainingPipeline({
12
+ * learningRate: 0.001,
13
+ * batchSize: 32,
14
+ * epochs: 10,
15
+ * });
16
+ *
17
+ * // Add training data
18
+ * pipeline.addBatch(inputs, targets, qualities);
19
+ *
20
+ * // Run training
21
+ * const result = pipeline.train();
22
+ * console.log(`Final loss: ${result.finalLoss}`);
23
+ * ```
24
+ */
25
+ import { LoraAdapter } from './lora';
26
+ import { EwcManager } from './sona';
27
+ /**
28
+ * Default training config
29
+ */
30
+ const DEFAULT_TRAINING_CONFIG = {
31
+ learningRate: 0.001,
32
+ batchSize: 32,
33
+ epochs: 10,
34
+ scheduler: 'cosine',
35
+ warmupSteps: 100,
36
+ weightDecay: 0.01,
37
+ gradientClip: 1.0,
38
+ earlyStoppingPatience: 3,
39
+ checkpointInterval: 1,
40
+ ewcLambda: 2000,
41
+ validationSplit: 0.1,
42
+ };
43
+ /**
44
+ * Learning Rate Scheduler
45
+ */
46
+ export class LRScheduler {
47
+ constructor(config, totalSteps) {
48
+ this.currentStep = 0;
49
+ this.config = config;
50
+ this.initialLR = config.learningRate;
51
+ this.totalSteps = totalSteps;
52
+ }
53
+ /**
54
+ * Get learning rate for current step
55
+ */
56
+ getLR() {
57
+ switch (this.config.scheduler) {
58
+ case 'constant':
59
+ return this.initialLR;
60
+ case 'linear':
61
+ return this.initialLR * (1 - this.currentStep / this.totalSteps);
62
+ case 'cosine':
63
+ return this.initialLR * 0.5 * (1 + Math.cos(Math.PI * this.currentStep / this.totalSteps));
64
+ case 'warmup':
65
+ if (this.currentStep < this.config.warmupSteps) {
66
+ return this.initialLR * (this.currentStep / this.config.warmupSteps);
67
+ }
68
+ // Cosine decay after warmup
69
+ const decaySteps = this.totalSteps - this.config.warmupSteps;
70
+ const decayProgress = (this.currentStep - this.config.warmupSteps) / decaySteps;
71
+ return this.initialLR * 0.5 * (1 + Math.cos(Math.PI * decayProgress));
72
+ default:
73
+ return this.initialLR;
74
+ }
75
+ }
76
+ /**
77
+ * Step the scheduler
78
+ */
79
+ step() {
80
+ this.currentStep++;
81
+ }
82
+ /**
83
+ * Reset scheduler
84
+ */
85
+ reset() {
86
+ this.currentStep = 0;
87
+ }
88
+ }
89
+ /**
90
+ * Training Metrics Tracker
91
+ */
92
+ export class MetricsTracker {
93
+ constructor() {
94
+ this.lossHistory = [];
95
+ this.valLossHistory = [];
96
+ this.gradNormHistory = [];
97
+ this.startTime = Date.now();
98
+ this.stepTimes = [];
99
+ }
100
+ /**
101
+ * Record training loss
102
+ */
103
+ recordLoss(loss) {
104
+ this.lossHistory.push(loss);
105
+ }
106
+ /**
107
+ * Record validation loss
108
+ */
109
+ recordValLoss(loss) {
110
+ this.valLossHistory.push(loss);
111
+ }
112
+ /**
113
+ * Record gradient norm
114
+ */
115
+ recordGradNorm(norm) {
116
+ this.gradNormHistory.push(norm);
117
+ }
118
+ /**
119
+ * Record step time
120
+ */
121
+ recordStepTime(ms) {
122
+ this.stepTimes.push(ms);
123
+ }
124
+ /**
125
+ * Get average loss over last N steps
126
+ */
127
+ avgLoss(n = 100) {
128
+ const recent = this.lossHistory.slice(-n);
129
+ return recent.length > 0 ? recent.reduce((a, b) => a + b, 0) / recent.length : 0;
130
+ }
131
+ /**
132
+ * Get average validation loss
133
+ */
134
+ avgValLoss(n = 10) {
135
+ const recent = this.valLossHistory.slice(-n);
136
+ return recent.length > 0 ? recent.reduce((a, b) => a + b, 0) / recent.length : 0;
137
+ }
138
+ /**
139
+ * Get steps per second
140
+ */
141
+ stepsPerSecond() {
142
+ if (this.stepTimes.length === 0)
143
+ return 0;
144
+ const avgStepTime = this.stepTimes.slice(-100).reduce((a, b) => a + b, 0) / Math.min(this.stepTimes.length, 100);
145
+ return avgStepTime > 0 ? 1000 / avgStepTime : 0;
146
+ }
147
+ /**
148
+ * Get ETA in seconds
149
+ */
150
+ eta(remainingSteps) {
151
+ const sps = this.stepsPerSecond();
152
+ return sps > 0 ? remainingSteps / sps : 0;
153
+ }
154
+ /**
155
+ * Get best validation loss
156
+ */
157
+ bestValLoss() {
158
+ return this.valLossHistory.length > 0 ? Math.min(...this.valLossHistory) : Infinity;
159
+ }
160
+ /**
161
+ * Get total duration
162
+ */
163
+ duration() {
164
+ return Date.now() - this.startTime;
165
+ }
166
+ /**
167
+ * Get all loss history
168
+ */
169
+ getLossHistory() {
170
+ return [...this.lossHistory];
171
+ }
172
+ /**
173
+ * Get all validation loss history
174
+ */
175
+ getValLossHistory() {
176
+ return [...this.valLossHistory];
177
+ }
178
+ /**
179
+ * Reset tracker
180
+ */
181
+ reset() {
182
+ this.lossHistory = [];
183
+ this.valLossHistory = [];
184
+ this.gradNormHistory = [];
185
+ this.stepTimes = [];
186
+ this.startTime = Date.now();
187
+ }
188
+ }
189
+ /**
190
+ * Training Pipeline
191
+ *
192
+ * Full training infrastructure for SONA models.
193
+ */
194
+ export class TrainingPipeline {
195
+ constructor(config, adapter) {
196
+ this.scheduler = null;
197
+ this.batches = [];
198
+ this.checkpoints = [];
199
+ this.currentEpoch = 0;
200
+ this.currentStep = 0;
201
+ this.bestValLoss = Infinity;
202
+ this.patienceCounter = 0;
203
+ this.config = { ...DEFAULT_TRAINING_CONFIG, ...config };
204
+ this.adapter = adapter || new LoraAdapter({ rank: 8 });
205
+ this.ewcManager = new EwcManager(this.config.ewcLambda);
206
+ this.metrics = new MetricsTracker();
207
+ }
208
+ /**
209
+ * Add training batch
210
+ */
211
+ addBatch(inputs, targets, qualities) {
212
+ this.batches.push({ inputs, targets, qualities });
213
+ }
214
+ /**
215
+ * Add training data
216
+ */
217
+ addData(data) {
218
+ // Group into batches
219
+ for (let i = 0; i < data.length; i += this.config.batchSize) {
220
+ const batch = data.slice(i, i + this.config.batchSize);
221
+ this.addBatch(batch.map(d => d.input), batch.map(d => d.target), batch.map(d => d.quality));
222
+ }
223
+ }
224
+ /**
225
+ * Run training
226
+ */
227
+ train() {
228
+ const totalSteps = this.batches.length * this.config.epochs;
229
+ this.scheduler = new LRScheduler(this.config, totalSteps);
230
+ this.metrics.reset();
231
+ this.adapter.startTraining(this.config.learningRate);
232
+ let earlyStopped = false;
233
+ for (let epoch = 0; epoch < this.config.epochs; epoch++) {
234
+ this.currentEpoch = epoch;
235
+ // Shuffle batches
236
+ const shuffledBatches = this.shuffleBatches();
237
+ // Split into train/val
238
+ const valSize = Math.floor(shuffledBatches.length * this.config.validationSplit);
239
+ const trainBatches = shuffledBatches.slice(valSize);
240
+ const valBatches = shuffledBatches.slice(0, valSize);
241
+ // Training epoch
242
+ for (const batch of trainBatches) {
243
+ const stepStart = Date.now();
244
+ const loss = this.trainStep(batch);
245
+ this.metrics.recordLoss(loss);
246
+ this.metrics.recordStepTime(Date.now() - stepStart);
247
+ this.scheduler.step();
248
+ this.currentStep++;
249
+ }
250
+ // Validation
251
+ if (valBatches.length > 0) {
252
+ const valLoss = this.validate(valBatches);
253
+ this.metrics.recordValLoss(valLoss);
254
+ // Early stopping
255
+ if (valLoss < this.bestValLoss) {
256
+ this.bestValLoss = valLoss;
257
+ this.patienceCounter = 0;
258
+ }
259
+ else {
260
+ this.patienceCounter++;
261
+ if (this.patienceCounter >= this.config.earlyStoppingPatience) {
262
+ earlyStopped = true;
263
+ break;
264
+ }
265
+ }
266
+ }
267
+ // Checkpoint
268
+ if ((epoch + 1) % this.config.checkpointInterval === 0) {
269
+ this.saveCheckpoint();
270
+ }
271
+ }
272
+ this.adapter.endTraining();
273
+ // Register with EWC for continual learning
274
+ const weights = this.adapter.merge().flat();
275
+ this.ewcManager.registerTask(`task-${Date.now()}`, weights);
276
+ return {
277
+ epochs: this.currentEpoch + 1,
278
+ steps: this.currentStep,
279
+ finalLoss: this.metrics.avgLoss(100),
280
+ bestValLoss: this.bestValLoss,
281
+ durationMs: this.metrics.duration(),
282
+ lossHistory: this.metrics.getLossHistory(),
283
+ valLossHistory: this.metrics.getValLossHistory(),
284
+ earlyStopped,
285
+ };
286
+ }
287
+ /**
288
+ * Single training step
289
+ */
290
+ trainStep(batch) {
291
+ let totalLoss = 0;
292
+ const lr = this.scheduler?.getLR() || this.config.learningRate;
293
+ for (let i = 0; i < batch.inputs.length; i++) {
294
+ const input = batch.inputs[i];
295
+ const target = batch.targets[i];
296
+ const quality = batch.qualities[i];
297
+ // Forward pass
298
+ const output = this.adapter.forward(input);
299
+ // Compute loss (MSE weighted by quality)
300
+ const gradOutput = [];
301
+ let loss = 0;
302
+ for (let j = 0; j < output.length; j++) {
303
+ const diff = output[j] - (target[j] || 0);
304
+ loss += diff * diff;
305
+ gradOutput.push(2 * diff * quality); // Quality-weighted gradient
306
+ }
307
+ loss = (loss / output.length) * quality;
308
+ // Add EWC penalty
309
+ const ewcPenalty = this.ewcManager.computePenalty(this.adapter.merge().flat());
310
+ loss += ewcPenalty * 0.001;
311
+ // Backward pass
312
+ this.adapter.backward(input, gradOutput, lr);
313
+ totalLoss += loss;
314
+ }
315
+ return totalLoss / batch.inputs.length;
316
+ }
317
+ /**
318
+ * Validation pass
319
+ */
320
+ validate(batches) {
321
+ let totalLoss = 0;
322
+ let count = 0;
323
+ for (const batch of batches) {
324
+ for (let i = 0; i < batch.inputs.length; i++) {
325
+ const output = this.adapter.forward(batch.inputs[i]);
326
+ const target = batch.targets[i];
327
+ let loss = 0;
328
+ for (let j = 0; j < output.length; j++) {
329
+ const diff = output[j] - (target[j] || 0);
330
+ loss += diff * diff;
331
+ }
332
+ totalLoss += loss / output.length;
333
+ count++;
334
+ }
335
+ }
336
+ return count > 0 ? totalLoss / count : 0;
337
+ }
338
+ /**
339
+ * Save checkpoint
340
+ */
341
+ saveCheckpoint() {
342
+ this.checkpoints.push({
343
+ epoch: this.currentEpoch,
344
+ step: this.currentStep,
345
+ loss: this.metrics.avgLoss(100),
346
+ weights: this.adapter.toJSON(),
347
+ timestamp: Date.now(),
348
+ });
349
+ }
350
+ /**
351
+ * Load checkpoint
352
+ */
353
+ loadCheckpoint(index) {
354
+ const checkpoint = this.checkpoints[index];
355
+ if (!checkpoint)
356
+ return false;
357
+ this.adapter = LoraAdapter.fromJSON(checkpoint.weights);
358
+ this.currentEpoch = checkpoint.epoch;
359
+ this.currentStep = checkpoint.step;
360
+ return true;
361
+ }
362
+ /**
363
+ * Get current metrics
364
+ */
365
+ getMetrics() {
366
+ return {
367
+ epoch: this.currentEpoch,
368
+ step: this.currentStep,
369
+ trainLoss: this.metrics.avgLoss(100),
370
+ valLoss: this.metrics.avgValLoss(10),
371
+ learningRate: this.scheduler?.getLR() || this.config.learningRate,
372
+ gradNorm: 0,
373
+ stepsPerSecond: this.metrics.stepsPerSecond(),
374
+ etaSeconds: this.metrics.eta((this.config.epochs - this.currentEpoch) * this.batches.length),
375
+ };
376
+ }
377
+ /**
378
+ * Get adapter
379
+ */
380
+ getAdapter() {
381
+ return this.adapter;
382
+ }
383
+ /**
384
+ * Get EWC manager
385
+ */
386
+ getEwcManager() {
387
+ return this.ewcManager;
388
+ }
389
+ /**
390
+ * Get checkpoints
391
+ */
392
+ getCheckpoints() {
393
+ return [...this.checkpoints];
394
+ }
395
+ /**
396
+ * Reset pipeline
397
+ */
398
+ reset() {
399
+ this.batches = [];
400
+ this.checkpoints = [];
401
+ this.currentEpoch = 0;
402
+ this.currentStep = 0;
403
+ this.bestValLoss = Infinity;
404
+ this.patienceCounter = 0;
405
+ this.metrics.reset();
406
+ this.adapter.reset();
407
+ }
408
+ shuffleBatches() {
409
+ const shuffled = [...this.batches];
410
+ for (let i = shuffled.length - 1; i > 0; i--) {
411
+ const j = Math.floor(Math.random() * (i + 1));
412
+ [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
413
+ }
414
+ return shuffled;
415
+ }
416
+ }
417
+ /**
418
+ * Training Factory
419
+ *
420
+ * Create pre-configured training pipelines for common scenarios.
421
+ */
422
+ export class TrainingFactory {
423
+ /**
424
+ * Create pipeline for quick fine-tuning
425
+ */
426
+ static quickFinetune() {
427
+ return new TrainingPipeline({
428
+ learningRate: 0.01,
429
+ epochs: 3,
430
+ batchSize: 16,
431
+ scheduler: 'constant',
432
+ });
433
+ }
434
+ /**
435
+ * Create pipeline for deep training
436
+ */
437
+ static deepTraining() {
438
+ return new TrainingPipeline({
439
+ learningRate: 0.001,
440
+ epochs: 50,
441
+ batchSize: 32,
442
+ scheduler: 'warmup',
443
+ warmupSteps: 500,
444
+ earlyStoppingPatience: 5,
445
+ });
446
+ }
447
+ /**
448
+ * Create pipeline for continual learning
449
+ */
450
+ static continualLearning(ewcLambda = 5000) {
451
+ return new TrainingPipeline({
452
+ learningRate: 0.0005,
453
+ epochs: 10,
454
+ batchSize: 16,
455
+ scheduler: 'cosine',
456
+ ewcLambda,
457
+ earlyStoppingPatience: 10,
458
+ });
459
+ }
460
+ /**
461
+ * Create pipeline for federated aggregation
462
+ */
463
+ static federatedAggregation() {
464
+ return new TrainingPipeline({
465
+ learningRate: 0.0001,
466
+ epochs: 5,
467
+ batchSize: 64,
468
+ scheduler: 'linear',
469
+ ewcLambda: 2000,
470
+ });
471
+ }
472
+ }
473
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhaW5pbmcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHJhaW5pbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBdUJHO0FBR0gsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUNyQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBRXBDOztHQUVHO0FBQ0gsTUFBTSx1QkFBdUIsR0FBNkI7SUFDeEQsWUFBWSxFQUFFLEtBQUs7SUFDbkIsU0FBUyxFQUFFLEVBQUU7SUFDYixNQUFNLEVBQUUsRUFBRTtJQUNWLFNBQVMsRUFBRSxRQUFRO0lBQ25CLFdBQVcsRUFBRSxHQUFHO0lBQ2hCLFdBQVcsRUFBRSxJQUFJO0lBQ2pCLFlBQVksRUFBRSxHQUFHO0lBQ2pCLHFCQUFxQixFQUFFLENBQUM7SUFDeEIsa0JBQWtCLEVBQUUsQ0FBQztJQUNyQixTQUFTLEVBQUUsSUFBSTtJQUNmLGVBQWUsRUFBRSxHQUFHO0NBQ3JCLENBQUM7QUFvREY7O0dBRUc7QUFDSCxNQUFNLE9BQU8sV0FBVztJQU10QixZQUFZLE1BQWdDLEVBQUUsVUFBa0I7UUFIeEQsZ0JBQVcsR0FBVyxDQUFDLENBQUM7UUFJOUIsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLFNBQVMsR0FBRyxNQUFNLENBQUMsWUFBWSxDQUFDO1FBQ3JDLElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO0lBQy9CLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUs7UUFDSCxRQUFRLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDOUIsS0FBSyxVQUFVO2dCQUNiLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQztZQUV4QixLQUFLLFFBQVE7Z0JBQ1gsT0FBTyxJQUFJLENBQUMsU0FBUyxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBRW5FLEtBQUssUUFBUTtnQkFDWCxPQUFPLElBQUksQ0FBQyxTQUFTLEdBQUcsR0FBRyxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO1lBRTdGLEtBQUssUUFBUTtnQkFDWCxJQUFJLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUUsQ0FBQztvQkFDL0MsT0FBTyxJQUFJLENBQUMsU0FBUyxHQUFHLENBQUMsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO2dCQUN2RSxDQUFDO2dCQUNELDRCQUE0QjtnQkFDNUIsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQztnQkFDN0QsTUFBTSxhQUFhLEdBQUcsQ0FBQyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLEdBQUcsVUFBVSxDQUFDO2dCQUNoRixPQUFPLElBQUksQ0FBQyxTQUFTLEdBQUcsR0FBRyxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxhQUFhLENBQUMsQ0FBQyxDQUFDO1lBRXhFO2dCQUNFLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQztRQUMxQixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0gsSUFBSTtRQUNGLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNyQixDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLO1FBQ0gsSUFBSSxDQUFDLFdBQVcsR0FBRyxDQUFDLENBQUM7SUFDdkIsQ0FBQztDQUNGO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sY0FBYztJQUEzQjtRQUNVLGdCQUFXLEdBQWEsRUFBRSxDQUFDO1FBQzNCLG1CQUFjLEdBQWEsRUFBRSxDQUFDO1FBQzlCLG9CQUFlLEdBQWEsRUFBRSxDQUFDO1FBQy9CLGNBQVMsR0FBVyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDL0IsY0FBUyxHQUFhLEVBQUUsQ0FBQztJQXFHbkMsQ0FBQztJQW5HQzs7T0FFRztJQUNILFVBQVUsQ0FBQyxJQUFZO1FBQ3JCLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzlCLENBQUM7SUFFRDs7T0FFRztJQUNILGFBQWEsQ0FBQyxJQUFZO1FBQ3hCLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2pDLENBQUM7SUFFRDs7T0FFRztJQUNILGNBQWMsQ0FBQyxJQUFZO1FBQ3pCLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2xDLENBQUM7SUFFRDs7T0FFRztJQUNILGNBQWMsQ0FBQyxFQUFVO1FBQ3ZCLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzFCLENBQUM7SUFFRDs7T0FFRztJQUNILE9BQU8sQ0FBQyxJQUFZLEdBQUc7UUFDckIsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUMxQyxPQUFPLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbkYsQ0FBQztJQUVEOztPQUVHO0lBQ0gsVUFBVSxDQUFDLElBQVksRUFBRTtRQUN2QixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzdDLE9BQU8sTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNuRixDQUFDO0lBRUQ7O09BRUc7SUFDSCxjQUFjO1FBQ1osSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sS0FBSyxDQUFDO1lBQUUsT0FBTyxDQUFDLENBQUM7UUFDMUMsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDakgsT0FBTyxXQUFXLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUcsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUVEOztPQUVHO0lBQ0gsR0FBRyxDQUFDLGNBQXNCO1FBQ3hCLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUNsQyxPQUFPLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLGNBQWMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM1QyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxXQUFXO1FBQ1QsT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQztJQUN0RixDQUFDO0lBRUQ7O09BRUc7SUFDSCxRQUFRO1FBQ04sT0FBTyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQztJQUNyQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxjQUFjO1FBQ1osT0FBTyxDQUFDLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQy9CLENBQUM7SUFFRDs7T0FFRztJQUNILGlCQUFpQjtRQUNmLE9BQU8sQ0FBQyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUNsQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLO1FBQ0gsSUFBSSxDQUFDLFdBQVcsR0FBRyxFQUFFLENBQUM7UUFDdEIsSUFBSSxDQUFDLGNBQWMsR0FBRyxFQUFFLENBQUM7UUFDekIsSUFBSSxDQUFDLGVBQWUsR0FBRyxFQUFFLENBQUM7UUFDMUIsSUFBSSxDQUFDLFNBQVMsR0FBRyxFQUFFLENBQUM7UUFDcEIsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDOUIsQ0FBQztDQUNGO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sT0FBTyxnQkFBZ0I7SUFhM0IsWUFBWSxNQUF1QixFQUFFLE9BQXFCO1FBUmxELGNBQVMsR0FBdUIsSUFBSSxDQUFDO1FBQ3JDLFlBQU8sR0FBb0IsRUFBRSxDQUFDO1FBQzlCLGdCQUFXLEdBQWlCLEVBQUUsQ0FBQztRQUMvQixpQkFBWSxHQUFXLENBQUMsQ0FBQztRQUN6QixnQkFBVyxHQUFXLENBQUMsQ0FBQztRQUN4QixnQkFBVyxHQUFXLFFBQVEsQ0FBQztRQUMvQixvQkFBZSxHQUFXLENBQUMsQ0FBQztRQUdsQyxJQUFJLENBQUMsTUFBTSxHQUFHLEVBQUUsR0FBRyx1QkFBdUIsRUFBRSxHQUFHLE1BQU0sRUFBRSxDQUFDO1FBQ3hELElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxJQUFJLElBQUksV0FBVyxDQUFDLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDdkQsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLFVBQVUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ3hELElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxjQUFjLEVBQUUsQ0FBQztJQUN0QyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxRQUFRLENBQUMsTUFBbUIsRUFBRSxPQUFvQixFQUFFLFNBQW1CO1FBQ3JFLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDO0lBQ3BELENBQUM7SUFFRDs7T0FFRztJQUNILE9BQU8sQ0FBQyxJQUFxRTtRQUMzRSxxQkFBcUI7UUFDckIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDNUQsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDdkQsSUFBSSxDQUFDLFFBQVEsQ0FDWCxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxFQUN2QixLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxFQUN4QixLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUMxQixDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUs7UUFDSCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQztRQUM1RCxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksV0FBVyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDMUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNyQixJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBRXJELElBQUksWUFBWSxHQUFHLEtBQUssQ0FBQztRQUV6QixLQUFLLElBQUksS0FBSyxHQUFHLENBQUMsRUFBRSxLQUFLLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQztZQUN4RCxJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssQ0FBQztZQUUxQixrQkFBa0I7WUFDbEIsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBRTlDLHVCQUF1QjtZQUN2QixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQztZQUNqRixNQUFNLFlBQVksR0FBRyxlQUFlLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ3BELE1BQU0sVUFBVSxHQUFHLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBRXJELGlCQUFpQjtZQUNqQixLQUFLLE1BQU0sS0FBSyxJQUFJLFlBQVksRUFBRSxDQUFDO2dCQUNqQyxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQzdCLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQ25DLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUM5QixJQUFJLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsU0FBUyxDQUFDLENBQUM7Z0JBQ3BELElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQ3RCLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNyQixDQUFDO1lBRUQsYUFBYTtZQUNiLElBQUksVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDMUIsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQztnQkFDMUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBRXBDLGlCQUFpQjtnQkFDakIsSUFBSSxPQUFPLEdBQUcsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO29CQUMvQixJQUFJLENBQUMsV0FBVyxHQUFHLE9BQU8sQ0FBQztvQkFDM0IsSUFBSSxDQUFDLGVBQWUsR0FBRyxDQUFDLENBQUM7Z0JBQzNCLENBQUM7cUJBQU0sQ0FBQztvQkFDTixJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7b0JBQ3ZCLElBQUksSUFBSSxDQUFDLGVBQWUsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLHFCQUFxQixFQUFFLENBQUM7d0JBQzlELFlBQVksR0FBRyxJQUFJLENBQUM7d0JBQ3BCLE1BQU07b0JBQ1IsQ0FBQztnQkFDSCxDQUFDO1lBQ0gsQ0FBQztZQUVELGFBQWE7WUFDYixJQUFJLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsa0JBQWtCLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQ3ZELElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN4QixDQUFDO1FBQ0gsQ0FBQztRQUVELElBQUksQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLENBQUM7UUFFM0IsMkNBQTJDO1FBQzNDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDNUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxZQUFZLENBQUMsUUFBUSxJQUFJLENBQUMsR0FBRyxFQUFFLEVBQUUsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUU1RCxPQUFPO1lBQ0wsTUFBTSxFQUFFLElBQUksQ0FBQyxZQUFZLEdBQUcsQ0FBQztZQUM3QixLQUFLLEVBQUUsSUFBSSxDQUFDLFdBQVc7WUFDdkIsU0FBUyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQztZQUNwQyxXQUFXLEVBQUUsSUFBSSxDQUFDLFdBQVc7WUFDN0IsVUFBVSxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFO1lBQ25DLFdBQVcsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLGNBQWMsRUFBRTtZQUMxQyxjQUFjLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsRUFBRTtZQUNoRCxZQUFZO1NBQ2IsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNLLFNBQVMsQ0FBQyxLQUFvQjtRQUNwQyxJQUFJLFNBQVMsR0FBRyxDQUFDLENBQUM7UUFDbEIsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLFNBQVMsRUFBRSxLQUFLLEVBQUUsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQztRQUUvRCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUM3QyxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzlCLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDaEMsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUVuQyxlQUFlO1lBQ2YsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7WUFFM0MseUNBQXlDO1lBQ3pDLE1BQU0sVUFBVSxHQUFhLEVBQUUsQ0FBQztZQUNoQyxJQUFJLElBQUksR0FBRyxDQUFDLENBQUM7WUFDYixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO2dCQUN2QyxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7Z0JBQzFDLElBQUksSUFBSSxJQUFJLEdBQUcsSUFBSSxDQUFDO2dCQUNwQixVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxJQUFJLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyw0QkFBNEI7WUFDbkUsQ0FBQztZQUNELElBQUksR0FBRyxDQUFDLElBQUksR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsT0FBTyxDQUFDO1lBRXhDLGtCQUFrQjtZQUNsQixNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7WUFDL0UsSUFBSSxJQUFJLFVBQVUsR0FBRyxLQUFLLENBQUM7WUFFM0IsZ0JBQWdCO1lBQ2hCLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxVQUFVLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFFN0MsU0FBUyxJQUFJLElBQUksQ0FBQztRQUNwQixDQUFDO1FBRUQsT0FBTyxTQUFTLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDekMsQ0FBQztJQUVEOztPQUVHO0lBQ0ssUUFBUSxDQUFDLE9BQXdCO1FBQ3ZDLElBQUksU0FBUyxHQUFHLENBQUMsQ0FBQztRQUNsQixJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7UUFFZCxLQUFLLE1BQU0sS0FBSyxJQUFJLE9BQU8sRUFBRSxDQUFDO1lBQzVCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO2dCQUM3QyxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ3JELE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBRWhDLElBQUksSUFBSSxHQUFHLENBQUMsQ0FBQztnQkFDYixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO29CQUN2QyxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7b0JBQzFDLElBQUksSUFBSSxJQUFJLEdBQUcsSUFBSSxDQUFDO2dCQUN0QixDQUFDO2dCQUNELFNBQVMsSUFBSSxJQUFJLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQztnQkFDbEMsS0FBSyxFQUFFLENBQUM7WUFDVixDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU8sS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFFRDs7T0FFRztJQUNLLGNBQWM7UUFDcEIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUM7WUFDcEIsS0FBSyxFQUFFLElBQUksQ0FBQyxZQUFZO1lBQ3hCLElBQUksRUFBRSxJQUFJLENBQUMsV0FBVztZQUN0QixJQUFJLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDO1lBQy9CLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRTtZQUM5QixTQUFTLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRTtTQUN0QixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxjQUFjLENBQUMsS0FBYTtRQUMxQixNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzNDLElBQUksQ0FBQyxVQUFVO1lBQUUsT0FBTyxLQUFLLENBQUM7UUFFOUIsSUFBSSxDQUFDLE9BQU8sR0FBRyxXQUFXLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN4RCxJQUFJLENBQUMsWUFBWSxHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUM7UUFDckMsSUFBSSxDQUFDLFdBQVcsR0FBRyxVQUFVLENBQUMsSUFBSSxDQUFDO1FBQ25DLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOztPQUVHO0lBQ0gsVUFBVTtRQUNSLE9BQU87WUFDTCxLQUFLLEVBQUUsSUFBSSxDQUFDLFlBQVk7WUFDeEIsSUFBSSxFQUFFLElBQUksQ0FBQyxXQUFXO1lBQ3RCLFNBQVMsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUM7WUFDcEMsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztZQUNwQyxZQUFZLEVBQUUsSUFBSSxDQUFDLFNBQVMsRUFBRSxLQUFLLEVBQUUsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVk7WUFDakUsUUFBUSxFQUFFLENBQUM7WUFDWCxjQUFjLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxjQUFjLEVBQUU7WUFDN0MsVUFBVSxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUMxQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FDL0Q7U0FDRixDQUFDO0lBQ0osQ0FBQztJQUVEOztPQUVHO0lBQ0gsVUFBVTtRQUNSLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQztJQUN0QixDQUFDO0lBRUQ7O09BRUc7SUFDSCxhQUFhO1FBQ1gsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ3pCLENBQUM7SUFFRDs7T0FFRztJQUNILGNBQWM7UUFDWixPQUFPLENBQUMsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDL0IsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSztRQUNILElBQUksQ0FBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1FBQ2xCLElBQUksQ0FBQyxXQUFXLEdBQUcsRUFBRSxDQUFDO1FBQ3RCLElBQUksQ0FBQyxZQUFZLEdBQUcsQ0FBQyxDQUFDO1FBQ3RCLElBQUksQ0FBQyxXQUFXLEdBQUcsQ0FBQyxDQUFDO1FBQ3JCLElBQUksQ0FBQyxXQUFXLEdBQUcsUUFBUSxDQUFDO1FBQzVCLElBQUksQ0FBQyxlQUFlLEdBQUcsQ0FBQyxDQUFDO1FBQ3pCLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDckIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUN2QixDQUFDO0lBRU8sY0FBYztRQUNwQixNQUFNLFFBQVEsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ25DLEtBQUssSUFBSSxDQUFDLEdBQUcsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQzdDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDOUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDMUQsQ0FBQztRQUNELE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7Q0FDRjtBQUVEOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sZUFBZTtJQUMxQjs7T0FFRztJQUNILE1BQU0sQ0FBQyxhQUFhO1FBQ2xCLE9BQU8sSUFBSSxnQkFBZ0IsQ0FBQztZQUMxQixZQUFZLEVBQUUsSUFBSTtZQUNsQixNQUFNLEVBQUUsQ0FBQztZQUNULFNBQVMsRUFBRSxFQUFFO1lBQ2IsU0FBUyxFQUFFLFVBQVU7U0FDdEIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLFlBQVk7UUFDakIsT0FBTyxJQUFJLGdCQUFnQixDQUFDO1lBQzFCLFlBQVksRUFBRSxLQUFLO1lBQ25CLE1BQU0sRUFBRSxFQUFFO1lBQ1YsU0FBUyxFQUFFLEVBQUU7WUFDYixTQUFTLEVBQUUsUUFBUTtZQUNuQixXQUFXLEVBQUUsR0FBRztZQUNoQixxQkFBcUIsRUFBRSxDQUFDO1NBQ3pCLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxZQUFvQixJQUFJO1FBQy9DLE9BQU8sSUFBSSxnQkFBZ0IsQ0FBQztZQUMxQixZQUFZLEVBQUUsTUFBTTtZQUNwQixNQUFNLEVBQUUsRUFBRTtZQUNWLFNBQVMsRUFBRSxFQUFFO1lBQ2IsU0FBUyxFQUFFLFFBQVE7WUFDbkIsU0FBUztZQUNULHFCQUFxQixFQUFFLEVBQUU7U0FDMUIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLG9CQUFvQjtRQUN6QixPQUFPLElBQUksZ0JBQWdCLENBQUM7WUFDMUIsWUFBWSxFQUFFLE1BQU07WUFDcEIsTUFBTSxFQUFFLENBQUM7WUFDVCxTQUFTLEVBQUUsRUFBRTtZQUNiLFNBQVMsRUFBRSxRQUFRO1lBQ25CLFNBQVMsRUFBRSxJQUFJO1NBQ2hCLENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVHJhaW5pbmcgUGlwZWxpbmUgZm9yIFNPTkFcbiAqXG4gKiBDb21wcmVoZW5zaXZlIHRyYWluaW5nIGluZnJhc3RydWN0dXJlIHdpdGggbWV0cmljcyB0cmFja2luZyxcbiAqIGxlYXJuaW5nIHJhdGUgc2NoZWR1bGluZywgYW5kIGNoZWNrcG9pbnQgbWFuYWdlbWVudC5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgVHJhaW5pbmdQaXBlbGluZSwgVHJhaW5pbmdDb25maWcgfSBmcm9tICdAcnV2ZWN0b3IvcnV2bGxtJztcbiAqXG4gKiBjb25zdCBwaXBlbGluZSA9IG5ldyBUcmFpbmluZ1BpcGVsaW5lKHtcbiAqICAgbGVhcm5pbmdSYXRlOiAwLjAwMSxcbiAqICAgYmF0Y2hTaXplOiAzMixcbiAqICAgZXBvY2hzOiAxMCxcbiAqIH0pO1xuICpcbiAqIC8vIEFkZCB0cmFpbmluZyBkYXRhXG4gKiBwaXBlbGluZS5hZGRCYXRjaChpbnB1dHMsIHRhcmdldHMsIHF1YWxpdGllcyk7XG4gKlxuICogLy8gUnVuIHRyYWluaW5nXG4gKiBjb25zdCByZXN1bHQgPSBwaXBlbGluZS50cmFpbigpO1xuICogY29uc29sZS5sb2coYEZpbmFsIGxvc3M6ICR7cmVzdWx0LmZpbmFsTG9zc31gKTtcbiAqIGBgYFxuICovXG5cbmltcG9ydCB7IEVtYmVkZGluZywgVHJhaW5pbmdDb25maWcsIFRyYWluaW5nUmVzdWx0IH0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBMb3JhQWRhcHRlciB9IGZyb20gJy4vbG9yYSc7XG5pbXBvcnQgeyBFd2NNYW5hZ2VyIH0gZnJvbSAnLi9zb25hJztcblxuLyoqXG4gKiBEZWZhdWx0IHRyYWluaW5nIGNvbmZpZ1xuICovXG5jb25zdCBERUZBVUxUX1RSQUlOSU5HX0NPTkZJRzogUmVxdWlyZWQ8VHJhaW5pbmdDb25maWc+ID0ge1xuICBsZWFybmluZ1JhdGU6IDAuMDAxLFxuICBiYXRjaFNpemU6IDMyLFxuICBlcG9jaHM6IDEwLFxuICBzY2hlZHVsZXI6ICdjb3NpbmUnLFxuICB3YXJtdXBTdGVwczogMTAwLFxuICB3ZWlnaHREZWNheTogMC4wMSxcbiAgZ3JhZGllbnRDbGlwOiAxLjAsXG4gIGVhcmx5U3RvcHBpbmdQYXRpZW5jZTogMyxcbiAgY2hlY2twb2ludEludGVydmFsOiAxLFxuICBld2NMYW1iZGE6IDIwMDAsXG4gIHZhbGlkYXRpb25TcGxpdDogMC4xLFxufTtcblxuLyoqXG4gKiBUcmFpbmluZyBtZXRyaWNzXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVHJhaW5pbmdNZXRyaWNzIHtcbiAgLyoqIEN1cnJlbnQgZXBvY2ggKi9cbiAgZXBvY2g6IG51bWJlcjtcbiAgLyoqIEN1cnJlbnQgc3RlcCAqL1xuICBzdGVwOiBudW1iZXI7XG4gIC8qKiBUcmFpbmluZyBsb3NzICovXG4gIHRyYWluTG9zczogbnVtYmVyO1xuICAvKiogVmFsaWRhdGlvbiBsb3NzICovXG4gIHZhbExvc3M6IG51bWJlcjtcbiAgLyoqIExlYXJuaW5nIHJhdGUgKi9cbiAgbGVhcm5pbmdSYXRlOiBudW1iZXI7XG4gIC8qKiBHcmFkaWVudCBub3JtICovXG4gIGdyYWROb3JtOiBudW1iZXI7XG4gIC8qKiBTdGVwcyBwZXIgc2Vjb25kICovXG4gIHN0ZXBzUGVyU2Vjb25kOiBudW1iZXI7XG4gIC8qKiBFVEEgaW4gc2Vjb25kcyAqL1xuICBldGFTZWNvbmRzOiBudW1iZXI7XG59XG5cbi8qKlxuICogVHJhaW5pbmcgZGF0YSBiYXRjaFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFRyYWluaW5nQmF0Y2gge1xuICAvKiogSW5wdXQgZW1iZWRkaW5ncyAqL1xuICBpbnB1dHM6IEVtYmVkZGluZ1tdO1xuICAvKiogVGFyZ2V0IG91dHB1dHMgKi9cbiAgdGFyZ2V0czogRW1iZWRkaW5nW107XG4gIC8qKiBRdWFsaXR5IHNjb3JlcyAqL1xuICBxdWFsaXRpZXM6IG51bWJlcltdO1xufVxuXG4vKipcbiAqIENoZWNrcG9pbnQgZGF0YVxuICovXG5leHBvcnQgaW50ZXJmYWNlIENoZWNrcG9pbnQge1xuICAvKiogRXBvY2ggbnVtYmVyICovXG4gIGVwb2NoOiBudW1iZXI7XG4gIC8qKiBTdGVwIG51bWJlciAqL1xuICBzdGVwOiBudW1iZXI7XG4gIC8qKiBUcmFpbmluZyBsb3NzIGF0IGNoZWNrcG9pbnQgKi9cbiAgbG9zczogbnVtYmVyO1xuICAvKiogTW9kZWwgd2VpZ2h0cyAoc2VyaWFsaXplZCkgKi9cbiAgd2VpZ2h0czogc3RyaW5nO1xuICAvKiogVGltZXN0YW1wICovXG4gIHRpbWVzdGFtcDogbnVtYmVyO1xufVxuXG4vKipcbiAqIExlYXJuaW5nIFJhdGUgU2NoZWR1bGVyXG4gKi9cbmV4cG9ydCBjbGFzcyBMUlNjaGVkdWxlciB7XG4gIHByaXZhdGUgY29uZmlnOiBSZXF1aXJlZDxUcmFpbmluZ0NvbmZpZz47XG4gIHByaXZhdGUgaW5pdGlhbExSOiBudW1iZXI7XG4gIHByaXZhdGUgY3VycmVudFN0ZXA6IG51bWJlciA9IDA7XG4gIHByaXZhdGUgdG90YWxTdGVwczogbnVtYmVyO1xuXG4gIGNvbnN0cnVjdG9yKGNvbmZpZzogUmVxdWlyZWQ8VHJhaW5pbmdDb25maWc+LCB0b3RhbFN0ZXBzOiBudW1iZXIpIHtcbiAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICB0aGlzLmluaXRpYWxMUiA9IGNvbmZpZy5sZWFybmluZ1JhdGU7XG4gICAgdGhpcy50b3RhbFN0ZXBzID0gdG90YWxTdGVwcztcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgbGVhcm5pbmcgcmF0ZSBmb3IgY3VycmVudCBzdGVwXG4gICAqL1xuICBnZXRMUigpOiBudW1iZXIge1xuICAgIHN3aXRjaCAodGhpcy5jb25maWcuc2NoZWR1bGVyKSB7XG4gICAgICBjYXNlICdjb25zdGFudCc6XG4gICAgICAgIHJldHVybiB0aGlzLmluaXRpYWxMUjtcblxuICAgICAgY2FzZSAnbGluZWFyJzpcbiAgICAgICAgcmV0dXJuIHRoaXMuaW5pdGlhbExSICogKDEgLSB0aGlzLmN1cnJlbnRTdGVwIC8gdGhpcy50b3RhbFN0ZXBzKTtcblxuICAgICAgY2FzZSAnY29zaW5lJzpcbiAgICAgICAgcmV0dXJuIHRoaXMuaW5pdGlhbExSICogMC41ICogKDEgKyBNYXRoLmNvcyhNYXRoLlBJICogdGhpcy5jdXJyZW50U3RlcCAvIHRoaXMudG90YWxTdGVwcykpO1xuXG4gICAgICBjYXNlICd3YXJtdXAnOlxuICAgICAgICBpZiAodGhpcy5jdXJyZW50U3RlcCA8IHRoaXMuY29uZmlnLndhcm11cFN0ZXBzKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMuaW5pdGlhbExSICogKHRoaXMuY3VycmVudFN0ZXAgLyB0aGlzLmNvbmZpZy53YXJtdXBTdGVwcyk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gQ29zaW5lIGRlY2F5IGFmdGVyIHdhcm11cFxuICAgICAgICBjb25zdCBkZWNheVN0ZXBzID0gdGhpcy50b3RhbFN0ZXBzIC0gdGhpcy5jb25maWcud2FybXVwU3RlcHM7XG4gICAgICAgIGNvbnN0IGRlY2F5UHJvZ3Jlc3MgPSAodGhpcy5jdXJyZW50U3RlcCAtIHRoaXMuY29uZmlnLndhcm11cFN0ZXBzKSAvIGRlY2F5U3RlcHM7XG4gICAgICAgIHJldHVybiB0aGlzLmluaXRpYWxMUiAqIDAuNSAqICgxICsgTWF0aC5jb3MoTWF0aC5QSSAqIGRlY2F5UHJvZ3Jlc3MpKTtcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIHRoaXMuaW5pdGlhbExSO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTdGVwIHRoZSBzY2hlZHVsZXJcbiAgICovXG4gIHN0ZXAoKTogdm9pZCB7XG4gICAgdGhpcy5jdXJyZW50U3RlcCsrO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc2V0IHNjaGVkdWxlclxuICAgKi9cbiAgcmVzZXQoKTogdm9pZCB7XG4gICAgdGhpcy5jdXJyZW50U3RlcCA9IDA7XG4gIH1cbn1cblxuLyoqXG4gKiBUcmFpbmluZyBNZXRyaWNzIFRyYWNrZXJcbiAqL1xuZXhwb3J0IGNsYXNzIE1ldHJpY3NUcmFja2VyIHtcbiAgcHJpdmF0ZSBsb3NzSGlzdG9yeTogbnVtYmVyW10gPSBbXTtcbiAgcHJpdmF0ZSB2YWxMb3NzSGlzdG9yeTogbnVtYmVyW10gPSBbXTtcbiAgcHJpdmF0ZSBncmFkTm9ybUhpc3Rvcnk6IG51bWJlcltdID0gW107XG4gIHByaXZhdGUgc3RhcnRUaW1lOiBudW1iZXIgPSBEYXRlLm5vdygpO1xuICBwcml2YXRlIHN0ZXBUaW1lczogbnVtYmVyW10gPSBbXTtcblxuICAvKipcbiAgICogUmVjb3JkIHRyYWluaW5nIGxvc3NcbiAgICovXG4gIHJlY29yZExvc3MobG9zczogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5sb3NzSGlzdG9yeS5wdXNoKGxvc3MpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlY29yZCB2YWxpZGF0aW9uIGxvc3NcbiAgICovXG4gIHJlY29yZFZhbExvc3MobG9zczogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy52YWxMb3NzSGlzdG9yeS5wdXNoKGxvc3MpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlY29yZCBncmFkaWVudCBub3JtXG4gICAqL1xuICByZWNvcmRHcmFkTm9ybShub3JtOiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLmdyYWROb3JtSGlzdG9yeS5wdXNoKG5vcm0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlY29yZCBzdGVwIHRpbWVcbiAgICovXG4gIHJlY29yZFN0ZXBUaW1lKG1zOiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLnN0ZXBUaW1lcy5wdXNoKG1zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgYXZlcmFnZSBsb3NzIG92ZXIgbGFzdCBOIHN0ZXBzXG4gICAqL1xuICBhdmdMb3NzKG46IG51bWJlciA9IDEwMCk6IG51bWJlciB7XG4gICAgY29uc3QgcmVjZW50ID0gdGhpcy5sb3NzSGlzdG9yeS5zbGljZSgtbik7XG4gICAgcmV0dXJuIHJlY2VudC5sZW5ndGggPiAwID8gcmVjZW50LnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApIC8gcmVjZW50Lmxlbmd0aCA6IDA7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGF2ZXJhZ2UgdmFsaWRhdGlvbiBsb3NzXG4gICAqL1xuICBhdmdWYWxMb3NzKG46IG51bWJlciA9IDEwKTogbnVtYmVyIHtcbiAgICBjb25zdCByZWNlbnQgPSB0aGlzLnZhbExvc3NIaXN0b3J5LnNsaWNlKC1uKTtcbiAgICByZXR1cm4gcmVjZW50Lmxlbmd0aCA+IDAgPyByZWNlbnQucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCkgLyByZWNlbnQubGVuZ3RoIDogMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgc3RlcHMgcGVyIHNlY29uZFxuICAgKi9cbiAgc3RlcHNQZXJTZWNvbmQoKTogbnVtYmVyIHtcbiAgICBpZiAodGhpcy5zdGVwVGltZXMubGVuZ3RoID09PSAwKSByZXR1cm4gMDtcbiAgICBjb25zdCBhdmdTdGVwVGltZSA9IHRoaXMuc3RlcFRpbWVzLnNsaWNlKC0xMDApLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApIC8gTWF0aC5taW4odGhpcy5zdGVwVGltZXMubGVuZ3RoLCAxMDApO1xuICAgIHJldHVybiBhdmdTdGVwVGltZSA+IDAgPyAxMDAwIC8gYXZnU3RlcFRpbWUgOiAwO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBFVEEgaW4gc2Vjb25kc1xuICAgKi9cbiAgZXRhKHJlbWFpbmluZ1N0ZXBzOiBudW1iZXIpOiBudW1iZXIge1xuICAgIGNvbnN0IHNwcyA9IHRoaXMuc3RlcHNQZXJTZWNvbmQoKTtcbiAgICByZXR1cm4gc3BzID4gMCA/IHJlbWFpbmluZ1N0ZXBzIC8gc3BzIDogMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgYmVzdCB2YWxpZGF0aW9uIGxvc3NcbiAgICovXG4gIGJlc3RWYWxMb3NzKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMudmFsTG9zc0hpc3RvcnkubGVuZ3RoID4gMCA/IE1hdGgubWluKC4uLnRoaXMudmFsTG9zc0hpc3RvcnkpIDogSW5maW5pdHk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRvdGFsIGR1cmF0aW9uXG4gICAqL1xuICBkdXJhdGlvbigpOiBudW1iZXIge1xuICAgIHJldHVybiBEYXRlLm5vdygpIC0gdGhpcy5zdGFydFRpbWU7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGFsbCBsb3NzIGhpc3RvcnlcbiAgICovXG4gIGdldExvc3NIaXN0b3J5KCk6IG51bWJlcltdIHtcbiAgICByZXR1cm4gWy4uLnRoaXMubG9zc0hpc3RvcnldO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhbGwgdmFsaWRhdGlvbiBsb3NzIGhpc3RvcnlcbiAgICovXG4gIGdldFZhbExvc3NIaXN0b3J5KCk6IG51bWJlcltdIHtcbiAgICByZXR1cm4gWy4uLnRoaXMudmFsTG9zc0hpc3RvcnldO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc2V0IHRyYWNrZXJcbiAgICovXG4gIHJlc2V0KCk6IHZvaWQge1xuICAgIHRoaXMubG9zc0hpc3RvcnkgPSBbXTtcbiAgICB0aGlzLnZhbExvc3NIaXN0b3J5ID0gW107XG4gICAgdGhpcy5ncmFkTm9ybUhpc3RvcnkgPSBbXTtcbiAgICB0aGlzLnN0ZXBUaW1lcyA9IFtdO1xuICAgIHRoaXMuc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgfVxufVxuXG4vKipcbiAqIFRyYWluaW5nIFBpcGVsaW5lXG4gKlxuICogRnVsbCB0cmFpbmluZyBpbmZyYXN0cnVjdHVyZSBmb3IgU09OQSBtb2RlbHMuXG4gKi9cbmV4cG9ydCBjbGFzcyBUcmFpbmluZ1BpcGVsaW5lIHtcbiAgcHJpdmF0ZSBjb25maWc6IFJlcXVpcmVkPFRyYWluaW5nQ29uZmlnPjtcbiAgcHJpdmF0ZSBhZGFwdGVyOiBMb3JhQWRhcHRlcjtcbiAgcHJpdmF0ZSBld2NNYW5hZ2VyOiBFd2NNYW5hZ2VyO1xuICBwcml2YXRlIG1ldHJpY3M6IE1ldHJpY3NUcmFja2VyO1xuICBwcml2YXRlIHNjaGVkdWxlcjogTFJTY2hlZHVsZXIgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBiYXRjaGVzOiBUcmFpbmluZ0JhdGNoW10gPSBbXTtcbiAgcHJpdmF0ZSBjaGVja3BvaW50czogQ2hlY2twb2ludFtdID0gW107XG4gIHByaXZhdGUgY3VycmVudEVwb2NoOiBudW1iZXIgPSAwO1xuICBwcml2YXRlIGN1cnJlbnRTdGVwOiBudW1iZXIgPSAwO1xuICBwcml2YXRlIGJlc3RWYWxMb3NzOiBudW1iZXIgPSBJbmZpbml0eTtcbiAgcHJpdmF0ZSBwYXRpZW5jZUNvdW50ZXI6IG51bWJlciA9IDA7XG5cbiAgY29uc3RydWN0b3IoY29uZmlnPzogVHJhaW5pbmdDb25maWcsIGFkYXB0ZXI/OiBMb3JhQWRhcHRlcikge1xuICAgIHRoaXMuY29uZmlnID0geyAuLi5ERUZBVUxUX1RSQUlOSU5HX0NPTkZJRywgLi4uY29uZmlnIH07XG4gICAgdGhpcy5hZGFwdGVyID0gYWRhcHRlciB8fCBuZXcgTG9yYUFkYXB0ZXIoeyByYW5rOiA4IH0pO1xuICAgIHRoaXMuZXdjTWFuYWdlciA9IG5ldyBFd2NNYW5hZ2VyKHRoaXMuY29uZmlnLmV3Y0xhbWJkYSk7XG4gICAgdGhpcy5tZXRyaWNzID0gbmV3IE1ldHJpY3NUcmFja2VyKCk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIHRyYWluaW5nIGJhdGNoXG4gICAqL1xuICBhZGRCYXRjaChpbnB1dHM6IEVtYmVkZGluZ1tdLCB0YXJnZXRzOiBFbWJlZGRpbmdbXSwgcXVhbGl0aWVzOiBudW1iZXJbXSk6IHZvaWQge1xuICAgIHRoaXMuYmF0Y2hlcy5wdXNoKHsgaW5wdXRzLCB0YXJnZXRzLCBxdWFsaXRpZXMgfSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIHRyYWluaW5nIGRhdGFcbiAgICovXG4gIGFkZERhdGEoZGF0YTogQXJyYXk8eyBpbnB1dDogRW1iZWRkaW5nOyB0YXJnZXQ6IEVtYmVkZGluZzsgcXVhbGl0eTogbnVtYmVyIH0+KTogdm9pZCB7XG4gICAgLy8gR3JvdXAgaW50byBiYXRjaGVzXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBkYXRhLmxlbmd0aDsgaSArPSB0aGlzLmNvbmZpZy5iYXRjaFNpemUpIHtcbiAgICAgIGNvbnN0IGJhdGNoID0gZGF0YS5zbGljZShpLCBpICsgdGhpcy5jb25maWcuYmF0Y2hTaXplKTtcbiAgICAgIHRoaXMuYWRkQmF0Y2goXG4gICAgICAgIGJhdGNoLm1hcChkID0+IGQuaW5wdXQpLFxuICAgICAgICBiYXRjaC5tYXAoZCA9PiBkLnRhcmdldCksXG4gICAgICAgIGJhdGNoLm1hcChkID0+IGQucXVhbGl0eSlcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1biB0cmFpbmluZ1xuICAgKi9cbiAgdHJhaW4oKTogVHJhaW5pbmdSZXN1bHQge1xuICAgIGNvbnN0IHRvdGFsU3RlcHMgPSB0aGlzLmJhdGNoZXMubGVuZ3RoICogdGhpcy5jb25maWcuZXBvY2hzO1xuICAgIHRoaXMuc2NoZWR1bGVyID0gbmV3IExSU2NoZWR1bGVyKHRoaXMuY29uZmlnLCB0b3RhbFN0ZXBzKTtcbiAgICB0aGlzLm1ldHJpY3MucmVzZXQoKTtcbiAgICB0aGlzLmFkYXB0ZXIuc3RhcnRUcmFpbmluZyh0aGlzLmNvbmZpZy5sZWFybmluZ1JhdGUpO1xuXG4gICAgbGV0IGVhcmx5U3RvcHBlZCA9IGZhbHNlO1xuXG4gICAgZm9yIChsZXQgZXBvY2ggPSAwOyBlcG9jaCA8IHRoaXMuY29uZmlnLmVwb2NoczsgZXBvY2grKykge1xuICAgICAgdGhpcy5jdXJyZW50RXBvY2ggPSBlcG9jaDtcblxuICAgICAgLy8gU2h1ZmZsZSBiYXRjaGVzXG4gICAgICBjb25zdCBzaHVmZmxlZEJhdGNoZXMgPSB0aGlzLnNodWZmbGVCYXRjaGVzKCk7XG5cbiAgICAgIC8vIFNwbGl0IGludG8gdHJhaW4vdmFsXG4gICAgICBjb25zdCB2YWxTaXplID0gTWF0aC5mbG9vcihzaHVmZmxlZEJhdGNoZXMubGVuZ3RoICogdGhpcy5jb25maWcudmFsaWRhdGlvblNwbGl0KTtcbiAgICAgIGNvbnN0IHRyYWluQmF0Y2hlcyA9IHNodWZmbGVkQmF0Y2hlcy5zbGljZSh2YWxTaXplKTtcbiAgICAgIGNvbnN0IHZhbEJhdGNoZXMgPSBzaHVmZmxlZEJhdGNoZXMuc2xpY2UoMCwgdmFsU2l6ZSk7XG5cbiAgICAgIC8vIFRyYWluaW5nIGVwb2NoXG4gICAgICBmb3IgKGNvbnN0IGJhdGNoIG9mIHRyYWluQmF0Y2hlcykge1xuICAgICAgICBjb25zdCBzdGVwU3RhcnQgPSBEYXRlLm5vdygpO1xuICAgICAgICBjb25zdCBsb3NzID0gdGhpcy50cmFpblN0ZXAoYmF0Y2gpO1xuICAgICAgICB0aGlzLm1ldHJpY3MucmVjb3JkTG9zcyhsb3NzKTtcbiAgICAgICAgdGhpcy5tZXRyaWNzLnJlY29yZFN0ZXBUaW1lKERhdGUubm93KCkgLSBzdGVwU3RhcnQpO1xuICAgICAgICB0aGlzLnNjaGVkdWxlci5zdGVwKCk7XG4gICAgICAgIHRoaXMuY3VycmVudFN0ZXArKztcbiAgICAgIH1cblxuICAgICAgLy8gVmFsaWRhdGlvblxuICAgICAgaWYgKHZhbEJhdGNoZXMubGVuZ3RoID4gMCkge1xuICAgICAgICBjb25zdCB2YWxMb3NzID0gdGhpcy52YWxpZGF0ZSh2YWxCYXRjaGVzKTtcbiAgICAgICAgdGhpcy5tZXRyaWNzLnJlY29yZFZhbExvc3ModmFsTG9zcyk7XG5cbiAgICAgICAgLy8gRWFybHkgc3RvcHBpbmdcbiAgICAgICAgaWYgKHZhbExvc3MgPCB0aGlzLmJlc3RWYWxMb3NzKSB7XG4gICAgICAgICAgdGhpcy5iZXN0VmFsTG9zcyA9IHZhbExvc3M7XG4gICAgICAgICAgdGhpcy5wYXRpZW5jZUNvdW50ZXIgPSAwO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMucGF0aWVuY2VDb3VudGVyKys7XG4gICAgICAgICAgaWYgKHRoaXMucGF0aWVuY2VDb3VudGVyID49IHRoaXMuY29uZmlnLmVhcmx5U3RvcHBpbmdQYXRpZW5jZSkge1xuICAgICAgICAgICAgZWFybHlTdG9wcGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBDaGVja3BvaW50XG4gICAgICBpZiAoKGVwb2NoICsgMSkgJSB0aGlzLmNvbmZpZy5jaGVja3BvaW50SW50ZXJ2YWwgPT09IDApIHtcbiAgICAgICAgdGhpcy5zYXZlQ2hlY2twb2ludCgpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMuYWRhcHRlci5lbmRUcmFpbmluZygpO1xuXG4gICAgLy8gUmVnaXN0ZXIgd2l0aCBFV0MgZm9yIGNvbnRpbnVhbCBsZWFybmluZ1xuICAgIGNvbnN0IHdlaWdodHMgPSB0aGlzLmFkYXB0ZXIubWVyZ2UoKS5mbGF0KCk7XG4gICAgdGhpcy5ld2NNYW5hZ2VyLnJlZ2lzdGVyVGFzayhgdGFzay0ke0RhdGUubm93KCl9YCwgd2VpZ2h0cyk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgZXBvY2hzOiB0aGlzLmN1cnJlbnRFcG9jaCArIDEsXG4gICAgICBzdGVwczogdGhpcy5jdXJyZW50U3RlcCxcbiAgICAgIGZpbmFsTG9zczogdGhpcy5tZXRyaWNzLmF2Z0xvc3MoMTAwKSxcbiAgICAgIGJlc3RWYWxMb3NzOiB0aGlzLmJlc3RWYWxMb3NzLFxuICAgICAgZHVyYXRpb25NczogdGhpcy5tZXRyaWNzLmR1cmF0aW9uKCksXG4gICAgICBsb3NzSGlzdG9yeTogdGhpcy5tZXRyaWNzLmdldExvc3NIaXN0b3J5KCksXG4gICAgICB2YWxMb3NzSGlzdG9yeTogdGhpcy5tZXRyaWNzLmdldFZhbExvc3NIaXN0b3J5KCksXG4gICAgICBlYXJseVN0b3BwZWQsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTaW5nbGUgdHJhaW5pbmcgc3RlcFxuICAgKi9cbiAgcHJpdmF0ZSB0cmFpblN0ZXAoYmF0Y2g6IFRyYWluaW5nQmF0Y2gpOiBudW1iZXIge1xuICAgIGxldCB0b3RhbExvc3MgPSAwO1xuICAgIGNvbnN0IGxyID0gdGhpcy5zY2hlZHVsZXI/LmdldExSKCkgfHwgdGhpcy5jb25maWcubGVhcm5pbmdSYXRlO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBiYXRjaC5pbnB1dHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGlucHV0ID0gYmF0Y2guaW5wdXRzW2ldO1xuICAgICAgY29uc3QgdGFyZ2V0ID0gYmF0Y2gudGFyZ2V0c1tpXTtcbiAgICAgIGNvbnN0IHF1YWxpdHkgPSBiYXRjaC5xdWFsaXRpZXNbaV07XG5cbiAgICAgIC8vIEZvcndhcmQgcGFzc1xuICAgICAgY29uc3Qgb3V0cHV0ID0gdGhpcy5hZGFwdGVyLmZvcndhcmQoaW5wdXQpO1xuXG4gICAgICAvLyBDb21wdXRlIGxvc3MgKE1TRSB3ZWlnaHRlZCBieSBxdWFsaXR5KVxuICAgICAgY29uc3QgZ3JhZE91dHB1dDogbnVtYmVyW10gPSBbXTtcbiAgICAgIGxldCBsb3NzID0gMDtcbiAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgb3V0cHV0Lmxlbmd0aDsgaisrKSB7XG4gICAgICAgIGNvbnN0IGRpZmYgPSBvdXRwdXRbal0gLSAodGFyZ2V0W2pdIHx8IDApO1xuICAgICAgICBsb3NzICs9IGRpZmYgKiBkaWZmO1xuICAgICAgICBncmFkT3V0cHV0LnB1c2goMiAqIGRpZmYgKiBxdWFsaXR5KTsgLy8gUXVhbGl0eS13ZWlnaHRlZCBncmFkaWVudFxuICAgICAgfVxuICAgICAgbG9zcyA9IChsb3NzIC8gb3V0cHV0Lmxlbmd0aCkgKiBxdWFsaXR5O1xuXG4gICAgICAvLyBBZGQgRVdDIHBlbmFsdHlcbiAgICAgIGNvbnN0IGV3Y1BlbmFsdHkgPSB0aGlzLmV3Y01hbmFnZXIuY29tcHV0ZVBlbmFsdHkodGhpcy5hZGFwdGVyLm1lcmdlKCkuZmxhdCgpKTtcbiAgICAgIGxvc3MgKz0gZXdjUGVuYWx0eSAqIDAuMDAxO1xuXG4gICAgICAvLyBCYWNrd2FyZCBwYXNzXG4gICAgICB0aGlzLmFkYXB0ZXIuYmFja3dhcmQoaW5wdXQsIGdyYWRPdXRwdXQsIGxyKTtcblxuICAgICAgdG90YWxMb3NzICs9IGxvc3M7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRvdGFsTG9zcyAvIGJhdGNoLmlucHV0cy5sZW5ndGg7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGlvbiBwYXNzXG4gICAqL1xuICBwcml2YXRlIHZhbGlkYXRlKGJhdGNoZXM6IFRyYWluaW5nQmF0Y2hbXSk6IG51bWJlciB7XG4gICAgbGV0IHRvdGFsTG9zcyA9IDA7XG4gICAgbGV0IGNvdW50ID0gMDtcblxuICAgIGZvciAoY29uc3QgYmF0Y2ggb2YgYmF0Y2hlcykge1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBiYXRjaC5pbnB1dHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgY29uc3Qgb3V0cHV0ID0gdGhpcy5hZGFwdGVyLmZvcndhcmQoYmF0Y2guaW5wdXRzW2ldKTtcbiAgICAgICAgY29uc3QgdGFyZ2V0ID0gYmF0Y2gudGFyZ2V0c1tpXTtcblxuICAgICAgICBsZXQgbG9zcyA9IDA7XG4gICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgb3V0cHV0Lmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgY29uc3QgZGlmZiA9IG91dHB1dFtqXSAtICh0YXJnZXRbal0gfHwgMCk7XG4gICAgICAgICAgbG9zcyArPSBkaWZmICogZGlmZjtcbiAgICAgICAgfVxuICAgICAgICB0b3RhbExvc3MgKz0gbG9zcyAvIG91dHB1dC5sZW5ndGg7XG4gICAgICAgIGNvdW50Kys7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGNvdW50ID4gMCA/IHRvdGFsTG9zcyAvIGNvdW50IDogMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTYXZlIGNoZWNrcG9pbnRcbiAgICovXG4gIHByaXZhdGUgc2F2ZUNoZWNrcG9pbnQoKTogdm9pZCB7XG4gICAgdGhpcy5jaGVja3BvaW50cy5wdXNoKHtcbiAgICAgIGVwb2NoOiB0aGlzLmN1cnJlbnRFcG9jaCxcbiAgICAgIHN0ZXA6IHRoaXMuY3VycmVudFN0ZXAsXG4gICAgICBsb3NzOiB0aGlzLm1ldHJpY3MuYXZnTG9zcygxMDApLFxuICAgICAgd2VpZ2h0czogdGhpcy5hZGFwdGVyLnRvSlNPTigpLFxuICAgICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIExvYWQgY2hlY2twb2ludFxuICAgKi9cbiAgbG9hZENoZWNrcG9pbnQoaW5kZXg6IG51bWJlcik6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGNoZWNrcG9pbnQgPSB0aGlzLmNoZWNrcG9pbnRzW2luZGV4XTtcbiAgICBpZiAoIWNoZWNrcG9pbnQpIHJldHVybiBmYWxzZTtcblxuICAgIHRoaXMuYWRhcHRlciA9IExvcmFBZGFwdGVyLmZyb21KU09OKGNoZWNrcG9pbnQud2VpZ2h0cyk7XG4gICAgdGhpcy5jdXJyZW50RXBvY2ggPSBjaGVja3BvaW50LmVwb2NoO1xuICAgIHRoaXMuY3VycmVudFN0ZXAgPSBjaGVja3BvaW50LnN0ZXA7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGN1cnJlbnQgbWV0cmljc1xuICAgKi9cbiAgZ2V0TWV0cmljcygpOiBUcmFpbmluZ01ldHJpY3Mge1xuICAgIHJldHVybiB7XG4gICAgICBlcG9jaDogdGhpcy5jdXJyZW50RXBvY2gsXG4gICAgICBzdGVwOiB0aGlzLmN1cnJlbnRTdGVwLFxuICAgICAgdHJhaW5Mb3NzOiB0aGlzLm1ldHJpY3MuYXZnTG9zcygxMDApLFxuICAgICAgdmFsTG9zczogdGhpcy5tZXRyaWNzLmF2Z1ZhbExvc3MoMTApLFxuICAgICAgbGVhcm5pbmdSYXRlOiB0aGlzLnNjaGVkdWxlcj8uZ2V0TFIoKSB8fCB0aGlzLmNvbmZpZy5sZWFybmluZ1JhdGUsXG4gICAgICBncmFkTm9ybTogMCxcbiAgICAgIHN0ZXBzUGVyU2Vjb25kOiB0aGlzLm1ldHJpY3Muc3RlcHNQZXJTZWNvbmQoKSxcbiAgICAgIGV0YVNlY29uZHM6IHRoaXMubWV0cmljcy5ldGEoXG4gICAgICAgICh0aGlzLmNvbmZpZy5lcG9jaHMgLSB0aGlzLmN1cnJlbnRFcG9jaCkgKiB0aGlzLmJhdGNoZXMubGVuZ3RoXG4gICAgICApLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogR2V0IGFkYXB0ZXJcbiAgICovXG4gIGdldEFkYXB0ZXIoKTogTG9yYUFkYXB0ZXIge1xuICAgIHJldHVybiB0aGlzLmFkYXB0ZXI7XG4gIH1cblxuICAvKipcbiAgICogR2V0IEVXQyBtYW5hZ2VyXG4gICAqL1xuICBnZXRFd2NNYW5hZ2VyKCk6IEV3Y01hbmFnZXIge1xuICAgIHJldHVybiB0aGlzLmV3Y01hbmFnZXI7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGNoZWNrcG9pbnRzXG4gICAqL1xuICBnZXRDaGVja3BvaW50cygpOiBDaGVja3BvaW50W10ge1xuICAgIHJldHVybiBbLi4udGhpcy5jaGVja3BvaW50c107XG4gIH1cblxuICAvKipcbiAgICogUmVzZXQgcGlwZWxpbmVcbiAgICovXG4gIHJlc2V0KCk6IHZvaWQge1xuICAgIHRoaXMuYmF0Y2hlcyA9IFtdO1xuICAgIHRoaXMuY2hlY2twb2ludHMgPSBbXTtcbiAgICB0aGlzLmN1cnJlbnRFcG9jaCA9IDA7XG4gICAgdGhpcy5jdXJyZW50U3RlcCA9IDA7XG4gICAgdGhpcy5iZXN0VmFsTG9zcyA9IEluZmluaXR5O1xuICAgIHRoaXMucGF0aWVuY2VDb3VudGVyID0gMDtcbiAgICB0aGlzLm1ldHJpY3MucmVzZXQoKTtcbiAgICB0aGlzLmFkYXB0ZXIucmVzZXQoKTtcbiAgfVxuXG4gIHByaXZhdGUgc2h1ZmZsZUJhdGNoZXMoKTogVHJhaW5pbmdCYXRjaFtdIHtcbiAgICBjb25zdCBzaHVmZmxlZCA9IFsuLi50aGlzLmJhdGNoZXNdO1xuICAgIGZvciAobGV0IGkgPSBzaHVmZmxlZC5sZW5ndGggLSAxOyBpID4gMDsgaS0tKSB7XG4gICAgICBjb25zdCBqID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogKGkgKyAxKSk7XG4gICAgICBbc2h1ZmZsZWRbaV0sIHNodWZmbGVkW2pdXSA9IFtzaHVmZmxlZFtqXSwgc2h1ZmZsZWRbaV1dO1xuICAgIH1cbiAgICByZXR1cm4gc2h1ZmZsZWQ7XG4gIH1cbn1cblxuLyoqXG4gKiBUcmFpbmluZyBGYWN0b3J5XG4gKlxuICogQ3JlYXRlIHByZS1jb25maWd1cmVkIHRyYWluaW5nIHBpcGVsaW5lcyBmb3IgY29tbW9uIHNjZW5hcmlvcy5cbiAqL1xuZXhwb3J0IGNsYXNzIFRyYWluaW5nRmFjdG9yeSB7XG4gIC8qKlxuICAgKiBDcmVhdGUgcGlwZWxpbmUgZm9yIHF1aWNrIGZpbmUtdHVuaW5nXG4gICAqL1xuICBzdGF0aWMgcXVpY2tGaW5ldHVuZSgpOiBUcmFpbmluZ1BpcGVsaW5lIHtcbiAgICByZXR1cm4gbmV3IFRyYWluaW5nUGlwZWxpbmUoe1xuICAgICAgbGVhcm5pbmdSYXRlOiAwLjAxLFxuICAgICAgZXBvY2hzOiAzLFxuICAgICAgYmF0Y2hTaXplOiAxNixcbiAgICAgIHNjaGVkdWxlcjogJ2NvbnN0YW50JyxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgcGlwZWxpbmUgZm9yIGRlZXAgdHJhaW5pbmdcbiAgICovXG4gIHN0YXRpYyBkZWVwVHJhaW5pbmcoKTogVHJhaW5pbmdQaXBlbGluZSB7XG4gICAgcmV0dXJuIG5ldyBUcmFpbmluZ1BpcGVsaW5lKHtcbiAgICAgIGxlYXJuaW5nUmF0ZTogMC4wMDEsXG4gICAgICBlcG9jaHM6IDUwLFxuICAgICAgYmF0Y2hTaXplOiAzMixcbiAgICAgIHNjaGVkdWxlcjogJ3dhcm11cCcsXG4gICAgICB3YXJtdXBTdGVwczogNTAwLFxuICAgICAgZWFybHlTdG9wcGluZ1BhdGllbmNlOiA1LFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBwaXBlbGluZSBmb3IgY29udGludWFsIGxlYXJuaW5nXG4gICAqL1xuICBzdGF0aWMgY29udGludWFsTGVhcm5pbmcoZXdjTGFtYmRhOiBudW1iZXIgPSA1MDAwKTogVHJhaW5pbmdQaXBlbGluZSB7XG4gICAgcmV0dXJuIG5ldyBUcmFpbmluZ1BpcGVsaW5lKHtcbiAgICAgIGxlYXJuaW5nUmF0ZTogMC4wMDA1LFxuICAgICAgZXBvY2hzOiAxMCxcbiAgICAgIGJhdGNoU2l6ZTogMTYsXG4gICAgICBzY2hlZHVsZXI6ICdjb3NpbmUnLFxuICAgICAgZXdjTGFtYmRhLFxuICAgICAgZWFybHlTdG9wcGluZ1BhdGllbmNlOiAxMCxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgcGlwZWxpbmUgZm9yIGZlZGVyYXRlZCBhZ2dyZWdhdGlvblxuICAgKi9cbiAgc3RhdGljIGZlZGVyYXRlZEFnZ3JlZ2F0aW9uKCk6IFRyYWluaW5nUGlwZWxpbmUge1xuICAgIHJldHVybiBuZXcgVHJhaW5pbmdQaXBlbGluZSh7XG4gICAgICBsZWFybmluZ1JhdGU6IDAuMDAwMSxcbiAgICAgIGVwb2NoczogNSxcbiAgICAgIGJhdGNoU2l6ZTogNjQsXG4gICAgICBzY2hlZHVsZXI6ICdsaW5lYXInLFxuICAgICAgZXdjTGFtYmRhOiAyMDAwLFxuICAgIH0pO1xuICB9XG59XG4iXX0=