@ruvector/ruvllm 2.7.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/GPU-LOOP.md +229 -0
  2. package/LICENSE +201 -0
  3. package/NOTICE +9 -0
  4. package/README.md +157 -263
  5. package/examples/gpu-loop.example.json +26 -0
  6. package/package.json +50 -120
  7. package/src/adapters-cli.mjs +23 -0
  8. package/src/adapters.mjs +91 -0
  9. package/src/cli.mjs +30 -0
  10. package/src/engine.mjs +238 -0
  11. package/src/fixture.mjs +38 -0
  12. package/src/gpu-host.mjs +47 -0
  13. package/src/gpu-loop-cli.mjs +67 -0
  14. package/src/gpu-loop.mjs +184 -0
  15. package/src/gpu-spool-adapter.mjs +80 -0
  16. package/src/vast-host-adapter.mjs +274 -0
  17. package/bin/cli.js +0 -1020
  18. package/dist/cjs/benchmarks/embedding-benchmark.d.ts +0 -102
  19. package/dist/cjs/benchmarks/embedding-benchmark.d.ts.map +0 -1
  20. package/dist/cjs/benchmarks/embedding-benchmark.js +0 -436
  21. package/dist/cjs/benchmarks/index.d.ts +0 -34
  22. package/dist/cjs/benchmarks/index.d.ts.map +0 -1
  23. package/dist/cjs/benchmarks/index.js +0 -132
  24. package/dist/cjs/benchmarks/model-comparison.d.ts +0 -71
  25. package/dist/cjs/benchmarks/model-comparison.d.ts.map +0 -1
  26. package/dist/cjs/benchmarks/model-comparison.js +0 -476
  27. package/dist/cjs/benchmarks/routing-benchmark.d.ts +0 -70
  28. package/dist/cjs/benchmarks/routing-benchmark.d.ts.map +0 -1
  29. package/dist/cjs/benchmarks/routing-benchmark.js +0 -289
  30. package/dist/cjs/contrastive.d.ts +0 -229
  31. package/dist/cjs/contrastive.d.ts.map +0 -1
  32. package/dist/cjs/contrastive.js +0 -589
  33. package/dist/cjs/engine.d.ts +0 -95
  34. package/dist/cjs/engine.d.ts.map +0 -1
  35. package/dist/cjs/engine.js +0 -372
  36. package/dist/cjs/export.d.ts +0 -182
  37. package/dist/cjs/export.d.ts.map +0 -1
  38. package/dist/cjs/export.js +0 -422
  39. package/dist/cjs/federated.d.ts +0 -233
  40. package/dist/cjs/federated.d.ts.map +0 -1
  41. package/dist/cjs/federated.js +0 -525
  42. package/dist/cjs/index.d.ts +0 -68
  43. package/dist/cjs/index.d.ts.map +0 -1
  44. package/dist/cjs/index.js +0 -104
  45. package/dist/cjs/intelligence.d.ts +0 -136
  46. package/dist/cjs/intelligence.d.ts.map +0 -1
  47. package/dist/cjs/intelligence.js +0 -226
  48. package/dist/cjs/lora.d.ts +0 -251
  49. package/dist/cjs/lora.d.ts.map +0 -1
  50. package/dist/cjs/lora.js +0 -509
  51. package/dist/cjs/models.d.ts +0 -129
  52. package/dist/cjs/models.d.ts.map +0 -1
  53. package/dist/cjs/models.js +0 -323
  54. package/dist/cjs/native.d.ts +0 -92
  55. package/dist/cjs/native.d.ts.map +0 -1
  56. package/dist/cjs/native.js +0 -77
  57. package/dist/cjs/session.d.ts +0 -80
  58. package/dist/cjs/session.d.ts.map +0 -1
  59. package/dist/cjs/session.js +0 -203
  60. package/dist/cjs/simd.d.ts +0 -90
  61. package/dist/cjs/simd.d.ts.map +0 -1
  62. package/dist/cjs/simd.js +0 -209
  63. package/dist/cjs/sona.d.ts +0 -223
  64. package/dist/cjs/sona.d.ts.map +0 -1
  65. package/dist/cjs/sona.js +0 -562
  66. package/dist/cjs/streaming.d.ts +0 -55
  67. package/dist/cjs/streaming.d.ts.map +0 -1
  68. package/dist/cjs/streaming.js +0 -131
  69. package/dist/cjs/training.d.ts +0 -312
  70. package/dist/cjs/training.d.ts.map +0 -1
  71. package/dist/cjs/training.js +0 -610
  72. package/dist/cjs/types.d.ts +0 -615
  73. package/dist/cjs/types.d.ts.map +0 -1
  74. package/dist/cjs/types.js +0 -6
  75. package/dist/esm/benchmarks/embedding-benchmark.d.ts +0 -102
  76. package/dist/esm/benchmarks/embedding-benchmark.d.ts.map +0 -1
  77. package/dist/esm/benchmarks/embedding-benchmark.js +0 -427
  78. package/dist/esm/benchmarks/index.d.ts +0 -34
  79. package/dist/esm/benchmarks/index.d.ts.map +0 -1
  80. package/dist/esm/benchmarks/index.js +0 -110
  81. package/dist/esm/benchmarks/model-comparison.d.ts +0 -71
  82. package/dist/esm/benchmarks/model-comparison.d.ts.map +0 -1
  83. package/dist/esm/benchmarks/model-comparison.js +0 -434
  84. package/dist/esm/benchmarks/routing-benchmark.d.ts +0 -70
  85. package/dist/esm/benchmarks/routing-benchmark.d.ts.map +0 -1
  86. package/dist/esm/benchmarks/routing-benchmark.js +0 -283
  87. package/dist/esm/contrastive.d.ts +0 -229
  88. package/dist/esm/contrastive.d.ts.map +0 -1
  89. package/dist/esm/contrastive.js +0 -578
  90. package/dist/esm/engine.d.ts +0 -95
  91. package/dist/esm/engine.d.ts.map +0 -1
  92. package/dist/esm/engine.js +0 -368
  93. package/dist/esm/export.d.ts +0 -182
  94. package/dist/esm/export.d.ts.map +0 -1
  95. package/dist/esm/export.js +0 -414
  96. package/dist/esm/federated.d.ts +0 -233
  97. package/dist/esm/federated.d.ts.map +0 -1
  98. package/dist/esm/federated.js +0 -520
  99. package/dist/esm/index.d.ts +0 -68
  100. package/dist/esm/index.d.ts.map +0 -1
  101. package/dist/esm/index.js +0 -84
  102. package/dist/esm/intelligence.d.ts +0 -136
  103. package/dist/esm/intelligence.d.ts.map +0 -1
  104. package/dist/esm/intelligence.js +0 -188
  105. package/dist/esm/lora.d.ts +0 -251
  106. package/dist/esm/lora.d.ts.map +0 -1
  107. package/dist/esm/lora.js +0 -504
  108. package/dist/esm/models.d.ts +0 -129
  109. package/dist/esm/models.d.ts.map +0 -1
  110. package/dist/esm/models.js +0 -282
  111. package/dist/esm/native.d.ts +0 -92
  112. package/dist/esm/native.d.ts.map +0 -1
  113. package/dist/esm/native.js +0 -72
  114. package/dist/esm/session.d.ts +0 -80
  115. package/dist/esm/session.d.ts.map +0 -1
  116. package/dist/esm/session.js +0 -199
  117. package/dist/esm/simd.d.ts +0 -90
  118. package/dist/esm/simd.d.ts.map +0 -1
  119. package/dist/esm/simd.js +0 -205
  120. package/dist/esm/sona.d.ts +0 -223
  121. package/dist/esm/sona.d.ts.map +0 -1
  122. package/dist/esm/sona.js +0 -556
  123. package/dist/esm/streaming.d.ts +0 -55
  124. package/dist/esm/streaming.d.ts.map +0 -1
  125. package/dist/esm/streaming.js +0 -126
  126. package/dist/esm/training.d.ts +0 -312
  127. package/dist/esm/training.d.ts.map +0 -1
  128. package/dist/esm/training.js +0 -603
  129. package/dist/esm/types.d.ts +0 -615
  130. package/dist/esm/types.d.ts.map +0 -1
  131. package/dist/esm/types.js +0 -5
  132. package/scripts/ensemble-model-compare.js +0 -287
  133. package/scripts/fix-esm-extensions.mjs +0 -181
  134. package/scripts/huggingface/README.md +0 -537
  135. package/scripts/huggingface/publish.sh +0 -112
  136. package/scripts/hybrid-model-compare.js +0 -373
  137. package/scripts/improved-model-compare.js +0 -288
  138. package/scripts/optimized-model-compare.js +0 -364
  139. package/scripts/real-model-compare.js +0 -280
  140. package/scripts/smoke-esm.mjs +0 -82
  141. package/scripts/training/agentic-flow-capabilities.json +0 -329
  142. package/scripts/training/claude-code-synth.js +0 -505
  143. package/scripts/training/claude-flow-capabilities.json +0 -1322
  144. package/scripts/training/claude-hard-negatives.js +0 -222
  145. package/scripts/training/contrastive-finetune.js +0 -517
  146. package/scripts/training/ecosystem-triplets.jsonl +0 -1467
  147. package/scripts/training/generate-ecosystem-triplets.js +0 -1324
  148. package/scripts/training/routing-dataset.js +0 -634
  149. package/scripts/training/ruvector-capabilities.json +0 -798
  150. package/scripts/training/validate-ecosystem.js +0 -381
  151. package/scripts/training/validation-results.json +0 -23
