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

305 lines 34.9 kB
import { Comparator } from "../../util/Comparator"; import { IndexOutOfBoundsException } from "../../util/exception/IndexOutOfBoundsException"; /** * Abstract parent class for Min and Max Heaps. * In computer science, a _heap_ is a specialized tree-based data structure that satisfies the heap property described below. * In a _min_ heap, if `P` is a parent node of `C`, then the key (the value) of `P` is less than or equal to the key of `C`. * In a _max_ heap, the key of `P` is greater than or equal to the key of `C`. * @abstract */ export class Heap { constructor(compare) { this._heapContainer = []; this._compare = Comparator.compare; if (compare) { this._compare = compare; } } /** * Returns the size of the heap structure */ get length() { return this._heapContainer.length; } /** * @param {number} parentIndex * @returns {number} */ getLeftChildIndex(parentIndex) { return (2 * parentIndex) + 1; } /** * @param {number} parentIndex * @returns {number} */ getRightChildIndex(parentIndex) { return (2 * parentIndex) + 2; } /** * @param {number} childIndex * @returns {number} */ getParentIndex(childIndex) { return Math.floor((childIndex - 1) / 2); } /** * @param {number} childIndex * @returns {boolean} */ hasParent(childIndex) { return this.getParentIndex(childIndex) >= 0; } /** * @param {number} parentIndex * @returns {boolean} */ hasLeftChild(parentIndex) { return this.getLeftChildIndex(parentIndex) < this._heapContainer.length; } /** * @param {number} parentIndex * @returns {boolean} */ hasRightChild(parentIndex) { return this.getRightChildIndex(parentIndex) < this._heapContainer.length; } /** * @param {number} parentIndex * @returns {*} */ leftChild(parentIndex) { return this._heapContainer[this.getLeftChildIndex(parentIndex)]; } /** * @param {number} parentIndex * @returns {*} */ rightChild(parentIndex) { return this._heapContainer[this.getRightChildIndex(parentIndex)]; } /** * @param {number} childIndex * @returns {*} */ parent(childIndex) { return this._heapContainer[this.getParentIndex(childIndex)]; } /** * @param {number} indexOne * @param {number} indexTwo */ swap(indexOne, indexTwo) { const tmp = this._heapContainer[indexTwo]; this._heapContainer[indexTwo] = this._heapContainer[indexOne]; this._heapContainer[indexOne] = tmp; } /** * Gets the heap item by its numeric index value * @param index The ordered number of the item * @returns The heap item, if the `index` in the bounds of the heap container, otherwise throws exception * @throws IndexOutOfBoundsException */ get(index) { if (index < 0 || index >= this.size()) { throw new IndexOutOfBoundsException(); } return this._heapContainer[index]; } /** * Gets the size of the current heap * @returns */ size() { return this._heapContainer.length; } /** * Retrieves, but does not remove the head of this heap, or returns `undefined` if this heap is empty * @return {*} */ peek() { if (this.isEmpty()) { return undefined; } return this._heapContainer[0]; } /** * Retrieves and removes the head of this heap, or returns `undefined` if this heap is empty * @return {*} */ poll() { if (this.isEmpty()) { return undefined; } if (this._heapContainer.length === 1) { return this._heapContainer.pop(); } const item = this._heapContainer[0]; // Move the last element from the end to the head. this._heapContainer[0] = this._heapContainer.pop(); this.heapifyDown(); return item; } /** * Inserts the specified element into this heap * @param {CollectionItem} item * @returns {boolean} */ add(item) { if (item === undefined || item === null) { return false; } this._heapContainer.push(item); this.heapifyUp(); return true; } /** * Removes all of the elements from this heap */ clear() { this._heapContainer = []; } /** * Returns true if this heap contains the specified element * @param item * @returns */ contains(item) { let index = -1; let len = this._heapContainer.length; while (++index < len) { if (this._compare(this._heapContainer[index], item) == 0) { return true; } } return false; } /** * Removes the item in the specified position in the heap * @param indexToRemove The ordered number of the item * @returns An old item in the removed position * @throws IndexOutOfBoundsException */ removeAt(indexToRemove) { if (!(indexToRemove >= 0 && indexToRemove < this.size())) { throw new IndexOutOfBoundsException(`Index ${indexToRemove} is out of range`); } // If we need to remove last child in the heap then just remove it. // There is no need to heapify the heap afterwards. if (indexToRemove === (this.size() - 1)) { return this._heapContainer.pop(); } let oldVal = this._heapContainer[indexToRemove]; // Move last element in heap to the vacant (removed) position. this._heapContainer[indexToRemove] = this._heapContainer.pop(); // Get parent. const parentItem = this.parent(indexToRemove); // If there is no parent or parent is in correct order with the node // we're going to delete then heapify down. Otherwise heapify up. if (this.hasLeftChild(indexToRemove) && (!parentItem || this.pairIsInCorrectOrder(parentItem, this._heapContainer[indexToRemove]))) { this.heapifyDown(indexToRemove); } else { this.heapifyUp(indexToRemove); } return oldVal; } /** * Removes a single instance of the specified element from this heap, if it is present * @param {*} item The item to remove * @returns {boolean} _true_ if the `item` was removed, else _false_ */ remove(item) { if (this.isEmpty() || item === undefined) { return false; } // Find number of items to remove. const numberOfItemsToRemove = this.find(item).length; if (numberOfItemsToRemove > 0) { for (let iteration = 0; iteration < numberOfItemsToRemove; iteration++) { // We need to find item index to remove each time after removal since // indices are being changed after each heapify process. const indexToRemove = this.find(item).pop(); this.removeAt(indexToRemove); } return true; } return false; } /** * @param {*} item * @param {Comparator} [comparator] * @return {Number[]} */ find(item) { const foundItemIndices = []; const nLen = this._heapContainer.length; for (let itemIndex = 0; itemIndex < nLen; itemIndex++) { if (this._compare(item, this._heapContainer[itemIndex]) == 0) { foundItemIndices.push(itemIndex); } } return foundItemIndices; } /** * @returns {boolean} */ isEmpty() { return this._heapContainer.length == 0; } /** * Returns an array containing all of the elements in this heap * @returns */ toArray() { return [...this._heapContainer]; } /** * @returns {string} */ toString() { return this._heapContainer.toString(); } /** * * @returns */ toJSON() { return this.toArray(); } /** * @param {number} [customStartIndex] */ heapifyUp(customStartIndex) { // Take the last element (last in array or the bottom left in a tree) // in the heap container and lift it up until it is in the correct // order with respect to its parent element. let currentIndex = customStartIndex || this._heapContainer.length - 1; while (this.hasParent(currentIndex) && !this.pairIsInCorrectOrder(this.parent(currentIndex), this._heapContainer[currentIndex])) { this.swap(currentIndex, this.getParentIndex(currentIndex)); currentIndex = this.getParentIndex(currentIndex); } } /** * @param {number} [customStartIndex] */ heapifyDown(customStartIndex = 0) { // Compare the parent element to its children and swap parent with the appropriate // child (smallest child for MinHeap, largest child for MaxHeap). // Do the same for next children after swap. let currentIndex = customStartIndex; let nextIndex = null; while (this.hasLeftChild(currentIndex)) { if (this.hasRightChild(currentIndex) && this.pairIsInCorrectOrder(this.rightChild(currentIndex), this.leftChild(currentIndex))) { nextIndex = this.getRightChildIndex(currentIndex); } else { nextIndex = this.getLeftChildIndex(currentIndex); } if (this.pairIsInCorrectOrder(this._heapContainer[currentIndex], this._heapContainer[nextIndex])) { break; } this.swap(currentIndex, nextIndex); currentIndex = nextIndex; } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSGVhcC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2N1dGUtY29yZS9zcmMvbGliL2NvbGxlY3Rpb25zL2hlYXAvSGVhcC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDbkQsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sZ0RBQWdELENBQUM7QUFJM0Y7Ozs7OztHQU1HO0FBQ0gsTUFBTSxPQUFnQixJQUFJO0lBSXRCLFlBQVksT0FBb0I7UUFIeEIsbUJBQWMsR0FBaUIsRUFBRSxDQUFDO1FBQ2hDLGFBQVEsR0FBZSxVQUFVLENBQUMsT0FBTyxDQUFDO1FBR2hELElBQUksT0FBTyxFQUFFO1lBQ1QsSUFBSSxDQUFDLFFBQVEsR0FBRyxPQUFPLENBQUM7U0FDM0I7SUFDTCxDQUFDO0lBQ0Q7O09BRUc7SUFDSCxJQUFJLE1BQU0sS0FBYSxPQUFPLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUUzRDs7O09BR0c7SUFDTyxpQkFBaUIsQ0FBQyxXQUFtQjtRQUMzQyxPQUFPLENBQUMsQ0FBQyxHQUFHLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNqQyxDQUFDO0lBQ0Q7OztPQUdHO0lBQ08sa0JBQWtCLENBQUMsV0FBbUI7UUFDNUMsT0FBTyxDQUFDLENBQUMsR0FBRyxXQUFXLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDakMsQ0FBQztJQUNEOzs7T0FHRztJQUNPLGNBQWMsQ0FBQyxVQUFrQjtRQUN2QyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxVQUFVLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDNUMsQ0FBQztJQUNEOzs7T0FHRztJQUNPLFNBQVMsQ0FBQyxVQUFrQjtRQUNsQyxPQUFPLElBQUksQ0FBQyxjQUFjLENBQUMsVUFBVSxDQUFDLElBQUks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ImltcG9ydCB7IENvbXBhcmF0b3IgfSBmcm9tIFwiLi4vLi4vdXRpbC9Db21wYXJhdG9yXCI7XHJcbmltcG9ydCB7IEluZGV4T3V0T2ZCb3VuZHNFeGNlcHRpb24gfSBmcm9tIFwiLi4vLi4vdXRpbC9leGNlcHRpb24vSW5kZXhPdXRPZkJvdW5kc0V4Y2VwdGlvblwiO1xyXG5pbXBvcnQgeyBDb21wYXJlIH0gZnJvbSBcIi4uLy4uL3V0aWwvZnVuY3Rpb24vQ29tcGFyZVwiO1xyXG5pbXBvcnQgeyBFbGVtZW50IH0gZnJvbSBcIi4uL0NvbGxlY3Rpb25cIjtcclxuXHJcbi8qKlxyXG4gKiBBYnN0cmFjdCBwYXJlbnQgY2xhc3MgZm9yIE1pbiBhbmQgTWF4IEhlYXBzLlxyXG4gKiBJbiBjb21wdXRlciBzY2llbmNlLCBhIF9oZWFwXyBpcyBhIHNwZWNpYWxpemVkIHRyZWUtYmFzZWQgZGF0YSBzdHJ1Y3R1cmUgdGhhdCBzYXRpc2ZpZXMgdGhlIGhlYXAgcHJvcGVydHkgZGVzY3JpYmVkIGJlbG93LlxyXG4gKiBJbiBhIF9taW5fIGhlYXAsIGlmIGBQYCBpcyBhIHBhcmVudCBub2RlIG9mIGBDYCwgdGhlbiB0aGUga2V5ICh0aGUgdmFsdWUpIG9mIGBQYCBpcyBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gdGhlIGtleSBvZiBgQ2AuXHJcbiAqIEluIGEgX21heF8gaGVhcCwgdGhlIGtleSBvZiBgUGAgaXMgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIHRoZSBrZXkgb2YgYENgLlxyXG4gKiBAYWJzdHJhY3RcclxuICovXHJcbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBIZWFwPFQ+IHtcclxuICAgIHByaXZhdGUgX2hlYXBDb250YWluZXI6IEVsZW1lbnQ8VD5bXSA9IFtdO1xyXG4gICAgcHJvdGVjdGVkIF9jb21wYXJlOiBDb21wYXJlPFQ+ID0gQ29tcGFyYXRvci5jb21wYXJlO1xyXG5cclxuICAgIGNvbnN0cnVjdG9yKGNvbXBhcmU/OiBDb21wYXJlPFQ+KSB7XHJcbiAgICAgICAgaWYgKGNvbXBhcmUpIHtcclxuICAgICAgICAgICAgdGhpcy5fY29tcGFyZSA9IGNvbXBhcmU7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm5zIHRoZSBzaXplIG9mIHRoZSBoZWFwIHN0cnVjdHVyZVxyXG4gICAgICovXHJcbiAgICBnZXQgbGVuZ3RoKCk6IG51bWJlciB7IHJldHVybiB0aGlzLl9oZWFwQ29udGFpbmVyLmxlbmd0aDsgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHBhcmVudEluZGV4XHJcbiAgICAgKiBAcmV0dXJucyB7bnVtYmVyfVxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgZ2V0TGVmdENoaWxkSW5kZXgocGFyZW50SW5kZXg6IG51bWJlcik6IG51bWJlciB7XHJcbiAgICAgICAgcmV0dXJuICgyICogcGFyZW50SW5kZXgpICsgMTtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHBhcmVudEluZGV4XHJcbiAgICAgKiBAcmV0dXJucyB7bnVtYmVyfVxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgZ2V0UmlnaHRDaGlsZEluZGV4KHBhcmVudEluZGV4OiBudW1iZXIpOiBudW1iZXIge1xyXG4gICAgICAgIHJldHVybiAoMiAqIHBhcmVudEluZGV4KSArIDI7XHJcbiAgICB9XHJcbiAgICAvKipcclxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBjaGlsZEluZGV4XHJcbiAgICAgKiBAcmV0dXJucyB7bnVtYmVyfVxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgZ2V0UGFyZW50SW5kZXgoY2hpbGRJbmRleDogbnVtYmVyKTogbnVtYmVyIHtcclxuICAgICAgICByZXR1cm4gTWF0aC5mbG9vcigoY2hpbGRJbmRleCAtIDEpIC8gMik7XHJcbiAgICB9XHJcbiAgICAvKipcclxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBjaGlsZEluZGV4XHJcbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGhhc1BhcmVudChjaGlsZEluZGV4OiBudW1iZXIpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5nZXRQYXJlbnRJbmRleChjaGlsZEluZGV4KSA+PSAwO1xyXG4gICAgfVxyXG4gICAgLyoqXHJcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gcGFyZW50SW5kZXhcclxuICAgICAqIEByZXR1cm5zIHtib29sZWFufVxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgaGFzTGVmdENoaWxkKHBhcmVudEluZGV4OiBudW1iZXIpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5nZXRMZWZ0Q2hpbGRJbmRleChwYXJlbnRJbmRleCkgPCB0aGlzLl9oZWFwQ29udGFpbmVyLmxlbmd0aDtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHBhcmVudEluZGV4XHJcbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGhhc1JpZ2h0Q2hpbGQocGFyZW50SW5kZXg6IG51bWJlcik6IGJvb2xlYW4ge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmdldFJpZ2h0Q2hpbGRJbmRleChwYXJlbnRJbmRleCkgPCB0aGlzLl9oZWFwQ29udGFpbmVyLmxlbmd0aDtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHBhcmVudEluZGV4XHJcbiAgICAgKiBAcmV0dXJucyB7Kn1cclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGxlZnRDaGlsZChwYXJlbnRJbmRleDogbnVtYmVyKTogRWxlbWVudDxUPiB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX2hlYXBDb250YWluZXJbdGhpcy5nZXRMZWZ0Q2hpbGRJbmRleChwYXJlbnRJbmRleCldO1xyXG4gICAgfVxyXG4gICAgLyoqXHJcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gcGFyZW50SW5kZXhcclxuICAgICAqIEByZXR1cm5zIHsqfVxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgcmlnaHRDaGlsZChwYXJlbnRJbmRleDogbnVtYmVyKTogRWxlbWVudDxUPiB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX2hlYXBDb250YWluZXJbdGhpcy5nZXRSaWdodENoaWxkSW5kZXgocGFyZW50SW5kZXgpXTtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGNoaWxkSW5kZXhcclxuICAgICAqIEByZXR1cm5zIHsqfVxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgcGFyZW50KGNoaWxkSW5kZXg6IG51bWJlcik6IEVsZW1lbnQ8VD4ge1xyXG4gICAgICAgIHJldHVybiB0aGlzLl9oZWFwQ29udGFpbmVyW3RoaXMuZ2V0UGFyZW50SW5kZXgoY2hpbGRJbmRleCldO1xyXG4gICAgfVxyXG4gICAgLyoqXHJcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gaW5kZXhPbmVcclxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBpbmRleFR3b1xyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgc3dhcChpbmRleE9uZTogbnVtYmVyLCBpbmRleFR3bzogbnVtYmVyKTogdm9pZCB7XHJcbiAgICAgICAgY29uc3QgdG1wID0gdGhpcy5faGVhcENvbnRhaW5lcltpbmRleFR3b107XHJcbiAgICAgICAgdGhpcy5faGVhcENvbnRhaW5lcltpbmRleFR3b10gPSB0aGlzLl9oZWFwQ29udGFpbmVyW2luZGV4T25lXTtcclxuICAgICAgICB0aGlzLl9oZWFwQ29udGFpbmVyW2luZGV4T25lXSA9IHRtcDtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogR2V0cyB0aGUgaGVhcCBpdGVtIGJ5IGl0cyBudW1lcmljIGluZGV4IHZhbHVlXHJcbiAgICAgKiBAcGFyYW0gaW5kZXggVGhlIG9yZGVyZWQgbnVtYmVyIG9mIHRoZSBpdGVtXHJcbiAgICAgKiBAcmV0dXJucyBUaGUgaGVhcCBpdGVtLCBpZiB0aGUgYGluZGV4YCBpbiB0aGUgYm91bmRzIG9mIHRoZSBoZWFwIGNvbnRhaW5lciwgb3RoZXJ3aXNlIHRocm93cyBleGNlcHRpb25cclxuICAgICAqIEB0aHJvd3MgSW5kZXhPdXRPZkJvdW5kc0V4Y2VwdGlvblxyXG4gICAgICovXHJcbiAgICBnZXQoaW5kZXg6IG51bWJlcik6IEVsZW1lbnQ8VD4ge1xyXG4gICAgICAgIGlmIChpbmRleCA8IDAgfHwgaW5kZXggPj0gdGhpcy5zaXplKCkpIHtcclxuICAgICAgICAgICAgdGhyb3cgbmV3IEluZGV4T3V0T2ZCb3VuZHNFeGNlcHRpb24oKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX2hlYXBDb250YWluZXJbaW5kZXhdO1xyXG4gICAgfVxyXG4gICAgLyoqXHJcbiAgICAgKiBHZXRzIHRoZSBzaXplIG9mIHRoZSBjdXJyZW50IGhlYXBcclxuICAgICAqIEByZXR1cm5zXHJcbiAgICAgKi9cclxuICAgIHNpemUoKTogbnVtYmVyIHsgcmV0dXJuIHRoaXMuX2hlYXBDb250YWluZXIubGVuZ3RoOyB9XHJcbiAgICAvKipcclxuICAgICAqIFJldHJpZXZlcywgYnV0IGRvZXMgbm90IHJlbW92ZSB0aGUgaGVhZCBvZiB0aGlzIGhlYXAsIG9yIHJldHVybnMgYHVuZGVmaW5lZGAgaWYgdGhpcyBoZWFwIGlzIGVtcHR5XHJcbiAgICAgKiBAcmV0dXJuIHsqfVxyXG4gICAgICovXHJcbiAgICBwZWVrKCk6IEVsZW1lbnQ8VD4gfCB1bmRlZmluZWQge1xyXG4gICAgICAgIGlmICh0aGlzLmlzRW1wdHkoKSkge1xyXG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdGhpcy5faGVhcENvbnRhaW5lclswXTtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogUmV0cmlldmVzIGFuZCByZW1vdmVzIHRoZSBoZWFkIG9mIHRoaXMgaGVhcCwgb3IgcmV0dXJucyBgdW5kZWZpbmVkYCBpZiB0aGlzIGhlYXAgaXMgZW1wdHlcclxuICAgICAqIEByZXR1cm4geyp9XHJcbiAgICAgKi9cclxuICAgIHBvbGwoKTogRWxlbWVudDxUPiB8IHVuZGVmaW5lZCB7XHJcbiAgICAgICAgaWYgKHRoaXMuaXNFbXB0eSgpKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAodGhpcy5faGVhcENvbnRhaW5lci5sZW5ndGggPT09IDEpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2hlYXBDb250YWluZXIucG9wKCkhO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgY29uc3QgaXRlbSA9IHRoaXMuX2hlYXBDb250YWluZXJbMF07XHJcblxyXG4gICAgICAgIC8vIE1vdmUgdGhlIGxhc3QgZWxlbWVudCBmcm9tIHRoZSBlbmQgdG8gdGhlIGhlYWQuXHJcbiAgICAgICAgdGhpcy5faGVhcENvbnRhaW5lclswXSA9IHRoaXMuX2hlYXBDb250YWluZXIucG9wKCkhO1xyXG4gICAgICAgIHRoaXMuaGVhcGlmeURvd24oKTtcclxuXHJcbiAgICAgICAgcmV0dXJuIGl0ZW07XHJcbiAgICB9XHJcbiAgICAvKipcclxuICAgICAqIEluc2VydHMgdGhlIHNwZWNpZmllZCBlbGVtZW50IGludG8gdGhpcyBoZWFwXHJcbiAgICAgKiBAcGFyYW0ge0NvbGxlY3Rpb25JdGVtfSBpdGVtXHJcbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuICAgICAqL1xyXG4gICAgYWRkKGl0ZW06IEVsZW1lbnQ8VD4pOiBib29sZWFuIHtcclxuICAgICAgICBpZiAoaXRlbSA9PT0gdW5kZWZpbmVkIHx8IGl0ZW0gPT09IG51bGwpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLl9oZWFwQ29udGFpbmVyLnB1c2goaXRlbSk7XHJcbiAgICAgICAgdGhpcy5oZWFwaWZ5VXAoKTtcclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogUmVtb3ZlcyBhbGwgb2YgdGhlIGVsZW1lbnRzIGZyb20gdGhpcyBoZWFwXHJcbiAgICAgKi9cclxuICAgIGNsZWFyKCk6IHZvaWQge1xyXG4gICAgICAgIHRoaXMuX2hlYXBDb250YWluZXIgPSBbXTtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogUmV0dXJucyB0cnVlIGlmIHRoaXMgaGVhcCBjb250YWlucyB0aGUgc3BlY2lmaWVkIGVsZW1lbnRcclxuICAgICAqIEBwYXJhbSBpdGVtXHJcbiAgICAgKiBAcmV0dXJuc1xyXG4gICAgICovXHJcbiAgICBjb250YWlucyhpdGVtOiBFbGVtZW50PFQ+KTogYm9vbGVhbiB7XHJcbiAgICAgICAgbGV0IGluZGV4OiBudW1iZXIgPSAtMTtcclxuICAgICAgICBsZXQgbGVuID0gdGhpcy5faGVhcENvbnRhaW5lci5sZW5ndGg7XHJcbiAgICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW4pIHtcclxuICAgICAgICAgICAgaWYgKHRoaXMuX2NvbXBhcmUodGhpcy5faGVhcENvbnRhaW5lcltpbmRleF0sIGl0ZW0pID09IDApIHtcclxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogUmVtb3ZlcyB0aGUgaXRlbSBpbiB0aGUgc3BlY2lmaWVkIHBvc2l0aW9uIGluIHRoZSBoZWFwXHJcbiAgICAgKiBAcGFyYW0gaW5kZXhUb1JlbW92ZSBUaGUgb3JkZXJlZCBudW1iZXIgb2YgdGhlIGl0ZW1cclxuICAgICAqIEByZXR1cm5zIEFuIG9sZCBpdGVtIGluIHRoZSByZW1vdmVkIHBvc2l0aW9uXHJcbiAgICAgKiBAdGhyb3dzIEluZGV4T3V0T2ZCb3VuZHNFeGNlcHRpb25cclxuICAgICAqL1xyXG4gICAgcmVtb3ZlQXQoaW5kZXhUb1JlbW92ZTogbnVtYmVyKTogRWxlbWVudDxUPiB7XHJcblxyXG4gICAgICAgIGlmICghKGluZGV4VG9SZW1vdmUgPj0gMCAmJiBpbmRleFRvUmVtb3ZlIDwgdGhpcy5zaXplKCkpKSB7XHJcbiAgICAgICAgICAgIHRocm93IG5ldyBJbmRleE91dE9mQm91bmRzRXhjZXB0aW9uKGBJbmRleCAke2luZGV4VG9SZW1vdmV9IGlzIG91dCBvZiByYW5nZWApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSWYgd2UgbmVlZCB0byByZW1vdmUgbGFzdCBjaGlsZCBpbiB0aGUgaGVhcCB0aGVuIGp1c3QgcmVtb3ZlIGl0LlxyXG4gICAgICAgIC8vIFRoZXJlIGlzIG5vIG5lZWQgdG8gaGVhcGlmeSB0aGUgaGVhcCBhZnRlcndhcmRzLlxyXG4gICAgICAgIGlmIChpbmRleFRvUmVtb3ZlID09PSAodGhpcy5zaXplKCkgLSAxKSkge1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5faGVhcENvbnRhaW5lci5wb3AoKSE7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBsZXQgb2xkVmFsID0gdGhpcy5faGVhcENvbnRhaW5lcltpbmRleFRvUmVtb3ZlXTtcclxuICAgICAgICAvLyBNb3ZlIGxhc3QgZWxlbWVudCBpbiBoZWFwIHRvIHRoZSB2YWNhbnQgKHJlbW92ZWQpIHBvc2l0aW9uLlxyXG4gICAgICAgIHRoaXMuX2hlYXBDb250YWluZXJbaW5kZXhUb1JlbW92ZV0gPSB0aGlzLl9oZWFwQ29udGFpbmVyLnBvcCgpITtcclxuXHJcbiAgICAgICAgLy8gR2V0IHBhcmVudC5cclxuICAgICAgICBjb25zdCBwYXJlbnRJdGVtID0gdGhpcy5wYXJlbnQoaW5kZXhUb1JlbW92ZSk7XHJcblxyXG4gICAgICAgIC8vIElmIHRoZXJlIGlzIG5vIHBhcmVudCBvciBwYXJlbnQgaXMgaW4gY29ycmVjdCBvcmRlciB3aXRoIHRoZSBub2RlXHJcbiAgICAgICAgLy8gd2UncmUgZ29pbmcgdG8gZGVsZXRlIHRoZW4gaGVhcGlmeSBkb3duLiBPdGhlcndpc2UgaGVhcGlmeSB1cC5cclxuICAgICAgICBpZiAodGhpcy5oYXNMZWZ0Q2hpbGQoaW5kZXhUb1JlbW92ZSkgJiYgKFxyXG4gICAgICAgICAgICAhcGFyZW50SXRlbVxyXG4gICAgICAgICAgICB8fCB0aGlzLnBhaXJJc0luQ29ycmVjdE9yZGVyKHBhcmVudEl0ZW0sIHRoaXMuX2hlYXBDb250YWluZXJbaW5kZXhUb1JlbW92ZV0pXHJcbiAgICAgICAgKSkge1xyXG4gICAgICAgICAgICB0aGlzLmhlYXBpZnlEb3duKGluZGV4VG9SZW1vdmUpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRoaXMuaGVhcGlmeVVwKGluZGV4VG9SZW1vdmUpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgcmV0dXJuIG9sZFZhbDtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogUmVtb3ZlcyBhIHNpbmdsZSBpbnN0YW5jZSBvZiB0aGUgc3BlY2lmaWVkIGVsZW1lbnQgZnJvbSB0aGlzIGhlYXAsIGlmIGl0IGlzIHByZXNlbnRcclxuICAgICAqIEBwYXJhbSB7Kn0gaXRlbSBUaGUgaXRlbSB0byByZW1vdmVcclxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBfdHJ1ZV8gaWYgdGhlIGBpdGVtYCB3YXMgcmVtb3ZlZCwgZWxzZSBfZmFsc2VfXHJcbiAgICAgKi9cclxuICAgIHJlbW92ZShpdGVtOiBFbGVtZW50PFQ+KTogYm9vbGVhbiB7XHJcblxyXG4gICAgICAgIGlmICh0aGlzLmlzRW1wdHkoKSB8fCBpdGVtID09PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRmluZCBudW1iZXIgb2YgaXRlbXMgdG8gcmVtb3ZlLlxyXG4gICAgICAgIGNvbnN0IG51bWJlck9mSXRlbXNUb1JlbW92ZSA9IHRoaXMuZmluZChpdGVtKS5sZW5ndGg7XHJcbiAgICAgICAgaWYgKG51bWJlck9mSXRlbXNUb1JlbW92ZSA+IDApIHtcclxuICAgICAgICAgICAgZm9yIChsZXQgaXRlcmF0aW9uID0gMDsgaXRlcmF0aW9uIDwgbnVtYmVyT2ZJdGVtc1RvUmVtb3ZlOyBpdGVyYXRpb24rKykge1xyXG4gICAgICAgICAgICAgICAgLy8gV2UgbmVlZCB0byBmaW5kIGl0ZW0gaW5kZXggdG8gcmVtb3ZlIGVhY2ggdGltZSBhZnRlciByZW1vdmFsIHNpbmNlXHJcbiAgICAgICAgICAgICAgICAvLyBpbmRpY2VzIGFyZSBiZWluZyBjaGFuZ2VkIGFmdGVyIGVhY2ggaGVhcGlmeSBwcm9jZXNzLlxyXG4gICAgICAgICAgICAgICAgY29uc3QgaW5kZXhUb1JlbW92ZSA9IHRoaXMuZmluZChpdGVtKS5wb3AoKSE7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnJlbW92ZUF0KGluZGV4VG9SZW1vdmUpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgICAvKipcclxuICAgICAqIEBwYXJhbSB7Kn0gaXRlbVxyXG4gICAgICogQHBhcmFtIHtDb21wYXJhdG9yfSBbY29tcGFyYXRvcl1cclxuICAgICAqIEByZXR1cm4ge051bWJlcltdfVxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgZmluZChpdGVtOiBFbGVtZW50PFQ+KTogbnVtYmVyW10ge1xyXG4gICAgICAgIGNvbnN0IGZvdW5kSXRlbUluZGljZXM6IG51bWJlcltdID0gW107XHJcbiAgICAgICAgY29uc3QgbkxlbiA9IHRoaXMuX2hlYXBDb250YWluZXIubGVuZ3RoO1xyXG4gICAgICAgIGZvciAobGV0IGl0ZW1JbmRleCA9IDA7IGl0ZW1JbmRleCA8IG5MZW47IGl0ZW1JbmRleCsrKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLl9jb21wYXJlKGl0ZW0sIHRoaXMuX2hlYXBDb250YWluZXJbaXRlbUluZGV4XSkgPT0gMCkge1xyXG4gICAgICAgICAgICAgICAgZm91bmRJdGVtSW5kaWNlcy5wdXNoKGl0ZW1JbmRleCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGZvdW5kSXRlbUluZGljZXM7XHJcbiAgICB9XHJcbiAgICAvKipcclxuICAgICAqIEByZXR1cm5zIHtib29sZWFufVxyXG4gICAgICovXHJcbiAgICBpc0VtcHR5KCk6IGJvb2xlYW4ge1xyXG4gICAgICAgIHJldHVybiB0aGlzLl9oZWFwQ29udGFpbmVyLmxlbmd0aCA9PSAwO1xyXG4gICAgfVxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm5zIGFuIGFycmF5IGNvbnRhaW5pbmcgYWxsIG9mIHRoZSBlbGVtZW50cyBpbiB0aGlzIGhlYXBcclxuICAgICAqIEByZXR1cm5zXHJcbiAgICAgKi9cclxuICAgIHRvQXJyYXkoKTogQXJyYXk8RWxlbWVudDxUPj4ge1xyXG4gICAgICAgIHJldHVybiBbLi4udGhpcy5faGVhcENvbnRhaW5lcl07XHJcbiAgICB9XHJcbiAgICAvKipcclxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9XHJcbiAgICAgKi9cclxuICAgIHRvU3RyaW5nKCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX2hlYXBDb250YWluZXIudG9TdHJpbmcoKTtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICpcclxuICAgICAqIEByZXR1cm5zXHJcbiAgICAgKi9cclxuICAgIHRvSlNPTigpOiBFbGVtZW50PFQ+W10ge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnRvQXJyYXkoKTtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFtjdXN0b21TdGFydEluZGV4XVxyXG4gICAgICovXHJcbiAgICBoZWFwaWZ5VXAoY3VzdG9tU3RhcnRJbmRleD86IG51bWJlcik6IHZvaWQge1xyXG4gICAgICAgIC8vIFRha2UgdGhlIGxhc3QgZWxlbWVudCAobGFzdCBpbiBhcnJheSBvciB0aGUgYm90dG9tIGxlZnQgaW4gYSB0cmVlKVxyXG4gICAgICAgIC8vIGluIHRoZSBoZWFwIGNvbnRhaW5lciBhbmQgbGlmdCBpdCB1cCB1bnRpbCBpdCBpcyBpbiB0aGUgY29ycmVjdFxyXG4gICAgICAgIC8vIG9yZGVyIHdpdGggcmVzcGVjdCB0byBpdHMgcGFyZW50IGVsZW1lbnQuXHJcbiAgICAgICAgbGV0IGN1cnJlbnRJbmRleCA9IGN1c3RvbVN0YXJ0SW5kZXggfHwgdGhpcy5faGVhcENvbnRhaW5lci5sZW5ndGggLSAxO1xyXG5cclxuICAgICAgICB3aGlsZSAoXHJcbiAgICAgICAgICAgIHRoaXMuaGFzUGFyZW50KGN1cnJlbnRJbmRleClcclxuICAgICAgICAgICAgJiYgIXRoaXMucGFpcklzSW5Db3JyZWN0T3JkZXIodGhpcy5wYXJlbnQoY3VycmVudEluZGV4KSwgdGhpcy5faGVhcENvbnRhaW5lcltjdXJyZW50SW5kZXhdKVxyXG4gICAgICAgICkge1xyXG4gICAgICAgICAgICB0aGlzLnN3YXAoY3VycmVudEluZGV4LCB0aGlzLmdldFBhcmVudEluZGV4KGN1cnJlbnRJbmRleCkpO1xyXG4gICAgICAgICAgICBjdXJyZW50SW5kZXggPSB0aGlzLmdldFBhcmVudEluZGV4KGN1cnJlbnRJbmRleCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgLyoqXHJcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gW2N1c3RvbVN0YXJ0SW5kZXhdXHJcbiAgICAgKi9cclxuICAgIGhlYXBpZnlEb3duKGN1c3RvbVN0YXJ0SW5kZXg6IG51bWJlciA9IDApIHtcclxuICAgICAgICAvLyBDb21wYXJlIHRoZSBwYXJlbnQgZWxlbWVudCB0byBpdHMgY2hpbGRyZW4gYW5kIHN3YXAgcGFyZW50IHdpdGggdGhlIGFwcHJvcHJpYXRlXHJcbiAgICAgICAgLy8gY2hpbGQgKHNtYWxsZXN0IGNoaWxkIGZvciBNaW5IZWFwLCBsYXJnZXN0IGNoaWxkIGZvciBNYXhIZWFwKS5cclxuICAgICAgICAvLyBEbyB0aGUgc2FtZSBmb3IgbmV4dCBjaGlsZHJlbiBhZnRlciBzd2FwLlxyXG4gICAgICAgIGxldCBjdXJyZW50SW5kZXggPSBjdXN0b21TdGFydEluZGV4O1xyXG4gICAgICAgIGxldCBuZXh0SW5kZXggPSBudWxsO1xyXG5cclxuICAgICAgICB3aGlsZSAodGhpcy5oYXNMZWZ0Q2hpbGQoY3VycmVudEluZGV4KSkge1xyXG4gICAgICAgICAgICBpZiAoXHJcbiAgICAgICAgICAgICAgICB0aGlzLmhhc1JpZ2h0Q2hpbGQoY3VycmVudEluZGV4KVxyXG4gICAgICAgICAgICAgICAgJiYgdGhpcy5wYWlySXNJbkNvcnJlY3RPcmRlcih0aGlzLnJpZ2h0Q2hpbGQoY3VycmVudEluZGV4KSwgdGhpcy5sZWZ0Q2hpbGQoY3VycmVudEluZGV4KSlcclxuICAgICAgICAgICAgKSB7XHJcbiAgICAgICAgICAgICAgICBuZXh0SW5kZXggPSB0aGlzLmdldFJpZ2h0Q2hpbGRJbmRleChjdXJyZW50SW5kZXgpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgbmV4dEluZGV4ID0gdGhpcy5nZXRMZWZ0Q2hpbGRJbmRleChjdXJyZW50SW5kZXgpO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICBpZiAodGhpcy5wYWlySXNJbkNvcnJlY3RPcmRlcihcclxuICAgICAgICAgICAgICAgIHRoaXMuX2hlYXBDb250YWluZXJbY3VycmVudEluZGV4XSxcclxuICAgICAgICAgICAgICAgIHRoaXMuX2hlYXBDb250YWluZXJbbmV4dEluZGV4XSxcclxuICAgICAgICAgICAgKSkge1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIHRoaXMuc3dhcChjdXJyZW50SW5kZXgsIG5leHRJbmRleCk7XHJcbiAgICAgICAgICAgIGN1cnJlbnRJbmRleCA9IG5leHRJbmRleDtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBDaGVja3MgaWYgcGFpciBvZiBoZWFwIGVsZW1lbnRzIGlzIGluIGNvcnJlY3Qgb3JkZXIuXHJcbiAgICAgKiBGb3IgTWluSGVhcCB0aGUgZmlyc3QgZWxlbWVudCBtdXN0IGJlIGFsd2F5cyBzbWFsbGVyIG9yIGVxdWFsLlxyXG4gICAgICogRm9yIE1heEhlYXAgdGhlIGZpcnN0IGVsZW1lbnQgbXVzdCBiZSBhbHdheXMgYmlnZ2VyIG9yIGVxdWFsLlxyXG4gICAgICogQHBhcmFtIHsqfSBmaXJzdEVsZW1lbnRcclxuICAgICAqIEBwYXJhbSB7Kn0gc2Vjb25kRWxlbWVudFxyXG4gICAgICogQHJldHVybiB7Ym9vbGVhbn1cclxuICAgICAqL1xyXG4gICAgYWJzdHJhY3QgcGFpcklzSW5Db3JyZWN0T3JkZXIoZmlyc3RFbGVtZW50OiBFbGVtZW50PFQ+LCBzZWNvbmRFbGVtZW50OiBFbGVtZW50PFQ+KTogYm9vbGVhbjtcclxufVxyXG4iXX0=