@ruvector/ruvllm 2.5.7 → 2.6.2

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 (83) hide show
  1. package/dist/cjs/benchmarks/embedding-benchmark.js +8 -8
  2. package/dist/cjs/benchmarks/index.js +5 -5
  3. package/dist/cjs/benchmarks/model-comparison.js +25 -15
  4. package/dist/cjs/benchmarks/routing-benchmark.js +5 -5
  5. package/dist/cjs/contrastive.js +9 -9
  6. package/dist/cjs/engine.d.ts +2 -2
  7. package/dist/cjs/engine.d.ts.map +1 -1
  8. package/dist/cjs/engine.js +41 -19
  9. package/dist/cjs/intelligence.js +18 -8
  10. package/dist/cjs/lora.d.ts +11 -0
  11. package/dist/cjs/lora.d.ts.map +1 -1
  12. package/dist/cjs/lora.js +16 -1
  13. package/dist/cjs/models.js +23 -13
  14. package/dist/cjs/native.d.ts +17 -8
  15. package/dist/cjs/native.d.ts.map +1 -1
  16. package/dist/cjs/native.js +4 -5
  17. package/dist/cjs/rlm/controller.d.ts +245 -0
  18. package/dist/cjs/rlm/controller.d.ts.map +1 -0
  19. package/dist/cjs/rlm/controller.js +554 -0
  20. package/dist/cjs/rlm/index.d.ts +62 -0
  21. package/dist/cjs/rlm/index.d.ts.map +1 -0
  22. package/dist/cjs/rlm/index.js +97 -0
  23. package/dist/cjs/rlm/training.d.ts +333 -0
  24. package/dist/cjs/rlm/training.d.ts.map +1 -0
  25. package/dist/cjs/rlm/training.js +680 -0
  26. package/dist/cjs/rlm/types.d.ts +189 -0
  27. package/dist/cjs/rlm/types.d.ts.map +1 -0
  28. package/dist/cjs/rlm/types.js +10 -0
  29. package/dist/cjs/streaming.d.ts +0 -1
  30. package/dist/cjs/streaming.d.ts.map +1 -1
  31. package/dist/cjs/streaming.js +3 -3
  32. package/dist/cjs/training.d.ts +31 -1
  33. package/dist/cjs/training.d.ts.map +1 -1
  34. package/dist/cjs/training.js +86 -6
  35. package/dist/cjs/types.d.ts +11 -2
  36. package/dist/cjs/types.d.ts.map +1 -1
  37. package/dist/cjs/types.js +1 -1
  38. package/dist/esm/benchmarks/index.d.ts +5 -5
  39. package/dist/esm/benchmarks/index.js +5 -5
  40. package/dist/esm/benchmarks/model-comparison.d.ts +2 -2
  41. package/dist/esm/benchmarks/model-comparison.js +2 -2
  42. package/dist/esm/contrastive.d.ts +1 -1
  43. package/dist/esm/engine.d.ts +2 -2
  44. package/dist/esm/engine.d.ts.map +1 -1
  45. package/dist/esm/engine.js +42 -20
  46. package/dist/esm/export.d.ts +2 -2
  47. package/dist/esm/federated.d.ts +1 -1
  48. package/dist/esm/federated.js +1 -1
  49. package/dist/esm/index.d.ts +16 -16
  50. package/dist/esm/index.js +16 -16
  51. package/dist/esm/lora.d.ts +12 -1
  52. package/dist/esm/lora.d.ts.map +1 -1
  53. package/dist/esm/lora.js +16 -1
  54. package/dist/esm/native.d.ts +17 -8
  55. package/dist/esm/native.d.ts.map +1 -1
  56. package/dist/esm/native.js +1 -1
  57. package/dist/esm/rlm/controller.d.ts +245 -0
  58. package/dist/esm/rlm/controller.d.ts.map +1 -0
  59. package/dist/esm/rlm/controller.js +550 -0
  60. package/dist/esm/rlm/index.d.ts +62 -0
  61. package/dist/esm/rlm/index.d.ts.map +1 -0
  62. package/dist/esm/rlm/index.js +71 -0
  63. package/dist/esm/rlm/training.d.ts +333 -0
  64. package/dist/esm/rlm/training.d.ts.map +1 -0
  65. package/dist/esm/rlm/training.js +672 -0
  66. package/dist/esm/rlm/types.d.ts +189 -0
  67. package/dist/esm/rlm/types.d.ts.map +1 -0
  68. package/dist/esm/rlm/types.js +9 -0
  69. package/dist/esm/session.d.ts +1 -1
  70. package/dist/esm/simd.js +1 -1
  71. package/dist/esm/sona.d.ts +1 -1
  72. package/dist/esm/sona.js +1 -1
  73. package/dist/esm/streaming.d.ts +1 -2
  74. package/dist/esm/streaming.d.ts.map +1 -1
  75. package/dist/esm/training.d.ts +34 -4
  76. package/dist/esm/training.d.ts.map +1 -1
  77. package/dist/esm/training.js +88 -8
  78. package/dist/esm/types.d.ts +11 -2
  79. package/dist/esm/types.d.ts.map +1 -1
  80. package/dist/esm/types.js +1 -1
  81. package/package.json +4 -2
  82. package/scripts/fix-esm-extensions.mjs +181 -0
  83. package/scripts/smoke-esm.mjs +82 -0
