velocious 1.0.535 → 1.0.537

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.
@@ -1,6 +1,7 @@
1
1
  // @ts-check
2
2
  const DEFAULT_INSERT_CHUNK_SIZE = 100;
3
3
  const DEFAULT_QUERY_CHUNK_SIZE = 500;
4
+ const DEFAULT_STREAM_BATCH_SIZE = 1000;
4
5
  /**
5
6
  * Splits an array into chunks of at most `chunkSize` items.
6
7
  * @template T
@@ -182,6 +183,149 @@ export default class DataCopier {
182
183
  }
183
184
  return { idsByTableName, rowsByTableName };
184
185
  }
186
+ /**
187
+ * The plan tables referenced as a parent by some child entry. Their ids must be retained
188
+ * while streaming so their children can be scoped; leaf tables — typically the high-volume
189
+ * ones — are never in this set and so are never accumulated in memory.
190
+ * @returns {Set<string>} - Table names that are a parent of another plan entry.
191
+ */
192
+ parentTableNames() {
193
+ /** @type {Set<string>} */
194
+ const names = new Set();
195
+ for (const tableConfig of this.tablePlan) {
196
+ if (tableConfig.parentTableName) {
197
+ names.add(tableConfig.parentTableName);
198
+ }
199
+ }
200
+ return names;
201
+ }
202
+ /**
203
+ * Streams every plan table's source rows scoped to `keyValue` in bounded `batchSize` batches,
204
+ * following parent/child chaining. Each table is read through a real
205
+ * {@link import("../drivers/base.js").default#queryStream} cursor, so a large table is never
206
+ * buffered; only the ids of tables that are themselves a parent are retained (to scope their
207
+ * children). `selectColumns` bounds each row's projection — pass `[idColumn]` for a light
208
+ * id-only scan, or omit it to stream full rows — and must include the id column for any table
209
+ * that has children. Memory stays bounded to one batch plus the retained parent-table ids.
210
+ * @param {import("../drivers/base.js").default} db - Source database to stream.
211
+ * @param {string} keyValue - Tenant key selecting the root plan rows.
212
+ * @param {{batchSize: number, selectColumns?: string[]}} options - Batch size and optional projection.
213
+ * @yields {{rows: Record<string, unknown>[], tableName: string}} - Successive row batches per table.
214
+ */
215
+ async *streamPlanSourceBatches(db, keyValue, { batchSize, selectColumns }) {
216
+ /** @type {Map<string, string[]>} */
217
+ const retainedIdsByTableName = new Map();
218
+ const parentTableNames = this.parentTableNames();
219
+ for (const tableConfig of this.tablePlan) {
220
+ /** @type {string} */
221
+ let scopeColumn;
222
+ /** @type {string[]} */
223
+ let scopeValues;
224
+ if (tableConfig.keyColumn) {
225
+ scopeColumn = tableConfig.keyColumn;
226
+ scopeValues = [keyValue];
227
+ }
228
+ else {
229
+ if (!tableConfig.parentColumn || !tableConfig.parentTableName) {
230
+ throw new Error(`Expected keyColumn or parentTableName+parentColumn for table ${tableConfig.tableName} in the tenant table plan.`);
231
+ }
232
+ if (!retainedIdsByTableName.has(tableConfig.parentTableName)) {
233
+ throw new Error(`Tenant table plan entry ${tableConfig.tableName} references parent table ${tableConfig.parentTableName}, which has not been streamed; parent tables must appear before their children in the plan.`);
234
+ }
235
+ scopeColumn = tableConfig.parentColumn;
236
+ scopeValues = retainedIdsByTableName.get(tableConfig.parentTableName) || [];
237
+ }
238
+ /** @type {string[] | null} */
239
+ const retainedIds = parentTableNames.has(tableConfig.tableName) ? [] : null;
240
+ const quotedTable = db.quoteTable(tableConfig.tableName);
241
+ const quotedScope = db.quoteColumn(scopeColumn);
242
+ const selectList = selectColumns
243
+ ? selectColumns.map((column) => `${quotedTable}.${db.quoteColumn(column)}`).join(", ")
244
+ : `${quotedTable}.*`;
245
+ /** @type {Record<string, unknown>[]} */
246
+ let batch = [];
247
+ for (const scopeChunk of chunks(uniqueStrings(scopeValues), this.queryChunkSize)) {
248
+ const sql = `SELECT ${selectList} FROM ${quotedTable} WHERE ${quotedScope} IN (${this.quotedValuesSql(db, scopeChunk)})`;
249
+ for await (const row of db.queryStream(sql)) {
250
+ batch.push(row);
251
+ if (retainedIds) {
252
+ retainedIds.push(String(row[this.idColumn]));
253
+ }
254
+ if (batch.length >= batchSize) {
255
+ yield { rows: batch, tableName: tableConfig.tableName };
256
+ batch = [];
257
+ }
258
+ }
259
+ }
260
+ if (batch.length > 0) {
261
+ yield { rows: batch, tableName: tableConfig.tableName };
262
+ }
263
+ retainedIdsByTableName.set(tableConfig.tableName, retainedIds || []);
264
+ }
265
+ }
266
+ /**
267
+ * Returns which of `ids` currently exist in `tableName` in `db`. `ids` is one already-bounded
268
+ * batch, so it is probed with a single `IN (...)` lookup.
269
+ * @param {{db: import("../drivers/base.js").default, ids: string[], tableName: string}} args - Database, ids to probe, and table.
270
+ * @returns {Promise<Set<string>>} - The subset of `ids` present in the table.
271
+ */
272
+ async queryExistingIds({ db, ids, tableName }) {
273
+ if (ids.length <= 0) {
274
+ return new Set();
275
+ }
276
+ const quotedTable = db.quoteTable(tableName);
277
+ const quotedId = db.quoteColumn(this.idColumn);
278
+ const rows = await this.executeQuietQuery(db, `SELECT ${quotedTable}.${quotedId} FROM ${quotedTable} WHERE ${quotedId} IN (${this.quotedValuesSql(db, ids)})`);
279
+ return new Set(rows.map((row) => String(row[this.idColumn])));
280
+ }
281
+ /**
282
+ * Streams the source ids for `keyValue` and returns the first table found to be missing rows in
283
+ * the target, with that batch's missing ids — stopping at the first shortfall instead of
284
+ * enumerating every missing row. Callers verifying a tenant already holds every source row (for
285
+ * example before deleting the source copies) treat an empty result as the go-ahead and any entry
286
+ * as a hard stop; failing fast keeps memory bounded to a single batch even when the target is
287
+ * far behind.
288
+ * @param {string} keyValue - Tenant key selecting the source rows to check.
289
+ * @param {{batchSize?: number}} [options] - Streaming batch size.
290
+ * @returns {Promise<Map<string, string[]>>} - The first table missing rows and that batch's missing ids, or empty when the target holds everything.
291
+ */
292
+ async findMissingRowIds(keyValue, { batchSize = DEFAULT_STREAM_BATCH_SIZE } = {}) {
293
+ /** @type {Map<string, string[]>} */
294
+ const missingByTableName = new Map();
295
+ for await (const { rows, tableName } of this.streamPlanSourceBatches(this.sourceDb, keyValue, { batchSize, selectColumns: [this.idColumn] })) {
296
+ const ids = rows.map((row) => String(row[this.idColumn]));
297
+ const existingIds = await this.queryExistingIds({ db: this.targetDb, ids, tableName });
298
+ const missingIds = ids.filter((id) => !existingIds.has(id));
299
+ if (missingIds.length > 0) {
300
+ missingByTableName.set(tableName, missingIds);
301
+ break;
302
+ }
303
+ }
304
+ return missingByTableName;
305
+ }
306
+ /**
307
+ * Streams the source rows for `keyValue` and copies into the target, batch by batch, only the
308
+ * rows missing there. Because the full rows travel in the stream, each batch's missing rows are
309
+ * inserted as it arrives — nothing is accumulated, and no second source query runs while the
310
+ * source connection is held by the stream — so a table with large columns stays bounded to one
311
+ * batch even when the target is empty. Intended for single-table plans (or plans whose per-table,
312
+ * parent-first insert order is foreign-key safe).
313
+ * @param {string} keyValue - Tenant key selecting the source rows to reconcile.
314
+ * @param {{batchSize?: number}} [options] - Streaming batch size.
315
+ * @returns {Promise<number>} - The number of rows copied into the target.
316
+ */
317
+ async copyMissingRows(keyValue, { batchSize = DEFAULT_STREAM_BATCH_SIZE } = {}) {
318
+ let copiedCount = 0;
319
+ for await (const { rows, tableName } of this.streamPlanSourceBatches(this.sourceDb, keyValue, { batchSize })) {
320
+ const existingIds = await this.queryExistingIds({ db: this.targetDb, ids: rows.map((row) => String(row[this.idColumn])), tableName });
321
+ const missingRows = rows.filter((row) => !existingIds.has(String(row[this.idColumn])));
322
+ if (missingRows.length > 0) {
323
+ await this.insertTargetRows(new Map([[tableName, missingRows]]));
324
+ copiedCount += missingRows.length;
325
+ }
326
+ }
327
+ return copiedCount;
328
+ }
185
329
  /**
186
330
  * Selects `tableName` rows in `db` whose `columnName` is in `values`, chunked. `selectColumns`
187
331
  * bounds the projection and defaults to every column.
@@ -286,4 +430,4 @@ export default class DataCopier {
286
430
  }
287
431
  }
288
432
  }
289
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YS1jb3BpZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvZGF0YWJhc2UvdGVuYW50cy9kYXRhLWNvcGllci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosTUFBTSx5QkFBeUIsR0FBRyxHQUFHLENBQUE7QUFDckMsTUFBTSx3QkFBd0IsR0FBRyxHQUFHLENBQUE7QUFFcEM7Ozs7OztHQU1HO0FBQ0gsU0FBUyxNQUFNLENBQUMsTUFBTSxFQUFFLFNBQVM7SUFDL0IsTUFBTSxhQUFhLEdBQUcsRUFBRSxDQUFBO0lBRXhCLEtBQUssSUFBSSxLQUFLLEdBQUcsQ0FBQyxFQUFFLEtBQUssR0FBRyxNQUFNLENBQUMsTUFBTSxFQUFFLEtBQUssSUFBSSxTQUFTLEVBQUUsQ0FBQztRQUM5RCxhQUFhLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLEtBQUssR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFBO0lBQzVELENBQUM7SUFFRCxPQUFPLGFBQWEsQ0FBQTtBQUN0QixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQVMsYUFBYSxDQUFDLE1BQU07SUFDM0IsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFBO0FBQ2xHLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sVUFBVTtJQUM3Qjs7Ozs7Ozs7Ozs7T0FXRztJQUNILFlBQVksRUFBQyxRQUFRLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxRQUFRLEdBQUcsSUFBSSxF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LENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxlQUFlLENBQUMsRUFBRSxFQUFFLE1BQU07UUFDeEIsT0FBTyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO0lBQzFELENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLEVBQUUsR0FBRztRQUM3QixPQUFPLE1BQU0sRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsRUFBQyxRQUFRLEVBQUUsS0FBSyxFQUFDLENBQUMsQ0FBQTtJQUMvQyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxFQUFDLE9BQU8sRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBQztRQUNwRCxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLFNBQVMsQ0FBQyxFQUFDLE9BQU8sRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFDLENBQUMsQ0FBQyxDQUFBO0lBQzVFLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsY0FBYyxDQUFDLE9BQU87UUFDcEIsSUFBSSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDcEIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUMxQixDQUFDO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmNvbnN0IERFRkFVTFRfSU5TRVJUX0NIVU5LX1NJWkUgPSAxMDBcbmNvbnN0IERFRkFVTFRfUVVFUllfQ0hVTktfU0laRSA9IDUwMFxuXG4vKipcbiAqIFNwbGl0cyBhbiBhcnJheSBpbnRvIGNodW5rcyBvZiBhdCBtb3N0IGBjaHVua1NpemVgIGl0ZW1zLlxuICogQHRlbXBsYXRlIFRcbiAqIEBwYXJhbSB7VFtdfSB2YWx1ZXMgLSBPcmRlcmVkIGl0ZW1zIHRvIHBhcnRpdGlvbi5cbiAqIEBwYXJhbSB7bnVtYmVyfSBjaHVua1NpemUgLSBNYXhpbXVtIGl0ZW1zIHBlciBjaHVuay5cbiAqIEByZXR1cm5zIHtUW11bXX0gLSBDb25zZWN1dGl2ZSBjaHVua3MgcHJlc2VydmluZyBpbnB1dCBvcmRlci5cbiAqL1xuZnVuY3Rpb24gY2h1bmtzKHZhbHVlcywgY2h1bmtTaXplKSB7XG4gIGNvbnN0IGNodW5rZWRWYWx1ZXMgPSBbXVxuXG4gIGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCB2YWx1ZXMubGVuZ3RoOyBpbmRleCArPSBjaHVua1NpemUpIHtcbiAgICBjaHVua2VkVmFsdWVzLnB1c2godmFsdWVzLnNsaWNlKGluZGV4LCBpbmRleCArIGNodW5rU2l6ZSkpXG4gIH1cblxuICByZXR1cm4gY2h1bmtlZFZhbHVlc1xufVxuXG4vKipcbiAqIFN0cmluZ2lmaWVzIHZhbHVlcyBhbmQgcmV0dXJucyB0aGUgZGlzdGluY3QsIG5vbi1ibGFuayBvbmVzLCBwcmVzZXJ2aW5nIGZpcnN0LXNlZW4gb3JkZXIuXG4gKiBAcGFyYW0ge3Vua25vd25bXX0gdmFsdWVzIC0gQ2FuZGlkYXRlIGRhdGFiYXNlIGlkZW50aWZpZXJzIHRvIHN0cmluZ2lmeSBhbmQgZGVkdXBsaWNhdGUuXG4gKiBAcmV0dXJucyB7c3RyaW5nW119IC0gRGlzdGluY3Qgbm9uLWJsYW5rIGlkZW50aWZpZXJzIGluIGZpcnN0LXNlZW4gb3JkZXIuXG4gKi9cbmZ1bmN0aW9uIHVuaXF1ZVN0cmluZ3ModmFsdWVzKSB7XG4gIHJldHVybiBBcnJheS5mcm9tKG5ldyBTZXQodmFsdWVzLm1hcCgodmFsdWUpID0+IFN0cmluZyh2YWx1ZSkpLmZpbHRlcigodmFsdWUpID0+IHZhbHVlLnRyaW0oKSkpKVxufVxuXG4vKipcbiAqIENvcGllcyBhIHNpbmdsZSB0ZW5hbnQncyByb3dzIGZyb20gYSBzb3VyY2UgZGF0YWJhc2UgaW50byBhIHRhcmdldCBkYXRhYmFzZSwgZm9sbG93aW5nIGFcbiAqIHRhYmxlIHBsYW4gdGhhdCBwYXJ0aXRpb25zIGVhY2ggdGFibGUgZWl0aGVyIGJ5IGEgZGlyZWN0IHRlbmFudCBrZXkgY29sdW1uIG9yIGJ5XG4gKiBwYXJlbnQtaWQgdHJhdmVyc2FsLiBUaGlzIGlzIHRoZSByb3ctbGV2ZWwgY291bnRlcnBhcnQgdG8gc2NoZW1hIGNsb25pbmc6IG11bHRpLXRlbmFudFxuICogYXBwcyB0aGF0IGtlZXAgZWFjaCB0ZW5hbnQncyBkYXRhIGluIGl0cyBvd24gZGF0YWJhc2UgdXNlIGl0IHRvIChyZSltYXRlcmlhbGlzZSB0aGVcbiAqIHRlbmFudCdzIHJvd3MgZnJvbSBhIGdsb2JhbC90ZW1wbGF0ZSBkYXRhYmFzZS5cbiAqXG4gKiBUaGUgY29weSBpcyBkZWxldGUtdGhlbi1yZWluc2VydCBhbmQgdGhlcmVmb3JlIGlkZW1wb3RlbnQsIGFuZCBpdCBtaXJyb3JzIHRoZSBzb3VyY2VcbiAqIHNuYXBzaG90OiB0aGUgcm93cyB0byBkZWxldGUgYXJlIHRoZSB0ZW5hbnQncyAqY3VycmVudCogcm93cyBpbiB0aGUgdGFyZ2V0IChzZWxlY3RlZCB3aXRoXG4gKiB0aGUgc2FtZSBwbGFuIHRyYXZlcnNhbCBydW4gYWdhaW5zdCB0aGUgdGFyZ2V0KSwgc28gYSByb3cgdGhhdCB3YXMgcmVtb3ZlZCBmcm9tIHRoZSBzb3VyY2VcbiAqIHNpbmNlIHRoZSBsYXN0IGNvcHkgaXMgZHJvcHBlZCBmcm9tIHRoZSB0YXJnZXQgdG9vIHJhdGhlciB0aGFuIGxpbmdlcmluZy4gVGhlIGRlbGV0ZXMgcnVuXG4gKiBjaGlsZHJlbiBmaXJzdCBhbmQgdGhlIHNvdXJjZSBpbnNlcnRzIHBhcmVudHMgZmlyc3QsIGFsbCBpbnNpZGUgb25lIHRhcmdldCB0cmFuc2FjdGlvbiB3aXRoXG4gKiBmb3JlaWduLWtleSBlbmZvcmNlbWVudCBkaXNhYmxlZCBzbyB0aGUgb3JkZXJpbmcgbmV2ZXIgdHJpcHMgYSBjb25zdHJhaW50LiBSZWFkcywgZGVsZXRlc1xuICogYW5kIGluc2VydHMgYXJlIGNodW5rZWQgdG8gYm91bmQgc3RhdGVtZW50IHNpemUuXG4gKlxuICogVGhlIGNvcGllciBpcyBwb2xpY3ktZnJlZTogdGhlIGNhbGxlciBzdXBwbGllcyB0aGUgcGxhbiwgdGhlIHNvdXJjZS90YXJnZXQgZGF0YWJhc2VzIGFuZFxuICogdGhlIHRlbmFudCBrZXksIGFuZCB7QGxpbmsgRGF0YUNvcGllciNjb3B5fSByZXR1cm5zIHRoZSBsb2FkZWQgcm93cyBrZXllZCBieSB0YWJsZSBuYW1lIHNvXG4gKiB0aGUgY2FsbGVyIGNhbiBwZXJmb3JtIGFueSBhcHAtc3BlY2lmaWMgcG9zdC1jb3B5IHdvcmsgKGZvciBleGFtcGxlIHJlZ2lzdGVyaW5nIHJlY29yZFxuICogbG9jYXRpb25zKSB3aXRob3V0IHRoYXQgcG9saWN5IGxlYWtpbmcgaW50byB0aGUgZnJhbWV3b3JrLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBEYXRhQ29waWVyIHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBjb3BpZXIgdGhhdCBtb3ZlcyB0ZW5hbnQtb3duZWQgcm93cyBmcm9tIGBzb3VyY2VEYmAgaW50byBgdGFyZ2V0RGJgLlxuICAgKiBAcGFyYW0ge3tcbiAgICogICBzb3VyY2VEYjogaW1wb3J0KFwiLi4vZHJpdmVycy9iYXNlLmpzXCIpLmRlZmF1bHQsXG4gICAqICAgdGFyZ2V0RGI6IGltcG9ydChcIi4uL2RyaXZlcnMvYmFzZS5qc1wiKS5kZWZhdWx0LFxuICAgKiAgIHRhYmxlUGxhbjogaW1wb3J0KFwiLi90ZW5hbnQtdGFibGUtcGxhbi5qc1wiKS5UZW5hbnRUYWJsZVBsYW5FbnRyeVtdLFxuICAgKiAgIGlkQ29sdW1uPzogc3RyaW5nLFxuICAgKiAgIGluc2VydENodW5rU2l6ZT86IG51bWJlcixcbiAgICogICBxdWVyeUNodW5rU2l6ZT86IG51bWJlcixcbiAgICogICBvblByb2dyZXNzPzogKG1lc3NhZ2U6IHN0cmluZykgPT4gdm9pZFxuICAgKiB9fSBhcmdzIC0gU291cmNlLCB0YXJnZXQsIHRyYXZlcnNhbCBwbGFuLCBjaHVuayBsaW1pdHMsIGFuZCBwcm9ncmVzcyBoYW5kbGVyLlxuICAgKi9cbiAgY29uc3RydWN0b3Ioe3NvdXJjZURiLCB0YXJnZXREYiwgdGFibGVQbGFuLCBpZENvbHVtbiA9IFwiaWRcIiwgaW5zZXJ0Q2h1bmtTaXplID0gREVGQVVMVF9JTlNFUlRfQ0hVTktfU0laRSwgcXVlcnlDaHVua1NpemUgPSBERUZBVUxUX1FVRVJZX0NIVU5LX1NJWkUsIG9uUHJvZ3Jlc3N9KSB7XG4gICAgdGhpcy5zb3VyY2VEYiA9IHNvdXJjZURiXG4gICAgdGhpcy50YXJnZXREYiA9IHRhcmdldERiXG4gICAgdGhpcy50YWJsZVBsYW4gPSB0YWJsZVBsYW5cbiAgICB0aGlzLmlkQ29sdW1uID0gaWRDb2x1bW5cbiAgICB0aGlzLmluc2VydENodW5rU2l6ZSA9IGluc2VydENodW5rU2l6ZVxuICAgIHRoaXMucXVlcnlDaHVua1NpemUgPSBxdWVyeUNodW5rU2l6ZVxuICAgIHRoaXMub25Qcm9ncmVzcyA9IG9uUHJvZ3Jlc3NcbiAgfVxuXG4gIC8qKlxuICAgKiBDb3BpZXMgZXZlcnkgcGxhbiB0YWJsZSdzIHJvd3MgZm9yIGBrZXlWYWx1ZWAgZnJvbSB0aGUgc291cmNlIGludG8gdGhlIHRhcmdldCBhbmRcbiAgICogcmV0dXJucyB0aGUgY29waWVkIHNvdXJjZSByb3dzIGtleWVkIGJ5IHRhYmxlIG5hbWUuIFRoZSB0YXJnZXQncyBjdXJyZW50IHRlbmFudCByb3dzXG4gICAqIGFyZSBkZWxldGVkIChjaGlsZHJlbiBmaXJzdCkgYW5kIHRoZSBzb3VyY2Ugcm93cyBpbnNlcnRlZCAocGFyZW50cyBmaXJzdCkgaW4gYSBzaW5nbGVcbiAgICogdGFyZ2V0IHRyYW5zYWN0aW9uIHdpdGggZm9yZWlnbiBrZXlzIGRpc2FibGVkLlxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5VmFsdWUgLSBUZW5hbnQga2V5IHNlbGVjdGluZyB0aGUgcm93cyB0byBjb3B5LlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxNYXA8c3RyaW5nLCBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdPj59IC0gQ29waWVkIHNvdXJjZSByb3dzIGdyb3VwZWQgYnkgdGFibGUgbmFtZS5cbiAgICovXG4gIGFzeW5jIGNvcHkoa2V5VmFsdWUpIHtcbiAgICBjb25zdCBzb3VyY2VSb3dzQnlUYWJsZU5hbWUgPSBhd2FpdCB0aGlzLmxvYWRSb3dzKHRoaXMuc291cmNlRGIsIGtleVZhbHVlKVxuICAgIGNvbnN0IHRhcmdldFJvd3NCeVRhYmxlTmFtZSA9IGF3YWl0IHRoaXMubG9hZFJvd3ModGhpcy50YXJnZXREYiwga2V5VmFsdWUpXG5cbiAgICBhd2FpdCB0aGlzLnRhcmdldERiLndpdGhEaXNhYmxlZEZvcmVpZ25LZXlzKGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IHRoaXMudGFyZ2V0RGIudHJhbnNhY3Rpb24oYXN5bmMgKCkgPT4ge1xuICAgICAgICBhd2FpdCB0aGlzLmRlbGV0ZVRhcmdldFJvd3ModGFyZ2V0Um93c0J5VGFibGVOYW1lKVxuICAgICAgICBhd2FpdCB0aGlzLmluc2VydFRhcmdldFJvd3Moc291cmNlUm93c0J5VGFibGVOYW1lKVxuICAgICAgfSlcbiAgICB9KVxuXG4gICAgcmV0dXJuIHNvdXJjZVJvd3NCeVRhYmxlTmFtZVxuICB9XG5cbiAgLyoqXG4gICAqIERlbGV0ZXMgb25lIHRlbmFudCdzIHJvd3MgZnJvbSB0aGUgdGFyZ2V0IGRhdGFiYXNlLCBjaGlsZHJlbiBiZWZvcmUgcGFyZW50cywgd2l0aFxuICAgKiBmb3JlaWduIGtleXMgZGlzYWJsZWQgaW5zaWRlIGEgc2luZ2xlIHRyYW5zYWN0aW9uLiBUaGlzIGlzIGBjb3B5YCB3aXRob3V0IHRoZSByZWluc2VydDpcbiAgICogdGhlIHNhbWUgcGxhbiB0cmF2ZXJzYWwgc2VsZWN0cyB0aGUgdGVuYW50J3MgY3VycmVudCB0YXJnZXQgcm93cyBhbmQgYGRlbGV0ZVRhcmdldFJvd3NgXG4gICAqIHJlbW92ZXMgdGhlbSBjaGlsZHJlbi1maXJzdCBzbyB0aGUgb3JkZXJpbmcgbmV2ZXIgdHJpcHMgYSBmb3JlaWduIGtleS4gTXVsdGktdGVuYW50IGFwcHNcbiAgICogdXNlIGl0IHRvIHB1cmdlIGEgdGVuYW50IOKAlCBmb3IgZXhhbXBsZSBjbGVhcmluZyB0aGUgdGVuYW50J3MgbWFzdGVyIGNvcHkgaW4gdGhlXG4gICAqIGdsb2JhbC9kZWZhdWx0IGRhdGFiYXNlIG9uIHRlYXJkb3duLCBzbyBmb3JlaWduIGtleXMgc3RvcCByZWZlcmVuY2luZyB0aGUgdGVuYW50J3NcbiAgICogYWJvdXQtdG8tYmUtcmVtb3ZlZCByb290IHJvdy5cbiAgICpcbiAgICogUmV0dXJucyB0aGUgZGVsZXRlZCByb3dzIGtleWVkIGJ5IHRhYmxlIG5hbWUgc28gdGhlIGNhbGxlciBjYW4gcGVyZm9ybSBhbnkgYXBwLXNwZWNpZmljXG4gICAqIHBvc3QtZGVsZXRlIHdvcmsgKHJlY29yZC1sb2NhdGlvbiBjbGVhbnVwLCBhdWRpdGluZykgd2l0aG91dCB0aGF0IHBvbGljeSBsZWFraW5nIGludG8gdGhlXG4gICAqIGZyYW1ld29yay5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleVZhbHVlIC0gVGVuYW50IGtleSB3aG9zZSByb3dzIHNob3VsZCBiZSByZW1vdmVkIGZyb20gdGhlIHRhcmdldC5cbiAgICogQHJldHVybnMge1Byb21pc2U8TWFwPHN0cmluZywgUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXT4+fSAtIFRoZSBkZWxldGVkIHJvd3MgYnkgdGFibGUgbmFtZS5cbiAgICovXG4gIGFzeW5jIGRlbGV0ZVRlbmFudFJvd3Moa2V5VmFsdWUpIHtcbiAgICBjb25zdCByb3dzQnlUYWJsZU5hbWUgPSBhd2FpdCB0aGlzLmxvYWRSb3dzKHRoaXMudGFyZ2V0RGIsIGtleVZhbHVlKVxuXG4gICAgYXdhaXQgdGhpcy50YXJnZXREYi53aXRoRGlzYWJsZWRGb3JlaWduS2V5cyhhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCB0aGlzLnRhcmdldERiLnRyYW5zYWN0aW9uKGFzeW5jICgpID0+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5kZWxldGVUYXJnZXRSb3dzKHJvd3NCeVRhYmxlTmFtZSlcbiAgICAgIH0pXG4gICAgfSlcblxuICAgIHJldHVybiByb3dzQnlUYWJsZU5hbWVcbiAgfVxuXG4gIC8qKlxuICAgKiBMb2FkcyB0aGUgcm93cyBmb3IgYGtleVZhbHVlYCBmb3IgZXZlcnkgdGFibGUgaW4gdGhlIHBsYW4gZnJvbSBgZGJgLCByZXNvbHZpbmdcbiAgICogcGFyZW50LXNjb3BlZCB0YWJsZXMgZnJvbSB0aGUgaWRzIGFscmVhZHkgc2VsZWN0ZWQgZm9yIHRoZWlyIHBhcmVudCB0YWJsZS4gVXNlZCBmb3JcbiAgICogYm90aCB0aGUgc291cmNlIHJvd3MgdG8gY29weSBhbmQgdGhlIHRhcmdldCdzIGN1cnJlbnQgdGVuYW50IHJvd3MgdG8gZGVsZXRlLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2RyaXZlcnMvYmFzZS5qc1wiKS5kZWZhdWx0fSBkYiAtIFNvdXJjZSBvciB0YXJnZXQgZGF0YWJhc2UgdG8gdHJhdmVyc2UuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXlWYWx1ZSAtIFRlbmFudCBrZXkgc2VsZWN0aW5nIHRoZSByb290IHBsYW4gcm93cy5cbiAgICogQHJldHVybnMge1Byb21pc2U8TWFwPHN0cmluZywgUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXT4+fSAtIExvYWRlZCByb3dzIGdyb3VwZWQgYnkgdGFibGUgbmFtZS5cbiAgICovXG4gIGFzeW5jIGxvYWRSb3dzKGRiLCBrZXlWYWx1ZSkge1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy50cmF2ZXJzZVBsYW4oZGIsIGtleVZhbHVlKSkucm93c0J5VGFibGVOYW1lXG4gIH1cblxuICAvKipcbiAgICogTG9hZHMgb25seSB0aGUgaWRzIGZvciBga2V5VmFsdWVgIGZvciBldmVyeSB0YWJsZSBpbiB0aGUgcGxhbiBmcm9tIGBkYmAsIHVzaW5nIHRoZSBzYW1lXG4gICAqIHBhcmVudC9jaGlsZCB0cmF2ZXJzYWwgYXMge0BsaW5rIERhdGFDb3BpZXIjbG9hZFJvd3N9IGJ1dCBzZWxlY3RpbmcganVzdCB0aGUgaWQgY29sdW1uLlxuICAgKiBDYWxsZXJzIHRoYXQgb25seSBuZWVkIHRvIGNvbXBhcmUgcm93IG1lbWJlcnNoaXAg4oCUIGZvciBleGFtcGxlIHZlcmlmeWluZyBhIHRlbmFudCBhbHJlYWR5XG4gICAqIGhvbGRzIGV2ZXJ5IGRlZmF1bHQgcm93IGJlZm9yZSBhIGNsZWFudXAgZGVsZXRlIOKAlCBzaG91bGQgdXNlIHRoaXMgaW5zdGVhZCBvZiBsb2FkUm93cyBzb1xuICAgKiB0aGV5IG5ldmVyIG1hdGVyaWFsaXNlIGZ1bGwgcm93czsgZm9yIGxhcmdlIHRlbmFudHMgdGhhdCBpcyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIGEgZmV3XG4gICAqIGtpbG9ieXRlcyBvZiBpZHMgYW5kIGdpZ2FieXRlcyBvZiByb3cgZGF0YS5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi9kcml2ZXJzL2Jhc2UuanNcIikuZGVmYXVsdH0gZGIgLSBTb3VyY2Ugb3IgdGFyZ2V0IGRhdGFiYXNlIHRvIHRyYXZlcnNlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5VmFsdWUgLSBUZW5hbnQga2V5IHNlbGVjdGluZyB0aGUgcm9vdCBwbGFuIHJvd3MuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPE1hcDxzdHJpbmcsIHN0cmluZ1tdPj59IC0gTG9hZGVkIGlkcyBncm91cGVkIGJ5IHRhYmxlIG5hbWUuXG4gICAqL1xuICBhc3luYyBsb2FkUm93SWRzKGRiLCBrZXlWYWx1ZSkge1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy50cmF2ZXJzZVBsYW4oZGIsIGtleVZhbHVlLCBbdGhpcy5pZENvbHVtbl0pKS5pZHNCeVRhYmxlTmFtZVxuICB9XG5cbiAgLyoqXG4gICAqIFRyYXZlcnNlcyB0aGUgdGFibGUgcGxhbiBmb3IgYGtleVZhbHVlYCwgcXVlcnlpbmcgZWFjaCB0YWJsZSBieSBpdHMgdGVuYW50IGtleSBjb2x1bW4gb3JcbiAgICogKGZvciBjaGlsZCB0YWJsZXMpIGJ5IHRoZSBpZHMgYWxyZWFkeSBzZWxlY3RlZCBmb3IgaXRzIHBhcmVudCwgYW5kIHJldHVybnMgYm90aCB0aGUgaWRzXG4gICAqIGFuZCB0aGUgbG9hZGVkIHJvd3MgZ3JvdXBlZCBieSB0YWJsZSBuYW1lLiBgc2VsZWN0Q29sdW1uc2AgYm91bmRzIHRoZSBjb2x1bW5zIGVhY2ggcXVlcnlcbiAgICogc2VsZWN0czsgcGFzcyBgW2lkQ29sdW1uXWAgZm9yIGFuIGlkLW9ubHkgdHJhdmVyc2FsLCBvciBvbWl0IGl0IHRvIGxvYWQgZnVsbCByb3dzLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2RyaXZlcnMvYmFzZS5qc1wiKS5kZWZhdWx0fSBkYiAtIFNvdXJjZSBvciB0YXJnZXQgZGF0YWJhc2UgdG8gdHJhdmVyc2UuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXlWYWx1ZSAtIFRlbmFudCBrZXkgc2VsZWN0aW5nIHRoZSByb290IHBsYW4gcm93cy5cbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gW3NlbGVjdENvbHVtbnNdIC0gQ29sdW1ucyB0byBzZWxlY3Q7IGRlZmF1bHRzIHRvIGV2ZXJ5IGNvbHVtbi5cbiAgICogQHJldHVybnMge1Byb21pc2U8e2lkc0J5VGFibGVOYW1lOiBNYXA8c3RyaW5nLCBzdHJpbmdbXT4sIHJvd3NCeVRhYmxlTmFtZTogTWFwPHN0cmluZywgUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXT59Pn0gLSBJZHMgYW5kIHJvd3MgZ3JvdXBlZCBieSB0YWJsZSBuYW1lLlxuICAgKi9cbiAgYXN5bmMgdHJhdmVyc2VQbGFuKGRiLCBrZXlWYWx1ZSwgc2VsZWN0Q29sdW1ucykge1xuICAgIC8qKiBAdHlwZSB7TWFwPHN0cmluZywgc3RyaW5nW10+fSAqL1xuICAgIGNvbnN0IGlkc0J5VGFibGVOYW1lID0gbmV3IE1hcCgpXG4gICAgLyoqIEB0eXBlIHtNYXA8c3RyaW5nLCBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdPn0gKi9cbiAgICBjb25zdCByb3dzQnlUYWJsZU5hbWUgPSBuZXcgTWFwKClcblxuICAgIGZvciAoY29uc3QgdGFibGVDb25maWcgb2YgdGhpcy50YWJsZVBsYW4pIHtcbiAgICAgIGxldCByb3dzXG5cbiAgICAgIGlmICh0YWJsZUNvbmZpZy5rZXlDb2x1bW4pIHtcbiAgICAgICAgcm93cyA9IGF3YWl0IHRoaXMucXVlcnlSb3dzQnlDb2x1bW4oe1xuICAgICAgICAgIGNvbHVtbk5hbWU6IHRhYmxlQ29uZmlnLmtleUNvbHVtbixcbiAgICAgICAgICBkYixcbiAgICAgICAgICBzZWxlY3RDb2x1bW5zLFxuICAgICAgICAgIHRhYmxlTmFtZTogdGFibGVDb25maWcudGFibGVOYW1lLFxuICAgICAgICAgIHZhbHVlczogW2tleVZhbHVlXVxuICAgICAgICB9KVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKCF0YWJsZUNvbmZpZy5wYXJlbnRDb2x1bW4gfHwgIXRhYmxlQ29uZmlnLnBhcmVudFRhYmxlTmFtZSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQga2V5Q29sdW1uIG9yIHBhcmVudFRhYmxlTmFtZStwYXJlbnRDb2x1bW4gZm9yIHRhYmxlICR7dGFibGVDb25maWcudGFibGVOYW1lfSBpbiB0aGUgdGVuYW50IHRhYmxlIHBsYW4uYClcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghaWRzQnlUYWJsZU5hbWUuaGFzKHRhYmxlQ29uZmlnLnBhcmVudFRhYmxlTmFtZSkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFRlbmFudCB0YWJsZSBwbGFuIGVudHJ5ICR7dGFibGVDb25maWcudGFibGVOYW1lfSByZWZlcmVuY2VzIHBhcmVudCB0YWJsZSAke3RhYmxlQ29uZmlnLnBhcmVudFRhYmxlTmFtZX0sIHdoaWNoIGhhcyBub3QgYmVlbiBsb2FkZWQ7IHBhcmVudCB0YWJsZXMgbXVzdCBhcHBlYXIgYmVmb3JlIHRoZWlyIGNoaWxkcmVuIGluIHRoZSBwbGFuLmApXG4gICAgICAgIH1cblxuICAgICAgICByb3dzID0gYXdhaXQgdGhpcy5xdWVyeVJvd3NCeUNvbHVtbih7XG4gICAgICAgICAgY29sdW1uTmFtZTogdGFibGVDb25maWcucGFyZW50Q29sdW1uLFxuICAgICAgICAgIGRiLFxuICAgICAgICAgIHNlbGVjdENvbHVtbnMsXG4gICAgICAgICAgdGFibGVOYW1lOiB0YWJsZUNvbmZpZy50YWJsZU5hbWUsXG4gICAgICAgICAgdmFsdWVzOiBpZHNCeVRhYmxlTmFtZS5nZXQodGFibGVDb25maWcucGFyZW50VGFibGVOYW1lKSB8fCBbXVxuICAgICAgICB9KVxuICAgICAgfVxuXG4gICAgICBpZiAocm93cy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHRoaXMucmVwb3J0UHJvZ3Jlc3MoYCR7dGFibGVDb25maWcudGFibGVOYW1lfTogbG9hZGVkICR7cm93cy5sZW5ndGh9IHJvdyhzKWApXG4gICAgICB9XG5cbiAgICAgIGlkc0J5VGFibGVOYW1lLnNldCh0YWJsZUNvbmZpZy50YWJsZU5hbWUsIHVuaXF1ZVN0cmluZ3Mocm93cy5tYXAoKHJvdykgPT4gcm93W3RoaXMuaWRDb2x1bW5dKSkpXG4gICAgICByb3dzQnlUYWJsZU5hbWUuc2V0KHRhYmxlQ29uZmlnLnRhYmxlTmFtZSwgcm93cylcbiAgICB9XG5cbiAgICByZXR1cm4ge2lkc0J5VGFibGVOYW1lLCByb3dzQnlUYWJsZU5hbWV9XG4gIH1cblxuICAvKipcbiAgICogU2VsZWN0cyBgdGFibGVOYW1lYCByb3dzIGluIGBkYmAgd2hvc2UgYGNvbHVtbk5hbWVgIGlzIGluIGB2YWx1ZXNgLCBjaHVua2VkLiBgc2VsZWN0Q29sdW1uc2BcbiAgICogYm91bmRzIHRoZSBwcm9qZWN0aW9uIGFuZCBkZWZhdWx0cyB0byBldmVyeSBjb2x1bW4uXG4gICAqIEBwYXJhbSB7e2NvbHVtbk5hbWU6IHN0cmluZywgZGI6IGltcG9ydChcIi4uL2RyaXZlcnMvYmFzZS5qc1wiKS5kZWZhdWx0LCBzZWxlY3RDb2x1bW5zPzogc3RyaW5nW10sIHRhYmxlTmFtZTogc3RyaW5nLCB2YWx1ZXM6IHN0cmluZ1tdfX0gYXJncyAtIFRhYmxlLCBjb2x1bW4sIHByb2plY3Rpb24sIGRhdGFiYXNlLCBhbmQgdmFsdWVzIGZvciB0aGUgY2h1bmtlZCBsb29rdXAuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIHVua25vd24+W10+fSAtIFJvd3MgbWF0Y2hpbmcgdGhlIHN1cHBsaWVkIGNvbHVtbiB2YWx1ZXMuXG4gICAqL1xuICBhc3luYyBxdWVyeVJvd3NCeUNvbHVtbih7Y29sdW1uTmFtZSwgZGIsIHNlbGVjdENvbHVtbnMsIHRhYmxlTmFtZSwgdmFsdWVzfSkge1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRWYWx1ZXMgPSB1bmlxdWVTdHJpbmdzKHZhbHVlcylcblxuICAgIGlmIChub3JtYWxpemVkVmFsdWVzLmxlbmd0aCA8PSAwKSB7XG4gICAgICByZXR1cm4gW11cbiAgICB9XG5cbiAgICBjb25zdCByb3dzID0gW11cbiAgICBjb25zdCBxdW90ZWRUYWJsZSA9IGRiLnF1b3RlVGFibGUodGFibGVOYW1lKVxuICAgIGNvbnN0IHF1b3RlZENvbHVtbiA9IGRiLnF1b3RlQ29sdW1uKGNvbHVtbk5hbWUpXG4gICAgY29uc3Qgc2VsZWN0TGlzdCA9IHNlbGVjdENvbHVtbnNcbiAgICAgID8gc2VsZWN0Q29sdW1ucy5tYXAoKGNvbHVtbikgPT4gYCR7cXVvdGVkVGFibGV9LiR7ZGIucXVvdGVDb2x1bW4oY29sdW1uKX1gKS5qb2luKFwiLCBcIilcbiAgICAgIDogYCR7cXVvdGVkVGFibGV9LipgXG5cbiAgICBmb3IgKGNvbnN0IHZhbHVlc0NodW5rIG9mIGNodW5rcyhub3JtYWxpemVkVmFsdWVzLCB0aGlzLnF1ZXJ5Q2h1bmtTaXplKSkge1xuICAgICAgY29uc3Qgc3FsID0gYFNFTEVDVCAke3NlbGVjdExpc3R9IEZST00gJHtxdW90ZWRUYWJsZX0gV0hFUkUgJHtxdW90ZWRDb2x1bW59IElOICgke3RoaXMucXVvdGVkVmFsdWVzU3FsKGRiLCB2YWx1ZXNDaHVuayl9KWBcblxuICAgICAgcm93cy5wdXNoKC4uLmF3YWl0IHRoaXMuZXhlY3V0ZVF1aWV0UXVlcnkoZGIsIHNxbCkpXG4gICAgfVxuXG4gICAgcmV0dXJuIHJvd3NcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWxldGVzIHRoZSBtYXRjaGluZyB0YXJnZXQgcm93cyBmb3IgZXZlcnkgcGxhbiB0YWJsZSwgY2hpbGRyZW4gYmVmb3JlIHBhcmVudHMsIHNvIHRoZVxuICAgKiByZWluc2VydCB0aGF0IGZvbGxvd3Mgc3RhcnRzIGZyb20gYSBjbGVhbiBzbGF0ZSB3aXRob3V0IHZpb2xhdGluZyBmb3JlaWduIGtleXMuXG4gICAqIEBwYXJhbSB7TWFwPHN0cmluZywgUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXT59IHJvd3NCeVRhYmxlTmFtZSAtIFJvd3MgZ3JvdXBlZCBieSB0YWJsZSBuYW1lLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIGRlbGV0ZVRhcmdldFJvd3Mocm93c0J5VGFibGVOYW1lKSB7XG4gICAgZm9yIChjb25zdCB0YWJsZUNvbmZpZyBvZiBbLi4udGhpcy50YWJsZVBsYW5dLnJldmVyc2UoKSkge1xuICAgICAgY29uc3Qgcm93SWRzID0gdW5pcXVlU3RyaW5ncygocm93c0J5VGFibGVOYW1lLmdldCh0YWJsZUNvbmZpZy50YWJsZU5hbWUpIHx8IFtdKS5tYXAoKHJvdykgPT4gcm93W3RoaXMuaWRDb2x1bW5dKSlcblxuICAgICAgaWYgKHJvd0lkcy5sZW5ndGggPD0gMCkge1xuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICBjb25zdCBxdW90ZWRUYWJsZSA9IHRoaXMudGFyZ2V0RGIucXVvdGVUYWJsZSh0YWJsZUNvbmZpZy50YWJsZU5hbWUpXG4gICAgICBjb25zdCBxdW90ZWRJZENvbHVtbiA9IHRoaXMudGFyZ2V0RGIucXVvdGVDb2x1bW4odGhpcy5pZENvbHVtbilcblxuICAgICAgZm9yIChjb25zdCByb3dJZHNDaHVuayBvZiBjaHVua3Mocm93SWRzLCB0aGlzLnF1ZXJ5Q2h1bmtTaXplKSkge1xuICAgICAgICBhd2FpdCB0aGlzLmV4ZWN1dGVRdWlldFF1ZXJ5KFxuICAgICAgICAgIHRoaXMudGFyZ2V0RGIsXG4gICAgICAgICAgYERFTEVURSBGUk9NICR7cXVvdGVkVGFibGV9IFdIRVJFICR7cXVvdGVkSWRDb2x1bW59IElOICgke3RoaXMucXVvdGVkVmFsdWVzU3FsKHRoaXMudGFyZ2V0RGIsIHJvd0lkc0NodW5rKX0pYFxuICAgICAgICApXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEluc2VydHMgdGhlIGxvYWRlZCBzb3VyY2Ugcm93cyBpbnRvIHRoZSB0YXJnZXQgZm9yIGV2ZXJ5IHBsYW4gdGFibGUsIHBhcmVudHMgYmVmb3JlXG4gICAqIGNoaWxkcmVuLCBjaHVua2VkIHRvIGJvdW5kIHN0YXRlbWVudCBzaXplLlxuICAgKiBAcGFyYW0ge01hcDxzdHJpbmcsIFJlY29yZDxzdHJpbmcsIHVua25vd24+W10+fSByb3dzQnlUYWJsZU5hbWUgLSBSb3dzIGdyb3VwZWQgYnkgdGFibGUgbmFtZS5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBpbnNlcnRUYXJnZXRSb3dzKHJvd3NCeVRhYmxlTmFtZSkge1xuICAgIGZvciAoY29uc3QgdGFibGVDb25maWcgb2YgdGhpcy50YWJsZVBsYW4pIHtcbiAgICAgIGNvbnN0IHJvd3MgPSByb3dzQnlUYWJsZU5hbWUuZ2V0KHRhYmxlQ29uZmlnLnRhYmxlTmFtZSkgfHwgW11cblxuICAgICAgaWYgKHJvd3MubGVuZ3RoIDw9IDApIHtcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgY29uc3QgY29sdW1ucyA9IE9iamVjdC5rZXlzKHJvd3NbMF0pXG4gICAgICBjb25zdCBpbnNlcnRDaHVua3MgPSBjaHVua3Mocm93cywgdGhpcy5pbnNlcnRDaHVua1NpemUpXG5cbiAgICAgIHRoaXMucmVwb3J0UHJvZ3Jlc3MoYCR7dGFibGVDb25maWcudGFibGVOYW1lfTogaW5zZXJ0aW5nICR7cm93cy5sZW5ndGh9IHJvdyhzKSBpbiAke2luc2VydENodW5rcy5sZW5ndGh9IGNodW5rKHMpYClcblxuICAgICAgZm9yIChjb25zdCByb3dzQ2h1bmsgb2YgaW5zZXJ0Q2h1bmtzKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuaW5zZXJ0Um93c1F1aWV0bHkoe1xuICAgICAgICAgIGNvbHVtbnMsXG4gICAgICAgICAgZGI6IHRoaXMudGFyZ2V0RGIsXG4gICAgICAgICAgcm93czogcm93c0NodW5rLm1hcCgocm93KSA9PiBjb2x1bW5zLm1hcCgoY29sdW1uKSA9PiByb3dbY29sdW1uXSkpLFxuICAgICAgICAgIHRhYmxlTmFtZTogdGFibGVDb25maWcudGFibGVOYW1lXG4gICAgICAgIH0pXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFF1b3RlcyBhbmQgY29tbWEtam9pbnMgdmFsdWVzIGZvciBhbiBTUUwgYElOICguLi4pYCBsaXN0IGFnYWluc3QgdGhlIGdpdmVuIGRhdGFiYXNlLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2RyaXZlcnMvYmFzZS5qc1wiKS5kZWZhdWx0fSBkYiAtIERhdGFiYXNlIHdob3NlIHF1b3RpbmcgcnVsZXMgZm9ybWF0IHRoZSB2YWx1ZXMuXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IHZhbHVlcyAtIFZhbHVlcyB0byBxdW90ZSBmb3IgdGhlIGBJTmAgbGlzdC5cbiAgICogQHJldHVybnMge3N0cmluZ30gLSBRdW90ZWQgU1FMIHZhbHVlIGxpc3QuXG4gICAqL1xuICBxdW90ZWRWYWx1ZXNTcWwoZGIsIHZhbHVlcykge1xuICAgIHJldHVybiB2YWx1ZXMubWFwKCh2YWx1ZSkgPT4gZGIucXVvdGUodmFsdWUpKS5qb2luKFwiLCBcIilcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGEgcXVlcnkgd2l0aG91dCBwZXItcXVlcnkgbG9nZ2luZywgdXNlZCBmb3IgdGhlIGhpZ2gtdm9sdW1lIGNvcHkgc3RhdGVtZW50cy5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi9kcml2ZXJzL2Jhc2UuanNcIikuZGVmYXVsdH0gZGIgLSBEYXRhYmFzZSBvbiB3aGljaCB0byBleGVjdXRlIHRoZSBjb3B5IHF1ZXJ5LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3FsIC0gQ29weS1yZWxhdGVkIFNRTCBzdGF0ZW1lbnQgdG8gZXhlY3V0ZSBxdWlldGx5LlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdPn0gLSBRdWVyeSByZXN1bHQgcm93cy5cbiAgICovXG4gIGFzeW5jIGV4ZWN1dGVRdWlldFF1ZXJ5KGRiLCBzcWwpIHtcbiAgICByZXR1cm4gYXdhaXQgZGIucXVlcnkoc3FsLCB7bG9nUXVlcnk6IGZhbHNlfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnNlcnRzIGNvbHVtbi1hbGlnbmVkIHJvdyB0dXBsZXMgaW50byBhIHRhYmxlIHdpdGhvdXQgcGVyLXF1ZXJ5IGxvZ2dpbmcuXG4gICAqIEBwYXJhbSB7e2NvbHVtbnM6IHN0cmluZ1tdLCBkYjogaW1wb3J0KFwiLi4vZHJpdmVycy9iYXNlLmpzXCIpLmRlZmF1bHQsIHJvd3M6IEFycmF5PEFycmF5PHVua25vd24+PiwgdGFibGVOYW1lOiBzdHJpbmd9fSBhcmdzIC0gRGVzdGluYXRpb24gdGFibGUgYW5kIGNvbHVtbi1hbGlnbmVkIHJvdyB2YWx1ZXMgdG8gaW5zZXJ0LlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIGluc2VydFJvd3NRdWlldGx5KHtjb2x1bW5zLCBkYiwgcm93cywgdGFibGVOYW1lfSkge1xuICAgIGF3YWl0IHRoaXMuZXhlY3V0ZVF1aWV0UXVlcnkoZGIsIGRiLmluc2VydFNxbCh7Y29sdW1ucywgdGFibGVOYW1lLCByb3dzfSkpXG4gIH1cblxuICAvKipcbiAgICogRm9yd2FyZHMgYSBwcm9ncmVzcyBtZXNzYWdlIHRvIHRoZSBvcHRpb25hbCBgb25Qcm9ncmVzc2AgY2FsbGJhY2sgd2hlbiBvbmUgd2FzIGdpdmVuLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIENvcHkgcHJvZ3Jlc3MgbWVzc2FnZSB0byBmb3J3YXJkIHdoZW4gcmVwb3J0aW5nIGlzIGVuYWJsZWQuXG4gICAqIEByZXR1cm5zIHt2b2lkfVxuICAgKi9cbiAgcmVwb3J0UHJvZ3Jlc3MobWVzc2FnZSkge1xuICAgIGlmICh0aGlzLm9uUHJvZ3Jlc3MpIHtcbiAgICAgIHRoaXMub25Qcm9ncmVzcyhtZXNzYWdlKVxuICAgIH1cbiAgfVxufVxuIl19
433
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YS1jb3BpZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvZGF0YWJhc2UvdGVuYW50cy9kYXRhLWNvcGllci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosTUFBTSx5QkFBeUIsR0FBRyxHQUFHLENBQUE7QUFDckMsTUFBTSx3QkFBd0IsR0FBRyxHQUFHLENBQUE7QUFDcEMsTUFBTSx5QkFBeUIsR0FBRyxJQUFJLENBQUE7QUFFdEM7Ozs7OztHQU1HO0FBQ0gsU0FBUyxNQUFNLENBQUMsTUFBTSxFQUFFLFNBQVM7SUFDL0IsTUFBTSxhQUFhLEdBQUcsRUFBRSxDQUFBO0lBRXhCLEtBQUssSUFBSSxLQUFLLEdBQUcsQ0FBQyxFQUFFLEtBQUssR0FBRyxNQUFNLENBQUMsTUFBTSxFQUFFLEtBQUssSUFBSSxTQUFTLEVBQUUsQ0FBQztRQUM5RCxhQUFhLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLEtBQUssR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFBO0lBQzVELENBQUM7SUFFRCxPQUFPLGFBQWEsQ0FBQTtBQUN0QixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQVMsYUFBYSxDQUFDLE1BQU07SUFDM0IsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFBO0FBQ2xHLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sVUFBVTtJQUM3Qjs7Ozs7Ozs7Ozs7T0FXRztJQUNILFlBQVksRUFBQyxRQUFRLEVBQUUsUUFB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LEVBQUUsQ0FBQztZQUNwQixJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBQzFCLENBQUM7SUFDSCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuY29uc3QgREVGQVVMVF9JTlNFUlRfQ0hVTktfU0laRSA9IDEwMFxuY29uc3QgREVGQVVMVF9RVUVSWV9DSFVOS19TSVpFID0gNTAwXG5jb25zdCBERUZBVUxUX1NUUkVBTV9CQVRDSF9TSVpFID0gMTAwMFxuXG4vKipcbiAqIFNwbGl0cyBhbiBhcnJheSBpbnRvIGNodW5rcyBvZiBhdCBtb3N0IGBjaHVua1NpemVgIGl0ZW1zLlxuICogQHRlbXBsYXRlIFRcbiAqIEBwYXJhbSB7VFtdfSB2YWx1ZXMgLSBPcmRlcmVkIGl0ZW1zIHRvIHBhcnRpdGlvbi5cbiAqIEBwYXJhbSB7bnVtYmVyfSBjaHVua1NpemUgLSBNYXhpbXVtIGl0ZW1zIHBlciBjaHVuay5cbiAqIEByZXR1cm5zIHtUW11bXX0gLSBDb25zZWN1dGl2ZSBjaHVua3MgcHJlc2VydmluZyBpbnB1dCBvcmRlci5cbiAqL1xuZnVuY3Rpb24gY2h1bmtzKHZhbHVlcywgY2h1bmtTaXplKSB7XG4gIGNvbnN0IGNodW5rZWRWYWx1ZXMgPSBbXVxuXG4gIGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCB2YWx1ZXMubGVuZ3RoOyBpbmRleCArPSBjaHVua1NpemUpIHtcbiAgICBjaHVua2VkVmFsdWVzLnB1c2godmFsdWVzLnNsaWNlKGluZGV4LCBpbmRleCArIGNodW5rU2l6ZSkpXG4gIH1cblxuICByZXR1cm4gY2h1bmtlZFZhbHVlc1xufVxuXG4vKipcbiAqIFN0cmluZ2lmaWVzIHZhbHVlcyBhbmQgcmV0dXJucyB0aGUgZGlzdGluY3QsIG5vbi1ibGFuayBvbmVzLCBwcmVzZXJ2aW5nIGZpcnN0LXNlZW4gb3JkZXIuXG4gKiBAcGFyYW0ge3Vua25vd25bXX0gdmFsdWVzIC0gQ2FuZGlkYXRlIGRhdGFiYXNlIGlkZW50aWZpZXJzIHRvIHN0cmluZ2lmeSBhbmQgZGVkdXBsaWNhdGUuXG4gKiBAcmV0dXJucyB7c3RyaW5nW119IC0gRGlzdGluY3Qgbm9uLWJsYW5rIGlkZW50aWZpZXJzIGluIGZpcnN0LXNlZW4gb3JkZXIuXG4gKi9cbmZ1bmN0aW9uIHVuaXF1ZVN0cmluZ3ModmFsdWVzKSB7XG4gIHJldHVybiBBcnJheS5mcm9tKG5ldyBTZXQodmFsdWVzLm1hcCgodmFsdWUpID0+IFN0cmluZyh2YWx1ZSkpLmZpbHRlcigodmFsdWUpID0+IHZhbHVlLnRyaW0oKSkpKVxufVxuXG4vKipcbiAqIENvcGllcyBhIHNpbmdsZSB0ZW5hbnQncyByb3dzIGZyb20gYSBzb3VyY2UgZGF0YWJhc2UgaW50byBhIHRhcmdldCBkYXRhYmFzZSwgZm9sbG93aW5nIGFcbiAqIHRhYmxlIHBsYW4gdGhhdCBwYXJ0aXRpb25zIGVhY2ggdGFibGUgZWl0aGVyIGJ5IGEgZGlyZWN0IHRlbmFudCBrZXkgY29sdW1uIG9yIGJ5XG4gKiBwYXJlbnQtaWQgdHJhdmVyc2FsLiBUaGlzIGlzIHRoZSByb3ctbGV2ZWwgY291bnRlcnBhcnQgdG8gc2NoZW1hIGNsb25pbmc6IG11bHRpLXRlbmFudFxuICogYXBwcyB0aGF0IGtlZXAgZWFjaCB0ZW5hbnQncyBkYXRhIGluIGl0cyBvd24gZGF0YWJhc2UgdXNlIGl0IHRvIChyZSltYXRlcmlhbGlzZSB0aGVcbiAqIHRlbmFudCdzIHJvd3MgZnJvbSBhIGdsb2JhbC90ZW1wbGF0ZSBkYXRhYmFzZS5cbiAqXG4gKiBUaGUgY29weSBpcyBkZWxldGUtdGhlbi1yZWluc2VydCBhbmQgdGhlcmVmb3JlIGlkZW1wb3RlbnQsIGFuZCBpdCBtaXJyb3JzIHRoZSBzb3VyY2VcbiAqIHNuYXBzaG90OiB0aGUgcm93cyB0byBkZWxldGUgYXJlIHRoZSB0ZW5hbnQncyAqY3VycmVudCogcm93cyBpbiB0aGUgdGFyZ2V0IChzZWxlY3RlZCB3aXRoXG4gKiB0aGUgc2FtZSBwbGFuIHRyYXZlcnNhbCBydW4gYWdhaW5zdCB0aGUgdGFyZ2V0KSwgc28gYSByb3cgdGhhdCB3YXMgcmVtb3ZlZCBmcm9tIHRoZSBzb3VyY2VcbiAqIHNpbmNlIHRoZSBsYXN0IGNvcHkgaXMgZHJvcHBlZCBmcm9tIHRoZSB0YXJnZXQgdG9vIHJhdGhlciB0aGFuIGxpbmdlcmluZy4gVGhlIGRlbGV0ZXMgcnVuXG4gKiBjaGlsZHJlbiBmaXJzdCBhbmQgdGhlIHNvdXJjZSBpbnNlcnRzIHBhcmVudHMgZmlyc3QsIGFsbCBpbnNpZGUgb25lIHRhcmdldCB0cmFuc2FjdGlvbiB3aXRoXG4gKiBmb3JlaWduLWtleSBlbmZvcmNlbWVudCBkaXNhYmxlZCBzbyB0aGUgb3JkZXJpbmcgbmV2ZXIgdHJpcHMgYSBjb25zdHJhaW50LiBSZWFkcywgZGVsZXRlc1xuICogYW5kIGluc2VydHMgYXJlIGNodW5rZWQgdG8gYm91bmQgc3RhdGVtZW50IHNpemUuXG4gKlxuICogVGhlIGNvcGllciBpcyBwb2xpY3ktZnJlZTogdGhlIGNhbGxlciBzdXBwbGllcyB0aGUgcGxhbiwgdGhlIHNvdXJjZS90YXJnZXQgZGF0YWJhc2VzIGFuZFxuICogdGhlIHRlbmFudCBrZXksIGFuZCB7QGxpbmsgRGF0YUNvcGllciNjb3B5fSByZXR1cm5zIHRoZSBsb2FkZWQgcm93cyBrZXllZCBieSB0YWJsZSBuYW1lIHNvXG4gKiB0aGUgY2FsbGVyIGNhbiBwZXJmb3JtIGFueSBhcHAtc3BlY2lmaWMgcG9zdC1jb3B5IHdvcmsgKGZvciBleGFtcGxlIHJlZ2lzdGVyaW5nIHJlY29yZFxuICogbG9jYXRpb25zKSB3aXRob3V0IHRoYXQgcG9saWN5IGxlYWtpbmcgaW50byB0aGUgZnJhbWV3b3JrLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBEYXRhQ29waWVyIHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBjb3BpZXIgdGhhdCBtb3ZlcyB0ZW5hbnQtb3duZWQgcm93cyBmcm9tIGBzb3VyY2VEYmAgaW50byBgdGFyZ2V0RGJgLlxuICAgKiBAcGFyYW0ge3tcbiAgICogICBzb3VyY2VEYjogaW1wb3J0KFwiLi4vZHJpdmVycy9iYXNlLmpzXCIpLmRlZmF1bHQsXG4gICAqICAgdGFyZ2V0RGI6IGltcG9ydChcIi4uL2RyaXZlcnMvYmFzZS5qc1wiKS5kZWZhdWx0LFxuICAgKiAgIHRhYmxlUGxhbjogaW1wb3J0KFwiLi90ZW5hbnQtdGFibGUtcGxhbi5qc1wiKS5UZW5hbnRUYWJsZVBsYW5FbnRyeVtdLFxuICAgKiAgIGlkQ29sdW1uPzogc3RyaW5nLFxuICAgKiAgIGluc2VydENodW5rU2l6ZT86IG51bWJlcixcbiAgICogICBxdWVyeUNodW5rU2l6ZT86IG51bWJlcixcbiAgICogICBvblByb2dyZXNzPzogKG1lc3NhZ2U6IHN0cmluZykgPT4gdm9pZFxuICAgKiB9fSBhcmdzIC0gU291cmNlLCB0YXJnZXQsIHRyYXZlcnNhbCBwbGFuLCBjaHVuayBsaW1pdHMsIGFuZCBwcm9ncmVzcyBoYW5kbGVyLlxuICAgKi9cbiAgY29uc3RydWN0b3Ioe3NvdXJjZURiLCB0YXJnZXREYiwgdGFibGVQbGFuLCBpZENvbHVtbiA9IFwiaWRcIiwgaW5zZXJ0Q2h1bmtTaXplID0gREVGQVVMVF9JTlNFUlRfQ0hVTktfU0laRSwgcXVlcnlDaHVua1NpemUgPSBERUZBVUxUX1FVRVJZX0NIVU5LX1NJWkUsIG9uUHJvZ3Jlc3N9KSB7XG4gICAgdGhpcy5zb3VyY2VEYiA9IHNvdXJjZURiXG4gICAgdGhpcy50YXJnZXREYiA9IHRhcmdldERiXG4gICAgdGhpcy50YWJsZVBsYW4gPSB0YWJsZVBsYW5cbiAgICB0aGlzLmlkQ29sdW1uID0gaWRDb2x1bW5cbiAgICB0aGlzLmluc2VydENodW5rU2l6ZSA9IGluc2VydENodW5rU2l6ZVxuICAgIHRoaXMucXVlcnlDaHVua1NpemUgPSBxdWVyeUNodW5rU2l6ZVxuICAgIHRoaXMub25Qcm9ncmVzcyA9IG9uUHJvZ3Jlc3NcbiAgfVxuXG4gIC8qKlxuICAgKiBDb3BpZXMgZXZlcnkgcGxhbiB0YWJsZSdzIHJvd3MgZm9yIGBrZXlWYWx1ZWAgZnJvbSB0aGUgc291cmNlIGludG8gdGhlIHRhcmdldCBhbmRcbiAgICogcmV0dXJucyB0aGUgY29waWVkIHNvdXJjZSByb3dzIGtleWVkIGJ5IHRhYmxlIG5hbWUuIFRoZSB0YXJnZXQncyBjdXJyZW50IHRlbmFudCByb3dzXG4gICAqIGFyZSBkZWxldGVkIChjaGlsZHJlbiBmaXJzdCkgYW5kIHRoZSBzb3VyY2Ugcm93cyBpbnNlcnRlZCAocGFyZW50cyBmaXJzdCkgaW4gYSBzaW5nbGVcbiAgICogdGFyZ2V0IHRyYW5zYWN0aW9uIHdpdGggZm9yZWlnbiBrZXlzIGRpc2FibGVkLlxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5VmFsdWUgLSBUZW5hbnQga2V5IHNlbGVjdGluZyB0aGUgcm93cyB0byBjb3B5LlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxNYXA8c3RyaW5nLCBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdPj59IC0gQ29waWVkIHNvdXJjZSByb3dzIGdyb3VwZWQgYnkgdGFibGUgbmFtZS5cbiAgICovXG4gIGFzeW5jIGNvcHkoa2V5VmFsdWUpIHtcbiAgICBjb25zdCBzb3VyY2VSb3dzQnlUYWJsZU5hbWUgPSBhd2FpdCB0aGlzLmxvYWRSb3dzKHRoaXMuc291cmNlRGIsIGtleVZhbHVlKVxuICAgIGNvbnN0IHRhcmdldFJvd3NCeVRhYmxlTmFtZSA9IGF3YWl0IHRoaXMubG9hZFJvd3ModGhpcy50YXJnZXREYiwga2V5VmFsdWUpXG5cbiAgICBhd2FpdCB0aGlzLnRhcmdldERiLndpdGhEaXNhYmxlZEZvcmVpZ25LZXlzKGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IHRoaXMudGFyZ2V0RGIudHJhbnNhY3Rpb24oYXN5bmMgKCkgPT4ge1xuICAgICAgICBhd2FpdCB0aGlzLmRlbGV0ZVRhcmdldFJvd3ModGFyZ2V0Um93c0J5VGFibGVOYW1lKVxuICAgICAgICBhd2FpdCB0aGlzLmluc2VydFRhcmdldFJvd3Moc291cmNlUm93c0J5VGFibGVOYW1lKVxuICAgICAgfSlcbiAgICB9KVxuXG4gICAgcmV0dXJuIHNvdXJjZVJvd3NCeVRhYmxlTmFtZVxuICB9XG5cbiAgLyoqXG4gICAqIERlbGV0ZXMgb25lIHRlbmFudCdzIHJvd3MgZnJvbSB0aGUgdGFyZ2V0IGRhdGFiYXNlLCBjaGlsZHJlbiBiZWZvcmUgcGFyZW50cywgd2l0aFxuICAgKiBmb3JlaWduIGtleXMgZGlzYWJsZWQgaW5zaWRlIGEgc2luZ2xlIHRyYW5zYWN0aW9uLiBUaGlzIGlzIGBjb3B5YCB3aXRob3V0IHRoZSByZWluc2VydDpcbiAgICogdGhlIHNhbWUgcGxhbiB0cmF2ZXJzYWwgc2VsZWN0cyB0aGUgdGVuYW50J3MgY3VycmVudCB0YXJnZXQgcm93cyBhbmQgYGRlbGV0ZVRhcmdldFJvd3NgXG4gICAqIHJlbW92ZXMgdGhlbSBjaGlsZHJlbi1maXJzdCBzbyB0aGUgb3JkZXJpbmcgbmV2ZXIgdHJpcHMgYSBmb3JlaWduIGtleS4gTXVsdGktdGVuYW50IGFwcHNcbiAgICogdXNlIGl0IHRvIHB1cmdlIGEgdGVuYW50IOKAlCBmb3IgZXhhbXBsZSBjbGVhcmluZyB0aGUgdGVuYW50J3MgbWFzdGVyIGNvcHkgaW4gdGhlXG4gICAqIGdsb2JhbC9kZWZhdWx0IGRhdGFiYXNlIG9uIHRlYXJkb3duLCBzbyBmb3JlaWduIGtleXMgc3RvcCByZWZlcmVuY2luZyB0aGUgdGVuYW50J3NcbiAgICogYWJvdXQtdG8tYmUtcmVtb3ZlZCByb290IHJvdy5cbiAgICpcbiAgICogUmV0dXJucyB0aGUgZGVsZXRlZCByb3dzIGtleWVkIGJ5IHRhYmxlIG5hbWUgc28gdGhlIGNhbGxlciBjYW4gcGVyZm9ybSBhbnkgYXBwLXNwZWNpZmljXG4gICAqIHBvc3QtZGVsZXRlIHdvcmsgKHJlY29yZC1sb2NhdGlvbiBjbGVhbnVwLCBhdWRpdGluZykgd2l0aG91dCB0aGF0IHBvbGljeSBsZWFraW5nIGludG8gdGhlXG4gICAqIGZyYW1ld29yay5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleVZhbHVlIC0gVGVuYW50IGtleSB3aG9zZSByb3dzIHNob3VsZCBiZSByZW1vdmVkIGZyb20gdGhlIHRhcmdldC5cbiAgICogQHJldHVybnMge1Byb21pc2U8TWFwPHN0cmluZywgUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXT4+fSAtIFRoZSBkZWxldGVkIHJvd3MgYnkgdGFibGUgbmFtZS5cbiAgICovXG4gIGFzeW5jIGRlbGV0ZVRlbmFudFJvd3Moa2V5VmFsdWUpIHtcbiAgICBjb25zdCByb3dzQnlUYWJsZU5hbWUgPSBhd2FpdCB0aGlzLmxvYWRSb3dzKHRoaXMudGFyZ2V0RGIsIGtleVZhbHVlKVxuXG4gICAgYXdhaXQgdGhpcy50YXJnZXREYi53aXRoRGlzYWJsZWRGb3JlaWduS2V5cyhhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCB0aGlzLnRhcmdldERiLnRyYW5zYWN0aW9uKGFzeW5jICgpID0+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5kZWxldGVUYXJnZXRSb3dzKHJvd3NCeVRhYmxlTmFtZSlcbiAgICAgIH0pXG4gICAgfSlcblxuICAgIHJldHVybiByb3dzQnlUYWJsZU5hbWVcbiAgfVxuXG4gIC8qKlxuICAgKiBMb2FkcyB0aGUgcm93cyBmb3IgYGtleVZhbHVlYCBmb3IgZXZlcnkgdGFibGUgaW4gdGhlIHBsYW4gZnJvbSBgZGJgLCByZXNvbHZpbmdcbiAgICogcGFyZW50LXNjb3BlZCB0YWJsZXMgZnJvbSB0aGUgaWRzIGFscmVhZHkgc2VsZWN0ZWQgZm9yIHRoZWlyIHBhcmVudCB0YWJsZS4gVXNlZCBmb3JcbiAgICogYm90aCB0aGUgc291cmNlIHJvd3MgdG8gY29weSBhbmQgdGhlIHRhcmdldCdzIGN1cnJlbnQgdGVuYW50IHJvd3MgdG8gZGVsZXRlLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2RyaXZlcnMvYmFzZS5qc1wiKS5kZWZhdWx0fSBkYiAtIFNvdXJjZSBvciB0YXJnZXQgZGF0YWJhc2UgdG8gdHJhdmVyc2UuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXlWYWx1ZSAtIFRlbmFudCBrZXkgc2VsZWN0aW5nIHRoZSByb290IHBsYW4gcm93cy5cbiAgICogQHJldHVybnMge1Byb21pc2U8TWFwPHN0cmluZywgUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXT4+fSAtIExvYWRlZCByb3dzIGdyb3VwZWQgYnkgdGFibGUgbmFtZS5cbiAgICovXG4gIGFzeW5jIGxvYWRSb3dzKGRiLCBrZXlWYWx1ZSkge1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy50cmF2ZXJzZVBsYW4oZGIsIGtleVZhbHVlKSkucm93c0J5VGFibGVOYW1lXG4gIH1cblxuICAvKipcbiAgICogTG9hZHMgb25seSB0aGUgaWRzIGZvciBga2V5VmFsdWVgIGZvciBldmVyeSB0YWJsZSBpbiB0aGUgcGxhbiBmcm9tIGBkYmAsIHVzaW5nIHRoZSBzYW1lXG4gICAqIHBhcmVudC9jaGlsZCB0cmF2ZXJzYWwgYXMge0BsaW5rIERhdGFDb3BpZXIjbG9hZFJvd3N9IGJ1dCBzZWxlY3RpbmcganVzdCB0aGUgaWQgY29sdW1uLlxuICAgKiBDYWxsZXJzIHRoYXQgb25seSBuZWVkIHRvIGNvbXBhcmUgcm93IG1lbWJlcnNoaXAg4oCUIGZvciBleGFtcGxlIHZlcmlmeWluZyBhIHRlbmFudCBhbHJlYWR5XG4gICAqIGhvbGRzIGV2ZXJ5IGRlZmF1bHQgcm93IGJlZm9yZSBhIGNsZWFudXAgZGVsZXRlIOKAlCBzaG91bGQgdXNlIHRoaXMgaW5zdGVhZCBvZiBsb2FkUm93cyBzb1xuICAgKiB0aGV5IG5ldmVyIG1hdGVyaWFsaXNlIGZ1bGwgcm93czsgZm9yIGxhcmdlIHRlbmFudHMgdGhhdCBpcyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIGEgZmV3XG4gICAqIGtpbG9ieXRlcyBvZiBpZHMgYW5kIGdpZ2FieXRlcyBvZiByb3cgZGF0YS5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi9kcml2ZXJzL2Jhc2UuanNcIikuZGVmYXVsdH0gZGIgLSBTb3VyY2Ugb3IgdGFyZ2V0IGRhdGFiYXNlIHRvIHRyYXZlcnNlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5VmFsdWUgLSBUZW5hbnQga2V5IHNlbGVjdGluZyB0aGUgcm9vdCBwbGFuIHJvd3MuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPE1hcDxzdHJpbmcsIHN0cmluZ1tdPj59IC0gTG9hZGVkIGlkcyBncm91cGVkIGJ5IHRhYmxlIG5hbWUuXG4gICAqL1xuICBhc3luYyBsb2FkUm93SWRzKGRiLCBrZXlWYWx1ZSkge1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy50cmF2ZXJzZVBsYW4oZGIsIGtleVZhbHVlLCBbdGhpcy5pZENvbHVtbl0pKS5pZHNCeVRhYmxlTmFtZVxuICB9XG5cbiAgLyoqXG4gICAqIFRyYXZlcnNlcyB0aGUgdGFibGUgcGxhbiBmb3IgYGtleVZhbHVlYCwgcXVlcnlpbmcgZWFjaCB0YWJsZSBieSBpdHMgdGVuYW50IGtleSBjb2x1bW4gb3JcbiAgICogKGZvciBjaGlsZCB0YWJsZXMpIGJ5IHRoZSBpZHMgYWxyZWFkeSBzZWxlY3RlZCBmb3IgaXRzIHBhcmVudCwgYW5kIHJldHVybnMgYm90aCB0aGUgaWRzXG4gICAqIGFuZCB0aGUgbG9hZGVkIHJvd3MgZ3JvdXBlZCBieSB0YWJsZSBuYW1lLiBgc2VsZWN0Q29sdW1uc2AgYm91bmRzIHRoZSBjb2x1bW5zIGVhY2ggcXVlcnlcbiAgICogc2VsZWN0czsgcGFzcyBgW2lkQ29sdW1uXWAgZm9yIGFuIGlkLW9ubHkgdHJhdmVyc2FsLCBvciBvbWl0IGl0IHRvIGxvYWQgZnVsbCByb3dzLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2RyaXZlcnMvYmFzZS5qc1wiKS5kZWZhdWx0fSBkYiAtIFNvdXJjZSBvciB0YXJnZXQgZGF0YWJhc2UgdG8gdHJhdmVyc2UuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXlWYWx1ZSAtIFRlbmFudCBrZXkgc2VsZWN0aW5nIHRoZSByb290IHBsYW4gcm93cy5cbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gW3NlbGVjdENvbHVtbnNdIC0gQ29sdW1ucyB0byBzZWxlY3Q7IGRlZmF1bHRzIHRvIGV2ZXJ5IGNvbHVtbi5cbiAgICogQHJldHVybnMge1Byb21pc2U8e2lkc0J5VGFibGVOYW1lOiBNYXA8c3RyaW5nLCBzdHJpbmdbXT4sIHJvd3NCeVRhYmxlTmFtZTogTWFwPHN0cmluZywgUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXT59Pn0gLSBJZHMgYW5kIHJvd3MgZ3JvdXBlZCBieSB0YWJsZSBuYW1lLlxuICAgKi9cbiAgYXN5bmMgdHJhdmVyc2VQbGFuKGRiLCBrZXlWYWx1ZSwgc2VsZWN0Q29sdW1ucykge1xuICAgIC8qKiBAdHlwZSB7TWFwPHN0cmluZywgc3RyaW5nW10+fSAqL1xuICAgIGNvbnN0IGlkc0J5VGFibGVOYW1lID0gbmV3IE1hcCgpXG4gICAgLyoqIEB0eXBlIHtNYXA8c3RyaW5nLCBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdPn0gKi9cbiAgICBjb25zdCByb3dzQnlUYWJsZU5hbWUgPSBuZXcgTWFwKClcblxuICAgIGZvciAoY29uc3QgdGFibGVDb25maWcgb2YgdGhpcy50YWJsZVBsYW4pIHtcbiAgICAgIGxldCByb3dzXG5cbiAgICAgIGlmICh0YWJsZUNvbmZpZy5rZXlDb2x1bW4pIHtcbiAgICAgICAgcm93cyA9IGF3YWl0IHRoaXMucXVlcnlSb3dzQnlDb2x1bW4oe1xuICAgICAgICAgIGNvbHVtbk5hbWU6IHRhYmxlQ29uZmlnLmtleUNvbHVtbixcbiAgICAgICAgICBkYixcbiAgICAgICAgICBzZWxlY3RDb2x1bW5zLFxuICAgICAgICAgIHRhYmxlTmFtZTogdGFibGVDb25maWcudGFibGVOYW1lLFxuICAgICAgICAgIHZhbHVlczogW2tleVZhbHVlXVxuICAgICAgICB9KVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKCF0YWJsZUNvbmZpZy5wYXJlbnRDb2x1bW4gfHwgIXRhYmxlQ29uZmlnLnBhcmVudFRhYmxlTmFtZSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQga2V5Q29sdW1uIG9yIHBhcmVudFRhYmxlTmFtZStwYXJlbnRDb2x1bW4gZm9yIHRhYmxlICR7dGFibGVDb25maWcudGFibGVOYW1lfSBpbiB0aGUgdGVuYW50IHRhYmxlIHBsYW4uYClcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghaWRzQnlUYWJsZU5hbWUuaGFzKHRhYmxlQ29uZmlnLnBhcmVudFRhYmxlTmFtZSkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFRlbmFudCB0YWJsZSBwbGFuIGVudHJ5ICR7dGFibGVDb25maWcudGFibGVOYW1lfSByZWZlcmVuY2VzIHBhcmVudCB0YWJsZSAke3RhYmxlQ29uZmlnLnBhcmVudFRhYmxlTmFtZX0sIHdoaWNoIGhhcyBub3QgYmVlbiBsb2FkZWQ7IHBhcmVudCB0YWJsZXMgbXVzdCBhcHBlYXIgYmVmb3JlIHRoZWlyIGNoaWxkcmVuIGluIHRoZSBwbGFuLmApXG4gICAgICAgIH1cblxuICAgICAgICByb3dzID0gYXdhaXQgdGhpcy5xdWVyeVJvd3NCeUNvbHVtbih7XG4gICAgICAgICAgY29sdW1uTmFtZTogdGFibGVDb25maWcucGFyZW50Q29sdW1uLFxuICAgICAgICAgIGRiLFxuICAgICAgICAgIHNlbGVjdENvbHVtbnMsXG4gICAgICAgICAgdGFibGVOYW1lOiB0YWJsZUNvbmZpZy50YWJsZU5hbWUsXG4gICAgICAgICAgdmFsdWVzOiBpZHNCeVRhYmxlTmFtZS5nZXQodGFibGVDb25maWcucGFyZW50VGFibGVOYW1lKSB8fCBbXVxuICAgICAgICB9KVxuICAgICAgfVxuXG4gICAgICBpZiAocm93cy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHRoaXMucmVwb3J0UHJvZ3Jlc3MoYCR7dGFibGVDb25maWcudGFibGVOYW1lfTogbG9hZGVkICR7cm93cy5sZW5ndGh9IHJvdyhzKWApXG4gICAgICB9XG5cbiAgICAgIGlkc0J5VGFibGVOYW1lLnNldCh0YWJsZUNvbmZpZy50YWJsZU5hbWUsIHVuaXF1ZVN0cmluZ3Mocm93cy5tYXAoKHJvdykgPT4gcm93W3RoaXMuaWRDb2x1bW5dKSkpXG4gICAgICByb3dzQnlUYWJsZU5hbWUuc2V0KHRhYmxlQ29uZmlnLnRhYmxlTmFtZSwgcm93cylcbiAgICB9XG5cbiAgICByZXR1cm4ge2lkc0J5VGFibGVOYW1lLCByb3dzQnlUYWJsZU5hbWV9XG4gIH1cblxuICAvKipcbiAgICogVGhlIHBsYW4gdGFibGVzIHJlZmVyZW5jZWQgYXMgYSBwYXJlbnQgYnkgc29tZSBjaGlsZCBlbnRyeS4gVGhlaXIgaWRzIG11c3QgYmUgcmV0YWluZWRcbiAgICogd2hpbGUgc3RyZWFtaW5nIHNvIHRoZWlyIGNoaWxkcmVuIGNhbiBiZSBzY29wZWQ7IGxlYWYgdGFibGVzIOKAlCB0eXBpY2FsbHkgdGhlIGhpZ2gtdm9sdW1lXG4gICAqIG9uZXMg4oCUIGFyZSBuZXZlciBpbiB0aGlzIHNldCBhbmQgc28gYXJlIG5ldmVyIGFjY3VtdWxhdGVkIGluIG1lbW9yeS5cbiAgICogQHJldHVybnMge1NldDxzdHJpbmc+fSAtIFRhYmxlIG5hbWVzIHRoYXQgYXJlIGEgcGFyZW50IG9mIGFub3RoZXIgcGxhbiBlbnRyeS5cbiAgICovXG4gIHBhcmVudFRhYmxlTmFtZXMoKSB7XG4gICAgLyoqIEB0eXBlIHtTZXQ8c3RyaW5nPn0gKi9cbiAgICBjb25zdCBuYW1lcyA9IG5ldyBTZXQoKVxuXG4gICAgZm9yIChjb25zdCB0YWJsZUNvbmZpZyBvZiB0aGlzLnRhYmxlUGxhbikge1xuICAgICAgaWYgKHRhYmxlQ29uZmlnLnBhcmVudFRhYmxlTmFtZSkge1xuICAgICAgICBuYW1lcy5hZGQodGFibGVDb25maWcucGFyZW50VGFibGVOYW1lKVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBuYW1lc1xuICB9XG5cbiAgLyoqXG4gICAqIFN0cmVhbXMgZXZlcnkgcGxhbiB0YWJsZSdzIHNvdXJjZSByb3dzIHNjb3BlZCB0byBga2V5VmFsdWVgIGluIGJvdW5kZWQgYGJhdGNoU2l6ZWAgYmF0Y2hlcyxcbiAgICogZm9sbG93aW5nIHBhcmVudC9jaGlsZCBjaGFpbmluZy4gRWFjaCB0YWJsZSBpcyByZWFkIHRocm91Z2ggYSByZWFsXG4gICAqIHtAbGluayBpbXBvcnQoXCIuLi9kcml2ZXJzL2Jhc2UuanNcIikuZGVmYXVsdCNxdWVyeVN0cmVhbX0gY3Vyc29yLCBzbyBhIGxhcmdlIHRhYmxlIGlzIG5ldmVyXG4gICAqIGJ1ZmZlcmVkOyBvbmx5IHRoZSBpZHMgb2YgdGFibGVzIHRoYXQgYXJlIHRoZW1zZWx2ZXMgYSBwYXJlbnQgYXJlIHJldGFpbmVkICh0byBzY29wZSB0aGVpclxuICAgKiBjaGlsZHJlbikuIGBzZWxlY3RDb2x1bW5zYCBib3VuZHMgZWFjaCByb3cncyBwcm9qZWN0aW9uIOKAlCBwYXNzIGBbaWRDb2x1bW5dYCBmb3IgYSBsaWdodFxuICAgKiBpZC1vbmx5IHNjYW4sIG9yIG9taXQgaXQgdG8gc3RyZWFtIGZ1bGwgcm93cyDigJQgYW5kIG11c3QgaW5jbHVkZSB0aGUgaWQgY29sdW1uIGZvciBhbnkgdGFibGVcbiAgICogdGhhdCBoYXMgY2hpbGRyZW4uIE1lbW9yeSBzdGF5cyBib3VuZGVkIHRvIG9uZSBiYXRjaCBwbHVzIHRoZSByZXRhaW5lZCBwYXJlbnQtdGFibGUgaWRzLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2RyaXZlcnMvYmFzZS5qc1wiKS5kZWZhdWx0fSBkYiAtIFNvdXJjZSBkYXRhYmFzZSB0byBzdHJlYW0uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXlWYWx1ZSAtIFRlbmFudCBrZXkgc2VsZWN0aW5nIHRoZSByb290IHBsYW4gcm93cy5cbiAgICogQHBhcmFtIHt7YmF0Y2hTaXplOiBudW1iZXIsIHNlbGVjdENvbHVtbnM/OiBzdHJpbmdbXX19IG9wdGlvbnMgLSBCYXRjaCBzaXplIGFuZCBvcHRpb25hbCBwcm9qZWN0aW9uLlxuICAgKiBAeWllbGRzIHt7cm93czogUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXSwgdGFibGVOYW1lOiBzdHJpbmd9fSAtIFN1Y2Nlc3NpdmUgcm93IGJhdGNoZXMgcGVyIHRhYmxlLlxuICAgKi9cbiAgYXN5bmMgKnN0cmVhbVBsYW5Tb3VyY2VCYXRjaGVzKGRiLCBrZXlWYWx1ZSwge2JhdGNoU2l6ZSwgc2VsZWN0Q29sdW1uc30pIHtcbiAgICAvKiogQHR5cGUge01hcDxzdHJpbmcsIHN0cmluZ1tdPn0gKi9cbiAgICBjb25zdCByZXRhaW5lZElkc0J5VGFibGVOYW1lID0gbmV3IE1hcCgpXG4gICAgY29uc3QgcGFyZW50VGFibGVOYW1lcyA9IHRoaXMucGFyZW50VGFibGVOYW1lcygpXG5cbiAgICBmb3IgKGNvbnN0IHRhYmxlQ29uZmlnIG9mIHRoaXMudGFibGVQbGFuKSB7XG4gICAgICAvKiogQHR5cGUge3N0cmluZ30gKi9cbiAgICAgIGxldCBzY29wZUNvbHVtblxuICAgICAgLyoqIEB0eXBlIHtzdHJpbmdbXX0gKi9cbiAgICAgIGxldCBzY29wZVZhbHVlc1xuXG4gICAgICBpZiAodGFibGVDb25maWcua2V5Q29sdW1uKSB7XG4gICAgICAgIHNjb3BlQ29sdW1uID0gdGFibGVDb25maWcua2V5Q29sdW1uXG4gICAgICAgIHNjb3BlVmFsdWVzID0gW2tleVZhbHVlXVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKCF0YWJsZUNvbmZpZy5wYXJlbnRDb2x1bW4gfHwgIXRhYmxlQ29uZmlnLnBhcmVudFRhYmxlTmFtZSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQga2V5Q29sdW1uIG9yIHBhcmVudFRhYmxlTmFtZStwYXJlbnRDb2x1bW4gZm9yIHRhYmxlICR7dGFibGVDb25maWcudGFibGVOYW1lfSBpbiB0aGUgdGVuYW50IHRhYmxlIHBsYW4uYClcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghcmV0YWluZWRJZHNCeVRhYmxlTmFtZS5oYXModGFibGVDb25maWcucGFyZW50VGFibGVOYW1lKSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVGVuYW50IHRhYmxlIHBsYW4gZW50cnkgJHt0YWJsZUNvbmZpZy50YWJsZU5hbWV9IHJlZmVyZW5jZXMgcGFyZW50IHRhYmxlICR7dGFibGVDb25maWcucGFyZW50VGFibGVOYW1lfSwgd2hpY2ggaGFzIG5vdCBiZWVuIHN0cmVhbWVkOyBwYXJlbnQgdGFibGVzIG11c3QgYXBwZWFyIGJlZm9yZSB0aGVpciBjaGlsZHJlbiBpbiB0aGUgcGxhbi5gKVxuICAgICAgICB9XG5cbiAgICAgICAgc2NvcGVDb2x1bW4gPSB0YWJsZUNvbmZpZy5wYXJlbnRDb2x1bW5cbiAgICAgICAgc2NvcGVWYWx1ZXMgPSByZXRhaW5lZElkc0J5VGFibGVOYW1lLmdldCh0YWJsZUNvbmZpZy5wYXJlbnRUYWJsZU5hbWUpIHx8IFtdXG4gICAgICB9XG5cbiAgICAgIC8qKiBAdHlwZSB7c3RyaW5nW10gfCBudWxsfSAqL1xuICAgICAgY29uc3QgcmV0YWluZWRJZHMgPSBwYXJlbnRUYWJsZU5hbWVzLmhhcyh0YWJsZUNvbmZpZy50YWJsZU5hbWUpID8gW10gOiBudWxsXG4gICAgICBjb25zdCBxdW90ZWRUYWJsZSA9IGRiLnF1b3RlVGFibGUodGFibGVDb25maWcudGFibGVOYW1lKVxuICAgICAgY29uc3QgcXVvdGVkU2NvcGUgPSBkYi5xdW90ZUNvbHVtbihzY29wZUNvbHVtbilcbiAgICAgIGNvbnN0IHNlbGVjdExpc3QgPSBzZWxlY3RDb2x1bW5zXG4gICAgICAgID8gc2VsZWN0Q29sdW1ucy5tYXAoKGNvbHVtbikgPT4gYCR7cXVvdGVkVGFibGV9LiR7ZGIucXVvdGVDb2x1bW4oY29sdW1uKX1gKS5qb2luKFwiLCBcIilcbiAgICAgICAgOiBgJHtxdW90ZWRUYWJsZX0uKmBcbiAgICAgIC8qKiBAdHlwZSB7UmVjb3JkPHN0cmluZywgdW5rbm93bj5bXX0gKi9cbiAgICAgIGxldCBiYXRjaCA9IFtdXG5cbiAgICAgIGZvciAoY29uc3Qgc2NvcGVDaHVuayBvZiBjaHVua3ModW5pcXVlU3RyaW5ncyhzY29wZVZhbHVlcyksIHRoaXMucXVlcnlDaHVua1NpemUpKSB7XG4gICAgICAgIGNvbnN0IHNxbCA9IGBTRUxFQ1QgJHtzZWxlY3RMaXN0fSBGUk9NICR7cXVvdGVkVGFibGV9IFdIRVJFICR7cXVvdGVkU2NvcGV9IElOICgke3RoaXMucXVvdGVkVmFsdWVzU3FsKGRiLCBzY29wZUNodW5rKX0pYFxuXG4gICAgICAgIGZvciBhd2FpdCAoY29uc3Qgcm93IG9mIGRiLnF1ZXJ5U3RyZWFtKHNxbCkpIHtcbiAgICAgICAgICBiYXRjaC5wdXNoKHJvdylcblxuICAgICAgICAgIGlmIChyZXRhaW5lZElkcykge1xuICAgICAgICAgICAgcmV0YWluZWRJZHMucHVzaChTdHJpbmcocm93W3RoaXMuaWRDb2x1bW5dKSlcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoYmF0Y2gubGVuZ3RoID49IGJhdGNoU2l6ZSkge1xuICAgICAgICAgICAgeWllbGQge3Jvd3M6IGJhdGNoLCB0YWJsZU5hbWU6IHRhYmxlQ29uZmlnLnRhYmxlTmFtZX1cbiAgICAgICAgICAgIGJhdGNoID0gW11cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGJhdGNoLmxlbmd0aCA+IDApIHtcbiAgICAgICAgeWllbGQge3Jvd3M6IGJhdGNoLCB0YWJsZU5hbWU6IHRhYmxlQ29uZmlnLnRhYmxlTmFtZX1cbiAgICAgIH1cblxuICAgICAgcmV0YWluZWRJZHNCeVRhYmxlTmFtZS5zZXQodGFibGVDb25maWcudGFibGVOYW1lLCByZXRhaW5lZElkcyB8fCBbXSlcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB3aGljaCBvZiBgaWRzYCBjdXJyZW50bHkgZXhpc3QgaW4gYHRhYmxlTmFtZWAgaW4gYGRiYC4gYGlkc2AgaXMgb25lIGFscmVhZHktYm91bmRlZFxuICAgKiBiYXRjaCwgc28gaXQgaXMgcHJvYmVkIHdpdGggYSBzaW5nbGUgYElOICguLi4pYCBsb29rdXAuXG4gICAqIEBwYXJhbSB7e2RiOiBpbXBvcnQoXCIuLi9kcml2ZXJzL2Jhc2UuanNcIikuZGVmYXVsdCwgaWRzOiBzdHJpbmdbXSwgdGFibGVOYW1lOiBzdHJpbmd9fSBhcmdzIC0gRGF0YWJhc2UsIGlkcyB0byBwcm9iZSwgYW5kIHRhYmxlLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxTZXQ8c3RyaW5nPj59IC0gVGhlIHN1YnNldCBvZiBgaWRzYCBwcmVzZW50IGluIHRoZSB0YWJsZS5cbiAgICovXG4gIGFzeW5jIHF1ZXJ5RXhpc3RpbmdJZHMoe2RiLCBpZHMsIHRhYmxlTmFtZX0pIHtcbiAgICBpZiAoaWRzLmxlbmd0aCA8PSAwKSB7XG4gICAgICByZXR1cm4gbmV3IFNldCgpXG4gICAgfVxuXG4gICAgY29uc3QgcXVvdGVkVGFibGUgPSBkYi5xdW90ZVRhYmxlKHRhYmxlTmFtZSlcbiAgICBjb25zdCBxdW90ZWRJZCA9IGRiLnF1b3RlQ29sdW1uKHRoaXMuaWRDb2x1bW4pXG4gICAgY29uc3Qgcm93cyA9IGF3YWl0IHRoaXMuZXhlY3V0ZVF1aWV0UXVlcnkoZGIsIGBTRUxFQ1QgJHtxdW90ZWRUYWJsZX0uJHtxdW90ZWRJZH0gRlJPTSAke3F1b3RlZFRhYmxlfSBXSEVSRSAke3F1b3RlZElkfSBJTiAoJHt0aGlzLnF1b3RlZFZhbHVlc1NxbChkYiwgaWRzKX0pYClcblxuICAgIHJldHVybiBuZXcgU2V0KHJvd3MubWFwKChyb3cpID0+IFN0cmluZyhyb3dbdGhpcy5pZENvbHVtbl0pKSlcbiAgfVxuXG4gIC8qKlxuICAgKiBTdHJlYW1zIHRoZSBzb3VyY2UgaWRzIGZvciBga2V5VmFsdWVgIGFuZCByZXR1cm5zIHRoZSBmaXJzdCB0YWJsZSBmb3VuZCB0byBiZSBtaXNzaW5nIHJvd3MgaW5cbiAgICogdGhlIHRhcmdldCwgd2l0aCB0aGF0IGJhdGNoJ3MgbWlzc2luZyBpZHMg4oCUIHN0b3BwaW5nIGF0IHRoZSBmaXJzdCBzaG9ydGZhbGwgaW5zdGVhZCBvZlxuICAgKiBlbnVtZXJhdGluZyBldmVyeSBtaXNzaW5nIHJvdy4gQ2FsbGVycyB2ZXJpZnlpbmcgYSB0ZW5hbnQgYWxyZWFkeSBob2xkcyBldmVyeSBzb3VyY2Ugcm93IChmb3JcbiAgICogZXhhbXBsZSBiZWZvcmUgZGVsZXRpbmcgdGhlIHNvdXJjZSBjb3BpZXMpIHRyZWF0IGFuIGVtcHR5IHJlc3VsdCBhcyB0aGUgZ28tYWhlYWQgYW5kIGFueSBlbnRyeVxuICAgKiBhcyBhIGhhcmQgc3RvcDsgZmFpbGluZyBmYXN0IGtlZXBzIG1lbW9yeSBib3VuZGVkIHRvIGEgc2luZ2xlIGJhdGNoIGV2ZW4gd2hlbiB0aGUgdGFyZ2V0IGlzXG4gICAqIGZhciBiZWhpbmQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXlWYWx1ZSAtIFRlbmFudCBrZXkgc2VsZWN0aW5nIHRoZSBzb3VyY2Ugcm93cyB0byBjaGVjay5cbiAgICogQHBhcmFtIHt7YmF0Y2hTaXplPzogbnVtYmVyfX0gW29wdGlvbnNdIC0gU3RyZWFtaW5nIGJhdGNoIHNpemUuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPE1hcDxzdHJpbmcsIHN0cmluZ1tdPj59IC0gVGhlIGZpcnN0IHRhYmxlIG1pc3Npbmcgcm93cyBhbmQgdGhhdCBiYXRjaCdzIG1pc3NpbmcgaWRzLCBvciBlbXB0eSB3aGVuIHRoZSB0YXJnZXQgaG9sZHMgZXZlcnl0aGluZy5cbiAgICovXG4gIGFzeW5jIGZpbmRNaXNzaW5nUm93SWRzKGtleVZhbHVlLCB7YmF0Y2hTaXplID0gREVGQVVMVF9TVFJFQU1fQkFUQ0hfU0laRX0gPSB7fSkge1xuICAgIC8qKiBAdHlwZSB7TWFwPHN0cmluZywgc3RyaW5nW10+fSAqL1xuICAgIGNvbnN0IG1pc3NpbmdCeVRhYmxlTmFtZSA9IG5ldyBNYXAoKVxuXG4gICAgZm9yIGF3YWl0IChjb25zdCB7cm93cywgdGFibGVOYW1lfSBvZiB0aGlzLnN0cmVhbVBsYW5Tb3VyY2VCYXRjaGVzKHRoaXMuc291cmNlRGIsIGtleVZhbHVlLCB7YmF0Y2hTaXplLCBzZWxlY3RDb2x1bW5zOiBbdGhpcy5pZENvbHVtbl19KSkge1xuICAgICAgY29uc3QgaWRzID0gcm93cy5tYXAoKHJvdykgPT4gU3RyaW5nKHJvd1t0aGlzLmlkQ29sdW1uXSkpXG4gICAgICBjb25zdCBleGlzdGluZ0lkcyA9IGF3YWl0IHRoaXMucXVlcnlFeGlzdGluZ0lkcyh7ZGI6IHRoaXMudGFyZ2V0RGIsIGlkcywgdGFibGVOYW1lfSlcbiAgICAgIGNvbnN0IG1pc3NpbmdJZHMgPSBpZHMuZmlsdGVyKChpZCkgPT4gIWV4aXN0aW5nSWRzLmhhcyhpZCkpXG5cbiAgICAgIGlmIChtaXNzaW5nSWRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgbWlzc2luZ0J5VGFibGVOYW1lLnNldCh0YWJsZU5hbWUsIG1pc3NpbmdJZHMpXG4gICAgICAgIGJyZWFrXG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIG1pc3NpbmdCeVRhYmxlTmFtZVxuICB9XG5cbiAgLyoqXG4gICAqIFN0cmVhbXMgdGhlIHNvdXJjZSByb3dzIGZvciBga2V5VmFsdWVgIGFuZCBjb3BpZXMgaW50byB0aGUgdGFyZ2V0LCBiYXRjaCBieSBiYXRjaCwgb25seSB0aGVcbiAgICogcm93cyBtaXNzaW5nIHRoZXJlLiBCZWNhdXNlIHRoZSBmdWxsIHJvd3MgdHJhdmVsIGluIHRoZSBzdHJlYW0sIGVhY2ggYmF0Y2gncyBtaXNzaW5nIHJvd3MgYXJlXG4gICAqIGluc2VydGVkIGFzIGl0IGFycml2ZXMg4oCUIG5vdGhpbmcgaXMgYWNjdW11bGF0ZWQsIGFuZCBubyBzZWNvbmQgc291cmNlIHF1ZXJ5IHJ1bnMgd2hpbGUgdGhlXG4gICAqIHNvdXJjZSBjb25uZWN0aW9uIGlzIGhlbGQgYnkgdGhlIHN0cmVhbSDigJQgc28gYSB0YWJsZSB3aXRoIGxhcmdlIGNvbHVtbnMgc3RheXMgYm91bmRlZCB0byBvbmVcbiAgICogYmF0Y2ggZXZlbiB3aGVuIHRoZSB0YXJnZXQgaXMgZW1wdHkuIEludGVuZGVkIGZvciBzaW5nbGUtdGFibGUgcGxhbnMgKG9yIHBsYW5zIHdob3NlIHBlci10YWJsZSxcbiAgICogcGFyZW50LWZpcnN0IGluc2VydCBvcmRlciBpcyBmb3JlaWduLWtleSBzYWZlKS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleVZhbHVlIC0gVGVuYW50IGtleSBzZWxlY3RpbmcgdGhlIHNvdXJjZSByb3dzIHRvIHJlY29uY2lsZS5cbiAgICogQHBhcmFtIHt7YmF0Y2hTaXplPzogbnVtYmVyfX0gW29wdGlvbnNdIC0gU3RyZWFtaW5nIGJhdGNoIHNpemUuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPG51bWJlcj59IC0gVGhlIG51bWJlciBvZiByb3dzIGNvcGllZCBpbnRvIHRoZSB0YXJnZXQuXG4gICAqL1xuICBhc3luYyBjb3B5TWlzc2luZ1Jvd3Moa2V5VmFsdWUsIHtiYXRjaFNpemUgPSBERUZBVUxUX1NUUkVBTV9CQVRDSF9TSVpFfSA9IHt9KSB7XG4gICAgbGV0IGNvcGllZENvdW50ID0gMFxuXG4gICAgZm9yIGF3YWl0IChjb25zdCB7cm93cywgdGFibGVOYW1lfSBvZiB0aGlzLnN0cmVhbVBsYW5Tb3VyY2VCYXRjaGVzKHRoaXMuc291cmNlRGIsIGtleVZhbHVlLCB7YmF0Y2hTaXplfSkpIHtcbiAgICAgIGNvbnN0IGV4aXN0aW5nSWRzID0gYXdhaXQgdGhpcy5xdWVyeUV4aXN0aW5nSWRzKHtkYjogdGhpcy50YXJnZXREYiwgaWRzOiByb3dzLm1hcCgocm93KSA9PiBTdHJpbmcocm93W3RoaXMuaWRDb2x1bW5dKSksIHRhYmxlTmFtZX0pXG4gICAgICBjb25zdCBtaXNzaW5nUm93cyA9IHJvd3MuZmlsdGVyKChyb3cpID0+ICFleGlzdGluZ0lkcy5oYXMoU3RyaW5nKHJvd1t0aGlzLmlkQ29sdW1uXSkpKVxuXG4gICAgICBpZiAobWlzc2luZ1Jvd3MubGVuZ3RoID4gMCkge1xuICAgICAgICBhd2FpdCB0aGlzLmluc2VydFRhcmdldFJvd3MobmV3IE1hcChbW3RhYmxlTmFtZSwgbWlzc2luZ1Jvd3NdXSkpXG4gICAgICAgIGNvcGllZENvdW50ICs9IG1pc3NpbmdSb3dzLmxlbmd0aFxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBjb3BpZWRDb3VudFxuICB9XG5cbiAgLyoqXG4gICAqIFNlbGVjdHMgYHRhYmxlTmFtZWAgcm93cyBpbiBgZGJgIHdob3NlIGBjb2x1bW5OYW1lYCBpcyBpbiBgdmFsdWVzYCwgY2h1bmtlZC4gYHNlbGVjdENvbHVtbnNgXG4gICAqIGJvdW5kcyB0aGUgcHJvamVjdGlvbiBhbmQgZGVmYXVsdHMgdG8gZXZlcnkgY29sdW1uLlxuICAgKiBAcGFyYW0ge3tjb2x1bW5OYW1lOiBzdHJpbmcsIGRiOiBpbXBvcnQoXCIuLi9kcml2ZXJzL2Jhc2UuanNcIikuZGVmYXVsdCwgc2VsZWN0Q29sdW1ucz86IHN0cmluZ1tdLCB0YWJsZU5hbWU6IHN0cmluZywgdmFsdWVzOiBzdHJpbmdbXX19IGFyZ3MgLSBUYWJsZSwgY29sdW1uLCBwcm9qZWN0aW9uLCBkYXRhYmFzZSwgYW5kIHZhbHVlcyBmb3IgdGhlIGNodW5rZWQgbG9va3VwLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdPn0gLSBSb3dzIG1hdGNoaW5nIHRoZSBzdXBwbGllZCBjb2x1bW4gdmFsdWVzLlxuICAgKi9cbiAgYXN5bmMgcXVlcnlSb3dzQnlDb2x1bW4oe2NvbHVtbk5hbWUsIGRiLCBzZWxlY3RDb2x1bW5zLCB0YWJsZU5hbWUsIHZhbHVlc30pIHtcbiAgICBjb25zdCBub3JtYWxpemVkVmFsdWVzID0gdW5pcXVlU3RyaW5ncyh2YWx1ZXMpXG5cbiAgICBpZiAobm9ybWFsaXplZFZhbHVlcy5sZW5ndGggPD0gMCkge1xuICAgICAgcmV0dXJuIFtdXG4gICAgfVxuXG4gICAgY29uc3Qgcm93cyA9IFtdXG4gICAgY29uc3QgcXVvdGVkVGFibGUgPSBkYi5xdW90ZVRhYmxlKHRhYmxlTmFtZSlcbiAgICBjb25zdCBxdW90ZWRDb2x1bW4gPSBkYi5xdW90ZUNvbHVtbihjb2x1bW5OYW1lKVxuICAgIGNvbnN0IHNlbGVjdExpc3QgPSBzZWxlY3RDb2x1bW5zXG4gICAgICA/IHNlbGVjdENvbHVtbnMubWFwKChjb2x1bW4pID0+IGAke3F1b3RlZFRhYmxlfS4ke2RiLnF1b3RlQ29sdW1uKGNvbHVtbil9YCkuam9pbihcIiwgXCIpXG4gICAgICA6IGAke3F1b3RlZFRhYmxlfS4qYFxuXG4gICAgZm9yIChjb25zdCB2YWx1ZXNDaHVuayBvZiBjaHVua3Mobm9ybWFsaXplZFZhbHVlcywgdGhpcy5xdWVyeUNodW5rU2l6ZSkpIHtcbiAgICAgIGNvbnN0IHNxbCA9IGBTRUxFQ1QgJHtzZWxlY3RMaXN0fSBGUk9NICR7cXVvdGVkVGFibGV9IFdIRVJFICR7cXVvdGVkQ29sdW1ufSBJTiAoJHt0aGlzLnF1b3RlZFZhbHVlc1NxbChkYiwgdmFsdWVzQ2h1bmspfSlgXG5cbiAgICAgIHJvd3MucHVzaCguLi5hd2FpdCB0aGlzLmV4ZWN1dGVRdWlldFF1ZXJ5KGRiLCBzcWwpKVxuICAgIH1cblxuICAgIHJldHVybiByb3dzXG4gIH1cblxuICAvKipcbiAgICogRGVsZXRlcyB0aGUgbWF0Y2hpbmcgdGFyZ2V0IHJvd3MgZm9yIGV2ZXJ5IHBsYW4gdGFibGUsIGNoaWxkcmVuIGJlZm9yZSBwYXJlbnRzLCBzbyB0aGVcbiAgICogcmVpbnNlcnQgdGhhdCBmb2xsb3dzIHN0YXJ0cyBmcm9tIGEgY2xlYW4gc2xhdGUgd2l0aG91dCB2aW9sYXRpbmcgZm9yZWlnbiBrZXlzLlxuICAgKiBAcGFyYW0ge01hcDxzdHJpbmcsIFJlY29yZDxzdHJpbmcsIHVua25vd24+W10+fSByb3dzQnlUYWJsZU5hbWUgLSBSb3dzIGdyb3VwZWQgYnkgdGFibGUgbmFtZS5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBkZWxldGVUYXJnZXRSb3dzKHJvd3NCeVRhYmxlTmFtZSkge1xuICAgIGZvciAoY29uc3QgdGFibGVDb25maWcgb2YgWy4uLnRoaXMudGFibGVQbGFuXS5yZXZlcnNlKCkpIHtcbiAgICAgIGNvbnN0IHJvd0lkcyA9IHVuaXF1ZVN0cmluZ3MoKHJvd3NCeVRhYmxlTmFtZS5nZXQodGFibGVDb25maWcudGFibGVOYW1lKSB8fCBbXSkubWFwKChyb3cpID0+IHJvd1t0aGlzLmlkQ29sdW1uXSkpXG5cbiAgICAgIGlmIChyb3dJZHMubGVuZ3RoIDw9IDApIHtcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgY29uc3QgcXVvdGVkVGFibGUgPSB0aGlzLnRhcmdldERiLnF1b3RlVGFibGUodGFibGVDb25maWcudGFibGVOYW1lKVxuICAgICAgY29uc3QgcXVvdGVkSWRDb2x1bW4gPSB0aGlzLnRhcmdldERiLnF1b3RlQ29sdW1uKHRoaXMuaWRDb2x1bW4pXG5cbiAgICAgIGZvciAoY29uc3Qgcm93SWRzQ2h1bmsgb2YgY2h1bmtzKHJvd0lkcywgdGhpcy5xdWVyeUNodW5rU2l6ZSkpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5leGVjdXRlUXVpZXRRdWVyeShcbiAgICAgICAgICB0aGlzLnRhcmdldERiLFxuICAgICAgICAgIGBERUxFVEUgRlJPTSAke3F1b3RlZFRhYmxlfSBXSEVSRSAke3F1b3RlZElkQ29sdW1ufSBJTiAoJHt0aGlzLnF1b3RlZFZhbHVlc1NxbCh0aGlzLnRhcmdldERiLCByb3dJZHNDaHVuayl9KWBcbiAgICAgICAgKVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBJbnNlcnRzIHRoZSBsb2FkZWQgc291cmNlIHJvd3MgaW50byB0aGUgdGFyZ2V0IGZvciBldmVyeSBwbGFuIHRhYmxlLCBwYXJlbnRzIGJlZm9yZVxuICAgKiBjaGlsZHJlbiwgY2h1bmtlZCB0byBib3VuZCBzdGF0ZW1lbnQgc2l6ZS5cbiAgICogQHBhcmFtIHtNYXA8c3RyaW5nLCBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdPn0gcm93c0J5VGFibGVOYW1lIC0gUm93cyBncm91cGVkIGJ5IHRhYmxlIG5hbWUuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgaW5zZXJ0VGFyZ2V0Um93cyhyb3dzQnlUYWJsZU5hbWUpIHtcbiAgICBmb3IgKGNvbnN0IHRhYmxlQ29uZmlnIG9mIHRoaXMudGFibGVQbGFuKSB7XG4gICAgICBjb25zdCByb3dzID0gcm93c0J5VGFibGVOYW1lLmdldCh0YWJsZUNvbmZpZy50YWJsZU5hbWUpIHx8IFtdXG5cbiAgICAgIGlmIChyb3dzLmxlbmd0aCA8PSAwKSB7XG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGNvbHVtbnMgPSBPYmplY3Qua2V5cyhyb3dzWzBdKVxuICAgICAgY29uc3QgaW5zZXJ0Q2h1bmtzID0gY2h1bmtzKHJvd3MsIHRoaXMuaW5zZXJ0Q2h1bmtTaXplKVxuXG4gICAgICB0aGlzLnJlcG9ydFByb2dyZXNzKGAke3RhYmxlQ29uZmlnLnRhYmxlTmFtZX06IGluc2VydGluZyAke3Jvd3MubGVuZ3RofSByb3cocykgaW4gJHtpbnNlcnRDaHVua3MubGVuZ3RofSBjaHVuayhzKWApXG5cbiAgICAgIGZvciAoY29uc3Qgcm93c0NodW5rIG9mIGluc2VydENodW5rcykge1xuICAgICAgICBhd2FpdCB0aGlzLmluc2VydFJvd3NRdWlldGx5KHtcbiAgICAgICAgICBjb2x1bW5zLFxuICAgICAgICAgIGRiOiB0aGlzLnRhcmdldERiLFxuICAgICAgICAgIHJvd3M6IHJvd3NDaHVuay5tYXAoKHJvdykgPT4gY29sdW1ucy5tYXAoKGNvbHVtbikgPT4gcm93W2NvbHVtbl0pKSxcbiAgICAgICAgICB0YWJsZU5hbWU6IHRhYmxlQ29uZmlnLnRhYmxlTmFtZVxuICAgICAgICB9KVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBRdW90ZXMgYW5kIGNvbW1hLWpvaW5zIHZhbHVlcyBmb3IgYW4gU1FMIGBJTiAoLi4uKWAgbGlzdCBhZ2FpbnN0IHRoZSBnaXZlbiBkYXRhYmFzZS5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi9kcml2ZXJzL2Jhc2UuanNcIikuZGVmYXVsdH0gZGIgLSBEYXRhYmFzZSB3aG9zZSBxdW90aW5nIHJ1bGVzIGZvcm1hdCB0aGUgdmFsdWVzLlxuICAgKiBAcGFyYW0ge3N0cmluZ1tdfSB2YWx1ZXMgLSBWYWx1ZXMgdG8gcXVvdGUgZm9yIHRoZSBgSU5gIGxpc3QuXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IC0gUXVvdGVkIFNRTCB2YWx1ZSBsaXN0LlxuICAgKi9cbiAgcXVvdGVkVmFsdWVzU3FsKGRiLCB2YWx1ZXMpIHtcbiAgICByZXR1cm4gdmFsdWVzLm1hcCgodmFsdWUpID0+IGRiLnF1b3RlKHZhbHVlKSkuam9pbihcIiwgXCIpXG4gIH1cblxuICAvKipcbiAgICogUnVucyBhIHF1ZXJ5IHdpdGhvdXQgcGVyLXF1ZXJ5IGxvZ2dpbmcsIHVzZWQgZm9yIHRoZSBoaWdoLXZvbHVtZSBjb3B5IHN0YXRlbWVudHMuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vZHJpdmVycy9iYXNlLmpzXCIpLmRlZmF1bHR9IGRiIC0gRGF0YWJhc2Ugb24gd2hpY2ggdG8gZXhlY3V0ZSB0aGUgY29weSBxdWVyeS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHNxbCAtIENvcHktcmVsYXRlZCBTUUwgc3RhdGVtZW50IHRvIGV4ZWN1dGUgcXVpZXRseS5cbiAgICogQHJldHVybnMge1Byb21pc2U8UmVjb3JkPHN0cmluZywgdW5rbm93bj5bXT59IC0gUXVlcnkgcmVzdWx0IHJvd3MuXG4gICAqL1xuICBhc3luYyBleGVjdXRlUXVpZXRRdWVyeShkYiwgc3FsKSB7XG4gICAgcmV0dXJuIGF3YWl0IGRiLnF1ZXJ5KHNxbCwge2xvZ1F1ZXJ5OiBmYWxzZX0pXG4gIH1cblxuICAvKipcbiAgICogSW5zZXJ0cyBjb2x1bW4tYWxpZ25lZCByb3cgdHVwbGVzIGludG8gYSB0YWJsZSB3aXRob3V0IHBlci1xdWVyeSBsb2dnaW5nLlxuICAgKiBAcGFyYW0ge3tjb2x1bW5zOiBzdHJpbmdbXSwgZGI6IGltcG9ydChcIi4uL2RyaXZlcnMvYmFzZS5qc1wiKS5kZWZhdWx0LCByb3dzOiBBcnJheTxBcnJheTx1bmtub3duPj4sIHRhYmxlTmFtZTogc3RyaW5nfX0gYXJncyAtIERlc3RpbmF0aW9uIHRhYmxlIGFuZCBjb2x1bW4tYWxpZ25lZCByb3cgdmFsdWVzIHRvIGluc2VydC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBpbnNlcnRSb3dzUXVpZXRseSh7Y29sdW1ucywgZGIsIHJvd3MsIHRhYmxlTmFtZX0pIHtcbiAgICBhd2FpdCB0aGlzLmV4ZWN1dGVRdWlldFF1ZXJ5KGRiLCBkYi5pbnNlcnRTcWwoe2NvbHVtbnMsIHRhYmxlTmFtZSwgcm93c30pKVxuICB9XG5cbiAgLyoqXG4gICAqIEZvcndhcmRzIGEgcHJvZ3Jlc3MgbWVzc2FnZSB0byB0aGUgb3B0aW9uYWwgYG9uUHJvZ3Jlc3NgIGNhbGxiYWNrIHdoZW4gb25lIHdhcyBnaXZlbi5cbiAgICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgLSBDb3B5IHByb2dyZXNzIG1lc3NhZ2UgdG8gZm9yd2FyZCB3aGVuIHJlcG9ydGluZyBpcyBlbmFibGVkLlxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIHJlcG9ydFByb2dyZXNzKG1lc3NhZ2UpIHtcbiAgICBpZiAodGhpcy5vblByb2dyZXNzKSB7XG4gICAgICB0aGlzLm9uUHJvZ3Jlc3MobWVzc2FnZSlcbiAgICB9XG4gIH1cbn1cbiJdfQ==
@@ -1 +1 @@
1
- {"root":["../index.js","../bin/velocious.js","../src/application.js","../src/configuration-resolver.js","../src/configuration-types.js","../src/configuration.js","../src/controller.js","../src/current-configuration.js","../src/current.js","../src/error-logger.js","../src/frontend-model-controller.js","../src/initializer.js","../src/logger.js","../src/mailer.js","../src/record-payload-values.js","../src/time-zone.js","../src/velocious-error.js","../src/authorization/ability.js","../src/authorization/base-resource.js","../src/background-jobs/client.js","../src/background-jobs/cron-expression.js","../src/background-jobs/forked-runner-child.js","../src/background-jobs/job-record.js","../src/background-jobs/job-registry.js","../src/background-jobs/job-runner.js","../src/background-jobs/job.js","../src/background-jobs/json-socket.js","../src/background-jobs/main.js","../src/background-jobs/normalize-error.js","../src/background-jobs/pooled-runner-child.js","../src/background-jobs/runner-process-title.js","../src/background-jobs/scheduler.js","../src/background-jobs/socket-request.js","../src/background-jobs/status-reporter.js","../src/background-jobs/store.js","../src/background-jobs/types.js","../src/background-jobs/worker.js","../src/background-jobs/web/authorization.js","../src/background-jobs/web/controller.js","../src/background-jobs/web/index.js","../src/background-jobs/web/path-matcher.js","../src/background-jobs/web/registry.js","../src/beacon/client.js","../src/beacon/in-process-broker.js","../src/beacon/in-process-client.js","../src/beacon/server.js","../src/beacon/types.js","../src/cli/base-command.js","../src/cli/browser-cli.js","../src/cli/index.js","../src/cli/tenant-database-command-helper.js","../src/cli/use-browser-cli.js","../src/cli/commands/background-jobs-main.js","../src/cli/commands/background-jobs-runner.js","../src/cli/commands/background-jobs-worker.js","../src/cli/commands/beacon.js","../src/cli/commands/console.js","../src/cli/commands/init.js","../src/cli/commands/routes.js","../src/cli/commands/run-script.js","../src/cli/commands/runner.js","../src/cli/commands/server.js","../src/cli/commands/test.js","../src/cli/commands/db/base-command.js","../src/cli/commands/db/create.js","../src/cli/commands/db/drop.js","../src/cli/commands/db/migrate.js","../src/cli/commands/db/reset.js","../src/cli/commands/db/rollback.js","../src/cli/commands/db/seed.js","../src/cli/commands/db/schema/dump.js","../src/cli/commands/db/schema/load.js","../src/cli/commands/db/tenants/check.js","../src/cli/commands/db/tenants/create.js","../src/cli/commands/db/tenants/drop.js","../src/cli/commands/db/tenants/migrate.js","../src/cli/commands/destroy/migration.js","../src/cli/commands/generate/base-models.js","../src/cli/commands/generate/frontend-models.js","../src/cli/commands/generate/migration.js","../src/cli/commands/generate/model.js","../src/cli/commands/lint/relationships.js","../src/database/advisory-lock-runner.js","../src/database/annotations-async-hooks.js","../src/database/annotations.js","../src/database/column-types.js","../src/database/datetime-storage.js","../src/database/handler.js","../src/database/initializer-from-require-context.js","../src/database/live-query.js","../src/database/migrations-ledger.js","../src/database/migrator.js","../src/database/record-changes.js","../src/database/use-database.js","../src/database/use-live-query.js","../src/database/drivers/base-column.js","../src/database/drivers/base-columns-index.js","../src/database/drivers/base-foreign-key.js","../src/database/drivers/base-table.js","../src/database/drivers/base.js","../src/database/drivers/mssql/column.js","../src/database/drivers/mssql/columns-index.js","../src/database/drivers/mssql/connect-connection.js","../src/database/drivers/mssql/foreign-key.js","../src/database/drivers/mssql/index.js","../src/database/drivers/mssql/options.js","../src/database/drivers/mssql/query-parser.js","../src/database/drivers/mssql/structure-sql.js","../src/database/drivers/mssql/table.js","../src/database/drivers/mssql/sql/alter-table.js","../src/database/drivers/mssql/sql/create-database.js","../src/database/drivers/mssql/sql/create-index.js","../src/database/drivers/mssql/sql/create-table.js","../src/database/drivers/mssql/sql/delete.js","../src/database/drivers/mssql/sql/drop-database.js","../src/database/drivers/mssql/sql/drop-table.js","../src/database/drivers/mssql/sql/insert.js","../src/database/drivers/mssql/sql/remove-index.js","../src/database/drivers/mssql/sql/update.js","../src/database/drivers/mssql/sql/upsert.js","../src/database/drivers/mysql/column.js","../src/database/drivers/mysql/columns-index.js","../src/database/drivers/mysql/foreign-key.js","../src/database/drivers/mysql/index.js","../src/database/drivers/mysql/options.js","../src/database/drivers/mysql/query-parser.js","../src/database/drivers/mysql/query.js","../src/database/drivers/mysql/structure-sql.js","../src/database/drivers/mysql/table.js","../src/database/drivers/mysql/sql/alter-table.js","../src/database/drivers/mysql/sql/create-database.js","../src/database/drivers/mysql/sql/create-index.js","../src/database/drivers/mysql/sql/create-table.js","../src/database/drivers/mysql/sql/delete.js","../src/database/drivers/mysql/sql/drop-database.js","../src/database/drivers/mysql/sql/drop-table.js","../src/database/drivers/mysql/sql/insert.js","../src/database/drivers/mysql/sql/remove-index.js","../src/database/drivers/mysql/sql/update.js","../src/database/drivers/mysql/sql/upsert.js","../src/database/drivers/pgsql/column.js","../src/database/drivers/pgsql/columns-index.js","../src/database/drivers/pgsql/foreign-key.js","../src/database/drivers/pgsql/index.js","../src/database/drivers/pgsql/options.js","../src/database/drivers/pgsql/query-parser.js","../src/database/drivers/pgsql/structure-sql.js","../src/database/drivers/pgsql/table.js","../src/database/drivers/pgsql/sql/alter-table.js","../src/database/drivers/pgsql/sql/create-database.js","../src/database/drivers/pgsql/sql/create-index.js","../src/database/drivers/pgsql/sql/create-table.js","../src/database/drivers/pgsql/sql/delete.js","../src/database/drivers/pgsql/sql/drop-database.js","../src/database/drivers/pgsql/sql/drop-table.js","../src/database/drivers/pgsql/sql/insert.js","../src/database/drivers/pgsql/sql/remove-index.js","../src/database/drivers/pgsql/sql/update.js","../src/database/drivers/pgsql/sql/upsert.js","../src/database/drivers/sqlite/base.js","../src/database/drivers/sqlite/column.js","../src/database/drivers/sqlite/columns-index.js","../src/database/drivers/sqlite/connection-sql-js.js","../src/database/drivers/sqlite/foreign-key.js","../src/database/drivers/sqlite/index.js","../src/database/drivers/sqlite/index.native.js","../src/database/drivers/sqlite/index.web.js","../src/database/drivers/sqlite/options.js","../src/database/drivers/sqlite/query-parser.js","../src/database/drivers/sqlite/query.js","../src/database/drivers/sqlite/query.native.js","../src/database/drivers/sqlite/query.web.js","../src/database/drivers/sqlite/structure-sql.js","../src/database/drivers/sqlite/table-rebuilder.js","../src/database/drivers/sqlite/table.js","../src/database/drivers/sqlite/web-persistence.js","../src/database/drivers/sqlite/sql/alter-table.js","../src/database/drivers/sqlite/sql/create-index.js","../src/database/drivers/sqlite/sql/create-table.js","../src/database/drivers/sqlite/sql/delete.js","../src/database/drivers/sqlite/sql/drop-table.js","../src/database/drivers/sqlite/sql/insert.js","../src/database/drivers/sqlite/sql/remove-index.js","../src/database/drivers/sqlite/sql/update.js","../src/database/drivers/sqlite/sql/upsert.js","../src/database/drivers/structure-sql/utils.js","../src/database/migration/index.js","../src/database/migrator/files-finder.js","../src/database/migrator/types.js","../src/database/pool/async-tracked-multi-connection.js","../src/database/pool/base-methods-forward.js","../src/database/pool/base.js","../src/database/pool/single-multi-use.js","../src/database/query/alter-table-base.js","../src/database/query/base.js","../src/database/query/create-database-base.js","../src/database/query/create-index-base.js","../src/database/query/create-table-base.js","../src/database/query/delete-base.js","../src/database/query/drop-database-base.js","../src/database/query/drop-table-base.js","../src/database/query/from-base.js","../src/database/query/from-plain.js","../src/database/query/from-table.js","../src/database/query/index.js","../src/database/query/insert-base.js","../src/database/query/join-base.js","../src/database/query/join-object.js","../src/database/query/join-plain.js","../src/database/query/join-tracker.js","../src/database/query/model-class-query.js","../src/database/query/order-base.js","../src/database/query/order-column.js","../src/database/query/order-plain.js","../src/database/query/preloader.js","../src/database/query/query-data.js","../src/database/query/remove-index-base.js","../src/database/query/select-base.js","../src/database/query/select-plain.js","../src/database/query/select-table-and-column.js","../src/database/query/update-base.js","../src/database/query/upsert-base.js","../src/database/query/where-base.js","../src/database/query/where-combinator.js","../src/database/query/where-hash.js","../src/database/query/where-model-class-hash.js","../src/database/query/where-not.js","../src/database/query/where-plain.js","../src/database/query/with-count.js","../src/database/query/preloader/belongs-to.js","../src/database/query/preloader/ensure-model-class-initialized.js","../src/database/query/preloader/has-many.js","../src/database/query/preloader/has-one.js","../src/database/query/preloader/selection.js","../src/database/query-parser/base-query-parser.js","../src/database/query-parser/from-parser.js","../src/database/query-parser/group-parser.js","../src/database/query-parser/joins-parser.js","../src/database/query-parser/limit-parser.js","../src/database/query-parser/options.js","../src/database/query-parser/order-parser.js","../src/database/query-parser/select-parser.js","../src/database/query-parser/where-parser.js","../src/database/record/acts-as-list.js","../src/database/record/auditing.js","../src/database/record/counter-cache-magnitude.js","../src/database/record/index.js","../src/database/record/record-not-found-error.js","../src/database/record/state-machine.js","../src/database/record/user-module.js","../src/database/record/validation-messages.js","../src/database/record/attachments/attachment-record.js","../src/database/record/attachments/download.js","../src/database/record/attachments/handle.js","../src/database/record/attachments/normalize-input.js","../src/database/record/attachments/store.js","../src/database/record/attachments/storage-drivers/filesystem.js","../src/database/record/attachments/storage-drivers/native.js","../src/database/record/attachments/storage-drivers/s3.js","../src/database/record/instance-relationships/base.js","../src/database/record/instance-relationships/belongs-to.js","../src/database/record/instance-relationships/has-many.js","../src/database/record/instance-relationships/has-one.js","../src/database/record/relationships/base.js","../src/database/record/relationships/belongs-to.js","../src/database/record/relationships/has-many.js","../src/database/record/relationships/has-one.js","../src/database/record/validators/base.js","../src/database/record/validators/format.js","../src/database/record/validators/length.js","../src/database/record/validators/presence.js","../src/database/record/validators/uniqueness.js","../src/database/table-data/index.js","../src/database/table-data/table-column.js","../src/database/table-data/table-foreign-key.js","../src/database/table-data/table-index.js","../src/database/table-data/table-reference.js","../src/database/tenants/data-copier.js","../src/database/tenants/schema-cloner.js","../src/database/tenants/tenant-table-plan.js","../src/environment-handlers/base.js","../src/environment-handlers/browser.js","../src/environment-handlers/node.js","../src/environment-handlers/node/cli/commands/background-jobs-main.js","../src/environment-handlers/node/cli/commands/background-jobs-runner.js","../src/environment-handlers/node/cli/commands/background-jobs-worker.js","../src/environment-handlers/node/cli/commands/beacon.js","../src/environment-handlers/node/cli/commands/cli-command-context.js","../src/environment-handlers/node/cli/commands/console.js","../src/environment-handlers/node/cli/commands/init.js","../src/environment-handlers/node/cli/commands/routes.js","../src/environment-handlers/node/cli/commands/run-script.js","../src/environment-handlers/node/cli/commands/runner.js","../src/environment-handlers/node/cli/commands/server.js","../src/environment-handlers/node/cli/commands/test.js","../src/environment-handlers/node/cli/commands/db/seed.js","../src/environment-handlers/node/cli/commands/db/schema/dump.js","../src/environment-handlers/node/cli/commands/db/schema/load.js","../src/environment-handlers/node/cli/commands/destroy/migration.js","../src/environment-handlers/node/cli/commands/generate/base-models.js","../src/environment-handlers/node/cli/commands/generate/frontend-models.js","../src/environment-handlers/node/cli/commands/generate/generated-file-banner.js","../src/environment-handlers/node/cli/commands/generate/migration.js","../src/environment-handlers/node/cli/commands/generate/model.js","../src/environment-handlers/node/cli/commands/lint/relationships.js","../src/error-reporting/request-details.js","../src/frontend-model-resource/base-resource.js","../src/frontend-model-resource/velocious-attachment-resource.js","../src/frontend-models/base.js","../src/frontend-models/built-in-resources.js","../src/frontend-models/clear-pending-debounced-callback.js","../src/frontend-models/event-hook-models.js","../src/frontend-models/model-registry.js","../src/frontend-models/outgoing-event-buffer.js","../src/frontend-models/preloader.js","../src/frontend-models/query.js","../src/frontend-models/resource-config-validation.js","../src/frontend-models/resource-definition.js","../src/frontend-models/transport-serialization.js","../src/frontend-models/use-created-event.js","../src/frontend-models/use-destroyed-event.js","../src/frontend-models/use-model-class-event.js","../src/frontend-models/use-updated-event.js","../src/frontend-models/websocket-channel.js","../src/frontend-models/websocket-publishers.js","../src/http-client/header.js","../src/http-client/index.js","../src/http-client/request.js","../src/http-client/response.js","../src/http-client/websocket-client.js","../src/http-server/cookie.js","../src/http-server/development-reloader.js","../src/http-server/index.js","../src/http-server/remote-address.js","../src/http-server/server-client.js","../src/http-server/server-lock.js","../src/http-server/websocket-channel-subscribers.js","../src/http-server/websocket-channel.js","../src/http-server/websocket-connection.js","../src/http-server/websocket-event-log-store.js","../src/http-server/websocket-events-host.js","../src/http-server/websocket-events.js","../src/http-server/client/index.js","../src/http-server/client/params-to-object.js","../src/http-server/client/request-parser.js","../src/http-server/client/request-runner.js","../src/http-server/client/request-timing.js","../src/http-server/client/request.js","../src/http-server/client/response.js","../src/http-server/client/websocket-request.js","../src/http-server/client/websocket-session.js","../src/http-server/client/request-buffer/form-data-part.js","../src/http-server/client/request-buffer/header.js","../src/http-server/client/request-buffer/index.js","../src/http-server/client/uploaded-file/memory-uploaded-file.js","../src/http-server/client/uploaded-file/temporary-uploaded-file.js","../src/http-server/client/uploaded-file/uploaded-file.js","../src/http-server/worker-handler/channel-subscriber-dispatch.js","../src/http-server/worker-handler/in-process.js","../src/http-server/worker-handler/index.js","../src/http-server/worker-handler/worker-script.js","../src/http-server/worker-handler/worker-thread.js","../src/jobs/mail-delivery.js","../src/jobs/prune-terminal-background-jobs.js","../src/logger/base-logger.js","../src/logger/console-logger.js","../src/logger/file-logger.js","../src/logger/outputs/array-output.js","../src/logger/outputs/console-output.js","../src/logger/outputs/file-output.js","../src/logger/outputs/stdout-output.js","../src/mailer/base.js","../src/mailer/delivery.js","../src/mailer/index.js","../src/mailer/backends/smtp.js","../src/packages/velocious-package.js","../src/plugins/sqljs-wasm-route-controller.js","../src/plugins/sqljs-wasm-route.js","../src/routes/app-routes.js","../src/routes/base-route.js","../src/routes/basic-route.js","../src/routes/get-route.js","../src/routes/index.js","../src/routes/namespace-route.js","../src/routes/plugin-routes.js","../src/routes/post-route.js","../src/routes/resolver.js","../src/routes/resource-route.js","../src/routes/root-route.js","../src/routes/built-in/api-manifest/controller.js","../src/routes/built-in/debug/controller.js","../src/routes/built-in/errors/controller.js","../src/routes/hooks/frontend-model-command-route-hook.js","../src/sync/conflict-strategy.js","../src/sync/device-identity.js","../src/sync/local-mutation-log.js","../src/sync/offline-grant.js","../src/sync/peer-mutation-bundle.js","../src/sync/query-scope.js","../src/sync/server-change-feed.js","../src/sync/server-sequence-allocator.js","../src/sync/stable-json.js","../src/sync/sync-api-client-types.js","../src/sync/sync-api-client.js","../src/sync/sync-api-controller.js","../src/sync/sync-change-fanout.js","../src/sync/sync-channel-name.js","../src/sync/sync-client-registry.js","../src/sync/sync-client-types.js","../src/sync/sync-client.js","../src/sync/sync-envelope-replay-service.js","../src/sync/sync-model-change-feed-service.js","../src/sync/sync-publish-suppression.js","../src/sync/sync-publisher-types.js","../src/sync/sync-publisher.js","../src/sync/sync-realtime-bridge.js","../src/sync/sync-replay-upsert-applier.js","../src/sync/sync-resource-base.js","../src/sync/sync-scope-attributes.js","../src/sync/sync-scope-store.js","../src/sync/sync-websocket-channel.js","../src/tenants/default-tenant-database-provisioning.js","../src/tenants/tenant-aggregator.js","../src/tenants/tenant-iterator.js","../src/tenants/tenant.js","../src/testing/base-expect.js","../src/testing/browser-frontend-model-event-hook-scenarios.js","../src/testing/browser-test-app.js","../src/testing/expect-to-change.js","../src/testing/expect-utils.js","../src/testing/expect.js","../src/testing/request-client.js","../src/testing/test-files-finder.js","../src/testing/test-filter-parser.js","../src/testing/test-runner.js","../src/testing/test-suite-splitter.js","../src/testing/test.js","../src/types/external-modules.d.ts","../src/utils/backtrace-cleaner-node.js","../src/utils/backtrace-cleaner.js","../src/utils/deburr-column-name.js","../src/utils/event-emitter.js","../src/utils/file-exists.js","../src/utils/format-value.js","../src/utils/is-date.js","../src/utils/model-scope.js","../src/utils/nest-callbacks.js","../src/utils/plain-object.js","../src/utils/ransack.js","../src/utils/rest-args-error.js","../src/utils/singularize-model-name.js","../src/utils/split-sql-statements.js","../src/utils/to-import-specifier.js","../src/utils/with-tracked-stack-async-hooks.js","../src/utils/with-tracked-stack.js"],"version":"6.0.3"}
1
+ {"root":["../index.js","../bin/velocious.js","../src/application.js","../src/configuration-resolver.js","../src/configuration-types.js","../src/configuration.js","../src/controller.js","../src/current-configuration.js","../src/current.js","../src/error-logger.js","../src/frontend-model-controller.js","../src/initializer.js","../src/logger.js","../src/mailer.js","../src/record-payload-values.js","../src/time-zone.js","../src/velocious-error.js","../src/authorization/ability.js","../src/authorization/base-resource.js","../src/background-jobs/client.js","../src/background-jobs/cron-expression.js","../src/background-jobs/forked-runner-child.js","../src/background-jobs/job-record.js","../src/background-jobs/job-registry.js","../src/background-jobs/job-runner.js","../src/background-jobs/job.js","../src/background-jobs/json-socket.js","../src/background-jobs/main.js","../src/background-jobs/normalize-error.js","../src/background-jobs/pooled-runner-child.js","../src/background-jobs/runner-process-title.js","../src/background-jobs/scheduler.js","../src/background-jobs/socket-request.js","../src/background-jobs/status-reporter.js","../src/background-jobs/store.js","../src/background-jobs/types.js","../src/background-jobs/worker.js","../src/background-jobs/web/authorization.js","../src/background-jobs/web/controller.js","../src/background-jobs/web/index.js","../src/background-jobs/web/path-matcher.js","../src/background-jobs/web/registry.js","../src/beacon/client.js","../src/beacon/in-process-broker.js","../src/beacon/in-process-client.js","../src/beacon/server.js","../src/beacon/types.js","../src/cli/base-command.js","../src/cli/browser-cli.js","../src/cli/index.js","../src/cli/tenant-database-command-helper.js","../src/cli/use-browser-cli.js","../src/cli/commands/background-jobs-main.js","../src/cli/commands/background-jobs-runner.js","../src/cli/commands/background-jobs-worker.js","../src/cli/commands/beacon.js","../src/cli/commands/console.js","../src/cli/commands/init.js","../src/cli/commands/routes.js","../src/cli/commands/run-script.js","../src/cli/commands/runner.js","../src/cli/commands/server.js","../src/cli/commands/test.js","../src/cli/commands/db/base-command.js","../src/cli/commands/db/create.js","../src/cli/commands/db/drop.js","../src/cli/commands/db/migrate.js","../src/cli/commands/db/reset.js","../src/cli/commands/db/rollback.js","../src/cli/commands/db/seed.js","../src/cli/commands/db/schema/dump.js","../src/cli/commands/db/schema/load.js","../src/cli/commands/db/tenants/check.js","../src/cli/commands/db/tenants/create.js","../src/cli/commands/db/tenants/drop.js","../src/cli/commands/db/tenants/migrate.js","../src/cli/commands/destroy/migration.js","../src/cli/commands/generate/base-models.js","../src/cli/commands/generate/frontend-models.js","../src/cli/commands/generate/migration.js","../src/cli/commands/generate/model.js","../src/cli/commands/lint/relationships.js","../src/database/advisory-lock-runner.js","../src/database/annotations-async-hooks.js","../src/database/annotations.js","../src/database/column-types.js","../src/database/datetime-storage.js","../src/database/handler.js","../src/database/initializer-from-require-context.js","../src/database/live-query.js","../src/database/migrations-ledger.js","../src/database/migrator.js","../src/database/record-changes.js","../src/database/use-database.js","../src/database/use-live-query.js","../src/database/drivers/base-column.js","../src/database/drivers/base-columns-index.js","../src/database/drivers/base-foreign-key.js","../src/database/drivers/base-table.js","../src/database/drivers/base.js","../src/database/drivers/mssql/column.js","../src/database/drivers/mssql/columns-index.js","../src/database/drivers/mssql/connect-connection.js","../src/database/drivers/mssql/foreign-key.js","../src/database/drivers/mssql/index.js","../src/database/drivers/mssql/options.js","../src/database/drivers/mssql/query-parser.js","../src/database/drivers/mssql/structure-sql.js","../src/database/drivers/mssql/table.js","../src/database/drivers/mssql/sql/alter-table.js","../src/database/drivers/mssql/sql/create-database.js","../src/database/drivers/mssql/sql/create-index.js","../src/database/drivers/mssql/sql/create-table.js","../src/database/drivers/mssql/sql/delete.js","../src/database/drivers/mssql/sql/drop-database.js","../src/database/drivers/mssql/sql/drop-table.js","../src/database/drivers/mssql/sql/insert.js","../src/database/drivers/mssql/sql/remove-index.js","../src/database/drivers/mssql/sql/update.js","../src/database/drivers/mssql/sql/upsert.js","../src/database/drivers/mysql/column.js","../src/database/drivers/mysql/columns-index.js","../src/database/drivers/mysql/foreign-key.js","../src/database/drivers/mysql/index.js","../src/database/drivers/mysql/options.js","../src/database/drivers/mysql/query-parser.js","../src/database/drivers/mysql/query-stream.js","../src/database/drivers/mysql/query.js","../src/database/drivers/mysql/structure-sql.js","../src/database/drivers/mysql/table.js","../src/database/drivers/mysql/sql/alter-table.js","../src/database/drivers/mysql/sql/create-database.js","../src/database/drivers/mysql/sql/create-index.js","../src/database/drivers/mysql/sql/create-table.js","../src/database/drivers/mysql/sql/delete.js","../src/database/drivers/mysql/sql/drop-database.js","../src/database/drivers/mysql/sql/drop-table.js","../src/database/drivers/mysql/sql/insert.js","../src/database/drivers/mysql/sql/remove-index.js","../src/database/drivers/mysql/sql/update.js","../src/database/drivers/mysql/sql/upsert.js","../src/database/drivers/pgsql/column.js","../src/database/drivers/pgsql/columns-index.js","../src/database/drivers/pgsql/foreign-key.js","../src/database/drivers/pgsql/index.js","../src/database/drivers/pgsql/options.js","../src/database/drivers/pgsql/query-parser.js","../src/database/drivers/pgsql/structure-sql.js","../src/database/drivers/pgsql/table.js","../src/database/drivers/pgsql/sql/alter-table.js","../src/database/drivers/pgsql/sql/create-database.js","../src/database/drivers/pgsql/sql/create-index.js","../src/database/drivers/pgsql/sql/create-table.js","../src/database/drivers/pgsql/sql/delete.js","../src/database/drivers/pgsql/sql/drop-database.js","../src/database/drivers/pgsql/sql/drop-table.js","../src/database/drivers/pgsql/sql/insert.js","../src/database/drivers/pgsql/sql/remove-index.js","../src/database/drivers/pgsql/sql/update.js","../src/database/drivers/pgsql/sql/upsert.js","../src/database/drivers/sqlite/base.js","../src/database/drivers/sqlite/column.js","../src/database/drivers/sqlite/columns-index.js","../src/database/drivers/sqlite/connection-sql-js.js","../src/database/drivers/sqlite/foreign-key.js","../src/database/drivers/sqlite/index.js","../src/database/drivers/sqlite/index.native.js","../src/database/drivers/sqlite/index.web.js","../src/database/drivers/sqlite/options.js","../src/database/drivers/sqlite/query-parser.js","../src/database/drivers/sqlite/query.js","../src/database/drivers/sqlite/query.native.js","../src/database/drivers/sqlite/query.web.js","../src/database/drivers/sqlite/structure-sql.js","../src/database/drivers/sqlite/table-rebuilder.js","../src/database/drivers/sqlite/table.js","../src/database/drivers/sqlite/web-persistence.js","../src/database/drivers/sqlite/sql/alter-table.js","../src/database/drivers/sqlite/sql/create-index.js","../src/database/drivers/sqlite/sql/create-table.js","../src/database/drivers/sqlite/sql/delete.js","../src/database/drivers/sqlite/sql/drop-table.js","../src/database/drivers/sqlite/sql/insert.js","../src/database/drivers/sqlite/sql/remove-index.js","../src/database/drivers/sqlite/sql/update.js","../src/database/drivers/sqlite/sql/upsert.js","../src/database/drivers/structure-sql/utils.js","../src/database/migration/index.js","../src/database/migrator/files-finder.js","../src/database/migrator/types.js","../src/database/pool/async-tracked-multi-connection.js","../src/database/pool/base-methods-forward.js","../src/database/pool/base.js","../src/database/pool/single-multi-use.js","../src/database/query/alter-table-base.js","../src/database/query/base.js","../src/database/query/create-database-base.js","../src/database/query/create-index-base.js","../src/database/query/create-table-base.js","../src/database/query/delete-base.js","../src/database/query/drop-database-base.js","../src/database/query/drop-table-base.js","../src/database/query/from-base.js","../src/database/query/from-plain.js","../src/database/query/from-table.js","../src/database/query/index.js","../src/database/query/insert-base.js","../src/database/query/join-base.js","../src/database/query/join-object.js","../src/database/query/join-plain.js","../src/database/query/join-tracker.js","../src/database/query/model-class-query.js","../src/database/query/order-base.js","../src/database/query/order-column.js","../src/database/query/order-plain.js","../src/database/query/preloader.js","../src/database/query/query-data.js","../src/database/query/remove-index-base.js","../src/database/query/select-base.js","../src/database/query/select-plain.js","../src/database/query/select-table-and-column.js","../src/database/query/update-base.js","../src/database/query/upsert-base.js","../src/database/query/where-base.js","../src/database/query/where-combinator.js","../src/database/query/where-hash.js","../src/database/query/where-model-class-hash.js","../src/database/query/where-not.js","../src/database/query/where-plain.js","../src/database/query/with-count.js","../src/database/query/preloader/belongs-to.js","../src/database/query/preloader/ensure-model-class-initialized.js","../src/database/query/preloader/has-many.js","../src/database/query/preloader/has-one.js","../src/database/query/preloader/selection.js","../src/database/query-parser/base-query-parser.js","../src/database/query-parser/from-parser.js","../src/database/query-parser/group-parser.js","../src/database/query-parser/joins-parser.js","../src/database/query-parser/limit-parser.js","../src/database/query-parser/options.js","../src/database/query-parser/order-parser.js","../src/database/query-parser/select-parser.js","../src/database/query-parser/where-parser.js","../src/database/record/acts-as-list.js","../src/database/record/auditing.js","../src/database/record/counter-cache-magnitude.js","../src/database/record/index.js","../src/database/record/record-not-found-error.js","../src/database/record/state-machine.js","../src/database/record/user-module.js","../src/database/record/validation-messages.js","../src/database/record/attachments/attachment-record.js","../src/database/record/attachments/download.js","../src/database/record/attachments/handle.js","../src/database/record/attachments/normalize-input.js","../src/database/record/attachments/store.js","../src/database/record/attachments/storage-drivers/filesystem.js","../src/database/record/attachments/storage-drivers/native.js","../src/database/record/attachments/storage-drivers/s3.js","../src/database/record/instance-relationships/base.js","../src/database/record/instance-relationships/belongs-to.js","../src/database/record/instance-relationships/has-many.js","../src/database/record/instance-relationships/has-one.js","../src/database/record/relationships/base.js","../src/database/record/relationships/belongs-to.js","../src/database/record/relationships/has-many.js","../src/database/record/relationships/has-one.js","../src/database/record/validators/base.js","../src/database/record/validators/format.js","../src/database/record/validators/length.js","../src/database/record/validators/presence.js","../src/database/record/validators/uniqueness.js","../src/database/table-data/index.js","../src/database/table-data/table-column.js","../src/database/table-data/table-foreign-key.js","../src/database/table-data/table-index.js","../src/database/table-data/table-reference.js","../src/database/tenants/data-copier.js","../src/database/tenants/schema-cloner.js","../src/database/tenants/tenant-table-plan.js","../src/environment-handlers/base.js","../src/environment-handlers/browser.js","../src/environment-handlers/node.js","../src/environment-handlers/node/cli/commands/background-jobs-main.js","../src/environment-handlers/node/cli/commands/background-jobs-runner.js","../src/environment-handlers/node/cli/commands/background-jobs-worker.js","../src/environment-handlers/node/cli/commands/beacon.js","../src/environment-handlers/node/cli/commands/cli-command-context.js","../src/environment-handlers/node/cli/commands/console.js","../src/environment-handlers/node/cli/commands/init.js","../src/environment-handlers/node/cli/commands/routes.js","../src/environment-handlers/node/cli/commands/run-script.js","../src/environment-handlers/node/cli/commands/runner.js","../src/environment-handlers/node/cli/commands/server.js","../src/environment-handlers/node/cli/commands/test.js","../src/environment-handlers/node/cli/commands/db/seed.js","../src/environment-handlers/node/cli/commands/db/schema/dump.js","../src/environment-handlers/node/cli/commands/db/schema/load.js","../src/environment-handlers/node/cli/commands/destroy/migration.js","../src/environment-handlers/node/cli/commands/generate/base-models.js","../src/environment-handlers/node/cli/commands/generate/frontend-models.js","../src/environment-handlers/node/cli/commands/generate/generated-file-banner.js","../src/environment-handlers/node/cli/commands/generate/migration.js","../src/environment-handlers/node/cli/commands/generate/model.js","../src/environment-handlers/node/cli/commands/lint/relationships.js","../src/error-reporting/request-details.js","../src/frontend-model-resource/base-resource.js","../src/frontend-model-resource/velocious-attachment-resource.js","../src/frontend-models/base.js","../src/frontend-models/built-in-resources.js","../src/frontend-models/clear-pending-debounced-callback.js","../src/frontend-models/event-hook-models.js","../src/frontend-models/model-registry.js","../src/frontend-models/outgoing-event-buffer.js","../src/frontend-models/preloader.js","../src/frontend-models/query.js","../src/frontend-models/resource-config-validation.js","../src/frontend-models/resource-definition.js","../src/frontend-models/transport-serialization.js","../src/frontend-models/use-created-event.js","../src/frontend-models/use-destroyed-event.js","../src/frontend-models/use-model-class-event.js","../src/frontend-models/use-updated-event.js","../src/frontend-models/websocket-channel.js","../src/frontend-models/websocket-publishers.js","../src/http-client/header.js","../src/http-client/index.js","../src/http-client/request.js","../src/http-client/response.js","../src/http-client/websocket-client.js","../src/http-server/cookie.js","../src/http-server/development-reloader.js","../src/http-server/index.js","../src/http-server/remote-address.js","../src/http-server/server-client.js","../src/http-server/server-lock.js","../src/http-server/websocket-channel-subscribers.js","../src/http-server/websocket-channel.js","../src/http-server/websocket-connection.js","../src/http-server/websocket-event-log-store.js","../src/http-server/websocket-events-host.js","../src/http-server/websocket-events.js","../src/http-server/client/index.js","../src/http-server/client/params-to-object.js","../src/http-server/client/request-parser.js","../src/http-server/client/request-runner.js","../src/http-server/client/request-timing.js","../src/http-server/client/request.js","../src/http-server/client/response.js","../src/http-server/client/websocket-request.js","../src/http-server/client/websocket-session.js","../src/http-server/client/request-buffer/form-data-part.js","../src/http-server/client/request-buffer/header.js","../src/http-server/client/request-buffer/index.js","../src/http-server/client/uploaded-file/memory-uploaded-file.js","../src/http-server/client/uploaded-file/temporary-uploaded-file.js","../src/http-server/client/uploaded-file/uploaded-file.js","../src/http-server/worker-handler/channel-subscriber-dispatch.js","../src/http-server/worker-handler/in-process.js","../src/http-server/worker-handler/index.js","../src/http-server/worker-handler/worker-script.js","../src/http-server/worker-handler/worker-thread.js","../src/jobs/mail-delivery.js","../src/jobs/prune-terminal-background-jobs.js","../src/logger/base-logger.js","../src/logger/console-logger.js","../src/logger/file-logger.js","../src/logger/outputs/array-output.js","../src/logger/outputs/console-output.js","../src/logger/outputs/file-output.js","../src/logger/outputs/stdout-output.js","../src/mailer/base.js","../src/mailer/delivery.js","../src/mailer/index.js","../src/mailer/backends/smtp.js","../src/packages/velocious-package.js","../src/plugins/sqljs-wasm-route-controller.js","../src/plugins/sqljs-wasm-route.js","../src/routes/app-routes.js","../src/routes/base-route.js","../src/routes/basic-route.js","../src/routes/get-route.js","../src/routes/index.js","../src/routes/namespace-route.js","../src/routes/plugin-routes.js","../src/routes/post-route.js","../src/routes/resolver.js","../src/routes/resource-route.js","../src/routes/root-route.js","../src/routes/built-in/api-manifest/controller.js","../src/routes/built-in/debug/controller.js","../src/routes/built-in/errors/controller.js","../src/routes/hooks/frontend-model-command-route-hook.js","../src/sync/conflict-strategy.js","../src/sync/device-identity.js","../src/sync/local-mutation-log.js","../src/sync/offline-grant.js","../src/sync/peer-mutation-bundle.js","../src/sync/query-scope.js","../src/sync/server-change-feed.js","../src/sync/server-sequence-allocator.js","../src/sync/stable-json.js","../src/sync/sync-api-client-types.js","../src/sync/sync-api-client.js","../src/sync/sync-api-controller.js","../src/sync/sync-change-fanout.js","../src/sync/sync-channel-name.js","../src/sync/sync-client-registry.js","../src/sync/sync-client-types.js","../src/sync/sync-client.js","../src/sync/sync-envelope-replay-service.js","../src/sync/sync-model-change-feed-service.js","../src/sync/sync-publish-suppression.js","../src/sync/sync-publisher-types.js","../src/sync/sync-publisher.js","../src/sync/sync-realtime-bridge.js","../src/sync/sync-replay-upsert-applier.js","../src/sync/sync-resource-base.js","../src/sync/sync-scope-attributes.js","../src/sync/sync-scope-store.js","../src/sync/sync-websocket-channel.js","../src/tenants/default-tenant-database-provisioning.js","../src/tenants/tenant-aggregator.js","../src/tenants/tenant-iterator.js","../src/tenants/tenant.js","../src/testing/base-expect.js","../src/testing/browser-frontend-model-event-hook-scenarios.js","../src/testing/browser-test-app.js","../src/testing/expect-to-change.js","../src/testing/expect-utils.js","../src/testing/expect.js","../src/testing/request-client.js","../src/testing/test-files-finder.js","../src/testing/test-filter-parser.js","../src/testing/test-runner.js","../src/testing/test-suite-splitter.js","../src/testing/test.js","../src/types/external-modules.d.ts","../src/utils/backtrace-cleaner-node.js","../src/utils/backtrace-cleaner.js","../src/utils/deburr-column-name.js","../src/utils/event-emitter.js","../src/utils/file-exists.js","../src/utils/format-value.js","../src/utils/is-date.js","../src/utils/model-scope.js","../src/utils/nest-callbacks.js","../src/utils/plain-object.js","../src/utils/ransack.js","../src/utils/rest-args-error.js","../src/utils/singularize-model-name.js","../src/utils/split-sql-statements.js","../src/utils/to-import-specifier.js","../src/utils/with-tracked-stack-async-hooks.js","../src/utils/with-tracked-stack.js"],"version":"6.0.3"}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "velocious": "build/bin/velocious.js"
4
4
  },
5
5
  "name": "velocious",
6
- "version": "1.0.535",
6
+ "version": "1.0.537",
7
7
  "main": "build/index.js",
8
8
  "types": "build/index.d.ts",
9
9
  "files": [
@@ -47,6 +47,7 @@
47
47
  * @typedef {object} RetryableDatabaseErrorResult
48
48
  * @property {boolean} retry - Whether the error should be retried.
49
49
  * @property {boolean} reconnect - Whether to reconnect before retrying.
50
+ * @property {boolean} [deadlock] - Whether the error is a transaction deadlock/lock-wait-timeout that should retry the whole transaction.
50
51
  * @property {number} [maxTries] - Override the max retry attempts.
51
52
  * @property {number} [waitMs] - Wait time before retrying in milliseconds.
52
53
  */
