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