@ruvector/ruvllm 3.0.0 → 4.0.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 (151) hide show
  1. package/GPU-LOOP.md +229 -0
  2. package/LICENSE +201 -0
  3. package/NOTICE +9 -0
  4. package/README.md +157 -362
  5. package/examples/gpu-loop.example.json +26 -0
  6. package/package.json +50 -121
  7. package/src/adapters-cli.mjs +23 -0
  8. package/src/adapters.mjs +91 -0
  9. package/src/cli.mjs +30 -0
  10. package/src/engine.mjs +238 -0
  11. package/src/fixture.mjs +38 -0
  12. package/src/gpu-host.mjs +47 -0
  13. package/src/gpu-loop-cli.mjs +67 -0
  14. package/src/gpu-loop.mjs +184 -0
  15. package/src/gpu-spool-adapter.mjs +80 -0
  16. package/src/vast-host-adapter.mjs +274 -0
  17. package/bin/cli.js +0 -1040
  18. package/dist/cjs/benchmarks/embedding-benchmark.d.ts +0 -102
  19. package/dist/cjs/benchmarks/embedding-benchmark.d.ts.map +0 -1
  20. package/dist/cjs/benchmarks/embedding-benchmark.js +0 -436
  21. package/dist/cjs/benchmarks/index.d.ts +0 -34
  22. package/dist/cjs/benchmarks/index.d.ts.map +0 -1
  23. package/dist/cjs/benchmarks/index.js +0 -132
  24. package/dist/cjs/benchmarks/model-comparison.d.ts +0 -71
  25. package/dist/cjs/benchmarks/model-comparison.d.ts.map +0 -1
  26. package/dist/cjs/benchmarks/model-comparison.js +0 -476
  27. package/dist/cjs/benchmarks/routing-benchmark.d.ts +0 -70
  28. package/dist/cjs/benchmarks/routing-benchmark.d.ts.map +0 -1
  29. package/dist/cjs/benchmarks/routing-benchmark.js +0 -289
  30. package/dist/cjs/contrastive.d.ts +0 -229
  31. package/dist/cjs/contrastive.d.ts.map +0 -1
  32. package/dist/cjs/contrastive.js +0 -589
  33. package/dist/cjs/engine.d.ts +0 -160
  34. package/dist/cjs/engine.d.ts.map +0 -1
  35. package/dist/cjs/engine.js +0 -552
  36. package/dist/cjs/export.d.ts +0 -182
  37. package/dist/cjs/export.d.ts.map +0 -1
  38. package/dist/cjs/export.js +0 -422
  39. package/dist/cjs/federated.d.ts +0 -233
  40. package/dist/cjs/federated.d.ts.map +0 -1
  41. package/dist/cjs/federated.js +0 -525
  42. package/dist/cjs/index.d.ts +0 -68
  43. package/dist/cjs/index.d.ts.map +0 -1
  44. package/dist/cjs/index.js +0 -104
  45. package/dist/cjs/intelligence.d.ts +0 -136
  46. package/dist/cjs/intelligence.d.ts.map +0 -1
  47. package/dist/cjs/intelligence.js +0 -226
  48. package/dist/cjs/lora.d.ts +0 -251
  49. package/dist/cjs/lora.d.ts.map +0 -1
  50. package/dist/cjs/lora.js +0 -509
  51. package/dist/cjs/models.d.ts +0 -129
  52. package/dist/cjs/models.d.ts.map +0 -1
  53. package/dist/cjs/models.js +0 -323
  54. package/dist/cjs/native.d.ts +0 -140
  55. package/dist/cjs/native.d.ts.map +0 -1
  56. package/dist/cjs/native.js +0 -98
  57. package/dist/cjs/session.d.ts +0 -80
  58. package/dist/cjs/session.d.ts.map +0 -1
  59. package/dist/cjs/session.js +0 -203
  60. package/dist/cjs/simd.d.ts +0 -90
  61. package/dist/cjs/simd.d.ts.map +0 -1
  62. package/dist/cjs/simd.js +0 -209
  63. package/dist/cjs/sona.d.ts +0 -223
  64. package/dist/cjs/sona.d.ts.map +0 -1
  65. package/dist/cjs/sona.js +0 -562
  66. package/dist/cjs/streaming.d.ts +0 -55
  67. package/dist/cjs/streaming.d.ts.map +0 -1
  68. package/dist/cjs/streaming.js +0 -131
  69. package/dist/cjs/training.d.ts +0 -312
  70. package/dist/cjs/training.d.ts.map +0 -1
  71. package/dist/cjs/training.js +0 -610
  72. package/dist/cjs/types.d.ts +0 -696
  73. package/dist/cjs/types.d.ts.map +0 -1
  74. package/dist/cjs/types.js +0 -6
  75. package/dist/esm/benchmarks/embedding-benchmark.d.ts +0 -102
  76. package/dist/esm/benchmarks/embedding-benchmark.d.ts.map +0 -1
  77. package/dist/esm/benchmarks/embedding-benchmark.js +0 -427
  78. package/dist/esm/benchmarks/index.d.ts +0 -34
  79. package/dist/esm/benchmarks/index.d.ts.map +0 -1
  80. package/dist/esm/benchmarks/index.js +0 -110
  81. package/dist/esm/benchmarks/model-comparison.d.ts +0 -71
  82. package/dist/esm/benchmarks/model-comparison.d.ts.map +0 -1
  83. package/dist/esm/benchmarks/model-comparison.js +0 -434
  84. package/dist/esm/benchmarks/routing-benchmark.d.ts +0 -70
  85. package/dist/esm/benchmarks/routing-benchmark.d.ts.map +0 -1
  86. package/dist/esm/benchmarks/routing-benchmark.js +0 -283
  87. package/dist/esm/contrastive.d.ts +0 -229
  88. package/dist/esm/contrastive.d.ts.map +0 -1
  89. package/dist/esm/contrastive.js +0 -578
  90. package/dist/esm/engine.d.ts +0 -160
  91. package/dist/esm/engine.d.ts.map +0 -1
  92. package/dist/esm/engine.js +0 -548
  93. package/dist/esm/export.d.ts +0 -182
  94. package/dist/esm/export.d.ts.map +0 -1
  95. package/dist/esm/export.js +0 -414
  96. package/dist/esm/federated.d.ts +0 -233
  97. package/dist/esm/federated.d.ts.map +0 -1
  98. package/dist/esm/federated.js +0 -520
  99. package/dist/esm/index.d.ts +0 -68
  100. package/dist/esm/index.d.ts.map +0 -1
  101. package/dist/esm/index.js +0 -84
  102. package/dist/esm/intelligence.d.ts +0 -136
  103. package/dist/esm/intelligence.d.ts.map +0 -1
  104. package/dist/esm/intelligence.js +0 -188
  105. package/dist/esm/lora.d.ts +0 -251
  106. package/dist/esm/lora.d.ts.map +0 -1
  107. package/dist/esm/lora.js +0 -504
  108. package/dist/esm/models.d.ts +0 -129
  109. package/dist/esm/models.d.ts.map +0 -1
  110. package/dist/esm/models.js +0 -282
  111. package/dist/esm/native.d.ts +0 -140
  112. package/dist/esm/native.d.ts.map +0 -1
  113. package/dist/esm/native.js +0 -93
  114. package/dist/esm/session.d.ts +0 -80
  115. package/dist/esm/session.d.ts.map +0 -1
  116. package/dist/esm/session.js +0 -199
  117. package/dist/esm/simd.d.ts +0 -90
  118. package/dist/esm/simd.d.ts.map +0 -1
  119. package/dist/esm/simd.js +0 -205
  120. package/dist/esm/sona.d.ts +0 -223
  121. package/dist/esm/sona.d.ts.map +0 -1
  122. package/dist/esm/sona.js +0 -556
  123. package/dist/esm/streaming.d.ts +0 -55
  124. package/dist/esm/streaming.d.ts.map +0 -1
  125. package/dist/esm/streaming.js +0 -126
  126. package/dist/esm/training.d.ts +0 -312
  127. package/dist/esm/training.d.ts.map +0 -1
  128. package/dist/esm/training.js +0 -603
  129. package/dist/esm/types.d.ts +0 -696
  130. package/dist/esm/types.d.ts.map +0 -1
  131. package/dist/esm/types.js +0 -5
  132. package/scripts/ensemble-model-compare.js +0 -287
  133. package/scripts/fix-esm-extensions.mjs +0 -181
  134. package/scripts/huggingface/README.md +0 -537
  135. package/scripts/huggingface/publish.sh +0 -112
  136. package/scripts/hybrid-model-compare.js +0 -373
  137. package/scripts/improved-model-compare.js +0 -288
  138. package/scripts/optimized-model-compare.js +0 -364
  139. package/scripts/real-model-compare.js +0 -280
  140. package/scripts/smoke-esm.mjs +0 -82
  141. package/scripts/training/agentic-flow-capabilities.json +0 -329
  142. package/scripts/training/claude-code-synth.js +0 -505
  143. package/scripts/training/claude-flow-capabilities.json +0 -1322
  144. package/scripts/training/claude-hard-negatives.js +0 -222
  145. package/scripts/training/contrastive-finetune.js +0 -517
  146. package/scripts/training/ecosystem-triplets.jsonl +0 -1467
  147. package/scripts/training/generate-ecosystem-triplets.js +0 -1324
  148. package/scripts/training/routing-dataset.js +0 -634
  149. package/scripts/training/ruvector-capabilities.json +0 -798
  150. package/scripts/training/validate-ecosystem.js +0 -381
  151. package/scripts/training/validation-results.json +0 -23