@@ -851,11 +852,50 @@ export default class VelociousDatabaseDriversBase {
851
852
  }
852
853
 
853
854
  /**
854
- * Runs transaction.
855
+ * Runs a callback inside a database transaction (or a savepoint when already inside one).
856
+ * The outermost transaction retries the whole callback on a deadlock / lock-wait-timeout,
857
+ * because such errors roll the entire transaction back and the standard recovery is to
858
+ * restart it. Nested savepoints let the deadlock bubble up to this outer retry.
855
859
  * @param {() => Promise<void>} callback - Callback function.
856
- * @returns {Promise<?>} - Resolves with the transaction.
860
+ * @returns {Promise<?>} - Resolves with the transaction result.
857
861
  */
858
862
  async transaction(callback) {
863
+ if (this._transactionsCount > 0) {
864
+ return await this._runTransactionAttempt(callback)
865
+ }
866
+
867
+ const maxAttempts = 5
868
+ let attempt = 0
869
+
870
+ while (true) {
871
+ attempt++
872
+
873
+ try {
874
+ return await this._runTransactionAttempt(callback)
875
+ } catch (error) {
876
+ const retryInfo = error instanceof Error ? this.retryableDatabaseError(error) : {retry: false, reconnect: false}
877
+
878
+ if (retryInfo.deadlock && attempt < maxAttempts && this._transactionsCount == 0) {
879
+ const baseWaitMs = typeof retryInfo.waitMs == "number" && retryInfo.waitMs > 0 ? retryInfo.waitMs : 50
880
+
881
+ this.logger.warn(`Retrying transaction after deadlock (attempt ${attempt}/${maxAttempts})`)
882
+ await wait(baseWaitMs * attempt)
883
+ continue
884
+ }
885
+
886
+ throw error
887
+ }
888
+ }
889
+ }
890
+
891
+ /**
892
+ * Runs a single transaction attempt: starts a transaction (or a savepoint when nested), runs
893
+ * `callback`, and commits — rolling back on error. {@link transaction} wraps this with deadlock
894
+ * retry at the outermost level.
895
+ * @param {() => Promise<void>} callback - Callback function.
896
+ * @returns {Promise<?>} - Resolves with the transaction result.
897
+ */
898
+ async _runTransactionAttempt(callback) {
859
899
  const savePointName = this.generateSavePointName()
860
900
  /**
861
901
  * Callback frame.
@@ -919,7 +959,11 @@ export default class VelociousDatabaseDriversBase {
919
959
  }
920
960
  }
921
961
 
922
- if (transactionStarted && !transactionRolledBack) {
962
+ // Only roll back if a transaction is still open. A nested savepoint whose rollback failed
963
+ // falls back to rolling back the whole transaction (above), which already closed it and
964
+ // dropped the count to 0; rolling back again here would issue a second ROLLBACK and drive
965
+ // `_transactionsCount` below zero, which would then defeat the outermost deadlock-retry guard.
966
+ if (transactionStarted && !transactionRolledBack && this._transactionsCount > 0) {
923
967
  this.logger.debug("Rollback transaction")
924
968
  await this.rollbackTransaction()
925
969
  }
@@ -1014,6 +1058,23 @@ export default class VelociousDatabaseDriversBase {
1014
1058
  }
1015
1059
  }
1016
1060
 
1061
+ /**
1062
+ * Streams the rows of `sql` one at a time instead of buffering the whole result set, so a
1063
+ * caller can process an arbitrarily large result with bounded memory. This base implementation
1064
+ * falls back to a buffered {@link query} and yields its rows; drivers backed by a cursor-capable
1065
+ * client (the MySQL driver) override it with true server-side streaming.
1066
+ * @param {string} sql - SQL string to stream.
1067
+ * @param {QueryOptions} [options] - Query options, as for {@link query}.
1068
+ * @yields {Record<string, unknown>} - The result rows, one at a time.
1069
+ */
1070
+ async *queryStream(sql, options = {}) {
1071
+ const rows = await this.query(sql, options)
1072
+
1073
+ for (const row of Array.isArray(rows) ? rows : []) {
1074
+ yield row
1075
+ }
1076
+ }
1077
+
1017
1078
  /**
1018
1079
  * Runs query.
1019
1080
  * @param {string} sql - SQL string.