UNPKG

@decaf-ts/core

Version:

Core persistence module for the decaf framework

142 lines 18.9 kB
import { Sequence as Seq } from "./model/RamSequence.js"; import { InternalError, NotFoundError } from "@decaf-ts/db-decorators"; import { Sequence } from "./../persistence/index.js"; import { Repository } from "./../repository/index.js"; /** * @description RAM-specific sequence implementation * @summary Extends the base Sequence class to provide auto-incrementing sequence functionality * for the RAM adapter. This class manages sequences stored in memory, allowing for the generation * of sequential identifiers for entities. * @param {SequenceOptions} options - Configuration options for the sequence * @param {RamAdapter} adapter - The RAM adapter instance to use for storage * @class RamSequence * @category Ram * @example * ```typescript * // Create a new numeric sequence starting at 1 * const sequence = new RamSequence({ * name: 'order_sequence', * type: 'Number', * startWith: 1, * incrementBy: 1 * }, ramAdapter); * * // Get the next value in the sequence * const nextId = await sequence.next(); * * // Get a range of values * const idRange = await sequence.range(5); // Returns 5 sequential values * ``` */ export class RamSequence extends Sequence { constructor(options, adapter) { super(options); this.repo = Repository.forModel(Seq, adapter.alias); } /** * @description Retrieves the current value of the sequence * @summary Gets the current value of the sequence from storage. If the sequence * doesn't exist yet, it returns the configured starting value. * @return A promise that resolves to the current sequence value */ async current() { const { name, startWith } = this.options; try { const sequence = await this.repo.read(name); return this.parse(sequence.current); } catch (e) { if (e instanceof NotFoundError) { if (typeof startWith === "undefined") throw new InternalError("Starting value is not defined for a non existing sequence"); try { return this.parse(startWith); } catch (e) { throw new InternalError(`Failed to parse initial value for sequence ${startWith}: ${e}`); } } throw new InternalError(`Failed to retrieve current value for sequence ${name}: ${e}`); } } /** * @description Parses a value according to the sequence type * @summary Converts a value to the appropriate type for the sequence (string, number, or bigint) * using the base Sequence class's parseValue method. * @param {string | number | bigint} value - The value to parse * @return {string | number | bigint} The parsed value in the correct type */ parse(value) { return Sequence.parseValue(this.options.type, value); } /** * @description Increments the sequence value * @summary Increases the current sequence value by the specified amount and persists * the new value to storage. This method handles both numeric and BigInt sequence types. * @param {string | number | bigint} current - The current value of the sequence * @param {number} [count] - Optional amount to increment by, defaults to the sequence's incrementBy value * @return A promise that resolves to the new sequence value after incrementing */ async increment(current, count) { const { type, incrementBy, name } = this.options; let next; const toIncrementBy = count || incrementBy; if (toIncrementBy % incrementBy !== 0) throw new InternalError(`Value to increment does not consider the incrementBy setting: ${incrementBy}`); switch (type) { case "Number": next = this.parse(current) + toIncrementBy; break; case "BigInt": next = this.parse(current) + BigInt(toIncrementBy); break; default: throw new InternalError("Should never happen"); } let seq; const repo = this.repo.override({ ignoredValidationProperties: ["updatedOn"], }); try { seq = await repo.update(new Seq({ id: name, current: next })); } catch (e) { if (!(e instanceof NotFoundError)) { throw e; } seq = await repo.create(new Seq({ id: name, current: next })); } return seq.current; } /** * @description Gets the next value in the sequence * @summary Retrieves the current value of the sequence and increments it by the * configured increment amount. This is the main method used to get a new sequential value. * @return A promise that resolves to the next value in the sequence */ async next() { const current = await this.current(); return this.increment(current); } /** * @description Generates a range of sequential values * @summary Retrieves a specified number of sequential values from the sequence. * This is useful when you need to allocate multiple IDs at once. * The method increments the sequence by the total amount needed and returns all values in the range. * @param {number} count - The number of sequential values to generate * @return A promise that resolves to an array of sequential values */ async range(count) { const current = (await this.current()); const incrementBy = this.parse(this.options.incrementBy); const next = await this.increment(current, this.parse(count) * incrementBy); const range = []; for (let i = 1; i <= count; i++) { range.push(current + incrementBy * this.parse(i)); } if (range[range.length - 1] !== next) throw new InternalError("Miscalculation of range"); return range; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmFtU2VxdWVuY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcmFtL1JhbVNlcXVlbmNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLElBQUksR0FBRyxFQUFFLCtCQUE0QjtBQUN0RCxPQUFPLEVBQUUsYUFBYSxFQUFFLGFBQWEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxRQUFRLEVBQUUsa0NBQXVCO0FBRzFDLE9BQU8sRUFBUSxVQUFVLEVBQUUsaUNBQXNCO0FBRWpEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBeUJHO0FBQ0gsTUFBTSxPQUFPLFdBQVksU0FBUSxRQUFRO0lBR3ZDLFlBQVksT0FBd0IsRUFBRSxPQUFtQjtRQUN2RCxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSSxHQUFHLFVBQVUsQ0FBQyxRQUFRLENBQUMsR0FBRyxFQUFFLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxLQUFLLENBQUMsT0FBTztRQUNYLE1BQU0sRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQztRQUN6QyxJQUFJLENBQUM7WUFDSCxNQUFNLFFBQVEsR0FBUSxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQWMsQ0FBQyxDQUFDO1lBQzNELE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsT0FBMEIsQ0FBQyxDQUFDO1FBQ3pELENBQUM7UUFBQyxPQUFPLENBQU0sRUFBRSxDQUFDO1lBQ2hCLElBQUksQ0FBQyxZQUFZLGFBQWEsRUFBRSxDQUFDO2dCQUMvQixJQUFJLE9BQU8sU0FBUyxLQUFLLFdBQVc7b0JBQ2xDLE1BQU0sSUFBSSxhQUFhLENBQ3JCLDJEQUEyRCxDQUM1RCxDQUFDO2dCQUNKLElBQUksQ0FB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Q25FLE1BQU0sSUFBSSxHQUE2QixNQUFNLElBQUksQ0FBQyxTQUFTLENBQ3pELE9BQU8sRUFDTixJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBWSxHQUFHLFdBQVcsQ0FDNUMsQ0FBQztRQUNGLE1BQU0sS0FBSyxHQUFpQyxFQUFFLENBQUM7UUFDL0MsS0FBSyxJQUFJLENBQUMsR0FBVyxDQUFDLEVBQUUsQ0FBQyxJQUFJLEtBQUssRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQ3hDLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxHQUFHLFdBQVcsR0FBSSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBWSxDQUFDLENBQUM7UUFDaEUsQ0FBQztRQUNELElBQUksS0FBSyxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLEtBQUssSUFBSTtZQUNsQyxNQUFNLElBQUksYUFBYSxDQUFDLHlCQUF5QixDQUFDLENBQUM7UUFDckQsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBTZXF1ZW5jZSBhcyBTZXEgfSBmcm9tIFwiLi9tb2RlbC9SYW1TZXF1ZW5jZVwiO1xuaW1wb3J0IHsgSW50ZXJuYWxFcnJvciwgTm90Rm91bmRFcnJvciB9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgU2VxdWVuY2UgfSBmcm9tIFwiLi4vcGVyc2lzdGVuY2VcIjtcbmltcG9ydCB7IFNlcXVlbmNlT3B0aW9ucyB9IGZyb20gXCIuLi9pbnRlcmZhY2VzXCI7XG5pbXBvcnQgeyBSYW1BZGFwdGVyIH0gZnJvbSBcIi4vUmFtQWRhcHRlclwiO1xuaW1wb3J0IHsgUmVwbywgUmVwb3NpdG9yeSB9IGZyb20gXCIuLi9yZXBvc2l0b3J5XCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFJBTS1zcGVjaWZpYyBzZXF1ZW5jZSBpbXBsZW1lbnRhdGlvblxuICogQHN1bW1hcnkgRXh0ZW5kcyB0aGUgYmFzZSBTZXF1ZW5jZSBjbGFzcyB0byBwcm92aWRlIGF1dG8taW5jcmVtZW50aW5nIHNlcXVlbmNlIGZ1bmN0aW9uYWxpdHlcbiAqIGZvciB0aGUgUkFNIGFkYXB0ZXIuIFRoaXMgY2xhc3MgbWFuYWdlcyBzZXF1ZW5jZXMgc3RvcmVkIGluIG1lbW9yeSwgYWxsb3dpbmcgZm9yIHRoZSBnZW5lcmF0aW9uXG4gKiBvZiBzZXF1ZW50aWFsIGlkZW50aWZpZXJzIGZvciBlbnRpdGllcy5cbiAqIEBwYXJhbSB7U2VxdWVuY2VPcHRpb25zfSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgc2VxdWVuY2VcbiAqIEBwYXJhbSB7UmFtQWRhcHRlcn0gYWRhcHRlciAtIFRoZSBSQU0gYWRhcHRlciBpbnN0YW5jZSB0byB1c2UgZm9yIHN0b3JhZ2VcbiAqIEBjbGFzcyBSYW1TZXF1ZW5jZVxuICogQGNhdGVnb3J5IFJhbVxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIENyZWF0ZSBhIG5ldyBudW1lcmljIHNlcXVlbmNlIHN0YXJ0aW5nIGF0IDFcbiAqIGNvbnN0IHNlcXVlbmNlID0gbmV3IFJhbVNlcXVlbmNlKHtcbiAqICAgbmFtZTogJ29yZGVyX3NlcXVlbmNlJyxcbiAqICAgdHlwZTogJ051bWJlcicsXG4gKiAgIHN0YXJ0V2l0aDogMSxcbiAqICAgaW5jcmVtZW50Qnk6IDFcbiAqIH0sIHJhbUFkYXB0ZXIpO1xuICpcbiAqIC8vIEdldCB0aGUgbmV4dCB2YWx1ZSBpbiB0aGUgc2VxdWVuY2VcbiAqIGNvbnN0IG5leHRJZCA9IGF3YWl0IHNlcXVlbmNlLm5leHQoKTtcbiAqXG4gKiAvLyBHZXQgYSByYW5nZSBvZiB2YWx1ZXNcbiAqIGNvbnN0IGlkUmFuZ2UgPSBhd2FpdCBzZXF1ZW5jZS5yYW5nZSg1KTsgLy8gUmV0dXJucyA1IHNlcXVlbnRpYWwgdmFsdWVzXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNsYXNzIFJhbVNlcXVlbmNlIGV4dGVuZHMgU2VxdWVuY2Uge1xuICBwcm90ZWN0ZWQgcmVwbzogUmVwbzxTZXE+O1xuXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM6IFNlcXVlbmNlT3B0aW9ucywgYWRhcHRlcjogUmFtQWRhcHRlcikge1xuICAgIHN1cGVyKG9wdGlvbnMpO1xuICAgIHRoaXMucmVwbyA9IFJlcG9zaXRvcnkuZm9yTW9kZWwoU2VxLCBhZGFwdGVyLmFsaWFzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmV0cmlldmVzIHRoZSBjdXJyZW50IHZhbHVlIG9mIHRoZSBzZXF1ZW5jZVxuICAgKiBAc3VtbWFyeSBHZXRzIHRoZSBjdXJyZW50IHZhbHVlIG9mIHRoZSBzZXF1ZW5jZSBmcm9tIHN0b3JhZ2UuIElmIHRoZSBzZXF1ZW5jZVxuICAgKiBkb2Vzbid0IGV4aXN0IHlldCwgaXQgcmV0dXJucyB0aGUgY29uZmlndXJlZCBzdGFydGluZyB2YWx1ZS5cbiAgICogQHJldHVybiBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgY3VycmVudCBzZXF1ZW5jZSB2YWx1ZVxuICAgKi9cbiAgYXN5bmMgY3VycmVudCgpOiBQcm9taXNlPHN0cmluZyB8IG51bWJlciB8IGJpZ2ludD4ge1xuICAgIGNvbnN0IHsgbmFtZSwgc3RhcnRXaXRoIH0gPSB0aGlzLm9wdGlvbnM7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHNlcXVlbmNlOiBTZXEgPSBhd2FpdCB0aGlzLnJlcG8ucmVhZChuYW1lIGFzIHN0cmluZyk7XG4gICAgICByZXR1cm4gdGhpcy5wYXJzZShzZXF1ZW5jZS5jdXJyZW50IGFzIHN0cmluZyB8IG51bWJlcik7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICBpZiAoZSBpbnN0YW5jZW9mIE5vdEZvdW5kRXJyb3IpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBzdGFydFdpdGggPT09IFwidW5kZWZpbmVkXCIpXG4gICAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgICAgICBcIlN0YXJ0aW5nIHZhbHVlIGlzIG5vdCBkZWZpbmVkIGZvciBhIG5vbiBleGlzdGluZyBzZXF1ZW5jZVwiXG4gICAgICAgICAgKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICByZXR1cm4gdGhpcy5wYXJzZShzdGFydFdpdGgpO1xuICAgICAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgICAgICAgIGBGYWlsZWQgdG8gcGFyc2UgaW5pdGlhbCB2YWx1ZSBmb3Igc2VxdWVuY2UgJHtzdGFydFdpdGh9OiAke2V9YFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICBgRmFpbGVkIHRvIHJldHJpZXZlIGN1cnJlbnQgdmFsdWUgZm9yIHNlcXVlbmNlICR7bmFtZX06ICR7ZX1gXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUGFyc2VzIGEgdmFsdWUgYWNjb3JkaW5nIHRvIHRoZSBzZXF1ZW5jZSB0eXBlXG4gICAqIEBzdW1tYXJ5IENvbnZlcnRzIGEgdmFsdWUgdG8gdGhlIGFwcHJvcHJpYXRlIHR5cGUgZm9yIHRoZSBzZXF1ZW5jZSAoc3RyaW5nLCBudW1iZXIsIG9yIGJpZ2ludClcbiAgICogdXNpbmcgdGhlIGJhc2UgU2VxdWVuY2UgY2xhc3MncyBwYXJzZVZhbHVlIG1ldGhvZC5cbiAgICogQHBhcmFtIHtzdHJpbmcgfCBudW1iZXIgfCBiaWdpbnR9IHZhbHVlIC0gVGhlIHZhbHVlIHRvIHBhcnNlXG4gICAqIEByZXR1cm4ge3N0cmluZyB8IG51bWJlciB8IGJpZ2ludH0gVGhlIHBhcnNlZCB2YWx1ZSBpbiB0aGUgY29ycmVjdCB0eXBlXG4gICAqL1xuICBwcml2YXRlIHBhcnNlKHZhbHVlOiBzdHJpbmcgfCBudW1iZXIgfCBiaWdpbnQpOiBzdHJpbmcgfCBudW1iZXIgfCBiaWdpbnQge1xuICAgIHJldHVybiBTZXF1ZW5jZS5wYXJzZVZhbHVlKHRoaXMub3B0aW9ucy50eXBlLCB2YWx1ZSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEluY3JlbWVudHMgdGhlIHNlcXVlbmNlIHZhbHVlXG4gICAqIEBzdW1tYXJ5IEluY3JlYXNlcyB0aGUgY3VycmVudCBzZXF1ZW5jZSB2YWx1ZSBieSB0aGUgc3BlY2lmaWVkIGFtb3VudCBhbmQgcGVyc2lzdHNcbiAgICogdGhlIG5ldyB2YWx1ZSB0byBzdG9yYWdlLiBUaGlzIG1ldGhvZCBoYW5kbGVzIGJvdGggbnVtZXJpYyBhbmQgQmlnSW50IHNlcXVlbmNlIHR5cGVzLlxuICAgKiBAcGFyYW0ge3N0cmluZyB8IG51bWJlciB8IGJpZ2ludH0gY3VycmVudCAtIFRoZSBjdXJyZW50IHZhbHVlIG9mIHRoZSBzZXF1ZW5jZVxuICAgKiBAcGFyYW0ge251bWJlcn0gW2NvdW50XSAtIE9wdGlvbmFsIGFtb3VudCB0byBpbmNyZW1lbnQgYnksIGRlZmF1bHRzIHRvIHRoZSBzZXF1ZW5jZSdzIGluY3JlbWVudEJ5IHZhbHVlXG4gICAqIEByZXR1cm4gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIG5ldyBzZXF1ZW5jZSB2YWx1ZSBhZnRlciBpbmNyZW1lbnRpbmdcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgaW5jcmVtZW50KFxuICAgIGN1cnJlbnQ6IHN0cmluZyB8IG51bWJlciB8IGJpZ2ludCxcbiAgICBjb3VudD86IG51bWJlclxuICApOiBQcm9taXNlPHN0cmluZyB8IG51bWJlciB8IGJpZ2ludD4ge1xuICAgIGNvbnN0IHsgdHlwZSwgaW5jcmVtZW50QnksIG5hbWUgfSA9IHRoaXMub3B0aW9ucztcbiAgICBsZXQgbmV4dDogc3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50O1xuICAgIGNvbnN0IHRvSW5jcmVtZW50QnkgPSBjb3VudCB8fCBpbmNyZW1lbnRCeTtcbiAgICBpZiAodG9JbmNyZW1lbnRCeSAlIGluY3JlbWVudEJ5ICE9PSAwKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgIGBWYWx1ZSB0byBpbmNyZW1lbnQgZG9lcyBub3QgY29uc2lkZXIgdGhlIGluY3JlbWVudEJ5IHNldHRpbmc6ICR7aW5jcmVtZW50Qnl9YFxuICAgICAgKTtcbiAgICBzd2l0Y2ggKHR5cGUpIHtcbiAgICAgIGNhc2UgXCJOdW1iZXJcIjpcbiAgICAgICAgbmV4dCA9ICh0aGlzLnBhcnNlKGN1cnJlbnQpIGFzIG51bWJlcikgKyB0b0luY3JlbWVudEJ5O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgXCJCaWdJbnRcIjpcbiAgICAgICAgbmV4dCA9ICh0aGlzLnBhcnNlKGN1cnJlbnQpIGFzIGJpZ2ludCkgKyBCaWdJbnQodG9JbmNyZW1lbnRCeSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJTaG91bGQgbmV2ZXIgaGFwcGVuXCIpO1xuICAgIH1cbiAgICBsZXQgc2VxOiBTZXE7XG4gICAgY29uc3QgcmVwbyA9IHRoaXMucmVwby5vdmVycmlkZSh7XG4gICAgICBpZ25vcmVkVmFsaWRhdGlvblByb3BlcnRpZXM6IFtcInVwZGF0ZWRPblwiXSxcbiAgICB9KTtcbiAgICB0cnkge1xuICAgICAgc2VxID0gYXdhaXQgcmVwby51cGRhdGUobmV3IFNlcSh7IGlkOiBuYW1lLCBjdXJyZW50OiBuZXh0IH0pKTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIGlmICghKGUgaW5zdGFuY2VvZiBOb3RGb3VuZEVycm9yKSkge1xuICAgICAgICB0aHJvdyBlO1xuICAgICAgfVxuICAgICAgc2VxID0gYXdhaXQgcmVwby5jcmVhdGUobmV3IFNlcSh7IGlkOiBuYW1lLCBjdXJyZW50OiBuZXh0IH0pKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc2VxLmN1cnJlbnQgYXMgc3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHZXRzIHRoZSBuZXh0IHZhbHVlIGluIHRoZSBzZXF1ZW5jZVxuICAgKiBAc3VtbWFyeSBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgdmFsdWUgb2YgdGhlIHNlcXVlbmNlIGFuZCBpbmNyZW1lbnRzIGl0IGJ5IHRoZVxuICAgKiBjb25maWd1cmVkIGluY3JlbWVudCBhbW91bnQuIFRoaXMgaXMgdGhlIG1haW4gbWV0aG9kIHVzZWQgdG8gZ2V0IGEgbmV3IHNlcXVlbnRpYWwgdmFsdWUuXG4gICAqIEByZXR1cm4gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIG5leHQgdmFsdWUgaW4gdGhlIHNlcXVlbmNlXG4gICAqL1xuICBhc3luYyBuZXh0KCk6IFByb21pc2U8bnVtYmVyIHwgc3RyaW5nIHwgYmlnaW50PiB7XG4gICAgY29uc3QgY3VycmVudCA9IGF3YWl0IHRoaXMuY3VycmVudCgpO1xuICAgIHJldHVybiB0aGlzLmluY3JlbWVudChjdXJyZW50KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gR2VuZXJhdGVzIGEgcmFuZ2Ugb2Ygc2VxdWVudGlhbCB2YWx1ZXNcbiAgICogQHN1bW1hcnkgUmV0cmlldmVzIGEgc3BlY2lmaWVkIG51bWJlciBvZiBzZXF1ZW50aWFsIHZhbHVlcyBmcm9tIHRoZSBzZXF1ZW5jZS5cbiAgICogVGhpcyBpcyB1c2VmdWwgd2hlbiB5b3UgbmVlZCB0byBhbGxvY2F0ZSBtdWx0aXBsZSBJRHMgYXQgb25jZS5cbiAgICogVGhlIG1ldGhvZCBpbmNyZW1lbnRzIHRoZSBzZXF1ZW5jZSBieSB0aGUgdG90YWwgYW1vdW50IG5lZWRlZCBhbmQgcmV0dXJucyBhbGwgdmFsdWVzIGluIHRoZSByYW5nZS5cbiAgICogQHBhcmFtIHtudW1iZXJ9IGNvdW50IC0gVGhlIG51bWJlciBvZiBzZXF1ZW50aWFsIHZhbHVlcyB0byBnZW5lcmF0ZVxuICAgKiBAcmV0dXJuIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIGFycmF5IG9mIHNlcXVlbnRpYWwgdmFsdWVzXG4gICAqL1xuICBhc3luYyByYW5nZShjb3VudDogbnVtYmVyKTogUHJvbWlzZTwobnVtYmVyIHwgc3RyaW5nIHwgYmlnaW50KVtdPiB7XG4gICAgY29uc3QgY3VycmVudCA9IChhd2FpdCB0aGlzLmN1cnJlbnQoKSkgYXMgbnVtYmVyO1xuICAgIGNvbnN0IGluY3JlbWVudEJ5ID0gdGhpcy5wYXJzZSh0aGlzLm9wdGlvbnMuaW5jcmVtZW50QnkpIGFzIG51bWJlcjtcbiAgICBjb25zdCBuZXh0OiBzdHJpbmcgfCBudW1iZXIgfCBiaWdpbnQgPSBhd2FpdCB0aGlzLmluY3JlbWVudChcbiAgICAgIGN1cnJlbnQsXG4gICAgICAodGhpcy5wYXJzZShjb3VudCkgYXMgbnVtYmVyKSAqIGluY3JlbWVudEJ5XG4gICAgKTtcbiAgICBjb25zdCByYW5nZTogKG51bWJlciB8IHN0cmluZyB8IGJpZ2ludClbXSA9IFtdO1xuICAgIGZvciAobGV0IGk6IG51bWJlciA9IDE7IGkgPD0gY291bnQ7IGkrKykge1xuICAgICAgcmFuZ2UucHVzaChjdXJyZW50ICsgaW5jcmVtZW50QnkgKiAodGhpcy5wYXJzZShpKSBhcyBudW1iZXIpKTtcbiAgICB9XG4gICAgaWYgKHJhbmdlW3JhbmdlLmxlbmd0aCAtIDFdICE9PSBuZXh0KVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJNaXNjYWxjdWxhdGlvbiBvZiByYW5nZVwiKTtcbiAgICByZXR1cm4gcmFuZ2U7XG4gIH1cbn1cblxuIl19