@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.
Files changed (78) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +3349 -0
  3. package/_bin/aarch64-apple-darwin/libsochdb_storage.dylib +0 -0
  4. package/_bin/aarch64-apple-darwin/sochdb-bulk +0 -0
  5. package/_bin/aarch64-apple-darwin/sochdb-grpc-server +0 -0
  6. package/_bin/aarch64-apple-darwin/sochdb-server +0 -0
  7. package/_bin/x86_64-pc-windows-msvc/sochdb-bulk.exe +0 -0
  8. package/_bin/x86_64-pc-windows-msvc/sochdb-grpc-server.exe +0 -0
  9. package/_bin/x86_64-pc-windows-msvc/sochdb_storage.dll +0 -0
  10. package/_bin/x86_64-unknown-linux-gnu/libsochdb_storage.so +0 -0
  11. package/_bin/x86_64-unknown-linux-gnu/sochdb-bulk +0 -0
  12. package/_bin/x86_64-unknown-linux-gnu/sochdb-grpc-server +0 -0
  13. package/_bin/x86_64-unknown-linux-gnu/sochdb-server +0 -0
  14. package/bin/sochdb-bulk.js +80 -0
  15. package/bin/sochdb-grpc-server.js +80 -0
  16. package/bin/sochdb-server.js +84 -0
  17. package/dist/cjs/analytics.js +196 -0
  18. package/dist/cjs/database.js +929 -0
  19. package/dist/cjs/embedded/database.js +236 -0
  20. package/dist/cjs/embedded/ffi/bindings.js +113 -0
  21. package/dist/cjs/embedded/ffi/library-finder.js +135 -0
  22. package/dist/cjs/embedded/index.js +14 -0
  23. package/dist/cjs/embedded/transaction.js +172 -0
  24. package/dist/cjs/errors.js +71 -0
  25. package/dist/cjs/format.js +176 -0
  26. package/dist/cjs/grpc-client.js +328 -0
  27. package/dist/cjs/index.js +75 -0
  28. package/dist/cjs/ipc-client.js +504 -0
  29. package/dist/cjs/query.js +154 -0
  30. package/dist/cjs/server-manager.js +295 -0
  31. package/dist/cjs/sql-engine.js +874 -0
  32. package/dist/esm/analytics.js +196 -0
  33. package/dist/esm/database.js +931 -0
  34. package/dist/esm/embedded/database.js +239 -0
  35. package/dist/esm/embedded/ffi/bindings.js +142 -0
  36. package/dist/esm/embedded/ffi/library-finder.js +135 -0
  37. package/dist/esm/embedded/index.js +14 -0
  38. package/dist/esm/embedded/transaction.js +176 -0
  39. package/dist/esm/errors.js +71 -0
  40. package/dist/esm/format.js +179 -0
  41. package/dist/esm/grpc-client.js +333 -0
  42. package/dist/esm/index.js +75 -0
  43. package/dist/esm/ipc-client.js +505 -0
  44. package/dist/esm/query.js +159 -0
  45. package/dist/esm/server-manager.js +295 -0
  46. package/dist/esm/sql-engine.js +875 -0
  47. package/dist/types/analytics.d.ts +66 -0
  48. package/dist/types/analytics.d.ts.map +1 -0
  49. package/dist/types/database.d.ts +523 -0
  50. package/dist/types/database.d.ts.map +1 -0
  51. package/dist/types/embedded/database.d.ts +105 -0
  52. package/dist/types/embedded/database.d.ts.map +1 -0
  53. package/dist/types/embedded/ffi/bindings.d.ts +24 -0
  54. package/dist/types/embedded/ffi/bindings.d.ts.map +1 -0
  55. package/dist/types/embedded/ffi/library-finder.d.ts +17 -0
  56. package/dist/types/embedded/ffi/library-finder.d.ts.map +1 -0
  57. package/dist/types/embedded/index.d.ts +9 -0
  58. package/dist/types/embedded/index.d.ts.map +1 -0
  59. package/dist/types/embedded/transaction.d.ts +21 -0
  60. package/dist/types/embedded/transaction.d.ts.map +1 -0
  61. package/dist/types/errors.d.ts +36 -0
  62. package/dist/types/errors.d.ts.map +1 -0
  63. package/dist/types/format.d.ts +117 -0
  64. package/dist/types/format.d.ts.map +1 -0
  65. package/dist/types/grpc-client.d.ts +120 -0
  66. package/dist/types/grpc-client.d.ts.map +1 -0
  67. package/dist/types/index.d.ts +50 -0
  68. package/dist/types/index.d.ts.map +1 -0
  69. package/dist/types/ipc-client.d.ts +177 -0
  70. package/dist/types/ipc-client.d.ts.map +1 -0
  71. package/dist/types/query.d.ts +85 -0
  72. package/dist/types/query.d.ts.map +1 -0
  73. package/dist/types/server-manager.d.ts +29 -0
  74. package/dist/types/server-manager.d.ts.map +1 -0
  75. package/dist/types/sql-engine.d.ts +100 -0
  76. package/dist/types/sql-engine.d.ts.map +1 -0
  77. package/package.json +90 -0
  78. package/scripts/postinstall.js +50 -0
