@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
JavaScript
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==