webglimpse
Version:
Webglimpse is a data visualization library for the web.
191 lines • 26.3 kB
JavaScript
/*
* Copyright (c) 2014, Metron, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import { BinaryTree } from './binary_tree';
import { getObjectId } from './util';
// A sorted map which allows multiple string values per key (K)
export class SortedMultimap {
constructor(comparator, idFn = getObjectId) {
this._tree = new BinaryTree(this.createContainerComparator(comparator));
this._idFn = idFn;
}
createContainerComparator(comparator) {
return {
compare: function (container1, container2) {
return comparator.compare(container1.key, container2.key);
}
};
}
// Inserts the value into the tree. Nothing is inserted if the value already exists
insert(key, value) {
const wrappedKey = new Container(key);
let values = this._tree.getValue(wrappedKey);
if (values === null) {
values = wrappedKey;
this._tree.insert(values);
}
values.add(value, this._idFn);
}
remove(key, value) {
const wrappedKey = new Container(key);
const values = this._tree.getValue(wrappedKey);
if (values === null) {
return;
}
values.remove(value, this._idFn);
if (values.size === 0) {
this._tree.remove(values);
}
}
contains(key, value) {
const wrappedKey = new Container(key);
const values = this._tree.getValue(wrappedKey);
if (values === null) {
return false;
}
else {
return values.contains(value, this._idFn);
}
}
// Returns the lowest element greater than or equal to the given value, or null if no such element exists
ceiling(key) {
return this.unwrap(this._tree.ceiling(this.wrap(key)));
}
// Returns the greatest element less than or equal to the given value, or null if no such element exists
floor(key) {
return this.unwrap(this._tree.floor(this.wrap(key)));
}
// Returns the greatest element strictly less than the given value, or null if no such element exists
lower(key) {
return this.unwrap(this._tree.lower(this.wrap(key)));
}
// Returns the lowest element strictly greater than the given value, or null if no such element exists
higher(key) {
return this.unwrap(this._tree.higher(this.wrap(key)));
}
// Returns all elements greater than (or equal to, if inclusive is true) the provided value (sorted from low to high)
headSet(key, inclusive = true) {
return this.unwrapArray(this._tree.headSet(this.wrap(key), inclusive));
}
// Returns all elements less than ( or equal to, if inclusive is true) the provided value (sorted from low to high)
tailSet(key, inclusive = false) {
return this.unwrapArray(this._tree.tailSet(this.wrap(key), inclusive));
}
// Returns all elements between the provided values (sorted from low to high)
subSet(low, high, lowInclusive = true, highInclusive = false) {
const wrappedLow = new Container(low);
const wrappedHigh = new Container(high);
const values = this._tree.subSet(wrappedLow, wrappedHigh, lowInclusive, highInclusive);
return this.unwrapArray(values);
}
// Returns all keys in the tree (sorted from low to high)
toArray() {
return this.unwrapArray(this._tree.toArray());
}
iterator() {
const iter = this._tree.iterator();
let currentArray = null;
let currentIndex = 0;
return {
next: function () {
let value;
if (currentArray == null || currentIndex >= currentArray.length) {
currentArray = iter.next().toArray();
currentIndex = 0;
value = currentArray[currentIndex];
}
else {
value = currentArray[currentIndex];
}
currentIndex += 1;
return value;
},
hasNext: function () {
return iter.hasNext() || (currentArray != null && currentIndex < currentArray.length);
}
};
}
wrap(key) {
return new Container(key);
}
unwrap(values) {
if (values === null) {
return [];
}
else {
return values.toArray();
}
}
unwrapArray(values) {
const unwrappedValues = new Array();
values.forEach(function (value) {
value.toArray().forEach(function (val) {
unwrappedValues.push(val);
});
});
return unwrappedValues;
}
}
export class SortedStringMultimap extends SortedMultimap {
constructor(comparator) {
super(comparator, (value) => value);
}
}
// a container which stores a set of values (V) associated with a sorted key (K)
// OrderedSet or even BinaryTree could be used here instead
// more sophisticated set implementation: http://stackoverflow.com/questions/7958292/mimicking-sets-in-javascript
class Container {
constructor(key) {
this._key = key;
this._values = {};
}
get size() {
return this.toArray().length;
}
get key() {
return this._key;
}
get values() {
return this._values;
}
toArray() {
return Object.keys(this._values).map(key => this._values[key]);
}
contains(value, idFn) {
// safer than 'value in this._values' because of potential conflict with built in properties/methods
return Object.prototype.hasOwnProperty.call(this._values, idFn(value));
}
add(value, idFn) {
this._values[idFn(value)] = value;
}
remove(value, idFn) {
delete this._values[idFn(value)];
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic29ydGVkX211bHRpbWFwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3dlYmdsaW1wc2UvdXRpbC9zb3J0ZWRfbXVsdGltYXAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E0Qkc7QUFDSCxPQUFPLEVBQUUsVUFBVSxFQUF3QixNQUFNLGVBQWUsQ0FBQztBQUNqRSxPQUFPLEVBQXlCLFdBQVcsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUU1RCwrREFBK0Q7QUFDL0QsTUFBTSxPQUFPLGNBQWM7SUFLdkIsWUFBWSxVQUF5QixFQUFFLE9BQXNCLFdBQVc7UUFDcEUsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLFVBQVUsQ0FBa0IsSUFBSSxDQUFDLHlCQUF5QixDQUFJLFVBQVUsQ0FBQyxDQUFDLENBQUM7UUFDNUYsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUM7SUFDdEIsQ0FBQztJQUVPLHlCQUF5QixDQUFJLFVBQXlCO1FBQzFELE9BQU87WUFDSCxPQUFPLEVBQUUsVUFBVSxVQUEyQixFQUFFLFVBQTJCO2dCQUN2RSxPQUFPLFVBQVUsQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDOUQsQ0FBQztTQUNKLENBQUM7SUFDTixDQUFDO0lBRUQsbUZBQW1GO0lBQ25GLE1BQU0sQ0FBQyxHQUFNLEVBQUUsS0FBUTtRQUNuQixNQUFNLFVBQVUsR0FBRyxJQUFJLFNBQVMsQ0FBTyxHQUFHLENBQUMsQ0FBQztRQUM1QyxJQUFJLE1BQU0sR0FBb0IsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUM7UUFFOUQsSUFBSSxNQUFNLEtBQUssSUFBSSxFQUFFO1lBQ2pCLE1BQU0sR0FBRyxVQUFVLENBQUM7WUFDcEIsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFB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T0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDO0lBQ3JCLENBQUM7SUFFRCxJQUFJLE1BQU07UUFDTixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDeEIsQ0FBQztJQUVELE9BQU87UUFDSCxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNuRSxDQUFDO0lBRUQsUUFBUSxDQUFDLEtBQVEsRUFBRSxJQUFtQjtRQUNsQyxvR0FBb0c7UUFDcEcsT0FBTyxNQUFNLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUMzRSxDQUFDO0lBRUQsR0FBRyxDQUFDLEtBQVEsRUFBRSxJQUFtQjtRQUM3QixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQztJQUN0QyxDQUFDO0lBRUQsTUFBTSxDQUFDLEtBQVEsRUFBRSxJQUFtQjtRQUNoQyxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDckMsQ0FBQztDQUNKIiwic291cmNlc0NvbnRlbnQiOlsiLypcclxuICogQ29weXJpZ2h0IChjKSAyMDE0LCBNZXRyb24sIEluYy5cclxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cclxuICpcclxuICogUmVkaXN0cmlidXRpb24gYW5kIHVzZSBpbiBzb3VyY2UgYW5kIGJpbmFyeSBmb3Jtcywgd2l0aCBvciB3aXRob3V0IG1vZGlmaWNhdGlvbixcclxuICogYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9ucyBhcmUgbWV0OlxyXG4gKlxyXG4gKiAxLiBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNvZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UsIHRoaXNcclxuICogICAgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuXHJcbiAqXHJcbiAqIDIuIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSxcclxuICogICAgdGhpcyBsaXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lciBpbiB0aGUgZG9jdW1lbnRhdGlvblxyXG4gKiAgICBhbmQvb3Igb3RoZXIgbWF0ZXJpYWxzIHByb3ZpZGVkIHdpdGggdGhlIGRpc3RyaWJ1dGlvbi5cclxuICpcclxuICogMy4gTmVpdGhlciB0aGUgbmFtZSBvZiB0aGUgY29weXJpZ2h0IGhvbGRlciBub3IgdGhlIG5hbWVzIG9mIGl0cyBjb250cmlidXRvcnNcclxuICogICAgbWF5IGJlIHVzZWQgdG8gZW5kb3JzZSBvciBwcm9tb3RlIHByb2R1Y3RzIGRlcml2ZWQgZnJvbSB0aGlzIHNvZnR3YXJlIHdpdGhvdXRcclxuICogICAgc3BlY2lmaWMgcHJpb3Igd3JpdHRlbiBwZXJtaXNzaW9uLlxyXG4gKlxyXG4gKiBUSElTIFNPRlRXQVJFIElTIFBST1ZJREVEIEJZIFRIRSBDT1BZUklHSFQgSE9MREVSUyBBTkQgQ09OVFJJQlVUT1JTIFwiQVMgSVNcIiBBTkRcclxuICogQU5ZIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFIElNUExJRURcclxuICogV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFSRVxyXG4gKiBESVNDTEFJTUVELiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQ09QWVJJR0hUIEhPTERFUiBPUiBDT05UUklCVVRPUlMgQkUgTElBQkxFIEZPUlxyXG4gKiBBTlkgRElSRUNULCBJTkRJUkVDVCwgSU5DSURFTlRBTCwgU1BFQ0lBTCwgRVhFTVBMQVJZLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVNcclxuICogKElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBQUk9DVVJFTUVOVCBPRiBTVUJTVElUVVRFIEdPT0RTIE9SIFNFUlZJQ0VTO1xyXG4gKiBMT1NTIE9GIFVTRSwgREFUQSwgT1IgUFJPRklUUzsgT1IgQlVTSU5FU1MgSU5URVJSVVBUSU9OKSBIT1dFVkVSIENBVVNFRCBBTkQgT05cclxuICogQU5ZIFRIRU9SWSBPRiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQ09OVFJBQ1QsIFNUUklDVCBMSUFCSUxJVFksIE9SIFRPUlRcclxuICogKElOQ0xVRElORyBORUdMSUdFTkNFIE9SIE9USEVSV0lTRSkgQVJJU0lORyBJTiBBTlkgV0FZIE9VVCBPRiBUSEUgVVNFIE9GIFRISVNcclxuICogU09GVFdBUkUsIEVWRU4gSUYgQURWSVNFRCBPRiBUSEUgUE9TU0lCSUxJVFkgT0YgU1VDSCBEQU1BR0UuXHJcbiAqL1xyXG5pbXBvcnQgeyBCaW5hcnlUcmVlLCBDb21wYXJhdG9yLCBJdGVyYXRvciB9IGZyb20gJy4vYmluYXJ5X3RyZWUnO1xyXG5pbXBvcnQgeyBJZEZ1bmN0aW9uLCBTdHJpbmdNYXAsIGdldE9iamVjdElkIH0gZnJvbSAnLi91dGlsJztcclxuXHJcbi8vIEEgc29ydGVkIG1hcCB3aGljaCBhbGxvd3MgbXVsdGlwbGUgc3RyaW5nIHZhbHVlcyBwZXIga2V5IChLKVxyXG5leHBvcnQgY2xhc3MgU29ydGVkTXVsdGltYXA8SywgVj4ge1xyXG5cclxuICAgIHByaXZhdGUgX3RyZWU6IEJpbmFyeVRyZWU8Q29udGFpbmVyPEssIFY+PjtcclxuICAgIHByaXZhdGUgX2lkRm46IElkRnVuY3Rpb248Vj47XHJcblxyXG4gICAgY29uc3RydWN0b3IoY29tcGFyYXRvcjogQ29tcGFyYXRvcjxLPiwgaWRGbjogSWRGdW5jdGlvbjxWPiA9IGdldE9iamVjdElkKSB7XHJcbiAgICAgICAgdGhpcy5fdHJlZSA9IG5ldyBCaW5hcnlUcmVlPENvbnRhaW5lcjxLLCBWPj4odGhpcy5jcmVhdGVDb250YWluZXJDb21wYXJhdG9yPFY+KGNvbXBhcmF0b3IpKTtcclxuICAgICAgICB0aGlzLl9pZEZuID0gaWRGbjtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGNyZWF0ZUNvbnRhaW5lckNvbXBhcmF0b3I8VT4oY29tcGFyYXRvcjogQ29tcGFyYXRvcjxLPik6IENvbXBhcmF0b3I8Q29udGFpbmVyPEssIFU+PiB7XHJcbiAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY29tcGFyZTogZnVuY3Rpb24gKGNvbnRhaW5lcjE6IENvbnRhaW5lcjxLLCBVPiwgY29udGFpbmVyMjogQ29udGFpbmVyPEssIFU+KTogbnVtYmVyIHtcclxuICAgICAgICAgICAgICAgIHJldHVybiBjb21wYXJhdG9yLmNvbXBhcmUoY29udGFpbmVyMS5rZXksIGNvbnRhaW5lcjIua2V5KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH07XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSW5zZXJ0cyB0aGUgdmFsdWUgaW50byB0aGUgdHJlZS4gTm90aGluZyBpcyBpbnNlcnRlZCBpZiB0aGUgdmFsdWUgYWxyZWFkeSBleGlzdHNcclxuICAgIGluc2VydChrZXk6IEssIHZhbHVlOiBWKSB7XHJcbiAgICAgICAgY29uc3Qgd3JhcHBlZEtleSA9IG5ldyBDb250YWluZXI8SywgVj4oa2V5KTtcclxuICAgICAgICBsZXQgdmFsdWVzOiBDb250YWluZXI8SywgVj4gPSB0aGlzLl90cmVlLmdldFZhbHVlKHdyYXBwZWRLZXkpO1xyXG5cclxuICAgICAgICBpZiAodmFsdWVzID09PSBudWxsKSB7XHJcbiAgICAgICAgICAgIHZhbHVlcyA9IHdyYXBwZWRLZXk7XHJcbiAgICAgICAgICAgIHRoaXMuX3RyZWUuaW5zZXJ0KHZhbHVlcyk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB2YWx1ZXMuYWRkKHZhbHVlLCB0aGlzLl9pZEZuKTtcclxuICAgIH1cclxuXHJcbiAgICByZW1vdmUoa2V5OiBLLCB2YWx1ZTogVikge1xyXG4gICAgICAgIGNvbnN0IHdyYXBwZWRLZXkgPSBuZXcgQ29udGFpbmVyPEssIFY+KGtleSk7XHJcbiAgICAgICAgY29uc3QgdmFsdWVzOiBDb250YWluZXI8SywgVj4gPSB0aGlzLl90cmVlLmdldFZhbHVlKHdyYXBwZWRLZXkpO1xyXG5cclxuICAgICAgICBpZiAodmFsdWVzID09PSBudWxsKSB7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHZhbHVlcy5yZW1vdmUodmFsdWUsIHRoaXMuX2lkRm4pO1xyXG5cclxuICAgICAgICBpZiAodmFsdWVzLnNpemUgPT09IDApIHtcclxuICAgICAgICAgICAgdGhpcy5fdHJlZS5yZW1vdmUodmFsdWVzKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgY29udGFpbnMoa2V5OiBLLCB2YWx1ZTogVikge1xyXG4gICAgICAgIGNvbnN0IHdyYXBwZWRLZXkgPSBuZXcgQ29udGFpbmVyPEssIFY+KGtleSk7XHJcbiAgICAgICAgY29uc3QgdmFsdWVzOiBDb250YWluZXI8SywgVj4gPSB0aGlzLl90cmVlLmdldFZhbHVlKHdyYXBwZWRLZXkpO1xyXG5cclxuICAgICAgICBpZiAodmFsdWVzID09PSBudWxsKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgIHJldHVybiB2YWx1ZXMuY29udGFpbnModmFsdWUsIHRoaXMuX2lkRm4pO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXR1cm5zIHRoZSBsb3dlc3QgZWxlbWVudCBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gdGhlIGdpdmVuIHZhbHVlLCBvciBudWxsIGlmIG5vIHN1Y2ggZWxlbWVudCBleGlzdHNcclxuICAgIGNlaWxpbmcoa2V5OiBLKTogVltdIHtcclxuICAgICAgICByZXR1cm4gdGhpcy51bndyYXAodGhpcy5fdHJlZS5jZWlsaW5nKHRoaXMud3JhcChrZXkpKSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJucyB0aGUgZ3JlYXRlc3QgZWxlbWVudCBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gdGhlIGdpdmVuIHZhbHVlLCBvciBudWxsIGlmIG5vIHN1Y2ggZWxlbWVudCBleGlzdHNcclxuICAgIGZsb29yKGtleTogSyk6IFZbXSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudW53cmFwKHRoaXMuX3RyZWUuZmxvb3IodGhpcy53cmFwKGtleSkpKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXR1cm5zIHRoZSBncmVhdGVzdCBlbGVtZW50IHN0cmljdGx5IGxlc3MgdGhhbiB0aGUgZ2l2ZW4gdmFsdWUsIG9yIG51bGwgaWYgbm8gc3VjaCBlbGVtZW50IGV4aXN0c1xyXG4gICAgbG93ZXIoa2V5OiBLKTogVltdIHtcclxuICAgICAgICByZXR1cm4gdGhpcy51bndyYXAodGhpcy5fdHJlZS5sb3dlcih0aGlzLndyYXAoa2V5KSkpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJldHVybnMgdGhlIGxvd2VzdCBlbGVtZW50IHN0cmljdGx5IGdyZWF0ZXIgdGhhbiB0aGUgZ2l2ZW4gdmFsdWUsIG9yIG51bGwgaWYgbm8gc3VjaCBlbGVtZW50IGV4aXN0c1xyXG4gICAgaGlnaGVyKGtleTogSyk6IFZbXSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudW53cmFwKHRoaXMuX3RyZWUuaGlnaGVyKHRoaXMud3JhcChrZXkpKSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJucyBhbGwgZWxlbWVudHMgZ3JlYXRlciB0aGFuIChvciBlcXVhbCB0bywgaWYgaW5jbHVzaXZlIGlzIHRydWUpIHRoZSBwcm92aWRlZCB2YWx1ZSAoc29ydGVkIGZyb20gbG93IHRvIGhpZ2gpXHJcbiAgICBoZWFkU2V0KGtleTogSywgaW5jbHVzaXZlOiBib29sZWFuID0gdHJ1ZSk6IFZbXSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudW53cmFwQXJyYXkodGhpcy5fdHJlZS5oZWFkU2V0KHRoaXMud3JhcChrZXkpLCBpbmNsdXNpdmUpKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXR1cm5zIGFsbCBlbGVtZW50cyBsZXNzIHRoYW4gKCBvciBlcXVhbCB0bywgaWYgaW5jbHVzaXZlIGlzIHRydWUpIHRoZSBwcm92aWRlZCB2YWx1ZSAoc29ydGVkIGZyb20gbG93IHRvIGhpZ2gpXHJcbiAgICB0YWlsU2V0KGtleTogSywgaW5jbHVzaXZlOiBib29sZWFuID0gZmFsc2UpOiBWW10ge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnVud3JhcEFycmF5KHRoaXMuX3RyZWUudGFpbFNldCh0aGlzLndyYXAoa2V5KSwgaW5jbHVzaXZlKSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJucyBhbGwgZWxlbWVudHMgYmV0d2VlbiB0aGUgcHJvdmlkZWQgdmFsdWVzIChzb3J0ZWQgZnJvbSBsb3cgdG8gaGlnaClcclxuICAgIHN1YlNldChsb3c6IEssIGhpZ2g6IEssIGxvd0luY2x1c2l2ZTogYm9vbGVhbiA9IHRydWUsIGhpZ2hJbmNsdXNpdmU6IGJvb2xlYW4gPSBmYWxzZSk6IFZbXSB7XHJcbiAgICAgICAgY29uc3Qgd3JhcHBlZExvdyA9IG5ldyBDb250YWluZXI8SywgVj4obG93KTtcclxuICAgICAgICBjb25zdCB3cmFwcGVkSGlnaCA9IG5ldyBDb250YWluZXI8SywgVj4oaGlnaCk7XHJcbiAgICAgICAgY29uc3QgdmFsdWVzOiBDb250YWluZXI8SywgVj5bXSA9IHRoaXMuX3RyZWUuc3ViU2V0KHdyYXBwZWRMb3csIHdyYXBwZWRIaWdoLCBsb3dJbmNsdXNpdmUsIGhpZ2hJbmNsdXNpdmUpO1xyXG4gICAgICAgIHJldHVybiB0aGlzLnVud3JhcEFycmF5KHZhbHVlcyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJucyBhbGwga2V5cyBpbiB0aGUgdHJlZSAoc29ydGVkIGZyb20gbG93IHRvIGhpZ2gpXHJcbiAgICB0b0FycmF5KCk6IFZbXSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudW53cmFwQXJyYXkodGhpcy5fdHJlZS50b0FycmF5KCkpO1xyXG4gICAgfVxyXG5cclxuICAgIGl0ZXJhdG9yKCk6IEl0ZXJhdG9yPFY+IHtcclxuXHJcbiAgICAgICAgY29uc3QgaXRlcjogSXRlcmF0b3I8Q29udGFpbmVyPEssIFY+PiA9IHRoaXMuX3RyZWUuaXRlcmF0b3IoKTtcclxuICAgICAgICBsZXQgY3VycmVudEFycmF5OiBWW10gPSBudWxsO1xyXG4gICAgICAgIGxldCBjdXJyZW50SW5kZXggPSAwO1xyXG5cclxuICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICBuZXh0OiBmdW5jdGlvbiAoKTogViB7XHJcblxyXG4gICAgICAgICAgICAgICAgbGV0IHZhbHVlOiBWO1xyXG5cclxuICAgICAgICAgICAgICAgIGlmIChjdXJyZW50QXJyYXkgPT0gbnVsbCB8fCBjdXJyZW50SW5kZXggPj0gY3VycmVudEFycmF5Lmxlbmd0aCkge1xyXG4gICAgICAgICAgICAgICAgICAgIGN1cnJlbnRBcnJheSA9IGl0ZXIubmV4dCgpLnRvQXJyYXkoKTtcclxuICAgICAgICAgICAgICAgICAgICBjdXJyZW50SW5kZXggPSAwO1xyXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gY3VycmVudEFycmF5W2N1cnJlbnRJbmRleF07XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IGN1cnJlbnRBcnJheVtjdXJyZW50SW5kZXhdO1xyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIGN1cnJlbnRJbmRleCArPSAxO1xyXG5cclxuICAgICAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgaGFzTmV4dDogZnVuY3Rpb24gKCk6IGJvb2xlYW4ge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGl0ZXIuaGFzTmV4dCgpIHx8IChjdXJyZW50QXJyYXkgIT0gbnVsbCAmJiBjdXJyZW50SW5kZXggPCBjdXJyZW50QXJyYXkubGVuZ3RoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH07XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSB3cmFwKGtleTogSyk6IENvbnRhaW5lcjxLLCBWPiB7XHJcbiAgICAgICAgcmV0dXJuIG5ldyBDb250YWluZXI8SywgVj4oa2V5KTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIHVud3JhcCh2YWx1ZXM6IENvbnRhaW5lcjxLLCBWPik6IFZbXSB7XHJcbiAgICAgICAgaWYgKHZhbHVlcyA9PT0gbnVsbCkge1xyXG4gICAgICAgICAgICByZXR1cm4gW107XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICByZXR1cm4gdmFsdWVzLnRvQXJyYXkoKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSB1bndyYXBBcnJheSh2YWx1ZXM6IENvbnRhaW5lcjxLLCBWPltdKTogVltdIHtcclxuICAgICAgICBjb25zdCB1bndyYXBwZWRWYWx1ZXM6IFZbXSA9IG5ldyBBcnJheTxWPigpO1xyXG4gICAgICAgIHZhbHVlcy5mb3JFYWNoKGZ1bmN0aW9uICh2YWx1ZTogQ29udGFpbmVyPEssIFY+KSB7XHJcbiAgICAgICAgICAgIHZhbHVlLnRvQXJyYXkoKS5mb3JFYWNoKGZ1bmN0aW9uICh2YWw6IFYpIHtcclxuICAgICAgICAgICAgICAgIHVud3JhcHBlZFZhbHVlcy5wdXNoKHZhbCk7XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICByZXR1cm4gdW53cmFwcGVkVmFsdWVzO1xyXG4gICAgfVxyXG59XHJcblxyXG5leHBvcnQgY2xhc3MgU29ydGVkU3RyaW5nTXVsdGltYXA8Sz4gZXh0ZW5kcyBTb3J0ZWRNdWx0aW1hcDxLLCBzdHJpbmc+IHtcclxuICAgIGNvbnN0cnVjdG9yKGNvbXBhcmF0b3I6IENvbXBhcmF0b3I8Sz4pIHtcclxuICAgICAgICBzdXBlcihjb21wYXJhdG9yLCAodmFsdWUpID0+IHZhbHVlKTtcclxuICAgIH1cclxufVxyXG5cclxuLy8gYSBjb250YWluZXIgd2hpY2ggc3RvcmVzIGEgc2V0IG9mIHZhbHVlcyAoVikgYXNzb2NpYXRlZCB3aXRoIGEgc29ydGVkIGtleSAoSylcclxuLy8gT3JkZXJlZFNldCBvciBldmVuIEJpbmFyeVRyZWUgY291bGQgYmUgdXNlZCBoZXJlIGluc3RlYWRcclxuLy8gbW9yZSBzb3BoaXN0aWNhdGVkIHNldCBpbXBsZW1lbnRhdGlvbjogaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy83OTU4MjkyL21pbWlja2luZy1zZXRzLWluLWphdmFzY3JpcHRcclxuY2xhc3MgQ29udGFpbmVyPEssIFY+IHtcclxuXHJcbiAgICBwcml2YXRlIF9rZXk6IEs7XHJcbiAgICBwcml2YXRlIF92YWx1ZXM6IFN0cmluZ01hcDxWPjtcclxuXHJcbiAgICBjb25zdHJ1Y3RvcihrZXk6IEspIHtcclxuICAgICAgICB0aGlzLl9rZXkgPSBrZXk7XHJcbiAgICAgICAgdGhpcy5fdmFsdWVzID0ge307XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0IHNpemUoKTogbnVtYmVyIHtcclxuICAgICAgICByZXR1cm4gdGhpcy50b0FycmF5KCkubGVuZ3RoO1xyXG4gICAgfVxyXG5cclxuICAgIGdldCBrZXkoKTogSyB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX2tleTtcclxuICAgIH1cclxuXHJcbiAgICBnZXQgdmFsdWVzKCk6IFN0cmluZ01hcDxWPiB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX3ZhbHVlcztcclxuICAgIH1cclxuXHJcbiAgICB0b0FycmF5KCk6IFZbXSB7XHJcbiAgICAgICAgcmV0dXJuIE9iamVjdC5rZXlzKHRoaXMuX3ZhbHVlcykubWFwKGtleSA9PiB0aGlzLl92YWx1ZXNba2V5XSk7XHJcbiAgICB9XHJcblxyXG4gICAgY29udGFpbnModmFsdWU6IFYsIGlkRm46IElkRnVuY3Rpb248Vj4pOiBib29sZWFuIHtcclxuICAgICAgICAvLyBzYWZlciB0aGFuICd2YWx1ZSBpbiB0aGlzLl92YWx1ZXMnIGJlY2F1c2Ugb2YgcG90ZW50aWFsIGNvbmZsaWN0IHdpdGggYnVpbHQgaW4gcHJvcGVydGllcy9tZXRob2RzXHJcbiAgICAgICAgcmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0aGlzLl92YWx1ZXMsIGlkRm4odmFsdWUpKTtcclxuICAgIH1cclxuXHJcbiAgICBhZGQodmFsdWU6IFYsIGlkRm46IElkRnVuY3Rpb248Vj4pIHtcclxuICAgICAgICB0aGlzLl92YWx1ZXNbaWRGbih2YWx1ZSldID0gdmFsdWU7XHJcbiAgICB9XHJcblxyXG4gICAgcmVtb3ZlKHZhbHVlOiBWLCBpZEZuOiBJZEZ1bmN0aW9uPFY+KSB7XHJcbiAgICAgICAgZGVsZXRlIHRoaXMuX3ZhbHVlc1tpZEZuKHZhbHVlKV07XHJcbiAgICB9XHJcbn1cclxuXHJcbiJdfQ==