@sochdb/sochdb 0.4.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/LICENSE +201 -0
- package/README.md +3349 -0
- 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 +80 -0
- package/bin/sochdb-grpc-server.js +80 -0
- package/bin/sochdb-server.js +84 -0
- package/dist/cjs/analytics.js +196 -0
- package/dist/cjs/database.js +929 -0
- package/dist/cjs/embedded/database.js +236 -0
- package/dist/cjs/embedded/ffi/bindings.js +113 -0
- package/dist/cjs/embedded/ffi/library-finder.js +135 -0
- package/dist/cjs/embedded/index.js +14 -0
- package/dist/cjs/embedded/transaction.js +172 -0
- package/dist/cjs/errors.js +71 -0
- package/dist/cjs/format.js +176 -0
- package/dist/cjs/grpc-client.js +328 -0
- package/dist/cjs/index.js +75 -0
- package/dist/cjs/ipc-client.js +504 -0
- package/dist/cjs/query.js +154 -0
- package/dist/cjs/server-manager.js +295 -0
- package/dist/cjs/sql-engine.js +874 -0
- package/dist/esm/analytics.js +196 -0
- package/dist/esm/database.js +931 -0
- package/dist/esm/embedded/database.js +239 -0
- package/dist/esm/embedded/ffi/bindings.js +142 -0
- package/dist/esm/embedded/ffi/library-finder.js +135 -0
- package/dist/esm/embedded/index.js +14 -0
- package/dist/esm/embedded/transaction.js +176 -0
- package/dist/esm/errors.js +71 -0
- package/dist/esm/format.js +179 -0
- package/dist/esm/grpc-client.js +333 -0
- package/dist/esm/index.js +75 -0
- package/dist/esm/ipc-client.js +505 -0
- package/dist/esm/query.js +159 -0
- package/dist/esm/server-manager.js +295 -0
- package/dist/esm/sql-engine.js +875 -0
- package/dist/types/analytics.d.ts +66 -0
- package/dist/types/analytics.d.ts.map +1 -0
- package/dist/types/database.d.ts +523 -0
- package/dist/types/database.d.ts.map +1 -0
- package/dist/types/embedded/database.d.ts +105 -0
- package/dist/types/embedded/database.d.ts.map +1 -0
- package/dist/types/embedded/ffi/bindings.d.ts +24 -0
- package/dist/types/embedded/ffi/bindings.d.ts.map +1 -0
- package/dist/types/embedded/ffi/library-finder.d.ts +17 -0
- package/dist/types/embedded/ffi/library-finder.d.ts.map +1 -0
- package/dist/types/embedded/index.d.ts +9 -0
- package/dist/types/embedded/index.d.ts.map +1 -0
- package/dist/types/embedded/transaction.d.ts +21 -0
- package/dist/types/embedded/transaction.d.ts.map +1 -0
- package/dist/types/errors.d.ts +36 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/format.d.ts +117 -0
- package/dist/types/format.d.ts.map +1 -0
- package/dist/types/grpc-client.d.ts +120 -0
- package/dist/types/grpc-client.d.ts.map +1 -0
- package/dist/types/index.d.ts +50 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/ipc-client.d.ts +177 -0
- package/dist/types/ipc-client.d.ts.map +1 -0
- package/dist/types/query.d.ts +85 -0
- package/dist/types/query.d.ts.map +1 -0
- package/dist/types/server-manager.d.ts +29 -0
- package/dist/types/server-manager.d.ts.map +1 -0
- package/dist/types/sql-engine.d.ts +100 -0
- package/dist/types/sql-engine.d.ts.map +1 -0
- package/package.json +90 -0
- package/scripts/postinstall.js +50 -0
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SochDB IPC Client
|
|
4
|
+
*
|
|
5
|
+
* Connects to a SochDB IPC server via Unix domain socket.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.IpcClient = exports.OpCode = void 0;
|
|
44
|
+
// Copyright 2025 Sushanth (https://github.com/sushanthpy)
|
|
45
|
+
//
|
|
46
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
47
|
+
// you may not use this file except in compliance with the License.
|
|
48
|
+
// You may obtain a copy of the License at
|
|
49
|
+
//
|
|
50
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
51
|
+
const net = __importStar(require("net"));
|
|
52
|
+
const errors_1 = require("./errors");
|
|
53
|
+
const query_1 = require("./query");
|
|
54
|
+
/**
|
|
55
|
+
* Wire protocol opcodes.
|
|
56
|
+
*/
|
|
57
|
+
exports.OpCode = {
|
|
58
|
+
// Client → Server (must match sochdb-storage/src/ipc_server.rs)
|
|
59
|
+
Put: 0x01,
|
|
60
|
+
Get: 0x02,
|
|
61
|
+
Delete: 0x03,
|
|
62
|
+
BeginTxn: 0x04,
|
|
63
|
+
CommitTxn: 0x05,
|
|
64
|
+
AbortTxn: 0x06,
|
|
65
|
+
Query: 0x07,
|
|
66
|
+
CreateTable: 0x08,
|
|
67
|
+
PutPath: 0x09,
|
|
68
|
+
GetPath: 0x0A,
|
|
69
|
+
Scan: 0x0B,
|
|
70
|
+
Checkpoint: 0x0C,
|
|
71
|
+
Stats: 0x0D,
|
|
72
|
+
Ping: 0x0E,
|
|
73
|
+
// Server → Client
|
|
74
|
+
OK: 0x80,
|
|
75
|
+
Error: 0x81,
|
|
76
|
+
Value: 0x82,
|
|
77
|
+
TxnId: 0x83,
|
|
78
|
+
Row: 0x84,
|
|
79
|
+
EndStream: 0x85,
|
|
80
|
+
StatsResp: 0x86,
|
|
81
|
+
Pong: 0x87,
|
|
82
|
+
};
|
|
83
|
+
// Internal OpCode map for backwards compatibility
|
|
84
|
+
const InternalOpCode = {
|
|
85
|
+
PUT: exports.OpCode.Put,
|
|
86
|
+
GET: exports.OpCode.Get,
|
|
87
|
+
DELETE: exports.OpCode.Delete,
|
|
88
|
+
BEGIN_TXN: exports.OpCode.BeginTxn,
|
|
89
|
+
COMMIT_TXN: exports.OpCode.CommitTxn,
|
|
90
|
+
ABORT_TXN: exports.OpCode.AbortTxn,
|
|
91
|
+
QUERY: exports.OpCode.Query,
|
|
92
|
+
PUT_PATH: exports.OpCode.PutPath,
|
|
93
|
+
GET_PATH: exports.OpCode.GetPath,
|
|
94
|
+
SCAN: exports.OpCode.Scan,
|
|
95
|
+
CHECKPOINT: exports.OpCode.Checkpoint,
|
|
96
|
+
STATS: exports.OpCode.Stats,
|
|
97
|
+
PING: exports.OpCode.Ping,
|
|
98
|
+
OK: exports.OpCode.OK,
|
|
99
|
+
ERROR: exports.OpCode.Error,
|
|
100
|
+
VALUE: exports.OpCode.Value,
|
|
101
|
+
TXN_ID: exports.OpCode.TxnId,
|
|
102
|
+
ROW: exports.OpCode.Row,
|
|
103
|
+
END_STREAM: exports.OpCode.EndStream,
|
|
104
|
+
STATS_RESP: exports.OpCode.StatsResp,
|
|
105
|
+
PONG: exports.OpCode.Pong,
|
|
106
|
+
};
|
|
107
|
+
const MAX_MESSAGE_SIZE = 16 * 1024 * 1024; // 16 MB
|
|
108
|
+
/**
|
|
109
|
+
* IPC Client for SochDB.
|
|
110
|
+
*
|
|
111
|
+
* Connects to a SochDB server via Unix domain socket.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* import { IpcClient } from '@sushanth/sochdb';
|
|
116
|
+
*
|
|
117
|
+
* const client = await IpcClient.connect('/tmp/sochdb.sock');
|
|
118
|
+
*
|
|
119
|
+
* await client.put(Buffer.from('key'), Buffer.from('value'));
|
|
120
|
+
* const value = await client.get(Buffer.from('key'));
|
|
121
|
+
*
|
|
122
|
+
* await client.close();
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
class IpcClient {
|
|
126
|
+
_socket = null;
|
|
127
|
+
_config;
|
|
128
|
+
_pendingReads = [];
|
|
129
|
+
_readBuffer = Buffer.alloc(0);
|
|
130
|
+
_closed = false;
|
|
131
|
+
constructor(config) {
|
|
132
|
+
this._config = {
|
|
133
|
+
connectTimeout: 5000,
|
|
134
|
+
readTimeout: 30000,
|
|
135
|
+
...config,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Connect to a SochDB IPC server.
|
|
140
|
+
*
|
|
141
|
+
* @param socketPath - Path to the Unix domain socket
|
|
142
|
+
* @returns A connected IpcClient instance
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```typescript
|
|
146
|
+
* const client = await IpcClient.connect('/tmp/sochdb.sock');
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
static async connect(socketPath) {
|
|
150
|
+
const client = new IpcClient({ socketPath });
|
|
151
|
+
await client._connect();
|
|
152
|
+
return client;
|
|
153
|
+
}
|
|
154
|
+
async _connect() {
|
|
155
|
+
return new Promise((resolve, reject) => {
|
|
156
|
+
const socket = net.createConnection({ path: this._config.socketPath }, () => {
|
|
157
|
+
this._socket = socket;
|
|
158
|
+
resolve();
|
|
159
|
+
});
|
|
160
|
+
socket.setTimeout(this._config.connectTimeout);
|
|
161
|
+
socket.on('timeout', () => {
|
|
162
|
+
socket.destroy();
|
|
163
|
+
reject(new errors_1.ConnectionError('Connection timeout'));
|
|
164
|
+
});
|
|
165
|
+
socket.on('error', (err) => {
|
|
166
|
+
reject(new errors_1.ConnectionError(`Connection failed: ${err.message}`));
|
|
167
|
+
});
|
|
168
|
+
socket.on('data', (data) => {
|
|
169
|
+
this._readBuffer = Buffer.concat([this._readBuffer, data]);
|
|
170
|
+
this._processBuffer();
|
|
171
|
+
});
|
|
172
|
+
socket.on('close', () => {
|
|
173
|
+
this._closed = true;
|
|
174
|
+
for (const pending of this._pendingReads) {
|
|
175
|
+
pending.reject(new errors_1.ConnectionError('Connection closed'));
|
|
176
|
+
}
|
|
177
|
+
this._pendingReads = [];
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
_processBuffer() {
|
|
182
|
+
// Process complete messages from the buffer
|
|
183
|
+
while (this._readBuffer.length >= 5 && this._pendingReads.length > 0) {
|
|
184
|
+
const length = this._readBuffer.readUInt32LE(1);
|
|
185
|
+
const totalLength = 5 + length;
|
|
186
|
+
if (this._readBuffer.length >= totalLength) {
|
|
187
|
+
const message = this._readBuffer.subarray(0, totalLength);
|
|
188
|
+
this._readBuffer = this._readBuffer.subarray(totalLength);
|
|
189
|
+
const pending = this._pendingReads.shift();
|
|
190
|
+
if (pending) {
|
|
191
|
+
pending.resolve(message);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
async _send(opcode, payload = Buffer.alloc(0)) {
|
|
200
|
+
if (this._closed || !this._socket) {
|
|
201
|
+
throw new errors_1.ConnectionError('Not connected');
|
|
202
|
+
}
|
|
203
|
+
// Encode message: opcode (1) + length (4 LE) + payload
|
|
204
|
+
const message = Buffer.alloc(5 + payload.length);
|
|
205
|
+
message.writeUInt8(opcode, 0);
|
|
206
|
+
message.writeUInt32LE(payload.length, 1);
|
|
207
|
+
payload.copy(message, 5);
|
|
208
|
+
return new Promise((resolve, reject) => {
|
|
209
|
+
this._pendingReads.push({ resolve, reject });
|
|
210
|
+
this._socket.write(message, (err) => {
|
|
211
|
+
if (err) {
|
|
212
|
+
this._pendingReads.pop();
|
|
213
|
+
reject(new errors_1.ConnectionError(`Write failed: ${err.message}`));
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
// Set timeout for response
|
|
217
|
+
setTimeout(() => {
|
|
218
|
+
const idx = this._pendingReads.findIndex((p) => p.resolve === resolve);
|
|
219
|
+
if (idx !== -1) {
|
|
220
|
+
this._pendingReads.splice(idx, 1);
|
|
221
|
+
reject(new errors_1.ConnectionError('Read timeout'));
|
|
222
|
+
}
|
|
223
|
+
}, this._config.readTimeout);
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
_parseResponse(response) {
|
|
227
|
+
const opcode = response.readUInt8(0);
|
|
228
|
+
const length = response.readUInt32LE(1);
|
|
229
|
+
const payload = response.subarray(5, 5 + length);
|
|
230
|
+
if (opcode === InternalOpCode.ERROR) {
|
|
231
|
+
throw new errors_1.ProtocolError(payload.toString('utf8'));
|
|
232
|
+
}
|
|
233
|
+
return { opcode, payload };
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Encode a key for the wire protocol.
|
|
237
|
+
* @internal
|
|
238
|
+
*/
|
|
239
|
+
static encodeKey(key) {
|
|
240
|
+
// Format: [length:4][op:1][key_len:4][key:...]
|
|
241
|
+
const msgLen = 1 + 4 + key.length;
|
|
242
|
+
const msg = Buffer.alloc(4 + msgLen);
|
|
243
|
+
msg.writeUInt32BE(msgLen, 0);
|
|
244
|
+
msg.writeUInt8(InternalOpCode.GET, 4);
|
|
245
|
+
msg.writeUInt32BE(key.length, 5);
|
|
246
|
+
key.copy(msg, 9);
|
|
247
|
+
return msg;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Encode a key-value pair for the wire protocol.
|
|
251
|
+
* @internal
|
|
252
|
+
*/
|
|
253
|
+
static encodeKeyValue(key, value) {
|
|
254
|
+
// Format: [length:4][op:1][key_len:4][key:...][value_len:4][value:...]
|
|
255
|
+
const msgLen = 1 + 4 + key.length + 4 + value.length;
|
|
256
|
+
const msg = Buffer.alloc(4 + msgLen);
|
|
257
|
+
msg.writeUInt32BE(msgLen, 0);
|
|
258
|
+
msg.writeUInt8(InternalOpCode.PUT, 4);
|
|
259
|
+
msg.writeUInt32BE(key.length, 5);
|
|
260
|
+
key.copy(msg, 9);
|
|
261
|
+
msg.writeUInt32BE(value.length, 9 + key.length);
|
|
262
|
+
value.copy(msg, 13 + key.length);
|
|
263
|
+
return msg;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Get a value by key.
|
|
267
|
+
*/
|
|
268
|
+
async get(key) {
|
|
269
|
+
const response = await this._send(InternalOpCode.GET, key);
|
|
270
|
+
const { opcode, payload } = this._parseResponse(response);
|
|
271
|
+
if (opcode === InternalOpCode.VALUE) {
|
|
272
|
+
// If payload is empty, the key doesn't exist
|
|
273
|
+
if (payload.length === 0) {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
return payload;
|
|
277
|
+
}
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Put a key-value pair.
|
|
282
|
+
*/
|
|
283
|
+
async put(key, value) {
|
|
284
|
+
// Encode: key_len (4 LE) + key + value
|
|
285
|
+
const payload = Buffer.alloc(4 + key.length + value.length);
|
|
286
|
+
payload.writeUInt32LE(key.length, 0);
|
|
287
|
+
key.copy(payload, 4);
|
|
288
|
+
value.copy(payload, 4 + key.length);
|
|
289
|
+
const response = await this._send(InternalOpCode.PUT, payload);
|
|
290
|
+
this._parseResponse(response);
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Delete a key.
|
|
294
|
+
*/
|
|
295
|
+
async delete(key) {
|
|
296
|
+
const response = await this._send(InternalOpCode.DELETE, key);
|
|
297
|
+
this._parseResponse(response);
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Get a value by path.
|
|
301
|
+
* Wire format: path_count(2 LE) + [path_len(2 LE) + path_segment]...
|
|
302
|
+
*/
|
|
303
|
+
async getPath(path) {
|
|
304
|
+
// Encode path as single segment for now (could split on '/' for multi-segment)
|
|
305
|
+
const pathBuf = Buffer.from(path, 'utf8');
|
|
306
|
+
const payload = Buffer.alloc(2 + 2 + pathBuf.length);
|
|
307
|
+
payload.writeUInt16LE(1, 0); // path_count = 1
|
|
308
|
+
payload.writeUInt16LE(pathBuf.length, 2); // path_len
|
|
309
|
+
pathBuf.copy(payload, 4); // path
|
|
310
|
+
const response = await this._send(InternalOpCode.GET_PATH, payload);
|
|
311
|
+
const { opcode, payload: responsePayload } = this._parseResponse(response);
|
|
312
|
+
if (opcode === InternalOpCode.VALUE) {
|
|
313
|
+
// If payload is empty, the key doesn't exist
|
|
314
|
+
if (responsePayload.length === 0) {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
return responsePayload;
|
|
318
|
+
}
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Put a value at a path.
|
|
323
|
+
* Wire format: path_count(2 LE) + [path_len(2 LE) + path_segment]... + value
|
|
324
|
+
*/
|
|
325
|
+
async putPath(path, value) {
|
|
326
|
+
const pathBuf = Buffer.from(path, 'utf8');
|
|
327
|
+
const payload = Buffer.alloc(2 + 2 + pathBuf.length + value.length);
|
|
328
|
+
payload.writeUInt16LE(1, 0); // path_count = 1
|
|
329
|
+
payload.writeUInt16LE(pathBuf.length, 2); // path_len
|
|
330
|
+
pathBuf.copy(payload, 4); // path
|
|
331
|
+
value.copy(payload, 4 + pathBuf.length); // value
|
|
332
|
+
const response = await this._send(InternalOpCode.PUT_PATH, payload);
|
|
333
|
+
this._parseResponse(response);
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Execute a query and return TOON-formatted results.
|
|
337
|
+
*
|
|
338
|
+
* Wire format: path_len(2) + path + limit(4) + offset(4) + cols_count(2) + [col_len(2) + col]...
|
|
339
|
+
*/
|
|
340
|
+
async query(pathPrefix, options) {
|
|
341
|
+
const opts = options || {};
|
|
342
|
+
const pathBuf = Buffer.from(pathPrefix, 'utf8');
|
|
343
|
+
const columns = opts.columns || [];
|
|
344
|
+
// Calculate payload size
|
|
345
|
+
let size = 2 + pathBuf.length + 4 + 4 + 2;
|
|
346
|
+
for (const col of columns) {
|
|
347
|
+
size += 2 + Buffer.byteLength(col, 'utf8');
|
|
348
|
+
}
|
|
349
|
+
const payload = Buffer.alloc(size);
|
|
350
|
+
let offset = 0;
|
|
351
|
+
// Path: path_len(2 LE) + path
|
|
352
|
+
payload.writeUInt16LE(pathBuf.length, offset);
|
|
353
|
+
offset += 2;
|
|
354
|
+
pathBuf.copy(payload, offset);
|
|
355
|
+
offset += pathBuf.length;
|
|
356
|
+
// Limit (4 LE) - 0 means no limit
|
|
357
|
+
payload.writeUInt32LE(opts.limit || 0, offset);
|
|
358
|
+
offset += 4;
|
|
359
|
+
// Offset (4 LE)
|
|
360
|
+
payload.writeUInt32LE(opts.offset || 0, offset);
|
|
361
|
+
offset += 4;
|
|
362
|
+
// Columns: count(2 LE) + [col_len(2 LE) + col]...
|
|
363
|
+
payload.writeUInt16LE(columns.length, offset);
|
|
364
|
+
offset += 2;
|
|
365
|
+
for (const col of columns) {
|
|
366
|
+
const colBuf = Buffer.from(col, 'utf8');
|
|
367
|
+
payload.writeUInt16LE(colBuf.length, offset);
|
|
368
|
+
offset += 2;
|
|
369
|
+
colBuf.copy(payload, offset);
|
|
370
|
+
offset += colBuf.length;
|
|
371
|
+
}
|
|
372
|
+
const response = await this._send(InternalOpCode.QUERY, payload);
|
|
373
|
+
const { payload: resultPayload } = this._parseResponse(response);
|
|
374
|
+
return resultPayload.toString('utf8');
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Scan for keys with a prefix, returning key-value pairs.
|
|
378
|
+
* This is the preferred method for simple prefix-based iteration.
|
|
379
|
+
*
|
|
380
|
+
* Wire format: prefix string
|
|
381
|
+
* Response format: count(4 LE) + [key_len(2 LE) + key + val_len(4 LE) + val]...
|
|
382
|
+
*/
|
|
383
|
+
async scan(prefix) {
|
|
384
|
+
const prefixBuf = Buffer.from(prefix, 'utf8');
|
|
385
|
+
const response = await this._send(InternalOpCode.SCAN, prefixBuf);
|
|
386
|
+
const { opcode, payload } = this._parseResponse(response);
|
|
387
|
+
if (opcode !== InternalOpCode.VALUE && opcode !== InternalOpCode.OK) {
|
|
388
|
+
throw new errors_1.ProtocolError(`Unexpected scan response opcode: 0x${opcode.toString(16)}`);
|
|
389
|
+
}
|
|
390
|
+
if (payload.length < 4) {
|
|
391
|
+
return []; // Empty result
|
|
392
|
+
}
|
|
393
|
+
// Parse response: count(4 LE) + [key_len(2 LE) + key + val_len(4 LE) + val]...
|
|
394
|
+
const count = payload.readUInt32LE(0);
|
|
395
|
+
const results = [];
|
|
396
|
+
let offset = 4;
|
|
397
|
+
for (let i = 0; i < count; i++) {
|
|
398
|
+
if (offset + 2 > payload.length) {
|
|
399
|
+
throw new errors_1.ProtocolError('Truncated scan response (key_len)');
|
|
400
|
+
}
|
|
401
|
+
const keyLen = payload.readUInt16LE(offset);
|
|
402
|
+
offset += 2;
|
|
403
|
+
if (offset + keyLen + 4 > payload.length) {
|
|
404
|
+
throw new errors_1.ProtocolError('Truncated scan response (key+val_len)');
|
|
405
|
+
}
|
|
406
|
+
const key = payload.subarray(offset, offset + keyLen);
|
|
407
|
+
offset += keyLen;
|
|
408
|
+
const valLen = payload.readUInt32LE(offset);
|
|
409
|
+
offset += 4;
|
|
410
|
+
if (offset + valLen > payload.length) {
|
|
411
|
+
throw new errors_1.ProtocolError('Truncated scan response (value)');
|
|
412
|
+
}
|
|
413
|
+
const value = payload.subarray(offset, offset + valLen);
|
|
414
|
+
offset += valLen;
|
|
415
|
+
results.push({ key, value });
|
|
416
|
+
}
|
|
417
|
+
return results;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Create a query builder.
|
|
421
|
+
*/
|
|
422
|
+
queryBuilder(pathPrefix) {
|
|
423
|
+
return new query_1.Query(this, pathPrefix);
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Begin a new transaction.
|
|
427
|
+
*/
|
|
428
|
+
async beginTransaction() {
|
|
429
|
+
const response = await this._send(InternalOpCode.BEGIN_TXN);
|
|
430
|
+
const { opcode, payload } = this._parseResponse(response);
|
|
431
|
+
if (opcode === InternalOpCode.TXN_ID) {
|
|
432
|
+
return payload.readBigUInt64LE(0);
|
|
433
|
+
}
|
|
434
|
+
throw new errors_1.TransactionError('Failed to begin transaction');
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Commit a transaction.
|
|
438
|
+
*/
|
|
439
|
+
async commitTransaction(txnId) {
|
|
440
|
+
const payload = Buffer.alloc(8);
|
|
441
|
+
payload.writeBigUInt64LE(txnId, 0);
|
|
442
|
+
const response = await this._send(InternalOpCode.COMMIT_TXN, payload);
|
|
443
|
+
this._parseResponse(response);
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Abort a transaction.
|
|
447
|
+
*/
|
|
448
|
+
async abortTransaction(txnId) {
|
|
449
|
+
const payload = Buffer.alloc(8);
|
|
450
|
+
payload.writeBigUInt64LE(txnId, 0);
|
|
451
|
+
const response = await this._send(InternalOpCode.ABORT_TXN, payload);
|
|
452
|
+
this._parseResponse(response);
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Force a checkpoint.
|
|
456
|
+
*/
|
|
457
|
+
async checkpoint() {
|
|
458
|
+
const response = await this._send(InternalOpCode.CHECKPOINT);
|
|
459
|
+
this._parseResponse(response);
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Get storage statistics.
|
|
463
|
+
*/
|
|
464
|
+
async stats() {
|
|
465
|
+
const response = await this._send(InternalOpCode.STATS);
|
|
466
|
+
const { payload } = this._parseResponse(response);
|
|
467
|
+
const json = JSON.parse(payload.toString('utf8'));
|
|
468
|
+
return {
|
|
469
|
+
memtableSizeBytes: json.memtable_size_bytes || 0,
|
|
470
|
+
walSizeBytes: json.wal_size_bytes || 0,
|
|
471
|
+
activeTransactions: json.active_transactions || 0,
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Ping the server.
|
|
476
|
+
*/
|
|
477
|
+
async ping() {
|
|
478
|
+
try {
|
|
479
|
+
const response = await this._send(InternalOpCode.PING);
|
|
480
|
+
const { opcode } = this._parseResponse(response);
|
|
481
|
+
return opcode === InternalOpCode.PONG;
|
|
482
|
+
}
|
|
483
|
+
catch {
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Close the connection.
|
|
489
|
+
*/
|
|
490
|
+
async close() {
|
|
491
|
+
if (this._closed)
|
|
492
|
+
return;
|
|
493
|
+
this._closed = true;
|
|
494
|
+
if (this._socket) {
|
|
495
|
+
return new Promise((resolve) => {
|
|
496
|
+
this._socket.end(() => {
|
|
497
|
+
this._socket = null;
|
|
498
|
+
resolve();
|
|
499
|
+
});
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
exports.IpcClient = IpcClient;
|
|
505
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXBjLWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9pcGMtY2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7O0dBTUc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUVILDBEQUEwRDtBQUMxRCxFQUFFO0FBQ0Ysa0VBQWtFO0FBQ2xFLG1FQUFtRTtBQUNuRSwwQ0FBMEM7QUFDMUMsRUFBRTtBQUNGLGlEQUFpRDtBQUVqRCx5Q0FBMkI7QUFDM0IscUNBQTRFO0FBQzVFLG1DQUFnQztBQUVoQzs7R0FFRztBQUNVLFFBQUEsTUFBTSxHQUFHO0lBQ3BCLGdFQUFnRTtJQUNoRSxHQUFHLEVBQUUsSUFBSTtJQUNULEdBQUcsRUFBRSxJQUFJO0lBQ1QsTUFBTSxFQUFFLElBQUk7SUFDWixRQUFRLEVBQUUsSUFBSTtJQUNkLFNBQVMsRUFBRSxJQUFJO0lBQ2YsUUFBUSxFQUFFLElBQUk7SUFDZCxLQUFLLEVBQUUsSUFBSTtJQUNYLFdBQVcsRUFBRSxJQUFJO0lBQ2pCLE9BQU8sRUFBRSxJQUFJO0lBQ2IsT0FBTyxFQUFFLElBQUk7SUFDYixJQUFJLEVBQUUsSUFBSTtJQUNWLFVBQVUsRUFBRSxJQUFJO0lBQ2hCLEtBQUssRUFBRSxJQUFJO0lBQ1gsSUFBSSxFQUFFLElBQUk7SUFFVixrQkFBa0I7SUFDbEIsRUFBRSxFQUFFLElBQUk7SUFDUixLQUFLLEVBQUUsSUFBSTtJQUNYLEtBQUssRUFBRSxJQUFJO0lBQ1gsS0FBSyxFQUFFLElBQUk7SUFDWCxHQUFHLEVBQUUsSUFBSTtJQUNULFNBQVMsRUFBRSxJQUFJO0lBQ2YsU0FBUyxFQUFFLElBQUk7SUFDZixJQUFJLEVBQUUsSUFBSTtDQUNGLENBQUM7QUFFWCxrREFBa0Q7QUFDbEQsTUFBTSxjQUFjLEdBQUc7SUFDckIsR0FBRyxFQUFFLGNBQU0sQ0FBQyxHQUFHO0lBQ2YsR0FBRyxFQUFFLGNBQU0sQ0FBQyxHQUFHO0lBQ2YsTUFB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QUFDO1NBQ2xELENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsSUFBSTtRQUNSLElBQUksQ0FBQztZQUNILE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDdkQsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDakQsT0FBTyxNQUFNLEtBQUssY0FBYyxDQUFDLElBQUksQ0FBQztRQUN4QyxDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1AsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLEtBQUs7UUFDVCxJQUFJLElBQUksQ0FBQyxPQUFPO1lBQUUsT0FBTztRQUN6QixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQztRQUVwQixJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNqQixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7Z0JBQzdCLElBQUksQ0FBQyxPQUFRLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRTtvQkFDckIsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7b0JBQ3BCLE9BQU8sRUFBRSxDQUFDO2dCQUNaLENBQUMsQ0FBQyxDQUFDO1lBQ0wsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBaGNELDhCQWdjQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU29jaERCIElQQyBDbGllbnRcbiAqXG4gKiBDb25uZWN0cyB0byBhIFNvY2hEQiBJUEMgc2VydmVyIHZpYSBVbml4IGRvbWFpbiBzb2NrZXQuXG4gKlxuICogQHBhY2thZ2VEb2N1bWVudGF0aW9uXG4gKi9cblxuLy8gQ29weXJpZ2h0IDIwMjUgU3VzaGFudGggKGh0dHBzOi8vZ2l0aHViLmNvbS9zdXNoYW50aHB5KVxuLy9cbi8vIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4vLyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4vLyBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbi8vXG4vLyAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG5cbmltcG9ydCAqIGFzIG5ldCBmcm9tICduZXQnO1xuaW1wb3J0IHsgQ29ubmVjdGlvbkVycm9yLCBQcm90b2NvbEVycm9yLCBUcmFuc2FjdGlvbkVycm9yIH0gZnJvbSAnLi9lcnJvcnMnO1xuaW1wb3J0IHsgUXVlcnkgfSBmcm9tICcuL3F1ZXJ5JztcblxuLyoqXG4gKiBXaXJlIHByb3RvY29sIG9wY29kZXMuXG4gKi9cbmV4cG9ydCBjb25zdCBPcENvZGUgPSB7XG4gIC8vIENsaWVudCDihpIgU2VydmVyIChtdXN0IG1hdGNoIHNvY2hkYi1zdG9yYWdlL3NyYy9pcGNfc2VydmVyLnJzKVxuICBQdXQ6IDB4MDEsXG4gIEdldDogMHgwMixcbiAgRGVsZXRlOiAweDAzLFxuICBCZWdpblR4bjogMHgwNCxcbiAgQ29tbWl0VHhuOiAweDA1LFxuICBBYm9ydFR4bjogMHgwNixcbiAgUXVlcnk6IDB4MDcsXG4gIENyZWF0ZVRhYmxlOiAweDA4LFxuICBQdXRQYXRoOiAweDA5LFxuICBHZXRQYXRoOiAweDBBLFxuICBTY2FuOiAweDBCLFxuICBDaGVja3BvaW50OiAweDBDLFxuICBTdGF0czogMHgwRCxcbiAgUGluZzogMHgwRSxcblxuICAvLyBTZXJ2ZXIg4oaSIENsaWVudFxuICBPSzogMHg4MCxcbiAgRXJyb3I6IDB4ODEsXG4gIFZhbHVlOiAweDgyLFxuICBUeG5JZDogMHg4MyxcbiAgUm93OiAweDg0LFxuICBFbmRTdHJlYW06IDB4ODUsXG4gIFN0YXRzUmVzcDogMHg4NixcbiAgUG9uZzogMHg4Nyxcbn0gYXMgY29uc3Q7XG5cbi8vIEludGVybmFsIE9wQ29kZSBtYXAgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5XG5jb25zdCBJbnRlcm5hbE9wQ29kZSA9IHtcbiAgUFVUOiBPcENvZGUuUHV0LFxuICBHRVQ6IE9wQ29kZS5HZXQsXG4gIERFTEVURTogT3BDb2RlLkRlbGV0ZSxcbiAgQkVHSU5fVFhOOiBPcENvZGUuQmVnaW5UeG4sXG4gIENPTU1JVF9UWE46IE9wQ29kZS5Db21taXRUeG4sXG4gIEFCT1JUX1RYTjogT3BDb2RlLkFib3J0VHhuLFxuICBRVUVSWTogT3BDb2RlLlF1ZXJ5LFxuICBQVVRfUEFUSDogT3BDb2RlLlB1dFBhdGgsXG4gIEdFVF9QQVRIOiBPcENvZGUuR2V0UGF0aCxcbiAgU0NBTjogT3BDb2RlLlNjYW4sXG4gIENIRUNLUE9JTlQ6IE9wQ29kZS5DaGVja3BvaW50LFxuICBTVEFUUzogT3BDb2RlLlN0YXRzLFxuICBQSU5HOiBPcENvZGUuUGluZyxcbiAgT0s6IE9wQ29kZS5PSyxcbiAgRVJST1I6IE9wQ29kZS5FcnJvcixcbiAgVkFMVUU6IE9wQ29kZS5WYWx1ZSxcbiAgVFhOX0lEOiBPcENvZGUuVHhuSWQsXG4gIFJPVzogT3BDb2RlLlJvdyxcbiAgRU5EX1NUUkVBTTogT3BDb2RlLkVuZFN0cmVhbSxcbiAgU1RBVFNfUkVTUDogT3BDb2RlLlN0YXRzUmVzcCxcbiAgUE9ORzogT3BDb2RlLlBvbmcsXG59IGFzIGNvbnN0O1xuXG5jb25zdCBNQVhfTUVTU0FHRV9TSVpFID0gMTYgKiAxMDI0ICogMTAyNDsgLy8gMTYgTUJcblxuLyoqXG4gKiBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIElwY0NsaWVudC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJcGNDbGllbnRDb25maWcge1xuICAvKiogUGF0aCB0byBVbml4IGRvbWFpbiBzb2NrZXQgKi9cbiAgc29ja2V0UGF0aDogc3RyaW5nO1xuICAvKiogQ29ubmVjdGlvbiB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcyAoZGVmYXVsdDogNTAwMCkgKi9cbiAgY29ubmVjdFRpbWVvdXQ/OiBudW1iZXI7XG4gIC8qKiBSZWFkIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIChkZWZhdWx0OiAzMDAwMCkgKi9cbiAgcmVhZFRpbWVvdXQ/OiBudW1iZXI7XG59XG5cbi8qKlxuICogSVBDIENsaWVudCBmb3IgU29jaERCLlxuICpcbiAqIENvbm5lY3RzIHRvIGEgU29jaERCIHNlcnZlciB2aWEgVW5peCBkb21haW4gc29ja2V0LlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBJcGNDbGllbnQgfSBmcm9tICdAc3VzaGFudGgvc29jaGRiJztcbiAqXG4gKiBjb25zdCBjbGllbnQgPSBhd2FpdCBJcGNDbGllbnQuY29ubmVjdCgnL3RtcC9zb2NoZGIuc29jaycpO1xuICpcbiAqIGF3YWl0IGNsaWVudC5wdXQoQnVmZmVyLmZyb20oJ2tleScpLCBCdWZmZXIuZnJvbSgndmFsdWUnKSk7XG4gKiBjb25zdCB2YWx1ZSA9IGF3YWl0IGNsaWVudC5nZXQoQnVmZmVyLmZyb20oJ2tleScpKTtcbiAqXG4gKiBhd2FpdCBjbGllbnQuY2xvc2UoKTtcbiAqIGBgYFxuICovXG5leHBvcnQgY2xhc3MgSXBjQ2xpZW50IHtcbiAgcHJpdmF0ZSBfc29ja2V0OiBuZXQuU29ja2V0IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgX2NvbmZpZzogUmVxdWlyZWQ8SXBjQ2xpZW50Q29uZmlnPjtcbiAgcHJpdmF0ZSBfcGVuZGluZ1JlYWRzOiBBcnJheTx7XG4gICAgcmVzb2x2ZTogKGJ1ZjogQnVmZmVyKSA9PiB2b2lkO1xuICAgIHJlamVjdDogKGVycjogRXJyb3IpID0+IHZvaWQ7XG4gIH0+ID0gW107XG4gIHByaXZhdGUgX3JlYWRCdWZmZXI6IEJ1ZmZlciA9IEJ1ZmZlci5hbGxvYygwKTtcbiAgcHJpdmF0ZSBfY2xvc2VkID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSBjb25zdHJ1Y3Rvcihjb25maWc6IElwY0NsaWVudENvbmZpZykge1xuICAgIHRoaXMuX2NvbmZpZyA9IHtcbiAgICAgIGNvbm5lY3RUaW1lb3V0OiA1MDAwLFxuICAgICAgcmVhZFRpbWVvdXQ6IDMwMDAwLFxuICAgICAgLi4uY29uZmlnLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQ29ubmVjdCB0byBhIFNvY2hEQiBJUEMgc2VydmVyLlxuICAgKlxuICAgKiBAcGFyYW0gc29ja2V0UGF0aCAtIFBhdGggdG8gdGhlIFVuaXggZG9tYWluIHNvY2tldFxuICAgKiBAcmV0dXJucyBBIGNvbm5lY3RlZCBJcGNDbGllbnQgaW5zdGFuY2VcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCBjbGllbnQgPSBhd2FpdCBJcGNDbGllbnQuY29ubmVjdCgnL3RtcC9zb2NoZGIuc29jaycpO1xuICAgKiBgYGBcbiAgICovXG4gIHN0YXRpYyBhc3luYyBjb25uZWN0KHNvY2tldFBhdGg6IHN0cmluZyk6IFByb21pc2U8SXBjQ2xpZW50PiB7XG4gICAgY29uc3QgY2xpZW50ID0gbmV3IElwY0NsaWVudCh7IHNvY2tldFBhdGggfSk7XG4gICAgYXdhaXQgY2xpZW50Ll9jb25uZWN0KCk7XG4gICAgcmV0dXJuIGNsaWVudDtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgX2Nvbm5lY3QoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGNvbnN0IHNvY2tldCA9IG5ldC5jcmVhdGVDb25uZWN0aW9uKFxuICAgICAgICB7IHBhdGg6IHRoaXMuX2NvbmZpZy5zb2NrZXRQYXRoIH0sXG4gICAgICAgICgpID0+IHtcbiAgICAgICAgICB0aGlzLl9zb2NrZXQgPSBzb2NrZXQ7XG4gICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICB9XG4gICAgICApO1xuXG4gICAgICBzb2NrZXQuc2V0VGltZW91dCh0aGlzLl9jb25maWcuY29ubmVjdFRpbWVvdXQpO1xuXG4gICAgICBzb2NrZXQub24oJ3RpbWVvdXQnLCAoKSA9PiB7XG4gICAgICAgIHNvY2tldC5kZXN0cm95KCk7XG4gICAgICAgIHJlamVjdChuZXcgQ29ubmVjdGlvbkVycm9yKCdDb25uZWN0aW9uIHRpbWVvdXQnKSk7XG4gICAgICB9KTtcblxuICAgICAgc29ja2V0Lm9uKCdlcnJvcicsIChlcnIpID0+IHtcbiAgICAgICAgcmVqZWN0KG5ldyBDb25uZWN0aW9uRXJyb3IoYENvbm5lY3Rpb24gZmFpbGVkOiAke2Vyci5tZXNzYWdlfWApKTtcbiAgICAgIH0pO1xuXG4gICAgICBzb2NrZXQub24oJ2RhdGEnLCAoZGF0YSkgPT4ge1xuICAgICAgICB0aGlzLl9yZWFkQnVmZmVyID0gQnVmZmVyLmNvbmNhdChbdGhpcy5fcmVhZEJ1ZmZlciwgZGF0YV0pO1xuICAgICAgICB0aGlzLl9wcm9jZXNzQnVmZmVyKCk7XG4gICAgICB9KTtcblxuICAgICAgc29ja2V0Lm9uKCdjbG9zZScsICgpID0+IHtcbiAgICAgICAgdGhpcy5fY2xvc2VkID0gdHJ1ZTtcbiAgICAgICAgZm9yIChjb25zdCBwZW5kaW5nIG9mIHRoaXMuX3BlbmRpbmdSZWFkcykge1xuICAgICAgICAgIHBlbmRpbmcucmVqZWN0KG5ldyBDb25uZWN0aW9uRXJyb3IoJ0Nvbm5lY3Rpb24gY2xvc2VkJykpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX3BlbmRpbmdSZWFkcyA9IFtdO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIF9wcm9jZXNzQnVmZmVyKCk6IHZvaWQge1xuICAgIC8vIFByb2Nlc3MgY29tcGxldGUgbWVzc2FnZXMgZnJvbSB0aGUgYnVmZmVyXG4gICAgd2hpbGUgKHRoaXMuX3JlYWRCdWZmZXIubGVuZ3RoID49IDUgJiYgdGhpcy5fcGVuZGluZ1JlYWRzLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IGxlbmd0aCA9IHRoaXMuX3JlYWRCdWZmZXIucmVhZFVJbnQzMkxFKDEpO1xuICAgICAgY29uc3QgdG90YWxMZW5ndGggPSA1ICsgbGVuZ3RoO1xuXG4gICAgICBpZiAodGhpcy5fcmVhZEJ1ZmZlci5sZW5ndGggPj0gdG90YWxMZW5ndGgpIHtcbiAgICAgICAgY29uc3QgbWVzc2FnZSA9IHRoaXMuX3JlYWRCdWZmZXIuc3ViYXJyYXkoMCwgdG90YWxMZW5ndGgpO1xuICAgICAgICB0aGlzLl9yZWFkQnVmZmVyID0gdGhpcy5fcmVhZEJ1ZmZlci5zdWJhcnJheSh0b3RhbExlbmd0aCk7XG5cbiAgICAgICAgY29uc3QgcGVuZGluZyA9IHRoaXMuX3BlbmRpbmdSZWFkcy5zaGlmdCgpO1xuICAgICAgICBpZiAocGVuZGluZykge1xuICAgICAgICAgIHBlbmRpbmcucmVzb2x2ZShtZXNzYWdlKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBfc2VuZChvcGNvZGU6IG51bWJlciwgcGF5bG9hZDogQnVmZmVyID0gQnVmZmVyLmFsbG9jKDApKTogUHJvbWlzZTxCdWZmZXI+IHtcbiAgICBpZiAodGhpcy5fY2xvc2VkIHx8ICF0aGlzLl9zb2NrZXQpIHtcbiAgICAgIHRocm93IG5ldyBDb25uZWN0aW9uRXJyb3IoJ05vdCBjb25uZWN0ZWQnKTtcbiAgICB9XG5cbiAgICAvLyBFbmNvZGUgbWVzc2FnZTogb3Bjb2RlICgxKSArIGxlbmd0aCAoNCBMRSkgKyBwYXlsb2FkXG4gICAgY29uc3QgbWVzc2FnZSA9IEJ1ZmZlci5hbGxvYyg1ICsgcGF5bG9hZC5sZW5ndGgpO1xuICAgIG1lc3NhZ2Uud3JpdGVVSW50OChvcGNvZGUsIDApO1xuICAgIG1lc3NhZ2Uud3JpdGVVSW50MzJMRShwYXlsb2FkLmxlbmd0aCwgMSk7XG4gICAgcGF5bG9hZC5jb3B5KG1lc3NhZ2UsIDUpO1xuXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHRoaXMuX3BlbmRpbmdSZWFkcy5wdXNoKHsgcmVzb2x2ZSwgcmVqZWN0IH0pO1xuXG4gICAgICB0aGlzLl9zb2NrZXQhLndyaXRlKG1lc3NhZ2UsIChlcnIpID0+IHtcbiAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgIHRoaXMuX3BlbmRpbmdSZWFkcy5wb3AoKTtcbiAgICAgICAgICByZWplY3QobmV3IENvbm5lY3Rpb25FcnJvcihgV3JpdGUgZmFpbGVkOiAke2Vyci5tZXNzYWdlfWApKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIC8vIFNldCB0aW1lb3V0IGZvciByZXNwb25zZVxuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIGNvbnN0IGlkeCA9IHRoaXMuX3BlbmRpbmdSZWFkcy5maW5kSW5kZXgoKHApID0+IHAucmVzb2x2ZSA9PT0gcmVzb2x2ZSk7XG4gICAgICAgIGlmIChpZHggIT09IC0xKSB7XG4gICAgICAgICAgdGhpcy5fcGVuZGluZ1JlYWRzLnNwbGljZShpZHgsIDEpO1xuICAgICAgICAgIHJlamVjdChuZXcgQ29ubmVjdGlvbkVycm9yKCdSZWFkIHRpbWVvdXQnKSk7XG4gICAgICAgIH1cbiAgICAgIH0sIHRoaXMuX2NvbmZpZy5yZWFkVGltZW91dCk7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIF9wYXJzZVJlc3BvbnNlKHJlc3BvbnNlOiBCdWZmZXIpOiB7IG9wY29kZTogbnVtYmVyOyBwYXlsb2FkOiBCdWZmZXIgfSB7XG4gICAgY29uc3Qgb3Bjb2RlID0gcmVzcG9uc2UucmVhZFVJbnQ4KDApO1xuICAgIGNvbnN0IGxlbmd0aCA9IHJlc3BvbnNlLnJlYWRVSW50MzJMRSgxKTtcbiAgICBjb25zdCBwYXlsb2FkID0gcmVzcG9uc2Uuc3ViYXJyYXkoNSwgNSArIGxlbmd0aCk7XG5cbiAgICBpZiAob3Bjb2RlID09PSBJbnRlcm5hbE9wQ29kZS5FUlJPUikge1xuICAgICAgdGhyb3cgbmV3IFByb3RvY29sRXJyb3IocGF5bG9hZC50b1N0cmluZygndXRmOCcpKTtcbiAgICB9XG5cbiAgICByZXR1cm4geyBvcGNvZGUsIHBheWxvYWQgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbmNvZGUgYSBrZXkgZm9yIHRoZSB3aXJlIHByb3RvY29sLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHN0YXRpYyBlbmNvZGVLZXkoa2V5OiBCdWZmZXIpOiBCdWZmZXIge1xuICAgIC8vIEZvcm1hdDogW2xlbmd0aDo0XVtvcDoxXVtrZXlfbGVuOjRdW2tleTouLi5dXG4gICAgY29uc3QgbXNnTGVuID0gMSArIDQgKyBrZXkubGVuZ3RoO1xuICAgIGNvbnN0IG1zZyA9IEJ1ZmZlci5hbGxvYyg0ICsgbXNnTGVuKTtcbiAgICBtc2cud3JpdGVVSW50MzJCRShtc2dMZW4sIDApO1xuICAgIG1zZy53cml0ZVVJbnQ4KEludGVybmFsT3BDb2RlLkdFVCwgNCk7XG4gICAgbXNnLndyaXRlVUludDMyQkUoa2V5Lmxlbmd0aCwgNSk7XG4gICAga2V5LmNvcHkobXNnLCA5KTtcbiAgICByZXR1cm4gbXNnO1xuICB9XG5cbiAgLyoqXG4gICAqIEVuY29kZSBhIGtleS12YWx1ZSBwYWlyIGZvciB0aGUgd2lyZSBwcm90b2NvbC5cbiAgICogQGludGVybmFsXG4gICAqL1xuICBzdGF0aWMgZW5jb2RlS2V5VmFsdWUoa2V5OiBCdWZmZXIsIHZhbHVlOiBCdWZmZXIpOiBCdWZmZXIge1xuICAgIC8vIEZvcm1hdDogW2xlbmd0aDo0XVtvcDoxXVtrZXlfbGVuOjRdW2tleTouLi5dW3ZhbHVlX2xlbjo0XVt2YWx1ZTouLi5dXG4gICAgY29uc3QgbXNnTGVuID0gMSArIDQgKyBrZXkubGVuZ3RoICsgNCArIHZhbHVlLmxlbmd0aDtcbiAgICBjb25zdCBtc2cgPSBCdWZmZXIuYWxsb2MoNCArIG1zZ0xlbik7XG4gICAgbXNnLndyaXRlVUludDMyQkUobXNnTGVuLCAwKTtcbiAgICBtc2cud3JpdGVVSW50OChJbnRlcm5hbE9wQ29kZS5QVVQsIDQpO1xuICAgIG1zZy53cml0ZVVJbnQzMkJFKGtleS5sZW5ndGgsIDUpO1xuICAgIGtleS5jb3B5KG1zZywgOSk7XG4gICAgbXNnLndyaXRlVUludDMyQkUodmFsdWUubGVuZ3RoLCA5ICsga2V5Lmxlbmd0aCk7XG4gICAgdmFsdWUuY29weShtc2csIDEzICsga2V5Lmxlbmd0aCk7XG4gICAgcmV0dXJuIG1zZztcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgYSB2YWx1ZSBieSBrZXkuXG4gICAqL1xuICBhc3luYyBnZXQoa2V5OiBCdWZmZXIpOiBQcm9taXNlPEJ1ZmZlciB8IG51bGw+IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuX3NlbmQoSW50ZXJuYWxPcENvZGUuR0VULCBrZXkpO1xuICAgIGNvbnN0IHsgb3Bjb2RlLCBwYXlsb2FkIH0gPSB0aGlzLl9wYXJzZVJlc3BvbnNlKHJlc3BvbnNlKTtcblxuICAgIGlmIChvcGNvZGUgPT09IEludGVybmFsT3BDb2RlLlZBTFVFKSB7XG4gICAgICAvLyBJZiBwYXlsb2FkIGlzIGVtcHR5LCB0aGUga2V5IGRvZXNuJ3QgZXhpc3RcbiAgICAgIGlmIChwYXlsb2FkLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICAgIHJldHVybiBwYXlsb2FkO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBQdXQgYSBrZXktdmFsdWUgcGFpci5cbiAgICovXG4gIGFzeW5jIHB1dChrZXk6IEJ1ZmZlciwgdmFsdWU6IEJ1ZmZlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIEVuY29kZToga2V5X2xlbiAoNCBMRSkgKyBrZXkgKyB2YWx1ZVxuICAgIGNvbnN0IHBheWxvYWQgPSBCdWZmZXIuYWxsb2MoNCArIGtleS5sZW5ndGggKyB2YWx1ZS5sZW5ndGgpO1xuICAgIHBheWxvYWQud3JpdGVVSW50MzJMRShrZXkubGVuZ3RoLCAwKTtcbiAgICBrZXkuY29weShwYXlsb2FkLCA0KTtcbiAgICB2YWx1ZS5jb3B5KHBheWxvYWQsIDQgKyBrZXkubGVuZ3RoKTtcblxuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5fc2VuZChJbnRlcm5hbE9wQ29kZS5QVVQsIHBheWxvYWQpO1xuICAgIHRoaXMuX3BhcnNlUmVzcG9uc2UocmVzcG9uc2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIERlbGV0ZSBhIGtleS5cbiAgICovXG4gIGFzeW5jIGRlbGV0ZShrZXk6IEJ1ZmZlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5fc2VuZChJbnRlcm5hbE9wQ29kZS5ERUxFVEUsIGtleSk7XG4gICAgdGhpcy5fcGFyc2VSZXNwb25zZShyZXNwb25zZSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGEgdmFsdWUgYnkgcGF0aC5cbiAgICogV2lyZSBmb3JtYXQ6IHBhdGhfY291bnQoMiBMRSkgKyBbcGF0aF9sZW4oMiBMRSkgKyBwYXRoX3NlZ21lbnRdLi4uXG4gICAqL1xuICBhc3luYyBnZXRQYXRoKHBhdGg6IHN0cmluZyk6IFByb21pc2U8QnVmZmVyIHwgbnVsbD4ge1xuICAgIC8vIEVuY29kZSBwYXRoIGFzIHNpbmdsZSBzZWdtZW50IGZvciBub3cgKGNvdWxkIHNwbGl0IG9uICcvJyBmb3IgbXVsdGktc2VnbWVudClcbiAgICBjb25zdCBwYXRoQnVmID0gQnVmZmVyLmZyb20ocGF0aCwgJ3V0ZjgnKTtcbiAgICBjb25zdCBwYXlsb2FkID0gQnVmZmVyLmFsbG9jKDIgKyAyICsgcGF0aEJ1Zi5sZW5ndGgpO1xuICAgIHBheWxvYWQud3JpdGVVSW50MTZMRSgxLCAwKTsgLy8gcGF0aF9jb3VudCA9IDFcbiAgICBwYXlsb2FkLndyaXRlVUludDE2TEUocGF0aEJ1Zi5sZW5ndGgsIDIpOyAvLyBwYXRoX2xlblxuICAgIHBhdGhCdWYuY29weShwYXlsb2FkLCA0KTsgLy8gcGF0aFxuICAgIFxuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5fc2VuZChJbnRlcm5hbE9wQ29kZS5HRVRfUEFUSCwgcGF5bG9hZCk7XG4gICAgY29uc3QgeyBvcGNvZGUsIHBheWxvYWQ6IHJlc3BvbnNlUGF5bG9hZCB9ID0gdGhpcy5fcGFyc2VSZXNwb25zZShyZXNwb25zZSk7XG5cbiAgICBpZiAob3Bjb2RlID09PSBJbnRlcm5hbE9wQ29kZS5WQUxVRSkge1xuICAgICAgLy8gSWYgcGF5bG9hZCBpcyBlbXB0eSwgdGhlIGtleSBkb2Vzbid0IGV4aXN0XG4gICAgICBpZiAocmVzcG9uc2VQYXlsb2FkLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXNwb25zZVBheWxvYWQ7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFB1dCBhIHZhbHVlIGF0IGEgcGF0aC5cbiAgICogV2lyZSBmb3JtYXQ6IHBhdGhfY291bnQoMiBMRSkgKyBbcGF0aF9sZW4oMiBMRSkgKyBwYXRoX3NlZ21lbnRdLi4uICsgdmFsdWVcbiAgICovXG4gIGFzeW5jIHB1dFBhdGgocGF0aDogc3RyaW5nLCB2YWx1ZTogQnVmZmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcGF0aEJ1ZiA9IEJ1ZmZlci5mcm9tKHBhdGgsICd1dGY4Jyk7XG4gICAgY29uc3QgcGF5bG9hZCA9IEJ1ZmZlci5hbGxvYygyICsgMiArIHBhdGhCdWYubGVuZ3RoICsgdmFsdWUubGVuZ3RoKTtcbiAgICBwYXlsb2FkLndyaXRlVUludDE2TEUoMSwgMCk7IC8vIHBhdGhfY291bnQgPSAxXG4gICAgcGF5bG9hZC53cml0ZVVJbnQxNkxFKHBhdGhCdWYubGVuZ3RoLCAyKTsgLy8gcGF0aF9sZW5cbiAgICBwYXRoQnVmLmNvcHkocGF5bG9hZCwgNCk7IC8vIHBhdGhcbiAgICB2YWx1ZS5jb3B5KHBheWxvYWQsIDQgKyBwYXRoQnVmLmxlbmd0aCk7IC8vIHZhbHVlXG5cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuX3NlbmQoSW50ZXJuYWxPcENvZGUuUFVUX1BBVEgsIHBheWxvYWQpO1xuICAgIHRoaXMuX3BhcnNlUmVzcG9uc2UocmVzcG9uc2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4ZWN1dGUgYSBxdWVyeSBhbmQgcmV0dXJuIFRPT04tZm9ybWF0dGVkIHJlc3VsdHMuXG4gICAqIFxuICAgKiBXaXJlIGZvcm1hdDogcGF0aF9sZW4oMikgKyBwYXRoICsgbGltaXQoNCkgKyBvZmZzZXQoNCkgKyBjb2xzX2NvdW50KDIpICsgW2NvbF9sZW4oMikgKyBjb2xdLi4uXG4gICAqL1xuICBhc3luYyBxdWVyeShcbiAgICBwYXRoUHJlZml4OiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IHsgbGltaXQ/OiBudW1iZXI7IG9mZnNldD86IG51bWJlcjsgY29sdW1ucz86IHN0cmluZ1tdIH1cbiAgKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBvcHRzID0gb3B0aW9ucyB8fCB7fTtcbiAgICBjb25zdCBwYXRoQnVmID0gQnVmZmVyLmZyb20ocGF0aFByZWZpeCwgJ3V0ZjgnKTtcbiAgICBjb25zdCBjb2x1bW5zID0gb3B0cy5jb2x1bW5zIHx8IFtdO1xuICAgIFxuICAgIC8vIENhbGN1bGF0ZSBwYXlsb2FkIHNpemVcbiAgICBsZXQgc2l6ZSA9IDIgKyBwYXRoQnVmLmxlbmd0aCArIDQgKyA0ICsgMjtcbiAgICBmb3IgKGNvbnN0IGNvbCBvZiBjb2x1bW5zKSB7XG4gICAgICBzaXplICs9IDIgKyBCdWZmZXIuYnl0ZUxlbmd0aChjb2wsICd1dGY4Jyk7XG4gICAgfVxuICAgIFxuICAgIGNvbnN0IHBheWxvYWQgPSBCdWZmZXIuYWxsb2Moc2l6ZSk7XG4gICAgbGV0IG9mZnNldCA9IDA7XG4gICAgXG4gICAgLy8gUGF0aDogcGF0aF9sZW4oMiBMRSkgKyBwYXRoXG4gICAgcGF5bG9hZC53cml0ZVVJbnQxNkxFKHBhdGhCdWYubGVuZ3RoLCBvZmZzZXQpO1xuICAgIG9mZnNldCArPSAyO1xuICAgIHBhdGhCdWYuY29weShwYXlsb2FkLCBvZmZzZXQpO1xuICAgIG9mZnNldCArPSBwYXRoQnVmLmxlbmd0aDtcbiAgICBcbiAgICAvLyBMaW1pdCAoNCBMRSkgLSAwIG1lYW5zIG5vIGxpbWl0XG4gICAgcGF5bG9hZC53cml0ZVVJbnQzMkxFKG9wdHMubGltaXQgfHwgMCwgb2Zmc2V0KTtcbiAgICBvZmZzZXQgKz0gNDtcbiAgICBcbiAgICAvLyBPZmZzZXQgKDQgTEUpXG4gICAgcGF5bG9hZC53cml0ZVVJbnQzMkxFKG9wdHMub2Zmc2V0IHx8IDAsIG9mZnNldCk7XG4gICAgb2Zmc2V0ICs9IDQ7XG4gICAgXG4gICAgLy8gQ29sdW1uczogY291bnQoMiBMRSkgKyBbY29sX2xlbigyIExFKSArIGNvbF0uLi5cbiAgICBwYXlsb2FkLndyaXRlVUludDE2TEUoY29sdW1ucy5sZW5ndGgsIG9mZnNldCk7XG4gICAgb2Zmc2V0ICs9IDI7XG4gICAgZm9yIChjb25zdCBjb2wgb2YgY29sdW1ucykge1xuICAgICAgY29uc3QgY29sQnVmID0gQnVmZmVyLmZyb20oY29sLCAndXRmOCcpO1xuICAgICAgcGF5bG9hZC53cml0ZVVJbnQxNkxFKGNvbEJ1Zi5sZW5ndGgsIG9mZnNldCk7XG4gICAgICBvZmZzZXQgKz0gMjtcbiAgICAgIGNvbEJ1Zi5jb3B5KHBheWxvYWQsIG9mZnNldCk7XG4gICAgICBvZmZzZXQgKz0gY29sQnVmLmxlbmd0aDtcbiAgICB9XG5cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuX3NlbmQoSW50ZXJuYWxPcENvZGUuUVVFUlksIHBheWxvYWQpO1xuICAgIGNvbnN0IHsgcGF5bG9hZDogcmVzdWx0UGF5bG9hZCB9ID0gdGhpcy5fcGFyc2VSZXNwb25zZShyZXNwb25zZSk7XG5cbiAgICByZXR1cm4gcmVzdWx0UGF5bG9hZC50b1N0cmluZygndXRmOCcpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNjYW4gZm9yIGtleXMgd2l0aCBhIHByZWZpeCwgcmV0dXJuaW5nIGtleS12YWx1ZSBwYWlycy5cbiAgICogVGhpcyBpcyB0aGUgcHJlZmVycmVkIG1ldGhvZCBmb3Igc2ltcGxlIHByZWZpeC1iYXNlZCBpdGVyYXRpb24uXG4gICAqIFxuICAgKiBXaXJlIGZvcm1hdDogcHJlZml4IHN0cmluZ1xuICAgKiBSZXNwb25zZSBmb3JtYXQ6IGNvdW50KDQgTEUpICsgW2tleV9sZW4oMiBMRSkgKyBrZXkgKyB2YWxfbGVuKDQgTEUpICsgdmFsXS4uLlxuICAgKi9cbiAgYXN5bmMgc2NhbihwcmVmaXg6IHN0cmluZyk6IFByb21pc2U8QXJyYXk8eyBrZXk6IEJ1ZmZlcjsgdmFsdWU6IEJ1ZmZlciB9Pj4ge1xuICAgIGNvbnN0IHByZWZpeEJ1ZiA9IEJ1ZmZlci5mcm9tKHByZWZpeCwgJ3V0ZjgnKTtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuX3NlbmQoSW50ZXJuYWxPcENvZGUuU0NBTiwgcHJlZml4QnVmKTtcbiAgICBjb25zdCB7IG9wY29kZSwgcGF5bG9hZCB9ID0gdGhpcy5fcGFyc2VSZXNwb25zZShyZXNwb25zZSk7XG5cbiAgICBpZiAob3Bjb2RlICE9PSBJbnRlcm5hbE9wQ29kZS5WQUxVRSAmJiBvcGNvZGUgIT09IEludGVybmFsT3BDb2RlLk9LKSB7XG4gICAgICB0aHJvdyBuZXcgUHJvdG9jb2xFcnJvcihgVW5leHBlY3RlZCBzY2FuIHJlc3BvbnNlIG9wY29kZTogMHgke29wY29kZS50b1N0cmluZygxNil9YCk7XG4gICAgfVxuXG4gICAgaWYgKHBheWxvYWQubGVuZ3RoIDwgNCkge1xuICAgICAgcmV0dXJuIFtdOyAvLyBFbXB0eSByZXN1bHRcbiAgICB9XG5cbiAgICAvLyBQYXJzZSByZXNwb25zZTogY291bnQoNCBMRSkgKyBba2V5X2xlbigyIExFKSArIGtleSArIHZhbF9sZW4oNCBMRSkgKyB2YWxdLi4uXG4gICAgY29uc3QgY291bnQgPSBwYXlsb2FkLnJlYWRVSW50MzJMRSgwKTtcbiAgICBjb25zdCByZXN1bHRzOiBBcnJheTx7IGtleTogQnVmZmVyOyB2YWx1ZTogQnVmZmVyIH0+ID0gW107XG4gICAgbGV0IG9mZnNldCA9IDQ7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNvdW50OyBpKyspIHtcbiAgICAgIGlmIChvZmZzZXQgKyAyID4gcGF5bG9hZC5sZW5ndGgpIHtcbiAgICAgICAgdGhyb3cgbmV3IFByb3RvY29sRXJyb3IoJ1RydW5jYXRlZCBzY2FuIHJlc3BvbnNlIChrZXlfbGVuKScpO1xuICAgICAgfVxuICAgICAgY29uc3Qga2V5TGVuID0gcGF5bG9hZC5yZWFkVUludDE2TEUob2Zmc2V0KTtcbiAgICAgIG9mZnNldCArPSAyO1xuXG4gICAgICBpZiAob2Zmc2V0ICsga2V5TGVuICsgNCA+IHBheWxvYWQubGVuZ3RoKSB7XG4gICAgICAgIHRocm93IG5ldyBQcm90b2NvbEVycm9yKCdUcnVuY2F0ZWQgc2NhbiByZXNwb25zZSAoa2V5K3ZhbF9sZW4pJyk7XG4gICAgICB9XG4gICAgICBjb25zdCBrZXkgPSBwYXlsb2FkLnN1YmFycmF5KG9mZnNldCwgb2Zmc2V0ICsga2V5TGVuKTtcbiAgICAgIG9mZnNldCArPSBrZXlMZW47XG5cbiAgICAgIGNvbnN0IHZhbExlbiA9IHBheWxvYWQucmVhZFVJbnQzMkxFKG9mZnNldCk7XG4gICAgICBvZmZzZXQgKz0gNDtcblxuICAgICAgaWYgKG9mZnNldCArIHZhbExlbiA+IHBheWxvYWQubGVuZ3RoKSB7XG4gICAgICAgIHRocm93IG5ldyBQcm90b2NvbEVycm9yKCdUcnVuY2F0ZWQgc2NhbiByZXNwb25zZSAodmFsdWUpJyk7XG4gICAgICB9XG4gICAgICBjb25zdCB2YWx1ZSA9IHBheWxvYWQuc3ViYXJyYXkob2Zmc2V0LCBvZmZzZXQgKyB2YWxMZW4pO1xuICAgICAgb2Zmc2V0ICs9IHZhbExlbjtcblxuICAgICAgcmVzdWx0cy5wdXNoKHsga2V5LCB2YWx1ZSB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0cztcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBxdWVyeSBidWlsZGVyLlxuICAgKi9cbiAgcXVlcnlCdWlsZGVyKHBhdGhQcmVmaXg6IHN0cmluZyk6IFF1ZXJ5IHtcbiAgICByZXR1cm4gbmV3IFF1ZXJ5KHRoaXMsIHBhdGhQcmVmaXgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEJlZ2luIGEgbmV3IHRyYW5zYWN0aW9uLlxuICAgKi9cbiAgYXN5bmMgYmVnaW5UcmFuc2FjdGlvbigpOiBQcm9taXNlPGJpZ2ludD4ge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5fc2VuZChJbnRlcm5hbE9wQ29kZS5CRUdJTl9UWE4pO1xuICAgIGNvbnN0IHsgb3Bjb2RlLCBwYXlsb2FkIH0gPSB0aGlzLl9wYXJzZVJlc3BvbnNlKHJlc3BvbnNlKTtcblxuICAgIGlmIChvcGNvZGUgPT09IEludGVybmFsT3BDb2RlLlRYTl9JRCkge1xuICAgICAgcmV0dXJuIHBheWxvYWQucmVhZEJpZ1VJbnQ2NExFKDApO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgVHJhbnNhY3Rpb25FcnJvcignRmFpbGVkIHRvIGJlZ2luIHRyYW5zYWN0aW9uJyk7XG4gIH1cblxuICAvKipcbiAgICogQ29tbWl0IGEgdHJhbnNhY3Rpb24uXG4gICAqL1xuICBhc3luYyBjb21taXRUcmFuc2FjdGlvbih0eG5JZDogYmlnaW50KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcGF5bG9hZCA9IEJ1ZmZlci5hbGxvYyg4KTtcbiAgICBwYXlsb2FkLndyaXRlQmlnVUludDY0TEUodHhuSWQsIDApO1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5fc2VuZChJbnRlcm5hbE9wQ29kZS5DT01NSVRfVFhOLCBwYXlsb2FkKTtcbiAgICB0aGlzLl9wYXJzZVJlc3BvbnNlKHJlc3BvbnNlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBYm9ydCBhIHRyYW5zYWN0aW9uLlxuICAgKi9cbiAgYXN5bmMgYWJvcnRUcmFuc2FjdGlvbih0eG5JZDogYmlnaW50KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcGF5bG9hZCA9IEJ1ZmZlci5hbGxvYyg4KTtcbiAgICBwYXlsb2FkLndyaXRlQmlnVUludDY0TEUodHhuSWQsIDApO1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5fc2VuZChJbnRlcm5hbE9wQ29kZS5BQk9SVF9UWE4sIHBheWxvYWQpO1xuICAgIHRoaXMuX3BhcnNlUmVzcG9uc2UocmVzcG9uc2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZvcmNlIGEgY2hlY2twb2ludC5cbiAgICovXG4gIGFzeW5jIGNoZWNrcG9pbnQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLl9zZW5kKEludGVybmFsT3BDb2RlLkNIRUNLUE9JTlQpO1xuICAgIHRoaXMuX3BhcnNlUmVzcG9uc2UocmVzcG9uc2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBzdG9yYWdlIHN0YXRpc3RpY3MuXG4gICAqL1xuICBhc3luYyBzdGF0cygpOiBQcm9taXNlPHtcbiAgICBtZW10YWJsZVNpemVCeXRlczogbnVtYmVyO1xuICAgIHdhbFNpemVCeXRlczogbnVtYmVyO1xuICAgIGFjdGl2ZVRyYW5zYWN0aW9uczogbnVtYmVyO1xuICB9PiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLl9zZW5kKEludGVybmFsT3BDb2RlLlNUQVRTKTtcbiAgICBjb25zdCB7IHBheWxvYWQgfSA9IHRoaXMuX3BhcnNlUmVzcG9uc2UocmVzcG9uc2UpO1xuICAgIGNvbnN0IGpzb24gPSBKU09OLnBhcnNlKHBheWxvYWQudG9TdHJpbmcoJ3V0ZjgnKSk7XG4gICAgcmV0dXJuIHtcbiAgICAgIG1lbXRhYmxlU2l6ZUJ5dGVzOiBqc29uLm1lbXRhYmxlX3NpemVfYnl0ZXMgfHwgMCxcbiAgICAgIHdhbFNpemVCeXRlczoganNvbi53YWxfc2l6ZV9ieXRlcyB8fCAwLFxuICAgICAgYWN0aXZlVHJhbnNhY3Rpb25zOiBqc29uLmFjdGl2ZV90cmFuc2FjdGlvbnMgfHwgMCxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFBpbmcgdGhlIHNlcnZlci5cbiAgICovXG4gIGFzeW5jIHBpbmcoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5fc2VuZChJbnRlcm5hbE9wQ29kZS5QSU5HKTtcbiAgICAgIGNvbnN0IHsgb3Bjb2RlIH0gPSB0aGlzLl9wYXJzZVJlc3BvbnNlKHJlc3BvbnNlKTtcbiAgICAgIHJldHVybiBvcGNvZGUgPT09IEludGVybmFsT3BDb2RlLlBPTkc7XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENsb3NlIHRoZSBjb25uZWN0aW9uLlxuICAgKi9cbiAgYXN5bmMgY2xvc2UoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuX2Nsb3NlZCkgcmV0dXJuO1xuICAgIHRoaXMuX2Nsb3NlZCA9IHRydWU7XG5cbiAgICBpZiAodGhpcy5fc29ja2V0KSB7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgICAgdGhpcy5fc29ja2V0IS5lbmQoKCkgPT4ge1xuICAgICAgICAgIHRoaXMuX3NvY2tldCA9IG51bGw7XG4gICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxufVxuIl19
|