@@ -0,0 +1,929 @@
1
+ "use strict";
2
+ /**
3
+ * SochDB Embedded Database
4
+ *
5
+ * Direct database access via IPC to the SochDB server.
6
+ * This provides the same API as the Python SDK's Database class.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
+ desc = { enumerable: true, get: function() { return m[k]; } };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }) : (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ o[k2] = m[k];
20
+ }));
21
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
23
+ }) : function(o, v) {
24
+ o["default"] = v;
25
+ });
26
+ var __importStar = (this && this.__importStar) || (function () {
27
+ var ownKeys = function(o) {
28
+ ownKeys = Object.getOwnPropertyNames || function (o) {
29
+ var ar = [];
30
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31
+ return ar;
32
+ };
33
+ return ownKeys(o);
34
+ };
35
+ return function (mod) {
36
+ if (mod && mod.__esModule) return mod;
37
+ var result = {};
38
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39
+ __setModuleDefault(result, mod);
40
+ return result;
41
+ };
42
+ })();
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.Database = exports.Transaction = void 0;
45
+ // Copyright 2025 Sushanth (https://github.com/sushanthpy)
46
+ //
47
+ // Licensed under the Apache License, Version 2.0 (the "License");
48
+ // you may not use this file except in compliance with the License.
49
+ // You may obtain a copy of the License at
50
+ //
51
+ // http://www.apache.org/licenses/LICENSE-2.0
52
+ const fs = __importStar(require("fs"));
53
+ const path = __importStar(require("path"));
54
+ const errors_1 = require("./errors");
55
+ const ipc_client_1 = require("./ipc-client");
56
+ const query_1 = require("./query");
57
+ const server_manager_1 = require("./server-manager");
58
+ /**
59
+ * Transaction handle for atomic operations.
60
+ */
61
+ class Transaction {
62
+ constructor(db) {
63
+ this._txnId = null;
64
+ this._committed = false;
65
+ this._aborted = false;
66
+ this._db = db;
67
+ }
68
+ /**
69
+ * Begin the transaction.
70
+ * @internal
71
+ */
72
+ async begin() {
73
+ this._txnId = await this._db['_beginTransaction']();
74
+ }
75
+ /**
76
+ * Get a value by key within this transaction.
77
+ */
78
+ async get(key) {
79
+ this._ensureActive();
80
+ return this._db.get(key);
81
+ }
82
+ /**
83
+ * Put a key-value pair within this transaction.
84
+ */
85
+ async put(key, value) {
86
+ this._ensureActive();
87
+ return this._db.put(key, value);
88
+ }
89
+ /**
90
+ * Delete a key within this transaction.
91
+ */
92
+ async delete(key) {
93
+ this._ensureActive();
94
+ return this._db.delete(key);
95
+ }
96
+ /**
97
+ * Scan keys with a prefix within this transaction.
98
+ * @param prefix - The prefix to scan for
99
+ * @param end - Optional end boundary (exclusive)
100
+ */
101
+ async *scan(prefix, end) {
102
+ this._ensureActive();
103
+ // Delegate to database's scan method
104
+ // Transactional isolation is maintained by the underlying storage
105
+ for await (const entry of this._db.scanGenerator(prefix, end)) {
106
+ yield entry;
107
+ }
108
+ }
109
+ /**
110
+ * Get a value by path within this transaction.
111
+ */
112
+ async getPath(pathStr) {
113
+ this._ensureActive();
114
+ return this._db.getPath(pathStr);
115
+ }
116
+ /**
117
+ * Put a value at a path within this transaction.
118
+ */
119
+ async putPath(pathStr, value) {
120
+ this._ensureActive();
121
+ return this._db.putPath(pathStr, value);
122
+ }
123
+ /**
124
+ * Commit the transaction.
125
+ *
126
+ * After committing, an optional checkpoint is triggered to ensure writes
127
+ * are durable. This prevents race conditions where subsequent reads might
128
+ * not see committed data due to async flush timing.
129
+ */
130
+ async commit() {
131
+ this._ensureActive();
132
+ if (this._txnId !== null) {
133
+ await this._db['_commitTransaction'](this._txnId);
134
+ // Trigger checkpoint to ensure durability (addresses race condition)
135
+ // Note: This is a trade-off between consistency and performance.
136
+ // For high-throughput scenarios, consider batching checkpoints.
137
+ await this._db.checkpoint();
138
+ }
139
+ this._committed = true;
140
+ }
141
+ /**
142
+ * Abort/rollback the transaction.
143
+ */
144
+ async abort() {
145
+ if (this._committed || this._aborted)
146
+ return;
147
+ if (this._txnId !== null) {
148
+ await this._db['_abortTransaction'](this._txnId);
149
+ }
150
+ this._aborted = true;
151
+ }
152
+ _ensureActive() {
153
+ if (this._committed) {
154
+ throw new errors_1.TransactionError('Transaction already committed');
155
+ }
156
+ if (this._aborted) {
157
+ throw new errors_1.TransactionError('Transaction already aborted');
158
+ }
159
+ }
160
+ }
161
+ exports.Transaction = Transaction;
162
+ /**
163
+ * SochDB Database client.
164
+ *
165
+ * Provides access to SochDB with full transaction support.
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * import { Database } from '@sushanth/sochdb';
170
+ *
171
+ * // Open a database
172
+ * const db = await Database.open('./my_database');
173
+ *
174
+ * // Simple key-value operations
175
+ * await db.put(Buffer.from('user:123'), Buffer.from('{"name": "Alice"}'));
176
+ * const value = await db.get(Buffer.from('user:123'));
177
+ *
178
+ * // Path-native API
179
+ * await db.putPath('users/alice/email', Buffer.from('alice@example.com'));
180
+ * const email = await db.getPath('users/alice/email');
181
+ *
182
+ * // Transactions
183
+ * await db.withTransaction(async (txn) => {
184
+ * await txn.put(Buffer.from('key1'), Buffer.from('value1'));
185
+ * await txn.put(Buffer.from('key2'), Buffer.from('value2'));
186
+ * });
187
+ *
188
+ * // Clean up
189
+ * await db.close();
190
+ * ```
191
+ */
192
+ class Database {
193
+ constructor(config) {
194
+ this._client = null;
195
+ this._closed = false;
196
+ this._embeddedServerStarted = false;
197
+ this._config = {
198
+ createIfMissing: true,
199
+ walEnabled: true,
200
+ syncMode: 'normal',
201
+ memtableSizeBytes: 64 * 1024 * 1024,
202
+ embedded: true, // Default to embedded mode
203
+ ...config,
204
+ };
205
+ }
206
+ /**
207
+ * Open a database at the specified path.
208
+ *
209
+ * @param pathOrConfig - Path to the database directory or configuration object
210
+ * @returns A new Database instance
211
+ *
212
+ * @example
213
+ * ```typescript
214
+ * // Simple usage (embedded mode - starts server automatically)
215
+ * const db = await Database.open('./my_database');
216
+ *
217
+ * // With configuration
218
+ * const db = await Database.open({
219
+ * path: './my_database',
220
+ * walEnabled: true,
221
+ * syncMode: 'full',
222
+ * });
223
+ *
224
+ * // Connect to existing external server
225
+ * const db = await Database.open({
226
+ * path: './my_database',
227
+ * embedded: false, // Don't start embedded server
228
+ * });
229
+ * ```
230
+ */
231
+ static async open(pathOrConfig) {
232
+ const config = typeof pathOrConfig === 'string' ? { path: pathOrConfig } : pathOrConfig;
233
+ // Ensure database directory exists
234
+ if (config.createIfMissing !== false) {
235
+ if (!fs.existsSync(config.path)) {
236
+ fs.mkdirSync(config.path, { recursive: true });
237
+ }
238
+ }
239
+ const db = new Database(config);
240
+ // Start embedded server if configured (default: true)
241
+ let socketPath;
242
+ if (db._config.embedded !== false) {
243
+ // Start embedded server and get socket path
244
+ socketPath = await (0, server_manager_1.startEmbeddedServer)(config.path);
245
+ db._embeddedServerStarted = true;
246
+ }
247
+ else {
248
+ // Connect to existing server socket
249
+ socketPath = path.join(config.path, 'sochdb.sock');
250
+ }
251
+ db._client = await ipc_client_1.IpcClient.connect(socketPath);
252
+ // Track database open event (only analytics event we send)
253
+ try {
254
+ const { trackDatabaseOpen } = await Promise.resolve().then(() => __importStar(require('./analytics.js')));
255
+ await trackDatabaseOpen(config.path, 'embedded');
256
+ }
257
+ catch {
258
+ // Never let analytics break database operations
259
+ }
260
+ return db;
261
+ }
262
+ /**
263
+ * Get a value by key.
264
+ *
265
+ * @param key - The key to look up (Buffer or string)
266
+ * @returns The value as a Buffer, or null if not found
267
+ */
268
+ async get(key) {
269
+ this._ensureOpen();
270
+ const keyBuf = typeof key === 'string' ? Buffer.from(key) : key;
271
+ return this._client.get(keyBuf);
272
+ }
273
+ /**
274
+ * Put a key-value pair.
275
+ *
276
+ * @param key - The key (Buffer or string)
277
+ * @param value - The value (Buffer or string)
278
+ */
279
+ async put(key, value) {
280
+ this._ensureOpen();
281
+ const keyBuf = typeof key === 'string' ? Buffer.from(key) : key;
282
+ const valueBuf = typeof value === 'string' ? Buffer.from(value) : value;
283
+ return this._client.put(keyBuf, valueBuf);
284
+ }
285
+ /**
286
+ * Delete a key.
287
+ *
288
+ * @param key - The key to delete (Buffer or string)
289
+ */
290
+ async delete(key) {
291
+ this._ensureOpen();
292
+ const keyBuf = typeof key === 'string' ? Buffer.from(key) : key;
293
+ return this._client.delete(keyBuf);
294
+ }
295
+ /**
296
+ * Get a value by path.
297
+ *
298
+ * @param pathStr - The path (e.g., "users/alice/email")
299
+ * @returns The value as a Buffer, or null if not found
300
+ */
301
+ async getPath(pathStr) {
302
+ this._ensureOpen();
303
+ return this._client.getPath(pathStr);
304
+ }
305
+ /**
306
+ * Put a value at a path.
307
+ *
308
+ * @param pathStr - The path (e.g., "users/alice/email")
309
+ * @param value - The value (Buffer or string)
310
+ */
311
+ async putPath(pathStr, value) {
312
+ this._ensureOpen();
313
+ const valueBuf = typeof value === 'string' ? Buffer.from(value) : value;
314
+ return this._client.putPath(pathStr, valueBuf);
315
+ }
316
+ /**
317
+ * Create a query builder for the given path prefix.
318
+ *
319
+ * @param pathPrefix - The path prefix to query (e.g., "users/")
320
+ * @returns A Query builder instance
321
+ *
322
+ * @example
323
+ * ```typescript
324
+ * const results = await db.query('users/')
325
+ * .limit(10)
326
+ * .select(['name', 'email'])
327
+ * .execute();
328
+ * ```
329
+ */
330
+ query(pathPrefix) {
331
+ this._ensureOpen();
332
+ return new query_1.Query(this._client, pathPrefix);
333
+ }
334
+ /**
335
+ * Scan for keys with a prefix, returning key-value pairs.
336
+ * This is the preferred method for simple prefix-based iteration.
337
+ *
338
+ * @param prefix - The prefix to scan for (e.g., "users/", "tenants/tenant1/")
339
+ * @returns Array of key-value pairs
340
+ *
341
+ * @example
342
+ * ```typescript
343
+ * const results = await db.scan('tenants/tenant1/');
344
+ * for (const { key, value } of results) {
345
+ * console.log(`${key.toString()}: ${value.toString()}`);
346
+ * }
347
+ * ```
348
+ */
349
+ async scan(prefix) {
350
+ this._ensureOpen();
351
+ return this._client.scan(prefix);
352
+ }
353
+ /**
354
+ * Scan for keys with a prefix using an async generator.
355
+ * This allows for memory-efficient iteration over large result sets.
356
+ *
357
+ * @param prefix - The prefix to scan for
358
+ * @param end - Optional end boundary (exclusive)
359
+ * @returns Async generator yielding [key, value] tuples
360
+ *
361
+ * @example
362
+ * ```typescript
363
+ * for await (const [key, value] of db.scanGenerator('users/')) {
364
+ * console.log(`${key.toString()}: ${value.toString()}`);
365
+ * }
366
+ * ```
367
+ */
368
+ async *scanGenerator(prefix, end) {
369
+ this._ensureOpen();
370
+ const prefixBuf = typeof prefix === 'string' ? Buffer.from(prefix) : prefix;
371
+ const endBuf = end ? (typeof end === 'string' ? Buffer.from(end) : end) : undefined;
372
+ const results = await this._client.scan(prefixBuf.toString());
373
+ for (const { key, value } of results) {
374
+ // Filter by end boundary if provided
375
+ if (endBuf && Buffer.compare(key, endBuf) >= 0) {
376
+ break;
377
+ }
378
+ yield [key, value];
379
+ }
380
+ }
381
+ /**
382
+ * Execute operations within a transaction.
383
+ *
384
+ * The transaction automatically commits on success or aborts on error.
385
+ *
386
+ * @param fn - Async function that receives a Transaction object
387
+ *
388
+ * @example
389
+ * ```typescript
390
+ * await db.withTransaction(async (txn) => {
391
+ * await txn.put(Buffer.from('key1'), Buffer.from('value1'));
392
+ * await txn.put(Buffer.from('key2'), Buffer.from('value2'));
393
+ * // Automatically commits
394
+ * });
395
+ * ```
396
+ */
397
+ async withTransaction(fn) {
398
+ this._ensureOpen();
399
+ const txn = new Transaction(this);
400
+ await txn.begin();
401
+ try {
402
+ const result = await fn(txn);
403
+ await txn.commit();
404
+ return result;
405
+ }
406
+ catch (error) {
407
+ await txn.abort();
408
+ throw error;
409
+ }
410
+ }
411
+ /**
412
+ * Create a new transaction.
413
+ *
414
+ * @returns A new Transaction instance
415
+ * @deprecated Use withTransaction() for automatic commit/abort handling
416
+ */
417
+ async transaction() {
418
+ this._ensureOpen();
419
+ const txn = new Transaction(this);
420
+ await txn.begin();
421
+ return txn;
422
+ }
423
+ /**
424
+ * Force a checkpoint to persist memtable to disk.
425
+ */
426
+ async checkpoint() {
427
+ this._ensureOpen();
428
+ return this._client.checkpoint();
429
+ }
430
+ /**
431
+ * Get storage statistics.
432
+ */
433
+ async stats() {
434
+ this._ensureOpen();
435
+ return this._client.stats();
436
+ }
437
+ /**
438
+ * Execute a SQL query.
439
+ *
440
+ * SochDB supports a subset of SQL for relational data stored on top of
441
+ * the key-value engine. Tables and rows are stored as:
442
+ * - Schema: _sql/tables/{table_name}/schema
443
+ * - Rows: _sql/tables/{table_name}/rows/{row_id}
444
+ *
445
+ * Supported SQL:
446
+ * - CREATE TABLE table_name (col1 TYPE, col2 TYPE, ...)
447
+ * - DROP TABLE table_name
448
+ * - INSERT INTO table_name (cols) VALUES (vals)
449
+ * - SELECT cols FROM table_name [WHERE ...] [ORDER BY ...] [LIMIT ...]
450
+ * - UPDATE table_name SET col=val [WHERE ...]
451
+ * - DELETE FROM table_name [WHERE ...]
452
+ *
453
+ * Supported types: INT, TEXT, FLOAT, BOOL, BLOB
454
+ *
455
+ * @param sql - SQL query string
456
+ * @returns SQLQueryResult with rows and metadata
457
+ *
458
+ * @example
459
+ * ```typescript
460
+ * // Create a table
461
+ * await db.execute("CREATE TABLE users (id INT PRIMARY KEY, name TEXT, age INT)");
462
+ *
463
+ * // Insert data
464
+ * await db.execute("INSERT INTO users (id, name, age) VALUES (1, 'Alice', 30)");
465
+ *
466
+ * // Query data
467
+ * const result = await db.execute("SELECT * FROM users WHERE age > 26");
468
+ * result.rows.forEach(row => console.log(row));
469
+ * ```
470
+ */
471
+ async execute(sql) {
472
+ this._ensureOpen();
473
+ // Import the SQL executor
474
+ const { SQLExecutor } = await Promise.resolve().then(() => __importStar(require('./sql-engine.js')));
475
+ // Create a database adapter for the SQL executor
476
+ const dbAdapter = {
477
+ get: (key) => this.get(key),
478
+ put: (key, value) => this.put(key, value),
479
+ delete: (key) => this.delete(key),
480
+ scan: (prefix) => this.scan(prefix),
481
+ };
482
+ const executor = new SQLExecutor(dbAdapter);
483
+ return executor.execute(sql);
484
+ }
485
+ // =========================================================================
486
+ // Static Serialization Methods
487
+ // =========================================================================
488
+ /**
489
+ * Convert records to TOON format for token-efficient LLM context.
490
+ *
491
+ * TOON format achieves 40-66% token reduction compared to JSON by using
492
+ * a columnar text format with minimal syntax.
493
+ *
494
+ * @param tableName - Name of the table/collection
495
+ * @param records - Array of objects with the data
496
+ * @param fields - Optional array of field names to include
497
+ * @returns TOON-formatted string
498
+ *
499
+ * @example
500
+ * ```typescript
501
+ * const records = [
502
+ * { id: 1, name: 'Alice', email: 'alice@ex.com' },
503
+ * { id: 2, name: 'Bob', email: 'bob@ex.com' }
504
+ * ];
505
+ * console.log(Database.toToon('users', records, ['name', 'email']));
506
+ * // users[2]{name,email}:Alice,alice@ex.com;Bob,bob@ex.com
507
+ * ```
508
+ */
509
+ static toToon(tableName, records, fields) {
510
+ if (!records || records.length === 0) {
511
+ return `${tableName}[0]{}:`;
512
+ }
513
+ // Determine fields from first record if not specified
514
+ const useFields = fields ?? Object.keys(records[0]);
515
+ // Build header: table[count]{field1,field2,...}:
516
+ const header = `${tableName}[${records.length}]{${useFields.join(',')}}:`;
517
+ // Escape values containing delimiters
518
+ const escapeValue = (v) => {
519
+ const s = v != null ? String(v) : '';
520
+ if (s.includes(',') || s.includes(';') || s.includes('\n')) {
521
+ return `"${s}"`;
522
+ }
523
+ return s;
524
+ };
525
+ // Build rows: value1,value2;value1,value2;...
526
+ const rows = records
527
+ .map(r => useFields.map(f => escapeValue(r[f])).join(','))
528
+ .join(';');
529
+ return header + rows;
530
+ }
531
+ /**
532
+ * Convert records to JSON format for easy application decoding.
533
+ *
534
+ * While TOON format is optimized for LLM context (40-66% token reduction),
535
+ * JSON is often easier for applications to parse. Use this method when
536
+ * the output will be consumed by application code rather than LLMs.
537
+ *
538
+ * @param tableName - Name of the table/collection
539
+ * @param records - Array of objects with the data
540
+ * @param fields - Optional array of field names to include
541
+ * @param compact - If true (default), outputs minified JSON
542
+ * @returns JSON-formatted string
543
+ *
544
+ * @example
545
+ * ```typescript
546
+ * const records = [
547
+ * { id: 1, name: 'Alice' },
548
+ * { id: 2, name: 'Bob' }
549
+ * ];
550
+ * console.log(Database.toJson('users', records));
551
+ * // {"table":"users","count":2,"records":[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]}
552
+ * ```
553
+ */
554
+ static toJson(tableName, records, fields, compact = true) {
555
+ if (!records || records.length === 0) {
556
+ return JSON.stringify({ table: tableName, count: 0, records: [] });
557
+ }
558
+ // Filter fields if specified
559
+ const filteredRecords = fields
560
+ ? records.map(r => {
561
+ const filtered = {};
562
+ for (const f of fields) {
563
+ filtered[f] = r[f];
564
+ }
565
+ return filtered;
566
+ })
567
+ : records;
568
+ const output = {
569
+ table: tableName,
570
+ count: filteredRecords.length,
571
+ records: filteredRecords,
572
+ };
573
+ return compact ? JSON.stringify(output) : JSON.stringify(output, null, 2);
574
+ }
575
+ /**
576
+ * Parse a JSON format string back to structured data.
577
+ *
578
+ * @param jsonStr - JSON-formatted string (from toJson)
579
+ * @returns Object with table, fields, and records
580
+ */
581
+ static fromJson(jsonStr) {
582
+ const data = JSON.parse(jsonStr);
583
+ const table = data.table ?? 'unknown';
584
+ const records = data.records ?? [];
585
+ const fields = records.length > 0 ? Object.keys(records[0]) : [];
586
+ return { table, fields, records };
587
+ }
588
+ // =========================================================================
589
+ // Graph Overlay Operations
590
+ // =========================================================================
591
+ /**
592
+ * Add a node to the graph overlay.
593
+ *
594
+ * @param namespace - Namespace for the graph
595
+ * @param nodeId - Unique node identifier
596
+ * @param nodeType - Type of node (e.g., "person", "document", "concept")
597
+ * @param properties - Optional node properties
598
+ *
599
+ * @example
600
+ * ```typescript
601
+ * await db.addNode('default', 'alice', 'person', { role: 'engineer' });
602
+ * await db.addNode('default', 'project_x', 'project', { status: 'active' });
603
+ * ```
604
+ */
605
+ async addNode(namespace, nodeId, nodeType, properties) {
606
+ this._ensureOpen();
607
+ const key = `_graph/${namespace}/nodes/${nodeId}`;
608
+ const value = JSON.stringify({
609
+ id: nodeId,
610
+ node_type: nodeType,
611
+ properties: properties || {},
612
+ });
613
+ await this.put(Buffer.from(key), Buffer.from(value));
614
+ }
615
+ /**
616
+ * Add an edge between nodes in the graph overlay.
617
+ *
618
+ * @param namespace - Namespace for the graph
619
+ * @param fromId - Source node ID
620
+ * @param edgeType - Type of relationship
621
+ * @param toId - Target node ID
622
+ * @param properties - Optional edge properties
623
+ *
624
+ * @example
625
+ * ```typescript
626
+ * await db.addEdge('default', 'alice', 'works_on', 'project_x');
627
+ * await db.addEdge('default', 'alice', 'knows', 'bob', { since: '2020' });
628
+ * ```
629
+ */
630
+ async addEdge(namespace, fromId, edgeType, toId, properties) {
631
+ this._ensureOpen();
632
+ const key = `_graph/${namespace}/edges/${fromId}/${edgeType}/${toId}`;
633
+ const value = JSON.stringify({
634
+ from_id: fromId,
635
+ edge_type: edgeType,
636
+ to_id: toId,
637
+ properties: properties || {},
638
+ });
639
+ await this.put(Buffer.from(key), Buffer.from(value));
640
+ }
641
+ /**
642
+ * Traverse the graph from a starting node.
643
+ *
644
+ * @param namespace - Namespace for the graph
645
+ * @param startNode - Node ID to start traversal from
646
+ * @param maxDepth - Maximum traversal depth (default: 10)
647
+ * @param order - "bfs" for breadth-first, "dfs" for depth-first
648
+ * @returns Object with nodes and edges arrays
649
+ *
650
+ * @example
651
+ * ```typescript
652
+ * const { nodes, edges } = await db.traverse('default', 'alice', 2);
653
+ * for (const node of nodes) {
654
+ * console.log(`Node: ${node.id} (${node.node_type})`);
655
+ * }
656
+ * ```
657
+ */
658
+ async traverse(namespace, startNode, maxDepth = 10, order = 'bfs') {
659
+ this._ensureOpen();
660
+ const visited = new Set();
661
+ const nodes = [];
662
+ const edges = [];
663
+ const frontier = [[startNode, 0]];
664
+ while (frontier.length > 0) {
665
+ const [currentNode, depth] = order === 'bfs'
666
+ ? frontier.shift()
667
+ : frontier.pop();
668
+ if (depth > maxDepth || visited.has(currentNode)) {
669
+ continue;
670
+ }
671
+ visited.add(currentNode);
672
+ // Get node data
673
+ const nodeKey = `_graph/${namespace}/nodes/${currentNode}`;
674
+ const nodeData = await this.get(Buffer.from(nodeKey));
675
+ if (nodeData) {
676
+ nodes.push(JSON.parse(nodeData.toString()));
677
+ }
678
+ // Get outgoing edges
679
+ const edgePrefix = `_graph/${namespace}/edges/${currentNode}/`;
680
+ const edgeResults = await this.scan(edgePrefix);
681
+ for (const { value } of edgeResults) {
682
+ const edge = JSON.parse(value.toString());
683
+ edges.push(edge);
684
+ if (!visited.has(edge.to_id)) {
685
+ frontier.push([edge.to_id, depth + 1]);
686
+ }
687
+ }
688
+ }
689
+ return { nodes, edges };
690
+ }
691
+ // =========================================================================
692
+ // Semantic Cache Operations
693
+ // =========================================================================
694
+ /**
695
+ * Store a value in the semantic cache with its embedding.
696
+ *
697
+ * @param cacheName - Name of the cache
698
+ * @param key - Cache key (for display/debugging)
699
+ * @param value - Value to cache
700
+ * @param embedding - Embedding vector for similarity matching
701
+ * @param ttlSeconds - Time-to-live in seconds (0 = no expiry)
702
+ *
703
+ * @example
704
+ * ```typescript
705
+ * await db.cachePut(
706
+ * 'llm_responses',
707
+ * 'What is Python?',
708
+ * 'Python is a programming language...',
709
+ * [0.1, 0.2, 0.3, ...], // 384-dim
710
+ * 3600
711
+ * );
712
+ * ```
713
+ */
714
+ async cachePut(cacheName, key, value, embedding, ttlSeconds = 0) {
715
+ this._ensureOpen();
716
+ // Hash the key for storage
717
+ const keyHash = Buffer.from(key).toString('hex').slice(0, 16);
718
+ const cacheKey = `_cache/${cacheName}/${keyHash}`;
719
+ const expiresAt = ttlSeconds > 0
720
+ ? Math.floor(Date.now() / 1000) + ttlSeconds
721
+ : 0;
722
+ const cacheValue = JSON.stringify({
723
+ key,
724
+ value,
725
+ embedding,
726
+ expires_at: expiresAt,
727
+ });
728
+ await this.put(Buffer.from(cacheKey), Buffer.from(cacheValue));
729
+ }
730
+ /**
731
+ * Look up a value in the semantic cache by embedding similarity.
732
+ *
733
+ * @param cacheName - Name of the cache
734
+ * @param queryEmbedding - Query embedding to match against
735
+ * @param threshold - Minimum cosine similarity threshold (0.0 to 1.0)
736
+ * @returns Cached value if similarity >= threshold, null otherwise
737
+ *
738
+ * @example
739
+ * ```typescript
740
+ * const result = await db.cacheGet(
741
+ * 'llm_responses',
742
+ * [0.12, 0.18, ...], // Similar to "What is Python?"
743
+ * 0.85
744
+ * );
745
+ * if (result) {
746
+ * console.log(`Cache hit: ${result}`);
747
+ * }
748
+ * ```
749
+ */
750
+ async cacheGet(cacheName, queryEmbedding, threshold = 0.85) {
751
+ this._ensureOpen();
752
+ const prefix = `_cache/${cacheName}/`;
753
+ const entries = await this.scan(prefix);
754
+ const now = Math.floor(Date.now() / 1000);
755
+ let bestMatch = null;
756
+ for (const { value } of entries) {
757
+ const entry = JSON.parse(value.toString());
758
+ // Check expiry
759
+ if (entry.expires_at > 0 && now > entry.expires_at) {
760
+ continue;
761
+ }
762
+ // Compute cosine similarity
763
+ if (entry.embedding && entry.embedding.length === queryEmbedding.length) {
764
+ const similarity = this._cosineSimilarity(queryEmbedding, entry.embedding);
765
+ if (similarity >= threshold) {
766
+ if (!bestMatch || similarity > bestMatch.similarity) {
767
+ bestMatch = { similarity, value: entry.value };
768
+ }
769
+ }
770
+ }
771
+ }
772
+ return bestMatch?.value ?? null;
773
+ }
774
+ _cosineSimilarity(a, b) {
775
+ let dot = 0, normA = 0, normB = 0;
776
+ for (let i = 0; i < a.length; i++) {
777
+ dot += a[i] * b[i];
778
+ normA += a[i] * a[i];
779
+ normB += b[i] * b[i];
780
+ }
781
+ normA = Math.sqrt(normA);
782
+ normB = Math.sqrt(normB);
783
+ return normA === 0 || normB === 0 ? 0 : dot / (normA * normB);
784
+ }
785
+ // =========================================================================
786
+ // Trace Operations (Observability)
787
+ // =========================================================================
788
+ /**
789
+ * Start a new trace.
790
+ *
791
+ * @param name - Name of the trace (e.g., "user_request", "batch_job")
792
+ * @returns Object with traceId and rootSpanId
793
+ *
794
+ * @example
795
+ * ```typescript
796
+ * const { traceId, rootSpanId } = await db.startTrace('user_query');
797
+ * // ... do work ...
798
+ * await db.endSpan(traceId, rootSpanId, 'ok');
799
+ * ```
800
+ */
801
+ async startTrace(name) {
802
+ this._ensureOpen();
803
+ const traceId = `trace_${Date.now().toString(16)}${Math.random().toString(16).slice(2, 10)}`;
804
+ const spanId = `span_${Date.now().toString(16)}${Math.random().toString(16).slice(2, 10)}`;
805
+ const now = Date.now() * 1000; // microseconds
806
+ // Store trace
807
+ const traceKey = `_traces/${traceId}`;
808
+ const traceValue = JSON.stringify({
809
+ trace_id: traceId,
810
+ name,
811
+ start_us: now,
812
+ root_span_id: spanId,
813
+ });
814
+ await this.put(Buffer.from(traceKey), Buffer.from(traceValue));
815
+ // Store root span
816
+ const spanKey = `_traces/${traceId}/spans/${spanId}`;
817
+ const spanValue = JSON.stringify({
818
+ span_id: spanId,
819
+ name,
820
+ start_us: now,
821
+ parent_span_id: null,
822
+ status: 'active',
823
+ });
824
+ await this.put(Buffer.from(spanKey), Buffer.from(spanValue));
825
+ return { traceId, rootSpanId: spanId };
826
+ }
827
+ /**
828
+ * Start a child span within a trace.
829
+ *
830
+ * @param traceId - ID of the parent trace
831
+ * @param parentSpanId - ID of the parent span
832
+ * @param name - Name of this span
833
+ * @returns The new span ID
834
+ *
835
+ * @example
836
+ * ```typescript
837
+ * const { traceId, rootSpanId } = await db.startTrace('user_query');
838
+ * const dbSpan = await db.startSpan(traceId, rootSpanId, 'database_lookup');
839
+ * // ... do database work ...
840
+ * const duration = await db.endSpan(traceId, dbSpan, 'ok');
841
+ * ```
842
+ */
843
+ async startSpan(traceId, parentSpanId, name) {
844
+ this._ensureOpen();
845
+ const spanId = `span_${Date.now().toString(16)}${Math.random().toString(16).slice(2, 10)}`;
846
+ const now = Date.now() * 1000;
847
+ const spanKey = `_traces/${traceId}/spans/${spanId}`;
848
+ const spanValue = JSON.stringify({
849
+ span_id: spanId,
850
+ name,
851
+ start_us: now,
852
+ parent_span_id: parentSpanId,
853
+ status: 'active',
854
+ });
855
+ await this.put(Buffer.from(spanKey), Buffer.from(spanValue));
856
+ return spanId;
857
+ }
858
+ /**
859
+ * End a span and record its duration.
860
+ *
861
+ * @param traceId - ID of the trace
862
+ * @param spanId - ID of the span to end
863
+ * @param status - "ok", "error", or "unset"
864
+ * @returns Duration in microseconds
865
+ *
866
+ * @example
867
+ * ```typescript
868
+ * const duration = await db.endSpan(traceId, spanId, 'ok');
869
+ * console.log(`Operation took ${duration}µs`);
870
+ * ```
871
+ */
872
+ async endSpan(traceId, spanId, status = 'ok') {
873
+ this._ensureOpen();
874
+ const spanKey = `_traces/${traceId}/spans/${spanId}`;
875
+ const spanData = await this.get(Buffer.from(spanKey));
876
+ if (!spanData) {
877
+ throw new errors_1.DatabaseError(`Span not found: ${spanId}`);
878
+ }
879
+ const span = JSON.parse(spanData.toString());
880
+ const now = Date.now() * 1000;
881
+ const duration = now - span.start_us;
882
+ const updatedSpan = {
883
+ ...span,
884
+ status,
885
+ end_us: now,
886
+ duration_us: duration,
887
+ };
888
+ await this.put(Buffer.from(spanKey), Buffer.from(JSON.stringify(updatedSpan)));
889
+ return duration;
890
+ }
891
+ /**
892
+ * Close the database connection.
893
+ * If running in embedded mode, also stops the embedded server.
894
+ */
895
+ async close() {
896
+ if (this._closed)
897
+ return;
898
+ if (this._client) {
899
+ await this._client.close();
900
+ this._client = null;
901
+ }
902
+ // Stop embedded server if we started it
903
+ if (this._embeddedServerStarted) {
904
+ await (0, server_manager_1.stopEmbeddedServer)(this._config.path);
905
+ this._embeddedServerStarted = false;
906
+ }
907
+ this._closed = true;
908
+ }
909
+ // Internal methods for transaction management
910
+ async _beginTransaction() {
911
+ return this._client.beginTransaction();
912
+ }
913
+ async _commitTransaction(txnId) {
914
+ return this._client.commitTransaction(txnId);
915
+ }
916
+ async _abortTransaction(txnId) {
917
+ return this._client.abortTransaction(txnId);
918
+ }
919
+ _ensureOpen() {
920
+ if (this._closed) {
921
+ throw new errors_1.DatabaseError('Database is closed');
922
+ }
923
+ if (!this._client) {
924
+ throw new errors_1.DatabaseError('Database not connected');
925
+ }
926
+ }
927
+ }
928
+ exports.Database = Database;
929
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YWJhc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZGF0YWJhc2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7O0dBT0c7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUVILDBEQUEwRDtBQUMxRCxFQUFFO0FBQ0Ysa0VBQWtFO0FBQ2xFLG1FQUFtRTtBQUNuRSwwQ0FBMEM7QUFDMUMsRUFBRTtBQUNGLGlEQUFpRDtBQUVqRCx1Q0FBeUI7QUFDekIsMkNBQTZCO0FBQzdCLHFDQUEyRDtBQUMzRCw2Q0FBeUM7QUFDekMsbUNBQWdDO0FBQ2hDLHFEQUEyRTtBQW1DM0U7O0dBRUc7QUFDSCxNQUFhLFdBQVc7SUFNdEIsWUFBWSxFQUFZO1FBSmhCLFdBQU0sR0FBa0IsSUFBSSxDQUFDO1FBQzdCLGVBQVUsR0FBRyxLQUFLLENBQUM7UUFDbkIsYUFBUSxHQUFHLEtBQUssQ0FBQztRQUd2QixJQUFJLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQztJQUNoQixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsS0FBSyxDQUFDLEtBQUs7UUFDVCxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLEdBQUcsQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFLENBQUM7SUFDdEQsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFvQjtRQUM1QixJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDckIsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMzQixDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsR0FBRyxDQUFDLEdBQW9CLEVBQUUsS0FBc0I7UUFDcEQsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ3JCLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lB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SSxzQkFBYSxDQUFDLHdCQUF3QixDQUFDLENBQUM7UUFDcEQsQ0FBQztJQUNILENBQUM7Q0FDRjtBQXgyQkQsNEJBdzJCQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU29jaERCIEVtYmVkZGVkIERhdGFiYXNlXG4gKlxuICogRGlyZWN0IGRhdGFiYXNlIGFjY2VzcyB2aWEgSVBDIHRvIHRoZSBTb2NoREIgc2VydmVyLlxuICogVGhpcyBwcm92aWRlcyB0aGUgc2FtZSBBUEkgYXMgdGhlIFB5dGhvbiBTREsncyBEYXRhYmFzZSBjbGFzcy5cbiAqXG4gKiBAcGFja2FnZURvY3VtZW50YXRpb25cbiAqL1xuXG4vLyBDb3B5cmlnaHQgMjAyNSBTdXNoYW50aCAoaHR0cHM6Ly9naXRodWIuY29tL3N1c2hhbnRocHkpXG4vL1xuLy8gTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbi8vIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbi8vIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuLy9cbi8vICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcblxuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IERhdGFiYXNlRXJyb3IsIFRyYW5zYWN0aW9uRXJyb3IgfSBmcm9tICcuL2Vycm9ycyc7XG5pbXBvcnQgeyBJcGNDbGllbnQgfSBmcm9tICcuL2lwYy1jbGllbnQnO1xuaW1wb3J0IHsgUXVlcnkgfSBmcm9tICcuL3F1ZXJ5JztcbmltcG9ydCB7IHN0YXJ0RW1iZWRkZWRTZXJ2ZXIsIHN0b3BFbWJlZGRlZFNlcnZlciB9IGZyb20gJy4vc2VydmVyLW1hbmFnZXInO1xuXG4vKipcbiAqIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIERhdGFiYXNlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIERhdGFiYXNlQ29uZmlnIHtcbiAgLyoqIFBhdGggdG8gdGhlIGRhdGFiYXNlIGRpcmVjdG9yeSAqL1xuICBwYXRoOiBzdHJpbmc7XG4gIC8qKiBXaGV0aGVyIHRvIGNyZWF0ZSB0aGUgZGF0YWJhc2UgaWYgaXQgZG9lc24ndCBleGlzdCAoZGVmYXVsdDogdHJ1ZSkgKi9cbiAgY3JlYXRlSWZNaXNzaW5nPzogYm9vbGVhbjtcbiAgLyoqIEVuYWJsZSBXQUwgKFdyaXRlLUFoZWFkIExvZ2dpbmcpIGZvciBkdXJhYmlsaXR5IChkZWZhdWx0OiB0cnVlKSAqL1xuICB3YWxFbmFibGVkPzogYm9vbGVhbjtcbiAgLyoqIFN5bmMgbW9kZTogJ2Z1bGwnIHwgJ25vcm1hbCcgfCAnb2ZmJyAoZGVmYXVsdDogJ25vcm1hbCcpICovXG4gIHN5bmNNb2RlPzogJ2Z1bGwnIHwgJ25vcm1hbCcgfCAnb2ZmJztcbiAgLyoqIE1heGltdW0gc2l6ZSBvZiB0aGUgbWVtdGFibGUgYmVmb3JlIGZsdXNoaW5nIChkZWZhdWx0OiA2NE1CKSAqL1xuICBtZW10YWJsZVNpemVCeXRlcz86IG51bWJlcjtcbiAgLyoqIFxuICAgKiBXaGV0aGVyIHRvIGF1dG9tYXRpY2FsbHkgc3RhcnQgYW4gZW1iZWRkZWQgc2VydmVyIChkZWZhdWx0OiB0cnVlKVxuICAgKiBTZXQgdG8gZmFsc2UgaWYgY29ubmVjdGluZyB0byBhbiBleGlzdGluZyBleHRlcm5hbCBzZXJ2ZXJcbiAgICovXG4gIGVtYmVkZGVkPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBSZXN1bHQgb2YgYSBTUUwgcXVlcnkgZXhlY3V0aW9uLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNRTFF1ZXJ5UmVzdWx0IHtcbiAgLyoqIFJlc3VsdCByb3dzICovXG4gIHJvd3M6IEFycmF5PFJlY29yZDxzdHJpbmcsIGFueT4+O1xuICAvKiogQ29sdW1uIG5hbWVzICovXG4gIGNvbHVtbnM6IHN0cmluZ1tdO1xuICAvKiogTnVtYmVyIG9mIHJvd3MgYWZmZWN0ZWQgKGZvciBJTlNFUlQvVVBEQVRFL0RFTEVURSkgKi9cbiAgcm93c0FmZmVjdGVkOiBudW1iZXI7XG59XG5cbi8qKlxuICogVHJhbnNhY3Rpb24gaGFuZGxlIGZvciBhdG9taWMgb3BlcmF0aW9ucy5cbiAqL1xuZXhwb3J0IGNsYXNzIFRyYW5zYWN0aW9uIHtcbiAgcHJpdmF0ZSBfZGI6IERhdGFiYXNlO1xuICBwcml2YXRlIF90eG5JZDogYmlnaW50IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgX2NvbW1pdHRlZCA9IGZhbHNlO1xuICBwcml2YXRlIF9hYm9ydGVkID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3IoZGI6IERhdGFiYXNlKSB7XG4gICAgdGhpcy5fZGIgPSBkYjtcbiAgfVxuXG4gIC8qKlxuICAgKiBCZWdpbiB0aGUgdHJhbnNhY3Rpb24uXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgYXN5bmMgYmVnaW4oKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5fdHhuSWQgPSBhd2FpdCB0aGlzLl9kYlsnX2JlZ2luVHJhbnNhY3Rpb24nXSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhIHZhbHVlIGJ5IGtleSB3aXRoaW4gdGhpcyB0cmFuc2FjdGlvbi5cbiAgICovXG4gIGFzeW5jIGdldChrZXk6IEJ1ZmZlciB8IHN0cmluZyk6IFByb21pc2U8QnVmZmVyIHwgbnVsbD4ge1xuICAgIHRoaXMuX2Vuc3VyZUFjdGl2ZSgpO1xuICAgIHJldHVybiB0aGlzLl9kYi5nZXQoa2V5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQdXQgYSBrZXktdmFsdWUgcGFpciB3aXRoaW4gdGhpcyB0cmFuc2FjdGlvbi5cbiAgICovXG4gIGFzeW5jIHB1dChrZXk6IEJ1ZmZlciB8IHN0cmluZywgdmFsdWU6IEJ1ZmZlciB8IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuX2Vuc3VyZUFjdGl2ZSgpO1xuICAgIHJldHVybiB0aGlzLl9kYi5wdXQoa2V5LCB2YWx1ZSk7XG4gIH1cblxuICAvKipcbiAgICogRGVsZXRlIGEga2V5IHdpdGhpbiB0aGlzIHRyYW5zYWN0aW9uLlxuICAgKi9cbiAgYXN5bmMgZGVsZXRlKGtleTogQnVmZmVyIHwgc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5fZW5zdXJlQWN0aXZlKCk7XG4gICAgcmV0dXJuIHRoaXMuX2RiLmRlbGV0ZShrZXkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNjYW4ga2V5cyB3aXRoIGEgcHJlZml4IHdpdGhpbiB0aGlzIHRyYW5zYWN0aW9uLlxuICAgKiBAcGFyYW0gcHJlZml4IC0gVGhlIHByZWZpeCB0byBzY2FuIGZvclxuICAgKiBAcGFyYW0gZW5kIC0gT3B0aW9uYWwgZW5kIGJvdW5kYXJ5IChleGNsdXNpdmUpXG4gICAqL1xuICBhc3luYyAqc2NhbihwcmVmaXg6IHN0cmluZyB8IEJ1ZmZlciwgZW5kPzogc3RyaW5nIHwgQnVmZmVyKTogQXN5bmNHZW5lcmF0b3I8W0J1ZmZlciwgQnVmZmVyXT4ge1xuICAgIHRoaXMuX2Vuc3VyZUFjdGl2ZSgpO1xuICAgIC8vIERlbGVnYXRlIHRvIGRhdGFiYXNlJ3Mgc2NhbiBtZXRob2RcbiAgICAvLyBUcmFuc2FjdGlvbmFsIGlzb2xhdGlvbiBpcyBtYWludGFpbmVkIGJ5IHRoZSB1bmRlcmx5aW5nIHN0b3JhZ2VcbiAgICBmb3IgYXdhaXQgKGNvbnN0IGVudHJ5IG9mIHRoaXMuX2RiLnNjYW5HZW5lcmF0b3IocHJlZml4LCBlbmQpKSB7XG4gICAgICB5aWVsZCBlbnRyeTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0IGEgdmFsdWUgYnkgcGF0aCB3aXRoaW4gdGhpcyB0cmFuc2FjdGlvbi5cbiAgICovXG4gIGFzeW5jIGdldFBhdGgocGF0aFN0cjogc3RyaW5nKTogUHJvbWlzZTxCdWZmZXIgfCBudWxsPiB7XG4gICAgdGhpcy5fZW5zdXJlQWN0aXZlKCk7XG4gICAgcmV0dXJuIHRoaXMuX2RiLmdldFBhdGgocGF0aFN0cik7XG4gIH1cblxuICAvKipcbiAgICogUHV0IGEgdmFsdWUgYXQgYSBwYXRoIHdpdGhpbiB0aGlzIHRyYW5zYWN0aW9uLlxuICAgKi9cbiAgYXN5bmMgcHV0UGF0aChwYXRoU3RyOiBzdHJpbmcsIHZhbHVlOiBCdWZmZXIgfCBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLl9lbnN1cmVBY3RpdmUoKTtcbiAgICByZXR1cm4gdGhpcy5fZGIucHV0UGF0aChwYXRoU3RyLCB2YWx1ZSk7XG4gIH1cblxuICAvKipcbiAgICogQ29tbWl0IHRoZSB0cmFuc2FjdGlvbi5cbiAgICogXG4gICAqIEFmdGVyIGNvbW1pdHRpbmcsIGFuIG9wdGlvbmFsIGNoZWNrcG9pbnQgaXMgdHJpZ2dlcmVkIHRvIGVuc3VyZSB3cml0ZXNcbiAgICogYXJlIGR1cmFibGUuIFRoaXMgcHJldmVudHMgcmFjZSBjb25kaXRpb25zIHdoZXJlIHN1YnNlcXVlbnQgcmVhZHMgbWlnaHRcbiAgICogbm90IHNlZSBjb21taXR0ZWQgZGF0YSBkdWUgdG8gYXN5bmMgZmx1c2ggdGltaW5nLlxuICAgKi9cbiAgYXN5bmMgY29tbWl0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuX2Vuc3VyZUFjdGl2ZSgpO1xuICAgIGlmICh0aGlzLl90eG5JZCAhPT0gbnVsbCkge1xuICAgICAgYXdhaXQgdGhpcy5fZGJbJ19jb21taXRUcmFuc2FjdGlvbiddKHRoaXMuX3R4bklkKTtcbiAgICAgIC8vIFRyaWdnZXIgY2hlY2twb2ludCB0byBlbnN1cmUgZHVyYWJpbGl0eSAoYWRkcmVzc2VzIHJhY2UgY29uZGl0aW9uKVxuICAgICAgLy8gTm90ZTogVGhpcyBpcyBhIHRyYWRlLW9mZiBiZXR3ZWVuIGNvbnNpc3RlbmN5IGFuZCBwZXJmb3JtYW5jZS5cbiAgICAgIC8vIEZvciBoaWdoLXRocm91Z2hwdXQgc2NlbmFyaW9zLCBjb25zaWRlciBiYXRjaGluZyBjaGVja3BvaW50cy5cbiAgICAgIGF3YWl0IHRoaXMuX2RiLmNoZWNrcG9pbnQoKTtcbiAgICB9XG4gICAgdGhpcy5fY29tbWl0dGVkID0gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBYm9ydC9yb2xsYmFjayB0aGUgdHJhbnNhY3Rpb24uXG4gICAqL1xuICBhc3luYyBhYm9ydCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5fY29tbWl0dGVkIHx8IHRoaXMuX2Fib3J0ZWQpIHJldHVybjtcbiAgICBpZiAodGhpcy5fdHhuSWQgIT09IG51bGwpIHtcbiAgICAgIGF3YWl0IHRoaXMuX2RiWydfYWJvcnRUcmFuc2FjdGlvbiddKHRoaXMuX3R4bklkKTtcbiAgICB9XG4gICAgdGhpcy5fYWJvcnRlZCA9IHRydWU7XG4gIH1cblxuICBwcml2YXRlIF9lbnN1cmVBY3RpdmUoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuX2NvbW1pdHRlZCkge1xuICAgICAgdGhyb3cgbmV3IFRyYW5zYWN0aW9uRXJyb3IoJ1RyYW5zYWN0aW9uIGFscmVhZHkgY29tbWl0dGVkJyk7XG4gICAgfVxuICAgIGlmICh0aGlzLl9hYm9ydGVkKSB7XG4gICAgICB0aHJvdyBuZXcgVHJhbnNhY3Rpb25FcnJvcignVHJhbnNhY3Rpb24gYWxyZWFkeSBhYm9ydGVkJyk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogU29jaERCIERhdGFiYXNlIGNsaWVudC5cbiAqXG4gKiBQcm92aWRlcyBhY2Nlc3MgdG8gU29jaERCIHdpdGggZnVsbCB0cmFuc2FjdGlvbiBzdXBwb3J0LlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBEYXRhYmFzZSB9IGZyb20gJ0BzdXNoYW50aC9zb2NoZGInO1xuICpcbiAqIC8vIE9wZW4gYSBkYXRhYmFzZVxuICogY29uc3QgZGIgPSBhd2FpdCBEYXRhYmFzZS5vcGVuKCcuL215X2RhdGFiYXNlJyk7XG4gKlxuICogLy8gU2ltcGxlIGtleS12YWx1ZSBvcGVyYXRpb25zXG4gKiBhd2FpdCBkYi5wdXQoQnVmZmVyLmZyb20oJ3VzZXI6MTIzJyksIEJ1ZmZlci5mcm9tKCd7XCJuYW1lXCI6IFwiQWxpY2VcIn0nKSk7XG4gKiBjb25zdCB2YWx1ZSA9IGF3YWl0IGRiLmdldChCdWZmZXIuZnJvbSgndXNlcjoxMjMnKSk7XG4gKlxuICogLy8gUGF0aC1uYXRpdmUgQVBJXG4gKiBhd2FpdCBkYi5wdXRQYXRoKCd1c2Vycy9hbGljZS9lbWFpbCcsIEJ1ZmZlci5mcm9tKCdhbGljZUBleGFtcGxlLmNvbScpKTtcbiAqIGNvbnN0IGVtYWlsID0gYXdhaXQgZGIuZ2V0UGF0aCgndXNlcnMvYWxpY2UvZW1haWwnKTtcbiAqXG4gKiAvLyBUcmFuc2FjdGlvbnNcbiAqIGF3YWl0IGRiLndpdGhUcmFuc2FjdGlvbihhc3luYyAodHhuKSA9PiB7XG4gKiAgIGF3YWl0IHR4bi5wdXQoQnVmZmVyLmZyb20oJ2tleTEnKSwgQnVmZmVyLmZyb20oJ3ZhbHVlMScpKTtcbiAqICAgYXdhaXQgdHhuLnB1dChCdWZmZXIuZnJvbSgna2V5MicpLCBCdWZmZXIuZnJvbSgndmFsdWUyJykpO1xuICogfSk7XG4gKlxuICogLy8gQ2xlYW4gdXBcbiAqIGF3YWl0IGRiLmNsb3NlKCk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNsYXNzIERhdGFiYXNlIHtcbiAgcHJpdmF0ZSBfY2xpZW50OiBJcGNDbGllbnQgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBfY29uZmlnOiBEYXRhYmFzZUNvbmZpZztcbiAgcHJpdmF0ZSBfY2xvc2VkID0gZmFsc2U7XG4gIHByaXZhdGUgX2VtYmVkZGVkU2VydmVyU3RhcnRlZCA9IGZhbHNlO1xuXG4gIHByaXZhdGUgY29uc3RydWN0b3IoY29uZmlnOiBEYXRhYmFzZUNvbmZpZykge1xuICAgIHRoaXMuX2NvbmZpZyA9IHtcbiAgICAgIGNyZWF0ZUlmTWlzc2luZzogdHJ1ZSxcbiAgICAgIHdhbEVuYWJsZWQ6IHRydWUsXG4gICAgICBzeW5jTW9kZTogJ25vcm1hbCcsXG4gICAgICBtZW10YWJsZVNpemVCeXRlczogNjQgKiAxMDI0ICogMTAyNCxcbiAgICAgIGVtYmVkZGVkOiB0cnVlLCAgLy8gRGVmYXVsdCB0byBlbWJlZGRlZCBtb2RlXG4gICAgICAuLi5jb25maWcsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPcGVuIGEgZGF0YWJhc2UgYXQgdGhlIHNwZWNpZmllZCBwYXRoLlxuICAgKlxuICAgKiBAcGFyYW0gcGF0aE9yQ29uZmlnIC0gUGF0aCB0byB0aGUgZGF0YWJhc2UgZGlyZWN0b3J5IG9yIGNvbmZpZ3VyYXRpb24gb2JqZWN0XG4gICAqIEByZXR1cm5zIEEgbmV3IERhdGFiYXNlIGluc3RhbmNlXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gU2ltcGxlIHVzYWdlIChlbWJlZGRlZCBtb2RlIC0gc3RhcnRzIHNlcnZlciBhdXRvbWF0aWNhbGx5KVxuICAgKiBjb25zdCBkYiA9IGF3YWl0IERhdGFiYXNlLm9wZW4oJy4vbXlfZGF0YWJhc2UnKTtcbiAgICpcbiAgICogLy8gV2l0aCBjb25maWd1cmF0aW9uXG4gICAqIGNvbnN0IGRiID0gYXdhaXQgRGF0YWJhc2Uub3Blbih7XG4gICAqICAgcGF0aDogJy4vbXlfZGF0YWJhc2UnLFxuICAgKiAgIHdhbEVuYWJsZWQ6IHRydWUsXG4gICAqICAgc3luY01vZGU6ICdmdWxsJyxcbiAgICogfSk7XG4gICAqIFxuICAgKiAvLyBDb25uZWN0IHRvIGV4aXN0aW5nIGV4dGVybmFsIHNlcnZlclxuICAgKiBjb25zdCBkYiA9IGF3YWl0IERhdGFiYXNlLm9wZW4oe1xuICAgKiAgIHBhdGg6ICcuL215X2RhdGFiYXNlJyxcbiAgICogICBlbWJlZGRlZDogZmFsc2UsICAvLyBEb24ndCBzdGFydCBlbWJlZGRlZCBzZXJ2ZXJcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgc3RhdGljIGFzeW5jIG9wZW4ocGF0aE9yQ29uZmlnOiBzdHJpbmcgfCBEYXRhYmFzZUNvbmZpZyk6IFByb21pc2U8RGF0YWJhc2U+IHtcbiAgICBjb25zdCBjb25maWc6IERhdGFiYXNlQ29uZmlnID1cbiAgICAgIHR5cGVvZiBwYXRoT3JDb25maWcgPT09ICdzdHJpbmcnID8geyBwYXRoOiBwYXRoT3JDb25maWcgfSA6IHBhdGhPckNvbmZpZztcblxuICAgIC8vIEVuc3VyZSBkYXRhYmFzZSBkaXJlY3RvcnkgZXhpc3RzXG4gICAgaWYgKGNvbmZpZy5jcmVhdGVJZk1pc3NpbmcgIT09IGZhbHNlKSB7XG4gICAgICBpZiAoIWZzLmV4aXN0c1N5bmMoY29uZmlnLnBhdGgpKSB7XG4gICAgICAgIGZzLm1rZGlyU3luYyhjb25maWcucGF0aCwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgZGIgPSBuZXcgRGF0YWJhc2UoY29uZmlnKTtcblxuICAgIC8vIFN0YXJ0IGVtYmVkZGVkIHNlcnZlciBpZiBjb25maWd1cmVkIChkZWZhdWx0OiB0cnVlKVxuICAgIGxldCBzb2NrZXRQYXRoOiBzdHJpbmc7XG4gICAgaWYgKGRiLl9jb25maWcuZW1iZWRkZWQgIT09IGZhbHNlKSB7XG4gICAgICAvLyBTdGFydCBlbWJlZGRlZCBzZXJ2ZXIgYW5kIGdldCBzb2NrZXQgcGF0aFxuICAgICAgc29ja2V0UGF0aCA9IGF3YWl0IHN0YXJ0RW1iZWRkZWRTZXJ2ZXIoY29uZmlnLnBhdGgpO1xuICAgICAgZGIuX2VtYmVkZGVkU2VydmVyU3RhcnRlZCA9IHRydWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIENvbm5lY3QgdG8gZXhpc3Rpbmcgc2VydmVyIHNvY2tldFxuICAgICAgc29ja2V0UGF0aCA9IHBhdGguam9pbihjb25maWcucGF0aCwgJ3NvY2hkYi5zb2NrJyk7XG4gICAgfVxuXG4gICAgZGIuX2NsaWVudCA9IGF3YWl0IElwY0NsaWVudC5jb25uZWN0KHNvY2tldFBhdGgpO1xuXG4gICAgLy8gVHJhY2sgZGF0YWJhc2Ugb3BlbiBldmVudCAob25seSBhbmFseXRpY3MgZXZlbnQgd2Ugc2VuZClcbiAgICB0cnkge1xuICAgICAgY29uc3QgeyB0cmFja0RhdGFiYXNlT3BlbiB9ID0gYXdhaXQgaW1wb3J0KCcuL2FuYWx5dGljcy5qcycpO1xuICAgICAgYXdhaXQgdHJhY2tEYXRhYmFzZU9wZW4oY29uZmlnLnBhdGgsICdlbWJlZGRlZCcpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gTmV2ZXIgbGV0IGFuYWx5dGljcyBicmVhayBkYXRhYmFzZSBvcGVyYXRpb25zXG4gICAgfVxuXG4gICAgcmV0dXJuIGRiO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhIHZhbHVlIGJ5IGtleS5cbiAgICpcbiAgICogQHBhcmFtIGtleSAtIFRoZSBrZXkgdG8gbG9vayB1cCAoQnVmZmVyIG9yIHN0cmluZylcbiAgICogQHJldHVybnMgVGhlIHZhbHVlIGFzIGEgQnVmZmVyLCBvciBudWxsIGlmIG5vdCBmb3VuZFxuICAgKi9cbiAgYXN5bmMgZ2V0KGtleTogQnVmZmVyIHwgc3RyaW5nKTogUHJvbWlzZTxCdWZmZXIgfCBudWxsPiB7XG4gICAgdGhpcy5fZW5zdXJlT3BlbigpO1xuICAgIGNvbnN0IGtleUJ1ZiA9IHR5cGVvZiBrZXkgPT09ICdzdHJpbmcnID8gQnVmZmVyLmZyb20oa2V5KSA6IGtleTtcbiAgICByZXR1cm4gdGhpcy5fY2xpZW50IS5nZXQoa2V5QnVmKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQdXQgYSBrZXktdmFsdWUgcGFpci5cbiAgICpcbiAgICogQHBhcmFtIGtleSAtIFRoZSBrZXkgKEJ1ZmZlciBvciBzdHJpbmcpXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSAoQnVmZmVyIG9yIHN0cmluZylcbiAgICovXG4gIGFzeW5jIHB1dChrZXk6IEJ1ZmZlciB8IHN0cmluZywgdmFsdWU6IEJ1ZmZlciB8IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuX2Vuc3VyZU9wZW4oKTtcbiAgICBjb25zdCBrZXlCdWYgPSB0eXBlb2Yga2V5ID09PSAnc3RyaW5nJyA/IEJ1ZmZlci5mcm9tKGtleSkgOiBrZXk7XG4gICAgY29uc3QgdmFsdWVCdWYgPSB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gQnVmZmVyLmZyb20odmFsdWUpIDogdmFsdWU7XG4gICAgcmV0dXJuIHRoaXMuX2NsaWVudCEucHV0KGtleUJ1ZiwgdmFsdWVCdWYpO1xuICB9XG5cbiAgLyoqXG4gICAqIERlbGV0ZSBhIGtleS5cbiAgICpcbiAgICogQHBhcmFtIGtleSAtIFRoZSBrZXkgdG8gZGVsZXRlIChCdWZmZXIgb3Igc3RyaW5nKVxuICAgKi9cbiAgYXN5bmMgZGVsZXRlKGtleTogQnVmZmVyIHwgc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5fZW5zdXJlT3BlbigpO1xuICAgIGNvbnN0IGtleUJ1ZiA9IHR5cGVvZiBrZXkgPT09ICdzdHJpbmcnID8gQnVmZmVyLmZyb20oa2V5KSA6IGtleTtcbiAgICByZXR1cm4gdGhpcy5fY2xpZW50IS5kZWxldGUoa2V5QnVmKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgYSB2YWx1ZSBieSBwYXRoLlxuICAgKlxuICAgKiBAcGFyYW0gcGF0aFN0ciAtIFRoZSBwYXRoIChlLmcuLCBcInVzZXJzL2FsaWNlL2VtYWlsXCIpXG4gICAqIEByZXR1cm5zIFRoZSB2YWx1ZSBhcyBhIEJ1ZmZlciwgb3IgbnVsbCBpZiBub3QgZm91bmRcbiAgICovXG4gIGFzeW5jIGdldFBhdGgocGF0aFN0cjogc3RyaW5nKTogUHJvbWlzZTxCdWZmZXIgfCBudWxsPiB7XG4gICAgdGhpcy5fZW5zdXJlT3BlbigpO1xuICAgIHJldHVybiB0aGlzLl9jbGllbnQhLmdldFBhdGgocGF0aFN0cik7XG4gIH1cblxuICAvKipcbiAgICogUHV0IGEgdmFsdWUgYXQgYSBwYXRoLlxuICAgKlxuICAgKiBAcGFyYW0gcGF0aFN0ciAtIFRoZSBwYXRoIChlLmcuLCBcInVzZXJzL2FsaWNlL2VtYWlsXCIpXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSAoQnVmZmVyIG9yIHN0cmluZylcbiAgICovXG4gIGFzeW5jIHB1dFBhdGgocGF0aFN0cjogc3RyaW5nLCB2YWx1ZTogQnVmZmVyIHwgc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5fZW5zdXJlT3BlbigpO1xuICAgIGNvbnN0IHZhbHVlQnVmID0gdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/IEJ1ZmZlci5mcm9tKHZhbHVlKSA6IHZhbHVlO1xuICAgIHJldHVybiB0aGlzLl9jbGllbnQhLnB1dFBhdGgocGF0aFN0ciwgdmFsdWVCdWYpO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIHF1ZXJ5IGJ1aWxkZXIgZm9yIHRoZSBnaXZlbiBwYXRoIHByZWZpeC5cbiAgICpcbiAgICogQHBhcmFtIHBhdGhQcmVmaXggLSBUaGUgcGF0aCBwcmVmaXggdG8gcXVlcnkgKGUuZy4sIFwidXNlcnMvXCIpXG4gICAqIEByZXR1cm5zIEEgUXVlcnkgYnVpbGRlciBpbnN0YW5jZVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCBkYi5xdWVyeSgndXNlcnMvJylcbiAgICogICAubGltaXQoMTApXG4gICAqICAgLnNlbGVjdChbJ25hbWUnLCAnZW1haWwnXSlcbiAgICogICAuZXhlY3V0ZSgpO1xuICAgKiBgYGBcbiAgICovXG4gIHF1ZXJ5KHBhdGhQcmVmaXg6IHN0cmluZyk6IFF1ZXJ5IHtcbiAgICB0aGlzLl9lbnN1cmVPcGVuKCk7XG4gICAgcmV0dXJuIG5ldyBRdWVyeSh0aGlzLl9jbGllbnQhLCBwYXRoUHJlZml4KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTY2FuIGZvciBrZXlzIHdpdGggYSBwcmVmaXgsIHJldHVybmluZyBrZXktdmFsdWUgcGFpcnMuXG4gICAqIFRoaXMgaXMgdGhlIHByZWZlcnJlZCBtZXRob2QgZm9yIHNpbXBsZSBwcmVmaXgtYmFzZWQgaXRlcmF0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0gcHJlZml4IC0gVGhlIHByZWZpeCB0byBzY2FuIGZvciAoZS5nLiwgXCJ1c2Vycy9cIiwgXCJ0ZW5hbnRzL3RlbmFudDEvXCIpXG4gICAqIEByZXR1cm5zIEFycmF5IG9mIGtleS12YWx1ZSBwYWlyc1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCBkYi5zY2FuKCd0ZW5hbnRzL3RlbmFudDEvJyk7XG4gICAqIGZvciAoY29uc3QgeyBrZXksIHZhbHVlIH0gb2YgcmVzdWx0cykge1xuICAgKiAgIGNvbnNvbGUubG9nKGAke2tleS50b1N0cmluZygpfTogJHt2YWx1ZS50b1N0cmluZygpfWApO1xuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgc2NhbihwcmVmaXg6IHN0cmluZyk6IFByb21pc2U8QXJyYXk8eyBrZXk6IEJ1ZmZlcjsgdmFsdWU6IEJ1ZmZlciB9Pj4ge1xuICAgIHRoaXMuX2Vuc3VyZU9wZW4oKTtcbiAgICByZXR1cm4gdGhpcy5fY2xpZW50IS5zY2FuKHByZWZpeCk7XG4gIH1cblxuICAvKipcbiAgICogU2NhbiBmb3Iga2V5cyB3aXRoIGEgcHJlZml4IHVzaW5nIGFuIGFzeW5jIGdlbmVyYXRvci5cbiAgICogVGhpcyBhbGxvd3MgZm9yIG1lbW9yeS1lZmZpY2llbnQgaXRlcmF0aW9uIG92ZXIgbGFyZ2UgcmVzdWx0IHNldHMuXG4gICAqXG4gICAqIEBwYXJhbSBwcmVmaXggLSBUaGUgcHJlZml4IHRvIHNjYW4gZm9yXG4gICAqIEBwYXJhbSBlbmQgLSBPcHRpb25hbCBlbmQgYm91bmRhcnkgKGV4Y2x1c2l2ZSlcbiAgICogQHJldHVybnMgQXN5bmMgZ2VuZXJhdG9yIHlpZWxkaW5nIFtrZXksIHZhbHVlXSB0dXBsZXNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBmb3IgYXdhaXQgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBkYi5zY2FuR2VuZXJhdG9yKCd1c2Vycy8nKSkge1xuICAgKiAgIGNvbnNvbGUubG9nKGAke2tleS50b1N0cmluZygpfTogJHt2YWx1ZS50b1N0cmluZygpfWApO1xuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgKnNjYW5HZW5lcmF0b3IocHJlZml4OiBzdHJpbmcgfCBCdWZmZXIsIGVuZD86IHN0cmluZyB8IEJ1ZmZlcik6IEFzeW5jR2VuZXJhdG9yPFtCdWZmZXIsIEJ1ZmZlcl0+IHtcbiAgICB0aGlzLl9lbnN1cmVPcGVuKCk7XG4gICAgY29uc3QgcHJlZml4QnVmID0gdHlwZW9mIHByZWZpeCA9PT0gJ3N0cmluZycgPyBCdWZmZXIuZnJvbShwcmVmaXgpIDogcHJlZml4O1xuICAgIGNvbnN0IGVuZEJ1ZiA9IGVuZCA/ICh0eXBlb2YgZW5kID09PSAnc3RyaW5nJyA/IEJ1ZmZlci5mcm9tKGVuZCkgOiBlbmQpIDogdW5kZWZpbmVkO1xuXG4gICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IHRoaXMuX2NsaWVudCEuc2NhbihwcmVmaXhCdWYudG9TdHJpbmcoKSk7XG4gICAgZm9yIChjb25zdCB7IGtleSwgdmFsdWUgfSBvZiByZXN1bHRzKSB7XG4gICAgICAvLyBGaWx0ZXIgYnkgZW5kIGJvdW5kYXJ5IGlmIHByb3ZpZGVkXG4gICAgICBpZiAoZW5kQnVmICYmIEJ1ZmZlci5jb21wYXJlKGtleSwgZW5kQnVmKSA+PSAwKSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgeWllbGQgW2tleSwgdmFsdWVdO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBFeGVjdXRlIG9wZXJhdGlvbnMgd2l0aGluIGEgdHJhbnNhY3Rpb24uXG4gICAqXG4gICAqIFRoZSB0cmFuc2FjdGlvbiBhdXRvbWF0aWNhbGx5IGNvbW1pdHMgb24gc3VjY2VzcyBvciBhYm9ydHMgb24gZXJyb3IuXG4gICAqXG4gICAqIEBwYXJhbSBmbiAtIEFzeW5jIGZ1bmN0aW9uIHRoYXQgcmVjZWl2ZXMgYSBUcmFuc2FjdGlvbiBvYmplY3RcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBhd2FpdCBkYi53aXRoVHJhbnNhY3Rpb24oYXN5bmMgKHR4bikgPT4ge1xuICAgKiAgIGF3YWl0IHR4bi5wdXQoQnVmZmVyLmZyb20oJ2tleTEnKSwgQnVmZmVyLmZyb20oJ3ZhbHVlMScpKTtcbiAgICogICBhd2FpdCB0eG4ucHV0KEJ1ZmZlci5mcm9tKCdrZXkyJyksIEJ1ZmZlci5mcm9tKCd2YWx1ZTInKSk7XG4gICAqICAgLy8gQXV0b21hdGljYWxseSBjb21taXRzXG4gICAqIH0pO1xuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIHdpdGhUcmFuc2FjdGlvbjxUPihmbjogKHR4bjogVHJhbnNhY3Rpb24pID0+IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+IHtcbiAgICB0aGlzLl9lbnN1cmVPcGVuKCk7XG4gICAgY29uc3QgdHhuID0gbmV3IFRyYW5zYWN0aW9uKHRoaXMpO1xuICAgIGF3YWl0IHR4bi5iZWdpbigpO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBmbih0eG4pO1xuICAgICAgYXdhaXQgdHhuLmNvbW1pdCgpO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgYXdhaXQgdHhuLmFib3J0KCk7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGEgbmV3IHRyYW5zYWN0aW9uLlxuICAgKlxuICAgKiBAcmV0dXJucyBBIG5ldyBUcmFuc2FjdGlvbiBpbnN0YW5jZVxuICAgKiBAZGVwcmVjYXRlZCBVc2Ugd2l0aFRyYW5zYWN0aW9uKCkgZm9yIGF1dG9tYXRpYyBjb21taXQvYWJvcnQgaGFuZGxpbmdcbiAgICovXG4gIGFzeW5jIHRyYW5zYWN0aW9uKCk6IFByb21pc2U8VHJhbnNhY3Rpb24+IHtcbiAgICB0aGlzLl9lbnN1cmVPcGVuKCk7XG4gICAgY29uc3QgdHhuID0gbmV3IFRyYW5zYWN0aW9uKHRoaXMpO1xuICAgIGF3YWl0IHR4bi5iZWdpbigpO1xuICAgIHJldHVybiB0eG47XG4gIH1cblxuICAvKipcbiAgICogRm9yY2UgYSBjaGVja3BvaW50IHRvIHBlcnNpc3QgbWVtdGFibGUgdG8gZGlzay5cbiAgICovXG4gIGFzeW5jIGNoZWNrcG9pbnQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5fZW5zdXJlT3BlbigpO1xuICAgIHJldHVybiB0aGlzLl9jbGllbnQhLmNoZWNrcG9pbnQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgc3RvcmFnZSBzdGF0aXN0aWNzLlxuICAgKi9cbiAgYXN5bmMgc3RhdHMoKTogUHJvbWlzZTx7XG4gICAgbWVtdGFibGVTaXplQnl0ZXM6IG51bWJlcjtcbiAgICB3YWxTaXplQnl0ZXM6IG51bWJlcjtcbiAgICBhY3RpdmVUcmFuc2FjdGlvbnM6IG51bWJlcjtcbiAgfT4ge1xuICAgIHRoaXMuX2Vuc3VyZU9wZW4oKTtcbiAgICByZXR1cm4gdGhpcy5fY2xpZW50IS5zdGF0cygpO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4ZWN1dGUgYSBTUUwgcXVlcnkuXG4gICAqIFxuICAgKiBTb2NoREIgc3VwcG9ydHMgYSBzdWJzZXQgb2YgU1FMIGZvciByZWxhdGlvbmFsIGRhdGEgc3RvcmVkIG9uIHRvcCBvZiBcbiAgICogdGhlIGtleS12YWx1ZSBlbmdpbmUuIFRhYmxlcyBhbmQgcm93cyBhcmUgc3RvcmVkIGFzOlxuICAgKiAtIFNjaGVtYTogX3NxbC90YWJsZXMve3RhYmxlX25hbWV9L3NjaGVtYVxuICAgKiAtIFJvd3M6IF9zcWwvdGFibGVzL3t0YWJsZV9uYW1lfS9yb3dzL3tyb3dfaWR9XG4gICAqIFxuICAgKiBTdXBwb3J0ZWQgU1FMOlxuICAgKiAtIENSRUFURSBUQUJMRSB0YWJsZV9uYW1lIChjb2wxIFRZUEUsIGNvbDIgVFlQRSwgLi4uKVxuICAgKiAtIERST1AgVEFCTEUgdGFibGVfbmFtZVxuICAgKiAtIElOU0VSVCBJTlRPIHRhYmxlX25hbWUgKGNvbHMpIFZBTFVFUyAodmFscylcbiAgICogLSBTRUxFQ1QgY29scyBGUk9NIHRhYmxlX25hbWUgW1dIRVJFIC4uLl0gW09SREVSIEJZIC4uLl0gW0xJTUlUIC4uLl1cbiAgICogLSBVUERBVEUgdGFibGVfbmFtZSBTRVQgY29sPXZhbCBbV0hFUkUgLi4uXVxuICAgKiAtIERFTEVURSBGUk9NIHRhYmxlX25hbWUgW1dIRVJFIC4uLl1cbiAgICogXG4gICAqIFN1cHBvcnRlZCB0eXBlczogSU5ULCBURVhULCBGTE9BVCwgQk9PTCwgQkxPQlxuICAgKiBcbiAgICogQHBhcmFtIHNxbCAtIFNRTCBxdWVyeSBzdHJpbmdcbiAgICogQHJldHVybnMgU1FMUXVlcnlSZXN1bHQgd2l0aCByb3dzIGFuZCBtZXRhZGF0YVxuICAgKiBcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiAvLyBDcmVhdGUgYSB0YWJsZVxuICAgKiBhd2FpdCBkYi5leGVjdXRlKFwiQ1JFQVRFIFRBQkxFIHVzZXJzIChpZCBJTlQgUFJJTUFSWSBLRVksIG5hbWUgVEVYVCwgYWdlIElOVClcIik7XG4gICAqIFxuICAgKiAvLyBJbnNlcnQgZGF0YVxuICAgKiBhd2FpdCBkYi5leGVjdXRlKFwiSU5TRVJUIElOVE8gdXNlcnMgKGlkLCBuYW1lLCBhZ2UpIFZBTFVFUyAoMSwgJ0FsaWNlJywgMzApXCIpO1xuICAgKiBcbiAgICogLy8gUXVlcnkgZGF0YVxuICAgKiBjb25zdCByZXN1bHQgPSBhd2FpdCBkYi5leGVjdXRlKFwiU0VMRUNUICogRlJPTSB1c2VycyBXSEVSRSBhZ2UgPiAyNlwiKTtcbiAgICogcmVzdWx0LnJvd3MuZm9yRWFjaChyb3cgPT4gY29uc29sZS5sb2cocm93KSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgZXhlY3V0ZShzcWw6IHN0cmluZyk6IFByb21pc2U8U1FMUXVlcnlSZXN1bHQ+IHtcbiAgICB0aGlzLl9lbnN1cmVPcGVuKCk7XG5cbiAgICAvLyBJbXBvcnQgdGhlIFNRTCBleGVjdXRvclxuICAgIGNvbnN0IHsgU1FMRXhlY3V0b3IgfSA9IGF3YWl0IGltcG9ydCgnLi9zcWwtZW5naW5lLmpzJyk7XG5cbiAgICAvLyBDcmVhdGUgYSBkYXRhYmFzZSBhZGFwdGVyIGZvciB0aGUgU1FMIGV4ZWN1dG9yXG4gICAgY29uc3QgZGJBZGFwdGVyID0ge1xuICAgICAgZ2V0OiAoa2V5OiBCdWZmZXIgfCBzdHJpbmcpID0+IHRoaXMuZ2V0KGtleSksXG4gICAgICBwdXQ6IChrZXk6IEJ1ZmZlciB8IHN0cmluZywgdmFsdWU6IEJ1ZmZlciB8IHN0cmluZykgPT4gdGhpcy5wdXQoa2V5LCB2YWx1ZSksXG4gICAgICBkZWxldGU6IChrZXk6IEJ1ZmZlciB8IHN0cmluZykgPT4gdGhpcy5kZWxldGUoa2V5KSxcbiAgICAgIHNjYW46IChwcmVmaXg6IHN0cmluZykgPT4gdGhpcy5zY2FuKHByZWZpeCksXG4gICAgfTtcblxuICAgIGNvbnN0IGV4ZWN1dG9yID0gbmV3IFNRTEV4ZWN1dG9yKGRiQWRhcHRlcik7XG4gICAgcmV0dXJuIGV4ZWN1dG9yLmV4ZWN1dGUoc3FsKTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gU3RhdGljIFNlcmlhbGl6YXRpb24gTWV0aG9kc1xuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgcmVjb3JkcyB0byBUT09OIGZvcm1hdCBmb3IgdG9rZW4tZWZmaWNpZW50IExMTSBjb250ZXh0LlxuICAgKiBcbiAgICogVE9PTiBmb3JtYXQgYWNoaWV2ZXMgNDAtNjYlIHRva2VuIHJlZHVjdGlvbiBjb21wYXJlZCB0byBKU09OIGJ5IHVzaW5nXG4gICAqIGEgY29sdW1uYXIgdGV4dCBmb3JtYXQgd2l0aCBtaW5pbWFsIHN5bnRheC5cbiAgICogXG4gICAqIEBwYXJhbSB0YWJsZU5hbWUgLSBOYW1lIG9mIHRoZSB0YWJsZS9jb2xsZWN0aW9uXG4gICAqIEBwYXJhbSByZWNvcmRzIC0gQXJyYXkgb2Ygb2JqZWN0cyB3aXRoIHRoZSBkYXRhXG4gICAqIEBwYXJhbSBmaWVsZHMgLSBPcHRpb25hbCBhcnJheSBvZiBmaWVsZCBuYW1lcyB0byBpbmNsdWRlXG4gICAqIEByZXR1cm5zIFRPT04tZm9ybWF0dGVkIHN0cmluZ1xuICAgKiBcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCByZWNvcmRzID0gW1xuICAgKiAgIHsgaWQ6IDEsIG5hbWU6ICdBbGljZScsIGVtYWlsOiAnYWxpY2VAZXguY29tJyB9LFxuICAgKiAgIHsgaWQ6IDIsIG5hbWU6ICdCb2InLCBlbWFpbDogJ2JvYkBleC5jb20nIH1cbiAgICogXTtcbiAgICogY29uc29sZS5sb2coRGF0YWJhc2UudG9Ub29uKCd1c2VycycsIHJlY29yZHMsIFsnbmFtZScsICdlbWFpbCddKSk7XG4gICAqIC8vIHVzZXJzWzJde25hbWUsZW1haWx9OkFsaWNlLGFsaWNlQGV4LmNvbTtCb2IsYm9iQGV4LmNvbVxuICAgKiBgYGBcbiAgICovXG4gIHN0YXRpYyB0b1Rvb24oXG4gICAgdGFibGVOYW1lOiBzdHJpbmcsXG4gICAgcmVjb3JkczogQXJyYXk8UmVjb3JkPHN0cmluZywgYW55Pj4sXG4gICAgZmllbGRzPzogc3RyaW5nW11cbiAgKTogc3RyaW5nIHtcbiAgICBpZiAoIXJlY29yZHMgfHwgcmVjb3Jkcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBgJHt0YWJsZU5hbWV9WzBde306YDtcbiAgICB9XG5cbiAgICAvLyBEZXRlcm1pbmUgZmllbGRzIGZyb20gZmlyc3QgcmVjb3JkIGlmIG5vdCBzcGVjaWZpZWRcbiAgICBjb25zdCB1c2VGaWVsZHMgPSBmaWVsZHMgPz8gT2JqZWN0LmtleXMocmVjb3Jkc1swXSk7XG5cbiAgICAvLyBCdWlsZCBoZWFkZXI6IHRhYmxlW2NvdW50XXtmaWVsZDEsZmllbGQyLC4uLn06XG4gICAgY29uc3QgaGVhZGVyID0gYCR7dGFibGVOYW1lfVske3JlY29yZHMubGVuZ3RofV17JHt1c2VGaWVsZHMuam9pbignLCcpfX06YDtcblxuICAgIC8vIEVzY2FwZSB2YWx1ZXMgY29udGFpbmluZyBkZWxpbWl0ZXJzXG4gICAgY29uc3QgZXNjYXBlVmFsdWUgPSAodjogYW55KTogc3RyaW5nID0+IHtcbiAgICAgIGNvbnN0IHMgPSB2ICE9IG51bGwgPyBTdHJpbmcodikgOiAnJztcbiAgICAgIGlmIChzLmluY2x1ZGVzKCcsJykgfHwgcy5pbmNsdWRlcygnOycpIHx8IHMuaW5jbHVkZXMoJ1xcbicpKSB7XG4gICAgICAgIHJldHVybiBgXCIke3N9XCJgO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHM7XG4gICAgfTtcblxuICAgIC8vIEJ1aWxkIHJvd3M6IHZhbHVlMSx2YWx1ZTI7dmFsdWUxLHZhbHVlMjsuLi5cbiAgICBjb25zdCByb3dzID0gcmVjb3Jkc1xuICAgICAgLm1hcChyID0+IHVzZUZpZWxkcy5tYXAoZiA9PiBlc2NhcGVWYWx1ZShyW2ZdKSkuam9pbignLCcpKVxuICAgICAgLmpvaW4oJzsnKTtcblxuICAgIHJldHVybiBoZWFkZXIgKyByb3dzO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgcmVjb3JkcyB0byBKU09OIGZvcm1hdCBmb3IgZWFzeSBhcHBsaWNhdGlvbiBkZWNvZGluZy5cbiAgICogXG4gICAqIFdoaWxlIFRPT04gZm9ybWF0IGlzIG9wdGltaXplZCBmb3IgTExNIGNvbnRleHQgKDQwLTY2JSB0b2tlbiByZWR1Y3Rpb24pLFxuICAgKiBKU09OIGlzIG9mdGVuIGVhc2llciBmb3IgYXBwbGljYXRpb25zIHRvIHBhcnNlLiBVc2UgdGhpcyBtZXRob2Qgd2hlblxuICAgKiB0aGUgb3V0cHV0IHdpbGwgYmUgY29uc3VtZWQgYnkgYXBwbGljYXRpb24gY29kZSByYXRoZXIgdGhhbiBMTE1zLlxuICAgKiBcbiAgICogQHBhcmFtIHRhYmxlTmFtZSAtIE5hbWUgb2YgdGhlIHRhYmxlL2NvbGxlY3Rpb25cbiAgICogQHBhcmFtIHJlY29yZHMgLSBBcnJheSBvZiBvYmplY3RzIHdpdGggdGhlIGRhdGFcbiAgICogQHBhcmFtIGZpZWxkcyAtIE9wdGlvbmFsIGFycmF5IG9mIGZpZWxkIG5hbWVzIHRvIGluY2x1ZGVcbiAgICogQHBhcmFtIGNvbXBhY3QgLSBJZiB0cnVlIChkZWZhdWx0KSwgb3V0cHV0cyBtaW5pZmllZCBKU09OXG4gICAqIEByZXR1cm5zIEpTT04tZm9ybWF0dGVkIHN0cmluZ1xuICAgKiBcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCByZWNvcmRzID0gW1xuICAgKiAgIHsgaWQ6IDEsIG5hbWU6ICdBbGljZScgfSxcbiAgICogICB7IGlkOiAyLCBuYW1lOiAnQm9iJyB9XG4gICAqIF07XG4gICAqIGNvbnNvbGUubG9nKERhdGFiYXNlLnRvSnNvbigndXNlcnMnLCByZWNvcmRzKSk7XG4gICAqIC8vIHtcInRhYmxlXCI6XCJ1c2Vyc1wiLFwiY291bnRcIjoyLFwicmVjb3Jkc1wiOlt7XCJpZFwiOjEsXCJuYW1lXCI6XCJBbGljZVwifSx7XCJpZFwiOjIsXCJuYW1lXCI6XCJCb2JcIn1dfVxuICAgKiBgYGBcbiAgICovXG4gIHN0YXRpYyB0b0pzb24oXG4gICAgdGFibGVOYW1lOiBzdHJpbmcsXG4gICAgcmVjb3JkczogQXJyYXk8UmVjb3JkPHN0cmluZywgYW55Pj4sXG4gICAgZmllbGRzPzogc3RyaW5nW10sXG4gICAgY29tcGFjdDogYm9vbGVhbiA9IHRydWVcbiAgKTogc3RyaW5nIHtcbiAgICBpZiAoIXJlY29yZHMgfHwgcmVjb3Jkcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeSh7IHRhYmxlOiB0YWJsZU5hbWUsIGNvdW50OiAwLCByZWNvcmRzOiBbXSB9KTtcbiAgICB9XG5cbiAgICAvLyBGaWx0ZXIgZmllbGRzIGlmIHNwZWNpZmllZFxuICAgIGNvbnN0IGZpbHRlcmVkUmVjb3JkcyA9IGZpZWxkc1xuICAgICAgPyByZWNvcmRzLm1hcChyID0+IHtcbiAgICAgICAgY29uc3QgZmlsdGVyZWQ6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcbiAgICAgICAgZm9yIChjb25zdCBmIG9mIGZpZWxkcykge1xuICAgICAgICAgIGZpbHRlcmVkW2ZdID0gcltmXTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmlsdGVyZWQ7XG4gICAgICB9KVxuICAgICAgOiByZWNvcmRzO1xuXG4gICAgY29uc3Qgb3V0cHV0ID0ge1xuICAgICAgdGFibGU6IHRhYmxlTmFtZSxcbiAgICAgIGNvdW50OiBmaWx0ZXJlZFJlY29yZHMubGVuZ3RoLFxuICAgICAgcmVjb3JkczogZmlsdGVyZWRSZWNvcmRzLFxuICAgIH07XG5cbiAgICByZXR1cm4gY29tcGFjdCA/IEpTT04uc3RyaW5naWZ5KG91dHB1dCkgOiBKU09OLnN0cmluZ2lmeShvdXRwdXQsIG51bGwsIDIpO1xuICB9XG5cbiAgLyoqXG4gICAqIFBhcnNlIGEgSlNPTiBmb3JtYXQgc3RyaW5nIGJhY2sgdG8gc3RydWN0dXJlZCBkYXRhLlxuICAgKiBcbiAgICogQHBhcmFtIGpzb25TdHIgLSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgKGZyb20gdG9Kc29uKVxuICAgKiBAcmV0dXJucyBPYmplY3Qgd2l0aCB0YWJsZSwgZmllbGRzLCBhbmQgcmVjb3Jkc1xuICAgKi9cbiAgc3RhdGljIGZyb21Kc29uKGpzb25TdHI6IHN0cmluZyk6IHtcbiAgICB0YWJsZTogc3RyaW5nO1xuICAgIGZpZWxkczogc3RyaW5nW107XG4gICAgcmVjb3JkczogQXJyYXk8UmVjb3JkPHN0cmluZywgYW55Pj47XG4gIH0ge1xuICAgIGNvbnN0IGRhdGEgPSBKU09OLnBhcnNlKGpzb25TdHIpO1xuICAgIGNvbnN0IHRhYmxlID0gZGF0YS50YWJsZSA/PyAndW5rbm93bic7XG4gICAgY29uc3QgcmVjb3JkcyA9IGRhdGEucmVjb3JkcyA/PyBbXTtcbiAgICBjb25zdCBmaWVsZHMgPSByZWNvcmRzLmxlbmd0aCA+IDAgPyBPYmplY3Qua2V5cyhyZWNvcmRzWzBdKSA6IFtdO1xuXG4gICAgcmV0dXJuIHsgdGFibGUsIGZpZWxkcywgcmVjb3JkcyB9O1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBHcmFwaCBPdmVybGF5IE9wZXJhdGlvbnNcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBBZGQgYSBub2RlIHRvIHRoZSBncmFwaCBvdmVybGF5LlxuICAgKlxuICAgKiBAcGFyYW0gbmFtZXNwYWNlIC0gTmFtZXNwYWNlIGZvciB0aGUgZ3JhcGhcbiAgICogQHBhcmFtIG5vZGVJZCAtIFVuaXF1ZSBub2RlIGlkZW50aWZpZXJcbiAgICogQHBhcmFtIG5vZGVUeXBlIC0gVHlwZSBvZiBub2RlIChlLmcuLCBcInBlcnNvblwiLCBcImRvY3VtZW50XCIsIFwiY29uY2VwdFwiKVxuICAgKiBAcGFyYW0gcHJvcGVydGllcyAtIE9wdGlvbmFsIG5vZGUgcHJvcGVydGllc1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGF3YWl0IGRiLmFkZE5vZGUoJ2RlZmF1bHQnLCAnYWxpY2UnLCAncGVyc29uJywgeyByb2xlOiAnZW5naW5lZXInIH0pO1xuICAgKiBhd2FpdCBkYi5hZGROb2RlKCdkZWZhdWx0JywgJ3Byb2plY3RfeCcsICdwcm9qZWN0JywgeyBzdGF0dXM6ICdhY3RpdmUnIH0pO1xuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIGFkZE5vZGUoXG4gICAgbmFtZXNwYWNlOiBzdHJpbmcsXG4gICAgbm9kZUlkOiBzdHJpbmcsXG4gICAgbm9kZVR5cGU6IHN0cmluZyxcbiAgICBwcm9wZXJ0aWVzPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPlxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLl9lbnN1cmVPcGVuKCk7XG5cbiAgICBjb25zdCBrZXkgPSBgX2dyYXBoLyR7bmFtZXNwYWNlfS9ub2Rlcy8ke25vZGVJZH1gO1xuICAgIGNvbnN0IHZhbHVlID0gSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgaWQ6IG5vZGVJZCxcbiAgICAgIG5vZGVfdHlwZTogbm9kZVR5cGUsXG4gICAgICBwcm9wZXJ0aWVzOiBwcm9wZXJ0aWVzIHx8IHt9LFxuICAgIH0pO1xuXG4gICAgYXdhaXQgdGhpcy5wdXQoQnVmZmVyLmZyb20oa2V5KSwgQnVmZmVyLmZyb20odmFsdWUpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYW4gZWRnZSBiZXR3ZWVuIG5vZGVzIGluIHRoZSBncmFwaCBvdmVybGF5LlxuICAgKlxuICAgKiBAcGFyYW0gbmFtZXNwYWNlIC0gTmFtZXNwYWNlIGZvciB0aGUgZ3JhcGhcbiAgICogQHBhcmFtIGZyb21JZCAtIFNvdXJjZSBub2RlIElEXG4gICAqIEBwYXJhbSBlZGdlVHlwZSAtIFR5cGUgb2YgcmVsYXRpb25zaGlwXG4gICAqIEBwYXJhbSB0b0lkIC0gVGFyZ2V0IG5vZGUgSURcbiAgICogQHBhcmFtIHByb3BlcnRpZXMgLSBPcHRpb25hbCBlZGdlIHByb3BlcnRpZXNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBhd2FpdCBkYi5hZGRFZGdlKCdkZWZhdWx0JywgJ2FsaWNlJywgJ3dvcmtzX29uJywgJ3Byb2plY3RfeCcpO1xuICAgKiBhd2FpdCBkYi5hZGRFZGdlKCdkZWZhdWx0JywgJ2FsaWNlJywgJ2tub3dzJywgJ2JvYicsIHsgc2luY2U6ICcyMDIwJyB9KTtcbiAgICogYGBgXG4gICAqL1xuICBhc3luYyBhZGRFZGdlKFxuICAgIG5hbWVzcGFjZTogc3RyaW5nLFxuICAgIGZyb21JZDogc3RyaW5nLFxuICAgIGVkZ2VUeXBlOiBzdHJpbmcsXG4gICAgdG9JZDogc3RyaW5nLFxuICAgIHByb3BlcnRpZXM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+XG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuX2Vuc3VyZU9wZW4oKTtcblxuICAgIGNvbnN0IGtleSA9IGBfZ3JhcGgvJHtuYW1lc3BhY2V9L2VkZ2VzLyR7ZnJvbUlkfS8ke2VkZ2VUeXBlfS8ke3RvSWR9YDtcbiAgICBjb25zdCB2YWx1ZSA9IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgIGZyb21faWQ6IGZyb21JZCxcbiAgICAgIGVkZ2VfdHlwZTogZWRnZVR5cGUsXG4gICAgICB0b19pZDogdG9JZCxcbiAgICAgIHByb3BlcnRpZXM6IHByb3BlcnRpZXMgfHwge30sXG4gICAgfSk7XG5cbiAgICBhd2FpdCB0aGlzLnB1dChCdWZmZXIuZnJvbShrZXkpLCBCdWZmZXIuZnJvbSh2YWx1ZSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyYXZlcnNlIHRoZSBncmFwaCBmcm9tIGEgc3RhcnRpbmcgbm9kZS5cbiAgICpcbiAgICogQHBhcmFtIG5hbWVzcGFjZSAtIE5hbWVzcGFjZSBmb3IgdGhlIGdyYXBoXG4gICAqIEBwYXJhbSBzdGFydE5vZGUgLSBOb2RlIElEIHRvIHN0YXJ0IHRyYXZlcnNhbCBmcm9tXG4gICAqIEBwYXJhbSBtYXhEZXB0aCAtIE1heGltdW0gdHJhdmVyc2FsIGRlcHRoIChkZWZhdWx0OiAxMClcbiAgICogQHBhcmFtIG9yZGVyIC0gXCJiZnNcIiBmb3IgYnJlYWR0aC1maXJzdCwgXCJkZnNcIiBmb3IgZGVwdGgtZmlyc3RcbiAgICogQHJldHVybnMgT2JqZWN0IHdpdGggbm9kZXMgYW5kIGVkZ2VzIGFycmF5c1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IHsgbm9kZXMsIGVkZ2VzIH0gPSBhd2FpdCBkYi50cmF2ZXJzZSgnZGVmYXVsdCcsICdhbGljZScsIDIpO1xuICAgKiBmb3IgKGNvbnN0IG5vZGUgb2Ygbm9kZXMpIHtcbiAgICogICBjb25zb2xlLmxvZyhgTm9kZTogJHtub2RlLmlkfSAoJHtub2RlLm5vZGVfdHlwZX0pYCk7XG4gICAqIH1cbiAgICogYGBgXG4gICAqL1xuICBhc3luYyB0cmF2ZXJzZShcbiAgICBuYW1lc3BhY2U6IHN0cmluZyxcbiAgICBzdGFydE5vZGU6IHN0cmluZyxcbiAgICBtYXhEZXB0aDogbnVtYmVyID0gMTAsXG4gICAgb3JkZXI6ICdiZnMnIHwgJ2RmcycgPSAnYmZzJ1xuICApOiBQcm9taXNlPHsgbm9kZXM6IGFueVtdOyBlZGdlczogYW55W10gfT4ge1xuICAgIHRoaXMuX2Vuc3VyZU9wZW4oKTtcblxuICAgIGNvbnN0IHZpc2l0ZWQgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBjb25zdCBub2RlczogYW55W10gPSBbXTtcbiAgICBjb25zdCBlZGdlczogYW55W10gPSBbXTtcbiAgICBjb25zdCBmcm9udGllcjogQXJyYXk8W3N0cmluZywgbnVtYmVyXT4gPSBbW3N0YXJ0Tm9kZSwgMF1dO1xuXG4gICAgd2hpbGUgKGZyb250aWVyLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IFtjdXJyZW50Tm9kZSwgZGVwdGhdID0gb3JkZXIgPT09ICdiZnMnXG4gICAgICAgID8gZnJvbnRpZXIuc2hpZnQoKSFcbiAgICAgICAgOiBmcm9udGllci5wb3AoKSE7XG5cbiAgICAgIGlmIChkZXB0aCA+IG1heERlcHRoIHx8IHZpc2l0ZWQuaGFzKGN1cnJlbnROb2RlKSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIHZpc2l0ZWQuYWRkKGN1cnJlbnROb2RlKTtcblxuICAgICAgLy8gR2V0IG5vZGUgZGF0YVxuICAgICAgY29uc3Qgbm9kZUtleSA9IGBfZ3JhcGgvJHtuYW1lc3BhY2V9L25vZGVzLyR7Y3VycmVudE5vZGV9YDtcbiAgICAgIGNvbnN0IG5vZGVEYXRhID0gYXdhaXQgdGhpcy5nZXQoQnVmZmVyLmZyb20obm9kZUtleSkpO1xuICAgICAgaWYgKG5vZGVEYXRhKSB7XG4gICAgICAgIG5vZGVzLnB1c2goSlNPTi5wYXJzZShub2RlRGF0YS50b1N0cmluZygpKSk7XG4gICAgICB9XG5cbiAgICAgIC8vIEdldCBvdXRnb2luZyBlZGdlc1xuICAgICAgY29uc3QgZWRnZVByZWZpeCA9IGBfZ3JhcGgvJHtuYW1lc3BhY2V9L2VkZ2VzLyR7Y3VycmVudE5vZGV9L2A7XG4gICAgICBjb25zdCBlZGdlUmVzdWx0cyA9IGF3YWl0IHRoaXMuc2NhbihlZGdlUHJlZml4KTtcbiAgICAgIGZvciAoY29uc3QgeyB2YWx1ZSB9IG9mIGVkZ2VSZXN1bHRzKSB7XG4gICAgICAgIGNvbnN0IGVkZ2UgPSBKU09OLnBhcnNlKHZhbHVlLnRvU3RyaW5nKCkpO1xuICAgICAgICBlZGdlcy5wdXNoKGVkZ2UpO1xuXG4gICAgICAgIGlmICghdmlzaXRlZC5oYXMoZWRnZS50b19pZCkpIHtcbiAgICAgICAgICBmcm9udGllci5wdXNoKFtlZGdlLnRvX2lkLCBkZXB0aCArIDFdKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7IG5vZGVzLCBlZGdlcyB9O1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBTZW1hbnRpYyBDYWNoZSBPcGVyYXRpb25zXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICAvKipcbiAgICogU3RvcmUgYSB2YWx1ZSBpbiB0aGUgc2VtYW50aWMgY2FjaGUgd2l0aCBpdHMgZW1iZWRkaW5nLlxuICAgKlxuICAgKiBAcGFyYW0gY2FjaGVOYW1lIC0gTmFtZSBvZiB0aGUgY2FjaGVcbiAgICogQHBhcmFtIGtleSAtIENhY2hlIGtleSAoZm9yIGRpc3BsYXkvZGVidWdnaW5nKVxuICAgKiBAcGFyYW0gdmFsdWUgLSBWYWx1ZSB0byBjYWNoZVxuICAgKiBAcGFyYW0gZW1iZWRkaW5nIC0gRW1iZWRkaW5nIHZlY3RvciBmb3Igc2ltaWxhcml0eSBtYXRjaGluZ1xuICAgKiBAcGFyYW0gdHRsU2Vjb25kcyAtIFRpbWUtdG8tbGl2ZSBpbiBzZWNvbmRzICgwID0gbm8gZXhwaXJ5KVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGF3YWl0IGRiLmNhY2hlUHV0KFxuICAgKiAgICdsbG1fcmVzcG9uc2VzJyxcbiAgICogICAnV2hhdCBpcyBQeXRob24/JyxcbiAgICogICAnUHl0aG9uIGlzIGEgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UuLi4nLFxuICAgKiAgIFswLjEsIDAuMiwgMC4zLCAuLi5dLCAgLy8gMzg0LWRpbVxuICAgKiAgIDM2MDBcbiAgICogKTtcbiAgICogYGBgXG4gICAqL1xuICBhc3luYyBjYWNoZVB1dChcbiAgICBjYWNoZU5hbWU6IHN0cmluZyxcbiAgICBrZXk6IHN0cmluZyxcbiAgICB2YWx1ZTogc3RyaW5nLFxuICAgIGVtYmVkZGluZzogbnVtYmVyW10sXG4gICAgdHRsU2Vjb25kczogbnVtYmVyID0gMFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLl9lbnN1cmVPcGVuKCk7XG5cbiAgICAvLyBIYXNoIHRoZSBrZXkgZm9yIHN0b3JhZ2VcbiAgICBjb25zdCBrZXlIYXNoID0gQnVmZmVyLmZyb20oa2V5KS50b1N0cmluZygnaGV4Jykuc2xpY2UoMCwgMTYpO1xuICAgIGNvbnN0IGNhY2hlS2V5ID0gYF9jYWNoZS8ke2NhY2hlTmFtZX0vJHtrZXlIYXNofWA7XG5cbiAgICBjb25zdCBleHBpcmVzQXQgPSB0dGxTZWNvbmRzID4gMFxuICAgICAgPyBNYXRoLmZsb29yKERhdGUubm93KCkgLyAxMDAwKSArIHR0bFNlY29uZHNcbiAgICAgIDogMDtcblxuICAgIGNvbnN0IGNhY2hlVmFsdWUgPSBKU09OLnN0cmluZ2lmeSh7XG4gICAgICBrZXksXG4gICAgICB2YWx1ZSxcbiAgICAgIGVtYmVkZGluZyxcbiAgICAgIGV4cGlyZXNfYXQ6IGV4cGlyZXNBdCxcbiAgICB9KTtcblxuICAgIGF3YWl0IHRoaXMucHV0KEJ1ZmZlci5mcm9tKGNhY2hlS2V5KSwgQnVmZmVyLmZyb20oY2FjaGVWYWx1ZSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIExvb2sgdXAgYSB2YWx1ZSBpbiB0aGUgc2VtYW50aWMgY2FjaGUgYnkgZW1iZWRkaW5nIHNpbWlsYXJpdHkuXG4gICAqXG4gICAqIEBwYXJhbSBjYWNoZU5hbWUgLSBOYW1lIG9mIHRoZSBjYWNoZVxuICAgKiBAcGFyYW0gcXVlcnlFbWJlZGRpbmcgLSBRdWVyeSBlbWJlZGRpbmcgdG8gbWF0Y2ggYWdhaW5zdFxuICAgKiBAcGFyYW0gdGhyZXNob2xkIC0gTWluaW11bSBjb3NpbmUgc2ltaWxhcml0eSB0aHJlc2hvbGQgKDAuMCB0byAxLjApXG4gICAqIEByZXR1cm5zIENhY2hlZCB2YWx1ZSBpZiBzaW1pbGFyaXR5ID49IHRocmVzaG9sZCwgbnVsbCBvdGhlcndpc2VcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCByZXN1bHQgPSBhd2FpdCBkYi5jYWNoZUdldChcbiAgICogICAnbGxtX3Jlc3BvbnNlcycsXG4gICAqICAgWzAuMTIsIDAuMTgsIC4uLl0sICAvLyBTaW1pbGFyIHRvIFwiV2hhdCBpcyBQeXRob24/XCJcbiAgICogICAwLjg1XG4gICAqICk7XG4gICAqIGlmIChyZXN1bHQpIHtcbiAgICogICBjb25zb2xlLmxvZyhgQ2FjaGUgaGl0OiAke3Jlc3VsdH1gKTtcbiAgICogfVxuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIGNhY2hlR2V0KFxuICAgIGNhY2hlTmFtZTogc3RyaW5nLFxuICAgIHF1ZXJ5RW1iZWRkaW5nOiBudW1iZXJbXSxcbiAgICB0aHJlc2hvbGQ6IG51bWJlciA9IDAuODVcbiAgKTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPiB7XG4gICAgdGhpcy5fZW5zdXJlT3BlbigpO1xuXG4gICAgY29uc3QgcHJlZml4ID0gYF9jYWNoZS8ke2NhY2hlTmFtZX0vYDtcbiAgICBjb25zdCBlbnRyaWVzID0gYXdhaXQgdGhpcy5zY2FuKHByZWZpeCk7XG5cbiAgICBjb25zdCBub3cgPSBNYXRoLmZsb29yKERhdGUubm93KCkgLyAxMDAwKTtcbiAgICBsZXQgYmVzdE1hdGNoOiB7IHNpbWlsYXJpdHk6IG51bWJlcjsgdmFsdWU6IHN0cmluZyB9IHwgbnVsbCA9IG51bGw7XG5cbiAgICBmb3IgKGNvbnN0IHsgdmFsdWUgfSBvZiBlbnRyaWVzKSB7XG4gICAgICBjb25zdCBlbnRyeSA9IEpTT04ucGFyc2UodmFsdWUudG9TdHJpbmcoKSk7XG5cbiAgICAgIC8vIENoZWNrIGV4cGlyeVxuICAgICAgaWYgKGVudHJ5LmV4cGlyZXNfYXQgPiAwICYmIG5vdyA+IGVudHJ5LmV4cGlyZXNfYXQpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIC8vIENvbXB1dGUgY29zaW5lIHNpbWlsYXJpdHlcbiAgICAgIGlmIChlbnRyeS5lbWJlZGRpbmcgJiYgZW50cnkuZW1iZWRkaW5nLmxlbmd0aCA9PT0gcXVlcnlFbWJlZGRpbmcubGVuZ3RoKSB7XG4gICAgICAgIGNvbnN0IHNpbWlsYXJpdHkgPSB0aGlzLl9jb3NpbmVTaW1pbGFyaXR5KHF1ZXJ5RW1iZWRkaW5nLCBlbnRyeS5lbWJlZGRpbmcpO1xuICAgICAgICBpZiAoc2ltaWxhcml0eSA+PSB0aHJlc2hvbGQpIHtcbiAgICAgICAgICBpZiAoIWJlc3RNYXRjaCB8fCBzaW1pbGFyaXR5ID4gYmVzdE1hdGNoLnNpbWlsYXJpdHkpIHtcbiAgICAgICAgICAgIGJlc3RNYXRjaCA9IHsgc2ltaWxhcml0eSwgdmFsdWU6IGVudHJ5LnZhbHVlIH07XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGJlc3RNYXRjaD8udmFsdWUgPz8gbnVsbDtcbiAgfVxuXG4gIHByaXZhdGUgX2Nvc2luZVNpbWlsYXJpdHkoYTogbnVtYmVyW10sIGI6IG51bWJlcltdKTogbnVtYmVyIHtcbiAgICBsZXQgZG90ID0gMCwgbm9ybUEgPSAwLCBub3JtQiA9IDA7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhLmxlbmd0aDsgaSsrKSB7XG4gICAgICBkb3QgKz0gYVtpXSAqIGJbaV07XG4gICAgICBub3JtQSArPSBhW2ldICogYVtpXTtcbiAgICAgIG5vcm1CICs9IGJbaV0gKiBiW2ldO1xuICAgIH1cbiAgICBub3JtQSA9IE1hdGguc3FydChub3JtQSk7XG4gICAgbm9ybUIgPSBNYXRoLnNxcnQobm9ybUIpO1xuICAgIHJldHVybiBub3JtQSA9PT0gMCB8fCBub3JtQiA9PT0gMCA/IDAgOiBkb3QgLyAobm9ybUEgKiBub3JtQik7XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFRyYWNlIE9wZXJhdGlvbnMgKE9ic2VydmFiaWxpdHkpXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICAvKipcbiAgICogU3RhcnQgYSBuZXcgdHJhY2UuXG4gICAqXG4gICAqIEBwYXJhbSBuYW1lIC0gTmFtZSBvZiB0aGUgdHJhY2UgKGUuZy4sIFwidXNlcl9yZXF1ZXN0XCIsIFwiYmF0Y2hfam9iXCIpXG4gICAqIEByZXR1cm5zIE9iamVjdCB3aXRoIHRyYWNlSWQgYW5kIHJvb3RTcGFuSWRcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCB7IHRyYWNlSWQsIHJvb3RTcGFuSWQgfSA9IGF3YWl0IGRiLnN0YXJ0VHJhY2UoJ3VzZXJfcXVlcnknKTtcbiAgICogLy8gLi4uIGRvIHdvcmsgLi4uXG4gICAqIGF3YWl0IGRiLmVuZFNwYW4odHJhY2VJZCwgcm9vdFNwYW5JZCwgJ29rJyk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgc3RhcnRUcmFjZShuYW1lOiBzdHJpbmcpOiBQcm9taXNlPHsgdHJhY2VJZDogc3RyaW5nOyByb290U3BhbklkOiBzdHJpbmcgfT4ge1xuICAgIHRoaXMuX2Vuc3VyZU9wZW4oKTtcblxuICAgIGNvbnN0IHRyYWNlSWQgPSBgdHJhY2VfJHtEYXRlLm5vdygpLnRvU3RyaW5nKDE2KX0ke01hdGgucmFuZG9tKCkudG9TdHJpbmcoMTYpLnNsaWNlKDIsIDEwKX1gO1xuICAgIGNvbnN0IHNwYW5JZCA9IGBzcGFuXyR7RGF0ZS5ub3coKS50b1N0cmluZygxNil9JHtNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDE2KS5zbGljZSgyLCAxMCl9YDtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpICogMTAwMDsgLy8gbWljcm9zZWNvbmRzXG5cbiAgICAvLyBTdG9yZSB0cmFjZVxuICAgIGNvbnN0IHRyYWNlS2V5ID0gYF90cmFjZXMvJHt0cmFjZUlkfWA7XG4gICAgY29uc3QgdHJhY2VWYWx1ZSA9IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgIHRyYWNlX2lkOiB0cmFjZUlkLFxuICAgICAgbmFtZSxcbiAgICAgIHN0YXJ0X3VzOiBub3csXG4gICAgICByb290X3NwYW5faWQ6IHNwYW5JZCxcbiAgICB9KTtcbiAgICBhd2FpdCB0aGlzLnB1dChCdWZmZXIuZnJvbSh0cmFjZUtleSksIEJ1ZmZlci5mcm9tKHRyYWNlVmFsdWUpKTtcblxuICAgIC8vIFN0b3JlIHJvb3Qgc3BhblxuICAgIGNvbnN0IHNwYW5LZXkgPSBgX3RyYWNlcy8ke3RyYWNlSWR9L3NwYW5zLyR7c3BhbklkfWA7XG4gICAgY29uc3Qgc3BhblZhbHVlID0gSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgc3Bhbl9pZDogc3BhbklkLFxuICAgICAgbmFtZSxcbiAgICAgIHN0YXJ0X3VzOiBub3csXG4gICAgICBwYXJlbnRfc3Bhbl9pZDogbnVsbCxcbiAgICAgIHN0YXR1czogJ2FjdGl2ZScsXG4gICAgfSk7XG4gICAgYXdhaXQgdGhpcy5wdXQoQnVmZmVyLmZyb20oc3BhbktleSksIEJ1ZmZlci5mcm9tKHNwYW5WYWx1ZSkpO1xuXG4gICAgcmV0dXJuIHsgdHJhY2VJZCwgcm9vdFNwYW5JZDogc3BhbklkIH07XG4gIH1cblxuICAvKipcbiAgICogU3RhcnQgYSBjaGlsZCBzcGFuIHdpdGhpbiBhIHRyYWNlLlxuICAgKlxuICAgKiBAcGFyYW0gdHJhY2VJZCAtIElEIG9mIHRoZSBwYXJlbnQgdHJhY2VcbiAgICogQHBhcmFtIHBhcmVudFNwYW5JZCAtIElEIG9mIHRoZSBwYXJlbnQgc3BhblxuICAgKiBAcGFyYW0gbmFtZSAtIE5hbWUgb2YgdGhpcyBzcGFuXG4gICAqIEByZXR1cm5zIFRoZSBuZXcgc3BhbiBJRFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IHsgdHJhY2VJZCwgcm9vdFNwYW5JZCB9ID0gYXdhaXQgZGIuc3RhcnRUcmFjZSgndXNlcl9xdWVyeScpO1xuICAgKiBjb25zdCBkYlNwYW4gPSBhd2FpdCBkYi5zdGFydFNwYW4odHJhY2VJZCwgcm9vdFNwYW5JZCwgJ2RhdGFiYXNlX2xvb2t1cCcpO1xuICAgKiAvLyAuLi4gZG8gZGF0YWJhc2Ugd29yayAuLi5cbiAgICogY29uc3QgZHVyYXRpb24gPSBhd2FpdCBkYi5lbmRTcGFuKHRyYWNlSWQsIGRiU3BhbiwgJ29rJyk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgc3RhcnRTcGFuKFxuICAgIHRyYWNlSWQ6IHN0cmluZyxcbiAgICBwYXJlbnRTcGFuSWQ6IHN0cmluZyxcbiAgICBuYW1lOiBzdHJpbmdcbiAgKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICB0aGlzLl9lbnN1cmVPcGVuKCk7XG5cbiAgICBjb25zdCBzcGFuSWQgPSBgc3Bhbl8ke0RhdGUubm93KCkudG9TdHJpbmcoMTYpfSR7TWF0aC5yYW5kb20oKS50b1N0cmluZygxNikuc2xpY2UoMiwgMTApfWA7XG4gICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKSAqIDEwMDA7XG5cbiAgICBjb25zdCBzcGFuS2V5ID0gYF90cmFjZXMvJHt0cmFjZUlkfS9zcGFucy8ke3NwYW5JZH1gO1xuICAgIGNvbnN0IHNwYW5WYWx1ZSA9IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgIHNwYW5faWQ6IHNwYW5JZCxcbiAgICAgIG5hbWUsXG4gICAgICBzdGFydF91czogbm93LFxuICAgICAgcGFyZW50X3NwYW5faWQ6IHBhcmVudFNwYW5JZCxcbiAgICAgIHN0YXR1czogJ2FjdGl2ZScsXG4gICAgfSk7XG4gICAgYXdhaXQgdGhpcy5wdXQoQnVmZmVyLmZyb20oc3BhbktleSksIEJ1ZmZlci5mcm9tKHNwYW5WYWx1ZSkpO1xuXG4gICAgcmV0dXJuIHNwYW5JZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbmQgYSBzcGFuIGFuZCByZWNvcmQgaXRzIGR1cmF0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0gdHJhY2VJZCAtIElEIG9mIHRoZSB0cmFjZVxuICAgKiBAcGFyYW0gc3BhbklkIC0gSUQgb2YgdGhlIHNwYW4gdG8gZW5kXG4gICAqIEBwYXJhbSBzdGF0dXMgLSBcIm9rXCIsIFwiZXJyb3JcIiwgb3IgXCJ1bnNldFwiXG4gICAqIEByZXR1cm5zIER1cmF0aW9uIGluIG1pY3Jvc2Vjb25kc1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IGR1cmF0aW9uID0gYXdhaXQgZGIuZW5kU3Bhbih0cmFjZUlkLCBzcGFuSWQsICdvaycpO1xuICAgKiBjb25zb2xlLmxvZyhgT3BlcmF0aW9uIHRvb2sgJHtkdXJhdGlvbn3CtXNgKTtcbiAgICogYGBgXG4gICAqL1xuICBhc3luYyBlbmRTcGFuKFxuICAgIHRyYWNlSWQ6IHN0cmluZyxcbiAgICBzcGFuSWQ6IHN0cmluZyxcbiAgICBzdGF0dXM6ICdvaycgfCAnZXJyb3InIHwgJ3Vuc2V0JyA9ICdvaydcbiAgKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICB0aGlzLl9lbnN1cmVPcGVuKCk7XG5cbiAgICBjb25zdCBzcGFuS2V5ID0gYF90cmFjZXMvJHt0cmFjZUlkfS9zcGFucy8ke3NwYW5JZH1gO1xuICAgIGNvbnN0IHNwYW5EYXRhID0gYXdhaXQgdGhpcy5nZXQoQnVmZmVyLmZyb20oc3BhbktleSkpO1xuXG4gICAgaWYgKCFzcGFuRGF0YSkge1xuICAgICAgdGhyb3cgbmV3IERhdGFiYXNlRXJyb3IoYFNwYW4gbm90IGZvdW5kOiAke3NwYW5JZH1gKTtcbiAgICB9XG5cbiAgICBjb25zdCBzcGFuID0gSlNPTi5wYXJzZShzcGFuRGF0YS50b1N0cmluZygpKTtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpICogMTAwMDtcbiAgICBjb25zdCBkdXJhdGlvbiA9IG5vdyAtIHNwYW4uc3RhcnRfdXM7XG5cbiAgICBjb25zdCB1cGRhdGVkU3BhbiA9IHtcbiAgICAgIC4uLnNwYW4sXG4gICAgICBzdGF0dXMsXG4gICAgICBlbmRfdXM6IG5vdyxcbiAgICAgIGR1cmF0aW9uX3VzOiBkdXJhdGlvbixcbiAgICB9O1xuICAgIGF3YWl0IHRoaXMucHV0KEJ1ZmZlci5mcm9tKHNwYW5LZXkpLCBCdWZmZXIuZnJvbShKU09OLnN0cmluZ2lmeSh1cGRhdGVkU3BhbikpKTtcblxuICAgIHJldHVybiBkdXJhdGlvbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBDbG9zZSB0aGUgZGF0YWJhc2UgY29ubmVjdGlvbi5cbiAgICogSWYgcnVubmluZyBpbiBlbWJlZGRlZCBtb2RlLCBhbHNvIHN0b3BzIHRoZSBlbWJlZGRlZCBzZXJ2ZXIuXG4gICAqL1xuICBhc3luYyBjbG9zZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5fY2xvc2VkKSByZXR1cm47XG4gICAgaWYgKHRoaXMuX2NsaWVudCkge1xuICAgICAgYXdhaXQgdGhpcy5fY2xpZW50LmNsb3NlKCk7XG4gICAgICB0aGlzLl9jbGllbnQgPSBudWxsO1xuICAgIH1cbiAgICAvLyBTdG9wIGVtYmVkZGVkIHNlcnZlciBpZiB3ZSBzdGFydGVkIGl0XG4gICAgaWYgKHRoaXMuX2VtYmVkZGVkU2VydmVyU3RhcnRlZCkge1xuICAgICAgYXdhaXQgc3RvcEVtYmVkZGVkU2VydmVyKHRoaXMuX2NvbmZpZy5wYXRoKTtcbiAgICAgIHRoaXMuX2VtYmVkZGVkU2VydmVyU3RhcnRlZCA9IGZhbHNlO1xuICAgIH1cbiAgICB0aGlzLl9jbG9zZWQgPSB0cnVlO1xuICB9XG5cbiAgLy8gSW50ZXJuYWwgbWV0aG9kcyBmb3IgdHJhbnNhY3Rpb24gbWFuYWdlbWVudFxuICBwcml2YXRlIGFzeW5jIF9iZWdpblRyYW5zYWN0aW9uKCk6IFByb21pc2U8YmlnaW50PiB7XG4gICAgcmV0dXJuIHRoaXMuX2NsaWVudCEuYmVnaW5UcmFuc2FjdGlvbigpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBfY29tbWl0VHJhbnNhY3Rpb24odHhuSWQ6IGJpZ2ludCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLl9jbGllbnQhLmNvbW1pdFRyYW5zYWN0aW9uKHR4bklkKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgX2Fib3J0VHJhbnNhY3Rpb24odHhuSWQ6IGJpZ2ludCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLl9jbGllbnQhLmFib3J0VHJhbnNhY3Rpb24odHhuSWQpO1xuICB9XG5cbiAgcHJpdmF0ZSBfZW5zdXJlT3BlbigpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5fY2xvc2VkKSB7XG4gICAgICB0aHJvdyBuZXcgRGF0YWJhc2VFcnJvcignRGF0YWJhc2UgaXMgY2xvc2VkJyk7XG4gICAgfVxuICAgIGlmICghdGhpcy5fY2xpZW50KSB7XG4gICAgICB0aHJvdyBuZXcgRGF0YWJhc2VFcnJvcignRGF0YWJhc2Ugbm90IGNvbm5lY3RlZCcpO1xuICAgIH1cbiAgfVxufVxuIl19