@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,610 @@
1
+ "use strict";
2
+ /**
3
+ * Training Pipeline for SONA
4
+ *
5
+ * Comprehensive training infrastructure with metrics tracking,
6
+ * learning rate scheduling, and checkpoint management.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { TrainingPipeline, TrainingConfig } from '@ruvector/ruvllm';
11
+ *
12
+ * const pipeline = new TrainingPipeline({
13
+ * learningRate: 0.001,
14
+ * batchSize: 32,
15
+ * epochs: 10,
16
+ * });
17
+ *
18
+ * // Add training data
19
+ * pipeline.addBatch(inputs, targets, qualities);
20
+ *
21
+ * // Run training
22
+ * const result = pipeline.train();
23
+ * console.log(`Final loss: ${result.finalLoss}`);
24
+ * ```
25
+ */
26
+ Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.TrainingFactory = exports.TrainingPipeline = exports.MetricsTracker = exports.LRScheduler = void 0;
28
+ const fs_1 = require("fs");
29
+ const path_1 = require("path");
30
+ const lora_1 = require("./lora");
31
+ const sona_1 = require("./sona");
32
+ /**
33
+ * Default training config
34
+ */
35
+ const DEFAULT_TRAINING_CONFIG = {
36
+ learningRate: 0.001,
37
+ batchSize: 32,
38
+ epochs: 10,
39
+ scheduler: 'cosine',
40
+ warmupSteps: 100,
41
+ weightDecay: 0.01,
42
+ gradientClip: 1.0,
43
+ earlyStoppingPatience: 3,
44
+ checkpointInterval: 1,
45
+ ewcLambda: 2000,
46
+ validationSplit: 0.1,
47
+ keepBestCheckpoint: '',
48
+ };
49
+ /**
50
+ * On-disk checkpoint envelope version.
51
+ *
52
+ * v1 — {format, version:1, epoch, step, loss, weights, timestamp}. No adapter
53
+ * geometry, so loadCheckpoint() could not detect a shape mismatch.
54
+ * v2 — adds {config:{inputDim, outputDim, rank}, pipelineConfig:{learningRate,
55
+ * batchSize}} so loadCheckpoint() can reject weights that don't fit the
56
+ * current adapter. v1 files still load (back-compat) with no shape check.
57
+ */
58
+ const CHECKPOINT_FORMAT_VERSION = 2;
59
+ /**
60
+ * Learning Rate Scheduler
61
+ */
62
+ class LRScheduler {
63
+ constructor(config, totalSteps) {
64
+ this.currentStep = 0;
65
+ this.config = config;
66
+ this.initialLR = config.learningRate;
67
+ this.totalSteps = totalSteps;
68
+ }
69
+ /**
70
+ * Get learning rate for current step
71
+ */
72
+ getLR() {
73
+ switch (this.config.scheduler) {
74
+ case 'constant':
75
+ return this.initialLR;
76
+ case 'linear':
77
+ return this.initialLR * (1 - this.currentStep / this.totalSteps);
78
+ case 'cosine':
79
+ return this.initialLR * 0.5 * (1 + Math.cos(Math.PI * this.currentStep / this.totalSteps));
80
+ case 'warmup':
81
+ if (this.currentStep < this.config.warmupSteps) {
82
+ return this.initialLR * (this.currentStep / this.config.warmupSteps);
83
+ }
84
+ // Cosine decay after warmup
85
+ const decaySteps = this.totalSteps - this.config.warmupSteps;
86
+ const decayProgress = (this.currentStep - this.config.warmupSteps) / decaySteps;
87
+ return this.initialLR * 0.5 * (1 + Math.cos(Math.PI * decayProgress));
88
+ default:
89
+ return this.initialLR;
90
+ }
91
+ }
92
+ /**
93
+ * Step the scheduler
94
+ */
95
+ step() {
96
+ this.currentStep++;
97
+ }
98
+ /**
99
+ * Reset scheduler
100
+ */
101
+ reset() {
102
+ this.currentStep = 0;
103
+ }
104
+ }
105
+ exports.LRScheduler = LRScheduler;
106
+ /**
107
+ * Training Metrics Tracker
108
+ */
109
+ class MetricsTracker {
110
+ constructor() {
111
+ this.lossHistory = [];
112
+ this.valLossHistory = [];
113
+ this.gradNormHistory = [];
114
+ this.startTime = Date.now();
115
+ this.stepTimes = [];
116
+ }
117
+ /**
118
+ * Record training loss
119
+ */
120
+ recordLoss(loss) {
121
+ this.lossHistory.push(loss);
122
+ }
123
+ /**
124
+ * Record validation loss
125
+ */
126
+ recordValLoss(loss) {
127
+ this.valLossHistory.push(loss);
128
+ }
129
+ /**
130
+ * Record gradient norm
131
+ */
132
+ recordGradNorm(norm) {
133
+ this.gradNormHistory.push(norm);
134
+ }
135
+ /**
136
+ * Record step time
137
+ */
138
+ recordStepTime(ms) {
139
+ this.stepTimes.push(ms);
140
+ }
141
+ /**
142
+ * Get average loss over last N steps
143
+ */
144
+ avgLoss(n = 100) {
145
+ const recent = this.lossHistory.slice(-n);
146
+ return recent.length > 0 ? recent.reduce((a, b) => a + b, 0) / recent.length : 0;
147
+ }
148
+ /**
149
+ * Get average validation loss
150
+ */
151
+ avgValLoss(n = 10) {
152
+ const recent = this.valLossHistory.slice(-n);
153
+ return recent.length > 0 ? recent.reduce((a, b) => a + b, 0) / recent.length : 0;
154
+ }
155
+ /**
156
+ * Get steps per second
157
+ */
158
+ stepsPerSecond() {
159
+ if (this.stepTimes.length === 0)
160
+ return 0;
161
+ const avgStepTime = this.stepTimes.slice(-100).reduce((a, b) => a + b, 0) / Math.min(this.stepTimes.length, 100);
162
+ return avgStepTime > 0 ? 1000 / avgStepTime : 0;
163
+ }
164
+ /**
165
+ * Get ETA in seconds
166
+ */
167
+ eta(remainingSteps) {
168
+ const sps = this.stepsPerSecond();
169
+ return sps > 0 ? remainingSteps / sps : 0;
170
+ }
171
+ /**
172
+ * Get best validation loss
173
+ */
174
+ bestValLoss() {
175
+ return this.valLossHistory.length > 0 ? Math.min(...this.valLossHistory) : Infinity;
176
+ }
177
+ /**
178
+ * Get total duration
179
+ */
180
+ duration() {
181
+ return Date.now() - this.startTime;
182
+ }
183
+ /**
184
+ * Get all loss history
185
+ */
186
+ getLossHistory() {
187
+ return [...this.lossHistory];
188
+ }
189
+ /**
190
+ * Get all validation loss history
191
+ */
192
+ getValLossHistory() {
193
+ return [...this.valLossHistory];
194
+ }
195
+ /**
196
+ * Reset tracker
197
+ */
198
+ reset() {
199
+ this.lossHistory = [];
200
+ this.valLossHistory = [];
201
+ this.gradNormHistory = [];
202
+ this.stepTimes = [];
203
+ this.startTime = Date.now();
204
+ }
205
+ }
206
+ exports.MetricsTracker = MetricsTracker;
207
+ /**
208
+ * Training Pipeline
209
+ *
210
+ * Full training infrastructure for SONA models.
211
+ */
212
+ class TrainingPipeline {
213
+ constructor(config, adapter) {
214
+ this.scheduler = null;
215
+ this.batches = [];
216
+ this.checkpoints = [];
217
+ this.currentEpoch = 0;
218
+ this.currentStep = 0;
219
+ this.bestValLoss = Infinity;
220
+ this.patienceCounter = 0;
221
+ /** Set by resumeFrom(); makes the next train() continue instead of restart. */
222
+ this.resumePending = false;
223
+ this.config = { ...DEFAULT_TRAINING_CONFIG, ...config };
224
+ this.adapter = adapter || new lora_1.LoraAdapter({ rank: 8 });
225
+ this.ewcManager = new sona_1.EwcManager(this.config.ewcLambda);
226
+ this.metrics = new MetricsTracker();
227
+ }
228
+ /**
229
+ * Add training batch
230
+ */
231
+ addBatch(inputs, targets, qualities) {
232
+ this.batches.push({ inputs, targets, qualities });
233
+ }
234
+ /**
235
+ * Add training data
236
+ */
237
+ addData(data) {
238
+ // Group into batches
239
+ for (let i = 0; i < data.length; i += this.config.batchSize) {
240
+ const batch = data.slice(i, i + this.config.batchSize);
241
+ this.addBatch(batch.map(d => d.input), batch.map(d => d.target), batch.map(d => d.quality));
242
+ }
243
+ }
244
+ /**
245
+ * Run training.
246
+ *
247
+ * When {@link resumeFrom} primed the pipeline, this continues from the
248
+ * restored epoch (running the remaining epochs of `config.epochs`) and
249
+ * advances the LR scheduler to the restored step so the schedule is
250
+ * unbroken; metrics history is preserved. Without a resume the run is
251
+ * unchanged from a fresh start — same reset, same scheduler, same result
252
+ * shape as before this method learned to resume.
253
+ */
254
+ train() {
255
+ const resuming = this.resumePending;
256
+ this.resumePending = false;
257
+ // currentEpoch is the last COMPLETED epoch index, so resume the next one.
258
+ const startEpoch = resuming ? this.currentEpoch + 1 : 0;
259
+ const totalSteps = this.batches.length * this.config.epochs;
260
+ this.scheduler = new LRScheduler(this.config, totalSteps);
261
+ if (resuming) {
262
+ // Fast-forward the fresh scheduler to the restored step.
263
+ for (let s = 0; s < this.currentStep && s < totalSteps; s++) {
264
+ this.scheduler.step();
265
+ }
266
+ }
267
+ else {
268
+ this.metrics.reset();
269
+ }
270
+ this.adapter.startTraining(this.config.learningRate);
271
+ let earlyStopped = false;
272
+ for (let epoch = startEpoch; epoch < this.config.epochs; epoch++) {
273
+ this.currentEpoch = epoch;
274
+ // Shuffle batches
275
+ const shuffledBatches = this.shuffleBatches();
276
+ // Split into train/val
277
+ const valSize = Math.floor(shuffledBatches.length * this.config.validationSplit);
278
+ const trainBatches = shuffledBatches.slice(valSize);
279
+ const valBatches = shuffledBatches.slice(0, valSize);
280
+ // Training epoch
281
+ for (const batch of trainBatches) {
282
+ const stepStart = Date.now();
283
+ const loss = this.trainStep(batch);
284
+ this.metrics.recordLoss(loss);
285
+ this.metrics.recordStepTime(Date.now() - stepStart);
286
+ this.scheduler.step();
287
+ this.currentStep++;
288
+ }
289
+ // Validation
290
+ if (valBatches.length > 0) {
291
+ const valLoss = this.validate(valBatches);
292
+ this.metrics.recordValLoss(valLoss);
293
+ // Early stopping
294
+ if (valLoss < this.bestValLoss) {
295
+ this.bestValLoss = valLoss;
296
+ this.patienceCounter = 0;
297
+ // Retain the best-validation model to a stable path when configured.
298
+ if (this.config.keepBestCheckpoint) {
299
+ this.saveCheckpoint(this.config.keepBestCheckpoint);
300
+ }
301
+ }
302
+ else {
303
+ this.patienceCounter++;
304
+ if (this.patienceCounter >= this.config.earlyStoppingPatience) {
305
+ earlyStopped = true;
306
+ break;
307
+ }
308
+ }
309
+ }
310
+ // Checkpoint
311
+ if ((epoch + 1) % this.config.checkpointInterval === 0) {
312
+ this.saveCheckpoint();
313
+ }
314
+ }
315
+ this.adapter.endTraining();
316
+ // Register with EWC for continual learning
317
+ const weights = this.adapter.merge().flat();
318
+ this.ewcManager.registerTask(`task-${Date.now()}`, weights);
319
+ return {
320
+ epochs: this.currentEpoch + 1,
321
+ steps: this.currentStep,
322
+ finalLoss: this.metrics.avgLoss(100),
323
+ bestValLoss: this.bestValLoss,
324
+ durationMs: this.metrics.duration(),
325
+ lossHistory: this.metrics.getLossHistory(),
326
+ valLossHistory: this.metrics.getValLossHistory(),
327
+ earlyStopped,
328
+ };
329
+ }
330
+ /**
331
+ * Single training step
332
+ */
333
+ trainStep(batch) {
334
+ let totalLoss = 0;
335
+ const lr = this.scheduler?.getLR() || this.config.learningRate;
336
+ for (let i = 0; i < batch.inputs.length; i++) {
337
+ const input = batch.inputs[i];
338
+ const target = batch.targets[i];
339
+ const quality = batch.qualities[i];
340
+ // Forward pass
341
+ const output = this.adapter.forward(input);
342
+ // Compute loss (MSE weighted by quality)
343
+ const gradOutput = [];
344
+ let loss = 0;
345
+ for (let j = 0; j < output.length; j++) {
346
+ const diff = output[j] - (target[j] || 0);
347
+ loss += diff * diff;
348
+ gradOutput.push(2 * diff * quality); // Quality-weighted gradient
349
+ }
350
+ loss = (loss / output.length) * quality;
351
+ // Add EWC penalty
352
+ const ewcPenalty = this.ewcManager.computePenalty(this.adapter.merge().flat());
353
+ loss += ewcPenalty * 0.001;
354
+ // Backward pass
355
+ this.adapter.backward(input, gradOutput, lr);
356
+ totalLoss += loss;
357
+ }
358
+ return totalLoss / batch.inputs.length;
359
+ }
360
+ /**
361
+ * Validation pass
362
+ */
363
+ validate(batches) {
364
+ let totalLoss = 0;
365
+ let count = 0;
366
+ for (const batch of batches) {
367
+ for (let i = 0; i < batch.inputs.length; i++) {
368
+ const output = this.adapter.forward(batch.inputs[i]);
369
+ const target = batch.targets[i];
370
+ let loss = 0;
371
+ for (let j = 0; j < output.length; j++) {
372
+ const diff = output[j] - (target[j] || 0);
373
+ loss += diff * diff;
374
+ }
375
+ totalLoss += loss / output.length;
376
+ count++;
377
+ }
378
+ }
379
+ return count > 0 ? totalLoss / count : 0;
380
+ }
381
+ /**
382
+ * Save a checkpoint.
383
+ *
384
+ * Always records the checkpoint in the in-memory list (the behavior the
385
+ * training loop relies on). When `path` is given, additionally persists
386
+ * the checkpoint to disk as versioned JSON — before v2.5.7 this method
387
+ * was private, ignored any argument, and never wrote a file, so callers
388
+ * passing a path got `undefined` back and zero bytes on disk.
389
+ *
390
+ * @param path Optional file path; parent directories are created.
391
+ * @returns Where the checkpoint went — in-memory index, and file
392
+ * path + byte size when persisted.
393
+ */
394
+ saveCheckpoint(path) {
395
+ const checkpoint = {
396
+ epoch: this.currentEpoch,
397
+ step: this.currentStep,
398
+ loss: this.metrics.avgLoss(100),
399
+ weights: this.adapter.toJSON(),
400
+ timestamp: Date.now(),
401
+ };
402
+ this.checkpoints.push(checkpoint);
403
+ const result = {
404
+ index: this.checkpoints.length - 1,
405
+ epoch: checkpoint.epoch,
406
+ step: checkpoint.step,
407
+ loss: checkpoint.loss,
408
+ };
409
+ if (path) {
410
+ const envelope = {
411
+ format: 'ruvllm-checkpoint',
412
+ version: CHECKPOINT_FORMAT_VERSION,
413
+ // Adapter geometry + pipeline hyperparams — lets loadCheckpoint()
414
+ // reject weights that don't fit the current adapter (v2, see below).
415
+ config: {
416
+ inputDim: this.adapter.getInputDim(),
417
+ outputDim: this.adapter.getOutputDim(),
418
+ rank: this.adapter.getConfig().rank,
419
+ },
420
+ pipelineConfig: {
421
+ learningRate: this.config.learningRate,
422
+ batchSize: this.config.batchSize,
423
+ },
424
+ ...checkpoint,
425
+ };
426
+ const serialized = JSON.stringify(envelope);
427
+ (0, fs_1.mkdirSync)((0, path_1.dirname)(path), { recursive: true });
428
+ (0, fs_1.writeFileSync)(path, serialized, 'utf-8');
429
+ result.path = path;
430
+ result.bytes = Buffer.byteLength(serialized, 'utf-8');
431
+ }
432
+ return result;
433
+ }
434
+ /**
435
+ * Load a checkpoint — by in-memory index, or from a file previously
436
+ * written by `saveCheckpoint(path)`.
437
+ *
438
+ * For v2 files, the envelope's adapter geometry is checked against the
439
+ * current adapter first; a mismatch (different inputDim/outputDim/rank)
440
+ * returns false and leaves the adapter untouched, so mis-shaped weights
441
+ * are never silently restored. v1 files carry no geometry and load as
442
+ * before (back-compat).
443
+ */
444
+ loadCheckpoint(indexOrPath) {
445
+ let checkpoint;
446
+ if (typeof indexOrPath === 'number') {
447
+ checkpoint = this.checkpoints[indexOrPath];
448
+ }
449
+ else {
450
+ try {
451
+ const parsed = JSON.parse((0, fs_1.readFileSync)(indexOrPath, 'utf-8'));
452
+ if (parsed?.format !== 'ruvllm-checkpoint' || typeof parsed.weights !== 'string') {
453
+ return false;
454
+ }
455
+ if (typeof parsed.version === 'number' && parsed.version >= 2 && parsed.config) {
456
+ const c = parsed.config;
457
+ if (c.inputDim !== this.adapter.getInputDim() ||
458
+ c.outputDim !== this.adapter.getOutputDim() ||
459
+ c.rank !== this.adapter.getConfig().rank) {
460
+ return false;
461
+ }
462
+ }
463
+ checkpoint = parsed;
464
+ }
465
+ catch {
466
+ return false;
467
+ }
468
+ }
469
+ if (!checkpoint)
470
+ return false;
471
+ this.adapter = lora_1.LoraAdapter.fromJSON(checkpoint.weights);
472
+ this.currentEpoch = checkpoint.epoch;
473
+ this.currentStep = checkpoint.step;
474
+ return true;
475
+ }
476
+ /**
477
+ * Resume training from a checkpoint file.
478
+ *
479
+ * Loads the checkpoint (with the same v2 shape validation as
480
+ * {@link loadCheckpoint}) AND primes the pipeline so the next {@link train}
481
+ * call continues from the restored epoch/step rather than restarting. This
482
+ * is the explicit, least-invasive resume path: a plain `loadCheckpoint()`
483
+ * still restores weights only (train() from scratch), while `resumeFrom()`
484
+ * additionally makes the subsequent train() pick up where the run stopped.
485
+ *
486
+ * @returns true when the checkpoint loaded and resume was primed; false if
487
+ * the file was missing, foreign, or shape-mismatched (in which case
488
+ * no resume is armed).
489
+ */
490
+ resumeFrom(path) {
491
+ if (!this.loadCheckpoint(path))
492
+ return false;
493
+ this.resumePending = true;
494
+ return true;
495
+ }
496
+ /**
497
+ * Get current metrics
498
+ */
499
+ getMetrics() {
500
+ return {
501
+ epoch: this.currentEpoch,
502
+ step: this.currentStep,
503
+ trainLoss: this.metrics.avgLoss(100),
504
+ valLoss: this.metrics.avgValLoss(10),
505
+ learningRate: this.scheduler?.getLR() || this.config.learningRate,
506
+ gradNorm: 0,
507
+ stepsPerSecond: this.metrics.stepsPerSecond(),
508
+ etaSeconds: this.metrics.eta((this.config.epochs - this.currentEpoch) * this.batches.length),
509
+ };
510
+ }
511
+ /**
512
+ * Get adapter
513
+ */
514
+ getAdapter() {
515
+ return this.adapter;
516
+ }
517
+ /**
518
+ * Get EWC manager
519
+ */
520
+ getEwcManager() {
521
+ return this.ewcManager;
522
+ }
523
+ /**
524
+ * Get checkpoints
525
+ */
526
+ getCheckpoints() {
527
+ return [...this.checkpoints];
528
+ }
529
+ /**
530
+ * Reset pipeline
531
+ */
532
+ reset() {
533
+ this.batches = [];
534
+ this.checkpoints = [];
535
+ this.currentEpoch = 0;
536
+ this.currentStep = 0;
537
+ this.bestValLoss = Infinity;
538
+ this.patienceCounter = 0;
539
+ this.resumePending = false;
540
+ this.metrics.reset();
541
+ this.adapter.reset();
542
+ }
543
+ shuffleBatches() {
544
+ const shuffled = [...this.batches];
545
+ for (let i = shuffled.length - 1; i > 0; i--) {
546
+ const j = Math.floor(Math.random() * (i + 1));
547
+ [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
548
+ }
549
+ return shuffled;
550
+ }
551
+ }
552
+ exports.TrainingPipeline = TrainingPipeline;
553
+ /**
554
+ * Training Factory
555
+ *
556
+ * Create pre-configured training pipelines for common scenarios.
557
+ */
558
+ class TrainingFactory {
559
+ /**
560
+ * Create pipeline for quick fine-tuning
561
+ */
562
+ static quickFinetune() {
563
+ return new TrainingPipeline({
564
+ learningRate: 0.01,
565
+ epochs: 3,
566
+ batchSize: 16,
567
+ scheduler: 'constant',
568
+ });
569
+ }
570
+ /**
571
+ * Create pipeline for deep training
572
+ */
573
+ static deepTraining() {
574
+ return new TrainingPipeline({
575
+ learningRate: 0.001,
576
+ epochs: 50,
577
+ batchSize: 32,
578
+ scheduler: 'warmup',
579
+ warmupSteps: 500,
580
+ earlyStoppingPatience: 5,
581
+ });
582
+ }
583
+ /**
584
+ * Create pipeline for continual learning
585
+ */
586
+ static continualLearning(ewcLambda = 5000) {
587
+ return new TrainingPipeline({
588
+ learningRate: 0.0005,
589
+ epochs: 10,
590
+ batchSize: 16,
591
+ scheduler: 'cosine',
592
+ ewcLambda,
593
+ earlyStoppingPatience: 10,
594
+ });
595
+ }
596
+ /**
597
+ * Create pipeline for federated aggregation
598
+ */
599
+ static federatedAggregation() {
600
+ return new TrainingPipeline({
601
+ learningRate: 0.0001,
602
+ epochs: 5,
603
+ batchSize: 64,
604
+ scheduler: 'linear',
605
+ ewcLambda: 2000,
606
+ });
607
+ }
608
+ }
609
+ exports.TrainingFactory = TrainingFactory;
610
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhaW5pbmcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHJhaW5pbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXVCRzs7O0FBRUgsMkJBQTREO0FBQzVELCtCQUErQjtBQUUvQixpQ0FBcUM7QUFDckMsaUNBQW9DO0FBRXBDOztHQUVHO0FBQ0gsTUFBTSx1QkFBdUIsR0FBNkI7SUFDeEQsWUFBWSxFQUFFLEtBQUs7SUFDbkIsU0FBUyxFQUFFLEVBQUU7SUFDYixNQUFNLEVBQUUsRUFBRTtJQUNWLFNBQVMsRUFBRSxRQUFRO0lBQ25CLFdBQVcsRUFBRSxHQUFHO0lBQ2hCLFdBQVcsRUFBRSxJQUFJO0lBQ2pCLFlBQVksRUFBRSxHQUFHO0lBQ2pCLHFCQUFxQixFQUFFLENBQUM7SUFDeEIsa0JBQWtCLEVBQUUsQ0FBQztJQUNyQixTQUFTLEVBQUUsSUFBSTtJQUNmLGVBQWUsRUFBRSxHQUFHO0lBQ3BCLGtCQUFrQixFQUFFLEVBQUU7Q0FDdkIsQ0FBQztBQXNFRjs7Ozs7Ozs7R0FRRztBQUNILE1BQU0seUJBQXlCLEdBQUcsQ0FBQyxDQUFDO0FBRXBDOztHQUVHO0FBQ0gsTUFBYSxXQUFXO0lBTXRCLFlBQVksTUFBZ0MsRUFBRSxVQUFrQjtRQUh4RCxnQkFBVyxHQUFXLENBQUMsQ0FBQztRQUk5QixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJQUFJLENBQUMsU0FBUyxHQUFHLE1BQU0sQ0FBQyxZQUFZLENBQUM7UUFDckMsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7SUFDL0IsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSztRQUNILFFBQVEsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUM5QixLQUFLLFVBQVU7Z0JBQ2IsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDO1lBRXhCLEtBQUssUUFBUTtnQkFDWCxPQUFPLElB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YWluaW5nIFBpcGVsaW5lIGZvciBTT05BXG4gKlxuICogQ29tcHJlaGVuc2l2ZSB0cmFpbmluZyBpbmZyYXN0cnVjdHVyZSB3aXRoIG1ldHJpY3MgdHJhY2tpbmcsXG4gKiBsZWFybmluZyByYXRlIHNjaGVkdWxpbmcsIGFuZCBjaGVja3BvaW50IG1hbmFnZW1lbnQuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IFRyYWluaW5nUGlwZWxpbmUsIFRyYWluaW5nQ29uZmlnIH0gZnJvbSAnQHJ1dmVjdG9yL3J1dmxsbSc7XG4gKlxuICogY29uc3QgcGlwZWxpbmUgPSBuZXcgVHJhaW5pbmdQaXBlbGluZSh7XG4gKiAgIGxlYXJuaW5nUmF0ZTogMC4wMDEsXG4gKiAgIGJhdGNoU2l6ZTogMzIsXG4gKiAgIGVwb2NoczogMTAsXG4gKiB9KTtcbiAqXG4gKiAvLyBBZGQgdHJhaW5pbmcgZGF0YVxuICogcGlwZWxpbmUuYWRkQmF0Y2goaW5wdXRzLCB0YXJnZXRzLCBxdWFsaXRpZXMpO1xuICpcbiAqIC8vIFJ1biB0cmFpbmluZ1xuICogY29uc3QgcmVzdWx0ID0gcGlwZWxpbmUudHJhaW4oKTtcbiAqIGNvbnNvbGUubG9nKGBGaW5hbCBsb3NzOiAke3Jlc3VsdC5maW5hbExvc3N9YCk7XG4gKiBgYGBcbiAqL1xuXG5pbXBvcnQgeyB3cml0ZUZpbGVTeW5jLCByZWFkRmlsZVN5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcbmltcG9ydCB7IGRpcm5hbWUgfSBmcm9tICdwYXRoJztcbmltcG9ydCB7IEVtYmVkZGluZywgVHJhaW5pbmdDb25maWcsIFRyYWluaW5nUmVzdWx0IH0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBMb3JhQWRhcHRlciB9IGZyb20gJy4vbG9yYSc7XG5pbXBvcnQgeyBFd2NNYW5hZ2VyIH0gZnJvbSAnLi9zb25hJztcblxuLyoqXG4gKiBEZWZhdWx0IHRyYWluaW5nIGNvbmZpZ1xuICovXG5jb25zdCBERUZBVUxUX1RSQUlOSU5HX0NPTkZJRzogUmVxdWlyZWQ8VHJhaW5pbmdDb25maWc+ID0ge1xuICBsZWFybmluZ1JhdGU6IDAuMDAxLFxuICBiYXRjaFNpemU6IDMyLFxuICBlcG9jaHM6IDEwLFxuICBzY2hlZHVsZXI6ICdjb3NpbmUnLFxuICB3YXJtdXBTdGVwczogMTAwLFxuICB3ZWlnaHREZWNheTogMC4wMSxcbiAgZ3JhZGllbnRDbGlwOiAxLjAsXG4gIGVhcmx5U3RvcHBpbmdQYXRpZW5jZTogMyxcbiAgY2hlY2twb2ludEludGVydmFsOiAxLFxuICBld2NMYW1iZGE6IDIwMDAsXG4gIHZhbGlkYXRpb25TcGxpdDogMC4xLFxuICBrZWVwQmVzdENoZWNrcG9pbnQ6ICcnLFxufTtcblxuLyoqXG4gKiBUcmFpbmluZyBtZXRyaWNzXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVHJhaW5pbmdNZXRyaWNzIHtcbiAgLyoqIEN1cnJlbnQgZXBvY2ggKi9cbiAgZXBvY2g6IG51bWJlcjtcbiAgLyoqIEN1cnJlbnQgc3RlcCAqL1xuICBzdGVwOiBudW1iZXI7XG4gIC8qKiBUcmFpbmluZyBsb3NzICovXG4gIHRyYWluTG9zczogbnVtYmVyO1xuICAvKiogVmFsaWRhdGlvbiBsb3NzICovXG4gIHZhbExvc3M6IG51bWJlcjtcbiAgLyoqIExlYXJuaW5nIHJhdGUgKi9cbiAgbGVhcm5pbmdSYXRlOiBudW1iZXI7XG4gIC8qKiBHcmFkaWVudCBub3JtICovXG4gIGdyYWROb3JtOiBudW1iZXI7XG4gIC8qKiBTdGVwcyBwZXIgc2Vjb25kICovXG4gIHN0ZXBzUGVyU2Vjb25kOiBudW1iZXI7XG4gIC8qKiBFVEEgaW4gc2Vjb25kcyAqL1xuICBldGFTZWNvbmRzOiBudW1iZXI7XG59XG5cbi8qKlxuICogVHJhaW5pbmcgZGF0YSBiYXRjaFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFRyYWluaW5nQmF0Y2gge1xuICAvKiogSW5wdXQgZW1iZWRkaW5ncyAqL1xuICBpbnB1dHM6IEVtYmVkZGluZ1tdO1xuICAvKiogVGFyZ2V0IG91dHB1dHMgKi9cbiAgdGFyZ2V0czogRW1iZWRkaW5nW107XG4gIC8qKiBRdWFsaXR5IHNjb3JlcyAqL1xuICBxdWFsaXRpZXM6IG51bWJlcltdO1xufVxuXG4vKipcbiAqIENoZWNrcG9pbnQgZGF0YVxuICovXG5leHBvcnQgaW50ZXJmYWNlIENoZWNrcG9pbnQge1xuICAvKiogRXBvY2ggbnVtYmVyICovXG4gIGVwb2NoOiBudW1iZXI7XG4gIC8qKiBTdGVwIG51bWJlciAqL1xuICBzdGVwOiBudW1iZXI7XG4gIC8qKiBUcmFpbmluZyBsb3NzIGF0IGNoZWNrcG9pbnQgKi9cbiAgbG9zczogbnVtYmVyO1xuICAvKiogTW9kZWwgd2VpZ2h0cyAoc2VyaWFsaXplZCkgKi9cbiAgd2VpZ2h0czogc3RyaW5nO1xuICAvKiogVGltZXN0YW1wICovXG4gIHRpbWVzdGFtcDogbnVtYmVyO1xufVxuXG4vKipcbiAqIFJlc3VsdCBvZiBhIHNhdmVDaGVja3BvaW50KCkgY2FsbC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDaGVja3BvaW50U2F2ZVJlc3VsdCB7XG4gIC8qKiBJbmRleCBvZiB0aGUgY2hlY2twb2ludCBpbiB0aGUgaW4tbWVtb3J5IGNoZWNrcG9pbnQgbGlzdCAqL1xuICBpbmRleDogbnVtYmVyO1xuICAvKiogRXBvY2ggdGhlIGNoZWNrcG9pbnQgY2FwdHVyZWQgKi9cbiAgZXBvY2g6IG51bWJlcjtcbiAgLyoqIFN0ZXAgdGhlIGNoZWNrcG9pbnQgY2FwdHVyZWQgKi9cbiAgc3RlcDogbnVtYmVyO1xuICAvKiogVHJhaW5pbmcgbG9zcyBhdCBjaGVja3BvaW50IHRpbWUgKi9cbiAgbG9zczogbnVtYmVyO1xuICAvKiogQWJzb2x1dGUgb3IgYXMtZ2l2ZW4gZmlsZSBwYXRoLCB3aGVuIHBlcnNpc3RlZCB0byBkaXNrICovXG4gIHBhdGg/OiBzdHJpbmc7XG4gIC8qKiBTZXJpYWxpemVkIHNpemUgaW4gYnl0ZXMsIHdoZW4gcGVyc2lzdGVkIHRvIGRpc2sgKi9cbiAgYnl0ZXM/OiBudW1iZXI7XG59XG5cbi8qKlxuICogT24tZGlzayBjaGVja3BvaW50IGVudmVsb3BlIHZlcnNpb24uXG4gKlxuICogdjEg4oCUIHtmb3JtYXQsIHZlcnNpb246MSwgZXBvY2gsIHN0ZXAsIGxvc3MsIHdlaWdodHMsIHRpbWVzdGFtcH0uIE5vIGFkYXB0ZXJcbiAqICAgICAgZ2VvbWV0cnksIHNvIGxvYWRDaGVja3BvaW50KCkgY291bGQgbm90IGRldGVjdCBhIHNoYXBlIG1pc21hdGNoLlxuICogdjIg4oCUIGFkZHMge2NvbmZpZzp7aW5wdXREaW0sIG91dHB1dERpbSwgcmFua30sIHBpcGVsaW5lQ29uZmlnOntsZWFybmluZ1JhdGUsXG4gKiAgICAgIGJhdGNoU2l6ZX19IHNvIGxvYWRDaGVja3BvaW50KCkgY2FuIHJlamVjdCB3ZWlnaHRzIHRoYXQgZG9uJ3QgZml0IHRoZVxuICogICAgICBjdXJyZW50IGFkYXB0ZXIuIHYxIGZpbGVzIHN0aWxsIGxvYWQgKGJhY2stY29tcGF0KSB3aXRoIG5vIHNoYXBlIGNoZWNrLlxuICovXG5jb25zdCBDSEVDS1BPSU5UX0ZPUk1BVF9WRVJTSU9OID0gMjtcblxuLyoqXG4gKiBMZWFybmluZyBSYXRlIFNjaGVkdWxlclxuICovXG5leHBvcnQgY2xhc3MgTFJTY2hlZHVsZXIge1xuICBwcml2YXRlIGNvbmZpZzogUmVxdWlyZWQ8VHJhaW5pbmdDb25maWc+O1xuICBwcml2YXRlIGluaXRpYWxMUjogbnVtYmVyO1xuICBwcml2YXRlIGN1cnJlbnRTdGVwOiBudW1iZXIgPSAwO1xuICBwcml2YXRlIHRvdGFsU3RlcHM6IG51bWJlcjtcblxuICBjb25zdHJ1Y3Rvcihjb25maWc6IFJlcXVpcmVkPFRyYWluaW5nQ29uZmlnPiwgdG90YWxTdGVwczogbnVtYmVyKSB7XG4gICAgdGhpcy5jb25maWcgPSBjb25maWc7XG4gICAgdGhpcy5pbml0aWFsTFIgPSBjb25maWcubGVhcm5pbmdSYXRlO1xuICAgIHRoaXMudG90YWxTdGVwcyA9IHRvdGFsU3RlcHM7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGxlYXJuaW5nIHJhdGUgZm9yIGN1cnJlbnQgc3RlcFxuICAgKi9cbiAgZ2V0TFIoKTogbnVtYmVyIHtcbiAgICBzd2l0Y2ggKHRoaXMuY29uZmlnLnNjaGVkdWxlcikge1xuICAgICAgY2FzZSAnY29uc3RhbnQnOlxuICAgICAgICByZXR1cm4gdGhpcy5pbml0aWFsTFI7XG5cbiAgICAgIGNhc2UgJ2xpbmVhcic6XG4gICAgICAgIHJldHVybiB0aGlzLmluaXRpYWxMUiAqICgxIC0gdGhpcy5jdXJyZW50U3RlcCAvIHRoaXMudG90YWxTdGVwcyk7XG5cbiAgICAgIGNhc2UgJ2Nvc2luZSc6XG4gICAgICAgIHJldHVybiB0aGlzLmluaXRpYWxMUiAqIDAuNSAqICgxICsgTWF0aC5jb3MoTWF0aC5QSSAqIHRoaXMuY3VycmVudFN0ZXAgLyB0aGlzLnRvdGFsU3RlcHMpKTtcblxuICAgICAgY2FzZSAnd2FybXVwJzpcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudFN0ZXAgPCB0aGlzLmNvbmZpZy53YXJtdXBTdGVwcykge1xuICAgICAgICAgIHJldHVybiB0aGlzLmluaXRpYWxMUiAqICh0aGlzLmN1cnJlbnRTdGVwIC8gdGhpcy5jb25maWcud2FybXVwU3RlcHMpO1xuICAgICAgICB9XG4gICAgICAgIC8vIENvc2luZSBkZWNheSBhZnRlciB3YXJtdXBcbiAgICAgICAgY29uc3QgZGVjYXlTdGVwcyA9IHRoaXMudG90YWxTdGVwcyAtIHRoaXMuY29uZmlnLndhcm11cFN0ZXBzO1xuICAgICAgICBjb25zdCBkZWNheVByb2dyZXNzID0gKHRoaXMuY3VycmVudFN0ZXAgLSB0aGlzLmNvbmZpZy53YXJtdXBTdGVwcykgLyBkZWNheVN0ZXBzO1xuICAgICAgICByZXR1cm4gdGhpcy5pbml0aWFsTFIgKiAwLjUgKiAoMSArIE1hdGguY29zKE1hdGguUEkgKiBkZWNheVByb2dyZXNzKSk7XG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiB0aGlzLmluaXRpYWxMUjtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU3RlcCB0aGUgc2NoZWR1bGVyXG4gICAqL1xuICBzdGVwKCk6IHZvaWQge1xuICAgIHRoaXMuY3VycmVudFN0ZXArKztcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNldCBzY2hlZHVsZXJcbiAgICovXG4gIHJlc2V0KCk6IHZvaWQge1xuICAgIHRoaXMuY3VycmVudFN0ZXAgPSAwO1xuICB9XG59XG5cbi8qKlxuICogVHJhaW5pbmcgTWV0cmljcyBUcmFja2VyXG4gKi9cbmV4cG9ydCBjbGFzcyBNZXRyaWNzVHJhY2tlciB7XG4gIHByaXZhdGUgbG9zc0hpc3Rvcnk6IG51bWJlcltdID0gW107XG4gIHByaXZhdGUgdmFsTG9zc0hpc3Rvcnk6IG51bWJlcltdID0gW107XG4gIHByaXZhdGUgZ3JhZE5vcm1IaXN0b3J5OiBudW1iZXJbXSA9IFtdO1xuICBwcml2YXRlIHN0YXJ0VGltZTogbnVtYmVyID0gRGF0ZS5ub3coKTtcbiAgcHJpdmF0ZSBzdGVwVGltZXM6IG51bWJlcltdID0gW107XG5cbiAgLyoqXG4gICAqIFJlY29yZCB0cmFpbmluZyBsb3NzXG4gICAqL1xuICByZWNvcmRMb3NzKGxvc3M6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMubG9zc0hpc3RvcnkucHVzaChsb3NzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWNvcmQgdmFsaWRhdGlvbiBsb3NzXG4gICAqL1xuICByZWNvcmRWYWxMb3NzKGxvc3M6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMudmFsTG9zc0hpc3RvcnkucHVzaChsb3NzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWNvcmQgZ3JhZGllbnQgbm9ybVxuICAgKi9cbiAgcmVjb3JkR3JhZE5vcm0obm9ybTogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5ncmFkTm9ybUhpc3RvcnkucHVzaChub3JtKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWNvcmQgc3RlcCB0aW1lXG4gICAqL1xuICByZWNvcmRTdGVwVGltZShtczogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5zdGVwVGltZXMucHVzaChtcyk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGF2ZXJhZ2UgbG9zcyBvdmVyIGxhc3QgTiBzdGVwc1xuICAgKi9cbiAgYXZnTG9zcyhuOiBudW1iZXIgPSAxMDApOiBudW1iZXIge1xuICAgIGNvbnN0IHJlY2VudCA9IHRoaXMubG9zc0hpc3Rvcnkuc2xpY2UoLW4pO1xuICAgIHJldHVybiByZWNlbnQubGVuZ3RoID4gMCA/IHJlY2VudC5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKSAvIHJlY2VudC5sZW5ndGggOiAwO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhdmVyYWdlIHZhbGlkYXRpb24gbG9zc1xuICAgKi9cbiAgYXZnVmFsTG9zcyhuOiBudW1iZXIgPSAxMCk6IG51bWJlciB7XG4gICAgY29uc3QgcmVjZW50ID0gdGhpcy52YWxMb3NzSGlzdG9yeS5zbGljZSgtbik7XG4gICAgcmV0dXJuIHJlY2VudC5sZW5ndGggPiAwID8gcmVjZW50LnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApIC8gcmVjZW50Lmxlbmd0aCA6IDA7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHN0ZXBzIHBlciBzZWNvbmRcbiAgICovXG4gIHN0ZXBzUGVyU2Vjb25kKCk6IG51bWJlciB7XG4gICAgaWYgKHRoaXMuc3RlcFRpbWVzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIDA7XG4gICAgY29uc3QgYXZnU3RlcFRpbWUgPSB0aGlzLnN0ZXBUaW1lcy5zbGljZSgtMTAwKS5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKSAvIE1hdGgubWluKHRoaXMuc3RlcFRpbWVzLmxlbmd0aCwgMTAwKTtcbiAgICByZXR1cm4gYXZnU3RlcFRpbWUgPiAwID8gMTAwMCAvIGF2Z1N0ZXBUaW1lIDogMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgRVRBIGluIHNlY29uZHNcbiAgICovXG4gIGV0YShyZW1haW5pbmdTdGVwczogbnVtYmVyKTogbnVtYmVyIHtcbiAgICBjb25zdCBzcHMgPSB0aGlzLnN0ZXBzUGVyU2Vjb25kKCk7XG4gICAgcmV0dXJuIHNwcyA+IDAgPyByZW1haW5pbmdTdGVwcyAvIHNwcyA6IDA7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGJlc3QgdmFsaWRhdGlvbiBsb3NzXG4gICAqL1xuICBiZXN0VmFsTG9zcygpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnZhbExvc3NIaXN0b3J5Lmxlbmd0aCA+IDAgPyBNYXRoLm1pbiguLi50aGlzLnZhbExvc3NIaXN0b3J5KSA6IEluZmluaXR5O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0b3RhbCBkdXJhdGlvblxuICAgKi9cbiAgZHVyYXRpb24oKTogbnVtYmVyIHtcbiAgICByZXR1cm4gRGF0ZS5ub3coKSAtIHRoaXMuc3RhcnRUaW1lO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhbGwgbG9zcyBoaXN0b3J5XG4gICAqL1xuICBnZXRMb3NzSGlzdG9yeSgpOiBudW1iZXJbXSB7XG4gICAgcmV0dXJuIFsuLi50aGlzLmxvc3NIaXN0b3J5XTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgYWxsIHZhbGlkYXRpb24gbG9zcyBoaXN0b3J5XG4gICAqL1xuICBnZXRWYWxMb3NzSGlzdG9yeSgpOiBudW1iZXJbXSB7XG4gICAgcmV0dXJuIFsuLi50aGlzLnZhbExvc3NIaXN0b3J5XTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNldCB0cmFja2VyXG4gICAqL1xuICByZXNldCgpOiB2b2lkIHtcbiAgICB0aGlzLmxvc3NIaXN0b3J5ID0gW107XG4gICAgdGhpcy52YWxMb3NzSGlzdG9yeSA9IFtdO1xuICAgIHRoaXMuZ3JhZE5vcm1IaXN0b3J5ID0gW107XG4gICAgdGhpcy5zdGVwVGltZXMgPSBbXTtcbiAgICB0aGlzLnN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gIH1cbn1cblxuLyoqXG4gKiBUcmFpbmluZyBQaXBlbGluZVxuICpcbiAqIEZ1bGwgdHJhaW5pbmcgaW5mcmFzdHJ1Y3R1cmUgZm9yIFNPTkEgbW9kZWxzLlxuICovXG5leHBvcnQgY2xhc3MgVHJhaW5pbmdQaXBlbGluZSB7XG4gIHByaXZhdGUgY29uZmlnOiBSZXF1aXJlZDxUcmFpbmluZ0NvbmZpZz47XG4gIHByaXZhdGUgYWRhcHRlcjogTG9yYUFkYXB0ZXI7XG4gIHByaXZhdGUgZXdjTWFuYWdlcjogRXdjTWFuYWdlcjtcbiAgcHJpdmF0ZSBtZXRyaWNzOiBNZXRyaWNzVHJhY2tlcjtcbiAgcHJpdmF0ZSBzY2hlZHVsZXI6IExSU2NoZWR1bGVyIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgYmF0Y2hlczogVHJhaW5pbmdCYXRjaFtdID0gW107XG4gIHByaXZhdGUgY2hlY2twb2ludHM6IENoZWNrcG9pbnRbXSA9IFtdO1xuICBwcml2YXRlIGN1cnJlbnRFcG9jaDogbnVtYmVyID0gMDtcbiAgcHJpdmF0ZSBjdXJyZW50U3RlcDogbnVtYmVyID0gMDtcbiAgcHJpdmF0ZSBiZXN0VmFsTG9zczogbnVtYmVyID0gSW5maW5pdHk7XG4gIHByaXZhdGUgcGF0aWVuY2VDb3VudGVyOiBudW1iZXIgPSAwO1xuICAvKiogU2V0IGJ5IHJlc3VtZUZyb20oKTsgbWFrZXMgdGhlIG5leHQgdHJhaW4oKSBjb250aW51ZSBpbnN0ZWFkIG9mIHJlc3RhcnQuICovXG4gIHByaXZhdGUgcmVzdW1lUGVuZGluZzogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIGNvbnN0cnVjdG9yKGNvbmZpZz86IFRyYWluaW5nQ29uZmlnLCBhZGFwdGVyPzogTG9yYUFkYXB0ZXIpIHtcbiAgICB0aGlzLmNvbmZpZyA9IHsgLi4uREVGQVVMVF9UUkFJTklOR19DT05GSUcsIC4uLmNvbmZpZyB9O1xuICAgIHRoaXMuYWRhcHRlciA9IGFkYXB0ZXIgfHwgbmV3IExvcmFBZGFwdGVyKHsgcmFuazogOCB9KTtcbiAgICB0aGlzLmV3Y01hbmFnZXIgPSBuZXcgRXdjTWFuYWdlcih0aGlzLmNvbmZpZy5ld2NMYW1iZGEpO1xuICAgIHRoaXMubWV0cmljcyA9IG5ldyBNZXRyaWNzVHJhY2tlcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCB0cmFpbmluZyBiYXRjaFxuICAgKi9cbiAgYWRkQmF0Y2goaW5wdXRzOiBFbWJlZGRpbmdbXSwgdGFyZ2V0czogRW1iZWRkaW5nW10sIHF1YWxpdGllczogbnVtYmVyW10pOiB2b2lkIHtcbiAgICB0aGlzLmJhdGNoZXMucHVzaCh7IGlucHV0cywgdGFyZ2V0cywgcXVhbGl0aWVzIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCB0cmFpbmluZyBkYXRhXG4gICAqL1xuICBhZGREYXRhKGRhdGE6IEFycmF5PHsgaW5wdXQ6IEVtYmVkZGluZzsgdGFyZ2V0OiBFbWJlZGRpbmc7IHF1YWxpdHk6IG51bWJlciB9Pik6IHZvaWQge1xuICAgIC8vIEdyb3VwIGludG8gYmF0Y2hlc1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZGF0YS5sZW5ndGg7IGkgKz0gdGhpcy5jb25maWcuYmF0Y2hTaXplKSB7XG4gICAgICBjb25zdCBiYXRjaCA9IGRhdGEuc2xpY2UoaSwgaSArIHRoaXMuY29uZmlnLmJhdGNoU2l6ZSk7XG4gICAgICB0aGlzLmFkZEJhdGNoKFxuICAgICAgICBiYXRjaC5tYXAoZCA9PiBkLmlucHV0KSxcbiAgICAgICAgYmF0Y2gubWFwKGQgPT4gZC50YXJnZXQpLFxuICAgICAgICBiYXRjaC5tYXAoZCA9PiBkLnF1YWxpdHkpXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSdW4gdHJhaW5pbmcuXG4gICAqXG4gICAqIFdoZW4ge0BsaW5rIHJlc3VtZUZyb219IHByaW1lZCB0aGUgcGlwZWxpbmUsIHRoaXMgY29udGludWVzIGZyb20gdGhlXG4gICAqIHJlc3RvcmVkIGVwb2NoIChydW5uaW5nIHRoZSByZW1haW5pbmcgZXBvY2hzIG9mIGBjb25maWcuZXBvY2hzYCkgYW5kXG4gICAqIGFkdmFuY2VzIHRoZSBMUiBzY2hlZHVsZXIgdG8gdGhlIHJlc3RvcmVkIHN0ZXAgc28gdGhlIHNjaGVkdWxlIGlzXG4gICAqIHVuYnJva2VuOyBtZXRyaWNzIGhpc3RvcnkgaXMgcHJlc2VydmVkLiBXaXRob3V0IGEgcmVzdW1lIHRoZSBydW4gaXNcbiAgICogdW5jaGFuZ2VkIGZyb20gYSBmcmVzaCBzdGFydCDigJQgc2FtZSByZXNldCwgc2FtZSBzY2hlZHVsZXIsIHNhbWUgcmVzdWx0XG4gICAqIHNoYXBlIGFzIGJlZm9yZSB0aGlzIG1ldGhvZCBsZWFybmVkIHRvIHJlc3VtZS5cbiAgICovXG4gIHRyYWluKCk6IFRyYWluaW5nUmVzdWx0IHtcbiAgICBjb25zdCByZXN1bWluZyA9IHRoaXMucmVzdW1lUGVuZGluZztcbiAgICB0aGlzLnJlc3VtZVBlbmRpbmcgPSBmYWxzZTtcbiAgICAvLyBjdXJyZW50RXBvY2ggaXMgdGhlIGxhc3QgQ09NUExFVEVEIGVwb2NoIGluZGV4LCBzbyByZXN1bWUgdGhlIG5leHQgb25lLlxuICAgIGNvbnN0IHN0YXJ0RXBvY2ggPSByZXN1bWluZyA/IHRoaXMuY3VycmVudEVwb2NoICsgMSA6IDA7XG5cbiAgICBjb25zdCB0b3RhbFN0ZXBzID0gdGhpcy5iYXRjaGVzLmxlbmd0aCAqIHRoaXMuY29uZmlnLmVwb2NocztcbiAgICB0aGlzLnNjaGVkdWxlciA9IG5ldyBMUlNjaGVkdWxlcih0aGlzLmNvbmZpZywgdG90YWxTdGVwcyk7XG4gICAgaWYgKHJlc3VtaW5nKSB7XG4gICAgICAvLyBGYXN0LWZvcndhcmQgdGhlIGZyZXNoIHNjaGVkdWxlciB0byB0aGUgcmVzdG9yZWQgc3RlcC5cbiAgICAgIGZvciAobGV0IHMgPSAwOyBzIDwgdGhpcy5jdXJyZW50U3RlcCAmJiBzIDwgdG90YWxTdGVwczsgcysrKSB7XG4gICAgICAgIHRoaXMuc2NoZWR1bGVyLnN0ZXAoKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5tZXRyaWNzLnJlc2V0KCk7XG4gICAgfVxuICAgIHRoaXMuYWRhcHRlci5zdGFydFRyYWluaW5nKHRoaXMuY29uZmlnLmxlYXJuaW5nUmF0ZSk7XG5cbiAgICBsZXQgZWFybHlTdG9wcGVkID0gZmFsc2U7XG5cbiAgICBmb3IgKGxldCBlcG9jaCA9IHN0YXJ0RXBvY2g7IGVwb2NoIDwgdGhpcy5jb25maWcuZXBvY2hzOyBlcG9jaCsrKSB7XG4gICAgICB0aGlzLmN1cnJlbnRFcG9jaCA9IGVwb2NoO1xuXG4gICAgICAvLyBTaHVmZmxlIGJhdGNoZXNcbiAgICAgIGNvbnN0IHNodWZmbGVkQmF0Y2hlcyA9IHRoaXMuc2h1ZmZsZUJhdGNoZXMoKTtcblxuICAgICAgLy8gU3BsaXQgaW50byB0cmFpbi92YWxcbiAgICAgIGNvbnN0IHZhbFNpemUgPSBNYXRoLmZsb29yKHNodWZmbGVkQmF0Y2hlcy5sZW5ndGggKiB0aGlzLmNvbmZpZy52YWxpZGF0aW9uU3BsaXQpO1xuICAgICAgY29uc3QgdHJhaW5CYXRjaGVzID0gc2h1ZmZsZWRCYXRjaGVzLnNsaWNlKHZhbFNpemUpO1xuICAgICAgY29uc3QgdmFsQmF0Y2hlcyA9IHNodWZmbGVkQmF0Y2hlcy5zbGljZSgwLCB2YWxTaXplKTtcblxuICAgICAgLy8gVHJhaW5pbmcgZXBvY2hcbiAgICAgIGZvciAoY29uc3QgYmF0Y2ggb2YgdHJhaW5CYXRjaGVzKSB7XG4gICAgICAgIGNvbnN0IHN0ZXBTdGFydCA9IERhdGUubm93KCk7XG4gICAgICAgIGNvbnN0IGxvc3MgPSB0aGlzLnRyYWluU3RlcChiYXRjaCk7XG4gICAgICAgIHRoaXMubWV0cmljcy5yZWNvcmRMb3NzKGxvc3MpO1xuICAgICAgICB0aGlzLm1ldHJpY3MucmVjb3JkU3RlcFRpbWUoRGF0ZS5ub3coKSAtIHN0ZXBTdGFydCk7XG4gICAgICAgIHRoaXMuc2NoZWR1bGVyLnN0ZXAoKTtcbiAgICAgICAgdGhpcy5jdXJyZW50U3RlcCsrO1xuICAgICAgfVxuXG4gICAgICAvLyBWYWxpZGF0aW9uXG4gICAgICBpZiAodmFsQmF0Y2hlcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IHZhbExvc3MgPSB0aGlzLnZhbGlkYXRlKHZhbEJhdGNoZXMpO1xuICAgICAgICB0aGlzLm1ldHJpY3MucmVjb3JkVmFsTG9zcyh2YWxMb3NzKTtcblxuICAgICAgICAvLyBFYXJseSBzdG9wcGluZ1xuICAgICAgICBpZiAodmFsTG9zcyA8IHRoaXMuYmVzdFZhbExvc3MpIHtcbiAgICAgICAgICB0aGlzLmJlc3RWYWxMb3NzID0gdmFsTG9zcztcbiAgICAgICAgICB0aGlzLnBhdGllbmNlQ291bnRlciA9IDA7XG4gICAgICAgICAgLy8gUmV0YWluIHRoZSBiZXN0LXZhbGlkYXRpb24gbW9kZWwgdG8gYSBzdGFibGUgcGF0aCB3aGVuIGNvbmZpZ3VyZWQuXG4gICAgICAgICAgaWYgKHRoaXMuY29uZmlnLmtlZXBCZXN0Q2hlY2twb2ludCkge1xuICAgICAgICAgICAgdGhpcy5zYXZlQ2hlY2twb2ludCh0aGlzLmNvbmZpZy5rZWVwQmVzdENoZWNrcG9pbnQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnBhdGllbmNlQ291bnRlcisrO1xuICAgICAgICAgIGlmICh0aGlzLnBhdGllbmNlQ291bnRlciA+PSB0aGlzLmNvbmZpZy5lYXJseVN0b3BwaW5nUGF0aWVuY2UpIHtcbiAgICAgICAgICAgIGVhcmx5U3RvcHBlZCA9IHRydWU7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gQ2hlY2twb2ludFxuICAgICAgaWYgKChlcG9jaCArIDEpICUgdGhpcy5jb25maWcuY2hlY2twb2ludEludGVydmFsID09PSAwKSB7XG4gICAgICAgIHRoaXMuc2F2ZUNoZWNrcG9pbnQoKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLmFkYXB0ZXIuZW5kVHJhaW5pbmcoKTtcblxuICAgIC8vIFJlZ2lzdGVyIHdpdGggRVdDIGZvciBjb250aW51YWwgbGVhcm5pbmdcbiAgICBjb25zdCB3ZWlnaHRzID0gdGhpcy5hZGFwdGVyLm1lcmdlKCkuZmxhdCgpO1xuICAgIHRoaXMuZXdjTWFuYWdlci5yZWdpc3RlclRhc2soYHRhc2stJHtEYXRlLm5vdygpfWAsIHdlaWdodHMpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGVwb2NoczogdGhpcy5jdXJyZW50RXBvY2ggKyAxLFxuICAgICAgc3RlcHM6IHRoaXMuY3VycmVudFN0ZXAsXG4gICAgICBmaW5hbExvc3M6IHRoaXMubWV0cmljcy5hdmdMb3NzKDEwMCksXG4gICAgICBiZXN0VmFsTG9zczogdGhpcy5iZXN0VmFsTG9zcyxcbiAgICAgIGR1cmF0aW9uTXM6IHRoaXMubWV0cmljcy5kdXJhdGlvbigpLFxuICAgICAgbG9zc0hpc3Rvcnk6IHRoaXMubWV0cmljcy5nZXRMb3NzSGlzdG9yeSgpLFxuICAgICAgdmFsTG9zc0hpc3Rvcnk6IHRoaXMubWV0cmljcy5nZXRWYWxMb3NzSGlzdG9yeSgpLFxuICAgICAgZWFybHlTdG9wcGVkLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogU2luZ2xlIHRyYWluaW5nIHN0ZXBcbiAgICovXG4gIHByaXZhdGUgdHJhaW5TdGVwKGJhdGNoOiBUcmFpbmluZ0JhdGNoKTogbnVtYmVyIHtcbiAgICBsZXQgdG90YWxMb3NzID0gMDtcbiAgICBjb25zdCBsciA9IHRoaXMuc2NoZWR1bGVyPy5nZXRMUigpIHx8IHRoaXMuY29uZmlnLmxlYXJuaW5nUmF0ZTtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYmF0Y2guaW5wdXRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBpbnB1dCA9IGJhdGNoLmlucHV0c1tpXTtcbiAgICAgIGNvbnN0IHRhcmdldCA9IGJhdGNoLnRhcmdldHNbaV07XG4gICAgICBjb25zdCBxdWFsaXR5ID0gYmF0Y2gucXVhbGl0aWVzW2ldO1xuXG4gICAgICAvLyBGb3J3YXJkIHBhc3NcbiAgICAgIGNvbnN0IG91dHB1dCA9IHRoaXMuYWRhcHRlci5mb3J3YXJkKGlucHV0KTtcblxuICAgICAgLy8gQ29tcHV0ZSBsb3NzIChNU0Ugd2VpZ2h0ZWQgYnkgcXVhbGl0eSlcbiAgICAgIGNvbnN0IGdyYWRPdXRwdXQ6IG51bWJlcltdID0gW107XG4gICAgICBsZXQgbG9zcyA9IDA7XG4gICAgICBmb3IgKGxldCBqID0gMDsgaiA8IG91dHB1dC5sZW5ndGg7IGorKykge1xuICAgICAgICBjb25zdCBkaWZmID0gb3V0cHV0W2pdIC0gKHRhcmdldFtqXSB8fCAwKTtcbiAgICAgICAgbG9zcyArPSBkaWZmICogZGlmZjtcbiAgICAgICAgZ3JhZE91dHB1dC5wdXNoKDIgKiBkaWZmICogcXVhbGl0eSk7IC8vIFF1YWxpdHktd2VpZ2h0ZWQgZ3JhZGllbnRcbiAgICAgIH1cbiAgICAgIGxvc3MgPSAobG9zcyAvIG91dHB1dC5sZW5ndGgpICogcXVhbGl0eTtcblxuICAgICAgLy8gQWRkIEVXQyBwZW5hbHR5XG4gICAgICBjb25zdCBld2NQZW5hbHR5ID0gdGhpcy5ld2NNYW5hZ2VyLmNvbXB1dGVQZW5hbHR5KHRoaXMuYWRhcHRlci5tZXJnZSgpLmZsYXQoKSk7XG4gICAgICBsb3NzICs9IGV3Y1BlbmFsdHkgKiAwLjAwMTtcblxuICAgICAgLy8gQmFja3dhcmQgcGFzc1xuICAgICAgdGhpcy5hZGFwdGVyLmJhY2t3YXJkKGlucHV0LCBncmFkT3V0cHV0LCBscik7XG5cbiAgICAgIHRvdGFsTG9zcyArPSBsb3NzO1xuICAgIH1cblxuICAgIHJldHVybiB0b3RhbExvc3MgLyBiYXRjaC5pbnB1dHMubGVuZ3RoO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRpb24gcGFzc1xuICAgKi9cbiAgcHJpdmF0ZSB2YWxpZGF0ZShiYXRjaGVzOiBUcmFpbmluZ0JhdGNoW10pOiBudW1iZXIge1xuICAgIGxldCB0b3RhbExvc3MgPSAwO1xuICAgIGxldCBjb3VudCA9IDA7XG5cbiAgICBmb3IgKGNvbnN0IGJhdGNoIG9mIGJhdGNoZXMpIHtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYmF0Y2guaW5wdXRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IG91dHB1dCA9IHRoaXMuYWRhcHRlci5mb3J3YXJkKGJhdGNoLmlucHV0c1tpXSk7XG4gICAgICAgIGNvbnN0IHRhcmdldCA9IGJhdGNoLnRhcmdldHNbaV07XG5cbiAgICAgICAgbGV0IGxvc3MgPSAwO1xuICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IG91dHB1dC5sZW5ndGg7IGorKykge1xuICAgICAgICAgIGNvbnN0IGRpZmYgPSBvdXRwdXRbal0gLSAodGFyZ2V0W2pdIHx8IDApO1xuICAgICAgICAgIGxvc3MgKz0gZGlmZiAqIGRpZmY7XG4gICAgICAgIH1cbiAgICAgICAgdG90YWxMb3NzICs9IGxvc3MgLyBvdXRwdXQubGVuZ3RoO1xuICAgICAgICBjb3VudCsrO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBjb3VudCA+IDAgPyB0b3RhbExvc3MgLyBjb3VudCA6IDA7XG4gIH1cblxuICAvKipcbiAgICogU2F2ZSBhIGNoZWNrcG9pbnQuXG4gICAqXG4gICAqIEFsd2F5cyByZWNvcmRzIHRoZSBjaGVja3BvaW50IGluIHRoZSBpbi1tZW1vcnkgbGlzdCAodGhlIGJlaGF2aW9yIHRoZVxuICAgKiB0cmFpbmluZyBsb29wIHJlbGllcyBvbikuIFdoZW4gYHBhdGhgIGlzIGdpdmVuLCBhZGRpdGlvbmFsbHkgcGVyc2lzdHNcbiAgICogdGhlIGNoZWNrcG9pbnQgdG8gZGlzayBhcyB2ZXJzaW9uZWQgSlNPTiDigJQgYmVmb3JlIHYyLjUuNyB0aGlzIG1ldGhvZFxuICAgKiB3YXMgcHJpdmF0ZSwgaWdub3JlZCBhbnkgYXJndW1lbnQsIGFuZCBuZXZlciB3cm90ZSBhIGZpbGUsIHNvIGNhbGxlcnNcbiAgICogcGFzc2luZyBhIHBhdGggZ290IGB1bmRlZmluZWRgIGJhY2sgYW5kIHplcm8gYnl0ZXMgb24gZGlzay5cbiAgICpcbiAgICogQHBhcmFtIHBhdGggT3B0aW9uYWwgZmlsZSBwYXRoOyBwYXJlbnQgZGlyZWN0b3JpZXMgYXJlIGNyZWF0ZWQuXG4gICAqIEByZXR1cm5zIFdoZXJlIHRoZSBjaGVja3BvaW50IHdlbnQg4oCUIGluLW1lbW9yeSBpbmRleCwgYW5kIGZpbGVcbiAgICogICAgICAgICAgcGF0aCArIGJ5dGUgc2l6ZSB3aGVuIHBlcnNpc3RlZC5cbiAgICovXG4gIHNhdmVDaGVja3BvaW50KHBhdGg/OiBzdHJpbmcpOiBDaGVja3BvaW50U2F2ZVJlc3VsdCB7XG4gICAgY29uc3QgY2hlY2twb2ludDogQ2hlY2twb2ludCA9IHtcbiAgICAgIGVwb2NoOiB0aGlzLmN1cnJlbnRFcG9jaCxcbiAgICAgIHN0ZXA6IHRoaXMuY3VycmVudFN0ZXAsXG4gICAgICBsb3NzOiB0aGlzLm1ldHJpY3MuYXZnTG9zcygxMDApLFxuICAgICAgd2VpZ2h0czogdGhpcy5hZGFwdGVyLnRvSlNPTigpLFxuICAgICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxuICAgIH07XG4gICAgdGhpcy5jaGVja3BvaW50cy5wdXNoKGNoZWNrcG9pbnQpO1xuXG4gICAgY29uc3QgcmVzdWx0OiBDaGVja3BvaW50U2F2ZVJlc3VsdCA9IHtcbiAgICAgIGluZGV4OiB0aGlzLmNoZWNrcG9pbnRzLmxlbmd0aCAtIDEsXG4gICAgICBlcG9jaDogY2hlY2twb2ludC5lcG9jaCxcbiAgICAgIHN0ZXA6IGNoZWNrcG9pbnQuc3RlcCxcbiAgICAgIGxvc3M6IGNoZWNrcG9pbnQubG9zcyxcbiAgICB9O1xuXG4gICAgaWYgKHBhdGgpIHtcbiAgICAgIGNvbnN0IGVudmVsb3BlID0ge1xuICAgICAgICBmb3JtYXQ6ICdydXZsbG0tY2hlY2twb2ludCcsXG4gICAgICAgIHZlcnNpb246IENIRUNLUE9JTlRfRk9STUFUX1ZFUlNJT04sXG4gICAgICAgIC8vIEFkYXB0ZXIgZ2VvbWV0cnkgKyBwaXBlbGluZSBoeXBlcnBhcmFtcyDigJQgbGV0cyBsb2FkQ2hlY2twb2ludCgpXG4gICAgICAgIC8vIHJlamVjdCB3ZWlnaHRzIHRoYXQgZG9uJ3QgZml0IHRoZSBjdXJyZW50IGFkYXB0ZXIgKHYyLCBzZWUgYmVsb3cpLlxuICAgICAgICBjb25maWc6IHtcbiAgICAgICAgICBpbnB1dERpbTogdGhpcy5hZGFwdGVyLmdldElucHV0RGltKCksXG4gICAgICAgICAgb3V0cHV0RGltOiB0aGlzLmFkYXB0ZXIuZ2V0T3V0cHV0RGltKCksXG4gICAgICAgICAgcmFuazogdGhpcy5hZGFwdGVyLmdldENvbmZpZygpLnJhbmssXG4gICAgICAgIH0sXG4gICAgICAgIHBpcGVsaW5lQ29uZmlnOiB7XG4gICAgICAgICAgbGVhcm5pbmdSYXRlOiB0aGlzLmNvbmZpZy5sZWFybmluZ1JhdGUsXG4gICAgICAgICAgYmF0Y2hTaXplOiB0aGlzLmNvbmZpZy5iYXRjaFNpemUsXG4gICAgICAgIH0sXG4gICAgICAgIC4uLmNoZWNrcG9pbnQsXG4gICAgICB9O1xuICAgICAgY29uc3Qgc2VyaWFsaXplZCA9IEpTT04uc3RyaW5naWZ5KGVudmVsb3BlKTtcbiAgICAgIG1rZGlyU3luYyhkaXJuYW1lKHBhdGgpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICAgIHdyaXRlRmlsZVN5bmMocGF0aCwgc2VyaWFsaXplZCwgJ3V0Zi04Jyk7XG4gICAgICByZXN1bHQucGF0aCA9IHBhdGg7XG4gICAgICByZXN1bHQuYnl0ZXMgPSBCdWZmZXIuYnl0ZUxlbmd0aChzZXJpYWxpemVkLCAndXRmLTgnKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqXG4gICAqIExvYWQgYSBjaGVja3BvaW50IOKAlCBieSBpbi1tZW1vcnkgaW5kZXgsIG9yIGZyb20gYSBmaWxlIHByZXZpb3VzbHlcbiAgICogd3JpdHRlbiBieSBgc2F2ZUNoZWNrcG9pbnQocGF0aClgLlxuICAgKlxuICAgKiBGb3IgdjIgZmlsZXMsIHRoZSBlbnZlbG9wZSdzIGFkYXB0ZXIgZ2VvbWV0cnkgaXMgY2hlY2tlZCBhZ2FpbnN0IHRoZVxuICAgKiBjdXJyZW50IGFkYXB0ZXIgZmlyc3Q7IGEgbWlzbWF0Y2ggKGRpZmZlcmVudCBpbnB1dERpbS9vdXRwdXREaW0vcmFuaylcbiAgICogcmV0dXJucyBmYWxzZSBhbmQgbGVhdmVzIHRoZSBhZGFwdGVyIHVudG91Y2hlZCwgc28gbWlzLXNoYXBlZCB3ZWlnaHRzXG4gICAqIGFyZSBuZXZlciBzaWxlbnRseSByZXN0b3JlZC4gdjEgZmlsZXMgY2Fycnkgbm8gZ2VvbWV0cnkgYW5kIGxvYWQgYXNcbiAgICogYmVmb3JlIChiYWNrLWNvbXBhdCkuXG4gICAqL1xuICBsb2FkQ2hlY2twb2ludChpbmRleE9yUGF0aDogbnVtYmVyIHwgc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgbGV0IGNoZWNrcG9pbnQ6IENoZWNrcG9pbnQgfCB1bmRlZmluZWQ7XG5cbiAgICBpZiAodHlwZW9mIGluZGV4T3JQYXRoID09PSAnbnVtYmVyJykge1xuICAgICAgY2hlY2twb2ludCA9IHRoaXMuY2hlY2twb2ludHNbaW5kZXhPclBhdGhdO1xuICAgIH0gZWxzZSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBwYXJzZWQgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhpbmRleE9yUGF0aCwgJ3V0Zi04JykpO1xuICAgICAgICBpZiAocGFyc2VkPy5mb3JtYXQgIT09ICdydXZsbG0tY2hlY2twb2ludCcgfHwgdHlwZW9mIHBhcnNlZC53ZWlnaHRzICE9PSAnc3RyaW5nJykge1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodHlwZW9mIHBhcnNlZC52ZXJzaW9uID09PSAnbnVtYmVyJyAmJiBwYXJzZWQudmVyc2lvbiA+PSAyICYmIHBhcnNlZC5jb25maWcpIHtcbiAgICAgICAgICBjb25zdCBjID0gcGFyc2VkLmNvbmZpZztcbiAgICAgICAgICBpZiAoXG4gICAgICAgICAgICBjLmlucHV0RGltICE9PSB0aGlzLmFkYXB0ZXIuZ2V0SW5wdXREaW0oKSB8fFxuICAgICAgICAgICAgYy5vdXRwdXREaW0gIT09IHRoaXMuYWRhcHRlci5nZXRPdXRwdXREaW0oKSB8fFxuICAgICAgICAgICAgYy5yYW5rICE9PSB0aGlzLmFkYXB0ZXIuZ2V0Q29uZmlnKCkucmFua1xuICAgICAgICAgICkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjaGVja3BvaW50ID0gcGFyc2VkIGFzIENoZWNrcG9pbnQ7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoIWNoZWNrcG9pbnQpIHJldHVybiBmYWxzZTtcblxuICAgIHRoaXMuYWRhcHRlciA9IExvcmFBZGFwdGVyLmZyb21KU09OKGNoZWNrcG9pbnQud2VpZ2h0cyk7XG4gICAgdGhpcy5jdXJyZW50RXBvY2ggPSBjaGVja3BvaW50LmVwb2NoO1xuICAgIHRoaXMuY3VycmVudFN0ZXAgPSBjaGVja3BvaW50LnN0ZXA7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogUmVzdW1lIHRyYWluaW5nIGZyb20gYSBjaGVja3BvaW50IGZpbGUuXG4gICAqXG4gICAqIExvYWRzIHRoZSBjaGVja3BvaW50ICh3aXRoIHRoZSBzYW1lIHYyIHNoYXBlIHZhbGlkYXRpb24gYXNcbiAgICoge0BsaW5rIGxvYWRDaGVja3BvaW50fSkgQU5EIHByaW1lcyB0aGUgcGlwZWxpbmUgc28gdGhlIG5leHQge0BsaW5rIHRyYWlufVxuICAgKiBjYWxsIGNvbnRpbnVlcyBmcm9tIHRoZSByZXN0b3JlZCBlcG9jaC9zdGVwIHJhdGhlciB0aGFuIHJlc3RhcnRpbmcuIFRoaXNcbiAgICogaXMgdGhlIGV4cGxpY2l0LCBsZWFzdC1pbnZhc2l2ZSByZXN1bWUgcGF0aDogYSBwbGFpbiBgbG9hZENoZWNrcG9pbnQoKWBcbiAgICogc3RpbGwgcmVzdG9yZXMgd2VpZ2h0cyBvbmx5ICh0cmFpbigpIGZyb20gc2NyYXRjaCksIHdoaWxlIGByZXN1bWVGcm9tKClgXG4gICAqIGFkZGl0aW9uYWxseSBtYWtlcyB0aGUgc3Vic2VxdWVudCB0cmFpbigpIHBpY2sgdXAgd2hlcmUgdGhlIHJ1biBzdG9wcGVkLlxuICAgKlxuICAgKiBAcmV0dXJucyB0cnVlIHdoZW4gdGhlIGNoZWNrcG9pbnQgbG9hZGVkIGFuZCByZXN1bWUgd2FzIHByaW1lZDsgZmFsc2UgaWZcbiAgICogICAgICAgICAgdGhlIGZpbGUgd2FzIG1pc3NpbmcsIGZvcmVpZ24sIG9yIHNoYXBlLW1pc21hdGNoZWQgKGluIHdoaWNoIGNhc2VcbiAgICogICAgICAgICAgbm8gcmVzdW1lIGlzIGFybWVkKS5cbiAgICovXG4gIHJlc3VtZUZyb20ocGF0aDogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgaWYgKCF0aGlzLmxvYWRDaGVja3BvaW50KHBhdGgpKSByZXR1cm4gZmFsc2U7XG4gICAgdGhpcy5yZXN1bWVQZW5kaW5nID0gdHJ1ZTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgY3VycmVudCBtZXRyaWNzXG4gICAqL1xuICBnZXRNZXRyaWNzKCk6IFRyYWluaW5nTWV0cmljcyB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGVwb2NoOiB0aGlzLmN1cnJlbnRFcG9jaCxcbiAgICAgIHN0ZXA6IHRoaXMuY3VycmVudFN0ZXAsXG4gICAgICB0cmFpbkxvc3M6IHRoaXMubWV0cmljcy5hdmdMb3NzKDEwMCksXG4gICAgICB2YWxMb3NzOiB0aGlzLm1ldHJpY3MuYXZnVmFsTG9zcygxMCksXG4gICAgICBsZWFybmluZ1JhdGU6IHRoaXMuc2NoZWR1bGVyPy5nZXRMUigpIHx8IHRoaXMuY29uZmlnLmxlYXJuaW5nUmF0ZSxcbiAgICAgIGdyYWROb3JtOiAwLFxuICAgICAgc3RlcHNQZXJTZWNvbmQ6IHRoaXMubWV0cmljcy5zdGVwc1BlclNlY29uZCgpLFxuICAgICAgZXRhU2Vjb25kczogdGhpcy5tZXRyaWNzLmV0YShcbiAgICAgICAgKHRoaXMuY29uZmlnLmVwb2NocyAtIHRoaXMuY3VycmVudEVwb2NoKSAqIHRoaXMuYmF0Y2hlcy5sZW5ndGhcbiAgICAgICksXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgYWRhcHRlclxuICAgKi9cbiAgZ2V0QWRhcHRlcigpOiBMb3JhQWRhcHRlciB7XG4gICAgcmV0dXJuIHRoaXMuYWRhcHRlcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgRVdDIG1hbmFnZXJcbiAgICovXG4gIGdldEV3Y01hbmFnZXIoKTogRXdjTWFuYWdlciB7XG4gICAgcmV0dXJuIHRoaXMuZXdjTWFuYWdlcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgY2hlY2twb2ludHNcbiAgICovXG4gIGdldENoZWNrcG9pbnRzKCk6IENoZWNrcG9pbnRbXSB7XG4gICAgcmV0dXJuIFsuLi50aGlzLmNoZWNrcG9pbnRzXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNldCBwaXBlbGluZVxuICAgKi9cbiAgcmVzZXQoKTogdm9pZCB7XG4gICAgdGhpcy5iYXRjaGVzID0gW107XG4gICAgdGhpcy5jaGVja3BvaW50cyA9IFtdO1xuICAgIHRoaXMuY3VycmVudEVwb2NoID0gMDtcbiAgICB0aGlzLmN1cnJlbnRTdGVwID0gMDtcbiAgICB0aGlzLmJlc3RWYWxMb3NzID0gSW5maW5pdHk7XG4gICAgdGhpcy5wYXRpZW5jZUNvdW50ZXIgPSAwO1xuICAgIHRoaXMucmVzdW1lUGVuZGluZyA9IGZhbHNlO1xuICAgIHRoaXMubWV0cmljcy5yZXNldCgpO1xuICAgIHRoaXMuYWRhcHRlci5yZXNldCgpO1xuICB9XG5cbiAgcHJpdmF0ZSBzaHVmZmxlQmF0Y2hlcygpOiBUcmFpbmluZ0JhdGNoW10ge1xuICAgIGNvbnN0IHNodWZmbGVkID0gWy4uLnRoaXMuYmF0Y2hlc107XG4gICAgZm9yIChsZXQgaSA9IHNodWZmbGVkLmxlbmd0aCAtIDE7IGkgPiAwOyBpLS0pIHtcbiAgICAgIGNvbnN0IGogPSBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAoaSArIDEpKTtcbiAgICAgIFtzaHVmZmxlZFtpXSwgc2h1ZmZsZWRbal1dID0gW3NodWZmbGVkW2pdLCBzaHVmZmxlZFtpXV07XG4gICAgfVxuICAgIHJldHVybiBzaHVmZmxlZDtcbiAgfVxufVxuXG4vKipcbiAqIFRyYWluaW5nIEZhY3RvcnlcbiAqXG4gKiBDcmVhdGUgcHJlLWNvbmZpZ3VyZWQgdHJhaW5pbmcgcGlwZWxpbmVzIGZvciBjb21tb24gc2NlbmFyaW9zLlxuICovXG5leHBvcnQgY2xhc3MgVHJhaW5pbmdGYWN0b3J5IHtcbiAgLyoqXG4gICAqIENyZWF0ZSBwaXBlbGluZSBmb3IgcXVpY2sgZmluZS10dW5pbmdcbiAgICovXG4gIHN0YXRpYyBxdWlja0ZpbmV0dW5lKCk6IFRyYWluaW5nUGlwZWxpbmUge1xuICAgIHJldHVybiBuZXcgVHJhaW5pbmdQaXBlbGluZSh7XG4gICAgICBsZWFybmluZ1JhdGU6IDAuMDEsXG4gICAgICBlcG9jaHM6IDMsXG4gICAgICBiYXRjaFNpemU6IDE2LFxuICAgICAgc2NoZWR1bGVyOiAnY29uc3RhbnQnLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBwaXBlbGluZSBmb3IgZGVlcCB0cmFpbmluZ1xuICAgKi9cbiAgc3RhdGljIGRlZXBUcmFpbmluZygpOiBUcmFpbmluZ1BpcGVsaW5lIHtcbiAgICByZXR1cm4gbmV3IFRyYWluaW5nUGlwZWxpbmUoe1xuICAgICAgbGVhcm5pbmdSYXRlOiAwLjAwMSxcbiAgICAgIGVwb2NoczogNTAsXG4gICAgICBiYXRjaFNpemU6IDMyLFxuICAgICAgc2NoZWR1bGVyOiAnd2FybXVwJyxcbiAgICAgIHdhcm11cFN0ZXBzOiA1MDAsXG4gICAgICBlYXJseVN0b3BwaW5nUGF0aWVuY2U6IDUsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIHBpcGVsaW5lIGZvciBjb250aW51YWwgbGVhcm5pbmdcbiAgICovXG4gIHN0YXRpYyBjb250aW51YWxMZWFybmluZyhld2NMYW1iZGE6IG51bWJlciA9IDUwMDApOiBUcmFpbmluZ1BpcGVsaW5lIHtcbiAgICByZXR1cm4gbmV3IFRyYWluaW5nUGlwZWxpbmUoe1xuICAgICAgbGVhcm5pbmdSYXRlOiAwLjAwMDUsXG4gICAgICBlcG9jaHM6IDEwLFxuICAgICAgYmF0Y2hTaXplOiAxNixcbiAgICAgIHNjaGVkdWxlcjogJ2Nvc2luZScsXG4gICAgICBld2NMYW1iZGEsXG4gICAgICBlYXJseVN0b3BwaW5nUGF0aWVuY2U6IDEwLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBwaXBlbGluZSBmb3IgZmVkZXJhdGVkIGFnZ3JlZ2F0aW9uXG4gICAqL1xuICBzdGF0aWMgZmVkZXJhdGVkQWdncmVnYXRpb24oKTogVHJhaW5pbmdQaXBlbGluZSB7XG4gICAgcmV0dXJuIG5ldyBUcmFpbmluZ1BpcGVsaW5lKHtcbiAgICAgIGxlYXJuaW5nUmF0ZTogMC4wMDAxLFxuICAgICAgZXBvY2hzOiA1LFxuICAgICAgYmF0Y2hTaXplOiA2NCxcbiAgICAgIHNjaGVkdWxlcjogJ2xpbmVhcicsXG4gICAgICBld2NMYW1iZGE6IDIwMDAsXG4gICAgfSk7XG4gIH1cbn1cbiJdfQ==