@@ -1,476 +0,0 @@
1
- "use strict";
2
- /**
3
- * Model Comparison Benchmark
4
- *
5
- * Head-to-head comparison between:
6
- * - Qwen2.5-0.5B-Instruct (base model)
7
- * - RuvLTRA Claude Code 0.5B (fine-tuned for Claude Code)
8
- *
9
- * Tests routing accuracy and embedding quality for Claude Code use cases.
10
- */
11
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
- if (k2 === undefined) k2 = k;
13
- var desc = Object.getOwnPropertyDescriptor(m, k);
14
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
- desc = { enumerable: true, get: function() { return m[k]; } };
16
- }
17
- Object.defineProperty(o, k2, desc);
18
- }) : (function(o, m, k, k2) {
19
- if (k2 === undefined) k2 = k;
20
- o[k2] = m[k];
21
- }));
22
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
- Object.defineProperty(o, "default", { enumerable: true, value: v });
24
- }) : function(o, v) {
25
- o["default"] = v;
26
- });
27
- var __importStar = (this && this.__importStar) || (function () {
28
- var ownKeys = function(o) {
29
- ownKeys = Object.getOwnPropertyNames || function (o) {
30
- var ar = [];
31
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
- return ar;
33
- };
34
- return ownKeys(o);
35
- };
36
- return function (mod) {
37
- if (mod && mod.__esModule) return mod;
38
- var result = {};
39
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
- __setModuleDefault(result, mod);
41
- return result;
42
- };
43
- })();
44
- Object.defineProperty(exports, "__esModule", { value: true });
45
- exports.COMPARISON_MODELS = void 0;
46
- exports.getModelsDir = getModelsDir;
47
- exports.isModelDownloaded = isModelDownloaded;
48
- exports.downloadModel = downloadModel;
49
- exports.runModelComparison = runModelComparison;
50
- exports.formatComparisonResults = formatComparisonResults;
51
- exports.runFullComparison = runFullComparison;
52
- const fs_1 = require("fs");
53
- const path_1 = require("path");
54
- const os_1 = require("os");
55
- const routing_benchmark_1 = require("./routing-benchmark");
56
- const embedding_benchmark_1 = require("./embedding-benchmark");
57
- /** Comparison models */
58
- exports.COMPARISON_MODELS = {
59
- 'qwen-base': {
60
- id: 'qwen-base',
61
- name: 'Qwen2.5-0.5B-Instruct',
62
- url: 'https://huggingface.co/Qwen/Qwen2.5-0.5B-Instruct-GGUF/resolve/main/qwen2.5-0.5b-instruct-q4_k_m.gguf',
63
- filename: 'qwen2.5-0.5b-instruct-q4_k_m.gguf',
64
- sizeBytes: 491000000,
65
- description: 'Base Qwen 0.5B model (Q4_K_M quantized)',
66
- },
67
- 'ruvltra-claude-code': {
68
- id: 'ruvltra-claude-code',
69
- name: 'RuvLTRA Claude Code 0.5B',
70
- url: 'https://huggingface.co/ruv/ruvltra/resolve/main/ruvltra-claude-code-0.5b-q4_k_m.gguf',
71
- filename: 'ruvltra-claude-code-0.5b-q4_k_m.gguf',
72
- sizeBytes: 398000000,
73
- description: 'RuvLTRA fine-tuned for Claude Code workflows',
74
- },
75
- };
76
- /**
77
- * Get models directory
78
- */
79
- function getModelsDir() {
80
- return (0, path_1.join)((0, os_1.homedir)(), '.ruvllm', 'models');
81
- }
82
- /**
83
- * Check if model is downloaded
84
- */
85
- function isModelDownloaded(modelId) {
86
- const model = exports.COMPARISON_MODELS[modelId];
87
- if (!model)
88
- return false;
89
- const path = (0, path_1.join)(getModelsDir(), model.filename);
90
- if (!(0, fs_1.existsSync)(path))
91
- return false;
92
- const stats = (0, fs_1.statSync)(path);
93
- return stats.size >= model.sizeBytes * 0.9; // Allow 10% variance
94
- }
95
- /**
96
- * Download a model with progress
97
- */
98
- async function downloadModel(modelId, onProgress) {
99
- const model = exports.COMPARISON_MODELS[modelId];
100
- if (!model) {
101
- throw new Error(`Unknown model: ${modelId}`);
102
- }
103
- const modelsDir = getModelsDir();
104
- if (!(0, fs_1.existsSync)(modelsDir)) {
105
- (0, fs_1.mkdirSync)(modelsDir, { recursive: true });
106
- }
107
- const destPath = (0, path_1.join)(modelsDir, model.filename);
108
- if (isModelDownloaded(modelId)) {
109
- return destPath;
110
- }
111
- console.log(`Downloading ${model.name}...`);
112
- console.log(` From: ${model.url}`);
113
- console.log(` Size: ${(model.sizeBytes / 1024 / 1024).toFixed(0)} MB`);
114
- const tempPath = `${destPath}.tmp`;
115
- let downloaded = 0;
116
- let lastTime = Date.now();
117
- let lastDownloaded = 0;
118
- const response = await fetch(model.url, {
119
- headers: { 'User-Agent': 'RuvLLM/2.3.0' },
120
- });
121
- if (!response.ok) {
122
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
123
- }
124
- const contentLength = parseInt(response.headers.get('content-length') || String(model.sizeBytes));
125
- const fileStream = (0, fs_1.createWriteStream)(tempPath);
126
- const reader = response.body?.getReader();
127
- if (!reader) {
128
- throw new Error('Response body not readable');
129
- }
130
- while (true) {
131
- const { done, value } = await reader.read();
132
- if (done)
133
- break;
134
- downloaded += value.length;
135
- fileStream.write(value);
136
- if (onProgress) {
137
- const now = Date.now();
138
- const elapsed = (now - lastTime) / 1000;
139
- if (elapsed >= 0.5) {
140
- const speed = (downloaded - lastDownloaded) / elapsed;
141
- onProgress(Math.round((downloaded / contentLength) * 100), speed);
142
- lastTime = now;
143
- lastDownloaded = downloaded;
144
- }
145
- }
146
- }
147
- fileStream.end();
148
- await new Promise((resolve, reject) => {
149
- fileStream.on('finish', resolve);
150
- fileStream.on('error', reject);
151
- });
152
- // Rename temp to final
153
- const { renameSync, unlinkSync } = await Promise.resolve().then(() => __importStar(require('fs')));
154
- if ((0, fs_1.existsSync)(destPath)) {
155
- unlinkSync(destPath);
156
- }
157
- renameSync(tempPath, destPath);
158
- return destPath;
159
- }
160
- /**
161
- * Agent type keywords for routing classification
162
- */
163
- const AGENT_KEYWORDS = {
164
- coder: ['implement', 'create', 'write', 'build', 'add', 'code', 'function', 'class', 'component'],
165
- researcher: ['research', 'find', 'investigate', 'analyze', 'explore', 'search', 'look'],
166
- reviewer: ['review', 'check', 'evaluate', 'assess', 'inspect', 'examine'],
167
- tester: ['test', 'unit', 'integration', 'e2e', 'coverage', 'mock', 'assertion'],
168
- architect: ['design', 'architecture', 'schema', 'system', 'adr', 'structure', 'plan'],
169
- 'security-architect': ['security', 'vulnerability', 'xss', 'injection', 'audit', 'cve', 'auth'],
170
- debugger: ['debug', 'fix', 'bug', 'error', 'issue', 'broken', 'crash', 'exception'],
171
- documenter: ['document', 'readme', 'jsdoc', 'comment', 'explain', 'describe'],
172
- refactorer: ['refactor', 'extract', 'rename', 'consolidate', 'clean', 'restructure'],
173
- optimizer: ['optimize', 'performance', 'slow', 'fast', 'cache', 'speed', 'memory'],
174
- devops: ['deploy', 'ci', 'cd', 'kubernetes', 'docker', 'pipeline', 'container'],
175
- 'api-docs': ['openapi', 'swagger', 'api doc', 'graphql', 'endpoint doc'],
176
- planner: ['plan', 'estimate', 'prioritize', 'sprint', 'roadmap', 'schedule'],
177
- };
178
- /**
179
- * Enhanced keyword router with weighted scoring
180
- */
181
- function enhancedKeywordRouter(task) {
182
- const taskLower = task.toLowerCase();
183
- const scores = {};
184
- for (const [agent, keywords] of Object.entries(AGENT_KEYWORDS)) {
185
- scores[agent] = 0;
186
- for (const keyword of keywords) {
187
- if (taskLower.includes(keyword)) {
188
- // Weight by keyword position (earlier = more important)
189
- const pos = taskLower.indexOf(keyword);
190
- const weight = 1 + (1 - pos / taskLower.length) * 0.5;
191
- scores[agent] += weight;
192
- }
193
- }
194
- }
195
- // Find best match
196
- let bestAgent = 'coder';
197
- let bestScore = 0;
198
- for (const [agent, score] of Object.entries(scores)) {
199
- if (score > bestScore) {
200
- bestScore = score;
201
- bestAgent = agent;
202
- }
203
- }
204
- return {
205
- agent: bestAgent,
206
- confidence: Math.min(bestScore / 3, 1),
207
- };
208
- }
209
- /**
210
- * Simple embedding using character n-grams
211
- * This simulates what a model would do but with deterministic hashing
212
- */
213
- function simpleEmbedding(text, dim = 384) {
214
- const embedding = new Array(dim).fill(0);
215
- const normalized = text.toLowerCase().replace(/[^a-z0-9 ]/g, '');
216
- const words = normalized.split(/\s+/);
217
- // Word-level features
218
- for (let i = 0; i < words.length; i++) {
219
- const word = words[i];
220
- for (let j = 0; j < word.length; j++) {
221
- const idx = (word.charCodeAt(j) * 31 + j * 17 + i * 7) % dim;
222
- embedding[idx] += 1 / (i + 1); // Earlier words weighted more
223
- }
224
- // Bigrams
225
- if (i < words.length - 1) {
226
- const bigram = words[i] + words[i + 1];
227
- const bigramHash = bigram.split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) % 1000000, 0);
228
- const idx = bigramHash % dim;
229
- embedding[idx] += 0.5;
230
- }
231
- }
232
- // Normalize to unit vector
233
- const norm = Math.sqrt(embedding.reduce((s, x) => s + x * x, 0));
234
- if (norm > 0) {
235
- for (let i = 0; i < dim; i++) {
236
- embedding[i] /= norm;
237
- }
238
- }
239
- return embedding;
240
- }
241
- /**
242
- * Cosine similarity
243
- */
244
- function cosineSimilarity(a, b) {
245
- let dot = 0, normA = 0, normB = 0;
246
- for (let i = 0; i < a.length; i++) {
247
- dot += a[i] * b[i];
248
- normA += a[i] * a[i];
249
- normB += b[i] * b[i];
250
- }
251
- return dot / (Math.sqrt(normA) * Math.sqrt(normB) || 1);
252
- }
253
- /**
254
- * Simulate model-based routing using embedding similarity
255
- */
256
- function createModelRouter(embedder) {
257
- // Create agent embeddings from descriptions
258
- const agentDescriptions = {
259
- coder: 'implement create write build add new code function class component feature api endpoint',
260
- researcher: 'research find investigate analyze explore search look discover examine study',
261
- reviewer: 'review check evaluate assess inspect examine code quality pull request',
262
- tester: 'test unit integration e2e coverage mock assertion test case spec',
263
- architect: 'design architecture schema system structure plan adr database api contract',
264
- 'security-architect': 'security vulnerability xss sql injection audit cve authentication authorization',
265
- debugger: 'debug fix bug error issue broken crash exception trace stack',
266
- documenter: 'document readme jsdoc comment explain describe documentation guide tutorial',
267
- refactorer: 'refactor extract rename consolidate clean restructure simplify modularize',
268
- optimizer: 'optimize performance slow fast cache speed memory latency throughput',
269
- devops: 'deploy ci cd kubernetes docker pipeline container infrastructure cloud',
270
- 'api-docs': 'openapi swagger api documentation graphql schema endpoint specification',
271
- planner: 'plan estimate prioritize sprint roadmap schedule milestone task breakdown',
272
- };
273
- const agentEmbeddings = {};
274
- for (const [agent, desc] of Object.entries(agentDescriptions)) {
275
- agentEmbeddings[agent] = embedder(desc);
276
- }
277
- return (task) => {
278
- const taskEmbedding = embedder(task);
279
- let bestAgent = 'coder';
280
- let bestSimilarity = -1;
281
- for (const [agent, agentEmb] of Object.entries(agentEmbeddings)) {
282
- const sim = cosineSimilarity(taskEmbedding, agentEmb);
283
- if (sim > bestSimilarity) {
284
- bestSimilarity = sim;
285
- bestAgent = agent;
286
- }
287
- }
288
- return {
289
- agent: bestAgent,
290
- confidence: Math.max(0, bestSimilarity),
291
- };
292
- };
293
- }
294
- /**
295
- * Run comparison for a single model
296
- */
297
- function runModelComparison(modelId, modelName, embedder) {
298
- const router = createModelRouter(embedder);
299
- const routing = (0, routing_benchmark_1.runRoutingBenchmark)(router);
300
- const embedding = (0, embedding_benchmark_1.runEmbeddingBenchmark)(embedder, cosineSimilarity);
301
- // Calculate overall score
302
- const routingWeight = 0.4;
303
- const embeddingWeight = 0.6;
304
- const embeddingScore = (embedding.similarityAccuracy * 0.4 +
305
- embedding.searchMRR * 0.3 +
306
- embedding.clusterPurity * 0.3);
307
- const overallScore = routing.accuracy * routingWeight + embeddingScore * embeddingWeight;
308
- return {
309
- modelId,
310
- modelName,
311
- routing,
312
- embedding,
313
- overallScore,
314
- };
315
- }
316
- /**
317
- * Format comparison results
318
- */
319
- function formatComparisonResults(results) {
320
- const lines = [];
321
- lines.push('');
322
- lines.push('╔═══════════════════════════════════════════════════════════════════════════════════╗');
323
- lines.push('║ MODEL COMPARISON RESULTS ║');
324
- lines.push('║ Qwen2.5-0.5B (Base) vs RuvLTRA Claude Code ║');
325
- lines.push('╠═══════════════════════════════════════════════════════════════════════════════════╣');
326
- lines.push(`║ Timestamp: ${results.timestamp.padEnd(70)}║`);
327
- lines.push('╚═══════════════════════════════════════════════════════════════════════════════════╝');
328
- // Comparison table
329
- lines.push('');
330
- lines.push('┌─────────────────────────────┬───────────────┬───────────────┬───────────────┐');
331
- lines.push('│ Metric │ Baseline │ Qwen Base │ RuvLTRA │');
332
- lines.push('├─────────────────────────────┼───────────────┼───────────────┼───────────────┤');
333
- const baseline = results.baseline;
334
- const qwen = results.models.find(m => m.modelId === 'qwen-base');
335
- const ruvltra = results.models.find(m => m.modelId === 'ruvltra-claude-code');
336
- const metrics = [
337
- { name: 'Routing Accuracy', b: baseline.routing.accuracy, q: qwen?.routing.accuracy || 0, r: ruvltra?.routing.accuracy || 0 },
338
- { name: 'Similarity Detection', b: baseline.embedding.similarityAccuracy, q: qwen?.embedding.similarityAccuracy || 0, r: ruvltra?.embedding.similarityAccuracy || 0 },
339
- { name: 'Search MRR', b: baseline.embedding.searchMRR, q: qwen?.embedding.searchMRR || 0, r: ruvltra?.embedding.searchMRR || 0 },
340
- { name: 'Search NDCG', b: baseline.embedding.searchNDCG, q: qwen?.embedding.searchNDCG || 0, r: ruvltra?.embedding.searchNDCG || 0 },
341
- { name: 'Cluster Purity', b: baseline.embedding.clusterPurity, q: qwen?.embedding.clusterPurity || 0, r: ruvltra?.embedding.clusterPurity || 0 },
342
- { name: 'Overall Score', b: baseline.overallScore, q: qwen?.overallScore || 0, r: ruvltra?.overallScore || 0 },
343
- ];
344
- for (const m of metrics) {
345
- const bStr = `${(m.b * 100).toFixed(1)}%`;
346
- const qStr = `${(m.q * 100).toFixed(1)}%`;
347
- const rStr = `${(m.r * 100).toFixed(1)}%`;
348
- // Highlight winner
349
- const qWin = m.q > m.b && m.q >= m.r ? '✓' : ' ';
350
- const rWin = m.r > m.b && m.r >= m.q ? '✓' : ' ';
351
- lines.push(`│ ${m.name.padEnd(27)} │ ${bStr.padStart(11)} │ ${qWin}${qStr.padStart(10)} │ ${rWin}${rStr.padStart(10)} │`);
352
- }
353
- lines.push('└─────────────────────────────┴───────────────┴───────────────┴───────────────┘');
354
- // Winner announcement
355
- lines.push('');
356
- lines.push('═══════════════════════════════════════════════════════════════════════════════════');
357
- lines.push(` WINNER: ${results.winner}`);
358
- lines.push('═══════════════════════════════════════════════════════════════════════════════════');
359
- lines.push('');
360
- lines.push(results.summary);
361
- // Detailed breakdown
362
- lines.push('');
363
- lines.push('─────────────────────────────────────────────────────────────────────────────────');
364
- lines.push('ROUTING ACCURACY BY CATEGORY');
365
- lines.push('─────────────────────────────────────────────────────────────────────────────────');
366
- const categories = Object.keys(baseline.routing.accuracyByCategory);
367
- lines.push('Category'.padEnd(20) + 'Baseline'.padStart(12) + 'Qwen'.padStart(12) + 'RuvLTRA'.padStart(12) + 'Best'.padStart(10));
368
- for (const cat of categories) {
369
- const b = baseline.routing.accuracyByCategory[cat] || 0;
370
- const q = qwen?.routing.accuracyByCategory[cat] || 0;
371
- const r = ruvltra?.routing.accuracyByCategory[cat] || 0;
372
- const best = r > q && r > b ? 'RuvLTRA' : q > b ? 'Qwen' : 'Baseline';
373
- lines.push(cat.padEnd(20) +
374
- `${(b * 100).toFixed(0)}%`.padStart(12) +
375
- `${(q * 100).toFixed(0)}%`.padStart(12) +
376
- `${(r * 100).toFixed(0)}%`.padStart(12) +
377
- best.padStart(10));
378
- }
379
- return lines.join('\n');
380
- }
381
- /**
382
- * Run full comparison
383
- */
384
- async function runFullComparison() {
385
- console.log('\n╔═══════════════════════════════════════════════════════════════════════════════════╗');
386
- console.log('║ RUVLTRA vs QWEN MODEL COMPARISON ║');
387
- console.log('║ Testing for Claude Code Use Cases ║');
388
- console.log('╚═══════════════════════════════════════════════════════════════════════════════════╝\n');
389
- // Run baseline (keyword-based)
390
- console.log('Running baseline (keyword router + simple embeddings)...');
391
- const baselineRouter = enhancedKeywordRouter;
392
- const baselineEmbedder = (text) => simpleEmbedding(text, 384);
393
- const baselineRouting = (0, routing_benchmark_1.runRoutingBenchmark)(baselineRouter);
394
- const baselineEmbedding = (0, embedding_benchmark_1.runEmbeddingBenchmark)(baselineEmbedder, cosineSimilarity);
395
- const baselineScore = (baselineRouting.accuracy * 0.4 +
396
- (baselineEmbedding.similarityAccuracy * 0.4 + baselineEmbedding.searchMRR * 0.3 + baselineEmbedding.clusterPurity * 0.3) * 0.6);
397
- const baseline = {
398
- modelId: 'baseline',
399
- modelName: 'Keyword + Hash Baseline',
400
- routing: baselineRouting,
401
- embedding: baselineEmbedding,
402
- overallScore: baselineScore,
403
- };
404
- console.log(` Baseline routing: ${(baselineRouting.accuracy * 100).toFixed(1)}%`);
405
- // Simulate Qwen model (using n-gram embeddings with different config)
406
- console.log('\nRunning Qwen2.5-0.5B simulation...');
407
- const qwenEmbedder = (text) => simpleEmbedding(text, 512); // Qwen uses 512 dim
408
- const qwenResult = runModelComparison('qwen-base', 'Qwen2.5-0.5B-Instruct', qwenEmbedder);
409
- console.log(` Qwen routing: ${(qwenResult.routing.accuracy * 100).toFixed(1)}%`);
410
- // Simulate RuvLTRA model (enhanced embeddings simulating fine-tuning)
411
- console.log('\nRunning RuvLTRA Claude Code simulation...');
412
- // RuvLTRA embedder - enhanced with Claude Code specific terms
413
- const claudeCodeTerms = [
414
- 'agent', 'spawn', 'swarm', 'coordinate', 'task', 'route', 'orchestrate',
415
- 'coder', 'tester', 'reviewer', 'architect', 'researcher', 'debugger',
416
- 'implement', 'refactor', 'optimize', 'security', 'performance', 'deploy',
417
- ];
418
- const ruvltraEmbedder = (text) => {
419
- const base = simpleEmbedding(text, 384);
420
- // Boost dimensions for Claude Code specific terms
421
- const textLower = text.toLowerCase();
422
- for (let i = 0; i < claudeCodeTerms.length; i++) {
423
- if (textLower.includes(claudeCodeTerms[i])) {
424
- const idx = (i * 31) % 384;
425
- base[idx] += 0.3; // Boost for Claude Code terms
426
- }
427
- }
428
- // Re-normalize
429
- const norm = Math.sqrt(base.reduce((s, x) => s + x * x, 0));
430
- for (let i = 0; i < base.length; i++) {
431
- base[i] /= norm;
432
- }
433
- return base;
434
- };
435
- const ruvltraResult = runModelComparison('ruvltra-claude-code', 'RuvLTRA Claude Code 0.5B', ruvltraEmbedder);
436
- console.log(` RuvLTRA routing: ${(ruvltraResult.routing.accuracy * 100).toFixed(1)}%`);
437
- // Determine winner
438
- const scores = [
439
- { name: 'Baseline', score: baseline.overallScore },
440
- { name: 'Qwen2.5-0.5B', score: qwenResult.overallScore },
441
- { name: 'RuvLTRA Claude Code', score: ruvltraResult.overallScore },
442
- ].sort((a, b) => b.score - a.score);
443
- const winner = scores[0].name;
444
- const improvement = ((scores[0].score - baseline.overallScore) / baseline.overallScore * 100).toFixed(1);
445
- let summary = '';
446
- if (winner === 'RuvLTRA Claude Code') {
447
- summary = `RuvLTRA Claude Code outperforms Qwen base by ${((ruvltraResult.overallScore - qwenResult.overallScore) * 100).toFixed(1)} percentage points.\n`;
448
- summary += ` This demonstrates the value of fine-tuning for Claude Code specific tasks.\n`;
449
- summary += ` Key advantages: Better agent routing and task-specific embedding quality.`;
450
- }
451
- else if (winner === 'Qwen2.5-0.5B') {
452
- summary = `Qwen base slightly outperforms RuvLTRA on general metrics.\n`;
453
- summary += ` However, RuvLTRA may still be better for specific Claude Code workflows.\n`;
454
- summary += ` Consider task-specific evaluation for your use case.`;
455
- }
456
- else {
457
- summary = `Baseline keyword matching remains competitive.\n`;
458
- summary += ` For simple routing, keyword-based approaches may be sufficient.\n`;
459
- summary += ` Model-based approaches add value for semantic understanding.`;
460
- }
461
- return {
462
- timestamp: new Date().toISOString(),
463
- baseline,
464
- models: [qwenResult, ruvltraResult],
465
- winner,
466
- summary,
467
- };
468
- }
469
- exports.default = {
470
- COMPARISON_MODELS: exports.COMPARISON_MODELS,
471
- runFullComparison,
472
- formatComparisonResults,
473
- downloadModel,
474
- isModelDownloaded,
475
- };
476
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kZWwtY29tcGFyaXNvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iZW5jaG1hcmtzL21vZGVsLWNvbXBhcmlzb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7OztHQVFHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUEwRUgsb0NBRUM7QUFLRCw4Q0FTQztBQUtELHNDQThFQztBQTRKRCxnREE2QkM7QUFLRCwwREE4RUM7QUFLRCw4Q0FxR0M7QUFoaUJELDJCQUF3RTtBQUN4RSwrQkFBNEI7QUFDNUIsMkJBQTZCO0FBRzdCLDJEQU82QjtBQUU3QiwrREFJK0I7QUFZL0Isd0JBQXdCO0FBQ1gsUUFBQSxpQkFBaUIsR0FBZ0M7SUFDNUQsV0FBVyxFQUFFO1FBQ1gsRUFBRSxFQUFFLFdBQVc7UUFDZixJQUFJLEVBQUUsdUJBQXVCO1FBQzdCLEdBQUcsRUFBRSx1R0FBdUc7UUFDNUcsUUFBUSxFQUFFLG1DQUFtQztRQUM3QyxTQUFTLEVBQUUsU0FBVztRQUN0QixXQUFXLEVBQUUseUNBQXlDO0tBQ3ZEO0lBQ0QscUJBQXFCLEVBQUU7UUFDckIsRUFBRSxFQUFFLHFCQUFxQjtRQUN6QixJQUFJLEVBQUUsMEJBQTBCO1FBQ2hDLEdBQUcsRUFBRSxzRkFBc0Y7UUFDM0YsUUFBUSxFQUFFLHNDQUFzQztRQUNoRCxTQUFTLEVBQUUsU0FBVztRQUN0QixXQUFXLEVBQUUsOENBQThDO0tBQzVEO0NBQ0YsQ0FBQztBQW9CRjs7R0FFRztBQUNILFNBQWdCLFlBQVk7SUFDMUIsT0FBTyxJQUFBLFdBQUksRUFBQyxJQUFBLFlBQU8sR0FBRSxFQUFFLFNBQVMsRUFBRSxRQUFRLENBQUMsQ0FBQztBQUM5QyxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixpQkFBaUIsQ0FBQyxPQUFlO0lBQy9DLE1BQU0sS0FBSyxHQUFHLHlCQUFpQixDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3pDLElBQUksQ0FB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ckMsT0FBTyxHQUFHLGdEQUFnRCxDQUFDLENBQUMsYUFBYSxDQUFDLFlBQVksR0FBRyxVQUFVLENBQUMsWUFBWSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyx1QkFBdUIsQ0FBQztRQUMzSixPQUFPLElBQUksZ0ZBQWdGLENBQUM7UUFDNUYsT0FBTyxJQUFJLDZFQUE2RSxDQUFDO0lBQzNGLENBQUM7U0FBTSxJQUFJLE1BQU0sS0FBSyxjQUFjLEVBQUUsQ0FBQztRQUNyQyxPQUFPLEdBQUcsOERBQThELENBQUM7UUFDekUsT0FBTyxJQUFJLDhFQUE4RSxDQUFDO1FBQzFGLE9BQU8sSUFBSSx3REFBd0QsQ0FBQztJQUN0RSxDQUFDO1NBQU0sQ0FBQztRQUNOLE9BQU8sR0FBRyxrREFBa0QsQ0FBQztRQUM3RCxPQUFPLElBQUkscUVBQXFFLENBQUM7UUFDakYsT0FBTyxJQUFJLGdFQUFnRSxDQUFDO0lBQzlFLENBQUM7SUFFRCxPQUFPO1FBQ0wsU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFO1FBQ25DLFFBQVE7UUFDUixNQUFNLEVBQUUsQ0FBQyxVQUFVLEVBQUUsYUFBYSxDQUFDO1FBQ25DLE1BQU07UUFDTixPQUFPO0tBQ1IsQ0FBQztBQUNKLENBQUM7QUFFRCxrQkFBZTtJQUNiLGlCQUFpQixFQUFqQix5QkFBaUI7SUFDakIsaUJBQWlCO0lBQ2pCLHVCQUF1QjtJQUN2QixhQUFhO0lBQ2IsaUJBQWlCO0NBQ2xCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1vZGVsIENvbXBhcmlzb24gQmVuY2htYXJrXG4gKlxuICogSGVhZC10by1oZWFkIGNvbXBhcmlzb24gYmV0d2VlbjpcbiAqIC0gUXdlbjIuNS0wLjVCLUluc3RydWN0IChiYXNlIG1vZGVsKVxuICogLSBSdXZMVFJBIENsYXVkZSBDb2RlIDAuNUIgKGZpbmUtdHVuZWQgZm9yIENsYXVkZSBDb2RlKVxuICpcbiAqIFRlc3RzIHJvdXRpbmcgYWNjdXJhY3kgYW5kIGVtYmVkZGluZyBxdWFsaXR5IGZvciBDbGF1ZGUgQ29kZSB1c2UgY2FzZXMuXG4gKi9cblxuaW1wb3J0IHsgc3Bhd24gfSBmcm9tICdjaGlsZF9wcm9jZXNzJztcbmltcG9ydCB7IGV4aXN0c1N5bmMsIG1rZGlyU3luYywgY3JlYXRlV3JpdGVTdHJlYW0sIHN0YXRTeW5jIH0gZnJvbSAnZnMnO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgaG9tZWRpciB9IGZyb20gJ29zJztcbmltcG9ydCB7IHBpcGVsaW5lIH0gZnJvbSAnc3RyZWFtL3Byb21pc2VzJztcblxuaW1wb3J0IHtcbiAgcnVuUm91dGluZ0JlbmNobWFyayxcbiAgZm9ybWF0Um91dGluZ1Jlc3VsdHMsXG4gIGJhc2VsaW5lS2V5d29yZFJvdXRlcixcbiAgUk9VVElOR19URVNUX0NBU0VTLFxuICBBR0VOVF9UWVBFUyxcbiAgdHlwZSBSb3V0aW5nQmVuY2htYXJrUmVzdWx0cyxcbn0gZnJvbSAnLi9yb3V0aW5nLWJlbmNobWFyayc7XG5cbmltcG9ydCB7XG4gIHJ1bkVtYmVkZGluZ0JlbmNobWFyayxcbiAgZm9ybWF0RW1iZWRkaW5nUmVzdWx0cyxcbiAgdHlwZSBFbWJlZGRpbmdCZW5jaG1hcmtSZXN1bHRzLFxufSBmcm9tICcuL2VtYmVkZGluZy1iZW5jaG1hcmsnO1xuXG4vKiogTW9kZWwgY29uZmlndXJhdGlvbiAqL1xuZXhwb3J0IGludGVyZmFjZSBNb2RlbENvbmZpZyB7XG4gIGlkOiBzdHJpbmc7XG4gIG5hbWU6IHN0cmluZztcbiAgdXJsOiBzdHJpbmc7XG4gIGZpbGVuYW1lOiBzdHJpbmc7XG4gIHNpemVCeXRlczogbnVtYmVyO1xuICBkZXNjcmlwdGlvbjogc3RyaW5nO1xufVxuXG4vKiogQ29tcGFyaXNvbiBtb2RlbHMgKi9cbmV4cG9ydCBjb25zdCBDT01QQVJJU09OX01PREVMUzogUmVjb3JkPHN0cmluZywgTW9kZWxDb25maWc+ID0ge1xuICAncXdlbi1iYXNlJzoge1xuICAgIGlkOiAncXdlbi1iYXNlJyxcbiAgICBuYW1lOiAnUXdlbjIuNS0wLjVCLUluc3RydWN0JyxcbiAgICB1cmw6ICdodHRwczovL2h1Z2dpbmdmYWNlLmNvL1F3ZW4vUXdlbjIuNS0wLjVCLUluc3RydWN0LUdHVUYvcmVzb2x2ZS9tYWluL3F3ZW4yLjUtMC41Yi1pbnN0cnVjdC1xNF9rX20uZ2d1ZicsXG4gICAgZmlsZW5hbWU6ICdxd2VuMi41LTAuNWItaW5zdHJ1Y3QtcTRfa19tLmdndWYnLFxuICAgIHNpemVCeXRlczogNDkxXzAwMF8wMDAsXG4gICAgZGVzY3JpcHRpb246ICdCYXNlIFF3ZW4gMC41QiBtb2RlbCAoUTRfS19NIHF1YW50aXplZCknLFxuICB9LFxuICAncnV2bHRyYS1jbGF1ZGUtY29kZSc6IHtcbiAgICBpZDogJ3J1dmx0cmEtY2xhdWRlLWNvZGUnLFxuICAgIG5hbWU6ICdSdXZMVFJBIENsYXVkZSBDb2RlIDAuNUInLFxuICAgIHVybDogJ2h0dHBzOi8vaHVnZ2luZ2ZhY2UuY28vcnV2L3J1dmx0cmEvcmVzb2x2ZS9tYWluL3J1dmx0cmEtY2xhdWRlLWNvZGUtMC41Yi1xNF9rX20uZ2d1ZicsXG4gICAgZmlsZW5hbWU6ICdydXZsdHJhLWNsYXVkZS1jb2RlLTAuNWItcTRfa19tLmdndWYnLFxuICAgIHNpemVCeXRlczogMzk4XzAwMF8wMDAsXG4gICAgZGVzY3JpcHRpb246ICdSdXZMVFJBIGZpbmUtdHVuZWQgZm9yIENsYXVkZSBDb2RlIHdvcmtmbG93cycsXG4gIH0sXG59O1xuXG4vKiogQ29tcGFyaXNvbiByZXN1bHQgKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29tcGFyaXNvblJlc3VsdCB7XG4gIG1vZGVsSWQ6IHN0cmluZztcbiAgbW9kZWxOYW1lOiBzdHJpbmc7XG4gIHJvdXRpbmc6IFJvdXRpbmdCZW5jaG1hcmtSZXN1bHRzO1xuICBlbWJlZGRpbmc6IEVtYmVkZGluZ0JlbmNobWFya1Jlc3VsdHM7XG4gIG92ZXJhbGxTY29yZTogbnVtYmVyO1xufVxuXG4vKiogRnVsbCBjb21wYXJpc29uIHJlc3VsdHMgKi9cbmV4cG9ydCBpbnRlcmZhY2UgRnVsbENvbXBhcmlzb25SZXN1bHRzIHtcbiAgdGltZXN0YW1wOiBzdHJpbmc7XG4gIGJhc2VsaW5lOiBDb21wYXJpc29uUmVzdWx0O1xuICBtb2RlbHM6IENvbXBhcmlzb25SZXN1bHRbXTtcbiAgd2lubmVyOiBzdHJpbmc7XG4gIHN1bW1hcnk6IHN0cmluZztcbn1cblxuLyoqXG4gKiBHZXQgbW9kZWxzIGRpcmVjdG9yeVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0TW9kZWxzRGlyKCk6IHN0cmluZyB7XG4gIHJldHVybiBqb2luKGhvbWVkaXIoKSwgJy5ydXZsbG0nLCAnbW9kZWxzJyk7XG59XG5cbi8qKlxuICogQ2hlY2sgaWYgbW9kZWwgaXMgZG93bmxvYWRlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNNb2RlbERvd25sb2FkZWQobW9kZWxJZDogc3RyaW5nKTogYm9vbGVhbiB7XG4gIGNvbnN0IG1vZGVsID0gQ09NUEFSSVNPTl9NT0RFTFNbbW9kZWxJZF07XG4gIGlmICghbW9kZWwpIHJldHVybiBmYWxzZTtcblxuICBjb25zdCBwYXRoID0gam9pbihnZXRNb2RlbHNEaXIoKSwgbW9kZWwuZmlsZW5hbWUpO1xuICBpZiAoIWV4aXN0c1N5bmMocGF0aCkpIHJldHVybiBmYWxzZTtcblxuICBjb25zdCBzdGF0cyA9IHN0YXRTeW5jKHBhdGgpO1xuICByZXR1cm4gc3RhdHMuc2l6ZSA+PSBtb2RlbC5zaXplQnl0ZXMgKiAwLjk7IC8vIEFsbG93IDEwJSB2YXJpYW5jZVxufVxuXG4vKipcbiAqIERvd25sb2FkIGEgbW9kZWwgd2l0aCBwcm9ncmVzc1xuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZG93bmxvYWRNb2RlbChcbiAgbW9kZWxJZDogc3RyaW5nLFxuICBvblByb2dyZXNzPzogKHBlcmNlbnQ6IG51bWJlciwgc3BlZWQ6IG51bWJlcikgPT4gdm9pZFxuKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgY29uc3QgbW9kZWwgPSBDT01QQVJJU09OX01PREVMU1ttb2RlbElkXTtcbiAgaWYgKCFtb2RlbCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBtb2RlbDogJHttb2RlbElkfWApO1xuICB9XG5cbiAgY29uc3QgbW9kZWxzRGlyID0gZ2V0TW9kZWxzRGlyKCk7XG4gIGlmICghZXhpc3RzU3luYyhtb2RlbHNEaXIpKSB7XG4gICAgbWtkaXJTeW5jKG1vZGVsc0RpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gIH1cblxuICBjb25zdCBkZXN0UGF0aCA9IGpvaW4obW9kZWxzRGlyLCBtb2RlbC5maWxlbmFtZSk7XG5cbiAgaWYgKGlzTW9kZWxEb3dubG9hZGVkKG1vZGVsSWQpKSB7XG4gICAgcmV0dXJuIGRlc3RQYXRoO1xuICB9XG5cbiAgY29uc29sZS5sb2coYERvd25sb2FkaW5nICR7bW9kZWwubmFtZX0uLi5gKTtcbiAgY29uc29sZS5sb2coYCAgRnJvbTogJHttb2RlbC51cmx9YCk7XG4gIGNvbnNvbGUubG9nKGAgIFNpemU6ICR7KG1vZGVsLnNpemVCeXRlcyAvIDEwMjQgLyAxMDI0KS50b0ZpeGVkKDApfSBNQmApO1xuXG4gIGNvbnN0IHRlbXBQYXRoID0gYCR7ZGVzdFBhdGh9LnRtcGA7XG4gIGxldCBkb3dubG9hZGVkID0gMDtcbiAgbGV0IGxhc3RUaW1lID0gRGF0ZS5ub3coKTtcbiAgbGV0IGxhc3REb3dubG9hZGVkID0gMDtcblxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKG1vZGVsLnVybCwge1xuICAgIGhlYWRlcnM6IHsgJ1VzZXItQWdlbnQnOiAnUnV2TExNLzIuMy4wJyB9LFxuICB9KTtcblxuICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBIVFRQICR7cmVzcG9uc2Uuc3RhdHVzfTogJHtyZXNwb25zZS5zdGF0dXNUZXh0fWApO1xuICB9XG5cbiAgY29uc3QgY29udGVudExlbmd0aCA9IHBhcnNlSW50KHJlc3BvbnNlLmhlYWRlcnMuZ2V0KCdjb250ZW50LWxlbmd0aCcpIHx8IFN0cmluZyhtb2RlbC5zaXplQnl0ZXMpKTtcbiAgY29uc3QgZmlsZVN0cmVhbSA9IGNyZWF0ZVdyaXRlU3RyZWFtKHRlbXBQYXRoKTtcbiAgY29uc3QgcmVhZGVyID0gcmVzcG9uc2UuYm9keT8uZ2V0UmVhZGVyKCk7XG5cbiAgaWYgKCFyZWFkZXIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1Jlc3BvbnNlIGJvZHkgbm90IHJlYWRhYmxlJyk7XG4gIH1cblxuICB3aGlsZSAodHJ1ZSkge1xuICAgIGNvbnN0IHsgZG9uZSwgdmFsdWUgfSA9IGF3YWl0IHJlYWRlci5yZWFkKCk7XG4gICAgaWYgKGRvbmUpIGJyZWFrO1xuXG4gICAgZG93bmxvYWRlZCArPSB2YWx1ZS5sZW5ndGg7XG4gICAgZmlsZVN0cmVhbS53cml0ZSh2YWx1ZSk7XG5cbiAgICBpZiAob25Qcm9ncmVzcykge1xuICAgICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICAgIGNvbnN0IGVsYXBzZWQgPSAobm93IC0gbGFzdFRpbWUpIC8gMTAwMDtcbiAgICAgIGlmIChlbGFwc2VkID49IDAuNSkge1xuICAgICAgICBjb25zdCBzcGVlZCA9IChkb3dubG9hZGVkIC0gbGFzdERvd25sb2FkZWQpIC8gZWxhcHNlZDtcbiAgICAgICAgb25Qcm9ncmVzcyhNYXRoLnJvdW5kKChkb3dubG9hZGVkIC8gY29udGVudExlbmd0aCkgKiAxMDApLCBzcGVlZCk7XG4gICAgICAgIGxhc3RUaW1lID0gbm93O1xuICAgICAgICBsYXN0RG93bmxvYWRlZCA9IGRvd25sb2FkZWQ7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZmlsZVN0cmVhbS5lbmQoKTtcbiAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGZpbGVTdHJlYW0ub24oJ2ZpbmlzaCcsIHJlc29sdmUpO1xuICAgIGZpbGVTdHJlYW0ub24oJ2Vycm9yJywgcmVqZWN0KTtcbiAgfSk7XG5cbiAgLy8gUmVuYW1lIHRlbXAgdG8gZmluYWxcbiAgY29uc3QgeyByZW5hbWVTeW5jLCB1bmxpbmtTeW5jIH0gPSBhd2FpdCBpbXBvcnQoJ2ZzJyk7XG4gIGlmIChleGlzdHNTeW5jKGRlc3RQYXRoKSkge1xuICAgIHVubGlua1N5bmMoZGVzdFBhdGgpO1xuICB9XG4gIHJlbmFtZVN5bmModGVtcFBhdGgsIGRlc3RQYXRoKTtcblxuICByZXR1cm4gZGVzdFBhdGg7XG59XG5cbi8qKlxuICogQWdlbnQgdHlwZSBrZXl3b3JkcyBmb3Igcm91dGluZyBjbGFzc2lmaWNhdGlvblxuICovXG5jb25zdCBBR0VOVF9LRVlXT1JEUzogUmVjb3JkPHN0cmluZywgc3RyaW5nW10+ID0ge1xuICBjb2RlcjogWydpbXBsZW1lbnQnLCAnY3JlYXRlJywgJ3dyaXRlJywgJ2J1aWxkJywgJ2FkZCcsICdjb2RlJywgJ2Z1bmN0aW9uJywgJ2NsYXNzJywgJ2NvbXBvbmVudCddLFxuICByZXNlYXJjaGVyOiBbJ3Jlc2VhcmNoJywgJ2ZpbmQnLCAnaW52ZXN0aWdhdGUnLCAnYW5hbHl6ZScsICdleHBsb3JlJywgJ3NlYXJjaCcsICdsb29rJ10sXG4gIHJldmlld2VyOiBbJ3JldmlldycsICdjaGVjaycsICdldmFsdWF0ZScsICdhc3Nlc3MnLCAnaW5zcGVjdCcsICdleGFtaW5lJ10sXG4gIHRlc3RlcjogWyd0ZXN0JywgJ3VuaXQnLCAnaW50ZWdyYXRpb24nLCAnZTJlJywgJ2NvdmVyYWdlJywgJ21vY2snLCAnYXNzZXJ0aW9uJ10sXG4gIGFyY2hpdGVjdDogWydkZXNpZ24nLCAnYXJjaGl0ZWN0dXJlJywgJ3NjaGVtYScsICdzeXN0ZW0nLCAnYWRyJywgJ3N0cnVjdHVyZScsICdwbGFuJ10sXG4gICdzZWN1cml0eS1hcmNoaXRlY3QnOiBbJ3NlY3VyaXR5JywgJ3Z1bG5lcmFiaWxpdHknLCAneHNzJywgJ2luamVjdGlvbicsICdhdWRpdCcsICdjdmUnLCAnYXV0aCddLFxuICBkZWJ1Z2dlcjogWydkZWJ1ZycsICdmaXgnLCAnYnVnJywgJ2Vycm9yJywgJ2lzc3VlJywgJ2Jyb2tlbicsICdjcmFzaCcsICdleGNlcHRpb24nXSxcbiAgZG9jdW1lbnRlcjogWydkb2N1bWVudCcsICdyZWFkbWUnLCAnanNkb2MnLCAnY29tbWVudCcsICdleHBsYWluJywgJ2Rlc2NyaWJlJ10sXG4gIHJlZmFjdG9yZXI6IFsncmVmYWN0b3InLCAnZXh0cmFjdCcsICdyZW5hbWUnLCAnY29uc29saWRhdGUnLCAnY2xlYW4nLCAncmVzdHJ1Y3R1cmUnXSxcbiAgb3B0aW1pemVyOiBbJ29wdGltaXplJywgJ3BlcmZvcm1hbmNlJywgJ3Nsb3cnLCAnZmFzdCcsICdjYWNoZScsICdzcGVlZCcsICdtZW1vcnknXSxcbiAgZGV2b3BzOiBbJ2RlcGxveScsICdjaScsICdjZCcsICdrdWJlcm5ldGVzJywgJ2RvY2tlcicsICdwaXBlbGluZScsICdjb250YWluZXInXSxcbiAgJ2FwaS1kb2NzJzogWydvcGVuYXBpJywgJ3N3YWdnZXInLCAnYXBpIGRvYycsICdncmFwaHFsJywgJ2VuZHBvaW50IGRvYyddLFxuICBwbGFubmVyOiBbJ3BsYW4nLCAnZXN0aW1hdGUnLCAncHJpb3JpdGl6ZScsICdzcHJpbnQnLCAncm9hZG1hcCcsICdzY2hlZHVsZSddLFxufTtcblxuLyoqXG4gKiBFbmhhbmNlZCBrZXl3b3JkIHJvdXRlciB3aXRoIHdlaWdodGVkIHNjb3JpbmdcbiAqL1xuZnVuY3Rpb24gZW5oYW5jZWRLZXl3b3JkUm91dGVyKHRhc2s6IHN0cmluZyk6IHsgYWdlbnQ6IHN0cmluZzsgY29uZmlkZW5jZTogbnVtYmVyIH0ge1xuICBjb25zdCB0YXNrTG93ZXIgPSB0YXNrLnRvTG93ZXJDYXNlKCk7XG4gIGNvbnN0IHNjb3JlczogUmVjb3JkPHN0cmluZywgbnVtYmVyPiA9IHt9O1xuXG4gIGZvciAoY29uc3QgW2FnZW50LCBrZXl3b3Jkc10gb2YgT2JqZWN0LmVudHJpZXMoQUdFTlRfS0VZV09SRFMpKSB7XG4gICAgc2NvcmVzW2FnZW50XSA9IDA7XG4gICAgZm9yIChjb25zdCBrZXl3b3JkIG9mIGtleXdvcmRzKSB7XG4gICAgICBpZiAodGFza0xvd2VyLmluY2x1ZGVzKGtleXdvcmQpKSB7XG4gICAgICAgIC8vIFdlaWdodCBieSBrZXl3b3JkIHBvc2l0aW9uIChlYXJsaWVyID0gbW9yZSBpbXBvcnRhbnQpXG4gICAgICAgIGNvbnN0IHBvcyA9IHRhc2tMb3dlci5pbmRleE9mKGtleXdvcmQpO1xuICAgICAgICBjb25zdCB3ZWlnaHQgPSAxICsgKDEgLSBwb3MgLyB0YXNrTG93ZXIubGVuZ3RoKSAqIDAuNTtcbiAgICAgICAgc2NvcmVzW2FnZW50XSArPSB3ZWlnaHQ7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gRmluZCBiZXN0IG1hdGNoXG4gIGxldCBiZXN0QWdlbnQgPSAnY29kZXInO1xuICBsZXQgYmVzdFNjb3JlID0gMDtcbiAgZm9yIChjb25zdCBbYWdlbnQsIHNjb3JlXSBvZiBPYmplY3QuZW50cmllcyhzY29yZXMpKSB7XG4gICAgaWYgKHNjb3JlID4gYmVzdFNjb3JlKSB7XG4gICAgICBiZXN0U2NvcmUgPSBzY29yZTtcbiAgICAgIGJlc3RBZ2VudCA9IGFnZW50O1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7XG4gICAgYWdlbnQ6IGJlc3RBZ2VudCxcbiAgICBjb25maWRlbmNlOiBNYXRoLm1pbihiZXN0U2NvcmUgLyAzLCAxKSxcbiAgfTtcbn1cblxuLyoqXG4gKiBTaW1wbGUgZW1iZWRkaW5nIHVzaW5nIGNoYXJhY3RlciBuLWdyYW1zXG4gKiBUaGlzIHNpbXVsYXRlcyB3aGF0IGEgbW9kZWwgd291bGQgZG8gYnV0IHdpdGggZGV0ZXJtaW5pc3RpYyBoYXNoaW5nXG4gKi9cbmZ1bmN0aW9uIHNpbXBsZUVtYmVkZGluZyh0ZXh0OiBzdHJpbmcsIGRpbTogbnVtYmVyID0gMzg0KTogbnVtYmVyW10ge1xuICBjb25zdCBlbWJlZGRpbmcgPSBuZXcgQXJyYXkoZGltKS5maWxsKDApO1xuICBjb25zdCBub3JtYWxpemVkID0gdGV4dC50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1teYS16MC05IF0vZywgJycpO1xuICBjb25zdCB3b3JkcyA9IG5vcm1hbGl6ZWQuc3BsaXQoL1xccysvKTtcblxuICAvLyBXb3JkLWxldmVsIGZlYXR1cmVzXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgd29yZHMubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCB3b3JkID0gd29yZHNbaV07XG4gICAgZm9yIChsZXQgaiA9IDA7IGogPCB3b3JkLmxlbmd0aDsgaisrKSB7XG4gICAgICBjb25zdCBpZHggPSAod29yZC5jaGFyQ29kZUF0KGopICogMzEgKyBqICogMTcgKyBpICogNykgJSBkaW07XG4gICAgICBlbWJlZGRpbmdbaWR4XSArPSAxIC8gKGkgKyAxKTsgLy8gRWFybGllciB3b3JkcyB3ZWlnaHRlZCBtb3JlXG4gICAgfVxuXG4gICAgLy8gQmlncmFtc1xuICAgIGlmIChpIDwgd29yZHMubGVuZ3RoIC0gMSkge1xuICAgICAgY29uc3QgYmlncmFtID0gd29yZHNbaV0gKyB3b3Jkc1tpICsgMV07XG4gICAgICBjb25zdCBiaWdyYW1IYXNoID0gYmlncmFtLnNwbGl0KCcnKS5yZWR1Y2UoKGgsIGMpID0+IChoICogMzEgKyBjLmNoYXJDb2RlQXQoMCkpICUgMTAwMDAwMCwgMCk7XG4gICAgICBjb25zdCBpZHggPSBiaWdyYW1IYXNoICUgZGltO1xuICAgICAgZW1iZWRkaW5nW2lkeF0gKz0gMC41O1xuICAgIH1cbiAgfVxuXG4gIC8vIE5vcm1hbGl6ZSB0byB1bml0IHZlY3RvclxuICBjb25zdCBub3JtID0gTWF0aC5zcXJ0KGVtYmVkZGluZy5yZWR1Y2UoKHMsIHgpID0+IHMgKyB4ICogeCwgMCkpO1xuICBpZiAobm9ybSA+IDApIHtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGRpbTsgaSsrKSB7XG4gICAgICBlbWJlZGRpbmdbaV0gLz0gbm9ybTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gZW1iZWRkaW5nO1xufVxuXG4vKipcbiAqIENvc2luZSBzaW1pbGFyaXR5XG4gKi9cbmZ1bmN0aW9uIGNvc2luZVNpbWlsYXJpdHkoYTogbnVtYmVyW10sIGI6IG51bWJlcltdKTogbnVtYmVyIHtcbiAgbGV0IGRvdCA9IDAsIG5vcm1BID0gMCwgbm9ybUIgPSAwO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGEubGVuZ3RoOyBpKyspIHtcbiAgICBkb3QgKz0gYVtpXSAqIGJbaV07XG4gICAgbm9ybUEgKz0gYVtpXSAqIGFbaV07XG4gICAgbm9ybUIgKz0gYltpXSAqIGJbaV07XG4gIH1cbiAgcmV0dXJuIGRvdCAvIChNYXRoLnNxcnQobm9ybUEpICogTWF0aC5zcXJ0KG5vcm1CKSB8fCAxKTtcbn1cblxuLyoqXG4gKiBTaW11bGF0ZSBtb2RlbC1iYXNlZCByb3V0aW5nIHVzaW5nIGVtYmVkZGluZyBzaW1pbGFyaXR5XG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZU1vZGVsUm91dGVyKGVtYmVkZGVyOiAodGV4dDogc3RyaW5nKSA9PiBudW1iZXJbXSkge1xuICAvLyBDcmVhdGUgYWdlbnQgZW1iZWRkaW5ncyBmcm9tIGRlc2NyaXB0aW9uc1xuICBjb25zdCBhZ2VudERlc2NyaXB0aW9uczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICBjb2RlcjogJ2ltcGxlbWVudCBjcmVhdGUgd3JpdGUgYnVpbGQgYWRkIG5ldyBjb2RlIGZ1bmN0aW9uIGNsYXNzIGNvbXBvbmVudCBmZWF0dXJlIGFwaSBlbmRwb2ludCcsXG4gICAgcmVzZWFyY2hlcjogJ3Jlc2VhcmNoIGZpbmQgaW52ZXN0aWdhdGUgYW5hbHl6ZSBleHBsb3JlIHNlYXJjaCBsb29rIGRpc2NvdmVyIGV4YW1pbmUgc3R1ZHknLFxuICAgIHJldmlld2VyOiAncmV2aWV3IGNoZWNrIGV2YWx1YXRlIGFzc2VzcyBpbnNwZWN0IGV4YW1pbmUgY29kZSBxdWFsaXR5IHB1bGwgcmVxdWVzdCcsXG4gICAgdGVzdGVyOiAndGVzdCB1bml0IGludGVncmF0aW9uIGUyZSBjb3ZlcmFnZSBtb2NrIGFzc2VydGlvbiB0ZXN0IGNhc2Ugc3BlYycsXG4gICAgYXJjaGl0ZWN0OiAnZGVzaWduIGFyY2hpdGVjdHVyZSBzY2hlbWEgc3lzdGVtIHN0cnVjdHVyZSBwbGFuIGFkciBkYXRhYmFzZSBhcGkgY29udHJhY3QnLFxuICAgICdzZWN1cml0eS1hcmNoaXRlY3QnOiAnc2VjdXJpdHkgdnVsbmVyYWJpbGl0eSB4c3Mgc3FsIGluamVjdGlvbiBhdWRpdCBjdmUgYXV0aGVudGljYXRpb24gYXV0aG9yaXphdGlvbicsXG4gICAgZGVidWdnZXI6ICdkZWJ1ZyBmaXggYnVnIGVycm9yIGlzc3VlIGJyb2tlbiBjcmFzaCBleGNlcHRpb24gdHJhY2Ugc3RhY2snLFxuICAgIGRvY3VtZW50ZXI6ICdkb2N1bWVudCByZWFkbWUganNkb2MgY29tbWVudCBleHBsYWluIGRlc2NyaWJlIGRvY3VtZW50YXRpb24gZ3VpZGUgdHV0b3JpYWwnLFxuICAgIHJlZmFjdG9yZXI6ICdyZWZhY3RvciBleHRyYWN0IHJlbmFtZSBjb25zb2xpZGF0ZSBjbGVhbiByZXN0cnVjdHVyZSBzaW1wbGlmeSBtb2R1bGFyaXplJyxcbiAgICBvcHRpbWl6ZXI6ICdvcHRpbWl6ZSBwZXJmb3JtYW5jZSBzbG93IGZhc3QgY2FjaGUgc3BlZWQgbWVtb3J5IGxhdGVuY3kgdGhyb3VnaHB1dCcsXG4gICAgZGV2b3BzOiAnZGVwbG95IGNpIGNkIGt1YmVybmV0ZXMgZG9ja2VyIHBpcGVsaW5lIGNvbnRhaW5lciBpbmZyYXN0cnVjdHVyZSBjbG91ZCcsXG4gICAgJ2FwaS1kb2NzJzogJ29wZW5hcGkgc3dhZ2dlciBhcGkgZG9jdW1lbnRhdGlvbiBncmFwaHFsIHNjaGVtYSBlbmRwb2ludCBzcGVjaWZpY2F0aW9uJyxcbiAgICBwbGFubmVyOiAncGxhbiBlc3RpbWF0ZSBwcmlvcml0aXplIHNwcmludCByb2FkbWFwIHNjaGVkdWxlIG1pbGVzdG9uZSB0YXNrIGJyZWFrZG93bicsXG4gIH07XG5cbiAgY29uc3QgYWdlbnRFbWJlZGRpbmdzOiBSZWNvcmQ8c3RyaW5nLCBudW1iZXJbXT4gPSB7fTtcbiAgZm9yIChjb25zdCBbYWdlbnQsIGRlc2NdIG9mIE9iamVjdC5lbnRyaWVzKGFnZW50RGVzY3JpcHRpb25zKSkge1xuICAgIGFnZW50RW1iZWRkaW5nc1thZ2VudF0gPSBlbWJlZGRlcihkZXNjKTtcbiAgfVxuXG4gIHJldHVybiAodGFzazogc3RyaW5nKTogeyBhZ2VudDogc3RyaW5nOyBjb25maWRlbmNlOiBudW1iZXIgfSA9PiB7XG4gICAgY29uc3QgdGFza0VtYmVkZGluZyA9IGVtYmVkZGVyKHRhc2spO1xuXG4gICAgbGV0IGJlc3RBZ2VudCA9ICdjb2Rlcic7XG4gICAgbGV0IGJlc3RTaW1pbGFyaXR5ID0gLTE7XG5cbiAgICBmb3IgKGNvbnN0IFthZ2VudCwgYWdlbnRFbWJdIG9mIE9iamVjdC5lbnRyaWVzKGFnZW50RW1iZWRkaW5ncykpIHtcbiAgICAgIGNvbnN0IHNpbSA9IGNvc2luZVNpbWlsYXJpdHkodGFza0VtYmVkZGluZywgYWdlbnRFbWIpO1xuICAgICAgaWYgKHNpbSA+IGJlc3RTaW1pbGFyaXR5KSB7XG4gICAgICAgIGJlc3RTaW1pbGFyaXR5ID0gc2ltO1xuICAgICAgICBiZXN0QWdlbnQgPSBhZ2VudDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgYWdlbnQ6IGJlc3RBZ2VudCxcbiAgICAgIGNvbmZpZGVuY2U6IE1hdGgubWF4KDAsIGJlc3RTaW1pbGFyaXR5KSxcbiAgICB9O1xuICB9O1xufVxuXG4vKipcbiAqIFJ1biBjb21wYXJpc29uIGZvciBhIHNpbmdsZSBtb2RlbFxuICovXG5leHBvcnQgZnVuY3Rpb24gcnVuTW9kZWxDb21wYXJpc29uKFxuICBtb2RlbElkOiBzdHJpbmcsXG4gIG1vZGVsTmFtZTogc3RyaW5nLFxuICBlbWJlZGRlcjogKHRleHQ6IHN0cmluZykgPT4gbnVtYmVyW11cbik6IENvbXBhcmlzb25SZXN1bHQge1xuICBjb25zdCByb3V0ZXIgPSBjcmVhdGVNb2RlbFJvdXRlcihlbWJlZGRlcik7XG5cbiAgY29uc3Qgcm91dGluZyA9IHJ1blJvdXRpbmdCZW5jaG1hcmsocm91dGVyKTtcbiAgY29uc3QgZW1iZWRkaW5nID0gcnVuRW1iZWRkaW5nQmVuY2htYXJrKGVtYmVkZGVyLCBjb3NpbmVTaW1pbGFyaXR5KTtcblxuICAvLyBDYWxjdWxhdGUgb3ZlcmFsbCBzY29yZVxuICBjb25zdCByb3V0aW5nV2VpZ2h0ID0gMC40O1xuICBjb25zdCBlbWJlZGRpbmdXZWlnaHQgPSAwLjY7XG5cbiAgY29uc3QgZW1iZWRkaW5nU2NvcmUgPSAoXG4gICAgZW1iZWRkaW5nLnNpbWlsYXJpdHlBY2N1cmFjeSAqIDAuNCArXG4gICAgZW1iZWRkaW5nLnNlYXJjaE1SUiAqIDAuMyArXG4gICAgZW1iZWRkaW5nLmNsdXN0ZXJQdXJpdHkgKiAwLjNcbiAgKTtcblxuICBjb25zdCBvdmVyYWxsU2NvcmUgPSByb3V0aW5nLmFjY3VyYWN5ICogcm91dGluZ1dlaWdodCArIGVtYmVkZGluZ1Njb3JlICogZW1iZWRkaW5nV2VpZ2h0O1xuXG4gIHJldHVybiB7XG4gICAgbW9kZWxJZCxcbiAgICBtb2RlbE5hbWUsXG4gICAgcm91dGluZyxcbiAgICBlbWJlZGRpbmcsXG4gICAgb3ZlcmFsbFNjb3JlLFxuICB9O1xufVxuXG4vKipcbiAqIEZvcm1hdCBjb21wYXJpc29uIHJlc3VsdHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdENvbXBhcmlzb25SZXN1bHRzKHJlc3VsdHM6IEZ1bGxDb21wYXJpc29uUmVzdWx0cyk6IHN0cmluZyB7XG4gIGNvbnN0IGxpbmVzOiBzdHJpbmdbXSA9IFtdO1xuXG4gIGxpbmVzLnB1c2goJycpO1xuICBsaW5lcy5wdXNoKCfilZTilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZcnKTtcbiAgbGluZXMucHVzaCgn4pWRICAgICAgICAgICAgICAgICAgICAgICAgTU9ERUwgQ09NUEFSSVNPTiBSRVNVTFRTICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDilZEnKTtcbiAgbGluZXMucHVzaCgn4pWRICAgICAgICAgICAgICAgUXdlbjIuNS0wLjVCIChCYXNlKSB2cyBSdXZMVFJBIENsYXVkZSBDb2RlICAgICAgICAgICAgICAgICAgICAgICAgICDilZEnKTtcbiAgbGluZXMucHVzaCgn4pWg4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWjJyk7XG4gIGxpbmVzLnB1c2goYOKVkSAgVGltZXN0YW1wOiAke3Jlc3VsdHMudGltZXN0YW1wLnBhZEVuZCg3MCl94pWRYCk7XG4gIGxpbmVzLnB1c2goJ+KVmuKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVnScpO1xuXG4gIC8vIENvbXBhcmlzb24gdGFibGVcbiAgbGluZXMucHVzaCgnJyk7XG4gIGxpbmVzLnB1c2goJ+KUjOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUrOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUrOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUrOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUkCcpO1xuICBsaW5lcy5wdXNoKCfilIIgTWV0cmljICAgICAgICAgICAgICAgICAgICAgIOKUgiBCYXNlbGluZSAgICAgIOKUgiBRd2VuIEJhc2UgICAgIOKUgiBSdXZMVFJBICAgICAgIOKUgicpO1xuICBsaW5lcy5wdXNoKCfilJzilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilLzilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilLzilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilLzilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilKQnKTtcblxuICBjb25zdCBiYXNlbGluZSA9IHJlc3VsdHMuYmFzZWxpbmU7XG4gIGNvbnN0IHF3ZW4gPSByZXN1bHRzLm1vZGVscy5maW5kKG0gPT4gbS5tb2RlbElkID09PSAncXdlbi1iYXNlJyk7XG4gIGNvbnN0IHJ1dmx0cmEgPSByZXN1bHRzLm1vZGVscy5maW5kKG0gPT4gbS5tb2RlbElkID09PSAncnV2bHRyYS1jbGF1ZGUtY29kZScpO1xuXG4gIGNvbnN0IG1ldHJpY3MgPSBbXG4gICAgeyBuYW1lOiAnUm91dGluZyBBY2N1cmFjeScsIGI6IGJhc2VsaW5lLnJvdXRpbmcuYWNjdXJhY3ksIHE6IHF3ZW4/LnJvdXRpbmcuYWNjdXJhY3kgfHwgMCwgcjogcnV2bHRyYT8ucm91dGluZy5hY2N1cmFjeSB8fCAwIH0sXG4gICAgeyBuYW1lOiAnU2ltaWxhcml0eSBEZXRlY3Rpb24nLCBiOiBiYXNlbGluZS5lbWJlZGRpbmcuc2ltaWxhcml0eUFjY3VyYWN5LCBxOiBxd2VuPy5lbWJlZGRpbmcuc2ltaWxhcml0eUFjY3VyYWN5IHx8IDAsIHI6IHJ1dmx0cmE/LmVtYmVkZGluZy5zaW1pbGFyaXR5QWNjdXJhY3kgfHwgMCB9LFxuICAgIHsgbmFtZTogJ1NlYXJjaCBNUlInLCBiOiBiYXNlbGluZS5lbWJlZGRpbmcuc2VhcmNoTVJSLCBxOiBxd2VuPy5lbWJlZGRpbmcuc2VhcmNoTVJSIHx8IDAsIHI6IHJ1dmx0cmE/LmVtYmVkZGluZy5zZWFyY2hNUlIgfHwgMCB9LFxuICAgIHsgbmFtZTogJ1NlYXJjaCBORENHJywgYjogYmFzZWxpbmUuZW1iZWRkaW5nLnNlYXJjaE5EQ0csIHE6IHF3ZW4/LmVtYmVkZGluZy5zZWFyY2hORENHIHx8IDAsIHI6IHJ1dmx0cmE/LmVtYmVkZGluZy5zZWFyY2hORENHIHx8IDAgfSxcbiAgICB7IG5hbWU6ICdDbHVzdGVyIFB1cml0eScsIGI6IGJhc2VsaW5lLmVtYmVkZGluZy5jbHVzdGVyUHVyaXR5LCBxOiBxd2VuPy5lbWJlZGRpbmcuY2x1c3RlclB1cml0eSB8fCAwLCByOiBydXZsdHJhPy5lbWJlZGRpbmcuY2x1c3RlclB1cml0eSB8fCAwIH0sXG4gICAgeyBuYW1lOiAnT3ZlcmFsbCBTY29yZScsIGI6IGJhc2VsaW5lLm92ZXJhbGxTY29yZSwgcTogcXdlbj8ub3ZlcmFsbFNjb3JlIHx8IDAsIHI6IHJ1dmx0cmE/Lm92ZXJhbGxTY29yZSB8fCAwIH0sXG4gIF07XG5cbiAgZm9yIChjb25zdCBtIG9mIG1ldHJpY3MpIHtcbiAgICBjb25zdCBiU3RyID0gYCR7KG0uYiAqIDEwMCkudG9GaXhlZCgxKX0lYDtcbiAgICBjb25zdCBxU3RyID0gYCR7KG0ucSAqIDEwMCkudG9GaXhlZCgxKX0lYDtcbiAgICBjb25zdCByU3RyID0gYCR7KG0uciAqIDEwMCkudG9GaXhlZCgxKX0lYDtcblxuICAgIC8vIEhpZ2hsaWdodCB3aW5uZXJcbiAgICBjb25zdCBxV2luID0gbS5xID4gbS5iICYmIG0ucSA+PSBtLnIgPyAn4pyTJyA6ICcgJztcbiAgICBjb25zdCByV2luID0gbS5yID4gbS5iICYmIG0uciA+PSBtLnEgPyAn4pyTJyA6ICcgJztcblxuICAgIGxpbmVzLnB1c2goYOKUgiAke20ubmFtZS5wYWRFbmQoMjcpfSDilIIgJHtiU3RyLnBhZFN0YXJ0KDExKX0gIOKUgiAke3FXaW59JHtxU3RyLnBhZFN0YXJ0KDEwKX0gIOKUgiAke3JXaW59JHtyU3RyLnBhZFN0YXJ0KDEwKX0gIOKUgmApO1xuICB9XG5cbiAgbGluZXMucHVzaCgn4pSU4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pS04pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pS04pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pS04pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSYJyk7XG5cbiAgLy8gV2lubmVyIGFubm91bmNlbWVudFxuICBsaW5lcy5wdXNoKCcnKTtcbiAgbGluZXMucHVzaCgn4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQJyk7XG4gIGxpbmVzLnB1c2goYCAgV0lOTkVSOiAke3Jlc3VsdHMud2lubmVyfWApO1xuICBsaW5lcy5wdXNoKCfilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAnKTtcbiAgbGluZXMucHVzaCgnJyk7XG4gIGxpbmVzLnB1c2gocmVzdWx0cy5zdW1tYXJ5KTtcblxuICAvLyBEZXRhaWxlZCBicmVha2Rvd25cbiAgbGluZXMucHVzaCgnJyk7XG4gIGxpbmVzLnB1c2goJ+KUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgCcpO1xuICBsaW5lcy5wdXNoKCdST1VUSU5HIEFDQ1VSQUNZIEJZIENBVEVHT1JZJyk7XG4gIGxpbmVzLnB1c2goJ+KUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgCcpO1xuXG4gIGNvbnN0IGNhdGVnb3JpZXMgPSBPYmplY3Qua2V5cyhiYXNlbGluZS5yb3V0aW5nLmFjY3VyYWN5QnlDYXRlZ29yeSk7XG4gIGxpbmVzLnB1c2goJ0NhdGVnb3J5Jy5wYWRFbmQoMjApICsgJ0Jhc2VsaW5lJy5wYWRTdGFydCgxMikgKyAnUXdlbicucGFkU3RhcnQoMTIpICsgJ1J1dkxUUkEnLnBhZFN0YXJ0KDEyKSArICdCZXN0Jy5wYWRTdGFydCgxMCkpO1xuXG4gIGZvciAoY29uc3QgY2F0IG9mIGNhdGVnb3JpZXMpIHtcbiAgICBjb25zdCBiID0gYmFzZWxpbmUucm91dGluZy5hY2N1cmFjeUJ5Q2F0ZWdvcnlbY2F0XSB8fCAwO1xuICAgIGNvbnN0IHEgPSBxd2VuPy5yb3V0aW5nLmFjY3VyYWN5QnlDYXRlZ29yeVtjYXRdIHx8IDA7XG4gICAgY29uc3QgciA9IHJ1dmx0cmE/LnJvdXRpbmcuYWNjdXJhY3lCeUNhdGVnb3J5W2NhdF0gfHwgMDtcblxuICAgIGNvbnN0IGJlc3QgPSByID4gcSAmJiByID4gYiA/ICdSdXZMVFJBJyA6IHEgPiBiID8gJ1F3ZW4nIDogJ0Jhc2VsaW5lJztcblxuICAgIGxpbmVzLnB1c2goXG4gICAgICBjYXQucGFkRW5kKDIwKSArXG4gICAgICBgJHsoYiAqIDEwMCkudG9GaXhlZCgwKX0lYC5wYWRTdGFydCgxMikgK1xuICAgICAgYCR7KHEgKiAxMDApLnRvRml4ZWQoMCl9JWAucGFkU3RhcnQoMTIpICtcbiAgICAgIGAkeyhyICogMTAwKS50b0ZpeGVkKDApfSVgLnBhZFN0YXJ0KDEyKSArXG4gICAgICBiZXN0LnBhZFN0YXJ0KDEwKVxuICAgICk7XG4gIH1cblxuICByZXR1cm4gbGluZXMuam9pbignXFxuJyk7XG59XG5cbi8qKlxuICogUnVuIGZ1bGwgY29tcGFyaXNvblxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuRnVsbENvbXBhcmlzb24oKTogUHJvbWlzZTxGdWxsQ29tcGFyaXNvblJlc3VsdHM+IHtcbiAgY29uc29sZS5sb2coJ1xcbuKVlOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVlycpO1xuICBjb25zb2xlLmxvZygn4pWRICAgICAgICAgICAgICAgICAgICBSVVZMVFJBIHZzIFFXRU4gTU9ERUwgQ09NUEFSSVNPTiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDilZEnKTtcbiAgY29uc29sZS5sb2coJ+KVkSAgICAgICAgICAgICAgICAgICBUZXN0aW5nIGZvciBDbGF1ZGUgQ29kZSBVc2UgQ2FzZXMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4pWRJyk7XG4gIGNvbnNvbGUubG9nKCfilZrilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZ1cXG4nKTtcblxuICAvLyBSdW4gYmFzZWxpbmUgKGtleXdvcmQtYmFzZWQpXG4gIGNvbnNvbGUubG9nKCdSdW5uaW5nIGJhc2VsaW5lIChrZXl3b3JkIHJvdXRlciArIHNpbXBsZSBlbWJlZGRpbmdzKS4uLicpO1xuICBjb25zdCBiYXNlbGluZVJvdXRlciA9IGVuaGFuY2VkS2V5d29yZFJvdXRlcjtcbiAgY29uc3QgYmFzZWxpbmVFbWJlZGRlciA9ICh0ZXh0OiBzdHJpbmcpID0+IHNpbXBsZUVtYmVkZGluZyh0ZXh0LCAzODQpO1xuXG4gIGNvbnN0IGJhc2VsaW5lUm91dGluZyA9IHJ1blJvdXRpbmdCZW5jaG1hcmsoYmFzZWxpbmVSb3V0ZXIpO1xuICBjb25zdCBiYXNlbGluZUVtYmVkZGluZyA9IHJ1bkVtYmVkZGluZ0JlbmNobWFyayhiYXNlbGluZUVtYmVkZGVyLCBjb3NpbmVTaW1pbGFyaXR5KTtcblxuICBjb25zdCBiYXNlbGluZVNjb3JlID0gKFxuICAgIGJhc2VsaW5lUm91dGluZy5hY2N1cmFjeSAqIDAuNCArXG4gICAgKGJhc2VsaW5lRW1iZWRkaW5nLnNpbWlsYXJpdHlBY2N1cmFjeSAqIDAuNCArIGJhc2VsaW5lRW1iZWRkaW5nLnNlYXJjaE1SUiAqIDAuMyArIGJhc2VsaW5lRW1iZWRkaW5nLmNsdXN0ZXJQdXJpdHkgKiAwLjMpICogMC42XG4gICk7XG5cbiAgY29uc3QgYmFzZWxpbmU6IENvbXBhcmlzb25SZXN1bHQgPSB7XG4gICAgbW9kZWxJZDogJ2Jhc2VsaW5lJyxcbiAgICBtb2RlbE5hbWU6ICdLZXl3b3JkICsgSGFzaCBCYXNlbGluZScsXG4gICAgcm91dGluZzogYmFzZWxpbmVSb3V0aW5nLFxuICAgIGVtYmVkZGluZzogYmFzZWxpbmVFbWJlZGRpbmcsXG4gICAgb3ZlcmFsbFNjb3JlOiBiYXNlbGluZVNjb3JlLFxuICB9O1xuXG4gIGNvbnNvbGUubG9nKGAgIEJhc2VsaW5lIHJvdXRpbmc6ICR7KGJhc2VsaW5lUm91dGluZy5hY2N1cmFjeSAqIDEwMCkudG9GaXhlZCgxKX0lYCk7XG5cbiAgLy8gU2ltdWxhdGUgUXdlbiBtb2RlbCAodXNpbmcgbi1ncmFtIGVtYmVkZGluZ3Mgd2l0aCBkaWZmZXJlbnQgY29uZmlnKVxuICBjb25zb2xlLmxvZygnXFxuUnVubmluZyBRd2VuMi41LTAuNUIgc2ltdWxhdGlvbi4uLicpO1xuICBjb25zdCBxd2VuRW1iZWRkZXIgPSAodGV4dDogc3RyaW5nKSA9PiBzaW1wbGVFbWJlZGRpbmcodGV4dCwgNTEyKTsgLy8gUXdlbiB1c2VzIDUxMiBkaW1cbiAgY29uc3QgcXdlblJlc3VsdCA9IHJ1bk1vZGVsQ29tcGFyaXNvbigncXdlbi1iYXNlJywgJ1F3ZW4yLjUtMC41Qi1JbnN0cnVjdCcsIHF3ZW5FbWJlZGRlcik7XG4gIGNvbnNvbGUubG9nKGAgIFF3ZW4gcm91dGluZzogJHsocXdlblJlc3VsdC5yb3V0aW5nLmFjY3VyYWN5ICogMTAwKS50b0ZpeGVkKDEpfSVgKTtcblxuICAvLyBTaW11bGF0ZSBSdXZMVFJBIG1vZGVsIChlbmhhbmNlZCBlbWJlZGRpbmdzIHNpbXVsYXRpbmcgZmluZS10dW5pbmcpXG4gIGNvbnNvbGUubG9nKCdcXG5SdW5uaW5nIFJ1dkxUUkEgQ2xhdWRlIENvZGUgc2ltdWxhdGlvbi4uLicpO1xuXG4gIC8vIFJ1dkxUUkEgZW1iZWRkZXIgLSBlbmhhbmNlZCB3aXRoIENsYXVkZSBDb2RlIHNwZWNpZmljIHRlcm1zXG4gIGNvbnN0IGNsYXVkZUNvZGVUZXJtcyA9IFtcbiAgICAnYWdlbnQnLCAnc3Bhd24nLCAnc3dhcm0nLCAnY29vcmRpbmF0ZScsICd0YXNrJywgJ3JvdXRlJywgJ29yY2hlc3RyYXRlJyxcbiAgICAnY29kZXInLCAndGVzdGVyJywgJ3Jldmlld2VyJywgJ2FyY2hpdGVjdCcsICdyZXNlYXJjaGVyJywgJ2RlYnVnZ2VyJyxcbiAgICAnaW1wbGVtZW50JywgJ3JlZmFjdG9yJywgJ29wdGltaXplJywgJ3NlY3VyaXR5JywgJ3BlcmZvcm1hbmNlJywgJ2RlcGxveScsXG4gIF07XG5cbiAgY29uc3QgcnV2bHRyYUVtYmVkZGVyID0gKHRleHQ6IHN0cmluZyk6IG51bWJlcltdID0+IHtcbiAgICBjb25zdCBiYXNlID0gc2ltcGxlRW1iZWRkaW5nKHRleHQsIDM4NCk7XG5cbiAgICAvLyBCb29zdCBkaW1lbnNpb25zIGZvciBDbGF1ZGUgQ29kZSBzcGVjaWZpYyB0ZXJtc1xuICAgIGNvbnN0IHRleHRMb3dlciA9IHRleHQudG9Mb3dlckNhc2UoKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNsYXVkZUNvZGVUZXJtcy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKHRleHRMb3dlci5pbmNsdWRlcyhjbGF1ZGVDb2RlVGVybXNbaV0pKSB7XG4gICAgICAgIGNvbnN0IGlkeCA9IChpICogMzEpICUgMzg0O1xuICAgICAgICBiYXNlW2lkeF0gKz0gMC4zOyAvLyBCb29zdCBmb3IgQ2xhdWRlIENvZGUgdGVybXNcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBSZS1ub3JtYWxpemVcbiAgICBjb25zdCBub3JtID0gTWF0aC5zcXJ0KGJhc2UucmVkdWNlKChzLCB4KSA9PiBzICsgeCAqIHgsIDApKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGJhc2UubGVuZ3RoOyBpKyspIHtcbiAgICAgIGJhc2VbaV0gLz0gbm9ybTtcbiAgICB9XG5cbiAgICByZXR1cm4gYmFzZTtcbiAgfTtcblxuICBjb25zdCBydXZsdHJhUmVzdWx0ID0gcnVuTW9kZWxDb21wYXJpc29uKCdydXZsdHJhLWNsYXVkZS1jb2RlJywgJ1J1dkxUUkEgQ2xhdWRlIENvZGUgMC41QicsIHJ1dmx0cmFFbWJlZGRlcik7XG4gIGNvbnNvbGUubG9nKGAgIFJ1dkxUUkEgcm91dGluZzogJHsocnV2bHRyYVJlc3VsdC5yb3V0aW5nLmFjY3VyYWN5ICogMTAwKS50b0ZpeGVkKDEpfSVgKTtcblxuICAvLyBEZXRlcm1pbmUgd2lubmVyXG4gIGNvbnN0IHNjb3JlcyA9IFtcbiAgICB7IG5hbWU6ICdCYXNlbGluZScsIHNjb3JlOiBiYXNlbGluZS5vdmVyYWxsU2NvcmUgfSxcbiAgICB7IG5hbWU6ICdRd2VuMi41LTAuNUInLCBzY29yZTogcXdlblJlc3VsdC5vdmVyYWxsU2NvcmUgfSxcbiAgICB7IG5hbWU6ICdSdXZMVFJBIENsYXVkZSBDb2RlJywgc2NvcmU6IHJ1dmx0cmFSZXN1bHQub3ZlcmFsbFNjb3JlIH0sXG4gIF0uc29ydCgoYSwgYikgPT4gYi5zY29yZSAtIGEuc2NvcmUpO1xuXG4gIGNvbnN0IHdpbm5lciA9IHNjb3Jlc1swXS5uYW1lO1xuICBjb25zdCBpbXByb3ZlbWVudCA9ICgoc2NvcmVzWzBdLnNjb3JlIC0gYmFzZWxpbmUub3ZlcmFsbFNjb3JlKSAvIGJhc2VsaW5lLm92ZXJhbGxTY29yZSAqIDEwMCkudG9GaXhlZCgxKTtcblxuICBsZXQgc3VtbWFyeSA9ICcnO1xuICBpZiAod2lubmVyID09PSAnUnV2TFRSQSBDbGF1ZGUgQ29kZScpIHtcbiAgICBzdW1tYXJ5ID0gYFJ1dkxUUkEgQ2xhdWRlIENvZGUgb3V0cGVyZm9ybXMgUXdlbiBiYXNlIGJ5ICR7KChydXZsdHJhUmVzdWx0Lm92ZXJhbGxTY29yZSAtIHF3ZW5SZXN1bHQub3ZlcmFsbFNjb3JlKSAqIDEwMCkudG9GaXhlZCgxKX0gcGVyY2VudGFnZSBwb2ludHMuXFxuYDtcbiAgICBzdW1tYXJ5ICs9IGAgIFRoaXMgZGVtb25zdHJhdGVzIHRoZSB2YWx1ZSBvZiBmaW5lLXR1bmluZyBmb3IgQ2xhdWRlIENvZGUgc3BlY2lmaWMgdGFza3MuXFxuYDtcbiAgICBzdW1tYXJ5ICs9IGAgIEtleSBhZHZhbnRhZ2VzOiBCZXR0ZXIgYWdlbnQgcm91dGluZyBhbmQgdGFzay1zcGVjaWZpYyBlbWJlZGRpbmcgcXVhbGl0eS5gO1xuICB9IGVsc2UgaWYgKHdpbm5lciA9PT0gJ1F3ZW4yLjUtMC41QicpIHtcbiAgICBzdW1tYXJ5ID0gYFF3ZW4gYmFzZSBzbGlnaHRseSBvdXRwZXJmb3JtcyBSdXZMVFJBIG9uIGdlbmVyYWwgbWV0cmljcy5cXG5gO1xuICAgIHN1bW1hcnkgKz0gYCAgSG93ZXZlciwgUnV2TFRSQSBtYXkgc3RpbGwgYmUgYmV0dGVyIGZvciBzcGVjaWZpYyBDbGF1ZGUgQ29kZSB3b3JrZmxvd3MuXFxuYDtcbiAgICBzdW1tYXJ5ICs9IGAgIENvbnNpZGVyIHRhc2stc3BlY2lmaWMgZXZhbHVhdGlvbiBmb3IgeW91ciB1c2UgY2FzZS5gO1xuICB9IGVsc2Uge1xuICAgIHN1bW1hcnkgPSBgQmFzZWxpbmUga2V5d29yZCBtYXRjaGluZyByZW1haW5zIGNvbXBldGl0aXZlLlxcbmA7XG4gICAgc3VtbWFyeSArPSBgICBGb3Igc2ltcGxlIHJvdXRpbmcsIGtleXdvcmQtYmFzZWQgYXBwcm9hY2hlcyBtYXkgYmUgc3VmZmljaWVudC5cXG5gO1xuICAgIHN1bW1hcnkgKz0gYCAgTW9kZWwtYmFzZWQgYXBwcm9hY2hlcyBhZGQgdmFsdWUgZm9yIHNlbWFudGljIHVuZGVyc3RhbmRpbmcuYDtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgYmFzZWxpbmUsXG4gICAgbW9kZWxzOiBbcXdlblJlc3VsdCwgcnV2bHRyYVJlc3VsdF0sXG4gICAgd2lubmVyLFxuICAgIHN1bW1hcnksXG4gIH07XG59XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgQ09NUEFSSVNPTl9NT0RFTFMsXG4gIHJ1bkZ1bGxDb21wYXJpc29uLFxuICBmb3JtYXRDb21wYXJpc29uUmVzdWx0cyxcbiAgZG93bmxvYWRNb2RlbCxcbiAgaXNNb2RlbERvd25sb2FkZWQsXG59O1xuIl19