UNPKG

@cute-dw/core

Version:

This TypeScript library is the main part of a more powerfull package designed for the fast WEB software development. The cornerstone of the library is the **DataStore** class, which might be useful when you need a full control of the data, but do not need

275 lines 30.2 kB
import { NullPointerException } from "../util/exception/NullPointerException"; import { IllegalArgumentException } from "../util/exception/IllegalArgumentException"; import { IllegalStateException } from "../util/exception/IllegalStateException"; import { Ciphers } from "../util/Ciphers"; import { ArrayList } from "./ArrayList"; const DEFAULT_HASH_SIZE = 32; const MAX_LIST_SIZE = 8192; // 4096 const MAX_LOCATIONS = 5; /** * **Hash table** (hash map) is a data structure which implements an _associative array_ abstract data type, a structure that can _map keys * to values_. A hash table uses a _hash function_ to compute an index into an array of buckets or slots, * from which the desired value can be found */ export class HashTable { constructor() { this._hashSize = DEFAULT_HASH_SIZE; this._buckets = new ArrayList(); this._keys = new Array(); this._initialize(this._hashSize); } _initialize(hashSize) { this._buckets.clear(); for (let i = 0; i < hashSize; i++) { this._buckets.add(new Array()); } this._keys = []; } _resize() { const oldDic = new ArrayList(); oldDic.appendAll(this._buckets); this._initialize(Math.min(oldDic.size * 4, MAX_LIST_SIZE)); this._buckets.appendAll(oldDic); } /** * @override */ clear() { this._initialize(this._hashSize); } /** * @override */ isEmpty() { return this.size == 0; } /** * @override */ get size() { return this._keys.length; } /** * Returns the value to which the `key` is mapped in this dictionary, or `undefined` if this map contains no mapping for the key * @param key The key whose associated value is to be returned * @returns The value to which the specified key is mapped, or `undefined` if this map contains no mapping for the key */ get(key) { if (key == null) { return undefined; } const aBucket = this._buckets.get(Ciphers.keyHash(String(key), this._buckets.size)); if (aBucket) { for (let pair of aBucket) { if (pair.key === key) { return pair.value; } } } return undefined; } /** * Returns the value to which the `key` is mapped in this dictionary, or `defaultValue` if this map contains no mapping for the key * @param key The key whose associated value is to be returned * @param defaultValue Default value that will be returned if there is no mapping for the `key` * @returns The value to which the specified key is mapped, or `defaultValue` if this map contains no mapping for the key */ getOrDefault(key, defaultValue) { return this.get(key) ?? defaultValue; } /** * Tests if some key maps into the specified value in this hashtable * @param key A key value * @returns _true_ if the map contains the entry with the key `key`, or _false_ otherwise * @see {@link contains} * @see {@link containsKey} */ has(key) { return this.containsKey(key); } /** * Tests if some key maps into the specified value in this hashtable * @param key A key value * @returns _true_ if the map contains the entry with the key `key`, or _false_ otherwise * @see {@link has} * @see {@link containsKey} */ contains(key) { return this.containsKey(key); } /** * @override * @see {@link has} * @see {@link contains} * @see {@link containsValue} */ containsKey(key) { return (this._keys.indexOf(key) >= 0); } /** * @override * @see {@link containsKey} */ containsValue(value) { for (let aBucket of this._buckets) { for (let anEntry of aBucket) { if (anEntry.value === value) { return true; } } } return false; } /** * Returns a `Set` view of the keys contained in this map */ keySet() { let set = new Set(); this._keys.forEach(key => set.add(key)); return set; } /** * Maps the specified key to the specified value in this hashtable * @param key The hashtable key * @param value The value * @returns The previous value of the specified key in this hashtable, or `undefined` if it did not have one * @throws `IllegalArgumentException` if the `key` or `value` is _null_ or _undefined_ * @see {@link set} */ put(key, value) { if (key == null || value == null) { throw new IllegalArgumentException(); } const keyHash = Ciphers.keyHash(String(key), this._buckets.size); const aBucket = this._buckets.get(keyHash); if (!aBucket) { throw new IllegalStateException(); } let count = -1; let index = -1; for (let pair of aBucket) { count++; if (pair.key === key) { index = count; break; } } let oldValue = undefined; if (index == -1) { const pair = { key, value }; index = aBucket.push(pair); this._keys.push(key); } else { oldValue = aBucket[index].value; aBucket[index].value = value; } if (index > MAX_LOCATIONS && this._buckets.size < MAX_LIST_SIZE) { // this bucket is big, grow dict this._resize(); } return oldValue; } /** * Copies all the mappings from the specified source map to this map * @param map Source `Map` object * @throws `NullPointerException` if the `map` is a nullish value * @see {@link put} */ putAll(map) { if (map == null) { throw new NullPointerException(); } map.forEach((value, key) => this.put(key, value)); } /** * Removes the key (and its corresponding value) from this hashtable * @param key The key that needs to be removed * @returns _true_ if the entry with the key `key` was deleted, or _false_ otherwise * @see {@link remove} */ delete(key) { if (key == null) return false; const aBucket = this._buckets.get(Ciphers.keyHash(String(key), this._buckets.size)); if (aBucket) { let index = -1; let keysInd; for (let pair of aBucket) { index++; if (pair.key === key) { aBucket.splice(index, 1); keysInd = this._keys.indexOf(key); if (keysInd >= 0) this._keys.splice(keysInd, 1); return true; } } } return false; } /** * Maps the specified key to the specified value in this hashtable and returns a reference to `this` value. * If a `key` or a `value` equals to _null_ or _undefined_ value operation is ignored. * @param key A key of the key/value pair * @param value A value of the key/value pair * @returns `this` value * @see {@link put} */ set(key, value) { if (!(key == null || value == null)) { this.put(key, value); } return this; } /** * Removes the key (and its corresponding value) from this hashtable * @param key The key that needs to be removed * @returns The value to which the key had been mapped in this hashtable, or `null` if the key did not have a mapping * @throws `IllegalArgumentException` if the `key` is _null_ or _undefined_ */ remove(key) { if (key == null) { throw new IllegalArgumentException(); } const aBucket = this._buckets.get(Ciphers.keyHash(String(key), this._buckets.size)); if (aBucket) { let index = -1; let keysInd; for (let pair of aBucket) { index++; if (pair.key === key) { const oldEntry = aBucket.splice(index, 1)[0]; keysInd = this._keys.indexOf(key); if (keysInd >= 0) this._keys.splice(keysInd, 1); return oldEntry.value; } } } return undefined; } /** * @override */ keys() { return [...this._keys]; } /** * @override */ values() { let arr = new Array(); this._keys.forEach(key => arr.push(this.get(key))); return arr; } /** * Executes a `callBack` function for each entry in this dictionary * @param callBack Function to call * @param thisArg A reference to `this` object */ forEach(callBack, thisArg) { this._keys.forEach(key => callBack(this.get(key), key, this), thisArg); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSGFzaFRhYmxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvY3V0ZS1jb3JlL3NyYy9saWIvY29sbGVjdGlvbnMvSGFzaFRhYmxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLHdDQUF3QyxDQUFDO0FBQzlFLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBQ3RGLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLHlDQUF5QyxDQUFDO0FBQ2hGLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMxQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBSXhDLE1BQU0saUJBQWlCLEdBQUcsRUFBRSxDQUFDO0FBQzdCLE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxDQUFFLE9BQU87QUFDcEMsTUFBTSxhQUFhLEdBQUcsQ0FBQyxDQUFBO0FBRXZCOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sU0FBUztJQUtwQjtRQUpRLGNBQVMsR0FBRyxpQkFBaUIsQ0FBQztRQUM5QixhQUFRLEdBQWlDLElBQUksU0FBUyxFQUFFLENBQUM7UUFDekQsVUFBSyxHQUFHLElBQUksS0FBSyxFQUFLLENBQUM7UUFHN0IsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDbkMsQ0FBQztJQUVPLFdBQVcsQ0FBQyxRQUFnQjtRQUNsQyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ3RCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxRQUFRLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDakMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxLQUFLLEVBQWMsQ0FBQyxDQUFDO1NBQzVDO1FBQ0QsSUFBSSxDQUFDLEtBQUss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QUssQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDO29CQUNqRCxPQUFPLFFBQVEsQ0FBQyxLQUFNLENBQUM7aUJBQ3hCO2FBQ0Y7U0FDRjtRQUNELE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFDRDs7T0FFRztJQUNILElBQUk7UUFDRixPQUFPLENBQUMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUNEOztPQUVHO0lBQ0gsTUFBTTtRQUNKLElBQUksR0FBRyxHQUFHLElBQUksS0FBSyxFQUFLLENBQUM7UUFDekIsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ3BELE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQztJQUNEOzs7O09BSUc7SUFDSCxPQUFPLENBQUMsUUFBdUQsRUFBRSxPQUFhO1FBQzVFLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQSxFQUFFLENBQUEsUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFFLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxFQUFFLE9BQU8sQ0FBRSxDQUFDO0lBQ3pFLENBQUM7Q0FFRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE51bGxQb2ludGVyRXhjZXB0aW9uIH0gZnJvbSBcIi4uL3V0aWwvZXhjZXB0aW9uL051bGxQb2ludGVyRXhjZXB0aW9uXCI7XHJcbmltcG9ydCB7IElsbGVnYWxBcmd1bWVudEV4Y2VwdGlvbiB9IGZyb20gXCIuLi91dGlsL2V4Y2VwdGlvbi9JbGxlZ2FsQXJndW1lbnRFeGNlcHRpb25cIjtcclxuaW1wb3J0IHsgSWxsZWdhbFN0YXRlRXhjZXB0aW9uIH0gZnJvbSBcIi4uL3V0aWwvZXhjZXB0aW9uL0lsbGVnYWxTdGF0ZUV4Y2VwdGlvblwiO1xyXG5pbXBvcnQgeyBDaXBoZXJzIH0gZnJvbSBcIi4uL3V0aWwvQ2lwaGVyc1wiO1xyXG5pbXBvcnQgeyBBcnJheUxpc3QgfSBmcm9tIFwiLi9BcnJheUxpc3RcIjtcclxuaW1wb3J0IHsgRGljdGlvbmFyeX0gZnJvbSBcIi4vRGljdGlvbmFyeVwiO1xyXG5pbXBvcnQgeyBFbnRyeSB9IGZyb20gXCIuL0Fic3RyYWN0TWFwXCI7XHJcblxyXG5jb25zdCBERUZBVUxUX0hBU0hfU0laRSA9IDMyO1xyXG5jb25zdCBNQVhfTElTVF9TSVpFID0gODE5MjsgIC8vIDQwOTZcclxuY29uc3QgTUFYX0xPQ0FUSU9OUyA9IDVcclxuXHJcbi8qKlxyXG4gKiAqKkhhc2ggdGFibGUqKiAoaGFzaCBtYXApIGlzIGEgZGF0YSBzdHJ1Y3R1cmUgd2hpY2ggaW1wbGVtZW50cyBhbiBfYXNzb2NpYXRpdmUgYXJyYXlfIGFic3RyYWN0IGRhdGEgdHlwZSwgYSBzdHJ1Y3R1cmUgdGhhdCBjYW4gX21hcCBrZXlzXHJcbiAqIHRvIHZhbHVlc18uIEEgaGFzaCB0YWJsZSB1c2VzIGEgX2hhc2ggZnVuY3Rpb25fIHRvIGNvbXB1dGUgYW4gaW5kZXggaW50byBhbiBhcnJheSBvZiBidWNrZXRzIG9yIHNsb3RzLFxyXG4gKiBmcm9tIHdoaWNoIHRoZSBkZXNpcmVkIHZhbHVlIGNhbiBiZSBmb3VuZFxyXG4gKi9cclxuZXhwb3J0IGNsYXNzIEhhc2hUYWJsZTxLLFY+IGltcGxlbWVudHMgRGljdGlvbmFyeTxLLFY+IHtcclxuICBwcml2YXRlIF9oYXNoU2l6ZSA9IERFRkFVTFRfSEFTSF9TSVpFO1xyXG4gIHByaXZhdGUgX2J1Y2tldHM6IEFycmF5TGlzdDxBcnJheTxFbnRyeTxLLFY+Pj4gPSBuZXcgQXJyYXlMaXN0KCk7XHJcbiAgcHJpdmF0ZSBfa2V5cyA9IG5ldyBBcnJheTxLPigpO1xyXG5cclxuICBjb25zdHJ1Y3RvcigpIHtcclxuICAgIHRoaXMuX2luaXRpYWxpemUodGhpcy5faGFzaFNpemUpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBfaW5pdGlhbGl6ZShoYXNoU2l6ZTogbnVtYmVyKTogdm9pZCB7XHJcbiAgICB0aGlzLl9idWNrZXRzLmNsZWFyKCk7XHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGhhc2hTaXplOyBpKyspIHtcclxuICAgICAgdGhpcy5fYnVja2V0cy5hZGQobmV3IEFycmF5PEVudHJ5PEssVj4+KCkpO1xyXG4gICAgfVxyXG4gICAgdGhpcy5fa2V5cyA9IFtdO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBfcmVzaXplKCk6IHZvaWQge1xyXG4gICAgY29uc3Qgb2xkRGljID0gbmV3IEFycmF5TGlzdDxBcnJheTxFbnRyeTxLLFY+Pj4oKTtcclxuICAgIG9sZERpYy5hcHBlbmRBbGw8QXJyYXk8RW50cnk8SyxWPj4+KHRoaXMuX2J1Y2tldHMpO1xyXG4gICAgdGhpcy5faW5pdGlhbGl6ZShNYXRoLm1pbihvbGREaWMuc2l6ZSAqIDQsIE1BWF9MSVNUX1NJWkUpKTtcclxuICAgIHRoaXMuX2J1Y2tldHMuYXBwZW5kQWxsPEFycmF5PEVudHJ5PEssVj4+PihvbGREaWMpO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBAb3ZlcnJpZGVcclxuICAgKi9cclxuICBjbGVhcigpOiB2b2lkIHtcclxuICAgIHRoaXMuX2luaXRpYWxpemUodGhpcy5faGFzaFNpemUpO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBAb3ZlcnJpZGVcclxuICAgKi9cclxuICBpc0VtcHR5KCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMuc2l6ZSA9PSAwO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBAb3ZlcnJpZGVcclxuICAgKi9cclxuICBnZXQgc2l6ZSgpOiBudW1iZXIge1xyXG4gICAgcmV0dXJuIHRoaXMuX2tleXMubGVuZ3RoO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBSZXR1cm5zIHRoZSB2YWx1ZSB0byB3aGljaCB0aGUgYGtleWAgaXMgbWFwcGVkIGluIHRoaXMgZGljdGlvbmFyeSwgb3IgYHVuZGVmaW5lZGAgaWYgdGhpcyBtYXAgY29udGFpbnMgbm8gbWFwcGluZyBmb3IgdGhlIGtleVxyXG4gICAqIEBwYXJhbSBrZXkgVGhlIGtleSB3aG9zZSBhc3NvY2lhdGVkIHZhbHVlIGlzIHRvIGJlIHJldHVybmVkXHJcbiAgICogQHJldHVybnMgVGhlIHZhbHVlIHRvIHdoaWNoIHRoZSBzcGVjaWZpZWQga2V5IGlzIG1hcHBlZCwgb3IgYHVuZGVmaW5lZGAgaWYgdGhpcyBtYXAgY29udGFpbnMgbm8gbWFwcGluZyBmb3IgdGhlIGtleVxyXG4gICAqL1xyXG4gICBnZXQoa2V5OiBLKTogViB8IHVuZGVmaW5lZCB7XHJcbiAgICBpZiAoa2V5ID09IG51bGwpIHtcclxuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcclxuICAgIH1cclxuICAgIGNvbnN0IGFCdWNrZXQgPSB0aGlzLl9idWNrZXRzLmdldChDaXBoZXJzLmtleUhhc2goU3RyaW5nKGtleSksIHRoaXMuX2J1Y2tldHMuc2l6ZSkpO1xyXG4gICAgaWYgKGFCdWNrZXQpIHtcclxuICAgICAgZm9yIChsZXQgcGFpciBvZiBhQnVja2V0KSB7XHJcbiAgICAgICAgaWYgKChwYWlyIGFzIEVudHJ5PEssVj4pLmtleSA9PT0ga2V5KSB7XHJcbiAgICAgICAgICByZXR1cm4gKHBhaXIgYXMgRW50cnk8SyxWPikudmFsdWUhO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcclxuICB9XHJcbiAgLyoqXHJcbiAgICogUmV0dXJucyB0aGUgdmFsdWUgdG8gd2hpY2ggdGhlIGBrZXlgIGlzIG1hcHBlZCBpbiB0aGlzIGRpY3Rpb25hcnksIG9yIGBkZWZhdWx0VmFsdWVgIGlmIHRoaXMgbWFwIGNvbnRhaW5zIG5vIG1hcHBpbmcgZm9yIHRoZSBrZXlcclxuICAgKiBAcGFyYW0ga2V5IFRoZSBrZXkgd2hvc2UgYXNzb2NpYXRlZCB2YWx1ZSBpcyB0byBiZSByZXR1cm5lZFxyXG4gICAqIEBwYXJhbSBkZWZhdWx0VmFsdWUgRGVmYXVsdCB2YWx1ZSB0aGF0IHdpbGwgYmUgcmV0dXJuZWQgaWYgdGhlcmUgaXMgbm8gbWFwcGluZyBmb3IgdGhlIGBrZXlgXHJcbiAgICogQHJldHVybnMgVGhlIHZhbHVlIHRvIHdoaWNoIHRoZSBzcGVjaWZpZWQga2V5IGlzIG1hcHBlZCwgb3IgYGRlZmF1bHRWYWx1ZWAgaWYgdGhpcyBtYXAgY29udGFpbnMgbm8gbWFwcGluZyBmb3IgdGhlIGtleVxyXG4gICAqL1xyXG4gIGdldE9yRGVmYXVsdChrZXk6IEssIGRlZmF1bHRWYWx1ZTogVik6IFYge1xyXG4gICAgcmV0dXJuIHRoaXMuZ2V0KGtleSkgPz8gZGVmYXVsdFZhbHVlO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBUZXN0cyBpZiBzb21lIGtleSBtYXBzIGludG8gdGhlIHNwZWNpZmllZCB2YWx1ZSBpbiB0aGlzIGhhc2h0YWJsZVxyXG4gICAqIEBwYXJhbSBrZXkgQSBrZXkgdmFsdWVcclxuICAgKiBAcmV0dXJucyBfdHJ1ZV8gaWYgdGhlIG1hcCBjb250YWlucyB0aGUgZW50cnkgd2l0aCB0aGUga2V5IGBrZXlgLCBvciBfZmFsc2VfIG90aGVyd2lzZVxyXG4gICAqIEBzZWUge0BsaW5rIGNvbnRhaW5zfVxyXG4gICAqIEBzZWUge0BsaW5rIGNvbnRhaW5zS2V5fVxyXG4gICAqL1xyXG4gIGhhcyhrZXk6IEspOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLmNvbnRhaW5zS2V5KGtleSk7XHJcbiAgfVxyXG4gIC8qKlxyXG4gICAqIFRlc3RzIGlmIHNvbWUga2V5IG1hcHMgaW50byB0aGUgc3BlY2lmaWVkIHZhbHVlIGluIHRoaXMgaGFzaHRhYmxlXHJcbiAgICogQHBhcmFtIGtleSBBIGtleSB2YWx1ZVxyXG4gICAqIEByZXR1cm5zIF90cnVlXyBpZiB0aGUgbWFwIGNvbnRhaW5zIHRoZSBlbnRyeSB3aXRoIHRoZSBrZXkgYGtleWAsIG9yIF9mYWxzZV8gb3RoZXJ3aXNlXHJcbiAgICogQHNlZSB7QGxpbmsgaGFzfVxyXG4gICAqIEBzZWUge0BsaW5rIGNvbnRhaW5zS2V5fVxyXG4gICAqL1xyXG4gIGNvbnRhaW5zKGtleTogSyk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMuY29udGFpbnNLZXkoa2V5KTtcclxuICB9XHJcbiAgLyoqXHJcbiAgICogQG92ZXJyaWRlXHJcbiAgICogQHNlZSB7QGxpbmsgaGFzfVxyXG4gICAqIEBzZWUge0BsaW5rIGNvbnRhaW5zfVxyXG4gICAqIEBzZWUge0BsaW5rIGNvbnRhaW5zVmFsdWV9XHJcbiAgICovXHJcbiAgY29udGFpbnNLZXkoa2V5OiBLKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gKHRoaXMuX2tleXMuaW5kZXhPZihrZXkpID49IDApO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBAb3ZlcnJpZGVcclxuICAgKiBAc2VlIHtAbGluayBjb250YWluc0tleX1cclxuICAgKi9cclxuICBjb250YWluc1ZhbHVlKHZhbHVlOiBWKTogYm9vbGVhbiB7XHJcbiAgICBmb3IgKGxldCBhQnVja2V0IG9mIHRoaXMuX2J1Y2tldHMpIHtcclxuICAgICAgZm9yIChsZXQgYW5FbnRyeSBvZiBhQnVja2V0ISkge1xyXG4gICAgICAgIGlmIChhbkVudHJ5LnZhbHVlID09PSB2YWx1ZSkge1xyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG4gIC8qKlxyXG4gICAqIFJldHVybnMgYSBgU2V0YCB2aWV3IG9mIHRoZSBrZXlzIGNvbnRhaW5lZCBpbiB0aGlzIG1hcFxyXG4gICAqL1xyXG4gIGtleVNldCgpOiBTZXQ8Sz4ge1xyXG4gICAgbGV0IHNldDogU2V0PEs+ID0gbmV3IFNldCgpO1xyXG4gICAgdGhpcy5fa2V5cy5mb3JFYWNoKGtleSA9PiBzZXQuYWRkKGtleSkpO1xyXG4gICAgcmV0dXJuIHNldDtcclxuICB9XHJcbiAgLyoqXHJcbiAgICogTWFwcyB0aGUgc3BlY2lmaWVkIGtleSB0byB0aGUgc3BlY2lmaWVkIHZhbHVlIGluIHRoaXMgaGFzaHRhYmxlXHJcbiAgICogQHBhcmFtIGtleSBUaGUgaGFzaHRhYmxlIGtleVxyXG4gICAqIEBwYXJhbSB2YWx1ZSBUaGUgdmFsdWVcclxuICAgKiBAcmV0dXJucyBUaGUgcHJldmlvdXMgdmFsdWUgb2YgdGhlIHNwZWNpZmllZCBrZXkgaW4gdGhpcyBoYXNodGFibGUsIG9yIGB1bmRlZmluZWRgIGlmIGl0IGRpZCBub3QgaGF2ZSBvbmVcclxuICAgKiBAdGhyb3dzIGBJbGxlZ2FsQXJndW1lbnRFeGNlcHRpb25gIGlmIHRoZSBga2V5YCBvciBgdmFsdWVgIGlzIF9udWxsXyBvciBfdW5kZWZpbmVkX1xyXG4gICAqIEBzZWUge0BsaW5rIHNldH1cclxuICAgKi9cclxuICBwdXQoa2V5OiBLLCB2YWx1ZTogVik6IFYgfCB1bmRlZmluZWQge1xyXG5cclxuICAgIGlmIChrZXkgPT0gbnVsbCB8fCB2YWx1ZSA9PSBudWxsKSB7XHJcbiAgICAgIHRocm93IG5ldyBJbGxlZ2FsQXJndW1lbnRFeGNlcHRpb24oKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBrZXlIYXNoID0gQ2lwaGVycy5rZXlIYXNoKFN0cmluZyhrZXkpLCB0aGlzLl9idWNrZXRzLnNpemUpO1xyXG4gICAgY29uc3QgYUJ1Y2tldCA9IHRoaXMuX2J1Y2tldHMuZ2V0KGtleUhhc2gpO1xyXG4gICAgaWYgKCFhQnVja2V0KSB7XHJcbiAgICAgIHRocm93IG5ldyBJbGxlZ2FsU3RhdGVFeGNlcHRpb24oKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgY291bnQgPSAtMTtcclxuICAgIGxldCBpbmRleCA9IC0xO1xyXG4gICAgZm9yIChsZXQgcGFpciBvZiBhQnVja2V0KSB7XHJcbiAgICAgIGNvdW50Kys7XHJcbiAgICAgIGlmIChwYWlyLmtleSA9PT0ga2V5KSB7XHJcbiAgICAgICAgaW5kZXggPSBjb3VudDtcclxuICAgICAgICBicmVhaztcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGxldCBvbGRWYWx1ZTogViB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcclxuXHJcbiAgICBpZiAoaW5kZXggPT0gLTEpIHtcclxuICAgICAgY29uc3QgcGFpcjogRW50cnk8SyxWPiA9IHsga2V5LCB2YWx1ZSB9O1xyXG4gICAgICBpbmRleCA9IGFCdWNrZXQucHVzaChwYWlyKTtcclxuICAgICAgdGhpcy5fa2V5cy5wdXNoKGtleSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBvbGRWYWx1ZSA9IGFCdWNrZXRbaW5kZXhdLnZhbHVlITtcclxuICAgICAgYUJ1Y2tldFtpbmRleF0udmFsdWUgPSB2YWx1ZTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoaW5kZXggPiBNQVhfTE9DQVRJT05TICYmIHRoaXMuX2J1Y2tldHMuc2l6ZSA8IE1BWF9MSVNUX1NJWkUpIHtcclxuICAgICAgLy8gdGhpcyBidWNrZXQgaXMgYmlnLCBncm93IGRpY3RcclxuICAgICAgdGhpcy5fcmVzaXplKCk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIG9sZFZhbHVlO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBDb3BpZXMgYWxsIHRoZSBtYXBwaW5ncyBmcm9tIHRoZSBzcGVjaWZpZWQgc291cmNlIG1hcCB0byB0aGlzIG1hcFxyXG4gICAqIEBwYXJhbSBtYXAgU291cmNlIGBNYXBgIG9iamVjdFxyXG4gICAqIEB0aHJvd3MgYE51bGxQb2ludGVyRXhjZXB0aW9uYCBpZiB0aGUgYG1hcGAgaXMgYSBudWxsaXNoIHZhbHVlXHJcbiAgICogQHNlZSB7QGxpbmsgcHV0fVxyXG4gICAqL1xyXG4gIHB1dEFsbChtYXA6IE1hcDxLLFY+fEhhc2hUYWJsZTxLLFY+KTogdm9pZCB7XHJcbiAgICBpZiAobWFwID09IG51bGwpIHtcclxuICAgICAgdGhyb3cgbmV3IE51bGxQb2ludGVyRXhjZXB0aW9uKCk7XHJcbiAgICB9XHJcbiAgICBtYXAuZm9yRWFjaCgodmFsdWUsIGtleSk9PnRoaXMucHV0KGtleSwgdmFsdWUpKTtcclxuICB9XHJcbiAgLyoqXHJcbiAgICogUmVtb3ZlcyB0aGUga2V5IChhbmQgaXRzIGNvcnJlc3BvbmRpbmcgdmFsdWUpIGZyb20gdGhpcyBoYXNodGFibGVcclxuICAgKiBAcGFyYW0ga2V5IFRoZSBrZXkgdGhhdCBuZWVkcyB0byBiZSByZW1vdmVkXHJcbiAgICogQHJldHVybnMgX3RydWVfIGlmIHRoZSBlbnRyeSB3aXRoIHRoZSBrZXkgYGtleWAgd2FzIGRlbGV0ZWQsIG9yIF9mYWxzZV8gb3RoZXJ3aXNlXHJcbiAgICogQHNlZSB7QGxpbmsgcmVtb3ZlfVxyXG4gICAqL1xyXG4gIGRlbGV0ZShrZXk6IEspOiBib29sZWFuIHtcclxuICAgIGlmIChrZXkgPT0gbnVsbCkgcmV0dXJuIGZhbHNlO1xyXG4gICAgY29uc3QgYUJ1Y2tldCA9IHRoaXMuX2J1Y2tldHMuZ2V0KENpcGhlcnMua2V5SGFzaCggU3RyaW5nKGtleSksIHRoaXMuX2J1Y2tldHMuc2l6ZSkpO1xyXG4gICAgaWYgKGFCdWNrZXQpIHtcclxuICAgICAgbGV0IGluZGV4ID0gLTE7XHJcbiAgICAgIGxldCBrZXlzSW5kO1xyXG4gICAgICBmb3IgKGxldCBwYWlyIG9mIGFCdWNrZXQpIHtcclxuICAgICAgICBpbmRleCsrO1xyXG4gICAgICAgIGlmIChwYWlyLmtleSA9PT0ga2V5KSB7XHJcbiAgICAgICAgICBhQnVja2V0LnNwbGljZShpbmRleCwgMSk7XHJcbiAgICAgICAgICBrZXlzSW5kID0gdGhpcy5fa2V5cy5pbmRleE9mKGtleSk7XHJcbiAgICAgICAgICBpZiAoa2V5c0luZCA+PSAwICkgdGhpcy5fa2V5cy5zcGxpY2Uoa2V5c0luZCwgMSk7XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiBmYWxzZVxyXG4gIH1cclxuICAvKipcclxuICAgKiBNYXBzIHRoZSBzcGVjaWZpZWQga2V5IHRvIHRoZSBzcGVjaWZpZWQgdmFsdWUgaW4gdGhpcyBoYXNodGFibGUgYW5kIHJldHVybnMgYSByZWZlcmVuY2UgdG8gYHRoaXNgIHZhbHVlLlxyXG4gICAqIElmIGEgYGtleWAgb3IgYSBgdmFsdWVgIGVxdWFscyB0byBfbnVsbF8gb3IgX3VuZGVmaW5lZF8gdmFsdWUgb3BlcmF0aW9uIGlzIGlnbm9yZWQuXHJcbiAgICogQHBhcmFtIGtleSBBIGtleSBvZiB0aGUga2V5L3ZhbHVlIHBhaXJcclxuICAgKiBAcGFyYW0gdmFsdWUgQSB2YWx1ZSBvZiB0aGUga2V5L3ZhbHVlIHBhaXJcclxuICAgKiBAcmV0dXJucyBgdGhpc2AgdmFsdWVcclxuICAgKiBAc2VlIHtAbGluayBwdXR9XHJcbiAgICovXHJcbiAgc2V0KGtleTpLLCB2YWx1ZTpWKTogdGhpcyB7XHJcbiAgICBpZiAoIShrZXkgPT0gbnVsbCB8fCB2YWx1ZSA9PSBudWxsKSkge1xyXG4gICAgICB0aGlzLnB1dChrZXksIHZhbHVlKTtcclxuICAgIH1cclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBSZW1vdmVzIHRoZSBrZXkgKGFuZCBpdHMgY29ycmVzcG9uZGluZyB2YWx1ZSkgZnJvbSB0aGlzIGhhc2h0YWJsZVxyXG4gICAqIEBwYXJhbSBrZXkgVGhlIGtleSB0aGF0IG5lZWRzIHRvIGJlIHJlbW92ZWRcclxuICAgKiBAcmV0dXJucyBUaGUgdmFsdWUgdG8gd2hpY2ggdGhlIGtleSBoYWQgYmVlbiBtYXBwZWQgaW4gdGhpcyBoYXNodGFibGUsIG9yIGBudWxsYCBpZiB0aGUga2V5IGRpZCBub3QgaGF2ZSBhIG1hcHBpbmdcclxuICAgKiBAdGhyb3dzIGBJbGxlZ2FsQXJndW1lbnRFeGNlcHRpb25gIGlmIHRoZSBga2V5YCBpcyBfbnVsbF8gb3IgX3VuZGVmaW5lZF9cclxuICAgKi9cclxuICByZW1vdmUoa2V5OiBLKTogViB8IHVuZGVmaW5lZCB7XHJcbiAgICBpZiAoa2V5ID09IG51bGwpIHtcclxuICAgICAgdGhyb3cgbmV3IElsbGVnYWxBcmd1bWVudEV4Y2VwdGlvbigpO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGFCdWNrZXQgPSB0aGlzLl9idWNrZXRzLmdldChDaXBoZXJzLmtleUhhc2goIFN0cmluZyhrZXkpLCB0aGlzLl9idWNrZXRzLnNpemUpKTtcclxuICAgIGlmIChhQnVja2V0KSB7XHJcbiAgICAgIGxldCBpbmRleCA9IC0xO1xyXG4gICAgICBsZXQga2V5c0luZDtcclxuICAgICAgZm9yIChsZXQgcGFpciBvZiBhQnVja2V0KSB7XHJcbiAgICAgICAgaW5kZXgrKztcclxuICAgICAgICBpZiAocGFpci5rZXkgPT09IGtleSkge1xyXG4gICAgICAgICAgY29uc3Qgb2xkRW50cnkgPSBhQnVja2V0LnNwbGljZShpbmRleCwgMSlbMF07XHJcbiAgICAgICAgICBrZXlzSW5kID0gdGhpcy5fa2V5cy5pbmRleE9mKGtleSk7XHJcbiAgICAgICAgICBpZiAoa2V5c0luZCA+PSAwICkgdGhpcy5fa2V5cy5zcGxpY2Uoa2V5c0luZCwgMSk7XHJcbiAgICAgICAgICByZXR1cm4gb2xkRW50cnkudmFsdWUhO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcclxuICB9XHJcbiAgLyoqXHJcbiAgICogQG92ZXJyaWRlXHJcbiAgICovXHJcbiAga2V5cygpOiBBcnJheTxLPiB7XHJcbiAgICByZXR1cm4gWy4uLnRoaXMuX2tleXNdO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBAb3ZlcnJpZGVcclxuICAgKi9cclxuICB2YWx1ZXMoKTogQXJyYXk8Vj4ge1xyXG4gICAgbGV0IGFyciA9IG5ldyBBcnJheTxWPigpO1xyXG4gICAgdGhpcy5fa2V5cy5mb3JFYWNoKGtleSA9PiBhcnIucHVzaCh0aGlzLmdldChrZXkpISkpO1xyXG4gICAgcmV0dXJuIGFycjtcclxuICB9XHJcbiAgLyoqXHJcbiAgICogRXhlY3V0ZXMgYSBgY2FsbEJhY2tgIGZ1bmN0aW9uIGZvciBlYWNoIGVudHJ5IGluIHRoaXMgZGljdGlvbmFyeVxyXG4gICAqIEBwYXJhbSBjYWxsQmFjayBGdW5jdGlvbiB0byBjYWxsXHJcbiAgICogQHBhcmFtIHRoaXNBcmcgQSByZWZlcmVuY2UgdG8gYHRoaXNgIG9iamVjdFxyXG4gICAqL1xyXG4gIGZvckVhY2goY2FsbEJhY2s6ICh2YWx1ZTogViwga2V5OiBLLCBtYXA6IEhhc2hUYWJsZTxLLFY+KT0+dm9pZCwgdGhpc0FyZz86IGFueSk6IHZvaWQge1xyXG4gICAgdGhpcy5fa2V5cy5mb3JFYWNoKGtleT0+Y2FsbEJhY2sodGhpcy5nZXQoa2V5KSEsIGtleSwgdGhpcyksIHRoaXNBcmcgKTtcclxuICB9XHJcblxyXG59XHJcbiJdfQ==