@ruvector/ruvllm 0.2.4 → 2.4.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 (100) hide show
  1. package/README.md +413 -293
  2. package/bin/cli.js +619 -2
  3. package/dist/cjs/benchmarks/embedding-benchmark.d.ts +102 -0
  4. package/dist/cjs/benchmarks/embedding-benchmark.d.ts.map +1 -0
  5. package/dist/cjs/benchmarks/embedding-benchmark.js +436 -0
  6. package/dist/cjs/benchmarks/index.d.ts +34 -0
  7. package/dist/cjs/benchmarks/index.d.ts.map +1 -0
  8. package/dist/cjs/benchmarks/index.js +132 -0
  9. package/dist/cjs/benchmarks/model-comparison.d.ts +71 -0
  10. package/dist/cjs/benchmarks/model-comparison.d.ts.map +1 -0
  11. package/dist/cjs/benchmarks/model-comparison.js +476 -0
  12. package/dist/cjs/benchmarks/routing-benchmark.d.ts +70 -0
  13. package/dist/cjs/benchmarks/routing-benchmark.d.ts.map +1 -0
  14. package/dist/cjs/benchmarks/routing-benchmark.js +289 -0
  15. package/dist/cjs/contrastive.d.ts +229 -0
  16. package/dist/cjs/contrastive.d.ts.map +1 -0
  17. package/dist/cjs/contrastive.js +589 -0
  18. package/dist/cjs/engine.d.ts +3 -0
  19. package/dist/cjs/engine.d.ts.map +1 -1
  20. package/dist/cjs/engine.js +26 -6
  21. package/dist/cjs/index.d.ts +4 -0
  22. package/dist/cjs/index.d.ts.map +1 -1
  23. package/dist/cjs/index.js +9 -1
  24. package/dist/cjs/models.d.ts +129 -0
  25. package/dist/cjs/models.d.ts.map +1 -0
  26. package/dist/cjs/models.js +323 -0
  27. package/dist/cjs/native.d.ts +3 -3
  28. package/dist/cjs/native.d.ts.map +1 -1
  29. package/dist/cjs/native.js +1 -1
  30. package/dist/cjs/rlm/controller.d.ts +245 -0
  31. package/dist/cjs/rlm/controller.d.ts.map +1 -0
  32. package/dist/cjs/rlm/controller.js +554 -0
  33. package/dist/cjs/rlm/index.d.ts +62 -0
  34. package/dist/cjs/rlm/index.d.ts.map +1 -0
  35. package/dist/cjs/rlm/index.js +97 -0
  36. package/dist/cjs/rlm/training.d.ts +333 -0
  37. package/dist/cjs/rlm/training.d.ts.map +1 -0
  38. package/dist/cjs/rlm/training.js +680 -0
  39. package/dist/cjs/rlm/types.d.ts +189 -0
  40. package/dist/cjs/rlm/types.d.ts.map +1 -0
  41. package/dist/cjs/rlm/types.js +10 -0
  42. package/dist/esm/benchmarks/embedding-benchmark.d.ts +102 -0
  43. package/dist/esm/benchmarks/embedding-benchmark.d.ts.map +1 -0
  44. package/dist/esm/benchmarks/embedding-benchmark.js +427 -0
  45. package/dist/esm/benchmarks/index.d.ts +34 -0
  46. package/dist/esm/benchmarks/index.d.ts.map +1 -0
  47. package/dist/esm/benchmarks/index.js +110 -0
  48. package/dist/esm/benchmarks/model-comparison.d.ts +71 -0
  49. package/dist/esm/benchmarks/model-comparison.d.ts.map +1 -0
  50. package/dist/esm/benchmarks/model-comparison.js +434 -0
  51. package/dist/esm/benchmarks/routing-benchmark.d.ts +70 -0
  52. package/dist/esm/benchmarks/routing-benchmark.d.ts.map +1 -0
  53. package/dist/esm/benchmarks/routing-benchmark.js +283 -0
  54. package/dist/esm/contrastive.d.ts +229 -0
  55. package/dist/esm/contrastive.d.ts.map +1 -0
  56. package/dist/esm/contrastive.js +578 -0
  57. package/dist/esm/engine.d.ts +3 -0
  58. package/dist/esm/engine.d.ts.map +1 -1
  59. package/dist/esm/engine.js +26 -6
  60. package/dist/esm/index.d.ts +4 -0
  61. package/dist/esm/index.d.ts.map +1 -1
  62. package/dist/esm/index.js +9 -1
  63. package/dist/esm/models.d.ts +129 -0
  64. package/dist/esm/models.d.ts.map +1 -0
  65. package/dist/esm/models.js +282 -0
  66. package/dist/esm/native.d.ts +3 -3
  67. package/dist/esm/native.d.ts.map +1 -1
  68. package/dist/esm/native.js +1 -1
  69. package/dist/esm/rlm/controller.d.ts +245 -0
  70. package/dist/esm/rlm/controller.d.ts.map +1 -0
  71. package/dist/esm/rlm/controller.js +550 -0
  72. package/dist/esm/rlm/index.d.ts +62 -0
  73. package/dist/esm/rlm/index.d.ts.map +1 -0
  74. package/dist/esm/rlm/index.js +71 -0
  75. package/dist/esm/rlm/training.d.ts +333 -0
  76. package/dist/esm/rlm/training.d.ts.map +1 -0
  77. package/dist/esm/rlm/training.js +672 -0
  78. package/dist/esm/rlm/types.d.ts +189 -0
  79. package/dist/esm/rlm/types.d.ts.map +1 -0
  80. package/dist/esm/rlm/types.js +9 -0
  81. package/package.json +13 -8
  82. package/scripts/ensemble-model-compare.js +287 -0
  83. package/scripts/huggingface/README.md +537 -0
  84. package/scripts/huggingface/publish.sh +112 -0
  85. package/scripts/hybrid-model-compare.js +373 -0
  86. package/scripts/improved-model-compare.js +288 -0
  87. package/scripts/optimized-model-compare.js +364 -0
  88. package/scripts/real-model-compare.js +280 -0
  89. package/scripts/training/agentic-flow-capabilities.json +329 -0
  90. package/scripts/training/claude-code-synth.js +505 -0
  91. package/scripts/training/claude-flow-capabilities.json +1322 -0
  92. package/scripts/training/claude-hard-negatives.js +222 -0
  93. package/scripts/training/contrastive-finetune.js +517 -0
  94. package/scripts/training/ecosystem-triplets.jsonl +1467 -0
  95. package/scripts/training/generate-ecosystem-triplets.js +1324 -0
  96. package/scripts/training/rlm-dataset.js +671 -0
  97. package/scripts/training/routing-dataset.js +634 -0
  98. package/scripts/training/ruvector-capabilities.json +798 -0
  99. package/scripts/training/validate-ecosystem.js +381 -0
  100. package/scripts/training/validation-results.json +23 -0
