@sochdb/sochdb 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +220 -33
- package/_bin/aarch64-apple-darwin/libsochdb_storage.dylib +0 -0
- package/_bin/aarch64-apple-darwin/sochdb-bulk +0 -0
- package/_bin/aarch64-apple-darwin/sochdb-grpc-server +0 -0
- package/_bin/aarch64-apple-darwin/sochdb-server +0 -0
- package/_bin/x86_64-pc-windows-msvc/sochdb-bulk.exe +0 -0
- package/_bin/x86_64-pc-windows-msvc/sochdb-grpc-server.exe +0 -0
- package/_bin/x86_64-pc-windows-msvc/sochdb_storage.dll +0 -0
- package/_bin/x86_64-unknown-linux-gnu/libsochdb_storage.so +0 -0
- package/_bin/x86_64-unknown-linux-gnu/sochdb-bulk +0 -0
- package/_bin/x86_64-unknown-linux-gnu/sochdb-grpc-server +0 -0
- package/_bin/x86_64-unknown-linux-gnu/sochdb-server +0 -0
- package/bin/sochdb-bulk.js +1 -1
- package/bin/sochdb-grpc-server.js +1 -1
- package/bin/sochdb-server.js +1 -1
- package/dist/cjs/context-builder.js +280 -0
- package/dist/cjs/database.js +2 -2
- package/dist/cjs/embedded/database.js +2 -2
- package/dist/cjs/errors.js +99 -7
- package/dist/cjs/index.js +40 -3
- package/dist/cjs/ipc-client.js +2 -2
- package/dist/cjs/memory/consolidation.js +202 -0
- package/dist/cjs/memory/extraction.js +181 -0
- package/dist/cjs/memory/index.js +26 -0
- package/dist/cjs/memory/retrieval.js +232 -0
- package/dist/cjs/memory/types.js +69 -0
- package/dist/cjs/namespace.js +255 -0
- package/dist/cjs/queue.js +289 -0
- package/dist/cjs/semantic-cache.js +220 -0
- package/dist/esm/context-builder.js +280 -0
- package/dist/esm/database.js +2 -2
- package/dist/esm/embedded/database.js +2 -2
- package/dist/esm/errors.js +107 -7
- package/dist/esm/index.js +40 -3
- package/dist/esm/ipc-client.js +2 -2
- package/dist/esm/memory/consolidation.js +206 -0
- package/dist/esm/memory/extraction.js +185 -0
- package/dist/esm/memory/index.js +26 -0
- package/dist/esm/memory/retrieval.js +243 -0
- package/dist/esm/memory/types.js +72 -0
- package/dist/esm/namespace.js +262 -0
- package/dist/esm/queue.js +291 -0
- package/dist/esm/semantic-cache.js +223 -0
- package/dist/types/context-builder.d.ts +97 -0
- package/dist/types/context-builder.d.ts.map +1 -0
- package/dist/types/database.d.ts +1 -1
- package/dist/types/embedded/database.d.ts +1 -1
- package/dist/types/errors.d.ts +57 -1
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/index.d.ts +12 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/ipc-client.d.ts +1 -1
- package/dist/types/memory/consolidation.d.ts +66 -0
- package/dist/types/memory/consolidation.d.ts.map +1 -0
- package/dist/types/memory/extraction.d.ts +82 -0
- package/dist/types/memory/extraction.d.ts.map +1 -0
- package/dist/types/memory/index.d.ts +10 -0
- package/dist/types/memory/index.d.ts.map +1 -0
- package/dist/types/memory/retrieval.d.ts +46 -0
- package/dist/types/memory/retrieval.d.ts.map +1 -0
- package/dist/types/memory/types.d.ts +147 -0
- package/dist/types/memory/types.d.ts.map +1 -0
- package/dist/types/namespace.d.ts +129 -0
- package/dist/types/namespace.d.ts.map +1 -0
- package/dist/types/queue.d.ts +120 -0
- package/dist/types/queue.d.ts.map +1 -0
- package/dist/types/semantic-cache.d.ts +84 -0
- package/dist/types/semantic-cache.d.ts.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,202 @@
|
|
|
1
|
-
# SochDB Node.js SDK
|
|
1
|
+
# SochDB Node.js SDK
|
|
2
2
|
|
|
3
3
|
**Dual-mode architecture: Embedded (FFI) + Server (gRPC/IPC)**
|
|
4
4
|
Choose the deployment mode that fits your needs.
|
|
5
5
|
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
### Memory System - LLM-Native Memory for AI Agents
|
|
9
|
+
Complete memory system with extraction, consolidation, and hybrid retrieval:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import {
|
|
13
|
+
EmbeddedDatabase,
|
|
14
|
+
ExtractionPipeline,
|
|
15
|
+
Consolidator,
|
|
16
|
+
HybridRetriever,
|
|
17
|
+
AllowedSet,
|
|
18
|
+
} from '@sochdb/sochdb';
|
|
19
|
+
|
|
20
|
+
const db = await EmbeddedDatabase.open('./memory_db');
|
|
21
|
+
|
|
22
|
+
// Extract entities and relations from text
|
|
23
|
+
const pipeline = ExtractionPipeline.fromDatabase(db, 'user_123', {
|
|
24
|
+
entityTypes: ['person', 'organization', 'location'],
|
|
25
|
+
minConfidence: 0.7,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const result = await pipeline.extractAndCommit(
|
|
29
|
+
'Alice works at Acme Corp',
|
|
30
|
+
myLLMExtractor // Your LLM integration
|
|
31
|
+
);
|
|
32
|
+
console.log(`Extracted ${result.entities.length} entities`);
|
|
33
|
+
|
|
34
|
+
// Consolidate facts with event sourcing
|
|
35
|
+
const consolidator = Consolidator.fromDatabase(db, 'user_123');
|
|
36
|
+
await consolidator.add({
|
|
37
|
+
fact: { subject: 'Alice', predicate: 'lives_in', object: 'SF' },
|
|
38
|
+
source: 'conversation_1',
|
|
39
|
+
confidence: 0.9,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const updated = await consolidator.consolidate();
|
|
43
|
+
const facts = await consolidator.getCanonicalFacts();
|
|
44
|
+
|
|
45
|
+
// Hybrid retrieval with RRF fusion
|
|
46
|
+
const retriever = HybridRetriever.fromDatabase(db, 'user_123', 'documents');
|
|
47
|
+
await retriever.indexDocuments(docs);
|
|
48
|
+
|
|
49
|
+
const results = await retriever.retrieve(
|
|
50
|
+
'machine learning papers',
|
|
51
|
+
queryEmbedding,
|
|
52
|
+
AllowedSet.fromNamespace('user_123')
|
|
53
|
+
);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**[→ See Full Example](./examples/memory-system-example.ts)**
|
|
57
|
+
|
|
58
|
+
**Key Features:**
|
|
59
|
+
- ✅ Extraction Pipeline: Compile LLM outputs into typed facts
|
|
60
|
+
- ✅ Event-Sourced Consolidation: Append-only with temporal updates
|
|
61
|
+
- ✅ Hybrid Retrieval: RRF fusion of vector + keyword search
|
|
62
|
+
- ✅ Namespace Isolation: Multi-tenant security with pre-filtering
|
|
63
|
+
- ✅ Schema Validation: Type checking and confidence thresholds
|
|
64
|
+
|
|
65
|
+
### Semantic Cache - LLM Response Caching
|
|
66
|
+
Vector similarity-based caching for LLM responses to reduce costs and latency:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { EmbeddedDatabase, SemanticCache } from '@sochdb/sochdb';
|
|
70
|
+
|
|
71
|
+
const db = await EmbeddedDatabase.open('./mydb');
|
|
72
|
+
const cache = new SemanticCache(db, 'llm_responses');
|
|
73
|
+
|
|
74
|
+
// Store LLM response with embedding
|
|
75
|
+
await cache.put(
|
|
76
|
+
'What is machine learning?',
|
|
77
|
+
'Machine learning is a subset of AI...',
|
|
78
|
+
embedding, // 384-dim vector
|
|
79
|
+
3600, // TTL in seconds
|
|
80
|
+
{ model: 'gpt-4', tokens: 150 }
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
// Check cache before calling LLM
|
|
84
|
+
const hit = await cache.get(queryEmbedding, 0.85);
|
|
85
|
+
if (hit) {
|
|
86
|
+
console.log(`Cache HIT! Similarity: ${hit.score.toFixed(4)}`);
|
|
87
|
+
console.log(`Response: ${hit.value}`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Get statistics
|
|
91
|
+
const stats = await cache.stats();
|
|
92
|
+
console.log(`Hit rate: ${(stats.hitRate * 100).toFixed(1)}%`);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**[→ See Full Example](./examples/semantic-cache-example.ts)**
|
|
96
|
+
|
|
97
|
+
**Key Benefits:**
|
|
98
|
+
- ✅ Cosine similarity matching (0-1 threshold)
|
|
99
|
+
- ✅ TTL-based expiration
|
|
100
|
+
- ✅ Hit/miss statistics tracking
|
|
101
|
+
- ✅ Memory usage monitoring
|
|
102
|
+
- ✅ Automatic expired entry purging
|
|
103
|
+
|
|
104
|
+
### Context Query Builder - Token-Aware LLM Context
|
|
105
|
+
Assemble LLM context with priority-based truncation and token budgeting:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { ContextQueryBuilder, ContextOutputFormat, TruncationStrategy } from '@sochdb/sochdb';
|
|
109
|
+
|
|
110
|
+
const builder = new ContextQueryBuilder()
|
|
111
|
+
.withBudget(4096) // Token limit
|
|
112
|
+
.setFormat(ContextOutputFormat.TOON)
|
|
113
|
+
.setTruncation(TruncationStrategy.TAIL_DROP);
|
|
114
|
+
|
|
115
|
+
builder
|
|
116
|
+
.literal('SYSTEM', 0, 'You are a helpful AI assistant.')
|
|
117
|
+
.literal('USER_PROFILE', 1, 'User: Alice, Role: Engineer')
|
|
118
|
+
.literal('HISTORY', 2, 'Recent conversation context...')
|
|
119
|
+
.literal('KNOWLEDGE', 3, 'Retrieved documents...');
|
|
120
|
+
|
|
121
|
+
const result = builder.execute();
|
|
122
|
+
console.log(`Tokens: ${result.tokenCount}/${4096}`);
|
|
123
|
+
console.log(`Context:\n${result.text}`);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**[→ See Full Example](./examples/context-builder-example.ts)**
|
|
127
|
+
|
|
128
|
+
**Key Benefits:**
|
|
129
|
+
- ✅ Priority-based section ordering (lower = higher priority)
|
|
130
|
+
- ✅ Token budget enforcement
|
|
131
|
+
- ✅ Multiple truncation strategies (tail drop, head drop, proportional)
|
|
132
|
+
- ✅ Multiple output formats (TOON, JSON, Markdown)
|
|
133
|
+
- ✅ Token count estimation
|
|
134
|
+
|
|
135
|
+
### Namespace API - Multi-Tenant Isolation
|
|
136
|
+
First-class namespace handles for secure multi-tenancy and data isolation:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
import { Database, Namespace, Collection, DistanceMetric } from '@sochdb/sochdb';
|
|
140
|
+
|
|
141
|
+
const db = await Database.open('./mydb');
|
|
142
|
+
|
|
143
|
+
// Create isolated namespace for each tenant
|
|
144
|
+
const namespace = new Namespace(db, 'tenant_acme', {
|
|
145
|
+
name: 'tenant_acme',
|
|
146
|
+
displayName: 'ACME Corporation',
|
|
147
|
+
labels: { plan: 'enterprise', region: 'us-west' }
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Create vector collection
|
|
151
|
+
const collection = await namespace.createCollection({
|
|
152
|
+
name: 'documents',
|
|
153
|
+
dimension: 384,
|
|
154
|
+
metric: DistanceMetric.Cosine,
|
|
155
|
+
indexed: true
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Insert and search vectors
|
|
159
|
+
await collection.insert([1.0, 2.0, ...], { title: 'Doc 1' });
|
|
160
|
+
const results = await collection.search({ queryVector: [...], k: 10 });
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**[→ See Full Example](./examples/namespace-example.ts)**
|
|
164
|
+
|
|
165
|
+
### Priority Queue API - Task Processing
|
|
166
|
+
Efficient priority queue with ordered-key storage (no O(N) blob rewrites):
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { Database, PriorityQueue } from '@sochdb/sochdb';
|
|
170
|
+
|
|
171
|
+
const db = await Database.open('./queue_db');
|
|
172
|
+
const queue = PriorityQueue.fromDatabase(db, 'tasks');
|
|
173
|
+
|
|
174
|
+
// Enqueue with priority (lower = higher urgency)
|
|
175
|
+
await queue.enqueue(1, Buffer.from('urgent task'), { type: 'payment' });
|
|
176
|
+
|
|
177
|
+
// Worker processes tasks
|
|
178
|
+
const task = await queue.dequeue('worker-1');
|
|
179
|
+
if (task) {
|
|
180
|
+
// Process task...
|
|
181
|
+
await queue.ack(task.taskId);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Get statistics
|
|
185
|
+
const stats = await queue.stats();
|
|
186
|
+
console.log(`Pending: ${stats.pending}, Completed: ${stats.completed}`);
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**[→ See Full Example](./examples/queue-example.ts)**
|
|
190
|
+
|
|
191
|
+
**Key Benefits:**
|
|
192
|
+
- ✅ O(log N) enqueue/dequeue with ordered scans
|
|
193
|
+
- ✅ Atomic claim protocol for concurrent workers
|
|
194
|
+
- ✅ Visibility timeout for crash recovery
|
|
195
|
+
- ✅ Dead letter queue for failed tasks
|
|
196
|
+
- ✅ Multiple queues per database
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
6
200
|
## Architecture: Flexible Deployment
|
|
7
201
|
|
|
8
202
|
```
|
|
@@ -67,40 +261,33 @@ npm install
|
|
|
67
261
|
|
|
68
262
|
1. [Quick Start](#1-quick-start)
|
|
69
263
|
2. [Installation](#2-installation)
|
|
70
|
-
3. [
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
264
|
+
3. [Features](#3-features)
|
|
265
|
+
- [Namespace API](#namespace-api---multi-tenant-isolation)
|
|
266
|
+
- [Priority Queue API](#priority-queue-api---task-processing)
|
|
267
|
+
4. [Architecture Overview](#4-architecture-overview)
|
|
268
|
+
5. [Core Key-Value Operations](#5-core-key-value-operations)
|
|
269
|
+
6. [Transactions (ACID with SSI)](#6-transactions-acid-with-ssi)
|
|
270
|
+
7. [Query Builder](#7-query-builder)
|
|
271
|
+
8. [Prefix Scanning](#8-prefix-scanning)
|
|
272
|
+
9. [SQL Operations](#9-sql-operations)
|
|
273
|
+
10. [Table Management & Index Policies](#10-table-management--index-policies)
|
|
274
|
+
11. [Namespaces & Collections](#11-namespaces--collections)
|
|
275
|
+
12. [Priority Queues](#12-priority-queues)
|
|
276
|
+
13. [Vector Search](#13-vector-search)
|
|
277
|
+
14. [Hybrid Search (Vector + BM25)](#14-hybrid-search-vector--bm25)
|
|
278
|
+
15. [Graph Operations](#15-graph-operations)
|
|
279
|
+
16. [Temporal Graph (Time-Travel)](#16-temporal-graph-time-travel)
|
|
280
|
+
17. [Semantic Cache](#17-semantic-cache)
|
|
281
|
+
18. [Context Query Builder (LLM Optimization)](#18-context-query-builder-llm-optimization)
|
|
282
|
+
19. [Atomic Multi-Index Writes](#19-atomic-multi-index-writes)
|
|
283
|
+
20. [Recovery & WAL Management](#20-recovery--wal-management)
|
|
284
|
+
21. [Checkpoints & Snapshots](#21-checkpoints--snapshots)
|
|
285
|
+
22. [Compression & Storage](#22-compression--storage)
|
|
286
|
+
23. [Statistics & Monitoring](#23-statistics--monitoring)
|
|
91
287
|
24. [Server Mode (gRPC Client)](#24-server-mode-grpc-client)
|
|
92
288
|
25. [IPC Client (Unix Sockets)](#25-ipc-client-unix-sockets)
|
|
93
|
-
26. [
|
|
94
|
-
27. [
|
|
95
|
-
28. [Data Formats (TOON/JSON/Columnar)](#28-data-formats-toonjsoncolumnar)
|
|
96
|
-
29. [Policy Service](#29-policy-service)
|
|
97
|
-
30. [MCP (Model Context Protocol)](#30-mcp-model-context-protocol)
|
|
98
|
-
31. [Configuration Reference](#31-configuration-reference)
|
|
99
|
-
32. [Error Handling](#32-error-handling)
|
|
100
|
-
33. [Async Support](#33-async-support)
|
|
101
|
-
34. [Building & Development](#34-building--development)
|
|
102
|
-
35. [Complete Examples](#35-complete-examples)
|
|
103
|
-
36. [Migration Guide](#36-migration-guide)
|
|
289
|
+
26. [Error Handling](#26-error-handling)
|
|
290
|
+
27. [Complete Examples](#27-complete-examples)
|
|
104
291
|
|
|
105
292
|
---
|
|
106
293
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/bin/sochdb-bulk.js
CHANGED
|
@@ -46,7 +46,7 @@ sochdb-bulk binary not found!
|
|
|
46
46
|
Searched at: ${bundledPath}
|
|
47
47
|
|
|
48
48
|
To fix:
|
|
49
|
-
1. Reinstall the package: npm install --force @
|
|
49
|
+
1. Reinstall the package: npm install --force @sochdb/sochdb
|
|
50
50
|
2. Or set SOCHDB_BULK_PATH environment variable
|
|
51
51
|
`);
|
|
52
52
|
}
|
|
@@ -46,7 +46,7 @@ sochdb-grpc-server binary not found!
|
|
|
46
46
|
Searched at: ${bundledPath}
|
|
47
47
|
|
|
48
48
|
To fix:
|
|
49
|
-
1. Reinstall the package: npm install --force @
|
|
49
|
+
1. Reinstall the package: npm install --force @sochdb/sochdb
|
|
50
50
|
2. Or set SOCHDB_GRPC_SERVER_PATH environment variable
|
|
51
51
|
`);
|
|
52
52
|
}
|
package/bin/sochdb-server.js
CHANGED
|
@@ -46,7 +46,7 @@ sochdb-server binary not found!
|
|
|
46
46
|
Searched at: ${bundledPath}
|
|
47
47
|
|
|
48
48
|
To fix:
|
|
49
|
-
1. Reinstall the package: npm install --force @
|
|
49
|
+
1. Reinstall the package: npm install --force @sochdb/sochdb
|
|
50
50
|
2. Or set SOCHDB_SERVER_PATH environment variable
|
|
51
51
|
`);
|
|
52
52
|
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Context Query Builder for LLM Context Assembly
|
|
4
|
+
*
|
|
5
|
+
* Token-aware context assembly with priority-based truncation.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.ContextQueryBuilder = exports.TruncationStrategy = exports.ContextOutputFormat = void 0;
|
|
9
|
+
exports.createContextBuilder = createContextBuilder;
|
|
10
|
+
var ContextOutputFormat;
|
|
11
|
+
(function (ContextOutputFormat) {
|
|
12
|
+
ContextOutputFormat["TOON"] = "toon";
|
|
13
|
+
ContextOutputFormat["JSON"] = "json";
|
|
14
|
+
ContextOutputFormat["MARKDOWN"] = "markdown";
|
|
15
|
+
})(ContextOutputFormat || (exports.ContextOutputFormat = ContextOutputFormat = {}));
|
|
16
|
+
var TruncationStrategy;
|
|
17
|
+
(function (TruncationStrategy) {
|
|
18
|
+
TruncationStrategy["TAIL_DROP"] = "tail_drop";
|
|
19
|
+
TruncationStrategy["HEAD_DROP"] = "head_drop";
|
|
20
|
+
TruncationStrategy["PROPORTIONAL"] = "proportional";
|
|
21
|
+
})(TruncationStrategy || (exports.TruncationStrategy = TruncationStrategy = {}));
|
|
22
|
+
/**
|
|
23
|
+
* Context Query Builder for assembling LLM context
|
|
24
|
+
*/
|
|
25
|
+
class ContextQueryBuilder {
|
|
26
|
+
constructor() {
|
|
27
|
+
this.tokenBudget = 4096;
|
|
28
|
+
this.format = ContextOutputFormat.TOON;
|
|
29
|
+
this.truncation = TruncationStrategy.TAIL_DROP;
|
|
30
|
+
this.sections = [];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Set session ID for context
|
|
34
|
+
*/
|
|
35
|
+
forSession(sessionId) {
|
|
36
|
+
this.sessionId = sessionId;
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Set token budget
|
|
41
|
+
*/
|
|
42
|
+
withBudget(tokens) {
|
|
43
|
+
this.tokenBudget = tokens;
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Set output format
|
|
48
|
+
*/
|
|
49
|
+
setFormat(format) {
|
|
50
|
+
this.format = format;
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Set truncation strategy
|
|
55
|
+
*/
|
|
56
|
+
setTruncation(strategy) {
|
|
57
|
+
this.truncation = strategy;
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Add literal text section
|
|
62
|
+
*/
|
|
63
|
+
literal(name, priority, text) {
|
|
64
|
+
const tokenCount = this.estimateTokens(text);
|
|
65
|
+
this.sections.push({
|
|
66
|
+
name,
|
|
67
|
+
priority,
|
|
68
|
+
content: text,
|
|
69
|
+
tokenCount,
|
|
70
|
+
});
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Start a new section
|
|
75
|
+
*/
|
|
76
|
+
section(name, priority) {
|
|
77
|
+
this.currentSection = {
|
|
78
|
+
name,
|
|
79
|
+
priority,
|
|
80
|
+
content: '',
|
|
81
|
+
tokenCount: 0,
|
|
82
|
+
};
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Add content to current section
|
|
87
|
+
*/
|
|
88
|
+
get(path) {
|
|
89
|
+
if (!this.currentSection) {
|
|
90
|
+
throw new Error('No active section. Call section() first.');
|
|
91
|
+
}
|
|
92
|
+
this.currentSection.content += `GET ${path}\n`;
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Add last N records query
|
|
97
|
+
*/
|
|
98
|
+
last(n, table) {
|
|
99
|
+
if (!this.currentSection) {
|
|
100
|
+
throw new Error('No active section. Call section() first.');
|
|
101
|
+
}
|
|
102
|
+
this.currentSection.content += `LAST ${n} FROM ${table}\n`;
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Add where equals condition
|
|
107
|
+
*/
|
|
108
|
+
whereEq(field, value) {
|
|
109
|
+
if (!this.currentSection) {
|
|
110
|
+
throw new Error('No active section. Call section() first.');
|
|
111
|
+
}
|
|
112
|
+
this.currentSection.content += `WHERE ${field} = ${JSON.stringify(value)}\n`;
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Add vector search
|
|
117
|
+
*/
|
|
118
|
+
search(collection, embedding, k) {
|
|
119
|
+
if (!this.currentSection) {
|
|
120
|
+
throw new Error('No active section. Call section() first.');
|
|
121
|
+
}
|
|
122
|
+
this.currentSection.content += `SEARCH ${collection} WITH ${embedding} LIMIT ${k}\n`;
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Add SQL query
|
|
127
|
+
*/
|
|
128
|
+
sql(query) {
|
|
129
|
+
if (!this.currentSection) {
|
|
130
|
+
throw new Error('No active section. Call section() first.');
|
|
131
|
+
}
|
|
132
|
+
this.currentSection.content += `SQL: ${query}\n`;
|
|
133
|
+
return this;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Finish current section
|
|
137
|
+
*/
|
|
138
|
+
done() {
|
|
139
|
+
if (this.currentSection) {
|
|
140
|
+
this.currentSection.tokenCount = this.estimateTokens(this.currentSection.content);
|
|
141
|
+
this.sections.push(this.currentSection);
|
|
142
|
+
this.currentSection = undefined;
|
|
143
|
+
}
|
|
144
|
+
return this;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Execute and build context
|
|
148
|
+
*/
|
|
149
|
+
execute() {
|
|
150
|
+
// Finish any pending section
|
|
151
|
+
if (this.currentSection) {
|
|
152
|
+
this.done();
|
|
153
|
+
}
|
|
154
|
+
// Sort sections by priority (lower = higher priority)
|
|
155
|
+
const sortedSections = [...this.sections].sort((a, b) => a.priority - b.priority);
|
|
156
|
+
// Calculate total tokens
|
|
157
|
+
let totalTokens = sortedSections.reduce((sum, s) => sum + s.tokenCount, 0);
|
|
158
|
+
// Truncate if needed
|
|
159
|
+
const truncatedSections = [];
|
|
160
|
+
const includedSections = [];
|
|
161
|
+
if (totalTokens <= this.tokenBudget) {
|
|
162
|
+
// No truncation needed
|
|
163
|
+
for (const section of sortedSections) {
|
|
164
|
+
includedSections.push(section);
|
|
165
|
+
truncatedSections.push({
|
|
166
|
+
name: section.name,
|
|
167
|
+
tokenCount: section.tokenCount,
|
|
168
|
+
truncated: false,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
// Apply truncation strategy
|
|
174
|
+
let remainingBudget = this.tokenBudget;
|
|
175
|
+
if (this.truncation === TruncationStrategy.TAIL_DROP) {
|
|
176
|
+
// Include sections in priority order until budget exhausted
|
|
177
|
+
for (const section of sortedSections) {
|
|
178
|
+
if (section.tokenCount <= remainingBudget) {
|
|
179
|
+
includedSections.push(section);
|
|
180
|
+
remainingBudget -= section.tokenCount;
|
|
181
|
+
truncatedSections.push({
|
|
182
|
+
name: section.name,
|
|
183
|
+
tokenCount: section.tokenCount,
|
|
184
|
+
truncated: false,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
truncatedSections.push({
|
|
189
|
+
name: section.name,
|
|
190
|
+
tokenCount: 0,
|
|
191
|
+
truncated: true,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else if (this.truncation === TruncationStrategy.PROPORTIONAL) {
|
|
197
|
+
// Proportionally reduce all sections
|
|
198
|
+
const ratio = this.tokenBudget / totalTokens;
|
|
199
|
+
for (const section of sortedSections) {
|
|
200
|
+
const allocatedTokens = Math.floor(section.tokenCount * ratio);
|
|
201
|
+
const truncatedContent = this.truncateText(section.content, allocatedTokens);
|
|
202
|
+
includedSections.push({
|
|
203
|
+
...section,
|
|
204
|
+
content: truncatedContent,
|
|
205
|
+
tokenCount: allocatedTokens,
|
|
206
|
+
});
|
|
207
|
+
truncatedSections.push({
|
|
208
|
+
name: section.name,
|
|
209
|
+
tokenCount: allocatedTokens,
|
|
210
|
+
truncated: allocatedTokens < section.tokenCount,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Build final context based on format
|
|
216
|
+
let text = '';
|
|
217
|
+
let actualTokens = 0;
|
|
218
|
+
if (this.format === ContextOutputFormat.TOON) {
|
|
219
|
+
text = this.buildToonFormat(includedSections);
|
|
220
|
+
}
|
|
221
|
+
else if (this.format === ContextOutputFormat.JSON) {
|
|
222
|
+
text = this.buildJsonFormat(includedSections);
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
text = this.buildMarkdownFormat(includedSections);
|
|
226
|
+
}
|
|
227
|
+
actualTokens = this.estimateTokens(text);
|
|
228
|
+
return {
|
|
229
|
+
text,
|
|
230
|
+
tokenCount: actualTokens,
|
|
231
|
+
sections: truncatedSections,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
// Helper methods
|
|
235
|
+
estimateTokens(text) {
|
|
236
|
+
// Rough estimate: ~4 characters per token for English
|
|
237
|
+
return Math.ceil(text.length / 4);
|
|
238
|
+
}
|
|
239
|
+
truncateText(text, maxTokens) {
|
|
240
|
+
const maxChars = maxTokens * 4;
|
|
241
|
+
if (text.length <= maxChars) {
|
|
242
|
+
return text;
|
|
243
|
+
}
|
|
244
|
+
return text.substring(0, maxChars) + '...';
|
|
245
|
+
}
|
|
246
|
+
buildToonFormat(sections) {
|
|
247
|
+
const lines = [];
|
|
248
|
+
for (const section of sections) {
|
|
249
|
+
lines.push(`[${section.name}]`);
|
|
250
|
+
lines.push(section.content);
|
|
251
|
+
lines.push('');
|
|
252
|
+
}
|
|
253
|
+
return lines.join('\n');
|
|
254
|
+
}
|
|
255
|
+
buildJsonFormat(sections) {
|
|
256
|
+
const obj = {};
|
|
257
|
+
for (const section of sections) {
|
|
258
|
+
obj[section.name] = section.content;
|
|
259
|
+
}
|
|
260
|
+
return JSON.stringify(obj, null, 2);
|
|
261
|
+
}
|
|
262
|
+
buildMarkdownFormat(sections) {
|
|
263
|
+
const lines = [];
|
|
264
|
+
for (const section of sections) {
|
|
265
|
+
lines.push(`## ${section.name}`);
|
|
266
|
+
lines.push('');
|
|
267
|
+
lines.push(section.content);
|
|
268
|
+
lines.push('');
|
|
269
|
+
}
|
|
270
|
+
return lines.join('\n');
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
exports.ContextQueryBuilder = ContextQueryBuilder;
|
|
274
|
+
/**
|
|
275
|
+
* Create a context query builder
|
|
276
|
+
*/
|
|
277
|
+
function createContextBuilder() {
|
|
278
|
+
return new ContextQueryBuilder();
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGV4dC1idWlsZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbnRleHQtYnVpbGRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7R0FJRzs7O0FBc1RILG9EQUVDO0FBdFRELElBQVksbUJBSVg7QUFKRCxXQUFZLG1CQUFtQjtJQUM3QixvQ0FBYSxDQUFBO0lBQ2Isb0NBQWEsQ0FBQTtJQUNiLDRDQUFxQixDQUFBO0FBQ3ZCLENBQUMsRUFKVyxtQkFBbUIsbUNBQW5CLG1CQUFtQixRQUk5QjtBQUVELElBQVksa0JBSVg7QUFKRCxXQUFZLGtCQUFrQjtJQUM1Qiw2Q0FBdUIsQ0FBQTtJQUN2Qiw2Q0FBdUIsQ0FBQTtJQUN2QixtREFBNkIsQ0FBQTtBQUMvQixDQUFDLEVBSlcsa0JBQWtCLGtDQUFsQixrQkFBa0IsUUFJN0I7QUFlRDs7R0FFRztBQUNILE1BQWEsbUJBQW1CO0lBQWhDO1FBRVUsZ0JBQVcsR0FBVyxJQUFJLENBQUM7UUFDM0IsV0FBTSxHQUF3QixtQkFBbUIsQ0FBQyxJQUFJLENBQUM7UUFDdkQsZUFBVSxHQUF1QixrQkFBa0IsQ0FBQyxTQUFTLENBQUM7UUFDOUQsYUFBUSxHQUFjLEVBQUUsQ0FBQztJQThRbkMsQ0FBQztJQTNRQzs7T0FFRztJQUNILFVBQVUsQ0FBQyxTQUFpQjtRQUMxQixJQUFJLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQztRQUMzQixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7T0FFRztJQUNILFVBQVUsQ0FBQyxNQUFjO1FBQ3ZCLElBQUksQ0FBQyxXQUFXLEdBQUcsTUFBTSxDQUFDO1FBQzFCLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOztPQUVHO0lBQ0gsU0FBUyxDQUFDLE1BQTJCO1FBQ25DLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOztPQUVHO0lBQ0gsYUFBYSxDQUFDLFFBQTRCO1FBQ3hDLElBQUksQ0FBQyxVQUFVLEdBQUcsUUFBUSxDQUFDO1FBQzNCLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOztPQUVHO0lBQ0gsT0FBTyxDQUFDLElBQVksRUFBRSxRQUFnQixFQUFFLElBQVk7UUFDbEQsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM3QyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQztZQUNqQixJQUFJO1lBQ0osUUFBUTtZQUNSLE9BQU8sRUFBRSxJQUFJO1lBQ2IsVUFBVTtTQUNYLENBQUMsQ0FBQztRQUNILE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOztPQUVHO0lBQ0gsT0FBTyxDQUFDLElBQVksRUFBRSxRQUFnQjtRQUNwQyxJQUFJLENBQUMsY0FBYyxHQUFHO1lBQ3BCLElBQUk7WUFDSixRQUFRO1lBQ1IsT0FBTyxFQUFFLEVBQUU7WUFDWCxVQUFVLEVBQUUsQ0FBQztTQUNkLENBQUM7UUFDRixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7T0FFRztJQUNILEdBQUcsQ0FBQyxJQUFZO1FBQ2QsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN6QixNQUFNLElBQUksS0FBSyxDQUFDLDBDQUEwQyxDQUFDLENBQUM7UUFDOUQsQ0FBQztRQUNELElBQUksQ0FBQyxjQUFjLENBQUMsT0FBTyxJQUFJLE9BQU8sSUFBSSxJQUFJLENBQUM7UUFDL0MsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxJQUFJLENBQUMsQ0FBUyxFQUFFLEtBQWE7UUFDM0IsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN6QixNQUFNLElBQUksS0FBSyxDQUFDLDBDQUEwQyxDQUFDLENBQUM7UUFDOUQsQ0FBQztRQUNELElBQUksQ0FBQyxjQUFjLENBQUMsT0FBTyxJQUFJLFFBQVEsQ0FBQyxTQUFTLEtBQUssSUFBSSxDQUFDO1FBQzNELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOztPQUVHO0lBQ0gsT0FBTyxDQUFDLEtBQWEsRUFBRSxLQUFVO1FBQy9CLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDekIsTUFBTSxJQUFJLEtBQUssQ0FBQywwQ0FBMEMsQ0FBQyxDQUFDO1FBQzlELENBQUM7UUFDRCxJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sSUFBSSxTQUFTLEtBQUssTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUM7UUFDN0UsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsVUFBa0IsRUFBRSxTQUFpQixFQUFFLENBQVM7UUFDckQsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN6QixNQUFNLElBQUksS0FBSyxDQUFDLDBDQUEwQyxDQUFDLENBQUM7UUFDOUQsQ0FBQztRQUNELElBQUksQ0FBQyxjQUFjLENBQUMsT0FBTyxJQUFJLFVBQVUsVUFBVSxTQUFTLFNBQVMsVUFBVSxDQUFDLElBQUksQ0FBQztRQUNyRixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7T0FFRztJQUNILEdBQUcsQ0FBQyxLQUFhO1FBQ2YsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN6QixNQUFNLElBQUksS0FBSyxDQUFDLDBDQUEwQyxDQUFDLENBQUM7UUFDOUQsQ0FBQztRQUNELElBQUksQ0FBQyxjQUFjLENBQUMsT0FBTyxJQUFJLFFBQVEsS0FBSyxJQUFJLENBQUM7UUFDakQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxJQUFJO1FBQ0YsSUFBSSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDeEIsSUFBSSxDQUFDLGNBQWMsQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ2xGLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUN4QyxJQUFJLENBQUMsY0FBYyxHQUFHLFNBQVMsQ0FBQztRQUNsQyxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxPQUFPO1FBQ0wsNkJBQTZCO1FBQzdCLElBQUksSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3hCLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNkLENBQUM7UUFFRCxzREFBc0Q7UUFDdEQsTUFBTSxjQUFjLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsUUFBUSxHQUFHLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUVsRix5QkFBeUI7UUFDekIsSUFBSSxXQUFXLEdBQUcsY0FBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBRTNFLHFCQUFxQjtRQUNyQixNQUFNLGlCQUFpQixHQUFvRSxFQUFFLENBQUM7UUFDOUYsTUFBTSxnQkFBZ0IsR0FBYyxFQUFFLENBQUM7UUFFdkMsSUFBSSxXQUFXLElBQUksSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ3BDLHVCQUF1QjtZQUN2QixLQUFLLE1BQU0sT0FBTyxJQUFJLGNBQWMsRUFBRSxDQUFDO2dCQUNyQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQy9CLGlCQUFpQixDQUFDLElBQUksQ0FBQztvQkFDckIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJO29CQUNsQixVQUFVLEVBQUUsT0FBTyxDQUFDLFVBQVU7b0JBQzlCLFNBQVMsRUFBRSxLQUFLO2lCQUNqQixDQUFDLENBQUM7WUFDTCxDQUFDO1FBQ0gsQ0FBQzthQUFNLENBQUM7WUFDTiw0QkFBNEI7WUFDNUIsSUFBSSxlQUFlLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQztZQUV2QyxJQUFJLElBQUksQ0FBQyxVQUFVLEtBQUssa0JBQWtCLENBQUMsU0FBUyxFQUFFLENBQUM7Z0JBQ3JELDREQUE0RDtnQkFDNUQsS0FBSyxNQUFNLE9BQU8sSUFBSSxjQUFjLEVBQUUsQ0FBQztvQkFDckMsSUFBSSxPQUFPLENBQUMsVUFBVSxJQUFJLGVBQWUsRUFBRSxDQUFDO3dCQUMxQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7d0JBQy9CLGVBQWUsSUFBSSxPQUFPLENBQUMsVUFBVSxDQUFDO3dCQUN0QyxpQkFBaUIsQ0FBQyxJQUFJLENBQUM7NEJBQ3JCLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTs0QkFDbEIsVUFBVSxFQUFFLE9BQU8sQ0FBQyxVQUFVOzRCQUM5QixTQUFTLEVBQUUsS0FBSzt5QkFDakIsQ0FBQyxDQUFDO29CQUNMLENBQUM7eUJBQU0sQ0FBQzt3QkFDTixpQkFBaUIsQ0FBQyxJQUFJLENBQUM7NEJBQ3JCLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTs0QkFDbEIsVUFBVSxFQUFFLENBQUM7NEJBQ2IsU0FBUyxFQUFFLElBQUk7eUJBQ2hCLENBQUMsQ0FBQztvQkFDTCxDQUFDO2dCQUNILENBQUM7WUFDSCxDQUFDO2lCQUFNLElBQUksSUFBSSxDQUFDLFVBQVUsS0FBSyxrQkFBa0IsQ0FBQyxZQUFZLEVBQUUsQ0FBQztnQkFDL0QscUNBQXFDO2dCQUNyQyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQztnQkFDN0MsS0FBSyxNQUFNLE9BQU8sSUFBSSxjQUFjLEVBQUUsQ0FBQztvQkFDckMsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsVUFBVSxHQUFHLEtBQUssQ0FBQyxDQUFDO29CQUMvRCxNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxlQUFlLENBQUMsQ0FBQztvQkFDN0UsZ0JBQWdCLENBQUMsSUFBSSxDQUFDO3dCQUNwQixHQUFHLE9BQU87d0JBQ1YsT0FBTyxFQUFFLGdCQUFnQjt3QkFDekIsVUFBVSxFQUFFLGVBQWU7cUJBQzVCLENBQUMsQ0FBQztvQkFDSCxpQkFBaUIsQ0FBQyxJQUFJLENBQUM7d0JBQ3JCLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTt3QkFDbEIsVUFBVSxFQUFFLGVBQWU7d0JBQzNCLFNBQVMsRUFBRSxlQUFlLEdBQUcsT0FBTyxDQUFDLFVBQVU7cUJBQ2hELENBQUMsQ0FBQztnQkFDTCxDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7UUFFRCxzQ0FBc0M7UUFDdEMsSUFBSSxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ2QsSUFBSSxZQUFZLEdBQUcsQ0FBQyxDQUFDO1FBRXJCLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxtQkFBbUIsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUM3QyxJQUFJLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ2hELENBQUM7YUFBTSxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssbUJBQW1CLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDcEQsSUFBSSxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUNoRCxDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksR0FBRyxJQUFJLENBQUMsbUJBQW1CLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUNwRCxDQUFDO1FBRUQsWUFBWSxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFekMsT0FBTztZQUNMLElBQUk7WUFDSixVQUFVLEVBQUUsWUFBWTtZQUN4QixRQUFRLEVBQUUsaUJBQWlCO1NBQzVCLENBQUM7SUFDSixDQUFDO0lBRUQsaUJBQWlCO0lBQ1QsY0FBYyxDQUFDLElBQVk7UUFDakMsc0RBQXNEO1FBQ3RELE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3BDLENBQUM7SUFFTyxZQUFZLENBQUMsSUFBWSxFQUFFLFNBQWlCO1FBQ2xELE1BQU0sUUFBUSxHQUFHLFNBQVMsR0FBRyxDQUFDLENBQUM7UUFDL0IsSUFBSSxJQUFJLENBQUMsTUFBTSxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQzVCLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDLEdBQUcsS0FBSyxDQUFDO0lBQzdDLENBQUM7SUFFTyxlQUFlLENBQUMsUUFBbUI7UUFDekMsTUFBTSxLQUFLLEdBQWEsRUFBRSxDQUFDO1FBRTNCLEtBQUssTUFBTSxPQUFPLElBQUksUUFBUSxFQUFFLENBQUM7WUFDL0IsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLE9BQU8sQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDO1lBQ2hDLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQzVCLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDakIsQ0FBQztRQUVELE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMxQixDQUFDO0lBRU8sZUFBZSxDQUFDLFFBQW1CO1FBQ3pDLE1BQU0sR0FBRyxHQUEyQixFQUFFLENBQUM7UUFFdkMsS0FBSyxNQUFNLE9BQU8sSUFBSSxRQUFRLEVBQUUsQ0FBQztZQUMvQixHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUM7UUFDdEMsQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3RDLENBQUM7SUFFTyxtQkFBbUIsQ0FBQyxRQUFtQjtRQUM3QyxNQUFNLEtBQUssR0FBYSxFQUFFLENBQUM7UUFFM0IsS0FBSyxNQUFNLE9BQU8sSUFBSSxRQUFRLEVBQUUsQ0FBQztZQUMvQixLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7WUFDakMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUNmLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQzVCLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDakIsQ0FBQztRQUVELE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMxQixDQUFDO0NBQ0Y7QUFuUkQsa0RBbVJDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixvQkFBb0I7SUFDbEMsT0FBTyxJQUFJLG1CQUFtQixFQUFFLENBQUM7QUFDbkMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ29udGV4dCBRdWVyeSBCdWlsZGVyIGZvciBMTE0gQ29udGV4dCBBc3NlbWJseVxuICogXG4gKiBUb2tlbi1hd2FyZSBjb250ZXh0IGFzc2VtYmx5IHdpdGggcHJpb3JpdHktYmFzZWQgdHJ1bmNhdGlvbi5cbiAqL1xuXG5leHBvcnQgZW51bSBDb250ZXh0T3V0cHV0Rm9ybWF0IHtcbiAgVE9PTiA9ICd0b29uJyxcbiAgSlNPTiA9ICdqc29uJyxcbiAgTUFSS0RPV04gPSAnbWFya2Rvd24nLFxufVxuXG5leHBvcnQgZW51bSBUcnVuY2F0aW9uU3RyYXRlZ3kge1xuICBUQUlMX0RST1AgPSAndGFpbF9kcm9wJywgICAgICAgLy8gRHJvcCBmcm9tIGVuZFxuICBIRUFEX0RST1AgPSAnaGVhZF9kcm9wJywgICAgICAgLy8gRHJvcCBmcm9tIGJlZ2lubmluZ1xuICBQUk9QT1JUSU9OQUwgPSAncHJvcG9ydGlvbmFsJywgLy8gUHJvcG9ydGlvbmFsIGFjcm9zcyBzZWN0aW9uc1xufVxuXG5pbnRlcmZhY2UgU2VjdGlvbiB7XG4gIG5hbWU6IHN0cmluZztcbiAgcHJpb3JpdHk6IG51bWJlcjtcbiAgY29udGVudDogc3RyaW5nO1xuICB0b2tlbkNvdW50OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29udGV4dFJlc3VsdCB7XG4gIHRleHQ6IHN0cmluZztcbiAgdG9rZW5Db3VudDogbnVtYmVyO1xuICBzZWN0aW9uczogQXJyYXk8eyBuYW1lOiBzdHJpbmc7IHRva2VuQ291bnQ6IG51bWJlcjsgdHJ1bmNhdGVkOiBib29sZWFuIH0+O1xufVxuXG4vKipcbiAqIENvbnRleHQgUXVlcnkgQnVpbGRlciBmb3IgYXNzZW1ibGluZyBMTE0gY29udGV4dFxuICovXG5leHBvcnQgY2xhc3MgQ29udGV4dFF1ZXJ5QnVpbGRlciB7XG4gIHByaXZhdGUgc2Vzc2lvbklkPzogc3RyaW5nO1xuICBwcml2YXRlIHRva2VuQnVkZ2V0OiBudW1iZXIgPSA0MDk2O1xuICBwcml2YXRlIGZvcm1hdDogQ29udGV4dE91dHB1dEZvcm1hdCA9IENvbnRleHRPdXRwdXRGb3JtYXQuVE9PTjtcbiAgcHJpdmF0ZSB0cnVuY2F0aW9uOiBUcnVuY2F0aW9uU3RyYXRlZ3kgPSBUcnVuY2F0aW9uU3RyYXRlZ3kuVEFJTF9EUk9QO1xuICBwcml2YXRlIHNlY3Rpb25zOiBTZWN0aW9uW10gPSBbXTtcbiAgcHJpdmF0ZSBjdXJyZW50U2VjdGlvbj86IFNlY3Rpb247XG5cbiAgLyoqXG4gICAqIFNldCBzZXNzaW9uIElEIGZvciBjb250ZXh0XG4gICAqL1xuICBmb3JTZXNzaW9uKHNlc3Npb25JZDogc3RyaW5nKTogdGhpcyB7XG4gICAgdGhpcy5zZXNzaW9uSWQgPSBzZXNzaW9uSWQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogU2V0IHRva2VuIGJ1ZGdldFxuICAgKi9cbiAgd2l0aEJ1ZGdldCh0b2tlbnM6IG51bWJlcik6IHRoaXMge1xuICAgIHRoaXMudG9rZW5CdWRnZXQgPSB0b2tlbnM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogU2V0IG91dHB1dCBmb3JtYXRcbiAgICovXG4gIHNldEZvcm1hdChmb3JtYXQ6IENvbnRleHRPdXRwdXRGb3JtYXQpOiB0aGlzIHtcbiAgICB0aGlzLmZvcm1hdCA9IGZvcm1hdDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXQgdHJ1bmNhdGlvbiBzdHJhdGVneVxuICAgKi9cbiAgc2V0VHJ1bmNhdGlvbihzdHJhdGVneTogVHJ1bmNhdGlvblN0cmF0ZWd5KTogdGhpcyB7XG4gICAgdGhpcy50cnVuY2F0aW9uID0gc3RyYXRlZ3k7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGxpdGVyYWwgdGV4dCBzZWN0aW9uXG4gICAqL1xuICBsaXRlcmFsKG5hbWU6IHN0cmluZywgcHJpb3JpdHk6IG51bWJlciwgdGV4dDogc3RyaW5nKTogdGhpcyB7XG4gICAgY29uc3QgdG9rZW5Db3VudCA9IHRoaXMuZXN0aW1hdGVUb2tlbnModGV4dCk7XG4gICAgdGhpcy5zZWN0aW9ucy5wdXNoKHtcbiAgICAgIG5hbWUsXG4gICAgICBwcmlvcml0eSxcbiAgICAgIGNvbnRlbnQ6IHRleHQsXG4gICAgICB0b2tlbkNvdW50LFxuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YXJ0IGEgbmV3IHNlY3Rpb25cbiAgICovXG4gIHNlY3Rpb24obmFtZTogc3RyaW5nLCBwcmlvcml0eTogbnVtYmVyKTogdGhpcyB7XG4gICAgdGhpcy5jdXJyZW50U2VjdGlvbiA9IHtcbiAgICAgIG5hbWUsXG4gICAgICBwcmlvcml0eSxcbiAgICAgIGNvbnRlbnQ6ICcnLFxuICAgICAgdG9rZW5Db3VudDogMCxcbiAgICB9O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBjb250ZW50IHRvIGN1cnJlbnQgc2VjdGlvblxuICAgKi9cbiAgZ2V0KHBhdGg6IHN0cmluZyk6IHRoaXMge1xuICAgIGlmICghdGhpcy5jdXJyZW50U2VjdGlvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBhY3RpdmUgc2VjdGlvbi4gQ2FsbCBzZWN0aW9uKCkgZmlyc3QuJyk7XG4gICAgfVxuICAgIHRoaXMuY3VycmVudFNlY3Rpb24uY29udGVudCArPSBgR0VUICR7cGF0aH1cXG5gO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBsYXN0IE4gcmVjb3JkcyBxdWVyeVxuICAgKi9cbiAgbGFzdChuOiBudW1iZXIsIHRhYmxlOiBzdHJpbmcpOiB0aGlzIHtcbiAgICBpZiAoIXRoaXMuY3VycmVudFNlY3Rpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTm8gYWN0aXZlIHNlY3Rpb24uIENhbGwgc2VjdGlvbigpIGZpcnN0LicpO1xuICAgIH1cbiAgICB0aGlzLmN1cnJlbnRTZWN0aW9uLmNvbnRlbnQgKz0gYExBU1QgJHtufSBGUk9NICR7dGFibGV9XFxuYDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgd2hlcmUgZXF1YWxzIGNvbmRpdGlvblxuICAgKi9cbiAgd2hlcmVFcShmaWVsZDogc3RyaW5nLCB2YWx1ZTogYW55KTogdGhpcyB7XG4gICAgaWYgKCF0aGlzLmN1cnJlbnRTZWN0aW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGFjdGl2ZSBzZWN0aW9uLiBDYWxsIHNlY3Rpb24oKSBmaXJzdC4nKTtcbiAgICB9XG4gICAgdGhpcy5jdXJyZW50U2VjdGlvbi5jb250ZW50ICs9IGBXSEVSRSAke2ZpZWxkfSA9ICR7SlNPTi5zdHJpbmdpZnkodmFsdWUpfVxcbmA7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQWRkIHZlY3RvciBzZWFyY2hcbiAgICovXG4gIHNlYXJjaChjb2xsZWN0aW9uOiBzdHJpbmcsIGVtYmVkZGluZzogc3RyaW5nLCBrOiBudW1iZXIpOiB0aGlzIHtcbiAgICBpZiAoIXRoaXMuY3VycmVudFNlY3Rpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTm8gYWN0aXZlIHNlY3Rpb24uIENhbGwgc2VjdGlvbigpIGZpcnN0LicpO1xuICAgIH1cbiAgICB0aGlzLmN1cnJlbnRTZWN0aW9uLmNvbnRlbnQgKz0gYFNFQVJDSCAke2NvbGxlY3Rpb259IFdJVEggJHtlbWJlZGRpbmd9IExJTUlUICR7a31cXG5gO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBTUUwgcXVlcnlcbiAgICovXG4gIHNxbChxdWVyeTogc3RyaW5nKTogdGhpcyB7XG4gICAgaWYgKCF0aGlzLmN1cnJlbnRTZWN0aW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGFjdGl2ZSBzZWN0aW9uLiBDYWxsIHNlY3Rpb24oKSBmaXJzdC4nKTtcbiAgICB9XG4gICAgdGhpcy5jdXJyZW50U2VjdGlvbi5jb250ZW50ICs9IGBTUUw6ICR7cXVlcnl9XFxuYDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5pc2ggY3VycmVudCBzZWN0aW9uXG4gICAqL1xuICBkb25lKCk6IHRoaXMge1xuICAgIGlmICh0aGlzLmN1cnJlbnRTZWN0aW9uKSB7XG4gICAgICB0aGlzLmN1cnJlbnRTZWN0aW9uLnRva2VuQ291bnQgPSB0aGlzLmVzdGltYXRlVG9rZW5zKHRoaXMuY3VycmVudFNlY3Rpb24uY29udGVudCk7XG4gICAgICB0aGlzLnNlY3Rpb25zLnB1c2godGhpcy5jdXJyZW50U2VjdGlvbik7XG4gICAgICB0aGlzLmN1cnJlbnRTZWN0aW9uID0gdW5kZWZpbmVkO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBFeGVjdXRlIGFuZCBidWlsZCBjb250ZXh0XG4gICAqL1xuICBleGVjdXRlKCk6IENvbnRleHRSZXN1bHQge1xuICAgIC8vIEZpbmlzaCBhbnkgcGVuZGluZyBzZWN0aW9uXG4gICAgaWYgKHRoaXMuY3VycmVudFNlY3Rpb24pIHtcbiAgICAgIHRoaXMuZG9uZSgpO1xuICAgIH1cblxuICAgIC8vIFNvcnQgc2VjdGlvbnMgYnkgcHJpb3JpdHkgKGxvd2VyID0gaGlnaGVyIHByaW9yaXR5KVxuICAgIGNvbnN0IHNvcnRlZFNlY3Rpb25zID0gWy4uLnRoaXMuc2VjdGlvbnNdLnNvcnQoKGEsIGIpID0+IGEucHJpb3JpdHkgLSBiLnByaW9yaXR5KTtcblxuICAgIC8vIENhbGN1bGF0ZSB0b3RhbCB0b2tlbnNcbiAgICBsZXQgdG90YWxUb2tlbnMgPSBzb3J0ZWRTZWN0aW9ucy5yZWR1Y2UoKHN1bSwgcykgPT4gc3VtICsgcy50b2tlbkNvdW50LCAwKTtcblxuICAgIC8vIFRydW5jYXRlIGlmIG5lZWRlZFxuICAgIGNvbnN0IHRydW5jYXRlZFNlY3Rpb25zOiBBcnJheTx7IG5hbWU6IHN0cmluZzsgdG9rZW5Db3VudDogbnVtYmVyOyB0cnVuY2F0ZWQ6IGJvb2xlYW4gfT4gPSBbXTtcbiAgICBjb25zdCBpbmNsdWRlZFNlY3Rpb25zOiBTZWN0aW9uW10gPSBbXTtcblxuICAgIGlmICh0b3RhbFRva2VucyA8PSB0aGlzLnRva2VuQnVkZ2V0KSB7XG4gICAgICAvLyBObyB0cnVuY2F0aW9uIG5lZWRlZFxuICAgICAgZm9yIChjb25zdCBzZWN0aW9uIG9mIHNvcnRlZFNlY3Rpb25zKSB7XG4gICAgICAgIGluY2x1ZGVkU2VjdGlvbnMucHVzaChzZWN0aW9uKTtcbiAgICAgICAgdHJ1bmNhdGVkU2VjdGlvbnMucHVzaCh7XG4gICAgICAgICAgbmFtZTogc2VjdGlvbi5uYW1lLFxuICAgICAgICAgIHRva2VuQ291bnQ6IHNlY3Rpb24udG9rZW5Db3VudCxcbiAgICAgICAgICB0cnVuY2F0ZWQ6IGZhbHNlLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gQXBwbHkgdHJ1bmNhdGlvbiBzdHJhdGVneVxuICAgICAgbGV0IHJlbWFpbmluZ0J1ZGdldCA9IHRoaXMudG9rZW5CdWRnZXQ7XG5cbiAgICAgIGlmICh0aGlzLnRydW5jYXRpb24gPT09IFRydW5jYXRpb25TdHJhdGVneS5UQUlMX0RST1ApIHtcbiAgICAgICAgLy8gSW5jbHVkZSBzZWN0aW9ucyBpbiBwcmlvcml0eSBvcmRlciB1bnRpbCBidWRnZXQgZXhoYXVzdGVkXG4gICAgICAgIGZvciAoY29uc3Qgc2VjdGlvbiBvZiBzb3J0ZWRTZWN0aW9ucykge1xuICAgICAgICAgIGlmIChzZWN0aW9uLnRva2VuQ291bnQgPD0gcmVtYWluaW5nQnVkZ2V0KSB7XG4gICAgICAgICAgICBpbmNsdWRlZFNlY3Rpb25zLnB1c2goc2VjdGlvbik7XG4gICAgICAgICAgICByZW1haW5pbmdCdWRnZXQgLT0gc2VjdGlvbi50b2tlbkNvdW50O1xuICAgICAgICAgICAgdHJ1bmNhdGVkU2VjdGlvbnMucHVzaCh7XG4gICAgICAgICAgICAgIG5hbWU6IHNlY3Rpb24ubmFtZSxcbiAgICAgICAgICAgICAgdG9rZW5Db3VudDogc2VjdGlvbi50b2tlbkNvdW50LFxuICAgICAgICAgICAgICB0cnVuY2F0ZWQ6IGZhbHNlLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRydW5jYXRlZFNlY3Rpb25zLnB1c2goe1xuICAgICAgICAgICAgICBuYW1lOiBzZWN0aW9uLm5hbWUsXG4gICAgICAgICAgICAgIHRva2VuQ291bnQ6IDAsXG4gICAgICAgICAgICAgIHRydW5jYXRlZDogdHJ1ZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICh0aGlzLnRydW5jYXRpb24gPT09IFRydW5jYXRpb25TdHJhdGVneS5QUk9QT1JUSU9OQUwpIHtcbiAgICAgICAgLy8gUHJvcG9ydGlvbmFsbHkgcmVkdWNlIGFsbCBzZWN0aW9uc1xuICAgICAgICBjb25zdCByYXRpbyA9IHRoaXMudG9rZW5CdWRnZXQgLyB0b3RhbFRva2VucztcbiAgICAgICAgZm9yIChjb25zdCBzZWN0aW9uIG9mIHNvcnRlZFNlY3Rpb25zKSB7XG4gICAgICAgICAgY29uc3QgYWxsb2NhdGVkVG9rZW5zID0gTWF0aC5mbG9vcihzZWN0aW9uLnRva2VuQ291bnQgKiByYXRpbyk7XG4gICAgICAgICAgY29uc3QgdHJ1bmNhdGVkQ29udGVudCA9IHRoaXMudHJ1bmNhdGVUZXh0KHNlY3Rpb24uY29udGVudCwgYWxsb2NhdGVkVG9rZW5zKTtcbiAgICAgICAgICBpbmNsdWRlZFNlY3Rpb25zLnB1c2goe1xuICAgICAgICAgICAgLi4uc2VjdGlvbixcbiAgICAgICAgICAgIGNvbnRlbnQ6IHRydW5jYXRlZENvbnRlbnQsXG4gICAgICAgICAgICB0b2tlbkNvdW50OiBhbGxvY2F0ZWRUb2tlbnMsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdHJ1bmNhdGVkU2VjdGlvbnMucHVzaCh7XG4gICAgICAgICAgICBuYW1lOiBzZWN0aW9uLm5hbWUsXG4gICAgICAgICAgICB0b2tlbkNvdW50OiBhbGxvY2F0ZWRUb2tlbnMsXG4gICAgICAgICAgICB0cnVuY2F0ZWQ6IGFsbG9jYXRlZFRva2VucyA8IHNlY3Rpb24udG9rZW5Db3VudCxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEJ1aWxkIGZpbmFsIGNvbnRleHQgYmFzZWQgb24gZm9ybWF0XG4gICAgbGV0IHRleHQgPSAnJztcbiAgICBsZXQgYWN0dWFsVG9rZW5zID0gMDtcblxuICAgIGlmICh0aGlzLmZvcm1hdCA9PT0gQ29udGV4dE91dHB1dEZvcm1hdC5UT09OKSB7XG4gICAgICB0ZXh0ID0gdGhpcy5idWlsZFRvb25Gb3JtYXQoaW5jbHVkZWRTZWN0aW9ucyk7XG4gICAgfSBlbHNlIGlmICh0aGlzLmZvcm1hdCA9PT0gQ29udGV4dE91dHB1dEZvcm1hdC5KU09OKSB7XG4gICAgICB0ZXh0ID0gdGhpcy5idWlsZEpzb25Gb3JtYXQoaW5jbHVkZWRTZWN0aW9ucyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRleHQgPSB0aGlzLmJ1aWxkTWFya2Rvd25Gb3JtYXQoaW5jbHVkZWRTZWN0aW9ucyk7XG4gICAgfVxuXG4gICAgYWN0dWFsVG9rZW5zID0gdGhpcy5lc3RpbWF0ZVRva2Vucyh0ZXh0KTtcblxuICAgIHJldHVybiB7XG4gICAgICB0ZXh0LFxuICAgICAgdG9rZW5Db3VudDogYWN0dWFsVG9rZW5zLFxuICAgICAgc2VjdGlvbnM6IHRydW5jYXRlZFNlY3Rpb25zLFxuICAgIH07XG4gIH1cblxuICAvLyBIZWxwZXIgbWV0aG9kc1xuICBwcml2YXRlIGVzdGltYXRlVG9rZW5zKHRleHQ6IHN0cmluZyk6IG51bWJlciB7XG4gICAgLy8gUm91Z2ggZXN0aW1hdGU6IH40IGNoYXJhY3RlcnMgcGVyIHRva2VuIGZvciBFbmdsaXNoXG4gICAgcmV0dXJuIE1hdGguY2VpbCh0ZXh0Lmxlbmd0aCAvIDQpO1xuICB9XG5cbiAgcHJpdmF0ZSB0cnVuY2F0ZVRleHQodGV4dDogc3RyaW5nLCBtYXhUb2tlbnM6IG51bWJlcik6IHN0cmluZyB7XG4gICAgY29uc3QgbWF4Q2hhcnMgPSBtYXhUb2tlbnMgKiA0O1xuICAgIGlmICh0ZXh0Lmxlbmd0aCA8PSBtYXhDaGFycykge1xuICAgICAgcmV0dXJuIHRleHQ7XG4gICAgfVxuICAgIHJldHVybiB0ZXh0LnN1YnN0cmluZygwLCBtYXhDaGFycykgKyAnLi4uJztcbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRUb29uRm9ybWF0KHNlY3Rpb25zOiBTZWN0aW9uW10pOiBzdHJpbmcge1xuICAgIGNvbnN0IGxpbmVzOiBzdHJpbmdbXSA9IFtdO1xuICAgIFxuICAgIGZvciAoY29uc3Qgc2VjdGlvbiBvZiBzZWN0aW9ucykge1xuICAgICAgbGluZXMucHVzaChgWyR7c2VjdGlvbi5uYW1lfV1gKTtcbiAgICAgIGxpbmVzLnB1c2goc2VjdGlvbi5jb250ZW50KTtcbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gbGluZXMuam9pbignXFxuJyk7XG4gIH1cblxuICBwcml2YXRlIGJ1aWxkSnNvbkZvcm1hdChzZWN0aW9uczogU2VjdGlvbltdKTogc3RyaW5nIHtcbiAgICBjb25zdCBvYmo6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgICBcbiAgICBmb3IgKGNvbnN0IHNlY3Rpb24gb2Ygc2VjdGlvbnMpIHtcbiAgICAgIG9ialtzZWN0aW9uLm5hbWVdID0gc2VjdGlvbi5jb250ZW50O1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob2JqLCBudWxsLCAyKTtcbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRNYXJrZG93bkZvcm1hdChzZWN0aW9uczogU2VjdGlvbltdKTogc3RyaW5nIHtcbiAgICBjb25zdCBsaW5lczogc3RyaW5nW10gPSBbXTtcbiAgICBcbiAgICBmb3IgKGNvbnN0IHNlY3Rpb24gb2Ygc2VjdGlvbnMpIHtcbiAgICAgIGxpbmVzLnB1c2goYCMjICR7c2VjdGlvbi5uYW1lfWApO1xuICAgICAgbGluZXMucHVzaCgnJyk7XG4gICAgICBsaW5lcy5wdXNoKHNlY3Rpb24uY29udGVudCk7XG4gICAgICBsaW5lcy5wdXNoKCcnKTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGxpbmVzLmpvaW4oJ1xcbicpO1xuICB9XG59XG5cbi8qKlxuICogQ3JlYXRlIGEgY29udGV4dCBxdWVyeSBidWlsZGVyXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVDb250ZXh0QnVpbGRlcigpOiBDb250ZXh0UXVlcnlCdWlsZGVyIHtcbiAgcmV0dXJuIG5ldyBDb250ZXh0UXVlcnlCdWlsZGVyKCk7XG59XG4iXX0=
|