@ruvector/ruvllm 3.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/GPU-LOOP.md +229 -0
- package/LICENSE +201 -0
- package/NOTICE +9 -0
- package/README.md +157 -362
- package/examples/gpu-loop.example.json +26 -0
- package/package.json +50 -121
- package/src/adapters-cli.mjs +23 -0
- package/src/adapters.mjs +91 -0
- package/src/cli.mjs +30 -0
- package/src/engine.mjs +238 -0
- package/src/fixture.mjs +38 -0
- package/src/gpu-host.mjs +47 -0
- package/src/gpu-loop-cli.mjs +67 -0
- package/src/gpu-loop.mjs +184 -0
- package/src/gpu-spool-adapter.mjs +80 -0
- package/src/vast-host-adapter.mjs +274 -0
- package/bin/cli.js +0 -1040
- package/dist/cjs/benchmarks/embedding-benchmark.d.ts +0 -102
- package/dist/cjs/benchmarks/embedding-benchmark.d.ts.map +0 -1
- package/dist/cjs/benchmarks/embedding-benchmark.js +0 -436
- package/dist/cjs/benchmarks/index.d.ts +0 -34
- package/dist/cjs/benchmarks/index.d.ts.map +0 -1
- package/dist/cjs/benchmarks/index.js +0 -132
- package/dist/cjs/benchmarks/model-comparison.d.ts +0 -71
- package/dist/cjs/benchmarks/model-comparison.d.ts.map +0 -1
- package/dist/cjs/benchmarks/model-comparison.js +0 -476
- package/dist/cjs/benchmarks/routing-benchmark.d.ts +0 -70
- package/dist/cjs/benchmarks/routing-benchmark.d.ts.map +0 -1
- package/dist/cjs/benchmarks/routing-benchmark.js +0 -289
- package/dist/cjs/contrastive.d.ts +0 -229
- package/dist/cjs/contrastive.d.ts.map +0 -1
- package/dist/cjs/contrastive.js +0 -589
- package/dist/cjs/engine.d.ts +0 -160
- package/dist/cjs/engine.d.ts.map +0 -1
- package/dist/cjs/engine.js +0 -552
- package/dist/cjs/export.d.ts +0 -182
- package/dist/cjs/export.d.ts.map +0 -1
- package/dist/cjs/export.js +0 -422
- package/dist/cjs/federated.d.ts +0 -233
- package/dist/cjs/federated.d.ts.map +0 -1
- package/dist/cjs/federated.js +0 -525
- package/dist/cjs/index.d.ts +0 -68
- package/dist/cjs/index.d.ts.map +0 -1
- package/dist/cjs/index.js +0 -104
- package/dist/cjs/intelligence.d.ts +0 -136
- package/dist/cjs/intelligence.d.ts.map +0 -1
- package/dist/cjs/intelligence.js +0 -226
- package/dist/cjs/lora.d.ts +0 -251
- package/dist/cjs/lora.d.ts.map +0 -1
- package/dist/cjs/lora.js +0 -509
- package/dist/cjs/models.d.ts +0 -129
- package/dist/cjs/models.d.ts.map +0 -1
- package/dist/cjs/models.js +0 -323
- package/dist/cjs/native.d.ts +0 -140
- package/dist/cjs/native.d.ts.map +0 -1
- package/dist/cjs/native.js +0 -98
- package/dist/cjs/session.d.ts +0 -80
- package/dist/cjs/session.d.ts.map +0 -1
- package/dist/cjs/session.js +0 -203
- package/dist/cjs/simd.d.ts +0 -90
- package/dist/cjs/simd.d.ts.map +0 -1
- package/dist/cjs/simd.js +0 -209
- package/dist/cjs/sona.d.ts +0 -223
- package/dist/cjs/sona.d.ts.map +0 -1
- package/dist/cjs/sona.js +0 -562
- package/dist/cjs/streaming.d.ts +0 -55
- package/dist/cjs/streaming.d.ts.map +0 -1
- package/dist/cjs/streaming.js +0 -131
- package/dist/cjs/training.d.ts +0 -312
- package/dist/cjs/training.d.ts.map +0 -1
- package/dist/cjs/training.js +0 -610
- package/dist/cjs/types.d.ts +0 -696
- package/dist/cjs/types.d.ts.map +0 -1
- package/dist/cjs/types.js +0 -6
- package/dist/esm/benchmarks/embedding-benchmark.d.ts +0 -102
- package/dist/esm/benchmarks/embedding-benchmark.d.ts.map +0 -1
- package/dist/esm/benchmarks/embedding-benchmark.js +0 -427
- package/dist/esm/benchmarks/index.d.ts +0 -34
- package/dist/esm/benchmarks/index.d.ts.map +0 -1
- package/dist/esm/benchmarks/index.js +0 -110
- package/dist/esm/benchmarks/model-comparison.d.ts +0 -71
- package/dist/esm/benchmarks/model-comparison.d.ts.map +0 -1
- package/dist/esm/benchmarks/model-comparison.js +0 -434
- package/dist/esm/benchmarks/routing-benchmark.d.ts +0 -70
- package/dist/esm/benchmarks/routing-benchmark.d.ts.map +0 -1
- package/dist/esm/benchmarks/routing-benchmark.js +0 -283
- package/dist/esm/contrastive.d.ts +0 -229
- package/dist/esm/contrastive.d.ts.map +0 -1
- package/dist/esm/contrastive.js +0 -578
- package/dist/esm/engine.d.ts +0 -160
- package/dist/esm/engine.d.ts.map +0 -1
- package/dist/esm/engine.js +0 -548
- package/dist/esm/export.d.ts +0 -182
- package/dist/esm/export.d.ts.map +0 -1
- package/dist/esm/export.js +0 -414
- package/dist/esm/federated.d.ts +0 -233
- package/dist/esm/federated.d.ts.map +0 -1
- package/dist/esm/federated.js +0 -520
- package/dist/esm/index.d.ts +0 -68
- package/dist/esm/index.d.ts.map +0 -1
- package/dist/esm/index.js +0 -84
- package/dist/esm/intelligence.d.ts +0 -136
- package/dist/esm/intelligence.d.ts.map +0 -1
- package/dist/esm/intelligence.js +0 -188
- package/dist/esm/lora.d.ts +0 -251
- package/dist/esm/lora.d.ts.map +0 -1
- package/dist/esm/lora.js +0 -504
- package/dist/esm/models.d.ts +0 -129
- package/dist/esm/models.d.ts.map +0 -1
- package/dist/esm/models.js +0 -282
- package/dist/esm/native.d.ts +0 -140
- package/dist/esm/native.d.ts.map +0 -1
- package/dist/esm/native.js +0 -93
- package/dist/esm/session.d.ts +0 -80
- package/dist/esm/session.d.ts.map +0 -1
- package/dist/esm/session.js +0 -199
- package/dist/esm/simd.d.ts +0 -90
- package/dist/esm/simd.d.ts.map +0 -1
- package/dist/esm/simd.js +0 -205
- package/dist/esm/sona.d.ts +0 -223
- package/dist/esm/sona.d.ts.map +0 -1
- package/dist/esm/sona.js +0 -556
- package/dist/esm/streaming.d.ts +0 -55
- package/dist/esm/streaming.d.ts.map +0 -1
- package/dist/esm/streaming.js +0 -126
- package/dist/esm/training.d.ts +0 -312
- package/dist/esm/training.d.ts.map +0 -1
- package/dist/esm/training.js +0 -603
- package/dist/esm/types.d.ts +0 -696
- package/dist/esm/types.d.ts.map +0 -1
- package/dist/esm/types.js +0 -5
- package/scripts/ensemble-model-compare.js +0 -287
- package/scripts/fix-esm-extensions.mjs +0 -181
- package/scripts/huggingface/README.md +0 -537
- package/scripts/huggingface/publish.sh +0 -112
- package/scripts/hybrid-model-compare.js +0 -373
- package/scripts/improved-model-compare.js +0 -288
- package/scripts/optimized-model-compare.js +0 -364
- package/scripts/real-model-compare.js +0 -280
- package/scripts/smoke-esm.mjs +0 -82
- package/scripts/training/agentic-flow-capabilities.json +0 -329
- package/scripts/training/claude-code-synth.js +0 -505
- package/scripts/training/claude-flow-capabilities.json +0 -1322
- package/scripts/training/claude-hard-negatives.js +0 -222
- package/scripts/training/contrastive-finetune.js +0 -517
- package/scripts/training/ecosystem-triplets.jsonl +0 -1467
- package/scripts/training/generate-ecosystem-triplets.js +0 -1324
- package/scripts/training/routing-dataset.js +0 -634
- package/scripts/training/ruvector-capabilities.json +0 -798
- package/scripts/training/validate-ecosystem.js +0 -381
- package/scripts/training/validation-results.json +0 -23
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Embedding Quality Benchmark for RuvLTRA Models
|
|
3
|
-
*
|
|
4
|
-
* Tests embedding quality for Claude Code use cases:
|
|
5
|
-
* - Code similarity detection
|
|
6
|
-
* - Task clustering
|
|
7
|
-
* - Semantic search accuracy
|
|
8
|
-
*/
|
|
9
|
-
export interface EmbeddingPair {
|
|
10
|
-
id: string;
|
|
11
|
-
text1: string;
|
|
12
|
-
text2: string;
|
|
13
|
-
similarity: 'high' | 'medium' | 'low' | 'none';
|
|
14
|
-
category: string;
|
|
15
|
-
}
|
|
16
|
-
export interface EmbeddingResult {
|
|
17
|
-
pairId: string;
|
|
18
|
-
expectedSimilarity: string;
|
|
19
|
-
computedScore: number;
|
|
20
|
-
correct: boolean;
|
|
21
|
-
latencyMs: number;
|
|
22
|
-
}
|
|
23
|
-
export interface ClusterTestCase {
|
|
24
|
-
id: string;
|
|
25
|
-
items: string[];
|
|
26
|
-
expectedCluster: string;
|
|
27
|
-
}
|
|
28
|
-
export interface EmbeddingBenchmarkResults {
|
|
29
|
-
similarityAccuracy: number;
|
|
30
|
-
similarityByCategory: Record<string, number>;
|
|
31
|
-
avgSimilarityLatencyMs: number;
|
|
32
|
-
clusterPurity: number;
|
|
33
|
-
silhouetteScore: number;
|
|
34
|
-
searchMRR: number;
|
|
35
|
-
searchNDCG: number;
|
|
36
|
-
similarityResults: EmbeddingResult[];
|
|
37
|
-
totalPairs: number;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Ground truth similarity pairs for testing
|
|
41
|
-
* Tests whether embeddings correctly capture semantic similarity
|
|
42
|
-
*/
|
|
43
|
-
export declare const SIMILARITY_TEST_PAIRS: EmbeddingPair[];
|
|
44
|
-
/**
|
|
45
|
-
* Search relevance test cases
|
|
46
|
-
* Query + documents with relevance scores
|
|
47
|
-
*/
|
|
48
|
-
export interface SearchTestCase {
|
|
49
|
-
id: string;
|
|
50
|
-
query: string;
|
|
51
|
-
documents: {
|
|
52
|
-
text: string;
|
|
53
|
-
relevance: number;
|
|
54
|
-
}[];
|
|
55
|
-
}
|
|
56
|
-
export declare const SEARCH_TEST_CASES: SearchTestCase[];
|
|
57
|
-
/**
|
|
58
|
-
* Cluster test cases - items that should cluster together
|
|
59
|
-
*/
|
|
60
|
-
export declare const CLUSTER_TEST_CASES: ClusterTestCase[];
|
|
61
|
-
/**
|
|
62
|
-
* Check if computed similarity matches expected category
|
|
63
|
-
*/
|
|
64
|
-
export declare function isCorrectSimilarity(expected: 'high' | 'medium' | 'low' | 'none', computed: number): boolean;
|
|
65
|
-
/**
|
|
66
|
-
* Calculate Mean Reciprocal Rank for search results
|
|
67
|
-
*/
|
|
68
|
-
export declare function calculateMRR(rankings: {
|
|
69
|
-
relevant: boolean;
|
|
70
|
-
}[][]): number;
|
|
71
|
-
/**
|
|
72
|
-
* Calculate NDCG for search results
|
|
73
|
-
*/
|
|
74
|
-
export declare function calculateNDCG(results: {
|
|
75
|
-
relevance: number;
|
|
76
|
-
}[], idealOrder: {
|
|
77
|
-
relevance: number;
|
|
78
|
-
}[]): number;
|
|
79
|
-
/**
|
|
80
|
-
* Calculate silhouette score for clustering
|
|
81
|
-
*/
|
|
82
|
-
export declare function calculateSilhouette(embeddings: number[][], labels: number[]): number;
|
|
83
|
-
/**
|
|
84
|
-
* Run the embedding benchmark
|
|
85
|
-
*/
|
|
86
|
-
export declare function runEmbeddingBenchmark(embedder: (text: string) => number[], similarityFn: (a: number[], b: number[]) => number): EmbeddingBenchmarkResults;
|
|
87
|
-
/**
|
|
88
|
-
* Format embedding benchmark results for display
|
|
89
|
-
*/
|
|
90
|
-
export declare function formatEmbeddingResults(results: EmbeddingBenchmarkResults): string;
|
|
91
|
-
declare const _default: {
|
|
92
|
-
SIMILARITY_TEST_PAIRS: EmbeddingPair[];
|
|
93
|
-
SEARCH_TEST_CASES: SearchTestCase[];
|
|
94
|
-
CLUSTER_TEST_CASES: ClusterTestCase[];
|
|
95
|
-
runEmbeddingBenchmark: typeof runEmbeddingBenchmark;
|
|
96
|
-
formatEmbeddingResults: typeof formatEmbeddingResults;
|
|
97
|
-
isCorrectSimilarity: typeof isCorrectSimilarity;
|
|
98
|
-
calculateMRR: typeof calculateMRR;
|
|
99
|
-
calculateNDCG: typeof calculateNDCG;
|
|
100
|
-
};
|
|
101
|
-
export default _default;
|
|
102
|
-
//# sourceMappingURL=embedding-benchmark.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"embedding-benchmark.d.ts","sourceRoot":"","sources":["../../../src/benchmarks/embedding-benchmark.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAC/C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,yBAAyB;IAExC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,sBAAsB,EAAE,MAAM,CAAC;IAG/B,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IAGxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IAGnB,iBAAiB,EAAE,eAAe,EAAE,CAAC;IACrC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,aAAa,EA8ChD,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAClD;AAED,eAAO,MAAM,iBAAiB,EAAE,cAAc,EAwD7C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,eAAe,EAwD/C,CAAC;AAYF;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,EAC5C,QAAQ,EAAE,MAAM,GACf,OAAO,CAGT;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,EAAE,EAAE,GAClC,MAAM,CASR;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EAAE,EAChC,UAAU,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EAAE,GAClC,MAAM,CAUR;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAAE,EAAE,EACtB,MAAM,EAAE,MAAM,EAAE,GACf,MAAM,CA8CR;AAUD;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAAE,EACpC,YAAY,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,MAAM,GACjD,yBAAyB,CA0G3B;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,yBAAyB,GAAG,MAAM,CAyDjF;;;;;;;;;;;AAED,wBASE"}
|
|
@@ -1,436 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Embedding Quality Benchmark for RuvLTRA Models
|
|
4
|
-
*
|
|
5
|
-
* Tests embedding quality for Claude Code use cases:
|
|
6
|
-
* - Code similarity detection
|
|
7
|
-
* - Task clustering
|
|
8
|
-
* - Semantic search accuracy
|
|
9
|
-
*/
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.CLUSTER_TEST_CASES = exports.SEARCH_TEST_CASES = exports.SIMILARITY_TEST_PAIRS = void 0;
|
|
12
|
-
exports.isCorrectSimilarity = isCorrectSimilarity;
|
|
13
|
-
exports.calculateMRR = calculateMRR;
|
|
14
|
-
exports.calculateNDCG = calculateNDCG;
|
|
15
|
-
exports.calculateSilhouette = calculateSilhouette;
|
|
16
|
-
exports.runEmbeddingBenchmark = runEmbeddingBenchmark;
|
|
17
|
-
exports.formatEmbeddingResults = formatEmbeddingResults;
|
|
18
|
-
/**
|
|
19
|
-
* Ground truth similarity pairs for testing
|
|
20
|
-
* Tests whether embeddings correctly capture semantic similarity
|
|
21
|
-
*/
|
|
22
|
-
exports.SIMILARITY_TEST_PAIRS = [
|
|
23
|
-
// === HIGH SIMILARITY (same concept, different wording) ===
|
|
24
|
-
{ id: 'H001', text1: 'implement user authentication', text2: 'create login functionality', similarity: 'high', category: 'code-task' },
|
|
25
|
-
{ id: 'H002', text1: 'write unit tests for the API', text2: 'create test cases for REST endpoints', similarity: 'high', category: 'code-task' },
|
|
26
|
-
{ id: 'H003', text1: 'fix the null pointer exception', text2: 'resolve the NullPointerException bug', similarity: 'high', category: 'debugging' },
|
|
27
|
-
{ id: 'H004', text1: 'optimize database queries', text2: 'improve SQL query performance', similarity: 'high', category: 'performance' },
|
|
28
|
-
{ id: 'H005', text1: 'deploy to production', text2: 'release to prod environment', similarity: 'high', category: 'devops' },
|
|
29
|
-
{ id: 'H006', text1: 'refactor the legacy code', text2: 'restructure old codebase', similarity: 'high', category: 'refactoring' },
|
|
30
|
-
{ id: 'H007', text1: 'add error handling', text2: 'implement exception handling', similarity: 'high', category: 'code-task' },
|
|
31
|
-
{ id: 'H008', text1: 'create REST API endpoint', text2: 'build HTTP API route', similarity: 'high', category: 'code-task' },
|
|
32
|
-
{ id: 'H009', text1: 'check for SQL injection', text2: 'audit for SQLi vulnerabilities', similarity: 'high', category: 'security' },
|
|
33
|
-
{ id: 'H010', text1: 'document the API', text2: 'write API documentation', similarity: 'high', category: 'documentation' },
|
|
34
|
-
// Code snippets - same functionality
|
|
35
|
-
{ id: 'H011', text1: 'function add(a, b) { return a + b; }', text2: 'const sum = (x, y) => x + y;', similarity: 'high', category: 'code-snippet' },
|
|
36
|
-
{ id: 'H012', text1: 'for (let i = 0; i < arr.length; i++)', text2: 'arr.forEach((item, index) => {})', similarity: 'high', category: 'code-snippet' },
|
|
37
|
-
{ id: 'H013', text1: 'async function fetchData() { await fetch(url); }', text2: 'const getData = async () => { await axios.get(url); }', similarity: 'high', category: 'code-snippet' },
|
|
38
|
-
// === MEDIUM SIMILARITY (related but different) ===
|
|
39
|
-
{ id: 'M001', text1: 'implement user authentication', text2: 'create user registration', similarity: 'medium', category: 'code-task' },
|
|
40
|
-
{ id: 'M002', text1: 'write unit tests', text2: 'write integration tests', similarity: 'medium', category: 'testing' },
|
|
41
|
-
{ id: 'M003', text1: 'fix the bug in checkout', text2: 'debug the payment flow', similarity: 'medium', category: 'debugging' },
|
|
42
|
-
{ id: 'M004', text1: 'optimize frontend performance', text2: 'improve backend response time', similarity: 'medium', category: 'performance' },
|
|
43
|
-
{ id: 'M005', text1: 'deploy to staging', text2: 'deploy to production', similarity: 'medium', category: 'devops' },
|
|
44
|
-
{ id: 'M006', text1: 'React component', text2: 'Vue component', similarity: 'medium', category: 'code-snippet' },
|
|
45
|
-
{ id: 'M007', text1: 'PostgreSQL query', text2: 'MySQL query', similarity: 'medium', category: 'code-snippet' },
|
|
46
|
-
{ id: 'M008', text1: 'REST API', text2: 'GraphQL API', similarity: 'medium', category: 'code-task' },
|
|
47
|
-
{ id: 'M009', text1: 'Node.js server', text2: 'Python Flask server', similarity: 'medium', category: 'code-snippet' },
|
|
48
|
-
{ id: 'M010', text1: 'add caching layer', text2: 'implement rate limiting', similarity: 'medium', category: 'performance' },
|
|
49
|
-
// === LOW SIMILARITY (same domain, different task) ===
|
|
50
|
-
{ id: 'L001', text1: 'implement authentication', text2: 'write documentation', similarity: 'low', category: 'code-task' },
|
|
51
|
-
{ id: 'L002', text1: 'fix bug', text2: 'add new feature', similarity: 'low', category: 'code-task' },
|
|
52
|
-
{ id: 'L003', text1: 'optimize query', text2: 'review pull request', similarity: 'low', category: 'mixed' },
|
|
53
|
-
{ id: 'L004', text1: 'deploy application', text2: 'design architecture', similarity: 'low', category: 'mixed' },
|
|
54
|
-
{ id: 'L005', text1: 'frontend React code', text2: 'backend database migration', similarity: 'low', category: 'code-snippet' },
|
|
55
|
-
{ id: 'L006', text1: 'security audit', text2: 'performance benchmark', similarity: 'low', category: 'mixed' },
|
|
56
|
-
{ id: 'L007', text1: 'write unit tests', text2: 'create CI/CD pipeline', similarity: 'low', category: 'mixed' },
|
|
57
|
-
{ id: 'L008', text1: 'CSS styling', text2: 'database schema', similarity: 'low', category: 'code-snippet' },
|
|
58
|
-
// === NO SIMILARITY (unrelated) ===
|
|
59
|
-
{ id: 'N001', text1: 'implement user login', text2: 'the weather is nice today', similarity: 'none', category: 'unrelated' },
|
|
60
|
-
{ id: 'N002', text1: 'fix JavaScript bug', text2: 'recipe for chocolate cake', similarity: 'none', category: 'unrelated' },
|
|
61
|
-
{ id: 'N003', text1: 'deploy Kubernetes cluster', text2: 'book a flight to Paris', similarity: 'none', category: 'unrelated' },
|
|
62
|
-
{ id: 'N004', text1: 'optimize SQL query', text2: 'learn to play guitar', similarity: 'none', category: 'unrelated' },
|
|
63
|
-
{ id: 'N005', text1: 'const x = 42;', text2: 'roses are red violets are blue', similarity: 'none', category: 'unrelated' },
|
|
64
|
-
];
|
|
65
|
-
exports.SEARCH_TEST_CASES = [
|
|
66
|
-
{
|
|
67
|
-
id: 'S001',
|
|
68
|
-
query: 'how to implement user authentication in Node.js',
|
|
69
|
-
documents: [
|
|
70
|
-
{ text: 'Implementing JWT authentication in Express.js with passport', relevance: 3 },
|
|
71
|
-
{ text: 'Node.js login system with bcrypt password hashing', relevance: 3 },
|
|
72
|
-
{ text: 'Building a React login form component', relevance: 2 },
|
|
73
|
-
{ text: 'PostgreSQL user table schema design', relevance: 1 },
|
|
74
|
-
{ text: 'How to deploy Docker containers', relevance: 0 },
|
|
75
|
-
],
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
id: 'S002',
|
|
79
|
-
query: 'fix memory leak in JavaScript',
|
|
80
|
-
documents: [
|
|
81
|
-
{ text: 'Debugging memory leaks with Chrome DevTools heap snapshots', relevance: 3 },
|
|
82
|
-
{ text: 'Common causes of memory leaks in Node.js applications', relevance: 3 },
|
|
83
|
-
{ text: 'JavaScript garbage collection explained', relevance: 2 },
|
|
84
|
-
{ text: 'Optimizing React component re-renders', relevance: 1 },
|
|
85
|
-
{ text: 'CSS flexbox layout tutorial', relevance: 0 },
|
|
86
|
-
],
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
id: 'S003',
|
|
90
|
-
query: 'database migration best practices',
|
|
91
|
-
documents: [
|
|
92
|
-
{ text: 'Schema migration strategies for zero-downtime deployments', relevance: 3 },
|
|
93
|
-
{ text: 'Using Prisma migrate for PostgreSQL schema changes', relevance: 3 },
|
|
94
|
-
{ text: 'Database backup and recovery procedures', relevance: 2 },
|
|
95
|
-
{ text: 'SQL query optimization techniques', relevance: 1 },
|
|
96
|
-
{ text: 'React state management with Redux', relevance: 0 },
|
|
97
|
-
],
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
id: 'S004',
|
|
101
|
-
query: 'write unit tests for React components',
|
|
102
|
-
documents: [
|
|
103
|
-
{ text: 'Testing React components with Jest and React Testing Library', relevance: 3 },
|
|
104
|
-
{ text: 'Snapshot testing for UI components', relevance: 3 },
|
|
105
|
-
{ text: 'Mocking API calls in frontend tests', relevance: 2 },
|
|
106
|
-
{ text: 'End-to-end testing with Cypress', relevance: 1 },
|
|
107
|
-
{ text: 'Kubernetes pod configuration', relevance: 0 },
|
|
108
|
-
],
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
id: 'S005',
|
|
112
|
-
query: 'optimize API response time',
|
|
113
|
-
documents: [
|
|
114
|
-
{ text: 'Implementing Redis caching for API endpoints', relevance: 3 },
|
|
115
|
-
{ text: 'Database query optimization with indexes', relevance: 3 },
|
|
116
|
-
{ text: 'Using CDN for static asset delivery', relevance: 2 },
|
|
117
|
-
{ text: 'Load balancing strategies for microservices', relevance: 2 },
|
|
118
|
-
{ text: 'Writing clean JavaScript code', relevance: 0 },
|
|
119
|
-
],
|
|
120
|
-
},
|
|
121
|
-
];
|
|
122
|
-
/**
|
|
123
|
-
* Cluster test cases - items that should cluster together
|
|
124
|
-
*/
|
|
125
|
-
exports.CLUSTER_TEST_CASES = [
|
|
126
|
-
{
|
|
127
|
-
id: 'CL001',
|
|
128
|
-
expectedCluster: 'authentication',
|
|
129
|
-
items: [
|
|
130
|
-
'implement user login',
|
|
131
|
-
'add JWT token validation',
|
|
132
|
-
'create password reset flow',
|
|
133
|
-
'implement OAuth integration',
|
|
134
|
-
'add two-factor authentication',
|
|
135
|
-
],
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
id: 'CL002',
|
|
139
|
-
expectedCluster: 'testing',
|
|
140
|
-
items: [
|
|
141
|
-
'write unit tests',
|
|
142
|
-
'add integration tests',
|
|
143
|
-
'create E2E test suite',
|
|
144
|
-
'improve test coverage',
|
|
145
|
-
'add snapshot tests',
|
|
146
|
-
],
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
id: 'CL003',
|
|
150
|
-
expectedCluster: 'database',
|
|
151
|
-
items: [
|
|
152
|
-
'optimize SQL queries',
|
|
153
|
-
'add database indexes',
|
|
154
|
-
'create migration script',
|
|
155
|
-
'implement connection pooling',
|
|
156
|
-
'design schema for users table',
|
|
157
|
-
],
|
|
158
|
-
},
|
|
159
|
-
{
|
|
160
|
-
id: 'CL004',
|
|
161
|
-
expectedCluster: 'frontend',
|
|
162
|
-
items: [
|
|
163
|
-
'build React component',
|
|
164
|
-
'add CSS styling',
|
|
165
|
-
'implement responsive design',
|
|
166
|
-
'create form validation',
|
|
167
|
-
'add loading spinner',
|
|
168
|
-
],
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
id: 'CL005',
|
|
172
|
-
expectedCluster: 'devops',
|
|
173
|
-
items: [
|
|
174
|
-
'set up CI/CD pipeline',
|
|
175
|
-
'configure Kubernetes deployment',
|
|
176
|
-
'create Docker container',
|
|
177
|
-
'add monitoring alerts',
|
|
178
|
-
'implement auto-scaling',
|
|
179
|
-
],
|
|
180
|
-
},
|
|
181
|
-
];
|
|
182
|
-
/**
|
|
183
|
-
* Expected similarity score ranges
|
|
184
|
-
*/
|
|
185
|
-
const SIMILARITY_THRESHOLDS = {
|
|
186
|
-
high: { min: 0.7, max: 1.0 },
|
|
187
|
-
medium: { min: 0.4, max: 0.7 },
|
|
188
|
-
low: { min: 0.2, max: 0.4 },
|
|
189
|
-
none: { min: 0.0, max: 0.2 },
|
|
190
|
-
};
|
|
191
|
-
/**
|
|
192
|
-
* Check if computed similarity matches expected category
|
|
193
|
-
*/
|
|
194
|
-
function isCorrectSimilarity(expected, computed) {
|
|
195
|
-
const threshold = SIMILARITY_THRESHOLDS[expected];
|
|
196
|
-
return computed >= threshold.min && computed <= threshold.max;
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Calculate Mean Reciprocal Rank for search results
|
|
200
|
-
*/
|
|
201
|
-
function calculateMRR(rankings) {
|
|
202
|
-
let sumRR = 0;
|
|
203
|
-
for (const ranking of rankings) {
|
|
204
|
-
const firstRelevantIdx = ranking.findIndex(r => r.relevant);
|
|
205
|
-
if (firstRelevantIdx >= 0) {
|
|
206
|
-
sumRR += 1 / (firstRelevantIdx + 1);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
return sumRR / rankings.length;
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Calculate NDCG for search results
|
|
213
|
-
*/
|
|
214
|
-
function calculateNDCG(results, idealOrder) {
|
|
215
|
-
const dcg = results.reduce((sum, r, i) => {
|
|
216
|
-
return sum + (Math.pow(2, r.relevance) - 1) / Math.log2(i + 2);
|
|
217
|
-
}, 0);
|
|
218
|
-
const idcg = idealOrder.reduce((sum, r, i) => {
|
|
219
|
-
return sum + (Math.pow(2, r.relevance) - 1) / Math.log2(i + 2);
|
|
220
|
-
}, 0);
|
|
221
|
-
return idcg > 0 ? dcg / idcg : 0;
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* Calculate silhouette score for clustering
|
|
225
|
-
*/
|
|
226
|
-
function calculateSilhouette(embeddings, labels) {
|
|
227
|
-
// Simplified silhouette calculation
|
|
228
|
-
const n = embeddings.length;
|
|
229
|
-
if (n < 2)
|
|
230
|
-
return 0;
|
|
231
|
-
let totalSilhouette = 0;
|
|
232
|
-
for (let i = 0; i < n; i++) {
|
|
233
|
-
const cluster = labels[i];
|
|
234
|
-
// Calculate mean intra-cluster distance (a)
|
|
235
|
-
let intraSum = 0;
|
|
236
|
-
let intraCount = 0;
|
|
237
|
-
for (let j = 0; j < n; j++) {
|
|
238
|
-
if (i !== j && labels[j] === cluster) {
|
|
239
|
-
intraSum += euclideanDistance(embeddings[i], embeddings[j]);
|
|
240
|
-
intraCount++;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
const a = intraCount > 0 ? intraSum / intraCount : 0;
|
|
244
|
-
// Calculate min mean inter-cluster distance (b)
|
|
245
|
-
const otherClusters = [...new Set(labels)].filter(c => c !== cluster);
|
|
246
|
-
let minInterMean = Infinity;
|
|
247
|
-
for (const otherCluster of otherClusters) {
|
|
248
|
-
let interSum = 0;
|
|
249
|
-
let interCount = 0;
|
|
250
|
-
for (let j = 0; j < n; j++) {
|
|
251
|
-
if (labels[j] === otherCluster) {
|
|
252
|
-
interSum += euclideanDistance(embeddings[i], embeddings[j]);
|
|
253
|
-
interCount++;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
if (interCount > 0) {
|
|
257
|
-
minInterMean = Math.min(minInterMean, interSum / interCount);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
const b = minInterMean === Infinity ? 0 : minInterMean;
|
|
261
|
-
// Silhouette for this point
|
|
262
|
-
const s = Math.max(a, b) > 0 ? (b - a) / Math.max(a, b) : 0;
|
|
263
|
-
totalSilhouette += s;
|
|
264
|
-
}
|
|
265
|
-
return totalSilhouette / n;
|
|
266
|
-
}
|
|
267
|
-
function euclideanDistance(a, b) {
|
|
268
|
-
let sum = 0;
|
|
269
|
-
for (let i = 0; i < a.length; i++) {
|
|
270
|
-
sum += Math.pow(a[i] - b[i], 2);
|
|
271
|
-
}
|
|
272
|
-
return Math.sqrt(sum);
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Run the embedding benchmark
|
|
276
|
-
*/
|
|
277
|
-
function runEmbeddingBenchmark(embedder, similarityFn) {
|
|
278
|
-
const similarityResults = [];
|
|
279
|
-
const latencies = [];
|
|
280
|
-
// Test similarity pairs
|
|
281
|
-
for (const pair of exports.SIMILARITY_TEST_PAIRS) {
|
|
282
|
-
const start = performance.now();
|
|
283
|
-
const emb1 = embedder(pair.text1);
|
|
284
|
-
const emb2 = embedder(pair.text2);
|
|
285
|
-
const score = similarityFn(emb1, emb2);
|
|
286
|
-
const latencyMs = performance.now() - start;
|
|
287
|
-
latencies.push(latencyMs);
|
|
288
|
-
similarityResults.push({
|
|
289
|
-
pairId: pair.id,
|
|
290
|
-
expectedSimilarity: pair.similarity,
|
|
291
|
-
computedScore: score,
|
|
292
|
-
correct: isCorrectSimilarity(pair.similarity, score),
|
|
293
|
-
latencyMs,
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
// Calculate similarity accuracy
|
|
297
|
-
const correctSimilarity = similarityResults.filter(r => r.correct).length;
|
|
298
|
-
const similarityAccuracy = correctSimilarity / similarityResults.length;
|
|
299
|
-
// Accuracy by category
|
|
300
|
-
const categories = [...new Set(exports.SIMILARITY_TEST_PAIRS.map(p => p.category))];
|
|
301
|
-
const similarityByCategory = {};
|
|
302
|
-
for (const cat of categories) {
|
|
303
|
-
const catResults = similarityResults.filter((r, i) => exports.SIMILARITY_TEST_PAIRS[i].category === cat);
|
|
304
|
-
similarityByCategory[cat] = catResults.filter(r => r.correct).length / catResults.length;
|
|
305
|
-
}
|
|
306
|
-
// Test search quality (MRR and NDCG)
|
|
307
|
-
const searchRankings = [];
|
|
308
|
-
let totalNDCG = 0;
|
|
309
|
-
for (const testCase of exports.SEARCH_TEST_CASES) {
|
|
310
|
-
const queryEmb = embedder(testCase.query);
|
|
311
|
-
const docScores = testCase.documents.map(doc => ({
|
|
312
|
-
...doc,
|
|
313
|
-
score: similarityFn(queryEmb, embedder(doc.text)),
|
|
314
|
-
}));
|
|
315
|
-
// Sort by computed score
|
|
316
|
-
const sorted = [...docScores].sort((a, b) => b.score - a.score);
|
|
317
|
-
// For MRR
|
|
318
|
-
searchRankings.push(sorted.map(d => ({ relevant: d.relevance >= 2 })));
|
|
319
|
-
// For NDCG
|
|
320
|
-
const idealOrder = [...testCase.documents].sort((a, b) => b.relevance - a.relevance);
|
|
321
|
-
totalNDCG += calculateNDCG(sorted, idealOrder);
|
|
322
|
-
}
|
|
323
|
-
const searchMRR = calculateMRR(searchRankings);
|
|
324
|
-
const searchNDCG = totalNDCG / exports.SEARCH_TEST_CASES.length;
|
|
325
|
-
// Test clustering
|
|
326
|
-
const allClusterItems = [];
|
|
327
|
-
exports.CLUSTER_TEST_CASES.forEach((tc, clusterIdx) => {
|
|
328
|
-
tc.items.forEach(item => {
|
|
329
|
-
allClusterItems.push({ text: item, cluster: clusterIdx });
|
|
330
|
-
});
|
|
331
|
-
});
|
|
332
|
-
const clusterEmbeddings = allClusterItems.map(item => embedder(item.text));
|
|
333
|
-
const clusterLabels = allClusterItems.map(item => item.cluster);
|
|
334
|
-
const silhouetteScore = calculateSilhouette(clusterEmbeddings, clusterLabels);
|
|
335
|
-
// Calculate cluster purity (how well items stay in their expected cluster)
|
|
336
|
-
// Using simple nearest-neighbor classification
|
|
337
|
-
let correctCluster = 0;
|
|
338
|
-
for (let i = 0; i < clusterEmbeddings.length; i++) {
|
|
339
|
-
let nearestIdx = -1;
|
|
340
|
-
let nearestDist = Infinity;
|
|
341
|
-
for (let j = 0; j < clusterEmbeddings.length; j++) {
|
|
342
|
-
if (i !== j) {
|
|
343
|
-
const dist = euclideanDistance(clusterEmbeddings[i], clusterEmbeddings[j]);
|
|
344
|
-
if (dist < nearestDist) {
|
|
345
|
-
nearestDist = dist;
|
|
346
|
-
nearestIdx = j;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
if (nearestIdx >= 0 && clusterLabels[nearestIdx] === clusterLabels[i]) {
|
|
351
|
-
correctCluster++;
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
const clusterPurity = correctCluster / clusterEmbeddings.length;
|
|
355
|
-
return {
|
|
356
|
-
similarityAccuracy,
|
|
357
|
-
similarityByCategory,
|
|
358
|
-
avgSimilarityLatencyMs: latencies.reduce((a, b) => a + b, 0) / latencies.length,
|
|
359
|
-
clusterPurity,
|
|
360
|
-
silhouetteScore,
|
|
361
|
-
searchMRR,
|
|
362
|
-
searchNDCG,
|
|
363
|
-
similarityResults,
|
|
364
|
-
totalPairs: similarityResults.length,
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
/**
|
|
368
|
-
* Format embedding benchmark results for display
|
|
369
|
-
*/
|
|
370
|
-
function formatEmbeddingResults(results) {
|
|
371
|
-
const lines = [];
|
|
372
|
-
lines.push('');
|
|
373
|
-
lines.push('╔══════════════════════════════════════════════════════════════╗');
|
|
374
|
-
lines.push('║ EMBEDDING BENCHMARK RESULTS ║');
|
|
375
|
-
lines.push('╠══════════════════════════════════════════════════════════════╣');
|
|
376
|
-
lines.push(`║ Similarity Detection: ${(results.similarityAccuracy * 100).toFixed(1)}%`.padEnd(63) + '║');
|
|
377
|
-
lines.push('╠══════════════════════════════════════════════════════════════╣');
|
|
378
|
-
lines.push('║ By Category: ║');
|
|
379
|
-
for (const [cat, acc] of Object.entries(results.similarityByCategory).sort((a, b) => b[1] - a[1])) {
|
|
380
|
-
const bar = '█'.repeat(Math.floor(acc * 20)) + '░'.repeat(20 - Math.floor(acc * 20));
|
|
381
|
-
lines.push(`║ ${cat.padEnd(18)} [${bar}] ${(acc * 100).toFixed(0).padStart(3)}% ║`);
|
|
382
|
-
}
|
|
383
|
-
lines.push('╠══════════════════════════════════════════════════════════════╣');
|
|
384
|
-
lines.push('║ Clustering Quality: ║');
|
|
385
|
-
lines.push(`║ Cluster Purity: ${(results.clusterPurity * 100).toFixed(1)}%`.padEnd(63) + '║');
|
|
386
|
-
lines.push(`║ Silhouette Score: ${results.silhouetteScore.toFixed(3)}`.padEnd(63) + '║');
|
|
387
|
-
lines.push('╠══════════════════════════════════════════════════════════════╣');
|
|
388
|
-
lines.push('║ Search Quality: ║');
|
|
389
|
-
lines.push(`║ MRR (Mean Reciprocal Rank): ${results.searchMRR.toFixed(3)}`.padEnd(63) + '║');
|
|
390
|
-
lines.push(`║ NDCG: ${results.searchNDCG.toFixed(3)}`.padEnd(63) + '║');
|
|
391
|
-
lines.push('╠══════════════════════════════════════════════════════════════╣');
|
|
392
|
-
lines.push(`║ Avg Latency: ${results.avgSimilarityLatencyMs.toFixed(2)}ms per pair`.padEnd(63) + '║');
|
|
393
|
-
lines.push('╚══════════════════════════════════════════════════════════════╝');
|
|
394
|
-
// Quality assessment
|
|
395
|
-
lines.push('');
|
|
396
|
-
lines.push('Quality Assessment:');
|
|
397
|
-
if (results.similarityAccuracy >= 0.8) {
|
|
398
|
-
lines.push(' ✓ Similarity detection: EXCELLENT (≥80%)');
|
|
399
|
-
}
|
|
400
|
-
else if (results.similarityAccuracy >= 0.6) {
|
|
401
|
-
lines.push(' ~ Similarity detection: GOOD (60-80%)');
|
|
402
|
-
}
|
|
403
|
-
else {
|
|
404
|
-
lines.push(' ✗ Similarity detection: NEEDS IMPROVEMENT (<60%)');
|
|
405
|
-
}
|
|
406
|
-
if (results.searchMRR >= 0.8) {
|
|
407
|
-
lines.push(' ✓ Search quality (MRR): EXCELLENT (≥0.8)');
|
|
408
|
-
}
|
|
409
|
-
else if (results.searchMRR >= 0.5) {
|
|
410
|
-
lines.push(' ~ Search quality (MRR): ACCEPTABLE (0.5-0.8)');
|
|
411
|
-
}
|
|
412
|
-
else {
|
|
413
|
-
lines.push(' ✗ Search quality (MRR): NEEDS IMPROVEMENT (<0.5)');
|
|
414
|
-
}
|
|
415
|
-
if (results.clusterPurity >= 0.8) {
|
|
416
|
-
lines.push(' ✓ Clustering: EXCELLENT (≥80% purity)');
|
|
417
|
-
}
|
|
418
|
-
else if (results.clusterPurity >= 0.6) {
|
|
419
|
-
lines.push(' ~ Clustering: ACCEPTABLE (60-80% purity)');
|
|
420
|
-
}
|
|
421
|
-
else {
|
|
422
|
-
lines.push(' ✗ Clustering: NEEDS IMPROVEMENT (<60% purity)');
|
|
423
|
-
}
|
|
424
|
-
return lines.join('\n');
|
|
425
|
-
}
|
|
426
|
-
exports.default = {
|
|
427
|
-
SIMILARITY_TEST_PAIRS: exports.SIMILARITY_TEST_PAIRS,
|
|
428
|
-
SEARCH_TEST_CASES: exports.SEARCH_TEST_CASES,
|
|
429
|
-
CLUSTER_TEST_CASES: exports.CLUSTER_TEST_CASES,
|
|
430
|
-
runEmbeddingBenchmark,
|
|
431
|
-
formatEmbeddingResults,
|
|
432
|
-
isCorrectSimilarity,
|
|
433
|
-
calculateMRR,
|
|
434
|
-
calculateNDCG,
|
|
435
|
-
};
|
|
436
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW1iZWRkaW5nLWJlbmNobWFyay5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iZW5jaG1hcmtzL2VtYmVkZGluZy1iZW5jaG1hcmsudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7O0dBT0c7OztBQTZPSCxrREFNQztBQUtELG9DQVdDO0FBS0Qsc0NBYUM7QUFLRCxrREFpREM7QUFhRCxzREE2R0M7QUFLRCx3REF5REM7QUF4ZEQ7OztHQUdHO0FBQ1UsUUFBQSxxQkFBcUIsR0FBb0I7SUFDcEQsNERBQTREO0lBQzVELEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsK0JBQStCLEVBQUUsS0FBSyxFQUFFLDRCQUE0QixFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRTtJQUN0SSxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLDhCQUE4QixFQUFFLEtBQUssRUFBRSxzQ0FBc0MsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUU7SUFDL0ksRUFBRSxFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxnQ0FBZ0MsRUFBRSxLQUFLLEVBQUUsc0NBQXNDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFO0lBQ2pKLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsMkJBQTJCLEVBQUUsS0FBSyxFQUFFLCtCQUErQixFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLGFBQWEsRUFBRTtJQUN2SSxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLHNCQUFzQixFQUFFLEtBQUssRUFBRSw2QkFBNkIsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUU7SUFDM0gsRUFBRSxFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSww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RUQsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQzFCLENBQUM7QUFFRCxrQkFBZTtJQUNiLHFCQUFxQixFQUFyQiw2QkFBcUI7SUFDckIsaUJBQWlCLEVBQWpCLHlCQUFpQjtJQUNqQixrQkFBa0IsRUFBbEIsMEJBQWtCO0lBQ2xCLHFCQUFxQjtJQUNyQixzQkFBc0I7SUFDdEIsbUJBQW1CO0lBQ25CLFlBQVk7SUFDWixhQUFhO0NBQ2QsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRW1iZWRkaW5nIFF1YWxpdHkgQmVuY2htYXJrIGZvciBSdXZMVFJBIE1vZGVsc1xuICpcbiAqIFRlc3RzIGVtYmVkZGluZyBxdWFsaXR5IGZvciBDbGF1ZGUgQ29kZSB1c2UgY2FzZXM6XG4gKiAtIENvZGUgc2ltaWxhcml0eSBkZXRlY3Rpb25cbiAqIC0gVGFzayBjbHVzdGVyaW5nXG4gKiAtIFNlbWFudGljIHNlYXJjaCBhY2N1cmFjeVxuICovXG5cbmV4cG9ydCBpbnRlcmZhY2UgRW1iZWRkaW5nUGFpciB7XG4gIGlkOiBzdHJpbmc7XG4gIHRleHQxOiBzdHJpbmc7XG4gIHRleHQyOiBzdHJpbmc7XG4gIHNpbWlsYXJpdHk6ICdoaWdoJyB8ICdtZWRpdW0nIHwgJ2xvdycgfCAnbm9uZSc7XG4gIGNhdGVnb3J5OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRW1iZWRkaW5nUmVzdWx0IHtcbiAgcGFpcklkOiBzdHJpbmc7XG4gIGV4cGVjdGVkU2ltaWxhcml0eTogc3RyaW5nO1xuICBjb21wdXRlZFNjb3JlOiBudW1iZXI7XG4gIGNvcnJlY3Q6IGJvb2xlYW47XG4gIGxhdGVuY3lNczogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENsdXN0ZXJUZXN0Q2FzZSB7XG4gIGlkOiBzdHJpbmc7XG4gIGl0ZW1zOiBzdHJpbmdbXTtcbiAgZXhwZWN0ZWRDbHVzdGVyOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRW1iZWRkaW5nQmVuY2htYXJrUmVzdWx0cyB7XG4gIC8vIFNpbWlsYXJpdHkgZGV0ZWN0aW9uXG4gIHNpbWlsYXJpdHlBY2N1cmFjeTogbnVtYmVyO1xuICBzaW1pbGFyaXR5QnlDYXRlZ29yeTogUmVjb3JkPHN0cmluZywgbnVtYmVyPjtcbiAgYXZnU2ltaWxhcml0eUxhdGVuY3lNczogbnVtYmVyO1xuXG4gIC8vIENsdXN0ZXJpbmcgcXVhbGl0eVxuICBjbHVzdGVyUHVyaXR5OiBudW1iZXI7XG4gIHNpbGhvdWV0dGVTY29yZTogbnVtYmVyO1xuXG4gIC8vIFNlYXJjaCBxdWFsaXR5XG4gIHNlYXJjaE1SUjogbnVtYmVyOyAvLyBNZWFuIFJlY2lwcm9jYWwgUmFua1xuICBzZWFyY2hORENHOiBudW1iZXI7IC8vIE5vcm1hbGl6ZWQgRGlzY291bnRlZCBDdW11bGF0aXZlIEdhaW5cblxuICAvLyBEZXRhaWxzXG4gIHNpbWlsYXJpdHlSZXN1bHRzOiBFbWJlZGRpbmdSZXN1bHRbXTtcbiAgdG90YWxQYWlyczogbnVtYmVyO1xufVxuXG4vKipcbiAqIEdyb3VuZCB0cnV0aCBzaW1pbGFyaXR5IHBhaXJzIGZvciB0ZXN0aW5nXG4gKiBUZXN0cyB3aGV0aGVyIGVtYmVkZGluZ3MgY29ycmVjdGx5IGNhcHR1cmUgc2VtYW50aWMgc2ltaWxhcml0eVxuICovXG5leHBvcnQgY29uc3QgU0lNSUxBUklUWV9URVNUX1BBSVJTOiBFbWJlZGRpbmdQYWlyW10gPSBbXG4gIC8vID09PSBISUdIIFNJTUlMQVJJVFkgKHNhbWUgY29uY2VwdCwgZGlmZmVyZW50IHdvcmRpbmcpID09PVxuICB7IGlkOiAnSDAwMScsIHRleHQxOiAnaW1wbGVtZW50IHVzZXIgYXV0aGVudGljYXRpb24nLCB0ZXh0MjogJ2NyZWF0ZSBsb2dpbiBmdW5jdGlvbmFsaXR5Jywgc2ltaWxhcml0eTogJ2hpZ2gnLCBjYXRlZ29yeTogJ2NvZGUtdGFzaycgfSxcbiAgeyBpZDogJ0gwMDInLCB0ZXh0MTogJ3dyaXRlIHVuaXQgdGVzdHMgZm9yIHRoZSBBUEknLCB0ZXh0MjogJ2NyZWF0ZSB0ZXN0IGNhc2VzIGZvciBSRVNUIGVuZHBvaW50cycsIHNpbWlsYXJpdHk6ICdoaWdoJywgY2F0ZWdvcnk6ICdjb2RlLXRhc2snIH0sXG4gIHsgaWQ6ICdIMDAzJywgdGV4dDE6ICdmaXggdGhlIG51bGwgcG9pbnRlciBleGNlcHRpb24nLCB0ZXh0MjogJ3Jlc29sdmUgdGhlIE51bGxQb2ludGVyRXhjZXB0aW9uIGJ1ZycsIHNpbWlsYXJpdHk6ICdoaWdoJywgY2F0ZWdvcnk6ICdkZWJ1Z2dpbmcnIH0sXG4gIHsgaWQ6ICdIMDA0JywgdGV4dDE6ICdvcHRpbWl6ZSBkYXRhYmFzZSBxdWVyaWVzJywgdGV4dDI6ICdpbXByb3ZlIFNRTCBxdWVyeSBwZXJmb3JtYW5jZScsIHNpbWlsYXJpdHk6ICdoaWdoJywgY2F0ZWdvcnk6ICdwZXJmb3JtYW5jZScgfSxcbiAgeyBpZDogJ0gwMDUnLCB0ZXh0MTogJ2RlcGxveSB0byBwcm9kdWN0aW9uJywgdGV4dDI6ICdyZWxlYXNlIHRvIHByb2QgZW52aXJvbm1lbnQnLCBzaW1pbGFyaXR5OiAnaGlnaCcsIGNhdGVnb3J5OiAnZGV2b3BzJyB9LFxuICB7IGlkOiAnSDAwNicsIHRleHQxOiAncmVmYWN0b3IgdGhlIGxlZ2FjeSBjb2RlJywgdGV4dDI6ICdyZXN0cnVjdHVyZSBvbGQgY29kZWJhc2UnLCBzaW1pbGFyaXR5OiAnaGlnaCcsIGNhdGVnb3J5OiAncmVmYWN0b3JpbmcnIH0sXG4gIHsgaWQ6ICdIMDA3JywgdGV4dDE6ICdhZGQgZXJyb3IgaGFuZGxpbmcnLCB0ZXh0MjogJ2ltcGxlbWVudCBleGNlcHRpb24gaGFuZGxpbmcnLCBzaW1pbGFyaXR5OiAnaGlnaCcsIGNhdGVnb3J5OiAnY29kZS10YXNrJyB9LFxuICB7IGlkOiAnSDAwOCcsIHRleHQxOiAnY3JlYXRlIFJFU1QgQVBJIGVuZHBvaW50JywgdGV4dDI6ICdidWlsZCBIVFRQIEFQSSByb3V0ZScsIHNpbWlsYXJpdHk6ICdoaWdoJywgY2F0ZWdvcnk6ICdjb2RlLXRhc2snIH0sXG4gIHsgaWQ6ICdIMDA5JywgdGV4dDE6ICdjaGVjayBmb3IgU1FMIGluamVjdGlvbicsIHRleHQyOiAnYXVkaXQgZm9yIFNRTGkgdnVsbmVyYWJpbGl0aWVzJywgc2ltaWxhcml0eTogJ2hpZ2gnLCBjYXRlZ29yeTogJ3NlY3VyaXR5JyB9LFxuICB7IGlkOiAnSDAxMCcsIHRleHQxOiAnZG9jdW1lbnQgdGhlIEFQSScsIHRleHQyOiAnd3JpdGUgQVBJIGRvY3VtZW50YXRpb24nLCBzaW1pbGFyaXR5OiAnaGlnaCcsIGNhdGVnb3J5OiAnZG9jdW1lbnRhdGlvbicgfSxcblxuICAvLyBDb2RlIHNuaXBwZXRzIC0gc2FtZSBmdW5jdGlvbmFsaXR5XG4gIHsgaWQ6ICdIMDExJywgdGV4dDE6ICdmdW5jdGlvbiBhZGQoYSwgYikgeyByZXR1cm4gYSArIGI7IH0nLCB0ZXh0MjogJ2NvbnN0IHN1bSA9ICh4LCB5KSA9PiB4ICsgeTsnLCBzaW1pbGFyaXR5OiAnaGlnaCcsIGNhdGVnb3J5OiAnY29kZS1zbmlwcGV0JyB9LFxuICB7IGlkOiAnSDAxMicsIHRleHQxOiAnZm9yIChsZXQgaSA9IDA7IGkgPCBhcnIubGVuZ3RoOyBpKyspJywgdGV4dDI6ICdhcnIuZm9yRWFjaCgoaXRlbSwgaW5kZXgpID0+IHt9KScsIHNpbWlsYXJpdHk6ICdoaWdoJywgY2F0ZWdvcnk6ICdjb2RlLXNuaXBwZXQnIH0sXG4gIHsgaWQ6ICdIMDEzJywgdGV4dDE6ICdhc3luYyBmdW5jdGlvbiBmZXRjaERhdGEoKSB7IGF3YWl0IGZldGNoKHVybCk7IH0nLCB0ZXh0MjogJ2NvbnN0IGdldERhdGEgPSBhc3luYyAoKSA9PiB7IGF3YWl0IGF4aW9zLmdldCh1cmwpOyB9Jywgc2ltaWxhcml0eTogJ2hpZ2gnLCBjYXRlZ29yeTogJ2NvZGUtc25pcHBldCcgfSxcblxuICAvLyA9PT0gTUVESVVNIFNJTUlMQVJJVFkgKHJlbGF0ZWQgYnV0IGRpZmZlcmVudCkgPT09XG4gIHsgaWQ6ICdNMDAxJywgdGV4dDE6ICdpbXBsZW1lbnQgdXNlciBhdXRoZW50aWNhdGlvbicsIHRleHQyOiAnY3JlYXRlIHVzZXIgcmVnaXN0cmF0aW9uJywgc2ltaWxhcml0eTogJ21lZGl1bScsIGNhdGVnb3J5OiAnY29kZS10YXNrJyB9LFxuICB7IGlkOiAnTTAwMicsIHRleHQxOiAnd3JpdGUgdW5pdCB0ZXN0cycsIHRleHQyOiAnd3JpdGUgaW50ZWdyYXRpb24gdGVzdHMnLCBzaW1pbGFyaXR5OiAnbWVkaXVtJywgY2F0ZWdvcnk6ICd0ZXN0aW5nJyB9LFxuICB7IGlkOiAnTTAwMycsIHRleHQxOiAnZml4IHRoZSBidWcgaW4gY2hlY2tvdXQnLCB0ZXh0MjogJ2RlYnVnIHRoZSBwYXltZW50IGZsb3cnLCBzaW1pbGFyaXR5OiAnbWVkaXVtJywgY2F0ZWdvcnk6ICdkZWJ1Z2dpbmcnIH0sXG4gIHsgaWQ6ICdNMDA0JywgdGV4dDE6ICdvcHRpbWl6ZSBmcm9udGVuZCBwZXJmb3JtYW5jZScsIHRleHQyOiAnaW1wcm92ZSBiYWNrZW5kIHJlc3BvbnNlIHRpbWUnLCBzaW1pbGFyaXR5OiAnbWVkaXVtJywgY2F0ZWdvcnk6ICdwZXJmb3JtYW5jZScgfSxcbiAgeyBpZDogJ00wMDUnLCB0ZXh0MTogJ2RlcGxveSB0byBzdGFnaW5nJywgdGV4dDI6ICdkZXBsb3kgdG8gcHJvZHVjdGlvbicsIHNpbWlsYXJpdHk6ICdtZWRpdW0nLCBjYXRlZ29yeTogJ2Rldm9wcycgfSxcbiAgeyBpZDogJ00wMDYnLCB0ZXh0MTogJ1JlYWN0IGNvbXBvbmVudCcsIHRleHQyOiAnVnVlIGNvbXBvbmVudCcsIHNpbWlsYXJpdHk6ICdtZWRpdW0nLCBjYXRlZ29yeTogJ2NvZGUtc25pcHBldCcgfSxcbiAgeyBpZDogJ00wMDcnLCB0ZXh0MTogJ1Bvc3RncmVTUUwgcXVlcnknLCB0ZXh0MjogJ015U1FMIHF1ZXJ5Jywgc2ltaWxhcml0eTogJ21lZGl1bScsIGNhdGVnb3J5OiAnY29kZS1zbmlwcGV0JyB9LFxuICB7IGlkOiAnTTAwOCcsIHRleHQxOiAnUkVTVCBBUEknLCB0ZXh0MjogJ0dyYXBoUUwgQVBJJywgc2ltaWxhcml0eTogJ21lZGl1bScsIGNhdGVnb3J5OiAnY29kZS10YXNrJyB9LFxuICB7IGlkOiAnTTAwOScsIHRleHQxOiAnTm9kZS5qcyBzZXJ2ZXInLCB0ZXh0MjogJ1B5dGhvbiBGbGFzayBzZXJ2ZXInLCBzaW1pbGFyaXR5OiAnbWVkaXVtJywgY2F0ZWdvcnk6ICdjb2RlLXNuaXBwZXQnIH0sXG4gIHsgaWQ6ICdNMDEwJywgdGV4dDE6ICdhZGQgY2FjaGluZyBsYXllcicsIHRleHQyOiAnaW1wbGVtZW50IHJhdGUgbGltaXRpbmcnLCBzaW1pbGFyaXR5OiAnbWVkaXVtJywgY2F0ZWdvcnk6ICdwZXJmb3JtYW5jZScgfSxcblxuICAvLyA9PT0gTE9XIFNJTUlMQVJJVFkgKHNhbWUgZG9tYWluLCBkaWZmZXJlbnQgdGFzaykgPT09XG4gIHsgaWQ6ICdMMDAxJywgdGV4dDE6ICdpbXBsZW1lbnQgYXV0aGVudGljYXRpb24nLCB0ZXh0MjogJ3dyaXRlIGRvY3VtZW50YXRpb24nLCBzaW1pbGFyaXR5OiAnbG93JywgY2F0ZWdvcnk6ICdjb2RlLXRhc2snIH0sXG4gIHsgaWQ6ICdMMDAyJywgdGV4dDE6ICdmaXggYnVnJywgdGV4dDI6ICdhZGQgbmV3IGZlYXR1cmUnLCBzaW1pbGFyaXR5OiAnbG93JywgY2F0ZWdvcnk6ICdjb2RlLXRhc2snIH0sXG4gIHsgaWQ6ICdMMDAzJywgdGV4dDE6ICdvcHRpbWl6ZSBxdWVyeScsIHRleHQyOiAncmV2aWV3IHB1bGwgcmVxdWVzdCcsIHNpbWlsYXJpdHk6ICdsb3cnLCBjYXRlZ29yeTogJ21peGVkJyB9LFxuICB7IGlkOiAnTDAwNCcsIHRleHQxOiAnZGVwbG95IGFwcGxpY2F0aW9uJywgdGV4dDI6ICdkZXNpZ24gYXJjaGl0ZWN0dXJlJywgc2ltaWxhcml0eTogJ2xvdycsIGNhdGVnb3J5OiAnbWl4ZWQnIH0sXG4gIHsgaWQ6ICdMMDA1JywgdGV4dDE6ICdmcm9udGVuZCBSZWFjdCBjb2RlJywgdGV4dDI6ICdiYWNrZW5kIGRhdGFiYXNlIG1pZ3JhdGlvbicsIHNpbWlsYXJpdHk6ICdsb3cnLCBjYXRlZ29yeTogJ2NvZGUtc25pcHBldCcgfSxcbiAgeyBpZDogJ0wwMDYnLCB0ZXh0MTogJ3NlY3VyaXR5IGF1ZGl0JywgdGV4dDI6ICdwZXJmb3JtYW5jZSBiZW5jaG1hcmsnLCBzaW1pbGFyaXR5OiAnbG93JywgY2F0ZWdvcnk6ICdtaXhlZCcgfSxcbiAgeyBpZDogJ0wwMDcnLCB0ZXh0MTogJ3dyaXRlIHVuaXQgdGVzdHMnLCB0ZXh0MjogJ2NyZWF0ZSBDSS9DRCBwaXBlbGluZScsIHNpbWlsYXJpdHk6ICdsb3cnLCBjYXRlZ29yeTogJ21peGVkJyB9LFxuICB7IGlkOiAnTDAwOCcsIHRleHQxOiAnQ1NTIHN0eWxpbmcnLCB0ZXh0MjogJ2RhdGFiYXNlIHNjaGVtYScsIHNpbWlsYXJpdHk6ICdsb3cnLCBjYXRlZ29yeTogJ2NvZGUtc25pcHBldCcgfSxcblxuICAvLyA9PT0gTk8gU0lNSUxBUklUWSAodW5yZWxhdGVkKSA9PT1cbiAgeyBpZDogJ04wMDEnLCB0ZXh0MTogJ2ltcGxlbWVudCB1c2VyIGxvZ2luJywgdGV4dDI6ICd0aGUgd2VhdGhlciBpcyBuaWNlIHRvZGF5Jywgc2ltaWxhcml0eTogJ25vbmUnLCBjYXRlZ29yeTogJ3VucmVsYXRlZCcgfSxcbiAgeyBpZDogJ04wMDInLCB0ZXh0MTogJ2ZpeCBKYXZhU2NyaXB0IGJ1ZycsIHRleHQyOiAncmVjaXBlIGZvciBjaG9jb2xhdGUgY2FrZScsIHNpbWlsYXJpdHk6ICdub25lJywgY2F0ZWdvcnk6ICd1bnJlbGF0ZWQnIH0sXG4gIHsgaWQ6ICdOMDAzJywgdGV4dDE6ICdkZXBsb3kgS3ViZXJuZXRlcyBjbHVzdGVyJywgdGV4dDI6ICdib29rIGEgZmxpZ2h0IHRvIFBhcmlzJywgc2ltaWxhcml0eTogJ25vbmUnLCBjYXRlZ29yeTogJ3VucmVsYXRlZCcgfSxcbiAgeyBpZDogJ04wMDQnLCB0ZXh0MTogJ29wdGltaXplIFNRTCBxdWVyeScsIHRleHQyOiAnbGVhcm4gdG8gcGxheSBndWl0YXInLCBzaW1pbGFyaXR5OiAnbm9uZScsIGNhdGVnb3J5OiAndW5yZWxhdGVkJyB9LFxuICB7IGlkOiAnTjAwNScsIHRleHQxOiAnY29uc3QgeCA9IDQyOycsIHRleHQyOiAncm9zZXMgYXJlIHJlZCB2aW9sZXRzIGFyZSBibHVlJywgc2ltaWxhcml0eTogJ25vbmUnLCBjYXRlZ29yeTogJ3VucmVsYXRlZCcgfSxcbl07XG5cbi8qKlxuICogU2VhcmNoIHJlbGV2YW5jZSB0ZXN0IGNhc2VzXG4gKiBRdWVyeSArIGRvY3VtZW50cyB3aXRoIHJlbGV2YW5jZSBzY29yZXNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZWFyY2hUZXN0Q2FzZSB7XG4gIGlkOiBzdHJpbmc7XG4gIHF1ZXJ5OiBzdHJpbmc7XG4gIGRvY3VtZW50czogeyB0ZXh0OiBzdHJpbmc7IHJlbGV2YW5jZTogbnVtYmVyIH1bXTsgLy8gcmVsZXZhbmNlOiAwLTMgKDA9aXJyZWxldmFudCwgMz1oaWdobHkgcmVsZXZhbnQpXG59XG5cbmV4cG9ydCBjb25zdCBTRUFSQ0hfVEVTVF9DQVNFUzogU2VhcmNoVGVzdENhc2VbXSA9IFtcbiAge1xuICAgIGlkOiAnUzAwMScsXG4gICAgcXVlcnk6ICdob3cgdG8gaW1wbGVtZW50IHVzZXIgYXV0aGVudGljYXRpb24gaW4gTm9kZS5qcycsXG4gICAgZG9jdW1lbnRzOiBbXG4gICAgICB7IHRleHQ6ICdJbXBsZW1lbnRpbmcgSldUIGF1dGhlbnRpY2F0aW9uIGluIEV4cHJlc3MuanMgd2l0aCBwYXNzcG9ydCcsIHJlbGV2YW5jZTogMyB9LFxuICAgICAgeyB0ZXh0OiAnTm9kZS5qcyBsb2dpbiBzeXN0ZW0gd2l0aCBiY3J5cHQgcGFzc3dvcmQgaGFzaGluZycsIHJlbGV2YW5jZTogMyB9LFxuICAgICAgeyB0ZXh0OiAnQnVpbGRpbmcgYSBSZWFjdCBsb2dpbiBmb3JtIGNvbXBvbmVudCcsIHJlbGV2YW5jZTogMiB9LFxuICAgICAgeyB0ZXh0OiAnUG9zdGdyZVNRTCB1c2VyIHRhYmxlIHNjaGVtYSBkZXNpZ24nLCByZWxldmFuY2U6IDEgfSxcbiAgICAgIHsgdGV4dDogJ0hvdyB0byBkZXBsb3kgRG9ja2VyIGNvbnRhaW5lcnMnLCByZWxldmFuY2U6IDAgfSxcbiAgICBdLFxuICB9LFxuICB7XG4gICAgaWQ6ICdTMDAyJyxcbiAgICBxdWVyeTogJ2ZpeCBtZW1vcnkgbGVhayBpbiBKYXZhU2NyaXB0JyxcbiAgICBkb2N1bWVudHM6IFtcbiAgICAgIHsgdGV4dDogJ0RlYnVnZ2luZyBtZW1vcnkgbGVha3Mgd2l0aCBDaHJvbWUgRGV2VG9vbHMgaGVhcCBzbmFwc2hvdHMnLCByZWxldmFuY2U6IDMgfSxcbiAgICAgIHsgdGV4dDogJ0NvbW1vbiBjYXVzZXMgb2YgbWVtb3J5IGxlYWtzIGluIE5vZGUuanMgYXBwbGljYXRpb25zJywgcmVsZXZhbmNlOiAzIH0sXG4gICAgICB7IHRleHQ6ICdKYXZhU2NyaXB0IGdhcmJhZ2UgY29sbGVjdGlvbiBleHBsYWluZWQnLCByZWxldmFuY2U6IDIgfSxcbiAgICAgIHsgdGV4dDogJ09wdGltaXppbmcgUmVhY3QgY29tcG9uZW50IHJlLXJlbmRlcnMnLCByZWxldmFuY2U6IDEgfSxcbiAgICAgIHsgdGV4dDogJ0NTUyBmbGV4Ym94IGxheW91dCB0dXRvcmlhbCcsIHJlbGV2YW5jZTogMCB9LFxuICAgIF0sXG4gIH0sXG4gIHtcbiAgICBpZDogJ1MwMDMnLFxuICAgIHF1ZXJ5OiAnZGF0YWJhc2UgbWlncmF0aW9uIGJlc3QgcHJhY3RpY2VzJyxcbiAgICBkb2N1bWVudHM6IFtcbiAgICAgIHsgdGV4dDogJ1NjaGVtYSBtaWdyYXRpb24gc3RyYXRlZ2llcyBmb3IgemVyby1kb3dudGltZSBkZXBsb3ltZW50cycsIHJlbGV2YW5jZTogMyB9LFxuICAgICAgeyB0ZXh0OiAnVXNpbmcgUHJpc21hIG1pZ3JhdGUgZm9yIFBvc3RncmVTUUwgc2NoZW1hIGNoYW5nZXMnLCByZWxldmFuY2U6IDMgfSxcbiAgICAgIHsgdGV4dDogJ0RhdGFiYXNlIGJhY2t1cCBhbmQgcmVjb3ZlcnkgcHJvY2VkdXJlcycsIHJlbGV2YW5jZTogMiB9LFxuICAgICAgeyB0ZXh0OiAnU1FMIHF1ZXJ5IG9wdGltaXphdGlvbiB0ZWNobmlxdWVzJywgcmVsZXZhbmNlOiAxIH0sXG4gICAgICB7IHRleHQ6ICdSZWFjdCBzdGF0ZSBtYW5hZ2VtZW50IHdpdGggUmVkdXgnLCByZWxldmFuY2U6IDAgfSxcbiAgICBdLFxuICB9LFxuICB7XG4gICAgaWQ6ICdTMDA0JyxcbiAgICBxdWVyeTogJ3dyaXRlIHVuaXQgdGVzdHMgZm9yIFJlYWN0IGNvbXBvbmVudHMnLFxuICAgIGRvY3VtZW50czogW1xuICAgICAgeyB0ZXh0OiAnVGVzdGluZyBSZWFjdCBjb21wb25lbnRzIHdpdGggSmVzdCBhbmQgUmVhY3QgVGVzdGluZyBMaWJyYXJ5JywgcmVsZXZhbmNlOiAzIH0sXG4gICAgICB7IHRleHQ6ICdTbmFwc2hvdCB0ZXN0aW5nIGZvciBVSSBjb21wb25lbnRzJywgcmVsZXZhbmNlOiAzIH0sXG4gICAgICB7IHRleHQ6ICdNb2NraW5nIEFQSSBjYWxscyBpbiBmcm9udGVuZCB0ZXN0cycsIHJlbGV2YW5jZTogMiB9LFxuICAgICAgeyB0ZXh0OiAnRW5kLXRvLWVuZCB0ZXN0aW5nIHdpdGggQ3lwcmVzcycsIHJlbGV2YW5jZTogMSB9LFxuICAgICAgeyB0ZXh0OiAnS3ViZXJuZXRlcyBwb2QgY29uZmlndXJhdGlvbicsIHJlbGV2YW5jZTogMCB9LFxuICAgIF0sXG4gIH0sXG4gIHtcbiAgICBpZDogJ1MwMDUnLFxuICAgIHF1ZXJ5OiAnb3B0aW1pemUgQVBJIHJlc3BvbnNlIHRpbWUnLFxuICAgIGRvY3VtZW50czogW1xuICAgICAgeyB0ZXh0OiAnSW1wbGVtZW50aW5nIFJlZGlzIGNhY2hpbmcgZm9yIEFQSSBlbmRwb2ludHMnLCByZWxldmFuY2U6IDMgfSxcbiAgICAgIHsgdGV4dDogJ0RhdGFiYXNlIHF1ZXJ5IG9wdGltaXphdGlvbiB3aXRoIGluZGV4ZXMnLCByZWxldmFuY2U6IDMgfSxcbiAgICAgIHsgdGV4dDogJ1VzaW5nIENETiBmb3Igc3RhdGljIGFzc2V0IGRlbGl2ZXJ5JywgcmVsZXZhbmNlOiAyIH0sXG4gICAgICB7IHRleHQ6ICdMb2FkIGJhbGFuY2luZyBzdHJhdGVnaWVzIGZvciBtaWNyb3NlcnZpY2VzJywgcmVsZXZhbmNlOiAyIH0sXG4gICAgICB7IHRleHQ6ICdXcml0aW5nIGNsZWFuIEphdmFTY3JpcHQgY29kZScsIHJlbGV2YW5jZTogMCB9LFxuICAgIF0sXG4gIH0sXG5dO1xuXG4vKipcbiAqIENsdXN0ZXIgdGVzdCBjYXNlcyAtIGl0ZW1zIHRoYXQgc2hvdWxkIGNsdXN0ZXIgdG9nZXRoZXJcbiAqL1xuZXhwb3J0IGNvbnN0IENMVVNURVJfVEVTVF9DQVNFUzogQ2x1c3RlclRlc3RDYXNlW10gPSBbXG4gIHtcbiAgICBpZDogJ0NMMDAxJyxcbiAgICBleHBlY3RlZENsdXN0ZXI6ICdhdXRoZW50aWNhdGlvbicsXG4gICAgaXRlbXM6IFtcbiAgICAgICdpbXBsZW1lbnQgdXNlciBsb2dpbicsXG4gICAgICAnYWRkIEpXVCB0b2tlbiB2YWxpZGF0aW9uJyxcbiAgICAgICdjcmVhdGUgcGFzc3dvcmQgcmVzZXQgZmxvdycsXG4gICAgICAnaW1wbGVtZW50IE9BdXRoIGludGVncmF0aW9uJyxcbiAgICAgICdhZGQgdHdvLWZhY3RvciBhdXRoZW50aWNhdGlvbicsXG4gICAgXSxcbiAgfSxcbiAge1xuICAgIGlkOiAnQ0wwMDInLFxuICAgIGV4cGVjdGVkQ2x1c3RlcjogJ3Rlc3RpbmcnLFxuICAgIGl0ZW1zOiBbXG4gICAgICAnd3JpdGUgdW5pdCB0ZXN0cycsXG4gICAgICAnYWRkIGludGVncmF0aW9uIHRlc3RzJyxcbiAgICAgICdjcmVhdGUgRTJFIHRlc3Qgc3VpdGUnLFxuICAgICAgJ2ltcHJvdmUgdGVzdCBjb3ZlcmFnZScsXG4gICAgICAnYWRkIHNuYXBzaG90IHRlc3RzJyxcbiAgICBdLFxuICB9LFxuICB7XG4gICAgaWQ6ICdDTDAwMycsXG4gICAgZXhwZWN0ZWRDbHVzdGVyOiAnZGF0YWJhc2UnLFxuICAgIGl0ZW1zOiBbXG4gICAgICAnb3B0aW1pemUgU1FMIHF1ZXJpZXMnLFxuICAgICAgJ2FkZCBkYXRhYmFzZSBpbmRleGVzJyxcbiAgICAgICdjcmVhdGUgbWlncmF0aW9uIHNjcmlwdCcsXG4gICAgICAnaW1wbGVtZW50IGNvbm5lY3Rpb24gcG9vbGluZycsXG4gICAgICAnZGVzaWduIHNjaGVtYSBmb3IgdXNlcnMgdGFibGUnLFxuICAgIF0sXG4gIH0sXG4gIHtcbiAgICBpZDogJ0NMMDA0JyxcbiAgICBleHBlY3RlZENsdXN0ZXI6ICdmcm9udGVuZCcsXG4gICAgaXRlbXM6IFtcbiAgICAgICdidWlsZCBSZWFjdCBjb21wb25lbnQnLFxuICAgICAgJ2FkZCBDU1Mgc3R5bGluZycsXG4gICAgICAnaW1wbGVtZW50IHJlc3BvbnNpdmUgZGVzaWduJyxcbiAgICAgICdjcmVhdGUgZm9ybSB2YWxpZGF0aW9uJyxcbiAgICAgICdhZGQgbG9hZGluZyBzcGlubmVyJyxcbiAgICBdLFxuICB9LFxuICB7XG4gICAgaWQ6ICdDTDAwNScsXG4gICAgZXhwZWN0ZWRDbHVzdGVyOiAnZGV2b3BzJyxcbiAgICBpdGVtczogW1xuICAgICAgJ3NldCB1cCBDSS9DRCBwaXBlbGluZScsXG4gICAgICAnY29uZmlndXJlIEt1YmVybmV0ZXMgZGVwbG95bWVudCcsXG4gICAgICAnY3JlYXRlIERvY2tlciBjb250YWluZXInLFxuICAgICAgJ2FkZCBtb25pdG9yaW5nIGFsZXJ0cycsXG4gICAgICAnaW1wbGVtZW50IGF1dG8tc2NhbGluZycsXG4gICAgXSxcbiAgfSxcbl07XG5cbi8qKlxuICogRXhwZWN0ZWQgc2ltaWxhcml0eSBzY29yZSByYW5nZXNcbiAqL1xuY29uc3QgU0lNSUxBUklUWV9USFJFU0hPTERTID0ge1xuICBoaWdoOiB7IG1pbjogMC43LCBtYXg6IDEuMCB9LFxuICBtZWRpdW06IHsgbWluOiAwLjQsIG1heDogMC43IH0sXG4gIGxvdzogeyBtaW46IDAuMiwgbWF4OiAwLjQgfSxcbiAgbm9uZTogeyBtaW46IDAuMCwgbWF4OiAwLjIgfSxcbn07XG5cbi8qKlxuICogQ2hlY2sgaWYgY29tcHV0ZWQgc2ltaWxhcml0eSBtYXRjaGVzIGV4cGVjdGVkIGNhdGVnb3J5XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0NvcnJlY3RTaW1pbGFyaXR5KFxuICBleHBlY3RlZDogJ2hpZ2gnIHwgJ21lZGl1bScgfCAnbG93JyB8ICdub25lJyxcbiAgY29tcHV0ZWQ6IG51bWJlclxuKTogYm9vbGVhbiB7XG4gIGNvbnN0IHRocmVzaG9sZCA9IFNJTUlMQVJJVFlfVEhSRVNIT0xEU1tleHBlY3RlZF07XG4gIHJldHVybiBjb21wdXRlZCA+PSB0aHJlc2hvbGQubWluICYmIGNvbXB1dGVkIDw9IHRocmVzaG9sZC5tYXg7XG59XG5cbi8qKlxuICogQ2FsY3VsYXRlIE1lYW4gUmVjaXByb2NhbCBSYW5rIGZvciBzZWFyY2ggcmVzdWx0c1xuICovXG5leHBvcnQgZnVuY3Rpb24gY2FsY3VsYXRlTVJSKFxuICByYW5raW5nczogeyByZWxldmFudDogYm9vbGVhbiB9W11bXVxuKTogbnVtYmVyIHtcbiAgbGV0IHN1bVJSID0gMDtcbiAgZm9yIChjb25zdCByYW5raW5nIG9mIHJhbmtpbmdzKSB7XG4gICAgY29uc3QgZmlyc3RSZWxldmFudElkeCA9IHJhbmtpbmcuZmluZEluZGV4KHIgPT4gci5yZWxldmFudCk7XG4gICAgaWYgKGZpcnN0UmVsZXZhbnRJZHggPj0gMCkge1xuICAgICAgc3VtUlIgKz0gMSAvIChmaXJzdFJlbGV2YW50SWR4ICsgMSk7XG4gICAgfVxuICB9XG4gIHJldHVybiBzdW1SUiAvIHJhbmtpbmdzLmxlbmd0aDtcbn1cblxuLyoqXG4gKiBDYWxjdWxhdGUgTkRDRyBmb3Igc2VhcmNoIHJlc3VsdHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNhbGN1bGF0ZU5EQ0coXG4gIHJlc3VsdHM6IHsgcmVsZXZhbmNlOiBudW1iZXIgfVtdLFxuICBpZGVhbE9yZGVyOiB7IHJlbGV2YW5jZTogbnVtYmVyIH1bXVxuKTogbnVtYmVyIHtcbiAgY29uc3QgZGNnID0gcmVzdWx0cy5yZWR1Y2UoKHN1bSwgciwgaSkgPT4ge1xuICAgIHJldHVybiBzdW0gKyAoTWF0aC5wb3coMiwgci5yZWxldmFuY2UpIC0gMSkgLyBNYXRoLmxvZzIoaSArIDIpO1xuICB9LCAwKTtcblxuICBjb25zdCBpZGNnID0gaWRlYWxPcmRlci5yZWR1Y2UoKHN1bSwgciwgaSkgPT4ge1xuICAgIHJldHVybiBzdW0gKyAoTWF0aC5wb3coMiwgci5yZWxldmFuY2UpIC0gMSkgLyBNYXRoLmxvZzIoaSArIDIpO1xuICB9LCAwKTtcblxuICByZXR1cm4gaWRjZyA+IDAgPyBkY2cgLyBpZGNnIDogMDtcbn1cblxuLyoqXG4gKiBDYWxjdWxhdGUgc2lsaG91ZXR0ZSBzY29yZSBmb3IgY2x1c3RlcmluZ1xuICovXG5leHBvcnQgZnVuY3Rpb24gY2FsY3VsYXRlU2lsaG91ZXR0ZShcbiAgZW1iZWRkaW5nczogbnVtYmVyW11bXSxcbiAgbGFiZWxzOiBudW1iZXJbXVxuKTogbnVtYmVyIHtcbiAgLy8gU2ltcGxpZmllZCBzaWxob3VldHRlIGNhbGN1bGF0aW9uXG4gIGNvbnN0IG4gPSBlbWJlZGRpbmdzLmxlbmd0aDtcbiAgaWYgKG4gPCAyKSByZXR1cm4gMDtcblxuICBsZXQgdG90YWxTaWxob3VldHRlID0gMDtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IG47IGkrKykge1xuICAgIGNvbnN0IGNsdXN0ZXIgPSBsYWJlbHNbaV07XG5cbiAgICAvLyBDYWxjdWxhdGUgbWVhbiBpbnRyYS1jbHVzdGVyIGRpc3RhbmNlIChhKVxuICAgIGxldCBpbnRyYVN1bSA9IDA7XG4gICAgbGV0IGludHJhQ291bnQgPSAwO1xuICAgIGZvciAobGV0IGogPSAwOyBqIDwgbjsgaisrKSB7XG4gICAgICBpZiAoaSAhPT0gaiAmJiBsYWJlbHNbal0gPT09IGNsdXN0ZXIpIHtcbiAgICAgICAgaW50cmFTdW0gKz0gZXVjbGlkZWFuRGlzdGFuY2UoZW1iZWRkaW5nc1tpXSwgZW1iZWRkaW5nc1tqXSk7XG4gICAgICAgIGludHJhQ291bnQrKztcbiAgICAgIH1cbiAgICB9XG4gICAgY29uc3QgYSA9IGludHJhQ291bnQgPiAwID8gaW50cmFTdW0gLyBpbnRyYUNvdW50IDogMDtcblxuICAgIC8vIENhbGN1bGF0ZSBtaW4gbWVhbiBpbnRlci1jbHVzdGVyIGRpc3RhbmNlIChiKVxuICAgIGNvbnN0IG90aGVyQ2x1c3RlcnMgPSBbLi4ubmV3IFNldChsYWJlbHMpXS5maWx0ZXIoYyA9PiBjICE9PSBjbHVzdGVyKTtcbiAgICBsZXQgbWluSW50ZXJNZWFuID0gSW5maW5pdHk7XG5cbiAgICBmb3IgKGNvbnN0IG90aGVyQ2x1c3RlciBvZiBvdGhlckNsdXN0ZXJzKSB7XG4gICAgICBsZXQgaW50ZXJTdW0gPSAwO1xuICAgICAgbGV0IGludGVyQ291bnQgPSAwO1xuICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBuOyBqKyspIHtcbiAgICAgICAgaWYgKGxhYmVsc1tqXSA9PT0gb3RoZXJDbHVzdGVyKSB7XG4gICAgICAgICAgaW50ZXJTdW0gKz0gZXVjbGlkZWFuRGlzdGFuY2UoZW1iZWRkaW5nc1tpXSwgZW1iZWRkaW5nc1tqXSk7XG4gICAgICAgICAgaW50ZXJDb3VudCsrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoaW50ZXJDb3VudCA+IDApIHtcbiAgICAgICAgbWluSW50ZXJNZWFuID0gTWF0aC5taW4obWluSW50ZXJNZWFuLCBpbnRlclN1bSAvIGludGVyQ291bnQpO1xuICAgICAgfVxuICAgIH1cbiAgICBjb25zdCBiID0gbWluSW50ZXJNZWFuID09PSBJbmZpbml0eSA/IDAgOiBtaW5JbnRlck1lYW47XG5cbiAgICAvLyBTaWxob3VldHRlIGZvciB0aGlzIHBvaW50XG4gICAgY29uc3QgcyA9IE1hdGgubWF4KGEsIGIpID4gMCA/IChiIC0gYSkgLyBNYXRoLm1heChhLCBiKSA6IDA7XG4gICAgdG90YWxTaWxob3VldHRlICs9IHM7XG4gIH1cblxuICByZXR1cm4gdG90YWxTaWxob3VldHRlIC8gbjtcbn1cblxuZnVuY3Rpb24gZXVjbGlkZWFuRGlzdGFuY2UoYTogbnVtYmVyW10sIGI6IG51bWJlcltdKTogbnVtYmVyIHtcbiAgbGV0IHN1bSA9IDA7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYS5sZW5ndGg7IGkrKykge1xuICAgIHN1bSArPSBNYXRoLnBvdyhhW2ldIC0gYltpXSwgMik7XG4gIH1cbiAgcmV0dXJuIE1hdGguc3FydChzdW0pO1xufVxuXG4vKipcbiAqIFJ1biB0aGUgZW1iZWRkaW5nIGJlbmNobWFya1xuICovXG5leHBvcnQgZnVuY3Rpb24gcnVuRW1iZWRkaW5nQmVuY2htYXJrKFxuICBlbWJlZGRlcjogKHRleHQ6IHN0cmluZykgPT4gbnVtYmVyW10sXG4gIHNpbWlsYXJpdHlGbjogKGE6IG51bWJlcltdLCBiOiBudW1iZXJbXSkgPT4gbnVtYmVyXG4pOiBFbWJlZGRpbmdCZW5jaG1hcmtSZXN1bHRzIHtcbiAgY29uc3Qgc2ltaWxhcml0eVJlc3VsdHM6IEVtYmVkZGluZ1Jlc3VsdFtdID0gW107XG4gIGNvbnN0IGxhdGVuY2llczogbnVtYmVyW10gPSBbXTtcblxuICAvLyBUZXN0IHNpbWlsYXJpdHkgcGFpcnNcbiAgZm9yIChjb25zdCBwYWlyIG9mIFNJTUlMQVJJVFlfVEVTVF9QQUlSUykge1xuICAgIGNvbnN0IHN0YXJ0ID0gcGVyZm9ybWFuY2Uubm93KCk7XG4gICAgY29uc3QgZW1iMSA9IGVtYmVkZGVyKHBhaXIudGV4dDEpO1xuICAgIGNvbnN0IGVtYjIgPSBlbWJlZGRlcihwYWlyLnRleHQyKTtcbiAgICBjb25zdCBzY29yZSA9IHNpbWlsYXJpdHlGbihlbWIxLCBlbWIyKTtcbiAgICBjb25zdCBsYXRlbmN5TXMgPSBwZXJmb3JtYW5jZS5ub3coKSAtIHN0YXJ0O1xuXG4gICAgbGF0ZW5jaWVzLnB1c2gobGF0ZW5jeU1zKTtcblxuICAgIHNpbWlsYXJpdHlSZXN1bHRzLnB1c2goe1xuICAgICAgcGFpcklkOiBwYWlyLmlkLFxuICAgICAgZXhwZWN0ZWRTaW1pbGFyaXR5OiBwYWlyLnNpbWlsYXJpdHksXG4gICAgICBjb21wdXRlZFNjb3JlOiBzY29yZSxcbiAgICAgIGNvcnJlY3Q6IGlzQ29ycmVjdFNpbWlsYXJpdHkocGFpci5zaW1pbGFyaXR5LCBzY29yZSksXG4gICAgICBsYXRlbmN5TXMsXG4gICAgfSk7XG4gIH1cblxuICAvLyBDYWxjdWxhdGUgc2ltaWxhcml0eSBhY2N1cmFjeVxuICBjb25zdCBjb3JyZWN0U2ltaWxhcml0eSA9IHNpbWlsYXJpdHlSZXN1bHRzLmZpbHRlcihyID0+IHIuY29ycmVjdCkubGVuZ3RoO1xuICBjb25zdCBzaW1pbGFyaXR5QWNjdXJhY3kgPSBjb3JyZWN0U2ltaWxhcml0eSAvIHNpbWlsYXJpdHlSZXN1bHRzLmxlbmd0aDtcblxuICAvLyBBY2N1cmFjeSBieSBjYXRlZ29yeVxuICBjb25zdCBjYXRlZ29yaWVzID0gWy4uLm5ldyBTZXQoU0lNSUxBUklUWV9URVNUX1BBSVJTLm1hcChwID0+IHAuY2F0ZWdvcnkpKV07XG4gIGNvbnN0IHNpbWlsYXJpdHlCeUNhdGVnb3J5OiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+ID0ge307XG4gIGZvciAoY29uc3QgY2F0IG9mIGNhdGVnb3JpZXMpIHtcbiAgICBjb25zdCBjYXRSZXN1bHRzID0gc2ltaWxhcml0eVJlc3VsdHMuZmlsdGVyKFxuICAgICAgKHIsIGkpID0+IFNJTUlMQVJJVFlfVEVTVF9QQUlSU1tpXS5jYXRlZ29yeSA9PT0gY2F0XG4gICAgKTtcbiAgICBzaW1pbGFyaXR5QnlDYXRlZ29yeVtjYXRdID0gY2F0UmVzdWx0cy5maWx0ZXIociA9PiByLmNvcnJlY3QpLmxlbmd0aCAvIGNhdFJlc3VsdHMubGVuZ3RoO1xuICB9XG5cbiAgLy8gVGVzdCBzZWFyY2ggcXVhbGl0eSAoTVJSIGFuZCBORENHKVxuICBjb25zdCBzZWFyY2hSYW5raW5nczogeyByZWxldmFudDogYm9vbGVhbiB9W11bXSA9IFtdO1xuICBsZXQgdG90YWxORENHID0gMDtcblxuICBmb3IgKGNvbnN0IHRlc3RDYXNlIG9mIFNFQVJDSF9URVNUX0NBU0VTKSB7XG4gICAgY29uc3QgcXVlcnlFbWIgPSBlbWJlZGRlcih0ZXN0Q2FzZS5xdWVyeSk7XG4gICAgY29uc3QgZG9jU2NvcmVzID0gdGVzdENhc2UuZG9jdW1lbnRzLm1hcChkb2MgPT4gKHtcbiAgICAgIC4uLmRvYyxcbiAgICAgIHNjb3JlOiBzaW1pbGFyaXR5Rm4ocXVlcnlFbWIsIGVtYmVkZGVyKGRvYy50ZXh0KSksXG4gICAgfSkpO1xuXG4gICAgLy8gU29ydCBieSBjb21wdXRlZCBzY29yZVxuICAgIGNvbnN0IHNvcnRlZCA9IFsuLi5kb2NTY29yZXNdLnNvcnQoKGEsIGIpID0+IGIuc2NvcmUgLSBhLnNjb3JlKTtcblxuICAgIC8vIEZvciBNUlJcbiAgICBzZWFyY2hSYW5raW5ncy5wdXNoKHNvcnRlZC5tYXAoZCA9PiAoeyByZWxldmFudDogZC5yZWxldmFuY2UgPj0gMiB9KSkpO1xuXG4gICAgLy8gRm9yIE5EQ0dcbiAgICBjb25zdCBpZGVhbE9yZGVyID0gWy4uLnRlc3RDYXNlLmRvY3VtZW50c10uc29ydCgoYSwgYikgPT4gYi5yZWxldmFuY2UgLSBhLnJlbGV2YW5jZSk7XG4gICAgdG90YWxORENHICs9IGNhbGN1bGF0ZU5EQ0coc29ydGVkLCBpZGVhbE9yZGVyKTtcbiAgfVxuXG4gIGNvbnN0IHNlYXJjaE1SUiA9IGNhbGN1bGF0ZU1SUihzZWFyY2hSYW5raW5ncyk7XG4gIGNvbnN0IHNlYXJjaE5EQ0cgPSB0b3RhbE5EQ0cgLyBTRUFSQ0hfVEVTVF9DQVNFUy5sZW5ndGg7XG5cbiAgLy8gVGVzdCBjbHVzdGVyaW5nXG4gIGNvbnN0IGFsbENsdXN0ZXJJdGVtczogeyB0ZXh0OiBzdHJpbmc7IGNsdXN0ZXI6IG51bWJlciB9W10gPSBbXTtcbiAgQ0xVU1RFUl9URVNUX0NBU0VTLmZvckVhY2goKHRjLCBjbHVzdGVySWR4KSA9PiB7XG4gICAgdGMuaXRlbXMuZm9yRWFjaChpdGVtID0+IHtcbiAgICAgIGFsbENsdXN0ZXJJdGVtcy5wdXNoKHsgdGV4dDogaXRlbSwgY2x1c3RlcjogY2x1c3RlcklkeCB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgY29uc3QgY2x1c3RlckVtYmVkZGluZ3MgPSBhbGxDbHVzdGVySXRlbXMubWFwKGl0ZW0gPT4gZW1iZWRkZXIoaXRlbS50ZXh0KSk7XG4gIGNvbnN0IGNsdXN0ZXJMYWJlbHMgPSBhbGxDbHVzdGVySXRlbXMubWFwKGl0ZW0gPT4gaXRlbS5jbHVzdGVyKTtcbiAgY29uc3Qgc2lsaG91ZXR0ZVNjb3JlID0gY2FsY3VsYXRlU2lsaG91ZXR0ZShjbHVzdGVyRW1iZWRkaW5ncywgY2x1c3RlckxhYmVscyk7XG5cbiAgLy8gQ2FsY3VsYXRlIGNsdXN0ZXIgcHVyaXR5IChob3cgd2VsbCBpdGVtcyBzdGF5IGluIHRoZWlyIGV4cGVjdGVkIGNsdXN0ZXIpXG4gIC8vIFVzaW5nIHNpbXBsZSBuZWFyZXN0LW5laWdoYm9yIGNsYXNzaWZpY2F0aW9uXG4gIGxldCBjb3JyZWN0Q2x1c3RlciA9IDA7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgY2x1c3RlckVtYmVkZGluZ3MubGVuZ3RoOyBpKyspIHtcbiAgICBsZXQgbmVhcmVzdElkeCA9IC0xO1xuICAgIGxldCBuZWFyZXN0RGlzdCA9IEluZmluaXR5O1xuICAgIGZvciAobGV0IGogPSAwOyBqIDwgY2x1c3RlckVtYmVkZGluZ3MubGVuZ3RoOyBqKyspIHtcbiAgICAgIGlmIChpICE9PSBqKSB7XG4gICAgICAgIGNvbnN0IGRpc3QgPSBldWNsaWRlYW5EaXN0YW5jZShjbHVzdGVyRW1iZWRkaW5nc1tpXSwgY2x1c3RlckVtYmVkZGluZ3Nbal0pO1xuICAgICAgICBpZiAoZGlzdCA8IG5lYXJlc3REaXN0KSB7XG4gICAgICAgICAgbmVhcmVzdERpc3QgPSBkaXN0O1xuICAgICAgICAgIG5lYXJlc3RJZHggPSBqO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChuZWFyZXN0SWR4ID49IDAgJiYgY2x1c3RlckxhYmVsc1tuZWFyZXN0SWR4XSA9PT0gY2x1c3RlckxhYmVsc1tpXSkge1xuICAgICAgY29ycmVjdENsdXN0ZXIrKztcbiAgICB9XG4gIH1cbiAgY29uc3QgY2x1c3RlclB1cml0eSA9IGNvcnJlY3RDbHVzdGVyIC8gY2x1c3RlckVtYmVkZGluZ3MubGVuZ3RoO1xuXG4gIHJldHVybiB7XG4gICAgc2ltaWxhcml0eUFjY3VyYWN5LFxuICAgIHNpbWlsYXJpdHlCeUNhdGVnb3J5LFxuICAgIGF2Z1NpbWlsYXJpdHlMYXRlbmN5TXM6IGxhdGVuY2llcy5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKSAvIGxhdGVuY2llcy5sZW5ndGgsXG4gICAgY2x1c3RlclB1cml0eSxcbiAgICBzaWxob3VldHRlU2NvcmUsXG4gICAgc2VhcmNoTVJSLFxuICAgIHNlYXJjaE5EQ0csXG4gICAgc2ltaWxhcml0eVJlc3VsdHMsXG4gICAgdG90YWxQYWlyczogc2ltaWxhcml0eVJlc3VsdHMubGVuZ3RoLFxuICB9O1xufVxuXG4vKipcbiAqIEZvcm1hdCBlbWJlZGRpbmcgYmVuY2htYXJrIHJlc3VsdHMgZm9yIGRpc3BsYXlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdEVtYmVkZGluZ1Jlc3VsdHMocmVzdWx0czogRW1iZWRkaW5nQmVuY2htYXJrUmVzdWx0cyk6IHN0cmluZyB7XG4gIGNvbnN0IGxpbmVzOiBzdHJpbmdbXSA9IFtdO1xuXG4gIGxpbmVzLnB1c2goJycpO1xuICBsaW5lcy5wdXNoKCfilZTilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZcnKTtcbiAgbGluZXMucHVzaCgn4pWRICAgICAgICAgICAgIEVNQkVERElORyBCRU5DSE1BUksgUkVTVUxUUyAgICAgICAgICAgICAgICAgICAgICDilZEnKTtcbiAgbGluZXMucHVzaCgn4pWg4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWjJyk7XG4gIGxpbmVzLnB1c2goYOKVkSAgU2ltaWxhcml0eSBEZXRlY3Rpb246ICR7KHJlc3VsdHMuc2ltaWxhcml0eUFjY3VyYWN5ICogMTAwKS50b0ZpeGVkKDEpfSVgLnBhZEVuZCg2MykgKyAn4pWRJyk7XG4gIGxpbmVzLnB1c2goJ+KVoOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVoycpO1xuICBsaW5lcy5wdXNoKCfilZEgIEJ5IENhdGVnb3J5OiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKVkScpO1xuXG4gIGZvciAoY29uc3QgW2NhdCwgYWNjXSBvZiBPYmplY3QuZW50cmllcyhyZXN1bHRzLnNpbWlsYXJpdHlCeUNhdGVnb3J5KS5zb3J0KChhLCBiKSA9PiBiWzFdIC0gYVsxXSkpIHtcbiAgICBjb25zdCBiYXIgPSAn4paIJy5yZXBlYXQoTWF0aC5mbG9vcihhY2MgKiAyMCkpICsgJ+KWkScucmVwZWF0KDIwIC0gTWF0aC5mbG9vcihhY2MgKiAyMCkpO1xuICAgIGxpbmVzLnB1c2goYOKVkSAgICAke2NhdC5wYWRFbmQoMTgpfSBbJHtiYXJ9XSAkeyhhY2MgKiAxMDApLnRvRml4ZWQoMCkucGFkU3RhcnQoMyl9JSAg4pWRYCk7XG4gIH1cblxuICBsaW5lcy5wdXNoKCfilaDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilaMnKTtcbiAgbGluZXMucHVzaCgn4pWRICBDbHVzdGVyaW5nIFF1YWxpdHk6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDilZEnKTtcbiAgbGluZXMucHVzaChg4pWRICAgIENsdXN0ZXIgUHVyaXR5OiAgICAkeyhyZXN1bHRzLmNsdXN0ZXJQdXJpdHkgKiAxMDApLnRvRml4ZWQoMSl9JWAucGFkRW5kKDYzKSArICfilZEnKTtcbiAgbGluZXMucHVzaChg4pWRICAgIFNpbGhvdWV0dGUgU2NvcmU6ICAke3Jlc3VsdHMuc2lsaG91ZXR0ZVNjb3JlLnRvRml4ZWQoMyl9YC5wYWRFbmQoNjMpICsgJ+KVkScpO1xuICBsaW5lcy5wdXNoKCfilaDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilaMnKTtcbiAgbGluZXMucHVzaCgn4pWRICBTZWFyY2ggUXVhbGl0eTogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDilZEnKTtcbiAgbGluZXMucHVzaChg4pWRICAgIE1SUiAoTWVhbiBSZWNpcHJvY2FsIFJhbmspOiAgJHtyZXN1bHRzLnNlYXJjaE1SUi50b0ZpeGVkKDMpfWAucGFkRW5kKDYzKSArICfilZEnKTtcbiAgbGluZXMucHVzaChg4pWRICAgIE5EQ0c6ICAgICAgICAgICAgICAgICAgICAgICAgJHtyZXN1bHRzLnNlYXJjaE5EQ0cudG9GaXhlZCgzKX1gLnBhZEVuZCg2MykgKyAn4pWRJyk7XG4gIGxpbmVzLnB1c2goJ+KVoOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVoycpO1xuICBsaW5lcy5wdXNoKGDilZEgIEF2ZyBMYXRlbmN5OiAke3Jlc3VsdHMuYXZnU2ltaWxhcml0eUxhdGVuY3lNcy50b0ZpeGVkKDIpfW1zIHBlciBwYWlyYC5wYWRFbmQoNjMpICsgJ+KVkScpO1xuICBsaW5lcy5wdXNoKCfilZrilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZ0nKTtcblxuICAvLyBRdWFsaXR5IGFzc2Vzc21lbnRcbiAgbGluZXMucHVzaCgnJyk7XG4gIGxpbmVzLnB1c2goJ1F1YWxpdHkgQXNzZXNzbWVudDonKTtcblxuICBpZiAocmVzdWx0cy5zaW1pbGFyaXR5QWNjdXJhY3kgPj0gMC44KSB7XG4gICAgbGluZXMucHVzaCgnICDinJMgU2ltaWxhcml0eSBkZXRlY3Rpb246IEVYQ0VMTEVOVCAo4omlODAlKScpO1xuICB9IGVsc2UgaWYgKHJlc3VsdHMuc2ltaWxhcml0eUFjY3VyYWN5ID49IDAuNikge1xuICAgIGxpbmVzLnB1c2goJyAgfiBTaW1pbGFyaXR5IGRldGVjdGlvbjogR09PRCAoNjAtODAlKScpO1xuICB9IGVsc2Uge1xuICAgIGxpbmVzLnB1c2goJyAg4pyXIFNpbWlsYXJpdHkgZGV0ZWN0aW9uOiBORUVEUyBJTVBST1ZFTUVOVCAoPDYwJSknKTtcbiAgfVxuXG4gIGlmIChyZXN1bHRzLnNlYXJjaE1SUiA+PSAwLjgpIHtcbiAgICBsaW5lcy5wdXNoKCcgIOKckyBTZWFyY2ggcXVhbGl0eSAoTVJSKTogRVhDRUxMRU5UICjiiaUwLjgpJyk7XG4gIH0gZWxzZSBpZiAocmVzdWx0cy5zZWFyY2hNUlIgPj0gMC41KSB7XG4gICAgbGluZXMucHVzaCgnICB+IFNlYXJjaCBxdWFsaXR5IChNUlIpOiBBQ0NFUFRBQkxFICgwLjUtMC44KScpO1xuICB9IGVsc2Uge1xuICAgIGxpbmVzLnB1c2goJyAg4pyXIFNlYXJjaCBxdWFsaXR5IChNUlIpOiBORUVEUyBJTVBST1ZFTUVOVCAoPDAuNSknKTtcbiAgfVxuXG4gIGlmIChyZXN1bHRzLmNsdXN0ZXJQdXJpdHkgPj0gMC44KSB7XG4gICAgbGluZXMucHVzaCgnICDinJMgQ2x1c3RlcmluZzogRVhDRUxMRU5UICjiiaU4MCUgcHVyaXR5KScpO1xuICB9IGVsc2UgaWYgKHJlc3VsdHMuY2x1c3RlclB1cml0eSA+PSAwLjYpIHtcbiAgICBsaW5lcy5wdXNoKCcgIH4gQ2x1c3RlcmluZzogQUNDRVBUQUJMRSAoNjAtODAlIHB1cml0eSknKTtcbiAgfSBlbHNlIHtcbiAgICBsaW5lcy5wdXNoKCcgIOKclyBDbHVzdGVyaW5nOiBORUVEUyBJTVBST1ZFTUVOVCAoPDYwJSBwdXJpdHkpJyk7XG4gIH1cblxuICByZXR1cm4gbGluZXMuam9pbignXFxuJyk7XG59XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgU0lNSUxBUklUWV9URVNUX1BBSVJTLFxuICBTRUFSQ0hfVEVTVF9DQVNFUyxcbiAgQ0xVU1RFUl9URVNUX0NBU0VTLFxuICBydW5FbWJlZGRpbmdCZW5jaG1hcmssXG4gIGZvcm1hdEVtYmVkZGluZ1Jlc3VsdHMsXG4gIGlzQ29ycmVjdFNpbWlsYXJpdHksXG4gIGNhbGN1bGF0ZU1SUixcbiAgY2FsY3VsYXRlTkRDRyxcbn07XG4iXX0=
|