@ruvector/ruvllm 4.0.1 → 4.1.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.
- package/README.md +447 -160
- package/bin/cli.js +1066 -0
- package/bin/gpu-delegate.js +67 -0
- package/bin/ruvllm-adapters.js +5 -0
- package/bin/ruvllm-gpu-loop.js +5 -0
- package/bin/serve.js +265 -0
- package/dist/cjs/benchmarks/embedding-benchmark.d.ts +102 -0
- package/dist/cjs/benchmarks/embedding-benchmark.d.ts.map +1 -0
- package/dist/cjs/benchmarks/embedding-benchmark.js +436 -0
- package/dist/cjs/benchmarks/index.d.ts +34 -0
- package/dist/cjs/benchmarks/index.d.ts.map +1 -0
- package/dist/cjs/benchmarks/index.js +132 -0
- package/dist/cjs/benchmarks/model-comparison.d.ts +71 -0
- package/dist/cjs/benchmarks/model-comparison.d.ts.map +1 -0
- package/dist/cjs/benchmarks/model-comparison.js +476 -0
- package/dist/cjs/benchmarks/routing-benchmark.d.ts +70 -0
- package/dist/cjs/benchmarks/routing-benchmark.d.ts.map +1 -0
- package/dist/cjs/benchmarks/routing-benchmark.js +289 -0
- package/dist/cjs/contrastive.d.ts +229 -0
- package/dist/cjs/contrastive.d.ts.map +1 -0
- package/dist/cjs/contrastive.js +589 -0
- package/dist/cjs/engine.d.ts +160 -0
- package/dist/cjs/engine.d.ts.map +1 -0
- package/dist/cjs/engine.js +552 -0
- package/dist/cjs/export.d.ts +182 -0
- package/dist/cjs/export.d.ts.map +1 -0
- package/dist/cjs/export.js +422 -0
- package/dist/cjs/federated.d.ts +233 -0
- package/dist/cjs/federated.d.ts.map +1 -0
- package/dist/cjs/federated.js +525 -0
- package/dist/cjs/index.d.ts +68 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +104 -0
- package/dist/cjs/intelligence.d.ts +136 -0
- package/dist/cjs/intelligence.d.ts.map +1 -0
- package/dist/cjs/intelligence.js +226 -0
- package/dist/cjs/lora.d.ts +251 -0
- package/dist/cjs/lora.d.ts.map +1 -0
- package/dist/cjs/lora.js +509 -0
- package/dist/cjs/models.d.ts +129 -0
- package/dist/cjs/models.d.ts.map +1 -0
- package/dist/cjs/models.js +323 -0
- package/dist/cjs/native.d.ts +140 -0
- package/dist/cjs/native.d.ts.map +1 -0
- package/dist/cjs/native.js +98 -0
- package/dist/cjs/session.d.ts +80 -0
- package/dist/cjs/session.d.ts.map +1 -0
- package/dist/cjs/session.js +203 -0
- package/dist/cjs/simd.d.ts +90 -0
- package/dist/cjs/simd.d.ts.map +1 -0
- package/dist/cjs/simd.js +209 -0
- package/dist/cjs/sona.d.ts +223 -0
- package/dist/cjs/sona.d.ts.map +1 -0
- package/dist/cjs/sona.js +562 -0
- package/dist/cjs/streaming.d.ts +55 -0
- package/dist/cjs/streaming.d.ts.map +1 -0
- package/dist/cjs/streaming.js +131 -0
- package/dist/cjs/training.d.ts +312 -0
- package/dist/cjs/training.d.ts.map +1 -0
- package/dist/cjs/training.js +610 -0
- package/dist/cjs/types.d.ts +696 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +6 -0
- package/dist/esm/benchmarks/embedding-benchmark.d.ts +102 -0
- package/dist/esm/benchmarks/embedding-benchmark.d.ts.map +1 -0
- package/dist/esm/benchmarks/embedding-benchmark.js +427 -0
- package/dist/esm/benchmarks/index.d.ts +34 -0
- package/dist/esm/benchmarks/index.d.ts.map +1 -0
- package/dist/esm/benchmarks/index.js +110 -0
- package/dist/esm/benchmarks/model-comparison.d.ts +71 -0
- package/dist/esm/benchmarks/model-comparison.d.ts.map +1 -0
- package/dist/esm/benchmarks/model-comparison.js +434 -0
- package/dist/esm/benchmarks/routing-benchmark.d.ts +70 -0
- package/dist/esm/benchmarks/routing-benchmark.d.ts.map +1 -0
- package/dist/esm/benchmarks/routing-benchmark.js +283 -0
- package/dist/esm/contrastive.d.ts +229 -0
- package/dist/esm/contrastive.d.ts.map +1 -0
- package/dist/esm/contrastive.js +578 -0
- package/dist/esm/engine.d.ts +160 -0
- package/dist/esm/engine.d.ts.map +1 -0
- package/dist/esm/engine.js +548 -0
- package/dist/esm/export.d.ts +182 -0
- package/dist/esm/export.d.ts.map +1 -0
- package/dist/esm/export.js +414 -0
- package/dist/esm/federated.d.ts +233 -0
- package/dist/esm/federated.d.ts.map +1 -0
- package/dist/esm/federated.js +520 -0
- package/dist/esm/index.d.ts +68 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +84 -0
- package/dist/esm/intelligence.d.ts +136 -0
- package/dist/esm/intelligence.d.ts.map +1 -0
- package/dist/esm/intelligence.js +188 -0
- package/dist/esm/lora.d.ts +251 -0
- package/dist/esm/lora.d.ts.map +1 -0
- package/dist/esm/lora.js +504 -0
- package/dist/esm/models.d.ts +129 -0
- package/dist/esm/models.d.ts.map +1 -0
- package/dist/esm/models.js +282 -0
- package/dist/esm/native.d.ts +140 -0
- package/dist/esm/native.d.ts.map +1 -0
- package/dist/esm/native.js +100 -0
- package/dist/esm/session.d.ts +80 -0
- package/dist/esm/session.d.ts.map +1 -0
- package/dist/esm/session.js +199 -0
- package/dist/esm/simd.d.ts +90 -0
- package/dist/esm/simd.d.ts.map +1 -0
- package/dist/esm/simd.js +205 -0
- package/dist/esm/sona.d.ts +223 -0
- package/dist/esm/sona.d.ts.map +1 -0
- package/dist/esm/sona.js +556 -0
- package/dist/esm/streaming.d.ts +55 -0
- package/dist/esm/streaming.d.ts.map +1 -0
- package/dist/esm/streaming.js +126 -0
- package/dist/esm/training.d.ts +312 -0
- package/dist/esm/training.d.ts.map +1 -0
- package/dist/esm/training.js +603 -0
- package/dist/esm/types.d.ts +696 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +5 -0
- package/gpu/_load.cjs +38 -0
- package/gpu/_load.mjs +33 -0
- package/gpu/adapters.cjs +3 -0
- package/gpu/adapters.mjs +5 -0
- package/gpu/engine.cjs +3 -0
- package/gpu/engine.mjs +5 -0
- package/gpu/fixture.cjs +3 -0
- package/gpu/fixture.mjs +5 -0
- package/gpu/gpu-host.cjs +3 -0
- package/gpu/gpu-host.mjs +5 -0
- package/gpu/gpu-loop.cjs +3 -0
- package/gpu/gpu-loop.mjs +5 -0
- package/gpu/gpu-spool-adapter.cjs +3 -0
- package/gpu/gpu-spool-adapter.mjs +5 -0
- package/gpu/vast-host-adapter.cjs +3 -0
- package/gpu/vast-host-adapter.mjs +5 -0
- package/package.json +159 -49
- package/scripts/ensemble-model-compare.js +287 -0
- package/scripts/fix-esm-extensions.mjs +220 -0
- package/scripts/huggingface/README.md +537 -0
- package/scripts/huggingface/publish.sh +112 -0
- package/scripts/hybrid-model-compare.js +373 -0
- package/scripts/improved-model-compare.js +288 -0
- package/scripts/optimized-model-compare.js +364 -0
- package/scripts/real-model-compare.js +280 -0
- package/scripts/smoke-esm.mjs +82 -0
- package/scripts/training/agentic-flow-capabilities.json +329 -0
- package/scripts/training/claude-code-synth.js +505 -0
- package/scripts/training/claude-flow-capabilities.json +1322 -0
- package/scripts/training/claude-hard-negatives.js +222 -0
- package/scripts/training/contrastive-finetune.js +517 -0
- package/scripts/training/ecosystem-triplets.jsonl +1467 -0
- package/scripts/training/generate-ecosystem-triplets.js +1324 -0
- package/scripts/training/routing-dataset.js +634 -0
- package/scripts/training/ruvector-capabilities.json +798 -0
- package/scripts/training/validate-ecosystem.js +381 -0
- package/scripts/training/validation-results.json +23 -0
- package/GPU-LOOP.md +0 -229
- package/LICENSE +0 -201
- package/NOTICE +0 -9
- package/examples/gpu-loop.example.json +0 -26
- package/src/adapters-cli.mjs +0 -23
- package/src/adapters.mjs +0 -91
- package/src/cli.mjs +0 -30
- package/src/engine.mjs +0 -238
- package/src/fixture.mjs +0 -38
- package/src/gpu-host.mjs +0 -47
- package/src/gpu-loop-cli.mjs +0 -67
- package/src/gpu-loop.mjs +0 -184
- package/src/gpu-spool-adapter.mjs +0 -80
- package/src/vast-host-adapter.mjs +0 -274
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Export/Serialization for SONA Models
|
|
3
|
+
*
|
|
4
|
+
* Support for SafeTensors, JSON, and other export formats.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { ModelExporter, SafeTensorsWriter } from '@ruvector/ruvllm';
|
|
9
|
+
*
|
|
10
|
+
* // Export model to SafeTensors format
|
|
11
|
+
* const exporter = new ModelExporter();
|
|
12
|
+
* const buffer = exporter.toSafeTensors({
|
|
13
|
+
* weights: loraAdapter.getWeights(),
|
|
14
|
+
* config: loraAdapter.getConfig(),
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // Save to file
|
|
18
|
+
* fs.writeFileSync('model.safetensors', buffer);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
import { LoRAConfig, LearnedPattern, EwcStats, Embedding, ModelMetadata } from './types.js';
|
|
22
|
+
import { LoraWeights } from './lora.js';
|
|
23
|
+
/**
|
|
24
|
+
* Exportable model data
|
|
25
|
+
*/
|
|
26
|
+
export interface ExportableModel {
|
|
27
|
+
/** Model metadata */
|
|
28
|
+
metadata: ModelMetadata;
|
|
29
|
+
/** LoRA weights (if applicable) */
|
|
30
|
+
loraWeights?: LoraWeights;
|
|
31
|
+
/** LoRA config */
|
|
32
|
+
loraConfig?: LoRAConfig;
|
|
33
|
+
/** Learned patterns */
|
|
34
|
+
patterns?: LearnedPattern[];
|
|
35
|
+
/** EWC statistics */
|
|
36
|
+
ewcStats?: EwcStats;
|
|
37
|
+
/** Raw tensors */
|
|
38
|
+
tensors?: Map<string, Float32Array>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* SafeTensors Writer
|
|
42
|
+
*
|
|
43
|
+
* Writes tensors in SafeTensors format for compatibility with
|
|
44
|
+
* HuggingFace ecosystem.
|
|
45
|
+
*/
|
|
46
|
+
export declare class SafeTensorsWriter {
|
|
47
|
+
private tensors;
|
|
48
|
+
private metadata;
|
|
49
|
+
/**
|
|
50
|
+
* Add a tensor
|
|
51
|
+
*/
|
|
52
|
+
addTensor(name: string, data: Float32Array, shape: number[]): this;
|
|
53
|
+
/**
|
|
54
|
+
* Add 2D tensor from number array
|
|
55
|
+
*/
|
|
56
|
+
add2D(name: string, data: number[][]): this;
|
|
57
|
+
/**
|
|
58
|
+
* Add 1D tensor from number array
|
|
59
|
+
*/
|
|
60
|
+
add1D(name: string, data: number[]): this;
|
|
61
|
+
/**
|
|
62
|
+
* Add metadata
|
|
63
|
+
*/
|
|
64
|
+
addMetadata(key: string, value: string): this;
|
|
65
|
+
/**
|
|
66
|
+
* Build SafeTensors buffer
|
|
67
|
+
*/
|
|
68
|
+
build(): Uint8Array;
|
|
69
|
+
/**
|
|
70
|
+
* Clear all tensors and metadata
|
|
71
|
+
*/
|
|
72
|
+
clear(): void;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* SafeTensors Reader
|
|
76
|
+
*
|
|
77
|
+
* Reads tensors from SafeTensors format.
|
|
78
|
+
*/
|
|
79
|
+
export declare class SafeTensorsReader {
|
|
80
|
+
private buffer;
|
|
81
|
+
private header;
|
|
82
|
+
private dataOffset;
|
|
83
|
+
constructor(buffer: Uint8Array);
|
|
84
|
+
/**
|
|
85
|
+
* Get tensor names
|
|
86
|
+
*/
|
|
87
|
+
getTensorNames(): string[];
|
|
88
|
+
/**
|
|
89
|
+
* Get tensor by name
|
|
90
|
+
*/
|
|
91
|
+
getTensor(name: string): {
|
|
92
|
+
data: Float32Array;
|
|
93
|
+
shape: number[];
|
|
94
|
+
} | null;
|
|
95
|
+
/**
|
|
96
|
+
* Get tensor as 2D array
|
|
97
|
+
*/
|
|
98
|
+
getTensor2D(name: string): number[][] | null;
|
|
99
|
+
/**
|
|
100
|
+
* Get tensor as 1D array
|
|
101
|
+
*/
|
|
102
|
+
getTensor1D(name: string): number[] | null;
|
|
103
|
+
/**
|
|
104
|
+
* Get metadata
|
|
105
|
+
*/
|
|
106
|
+
getMetadata(): Record<string, string>;
|
|
107
|
+
private parseHeader;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Model Exporter
|
|
111
|
+
*
|
|
112
|
+
* Unified export interface for SONA models.
|
|
113
|
+
*/
|
|
114
|
+
export declare class ModelExporter {
|
|
115
|
+
/**
|
|
116
|
+
* Export to SafeTensors format
|
|
117
|
+
*/
|
|
118
|
+
toSafeTensors(model: ExportableModel): Uint8Array;
|
|
119
|
+
/**
|
|
120
|
+
* Export to JSON format
|
|
121
|
+
*/
|
|
122
|
+
toJSON(model: ExportableModel): string;
|
|
123
|
+
/**
|
|
124
|
+
* Export to compact binary format
|
|
125
|
+
*/
|
|
126
|
+
toBinary(model: ExportableModel): Uint8Array;
|
|
127
|
+
/**
|
|
128
|
+
* Export for HuggingFace Hub compatibility
|
|
129
|
+
*/
|
|
130
|
+
toHuggingFace(model: ExportableModel): {
|
|
131
|
+
safetensors: Uint8Array;
|
|
132
|
+
config: string;
|
|
133
|
+
readme: string;
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Model Importer
|
|
138
|
+
*
|
|
139
|
+
* Import models from various formats.
|
|
140
|
+
*/
|
|
141
|
+
export declare class ModelImporter {
|
|
142
|
+
/**
|
|
143
|
+
* Import from SafeTensors format
|
|
144
|
+
*/
|
|
145
|
+
fromSafeTensors(buffer: Uint8Array): Partial<ExportableModel>;
|
|
146
|
+
/**
|
|
147
|
+
* Import from JSON format
|
|
148
|
+
*/
|
|
149
|
+
fromJSON(json: string): Partial<ExportableModel>;
|
|
150
|
+
/**
|
|
151
|
+
* Import from binary format
|
|
152
|
+
*/
|
|
153
|
+
fromBinary(buffer: Uint8Array): Partial<ExportableModel>;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Dataset Exporter
|
|
157
|
+
*
|
|
158
|
+
* Export training data in various formats.
|
|
159
|
+
*/
|
|
160
|
+
export declare class DatasetExporter {
|
|
161
|
+
/**
|
|
162
|
+
* Export to JSONL format (one JSON per line)
|
|
163
|
+
*/
|
|
164
|
+
toJSONL(data: Array<{
|
|
165
|
+
input: Embedding;
|
|
166
|
+
output: Embedding;
|
|
167
|
+
quality: number;
|
|
168
|
+
}>): string;
|
|
169
|
+
/**
|
|
170
|
+
* Export to CSV format
|
|
171
|
+
*/
|
|
172
|
+
toCSV(data: Array<{
|
|
173
|
+
input: Embedding;
|
|
174
|
+
output: Embedding;
|
|
175
|
+
quality: number;
|
|
176
|
+
}>): string;
|
|
177
|
+
/**
|
|
178
|
+
* Export patterns for pre-training
|
|
179
|
+
*/
|
|
180
|
+
toPretrain(patterns: LearnedPattern[]): string;
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Export/Serialization for SONA Models
|
|
3
|
+
*
|
|
4
|
+
* Support for SafeTensors, JSON, and other export formats.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { ModelExporter, SafeTensorsWriter } from '@ruvector/ruvllm';
|
|
9
|
+
*
|
|
10
|
+
* // Export model to SafeTensors format
|
|
11
|
+
* const exporter = new ModelExporter();
|
|
12
|
+
* const buffer = exporter.toSafeTensors({
|
|
13
|
+
* weights: loraAdapter.getWeights(),
|
|
14
|
+
* config: loraAdapter.getConfig(),
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // Save to file
|
|
18
|
+
* fs.writeFileSync('model.safetensors', buffer);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* SafeTensors Writer
|
|
23
|
+
*
|
|
24
|
+
* Writes tensors in SafeTensors format for compatibility with
|
|
25
|
+
* HuggingFace ecosystem.
|
|
26
|
+
*/
|
|
27
|
+
export class SafeTensorsWriter {
|
|
28
|
+
constructor() {
|
|
29
|
+
this.tensors = new Map();
|
|
30
|
+
this.metadata = {};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Add a tensor
|
|
34
|
+
*/
|
|
35
|
+
addTensor(name, data, shape) {
|
|
36
|
+
this.tensors.set(name, { data, shape });
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Add 2D tensor from number array
|
|
41
|
+
*/
|
|
42
|
+
add2D(name, data) {
|
|
43
|
+
const rows = data.length;
|
|
44
|
+
const cols = data[0]?.length || 0;
|
|
45
|
+
const flat = new Float32Array(rows * cols);
|
|
46
|
+
for (let i = 0; i < rows; i++) {
|
|
47
|
+
for (let j = 0; j < cols; j++) {
|
|
48
|
+
flat[i * cols + j] = data[i][j];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return this.addTensor(name, flat, [rows, cols]);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Add 1D tensor from number array
|
|
55
|
+
*/
|
|
56
|
+
add1D(name, data) {
|
|
57
|
+
return this.addTensor(name, new Float32Array(data), [data.length]);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Add metadata
|
|
61
|
+
*/
|
|
62
|
+
addMetadata(key, value) {
|
|
63
|
+
this.metadata[key] = value;
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Build SafeTensors buffer
|
|
68
|
+
*/
|
|
69
|
+
build() {
|
|
70
|
+
// Build header
|
|
71
|
+
const header = {};
|
|
72
|
+
let offset = 0;
|
|
73
|
+
const tensorData = [];
|
|
74
|
+
for (const [name, { data, shape }] of this.tensors) {
|
|
75
|
+
const bytes = new Uint8Array(data.buffer);
|
|
76
|
+
const dataLength = bytes.length;
|
|
77
|
+
header[name] = {
|
|
78
|
+
dtype: 'F32',
|
|
79
|
+
shape,
|
|
80
|
+
data_offsets: [offset, offset + dataLength],
|
|
81
|
+
};
|
|
82
|
+
tensorData.push(bytes);
|
|
83
|
+
offset += dataLength;
|
|
84
|
+
}
|
|
85
|
+
// Add metadata
|
|
86
|
+
if (Object.keys(this.metadata).length > 0) {
|
|
87
|
+
header['__metadata__'] = this.metadata;
|
|
88
|
+
}
|
|
89
|
+
// Encode header
|
|
90
|
+
const headerJson = JSON.stringify(header);
|
|
91
|
+
const headerBytes = new TextEncoder().encode(headerJson);
|
|
92
|
+
// Pad header to 8-byte alignment
|
|
93
|
+
const headerPadding = (8 - (headerBytes.length % 8)) % 8;
|
|
94
|
+
const paddedHeaderLength = headerBytes.length + headerPadding;
|
|
95
|
+
// Build final buffer
|
|
96
|
+
const totalLength = 8 + paddedHeaderLength + offset;
|
|
97
|
+
const buffer = new Uint8Array(totalLength);
|
|
98
|
+
const view = new DataView(buffer.buffer);
|
|
99
|
+
// Write header length (8 bytes, little-endian)
|
|
100
|
+
view.setBigUint64(0, BigInt(paddedHeaderLength), true);
|
|
101
|
+
// Write header
|
|
102
|
+
buffer.set(headerBytes, 8);
|
|
103
|
+
// Write tensor data
|
|
104
|
+
let dataOffset = 8 + paddedHeaderLength;
|
|
105
|
+
for (const data of tensorData) {
|
|
106
|
+
buffer.set(data, dataOffset);
|
|
107
|
+
dataOffset += data.length;
|
|
108
|
+
}
|
|
109
|
+
return buffer;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Clear all tensors and metadata
|
|
113
|
+
*/
|
|
114
|
+
clear() {
|
|
115
|
+
this.tensors.clear();
|
|
116
|
+
this.metadata = {};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* SafeTensors Reader
|
|
121
|
+
*
|
|
122
|
+
* Reads tensors from SafeTensors format.
|
|
123
|
+
*/
|
|
124
|
+
export class SafeTensorsReader {
|
|
125
|
+
constructor(buffer) {
|
|
126
|
+
this.header = {};
|
|
127
|
+
this.dataOffset = 0;
|
|
128
|
+
this.buffer = buffer;
|
|
129
|
+
this.parseHeader();
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Get tensor names
|
|
133
|
+
*/
|
|
134
|
+
getTensorNames() {
|
|
135
|
+
return Object.keys(this.header).filter(k => k !== '__metadata__');
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get tensor by name
|
|
139
|
+
*/
|
|
140
|
+
getTensor(name) {
|
|
141
|
+
const entry = this.header[name];
|
|
142
|
+
if (!entry || typeof entry === 'object' && 'dtype' in entry === false) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
const tensorHeader = entry;
|
|
146
|
+
const [start, end] = tensorHeader.data_offsets;
|
|
147
|
+
const bytes = this.buffer.slice(this.dataOffset + start, this.dataOffset + end);
|
|
148
|
+
return {
|
|
149
|
+
data: new Float32Array(bytes.buffer, bytes.byteOffset, bytes.length / 4),
|
|
150
|
+
shape: tensorHeader.shape,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Get tensor as 2D array
|
|
155
|
+
*/
|
|
156
|
+
getTensor2D(name) {
|
|
157
|
+
const tensor = this.getTensor(name);
|
|
158
|
+
if (!tensor || tensor.shape.length !== 2)
|
|
159
|
+
return null;
|
|
160
|
+
const [rows, cols] = tensor.shape;
|
|
161
|
+
const result = [];
|
|
162
|
+
for (let i = 0; i < rows; i++) {
|
|
163
|
+
const row = [];
|
|
164
|
+
for (let j = 0; j < cols; j++) {
|
|
165
|
+
row.push(tensor.data[i * cols + j]);
|
|
166
|
+
}
|
|
167
|
+
result.push(row);
|
|
168
|
+
}
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get tensor as 1D array
|
|
173
|
+
*/
|
|
174
|
+
getTensor1D(name) {
|
|
175
|
+
const tensor = this.getTensor(name);
|
|
176
|
+
if (!tensor)
|
|
177
|
+
return null;
|
|
178
|
+
return Array.from(tensor.data);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Get metadata
|
|
182
|
+
*/
|
|
183
|
+
getMetadata() {
|
|
184
|
+
const meta = this.header['__metadata__'];
|
|
185
|
+
if (!meta || typeof meta !== 'object')
|
|
186
|
+
return {};
|
|
187
|
+
return meta;
|
|
188
|
+
}
|
|
189
|
+
parseHeader() {
|
|
190
|
+
const view = new DataView(this.buffer.buffer, this.buffer.byteOffset);
|
|
191
|
+
const headerLength = Number(view.getBigUint64(0, true));
|
|
192
|
+
const headerBytes = this.buffer.slice(8, 8 + headerLength);
|
|
193
|
+
const headerJson = new TextDecoder().decode(headerBytes);
|
|
194
|
+
this.header = JSON.parse(headerJson.replace(/\0+$/, '')); // Remove padding nulls
|
|
195
|
+
this.dataOffset = 8 + headerLength;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Model Exporter
|
|
200
|
+
*
|
|
201
|
+
* Unified export interface for SONA models.
|
|
202
|
+
*/
|
|
203
|
+
export class ModelExporter {
|
|
204
|
+
/**
|
|
205
|
+
* Export to SafeTensors format
|
|
206
|
+
*/
|
|
207
|
+
toSafeTensors(model) {
|
|
208
|
+
const writer = new SafeTensorsWriter();
|
|
209
|
+
// Add metadata
|
|
210
|
+
writer.addMetadata('name', model.metadata.name);
|
|
211
|
+
writer.addMetadata('version', model.metadata.version);
|
|
212
|
+
writer.addMetadata('architecture', model.metadata.architecture);
|
|
213
|
+
if (model.metadata.training) {
|
|
214
|
+
writer.addMetadata('training_steps', String(model.metadata.training.steps));
|
|
215
|
+
writer.addMetadata('training_loss', String(model.metadata.training.loss));
|
|
216
|
+
}
|
|
217
|
+
// Add LoRA weights
|
|
218
|
+
if (model.loraWeights) {
|
|
219
|
+
writer.add2D('lora.A', model.loraWeights.loraA);
|
|
220
|
+
writer.add2D('lora.B', model.loraWeights.loraB);
|
|
221
|
+
writer.add1D('lora.scaling', [model.loraWeights.scaling]);
|
|
222
|
+
}
|
|
223
|
+
// Add patterns as embeddings
|
|
224
|
+
if (model.patterns && model.patterns.length > 0) {
|
|
225
|
+
const embeddings = model.patterns.map(p => p.embedding);
|
|
226
|
+
writer.add2D('patterns.embeddings', embeddings);
|
|
227
|
+
const successRates = model.patterns.map(p => p.successRate);
|
|
228
|
+
writer.add1D('patterns.success_rates', successRates);
|
|
229
|
+
}
|
|
230
|
+
// Add raw tensors
|
|
231
|
+
if (model.tensors) {
|
|
232
|
+
for (const [name, data] of model.tensors) {
|
|
233
|
+
writer.addTensor(name, data, [data.length]);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return writer.build();
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Export to JSON format
|
|
240
|
+
*/
|
|
241
|
+
toJSON(model) {
|
|
242
|
+
return JSON.stringify({
|
|
243
|
+
metadata: model.metadata,
|
|
244
|
+
loraConfig: model.loraConfig,
|
|
245
|
+
loraWeights: model.loraWeights,
|
|
246
|
+
patterns: model.patterns,
|
|
247
|
+
ewcStats: model.ewcStats,
|
|
248
|
+
}, null, 2);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Export to compact binary format
|
|
252
|
+
*/
|
|
253
|
+
toBinary(model) {
|
|
254
|
+
const json = this.toJSON(model);
|
|
255
|
+
const jsonBytes = new TextEncoder().encode(json);
|
|
256
|
+
// Simple format: [4-byte length][json bytes]
|
|
257
|
+
const buffer = new Uint8Array(4 + jsonBytes.length);
|
|
258
|
+
const view = new DataView(buffer.buffer);
|
|
259
|
+
view.setUint32(0, jsonBytes.length, true);
|
|
260
|
+
buffer.set(jsonBytes, 4);
|
|
261
|
+
return buffer;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Export for HuggingFace Hub compatibility
|
|
265
|
+
*/
|
|
266
|
+
toHuggingFace(model) {
|
|
267
|
+
const safetensors = this.toSafeTensors(model);
|
|
268
|
+
const config = JSON.stringify({
|
|
269
|
+
model_type: 'sona-lora',
|
|
270
|
+
...model.metadata,
|
|
271
|
+
lora_config: model.loraConfig,
|
|
272
|
+
}, null, 2);
|
|
273
|
+
const readme = `---
|
|
274
|
+
license: mit
|
|
275
|
+
tags:
|
|
276
|
+
- sona
|
|
277
|
+
- lora
|
|
278
|
+
- ruvector
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
# ${model.metadata.name}
|
|
282
|
+
|
|
283
|
+
${model.metadata.architecture} model trained with SONA adaptive learning.
|
|
284
|
+
|
|
285
|
+
## Usage
|
|
286
|
+
|
|
287
|
+
\`\`\`typescript
|
|
288
|
+
import { LoraAdapter, SafeTensorsReader } from '@ruvector/ruvllm';
|
|
289
|
+
|
|
290
|
+
const reader = new SafeTensorsReader(buffer);
|
|
291
|
+
const adapter = new LoraAdapter();
|
|
292
|
+
adapter.setWeights({
|
|
293
|
+
loraA: reader.getTensor2D('lora.A'),
|
|
294
|
+
loraB: reader.getTensor2D('lora.B'),
|
|
295
|
+
scaling: reader.getTensor1D('lora.scaling')[0],
|
|
296
|
+
});
|
|
297
|
+
\`\`\`
|
|
298
|
+
|
|
299
|
+
## Training Info
|
|
300
|
+
|
|
301
|
+
- Steps: ${model.metadata.training?.steps || 'N/A'}
|
|
302
|
+
- Final Loss: ${model.metadata.training?.loss || 'N/A'}
|
|
303
|
+
`;
|
|
304
|
+
return { safetensors, config, readme };
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Model Importer
|
|
309
|
+
*
|
|
310
|
+
* Import models from various formats.
|
|
311
|
+
*/
|
|
312
|
+
export class ModelImporter {
|
|
313
|
+
/**
|
|
314
|
+
* Import from SafeTensors format
|
|
315
|
+
*/
|
|
316
|
+
fromSafeTensors(buffer) {
|
|
317
|
+
const reader = new SafeTensorsReader(buffer);
|
|
318
|
+
const metadata = reader.getMetadata();
|
|
319
|
+
const result = {
|
|
320
|
+
metadata: {
|
|
321
|
+
name: metadata.name || 'unknown',
|
|
322
|
+
version: metadata.version || '1.0.0',
|
|
323
|
+
architecture: metadata.architecture || 'sona-lora',
|
|
324
|
+
training: metadata.training_steps ? {
|
|
325
|
+
steps: parseInt(metadata.training_steps),
|
|
326
|
+
loss: parseFloat(metadata.training_loss || '0'),
|
|
327
|
+
learningRate: 0,
|
|
328
|
+
} : undefined,
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
// Load LoRA weights
|
|
332
|
+
const loraA = reader.getTensor2D('lora.A');
|
|
333
|
+
const loraB = reader.getTensor2D('lora.B');
|
|
334
|
+
const loraScaling = reader.getTensor1D('lora.scaling');
|
|
335
|
+
if (loraA && loraB && loraScaling) {
|
|
336
|
+
result.loraWeights = {
|
|
337
|
+
loraA,
|
|
338
|
+
loraB,
|
|
339
|
+
scaling: loraScaling[0],
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
// Load patterns
|
|
343
|
+
const patternEmbeddings = reader.getTensor2D('patterns.embeddings');
|
|
344
|
+
const patternRates = reader.getTensor1D('patterns.success_rates');
|
|
345
|
+
if (patternEmbeddings && patternRates) {
|
|
346
|
+
result.patterns = patternEmbeddings.map((embedding, i) => ({
|
|
347
|
+
id: `imported-${i}`,
|
|
348
|
+
type: 'query_response',
|
|
349
|
+
embedding,
|
|
350
|
+
successRate: patternRates[i] || 0,
|
|
351
|
+
useCount: 0,
|
|
352
|
+
lastUsed: new Date(),
|
|
353
|
+
}));
|
|
354
|
+
}
|
|
355
|
+
return result;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Import from JSON format
|
|
359
|
+
*/
|
|
360
|
+
fromJSON(json) {
|
|
361
|
+
return JSON.parse(json);
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Import from binary format
|
|
365
|
+
*/
|
|
366
|
+
fromBinary(buffer) {
|
|
367
|
+
const view = new DataView(buffer.buffer, buffer.byteOffset);
|
|
368
|
+
const length = view.getUint32(0, true);
|
|
369
|
+
const jsonBytes = buffer.slice(4, 4 + length);
|
|
370
|
+
const json = new TextDecoder().decode(jsonBytes);
|
|
371
|
+
return this.fromJSON(json);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Dataset Exporter
|
|
376
|
+
*
|
|
377
|
+
* Export training data in various formats.
|
|
378
|
+
*/
|
|
379
|
+
export class DatasetExporter {
|
|
380
|
+
/**
|
|
381
|
+
* Export to JSONL format (one JSON per line)
|
|
382
|
+
*/
|
|
383
|
+
toJSONL(data) {
|
|
384
|
+
return data
|
|
385
|
+
.map(item => JSON.stringify({
|
|
386
|
+
input: item.input,
|
|
387
|
+
output: item.output,
|
|
388
|
+
quality: item.quality,
|
|
389
|
+
}))
|
|
390
|
+
.join('\n');
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Export to CSV format
|
|
394
|
+
*/
|
|
395
|
+
toCSV(data) {
|
|
396
|
+
const header = 'quality,input,output';
|
|
397
|
+
const rows = data.map(item => `${item.quality},"${item.input.join(',')}","${item.output.join(',')}"`);
|
|
398
|
+
return [header, ...rows].join('\n');
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Export patterns for pre-training
|
|
402
|
+
*/
|
|
403
|
+
toPretrain(patterns) {
|
|
404
|
+
return patterns
|
|
405
|
+
.filter(p => p.successRate >= 0.7)
|
|
406
|
+
.map(p => JSON.stringify({
|
|
407
|
+
embedding: p.embedding,
|
|
408
|
+
type: p.type,
|
|
409
|
+
quality: p.successRate,
|
|
410
|
+
}))
|
|
411
|
+
.join('\n');
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhwb3J0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2V4cG9ydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQWdDSDs7Ozs7R0FLRztBQUNILE1BQU0sT0FBTyxpQkFBaUI7SUFBOUI7UUFDVSxZQUFPLEdBQXlELElBQUksR0FBRyxFQUFFLENBQUM7UUFDMUUsYUFBUSxHQUEyQixFQUFFLENBQUM7SUEyR2hELENBQUM7SUF6R0M7O09BRUc7SUFDSCxTQUFTLENBQUMsSUFBWSxFQUFFLElBQWtCLEVBQUUsS0FBZTtRQUN6RCxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUN4QyxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxJQUFZLEVBQUUsSUFBZ0I7UUFDbEMsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUN6QixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxJQUFJLENBQUMsQ0FBQztRQUNsQyxNQUFNLElBQUksR0FBRyxJQUFJLFlBQVksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLENBQUM7UUFFM0MsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQzlCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztnQkFDOUIsSUFBSSxDQUFDLENBQUMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ2xDLENBQUM7UUFDSCxDQUFDO1FBRUQsT0FB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dkIsQ0FBQyxDQUFDO2FBQ0YsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2hCLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRXhwb3J0L1NlcmlhbGl6YXRpb24gZm9yIFNPTkEgTW9kZWxzXG4gKlxuICogU3VwcG9ydCBmb3IgU2FmZVRlbnNvcnMsIEpTT04sIGFuZCBvdGhlciBleHBvcnQgZm9ybWF0cy5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgTW9kZWxFeHBvcnRlciwgU2FmZVRlbnNvcnNXcml0ZXIgfSBmcm9tICdAcnV2ZWN0b3IvcnV2bGxtJztcbiAqXG4gKiAvLyBFeHBvcnQgbW9kZWwgdG8gU2FmZVRlbnNvcnMgZm9ybWF0XG4gKiBjb25zdCBleHBvcnRlciA9IG5ldyBNb2RlbEV4cG9ydGVyKCk7XG4gKiBjb25zdCBidWZmZXIgPSBleHBvcnRlci50b1NhZmVUZW5zb3JzKHtcbiAqICAgd2VpZ2h0czogbG9yYUFkYXB0ZXIuZ2V0V2VpZ2h0cygpLFxuICogICBjb25maWc6IGxvcmFBZGFwdGVyLmdldENvbmZpZygpLFxuICogfSk7XG4gKlxuICogLy8gU2F2ZSB0byBmaWxlXG4gKiBmcy53cml0ZUZpbGVTeW5jKCdtb2RlbC5zYWZldGVuc29ycycsIGJ1ZmZlcik7XG4gKiBgYGBcbiAqL1xuXG5pbXBvcnQgeyBMb1JBQ29uZmlnLCBMZWFybmVkUGF0dGVybiwgRXdjU3RhdHMsIEVtYmVkZGluZywgTW9kZWxNZXRhZGF0YSB9IGZyb20gJy4vdHlwZXMnO1xuaW1wb3J0IHsgTG9yYVdlaWdodHMgfSBmcm9tICcuL2xvcmEnO1xuXG4vKipcbiAqIEV4cG9ydGFibGUgbW9kZWwgZGF0YVxuICovXG5leHBvcnQgaW50ZXJmYWNlIEV4cG9ydGFibGVNb2RlbCB7XG4gIC8qKiBNb2RlbCBtZXRhZGF0YSAqL1xuICBtZXRhZGF0YTogTW9kZWxNZXRhZGF0YTtcbiAgLyoqIExvUkEgd2VpZ2h0cyAoaWYgYXBwbGljYWJsZSkgKi9cbiAgbG9yYVdlaWdodHM/OiBMb3JhV2VpZ2h0cztcbiAgLyoqIExvUkEgY29uZmlnICovXG4gIGxvcmFDb25maWc/OiBMb1JBQ29uZmlnO1xuICAvKiogTGVhcm5lZCBwYXR0ZXJucyAqL1xuICBwYXR0ZXJucz86IExlYXJuZWRQYXR0ZXJuW107XG4gIC8qKiBFV0Mgc3RhdGlzdGljcyAqL1xuICBld2NTdGF0cz86IEV3Y1N0YXRzO1xuICAvKiogUmF3IHRlbnNvcnMgKi9cbiAgdGVuc29ycz86IE1hcDxzdHJpbmcsIEZsb2F0MzJBcnJheT47XG59XG5cbi8qKlxuICogU2FmZVRlbnNvcnMgaGVhZGVyIGVudHJ5XG4gKi9cbmludGVyZmFjZSBTYWZlVGVuc29yc0hlYWRlciB7XG4gIGR0eXBlOiBzdHJpbmc7XG4gIHNoYXBlOiBudW1iZXJbXTtcbiAgZGF0YV9vZmZzZXRzOiBbbnVtYmVyLCBudW1iZXJdO1xufVxuXG4vKipcbiAqIFNhZmVUZW5zb3JzIFdyaXRlclxuICpcbiAqIFdyaXRlcyB0ZW5zb3JzIGluIFNhZmVUZW5zb3JzIGZvcm1hdCBmb3IgY29tcGF0aWJpbGl0eSB3aXRoXG4gKiBIdWdnaW5nRmFjZSBlY29zeXN0ZW0uXG4gKi9cbmV4cG9ydCBjbGFzcyBTYWZlVGVuc29yc1dyaXRlciB7XG4gIHByaXZhdGUgdGVuc29yczogTWFwPHN0cmluZywgeyBkYXRhOiBGbG9hdDMyQXJyYXk7IHNoYXBlOiBudW1iZXJbXSB9PiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBtZXRhZGF0YTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuXG4gIC8qKlxuICAgKiBBZGQgYSB0ZW5zb3JcbiAgICovXG4gIGFkZFRlbnNvcihuYW1lOiBzdHJpbmcsIGRhdGE6IEZsb2F0MzJBcnJheSwgc2hhcGU6IG51bWJlcltdKTogdGhpcyB7XG4gICAgdGhpcy50ZW5zb3JzLnNldChuYW1lLCB7IGRhdGEsIHNoYXBlIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCAyRCB0ZW5zb3IgZnJvbSBudW1iZXIgYXJyYXlcbiAgICovXG4gIGFkZDJEKG5hbWU6IHN0cmluZywgZGF0YTogbnVtYmVyW11bXSk6IHRoaXMge1xuICAgIGNvbnN0IHJvd3MgPSBkYXRhLmxlbmd0aDtcbiAgICBjb25zdCBjb2xzID0gZGF0YVswXT8ubGVuZ3RoIHx8IDA7XG4gICAgY29uc3QgZmxhdCA9IG5ldyBGbG9hdDMyQXJyYXkocm93cyAqIGNvbHMpO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCByb3dzOyBpKyspIHtcbiAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgY29sczsgaisrKSB7XG4gICAgICAgIGZsYXRbaSAqIGNvbHMgKyBqXSA9IGRhdGFbaV1bal07XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuYWRkVGVuc29yKG5hbWUsIGZsYXQsIFtyb3dzLCBjb2xzXSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIDFEIHRlbnNvciBmcm9tIG51bWJlciBhcnJheVxuICAgKi9cbiAgYWRkMUQobmFtZTogc3RyaW5nLCBkYXRhOiBudW1iZXJbXSk6IHRoaXMge1xuICAgIHJldHVybiB0aGlzLmFkZFRlbnNvcihuYW1lLCBuZXcgRmxvYXQzMkFycmF5KGRhdGEpLCBbZGF0YS5sZW5ndGhdKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgbWV0YWRhdGFcbiAgICovXG4gIGFkZE1ldGFkYXRhKGtleTogc3RyaW5nLCB2YWx1ZTogc3RyaW5nKTogdGhpcyB7XG4gICAgdGhpcy5tZXRhZGF0YVtrZXldID0gdmFsdWU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQnVpbGQgU2FmZVRlbnNvcnMgYnVmZmVyXG4gICAqL1xuICBidWlsZCgpOiBVaW50OEFycmF5IHtcbiAgICAvLyBCdWlsZCBoZWFkZXJcbiAgICBjb25zdCBoZWFkZXI6IFJlY29yZDxzdHJpbmcsIFNhZmVUZW5zb3JzSGVhZGVyIHwgUmVjb3JkPHN0cmluZywgc3RyaW5nPj4gPSB7fTtcbiAgICBsZXQgb2Zmc2V0ID0gMDtcblxuICAgIGNvbnN0IHRlbnNvckRhdGE6IFVpbnQ4QXJyYXlbXSA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBbbmFtZSwgeyBkYXRhLCBzaGFwZSB9XSBvZiB0aGlzLnRlbnNvcnMpIHtcbiAgICAgIGNvbnN0IGJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkoZGF0YS5idWZmZXIpO1xuICAgICAgY29uc3QgZGF0YUxlbmd0aCA9IGJ5dGVzLmxlbmd0aDtcblxuICAgICAgaGVhZGVyW25hbWVdID0ge1xuICAgICAgICBkdHlwZTogJ0YzMicsXG4gICAgICAgIHNoYXBlLFxuICAgICAgICBkYXRhX29mZnNldHM6IFtvZmZzZXQsIG9mZnNldCArIGRhdGFMZW5ndGhdLFxuICAgICAgfTtcblxuICAgICAgdGVuc29yRGF0YS5wdXNoKGJ5dGVzKTtcbiAgICAgIG9mZnNldCArPSBkYXRhTGVuZ3RoO1xuICAgIH1cblxuICAgIC8vIEFkZCBtZXRhZGF0YVxuICAgIGlmIChPYmplY3Qua2V5cyh0aGlzLm1ldGFkYXRhKS5sZW5ndGggPiAwKSB7XG4gICAgICBoZWFkZXJbJ19fbWV0YWRhdGFfXyddID0gdGhpcy5tZXRhZGF0YTtcbiAgICB9XG5cbiAgICAvLyBFbmNvZGUgaGVhZGVyXG4gICAgY29uc3QgaGVhZGVySnNvbiA9IEpTT04uc3RyaW5naWZ5KGhlYWRlcik7XG4gICAgY29uc3QgaGVhZGVyQnl0ZXMgPSBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoaGVhZGVySnNvbik7XG5cbiAgICAvLyBQYWQgaGVhZGVyIHRvIDgtYnl0ZSBhbGlnbm1lbnRcbiAgICBjb25zdCBoZWFkZXJQYWRkaW5nID0gKDggLSAoaGVhZGVyQnl0ZXMubGVuZ3RoICUgOCkpICUgODtcbiAgICBjb25zdCBwYWRkZWRIZWFkZXJMZW5ndGggPSBoZWFkZXJCeXRlcy5sZW5ndGggKyBoZWFkZXJQYWRkaW5nO1xuXG4gICAgLy8gQnVpbGQgZmluYWwgYnVmZmVyXG4gICAgY29uc3QgdG90YWxMZW5ndGggPSA4ICsgcGFkZGVkSGVhZGVyTGVuZ3RoICsgb2Zmc2V0O1xuICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBVaW50OEFycmF5KHRvdGFsTGVuZ3RoKTtcbiAgICBjb25zdCB2aWV3ID0gbmV3IERhdGFWaWV3KGJ1ZmZlci5idWZmZXIpO1xuXG4gICAgLy8gV3JpdGUgaGVhZGVyIGxlbmd0aCAoOCBieXRlcywgbGl0dGxlLWVuZGlhbilcbiAgICB2aWV3LnNldEJpZ1VpbnQ2NCgwLCBCaWdJbnQocGFkZGVkSGVhZGVyTGVuZ3RoKSwgdHJ1ZSk7XG5cbiAgICAvLyBXcml0ZSBoZWFkZXJcbiAgICBidWZmZXIuc2V0KGhlYWRlckJ5dGVzLCA4KTtcblxuICAgIC8vIFdyaXRlIHRlbnNvciBkYXRhXG4gICAgbGV0IGRhdGFPZmZzZXQgPSA4ICsgcGFkZGVkSGVhZGVyTGVuZ3RoO1xuICAgIGZvciAoY29uc3QgZGF0YSBvZiB0ZW5zb3JEYXRhKSB7XG4gICAgICBidWZmZXIuc2V0KGRhdGEsIGRhdGFPZmZzZXQpO1xuICAgICAgZGF0YU9mZnNldCArPSBkYXRhLmxlbmd0aDtcbiAgICB9XG5cbiAgICByZXR1cm4gYnVmZmVyO1xuICB9XG5cbiAgLyoqXG4gICAqIENsZWFyIGFsbCB0ZW5zb3JzIGFuZCBtZXRhZGF0YVxuICAgKi9cbiAgY2xlYXIoKTogdm9pZCB7XG4gICAgdGhpcy50ZW5zb3JzLmNsZWFyKCk7XG4gICAgdGhpcy5tZXRhZGF0YSA9IHt9O1xuICB9XG59XG5cbi8qKlxuICogU2FmZVRlbnNvcnMgUmVhZGVyXG4gKlxuICogUmVhZHMgdGVuc29ycyBmcm9tIFNhZmVUZW5zb3JzIGZvcm1hdC5cbiAqL1xuZXhwb3J0IGNsYXNzIFNhZmVUZW5zb3JzUmVhZGVyIHtcbiAgcHJpdmF0ZSBidWZmZXI6IFVpbnQ4QXJyYXk7XG4gIHByaXZhdGUgaGVhZGVyOiBSZWNvcmQ8c3RyaW5nLCBTYWZlVGVuc29yc0hlYWRlciB8IFJlY29yZDxzdHJpbmcsIHN0cmluZz4+ID0ge307XG4gIHByaXZhdGUgZGF0YU9mZnNldDogbnVtYmVyID0gMDtcblxuICBjb25zdHJ1Y3RvcihidWZmZXI6IFVpbnQ4QXJyYXkpIHtcbiAgICB0aGlzLmJ1ZmZlciA9IGJ1ZmZlcjtcbiAgICB0aGlzLnBhcnNlSGVhZGVyKCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRlbnNvciBuYW1lc1xuICAgKi9cbiAgZ2V0VGVuc29yTmFtZXMoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiBPYmplY3Qua2V5cyh0aGlzLmhlYWRlcikuZmlsdGVyKGsgPT4gayAhPT0gJ19fbWV0YWRhdGFfXycpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0ZW5zb3IgYnkgbmFtZVxuICAgKi9cbiAgZ2V0VGVuc29yKG5hbWU6IHN0cmluZyk6IHsgZGF0YTogRmxvYXQzMkFycmF5OyBzaGFwZTogbnVtYmVyW10gfSB8IG51bGwge1xuICAgIGNvbnN0IGVudHJ5ID0gdGhpcy5oZWFkZXJbbmFtZV07XG4gICAgaWYgKCFlbnRyeSB8fCB0eXBlb2YgZW50cnkgPT09ICdvYmplY3QnICYmICdkdHlwZScgaW4gZW50cnkgPT09IGZhbHNlKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBjb25zdCB0ZW5zb3JIZWFkZXIgPSBlbnRyeSBhcyBTYWZlVGVuc29yc0hlYWRlcjtcbiAgICBjb25zdCBbc3RhcnQsIGVuZF0gPSB0ZW5zb3JIZWFkZXIuZGF0YV9vZmZzZXRzO1xuICAgIGNvbnN0IGJ5dGVzID0gdGhpcy5idWZmZXIuc2xpY2UodGhpcy5kYXRhT2Zmc2V0ICsgc3RhcnQsIHRoaXMuZGF0YU9mZnNldCArIGVuZCk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgZGF0YTogbmV3IEZsb2F0MzJBcnJheShieXRlcy5idWZmZXIsIGJ5dGVzLmJ5dGVPZmZzZXQsIGJ5dGVzLmxlbmd0aCAvIDQpLFxuICAgICAgc2hhcGU6IHRlbnNvckhlYWRlci5zaGFwZSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0ZW5zb3IgYXMgMkQgYXJyYXlcbiAgICovXG4gIGdldFRlbnNvcjJEKG5hbWU6IHN0cmluZyk6IG51bWJlcltdW10gfCBudWxsIHtcbiAgICBjb25zdCB0ZW5zb3IgPSB0aGlzLmdldFRlbnNvcihuYW1lKTtcbiAgICBpZiAoIXRlbnNvciB8fCB0ZW5zb3Iuc2hhcGUubGVuZ3RoICE9PSAyKSByZXR1cm4gbnVsbDtcblxuICAgIGNvbnN0IFtyb3dzLCBjb2xzXSA9IHRlbnNvci5zaGFwZTtcbiAgICBjb25zdCByZXN1bHQ6IG51bWJlcltdW10gPSBbXTtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcm93czsgaSsrKSB7XG4gICAgICBjb25zdCByb3c6IG51bWJlcltdID0gW107XG4gICAgICBmb3IgKGxldCBqID0gMDsgaiA8IGNvbHM7IGorKykge1xuICAgICAgICByb3cucHVzaCh0ZW5zb3IuZGF0YVtpICogY29scyArIGpdKTtcbiAgICAgIH1cbiAgICAgIHJlc3VsdC5wdXNoKHJvdyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGVuc29yIGFzIDFEIGFycmF5XG4gICAqL1xuICBnZXRUZW5zb3IxRChuYW1lOiBzdHJpbmcpOiBudW1iZXJbXSB8IG51bGwge1xuICAgIGNvbnN0IHRlbnNvciA9IHRoaXMuZ2V0VGVuc29yKG5hbWUpO1xuICAgIGlmICghdGVuc29yKSByZXR1cm4gbnVsbDtcbiAgICByZXR1cm4gQXJyYXkuZnJvbSh0ZW5zb3IuZGF0YSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IG1ldGFkYXRhXG4gICAqL1xuICBnZXRNZXRhZGF0YSgpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgICBjb25zdCBtZXRhID0gdGhpcy5oZWFkZXJbJ19fbWV0YWRhdGFfXyddO1xuICAgIGlmICghbWV0YSB8fCB0eXBlb2YgbWV0YSAhPT0gJ29iamVjdCcpIHJldHVybiB7fTtcbiAgICByZXR1cm4gbWV0YSBhcyBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICB9XG5cbiAgcHJpdmF0ZSBwYXJzZUhlYWRlcigpOiB2b2lkIHtcbiAgICBjb25zdCB2aWV3ID0gbmV3IERhdGFWaWV3KHRoaXMuYnVmZmVyLmJ1ZmZlciwgdGhpcy5idWZmZXIuYnl0ZU9mZnNldCk7XG4gICAgY29uc3QgaGVhZGVyTGVuZ3RoID0gTnVtYmVyKHZpZXcuZ2V0QmlnVWludDY0KDAsIHRydWUpKTtcblxuICAgIGNvbnN0IGhlYWRlckJ5dGVzID0gdGhpcy5idWZmZXIuc2xpY2UoOCwgOCArIGhlYWRlckxlbmd0aCk7XG4gICAgY29uc3QgaGVhZGVySnNvbiA9IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShoZWFkZXJCeXRlcyk7XG4gICAgdGhpcy5oZWFkZXIgPSBKU09OLnBhcnNlKGhlYWRlckpzb24ucmVwbGFjZSgvXFwwKyQvLCAnJykpOyAvLyBSZW1vdmUgcGFkZGluZyBudWxsc1xuXG4gICAgdGhpcy5kYXRhT2Zmc2V0ID0gOCArIGhlYWRlckxlbmd0aDtcbiAgfVxufVxuXG4vKipcbiAqIE1vZGVsIEV4cG9ydGVyXG4gKlxuICogVW5pZmllZCBleHBvcnQgaW50ZXJmYWNlIGZvciBTT05BIG1vZGVscy5cbiAqL1xuZXhwb3J0IGNsYXNzIE1vZGVsRXhwb3J0ZXIge1xuICAvKipcbiAgICogRXhwb3J0IHRvIFNhZmVUZW5zb3JzIGZvcm1hdFxuICAgKi9cbiAgdG9TYWZlVGVuc29ycyhtb2RlbDogRXhwb3J0YWJsZU1vZGVsKTogVWludDhBcnJheSB7XG4gICAgY29uc3Qgd3JpdGVyID0gbmV3IFNhZmVUZW5zb3JzV3JpdGVyKCk7XG5cbiAgICAvLyBBZGQgbWV0YWRhdGFcbiAgICB3cml0ZXIuYWRkTWV0YWRhdGEoJ25hbWUnLCBtb2RlbC5tZXRhZGF0YS5uYW1lKTtcbiAgICB3cml0ZXIuYWRkTWV0YWRhdGEoJ3ZlcnNpb24nLCBtb2RlbC5tZXRhZGF0YS52ZXJzaW9uKTtcbiAgICB3cml0ZXIuYWRkTWV0YWRhdGEoJ2FyY2hpdGVjdHVyZScsIG1vZGVsLm1ldGFkYXRhLmFyY2hpdGVjdHVyZSk7XG5cbiAgICBpZiAobW9kZWwubWV0YWRhdGEudHJhaW5pbmcpIHtcbiAgICAgIHdyaXRlci5hZGRNZXRhZGF0YSgndHJhaW5pbmdfc3RlcHMnLCBTdHJpbmcobW9kZWwubWV0YWRhdGEudHJhaW5pbmcuc3RlcHMpKTtcbiAgICAgIHdyaXRlci5hZGRNZXRhZGF0YSgndHJhaW5pbmdfbG9zcycsIFN0cmluZyhtb2RlbC5tZXRhZGF0YS50cmFpbmluZy5sb3NzKSk7XG4gICAgfVxuXG4gICAgLy8gQWRkIExvUkEgd2VpZ2h0c1xuICAgIGlmIChtb2RlbC5sb3JhV2VpZ2h0cykge1xuICAgICAgd3JpdGVyLmFkZDJEKCdsb3JhLkEnLCBtb2RlbC5sb3JhV2VpZ2h0cy5sb3JhQSk7XG4gICAgICB3cml0ZXIuYWRkMkQoJ2xvcmEuQicsIG1vZGVsLmxvcmFXZWlnaHRzLmxvcmFCKTtcbiAgICAgIHdyaXRlci5hZGQxRCgnbG9yYS5zY2FsaW5nJywgW21vZGVsLmxvcmFXZWlnaHRzLnNjYWxpbmddKTtcbiAgICB9XG5cbiAgICAvLyBBZGQgcGF0dGVybnMgYXMgZW1iZWRkaW5nc1xuICAgIGlmIChtb2RlbC5wYXR0ZXJucyAmJiBtb2RlbC5wYXR0ZXJucy5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBlbWJlZGRpbmdzOiBudW1iZXJbXVtdID0gbW9kZWwucGF0dGVybnMubWFwKHAgPT4gcC5lbWJlZGRpbmcpO1xuICAgICAgd3JpdGVyLmFkZDJEKCdwYXR0ZXJucy5lbWJlZGRpbmdzJywgZW1iZWRkaW5ncyk7XG5cbiAgICAgIGNvbnN0IHN1Y2Nlc3NSYXRlcyA9IG1vZGVsLnBhdHRlcm5zLm1hcChwID0+IHAuc3VjY2Vzc1JhdGUpO1xuICAgICAgd3JpdGVyLmFkZDFEKCdwYXR0ZXJucy5zdWNjZXNzX3JhdGVzJywgc3VjY2Vzc1JhdGVzKTtcbiAgICB9XG5cbiAgICAvLyBBZGQgcmF3IHRlbnNvcnNcbiAgICBpZiAobW9kZWwudGVuc29ycykge1xuICAgICAgZm9yIChjb25zdCBbbmFtZSwgZGF0YV0gb2YgbW9kZWwudGVuc29ycykge1xuICAgICAgICB3cml0ZXIuYWRkVGVuc29yKG5hbWUsIGRhdGEsIFtkYXRhLmxlbmd0aF0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB3cml0ZXIuYnVpbGQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHBvcnQgdG8gSlNPTiBmb3JtYXRcbiAgICovXG4gIHRvSlNPTihtb2RlbDogRXhwb3J0YWJsZU1vZGVsKTogc3RyaW5nIHtcbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgbWV0YWRhdGE6IG1vZGVsLm1ldGFkYXRhLFxuICAgICAgbG9yYUNvbmZpZzogbW9kZWwubG9yYUNvbmZpZyxcbiAgICAgIGxvcmFXZWlnaHRzOiBtb2RlbC5sb3JhV2VpZ2h0cyxcbiAgICAgIHBhdHRlcm5zOiBtb2RlbC5wYXR0ZXJucyxcbiAgICAgIGV3Y1N0YXRzOiBtb2RlbC5ld2NTdGF0cyxcbiAgICB9LCBudWxsLCAyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHBvcnQgdG8gY29tcGFjdCBiaW5hcnkgZm9ybWF0XG4gICAqL1xuICB0b0JpbmFyeShtb2RlbDogRXhwb3J0YWJsZU1vZGVsKTogVWludDhBcnJheSB7XG4gICAgY29uc3QganNvbiA9IHRoaXMudG9KU09OKG1vZGVsKTtcbiAgICBjb25zdCBqc29uQnl0ZXMgPSBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoanNvbik7XG5cbiAgICAvLyBTaW1wbGUgZm9ybWF0OiBbNC1ieXRlIGxlbmd0aF1banNvbiBieXRlc11cbiAgICBjb25zdCBidWZmZXIgPSBuZXcgVWludDhBcnJheSg0ICsganNvbkJ5dGVzLmxlbmd0aCk7XG4gICAgY29uc3QgdmlldyA9IG5ldyBEYXRhVmlldyhidWZmZXIuYnVmZmVyKTtcbiAgICB2aWV3LnNldFVpbnQzMigwLCBqc29uQnl0ZXMubGVuZ3RoLCB0cnVlKTtcbiAgICBidWZmZXIuc2V0KGpzb25CeXRlcywgNCk7XG5cbiAgICByZXR1cm4gYnVmZmVyO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4cG9ydCBmb3IgSHVnZ2luZ0ZhY2UgSHViIGNvbXBhdGliaWxpdHlcbiAgICovXG4gIHRvSHVnZ2luZ0ZhY2UobW9kZWw6IEV4cG9ydGFibGVNb2RlbCk6IHtcbiAgICBzYWZldGVuc29yczogVWludDhBcnJheTtcbiAgICBjb25maWc6IHN0cmluZztcbiAgICByZWFkbWU6IHN0cmluZztcbiAgfSB7XG4gICAgY29uc3Qgc2FmZXRlbnNvcnMgPSB0aGlzLnRvU2FmZVRlbnNvcnMobW9kZWwpO1xuXG4gICAgY29uc3QgY29uZmlnID0gSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgbW9kZWxfdHlwZTogJ3NvbmEtbG9yYScsXG4gICAgICAuLi5tb2RlbC5tZXRhZGF0YSxcbiAgICAgIGxvcmFfY29uZmlnOiBtb2RlbC5sb3JhQ29uZmlnLFxuICAgIH0sIG51bGwsIDIpO1xuXG4gICAgY29uc3QgcmVhZG1lID0gYC0tLVxubGljZW5zZTogbWl0XG50YWdzOlxuLSBzb25hXG4tIGxvcmFcbi0gcnV2ZWN0b3Jcbi0tLVxuXG4jICR7bW9kZWwubWV0YWRhdGEubmFtZX1cblxuJHttb2RlbC5tZXRhZGF0YS5hcmNoaXRlY3R1cmV9IG1vZGVsIHRyYWluZWQgd2l0aCBTT05BIGFkYXB0aXZlIGxlYXJuaW5nLlxuXG4jIyBVc2FnZVxuXG5cXGBcXGBcXGB0eXBlc2NyaXB0XG5pbXBvcnQgeyBMb3JhQWRhcHRlciwgU2FmZVRlbnNvcnNSZWFkZXIgfSBmcm9tICdAcnV2ZWN0b3IvcnV2bGxtJztcblxuY29uc3QgcmVhZGVyID0gbmV3IFNhZmVUZW5zb3JzUmVhZGVyKGJ1ZmZlcik7XG5jb25zdCBhZGFwdGVyID0gbmV3IExvcmFBZGFwdGVyKCk7XG5hZGFwdGVyLnNldFdlaWdodHMoe1xuICBsb3JhQTogcmVhZGVyLmdldFRlbnNvcjJEKCdsb3JhLkEnKSxcbiAgbG9yYUI6IHJlYWRlci5nZXRUZW5zb3IyRCgnbG9yYS5CJyksXG4gIHNjYWxpbmc6IHJlYWRlci5nZXRUZW5zb3IxRCgnbG9yYS5zY2FsaW5nJylbMF0sXG59KTtcblxcYFxcYFxcYFxuXG4jIyBUcmFpbmluZyBJbmZvXG5cbi0gU3RlcHM6ICR7bW9kZWwubWV0YWRhdGEudHJhaW5pbmc/LnN0ZXBzIHx8ICdOL0EnfVxuLSBGaW5hbCBMb3NzOiAke21vZGVsLm1ldGFkYXRhLnRyYWluaW5nPy5sb3NzIHx8ICdOL0EnfVxuYDtcblxuICAgIHJldHVybiB7IHNhZmV0ZW5zb3JzLCBjb25maWcsIHJlYWRtZSB9O1xuICB9XG59XG5cbi8qKlxuICogTW9kZWwgSW1wb3J0ZXJcbiAqXG4gKiBJbXBvcnQgbW9kZWxzIGZyb20gdmFyaW91cyBmb3JtYXRzLlxuICovXG5leHBvcnQgY2xhc3MgTW9kZWxJbXBvcnRlciB7XG4gIC8qKlxuICAgKiBJbXBvcnQgZnJvbSBTYWZlVGVuc29ycyBmb3JtYXRcbiAgICovXG4gIGZyb21TYWZlVGVuc29ycyhidWZmZXI6IFVpbnQ4QXJyYXkpOiBQYXJ0aWFsPEV4cG9ydGFibGVNb2RlbD4ge1xuICAgIGNvbnN0IHJlYWRlciA9IG5ldyBTYWZlVGVuc29yc1JlYWRlcihidWZmZXIpO1xuICAgIGNvbnN0IG1ldGFkYXRhID0gcmVhZGVyLmdldE1ldGFkYXRhKCk7XG5cbiAgICBjb25zdCByZXN1bHQ6IFBhcnRpYWw8RXhwb3J0YWJsZU1vZGVsPiA9IHtcbiAgICAgIG1ldGFkYXRhOiB7XG4gICAgICAgIG5hbWU6IG1ldGFkYXRhLm5hbWUgfHwgJ3Vua25vd24nLFxuICAgICAgICB2ZXJzaW9uOiBtZXRhZGF0YS52ZXJzaW9uIHx8ICcxLjAuMCcsXG4gICAgICAgIGFyY2hpdGVjdHVyZTogbWV0YWRhdGEuYXJjaGl0ZWN0dXJlIHx8ICdzb25hLWxvcmEnLFxuICAgICAgICB0cmFpbmluZzogbWV0YWRhdGEudHJhaW5pbmdfc3RlcHMgPyB7XG4gICAgICAgICAgc3RlcHM6IHBhcnNlSW50KG1ldGFkYXRhLnRyYWluaW5nX3N0ZXBzKSxcbiAgICAgICAgICBsb3NzOiBwYXJzZUZsb2F0KG1ldGFkYXRhLnRyYWluaW5nX2xvc3MgfHwgJzAnKSxcbiAgICAgICAgICBsZWFybmluZ1JhdGU6IDAsXG4gICAgICAgIH0gOiB1bmRlZmluZWQsXG4gICAgICB9LFxuICAgIH07XG5cbiAgICAvLyBMb2FkIExvUkEgd2VpZ2h0c1xuICAgIGNvbnN0IGxvcmFBID0gcmVhZGVyLmdldFRlbnNvcjJEKCdsb3JhLkEnKTtcbiAgICBjb25zdCBsb3JhQiA9IHJlYWRlci5nZXRUZW5zb3IyRCgnbG9yYS5CJyk7XG4gICAgY29uc3QgbG9yYVNjYWxpbmcgPSByZWFkZXIuZ2V0VGVuc29yMUQoJ2xvcmEuc2NhbGluZycpO1xuXG4gICAgaWYgKGxvcmFBICYmIGxvcmFCICYmIGxvcmFTY2FsaW5nKSB7XG4gICAgICByZXN1bHQubG9yYVdlaWdodHMgPSB7XG4gICAgICAgIGxvcmFBLFxuICAgICAgICBsb3JhQixcbiAgICAgICAgc2NhbGluZzogbG9yYVNjYWxpbmdbMF0sXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIExvYWQgcGF0dGVybnNcbiAgICBjb25zdCBwYXR0ZXJuRW1iZWRkaW5ncyA9IHJlYWRlci5nZXRUZW5zb3IyRCgncGF0dGVybnMuZW1iZWRkaW5ncycpO1xuICAgIGNvbnN0IHBhdHRlcm5SYXRlcyA9IHJlYWRlci5nZXRUZW5zb3IxRCgncGF0dGVybnMuc3VjY2Vzc19yYXRlcycpO1xuXG4gICAgaWYgKHBhdHRlcm5FbWJlZGRpbmdzICYmIHBhdHRlcm5SYXRlcykge1xuICAgICAgcmVzdWx0LnBhdHRlcm5zID0gcGF0dGVybkVtYmVkZGluZ3MubWFwKChlbWJlZGRpbmcsIGkpID0+ICh7XG4gICAgICAgIGlkOiBgaW1wb3J0ZWQtJHtpfWAsXG4gICAgICAgIHR5cGU6ICdxdWVyeV9yZXNwb25zZScgYXMgY29uc3QsXG4gICAgICAgIGVtYmVkZGluZyxcbiAgICAgICAgc3VjY2Vzc1JhdGU6IHBhdHRlcm5SYXRlc1tpXSB8fCAwLFxuICAgICAgICB1c2VDb3VudDogMCxcbiAgICAgICAgbGFzdFVzZWQ6IG5ldyBEYXRlKCksXG4gICAgICB9KSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbXBvcnQgZnJvbSBKU09OIGZvcm1hdFxuICAgKi9cbiAgZnJvbUpTT04oanNvbjogc3RyaW5nKTogUGFydGlhbDxFeHBvcnRhYmxlTW9kZWw+IHtcbiAgICByZXR1cm4gSlNPTi5wYXJzZShqc29uKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbXBvcnQgZnJvbSBiaW5hcnkgZm9ybWF0XG4gICAqL1xuICBmcm9tQmluYXJ5KGJ1ZmZlcjogVWludDhBcnJheSk6IFBhcnRpYWw8RXhwb3J0YWJsZU1vZGVsPiB7XG4gICAgY29uc3QgdmlldyA9IG5ldyBEYXRhVmlldyhidWZmZXIuYnVmZmVyLCBidWZmZXIuYnl0ZU9mZnNldCk7XG4gICAgY29uc3QgbGVuZ3RoID0gdmlldy5nZXRVaW50MzIoMCwgdHJ1ZSk7XG4gICAgY29uc3QganNvbkJ5dGVzID0gYnVmZmVyLnNsaWNlKDQsIDQgKyBsZW5ndGgpO1xuICAgIGNvbnN0IGpzb24gPSBuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoanNvbkJ5dGVzKTtcbiAgICByZXR1cm4gdGhpcy5mcm9tSlNPTihqc29uKTtcbiAgfVxufVxuXG4vKipcbiAqIERhdGFzZXQgRXhwb3J0ZXJcbiAqXG4gKiBFeHBvcnQgdHJhaW5pbmcgZGF0YSBpbiB2YXJpb3VzIGZvcm1hdHMuXG4gKi9cbmV4cG9ydCBjbGFzcyBEYXRhc2V0RXhwb3J0ZXIge1xuICAvKipcbiAgICogRXhwb3J0IHRvIEpTT05MIGZvcm1hdCAob25lIEpTT04gcGVyIGxpbmUpXG4gICAqL1xuICB0b0pTT05MKGRhdGE6IEFycmF5PHsgaW5wdXQ6IEVtYmVkZGluZzsgb3V0cHV0OiBFbWJlZGRpbmc7IHF1YWxpdHk6IG51bWJlciB9Pik6IHN0cmluZyB7XG4gICAgcmV0dXJuIGRhdGFcbiAgICAgIC5tYXAoaXRlbSA9PiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIGlucHV0OiBpdGVtLmlucHV0LFxuICAgICAgICBvdXRwdXQ6IGl0ZW0ub3V0cHV0LFxuICAgICAgICBxdWFsaXR5OiBpdGVtLnF1YWxpdHksXG4gICAgICB9KSlcbiAgICAgIC5qb2luKCdcXG4nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHBvcnQgdG8gQ1NWIGZvcm1hdFxuICAgKi9cbiAgdG9DU1YoZGF0YTogQXJyYXk8eyBpbnB1dDogRW1iZWRkaW5nOyBvdXRwdXQ6IEVtYmVkZGluZzsgcXVhbGl0eTogbnVtYmVyIH0+KTogc3RyaW5nIHtcbiAgICBjb25zdCBoZWFkZXIgPSAncXVhbGl0eSxpbnB1dCxvdXRwdXQnO1xuICAgIGNvbnN0IHJvd3MgPSBkYXRhLm1hcChpdGVtID0+XG4gICAgICBgJHtpdGVtLnF1YWxpdHl9LFwiJHtpdGVtLmlucHV0LmpvaW4oJywnKX1cIixcIiR7aXRlbS5vdXRwdXQuam9pbignLCcpfVwiYFxuICAgICk7XG4gICAgcmV0dXJuIFtoZWFkZXIsIC4uLnJvd3NdLmpvaW4oJ1xcbicpO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4cG9ydCBwYXR0ZXJucyBmb3IgcHJlLXRyYWluaW5nXG4gICAqL1xuICB0b1ByZXRyYWluKHBhdHRlcm5zOiBMZWFybmVkUGF0dGVybltdKTogc3RyaW5nIHtcbiAgICByZXR1cm4gcGF0dGVybnNcbiAgICAgIC5maWx0ZXIocCA9PiBwLnN1Y2Nlc3NSYXRlID49IDAuNylcbiAgICAgIC5tYXAocCA9PiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIGVtYmVkZGluZzogcC5lbWJlZGRpbmcsXG4gICAgICAgIHR5cGU6IHAudHlwZSxcbiAgICAgICAgcXVhbGl0eTogcC5zdWNjZXNzUmF0ZSxcbiAgICAgIH0pKVxuICAgICAgLmpvaW4oJ1xcbicpO1xuICB9XG59XG4iXX0=
|