@@ -0,0 +1,550 @@
1
+ /**
2
+ * RLM Controller - Recursive Retrieval Language Model
3
+ *
4
+ * Implements a recursive retrieval-augmented generation system that:
5
+ * 1. Breaks down complex queries into sub-queries
6
+ * 2. Retrieves relevant memory spans for each query
7
+ * 3. Synthesizes coherent answers from retrieved context
8
+ * 4. Optionally reflects on and refines answers
9
+ *
10
+ * @example Basic Usage
11
+ * ```typescript
12
+ * import { RlmController } from '@ruvector/ruvllm';
13
+ *
14
+ * const rlm = new RlmController({
15
+ * maxDepth: 3,
16
+ * retrievalTopK: 10,
17
+ * enableCache: true,
18
+ * });
19
+ *
20
+ * // Add knowledge to memory
21
+ * await rlm.addMemory('Machine learning is a subset of AI that enables systems to learn from data.');
22
+ * await rlm.addMemory('Deep learning uses neural networks with many layers.');
23
+ *
24
+ * // Query with recursive retrieval
25
+ * const answer = await rlm.query('Explain the relationship between ML and deep learning');
26
+ * console.log(answer.text);
27
+ * console.log('Sources:', answer.sources.length);
28
+ * console.log('Confidence:', answer.confidence);
29
+ * ```
30
+ *
31
+ * @example Streaming
32
+ * ```typescript
33
+ * const rlm = new RlmController();
34
+ *
35
+ * for await (const event of rlm.queryStream('What is AI?')) {
36
+ * if (event.type === 'token') {
37
+ * process.stdout.write(event.text);
38
+ * } else {
39
+ * console.log('\n\nDone! Quality:', event.answer.qualityScore);
40
+ * }
41
+ * }
42
+ * ```
43
+ *
44
+ * @example With Reflection
45
+ * ```typescript
46
+ * const rlm = new RlmController({
47
+ * enableReflection: true,
48
+ * maxReflectionIterations: 2,
49
+ * minQualityScore: 0.8,
50
+ * });
51
+ *
52
+ * const answer = await rlm.query('Complex multi-part question...');
53
+ * // Answer will be iteratively refined until quality >= 0.8
54
+ * ```
55
+ */
56
+ import { RuvLLM } from '../engine.js';
57
+ /**
58
+ * Default configuration values
59
+ */
60
+ const DEFAULT_CONFIG = {
61
+ maxDepth: 3,
62
+ maxSubQueries: 5,
63
+ tokenBudget: 4096,
64
+ enableCache: true,
65
+ cacheTtl: 300000, // 5 minutes
66
+ retrievalTopK: 10,
67
+ minQualityScore: 0.7,
68
+ enableReflection: false,
69
+ maxReflectionIterations: 2,
70
+ };
71
+ /**
72
+ * RlmController - Recursive Retrieval Language Model Controller
73
+ *
74
+ * Orchestrates retrieval-augmented generation with recursive sub-query
75
+ * decomposition, memory search, and optional self-reflection.
76
+ */
77
+ export class RlmController {
78
+ /**
79
+ * Create a new RLM controller
80
+ *
81
+ * @param config - Configuration options
82
+ * @param engine - Optional RuvLLM engine instance (creates new if not provided)
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * // With default config
87
+ * const rlm = new RlmController();
88
+ *
89
+ * // With custom config
90
+ * const rlm = new RlmController({
91
+ * maxDepth: 5,
92
+ * enableReflection: true,
93
+ * });
94
+ *
95
+ * // With existing engine
96
+ * const engine = new RuvLLM({ learningEnabled: true });
97
+ * const rlm = new RlmController({}, engine);
98
+ * ```
99
+ */
100
+ constructor(config, engine) {
101
+ this.config = { ...DEFAULT_CONFIG, ...config };
102
+ this.cache = new Map();
103
+ this.engine = engine ?? new RuvLLM({ learningEnabled: true });
104
+ this.memoryIdCounter = 0;
105
+ }
106
+ /**
107
+ * Query the RLM with recursive retrieval
108
+ *
109
+ * @param input - The query string
110
+ * @returns Promise resolving to the answer with sources and metadata
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * const answer = await rlm.query('What is the capital of France?');
115
+ * console.log(answer.text); // "The capital of France is Paris..."
116
+ * console.log(answer.confidence); // 0.95
117
+ * console.log(answer.sources); // [{ id: '...', text: '...', similarityScore: 0.92 }]
118
+ * ```
119
+ */
120
+ async query(input) {
121
+ // Check cache first
122
+ if (this.config.enableCache) {
123
+ const cached = this.getCached(input);
124
+ if (cached) {
125
+ return { ...cached, cached: true };
126
+ }
127
+ }
128
+ // Retrieve relevant memory spans
129
+ const sources = await this.searchMemory(input, this.config.retrievalTopK);
130
+ // Generate sub-queries if needed and depth allows
131
+ const subQueries = await this.generateSubQueries(input, sources, 0);
132
+ // Build context from sources and sub-query answers
133
+ const context = this.buildContext(sources, subQueries);
134
+ // Generate the answer
135
+ const startTime = Date.now();
136
+ const response = this.engine.query(this.buildPrompt(input, context), this.getGenerationConfig());
137
+ // Calculate token usage (estimate if not provided by engine)
138
+ const tokenUsage = this.estimateTokenUsage(input, context, response.text);
139
+ // Calculate quality score
140
+ const qualityScore = this.calculateQualityScore(sources, response.confidence);
141
+ let answer = {
142
+ text: response.text,
143
+ confidence: response.confidence,
144
+ qualityScore,
145
+ sources,
146
+ subQueries: subQueries.length > 0 ? subQueries : undefined,
147
+ tokenUsage,
148
+ cached: false,
149
+ };
150
+ // Apply reflection if enabled and quality is below threshold
151
+ if (this.config.enableReflection && qualityScore < this.config.minQualityScore) {
152
+ answer = await this.applyReflection(input, answer);
153
+ }
154
+ // Cache the result
155
+ if (this.config.enableCache) {
156
+ this.setCache(input, answer);
157
+ }
158
+ return answer;
159
+ }
160
+ /**
161
+ * Query with streaming response
162
+ *
163
+ * @param input - The query string
164
+ * @yields StreamToken events (either partial tokens or final answer)
165
+ *
166
+ * @example
167
+ * ```typescript
168
+ * for await (const event of rlm.queryStream('Explain quantum computing')) {
169
+ * if (event.type === 'token') {
170
+ * // Partial token received
171
+ * process.stdout.write(event.text);
172
+ * } else {
173
+ * // Generation complete
174
+ * console.log('\n\nSources:', event.answer.sources.length);
175
+ * }
176
+ * }
177
+ * ```
178
+ */
179
+ async *queryStream(input) {
180
+ // Check cache first
181
+ if (this.config.enableCache) {
182
+ const cached = this.getCached(input);
183
+ if (cached) {
184
+ // Simulate streaming for cached response
185
+ const words = cached.text.split(' ');
186
+ for (const word of words) {
187
+ yield { type: 'token', text: word + ' ', done: false };
188
+ await this.delay(10); // Small delay for realistic streaming
189
+ }
190
+ yield { type: 'done', answer: { ...cached, cached: true }, done: true };
191
+ return;
192
+ }
193
+ }
194
+ // Retrieve sources
195
+ const sources = await this.searchMemory(input, this.config.retrievalTopK);
196
+ const subQueries = await this.generateSubQueries(input, sources, 0);
197
+ const context = this.buildContext(sources, subQueries);
198
+ // Generate with simulated streaming
199
+ const prompt = this.buildPrompt(input, context);
200
+ const response = this.engine.query(prompt, this.getGenerationConfig());
201
+ // Stream the response word by word
202
+ const words = response.text.split(' ');
203
+ let streamedText = '';
204
+ for (let i = 0; i < words.length; i++) {
205
+ const word = words[i];
206
+ const text = i < words.length - 1 ? word + ' ' : word;
207
+ streamedText += text;
208
+ yield { type: 'token', text, done: false };
209
+ await this.delay(20); // Simulate generation latency
210
+ }
211
+ const tokenUsage = this.estimateTokenUsage(input, context, streamedText);
212
+ const qualityScore = this.calculateQualityScore(sources, response.confidence);
213
+ const answer = {
214
+ text: streamedText,
215
+ confidence: response.confidence,
216
+ qualityScore,
217
+ sources,
218
+ subQueries: subQueries.length > 0 ? subQueries : undefined,
219
+ tokenUsage,
220
+ cached: false,
221
+ };
222
+ // Cache the result
223
+ if (this.config.enableCache) {
224
+ this.setCache(input, answer);
225
+ }
226
+ yield { type: 'done', answer, done: true };
227
+ }
228
+ /**
229
+ * Add content to memory for retrieval
230
+ *
231
+ * @param text - The text content to store
232
+ * @param metadata - Optional metadata to associate with the memory
233
+ * @returns Promise resolving to the memory span ID
234
+ *
235
+ * @example
236
+ * ```typescript
237
+ * const id1 = await rlm.addMemory(
238
+ * 'TypeScript is a typed superset of JavaScript.',
239
+ * { source: 'documentation', category: 'programming' }
240
+ * );
241
+ *
242
+ * const id2 = await rlm.addMemory(
243
+ * 'React is a JavaScript library for building UIs.'
244
+ * );
245
+ * ```
246
+ */
247
+ async addMemory(text, metadata) {
248
+ const nodeId = this.engine.addMemory(text, metadata);
249
+ const id = `rlm-mem-${this.memoryIdCounter++}-${nodeId}`;
250
+ return id;
251
+ }
252
+ /**
253
+ * Search memory for relevant spans
254
+ *
255
+ * @param query - The search query
256
+ * @param topK - Number of results to return (default: config.retrievalTopK)
257
+ * @returns Promise resolving to array of memory spans
258
+ *
259
+ * @example
260
+ * ```typescript
261
+ * const spans = await rlm.searchMemory('JavaScript frameworks', 5);
262
+ * for (const span of spans) {
263
+ * console.log(`[${span.similarityScore.toFixed(2)}] ${span.text}`);
264
+ * }
265
+ * ```
266
+ */
267
+ async searchMemory(query, topK) {
268
+ const k = topK ?? this.config.retrievalTopK;
269
+ const results = this.engine.searchMemory(query, k);
270
+ return results.map((result, index) => ({
271
+ id: `rlm-span-${result.id}-${index}`,
272
+ text: result.content,
273
+ similarityScore: result.score,
274
+ source: result.metadata?.source,
275
+ metadata: result.metadata,
276
+ }));
277
+ }
278
+ /**
279
+ * Clear the response cache
280
+ *
281
+ * @example
282
+ * ```typescript
283
+ * rlm.clearCache();
284
+ * console.log('Cache cleared');
285
+ * ```
286
+ */
287
+ clearCache() {
288
+ this.cache.clear();
289
+ }
290
+ /**
291
+ * Get current cache statistics
292
+ *
293
+ * @returns Object with cache size and hit rate info
294
+ */
295
+ getCacheStats() {
296
+ return {
297
+ size: this.cache.size,
298
+ entries: this.cache.size,
299
+ };
300
+ }
301
+ /**
302
+ * Update configuration at runtime
303
+ *
304
+ * @param config - Partial configuration to merge
305
+ */
306
+ updateConfig(config) {
307
+ this.config = { ...this.config, ...config };
308
+ }
309
+ /**
310
+ * Get current configuration
311
+ */
312
+ getConfig() {
313
+ return { ...this.config };
314
+ }
315
+ // ============================================
316
+ // Private Methods
317
+ // ============================================
318
+ /**
319
+ * Generate sub-queries for complex questions
320
+ */
321
+ async generateSubQueries(query, sources, depth) {
322
+ if (depth >= this.config.maxDepth) {
323
+ return [];
324
+ }
325
+ // Simple heuristic: generate sub-queries for questions with multiple parts
326
+ const subQueries = [];
327
+ const parts = this.decomposeQuery(query);
328
+ for (const part of parts.slice(0, this.config.maxSubQueries)) {
329
+ if (part.trim().length < 10)
330
+ continue;
331
+ // Search for sub-query specific sources
332
+ const subSources = await this.searchMemory(part, Math.ceil(this.config.retrievalTopK / 2));
333
+ const context = this.buildContext(subSources, []);
334
+ const response = this.engine.query(this.buildPrompt(part, context), { ...this.getGenerationConfig(), maxTokens: 256 });
335
+ subQueries.push({
336
+ query: part,
337
+ answer: response.text,
338
+ depth: depth + 1,
339
+ });
340
+ }
341
+ return subQueries;
342
+ }
343
+ /**
344
+ * Decompose a complex query into simpler parts
345
+ */
346
+ decomposeQuery(query) {
347
+ // Split on common conjunctions and question markers
348
+ const parts = [];
349
+ // Check for multi-part questions
350
+ const conjunctions = [' and ', ' or ', '. ', '? ', '; '];
351
+ let current = query;
352
+ for (const conj of conjunctions) {
353
+ if (current.includes(conj)) {
354
+ const split = current.split(conj);
355
+ parts.push(...split.filter(p => p.trim().length > 10));
356
+ current = '';
357
+ break;
358
+ }
359
+ }
360
+ // If no decomposition happened, return original
361
+ if (parts.length === 0) {
362
+ return [query];
363
+ }
364
+ return parts;
365
+ }
366
+ /**
367
+ * Build context string from sources and sub-queries
368
+ */
369
+ buildContext(sources, subQueries) {
370
+ const parts = [];
371
+ // Add sources
372
+ if (sources.length > 0) {
373
+ parts.push('Relevant context:');
374
+ for (const source of sources) {
375
+ parts.push(`- ${source.text}`);
376
+ }
377
+ }
378
+ // Add sub-query answers
379
+ if (subQueries.length > 0) {
380
+ parts.push('\nRelated information:');
381
+ for (const sq of subQueries) {
382
+ parts.push(`Q: ${sq.query}`);
383
+ parts.push(`A: ${sq.answer}`);
384
+ }
385
+ }
386
+ return parts.join('\n');
387
+ }
388
+ /**
389
+ * Build the full prompt with context
390
+ */
391
+ buildPrompt(query, context) {
392
+ if (context.trim().length === 0) {
393
+ return query;
394
+ }
395
+ return `${context}\n\nBased on the above context, answer the following question:\n${query}`;
396
+ }
397
+ /**
398
+ * Get generation config based on RLM settings
399
+ */
400
+ getGenerationConfig() {
401
+ return {
402
+ maxTokens: Math.min(this.config.tokenBudget, 2048),
403
+ temperature: 0.7,
404
+ topP: 0.9,
405
+ };
406
+ }
407
+ /**
408
+ * Estimate token usage
409
+ */
410
+ estimateTokenUsage(query, context, response) {
411
+ // Rough estimation: ~4 characters per token
412
+ const promptTokens = Math.ceil((query.length + context.length) / 4);
413
+ const completionTokens = Math.ceil(response.length / 4);
414
+ return {
415
+ prompt: promptTokens,
416
+ completion: completionTokens,
417
+ total: promptTokens + completionTokens,
418
+ };
419
+ }
420
+ /**
421
+ * Calculate quality score based on sources and confidence
422
+ */
423
+ calculateQualityScore(sources, confidence) {
424
+ if (sources.length === 0) {
425
+ return confidence * 0.5; // Penalize answers without sources
426
+ }
427
+ // Average source similarity
428
+ const avgSimilarity = sources.reduce((sum, s) => sum + s.similarityScore, 0) / sources.length;
429
+ // Weighted combination
430
+ return confidence * 0.6 + avgSimilarity * 0.4;
431
+ }
432
+ /**
433
+ * Apply self-reflection to improve answer
434
+ */
435
+ async applyReflection(query, answer) {
436
+ let currentAnswer = answer;
437
+ let iterations = 0;
438
+ while (iterations < this.config.maxReflectionIterations &&
439
+ currentAnswer.qualityScore < this.config.minQualityScore) {
440
+ iterations++;
441
+ // Generate critique
442
+ const critiquePrompt = `Evaluate this answer for accuracy and completeness:
443
+ Question: ${query}
444
+ Answer: ${currentAnswer.text}
445
+
446
+ Provide a brief critique and suggest improvements.`;
447
+ const critiqueResponse = this.engine.query(critiquePrompt, {
448
+ maxTokens: 256,
449
+ temperature: 0.5,
450
+ });
451
+ // Generate improved answer
452
+ const improvePrompt = `Based on this feedback: "${critiqueResponse.text}"
453
+
454
+ Improve this answer:
455
+ Question: ${query}
456
+ Original: ${currentAnswer.text}
457
+
458
+ Provide an improved answer:`;
459
+ const improvedResponse = this.engine.query(improvePrompt, this.getGenerationConfig());
460
+ // Update answer with reflection improvements
461
+ const newQualityScore = Math.min(1.0, currentAnswer.qualityScore + 0.1 * iterations);
462
+ currentAnswer = {
463
+ ...currentAnswer,
464
+ text: improvedResponse.text,
465
+ confidence: Math.max(currentAnswer.confidence, improvedResponse.confidence),
466
+ qualityScore: newQualityScore,
467
+ tokenUsage: {
468
+ prompt: currentAnswer.tokenUsage.prompt + 100, // Approximate additional tokens
469
+ completion: currentAnswer.tokenUsage.completion + 100,
470
+ total: currentAnswer.tokenUsage.total + 200,
471
+ },
472
+ };
473
+ }
474
+ return currentAnswer;
475
+ }
476
+ /**
477
+ * Get cached answer if valid
478
+ */
479
+ getCached(query) {
480
+ const hash = this.hashQuery(query);
481
+ const entry = this.cache.get(hash);
482
+ if (!entry) {
483
+ return null;
484
+ }
485
+ // Check TTL
486
+ if (Date.now() - entry.timestamp > this.config.cacheTtl) {
487
+ this.cache.delete(hash);
488
+ return null;
489
+ }
490
+ return entry.answer;
491
+ }
492
+ /**
493
+ * Set cache entry
494
+ */
495
+ setCache(query, answer) {
496
+ const hash = this.hashQuery(query);
497
+ this.cache.set(hash, {
498
+ answer,
499
+ timestamp: Date.now(),
500
+ queryHash: hash,
501
+ });
502
+ // Prune old entries if cache gets too large
503
+ if (this.cache.size > 1000) {
504
+ this.pruneCache();
505
+ }
506
+ }
507
+ /**
508
+ * Simple hash function for cache keys
509
+ */
510
+ hashQuery(query) {
511
+ let hash = 0;
512
+ for (let i = 0; i < query.length; i++) {
513
+ const char = query.charCodeAt(i);
514
+ hash = ((hash << 5) - hash) + char;
515
+ hash = hash & hash; // Convert to 32-bit integer
516
+ }
517
+ return `rlm-cache-${hash.toString(16)}`;
518
+ }
519
+ /**
520
+ * Prune expired cache entries
521
+ */
522
+ pruneCache() {
523
+ const now = Date.now();
524
+ const toDelete = [];
525
+ for (const [key, entry] of this.cache.entries()) {
526
+ if (now - entry.timestamp > this.config.cacheTtl) {
527
+ toDelete.push(key);
528
+ }
529
+ }
530
+ // Delete oldest entries if still too large
531
+ if (this.cache.size - toDelete.length > 800) {
532
+ const entries = Array.from(this.cache.entries())
533
+ .sort((a, b) => a[1].timestamp - b[1].timestamp);
534
+ const deleteCount = entries.length - 500;
535
+ for (let i = 0; i < deleteCount; i++) {
536
+ toDelete.push(entries[i][0]);
537
+ }
538
+ }
539
+ for (const key of toDelete) {
540
+ this.cache.delete(key);
541
+ }
542
+ }
543
+ /**
544
+ * Utility delay function for streaming simulation
545
+ */
546
+ delay(ms) {
547
+ return new Promise(resolve => setTimeout(resolve, ms));
548
+ }
549
+ }
550
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udHJvbGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9ybG0vY29udHJvbGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0RHO0FBYUgsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUduQzs7R0FFRztBQUNILE1BQU0sY0FBYyxHQUF3QjtJQUMxQyxRQUFRLEVBQUUsQ0FBQztJQUNYLGFBQWEsRUFBRSxDQUFDO0lBQ2hCLFdBQVcsRUFBRSxJQUFJO0lBQ2pCLFdBQVcsRUFBRSxJQUFJO0lBQ2pCLFFBQVEsRUFBRSxNQUFNLEVBQUUsWUFBWTtJQUM5QixhQUFhLEVBQUUsRUFBRTtJQUNqQixlQUFlLEVBQUUsR0FBRztJQUNwQixnQkFBZ0IsRUFBRSxLQUFLO0lBQ3ZCLHVCQUF1QixFQUFFLENBQUM7Q0FDM0IsQ0FBQztBQUVGOzs7OztHQUtHO0FBQ0gsTUFBTSxPQUFPLGFBQWE7SUFNeEI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQXFCRztJQUNILFlBQVksTUFBa0IsRUFBRSxNQUFlO1FBQzdDLElBQUksQ0FBQyxNQUFNLEdBQUcsRUFBRSxHQUFHLGNBQWMsRUFBRSxHQUFHLE1BQU0sRUFBRSxDQUFDO1FBQy9DLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sSUFBSSxJQUFJLE1BQU0sQ0FBQyxFQUFFLGVBQWUsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQzlELElBQUksQ0FBQyxlQUFlLEdBQUcsQ0FBQyxDQUFDO0lBQzNCLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7OztPQWFHO0lBQ0gsS0FBSyxDQUFDLEtBQUssQ0FBQyxLQUFhO1FBQ3ZCLG9CQUFvQjtRQUNwQixJQUFJLElBQUksQ0FBQyxNQUFNLENB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QUcsR0FBRyxFQUFFLENBQUM7WUFDNUMsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO2lCQUM3QyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUVuRCxNQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsTUFBTSxHQUFHLEdBQUcsQ0FBQztZQUN6QyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsV0FBVyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7Z0JBQ3JDLFFBQVEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDL0IsQ0FBQztRQUNILENBQUM7UUFFRCxLQUFLLE1BQU0sR0FBRyxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQzNCLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3pCLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxLQUFLLENBQUMsRUFBVTtRQUN0QixPQUFPLElBQUksT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3pELENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUkxNIENvbnRyb2xsZXIgLSBSZWN1cnNpdmUgUmV0cmlldmFsIExhbmd1YWdlIE1vZGVsXG4gKlxuICogSW1wbGVtZW50cyBhIHJlY3Vyc2l2ZSByZXRyaWV2YWwtYXVnbWVudGVkIGdlbmVyYXRpb24gc3lzdGVtIHRoYXQ6XG4gKiAxLiBCcmVha3MgZG93biBjb21wbGV4IHF1ZXJpZXMgaW50byBzdWItcXVlcmllc1xuICogMi4gUmV0cmlldmVzIHJlbGV2YW50IG1lbW9yeSBzcGFucyBmb3IgZWFjaCBxdWVyeVxuICogMy4gU3ludGhlc2l6ZXMgY29oZXJlbnQgYW5zd2VycyBmcm9tIHJldHJpZXZlZCBjb250ZXh0XG4gKiA0LiBPcHRpb25hbGx5IHJlZmxlY3RzIG9uIGFuZCByZWZpbmVzIGFuc3dlcnNcbiAqXG4gKiBAZXhhbXBsZSBCYXNpYyBVc2FnZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgUmxtQ29udHJvbGxlciB9IGZyb20gJ0BydXZlY3Rvci9ydXZsbG0nO1xuICpcbiAqIGNvbnN0IHJsbSA9IG5ldyBSbG1Db250cm9sbGVyKHtcbiAqICAgbWF4RGVwdGg6IDMsXG4gKiAgIHJldHJpZXZhbFRvcEs6IDEwLFxuICogICBlbmFibGVDYWNoZTogdHJ1ZSxcbiAqIH0pO1xuICpcbiAqIC8vIEFkZCBrbm93bGVkZ2UgdG8gbWVtb3J5XG4gKiBhd2FpdCBybG0uYWRkTWVtb3J5KCdNYWNoaW5lIGxlYXJuaW5nIGlzIGEgc3Vic2V0IG9mIEFJIHRoYXQgZW5hYmxlcyBzeXN0ZW1zIHRvIGxlYXJuIGZyb20gZGF0YS4nKTtcbiAqIGF3YWl0IHJsbS5hZGRNZW1vcnkoJ0RlZXAgbGVhcm5pbmcgdXNlcyBuZXVyYWwgbmV0d29ya3Mgd2l0aCBtYW55IGxheWVycy4nKTtcbiAqXG4gKiAvLyBRdWVyeSB3aXRoIHJlY3Vyc2l2ZSByZXRyaWV2YWxcbiAqIGNvbnN0IGFuc3dlciA9IGF3YWl0IHJsbS5xdWVyeSgnRXhwbGFpbiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gTUwgYW5kIGRlZXAgbGVhcm5pbmcnKTtcbiAqIGNvbnNvbGUubG9nKGFuc3dlci50ZXh0KTtcbiAqIGNvbnNvbGUubG9nKCdTb3VyY2VzOicsIGFuc3dlci5zb3VyY2VzLmxlbmd0aCk7XG4gKiBjb25zb2xlLmxvZygnQ29uZmlkZW5jZTonLCBhbnN3ZXIuY29uZmlkZW5jZSk7XG4gKiBgYGBcbiAqXG4gKiBAZXhhbXBsZSBTdHJlYW1pbmdcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IHJsbSA9IG5ldyBSbG1Db250cm9sbGVyKCk7XG4gKlxuICogZm9yIGF3YWl0IChjb25zdCBldmVudCBvZiBybG0ucXVlcnlTdHJlYW0oJ1doYXQgaXMgQUk/JykpIHtcbiAqICAgaWYgKGV2ZW50LnR5cGUgPT09ICd0b2tlbicpIHtcbiAqICAgICBwcm9jZXNzLnN0ZG91dC53cml0ZShldmVudC50ZXh0KTtcbiAqICAgfSBlbHNlIHtcbiAqICAgICBjb25zb2xlLmxvZygnXFxuXFxuRG9uZSEgUXVhbGl0eTonLCBldmVudC5hbnN3ZXIucXVhbGl0eVNjb3JlKTtcbiAqICAgfVxuICogfVxuICogYGBgXG4gKlxuICogQGV4YW1wbGUgV2l0aCBSZWZsZWN0aW9uXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBybG0gPSBuZXcgUmxtQ29udHJvbGxlcih7XG4gKiAgIGVuYWJsZVJlZmxlY3Rpb246IHRydWUsXG4gKiAgIG1heFJlZmxlY3Rpb25JdGVyYXRpb25zOiAyLFxuICogICBtaW5RdWFsaXR5U2NvcmU6IDAuOCxcbiAqIH0pO1xuICpcbiAqIGNvbnN0IGFuc3dlciA9IGF3YWl0IHJsbS5xdWVyeSgnQ29tcGxleCBtdWx0aS1wYXJ0IHF1ZXN0aW9uLi4uJyk7XG4gKiAvLyBBbnN3ZXIgd2lsbCBiZSBpdGVyYXRpdmVseSByZWZpbmVkIHVudGlsIHF1YWxpdHkgPj0gMC44XG4gKiBgYGBcbiAqL1xuXG5pbXBvcnQge1xuICBSbG1Db25maWcsXG4gIFJsbUFuc3dlcixcbiAgTWVtb3J5U3BhbixcbiAgU3ViUXVlcnksXG4gIFRva2VuVXNhZ2UsXG4gIFN0cmVhbVRva2VuLFxuICBSbG1DYWNoZUVudHJ5LFxuICBSZWZsZWN0aW9uUmVzdWx0LFxufSBmcm9tICcuL3R5cGVzJztcblxuaW1wb3J0IHsgUnV2TExNIH0gZnJvbSAnLi4vZW5naW5lJztcbmltcG9ydCB0eXBlIHsgR2VuZXJhdGlvbkNvbmZpZywgUXVlcnlSZXNwb25zZSB9IGZyb20gJy4uL3R5cGVzJztcblxuLyoqXG4gKiBEZWZhdWx0IGNvbmZpZ3VyYXRpb24gdmFsdWVzXG4gKi9cbmNvbnN0IERFRkFVTFRfQ09ORklHOiBSZXF1aXJlZDxSbG1Db25maWc+ID0ge1xuICBtYXhEZXB0aDogMyxcbiAgbWF4U3ViUXVlcmllczogNSxcbiAgdG9rZW5CdWRnZXQ6IDQwOTYsXG4gIGVuYWJsZUNhY2hlOiB0cnVlLFxuICBjYWNoZVR0bDogMzAwMDAwLCAvLyA1IG1pbnV0ZXNcbiAgcmV0cmlldmFsVG9wSzogMTAsXG4gIG1pblF1YWxpdHlTY29yZTogMC43LFxuICBlbmFibGVSZWZsZWN0aW9uOiBmYWxzZSxcbiAgbWF4UmVmbGVjdGlvbkl0ZXJhdGlvbnM6IDIsXG59O1xuXG4vKipcbiAqIFJsbUNvbnRyb2xsZXIgLSBSZWN1cnNpdmUgUmV0cmlldmFsIExhbmd1YWdlIE1vZGVsIENvbnRyb2xsZXJcbiAqXG4gKiBPcmNoZXN0cmF0ZXMgcmV0cmlldmFsLWF1Z21lbnRlZCBnZW5lcmF0aW9uIHdpdGggcmVjdXJzaXZlIHN1Yi1xdWVyeVxuICogZGVjb21wb3NpdGlvbiwgbWVtb3J5IHNlYXJjaCwgYW5kIG9wdGlvbmFsIHNlbGYtcmVmbGVjdGlvbi5cbiAqL1xuZXhwb3J0IGNsYXNzIFJsbUNvbnRyb2xsZXIge1xuICBwcml2YXRlIGNvbmZpZzogUmVxdWlyZWQ8UmxtQ29uZmlnPjtcbiAgcHJpdmF0ZSBjYWNoZTogTWFwPHN0cmluZywgUmxtQ2FjaGVFbnRyeT47XG4gIHByaXZhdGUgZW5naW5lOiBSdXZMTE07XG4gIHByaXZhdGUgbWVtb3J5SWRDb3VudGVyOiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIG5ldyBSTE0gY29udHJvbGxlclxuICAgKlxuICAgKiBAcGFyYW0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAqIEBwYXJhbSBlbmdpbmUgLSBPcHRpb25hbCBSdXZMTE0gZW5naW5lIGluc3RhbmNlIChjcmVhdGVzIG5ldyBpZiBub3QgcHJvdmlkZWQpXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gV2l0aCBkZWZhdWx0IGNvbmZpZ1xuICAgKiBjb25zdCBybG0gPSBuZXcgUmxtQ29udHJvbGxlcigpO1xuICAgKlxuICAgKiAvLyBXaXRoIGN1c3RvbSBjb25maWdcbiAgICogY29uc3QgcmxtID0gbmV3IFJsbUNvbnRyb2xsZXIoe1xuICAgKiAgIG1heERlcHRoOiA1LFxuICAgKiAgIGVuYWJsZVJlZmxlY3Rpb246IHRydWUsXG4gICAqIH0pO1xuICAgKlxuICAgKiAvLyBXaXRoIGV4aXN0aW5nIGVuZ2luZVxuICAgKiBjb25zdCBlbmdpbmUgPSBuZXcgUnV2TExNKHsgbGVhcm5pbmdFbmFibGVkOiB0cnVlIH0pO1xuICAgKiBjb25zdCBybG0gPSBuZXcgUmxtQ29udHJvbGxlcih7fSwgZW5naW5lKTtcbiAgICogYGBgXG4gICAqL1xuICBjb25zdHJ1Y3Rvcihjb25maWc/OiBSbG1Db25maWcsIGVuZ2luZT86IFJ1dkxMTSkge1xuICAgIHRoaXMuY29uZmlnID0geyAuLi5ERUZBVUxUX0NPTkZJRywgLi4uY29uZmlnIH07XG4gICAgdGhpcy5jYWNoZSA9IG5ldyBNYXAoKTtcbiAgICB0aGlzLmVuZ2luZSA9IGVuZ2luZSA/PyBuZXcgUnV2TExNKHsgbGVhcm5pbmdFbmFibGVkOiB0cnVlIH0pO1xuICAgIHRoaXMubWVtb3J5SWRDb3VudGVyID0gMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBRdWVyeSB0aGUgUkxNIHdpdGggcmVjdXJzaXZlIHJldHJpZXZhbFxuICAgKlxuICAgKiBAcGFyYW0gaW5wdXQgLSBUaGUgcXVlcnkgc3RyaW5nXG4gICAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBhbnN3ZXIgd2l0aCBzb3VyY2VzIGFuZCBtZXRhZGF0YVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IGFuc3dlciA9IGF3YWl0IHJsbS5xdWVyeSgnV2hhdCBpcyB0aGUgY2FwaXRhbCBvZiBGcmFuY2U/Jyk7XG4gICAqIGNvbnNvbGUubG9nKGFuc3dlci50ZXh0KTsgLy8gXCJUaGUgY2FwaXRhbCBvZiBGcmFuY2UgaXMgUGFyaXMuLi5cIlxuICAgKiBjb25zb2xlLmxvZyhhbnN3ZXIuY29uZmlkZW5jZSk7IC8vIDAuOTVcbiAgICogY29uc29sZS5sb2coYW5zd2VyLnNvdXJjZXMpOyAvLyBbeyBpZDogJy4uLicsIHRleHQ6ICcuLi4nLCBzaW1pbGFyaXR5U2NvcmU6IDAuOTIgfV1cbiAgICogYGBgXG4gICAqL1xuICBhc3luYyBxdWVyeShpbnB1dDogc3RyaW5nKTogUHJvbWlzZTxSbG1BbnN3ZXI+IHtcbiAgICAvLyBDaGVjayBjYWNoZSBmaXJzdFxuICAgIGlmICh0aGlzLmNvbmZpZy5lbmFibGVDYWNoZSkge1xuICAgICAgY29uc3QgY2FjaGVkID0gdGhpcy5nZXRDYWNoZWQoaW5wdXQpO1xuICAgICAgaWYgKGNhY2hlZCkge1xuICAgICAgICByZXR1cm4geyAuLi5jYWNoZWQsIGNhY2hlZDogdHJ1ZSB9O1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFJldHJpZXZlIHJlbGV2YW50IG1lbW9yeSBzcGFuc1xuICAgIGNvbnN0IHNvdXJjZXMgPSBhd2FpdCB0aGlzLnNlYXJjaE1lbW9yeShpbnB1dCwgdGhpcy5jb25maWcucmV0cmlldmFsVG9wSyk7XG5cbiAgICAvLyBHZW5lcmF0ZSBzdWItcXVlcmllcyBpZiBuZWVkZWQgYW5kIGRlcHRoIGFsbG93c1xuICAgIGNvbnN0IHN1YlF1ZXJpZXMgPSBhd2FpdCB0aGlzLmdlbmVyYXRlU3ViUXVlcmllcyhpbnB1dCwgc291cmNlcywgMCk7XG5cbiAgICAvLyBCdWlsZCBjb250ZXh0IGZyb20gc291cmNlcyBhbmQgc3ViLXF1ZXJ5IGFuc3dlcnNcbiAgICBjb25zdCBjb250ZXh0ID0gdGhpcy5idWlsZENvbnRleHQoc291cmNlcywgc3ViUXVlcmllcyk7XG5cbiAgICAvLyBHZW5lcmF0ZSB0aGUgYW5zd2VyXG4gICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICBjb25zdCByZXNwb25zZSA9IHRoaXMuZW5naW5lLnF1ZXJ5KFxuICAgICAgdGhpcy5idWlsZFByb21wdChpbnB1dCwgY29udGV4dCksXG4gICAgICB0aGlzLmdldEdlbmVyYXRpb25Db25maWcoKVxuICAgICk7XG5cbiAgICAvLyBDYWxjdWxhdGUgdG9rZW4gdXNhZ2UgKGVzdGltYXRlIGlmIG5vdCBwcm92aWRlZCBieSBlbmdpbmUpXG4gICAgY29uc3QgdG9rZW5Vc2FnZSA9IHRoaXMuZXN0aW1hdGVUb2tlblVzYWdlKGlucHV0LCBjb250ZXh0LCByZXNwb25zZS50ZXh0KTtcblxuICAgIC8vIENhbGN1bGF0ZSBxdWFsaXR5IHNjb3JlXG4gICAgY29uc3QgcXVhbGl0eVNjb3JlID0gdGhpcy5jYWxjdWxhdGVRdWFsaXR5U2NvcmUoc291cmNlcywgcmVzcG9uc2UuY29uZmlkZW5jZSk7XG5cbiAgICBsZXQgYW5zd2VyOiBSbG1BbnN3ZXIgPSB7XG4gICAgICB0ZXh0OiByZXNwb25zZS50ZXh0LFxuICAgICAgY29uZmlkZW5jZTogcmVzcG9uc2UuY29uZmlkZW5jZSxcbiAgICAgIHF1YWxpdHlTY29yZSxcbiAgICAgIHNvdXJjZXMsXG4gICAgICBzdWJRdWVyaWVzOiBzdWJRdWVyaWVzLmxlbmd0aCA+IDAgPyBzdWJRdWVyaWVzIDogdW5kZWZpbmVkLFxuICAgICAgdG9rZW5Vc2FnZSxcbiAgICAgIGNhY2hlZDogZmFsc2UsXG4gICAgfTtcblxuICAgIC8vIEFwcGx5IHJlZmxlY3Rpb24gaWYgZW5hYmxlZCBhbmQgcXVhbGl0eSBpcyBiZWxvdyB0aHJlc2hvbGRcbiAgICBpZiAodGhpcy5jb25maWcuZW5hYmxlUmVmbGVjdGlvbiAmJiBxdWFsaXR5U2NvcmUgPCB0aGlzLmNvbmZpZy5taW5RdWFsaXR5U2NvcmUpIHtcbiAgICAgIGFuc3dlciA9IGF3YWl0IHRoaXMuYXBwbHlSZWZsZWN0aW9uKGlucHV0LCBhbnN3ZXIpO1xuICAgIH1cblxuICAgIC8vIENhY2hlIHRoZSByZXN1bHRcbiAgICBpZiAodGhpcy5jb25maWcuZW5hYmxlQ2FjaGUpIHtcbiAgICAgIHRoaXMuc2V0Q2FjaGUoaW5wdXQsIGFuc3dlcik7XG4gICAgfVxuXG4gICAgcmV0dXJuIGFuc3dlcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBRdWVyeSB3aXRoIHN0cmVhbWluZyByZXNwb25zZVxuICAgKlxuICAgKiBAcGFyYW0gaW5wdXQgLSBUaGUgcXVlcnkgc3RyaW5nXG4gICAqIEB5aWVsZHMgU3RyZWFtVG9rZW4gZXZlbnRzIChlaXRoZXIgcGFydGlhbCB0b2tlbnMgb3IgZmluYWwgYW5zd2VyKVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGZvciBhd2FpdCAoY29uc3QgZXZlbnQgb2YgcmxtLnF1ZXJ5U3RyZWFtKCdFeHBsYWluIHF1YW50dW0gY29tcHV0aW5nJykpIHtcbiAgICogICBpZiAoZXZlbnQudHlwZSA9PT0gJ3Rva2VuJykge1xuICAgKiAgICAgLy8gUGFydGlhbCB0b2tlbiByZWNlaXZlZFxuICAgKiAgICAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoZXZlbnQudGV4dCk7XG4gICAqICAgfSBlbHNlIHtcbiAgICogICAgIC8vIEdlbmVyYXRpb24gY29tcGxldGVcbiAgICogICAgIGNvbnNvbGUubG9nKCdcXG5cXG5Tb3VyY2VzOicsIGV2ZW50LmFuc3dlci5zb3VyY2VzLmxlbmd0aCk7XG4gICAqICAgfVxuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgKnF1ZXJ5U3RyZWFtKGlucHV0OiBzdHJpbmcpOiBBc3luY0dlbmVyYXRvcjxTdHJlYW1Ub2tlbj4ge1xuICAgIC8vIENoZWNrIGNhY2hlIGZpcnN0XG4gICAgaWYgKHRoaXMuY29uZmlnLmVuYWJsZUNhY2hlKSB7XG4gICAgICBjb25zdCBjYWNoZWQgPSB0aGlzLmdldENhY2hlZChpbnB1dCk7XG4gICAgICBpZiAoY2FjaGVkKSB7XG4gICAgICAgIC8vIFNpbXVsYXRlIHN0cmVhbWluZyBmb3IgY2FjaGVkIHJlc3BvbnNlXG4gICAgICAgIGNvbnN0IHdvcmRzID0gY2FjaGVkLnRleHQuc3BsaXQoJyAnKTtcbiAgICAgICAgZm9yIChjb25zdCB3b3JkIG9mIHdvcmRzKSB7XG4gICAgICAgICAgeWllbGQgeyB0eXBlOiAndG9rZW4nLCB0ZXh0OiB3b3JkICsgJyAnLCBkb25lOiBmYWxzZSB9O1xuICAgICAgICAgIGF3YWl0IHRoaXMuZGVsYXkoMTApOyAvLyBTbWFsbCBkZWxheSBmb3IgcmVhbGlzdGljIHN0cmVhbWluZ1xuICAgICAgICB9XG4gICAgICAgIHlpZWxkIHsgdHlwZTogJ2RvbmUnLCBhbnN3ZXI6IHsgLi4uY2FjaGVkLCBjYWNoZWQ6IHRydWUgfSwgZG9uZTogdHJ1ZSB9O1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gUmV0cmlldmUgc291cmNlc1xuICAgIGNvbnN0IHNvdXJjZXMgPSBhd2FpdCB0aGlzLnNlYXJjaE1lbW9yeShpbnB1dCwgdGhpcy5jb25maWcucmV0cmlldmFsVG9wSyk7XG4gICAgY29uc3Qgc3ViUXVlcmllcyA9IGF3YWl0IHRoaXMuZ2VuZXJhdGVTdWJRdWVyaWVzKGlucHV0LCBzb3VyY2VzLCAwKTtcbiAgICBjb25zdCBjb250ZXh0ID0gdGhpcy5idWlsZENvbnRleHQoc291cmNlcywgc3ViUXVlcmllcyk7XG5cbiAgICAvLyBHZW5lcmF0ZSB3aXRoIHNpbXVsYXRlZCBzdHJlYW1pbmdcbiAgICBjb25zdCBwcm9tcHQgPSB0aGlzLmJ1aWxkUHJvbXB0KGlucHV0LCBjb250ZXh0KTtcbiAgICBjb25zdCByZXNwb25zZSA9IHRoaXMuZW5naW5lLnF1ZXJ5KHByb21wdCwgdGhpcy5nZXRHZW5lcmF0aW9uQ29uZmlnKCkpO1xuXG4gICAgLy8gU3RyZWFtIHRoZSByZXNwb25zZSB3b3JkIGJ5IHdvcmRcbiAgICBjb25zdCB3b3JkcyA9IHJlc3BvbnNlLnRleHQuc3BsaXQoJyAnKTtcbiAgICBsZXQgc3RyZWFtZWRUZXh0ID0gJyc7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHdvcmRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCB3b3JkID0gd29yZHNbaV07XG4gICAgICBjb25zdCB0ZXh0ID0gaSA8IHdvcmRzLmxlbmd0aCAtIDEgPyB3b3JkICsgJyAnIDogd29yZDtcbiAgICAgIHN0cmVhbWVkVGV4dCArPSB0ZXh0O1xuXG4gICAgICB5aWVsZCB7IHR5cGU6ICd0b2tlbicsIHRleHQsIGRvbmU6IGZhbHNlIH07XG4gICAgICBhd2FpdCB0aGlzLmRlbGF5KDIwKTsgLy8gU2ltdWxhdGUgZ2VuZXJhdGlvbiBsYXRlbmN5XG4gICAgfVxuXG4gICAgY29uc3QgdG9rZW5Vc2FnZSA9IHRoaXMuZXN0aW1hdGVUb2tlblVzYWdlKGlucHV0LCBjb250ZXh0LCBzdHJlYW1lZFRleHQpO1xuICAgIGNvbnN0IHF1YWxpdHlTY29yZSA9IHRoaXMuY2FsY3VsYXRlUXVhbGl0eVNjb3JlKHNvdXJjZXMsIHJlc3BvbnNlLmNvbmZpZGVuY2UpO1xuXG4gICAgY29uc3QgYW5zd2VyOiBSbG1BbnN3ZXIgPSB7XG4gICAgICB0ZXh0OiBzdHJlYW1lZFRleHQsXG4gICAgICBjb25maWRlbmNlOiByZXNwb25zZS5jb25maWRlbmNlLFxuICAgICAgcXVhbGl0eVNjb3JlLFxuICAgICAgc291cmNlcyxcbiAgICAgIHN1YlF1ZXJpZXM6IHN1YlF1ZXJpZXMubGVuZ3RoID4gMCA/IHN1YlF1ZXJpZXMgOiB1bmRlZmluZWQsXG4gICAgICB0b2tlblVzYWdlLFxuICAgICAgY2FjaGVkOiBmYWxzZSxcbiAgICB9O1xuXG4gICAgLy8gQ2FjaGUgdGhlIHJlc3VsdFxuICAgIGlmICh0aGlzLmNvbmZpZy5lbmFibGVDYWNoZSkge1xuICAgICAgdGhpcy5zZXRDYWNoZShpbnB1dCwgYW5zd2VyKTtcbiAgICB9XG5cbiAgICB5aWVsZCB7IHR5cGU6ICdkb25lJywgYW5zd2VyLCBkb25lOiB0cnVlIH07XG4gIH1cblxuICAvKipcbiAgICogQWRkIGNvbnRlbnQgdG8gbWVtb3J5IGZvciByZXRyaWV2YWxcbiAgICpcbiAgICogQHBhcmFtIHRleHQgLSBUaGUgdGV4dCBjb250ZW50IHRvIHN0b3JlXG4gICAqIEBwYXJhbSBtZXRhZGF0YSAtIE9wdGlvbmFsIG1ldGFkYXRhIHRvIGFzc29jaWF0ZSB3aXRoIHRoZSBtZW1vcnlcbiAgICogQHJldHVybnMgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIG1lbW9yeSBzcGFuIElEXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgaWQxID0gYXdhaXQgcmxtLmFkZE1lbW9yeShcbiAgICogICAnVHlwZVNjcmlwdCBpcyBhIHR5cGVkIHN1cGVyc2V0IG9mIEphdmFTY3JpcHQuJyxcbiAgICogICB7IHNvdXJjZTogJ2RvY3VtZW50YXRpb24nLCBjYXRlZ29yeTogJ3Byb2dyYW1taW5nJyB9XG4gICAqICk7XG4gICAqXG4gICAqIGNvbnN0IGlkMiA9IGF3YWl0IHJsbS5hZGRNZW1vcnkoXG4gICAqICAgJ1JlYWN0IGlzIGEgSmF2YVNjcmlwdCBsaWJyYXJ5IGZvciBidWlsZGluZyBVSXMuJ1xuICAgKiApO1xuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIGFkZE1lbW9yeSh0ZXh0OiBzdHJpbmcsIG1ldGFkYXRhPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IG5vZGVJZCA9IHRoaXMuZW5naW5lLmFkZE1lbW9yeSh0ZXh0LCBtZXRhZGF0YSk7XG4gICAgY29uc3QgaWQgPSBgcmxtLW1lbS0ke3RoaXMubWVtb3J5SWRDb3VudGVyKyt9LSR7bm9kZUlkfWA7XG4gICAgcmV0dXJuIGlkO1xuICB9XG5cbiAgLyoqXG4gICAqIFNlYXJjaCBtZW1vcnkgZm9yIHJlbGV2YW50IHNwYW5zXG4gICAqXG4gICAqIEBwYXJhbSBxdWVyeSAtIFRoZSBzZWFyY2ggcXVlcnlcbiAgICogQHBhcmFtIHRvcEsgLSBOdW1iZXIgb2YgcmVzdWx0cyB0byByZXR1cm4gKGRlZmF1bHQ6IGNvbmZpZy5yZXRyaWV2YWxUb3BLKVxuICAgKiBAcmV0dXJucyBQcm9taXNlIHJlc29sdmluZyB0byBhcnJheSBvZiBtZW1vcnkgc3BhbnNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCBzcGFucyA9IGF3YWl0IHJsbS5zZWFyY2hNZW1vcnkoJ0phdmFTY3JpcHQgZnJhbWV3b3JrcycsIDUpO1xuICAgKiBmb3IgKGNvbnN0IHNwYW4gb2Ygc3BhbnMpIHtcbiAgICogICBjb25zb2xlLmxvZyhgWyR7c3Bhbi5zaW1pbGFyaXR5U2NvcmUudG9GaXhlZCgyKX1dICR7c3Bhbi50ZXh0fWApO1xuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgc2VhcmNoTWVtb3J5KHF1ZXJ5OiBzdHJpbmcsIHRvcEs/OiBudW1iZXIpOiBQcm9taXNlPE1lbW9yeVNwYW5bXT4ge1xuICAgIGNvbnN0IGsgPSB0b3BLID8/IHRoaXMuY29uZmlnLnJldHJpZXZhbFRvcEs7XG4gICAgY29uc3QgcmVzdWx0cyA9IHRoaXMuZW5naW5lLnNlYXJjaE1lbW9yeShxdWVyeSwgayk7XG5cbiAgICByZXR1cm4gcmVzdWx0cy5tYXAoKHJlc3VsdCwgaW5kZXgpID0+ICh7XG4gICAgICBpZDogYHJsbS1zcGFuLSR7cmVzdWx0LmlkfS0ke2luZGV4fWAsXG4gICAgICB0ZXh0OiByZXN1bHQuY29udGVudCxcbiAgICAgIHNpbWlsYXJpdHlTY29yZTogcmVzdWx0LnNjb3JlLFxuICAgICAgc291cmNlOiByZXN1bHQubWV0YWRhdGE/LnNvdXJjZSBhcyBzdHJpbmcgfCB1bmRlZmluZWQsXG4gICAgICBtZXRhZGF0YTogcmVzdWx0Lm1ldGFkYXRhLFxuICAgIH0pKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDbGVhciB0aGUgcmVzcG9uc2UgY2FjaGVcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBybG0uY2xlYXJDYWNoZSgpO1xuICAgKiBjb25zb2xlLmxvZygnQ2FjaGUgY2xlYXJlZCcpO1xuICAgKiBgYGBcbiAgICovXG4gIGNsZWFyQ2FjaGUoKTogdm9pZCB7XG4gICAgdGhpcy5jYWNoZS5jbGVhcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBjdXJyZW50IGNhY2hlIHN0YXRpc3RpY3NcbiAgICpcbiAgICogQHJldHVybnMgT2JqZWN0IHdpdGggY2FjaGUgc2l6ZSBhbmQgaGl0IHJhdGUgaW5mb1xuICAgKi9cbiAgZ2V0Q2FjaGVTdGF0cygpOiB7IHNpemU6IG51bWJlcjsgZW50cmllczogbnVtYmVyIH0ge1xuICAgIHJldHVybiB7XG4gICAgICBzaXplOiB0aGlzLmNhY2hlLnNpemUsXG4gICAgICBlbnRyaWVzOiB0aGlzLmNhY2hlLnNpemUsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGUgY29uZmlndXJhdGlvbiBhdCBydW50aW1lXG4gICAqXG4gICAqIEBwYXJhbSBjb25maWcgLSBQYXJ0aWFsIGNvbmZpZ3VyYXRpb24gdG8gbWVyZ2VcbiAgICovXG4gIHVwZGF0ZUNvbmZpZyhjb25maWc6IFBhcnRpYWw8UmxtQ29uZmlnPik6IHZvaWQge1xuICAgIHRoaXMuY29uZmlnID0geyAuLi50aGlzLmNvbmZpZywgLi4uY29uZmlnIH07XG4gIH1cblxuICAvKipcbiAgICogR2V0IGN1cnJlbnQgY29uZmlndXJhdGlvblxuICAgKi9cbiAgZ2V0Q29uZmlnKCk6IFJlcXVpcmVkPFJsbUNvbmZpZz4ge1xuICAgIHJldHVybiB7IC4uLnRoaXMuY29uZmlnIH07XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBQcml2YXRlIE1ldGhvZHNcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICAvKipcbiAgICogR2VuZXJhdGUgc3ViLXF1ZXJpZXMgZm9yIGNvbXBsZXggcXVlc3Rpb25zXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGdlbmVyYXRlU3ViUXVlcmllcyhcbiAgICBxdWVyeTogc3RyaW5nLFxuICAgIHNvdXJjZXM6IE1lbW9yeVNwYW5bXSxcbiAgICBkZXB0aDogbnVtYmVyXG4gICk6IFByb21pc2U8U3ViUXVlcnlbXT4ge1xuICAgIGlmIChkZXB0aCA+PSB0aGlzLmNvbmZpZy5tYXhEZXB0aCkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIC8vIFNpbXBsZSBoZXVyaXN0aWM6IGdlbmVyYXRlIHN1Yi1xdWVyaWVzIGZvciBxdWVzdGlvbnMgd2l0aCBtdWx0aXBsZSBwYXJ0c1xuICAgIGNvbnN0IHN1YlF1ZXJpZXM6IFN1YlF1ZXJ5W10gPSBbXTtcbiAgICBjb25zdCBwYXJ0cyA9IHRoaXMuZGVjb21wb3NlUXVlcnkocXVlcnkpO1xuXG4gICAgZm9yIChjb25zdCBwYXJ0IG9mIHBhcnRzLnNsaWNlKDAsIHRoaXMuY29uZmlnLm1heFN1YlF1ZXJpZXMpKSB7XG4gICAgICBpZiAocGFydC50cmltKCkubGVuZ3RoIDwgMTApIGNvbnRpbnVlO1xuXG4gICAgICAvLyBTZWFyY2ggZm9yIHN1Yi1xdWVyeSBzcGVjaWZpYyBzb3VyY2VzXG4gICAgICBjb25zdCBzdWJTb3VyY2VzID0gYXdhaXQgdGhpcy5zZWFyY2hNZW1vcnkocGFydCwgTWF0aC5jZWlsKHRoaXMuY29uZmlnLnJldHJpZXZhbFRvcEsgLyAyKSk7XG4gICAgICBjb25zdCBjb250ZXh0ID0gdGhpcy5idWlsZENvbnRleHQoc3ViU291cmNlcywgW10pO1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSB0aGlzLmVuZ2luZS5xdWVyeShcbiAgICAgICAgdGhpcy5idWlsZFByb21wdChwYXJ0LCBjb250ZXh0KSxcbiAgICAgICAgeyAuLi50aGlzLmdldEdlbmVyYXRpb25Db25maWcoKSwgbWF4VG9rZW5zOiAyNTYgfVxuICAgICAgKTtcblxuICAgICAgc3ViUXVlcmllcy5wdXNoKHtcbiAgICAgICAgcXVlcnk6IHBhcnQsXG4gICAgICAgIGFuc3dlcjogcmVzcG9uc2UudGV4dCxcbiAgICAgICAgZGVwdGg6IGRlcHRoICsgMSxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiBzdWJRdWVyaWVzO1xuICB9XG5cbiAgLyoqXG4gICAqIERlY29tcG9zZSBhIGNvbXBsZXggcXVlcnkgaW50byBzaW1wbGVyIHBhcnRzXG4gICAqL1xuICBwcml2YXRlIGRlY29tcG9zZVF1ZXJ5KHF1ZXJ5OiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gICAgLy8gU3BsaXQgb24gY29tbW9uIGNvbmp1bmN0aW9ucyBhbmQgcXVlc3Rpb24gbWFya2Vyc1xuICAgIGNvbnN0IHBhcnRzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgLy8gQ2hlY2sgZm9yIG11bHRpLXBhcnQgcXVlc3Rpb25zXG4gICAgY29uc3QgY29uanVuY3Rpb25zID0gWycgYW5kICcsICcgb3IgJywgJy4gJywgJz8gJywgJzsgJ107XG4gICAgbGV0IGN1cnJlbnQgPSBxdWVyeTtcblxuICAgIGZvciAoY29uc3QgY29uaiBvZiBjb25qdW5jdGlvbnMpIHtcbiAgICAgIGlmIChjdXJyZW50LmluY2x1ZGVzKGNvbmopKSB7XG4gICAgICAgIGNvbnN0IHNwbGl0ID0gY3VycmVudC5zcGxpdChjb25qKTtcbiAgICAgICAgcGFydHMucHVzaCguLi5zcGxpdC5maWx0ZXIocCA9PiBwLnRyaW0oKS5sZW5ndGggPiAxMCkpO1xuICAgICAgICBjdXJyZW50ID0gJyc7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIElmIG5vIGRlY29tcG9zaXRpb24gaGFwcGVuZWQsIHJldHVybiBvcmlnaW5hbFxuICAgIGlmIChwYXJ0cy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBbcXVlcnldO1xuICAgIH1cblxuICAgIHJldHVybiBwYXJ0cztcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZCBjb250ZXh0IHN0cmluZyBmcm9tIHNvdXJjZXMgYW5kIHN1Yi1xdWVyaWVzXG4gICAqL1xuICBwcml2YXRlIGJ1aWxkQ29udGV4dChzb3VyY2VzOiBNZW1vcnlTcGFuW10sIHN1YlF1ZXJpZXM6IFN1YlF1ZXJ5W10pOiBzdHJpbmcge1xuICAgIGNvbnN0IHBhcnRzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgLy8gQWRkIHNvdXJjZXNcbiAgICBpZiAoc291cmNlcy5sZW5ndGggPiAwKSB7XG4gICAgICBwYXJ0cy5wdXNoKCdSZWxldmFudCBjb250ZXh0OicpO1xuICAgICAgZm9yIChjb25zdCBzb3VyY2Ugb2Ygc291cmNlcykge1xuICAgICAgICBwYXJ0cy5wdXNoKGAtICR7c291cmNlLnRleHR9YCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQWRkIHN1Yi1xdWVyeSBhbnN3ZXJzXG4gICAgaWYgKHN1YlF1ZXJpZXMubGVuZ3RoID4gMCkge1xuICAgICAgcGFydHMucHVzaCgnXFxuUmVsYXRlZCBpbmZvcm1hdGlvbjonKTtcbiAgICAgIGZvciAoY29uc3Qgc3Egb2Ygc3ViUXVlcmllcykge1xuICAgICAgICBwYXJ0cy5wdXNoKGBROiAke3NxLnF1ZXJ5fWApO1xuICAgICAgICBwYXJ0cy5wdXNoKGBBOiAke3NxLmFuc3dlcn1gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcGFydHMuam9pbignXFxuJyk7XG4gIH1cblxuICAvKipcbiAgICogQnVpbGQgdGhlIGZ1bGwgcHJvbXB0IHdpdGggY29udGV4dFxuICAgKi9cbiAgcHJpdmF0ZSBidWlsZFByb21wdChxdWVyeTogc3RyaW5nLCBjb250ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGlmIChjb250ZXh0LnRyaW0oKS5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBxdWVyeTtcbiAgICB9XG5cbiAgICByZXR1cm4gYCR7Y29udGV4dH1cXG5cXG5CYXNlZCBvbiB0aGUgYWJvdmUgY29udGV4dCwgYW5zd2VyIHRoZSBmb2xsb3dpbmcgcXVlc3Rpb246XFxuJHtxdWVyeX1gO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBnZW5lcmF0aW9uIGNvbmZpZyBiYXNlZCBvbiBSTE0gc2V0dGluZ3NcbiAgICovXG4gIHByaXZhdGUgZ2V0R2VuZXJhdGlvbkNvbmZpZygpOiBHZW5lcmF0aW9uQ29uZmlnIHtcbiAgICByZXR1cm4ge1xuICAgICAgbWF4VG9rZW5zOiBNYXRoLm1pbih0aGlzLmNvbmZpZy50b2tlbkJ1ZGdldCwgMjA0OCksXG4gICAgICB0ZW1wZXJhdHVyZTogMC43LFxuICAgICAgdG9wUDogMC45LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogRXN0aW1hdGUgdG9rZW4gdXNhZ2VcbiAgICovXG4gIHByaXZhdGUgZXN0aW1hdGVUb2tlblVzYWdlKHF1ZXJ5OiBzdHJpbmcsIGNvbnRleHQ6IHN0cmluZywgcmVzcG9uc2U6IHN0cmluZyk6IFRva2VuVXNhZ2Uge1xuICAgIC8vIFJvdWdoIGVzdGltYXRpb246IH40IGNoYXJhY3RlcnMgcGVyIHRva2VuXG4gICAgY29uc3QgcHJvbXB0VG9rZW5zID0gTWF0aC5jZWlsKChxdWVyeS5sZW5ndGggKyBjb250ZXh0Lmxlbmd0aCkgLyA0KTtcbiAgICBjb25zdCBjb21wbGV0aW9uVG9rZW5zID0gTWF0aC5jZWlsKHJlc3BvbnNlLmxlbmd0aCAvIDQpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHByb21wdDogcHJvbXB0VG9rZW5zLFxuICAgICAgY29tcGxldGlvbjogY29tcGxldGlvblRva2VucyxcbiAgICAgIHRvdGFsOiBwcm9tcHRUb2tlbnMgKyBjb21wbGV0aW9uVG9rZW5zLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQ2FsY3VsYXRlIHF1YWxpdHkgc2NvcmUgYmFzZWQgb24gc291cmNlcyBhbmQgY29uZmlkZW5jZVxuICAgKi9cbiAgcHJpdmF0ZSBjYWxjdWxhdGVRdWFsaXR5U2NvcmUoc291cmNlczogTWVtb3J5U3BhbltdLCBjb25maWRlbmNlOiBudW1iZXIpOiBudW1iZXIge1xuICAgIGlmIChzb3VyY2VzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIGNvbmZpZGVuY2UgKiAwLjU7IC8vIFBlbmFsaXplIGFuc3dlcnMgd2l0aG91dCBzb3VyY2VzXG4gICAgfVxuXG4gICAgLy8gQXZlcmFnZSBzb3VyY2Ugc2ltaWxhcml0eVxuICAgIGNvbnN0IGF2Z1NpbWlsYXJpdHkgPSBzb3VyY2VzLnJlZHVjZSgoc3VtLCBzKSA9PiBzdW0gKyBzLnNpbWlsYXJpdHlTY29yZSwgMCkgLyBzb3VyY2VzLmxlbmd0aDtcblxuICAgIC8vIFdlaWdodGVkIGNvbWJpbmF0aW9uXG4gICAgcmV0dXJuIGNvbmZpZGVuY2UgKiAwLjYgKyBhdmdTaW1pbGFyaXR5ICogMC40O1xuICB9XG5cbiAgLyoqXG4gICAqIEFwcGx5IHNlbGYtcmVmbGVjdGlvbiB0byBpbXByb3ZlIGFuc3dlclxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBhcHBseVJlZmxlY3Rpb24oXG4gICAgcXVlcnk6IHN0cmluZyxcbiAgICBhbnN3ZXI6IFJsbUFuc3dlclxuICApOiBQcm9taXNlPFJsbUFuc3dlcj4ge1xuICAgIGxldCBjdXJyZW50QW5zd2VyID0gYW5zd2VyO1xuICAgIGxldCBpdGVyYXRpb25zID0gMDtcblxuICAgIHdoaWxlIChcbiAgICAgIGl0ZXJhdGlvbnMgPCB0aGlzLmNvbmZpZy5tYXhSZWZsZWN0aW9uSXRlcmF0aW9ucyAmJlxuICAgICAgY3VycmVudEFuc3dlci5xdWFsaXR5U2NvcmUgPCB0aGlzLmNvbmZpZy5taW5RdWFsaXR5U2NvcmVcbiAgICApIHtcbiAgICAgIGl0ZXJhdGlvbnMrKztcblxuICAgICAgLy8gR2VuZXJhdGUgY3JpdGlxdWVcbiAgICAgIGNvbnN0IGNyaXRpcXVlUHJvbXB0ID0gYEV2YWx1YXRlIHRoaXMgYW5zd2VyIGZvciBhY2N1cmFjeSBhbmQgY29tcGxldGVuZXNzOlxuUXVlc3Rpb246ICR7cXVlcnl9XG5BbnN3ZXI6ICR7Y3VycmVudEFuc3dlci50ZXh0fVxuXG5Qcm92aWRlIGEgYnJpZWYgY3JpdGlxdWUgYW5kIHN1Z2dlc3QgaW1wcm92ZW1lbnRzLmA7XG5cbiAgICAgIGNvbnN0IGNyaXRpcXVlUmVzcG9uc2UgPSB0aGlzLmVuZ2luZS5xdWVyeShjcml0aXF1ZVByb21wdCwge1xuICAgICAgICBtYXhUb2tlbnM6IDI1NixcbiAgICAgICAgdGVtcGVyYXR1cmU6IDAuNSxcbiAgICAgIH0pO1xuXG4gICAgICAvLyBHZW5lcmF0ZSBpbXByb3ZlZCBhbnN3ZXJcbiAgICAgIGNvbnN0IGltcHJvdmVQcm9tcHQgPSBgQmFzZWQgb24gdGhpcyBmZWVkYmFjazogXCIke2NyaXRpcXVlUmVzcG9uc2UudGV4dH1cIlxuXG5JbXByb3ZlIHRoaXMgYW5zd2VyOlxuUXVlc3Rpb246ICR7cXVlcnl9XG5PcmlnaW5hbDogJHtjdXJyZW50QW5zd2VyLnRleHR9XG5cblByb3ZpZGUgYW4gaW1wcm92ZWQgYW5zd2VyOmA7XG5cbiAgICAgIGNvbnN0IGltcHJvdmVkUmVzcG9uc2UgPSB0aGlzLmVuZ2luZS5xdWVyeShpbXByb3ZlUHJvbXB0LCB0aGlzLmdldEdlbmVyYXRpb25Db25maWcoKSk7XG5cbiAgICAgIC8vIFVwZGF0ZSBhbnN3ZXIgd2l0aCByZWZsZWN0aW9uIGltcHJvdmVtZW50c1xuICAgICAgY29uc3QgbmV3UXVhbGl0eVNjb3JlID0gTWF0aC5taW4oXG4gICAgICAgIDEuMCxcbiAgICAgICAgY3VycmVudEFuc3dlci5xdWFsaXR5U2NvcmUgKyAwLjEgKiBpdGVyYXRpb25zXG4gICAgICApO1xuXG4gICAgICBjdXJyZW50QW5zd2VyID0ge1xuICAgICAgICAuLi5jdXJyZW50QW5zd2VyLFxuICAgICAgICB0ZXh0OiBpbXByb3ZlZFJlc3BvbnNlLnRleHQsXG4gICAgICAgIGNvbmZpZGVuY2U6IE1hdGgubWF4KGN1cnJlbnRBbnN3ZXIuY29uZmlkZW5jZSwgaW1wcm92ZWRSZXNwb25zZS5jb25maWRlbmNlKSxcbiAgICAgICAgcXVhbGl0eVNjb3JlOiBuZXdRdWFsaXR5U2NvcmUsXG4gICAgICAgIHRva2VuVXNhZ2U6IHtcbiAgICAgICAgICBwcm9tcHQ6IGN1cnJlbnRBbnN3ZXIudG9rZW5Vc2FnZS5wcm9tcHQgKyAxMDAsIC8vIEFwcHJveGltYXRlIGFkZGl0aW9uYWwgdG9rZW5zXG4gICAgICAgICAgY29tcGxldGlvbjogY3VycmVudEFuc3dlci50b2tlblVzYWdlLmNvbXBsZXRpb24gKyAxMDAsXG4gICAgICAgICAgdG90YWw6IGN1cnJlbnRBbnN3ZXIudG9rZW5Vc2FnZS50b3RhbCArIDIwMCxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIGN1cnJlbnRBbnN3ZXI7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGNhY2hlZCBhbnN3ZXIgaWYgdmFsaWRcbiAgICovXG4gIHByaXZhdGUgZ2V0Q2FjaGVkKHF1ZXJ5OiBzdHJpbmcpOiBSbG1BbnN3ZXIgfCBudWxsIHtcbiAgICBjb25zdCBoYXNoID0gdGhpcy5oYXNoUXVlcnkocXVlcnkpO1xuICAgIGNvbnN0IGVudHJ5ID0gdGhpcy5jYWNoZS5nZXQoaGFzaCk7XG5cbiAgICBpZiAoIWVudHJ5KSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICAvLyBDaGVjayBUVExcbiAgICBpZiAoRGF0ZS5ub3coKSAtIGVudHJ5LnRpbWVzdGFtcCA+IHRoaXMuY29uZmlnLmNhY2hlVHRsKSB7XG4gICAgICB0aGlzLmNhY2hlLmRlbGV0ZShoYXNoKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHJldHVybiBlbnRyeS5hbnN3ZXI7XG4gIH1cblxuICAvKipcbiAgICogU2V0IGNhY2hlIGVudHJ5XG4gICAqL1xuICBwcml2YXRlIHNldENhY2hlKHF1ZXJ5OiBzdHJpbmcsIGFuc3dlcjogUmxtQW5zd2VyKTogdm9pZCB7XG4gICAgY29uc3QgaGFzaCA9IHRoaXMuaGFzaFF1ZXJ5KHF1ZXJ5KTtcbiAgICB0aGlzLmNhY2hlLnNldChoYXNoLCB7XG4gICAgICBhbnN3ZXIsXG4gICAgICB0aW1lc3RhbXA6IERhdGUubm93KCksXG4gICAgICBxdWVyeUhhc2g6IGhhc2gsXG4gICAgfSk7XG5cbiAgICAvLyBQcnVuZSBvbGQgZW50cmllcyBpZiBjYWNoZSBnZXRzIHRvbyBsYXJnZVxuICAgIGlmICh0aGlzLmNhY2hlLnNpemUgPiAxMDAwKSB7XG4gICAgICB0aGlzLnBydW5lQ2FjaGUoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2ltcGxlIGhhc2ggZnVuY3Rpb24gZm9yIGNhY2hlIGtleXNcbiAgICovXG4gIHByaXZhdGUgaGFzaFF1ZXJ5KHF1ZXJ5OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGxldCBoYXNoID0gMDtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHF1ZXJ5Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBjaGFyID0gcXVlcnkuY2hhckNvZGVBdChpKTtcbiAgICAgIGhhc2ggPSAoKGhhc2ggPDwgNSkgLSBoYXNoKSArIGNoYXI7XG4gICAgICBoYXNoID0gaGFzaCAmIGhhc2g7IC8vIENvbnZlcnQgdG8gMzItYml0IGludGVnZXJcbiAgICB9XG4gICAgcmV0dXJuIGBybG0tY2FjaGUtJHtoYXNoLnRvU3RyaW5nKDE2KX1gO1xuICB9XG5cbiAgLyoqXG4gICAqIFBydW5lIGV4cGlyZWQgY2FjaGUgZW50cmllc1xuICAgKi9cbiAgcHJpdmF0ZSBwcnVuZUNhY2hlKCk6IHZvaWQge1xuICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gICAgY29uc3QgdG9EZWxldGU6IHN0cmluZ1tdID0gW107XG5cbiAgICBmb3IgKGNvbnN0IFtrZXksIGVudHJ5XSBvZiB0aGlzLmNhY2hlLmVudHJpZXMoKSkge1xuICAgICAgaWYgKG5vdyAtIGVudHJ5LnRpbWVzdGFtcCA+IHRoaXMuY29uZmlnLmNhY2hlVHRsKSB7XG4gICAgICAgIHRvRGVsZXRlLnB1c2goa2V5KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBEZWxldGUgb2xkZXN0IGVudHJpZXMgaWYgc3RpbGwgdG9vIGxhcmdlXG4gICAgaWYgKHRoaXMuY2FjaGUuc2l6ZSAtIHRvRGVsZXRlLmxlbmd0aCA+IDgwMCkge1xuICAgICAgY29uc3QgZW50cmllcyA9IEFycmF5LmZyb20odGhpcy5jYWNoZS5lbnRyaWVzKCkpXG4gICAgICAgIC5zb3J0KChhLCBiKSA9PiBhWzFdLnRpbWVzdGFtcCAtIGJbMV0udGltZXN0YW1wKTtcblxuICAgICAgY29uc3QgZGVsZXRlQ291bnQgPSBlbnRyaWVzLmxlbmd0aCAtIDUwMDtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZGVsZXRlQ291bnQ7IGkrKykge1xuICAgICAgICB0b0RlbGV0ZS5wdXNoKGVudHJpZXNbaV1bMF0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZvciAoY29uc3Qga2V5IG9mIHRvRGVsZXRlKSB7XG4gICAgICB0aGlzLmNhY2hlLmRlbGV0ZShrZXkpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBVdGlsaXR5IGRlbGF5IGZ1bmN0aW9uIGZvciBzdHJlYW1pbmcgc2ltdWxhdGlvblxuICAgKi9cbiAgcHJpdmF0ZSBkZWxheShtczogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKHJlc29sdmUgPT4gc2V0VGltZW91dChyZXNvbHZlLCBtcykpO1xuICB9XG59XG4iXX0=