@ruvector/ruvllm 4.0.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/README.md +449 -158
  2. package/bin/cli.js +1066 -0
  3. package/bin/gpu-delegate.js +67 -0
  4. package/bin/ruvllm-adapters.js +5 -0
  5. package/bin/ruvllm-gpu-loop.js +5 -0
  6. package/bin/serve.js +265 -0
  7. package/dist/cjs/benchmarks/embedding-benchmark.d.ts +102 -0
  8. package/dist/cjs/benchmarks/embedding-benchmark.d.ts.map +1 -0
  9. package/dist/cjs/benchmarks/embedding-benchmark.js +436 -0
  10. package/dist/cjs/benchmarks/index.d.ts +34 -0
  11. package/dist/cjs/benchmarks/index.d.ts.map +1 -0
  12. package/dist/cjs/benchmarks/index.js +132 -0
  13. package/dist/cjs/benchmarks/model-comparison.d.ts +71 -0
  14. package/dist/cjs/benchmarks/model-comparison.d.ts.map +1 -0
  15. package/dist/cjs/benchmarks/model-comparison.js +476 -0
  16. package/dist/cjs/benchmarks/routing-benchmark.d.ts +70 -0
  17. package/dist/cjs/benchmarks/routing-benchmark.d.ts.map +1 -0
  18. package/dist/cjs/benchmarks/routing-benchmark.js +289 -0
  19. package/dist/cjs/contrastive.d.ts +229 -0
  20. package/dist/cjs/contrastive.d.ts.map +1 -0
  21. package/dist/cjs/contrastive.js +589 -0
  22. package/dist/cjs/engine.d.ts +160 -0
  23. package/dist/cjs/engine.d.ts.map +1 -0
  24. package/dist/cjs/engine.js +552 -0
  25. package/dist/cjs/export.d.ts +182 -0
  26. package/dist/cjs/export.d.ts.map +1 -0
  27. package/dist/cjs/export.js +422 -0
  28. package/dist/cjs/federated.d.ts +233 -0
  29. package/dist/cjs/federated.d.ts.map +1 -0
  30. package/dist/cjs/federated.js +525 -0
  31. package/dist/cjs/index.d.ts +68 -0
  32. package/dist/cjs/index.d.ts.map +1 -0
  33. package/dist/cjs/index.js +104 -0
  34. package/dist/cjs/intelligence.d.ts +136 -0
  35. package/dist/cjs/intelligence.d.ts.map +1 -0
  36. package/dist/cjs/intelligence.js +226 -0
  37. package/dist/cjs/lora.d.ts +251 -0
  38. package/dist/cjs/lora.d.ts.map +1 -0
  39. package/dist/cjs/lora.js +509 -0
  40. package/dist/cjs/models.d.ts +129 -0
  41. package/dist/cjs/models.d.ts.map +1 -0
  42. package/dist/cjs/models.js +323 -0
  43. package/dist/cjs/native.d.ts +140 -0
  44. package/dist/cjs/native.d.ts.map +1 -0
  45. package/dist/cjs/native.js +98 -0
  46. package/dist/cjs/session.d.ts +80 -0
  47. package/dist/cjs/session.d.ts.map +1 -0
  48. package/dist/cjs/session.js +203 -0
  49. package/dist/cjs/simd.d.ts +90 -0
  50. package/dist/cjs/simd.d.ts.map +1 -0
  51. package/dist/cjs/simd.js +209 -0
  52. package/dist/cjs/sona.d.ts +223 -0
  53. package/dist/cjs/sona.d.ts.map +1 -0
  54. package/dist/cjs/sona.js +562 -0
  55. package/dist/cjs/streaming.d.ts +55 -0
  56. package/dist/cjs/streaming.d.ts.map +1 -0
  57. package/dist/cjs/streaming.js +131 -0
  58. package/dist/cjs/training.d.ts +312 -0
  59. package/dist/cjs/training.d.ts.map +1 -0
  60. package/dist/cjs/training.js +610 -0
  61. package/dist/cjs/types.d.ts +696 -0
  62. package/dist/cjs/types.d.ts.map +1 -0
  63. package/dist/cjs/types.js +6 -0
  64. package/dist/esm/benchmarks/embedding-benchmark.d.ts +102 -0
  65. package/dist/esm/benchmarks/embedding-benchmark.d.ts.map +1 -0
  66. package/dist/esm/benchmarks/embedding-benchmark.js +427 -0
  67. package/dist/esm/benchmarks/index.d.ts +34 -0
  68. package/dist/esm/benchmarks/index.d.ts.map +1 -0
  69. package/dist/esm/benchmarks/index.js +110 -0
  70. package/dist/esm/benchmarks/model-comparison.d.ts +71 -0
  71. package/dist/esm/benchmarks/model-comparison.d.ts.map +1 -0
  72. package/dist/esm/benchmarks/model-comparison.js +434 -0
  73. package/dist/esm/benchmarks/routing-benchmark.d.ts +70 -0
  74. package/dist/esm/benchmarks/routing-benchmark.d.ts.map +1 -0
  75. package/dist/esm/benchmarks/routing-benchmark.js +283 -0
  76. package/dist/esm/contrastive.d.ts +229 -0
  77. package/dist/esm/contrastive.d.ts.map +1 -0
  78. package/dist/esm/contrastive.js +578 -0
  79. package/dist/esm/engine.d.ts +160 -0
  80. package/dist/esm/engine.d.ts.map +1 -0
  81. package/dist/esm/engine.js +548 -0
  82. package/dist/esm/export.d.ts +182 -0
  83. package/dist/esm/export.d.ts.map +1 -0
  84. package/dist/esm/export.js +414 -0
  85. package/dist/esm/federated.d.ts +233 -0
  86. package/dist/esm/federated.d.ts.map +1 -0
  87. package/dist/esm/federated.js +520 -0
  88. package/dist/esm/index.d.ts +68 -0
  89. package/dist/esm/index.d.ts.map +1 -0
  90. package/dist/esm/index.js +84 -0
  91. package/dist/esm/intelligence.d.ts +136 -0
  92. package/dist/esm/intelligence.d.ts.map +1 -0
  93. package/dist/esm/intelligence.js +188 -0
  94. package/dist/esm/lora.d.ts +251 -0
  95. package/dist/esm/lora.d.ts.map +1 -0
  96. package/dist/esm/lora.js +504 -0
  97. package/dist/esm/models.d.ts +129 -0
  98. package/dist/esm/models.d.ts.map +1 -0
  99. package/dist/esm/models.js +282 -0
  100. package/dist/esm/native.d.ts +140 -0
  101. package/dist/esm/native.d.ts.map +1 -0
  102. package/dist/esm/native.js +100 -0
  103. package/dist/esm/session.d.ts +80 -0
  104. package/dist/esm/session.d.ts.map +1 -0
  105. package/dist/esm/session.js +199 -0
  106. package/dist/esm/simd.d.ts +90 -0
  107. package/dist/esm/simd.d.ts.map +1 -0
  108. package/dist/esm/simd.js +205 -0
  109. package/dist/esm/sona.d.ts +223 -0
  110. package/dist/esm/sona.d.ts.map +1 -0
  111. package/dist/esm/sona.js +556 -0
  112. package/dist/esm/streaming.d.ts +55 -0
  113. package/dist/esm/streaming.d.ts.map +1 -0
  114. package/dist/esm/streaming.js +126 -0
  115. package/dist/esm/training.d.ts +312 -0
  116. package/dist/esm/training.d.ts.map +1 -0
  117. package/dist/esm/training.js +603 -0
  118. package/dist/esm/types.d.ts +696 -0
  119. package/dist/esm/types.d.ts.map +1 -0
  120. package/dist/esm/types.js +5 -0
  121. package/gpu/_load.cjs +38 -0
  122. package/gpu/_load.mjs +33 -0
  123. package/gpu/adapters.cjs +3 -0
  124. package/gpu/adapters.mjs +5 -0
  125. package/gpu/engine.cjs +3 -0
  126. package/gpu/engine.mjs +5 -0
  127. package/gpu/fixture.cjs +3 -0
  128. package/gpu/fixture.mjs +5 -0
  129. package/gpu/gpu-host.cjs +3 -0
  130. package/gpu/gpu-host.mjs +5 -0
  131. package/gpu/gpu-loop.cjs +3 -0
  132. package/gpu/gpu-loop.mjs +5 -0
  133. package/gpu/gpu-spool-adapter.cjs +3 -0
  134. package/gpu/gpu-spool-adapter.mjs +5 -0
  135. package/gpu/vast-host-adapter.cjs +3 -0
  136. package/gpu/vast-host-adapter.mjs +5 -0
  137. package/package.json +159 -49
  138. package/scripts/ensemble-model-compare.js +287 -0
  139. package/scripts/fix-esm-extensions.mjs +220 -0
  140. package/scripts/huggingface/README.md +537 -0
  141. package/scripts/huggingface/publish.sh +112 -0
  142. package/scripts/hybrid-model-compare.js +373 -0
  143. package/scripts/improved-model-compare.js +288 -0
  144. package/scripts/optimized-model-compare.js +364 -0
  145. package/scripts/real-model-compare.js +280 -0
  146. package/scripts/smoke-esm.mjs +82 -0
  147. package/scripts/training/agentic-flow-capabilities.json +329 -0
  148. package/scripts/training/claude-code-synth.js +505 -0
  149. package/scripts/training/claude-flow-capabilities.json +1322 -0
  150. package/scripts/training/claude-hard-negatives.js +222 -0
  151. package/scripts/training/contrastive-finetune.js +517 -0
  152. package/scripts/training/ecosystem-triplets.jsonl +1467 -0
  153. package/scripts/training/generate-ecosystem-triplets.js +1324 -0
  154. package/scripts/training/routing-dataset.js +634 -0
  155. package/scripts/training/ruvector-capabilities.json +798 -0
  156. package/scripts/training/validate-ecosystem.js +381 -0
  157. package/scripts/training/validation-results.json +23 -0
  158. package/GPU-LOOP.md +0 -229
  159. package/LICENSE +0 -201
  160. package/NOTICE +0 -9
  161. package/examples/gpu-loop.example.json +0 -26
  162. package/src/adapters-cli.mjs +0 -23
  163. package/src/adapters.mjs +0 -91
  164. package/src/cli.mjs +0 -30
  165. package/src/engine.mjs +0 -238
  166. package/src/fixture.mjs +0 -38
  167. package/src/gpu-host.mjs +0 -47
  168. package/src/gpu-loop-cli.mjs +0 -67
  169. package/src/gpu-loop.mjs +0 -184
  170. package/src/gpu-spool-adapter.mjs +0 -80
  171. package/src/vast-host-adapter.mjs +0 -274
@@ -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==