@ruvector/ruvllm 4.0.1 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/README.md +446 -160
  2. package/bin/cli.js +1066 -0
  3. package/bin/gpu-delegate.js +67 -0
  4. package/bin/ruvllm-adapters.js +5 -0
  5. package/bin/ruvllm-gpu-loop.js +5 -0
  6. package/bin/serve.js +265 -0
  7. package/dist/cjs/benchmarks/embedding-benchmark.d.ts +102 -0
  8. package/dist/cjs/benchmarks/embedding-benchmark.d.ts.map +1 -0
  9. package/dist/cjs/benchmarks/embedding-benchmark.js +436 -0
  10. package/dist/cjs/benchmarks/index.d.ts +34 -0
  11. package/dist/cjs/benchmarks/index.d.ts.map +1 -0
  12. package/dist/cjs/benchmarks/index.js +132 -0
  13. package/dist/cjs/benchmarks/model-comparison.d.ts +71 -0
  14. package/dist/cjs/benchmarks/model-comparison.d.ts.map +1 -0
  15. package/dist/cjs/benchmarks/model-comparison.js +476 -0
  16. package/dist/cjs/benchmarks/routing-benchmark.d.ts +70 -0
  17. package/dist/cjs/benchmarks/routing-benchmark.d.ts.map +1 -0
  18. package/dist/cjs/benchmarks/routing-benchmark.js +289 -0
  19. package/dist/cjs/contrastive.d.ts +229 -0
  20. package/dist/cjs/contrastive.d.ts.map +1 -0
  21. package/dist/cjs/contrastive.js +589 -0
  22. package/dist/cjs/engine.d.ts +160 -0
  23. package/dist/cjs/engine.d.ts.map +1 -0
  24. package/dist/cjs/engine.js +552 -0
  25. package/dist/cjs/export.d.ts +182 -0
  26. package/dist/cjs/export.d.ts.map +1 -0
  27. package/dist/cjs/export.js +422 -0
  28. package/dist/cjs/federated.d.ts +233 -0
  29. package/dist/cjs/federated.d.ts.map +1 -0
  30. package/dist/cjs/federated.js +525 -0
  31. package/dist/cjs/index.d.ts +68 -0
  32. package/dist/cjs/index.d.ts.map +1 -0
  33. package/dist/cjs/index.js +104 -0
  34. package/dist/cjs/intelligence.d.ts +136 -0
  35. package/dist/cjs/intelligence.d.ts.map +1 -0
  36. package/dist/cjs/intelligence.js +226 -0
  37. package/dist/cjs/lora.d.ts +251 -0
  38. package/dist/cjs/lora.d.ts.map +1 -0
  39. package/dist/cjs/lora.js +509 -0
  40. package/dist/cjs/models.d.ts +129 -0
  41. package/dist/cjs/models.d.ts.map +1 -0
  42. package/dist/cjs/models.js +323 -0
  43. package/dist/cjs/native.d.ts +140 -0
  44. package/dist/cjs/native.d.ts.map +1 -0
  45. package/dist/cjs/native.js +98 -0
  46. package/dist/cjs/session.d.ts +80 -0
  47. package/dist/cjs/session.d.ts.map +1 -0
  48. package/dist/cjs/session.js +203 -0
  49. package/dist/cjs/simd.d.ts +90 -0
  50. package/dist/cjs/simd.d.ts.map +1 -0
  51. package/dist/cjs/simd.js +209 -0
  52. package/dist/cjs/sona.d.ts +223 -0
  53. package/dist/cjs/sona.d.ts.map +1 -0
  54. package/dist/cjs/sona.js +562 -0
  55. package/dist/cjs/streaming.d.ts +55 -0
  56. package/dist/cjs/streaming.d.ts.map +1 -0
  57. package/dist/cjs/streaming.js +131 -0
  58. package/dist/cjs/training.d.ts +312 -0
  59. package/dist/cjs/training.d.ts.map +1 -0
  60. package/dist/cjs/training.js +610 -0
  61. package/dist/cjs/types.d.ts +696 -0
  62. package/dist/cjs/types.d.ts.map +1 -0
  63. package/dist/cjs/types.js +6 -0
  64. package/dist/esm/benchmarks/embedding-benchmark.d.ts +102 -0
  65. package/dist/esm/benchmarks/embedding-benchmark.d.ts.map +1 -0
  66. package/dist/esm/benchmarks/embedding-benchmark.js +427 -0
  67. package/dist/esm/benchmarks/index.d.ts +34 -0
  68. package/dist/esm/benchmarks/index.d.ts.map +1 -0
  69. package/dist/esm/benchmarks/index.js +110 -0
  70. package/dist/esm/benchmarks/model-comparison.d.ts +71 -0
  71. package/dist/esm/benchmarks/model-comparison.d.ts.map +1 -0
  72. package/dist/esm/benchmarks/model-comparison.js +434 -0
  73. package/dist/esm/benchmarks/routing-benchmark.d.ts +70 -0
  74. package/dist/esm/benchmarks/routing-benchmark.d.ts.map +1 -0
  75. package/dist/esm/benchmarks/routing-benchmark.js +283 -0
  76. package/dist/esm/contrastive.d.ts +229 -0
  77. package/dist/esm/contrastive.d.ts.map +1 -0
  78. package/dist/esm/contrastive.js +578 -0
  79. package/dist/esm/engine.d.ts +160 -0
  80. package/dist/esm/engine.d.ts.map +1 -0
  81. package/dist/esm/engine.js +548 -0
  82. package/dist/esm/export.d.ts +182 -0
  83. package/dist/esm/export.d.ts.map +1 -0
  84. package/dist/esm/export.js +414 -0
  85. package/dist/esm/federated.d.ts +233 -0
  86. package/dist/esm/federated.d.ts.map +1 -0
  87. package/dist/esm/federated.js +520 -0
  88. package/dist/esm/index.d.ts +68 -0
  89. package/dist/esm/index.d.ts.map +1 -0
  90. package/dist/esm/index.js +84 -0
  91. package/dist/esm/intelligence.d.ts +136 -0
  92. package/dist/esm/intelligence.d.ts.map +1 -0
  93. package/dist/esm/intelligence.js +188 -0
  94. package/dist/esm/lora.d.ts +251 -0
  95. package/dist/esm/lora.d.ts.map +1 -0
  96. package/dist/esm/lora.js +504 -0
  97. package/dist/esm/models.d.ts +129 -0
  98. package/dist/esm/models.d.ts.map +1 -0
  99. package/dist/esm/models.js +282 -0
  100. package/dist/esm/native.d.ts +140 -0
  101. package/dist/esm/native.d.ts.map +1 -0
  102. package/dist/esm/native.js +100 -0
  103. package/dist/esm/session.d.ts +80 -0
  104. package/dist/esm/session.d.ts.map +1 -0
  105. package/dist/esm/session.js +199 -0
  106. package/dist/esm/simd.d.ts +90 -0
  107. package/dist/esm/simd.d.ts.map +1 -0
  108. package/dist/esm/simd.js +205 -0
  109. package/dist/esm/sona.d.ts +223 -0
  110. package/dist/esm/sona.d.ts.map +1 -0
  111. package/dist/esm/sona.js +556 -0
  112. package/dist/esm/streaming.d.ts +55 -0
  113. package/dist/esm/streaming.d.ts.map +1 -0
  114. package/dist/esm/streaming.js +126 -0
  115. package/dist/esm/training.d.ts +312 -0
  116. package/dist/esm/training.d.ts.map +1 -0
  117. package/dist/esm/training.js +603 -0
  118. package/dist/esm/types.d.ts +696 -0
  119. package/dist/esm/types.d.ts.map +1 -0
  120. package/dist/esm/types.js +5 -0
  121. package/gpu/_load.cjs +38 -0
  122. package/gpu/_load.mjs +33 -0
  123. package/gpu/adapters.cjs +3 -0
  124. package/gpu/adapters.mjs +5 -0
  125. package/gpu/engine.cjs +3 -0
  126. package/gpu/engine.mjs +5 -0
  127. package/gpu/fixture.cjs +3 -0
  128. package/gpu/fixture.mjs +5 -0
  129. package/gpu/gpu-host.cjs +3 -0
  130. package/gpu/gpu-host.mjs +5 -0
  131. package/gpu/gpu-loop.cjs +3 -0
  132. package/gpu/gpu-loop.mjs +5 -0
  133. package/gpu/gpu-spool-adapter.cjs +3 -0
  134. package/gpu/gpu-spool-adapter.mjs +5 -0
  135. package/gpu/vast-host-adapter.cjs +3 -0
  136. package/gpu/vast-host-adapter.mjs +5 -0
  137. package/package.json +159 -49
  138. package/scripts/ensemble-model-compare.js +287 -0
  139. package/scripts/fix-esm-extensions.mjs +220 -0
  140. package/scripts/huggingface/README.md +537 -0
  141. package/scripts/huggingface/publish.sh +112 -0
  142. package/scripts/hybrid-model-compare.js +373 -0
  143. package/scripts/improved-model-compare.js +288 -0
  144. package/scripts/optimized-model-compare.js +364 -0
  145. package/scripts/real-model-compare.js +280 -0
  146. package/scripts/smoke-esm.mjs +82 -0
  147. package/scripts/training/agentic-flow-capabilities.json +329 -0
  148. package/scripts/training/claude-code-synth.js +505 -0
  149. package/scripts/training/claude-flow-capabilities.json +1322 -0
  150. package/scripts/training/claude-hard-negatives.js +222 -0
  151. package/scripts/training/contrastive-finetune.js +517 -0
  152. package/scripts/training/ecosystem-triplets.jsonl +1467 -0
  153. package/scripts/training/generate-ecosystem-triplets.js +1324 -0
  154. package/scripts/training/routing-dataset.js +634 -0
  155. package/scripts/training/ruvector-capabilities.json +798 -0
  156. package/scripts/training/validate-ecosystem.js +381 -0
  157. package/scripts/training/validation-results.json +23 -0
  158. package/GPU-LOOP.md +0 -229
  159. package/LICENSE +0 -201
  160. package/NOTICE +0 -9
  161. package/examples/gpu-loop.example.json +0 -26
  162. package/src/adapters-cli.mjs +0 -23
  163. package/src/adapters.mjs +0 -91
  164. package/src/cli.mjs +0 -30
  165. package/src/engine.mjs +0 -238
  166. package/src/fixture.mjs +0 -38
  167. package/src/gpu-host.mjs +0 -47
  168. package/src/gpu-loop-cli.mjs +0 -67
  169. package/src/gpu-loop.mjs +0 -184
  170. package/src/gpu-spool-adapter.mjs +0 -80
  171. package/src/vast-host-adapter.mjs +0 -274
