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