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