@@ -0,0 +1,548 @@
1
+ /**
2
+ * RuvLLM Engine - Main orchestrator for self-learning LLM
3
+ */
4
+ import { getNativeModule, } from './native.js';
5
+ /**
6
+ * Convert JS config to native config format
7
+ */
8
+ function toNativeConfig(config) {
9
+ if (!config)
10
+ return undefined;
11
+ return {
12
+ embedding_dim: config.embeddingDim,
13
+ router_hidden_dim: config.routerHiddenDim,
14
+ hnsw_m: config.hnswM,
15
+ hnsw_ef_construction: config.hnswEfConstruction,
16
+ hnsw_ef_search: config.hnswEfSearch,
17
+ learning_enabled: config.learningEnabled,
18
+ quality_threshold: config.qualityThreshold,
19
+ ewc_lambda: config.ewcLambda,
20
+ };
21
+ }
22
+ /**
23
+ * Convert JS generation config to native format
24
+ */
25
+ function toNativeGenConfig(config) {
26
+ if (!config)
27
+ return undefined;
28
+ // camelCase: napi-rs ignores snake_case keys on `#[napi(object)]` inputs.
29
+ return {
30
+ maxTokens: config.maxTokens,
31
+ temperature: config.temperature,
32
+ topP: config.topP,
33
+ topK: config.topK,
34
+ repetitionPenalty: config.repetitionPenalty,
35
+ stopSequences: config.stopSequences,
36
+ seed: config.seed,
37
+ };
38
+ }
39
+ function toGenerationResult(r) {
40
+ return {
41
+ text: r.text,
42
+ promptTokens: r.promptTokens,
43
+ completionTokens: r.completionTokens,
44
+ finishReason: r.finishReason,
45
+ };
46
+ }
47
+ function toModelInfo(i) {
48
+ return {
49
+ name: i.name,
50
+ architecture: i.architecture,
51
+ numParameters: i.numParameters,
52
+ vocabSize: i.vocabSize,
53
+ hiddenSize: i.hiddenSize,
54
+ numLayers: i.numLayers,
55
+ maxContextLength: i.maxContextLength,
56
+ quantization: i.quantization ?? null,
57
+ memoryUsageBytes: i.memoryUsageBytes,
58
+ chatTemplate: i.chatTemplate ?? null,
59
+ };
60
+ }
61
+ const warned = new Set();
62
+ /** Warn once per process (or throw when `strict`). */
63
+ function notice(code, message, strict) {
64
+ if (strict)
65
+ throw codedError(code, message);
66
+ if (warned.has(code))
67
+ return;
68
+ warned.add(code);
69
+ const g = globalThis;
70
+ if (typeof g.process?.emitWarning === 'function')
71
+ g.process.emitWarning(message, { code });
72
+ else
73
+ g.console?.warn?.(`${code}: ${message}`);
74
+ }
75
+ /** An Error whose message starts with, and whose `code` is, `code`. */
76
+ function codedError(code, message) {
77
+ const err = new Error(`${code}: ${message}`);
78
+ err.code = code;
79
+ return err;
80
+ }
81
+ /**
82
+ * Call into the native engine, giving its errors the same `code` as the
83
+ * wrapper's own: native messages start with `RUVLLM_<CODE>:`, but napi-rs
84
+ * sets `code` to a generic status such as `GenericFailure`.
85
+ */
86
+ function callNative(f) {
87
+ try {
88
+ return f();
89
+ }
90
+ catch (e) {
91
+ const match = /^(RUVLLM_[A-Z_]+):/.exec(e instanceof Error ? e.message : '');
92
+ if (match)
93
+ e.code = match[1];
94
+ throw e;
95
+ }
96
+ }
97
+ function platformKey() {
98
+ const p = globalThis.process;
99
+ return `${p?.platform ?? 'unknown'}-${p?.arch ?? 'unknown'}`;
100
+ }
101
+ function envAllowsPlaceholder() {
102
+ const p = globalThis.process;
103
+ return p?.env?.RUVLLM_ALLOW_MOCK === '1';
104
+ }
105
+ /** Returned by generate()/query() only with `allowPlaceholder` / `RUVLLM_ALLOW_MOCK=1`. */
106
+ export const PLACEHOLDER_TEXT = '[RuvLLM placeholder: no language model is loaded; this text is not model output]';
107
+ /**
108
+ * RuvLLM - Self-learning LLM orchestrator
109
+ *
110
+ * Combines SONA adaptive learning with HNSW memory, FastGRNN routing, and
111
+ * GGUF inference through the native candle backend.
112
+ *
113
+ * Text comes only from a model loaded with `loadModel()` (or the `modelPath`
114
+ * option). Without one, `generate()`, `query()`, `chat()` and
115
+ * `generateDetailed()` throw `RUVLLM_NO_LANGUAGE_MODEL`.
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * import { RuvLLM } from '@ruvector/ruvllm';
120
+ *
121
+ * const llm = new RuvLLM();
122
+ * llm.loadModel('./qwen2.5-0.5b-instruct-q4_k_m.gguf');
123
+ *
124
+ * const out = llm.chat([{ role: 'user', content: 'What is machine learning?' }], {
125
+ * maxTokens: 128,
126
+ * });
127
+ * console.log(out.text, out.finishReason, out.completionTokens);
128
+ *
129
+ * // Routed query, answered by the loaded model
130
+ * const response = llm.query('What is machine learning?');
131
+ * llm.feedback({ requestId: response.requestId, rating: 5 });
132
+ * ```
133
+ */
134
+ export class RuvLLM {
135
+ /**
136
+ * Create a new RuvLLM instance
137
+ */
138
+ constructor(config) {
139
+ this.native = null;
140
+ this.nativeVersion = null;
141
+ // Fallback state for when native module is not available
142
+ this.fallbackState = {
143
+ memory: new Map(),
144
+ nextId: 1,
145
+ queryCount: 0,
146
+ };
147
+ this.config = config ?? {};
148
+ this.allowPlaceholder = this.config.allowPlaceholder === true || envAllowsPlaceholder();
149
+ const extra = this.config;
150
+ if (extra.backend !== undefined) {
151
+ notice('RUVLLM_UNSUPPORTED_OPTION', '`backend` is not supported by @ruvector/ruvllm and is ignored: models loaded with ' +
152
+ 'loadModel() run on the built-in candle backend.', this.config.strict);
153
+ }
154
+ const mod = getNativeModule();
155
+ if (mod) {
156
+ try {
157
+ this.native = new mod.RuvLLMEngine(toNativeConfig(config));
158
+ this.nativeVersion = mod.version();
159
+ }
160
+ catch {
161
+ // Silently fall back to JS implementation
162
+ }
163
+ }
164
+ if (this.config.modelPath !== undefined) {
165
+ this.loadModel(this.config.modelPath, this.config.modelOptions);
166
+ }
167
+ }
168
+ /**
169
+ * Whether the native binary can load and run a language model. False
170
+ * without a native binary, for binaries that predate `loadModel` (the 2.0.x
171
+ * `@ruvector/ruvllm-<platform>` packages), and for binaries built without
172
+ * the `candle` inference backend.
173
+ */
174
+ supportsModelLoading() {
175
+ const native = this.native;
176
+ if (typeof native?.loadModel !== 'function')
177
+ return false;
178
+ // Builds that predate this probe all had the backend (they were local
179
+ // `npm run build:native` builds, which enable `candle`).
180
+ return typeof native.supportsModelLoading === 'function' ? native.supportsModelLoading() : true;
181
+ }
182
+ /** Error for a binary that has `loadModel` but no inference backend. */
183
+ noBackendError() {
184
+ return codedError('RUVLLM_NO_INFERENCE_BACKEND', `the installed native binary (version ${this.nativeVersion ?? 'unknown'}) was built ` +
185
+ 'without the `candle` inference backend and cannot load models. Rebuild it with ' +
186
+ '`npm run build:native` (which enables `candle`) and set RUVLLM_NATIVE_PATH to it, ' +
187
+ 'or use the ruvllm CLI (`ruvllm serve <model>`).');
188
+ }
189
+ /**
190
+ * Load a GGUF model (or a directory holding one) for `generate()`,
191
+ * `chat()` and `query()`. Supported GGUF architectures: llama, mistral,
192
+ * qwen2, qwen3; others fail with an error naming the architecture. The
193
+ * tokenizer comes from a `tokenizer.json` beside the file, else from the
194
+ * GGUF itself. Replaces any loaded model; if loading fails, no model is
195
+ * loaded. Synchronous: blocks the event loop while the weights load.
196
+ *
197
+ * @throws `RUVLLM_NATIVE_UNAVAILABLE` without a native binary,
198
+ * `RUVLLM_NATIVE_TOO_OLD` when the binary predates model loading,
199
+ * `RUVLLM_NO_INFERENCE_BACKEND` when it was built without `candle`,
200
+ * `RUVLLM_MODEL_NOT_FOUND` / `RUVLLM_MODEL_LOAD_FAILED` from the backend.
201
+ */
202
+ loadModel(path, options) {
203
+ if (typeof path !== 'string' || path.length === 0) {
204
+ throw new TypeError('loadModel: path must be a non-empty string');
205
+ }
206
+ if (!this.native) {
207
+ throw codedError('RUVLLM_NATIVE_UNAVAILABLE', `no native RuvLLM binary could be loaded for ${platformKey()}, so models cannot be ` +
208
+ 'loaded. Install the matching @ruvector/ruvllm-<platform> package, or build one ' +
209
+ '(`npm run build:native`) and set RUVLLM_NATIVE_PATH to it.');
210
+ }
211
+ if (typeof this.native.loadModel !== 'function') {
212
+ throw codedError('RUVLLM_NATIVE_TOO_OLD', `the installed native binary (version ${this.nativeVersion ?? 'unknown'}) cannot load ` +
213
+ 'models: it predates loadModel(). The @ruvector/ruvllm-<platform> 2.0.x packages are ' +
214
+ 'such builds. Install the 2.1+ platform package (@ruvector/ruvllm >= 4.2.0), or build the binary from source ' +
215
+ '(`npm run build:native`, which enables the `candle` feature) and set ' +
216
+ 'RUVLLM_NATIVE_PATH to it, or use the ruvllm CLI (`ruvllm serve <model>`).');
217
+ }
218
+ if (!this.supportsModelLoading())
219
+ throw this.noBackendError();
220
+ const native = this.native;
221
+ return toModelInfo(callNative(() => native.loadModel(path, options)));
222
+ }
223
+ /**
224
+ * Unload the language model and free its memory
225
+ */
226
+ unloadModel() {
227
+ this.native?.unloadModel?.();
228
+ }
229
+ /**
230
+ * Whether a language model is loaded
231
+ */
232
+ isModelLoaded() {
233
+ return this.native?.isModelLoaded?.() ?? false;
234
+ }
235
+ /**
236
+ * The loaded language model, or null
237
+ */
238
+ modelInfo() {
239
+ const info = this.native?.modelInfo?.();
240
+ return info ? toModelInfo(info) : null;
241
+ }
242
+ /**
243
+ * Route `text`, then answer it with the loaded model (as one user message
244
+ * under the model's chat template).
245
+ *
246
+ * @throws `RUVLLM_NO_LANGUAGE_MODEL` when no model is loaded, unless
247
+ * `allowPlaceholder` is set (then `text` is `PLACEHOLDER_TEXT`).
248
+ */
249
+ query(text, config) {
250
+ if (!this.isModelLoaded()) {
251
+ const placeholder = this.placeholderOrThrow();
252
+ this.fallbackState.queryCount++;
253
+ const route = this.route(text);
254
+ return {
255
+ text: placeholder,
256
+ confidence: route.confidence,
257
+ model: route.model,
258
+ contextSize: route.contextSize,
259
+ latencyMs: 0,
260
+ requestId: `placeholder-${Date.now()}-${Math.random().toString(36).slice(2)}`,
261
+ };
262
+ }
263
+ const native = this.native;
264
+ const result = callNative(() => native.query(text, toNativeGenConfig(config)));
265
+ return {
266
+ text: result.text,
267
+ confidence: result.confidence,
268
+ model: result.model,
269
+ contextSize: result.contextSize,
270
+ latencyMs: result.latencyMs,
271
+ requestId: result.requestId,
272
+ promptTokens: result.promptTokens,
273
+ completionTokens: result.completionTokens,
274
+ finishReason: result.finishReason,
275
+ };
276
+ }
277
+ /**
278
+ * Continue `prompt` verbatim with the loaded model (no chat template; use
279
+ * `chat()` for instruction-tuned models). Returns the generated text.
280
+ *
281
+ * @throws `RUVLLM_NO_LANGUAGE_MODEL` when no model is loaded, unless
282
+ * `allowPlaceholder` is set (then it returns `PLACEHOLDER_TEXT`).
283
+ */
284
+ generate(prompt, config) {
285
+ if (!this.isModelLoaded())
286
+ return this.placeholderOrThrow();
287
+ return this.generateDetailed(prompt, config).text;
288
+ }
289
+ /**
290
+ * Like `generate()`, with token counts (from the model's tokenizer) and
291
+ * the finish reason. Always throws `RUVLLM_NO_LANGUAGE_MODEL` without a
292
+ * loaded model.
293
+ */
294
+ generateDetailed(prompt, config) {
295
+ const native = this.requireModel();
296
+ return toGenerationResult(callNative(() => native.generate(prompt, toNativeGenConfig(config))));
297
+ }
298
+ /**
299
+ * Run the loaded model on a conversation, formatted with the model's chat
300
+ * template (ChatML for Qwen, Llama 3 / Mistral formats for those models).
301
+ * Always throws `RUVLLM_NO_LANGUAGE_MODEL` without a loaded model.
302
+ */
303
+ chat(messages, config) {
304
+ const native = this.requireModel();
305
+ return toGenerationResult(callNative(() => native.chat(messages, toNativeGenConfig(config))));
306
+ }
307
+ requireModel() {
308
+ if (!this.isModelLoaded())
309
+ throw this.noModelError();
310
+ return this.native;
311
+ }
312
+ noModelError() {
313
+ let fix;
314
+ if (!this.native) {
315
+ fix =
316
+ `no native RuvLLM binary is available for ${platformKey()}, so no model can be loaded ` +
317
+ '(see RUVLLM_NATIVE_UNAVAILABLE in the README)';
318
+ }
319
+ else if (typeof this.native.loadModel !== 'function') {
320
+ fix =
321
+ `the installed native binary (version ${this.nativeVersion ?? 'unknown'}) cannot load ` +
322
+ 'models (see RUVLLM_NATIVE_TOO_OLD in the README)';
323
+ }
324
+ else if (!this.supportsModelLoading()) {
325
+ fix =
326
+ `the installed native binary (version ${this.nativeVersion ?? 'unknown'}) was built ` +
327
+ 'without the candle inference backend, so it cannot load models (see ' +
328
+ 'RUVLLM_NO_INFERENCE_BACKEND in the README)';
329
+ }
330
+ else {
331
+ fix = 'call loadModel(<path to a GGUF file>) first';
332
+ }
333
+ return codedError('RUVLLM_NO_LANGUAGE_MODEL', `no language model is loaded, so there is no model output to return: ${fix}. Routing, ` +
334
+ 'memory and embeddings work without a model. For an HTTP server use the ruvllm CLI ' +
335
+ '(`ruvllm serve <model>`).');
336
+ }
337
+ /** Throw `RUVLLM_NO_LANGUAGE_MODEL`, or return the labelled placeholder when opted in. */
338
+ placeholderOrThrow() {
339
+ if (!this.allowPlaceholder)
340
+ throw this.noModelError();
341
+ notice('RUVLLM_PLACEHOLDER_TEXT', 'no language model is loaded: generate()/query() are returning a labelled placeholder, ' +
342
+ 'not model output, because allowPlaceholder (or RUVLLM_ALLOW_MOCK=1) is set.', false);
343
+ return PLACEHOLDER_TEXT;
344
+ }
345
+ /**
346
+ * Get routing decision for a query
347
+ */
348
+ route(text) {
349
+ if (this.native) {
350
+ const result = this.native.route(text);
351
+ return {
352
+ model: result.model,
353
+ contextSize: result.contextSize ?? result.context_size,
354
+ temperature: result.temperature,
355
+ topP: result.topP ?? result.top_p,
356
+ confidence: result.confidence,
357
+ };
358
+ }
359
+ // Fallback
360
+ return {
361
+ model: 'M700',
362
+ contextSize: 512,
363
+ temperature: 0.7,
364
+ topP: 0.9,
365
+ confidence: 0.5,
366
+ };
367
+ }
368
+ /**
369
+ * Search memory for similar content
370
+ */
371
+ searchMemory(text, k = 10) {
372
+ if (this.native) {
373
+ const results = this.native.searchMemory(text, k);
374
+ return results.map(r => {
375
+ // The native side reports `distance` (smaller is closer). MemoryResult
376
+ // documents `score` as a similarity, so convert rather than passing a
377
+ // distance through under a similarity's name. Older builds that already
378
+ // emit `score` are used as-is.
379
+ const anyR = r;
380
+ const score = typeof anyR.score === 'number'
381
+ ? anyR.score
382
+ : typeof anyR.distance === 'number'
383
+ ? 1 / (1 + Math.max(0, anyR.distance))
384
+ : 0;
385
+ return {
386
+ id: r.id,
387
+ score,
388
+ content: r.content,
389
+ metadata: JSON.parse(r.metadata || '{}'),
390
+ };
391
+ });
392
+ }
393
+ // Fallback - simple search
394
+ return Array.from(this.fallbackState.memory.entries())
395
+ .slice(0, k)
396
+ .map(([id, data]) => ({
397
+ id,
398
+ score: 0.5,
399
+ content: data.content,
400
+ metadata: data.metadata,
401
+ }));
402
+ }
403
+ /**
404
+ * Add content to memory
405
+ */
406
+ addMemory(content, metadata) {
407
+ if (this.native) {
408
+ return this.native.addMemory(content, metadata ? JSON.stringify(metadata) : undefined);
409
+ }
410
+ // Fallback
411
+ const id = this.fallbackState.nextId++;
412
+ this.fallbackState.memory.set(id, {
413
+ content,
414
+ embedding: this.embed(content),
415
+ metadata: metadata ?? {},
416
+ });
417
+ return id;
418
+ }
419
+ /**
420
+ * Provide feedback for learning
421
+ */
422
+ feedback(fb) {
423
+ if (this.native) {
424
+ return this.native.feedback(fb.requestId, fb.rating, fb.correction);
425
+ }
426
+ return false;
427
+ }
428
+ /**
429
+ * Get engine statistics
430
+ */
431
+ stats() {
432
+ if (this.native) {
433
+ const s = this.native.stats();
434
+ // Map native stats (snake_case) to TypeScript interface (camelCase)
435
+ // Handle both old and new field names for backward compatibility
436
+ return {
437
+ totalQueries: s.totalQueries ?? s.total_queries ?? 0,
438
+ memoryNodes: s.memoryNodes ?? s.memory_nodes ?? 0,
439
+ patternsLearned: s.trainingSteps ??
440
+ s.patterns_learned ??
441
+ s.training_steps ??
442
+ 0,
443
+ avgLatencyMs: s.avgLatencyMs ?? s.avg_latency_ms ?? 0,
444
+ cacheHitRate: s.cacheHitRate ?? s.cache_hit_rate ?? 0,
445
+ routerAccuracy: s.routerAccuracy ?? s.router_accuracy ?? 0.5,
446
+ };
447
+ }
448
+ // Fallback
449
+ return {
450
+ totalQueries: this.fallbackState.queryCount,
451
+ memoryNodes: this.fallbackState.memory.size,
452
+ patternsLearned: 0,
453
+ avgLatencyMs: 1.0,
454
+ cacheHitRate: 0.0,
455
+ routerAccuracy: 0.5,
456
+ };
457
+ }
458
+ /**
459
+ * Force router learning cycle
460
+ */
461
+ forceLearn() {
462
+ if (this.native) {
463
+ return this.native.forceLearn();
464
+ }
465
+ return 'Learning not available in fallback mode';
466
+ }
467
+ /**
468
+ * Get embedding for text
469
+ */
470
+ embed(text) {
471
+ if (this.native) {
472
+ return this.native.embed(text);
473
+ }
474
+ // Fallback - simple hash-based embedding
475
+ const dim = this.config.embeddingDim ?? 768;
476
+ const embedding = new Array(dim).fill(0);
477
+ for (let i = 0; i < text.length; i++) {
478
+ const idx = (text.charCodeAt(i) * (i + 1)) % dim;
479
+ embedding[idx] += 0.1;
480
+ }
481
+ // Normalize
482
+ const norm = Math.sqrt(embedding.reduce((sum, x) => sum + x * x, 0)) || 1;
483
+ return embedding.map(x => x / norm);
484
+ }
485
+ /**
486
+ * Compute similarity between two texts
487
+ */
488
+ similarity(text1, text2) {
489
+ if (this.native) {
490
+ // f32 accumulation can land just outside the mathematical range — an
491
+ // identical pair measures 1.0000001 — which turns Math.acos(sim) into
492
+ // NaN downstream. Cosine similarity is defined on [-1, 1], so clamp.
493
+ const raw = this.native.similarity(text1, text2);
494
+ return Math.min(1, Math.max(-1, raw));
495
+ }
496
+ // Fallback - cosine similarity
497
+ const emb1 = this.embed(text1);
498
+ const emb2 = this.embed(text2);
499
+ let dot = 0;
500
+ let norm1 = 0;
501
+ let norm2 = 0;
502
+ for (let i = 0; i < emb1.length; i++) {
503
+ dot += emb1[i] * emb2[i];
504
+ norm1 += emb1[i] * emb1[i];
505
+ norm2 += emb2[i] * emb2[i];
506
+ }
507
+ const denom = Math.sqrt(norm1) * Math.sqrt(norm2);
508
+ const similarity = denom > 0 ? dot / denom : 0;
509
+ // Clamp to [0, 1] to handle floating point errors
510
+ return Math.max(0, Math.min(1, similarity));
511
+ }
512
+ /**
513
+ * Check if SIMD is available
514
+ */
515
+ hasSimd() {
516
+ if (this.native) {
517
+ return this.native.hasSimd();
518
+ }
519
+ return false;
520
+ }
521
+ /**
522
+ * Get SIMD capabilities
523
+ */
524
+ simdCapabilities() {
525
+ if (this.native) {
526
+ return this.native.simdCapabilities();
527
+ }
528
+ return ['Scalar (fallback)'];
529
+ }
530
+ /**
531
+ * Batch query multiple prompts
532
+ */
533
+ batchQuery(request) {
534
+ const start = Date.now();
535
+ const responses = request.queries.map(q => this.query(q, request.config));
536
+ return {
537
+ responses,
538
+ totalLatencyMs: Date.now() - start,
539
+ };
540
+ }
541
+ /**
542
+ * Check if native module is loaded
543
+ */
544
+ isNativeLoaded() {
545
+ return this.native !== null;
546
+ }
547
+ }
548
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW5naW5lLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2VuZ2luZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQXFCSCxPQUFPLEVBQ0wsZUFBZSxHQU1oQixNQUFNLFVBQVUsQ0FBQztBQUVsQjs7R0FFRztBQUNILFNBQVMsY0FBYyxDQUFDLE1BQXFCO0lBQzNDLElBQUksQ0FBQyxNQUFNO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFFOUIsT0FBTztRQUNMLGFBQWEsRUFBRSxNQUFNLENBQUMsWUFBWTtRQUNsQyxpQkFBaUIsRUFBRSxNQUFNLENBQUMsZUFBZTtRQUN6QyxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUs7UUFDcEIsb0JBQW9CLEVBQUUsTUFBTSxDQUFDLGtCQUFrQjtRQUMvQyxjQUFjLEVBQUUsTUFBTSxDQUFDLFlBQVk7UUFDbkMsZ0JBQWdCLEVBQUUsTUFBTSxDQUFDLGVBQWU7UUFDeEMsaUJBQWlCLEVBQUUsTUFBTSxDQUFDLGdCQUFnQjtRQUMxQyxVQUFVLEVBQUUsTUFBTSxDQUFDLFNBQVM7S0FDN0IsQ0FBQztBQUNKLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQVMsaUJBQWlCLENBQUMsTUFBeUI7SUFDbEQsSUFBSSxDQUFDLE1BQU07UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUU5QiwwRUFBMEU7SUFDMUUsT0FBTztRQUNMLFNBQVMsRUFBRSxNQUFNLENBQUMsU0FBUztRQUMzQixXQUFXLEVBQUUsTUFBTSxDQUFDLFdBQVc7UUFDL0IsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJO1FBQ2pCLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSTtRQUNqQixpQkFBaUIsRUFBRSxNQUFNLENBQUMsaUJBQWlCO1FBQzNDLGFBQWEsRUFBRSxNQUFNLENBQUMsYUFBYTtRQUNuQyxJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUk7S0FDbEIsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFTLGtCQUFrQixDQUFDLENBQXlC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RUFBRSxHQUFHLEtBQUs7U0FDbkMsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNILGNBQWM7UUFDWixPQUFPLElBQUksQ0FBQyxNQUFNLEtBQUssSUFBSSxDQUFDO0lBQzlCLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUnV2TExNIEVuZ2luZSAtIE1haW4gb3JjaGVzdHJhdG9yIGZvciBzZWxmLWxlYXJuaW5nIExMTVxuICovXG5cbmltcG9ydCB7XG4gIFJ1dkxMTUNvbmZpZyxcbiAgR2VuZXJhdGlvbkNvbmZpZyxcbiAgUXVlcnlSZXNwb25zZSxcbiAgUm91dGluZ0RlY2lzaW9uLFxuICBNZW1vcnlSZXN1bHQsXG4gIE1lbW9yeUlkLFxuICBSdXZMTE1TdGF0cyxcbiAgRmVlZGJhY2ssXG4gIEVtYmVkZGluZyxcbiAgQmF0Y2hRdWVyeVJlcXVlc3QsXG4gIEJhdGNoUXVlcnlSZXNwb25zZSxcbiAgQ2hhdE1lc3NhZ2UsXG4gIEZpbmlzaFJlYXNvbixcbiAgR2VuZXJhdGlvblJlc3VsdCxcbiAgTG9hZE1vZGVsT3B0aW9ucyxcbiAgTG9hZGVkTW9kZWxJbmZvLFxufSBmcm9tICcuL3R5cGVzJztcblxuaW1wb3J0IHtcbiAgZ2V0TmF0aXZlTW9kdWxlLFxuICBOYXRpdmVFbmdpbmUsXG4gIE5hdGl2ZUNvbmZpZyxcbiAgTmF0aXZlR2VuQ29uZmlnLFxuICBOYXRpdmVHZW5lcmF0aW9uUmVzdWx0LFxuICBOYXRpdmVNb2RlbEluZm8sXG59IGZyb20gJy4vbmF0aXZlJztcblxuLyoqXG4gKiBDb252ZXJ0IEpTIGNvbmZpZyB0byBuYXRpdmUgY29uZmlnIGZvcm1hdFxuICovXG5mdW5jdGlvbiB0b05hdGl2ZUNvbmZpZyhjb25maWc/OiBSdXZMTE1Db25maWcpOiBOYXRpdmVDb25maWcgfCB1bmRlZmluZWQge1xuICBpZiAoIWNvbmZpZykgcmV0dXJuIHVuZGVmaW5lZDtcblxuICByZXR1cm4ge1xuICAgIGVtYmVkZGluZ19kaW06IGNvbmZpZy5lbWJlZGRpbmdEaW0sXG4gICAgcm91dGVyX2hpZGRlbl9kaW06IGNvbmZpZy5yb3V0ZXJIaWRkZW5EaW0sXG4gICAgaG5zd19tOiBjb25maWcuaG5zd00sXG4gICAgaG5zd19lZl9jb25zdHJ1Y3Rpb246IGNvbmZpZy5obnN3RWZDb25zdHJ1Y3Rpb24sXG4gICAgaG5zd19lZl9zZWFyY2g6IGNvbmZpZy5obnN3RWZTZWFyY2gsXG4gICAgbGVhcm5pbmdfZW5hYmxlZDogY29uZmlnLmxlYXJuaW5nRW5hYmxlZCxcbiAgICBxdWFsaXR5X3RocmVzaG9sZDogY29uZmlnLnF1YWxpdHlUaHJlc2hvbGQsXG4gICAgZXdjX2xhbWJkYTogY29uZmlnLmV3Y0xhbWJkYSxcbiAgfTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IEpTIGdlbmVyYXRpb24gY29uZmlnIHRvIG5hdGl2ZSBmb3JtYXRcbiAqL1xuZnVuY3Rpb24gdG9OYXRpdmVHZW5Db25maWcoY29uZmlnPzogR2VuZXJhdGlvbkNvbmZpZyk6IE5hdGl2ZUdlbkNvbmZpZyB8IHVuZGVmaW5lZCB7XG4gIGlmICghY29uZmlnKSByZXR1cm4gdW5kZWZpbmVkO1xuXG4gIC8vIGNhbWVsQ2FzZTogbmFwaS1ycyBpZ25vcmVzIHNuYWtlX2Nhc2Uga2V5cyBvbiBgI1tuYXBpKG9iamVjdCldYCBpbnB1dHMuXG4gIHJldHVybiB7XG4gICAgbWF4VG9rZW5zOiBjb25maWcubWF4VG9rZW5zLFxuICAgIHRlbXBlcmF0dXJlOiBjb25maWcudGVtcGVyYXR1cmUsXG4gICAgdG9wUDogY29uZmlnLnRvcFAsXG4gICAgdG9wSzogY29uZmlnLnRvcEssXG4gICAgcmVwZXRpdGlvblBlbmFsdHk6IGNvbmZpZy5yZXBldGl0aW9uUGVuYWx0eSxcbiAgICBzdG9wU2VxdWVuY2VzOiBjb25maWcuc3RvcFNlcXVlbmNlcyxcbiAgICBzZWVkOiBjb25maWcuc2VlZCxcbiAgfTtcbn1cblxuZnVuY3Rpb24gdG9HZW5lcmF0aW9uUmVzdWx0KHI6IE5hdGl2ZUdlbmVyYXRpb25SZXN1bHQpOiBHZW5lcmF0aW9uUmVzdWx0IHtcbiAgcmV0dXJuIHtcbiAgICB0ZXh0OiByLnRleHQsXG4gICAgcHJvbXB0VG9rZW5zOiByLnByb21wdFRva2VucyxcbiAgICBjb21wbGV0aW9uVG9rZW5zOiByLmNvbXBsZXRpb25Ub2tlbnMsXG4gICAgZmluaXNoUmVhc29uOiByLmZpbmlzaFJlYXNvbiBhcyBGaW5pc2hSZWFzb24sXG4gIH07XG59XG5cbmZ1bmN0aW9uIHRvTW9kZWxJbmZvKGk6IE5hdGl2ZU1vZGVsSW5mbyk6IExvYWRlZE1vZGVsSW5mbyB7XG4gIHJldHVybiB7XG4gICAgbmFtZTogaS5uYW1lLFxuICAgIGFyY2hpdGVjdHVyZTogaS5hcmNoaXRlY3R1cmUsXG4gICAgbnVtUGFyYW1ldGVyczogaS5udW1QYXJhbWV0ZXJzLFxuICAgIHZvY2FiU2l6ZTogaS52b2NhYlNpemUsXG4gICAgaGlkZGVuU2l6ZTogaS5oaWRkZW5TaXplLFxuICAgIG51bUxheWVyczogaS5udW1MYXllcnMsXG4gICAgbWF4Q29udGV4dExlbmd0aDogaS5tYXhDb250ZXh0TGVuZ3RoLFxuICAgIHF1YW50aXphdGlvbjogaS5xdWFudGl6YXRpb24gPz8gbnVsbCxcbiAgICBtZW1vcnlVc2FnZUJ5dGVzOiBpLm1lbW9yeVVzYWdlQnl0ZXMsXG4gICAgY2hhdFRlbXBsYXRlOiBpLmNoYXRUZW1wbGF0ZSA/PyBudWxsLFxuICB9O1xufVxuXG5jb25zdCB3YXJuZWQgPSBuZXcgU2V0PHN0cmluZz4oKTtcblxuLyoqIFdhcm4gb25jZSBwZXIgcHJvY2VzcyAob3IgdGhyb3cgd2hlbiBgc3RyaWN0YCkuICovXG5mdW5jdGlvbiBub3RpY2UoY29kZTogc3RyaW5nLCBtZXNzYWdlOiBzdHJpbmcsIHN0cmljdDogYm9vbGVhbiB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICBpZiAoc3RyaWN0KSB0aHJvdyBjb2RlZEVycm9yKGNvZGUsIG1lc3NhZ2UpO1xuICBpZiAod2FybmVkLmhhcyhjb2RlKSkgcmV0dXJuO1xuICB3YXJuZWQuYWRkKGNvZGUpO1xuICBjb25zdCBnID0gZ2xvYmFsVGhpcyBhcyB1bmtub3duIGFzIHtcbiAgICBwcm9jZXNzPzogeyBlbWl0V2FybmluZz86IChtOiBzdHJpbmcsIG8/OiB7IGNvZGU/OiBzdHJpbmcgfSkgPT4gdm9pZCB9O1xuICAgIGNvbnNvbGU/OiB7IHdhcm4/OiAobTogc3RyaW5nKSA9PiB2b2lkIH07XG4gIH07XG4gIGlmICh0eXBlb2YgZy5wcm9jZXNzPy5lbWl0V2FybmluZyA9PT0gJ2Z1bmN0aW9uJykgZy5wcm9jZXNzLmVtaXRXYXJuaW5nKG1lc3NhZ2UsIHsgY29kZSB9KTtcbiAgZWxzZSBnLmNvbnNvbGU/Lndhcm4/LihgJHtjb2RlfTogJHttZXNzYWdlfWApO1xufVxuXG4vKiogQW4gRXJyb3Igd2hvc2UgbWVzc2FnZSBzdGFydHMgd2l0aCwgYW5kIHdob3NlIGBjb2RlYCBpcywgYGNvZGVgLiAqL1xuZnVuY3Rpb24gY29kZWRFcnJvcihjb2RlOiBzdHJpbmcsIG1lc3NhZ2U6IHN0cmluZyk6IEVycm9yICYgeyBjb2RlOiBzdHJpbmcgfSB7XG4gIGNvbnN0IGVyciA9IG5ldyBFcnJvcihgJHtjb2RlfTogJHttZXNzYWdlfWApIGFzIEVycm9yICYgeyBjb2RlOiBzdHJpbmcgfTtcbiAgZXJyLmNvZGUgPSBjb2RlO1xuICByZXR1cm4gZXJyO1xufVxuXG4vKipcbiAqIENhbGwgaW50byB0aGUgbmF0aXZlIGVuZ2luZSwgZ2l2aW5nIGl0cyBlcnJvcnMgdGhlIHNhbWUgYGNvZGVgIGFzIHRoZVxuICogd3JhcHBlcidzIG93bjogbmF0aXZlIG1lc3NhZ2VzIHN0YXJ0IHdpdGggYFJVVkxMTV88Q09ERT46YCwgYnV0IG5hcGktcnNcbiAqIHNldHMgYGNvZGVgIHRvIGEgZ2VuZXJpYyBzdGF0dXMgc3VjaCBhcyBgR2VuZXJpY0ZhaWx1cmVgLlxuICovXG5mdW5jdGlvbiBjYWxsTmF0aXZlPFQ+KGY6ICgpID0+IFQpOiBUIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gZigpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgY29uc3QgbWF0Y2ggPSAvXihSVVZMTE1fW0EtWl9dKyk6Ly5leGVjKGUgaW5zdGFuY2VvZiBFcnJvciA/IGUubWVzc2FnZSA6ICcnKTtcbiAgICBpZiAobWF0Y2gpIChlIGFzIHsgY29kZT86IHN0cmluZyB9KS5jb2RlID0gbWF0Y2hbMV07XG4gICAgdGhyb3cgZTtcbiAgfVxufVxuXG5mdW5jdGlvbiBwbGF0Zm9ybUtleSgpOiBzdHJpbmcge1xuICBjb25zdCBwID0gKGdsb2JhbFRoaXMgYXMgeyBwcm9jZXNzPzogeyBwbGF0Zm9ybT86IHN0cmluZzsgYXJjaD86IHN0cmluZyB9IH0pLnByb2Nlc3M7XG4gIHJldHVybiBgJHtwPy5wbGF0Zm9ybSA/PyAndW5rbm93bid9LSR7cD8uYXJjaCA/PyAndW5rbm93bid9YDtcbn1cblxuZnVuY3Rpb24gZW52QWxsb3dzUGxhY2Vob2xkZXIoKTogYm9vbGVhbiB7XG4gIGNvbnN0IHAgPSAoZ2xvYmFsVGhpcyBhcyB7IHByb2Nlc3M/OiB7IGVudj86IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IHVuZGVmaW5lZD4gfSB9KS5wcm9jZXNzO1xuICByZXR1cm4gcD8uZW52Py5SVVZMTE1fQUxMT1dfTU9DSyA9PT0gJzEnO1xufVxuXG4vKiogUmV0dXJuZWQgYnkgZ2VuZXJhdGUoKS9xdWVyeSgpIG9ubHkgd2l0aCBgYWxsb3dQbGFjZWhvbGRlcmAgLyBgUlVWTExNX0FMTE9XX01PQ0s9MWAuICovXG5leHBvcnQgY29uc3QgUExBQ0VIT0xERVJfVEVYVCA9XG4gICdbUnV2TExNIHBsYWNlaG9sZGVyOiBubyBsYW5ndWFnZSBtb2RlbCBpcyBsb2FkZWQ7IHRoaXMgdGV4dCBpcyBub3QgbW9kZWwgb3V0cHV0XSc7XG5cbi8qKlxuICogUnV2TExNIC0gU2VsZi1sZWFybmluZyBMTE0gb3JjaGVzdHJhdG9yXG4gKlxuICogQ29tYmluZXMgU09OQSBhZGFwdGl2ZSBsZWFybmluZyB3aXRoIEhOU1cgbWVtb3J5LCBGYXN0R1JOTiByb3V0aW5nLCBhbmRcbiAqIEdHVUYgaW5mZXJlbmNlIHRocm91Z2ggdGhlIG5hdGl2ZSBjYW5kbGUgYmFja2VuZC5cbiAqXG4gKiBUZXh0IGNvbWVzIG9ubHkgZnJvbSBhIG1vZGVsIGxvYWRlZCB3aXRoIGBsb2FkTW9kZWwoKWAgKG9yIHRoZSBgbW9kZWxQYXRoYFxuICogb3B0aW9uKS4gV2l0aG91dCBvbmUsIGBnZW5lcmF0ZSgpYCwgYHF1ZXJ5KClgLCBgY2hhdCgpYCBhbmRcbiAqIGBnZW5lcmF0ZURldGFpbGVkKClgIHRocm93IGBSVVZMTE1fTk9fTEFOR1VBR0VfTU9ERUxgLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBSdXZMTE0gfSBmcm9tICdAcnV2ZWN0b3IvcnV2bGxtJztcbiAqXG4gKiBjb25zdCBsbG0gPSBuZXcgUnV2TExNKCk7XG4gKiBsbG0ubG9hZE1vZGVsKCcuL3F3ZW4yLjUtMC41Yi1pbnN0cnVjdC1xNF9rX20uZ2d1ZicpO1xuICpcbiAqIGNvbnN0IG91dCA9IGxsbS5jaGF0KFt7IHJvbGU6ICd1c2VyJywgY29udGVudDogJ1doYXQgaXMgbWFjaGluZSBsZWFybmluZz8nIH1dLCB7XG4gKiAgIG1heFRva2VuczogMTI4LFxuICogfSk7XG4gKiBjb25zb2xlLmxvZyhvdXQudGV4dCwgb3V0LmZpbmlzaFJlYXNvbiwgb3V0LmNvbXBsZXRpb25Ub2tlbnMpO1xuICpcbiAqIC8vIFJvdXRlZCBxdWVyeSwgYW5zd2VyZWQgYnkgdGhlIGxvYWRlZCBtb2RlbFxuICogY29uc3QgcmVzcG9uc2UgPSBsbG0ucXVlcnkoJ1doYXQgaXMgbWFjaGluZSBsZWFybmluZz8nKTtcbiAqIGxsbS5mZWVkYmFjayh7IHJlcXVlc3RJZDogcmVzcG9uc2UucmVxdWVzdElkLCByYXRpbmc6IDUgfSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNsYXNzIFJ1dkxMTSB7XG4gIHByaXZhdGUgbmF0aXZlOiBOYXRpdmVFbmdpbmUgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBuYXRpdmVWZXJzaW9uOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBjb25maWc6IFJ1dkxMTUNvbmZpZztcbiAgcHJpdmF0ZSBhbGxvd1BsYWNlaG9sZGVyOiBib29sZWFuO1xuXG4gIC8vIEZhbGxiYWNrIHN0YXRlIGZvciB3aGVuIG5hdGl2ZSBtb2R1bGUgaXMgbm90IGF2YWlsYWJsZVxuICBwcml2YXRlIGZhbGxiYWNrU3RhdGUgPSB7XG4gICAgbWVtb3J5OiBuZXcgTWFwPG51bWJlciwgeyBjb250ZW50OiBzdHJpbmc7IGVtYmVkZGluZzogbnVtYmVyW107IG1ldGFkYXRhOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB9PigpLFxuICAgIG5leHRJZDogMSxcbiAgICBxdWVyeUNvdW50OiAwLFxuICB9O1xuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBuZXcgUnV2TExNIGluc3RhbmNlXG4gICAqL1xuICBjb25zdHJ1Y3Rvcihjb25maWc/OiBSdXZMTE1Db25maWcpIHtcbiAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZyA/PyB7fTtcbiAgICB0aGlzLmFsbG93UGxhY2Vob2xkZXIgPSB0aGlzLmNvbmZpZy5hbGxvd1BsYWNlaG9sZGVyID09PSB0cnVlIHx8IGVudkFsbG93c1BsYWNlaG9sZGVyKCk7XG4gICAgY29uc3QgZXh0cmEgPSB0aGlzLmNvbmZpZyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICBpZiAoZXh0cmEuYmFja2VuZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBub3RpY2UoXG4gICAgICAgICdSVVZMTE1fVU5TVVBQT1JURURfT1BUSU9OJyxcbiAgICAgICAgJ2BiYWNrZW5kYCBpcyBub3Qgc3VwcG9ydGVkIGJ5IEBydXZlY3Rvci9ydXZsbG0gYW5kIGlzIGlnbm9yZWQ6IG1vZGVscyBsb2FkZWQgd2l0aCAnICtcbiAgICAgICAgICAnbG9hZE1vZGVsKCkgcnVuIG9uIHRoZSBidWlsdC1pbiBjYW5kbGUgYmFja2VuZC4nLFxuICAgICAgICB0aGlzLmNvbmZpZy5zdHJpY3QsXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IG1vZCA9IGdldE5hdGl2ZU1vZHVsZSgpO1xuICAgIGlmIChtb2QpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHRoaXMubmF0aXZlID0gbmV3IG1vZC5SdXZMTE1FbmdpbmUodG9OYXRpdmVDb25maWcoY29uZmlnKSk7XG4gICAgICAgIHRoaXMubmF0aXZlVmVyc2lvbiA9IG1vZC52ZXJzaW9uKCk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLy8gU2lsZW50bHkgZmFsbCBiYWNrIHRvIEpTIGltcGxlbWVudGF0aW9uXG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuY29uZmlnLm1vZGVsUGF0aCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLmxvYWRNb2RlbCh0aGlzLmNvbmZpZy5tb2RlbFBhdGgsIHRoaXMuY29uZmlnLm1vZGVsT3B0aW9ucyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIG5hdGl2ZSBiaW5hcnkgY2FuIGxvYWQgYW5kIHJ1biBhIGxhbmd1YWdlIG1vZGVsLiBGYWxzZVxuICAgKiB3aXRob3V0IGEgbmF0aXZlIGJpbmFyeSwgZm9yIGJpbmFyaWVzIHRoYXQgcHJlZGF0ZSBgbG9hZE1vZGVsYCAodGhlIDIuMC54XG4gICAqIGBAcnV2ZWN0b3IvcnV2bGxtLTxwbGF0Zm9ybT5gIHBhY2thZ2VzKSwgYW5kIGZvciBiaW5hcmllcyBidWlsdCB3aXRob3V0XG4gICAqIHRoZSBgY2FuZGxlYCBpbmZlcmVuY2UgYmFja2VuZC5cbiAgICovXG4gIHN1cHBvcnRzTW9kZWxMb2FkaW5nKCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IG5hdGl2ZSA9IHRoaXMubmF0aXZlO1xuICAgIGlmICh0eXBlb2YgbmF0aXZlPy5sb2FkTW9kZWwgIT09ICdmdW5jdGlvbicpIHJldHVybiBmYWxzZTtcbiAgICAvLyBCdWlsZHMgdGhhdCBwcmVkYXRlIHRoaXMgcHJvYmUgYWxsIGhhZCB0aGUgYmFja2VuZCAodGhleSB3ZXJlIGxvY2FsXG4gICAgLy8gYG5wbSBydW4gYnVpbGQ6bmF0aXZlYCBidWlsZHMsIHdoaWNoIGVuYWJsZSBgY2FuZGxlYCkuXG4gICAgcmV0dXJuIHR5cGVvZiBuYXRpdmUuc3VwcG9ydHNNb2RlbExvYWRpbmcgPT09ICdmdW5jdGlvbicgPyBuYXRpdmUuc3VwcG9ydHNNb2RlbExvYWRpbmcoKSA6IHRydWU7XG4gIH1cblxuICAvKiogRXJyb3IgZm9yIGEgYmluYXJ5IHRoYXQgaGFzIGBsb2FkTW9kZWxgIGJ1dCBubyBpbmZlcmVuY2UgYmFja2VuZC4gKi9cbiAgcHJpdmF0ZSBub0JhY2tlbmRFcnJvcigpOiBFcnJvciB7XG4gICAgcmV0dXJuIGNvZGVkRXJyb3IoXG4gICAgICAnUlVWTExNX05PX0lORkVSRU5DRV9CQUNLRU5EJyxcbiAgICAgIGB0aGUgaW5zdGFsbGVkIG5hdGl2ZSBiaW5hcnkgKHZlcnNpb24gJHt0aGlzLm5hdGl2ZVZlcnNpb24gPz8gJ3Vua25vd24nfSkgd2FzIGJ1aWx0IGAgK1xuICAgICAgICAnd2l0aG91dCB0aGUgYGNhbmRsZWAgaW5mZXJlbmNlIGJhY2tlbmQgYW5kIGNhbm5vdCBsb2FkIG1vZGVscy4gUmVidWlsZCBpdCB3aXRoICcgK1xuICAgICAgICAnYG5wbSBydW4gYnVpbGQ6bmF0aXZlYCAod2hpY2ggZW5hYmxlcyBgY2FuZGxlYCkgYW5kIHNldCBSVVZMTE1fTkFUSVZFX1BBVEggdG8gaXQsICcgK1xuICAgICAgICAnb3IgdXNlIHRoZSBydXZsbG0gQ0xJIChgcnV2bGxtIHNlcnZlIDxtb2RlbD5gKS4nLFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogTG9hZCBhIEdHVUYgbW9kZWwgKG9yIGEgZGlyZWN0b3J5IGhvbGRpbmcgb25lKSBmb3IgYGdlbmVyYXRlKClgLFxuICAgKiBgY2hhdCgpYCBhbmQgYHF1ZXJ5KClgLiBTdXBwb3J0ZWQgR0dVRiBhcmNoaXRlY3R1cmVzOiBsbGFtYSwgbWlzdHJhbCxcbiAgICogcXdlbjIsIHF3ZW4zOyBvdGhlcnMgZmFpbCB3aXRoIGFuIGVycm9yIG5hbWluZyB0aGUgYXJjaGl0ZWN0dXJlLiBUaGVcbiAgICogdG9rZW5pemVyIGNvbWVzIGZyb20gYSBgdG9rZW5pemVyLmpzb25gIGJlc2lkZSB0aGUgZmlsZSwgZWxzZSBmcm9tIHRoZVxuICAgKiBHR1VGIGl0c2VsZi4gUmVwbGFjZXMgYW55IGxvYWRlZCBtb2RlbDsgaWYgbG9hZGluZyBmYWlscywgbm8gbW9kZWwgaXNcbiAgICogbG9hZGVkLiBTeW5jaHJvbm91czogYmxvY2tzIHRoZSBldmVudCBsb29wIHdoaWxlIHRoZSB3ZWlnaHRzIGxvYWQuXG4gICAqXG4gICAqIEB0aHJvd3MgYFJVVkxMTV9OQVRJVkVfVU5BVkFJTEFCTEVgIHdpdGhvdXQgYSBuYXRpdmUgYmluYXJ5LFxuICAgKiAgIGBSVVZMTE1fTkFUSVZFX1RPT19PTERgIHdoZW4gdGhlIGJpbmFyeSBwcmVkYXRlcyBtb2RlbCBsb2FkaW5nLFxuICAgKiAgIGBSVVZMTE1fTk9fSU5GRVJFTkNFX0JBQ0tFTkRgIHdoZW4gaXQgd2FzIGJ1aWx0IHdpdGhvdXQgYGNhbmRsZWAsXG4gICAqICAgYFJVVkxMTV9NT0RFTF9OT1RfRk9VTkRgIC8gYFJVVkxMTV9NT0RFTF9MT0FEX0ZBSUxFRGAgZnJvbSB0aGUgYmFja2VuZC5cbiAgICovXG4gIGxvYWRNb2RlbChwYXRoOiBzdHJpbmcsIG9wdGlvbnM/OiBMb2FkTW9kZWxPcHRpb25zKTogTG9hZGVkTW9kZWxJbmZvIHtcbiAgICBpZiAodHlwZW9mIHBhdGggIT09ICdzdHJpbmcnIHx8IHBhdGgubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdsb2FkTW9kZWw6IHBhdGggbXVzdCBiZSBhIG5vbi1lbXB0eSBzdHJpbmcnKTtcbiAgICB9XG4gICAgaWYgKCF0aGlzLm5hdGl2ZSkge1xuICAgICAgdGhyb3cgY29kZWRFcnJvcihcbiAgICAgICAgJ1JVVkxMTV9OQVRJVkVfVU5BVkFJTEFCTEUnLFxuICAgICAgICBgbm8gbmF0aXZlIFJ1dkxMTSBiaW5hcnkgY291bGQgYmUgbG9hZGVkIGZvciAke3BsYXRmb3JtS2V5KCl9LCBzbyBtb2RlbHMgY2Fubm90IGJlIGAgK1xuICAgICAgICAgICdsb2FkZWQuIEluc3RhbGwgdGhlIG1hdGNoaW5nIEBydXZlY3Rvci9ydXZsbG0tPHBsYXRmb3JtPiBwYWNrYWdlLCBvciBidWlsZCBvbmUgJyArXG4gICAgICAgICAgJyhgbnBtIHJ1biBidWlsZDpuYXRpdmVgKSBhbmQgc2V0IFJVVkxMTV9OQVRJVkVfUEFUSCB0byBpdC4nLFxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKHR5cGVvZiB0aGlzLm5hdGl2ZS5sb2FkTW9kZWwgIT09ICdmdW5jdGlvbicpIHtcbiAgICAgIHRocm93IGNvZGVkRXJyb3IoXG4gICAgICAgICdSVVZMTE1fTkFUSVZFX1RPT19PTEQnLFxuICAgICAgICBgdGhlIGluc3RhbGxlZCBuYXRpdmUgYmluYXJ5ICh2ZXJzaW9uICR7dGhpcy5uYXRpdmVWZXJzaW9uID8/ICd1bmtub3duJ30pIGNhbm5vdCBsb2FkIGAgK1xuICAgICAgICAgICdtb2RlbHM6IGl0IHByZWRhdGVzIGxvYWRNb2RlbCgpLiBUaGUgQHJ1dmVjdG9yL3J1dmxsbS08cGxhdGZvcm0+IDIuMC54IHBhY2thZ2VzIGFyZSAnICtcbiAgICAgICAgICAnc3VjaCBidWlsZHMuIEluc3RhbGwgdGhlIDIuMSsgcGxhdGZvcm0gcGFja2FnZSAoQHJ1dmVjdG9yL3J1dmxsbSA+PSA0LjIuMCksIG9yIGJ1aWxkIHRoZSBiaW5hcnkgZnJvbSBzb3VyY2UgJyArXG4gICAgICAgICAgJyhgbnBtIHJ1biBidWlsZDpuYXRpdmVgLCB3aGljaCBlbmFibGVzIHRoZSBgY2FuZGxlYCBmZWF0dXJlKSBhbmQgc2V0ICcgK1xuICAgICAgICAgICdSVVZMTE1fTkFUSVZFX1BBVEggdG8gaXQsIG9yIHVzZSB0aGUgcnV2bGxtIENMSSAoYHJ1dmxsbSBzZXJ2ZSA8bW9kZWw+YCkuJyxcbiAgICAgICk7XG4gICAgfVxuICAgIGlmICghdGhpcy5zdXBwb3J0c01vZGVsTG9hZGluZygpKSB0aHJvdyB0aGlzLm5vQmFja2VuZEVycm9yKCk7XG4gICAgY29uc3QgbmF0aXZlID0gdGhpcy5uYXRpdmU7XG4gICAgcmV0dXJuIHRvTW9kZWxJbmZvKGNhbGxOYXRpdmUoKCkgPT4gbmF0aXZlLmxvYWRNb2RlbCEocGF0aCwgb3B0aW9ucykpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVbmxvYWQgdGhlIGxhbmd1YWdlIG1vZGVsIGFuZCBmcmVlIGl0cyBtZW1vcnlcbiAgICovXG4gIHVubG9hZE1vZGVsKCk6IHZvaWQge1xuICAgIHRoaXMubmF0aXZlPy51bmxvYWRNb2RlbD8uKCk7XG4gIH1cblxuICAvKipcbiAgICogV2hldGhlciBhIGxhbmd1YWdlIG1vZGVsIGlzIGxvYWRlZFxuICAgKi9cbiAgaXNNb2RlbExvYWRlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5uYXRpdmU/LmlzTW9kZWxMb2FkZWQ/LigpID8/IGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBsb2FkZWQgbGFuZ3VhZ2UgbW9kZWwsIG9yIG51bGxcbiAgICovXG4gIG1vZGVsSW5mbygpOiBMb2FkZWRNb2RlbEluZm8gfCBudWxsIHtcbiAgICBjb25zdCBpbmZvID0gdGhpcy5uYXRpdmU/Lm1vZGVsSW5mbz8uKCk7XG4gICAgcmV0dXJuIGluZm8gPyB0b01vZGVsSW5mbyhpbmZvKSA6IG51bGw7XG4gIH1cblxuICAvKipcbiAgICogUm91dGUgYHRleHRgLCB0aGVuIGFuc3dlciBpdCB3aXRoIHRoZSBsb2FkZWQgbW9kZWwgKGFzIG9uZSB1c2VyIG1lc3NhZ2VcbiAgICogdW5kZXIgdGhlIG1vZGVsJ3MgY2hhdCB0ZW1wbGF0ZSkuXG4gICAqXG4gICAqIEB0aHJvd3MgYFJVVkxMTV9OT19MQU5HVUFHRV9NT0RFTGAgd2hlbiBubyBtb2RlbCBpcyBsb2FkZWQsIHVubGVzc1xuICAgKiAgIGBhbGxvd1BsYWNlaG9sZGVyYCBpcyBzZXQgKHRoZW4gYHRleHRgIGlzIGBQTEFDRUhPTERFUl9URVhUYCkuXG4gICAqL1xuICBxdWVyeSh0ZXh0OiBzdHJpbmcsIGNvbmZpZz86IEdlbmVyYXRpb25Db25maWcpOiBRdWVyeVJlc3BvbnNlIHtcbiAgICBpZiAoIXRoaXMuaXNNb2RlbExvYWRlZCgpKSB7XG4gICAgICBjb25zdCBwbGFjZWhvbGRlciA9IHRoaXMucGxhY2Vob2xkZXJPclRocm93KCk7XG4gICAgICB0aGlzLmZhbGxiYWNrU3RhdGUucXVlcnlDb3VudCsrO1xuICAgICAgY29uc3Qgcm91dGUgPSB0aGlzLnJvdXRlKHRleHQpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdGV4dDogcGxhY2Vob2xkZXIsXG4gICAgICAgIGNvbmZpZGVuY2U6IHJvdXRlLmNvbmZpZGVuY2UsXG4gICAgICAgIG1vZGVsOiByb3V0ZS5tb2RlbCxcbiAgICAgICAgY29udGV4dFNpemU6IHJvdXRlLmNvbnRleHRTaXplLFxuICAgICAgICBsYXRlbmN5TXM6IDAsXG4gICAgICAgIHJlcXVlc3RJZDogYHBsYWNlaG9sZGVyLSR7RGF0ZS5ub3coKX0tJHtNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDM2KS5zbGljZSgyKX1gLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICBjb25zdCBuYXRpdmUgPSB0aGlzLm5hdGl2ZSE7XG4gICAgY29uc3QgcmVzdWx0ID0gY2FsbE5hdGl2ZSgoKSA9PiBuYXRpdmUucXVlcnkodGV4dCwgdG9OYXRpdmVHZW5Db25maWcoY29uZmlnKSkpO1xuICAgIHJldHVybiB7XG4gICAgICB0ZXh0OiByZXN1bHQudGV4dCxcbiAgICAgIGNvbmZpZGVuY2U6IHJlc3VsdC5jb25maWRlbmNlLFxuICAgICAgbW9kZWw6IHJlc3VsdC5tb2RlbCxcbiAgICAgIGNvbnRleHRTaXplOiByZXN1bHQuY29udGV4dFNpemUsXG4gICAgICBsYXRlbmN5TXM6IHJlc3VsdC5sYXRlbmN5TXMsXG4gICAgICByZXF1ZXN0SWQ6IHJlc3VsdC5yZXF1ZXN0SWQsXG4gICAgICBwcm9tcHRUb2tlbnM6IHJlc3VsdC5wcm9tcHRUb2tlbnMsXG4gICAgICBjb21wbGV0aW9uVG9rZW5zOiByZXN1bHQuY29tcGxldGlvblRva2VucyxcbiAgICAgIGZpbmlzaFJlYXNvbjogcmVzdWx0LmZpbmlzaFJlYXNvbiBhcyBGaW5pc2hSZWFzb24gfCB1bmRlZmluZWQsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb250aW51ZSBgcHJvbXB0YCB2ZXJiYXRpbSB3aXRoIHRoZSBsb2FkZWQgbW9kZWwgKG5vIGNoYXQgdGVtcGxhdGU7IHVzZVxuICAgKiBgY2hhdCgpYCBmb3IgaW5zdHJ1Y3Rpb24tdHVuZWQgbW9kZWxzKS4gUmV0dXJucyB0aGUgZ2VuZXJhdGVkIHRleHQuXG4gICAqXG4gICAqIEB0aHJvd3MgYFJVVkxMTV9OT19MQU5HVUFHRV9NT0RFTGAgd2hlbiBubyBtb2RlbCBpcyBsb2FkZWQsIHVubGVzc1xuICAgKiAgIGBhbGxvd1BsYWNlaG9sZGVyYCBpcyBzZXQgKHRoZW4gaXQgcmV0dXJucyBgUExBQ0VIT0xERVJfVEVYVGApLlxuICAgKi9cbiAgZ2VuZXJhdGUocHJvbXB0OiBzdHJpbmcsIGNvbmZpZz86IEdlbmVyYXRpb25Db25maWcpOiBzdHJpbmcge1xuICAgIGlmICghdGhpcy5pc01vZGVsTG9hZGVkKCkpIHJldHVybiB0aGlzLnBsYWNlaG9sZGVyT3JUaHJvdygpO1xuICAgIHJldHVybiB0aGlzLmdlbmVyYXRlRGV0YWlsZWQocHJvbXB0LCBjb25maWcpLnRleHQ7XG4gIH1cblxuICAvKipcbiAgICogTGlrZSBgZ2VuZXJhdGUoKWAsIHdpdGggdG9rZW4gY291bnRzIChmcm9tIHRoZSBtb2RlbCdzIHRva2VuaXplcikgYW5kXG4gICAqIHRoZSBmaW5pc2ggcmVhc29uLiBBbHdheXMgdGhyb3dzIGBSVVZMTE1fTk9fTEFOR1VBR0VfTU9ERUxgIHdpdGhvdXQgYVxuICAgKiBsb2FkZWQgbW9kZWwuXG4gICAqL1xuICBnZW5lcmF0ZURldGFpbGVkKHByb21wdDogc3RyaW5nLCBjb25maWc/OiBHZW5lcmF0aW9uQ29uZmlnKTogR2VuZXJhdGlvblJlc3VsdCB7XG4gICAgY29uc3QgbmF0aXZlID0gdGhpcy5yZXF1aXJlTW9kZWwoKTtcbiAgICByZXR1cm4gdG9HZW5lcmF0aW9uUmVzdWx0KFxuICAgICAgY2FsbE5hdGl2ZSgoKSA9PiBuYXRpdmUuZ2VuZXJhdGUocHJvbXB0LCB0b05hdGl2ZUdlbkNvbmZpZyhjb25maWcpKSkgYXMgTmF0aXZlR2VuZXJhdGlvblJlc3VsdCxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1biB0aGUgbG9hZGVkIG1vZGVsIG9uIGEgY29udmVyc2F0aW9uLCBmb3JtYXR0ZWQgd2l0aCB0aGUgbW9kZWwncyBjaGF0XG4gICAqIHRlbXBsYXRlIChDaGF0TUwgZm9yIFF3ZW4sIExsYW1hIDMgLyBNaXN0cmFsIGZvcm1hdHMgZm9yIHRob3NlIG1vZGVscykuXG4gICAqIEFsd2F5cyB0aHJvd3MgYFJVVkxMTV9OT19MQU5HVUFHRV9NT0RFTGAgd2l0aG91dCBhIGxvYWRlZCBtb2RlbC5cbiAgICovXG4gIGNoYXQobWVzc2FnZXM6IENoYXRNZXNzYWdlW10sIGNvbmZpZz86IEdlbmVyYXRpb25Db25maWcpOiBHZW5lcmF0aW9uUmVzdWx0IHtcbiAgICBjb25zdCBuYXRpdmUgPSB0aGlzLnJlcXVpcmVNb2RlbCgpO1xuICAgIHJldHVybiB0b0dlbmVyYXRpb25SZXN1bHQoY2FsbE5hdGl2ZSgoKSA9PiBuYXRpdmUuY2hhdCEobWVzc2FnZXMsIHRvTmF0aXZlR2VuQ29uZmlnKGNvbmZpZykpKSk7XG4gIH1cblxuICBwcml2YXRlIHJlcXVpcmVNb2RlbCgpOiBOYXRpdmVFbmdpbmUge1xuICAgIGlmICghdGhpcy5pc01vZGVsTG9hZGVkKCkpIHRocm93IHRoaXMubm9Nb2RlbEVycm9yKCk7XG4gICAgcmV0dXJuIHRoaXMubmF0aXZlITtcbiAgfVxuXG4gIHByaXZhdGUgbm9Nb2RlbEVycm9yKCk6IEVycm9yIHtcbiAgICBsZXQgZml4OiBzdHJpbmc7XG4gICAgaWYgKCF0aGlzLm5hdGl2ZSkge1xuICAgICAgZml4ID1cbiAgICAgICAgYG5vIG5hdGl2ZSBSdXZMTE0gYmluYXJ5IGlzIGF2YWlsYWJsZSBmb3IgJHtwbGF0Zm9ybUtleSgpfSwgc28gbm8gbW9kZWwgY2FuIGJlIGxvYWRlZCBgICtcbiAgICAgICAgJyhzZWUgUlVWTExNX05BVElWRV9VTkFWQUlMQUJMRSBpbiB0aGUgUkVBRE1FKSc7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgdGhpcy5uYXRpdmUubG9hZE1vZGVsICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICBmaXggPVxuICAgICAgICBgdGhlIGluc3RhbGxlZCBuYXRpdmUgYmluYXJ5ICh2ZXJzaW9uICR7dGhpcy5uYXRpdmVWZXJzaW9uID8/ICd1bmtub3duJ30pIGNhbm5vdCBsb2FkIGAgK1xuICAgICAgICAnbW9kZWxzIChzZWUgUlVWTExNX05BVElWRV9UT09fT0xEIGluIHRoZSBSRUFETUUpJztcbiAgICB9IGVsc2UgaWYgKCF0aGlzLnN1cHBvcnRzTW9kZWxMb2FkaW5nKCkpIHtcbiAgICAgIGZpeCA9XG4gICAgICAgIGB0aGUgaW5zdGFsbGVkIG5hdGl2ZSBiaW5hcnkgKHZlcnNpb24gJHt0aGlzLm5hdGl2ZVZlcnNpb24gPz8gJ3Vua25vd24nfSkgd2FzIGJ1aWx0IGAgK1xuICAgICAgICAnd2l0aG91dCB0aGUgY2FuZGxlIGluZmVyZW5jZSBiYWNrZW5kLCBzbyBpdCBjYW5ub3QgbG9hZCBtb2RlbHMgKHNlZSAnICtcbiAgICAgICAgJ1JVVkxMTV9OT19JTkZFUkVOQ0VfQkFDS0VORCBpbiB0aGUgUkVBRE1FKSc7XG4gICAgfSBlbHNlIHtcbiAgICAgIGZpeCA9ICdjYWxsIGxvYWRNb2RlbCg8cGF0aCB0byBhIEdHVUYgZmlsZT4pIGZpcnN0JztcbiAgICB9XG4gICAgcmV0dXJuIGNvZGVkRXJyb3IoXG4gICAgICAnUlVWTExNX05PX0xBTkdVQUdFX01PREVMJyxcbiAgICAgIGBubyBsYW5ndWFnZSBtb2RlbCBpcyBsb2FkZWQsIHNvIHRoZXJlIGlzIG5vIG1vZGVsIG91dHB1dCB0byByZXR1cm46ICR7Zml4fS4gUm91dGluZywgYCArXG4gICAgICAgICdtZW1vcnkgYW5kIGVtYmVkZGluZ3Mgd29yayB3aXRob3V0IGEgbW9kZWwuIEZvciBhbiBIVFRQIHNlcnZlciB1c2UgdGhlIHJ1dmxsbSBDTEkgJyArXG4gICAgICAgICcoYHJ1dmxsbSBzZXJ2ZSA8bW9kZWw+YCkuJyxcbiAgICApO1xuICB9XG5cbiAgLyoqIFRocm93IGBSVVZMTE1fTk9fTEFOR1VBR0VfTU9ERUxgLCBvciByZXR1cm4gdGhlIGxhYmVsbGVkIHBsYWNlaG9sZGVyIHdoZW4gb3B0ZWQgaW4uICovXG4gIHByaXZhdGUgcGxhY2Vob2xkZXJPclRocm93KCk6IHN0cmluZyB7XG4gICAgaWYgKCF0aGlzLmFsbG93UGxhY2Vob2xkZXIpIHRocm93IHRoaXMubm9Nb2RlbEVycm9yKCk7XG4gICAgbm90aWNlKFxuICAgICAgJ1JVVkxMTV9QTEFDRUhPTERFUl9URVhUJyxcbiAgICAgICdubyBsYW5ndWFnZSBtb2RlbCBpcyBsb2FkZWQ6IGdlbmVyYXRlKCkvcXVlcnkoKSBhcmUgcmV0dXJuaW5nIGEgbGFiZWxsZWQgcGxhY2Vob2xkZXIsICcgK1xuICAgICAgICAnbm90IG1vZGVsIG91dHB1dCwgYmVjYXVzZSBhbGxvd1BsYWNlaG9sZGVyIChvciBSVVZMTE1fQUxMT1dfTU9DSz0xKSBpcyBzZXQuJyxcbiAgICAgIGZhbHNlLFxuICAgICk7XG4gICAgcmV0dXJuIFBMQUNFSE9MREVSX1RFWFQ7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHJvdXRpbmcgZGVjaXNpb24gZm9yIGEgcXVlcnlcbiAgICovXG4gIHJvdXRlKHRleHQ6IHN0cmluZyk6IFJvdXRpbmdEZWNpc2lvbiB7XG4gICAgaWYgKHRoaXMubmF0aXZlKSB7XG4gICAgICBjb25zdCByZXN1bHQgPSB0aGlzLm5hdGl2ZS5yb3V0ZSh0ZXh0KTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIG1vZGVsOiByZXN1bHQubW9kZWwgYXMgYW55LFxuICAgICAgICBjb250ZXh0U2l6ZTogcmVzdWx0LmNvbnRleHRTaXplID8/IHJlc3VsdC5jb250ZXh0X3NpemUsXG4gICAgICAgIHRlbXBlcmF0dXJlOiByZXN1bHQudGVtcGVyYXR1cmUsXG4gICAgICAgIHRvcFA6IHJlc3VsdC50b3BQID8/IHJlc3VsdC50b3BfcCxcbiAgICAgICAgY29uZmlkZW5jZTogcmVzdWx0LmNvbmZpZGVuY2UsXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIEZhbGxiYWNrXG4gICAgcmV0dXJuIHtcbiAgICAgIG1vZGVsOiAnTTcwMCcsXG4gICAgICBjb250ZXh0U2l6ZTogNTEyLFxuICAgICAgdGVtcGVyYXR1cmU6IDAuNyxcbiAgICAgIHRvcFA6IDAuOSxcbiAgICAgIGNvbmZpZGVuY2U6IDAuNSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFNlYXJjaCBtZW1vcnkgZm9yIHNpbWlsYXIgY29udGVudFxuICAgKi9cbiAgc2VhcmNoTWVtb3J5KHRleHQ6IHN0cmluZywgayA9IDEwKTogTWVtb3J5UmVzdWx0W10ge1xuICAgIGlmICh0aGlzLm5hdGl2ZSkge1xuICAgICAgY29uc3QgcmVzdWx0cyA9IHRoaXMubmF0aXZlLnNlYXJjaE1lbW9yeSh0ZXh0LCBrKTtcbiAgICAgIHJldHVybiByZXN1bHRzLm1hcChyID0+IHtcbiAgICAgICAgLy8gVGhlIG5hdGl2ZSBzaWRlIHJlcG9ydHMgYGRpc3RhbmNlYCAoc21hbGxlciBpcyBjbG9zZXIpLiBNZW1vcnlSZXN1bHRcbiAgICAgICAgLy8gZG9jdW1lbnRzIGBzY29yZWAgYXMgYSBzaW1pbGFyaXR5LCBzbyBjb252ZXJ0IHJhdGhlciB0aGFuIHBhc3NpbmcgYVxuICAgICAgICAvLyBkaXN0YW5jZSB0aHJvdWdoIHVuZGVyIGEgc2ltaWxhcml0eSdzIG5hbWUuIE9sZGVyIGJ1aWxkcyB0aGF0IGFscmVhZHlcbiAgICAgICAgLy8gZW1pdCBgc2NvcmVgIGFyZSB1c2VkIGFzLWlzLlxuICAgICAgICBjb25zdCBhbnlSID0gciBhcyBhbnk7XG4gICAgICAgIGNvbnN0IHNjb3JlID1cbiAgICAgICAgICB0eXBlb2YgYW55Ui5zY29yZSA9PT0gJ251bWJlcidcbiAgICAgICAgICAgID8gYW55Ui5zY29yZVxuICAgICAgICAgICAgOiB0eXBlb2YgYW55Ui5kaXN0YW5jZSA9PT0gJ251bWJlcidcbiAgICAgICAgICAgICAgPyAxIC8gKDEgKyBNYXRoLm1heCgwLCBhbnlSLmRpc3RhbmNlKSlcbiAgICAgICAgICAgICAgOiAwO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGlkOiByLmlkLFxuICAgICAgICAgIHNjb3JlLFxuICAgICAgICAgIGNvbnRlbnQ6IHIuY29udGVudCxcbiAgICAgICAgICBtZXRhZGF0YTogSlNPTi5wYXJzZShyLm1ldGFkYXRhIHx8ICd7fScpLFxuICAgICAgICB9O1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gRmFsbGJhY2sgLSBzaW1wbGUgc2VhcmNoXG4gICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy5mYWxsYmFja1N0YXRlLm1lbW9yeS5lbnRyaWVzKCkpXG4gICAgICAuc2xpY2UoMCwgaylcbiAgICAgIC5tYXAoKFtpZCwgZGF0YV0pID0+ICh7XG4gICAgICAgIGlkLFxuICAgICAgICBzY29yZTogMC41LFxuICAgICAgICBjb250ZW50OiBkYXRhLmNvbnRlbnQsXG4gICAgICAgIG1ldGFkYXRhOiBkYXRhLm1ldGFkYXRhLFxuICAgICAgfSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBjb250ZW50IHRvIG1lbW9yeVxuICAgKi9cbiAgYWRkTWVtb3J5KGNvbnRlbnQ6IHN0cmluZywgbWV0YWRhdGE/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IE1lbW9yeUlkIHtcbiAgICBpZiAodGhpcy5uYXRpdmUpIHtcbiAgICAgIHJldHVybiB0aGlzLm5hdGl2ZS5hZGRNZW1vcnkoY29udGVudCwgbWV0YWRhdGEgPyBKU09OLnN0cmluZ2lmeShtZXRhZGF0YSkgOiB1bmRlZmluZWQpO1xuICAgIH1cblxuICAgIC8vIEZhbGxiYWNrXG4gICAgY29uc3QgaWQgPSB0aGlzLmZhbGxiYWNrU3RhdGUubmV4dElkKys7XG4gICAgdGhpcy5mYWxsYmFja1N0YXRlLm1lbW9yeS5zZXQoaWQsIHtcbiAgICAgIGNvbnRlbnQsXG4gICAgICBlbWJlZGRpbmc6IHRoaXMuZW1iZWQoY29udGVudCksXG4gICAgICBtZXRhZGF0YTogbWV0YWRhdGEgPz8ge30sXG4gICAgfSk7XG4gICAgcmV0dXJuIGlkO1xuICB9XG5cbiAgLyoqXG4gICAqIFByb3ZpZGUgZmVlZGJhY2sgZm9yIGxlYXJuaW5nXG4gICAqL1xuICBmZWVkYmFjayhmYjogRmVlZGJhY2spOiBib29sZWFuIHtcbiAgICBpZiAodGhpcy5uYXRpdmUpIHtcbiAgICAgIHJldHVybiB0aGlzLm5hdGl2ZS5mZWVkYmFjayhmYi5yZXF1ZXN0SWQsIGZiLnJhdGluZywgZmIuY29ycmVjdGlvbik7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgZW5naW5lIHN0YXRpc3RpY3NcbiAgICovXG4gIHN0YXRzKCk6IFJ1dkxMTVN0YXRzIHtcbiAgICBpZiAodGhpcy5uYXRpdmUpIHtcbiAgICAgIGNvbnN0IHMgPSB0aGlzLm5hdGl2ZS5zdGF0cygpO1xuICAgICAgLy8gTWFwIG5hdGl2ZSBzdGF0cyAoc25ha2VfY2FzZSkgdG8gVHlwZVNjcmlwdCBpbnRlcmZhY2UgKGNhbWVsQ2FzZSlcbiAgICAgIC8vIEhhbmRsZSBib3RoIG9sZCBhbmQgbmV3IGZpZWxkIG5hbWVzIGZvciBiYWNrd2FyZCBjb21wYXRpYmlsaXR5XG4gICAgICByZXR1cm4ge1xuICAgICAgICB0b3RhbFF1ZXJpZXM6IChzIGFzIGFueSkudG90YWxRdWVyaWVzID8/IHMudG90YWxfcXVlcmllcyA/PyAwLFxuICAgICAgICBtZW1vcnlOb2RlczogKHMgYXMgYW55KS5tZW1vcnlOb2RlcyA/PyBzLm1lbW9yeV9ub2RlcyA/PyAwLFxuICAgICAgICBwYXR0ZXJuc0xlYXJuZWQ6XG4gICAgICAgICAgKHMgYXMgYW55KS50cmFpbmluZ1N0ZXBzID8/XG4gICAgICAgICAgcy5wYXR0ZXJuc19sZWFybmVkID8/XG4gICAgICAgICAgKHMgYXMgYW55KS50cmFpbmluZ19zdGVwcyA/P1xuICAgICAgICAgIDAsXG4gICAgICAgIGF2Z0xhdGVuY3lNczogKHMgYXMgYW55KS5hdmdMYXRlbmN5TXMgPz8gcy5hdmdfbGF0ZW5jeV9tcyA/PyAwLFxuICAgICAgICBjYWNoZUhpdFJhdGU6IChzIGFzIGFueSkuY2FjaGVIaXRSYXRlID8/IHMuY2FjaGVfaGl0X3JhdGUgPz8gMCxcbiAgICAgICAgcm91dGVyQWNjdXJhY3k6IChzIGFzIGFueSkucm91dGVyQWNjdXJhY3kgPz8gcy5yb3V0ZXJfYWNjdXJhY3kgPz8gMC41LFxuICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBGYWxsYmFja1xuICAgIHJldHVybiB7XG4gICAgICB0b3RhbFF1ZXJpZXM6IHRoaXMuZmFsbGJhY2tTdGF0ZS5xdWVyeUNvdW50LFxuICAgICAgbWVtb3J5Tm9kZXM6IHRoaXMuZmFsbGJhY2tTdGF0ZS5tZW1vcnkuc2l6ZSxcbiAgICAgIHBhdHRlcm5zTGVhcm5lZDogMCxcbiAgICAgIGF2Z0xhdGVuY3lNczogMS4wLFxuICAgICAgY2FjaGVIaXRSYXRlOiAwLjAsXG4gICAgICByb3V0ZXJBY2N1cmFjeTogMC41LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogRm9yY2Ugcm91dGVyIGxlYXJuaW5nIGN5Y2xlXG4gICAqL1xuICBmb3JjZUxlYXJuKCk6IHN0cmluZyB7XG4gICAgaWYgKHRoaXMubmF0aXZlKSB7XG4gICAgICByZXR1cm4gdGhpcy5uYXRpdmUuZm9yY2VMZWFybigpO1xuICAgIH1cbiAgICByZXR1cm4gJ0xlYXJuaW5nIG5vdCBhdmFpbGFibGUgaW4gZmFsbGJhY2sgbW9kZSc7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGVtYmVkZGluZyBmb3IgdGV4dFxuICAgKi9cbiAgZW1iZWQodGV4dDogc3RyaW5nKTogRW1iZWRkaW5nIHtcbiAgICBpZiAodGhpcy5uYXRpdmUpIHtcbiAgICAgIHJldHVybiB0aGlzLm5hdGl2ZS5lbWJlZCh0ZXh0KTtcbiAgICB9XG5cbiAgICAvLyBGYWxsYmFjayAtIHNpbXBsZSBoYXNoLWJhc2VkIGVtYmVkZGluZ1xuICAgIGNvbnN0IGRpbSA9IHRoaXMuY29uZmlnLmVtYmVkZGluZ0RpbSA/PyA3Njg7XG4gICAgY29uc3QgZW1iZWRkaW5nID0gbmV3IEFycmF5KGRpbSkuZmlsbCgwKTtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGV4dC5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgaWR4ID0gKHRleHQuY2hhckNvZGVBdChpKSAqIChpICsgMSkpICUgZGltO1xuICAgICAgZW1iZWRkaW5nW2lkeF0gKz0gMC4xO1xuICAgIH1cblxuICAgIC8vIE5vcm1hbGl6ZVxuICAgIGNvbnN0IG5vcm0gPSBNYXRoLnNxcnQoZW1iZWRkaW5nLnJlZHVjZSgoc3VtLCB4KSA9PiBzdW0gKyB4ICogeCwgMCkpIHx8IDE7XG4gICAgcmV0dXJuIGVtYmVkZGluZy5tYXAoeCA9PiB4IC8gbm9ybSk7XG4gIH1cblxuICAvKipcbiAgICogQ29tcHV0ZSBzaW1pbGFyaXR5IGJldHdlZW4gdHdvIHRleHRzXG4gICAqL1xuICBzaW1pbGFyaXR5KHRleHQxOiBzdHJpbmcsIHRleHQyOiBzdHJpbmcpOiBudW1iZXIge1xuICAgIGlmICh0aGlzLm5hdGl2ZSkge1xuICAgICAgLy8gZjMyIGFjY3VtdWxhdGlvbiBjYW4gbGFuZCBqdXN0IG91dHNpZGUgdGhlIG1hdGhlbWF0aWNhbCByYW5nZSDigJQgYW5cbiAgICAgIC8vIGlkZW50aWNhbCBwYWlyIG1lYXN1cmVzIDEuMDAwMDAwMSDigJQgd2hpY2ggdHVybnMgTWF0aC5hY29zKHNpbSkgaW50b1xuICAgICAgLy8gTmFOIGRvd25zdHJlYW0uIENvc2luZSBzaW1pbGFyaXR5IGlzIGRlZmluZWQgb24gWy0xLCAxXSwgc28gY2xhbXAuXG4gICAgICBjb25zdCByYXcgPSB0aGlzLm5hdGl2ZS5zaW1pbGFyaXR5KHRleHQxLCB0ZXh0Mik7XG4gICAgICByZXR1cm4gTWF0aC5taW4oMSwgTWF0aC5tYXgoLTEsIHJhdykpO1xuICAgIH1cblxuICAgIC8vIEZhbGxiYWNrIC0gY29zaW5lIHNpbWlsYXJpdHlcbiAgICBjb25zdCBlbWIxID0gdGhpcy5lbWJlZCh0ZXh0MSk7XG4gICAgY29uc3QgZW1iMiA9IHRoaXMuZW1iZWQodGV4dDIpO1xuXG4gICAgbGV0IGRvdCA9IDA7XG4gICAgbGV0IG5vcm0xID0gMDtcbiAgICBsZXQgbm9ybTIgPSAwO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBlbWIxLmxlbmd0aDsgaSsrKSB7XG4gICAgICBkb3QgKz0gZW1iMVtpXSAqIGVtYjJbaV07XG4gICAgICBub3JtMSArPSBlbWIxW2ldICogZW1iMVtpXTtcbiAgICAgIG5vcm0yICs9IGVtYjJbaV0gKiBlbWIyW2ldO1xuICAgIH1cblxuICAgIGNvbnN0IGRlbm9tID0gTWF0aC5zcXJ0KG5vcm0xKSAqIE1hdGguc3FydChub3JtMik7XG4gICAgY29uc3Qgc2ltaWxhcml0eSA9IGRlbm9tID4gMCA/IGRvdCAvIGRlbm9tIDogMDtcbiAgICAvLyBDbGFtcCB0byBbMCwgMV0gdG8gaGFuZGxlIGZsb2F0aW5nIHBvaW50IGVycm9yc1xuICAgIHJldHVybiBNYXRoLm1heCgwLCBNYXRoLm1pbigxLCBzaW1pbGFyaXR5KSk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgaWYgU0lNRCBpcyBhdmFpbGFibGVcbiAgICovXG4gIGhhc1NpbWQoKTogYm9vbGVhbiB7XG4gICAgaWYgKHRoaXMubmF0aXZlKSB7XG4gICAgICByZXR1cm4gdGhpcy5uYXRpdmUuaGFzU2ltZCgpO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogR2V0IFNJTUQgY2FwYWJpbGl0aWVzXG4gICAqL1xuICBzaW1kQ2FwYWJpbGl0aWVzKCk6IHN0cmluZ1tdIHtcbiAgICBpZiAodGhpcy5uYXRpdmUpIHtcbiAgICAgIHJldHVybiB0aGlzLm5hdGl2ZS5zaW1kQ2FwYWJpbGl0aWVzKCk7XG4gICAgfVxuICAgIHJldHVybiBbJ1NjYWxhciAoZmFsbGJhY2spJ107XG4gIH1cblxuICAvKipcbiAgICogQmF0Y2ggcXVlcnkgbXVsdGlwbGUgcHJvbXB0c1xuICAgKi9cbiAgYmF0Y2hRdWVyeShyZXF1ZXN0OiBCYXRjaFF1ZXJ5UmVxdWVzdCk6IEJhdGNoUXVlcnlSZXNwb25zZSB7XG4gICAgY29uc3Qgc3RhcnQgPSBEYXRlLm5vdygpO1xuICAgIGNvbnN0IHJlc3BvbnNlcyA9IHJlcXVlc3QucXVlcmllcy5tYXAocSA9PiB0aGlzLnF1ZXJ5KHEsIHJlcXVlc3QuY29uZmlnKSk7XG4gICAgcmV0dXJuIHtcbiAgICAgIHJlc3BvbnNlcyxcbiAgICAgIHRvdGFsTGF0ZW5jeU1zOiBEYXRlLm5vdygpIC0gc3RhcnQsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiBuYXRpdmUgbW9kdWxlIGlzIGxvYWRlZFxuICAgKi9cbiAgaXNOYXRpdmVMb2FkZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMubmF0aXZlICE9PSBudWxsO1xuICB9XG59XG4iXX0=