@ruvector/ruvllm 3.0.0 → 4.0.1

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 +159 -360
  5. package/examples/gpu-loop.example.json +26 -0
  6. package/package.json +50 -121
  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 -1040
  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 -160
  34. package/dist/cjs/engine.d.ts.map +0 -1
  35. package/dist/cjs/engine.js +0 -552
  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 -140
  55. package/dist/cjs/native.d.ts.map +0 -1
  56. package/dist/cjs/native.js +0 -98
  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 -696
  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 -160
  91. package/dist/esm/engine.d.ts.map +0 -1
  92. package/dist/esm/engine.js +0 -548
  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 -140
  112. package/dist/esm/native.d.ts.map +0 -1
  113. package/dist/esm/native.js +0 -93
  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 -696
  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,610 +0,0 @@
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==