@@ -0,0 +1,578 @@
1
+ /**
2
+ * Contrastive Fine-tuning for RuvLTRA Claude Code Router
3
+ *
4
+ * Uses triplet loss to fine-tune embeddings:
5
+ * - Anchor: task description
6
+ * - Positive: correct agent description
7
+ * - Negative: wrong agent description (hard negative)
8
+ *
9
+ * Goal: minimize distance(anchor, positive) and maximize distance(anchor, negative)
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * import { ContrastiveTrainer, tripletLoss, infoNCELoss } from '@ruvector/ruvllm';
14
+ *
15
+ * const trainer = new ContrastiveTrainer({
16
+ * epochs: 10,
17
+ * batchSize: 16,
18
+ * margin: 0.5,
19
+ * });
20
+ *
21
+ * // Add triplets
22
+ * trainer.addTriplet(anchorEmb, positiveEmb, negativeEmb, true);
23
+ *
24
+ * // Train and export
25
+ * const results = trainer.train();
26
+ * trainer.exportTrainingData('./output');
27
+ * ```
28
+ */
29
+ import { writeFileSync, mkdirSync, existsSync } from 'fs';
30
+ import { join } from 'path';
31
+ /**
32
+ * Default contrastive config
33
+ */
34
+ const DEFAULT_CONTRASTIVE_CONFIG = {
35
+ epochs: 10,
36
+ batchSize: 16,
37
+ learningRate: 0.0001,
38
+ margin: 0.5,
39
+ temperature: 0.07,
40
+ hardNegativeRatio: 0.7,
41
+ outputPath: './training-output',
42
+ };
43
+ /**
44
+ * Compute cosine similarity between two embeddings
45
+ */
46
+ export function cosineSimilarity(a, b) {
47
+ if (!a || !b || a.length !== b.length)
48
+ return 0;
49
+ let dot = 0, normA = 0, normB = 0;
50
+ for (let i = 0; i < a.length; i++) {
51
+ dot += a[i] * b[i];
52
+ normA += a[i] * a[i];
53
+ normB += b[i] * b[i];
54
+ }
55
+ return dot / (Math.sqrt(normA) * Math.sqrt(normB) || 1);
56
+ }
57
+ /**
58
+ * Compute triplet loss
59
+ * L = max(0, margin + d(anchor, positive) - d(anchor, negative))
60
+ */
61
+ export function tripletLoss(anchorEmb, positiveEmb, negativeEmb, margin = 0.5) {
62
+ const posDist = 1 - cosineSimilarity(anchorEmb, positiveEmb);
63
+ const negDist = 1 - cosineSimilarity(anchorEmb, negativeEmb);
64
+ return Math.max(0, margin + posDist - negDist);
65
+ }
66
+ /**
67
+ * Compute InfoNCE loss (contrastive)
68
+ */
69
+ export function infoNCELoss(anchorEmb, positiveEmb, negativeEmbs, temperature = 0.07) {
70
+ const posSim = cosineSimilarity(anchorEmb, positiveEmb) / temperature;
71
+ const negSims = negativeEmbs.map(neg => cosineSimilarity(anchorEmb, neg) / temperature);
72
+ // Softmax denominator
73
+ const maxSim = Math.max(posSim, ...negSims);
74
+ const expPos = Math.exp(posSim - maxSim);
75
+ const expNegs = negSims.map(sim => Math.exp(sim - maxSim));
76
+ const denominator = expPos + expNegs.reduce((a, b) => a + b, 0);
77
+ // Cross-entropy loss
78
+ return -Math.log(expPos / denominator);
79
+ }
80
+ /**
81
+ * Compute gradient for embedding update (simplified)
82
+ */
83
+ export function computeGradient(anchorEmb, positiveEmb, negativeEmb, lr = 0.0001) {
84
+ const dim = anchorEmb.length;
85
+ const gradient = new Array(dim).fill(0);
86
+ // Pull anchor towards positive
87
+ for (let i = 0; i < dim; i++) {
88
+ gradient[i] += lr * (positiveEmb[i] - anchorEmb[i]);
89
+ }
90
+ // Push anchor away from negative
91
+ for (let i = 0; i < dim; i++) {
92
+ gradient[i] -= lr * 0.5 * (negativeEmb[i] - anchorEmb[i]);
93
+ }
94
+ return gradient;
95
+ }
96
+ /**
97
+ * Contrastive Trainer for RuvLTRA models
98
+ *
99
+ * Implements triplet loss and InfoNCE loss for embedding fine-tuning.
100
+ */
101
+ export class ContrastiveTrainer {
102
+ constructor(config) {
103
+ this.triplets = [];
104
+ this.history = [];
105
+ this.agentEmbeddings = new Map();
106
+ this.config = { ...DEFAULT_CONTRASTIVE_CONFIG, ...config };
107
+ }
108
+ /**
109
+ * Add a training triplet
110
+ */
111
+ addTriplet(anchor, anchorEmb, positive, positiveEmb, negative, negativeEmb, isHard = false) {
112
+ this.triplets.push({
113
+ anchor,
114
+ anchorEmb,
115
+ positive,
116
+ positiveEmb,
117
+ negative,
118
+ negativeEmb,
119
+ isHard,
120
+ });
121
+ }
122
+ /**
123
+ * Add agent embedding for reference
124
+ */
125
+ addAgentEmbedding(agentName, embedding) {
126
+ this.agentEmbeddings.set(agentName, embedding);
127
+ }
128
+ /**
129
+ * Get all agent embeddings
130
+ */
131
+ getAgentEmbeddings() {
132
+ return this.agentEmbeddings;
133
+ }
134
+ /**
135
+ * Get triplet count
136
+ */
137
+ getTripletCount() {
138
+ return this.triplets.length;
139
+ }
140
+ /**
141
+ * Simulate training (compute losses without actual backprop)
142
+ * In a full implementation, this would use proper gradient descent
143
+ */
144
+ train() {
145
+ const startTime = Date.now();
146
+ const { epochs, batchSize, margin } = this.config;
147
+ if (this.triplets.length === 0) {
148
+ return {
149
+ tripletCount: 0,
150
+ finalLoss: 0,
151
+ initialLoss: 0,
152
+ improvement: 0,
153
+ history: [],
154
+ durationMs: 0,
155
+ };
156
+ }
157
+ for (let epoch = 0; epoch < epochs; epoch++) {
158
+ let epochLoss = 0;
159
+ let batchCount = 0;
160
+ // Shuffle triplets
161
+ const shuffled = [...this.triplets].sort(() => Math.random() - 0.5);
162
+ for (let i = 0; i < shuffled.length; i += batchSize) {
163
+ const batch = shuffled.slice(i, i + batchSize);
164
+ let batchLoss = 0;
165
+ for (const triplet of batch) {
166
+ const loss = tripletLoss(triplet.anchorEmb, triplet.positiveEmb, triplet.negativeEmb, margin);
167
+ batchLoss += loss;
168
+ }
169
+ epochLoss += batchLoss / batch.length;
170
+ batchCount++;
171
+ }
172
+ const avgLoss = epochLoss / batchCount;
173
+ this.history.push({ epoch: epoch + 1, loss: avgLoss });
174
+ }
175
+ const initialLoss = this.history[0]?.loss || 0;
176
+ const finalLoss = this.history[this.history.length - 1]?.loss || 0;
177
+ const improvement = initialLoss > 0 ? (1 - finalLoss / initialLoss) * 100 : 0;
178
+ return {
179
+ tripletCount: this.triplets.length,
180
+ finalLoss,
181
+ initialLoss,
182
+ improvement,
183
+ history: this.history,
184
+ durationMs: Date.now() - startTime,
185
+ };
186
+ }
187
+ /**
188
+ * Export training data for external fine-tuning tools
189
+ */
190
+ exportTrainingData(outputPath) {
191
+ const outDir = outputPath || this.config.outputPath;
192
+ if (!existsSync(outDir)) {
193
+ mkdirSync(outDir, { recursive: true });
194
+ }
195
+ // JSONL format for fine-tuning
196
+ const jsonlData = this.triplets.map(t => ({
197
+ anchor: t.anchor,
198
+ positive: t.positive,
199
+ negative: t.negative,
200
+ isHard: t.isHard,
201
+ }));
202
+ // CSV format for analysis
203
+ const csvData = [
204
+ 'anchor,positive,negative,is_hard',
205
+ ...this.triplets.map(t => `"${t.anchor.replace(/"/g, '""')}",${t.positive},${t.negative},${t.isHard}`),
206
+ ].join('\n');
207
+ // Embedding matrix for direct training
208
+ const embeddingData = {
209
+ anchors: this.triplets.map(t => t.anchorEmb),
210
+ positives: this.triplets.map(t => t.positiveEmb),
211
+ negatives: this.triplets.map(t => t.negativeEmb),
212
+ labels: this.triplets.map(t => t.positive),
213
+ };
214
+ writeFileSync(join(outDir, 'triplets.jsonl'), jsonlData.map(item => JSON.stringify(item)).join('\n'));
215
+ writeFileSync(join(outDir, 'triplets.csv'), csvData);
216
+ writeFileSync(join(outDir, 'embeddings.json'), JSON.stringify(embeddingData, null, 2));
217
+ return outDir;
218
+ }
219
+ /**
220
+ * Generate LoRA adapter configuration
221
+ */
222
+ generateLoRAConfig(outputPath) {
223
+ const outDir = outputPath || this.config.outputPath;
224
+ const loraConfig = {
225
+ model_type: 'qwen2',
226
+ base_model: 'Qwen/Qwen2.5-0.5B',
227
+ output_dir: outDir,
228
+ lora_r: 8,
229
+ lora_alpha: 16,
230
+ lora_dropout: 0.05,
231
+ target_modules: ['q_proj', 'v_proj', 'k_proj', 'o_proj'],
232
+ learning_rate: this.config.learningRate,
233
+ num_train_epochs: this.config.epochs,
234
+ per_device_train_batch_size: this.config.batchSize,
235
+ gradient_accumulation_steps: 4,
236
+ warmup_ratio: 0.1,
237
+ loss_type: 'triplet',
238
+ margin: this.config.margin,
239
+ temperature: this.config.temperature,
240
+ train_data: join(outDir, 'triplets.jsonl'),
241
+ eval_data: join(outDir, 'eval.jsonl'),
242
+ };
243
+ if (!existsSync(outDir)) {
244
+ mkdirSync(outDir, { recursive: true });
245
+ }
246
+ writeFileSync(join(outDir, 'lora_config.json'), JSON.stringify(loraConfig, null, 2));
247
+ return loraConfig;
248
+ }
249
+ /**
250
+ * Generate training script for external tools
251
+ */
252
+ generateTrainingScript(outputPath) {
253
+ const outDir = outputPath || this.config.outputPath;
254
+ const script = `#!/bin/bash
255
+ # RuvLTRA Fine-tuning Script
256
+ # Prerequisites: pip install transformers peft accelerate
257
+
258
+ set -e
259
+
260
+ MODEL_PATH="${outDir}"
261
+ BASE_MODEL="Qwen/Qwen2.5-0.5B"
262
+
263
+ echo "=== RuvLTRA Contrastive Fine-tuning ==="
264
+ echo "Base model: $BASE_MODEL"
265
+ echo "Output: $MODEL_PATH"
266
+
267
+ # Check for training data
268
+ if [ ! -f "$MODEL_PATH/triplets.jsonl" ]; then
269
+ echo "Error: Training data not found at $MODEL_PATH/triplets.jsonl"
270
+ exit 1
271
+ fi
272
+
273
+ # Install dependencies if needed
274
+ python3 -c "import transformers, peft" 2>/dev/null || {
275
+ echo "Installing dependencies..."
276
+ pip install transformers peft accelerate sentencepiece
277
+ }
278
+
279
+ # Fine-tune with LoRA
280
+ python3 << 'PYTHON'
281
+ import json
282
+ import torch
283
+ from pathlib import Path
284
+ from transformers import AutoModelForCausalLM, AutoTokenizer
285
+ from peft import LoraConfig, get_peft_model, TaskType
286
+
287
+ # Load config
288
+ config_path = Path("${outDir}/lora_config.json")
289
+ with open(config_path) as f:
290
+ config = json.load(f)
291
+
292
+ print(f"Loading base model: {config['base_model']}")
293
+
294
+ # Load model and tokenizer
295
+ tokenizer = AutoTokenizer.from_pretrained(config['base_model'])
296
+ model = AutoModelForCausalLM.from_pretrained(
297
+ config['base_model'],
298
+ torch_dtype=torch.float16,
299
+ device_map='auto'
300
+ )
301
+
302
+ # Configure LoRA
303
+ lora_config = LoraConfig(
304
+ r=config['lora_r'],
305
+ lora_alpha=config['lora_alpha'],
306
+ lora_dropout=config['lora_dropout'],
307
+ target_modules=config['target_modules'],
308
+ task_type=TaskType.CAUSAL_LM,
309
+ )
310
+
311
+ model = get_peft_model(model, lora_config)
312
+ model.print_trainable_parameters()
313
+
314
+ print("Model ready for fine-tuning!")
315
+ print(f"Training data: {config['train_data']}")
316
+ print("Note: Full training requires GPU. This script validates the setup.")
317
+ PYTHON
318
+
319
+ echo ""
320
+ echo "=== Setup Complete ==="
321
+ echo "To train on GPU, run the full training pipeline."
322
+ echo "Training data exported to: $MODEL_PATH/triplets.jsonl"
323
+ `;
324
+ if (!existsSync(outDir)) {
325
+ mkdirSync(outDir, { recursive: true });
326
+ }
327
+ const scriptPath = join(outDir, 'train.sh');
328
+ writeFileSync(scriptPath, script);
329
+ return scriptPath;
330
+ }
331
+ /**
332
+ * Get training history
333
+ */
334
+ getHistory() {
335
+ return [...this.history];
336
+ }
337
+ /**
338
+ * Reset trainer
339
+ */
340
+ reset() {
341
+ this.triplets = [];
342
+ this.history = [];
343
+ }
344
+ }
345
+ /**
346
+ * Agent Training Data for Claude Code Router
347
+ */
348
+ export const AGENT_TRAINING_DATA = {
349
+ coder: {
350
+ description: 'Implementation specialist for writing clean, efficient code. Handles coding tasks, feature implementation, and code generation.',
351
+ keywords: ['implement', 'code', 'write', 'build', 'create', 'develop', 'function', 'class', 'component', 'feature'],
352
+ examples: [
353
+ 'Implement a binary search function',
354
+ 'Write a React component for user registration',
355
+ 'Create a REST API endpoint for user authentication',
356
+ 'Build a caching layer for the database queries',
357
+ ],
358
+ confusing_with: ['refactorer', 'debugger'],
359
+ },
360
+ tester: {
361
+ description: 'Testing specialist for writing and maintaining tests. Creates unit tests, integration tests, and ensures code quality through testing.',
362
+ keywords: ['test', 'unit test', 'integration test', 'coverage', 'mock', 'assertion', 'spec', 'jest', 'pytest'],
363
+ examples: [
364
+ 'Write unit tests for the authentication module',
365
+ 'Add integration tests for the payment gateway',
366
+ 'Create test coverage for the user service',
367
+ 'Write e2e tests for the checkout flow',
368
+ ],
369
+ confusing_with: ['reviewer'],
370
+ },
371
+ reviewer: {
372
+ description: 'Code review specialist for analyzing code quality, identifying issues, and suggesting improvements.',
373
+ keywords: ['review', 'analyze', 'check', 'inspect', 'audit', 'evaluate', 'assess', 'critique'],
374
+ examples: [
375
+ 'Review the pull request for code quality',
376
+ 'Check the code for potential security vulnerabilities',
377
+ 'Analyze the implementation for best practices',
378
+ 'Evaluate the architecture decisions in this PR',
379
+ ],
380
+ confusing_with: ['tester', 'security-architect'],
381
+ },
382
+ researcher: {
383
+ description: 'Research specialist for investigating technologies, gathering information, and analyzing options.',
384
+ keywords: ['research', 'investigate', 'explore', 'analyze', 'study', 'compare', 'evaluate', 'learn'],
385
+ examples: [
386
+ 'Research best practices for React state management',
387
+ 'Investigate the performance issues in the dashboard',
388
+ 'Compare different authentication strategies',
389
+ 'Study the codebase architecture for the new feature',
390
+ ],
391
+ confusing_with: ['planner'],
392
+ },
393
+ architect: {
394
+ description: 'System architect for designing software architecture, making technical decisions, and planning system structure.',
395
+ keywords: ['design', 'architect', 'structure', 'plan', 'schema', 'model', 'pattern', 'system'],
396
+ examples: [
397
+ 'Design the database schema for user profiles',
398
+ 'Plan the architecture for real-time notifications',
399
+ 'Create a system design for the microservices migration',
400
+ 'Design the API structure for the new product catalog',
401
+ ],
402
+ confusing_with: ['planner'],
403
+ },
404
+ debugger: {
405
+ description: 'Debugging specialist for finding and fixing bugs, analyzing errors, and troubleshooting issues.',
406
+ keywords: ['debug', 'fix', 'bug', 'error', 'issue', 'crash', 'exception', 'troubleshoot'],
407
+ examples: [
408
+ 'Fix the null pointer exception in the login handler',
409
+ 'Debug the memory leak in the WebSocket handler',
410
+ 'Troubleshoot the race condition in the payment processor',
411
+ 'Find the root cause of the intermittent test failures',
412
+ ],
413
+ confusing_with: ['coder'],
414
+ },
415
+ 'security-architect': {
416
+ description: 'Security specialist for auditing code security, identifying vulnerabilities, and implementing security measures.',
417
+ keywords: ['security', 'vulnerability', 'xss', 'sql injection', 'auth', 'encryption', 'audit', 'penetration'],
418
+ examples: [
419
+ 'Audit the API endpoints for XSS vulnerabilities',
420
+ 'Review the authentication flow for security issues',
421
+ 'Implement input validation for the user forms',
422
+ 'Check for SQL injection vulnerabilities in the search',
423
+ ],
424
+ confusing_with: ['reviewer'],
425
+ },
426
+ documenter: {
427
+ description: 'Documentation specialist for writing technical documentation, comments, and API docs.',
428
+ keywords: ['document', 'comment', 'jsdoc', 'readme', 'docs', 'explain', 'describe', 'annotate'],
429
+ examples: [
430
+ 'Write JSDoc comments for the utility functions',
431
+ 'Create README documentation for the new module',
432
+ 'Document the API endpoints with examples',
433
+ 'Add inline comments explaining the algorithm',
434
+ ],
435
+ confusing_with: ['api-docs'],
436
+ },
437
+ refactorer: {
438
+ description: 'Refactoring specialist for improving code structure, cleaning up technical debt, and modernizing codebases.',
439
+ keywords: ['refactor', 'clean', 'restructure', 'modernize', 'improve', 'simplify', 'extract', 'rename'],
440
+ examples: [
441
+ 'Refactor the payment module to use async/await',
442
+ 'Clean up the legacy authentication code',
443
+ 'Extract common logic into a shared utility',
444
+ 'Simplify the complex conditional logic in checkout',
445
+ ],
446
+ confusing_with: ['coder'],
447
+ },
448
+ optimizer: {
449
+ description: 'Performance optimization specialist for improving speed, reducing memory usage, and optimizing queries.',
450
+ keywords: ['optimize', 'performance', 'speed', 'memory', 'cache', 'index', 'query', 'latency'],
451
+ examples: [
452
+ 'Optimize the database queries for the dashboard',
453
+ 'Improve the page load time for the homepage',
454
+ 'Add caching to reduce API response times',
455
+ 'Reduce memory usage in the image processing pipeline',
456
+ ],
457
+ confusing_with: ['researcher'],
458
+ },
459
+ devops: {
460
+ description: 'DevOps specialist for CI/CD pipelines, deployment automation, and infrastructure management.',
461
+ keywords: ['deploy', 'ci/cd', 'pipeline', 'docker', 'kubernetes', 'terraform', 'aws', 'infrastructure'],
462
+ examples: [
463
+ 'Set up the CI/CD pipeline for the microservices',
464
+ 'Configure Docker containers for the application',
465
+ 'Deploy the application to the staging environment',
466
+ 'Create Terraform scripts for the AWS infrastructure',
467
+ ],
468
+ confusing_with: [],
469
+ },
470
+ 'api-docs': {
471
+ description: 'API documentation specialist for creating OpenAPI specs, Swagger documentation, and API references.',
472
+ keywords: ['openapi', 'swagger', 'api docs', 'endpoint', 'specification', 'schema', 'rest'],
473
+ examples: [
474
+ 'Generate OpenAPI documentation for the REST API',
475
+ 'Create Swagger specs for the user endpoints',
476
+ 'Document the API authentication requirements',
477
+ 'Update the API reference with new endpoints',
478
+ ],
479
+ confusing_with: ['documenter'],
480
+ },
481
+ planner: {
482
+ description: 'Project planning specialist for creating task plans, sprint planning, and roadmap development.',
483
+ keywords: ['plan', 'roadmap', 'sprint', 'milestone', 'timeline', 'estimate', 'breakdown', 'prioritize'],
484
+ examples: [
485
+ 'Create a sprint plan for the next two weeks',
486
+ 'Break down the feature into smaller tasks',
487
+ 'Estimate the effort for the migration project',
488
+ 'Prioritize the bug fixes for the release',
489
+ ],
490
+ confusing_with: ['architect', 'researcher'],
491
+ },
492
+ };
493
+ /**
494
+ * Generate training dataset from agent data
495
+ */
496
+ export function generateTrainingDataset() {
497
+ const examples = [];
498
+ for (const [agent, data] of Object.entries(AGENT_TRAINING_DATA)) {
499
+ // Add direct examples
500
+ for (const example of data.examples) {
501
+ examples.push({
502
+ task: example,
503
+ agent,
504
+ complexity: 'medium',
505
+ });
506
+ }
507
+ // Generate variations with keywords
508
+ for (const keyword of data.keywords) {
509
+ examples.push({
510
+ task: `${keyword} a solution for the authentication system`,
511
+ agent,
512
+ complexity: 'low',
513
+ });
514
+ }
515
+ // Add confusing pairs for hard negatives
516
+ if (data.confusing_with) {
517
+ for (const confusingAgent of data.confusing_with) {
518
+ for (const example of data.examples.slice(0, 2)) {
519
+ examples.push({
520
+ task: example,
521
+ agent,
522
+ complexity: 'hard',
523
+ confusing_with: confusingAgent,
524
+ });
525
+ }
526
+ }
527
+ }
528
+ }
529
+ return examples;
530
+ }
531
+ /**
532
+ * Generate contrastive pairs for training
533
+ */
534
+ export function generateContrastivePairs() {
535
+ const pairs = [];
536
+ const agents = Object.keys(AGENT_TRAINING_DATA);
537
+ for (const [agent, data] of Object.entries(AGENT_TRAINING_DATA)) {
538
+ for (const example of data.examples) {
539
+ // Hard negatives from confusing agents
540
+ if (data.confusing_with) {
541
+ for (const negAgent of data.confusing_with) {
542
+ pairs.push({
543
+ anchor: example,
544
+ positive: agent,
545
+ negative: negAgent,
546
+ isHard: true,
547
+ });
548
+ }
549
+ }
550
+ // Random negatives
551
+ const randomNegs = agents.filter(a => a !== agent).slice(0, 2);
552
+ for (const negAgent of randomNegs) {
553
+ pairs.push({
554
+ anchor: example,
555
+ positive: agent,
556
+ negative: negAgent,
557
+ isHard: false,
558
+ });
559
+ }
560
+ }
561
+ }
562
+ return pairs;
563
+ }
564
+ /**
565
+ * Get dataset statistics
566
+ */
567
+ export function getDatasetStats() {
568
+ const examples = generateTrainingDataset();
569
+ const pairs = generateContrastivePairs();
570
+ const agents = Object.keys(AGENT_TRAINING_DATA);
571
+ return {
572
+ totalExamples: examples.length,
573
+ contrastivePairs: pairs.length,
574
+ agentTypes: agents.length,
575
+ agents,
576
+ };
577
+ }
578
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udHJhc3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29udHJhc3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTJCRztBQUVILE9BQU8sRUFBRSxhQUFhLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxNQUFNLElBQUksQ0FBQztBQUMxRCxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBeUY1Qjs7R0FFRztBQUNILE1BQU0sMEJBQTBCLEdBQWdDO0lBQzlELE1BQU0sRUFBRSxFQUFFO0lBQ1YsU0FBUyxFQUFFLEVBQUU7SUFDYixZQUFZLEVBQUUsTUFBTTtJQUNwQixNQUFNLEVBQUUsR0FBRztJQUNYLFdBQVcsRUFBRSxJQUFJO0lBQ2pCLGlCQUFpQixFQUFFLEdBQUc7SUFDdEIsVUFBVSxFQUFFLG1CQUFtQjtDQUNoQyxDQUFDO0FBRUY7O0dBRUc7QUFDSCxNQUFNLFVBQVUsZ0JBQWdCLENBQUMsQ0FBWSxFQUFFLENBQVk7SUFDekQsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsQ0FBQyxNQUFNO1FBQUUsT0FBTyxDQUFDLENBQUM7SUFDaEQsSUFBSSxHQUFHLEdBQUcsQ0FBQyxFQUFFLEtBQUssR0FBRyxDQUFDLEVBQUUsS0FBSyxHQUFHLENBQUMsQ0FBQztJQUNsQyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQ2xDLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ25CLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3JCLEtBQUssSUFB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LENBQUM7SUFFaEQsT0FBTztRQUNMLGFBQWEsRUFBRSxRQUFRLENBQUMsTUFBTTtRQUM5QixnQkFBZ0IsRUFBRSxLQUFLLENBQUMsTUFBTTtRQUM5QixVQUFVLEVBQUUsTUFBTSxDQUFDLE1BQU07UUFDekIsTUFBTTtLQUNQLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb250cmFzdGl2ZSBGaW5lLXR1bmluZyBmb3IgUnV2TFRSQSBDbGF1ZGUgQ29kZSBSb3V0ZXJcbiAqXG4gKiBVc2VzIHRyaXBsZXQgbG9zcyB0byBmaW5lLXR1bmUgZW1iZWRkaW5nczpcbiAqIC0gQW5jaG9yOiB0YXNrIGRlc2NyaXB0aW9uXG4gKiAtIFBvc2l0aXZlOiBjb3JyZWN0IGFnZW50IGRlc2NyaXB0aW9uXG4gKiAtIE5lZ2F0aXZlOiB3cm9uZyBhZ2VudCBkZXNjcmlwdGlvbiAoaGFyZCBuZWdhdGl2ZSlcbiAqXG4gKiBHb2FsOiBtaW5pbWl6ZSBkaXN0YW5jZShhbmNob3IsIHBvc2l0aXZlKSBhbmQgbWF4aW1pemUgZGlzdGFuY2UoYW5jaG9yLCBuZWdhdGl2ZSlcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgQ29udHJhc3RpdmVUcmFpbmVyLCB0cmlwbGV0TG9zcywgaW5mb05DRUxvc3MgfSBmcm9tICdAcnV2ZWN0b3IvcnV2bGxtJztcbiAqXG4gKiBjb25zdCB0cmFpbmVyID0gbmV3IENvbnRyYXN0aXZlVHJhaW5lcih7XG4gKiAgIGVwb2NoczogMTAsXG4gKiAgIGJhdGNoU2l6ZTogMTYsXG4gKiAgIG1hcmdpbjogMC41LFxuICogfSk7XG4gKlxuICogLy8gQWRkIHRyaXBsZXRzXG4gKiB0cmFpbmVyLmFkZFRyaXBsZXQoYW5jaG9yRW1iLCBwb3NpdGl2ZUVtYiwgbmVnYXRpdmVFbWIsIHRydWUpO1xuICpcbiAqIC8vIFRyYWluIGFuZCBleHBvcnRcbiAqIGNvbnN0IHJlc3VsdHMgPSB0cmFpbmVyLnRyYWluKCk7XG4gKiB0cmFpbmVyLmV4cG9ydFRyYWluaW5nRGF0YSgnLi9vdXRwdXQnKTtcbiAqIGBgYFxuICovXG5cbmltcG9ydCB7IHdyaXRlRmlsZVN5bmMsIG1rZGlyU3luYywgZXhpc3RzU3luYyB9IGZyb20gJ2ZzJztcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcbmltcG9ydCB7IEVtYmVkZGluZyB9IGZyb20gJy4vdHlwZXMnO1xuXG4vKipcbiAqIENvbnRyYXN0aXZlIHRyYWluaW5nIGNvbmZpZ3VyYXRpb25cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDb250cmFzdGl2ZUNvbmZpZyB7XG4gIC8qKiBOdW1iZXIgb2YgdHJhaW5pbmcgZXBvY2hzIChkZWZhdWx0OiAxMCkgKi9cbiAgZXBvY2hzPzogbnVtYmVyO1xuICAvKiogQmF0Y2ggc2l6ZSAoZGVmYXVsdDogMTYpICovXG4gIGJhdGNoU2l6ZT86IG51bWJlcjtcbiAgLyoqIExlYXJuaW5nIHJhdGUgKGRlZmF1bHQ6IDAuMDAwMSkgKi9cbiAgbGVhcm5pbmdSYXRlPzogbnVtYmVyO1xuICAvKiogVHJpcGxldCBsb3NzIG1hcmdpbiAoZGVmYXVsdDogMC41KSAqL1xuICBtYXJnaW4/OiBudW1iZXI7XG4gIC8qKiBJbmZvTkNFIHRlbXBlcmF0dXJlIChkZWZhdWx0OiAwLjA3KSAqL1xuICB0ZW1wZXJhdHVyZT86IG51bWJlcjtcbiAgLyoqIFJhdGlvIG9mIGhhcmQgbmVnYXRpdmVzIChkZWZhdWx0OiAwLjcpICovXG4gIGhhcmROZWdhdGl2ZVJhdGlvPzogbnVtYmVyO1xuICAvKiogT3V0cHV0IGRpcmVjdG9yeSBmb3IgdHJhaW5pbmcgZGF0YSAqL1xuICBvdXRwdXRQYXRoPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFRyYWluaW5nIHRyaXBsZXRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBUcmFpbmluZ1RyaXBsZXQge1xuICAvKiogQW5jaG9yIGVtYmVkZGluZyAodGFzaykgKi9cbiAgYW5jaG9yOiBzdHJpbmc7XG4gIGFuY2hvckVtYjogRW1iZWRkaW5nO1xuICAvKiogUG9zaXRpdmUgZXhhbXBsZSAoY29ycmVjdCBhZ2VudCkgKi9cbiAgcG9zaXRpdmU6IHN0cmluZztcbiAgcG9zaXRpdmVFbWI6IEVtYmVkZGluZztcbiAgLyoqIE5lZ2F0aXZlIGV4YW1wbGUgKHdyb25nIGFnZW50KSAqL1xuICBuZWdhdGl2ZTogc3RyaW5nO1xuICBuZWdhdGl2ZUVtYjogRW1iZWRkaW5nO1xuICAvKiogV2hldGhlciB0aGlzIGlzIGEgaGFyZCBuZWdhdGl2ZSAqL1xuICBpc0hhcmQ6IGJvb2xlYW47XG59XG5cbi8qKlxuICogVHJhaW5pbmcgaGlzdG9yeSBlbnRyeVxuICovXG5leHBvcnQgaW50ZXJmYWNlIFRyYWluaW5nSGlzdG9yeUVudHJ5IHtcbiAgZXBvY2g6IG51bWJlcjtcbiAgbG9zczogbnVtYmVyO1xufVxuXG4vKipcbiAqIENvbnRyYXN0aXZlIHRyYWluaW5nIHJlc3VsdHNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDb250cmFzdGl2ZVRyYWluaW5nUmVzdWx0IHtcbiAgLyoqIFRvdGFsIHRyaXBsZXRzIHRyYWluZWQgb24gKi9cbiAgdHJpcGxldENvdW50OiBudW1iZXI7XG4gIC8qKiBGaW5hbCBsb3NzIHZhbHVlICovXG4gIGZpbmFsTG9zczogbnVtYmVyO1xuICAvKiogSW5pdGlhbCBsb3NzIHZhbHVlICovXG4gIGluaXRpYWxMb3NzOiBudW1iZXI7XG4gIC8qKiBJbXByb3ZlbWVudCBwZXJjZW50YWdlICovXG4gIGltcHJvdmVtZW50OiBudW1iZXI7XG4gIC8qKiBUcmFpbmluZyBoaXN0b3J5ICovXG4gIGhpc3Rvcnk6IFRyYWluaW5nSGlzdG9yeUVudHJ5W107XG4gIC8qKiBEdXJhdGlvbiBpbiBtcyAqL1xuICBkdXJhdGlvbk1zOiBudW1iZXI7XG59XG5cbi8qKlxuICogTG9SQSBjb25maWd1cmF0aW9uIGZvciBmaW5lLXR1bmluZ1xuICovXG5leHBvcnQgaW50ZXJmYWNlIExvUkFFeHBvcnRDb25maWcge1xuICBtb2RlbF90eXBlOiBzdHJpbmc7XG4gIGJhc2VfbW9kZWw6IHN0cmluZztcbiAgb3V0cHV0X2Rpcjogc3RyaW5nO1xuICBsb3JhX3I6IG51bWJlcjtcbiAgbG9yYV9hbHBoYTogbnVtYmVyO1xuICBsb3JhX2Ryb3BvdXQ6IG51bWJlcjtcbiAgdGFyZ2V0X21vZHVsZXM6IHN0cmluZ1tdO1xuICBsZWFybmluZ19yYXRlOiBudW1iZXI7XG4gIG51bV90cmFpbl9lcG9jaHM6IG51bWJlcjtcbiAgcGVyX2RldmljZV90cmFpbl9iYXRjaF9zaXplOiBudW1iZXI7XG4gIGdyYWRpZW50X2FjY3VtdWxhdGlvbl9zdGVwczogbnVtYmVyO1xuICB3YXJtdXBfcmF0aW86IG51bWJlcjtcbiAgbG9zc190eXBlOiBzdHJpbmc7XG4gIG1hcmdpbjogbnVtYmVyO1xuICB0ZW1wZXJhdHVyZTogbnVtYmVyO1xuICB0cmFpbl9kYXRhOiBzdHJpbmc7XG4gIGV2YWxfZGF0YTogc3RyaW5nO1xufVxuXG4vKipcbiAqIERlZmF1bHQgY29udHJhc3RpdmUgY29uZmlnXG4gKi9cbmNvbnN0IERFRkFVTFRfQ09OVFJBU1RJVkVfQ09ORklHOiBSZXF1aXJlZDxDb250cmFzdGl2ZUNvbmZpZz4gPSB7XG4gIGVwb2NoczogMTAsXG4gIGJhdGNoU2l6ZTogMTYsXG4gIGxlYXJuaW5nUmF0ZTogMC4wMDAxLFxuICBtYXJnaW46IDAuNSxcbiAgdGVtcGVyYXR1cmU6IDAuMDcsXG4gIGhhcmROZWdhdGl2ZVJhdGlvOiAwLjcsXG4gIG91dHB1dFBhdGg6ICcuL3RyYWluaW5nLW91dHB1dCcsXG59O1xuXG4vKipcbiAqIENvbXB1dGUgY29zaW5lIHNpbWlsYXJpdHkgYmV0d2VlbiB0d28gZW1iZWRkaW5nc1xuICovXG5leHBvcnQgZnVuY3Rpb24gY29zaW5lU2ltaWxhcml0eShhOiBFbWJlZGRpbmcsIGI6IEVtYmVkZGluZyk6IG51bWJlciB7XG4gIGlmICghYSB8fCAhYiB8fCBhLmxlbmd0aCAhPT0gYi5sZW5ndGgpIHJldHVybiAwO1xuICBsZXQgZG90ID0gMCwgbm9ybUEgPSAwLCBub3JtQiA9IDA7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYS5sZW5ndGg7IGkrKykge1xuICAgIGRvdCArPSBhW2ldICogYltpXTtcbiAgICBub3JtQSArPSBhW2ldICogYVtpXTtcbiAgICBub3JtQiArPSBiW2ldICogYltpXTtcbiAgfVxuICByZXR1cm4gZG90IC8gKE1hdGguc3FydChub3JtQSkgKiBNYXRoLnNxcnQobm9ybUIpIHx8IDEpO1xufVxuXG4vKipcbiAqIENvbXB1dGUgdHJpcGxldCBsb3NzXG4gKiBMID0gbWF4KDAsIG1hcmdpbiArIGQoYW5jaG9yLCBwb3NpdGl2ZSkgLSBkKGFuY2hvciwgbmVnYXRpdmUpKVxuICovXG5leHBvcnQgZnVuY3Rpb24gdHJpcGxldExvc3MoXG4gIGFuY2hvckVtYjogRW1iZWRkaW5nLFxuICBwb3NpdGl2ZUVtYjogRW1iZWRkaW5nLFxuICBuZWdhdGl2ZUVtYjogRW1iZWRkaW5nLFxuICBtYXJnaW46IG51bWJlciA9IDAuNVxuKTogbnVtYmVyIHtcbiAgY29uc3QgcG9zRGlzdCA9IDEgLSBjb3NpbmVTaW1pbGFyaXR5KGFuY2hvckVtYiwgcG9zaXRpdmVFbWIpO1xuICBjb25zdCBuZWdEaXN0ID0gMSAtIGNvc2luZVNpbWlsYXJpdHkoYW5jaG9yRW1iLCBuZWdhdGl2ZUVtYik7XG4gIHJldHVybiBNYXRoLm1heCgwLCBtYXJnaW4gKyBwb3NEaXN0IC0gbmVnRGlzdCk7XG59XG5cbi8qKlxuICogQ29tcHV0ZSBJbmZvTkNFIGxvc3MgKGNvbnRyYXN0aXZlKVxuICovXG5leHBvcnQgZnVuY3Rpb24gaW5mb05DRUxvc3MoXG4gIGFuY2hvckVtYjogRW1iZWRkaW5nLFxuICBwb3NpdGl2ZUVtYjogRW1iZWRkaW5nLFxuICBuZWdhdGl2ZUVtYnM6IEVtYmVkZGluZ1tdLFxuICB0ZW1wZXJhdHVyZTogbnVtYmVyID0gMC4wN1xuKTogbnVtYmVyIHtcbiAgY29uc3QgcG9zU2ltID0gY29zaW5lU2ltaWxhcml0eShhbmNob3JFbWIsIHBvc2l0aXZlRW1iKSAvIHRlbXBlcmF0dXJlO1xuICBjb25zdCBuZWdTaW1zID0gbmVnYXRpdmVFbWJzLm1hcChuZWcgPT4gY29zaW5lU2ltaWxhcml0eShhbmNob3JFbWIsIG5lZykgLyB0ZW1wZXJhdHVyZSk7XG5cbiAgLy8gU29mdG1heCBkZW5vbWluYXRvclxuICBjb25zdCBtYXhTaW0gPSBNYXRoLm1heChwb3NTaW0sIC4uLm5lZ1NpbXMpO1xuICBjb25zdCBleHBQb3MgPSBNYXRoLmV4cChwb3NTaW0gLSBtYXhTaW0pO1xuICBjb25zdCBleHBOZWdzID0gbmVnU2ltcy5tYXAoc2ltID0+IE1hdGguZXhwKHNpbSAtIG1heFNpbSkpO1xuICBjb25zdCBkZW5vbWluYXRvciA9IGV4cFBvcyArIGV4cE5lZ3MucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCk7XG5cbiAgLy8gQ3Jvc3MtZW50cm9weSBsb3NzXG4gIHJldHVybiAtTWF0aC5sb2coZXhwUG9zIC8gZGVub21pbmF0b3IpO1xufVxuXG4vKipcbiAqIENvbXB1dGUgZ3JhZGllbnQgZm9yIGVtYmVkZGluZyB1cGRhdGUgKHNpbXBsaWZpZWQpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb21wdXRlR3JhZGllbnQoXG4gIGFuY2hvckVtYjogRW1iZWRkaW5nLFxuICBwb3NpdGl2ZUVtYjogRW1iZWRkaW5nLFxuICBuZWdhdGl2ZUVtYjogRW1iZWRkaW5nLFxuICBscjogbnVtYmVyID0gMC4wMDAxXG4pOiBFbWJlZGRpbmcge1xuICBjb25zdCBkaW0gPSBhbmNob3JFbWIubGVuZ3RoO1xuICBjb25zdCBncmFkaWVudDogbnVtYmVyW10gPSBuZXcgQXJyYXkoZGltKS5maWxsKDApO1xuXG4gIC8vIFB1bGwgYW5jaG9yIHRvd2FyZHMgcG9zaXRpdmVcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBkaW07IGkrKykge1xuICAgIGdyYWRpZW50W2ldICs9IGxyICogKHBvc2l0aXZlRW1iW2ldIC0gYW5jaG9yRW1iW2ldKTtcbiAgfVxuXG4gIC8vIFB1c2ggYW5jaG9yIGF3YXkgZnJvbSBuZWdhdGl2ZVxuICBmb3IgKGxldCBpID0gMDsgaSA8IGRpbTsgaSsrKSB7XG4gICAgZ3JhZGllbnRbaV0gLT0gbHIgKiAwLjUgKiAobmVnYXRpdmVFbWJbaV0gLSBhbmNob3JFbWJbaV0pO1xuICB9XG5cbiAgcmV0dXJuIGdyYWRpZW50O1xufVxuXG4vKipcbiAqIENvbnRyYXN0aXZlIFRyYWluZXIgZm9yIFJ1dkxUUkEgbW9kZWxzXG4gKlxuICogSW1wbGVtZW50cyB0cmlwbGV0IGxvc3MgYW5kIEluZm9OQ0UgbG9zcyBmb3IgZW1iZWRkaW5nIGZpbmUtdHVuaW5nLlxuICovXG5leHBvcnQgY2xhc3MgQ29udHJhc3RpdmVUcmFpbmVyIHtcbiAgcHJpdmF0ZSBjb25maWc6IFJlcXVpcmVkPENvbnRyYXN0aXZlQ29uZmlnPjtcbiAgcHJpdmF0ZSB0cmlwbGV0czogVHJhaW5pbmdUcmlwbGV0W10gPSBbXTtcbiAgcHJpdmF0ZSBoaXN0b3J5OiBUcmFpbmluZ0hpc3RvcnlFbnRyeVtdID0gW107XG4gIHByaXZhdGUgYWdlbnRFbWJlZGRpbmdzOiBNYXA8c3RyaW5nLCBFbWJlZGRpbmc+ID0gbmV3IE1hcCgpO1xuXG4gIGNvbnN0cnVjdG9yKGNvbmZpZz86IENvbnRyYXN0aXZlQ29uZmlnKSB7XG4gICAgdGhpcy5jb25maWcgPSB7IC4uLkRFRkFVTFRfQ09OVFJBU1RJVkVfQ09ORklHLCAuLi5jb25maWcgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSB0cmFpbmluZyB0cmlwbGV0XG4gICAqL1xuICBhZGRUcmlwbGV0KFxuICAgIGFuY2hvcjogc3RyaW5nLFxuICAgIGFuY2hvckVtYjogRW1iZWRkaW5nLFxuICAgIHBvc2l0aXZlOiBzdHJpbmcsXG4gICAgcG9zaXRpdmVFbWI6IEVtYmVkZGluZyxcbiAgICBuZWdhdGl2ZTogc3RyaW5nLFxuICAgIG5lZ2F0aXZlRW1iOiBFbWJlZGRpbmcsXG4gICAgaXNIYXJkOiBib29sZWFuID0gZmFsc2VcbiAgKTogdm9pZCB7XG4gICAgdGhpcy50cmlwbGV0cy5wdXNoKHtcbiAgICAgIGFuY2hvcixcbiAgICAgIGFuY2hvckVtYixcbiAgICAgIHBvc2l0aXZlLFxuICAgICAgcG9zaXRpdmVFbWIsXG4gICAgICBuZWdhdGl2ZSxcbiAgICAgIG5lZ2F0aXZlRW1iLFxuICAgICAgaXNIYXJkLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhZ2VudCBlbWJlZGRpbmcgZm9yIHJlZmVyZW5jZVxuICAgKi9cbiAgYWRkQWdlbnRFbWJlZGRpbmcoYWdlbnROYW1lOiBzdHJpbmcsIGVtYmVkZGluZzogRW1iZWRkaW5nKTogdm9pZCB7XG4gICAgdGhpcy5hZ2VudEVtYmVkZGluZ3Muc2V0KGFnZW50TmFtZSwgZW1iZWRkaW5nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgYWxsIGFnZW50IGVtYmVkZGluZ3NcbiAgICovXG4gIGdldEFnZW50RW1iZWRkaW5ncygpOiBNYXA8c3RyaW5nLCBFbWJlZGRpbmc+IHtcbiAgICByZXR1cm4gdGhpcy5hZ2VudEVtYmVkZGluZ3M7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRyaXBsZXQgY291bnRcbiAgICovXG4gIGdldFRyaXBsZXRDb3VudCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnRyaXBsZXRzLmxlbmd0aDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTaW11bGF0ZSB0cmFpbmluZyAoY29tcHV0ZSBsb3NzZXMgd2l0aG91dCBhY3R1YWwgYmFja3Byb3ApXG4gICAqIEluIGEgZnVsbCBpbXBsZW1lbnRhdGlvbiwgdGhpcyB3b3VsZCB1c2UgcHJvcGVyIGdyYWRpZW50IGRlc2NlbnRcbiAgICovXG4gIHRyYWluKCk6IENvbnRyYXN0aXZlVHJhaW5pbmdSZXN1bHQge1xuICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgY29uc3QgeyBlcG9jaHMsIGJhdGNoU2l6ZSwgbWFyZ2luIH0gPSB0aGlzLmNvbmZpZztcblxuICAgIGlmICh0aGlzLnRyaXBsZXRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdHJpcGxldENvdW50OiAwLFxuICAgICAgICBmaW5hbExvc3M6IDAsXG4gICAgICAgIGluaXRpYWxMb3NzOiAwLFxuICAgICAgICBpbXByb3ZlbWVudDogMCxcbiAgICAgICAgaGlzdG9yeTogW10sXG4gICAgICAgIGR1cmF0aW9uTXM6IDAsXG4gICAgICB9O1xuICAgIH1cblxuICAgIGZvciAobGV0IGVwb2NoID0gMDsgZXBvY2ggPCBlcG9jaHM7IGVwb2NoKyspIHtcbiAgICAgIGxldCBlcG9jaExvc3MgPSAwO1xuICAgICAgbGV0IGJhdGNoQ291bnQgPSAwO1xuXG4gICAgICAvLyBTaHVmZmxlIHRyaXBsZXRzXG4gICAgICBjb25zdCBzaHVmZmxlZCA9IFsuLi50aGlzLnRyaXBsZXRzXS5zb3J0KCgpID0+IE1hdGgucmFuZG9tKCkgLSAwLjUpO1xuXG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNodWZmbGVkLmxlbmd0aDsgaSArPSBiYXRjaFNpemUpIHtcbiAgICAgICAgY29uc3QgYmF0Y2ggPSBzaHVmZmxlZC5zbGljZShpLCBpICsgYmF0Y2hTaXplKTtcbiAgICAgICAgbGV0IGJhdGNoTG9zcyA9IDA7XG5cbiAgICAgICAgZm9yIChjb25zdCB0cmlwbGV0IG9mIGJhdGNoKSB7XG4gICAgICAgICAgY29uc3QgbG9zcyA9IHRyaXBsZXRMb3NzKFxuICAgICAgICAgICAgdHJpcGxldC5hbmNob3JFbWIsXG4gICAgICAgICAgICB0cmlwbGV0LnBvc2l0aXZlRW1iLFxuICAgICAgICAgICAgdHJpcGxldC5uZWdhdGl2ZUVtYixcbiAgICAgICAgICAgIG1hcmdpblxuICAgICAgICAgICk7XG4gICAgICAgICAgYmF0Y2hMb3NzICs9IGxvc3M7XG4gICAgICAgIH1cblxuICAgICAgICBlcG9jaExvc3MgKz0gYmF0Y2hMb3NzIC8gYmF0Y2gubGVuZ3RoO1xuICAgICAgICBiYXRjaENvdW50Kys7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGF2Z0xvc3MgPSBlcG9jaExvc3MgLyBiYXRjaENvdW50O1xuICAgICAgdGhpcy5oaXN0b3J5LnB1c2goeyBlcG9jaDogZXBvY2ggKyAxLCBsb3NzOiBhdmdMb3NzIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IGluaXRpYWxMb3NzID0gdGhpcy5oaXN0b3J5WzBdPy5sb3NzIHx8IDA7XG4gICAgY29uc3QgZmluYWxMb3NzID0gdGhpcy5oaXN0b3J5W3RoaXMuaGlzdG9yeS5sZW5ndGggLSAxXT8ubG9zcyB8fCAwO1xuICAgIGNvbnN0IGltcHJvdmVtZW50ID0gaW5pdGlhbExvc3MgPiAwID8gKDEgLSBmaW5hbExvc3MgLyBpbml0aWFsTG9zcykgKiAxMDAgOiAwO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHRyaXBsZXRDb3VudDogdGhpcy50cmlwbGV0cy5sZW5ndGgsXG4gICAgICBmaW5hbExvc3MsXG4gICAgICBpbml0aWFsTG9zcyxcbiAgICAgIGltcHJvdmVtZW50LFxuICAgICAgaGlzdG9yeTogdGhpcy5oaXN0b3J5LFxuICAgICAgZHVyYXRpb25NczogRGF0ZS5ub3coKSAtIHN0YXJ0VGltZSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEV4cG9ydCB0cmFpbmluZyBkYXRhIGZvciBleHRlcm5hbCBmaW5lLXR1bmluZyB0b29sc1xuICAgKi9cbiAgZXhwb3J0VHJhaW5pbmdEYXRhKG91dHB1dFBhdGg/OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IG91dERpciA9IG91dHB1dFBhdGggfHwgdGhpcy5jb25maWcub3V0cHV0UGF0aDtcblxuICAgIGlmICghZXhpc3RzU3luYyhvdXREaXIpKSB7XG4gICAgICBta2RpclN5bmMob3V0RGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICB9XG5cbiAgICAvLyBKU09OTCBmb3JtYXQgZm9yIGZpbmUtdHVuaW5nXG4gICAgY29uc3QganNvbmxEYXRhID0gdGhpcy50cmlwbGV0cy5tYXAodCA9PiAoe1xuICAgICAgYW5jaG9yOiB0LmFuY2hvcixcbiAgICAgIHBvc2l0aXZlOiB0LnBvc2l0aXZlLFxuICAgICAgbmVnYXRpdmU6IHQubmVnYXRpdmUsXG4gICAgICBpc0hhcmQ6IHQuaXNIYXJkLFxuICAgIH0pKTtcblxuICAgIC8vIENTViBmb3JtYXQgZm9yIGFuYWx5c2lzXG4gICAgY29uc3QgY3N2RGF0YSA9IFtcbiAgICAgICdhbmNob3IscG9zaXRpdmUsbmVnYXRpdmUsaXNfaGFyZCcsXG4gICAgICAuLi50aGlzLnRyaXBsZXRzLm1hcCh0ID0+XG4gICAgICAgIGBcIiR7dC5hbmNob3IucmVwbGFjZSgvXCIvZywgJ1wiXCInKX1cIiwke3QucG9zaXRpdmV9LCR7dC5uZWdhdGl2ZX0sJHt0LmlzSGFyZH1gXG4gICAgICApLFxuICAgIF0uam9pbignXFxuJyk7XG5cbiAgICAvLyBFbWJlZGRpbmcgbWF0cml4IGZvciBkaXJlY3QgdHJhaW5pbmdcbiAgICBjb25zdCBlbWJlZGRpbmdEYXRhID0ge1xuICAgICAgYW5jaG9yczogdGhpcy50cmlwbGV0cy5tYXAodCA9PiB0LmFuY2hvckVtYiksXG4gICAgICBwb3NpdGl2ZXM6IHRoaXMudHJpcGxldHMubWFwKHQgPT4gdC5wb3NpdGl2ZUVtYiksXG4gICAgICBuZWdhdGl2ZXM6IHRoaXMudHJpcGxldHMubWFwKHQgPT4gdC5uZWdhdGl2ZUVtYiksXG4gICAgICBsYWJlbHM6IHRoaXMudHJpcGxldHMubWFwKHQgPT4gdC5wb3NpdGl2ZSksXG4gICAgfTtcblxuICAgIHdyaXRlRmlsZVN5bmMoam9pbihvdXREaXIsICd0cmlwbGV0cy5qc29ubCcpLCBqc29ubERhdGEubWFwKGl0ZW0gPT4gSlNPTi5zdHJpbmdpZnkoaXRlbSkpLmpvaW4oJ1xcbicpKTtcbiAgICB3cml0ZUZpbGVTeW5jKGpvaW4ob3V0RGlyLCAndHJpcGxldHMuY3N2JyksIGNzdkRhdGEpO1xuICAgIHdyaXRlRmlsZVN5bmMoam9pbihvdXREaXIsICdlbWJlZGRpbmdzLmpzb24nKSwgSlNPTi5zdHJpbmdpZnkoZW1iZWRkaW5nRGF0YSwgbnVsbCwgMikpO1xuXG4gICAgcmV0dXJuIG91dERpcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBMb1JBIGFkYXB0ZXIgY29uZmlndXJhdGlvblxuICAgKi9cbiAgZ2VuZXJhdGVMb1JBQ29uZmlnKG91dHB1dFBhdGg/OiBzdHJpbmcpOiBMb1JBRXhwb3J0Q29uZmlnIHtcbiAgICBjb25zdCBvdXREaXIgPSBvdXRwdXRQYXRoIHx8IHRoaXMuY29uZmlnLm91dHB1dFBhdGg7XG5cbiAgICBjb25zdCBsb3JhQ29uZmlnOiBMb1JBRXhwb3J0Q29uZmlnID0ge1xuICAgICAgbW9kZWxfdHlwZTogJ3F3ZW4yJyxcbiAgICAgIGJhc2VfbW9kZWw6ICdRd2VuL1F3ZW4yLjUtMC41QicsXG4gICAgICBvdXRwdXRfZGlyOiBvdXREaXIsXG4gICAgICBsb3JhX3I6IDgsXG4gICAgICBsb3JhX2FscGhhOiAxNixcbiAgICAgIGxvcmFfZHJvcG91dDogMC4wNSxcbiAgICAgIHRhcmdldF9tb2R1bGVzOiBbJ3FfcHJvaicsICd2X3Byb2onLCAna19wcm9qJywgJ29fcHJvaiddLFxuICAgICAgbGVhcm5pbmdfcmF0ZTogdGhpcy5jb25maWcubGVhcm5pbmdSYXRlLFxuICAgICAgbnVtX3RyYWluX2Vwb2NoczogdGhpcy5jb25maWcuZXBvY2hzLFxuICAgICAgcGVyX2RldmljZV90cmFpbl9iYXRjaF9zaXplOiB0aGlzLmNvbmZpZy5iYXRjaFNpemUsXG4gICAgICBncmFkaWVudF9hY2N1bXVsYXRpb25fc3RlcHM6IDQsXG4gICAgICB3YXJtdXBfcmF0aW86IDAuMSxcbiAgICAgIGxvc3NfdHlwZTogJ3RyaXBsZXQnLFxuICAgICAgbWFyZ2luOiB0aGlzLmNvbmZpZy5tYXJnaW4sXG4gICAgICB0ZW1wZXJhdHVyZTogdGhpcy5jb25maWcudGVtcGVyYXR1cmUsXG4gICAgICB0cmFpbl9kYXRhOiBqb2luKG91dERpciwgJ3RyaXBsZXRzLmpzb25sJyksXG4gICAgICBldmFsX2RhdGE6IGpvaW4ob3V0RGlyLCAnZXZhbC5qc29ubCcpLFxuICAgIH07XG5cbiAgICBpZiAoIWV4aXN0c1N5bmMob3V0RGlyKSkge1xuICAgICAgbWtkaXJTeW5jKG91dERpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgfVxuXG4gICAgd3JpdGVGaWxlU3luYyhqb2luKG91dERpciwgJ2xvcmFfY29uZmlnLmpzb24nKSwgSlNPTi5zdHJpbmdpZnkobG9yYUNvbmZpZywgbnVsbCwgMikpO1xuICAgIHJldHVybiBsb3JhQ29uZmlnO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIHRyYWluaW5nIHNjcmlwdCBmb3IgZXh0ZXJuYWwgdG9vbHNcbiAgICovXG4gIGdlbmVyYXRlVHJhaW5pbmdTY3JpcHQob3V0cHV0UGF0aD86IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3Qgb3V0RGlyID0gb3V0cHV0UGF0aCB8fCB0aGlzLmNvbmZpZy5vdXRwdXRQYXRoO1xuXG4gICAgY29uc3Qgc2NyaXB0ID0gYCMhL2Jpbi9iYXNoXG4jIFJ1dkxUUkEgRmluZS10dW5pbmcgU2NyaXB0XG4jIFByZXJlcXVpc2l0ZXM6IHBpcCBpbnN0YWxsIHRyYW5zZm9ybWVycyBwZWZ0IGFjY2VsZXJhdGVcblxuc2V0IC1lXG5cbk1PREVMX1BBVEg9XCIke291dERpcn1cIlxuQkFTRV9NT0RFTD1cIlF3ZW4vUXdlbjIuNS0wLjVCXCJcblxuZWNobyBcIj09PSBSdXZMVFJBIENvbnRyYXN0aXZlIEZpbmUtdHVuaW5nID09PVwiXG5lY2hvIFwiQmFzZSBtb2RlbDogJEJBU0VfTU9ERUxcIlxuZWNobyBcIk91dHB1dDogJE1PREVMX1BBVEhcIlxuXG4jIENoZWNrIGZvciB0cmFpbmluZyBkYXRhXG5pZiBbICEgLWYgXCIkTU9ERUxfUEFUSC90cmlwbGV0cy5qc29ubFwiIF07IHRoZW5cbiAgZWNobyBcIkVycm9yOiBUcmFpbmluZyBkYXRhIG5vdCBmb3VuZCBhdCAkTU9ERUxfUEFUSC90cmlwbGV0cy5qc29ubFwiXG4gIGV4aXQgMVxuZmlcblxuIyBJbnN0YWxsIGRlcGVuZGVuY2llcyBpZiBuZWVkZWRcbnB5dGhvbjMgLWMgXCJpbXBvcnQgdHJhbnNmb3JtZXJzLCBwZWZ0XCIgMj4vZGV2L251bGwgfHwge1xuICBlY2hvIFwiSW5zdGFsbGluZyBkZXBlbmRlbmNpZXMuLi5cIlxuICBwaXAgaW5zdGFsbCB0cmFuc2Zvcm1lcnMgcGVmdCBhY2NlbGVyYXRlIHNlbnRlbmNlcGllY2Vcbn1cblxuIyBGaW5lLXR1bmUgd2l0aCBMb1JBXG5weXRob24zIDw8ICdQWVRIT04nXG5pbXBvcnQganNvblxuaW1wb3J0IHRvcmNoXG5mcm9tIHBhdGhsaWIgaW1wb3J0IFBhdGhcbmZyb20gdHJhbnNmb3JtZXJzIGltcG9ydCBBdXRvTW9kZWxGb3JDYXVzYWxMTSwgQXV0b1Rva2VuaXplclxuZnJvbSBwZWZ0IGltcG9ydCBMb3JhQ29uZmlnLCBnZXRfcGVmdF9tb2RlbCwgVGFza1R5cGVcblxuIyBMb2FkIGNvbmZpZ1xuY29uZmlnX3BhdGggPSBQYXRoKFwiJHtvdXREaXJ9L2xvcmFfY29uZmlnLmpzb25cIilcbndpdGggb3Blbihjb25maWdfcGF0aCkgYXMgZjpcbiAgICBjb25maWcgPSBqc29uLmxvYWQoZilcblxucHJpbnQoZlwiTG9hZGluZyBiYXNlIG1vZGVsOiB7Y29uZmlnWydiYXNlX21vZGVsJ119XCIpXG5cbiMgTG9hZCBtb2RlbCBhbmQgdG9rZW5pemVyXG50b2tlbml6ZXIgPSBBdXRvVG9rZW5pemVyLmZyb21fcHJldHJhaW5lZChjb25maWdbJ2Jhc2VfbW9kZWwnXSlcbm1vZGVsID0gQXV0b01vZGVsRm9yQ2F1c2FsTE0uZnJvbV9wcmV0cmFpbmVkKFxuICAgIGNvbmZpZ1snYmFzZV9tb2RlbCddLFxuICAgIHRvcmNoX2R0eXBlPXRvcmNoLmZsb2F0MTYsXG4gICAgZGV2aWNlX21hcD0nYXV0bydcbilcblxuIyBDb25maWd1cmUgTG9SQVxubG9yYV9jb25maWcgPSBMb3JhQ29uZmlnKFxuICAgIHI9Y29uZmlnWydsb3JhX3InXSxcbiAgICBsb3JhX2FscGhhPWNvbmZpZ1snbG9yYV9hbHBoYSddLFxuICAgIGxvcmFfZHJvcG91dD1jb25maWdbJ2xvcmFfZHJvcG91dCddLFxuICAgIHRhcmdldF9tb2R1bGVzPWNvbmZpZ1sndGFyZ2V0X21vZHVsZXMnXSxcbiAgICB0YXNrX3R5cGU9VGFza1R5cGUuQ0FVU0FMX0xNLFxuKVxuXG5tb2RlbCA9IGdldF9wZWZ0X21vZGVsKG1vZGVsLCBsb3JhX2NvbmZpZylcbm1vZGVsLnByaW50X3RyYWluYWJsZV9wYXJhbWV0ZXJzKClcblxucHJpbnQoXCJNb2RlbCByZWFkeSBmb3IgZmluZS10dW5pbmchXCIpXG5wcmludChmXCJUcmFpbmluZyBkYXRhOiB7Y29uZmlnWyd0cmFpbl9kYXRhJ119XCIpXG5wcmludChcIk5vdGU6IEZ1bGwgdHJhaW5pbmcgcmVxdWlyZXMgR1BVLiBUaGlzIHNjcmlwdCB2YWxpZGF0ZXMgdGhlIHNldHVwLlwiKVxuUFlUSE9OXG5cbmVjaG8gXCJcIlxuZWNobyBcIj09PSBTZXR1cCBDb21wbGV0ZSA9PT1cIlxuZWNobyBcIlRvIHRyYWluIG9uIEdQVSwgcnVuIHRoZSBmdWxsIHRyYWluaW5nIHBpcGVsaW5lLlwiXG5lY2hvIFwiVHJhaW5pbmcgZGF0YSBleHBvcnRlZCB0bzogJE1PREVMX1BBVEgvdHJpcGxldHMuanNvbmxcIlxuYDtcblxuICAgIGlmICghZXhpc3RzU3luYyhvdXREaXIpKSB7XG4gICAgICBta2RpclN5bmMob3V0RGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICB9XG5cbiAgICBjb25zdCBzY3JpcHRQYXRoID0gam9pbihvdXREaXIsICd0cmFpbi5zaCcpO1xuICAgIHdyaXRlRmlsZVN5bmMoc2NyaXB0UGF0aCwgc2NyaXB0KTtcblxuICAgIHJldHVybiBzY3JpcHRQYXRoO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0cmFpbmluZyBoaXN0b3J5XG4gICAqL1xuICBnZXRIaXN0b3J5KCk6IFRyYWluaW5nSGlzdG9yeUVudHJ5W10ge1xuICAgIHJldHVybiBbLi4udGhpcy5oaXN0b3J5XTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNldCB0cmFpbmVyXG4gICAqL1xuICByZXNldCgpOiB2b2lkIHtcbiAgICB0aGlzLnRyaXBsZXRzID0gW107XG4gICAgdGhpcy5oaXN0b3J5ID0gW107XG4gIH1cbn1cblxuLyoqXG4gKiBBZ2VudCBUcmFpbmluZyBEYXRhIEludGVyZmFjZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIEFnZW50VHJhaW5pbmdEYXRhIHtcbiAgZGVzY3JpcHRpb246IHN0cmluZztcbiAga2V5d29yZHM6IHN0cmluZ1tdO1xuICBleGFtcGxlczogc3RyaW5nW107XG4gIGNvbmZ1c2luZ193aXRoPzogc3RyaW5nW107XG59XG5cbi8qKlxuICogVHJhaW5pbmcgRXhhbXBsZSBJbnRlcmZhY2VcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBUcmFpbmluZ0V4YW1wbGUge1xuICB0YXNrOiBzdHJpbmc7XG4gIGFnZW50OiBzdHJpbmc7XG4gIGNvbXBsZXhpdHk/OiBzdHJpbmc7XG4gIGNvbmZ1c2luZ193aXRoPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIERhdGFzZXQgU3RhdGlzdGljc1xuICovXG5leHBvcnQgaW50ZXJmYWNlIERhdGFzZXRTdGF0cyB7XG4gIHRvdGFsRXhhbXBsZXM6IG51bWJlcjtcbiAgY29udHJhc3RpdmVQYWlyczogbnVtYmVyO1xuICBhZ2VudFR5cGVzOiBudW1iZXI7XG4gIGFnZW50czogc3RyaW5nW107XG59XG5cbi8qKlxuICogQWdlbnQgVHJhaW5pbmcgRGF0YSBmb3IgQ2xhdWRlIENvZGUgUm91dGVyXG4gKi9cbmV4cG9ydCBjb25zdCBBR0VOVF9UUkFJTklOR19EQVRBOiBSZWNvcmQ8c3RyaW5nLCBBZ2VudFRyYWluaW5nRGF0YT4gPSB7XG4gIGNvZGVyOiB7XG4gICAgZGVzY3JpcHRpb246ICdJbXBsZW1lbnRhdGlvbiBzcGVjaWFsaXN0IGZvciB3cml0aW5nIGNsZWFuLCBlZmZpY2llbnQgY29kZS4gSGFuZGxlcyBjb2RpbmcgdGFza3MsIGZlYXR1cmUgaW1wbGVtZW50YXRpb24sIGFuZCBjb2RlIGdlbmVyYXRpb24uJyxcbiAgICBrZXl3b3JkczogWydpbXBsZW1lbnQnLCAnY29kZScsICd3cml0ZScsICdidWlsZCcsICdjcmVhdGUnLCAnZGV2ZWxvcCcsICdmdW5jdGlvbicsICdjbGFzcycsICdjb21wb25lbnQnLCAnZmVhdHVyZSddLFxuICAgIGV4YW1wbGVzOiBbXG4gICAgICAnSW1wbGVtZW50IGEgYmluYXJ5IHNlYXJjaCBmdW5jdGlvbicsXG4gICAgICAnV3JpdGUgYSBSZWFjdCBjb21wb25lbnQgZm9yIHVzZXIgcmVnaXN0cmF0aW9uJyxcbiAgICAgICdDcmVhdGUgYSBSRVNUIEFQSSBlbmRwb2ludCBmb3IgdXNlciBhdXRoZW50aWNhdGlvbicsXG4gICAgICAnQnVpbGQgYSBjYWNoaW5nIGxheWVyIGZvciB0aGUgZGF0YWJhc2UgcXVlcmllcycsXG4gICAgXSxcbiAgICBjb25mdXNpbmdfd2l0aDogWydyZWZhY3RvcmVyJywgJ2RlYnVnZ2VyJ10sXG4gIH0sXG4gIHRlc3Rlcjoge1xuICAgIGRlc2NyaXB0aW9uOiAnVGVzdGluZyBzcGVjaWFsaXN0IGZvciB3cml0aW5nIGFuZCBtYWludGFpbmluZyB0ZXN0cy4gQ3JlYXRlcyB1bml0IHRlc3RzLCBpbnRlZ3JhdGlvbiB0ZXN0cywgYW5kIGVuc3VyZXMgY29kZSBxdWFsaXR5IHRocm91Z2ggdGVzdGluZy4nLFxuICAgIGtleXdvcmRzOiBbJ3Rlc3QnLCAndW5pdCB0ZXN0JywgJ2ludGVncmF0aW9uIHRlc3QnLCAnY292ZXJhZ2UnLCAnbW9jaycsICdhc3NlcnRpb24nLCAnc3BlYycsICdqZXN0JywgJ3B5dGVzdCddLFxuICAgIGV4YW1wbGVzOiBbXG4gICAgICAnV3JpdGUgdW5pdCB0ZXN0cyBmb3IgdGhlIGF1dGhlbnRpY2F0aW9uIG1vZHVsZScsXG4gICAgICAnQWRkIGludGVncmF0aW9uIHRlc3RzIGZvciB0aGUgcGF5bWVudCBnYXRld2F5JyxcbiAgICAgICdDcmVhdGUgdGVzdCBjb3ZlcmFnZSBmb3IgdGhlIHVzZXIgc2VydmljZScsXG4gICAgICAnV3JpdGUgZTJlIHRlc3RzIGZvciB0aGUgY2hlY2tvdXQgZmxvdycsXG4gICAgXSxcbiAgICBjb25mdXNpbmdfd2l0aDogWydyZXZpZXdlciddLFxuICB9LFxuICByZXZpZXdlcjoge1xuICAgIGRlc2NyaXB0aW9uOiAnQ29kZSByZXZpZXcgc3BlY2lhbGlzdCBmb3IgYW5hbHl6aW5nIGNvZGUgcXVhbGl0eSwgaWRlbnRpZnlpbmcgaXNzdWVzLCBhbmQgc3VnZ2VzdGluZyBpbXByb3ZlbWVudHMuJyxcbiAgICBrZXl3b3JkczogWydyZXZpZXcnLCAnYW5hbHl6ZScsICdjaGVjaycsICdpbnNwZWN0JywgJ2F1ZGl0JywgJ2V2YWx1YXRlJywgJ2Fzc2VzcycsICdjcml0aXF1ZSddLFxuICAgIGV4YW1wbGVzOiBbXG4gICAgICAnUmV2aWV3IHRoZSBwdWxsIHJlcXVlc3QgZm9yIGNvZGUgcXVhbGl0eScsXG4gICAgICAnQ2hlY2sgdGhlIGNvZGUgZm9yIHBvdGVudGlhbCBzZWN1cml0eSB2dWxuZXJhYmlsaXRpZXMnLFxuICAgICAgJ0FuYWx5emUgdGhlIGltcGxlbWVudGF0aW9uIGZvciBiZXN0IHByYWN0aWNlcycsXG4gICAgICAnRXZhbHVhdGUgdGhlIGFyY2hpdGVjdHVyZSBkZWNpc2lvbnMgaW4gdGhpcyBQUicsXG4gICAgXSxcbiAgICBjb25mdXNpbmdfd2l0aDogWyd0ZXN0ZXInLCAnc2VjdXJpdHktYXJjaGl0ZWN0J10sXG4gIH0sXG4gIHJlc2VhcmNoZXI6IHtcbiAgICBkZXNjcmlwdGlvbjogJ1Jlc2VhcmNoIHNwZWNpYWxpc3QgZm9yIGludmVzdGlnYXRpbmcgdGVjaG5vbG9naWVzLCBnYXRoZXJpbmcgaW5mb3JtYXRpb24sIGFuZCBhbmFseXppbmcgb3B0aW9ucy4nLFxuICAgIGtleXdvcmRzOiBbJ3Jlc2VhcmNoJywgJ2ludmVzdGlnYXRlJywgJ2V4cGxvcmUnLCAnYW5hbHl6ZScsICdzdHVkeScsICdjb21wYXJlJywgJ2V2YWx1YXRlJywgJ2xlYXJuJ10sXG4gICAgZXhhbXBsZXM6IFtcbiAgICAgICdSZXNlYXJjaCBiZXN0IHByYWN0aWNlcyBmb3IgUmVhY3Qgc3RhdGUgbWFuYWdlbWVudCcsXG4gICAgICAnSW52ZXN0aWdhdGUgdGhlIHBlcmZvcm1hbmNlIGlzc3VlcyBpbiB0aGUgZGFzaGJvYXJkJyxcbiAgICAgICdDb21wYXJlIGRpZmZlcmVudCBhdXRoZW50aWNhdGlvbiBzdHJhdGVnaWVzJyxcbiAgICAgICdTdHVkeSB0aGUgY29kZWJhc2UgYXJjaGl0ZWN0dXJlIGZvciB0aGUgbmV3IGZlYXR1cmUnLFxuICAgIF0sXG4gICAgY29uZnVzaW5nX3dpdGg6IFsncGxhbm5lciddLFxuICB9LFxuICBhcmNoaXRlY3Q6IHtcbiAgICBkZXNjcmlwdGlvbjogJ1N5c3RlbSBhcmNoaXRlY3QgZm9yIGRlc2lnbmluZyBzb2Z0d2FyZSBhcmNoaXRlY3R1cmUsIG1ha2luZyB0ZWNobmljYWwgZGVjaXNpb25zLCBhbmQgcGxhbm5pbmcgc3lzdGVtIHN0cnVjdHVyZS4nLFxuICAgIGtleXdvcmRzOiBbJ2Rlc2lnbicsICdhcmNoaXRlY3QnLCAnc3RydWN0dXJlJywgJ3BsYW4nLCAnc2NoZW1hJywgJ21vZGVsJywgJ3BhdHRlcm4nLCAnc3lzdGVtJ10sXG4gICAgZXhhbXBsZXM6IFtcbiAgICAgICdEZXNpZ24gdGhlIGRhdGFiYXNlIHNjaGVtYSBmb3IgdXNlciBwcm9maWxlcycsXG4gICAgICAnUGxhbiB0aGUgYXJjaGl0ZWN0dXJlIGZvciByZWFsLXRpbWUgbm90aWZpY2F0aW9ucycsXG4gICAgICAnQ3JlYXRlIGEgc3lzdGVtIGRlc2lnbiBmb3IgdGhlIG1pY3Jvc2VydmljZXMgbWlncmF0aW9uJyxcbiAgICAgICdEZXNpZ24gdGhlIEFQSSBzdHJ1Y3R1cmUgZm9yIHRoZSBuZXcgcHJvZHVjdCBjYXRhbG9nJyxcbiAgICBdLFxuICAgIGNvbmZ1c2luZ193aXRoOiBbJ3BsYW5uZXInXSxcbiAgfSxcbiAgZGVidWdnZXI6IHtcbiAgICBkZXNjcmlwdGlvbjogJ0RlYnVnZ2luZyBzcGVjaWFsaXN0IGZvciBmaW5kaW5nIGFuZCBmaXhpbmcgYnVncywgYW5hbHl6aW5nIGVycm9ycywgYW5kIHRyb3VibGVzaG9vdGluZyBpc3N1ZXMuJyxcbiAgICBrZXl3b3JkczogWydkZWJ1ZycsICdmaXgnLCAnYnVnJywgJ2Vycm9yJywgJ2lzc3VlJywgJ2NyYXNoJywgJ2V4Y2VwdGlvbicsICd0cm91Ymxlc2hvb3QnXSxcbiAgICBleGFtcGxlczogW1xuICAgICAgJ0ZpeCB0aGUgbnVsbCBwb2ludGVyIGV4Y2VwdGlvbiBpbiB0aGUgbG9naW4gaGFuZGxlcicsXG4gICAgICAnRGVidWcgdGhlIG1lbW9yeSBsZWFrIGluIHRoZSBXZWJTb2NrZXQgaGFuZGxlcicsXG4gICAgICAnVHJvdWJsZXNob290IHRoZSByYWNlIGNvbmRpdGlvbiBpbiB0aGUgcGF5bWVudCBwcm9jZXNzb3InLFxuICAgICAgJ0ZpbmQgdGhlIHJvb3QgY2F1c2Ugb2YgdGhlIGludGVybWl0dGVudCB0ZXN0IGZhaWx1cmVzJyxcbiAgICBdLFxuICAgIGNvbmZ1c2luZ193aXRoOiBbJ2NvZGVyJ10sXG4gIH0sXG4gICdzZWN1cml0eS1hcmNoaXRlY3QnOiB7XG4gICAgZGVzY3JpcHRpb246ICdTZWN1cml0eSBzcGVjaWFsaXN0IGZvciBhdWRpdGluZyBjb2RlIHNlY3VyaXR5LCBpZGVudGlmeWluZyB2dWxuZXJhYmlsaXRpZXMsIGFuZCBpbXBsZW1lbnRpbmcgc2VjdXJpdHkgbWVhc3VyZXMuJyxcbiAgICBrZXl3b3JkczogWydzZWN1cml0eScsICd2dWxuZXJhYmlsaXR5JywgJ3hzcycsICdzcWwgaW5qZWN0aW9uJywgJ2F1dGgnLCAnZW5jcnlwdGlvbicsICdhdWRpdCcsICdwZW5ldHJhdGlvbiddLFxuICAgIGV4YW1wbGVzOiBbXG4gICAgICAnQXVkaXQgdGhlIEFQSSBlbmRwb2ludHMgZm9yIFhTUyB2dWxuZXJhYmlsaXRpZXMnLFxuICAgICAgJ1JldmlldyB0aGUgYXV0aGVudGljYXRpb24gZmxvdyBmb3Igc2VjdXJpdHkgaXNzdWVzJyxcbiAgICAgICdJbXBsZW1lbnQgaW5wdXQgdmFsaWRhdGlvbiBmb3IgdGhlIHVzZXIgZm9ybXMnLFxuICAgICAgJ0NoZWNrIGZvciBTUUwgaW5qZWN0aW9uIHZ1bG5lcmFiaWxpdGllcyBpbiB0aGUgc2VhcmNoJyxcbiAgICBdLFxuICAgIGNvbmZ1c2luZ193aXRoOiBbJ3Jldmlld2VyJ10sXG4gIH0sXG4gIGRvY3VtZW50ZXI6IHtcbiAgICBkZXNjcmlwdGlvbjogJ0RvY3VtZW50YXRpb24gc3BlY2lhbGlzdCBmb3Igd3JpdGluZyB0ZWNobmljYWwgZG9jdW1lbnRhdGlvbiwgY29tbWVudHMsIGFuZCBBUEkgZG9jcy4nLFxuICAgIGtleXdvcmRzOiBbJ2RvY3VtZW50JywgJ2NvbW1lbnQnLCAnanNkb2MnLCAncmVhZG1lJywgJ2RvY3MnLCAnZXhwbGFpbicsICdkZXNjcmliZScsICdhbm5vdGF0ZSddLFxuICAgIGV4YW1wbGVzOiBbXG4gICAgICAnV3JpdGUgSlNEb2MgY29tbWVudHMgZm9yIHRoZSB1dGlsaXR5IGZ1bmN0aW9ucycsXG4gICAgICAnQ3JlYXRlIFJFQURNRSBkb2N1bWVudGF0aW9uIGZvciB0aGUgbmV3IG1vZHVsZScsXG4gICAgICAnRG9jdW1lbnQgdGhlIEFQSSBlbmRwb2ludHMgd2l0aCBleGFtcGxlcycsXG4gICAgICAnQWRkIGlubGluZSBjb21tZW50cyBleHBsYWluaW5nIHRoZSBhbGdvcml0aG0nLFxuICAgIF0sXG4gICAgY29uZnVzaW5nX3dpdGg6IFsnYXBpLWRvY3MnXSxcbiAgfSxcbiAgcmVmYWN0b3Jlcjoge1xuICAgIGRlc2NyaXB0aW9uOiAnUmVmYWN0b3Jpbmcgc3BlY2lhbGlzdCBmb3IgaW1wcm92aW5nIGNvZGUgc3RydWN0dXJlLCBjbGVhbmluZyB1cCB0ZWNobmljYWwgZGVidCwgYW5kIG1vZGVybml6aW5nIGNvZGViYXNlcy4nLFxuICAgIGtleXdvcmRzOiBbJ3JlZmFjdG9yJywgJ2NsZWFuJywgJ3Jlc3RydWN0dXJlJywgJ21vZGVybml6ZScsICdpbXByb3ZlJywgJ3NpbXBsaWZ5JywgJ2V4dHJhY3QnLCAncmVuYW1lJ10sXG4gICAgZXhhbXBsZXM6IFtcbiAgICAgICdSZWZhY3RvciB0aGUgcGF5bWVudCBtb2R1bGUgdG8gdXNlIGFzeW5jL2F3YWl0JyxcbiAgICAgICdDbGVhbiB1cCB0aGUgbGVnYWN5IGF1dGhlbnRpY2F0aW9uIGNvZGUnLFxuICAgICAgJ0V4dHJhY3QgY29tbW9uIGxvZ2ljIGludG8gYSBzaGFyZWQgdXRpbGl0eScsXG4gICAgICAnU2ltcGxpZnkgdGhlIGNvbXBsZXggY29uZGl0aW9uYWwgbG9naWMgaW4gY2hlY2tvdXQnLFxuICAgIF0sXG4gICAgY29uZnVzaW5nX3dpdGg6IFsnY29kZXInXSxcbiAgfSxcbiAgb3B0aW1pemVyOiB7XG4gICAgZGVzY3JpcHRpb246ICdQZXJmb3JtYW5jZSBvcHRpbWl6YXRpb24gc3BlY2lhbGlzdCBmb3IgaW1wcm92aW5nIHNwZWVkLCByZWR1Y2luZyBtZW1vcnkgdXNhZ2UsIGFuZCBvcHRpbWl6aW5nIHF1ZXJpZXMuJyxcbiAgICBrZXl3b3JkczogWydvcHRpbWl6ZScsICdwZXJmb3JtYW5jZScsICdzcGVlZCcsICdtZW1vcnknLCAnY2FjaGUnLCAnaW5kZXgnLCAncXVlcnknLCAnbGF0ZW5jeSddLFxuICAgIGV4YW1wbGVzOiBbXG4gICAgICAnT3B0aW1pemUgdGhlIGRhdGFiYXNlIHF1ZXJpZXMgZm9yIHRoZSBkYXNoYm9hcmQnLFxuICAgICAgJ0ltcHJvdmUgdGhlIHBhZ2UgbG9hZCB0aW1lIGZvciB0aGUgaG9tZXBhZ2UnLFxuICAgICAgJ0FkZCBjYWNoaW5nIHRvIHJlZHVjZSBBUEkgcmVzcG9uc2UgdGltZXMnLFxuICAgICAgJ1JlZHVjZSBtZW1vcnkgdXNhZ2UgaW4gdGhlIGltYWdlIHByb2Nlc3NpbmcgcGlwZWxpbmUnLFxuICAgIF0sXG4gICAgY29uZnVzaW5nX3dpdGg6IFsncmVzZWFyY2hlciddLFxuICB9LFxuICBkZXZvcHM6IHtcbiAgICBkZXNjcmlwdGlvbjogJ0Rldk9wcyBzcGVjaWFsaXN0IGZvciBDSS9DRCBwaXBlbGluZXMsIGRlcGxveW1lbnQgYXV0b21hdGlvbiwgYW5kIGluZnJhc3RydWN0dXJlIG1hbmFnZW1lbnQuJyxcbiAgICBrZXl3b3JkczogWydkZXBsb3knLCAnY2kvY2QnLCAncGlwZWxpbmUnLCAnZG9ja2VyJywgJ2t1YmVybmV0ZXMnLCAndGVycmFmb3JtJywgJ2F3cycsICdpbmZyYXN0cnVjdHVyZSddLFxuICAgIGV4YW1wbGVzOiBbXG4gICAgICAnU2V0IHVwIHRoZSBDSS9DRCBwaXBlbGluZSBmb3IgdGhlIG1pY3Jvc2VydmljZXMnLFxuICAgICAgJ0NvbmZpZ3VyZSBEb2NrZXIgY29udGFpbmVycyBmb3IgdGhlIGFwcGxpY2F0aW9uJyxcbiAgICAgICdEZXBsb3kgdGhlIGFwcGxpY2F0aW9uIHRvIHRoZSBzdGFnaW5nIGVudmlyb25tZW50JyxcbiAgICAgICdDcmVhdGUgVGVycmFmb3JtIHNjcmlwdHMgZm9yIHRoZSBBV1MgaW5mcmFzdHJ1Y3R1cmUnLFxuICAgIF0sXG4gICAgY29uZnVzaW5nX3dpdGg6IFtdLFxuICB9LFxuICAnYXBpLWRvY3MnOiB7XG4gICAgZGVzY3JpcHRpb246ICdBUEkgZG9jdW1lbnRhdGlvbiBzcGVjaWFsaXN0IGZvciBjcmVhdGluZyBPcGVuQVBJIHNwZWNzLCBTd2FnZ2VyIGRvY3VtZW50YXRpb24sIGFuZCBBUEkgcmVmZXJlbmNlcy4nLFxuICAgIGtleXdvcmRzOiBbJ29wZW5hcGknLCAnc3dhZ2dlcicsICdhcGkgZG9jcycsICdlbmRwb2ludCcsICdzcGVjaWZpY2F0aW9uJywgJ3NjaGVtYScsICdyZXN0J10sXG4gICAgZXhhbXBsZXM6IFtcbiAgICAgICdHZW5lcmF0ZSBPcGVuQVBJIGRvY3VtZW50YXRpb24gZm9yIHRoZSBSRVNUIEFQSScsXG4gICAgICAnQ3JlYXRlIFN3YWdnZXIgc3BlY3MgZm9yIHRoZSB1c2VyIGVuZHBvaW50cycsXG4gICAgICAnRG9jdW1lbnQgdGhlIEFQSSBhdXRoZW50aWNhdGlvbiByZXF1aXJlbWVudHMnLFxuICAgICAgJ1VwZGF0ZSB0aGUgQVBJIHJlZmVyZW5jZSB3aXRoIG5ldyBlbmRwb2ludHMnLFxuICAgIF0sXG4gICAgY29uZnVzaW5nX3dpdGg6IFsnZG9jdW1lbnRlciddLFxuICB9LFxuICBwbGFubmVyOiB7XG4gICAgZGVzY3JpcHRpb246ICdQcm9qZWN0IHBsYW5uaW5nIHNwZWNpYWxpc3QgZm9yIGNyZWF0aW5nIHRhc2sgcGxhbnMsIHNwcmludCBwbGFubmluZywgYW5kIHJvYWRtYXAgZGV2ZWxvcG1lbnQuJyxcbiAgICBrZXl3b3JkczogWydwbGFuJywgJ3JvYWRtYXAnLCAnc3ByaW50JywgJ21pbGVzdG9uZScsICd0aW1lbGluZScsICdlc3RpbWF0ZScsICdicmVha2Rvd24nLCAncHJpb3JpdGl6ZSddLFxuICAgIGV4YW1wbGVzOiBbXG4gICAgICAnQ3JlYXRlIGEgc3ByaW50IHBsYW4gZm9yIHRoZSBuZXh0IHR3byB3ZWVrcycsXG4gICAgICAnQnJlYWsgZG93biB0aGUgZmVhdHVyZSBpbnRvIHNtYWxsZXIgdGFza3MnLFxuICAgICAgJ0VzdGltYXRlIHRoZSBlZmZvcnQgZm9yIHRoZSBtaWdyYXRpb24gcHJvamVjdCcsXG4gICAgICAnUHJpb3JpdGl6ZSB0aGUgYnVnIGZpeGVzIGZvciB0aGUgcmVsZWFzZScsXG4gICAgXSxcbiAgICBjb25mdXNpbmdfd2l0aDogWydhcmNoaXRlY3QnLCAncmVzZWFyY2hlciddLFxuICB9LFxufTtcblxuLyoqXG4gKiBHZW5lcmF0ZSB0cmFpbmluZyBkYXRhc2V0IGZyb20gYWdlbnQgZGF0YVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2VuZXJhdGVUcmFpbmluZ0RhdGFzZXQoKTogVHJhaW5pbmdFeGFtcGxlW10ge1xuICBjb25zdCBleGFtcGxlczogVHJhaW5pbmdFeGFtcGxlW10gPSBbXTtcblxuICBmb3IgKGNvbnN0IFthZ2VudCwgZGF0YV0gb2YgT2JqZWN0LmVudHJpZXMoQUdFTlRfVFJBSU5JTkdfREFUQSkpIHtcbiAgICAvLyBBZGQgZGlyZWN0IGV4YW1wbGVzXG4gICAgZm9yIChjb25zdCBleGFtcGxlIG9mIGRhdGEuZXhhbXBsZXMpIHtcbiAgICAgIGV4YW1wbGVzLnB1c2goe1xuICAgICAgICB0YXNrOiBleGFtcGxlLFxuICAgICAgICBhZ2VudCxcbiAgICAgICAgY29tcGxleGl0eTogJ21lZGl1bScsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBHZW5lcmF0ZSB2YXJpYXRpb25zIHdpdGgga2V5d29yZHNcbiAgICBmb3IgKGNvbnN0IGtleXdvcmQgb2YgZGF0YS5rZXl3b3Jkcykge1xuICAgICAgZXhhbXBsZXMucHVzaCh7XG4gICAgICAgIHRhc2s6IGAke2tleXdvcmR9IGEgc29sdXRpb24gZm9yIHRoZSBhdXRoZW50aWNhdGlvbiBzeXN0ZW1gLFxuICAgICAgICBhZ2VudCxcbiAgICAgICAgY29tcGxleGl0eTogJ2xvdycsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBBZGQgY29uZnVzaW5nIHBhaXJzIGZvciBoYXJkIG5lZ2F0aXZlc1xuICAgIGlmIChkYXRhLmNvbmZ1c2luZ193aXRoKSB7XG4gICAgICBmb3IgKGNvbnN0IGNvbmZ1c2luZ0FnZW50IG9mIGRhdGEuY29uZnVzaW5nX3dpdGgpIHtcbiAgICAgICAgZm9yIChjb25zdCBleGFtcGxlIG9mIGRhdGEuZXhhbXBsZXMuc2xpY2UoMCwgMikpIHtcbiAgICAgICAgICBleGFtcGxlcy5wdXNoKHtcbiAgICAgICAgICAgIHRhc2s6IGV4YW1wbGUsXG4gICAgICAgICAgICBhZ2VudCxcbiAgICAgICAgICAgIGNvbXBsZXhpdHk6ICdoYXJkJyxcbiAgICAgICAgICAgIGNvbmZ1c2luZ193aXRoOiBjb25mdXNpbmdBZ2VudCxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBleGFtcGxlcztcbn1cblxuLyoqXG4gKiBHZW5lcmF0ZSBjb250cmFzdGl2ZSBwYWlycyBmb3IgdHJhaW5pbmdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlQ29udHJhc3RpdmVQYWlycygpOiBBcnJheTx7XG4gIGFuY2hvcjogc3RyaW5nO1xuICBwb3NpdGl2ZTogc3RyaW5nO1xuICBuZWdhdGl2ZTogc3RyaW5nO1xuICBpc0hhcmQ6IGJvb2xlYW47XG59PiB7XG4gIGNvbnN0IHBhaXJzOiBBcnJheTx7IGFuY2hvcjogc3RyaW5nOyBwb3NpdGl2ZTogc3RyaW5nOyBuZWdhdGl2ZTogc3RyaW5nOyBpc0hhcmQ6IGJvb2xlYW4gfT4gPSBbXTtcbiAgY29uc3QgYWdlbnRzID0gT2JqZWN0LmtleXMoQUdFTlRfVFJBSU5JTkdfREFUQSk7XG5cbiAgZm9yIChjb25zdCBbYWdlbnQsIGRhdGFdIG9mIE9iamVjdC5lbnRyaWVzKEFHRU5UX1RSQUlOSU5HX0RBVEEpKSB7XG4gICAgZm9yIChjb25zdCBleGFtcGxlIG9mIGRhdGEuZXhhbXBsZXMpIHtcbiAgICAgIC8vIEhhcmQgbmVnYXRpdmVzIGZyb20gY29uZnVzaW5nIGFnZW50c1xuICAgICAgaWYgKGRhdGEuY29uZnVzaW5nX3dpdGgpIHtcbiAgICAgICAgZm9yIChjb25zdCBuZWdBZ2VudCBvZiBkYXRhLmNvbmZ1c2luZ193aXRoKSB7XG4gICAgICAgICAgcGFpcnMucHVzaCh7XG4gICAgICAgICAgICBhbmNob3I6IGV4YW1wbGUsXG4gICAgICAgICAgICBwb3NpdGl2ZTogYWdlbnQsXG4gICAgICAgICAgICBuZWdhdGl2ZTogbmVnQWdlbnQsXG4gICAgICAgICAgICBpc0hhcmQ6IHRydWUsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gUmFuZG9tIG5lZ2F0aXZlc1xuICAgICAgY29uc3QgcmFuZG9tTmVncyA9IGFnZW50cy5maWx0ZXIoYSA9PiBhICE9PSBhZ2VudCkuc2xpY2UoMCwgMik7XG4gICAgICBmb3IgKGNvbnN0IG5lZ0FnZW50IG9mIHJhbmRvbU5lZ3MpIHtcbiAgICAgICAgcGFpcnMucHVzaCh7XG4gICAgICAgICAgYW5jaG9yOiBleGFtcGxlLFxuICAgICAgICAgIHBvc2l0aXZlOiBhZ2VudCxcbiAgICAgICAgICBuZWdhdGl2ZTogbmVnQWdlbnQsXG4gICAgICAgICAgaXNIYXJkOiBmYWxzZSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHBhaXJzO1xufVxuXG4vKipcbiAqIEdldCBkYXRhc2V0IHN0YXRpc3RpY3NcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldERhdGFzZXRTdGF0cygpOiBEYXRhc2V0U3RhdHMge1xuICBjb25zdCBleGFtcGxlcyA9IGdlbmVyYXRlVHJhaW5pbmdEYXRhc2V0KCk7XG4gIGNvbnN0IHBhaXJzID0gZ2VuZXJhdGVDb250cmFzdGl2ZVBhaXJzKCk7XG4gIGNvbnN0IGFnZW50cyA9IE9iamVjdC5rZXlzKEFHRU5UX1RSQUlOSU5HX0RBVEEpO1xuXG4gIHJldHVybiB7XG4gICAgdG90YWxFeGFtcGxlczogZXhhbXBsZXMubGVuZ3RoLFxuICAgIGNvbnRyYXN0aXZlUGFpcnM6IHBhaXJzLmxlbmd0aCxcbiAgICBhZ2VudFR5cGVzOiBhZ2VudHMubGVuZ3RoLFxuICAgIGFnZW50cyxcbiAgfTtcbn1cbiJdfQ==