@@ -1,95 +0,0 @@
1
- /**
2
- * RuvLLM Engine - Main orchestrator for self-learning LLM
3
- */
4
- import { RuvLLMConfig, GenerationConfig, QueryResponse, RoutingDecision, MemoryResult, MemoryId, RuvLLMStats, Feedback, Embedding, BatchQueryRequest, BatchQueryResponse } from './types.js';
5
- /**
6
- * RuvLLM - Self-learning LLM orchestrator
7
- *
8
- * Combines SONA adaptive learning with HNSW memory,
9
- * FastGRNN routing, and SIMD-optimized inference.
10
- *
11
- * @example
12
- * ```typescript
13
- * import { RuvLLM } from '@ruvector/ruvllm';
14
- *
15
- * const llm = new RuvLLM({ embeddingDim: 768 });
16
- *
17
- * // Query with automatic routing
18
- * const response = await llm.query('What is machine learning?');
19
- * console.log(response.text);
20
- *
21
- * // Provide feedback for learning
22
- * llm.feedback({ requestId: response.requestId, rating: 5 });
23
- * ```
24
- */
25
- export declare class RuvLLM {
26
- private native;
27
- private config;
28
- private fallbackState;
29
- /**
30
- * Create a new RuvLLM instance
31
- */
32
- constructor(config?: RuvLLMConfig);
33
- /**
34
- * Query the LLM with automatic routing
35
- */
36
- query(text: string, config?: GenerationConfig): QueryResponse;
37
- /**
38
- * Generate text with SIMD-optimized inference
39
- *
40
- * Note: the native engine has no language-model weights, so its text is
41
- * not model output; the first call emits a `RUVLLM_NO_LANGUAGE_MODEL`
42
- * warning (or throws with `strict: true`). Without the native module this
43
- * returns an informational message.
44
- */
45
- generate(prompt: string, config?: GenerationConfig): string;
46
- /**
47
- * Get routing decision for a query
48
- */
49
- route(text: string): RoutingDecision;
50
- /**
51
- * Search memory for similar content
52
- */
53
- searchMemory(text: string, k?: number): MemoryResult[];
54
- /**
55
- * Add content to memory
56
- */
57
- addMemory(content: string, metadata?: Record<string, unknown>): MemoryId;
58
- /**
59
- * Provide feedback for learning
60
- */
61
- feedback(fb: Feedback): boolean;
62
- /**
63
- * Get engine statistics
64
- */
65
- stats(): RuvLLMStats;
66
- /**
67
- * Force router learning cycle
68
- */
69
- forceLearn(): string;
70
- /**
71
- * Get embedding for text
72
- */
73
- embed(text: string): Embedding;
74
- /**
75
- * Compute similarity between two texts
76
- */
77
- similarity(text1: string, text2: string): number;
78
- /**
79
- * Check if SIMD is available
80
- */
81
- hasSimd(): boolean;
82
- /**
83
- * Get SIMD capabilities
84
- */
85
- simdCapabilities(): string[];
86
- /**
87
- * Batch query multiple prompts
88
- */
89
- batchQuery(request: BatchQueryRequest): BatchQueryResponse;
90
- /**
91
- * Check if native module is loaded
92
- */
93
- isNativeLoaded(): boolean;
94
- }
95
- //# sourceMappingURL=engine.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/engine.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,SAAS,CAAC;AA+DjB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,MAAM,CAAe;IAG7B,OAAO,CAAC,aAAa,CAInB;IAEF;;OAEG;gBACS,MAAM,CAAC,EAAE,YAAY;IAwBjC;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,gBAAgB,GAAG,aAAa;IA6B7D;;;;;;;OAOG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,gBAAgB,GAAG,MAAM;IA0B3D;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe;IAsBpC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,SAAK,GAAG,YAAY,EAAE;IAmClD;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ;IAexE;;OAEG;IACH,QAAQ,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO;IAO/B;;OAEG;IACH,KAAK,IAAI,WAAW;IA8BpB;;OAEG;IACH,UAAU,IAAI,MAAM;IAOpB;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS;IAmB9B;;OAEG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IA6BhD;;OAEG;IACH,OAAO,IAAI,OAAO;IAOlB;;OAEG;IACH,gBAAgB,IAAI,MAAM,EAAE;IAO5B;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,kBAAkB;IAS1D;;OAEG;IACH,cAAc,IAAI,OAAO;CAG1B"}
@@ -1,368 +0,0 @@
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
- return {
29
- max_tokens: config.maxTokens,
30
- temperature: config.temperature,
31
- top_p: config.topP,
32
- top_k: config.topK,
33
- repetition_penalty: config.repetitionPenalty,
34
- };
35
- }
36
- const warned = new Set();
37
- /** Warn once per process (or throw when `strict`). */
38
- function notice(code, message, strict) {
39
- if (strict)
40
- throw new Error(`${code}: ${message}`);
41
- if (warned.has(code))
42
- return;
43
- warned.add(code);
44
- const g = globalThis;
45
- if (typeof g.process?.emitWarning === 'function')
46
- g.process.emitWarning(message, { code });
47
- else
48
- g.console?.warn?.(`${code}: ${message}`);
49
- }
50
- const NO_LM_MESSAGE = 'the native RuvLLM engine has no language-model weights, so generate()/query() text is ' +
51
- 'not model output. For GGUF inference use the ruvllm CLI (`ruvllm serve <model> --strict`) ' +
52
- 'or another OpenAI-compatible server. Routing, memory and embeddings are unaffected. ' +
53
- 'Pass { strict: true } to throw instead.';
54
- /**
55
- * RuvLLM - Self-learning LLM orchestrator
56
- *
57
- * Combines SONA adaptive learning with HNSW memory,
58
- * FastGRNN routing, and SIMD-optimized inference.
59
- *
60
- * @example
61
- * ```typescript
62
- * import { RuvLLM } from '@ruvector/ruvllm';
63
- *
64
- * const llm = new RuvLLM({ embeddingDim: 768 });
65
- *
66
- * // Query with automatic routing
67
- * const response = await llm.query('What is machine learning?');
68
- * console.log(response.text);
69
- *
70
- * // Provide feedback for learning
71
- * llm.feedback({ requestId: response.requestId, rating: 5 });
72
- * ```
73
- */
74
- export class RuvLLM {
75
- /**
76
- * Create a new RuvLLM instance
77
- */
78
- constructor(config) {
79
- this.native = null;
80
- // Fallback state for when native module is not available
81
- this.fallbackState = {
82
- memory: new Map(),
83
- nextId: 1,
84
- queryCount: 0,
85
- };
86
- this.config = config ?? {};
87
- const extra = this.config;
88
- for (const key of ['modelPath', 'backend']) {
89
- if (extra[key] !== undefined) {
90
- notice('RUVLLM_UNSUPPORTED_OPTION', `\`${key}\` is not supported by @ruvector/ruvllm and is ignored: this package does not ` +
91
- 'load model files. For GGUF inference use the ruvllm CLI (`ruvllm serve <model> --strict`).', this.config.strict);
92
- }
93
- }
94
- const mod = getNativeModule();
95
- if (mod) {
96
- try {
97
- this.native = new mod.RuvLLMEngine(toNativeConfig(config));
98
- }
99
- catch {
100
- // Silently fall back to JS implementation
101
- }
102
- }
103
- }
104
- /**
105
- * Query the LLM with automatic routing
106
- */
107
- query(text, config) {
108
- if (this.native) {
109
- notice('RUVLLM_NO_LANGUAGE_MODEL', NO_LM_MESSAGE, this.config.strict);
110
- const result = this.native.query(text, toNativeGenConfig(config));
111
- // napi-rs camelCases Rust field names on the way out, so the native
112
- // object carries `contextSize`/`latencyMs`/`requestId`. The snake_case
113
- // reads are kept as a fallback for older native builds.
114
- return {
115
- text: result.text,
116
- confidence: result.confidence,
117
- model: result.model,
118
- contextSize: result.contextSize ?? result.context_size,
119
- latencyMs: result.latencyMs ?? result.latency_ms,
120
- requestId: result.requestId ?? result.request_id,
121
- };
122
- }
123
- // Fallback implementation
124
- this.fallbackState.queryCount++;
125
- return {
126
- text: `[Fallback] Response to: ${text.slice(0, 50)}...`,
127
- confidence: 0.5,
128
- model: 'fallback',
129
- contextSize: 512,
130
- latencyMs: 1.0,
131
- requestId: `fb-${Date.now()}-${Math.random().toString(36).slice(2)}`,
132
- };
133
- }
134
- /**
135
- * Generate text with SIMD-optimized inference
136
- *
137
- * Note: the native engine has no language-model weights, so its text is
138
- * not model output; the first call emits a `RUVLLM_NO_LANGUAGE_MODEL`
139
- * warning (or throws with `strict: true`). Without the native module this
140
- * returns an informational message.
141
- */
142
- generate(prompt, config) {
143
- if (this.native) {
144
- notice('RUVLLM_NO_LANGUAGE_MODEL', NO_LM_MESSAGE, this.config.strict);
145
- return this.native.generate(prompt, toNativeGenConfig(config));
146
- }
147
- // Fallback - provide helpful message instead of garbled output
148
- const maxTokens = config?.maxTokens ?? 256;
149
- const temp = config?.temperature ?? 0.7;
150
- const topP = config?.topP ?? 0.9;
151
- return `[RuvLLM JavaScript Fallback Mode]
152
- No native SIMD module loaded. Running in JavaScript fallback mode.
153
-
154
- Your prompt: "${prompt.slice(0, 100)}${prompt.length > 100 ? '...' : ''}"
155
-
156
- To enable native SIMD inference:
157
- 1. Install the native bindings: npm install @ruvector/ruvllm-${process.platform}-${process.arch}
158
- 2. Or load a GGUF model file
159
- 3. Or connect to an external LLM API
160
-
161
- Config: temp=${temp.toFixed(2)}, top_p=${topP.toFixed(2)}, max_tokens=${maxTokens}
162
-
163
- This fallback provides routing, memory, and embedding features but not full text generation.`;
164
- }
165
- /**
166
- * Get routing decision for a query
167
- */
168
- route(text) {
169
- if (this.native) {
170
- const result = this.native.route(text);
171
- return {
172
- model: result.model,
173
- contextSize: result.contextSize ?? result.context_size,
174
- temperature: result.temperature,
175
- topP: result.topP ?? result.top_p,
176
- confidence: result.confidence,
177
- };
178
- }
179
- // Fallback
180
- return {
181
- model: 'M700',
182
- contextSize: 512,
183
- temperature: 0.7,
184
- topP: 0.9,
185
- confidence: 0.5,
186
- };
187
- }
188
- /**
189
- * Search memory for similar content
190
- */
191
- searchMemory(text, k = 10) {
192
- if (this.native) {
193
- const results = this.native.searchMemory(text, k);
194
- return results.map(r => {
195
- // The native side reports `distance` (smaller is closer). MemoryResult
196
- // documents `score` as a similarity, so convert rather than passing a
197
- // distance through under a similarity's name. Older builds that already
198
- // emit `score` are used as-is.
199
- const anyR = r;
200
- const score = typeof anyR.score === 'number'
201
- ? anyR.score
202
- : typeof anyR.distance === 'number'
203
- ? 1 / (1 + Math.max(0, anyR.distance))
204
- : 0;
205
- return {
206
- id: r.id,
207
- score,
208
- content: r.content,
209
- metadata: JSON.parse(r.metadata || '{}'),
210
- };
211
- });
212
- }
213
- // Fallback - simple search
214
- return Array.from(this.fallbackState.memory.entries())
215
- .slice(0, k)
216
- .map(([id, data]) => ({
217
- id,
218
- score: 0.5,
219
- content: data.content,
220
- metadata: data.metadata,
221
- }));
222
- }
223
- /**
224
- * Add content to memory
225
- */
226
- addMemory(content, metadata) {
227
- if (this.native) {
228
- return this.native.addMemory(content, metadata ? JSON.stringify(metadata) : undefined);
229
- }
230
- // Fallback
231
- const id = this.fallbackState.nextId++;
232
- this.fallbackState.memory.set(id, {
233
- content,
234
- embedding: this.embed(content),
235
- metadata: metadata ?? {},
236
- });
237
- return id;
238
- }
239
- /**
240
- * Provide feedback for learning
241
- */
242
- feedback(fb) {
243
- if (this.native) {
244
- return this.native.feedback(fb.requestId, fb.rating, fb.correction);
245
- }
246
- return false;
247
- }
248
- /**
249
- * Get engine statistics
250
- */
251
- stats() {
252
- if (this.native) {
253
- const s = this.native.stats();
254
- // Map native stats (snake_case) to TypeScript interface (camelCase)
255
- // Handle both old and new field names for backward compatibility
256
- return {
257
- totalQueries: s.totalQueries ?? s.total_queries ?? 0,
258
- memoryNodes: s.memoryNodes ?? s.memory_nodes ?? 0,
259
- patternsLearned: s.trainingSteps ??
260
- s.patterns_learned ??
261
- s.training_steps ??
262
- 0,
263
- avgLatencyMs: s.avgLatencyMs ?? s.avg_latency_ms ?? 0,
264
- cacheHitRate: s.cacheHitRate ?? s.cache_hit_rate ?? 0,
265
- routerAccuracy: s.routerAccuracy ?? s.router_accuracy ?? 0.5,
266
- };
267
- }
268
- // Fallback
269
- return {
270
- totalQueries: this.fallbackState.queryCount,
271
- memoryNodes: this.fallbackState.memory.size,
272
- patternsLearned: 0,
273
- avgLatencyMs: 1.0,
274
- cacheHitRate: 0.0,
275
- routerAccuracy: 0.5,
276
- };
277
- }
278
- /**
279
- * Force router learning cycle
280
- */
281
- forceLearn() {
282
- if (this.native) {
283
- return this.native.forceLearn();
284
- }
285
- return 'Learning not available in fallback mode';
286
- }
287
- /**
288
- * Get embedding for text
289
- */
290
- embed(text) {
291
- if (this.native) {
292
- return this.native.embed(text);
293
- }
294
- // Fallback - simple hash-based embedding
295
- const dim = this.config.embeddingDim ?? 768;
296
- const embedding = new Array(dim).fill(0);
297
- for (let i = 0; i < text.length; i++) {
298
- const idx = (text.charCodeAt(i) * (i + 1)) % dim;
299
- embedding[idx] += 0.1;
300
- }
301
- // Normalize
302
- const norm = Math.sqrt(embedding.reduce((sum, x) => sum + x * x, 0)) || 1;
303
- return embedding.map(x => x / norm);
304
- }
305
- /**
306
- * Compute similarity between two texts
307
- */
308
- similarity(text1, text2) {
309
- if (this.native) {
310
- // f32 accumulation can land just outside the mathematical range — an
311
- // identical pair measures 1.0000001 — which turns Math.acos(sim) into
312
- // NaN downstream. Cosine similarity is defined on [-1, 1], so clamp.
313
- const raw = this.native.similarity(text1, text2);
314
- return Math.min(1, Math.max(-1, raw));
315
- }
316
- // Fallback - cosine similarity
317
- const emb1 = this.embed(text1);
318
- const emb2 = this.embed(text2);
319
- let dot = 0;
320
- let norm1 = 0;
321
- let norm2 = 0;
322
- for (let i = 0; i < emb1.length; i++) {
323
- dot += emb1[i] * emb2[i];
324
- norm1 += emb1[i] * emb1[i];
325
- norm2 += emb2[i] * emb2[i];
326
- }
327
- const denom = Math.sqrt(norm1) * Math.sqrt(norm2);
328
- const similarity = denom > 0 ? dot / denom : 0;
329
- // Clamp to [0, 1] to handle floating point errors
330
- return Math.max(0, Math.min(1, similarity));
331
- }
332
- /**
333
- * Check if SIMD is available
334
- */
335
- hasSimd() {
336
- if (this.native) {
337
- return this.native.hasSimd();
338
- }
339
- return false;
340
- }
341
- /**
342
- * Get SIMD capabilities
343
- */
344
- simdCapabilities() {
345
- if (this.native) {
346
- return this.native.simdCapabilities();
347
- }
348
- return ['Scalar (fallback)'];
349
- }
350
- /**
351
- * Batch query multiple prompts
352
- */
353
- batchQuery(request) {
354
- const start = Date.now();
355
- const responses = request.queries.map(q => this.query(q, request.config));
356
- return {
357
- responses,
358
- totalLatencyMs: Date.now() - start,
359
- };
360
- }
361
- /**
362
- * Check if native module is loaded
363
- */
364
- isNativeLoaded() {
365
- return this.native !== null;
366
- }
367
- }
368
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW5naW5lLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2VuZ2luZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQWdCSCxPQUFPLEVBQ0wsZUFBZSxHQUloQixNQUFNLFVBQVUsQ0FBQztBQUVsQjs7R0FFRztBQUNILFNBQVMsY0FBYyxDQUFDLE1BQXFCO0lBQzNDLElBQUksQ0FBQyxNQUFNO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFFOUIsT0FBTztRQUNMLGFBQWEsRUFBRSxNQUFNLENBQUMsWUFBWTtRQUNsQyxpQkFBaUIsRUFBRSxNQUFNLENBQUMsZUFBZTtRQUN6QyxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUs7UUFDcEIsb0JBQW9CLEVBQUUsTUFBTSxDQUFDLGtCQUFrQjtRQUMvQyxjQUFjLEVBQUUsTUFBTSxDQUFDLFlBQVk7UUFDbkMsZ0JBQWdCLEVBQUUsTUFBTSxDQUFDLGVBQWU7UUFDeEMsaUJBQWlCLEVBQUUsTUFBTSxDQUFDLGdCQUFnQjtRQUMxQyxVQUFVLEVBQUUsTUFBTSxDQUFDLFNBQVM7S0FDN0IsQ0FBQztBQUNKLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQVMsaUJBQWlCLENBQUMsTUFBeUI7SUFDbEQsSUFBSSxDQUFDLE1BQU07UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUU5QixPQUFPO1FBQ0wsVUFBVSxFQUFFLE1BQU0sQ0FBQyxTQUFTO1FBQzVCLFdBQVcsRUFBRSxNQUFNLENBQUMsV0FBVztRQUMvQixLQUFLLEVBQUUsTUFBTSxDQUFDLElBQUk7UUFDbEIsS0FBSyxFQUFFLE1BQU0sQ0FBQyxJQUFJO1FBQ2xCLGtCQUFrQixFQUFFLE1BQU0sQ0FBQyxpQkFBaUI7S0FDN0MsQ0FBQztBQUNKLENBQUM7QUFFRCxNQUFNLE1BQU0sR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO0FBRWpDLHNEQUFzRDtBQUN0RCxTQUFTLE1BQU0sQ0FBQyxJQUFZLEVBQUUsT0FBZSxFQUFFLE1BQTJCO0lBQ3hFLElBQUksTUFBTTtRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsR0FBRyxJQUFJLEtBQUssT0FBTyxFQUFFLENBQUMsQ0FBQztJQUNuRCxJQUFJLE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDO1FBQUUsT0FBTztJQUM3QixNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2pCLE1BQU0sQ0FBQyxHQUFHLFVBR1QsQ0FBQztJQUNGLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLFdBQVcsS0FBSyxVQUFVO1FBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsT0FBTyxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQzs7UUFDdEYsQ0FBQyxDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQyxHQUFHLElBQUksS0FBSyxPQUFPLEVBQUUsQ0FBQyxDQUFDO0FBQ2hELENBQUM7QUFFRCxNQUFNLGFBQWEsR0FDakIsd0ZBQXdGO0lBQ3hGLDRGQUE0RjtJQUM1RixzRkFBc0Y7SUFDdEYseUNBQXlDLENBQUM7QUFFNUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQkc7QUFDSCxNQUFNLE9BQU8sTUFBTTtJQVdqQjs7T0FFRztJQUNILFlBQVksTUFBcUI7UUFiekIsV0FBTSxHQUF3QixJQUFJLENBQUM7UUFHM0MseURBQXlEO1FBQ2pELGtCQUFhLEdBQUc7WUFDdEIsTUFBTSxFQUFFLElBQUksR0FBRyxFQUF1RjtZQUN0RyxNQUFNLEVBQUUsQ0FBQztZQUNULFVBQVUsRUFBRSxDQUFDO1NBQ2QsQ0FBQztRQU1BLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxJQUFJLEVBQUUsQ0FBQztRQUMzQixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBaUMsQ0FBQztRQUNyRCxLQUFLLE1BQU0sR0FBRyxJQUFJLENBQUMsV0FBVyxFQUFFLFNBQVMsQ0FBQyxFQUFFLENBQUM7WUFDM0MsSUFBSSxLQUFLLENBQUMsR0FBRyxDQUFDLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQzdCLE1BQU0sQ0FDSiwyQkFBMkIsRUFDM0IsS0FBSyxHQUFHLGdGQUFnRjtvQkFDdEYsNEZBQTRGLEVBQzlGLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUNuQixDQUFDO1lBQ0osQ0FBQztRQUNILENBQUM7UUFFRCxNQUFNLEdBQUcsR0FBRyxlQUFlLEVBQUUsQ0FBQztRQUM5QixJQUFJLEdBQUcsRUFBRSxDQUFDO1lBQ1IsSUFBSSxDQUFDO2dCQUNILElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxHQUFHLENBQUMsWUFBWSxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1lBQzdELENBQUM7WUFBQyxNQUFNLENBQUM7Z0JBQ1AsMENBQTBDO1lBQzVDLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLElBQVksRUFBRSxNQUF5QjtRQUMzQyxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNoQixNQUFNLENBQUMsMEJBQTBCLEVBQUUsYUFBYSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDdEUsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7WUFDbEUsb0VBQW9FO1lBQ3BFLHVFQUF1RTtZQUN2RSx3REFBd0Q7WUFDeEQsT0FBTztnQkFDTCxJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUk7Z0JBQ2pCLFVBQVUsRUFBRSxNQUFNLENBQUMsVUFBVTtnQkFDN0IsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFLO2dCQUNuQixXQUFXLEVBQUUsTUFBTSxDQUFDLFdBQVcsSUFBSSxNQUFNLENBQUMsWUFBWTtnQkFDdEQsU0FBUyxFQUFFLE1BQU0sQ0FBQyxTQUFTLElBQUksTUFBTSxDQUFDLFVBQVU7Z0JBQ2hELFNBQVMsRUFBRSxNQUFNLENBQUMsU0FBUyxJQUFJLE1BQU0sQ0FBQyxVQUFVO2FBQ2pELENBQUM7UUFDSixDQUFDO1FBRUQsMEJBQTBCO1FBQzFCLElBQUksQ0FBQyxhQUFhLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDaEMsT0FBTztZQUNMLElBQUksRUFBRSwyQkFBMkIsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEtBQUs7WUFDdkQsVUFBVSxFQUFFLEdBQUc7WUFDZixLQUFLLEVBQUUsVUFBVTtZQUNqQixXQUFXLEVBQUUsR0FBRztZQUNoQixTQUFTLEVBQUUsR0FBRztZQUNkLFNBQVMsRUFBRSxNQUFNLElBQUksQ0FBQyxHQUFHLEVBQUUsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRTtTQUNyRSxDQUFDO0lBQ0osQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSCxRQUFRLENBQUMsTUFBYyxFQUFFLE1BQXlCO1FBQ2hELElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2hCLE1BQU0sQ0FBQywwQkFBMEIsRUFBRSxhQUFhLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUN0RSxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ2pFLENBQUM7UUFFRCwrREFBK0Q7UUFDL0QsTUFBTSxTQUFTLEdBQUcsTUFBTSxFQUFFLFNBQVMsSUFBSSxHQUFHLENBQUM7UUFDM0MsTUFBTSxJQUFJLEdBQUcsTUFBTSxFQUFFLFdBQVcsSUFBSSxHQUFHLENBQUM7UUFDeEMsTUFBTSxJQUFJLEdBQUcsTUFBTSxFQUFFLElBQUksSUFBSSxHQUFHLENBQUM7UUFFakMsT0FBTzs7O2dCQUdLLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUU7OzsrREFHUixPQUFPLENBQUMsUUFBUSxJQUFJLE9BQU8sQ0FBQyxJQUFJOzs7O2VBSWhGLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFdBQVcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLFNBQVM7OzZGQUVZLENBQUM7SUFDNUYsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLElBQVk7UUFDaEIsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDaEIsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDdkMsT0FBTztnQkFDTCxLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQVk7Z0JBQzFCLFdBQVcsRUFBRSxNQUFNLENBQUMsV0FBVyxJQUFJLE1BQU0sQ0FBQyxZQUFZO2dCQUN0RCxXQUFXLEVBQUUsTUFBTSxDQUFDLFdBQVc7Z0JBQy9CLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSSxJQUFJLE1BQU0sQ0FBQyxLQUFLO2dCQUNqQyxVQUFVLEVBQUUsTUFBTSxDQUFDLFVBQVU7YUFDOUIsQ0FBQztRQUNKLENBQUM7UUFFRCxXQUFXO1FBQ1gsT0FBTztZQUNMLEtBQUssRUFBRSxNQUFNO1lBQ2IsV0FBVyxFQUFFLEdBQUc7WUFDaEIsV0FBVyxFQUFFLEdBQUc7WUFDaEIsSUFBSSxFQUFFLEdBQUc7WUFDVCxVQUFVLEVBQUUsR0FBRztTQUNoQixDQUFDO0lBQ0osQ0FBQztJQUVEOztPQUVHO0lBQ0gsWUFBWSxDQUFDLElBQVksRUFBRSxDQUFDLEdBQUcsRUFBRTtRQUMvQixJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNoQixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDbEQsT0FBTyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFO2dCQUNyQix1RUFBdUU7Z0JBQ3ZFLHNFQUFzRTtnQkFDdEUsd0VBQXdFO2dCQUN4RSwrQkFBK0I7Z0JBQy9CLE1BQU0sSUFBSSxHQUFHLENBQVEsQ0FBQztnQkFDdEIsTUFBTSxLQUFLLEdBQ1QsT0FBTyxJQUFJLENBQUMsS0FBSyxLQUFLLFFBQVE7b0JBQzVCLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSztvQkFDWixDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsUUFBUSxLQUFLLFFBQVE7d0JBQ2pDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO3dCQUN0QyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUNWLE9BQU87b0JBQ0wsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFO29CQUNSLEtBQUs7b0JBQ0wsT0FBTyxFQUFFLENBQUMsQ0FBQyxPQUFPO29CQUNsQixRQUFRLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQztpQkFDekMsQ0FBQztZQUNKLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELDJCQUEyQjtRQUMzQixPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7YUFDbkQsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7YUFDWCxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUNwQixFQUFFO1lBQ0YsS0FBSyxFQUFFLEdBQUc7WUFDVixPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU87WUFDckIsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRO1NBQ3hCLENBQUMsQ0FBQyxDQUFDO0lBQ1IsQ0FBQztJQUVEOztPQUVHO0lBQ0gsU0FBUyxDQUFDLE9BQWUsRUFBRSxRQUFrQztRQUMzRCxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNoQixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLE9BQU8sRUFBRSxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ3pGLENBQUM7UUFFRCxXQUFXO1FBQ1gsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUN2QyxJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFO1lBQ2hDLE9BQU87WUFDUCxTQUFTLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUM7WUFDOUIsUUFBUSxFQUFFLFFBQVEsSUFBSSxFQUFFO1NBQ3pCLENBQUMsQ0FBQztRQUNILE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUVEOztPQUVHO0lBQ0gsUUFBUSxDQUFDLEVBQVk7UUFDbkIsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDaEIsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3RFLENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUs7UUFDSCxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNoQixNQUFNLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQzlCLG9FQUFvRTtZQUNwRSxpRUFBaUU7WUFDakUsT0FBTztnQkFDTCxZQUFZLEVBQUcsQ0FBUyxDQUFDLFlBQVksSUFBSSxDQUFDLENBQUMsYUFBYSxJQUFJLENBQUM7Z0JBQzdELFdBQVcsRUFBRyxDQUFTLENBQUMsV0FBVyxJQUFJLENBQUMsQ0FBQyxZQUFZLElBQUksQ0FBQztnQkFDMUQsZUFBZSxFQUNaLENBQVMsQ0FBQyxhQUFhO29CQUN4QixDQUFDLENBQUMsZ0JBQWdCO29CQUNqQixDQUFTLENBQUMsY0FBYztvQkFDekIsQ0FBQztnQkFDSCxZQUFZLEVBQUcsQ0FBUyxDQUFDLFlBQVksSUFBSSxDQUFDLENBQUMsY0FBYyxJQUFJLENBQUM7Z0JBQzlELFlBQVksRUFBRyxDQUFTLENBQUMsWUFBWSxJQUFJLENBQUMsQ0FBQyxjQUFjLElBQUksQ0FBQztnQkFDOUQsY0FBYyxFQUFHLENBQVMsQ0FBQyxjQUFjLElBQUksQ0FBQyxDQUFDLGVBQWUsSUFBSSxHQUFHO2FBQ3RFLENBQUM7UUFDSixDQUFDO1FBRUQsV0FBVztRQUNYLE9BQU87WUFDTCxZQUFZLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxVQUFVO1lBQzNDLFdBQVcsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxJQUFJO1lBQzNDLGVBQWUsRUFBRSxDQUFDO1lBQ2xCLFlBQVksRUFBRSxHQUFHO1lBQ2pCLFlBQVksRUFBRSxHQUFHO1lBQ2pCLGNBQWMsRUFBRSxHQUFHO1NBQ3BCLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSCxVQUFVO1FBQ1IsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDaEIsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ2xDLENBQUM7UUFDRCxPQUFPLHlDQUF5QyxDQUFDO0lBQ25ELENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxJQUFZO1FBQ2hCLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2hCLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDakMsQ0FBQztRQUVELHlDQUF5QztRQUN6QyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksSUFBSSxHQUFHLENBQUM7UUFDNUMsTUFBTSxTQUFTLEdBQUcsSUFBSSxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRXpDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDckMsTUFBTSxHQUFHLEdBQUcsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDO1lBQ2pELFNBQVMsQ0FBQyxHQUFHLENBQUMsSUFBSSxHQUFHLENBQUM7UUFDeEIsQ0FBQztRQUVELFlBQVk7UUFDWixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMxRSxPQUFPLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDdEMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsVUFBVSxDQUFDLEtBQWEsRUFBRSxLQUFhO1FBQ3JDLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2hCLHFFQUFxRTtZQUNyRSxzRUFBc0U7WUFDdEUscUVBQXFFO1lBQ3JFLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNqRCxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUN4QyxDQUFDO1FBRUQsK0JBQStCO1FBQy9CLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDL0IsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUUvQixJQUFJLEdBQUcsR0FBRyxDQUFDLENBQUM7UUFDWixJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7UUFDZCxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7UUFFZCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQ3JDLEdBQUcsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3pCLEtBQUssSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzNCLEtBQUssSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzdCLENBQUM7UUFFRCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDbEQsTUFBTSxVQUFVLEdBQUcsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQy9DLGtEQUFrRDtRQUNsRCxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUM7SUFDOUMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsT0FBTztRQUNMLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2hCLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUMvQixDQUFDO1FBQ0QsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQ7O09BRUc7SUFDSCxnQkFBZ0I7UUFDZCxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNoQixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztRQUN4QyxDQUFDO1FBQ0QsT0FBTyxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDL0IsQ0FBQztJQUVEOztPQUVHO0lBQ0gsVUFBVSxDQUFDLE9BQTBCO1FBQ25DLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUN6QixNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQzFFLE9BQU87WUFDTCxTQUFTO1lBQ1QsY0FBYyxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxLQUFLO1NBQ25DLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSCxjQUFjO1FBQ1osT0FBTyxJQUFJLENBQUMsTUFBTSxLQUFLLElBQUksQ0FBQztJQUM5QixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFJ1dkxMTSBFbmdpbmUgLSBNYWluIG9yY2hlc3RyYXRvciBmb3Igc2VsZi1sZWFybmluZyBMTE1cbiAqL1xuXG5pbXBvcnQge1xuICBSdXZMTE1Db25maWcsXG4gIEdlbmVyYXRpb25Db25maWcsXG4gIFF1ZXJ5UmVzcG9uc2UsXG4gIFJvdXRpbmdEZWNpc2lvbixcbiAgTWVtb3J5UmVzdWx0LFxuICBNZW1vcnlJZCxcbiAgUnV2TExNU3RhdHMsXG4gIEZlZWRiYWNrLFxuICBFbWJlZGRpbmcsXG4gIEJhdGNoUXVlcnlSZXF1ZXN0LFxuICBCYXRjaFF1ZXJ5UmVzcG9uc2UsXG59IGZyb20gJy4vdHlwZXMnO1xuXG5pbXBvcnQge1xuICBnZXROYXRpdmVNb2R1bGUsXG4gIE5hdGl2ZUVuZ2luZSxcbiAgTmF0aXZlQ29uZmlnLFxuICBOYXRpdmVHZW5Db25maWcsXG59IGZyb20gJy4vbmF0aXZlJztcblxuLyoqXG4gKiBDb252ZXJ0IEpTIGNvbmZpZyB0byBuYXRpdmUgY29uZmlnIGZvcm1hdFxuICovXG5mdW5jdGlvbiB0b05hdGl2ZUNvbmZpZyhjb25maWc/OiBSdXZMTE1Db25maWcpOiBOYXRpdmVDb25maWcgfCB1bmRlZmluZWQge1xuICBpZiAoIWNvbmZpZykgcmV0dXJuIHVuZGVmaW5lZDtcblxuICByZXR1cm4ge1xuICAgIGVtYmVkZGluZ19kaW06IGNvbmZpZy5lbWJlZGRpbmdEaW0sXG4gICAgcm91dGVyX2hpZGRlbl9kaW06IGNvbmZpZy5yb3V0ZXJIaWRkZW5EaW0sXG4gICAgaG5zd19tOiBjb25maWcuaG5zd00sXG4gICAgaG5zd19lZl9jb25zdHJ1Y3Rpb246IGNvbmZpZy5obnN3RWZDb25zdHJ1Y3Rpb24sXG4gICAgaG5zd19lZl9zZWFyY2g6IGNvbmZpZy5obnN3RWZTZWFyY2gsXG4gICAgbGVhcm5pbmdfZW5hYmxlZDogY29uZmlnLmxlYXJuaW5nRW5hYmxlZCxcbiAgICBxdWFsaXR5X3RocmVzaG9sZDogY29uZmlnLnF1YWxpdHlUaHJlc2hvbGQsXG4gICAgZXdjX2xhbWJkYTogY29uZmlnLmV3Y0xhbWJkYSxcbiAgfTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IEpTIGdlbmVyYXRpb24gY29uZmlnIHRvIG5hdGl2ZSBmb3JtYXRcbiAqL1xuZnVuY3Rpb24gdG9OYXRpdmVHZW5Db25maWcoY29uZmlnPzogR2VuZXJhdGlvbkNvbmZpZyk6IE5hdGl2ZUdlbkNvbmZpZyB8IHVuZGVmaW5lZCB7XG4gIGlmICghY29uZmlnKSByZXR1cm4gdW5kZWZpbmVkO1xuXG4gIHJldHVybiB7XG4gICAgbWF4X3Rva2VuczogY29uZmlnLm1heFRva2VucyxcbiAgICB0ZW1wZXJhdHVyZTogY29uZmlnLnRlbXBlcmF0dXJlLFxuICAgIHRvcF9wOiBjb25maWcudG9wUCxcbiAgICB0b3BfazogY29uZmlnLnRvcEssXG4gICAgcmVwZXRpdGlvbl9wZW5hbHR5OiBjb25maWcucmVwZXRpdGlvblBlbmFsdHksXG4gIH07XG59XG5cbmNvbnN0IHdhcm5lZCA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4vKiogV2FybiBvbmNlIHBlciBwcm9jZXNzIChvciB0aHJvdyB3aGVuIGBzdHJpY3RgKS4gKi9cbmZ1bmN0aW9uIG5vdGljZShjb2RlOiBzdHJpbmcsIG1lc3NhZ2U6IHN0cmluZywgc3RyaWN0OiBib29sZWFuIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gIGlmIChzdHJpY3QpIHRocm93IG5ldyBFcnJvcihgJHtjb2RlfTogJHttZXNzYWdlfWApO1xuICBpZiAod2FybmVkLmhhcyhjb2RlKSkgcmV0dXJuO1xuICB3YXJuZWQuYWRkKGNvZGUpO1xuICBjb25zdCBnID0gZ2xvYmFsVGhpcyBhcyB1bmtub3duIGFzIHtcbiAgICBwcm9jZXNzPzogeyBlbWl0V2FybmluZz86IChtOiBzdHJpbmcsIG8/OiB7IGNvZGU/OiBzdHJpbmcgfSkgPT4gdm9pZCB9O1xuICAgIGNvbnNvbGU/OiB7IHdhcm4/OiAobTogc3RyaW5nKSA9PiB2b2lkIH07XG4gIH07XG4gIGlmICh0eXBlb2YgZy5wcm9jZXNzPy5lbWl0V2FybmluZyA9PT0gJ2Z1bmN0aW9uJykgZy5wcm9jZXNzLmVtaXRXYXJuaW5nKG1lc3NhZ2UsIHsgY29kZSB9KTtcbiAgZWxzZSBnLmNvbnNvbGU/Lndhcm4/LihgJHtjb2RlfTogJHttZXNzYWdlfWApO1xufVxuXG5jb25zdCBOT19MTV9NRVNTQUdFID1cbiAgJ3RoZSBuYXRpdmUgUnV2TExNIGVuZ2luZSBoYXMgbm8gbGFuZ3VhZ2UtbW9kZWwgd2VpZ2h0cywgc28gZ2VuZXJhdGUoKS9xdWVyeSgpIHRleHQgaXMgJyArXG4gICdub3QgbW9kZWwgb3V0cHV0LiBGb3IgR0dVRiBpbmZlcmVuY2UgdXNlIHRoZSBydXZsbG0gQ0xJIChgcnV2bGxtIHNlcnZlIDxtb2RlbD4gLS1zdHJpY3RgKSAnICtcbiAgJ29yIGFub3RoZXIgT3BlbkFJLWNvbXBhdGlibGUgc2VydmVyLiBSb3V0aW5nLCBtZW1vcnkgYW5kIGVtYmVkZGluZ3MgYXJlIHVuYWZmZWN0ZWQuICcgK1xuICAnUGFzcyB7IHN0cmljdDogdHJ1ZSB9IHRvIHRocm93IGluc3RlYWQuJztcblxuLyoqXG4gKiBSdXZMTE0gLSBTZWxmLWxlYXJuaW5nIExMTSBvcmNoZXN0cmF0b3JcbiAqXG4gKiBDb21iaW5lcyBTT05BIGFkYXB0aXZlIGxlYXJuaW5nIHdpdGggSE5TVyBtZW1vcnksXG4gKiBGYXN0R1JOTiByb3V0aW5nLCBhbmQgU0lNRC1vcHRpbWl6ZWQgaW5mZXJlbmNlLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBSdXZMTE0gfSBmcm9tICdAcnV2ZWN0b3IvcnV2bGxtJztcbiAqXG4gKiBjb25zdCBsbG0gPSBuZXcgUnV2TExNKHsgZW1iZWRkaW5nRGltOiA3NjggfSk7XG4gKlxuICogLy8gUXVlcnkgd2l0aCBhdXRvbWF0aWMgcm91dGluZ1xuICogY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBsbG0ucXVlcnkoJ1doYXQgaXMgbWFjaGluZSBsZWFybmluZz8nKTtcbiAqIGNvbnNvbGUubG9nKHJlc3BvbnNlLnRleHQpO1xuICpcbiAqIC8vIFByb3ZpZGUgZmVlZGJhY2sgZm9yIGxlYXJuaW5nXG4gKiBsbG0uZmVlZGJhY2soeyByZXF1ZXN0SWQ6IHJlc3BvbnNlLnJlcXVlc3RJZCwgcmF0aW5nOiA1IH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjbGFzcyBSdXZMTE0ge1xuICBwcml2YXRlIG5hdGl2ZTogTmF0aXZlRW5naW5lIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgY29uZmlnOiBSdXZMTE1Db25maWc7XG5cbiAgLy8gRmFsbGJhY2sgc3RhdGUgZm9yIHdoZW4gbmF0aXZlIG1vZHVsZSBpcyBub3QgYXZhaWxhYmxlXG4gIHByaXZhdGUgZmFsbGJhY2tTdGF0ZSA9IHtcbiAgICBtZW1vcnk6IG5ldyBNYXA8bnVtYmVyLCB7IGNvbnRlbnQ6IHN0cmluZzsgZW1iZWRkaW5nOiBudW1iZXJbXTsgbWV0YWRhdGE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IH0+KCksXG4gICAgbmV4dElkOiAxLFxuICAgIHF1ZXJ5Q291bnQ6IDAsXG4gIH07XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIG5ldyBSdXZMTE0gaW5zdGFuY2VcbiAgICovXG4gIGNvbnN0cnVjdG9yKGNvbmZpZz86IFJ1dkxMTUNvbmZpZykge1xuICAgIHRoaXMuY29uZmlnID0gY29uZmlnID8/IHt9O1xuICAgIGNvbnN0IGV4dHJhID0gdGhpcy5jb25maWcgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgZm9yIChjb25zdCBrZXkgb2YgWydtb2RlbFBhdGgnLCAnYmFja2VuZCddKSB7XG4gICAgICBpZiAoZXh0cmFba2V5XSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIG5vdGljZShcbiAgICAgICAgICAnUlVWTExNX1VOU1VQUE9SVEVEX09QVElPTicsXG4gICAgICAgICAgYFxcYCR7a2V5fVxcYCBpcyBub3Qgc3VwcG9ydGVkIGJ5IEBydXZlY3Rvci9ydXZsbG0gYW5kIGlzIGlnbm9yZWQ6IHRoaXMgcGFja2FnZSBkb2VzIG5vdCBgICtcbiAgICAgICAgICAgICdsb2FkIG1vZGVsIGZpbGVzLiBGb3IgR0dVRiBpbmZlcmVuY2UgdXNlIHRoZSBydXZsbG0gQ0xJIChgcnV2bGxtIHNlcnZlIDxtb2RlbD4gLS1zdHJpY3RgKS4nLFxuICAgICAgICAgIHRoaXMuY29uZmlnLnN0cmljdCxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBtb2QgPSBnZXROYXRpdmVNb2R1bGUoKTtcbiAgICBpZiAobW9kKSB7XG4gICAgICB0cnkge1xuICAgICAgICB0aGlzLm5hdGl2ZSA9IG5ldyBtb2QuUnV2TExNRW5naW5lKHRvTmF0aXZlQ29uZmlnKGNvbmZpZykpO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIC8vIFNpbGVudGx5IGZhbGwgYmFjayB0byBKUyBpbXBsZW1lbnRhdGlvblxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBRdWVyeSB0aGUgTExNIHdpdGggYXV0b21hdGljIHJvdXRpbmdcbiAgICovXG4gIHF1ZXJ5KHRleHQ6IHN0cmluZywgY29uZmlnPzogR2VuZXJhdGlvbkNvbmZpZyk6IFF1ZXJ5UmVzcG9uc2Uge1xuICAgIGlmICh0aGlzLm5hdGl2ZSkge1xuICAgICAgbm90aWNlKCdSVVZMTE1fTk9fTEFOR1VBR0VfTU9ERUwnLCBOT19MTV9NRVNTQUdFLCB0aGlzLmNvbmZpZy5zdHJpY3QpO1xuICAgICAgY29uc3QgcmVzdWx0ID0gdGhpcy5uYXRpdmUucXVlcnkodGV4dCwgdG9OYXRpdmVHZW5Db25maWcoY29uZmlnKSk7XG4gICAgICAvLyBuYXBpLXJzIGNhbWVsQ2FzZXMgUnVzdCBmaWVsZCBuYW1lcyBvbiB0aGUgd2F5IG91dCwgc28gdGhlIG5hdGl2ZVxuICAgICAgLy8gb2JqZWN0IGNhcnJpZXMgYGNvbnRleHRTaXplYC9gbGF0ZW5jeU1zYC9gcmVxdWVzdElkYC4gVGhlIHNuYWtlX2Nhc2VcbiAgICAgIC8vIHJlYWRzIGFyZSBrZXB0IGFzIGEgZmFsbGJhY2sgZm9yIG9sZGVyIG5hdGl2ZSBidWlsZHMuXG4gICAgICByZXR1cm4ge1xuICAgICAgICB0ZXh0OiByZXN1bHQudGV4dCxcbiAgICAgICAgY29uZmlkZW5jZTogcmVzdWx0LmNvbmZpZGVuY2UsXG4gICAgICAgIG1vZGVsOiByZXN1bHQubW9kZWwsXG4gICAgICAgIGNvbnRleHRTaXplOiByZXN1bHQuY29udGV4dFNpemUgPz8gcmVzdWx0LmNvbnRleHRfc2l6ZSxcbiAgICAgICAgbGF0ZW5jeU1zOiByZXN1bHQubGF0ZW5jeU1zID8/IHJlc3VsdC5sYXRlbmN5X21zLFxuICAgICAgICByZXF1ZXN0SWQ6IHJlc3VsdC5yZXF1ZXN0SWQgPz8gcmVzdWx0LnJlcXVlc3RfaWQsXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIEZhbGxiYWNrIGltcGxlbWVudGF0aW9uXG4gICAgdGhpcy5mYWxsYmFja1N0YXRlLnF1ZXJ5Q291bnQrKztcbiAgICByZXR1cm4ge1xuICAgICAgdGV4dDogYFtGYWxsYmFja10gUmVzcG9uc2UgdG86ICR7dGV4dC5zbGljZSgwLCA1MCl9Li4uYCxcbiAgICAgIGNvbmZpZGVuY2U6IDAuNSxcbiAgICAgIG1vZGVsOiAnZmFsbGJhY2snLFxuICAgICAgY29udGV4dFNpemU6IDUxMixcbiAgICAgIGxhdGVuY3lNczogMS4wLFxuICAgICAgcmVxdWVzdElkOiBgZmItJHtEYXRlLm5vdygpfS0ke01hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnNsaWNlKDIpfWAsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSB0ZXh0IHdpdGggU0lNRC1vcHRpbWl6ZWQgaW5mZXJlbmNlXG4gICAqXG4gICAqIE5vdGU6IHRoZSBuYXRpdmUgZW5naW5lIGhhcyBubyBsYW5ndWFnZS1tb2RlbCB3ZWlnaHRzLCBzbyBpdHMgdGV4dCBpc1xuICAgKiBub3QgbW9kZWwgb3V0cHV0OyB0aGUgZmlyc3QgY2FsbCBlbWl0cyBhIGBSVVZMTE1fTk9fTEFOR1VBR0VfTU9ERUxgXG4gICAqIHdhcm5pbmcgKG9yIHRocm93cyB3aXRoIGBzdHJpY3Q6IHRydWVgKS4gV2l0aG91dCB0aGUgbmF0aXZlIG1vZHVsZSB0aGlzXG4gICAqIHJldHVybnMgYW4gaW5mb3JtYXRpb25hbCBtZXNzYWdlLlxuICAgKi9cbiAgZ2VuZXJhdGUocHJvbXB0OiBzdHJpbmcsIGNvbmZpZz86IEdlbmVyYXRpb25Db25maWcpOiBzdHJpbmcge1xuICAgIGlmICh0aGlzLm5hdGl2ZSkge1xuICAgICAgbm90aWNlKCdSVVZMTE1fTk9fTEFOR1VBR0VfTU9ERUwnLCBOT19MTV9NRVNTQUdFLCB0aGlzLmNvbmZpZy5zdHJpY3QpO1xuICAgICAgcmV0dXJuIHRoaXMubmF0aXZlLmdlbmVyYXRlKHByb21wdCwgdG9OYXRpdmVHZW5Db25maWcoY29uZmlnKSk7XG4gICAgfVxuXG4gICAgLy8gRmFsbGJhY2sgLSBwcm92aWRlIGhlbHBmdWwgbWVzc2FnZSBpbnN0ZWFkIG9mIGdhcmJsZWQgb3V0cHV0XG4gICAgY29uc3QgbWF4VG9rZW5zID0gY29uZmlnPy5tYXhUb2tlbnMgPz8gMjU2O1xuICAgIGNvbnN0IHRlbXAgPSBjb25maWc/LnRlbXBlcmF0dXJlID8/IDAuNztcbiAgICBjb25zdCB0b3BQID0gY29uZmlnPy50b3BQID8/IDAuOTtcblxuICAgIHJldHVybiBgW1J1dkxMTSBKYXZhU2NyaXB0IEZhbGxiYWNrIE1vZGVdXG5ObyBuYXRpdmUgU0lNRCBtb2R1bGUgbG9hZGVkLiBSdW5uaW5nIGluIEphdmFTY3JpcHQgZmFsbGJhY2sgbW9kZS5cblxuWW91ciBwcm9tcHQ6IFwiJHtwcm9tcHQuc2xpY2UoMCwgMTAwKX0ke3Byb21wdC5sZW5ndGggPiAxMDAgPyAnLi4uJyA6ICcnfVwiXG5cblRvIGVuYWJsZSBuYXRpdmUgU0lNRCBpbmZlcmVuY2U6XG4xLiBJbnN0YWxsIHRoZSBuYXRpdmUgYmluZGluZ3M6IG5wbSBpbnN0YWxsIEBydXZlY3Rvci9ydXZsbG0tJHtwcm9jZXNzLnBsYXRmb3JtfS0ke3Byb2Nlc3MuYXJjaH1cbjIuIE9yIGxvYWQgYSBHR1VGIG1vZGVsIGZpbGVcbjMuIE9yIGNvbm5lY3QgdG8gYW4gZXh0ZXJuYWwgTExNIEFQSVxuXG5Db25maWc6IHRlbXA9JHt0ZW1wLnRvRml4ZWQoMil9LCB0b3BfcD0ke3RvcFAudG9GaXhlZCgyKX0sIG1heF90b2tlbnM9JHttYXhUb2tlbnN9XG5cblRoaXMgZmFsbGJhY2sgcHJvdmlkZXMgcm91dGluZywgbWVtb3J5LCBhbmQgZW1iZWRkaW5nIGZlYXR1cmVzIGJ1dCBub3QgZnVsbCB0ZXh0IGdlbmVyYXRpb24uYDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgcm91dGluZyBkZWNpc2lvbiBmb3IgYSBxdWVyeVxuICAgKi9cbiAgcm91dGUodGV4dDogc3RyaW5nKTogUm91dGluZ0RlY2lzaW9uIHtcbiAgICBpZiAodGhpcy5uYXRpdmUpIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IHRoaXMubmF0aXZlLnJvdXRlKHRleHQpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbW9kZWw6IHJlc3VsdC5tb2RlbCBhcyBhbnksXG4gICAgICAgIGNvbnRleHRTaXplOiByZXN1bHQuY29udGV4dFNpemUgPz8gcmVzdWx0LmNvbnRleHRfc2l6ZSxcbiAgICAgICAgdGVtcGVyYXR1cmU6IHJlc3VsdC50ZW1wZXJhdHVyZSxcbiAgICAgICAgdG9wUDogcmVzdWx0LnRvcFAgPz8gcmVzdWx0LnRvcF9wLFxuICAgICAgICBjb25maWRlbmNlOiByZXN1bHQuY29uZmlkZW5jZSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gRmFsbGJhY2tcbiAgICByZXR1cm4ge1xuICAgICAgbW9kZWw6ICdNNzAwJyxcbiAgICAgIGNvbnRleHRTaXplOiA1MTIsXG4gICAgICB0ZW1wZXJhdHVyZTogMC43LFxuICAgICAgdG9wUDogMC45LFxuICAgICAgY29uZmlkZW5jZTogMC41LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogU2VhcmNoIG1lbW9yeSBmb3Igc2ltaWxhciBjb250ZW50XG4gICAqL1xuICBzZWFyY2hNZW1vcnkodGV4dDogc3RyaW5nLCBrID0gMTApOiBNZW1vcnlSZXN1bHRbXSB7XG4gICAgaWYgKHRoaXMubmF0aXZlKSB7XG4gICAgICBjb25zdCByZXN1bHRzID0gdGhpcy5uYXRpdmUuc2VhcmNoTWVtb3J5KHRleHQsIGspO1xuICAgICAgcmV0dXJuIHJlc3VsdHMubWFwKHIgPT4ge1xuICAgICAgICAvLyBUaGUgbmF0aXZlIHNpZGUgcmVwb3J0cyBgZGlzdGFuY2VgIChzbWFsbGVyIGlzIGNsb3NlcikuIE1lbW9yeVJlc3VsdFxuICAgICAgICAvLyBkb2N1bWVudHMgYHNjb3JlYCBhcyBhIHNpbWlsYXJpdHksIHNvIGNvbnZlcnQgcmF0aGVyIHRoYW4gcGFzc2luZyBhXG4gICAgICAgIC8vIGRpc3RhbmNlIHRocm91Z2ggdW5kZXIgYSBzaW1pbGFyaXR5J3MgbmFtZS4gT2xkZXIgYnVpbGRzIHRoYXQgYWxyZWFkeVxuICAgICAgICAvLyBlbWl0IGBzY29yZWAgYXJlIHVzZWQgYXMtaXMuXG4gICAgICAgIGNvbnN0IGFueVIgPSByIGFzIGFueTtcbiAgICAgICAgY29uc3Qgc2NvcmUgPVxuICAgICAgICAgIHR5cGVvZiBhbnlSLnNjb3JlID09PSAnbnVtYmVyJ1xuICAgICAgICAgICAgPyBhbnlSLnNjb3JlXG4gICAgICAgICAgICA6IHR5cGVvZiBhbnlSLmRpc3RhbmNlID09PSAnbnVtYmVyJ1xuICAgICAgICAgICAgICA/IDEgLyAoMSArIE1hdGgubWF4KDAsIGFueVIuZGlzdGFuY2UpKVxuICAgICAgICAgICAgICA6IDA7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgaWQ6IHIuaWQsXG4gICAgICAgICAgc2NvcmUsXG4gICAgICAgICAgY29udGVudDogci5jb250ZW50LFxuICAgICAgICAgIG1ldGFkYXRhOiBKU09OLnBhcnNlKHIubWV0YWRhdGEgfHwgJ3t9JyksXG4gICAgICAgIH07XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBGYWxsYmFjayAtIHNpbXBsZSBzZWFyY2hcbiAgICByZXR1cm4gQXJyYXkuZnJvbSh0aGlzLmZhbGxiYWNrU3RhdGUubWVtb3J5LmVudHJpZXMoKSlcbiAgICAgIC5zbGljZSgwLCBrKVxuICAgICAgLm1hcCgoW2lkLCBkYXRhXSkgPT4gKHtcbiAgICAgICAgaWQsXG4gICAgICAgIHNjb3JlOiAwLjUsXG4gICAgICAgIGNvbnRlbnQ6IGRhdGEuY29udGVudCxcbiAgICAgICAgbWV0YWRhdGE6IGRhdGEubWV0YWRhdGEsXG4gICAgICB9KSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGNvbnRlbnQgdG8gbWVtb3J5XG4gICAqL1xuICBhZGRNZW1vcnkoY29udGVudDogc3RyaW5nLCBtZXRhZGF0YT86IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogTWVtb3J5SWQge1xuICAgIGlmICh0aGlzLm5hdGl2ZSkge1xuICAgICAgcmV0dXJuIHRoaXMubmF0aXZlLmFkZE1lbW9yeShjb250ZW50LCBtZXRhZGF0YSA/IEpTT04uc3RyaW5naWZ5KG1ldGFkYXRhKSA6IHVuZGVmaW5lZCk7XG4gICAgfVxuXG4gICAgLy8gRmFsbGJhY2tcbiAgICBjb25zdCBpZCA9IHRoaXMuZmFsbGJhY2tTdGF0ZS5uZXh0SWQrKztcbiAgICB0aGlzLmZhbGxiYWNrU3RhdGUubWVtb3J5LnNldChpZCwge1xuICAgICAgY29udGVudCxcbiAgICAgIGVtYmVkZGluZzogdGhpcy5lbWJlZChjb250ZW50KSxcbiAgICAgIG1ldGFkYXRhOiBtZXRhZGF0YSA/PyB7fSxcbiAgICB9KTtcbiAgICByZXR1cm4gaWQ7XG4gIH1cblxuICAvKipcbiAgICogUHJvdmlkZSBmZWVkYmFjayBmb3IgbGVhcm5pbmdcbiAgICovXG4gIGZlZWRiYWNrKGZiOiBGZWVkYmFjayk6IGJvb2xlYW4ge1xuICAgIGlmICh0aGlzLm5hdGl2ZSkge1xuICAgICAgcmV0dXJuIHRoaXMubmF0aXZlLmZlZWRiYWNrKGZiLnJlcXVlc3RJZCwgZmIucmF0aW5nLCBmYi5jb3JyZWN0aW9uKTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBlbmdpbmUgc3RhdGlzdGljc1xuICAgKi9cbiAgc3RhdHMoKTogUnV2TExNU3RhdHMge1xuICAgIGlmICh0aGlzLm5hdGl2ZSkge1xuICAgICAgY29uc3QgcyA9IHRoaXMubmF0aXZlLnN0YXRzKCk7XG4gICAgICAvLyBNYXAgbmF0aXZlIHN0YXRzIChzbmFrZV9jYXNlKSB0byBUeXBlU2NyaXB0IGludGVyZmFjZSAoY2FtZWxDYXNlKVxuICAgICAgLy8gSGFuZGxlIGJvdGggb2xkIGFuZCBuZXcgZmllbGQgbmFtZXMgZm9yIGJhY2t3YXJkIGNvbXBhdGliaWxpdHlcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHRvdGFsUXVlcmllczogKHMgYXMgYW55KS50b3RhbFF1ZXJpZXMgPz8gcy50b3RhbF9xdWVyaWVzID8/IDAsXG4gICAgICAgIG1lbW9yeU5vZGVzOiAocyBhcyBhbnkpLm1lbW9yeU5vZGVzID8/IHMubWVtb3J5X25vZGVzID8/IDAsXG4gICAgICAgIHBhdHRlcm5zTGVhcm5lZDpcbiAgICAgICAgICAocyBhcyBhbnkpLnRyYWluaW5nU3RlcHMgPz9cbiAgICAgICAgICBzLnBhdHRlcm5zX2xlYXJuZWQgPz9cbiAgICAgICAgICAocyBhcyBhbnkpLnRyYWluaW5nX3N0ZXBzID8/XG4gICAgICAgICAgMCxcbiAgICAgICAgYXZnTGF0ZW5jeU1zOiAocyBhcyBhbnkpLmF2Z0xhdGVuY3lNcyA/PyBzLmF2Z19sYXRlbmN5X21zID8/IDAsXG4gICAgICAgIGNhY2hlSGl0UmF0ZTogKHMgYXMgYW55KS5jYWNoZUhpdFJhdGUgPz8gcy5jYWNoZV9oaXRfcmF0ZSA/PyAwLFxuICAgICAgICByb3V0ZXJBY2N1cmFjeTogKHMgYXMgYW55KS5yb3V0ZXJBY2N1cmFjeSA/PyBzLnJvdXRlcl9hY2N1cmFjeSA/PyAwLjUsXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIEZhbGxiYWNrXG4gICAgcmV0dXJuIHtcbiAgICAgIHRvdGFsUXVlcmllczogdGhpcy5mYWxsYmFja1N0YXRlLnF1ZXJ5Q291bnQsXG4gICAgICBtZW1vcnlOb2RlczogdGhpcy5mYWxsYmFja1N0YXRlLm1lbW9yeS5zaXplLFxuICAgICAgcGF0dGVybnNMZWFybmVkOiAwLFxuICAgICAgYXZnTGF0ZW5jeU1zOiAxLjAsXG4gICAgICBjYWNoZUhpdFJhdGU6IDAuMCxcbiAgICAgIHJvdXRlckFjY3VyYWN5OiAwLjUsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGb3JjZSByb3V0ZXIgbGVhcm5pbmcgY3ljbGVcbiAgICovXG4gIGZvcmNlTGVhcm4oKTogc3RyaW5nIHtcbiAgICBpZiAodGhpcy5uYXRpdmUpIHtcbiAgICAgIHJldHVybiB0aGlzLm5hdGl2ZS5mb3JjZUxlYXJuKCk7XG4gICAgfVxuICAgIHJldHVybiAnTGVhcm5pbmcgbm90IGF2YWlsYWJsZSBpbiBmYWxsYmFjayBtb2RlJztcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgZW1iZWRkaW5nIGZvciB0ZXh0XG4gICAqL1xuICBlbWJlZCh0ZXh0OiBzdHJpbmcpOiBFbWJlZGRpbmcge1xuICAgIGlmICh0aGlzLm5hdGl2ZSkge1xuICAgICAgcmV0dXJuIHRoaXMubmF0aXZlLmVtYmVkKHRleHQpO1xuICAgIH1cblxuICAgIC8vIEZhbGxiYWNrIC0gc2ltcGxlIGhhc2gtYmFzZWQgZW1iZWRkaW5nXG4gICAgY29uc3QgZGltID0gdGhpcy5jb25maWcuZW1iZWRkaW5nRGltID8/IDc2ODtcbiAgICBjb25zdCBlbWJlZGRpbmcgPSBuZXcgQXJyYXkoZGltKS5maWxsKDApO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0ZXh0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBpZHggPSAodGV4dC5jaGFyQ29kZUF0KGkpICogKGkgKyAxKSkgJSBkaW07XG4gICAgICBlbWJlZGRpbmdbaWR4XSArPSAwLjE7XG4gICAgfVxuXG4gICAgLy8gTm9ybWFsaXplXG4gICAgY29uc3Qgbm9ybSA9IE1hdGguc3FydChlbWJlZGRpbmcucmVkdWNlKChzdW0sIHgpID0+IHN1bSArIHggKiB4LCAwKSkgfHwgMTtcbiAgICByZXR1cm4gZW1iZWRkaW5nLm1hcCh4ID0+IHggLyBub3JtKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb21wdXRlIHNpbWlsYXJpdHkgYmV0d2VlbiB0d28gdGV4dHNcbiAgICovXG4gIHNpbWlsYXJpdHkodGV4dDE6IHN0cmluZywgdGV4dDI6IHN0cmluZyk6IG51bWJlciB7XG4gICAgaWYgKHRoaXMubmF0aXZlKSB7XG4gICAgICAvLyBmMzIgYWNjdW11bGF0aW9uIGNhbiBsYW5kIGp1c3Qgb3V0c2lkZSB0aGUgbWF0aGVtYXRpY2FsIHJhbmdlIOKAlCBhblxuICAgICAgLy8gaWRlbnRpY2FsIHBhaXIgbWVhc3VyZXMgMS4wMDAwMDAxIOKAlCB3aGljaCB0dXJucyBNYXRoLmFjb3Moc2ltKSBpbnRvXG4gICAgICAvLyBOYU4gZG93bnN0cmVhbS4gQ29zaW5lIHNpbWlsYXJpdHkgaXMgZGVmaW5lZCBvbiBbLTEsIDFdLCBzbyBjbGFtcC5cbiAgICAgIGNvbnN0IHJhdyA9IHRoaXMubmF0aXZlLnNpbWlsYXJpdHkodGV4dDEsIHRleHQyKTtcbiAgICAgIHJldHVybiBNYXRoLm1pbigxLCBNYXRoLm1heCgtMSwgcmF3KSk7XG4gICAgfVxuXG4gICAgLy8gRmFsbGJhY2sgLSBjb3NpbmUgc2ltaWxhcml0eVxuICAgIGNvbnN0IGVtYjEgPSB0aGlzLmVtYmVkKHRleHQxKTtcbiAgICBjb25zdCBlbWIyID0gdGhpcy5lbWJlZCh0ZXh0Mik7XG5cbiAgICBsZXQgZG90ID0gMDtcbiAgICBsZXQgbm9ybTEgPSAwO1xuICAgIGxldCBub3JtMiA9IDA7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGVtYjEubGVuZ3RoOyBpKyspIHtcbiAgICAgIGRvdCArPSBlbWIxW2ldICogZW1iMltpXTtcbiAgICAgIG5vcm0xICs9IGVtYjFbaV0gKiBlbWIxW2ldO1xuICAgICAgbm9ybTIgKz0gZW1iMltpXSAqIGVtYjJbaV07XG4gICAgfVxuXG4gICAgY29uc3QgZGVub20gPSBNYXRoLnNxcnQobm9ybTEpICogTWF0aC5zcXJ0KG5vcm0yKTtcbiAgICBjb25zdCBzaW1pbGFyaXR5ID0gZGVub20gPiAwID8gZG90IC8gZGVub20gOiAwO1xuICAgIC8vIENsYW1wIHRvIFswLCAxXSB0byBoYW5kbGUgZmxvYXRpbmcgcG9pbnQgZXJyb3JzXG4gICAgcmV0dXJuIE1hdGgubWF4KDAsIE1hdGgubWluKDEsIHNpbWlsYXJpdHkpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiBTSU1EIGlzIGF2YWlsYWJsZVxuICAgKi9cbiAgaGFzU2ltZCgpOiBib29sZWFuIHtcbiAgICBpZiAodGhpcy5uYXRpdmUpIHtcbiAgICAgIHJldHVybiB0aGlzLm5hdGl2ZS5oYXNTaW1kKCk7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgU0lNRCBjYXBhYmlsaXRpZXNcbiAgICovXG4gIHNpbWRDYXBhYmlsaXRpZXMoKTogc3RyaW5nW10ge1xuICAgIGlmICh0aGlzLm5hdGl2ZSkge1xuICAgICAgcmV0dXJuIHRoaXMubmF0aXZlLnNpbWRDYXBhYmlsaXRpZXMoKTtcbiAgICB9XG4gICAgcmV0dXJuIFsnU2NhbGFyIChmYWxsYmFjayknXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCYXRjaCBxdWVyeSBtdWx0aXBsZSBwcm9tcHRzXG4gICAqL1xuICBiYXRjaFF1ZXJ5KHJlcXVlc3Q6IEJhdGNoUXVlcnlSZXF1ZXN0KTogQmF0Y2hRdWVyeVJlc3BvbnNlIHtcbiAgICBjb25zdCBzdGFydCA9IERhdGUubm93KCk7XG4gICAgY29uc3QgcmVzcG9uc2VzID0gcmVxdWVzdC5xdWVyaWVzLm1hcChxID0+IHRoaXMucXVlcnkocSwgcmVxdWVzdC5jb25maWcpKTtcbiAgICByZXR1cm4ge1xuICAgICAgcmVzcG9uc2VzLFxuICAgICAgdG90YWxMYXRlbmN5TXM6IERhdGUubm93KCkgLSBzdGFydCxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIG5hdGl2ZSBtb2R1bGUgaXMgbG9hZGVkXG4gICAqL1xuICBpc05hdGl2ZUxvYWRlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5uYXRpdmUgIT09IG51bGw7XG4gIH1cbn1cbiJdfQ==