@gpa-gemstone/react-graph
Version:
Interactive UI Components for GPA products
568 lines • 55.1 kB
JavaScript
"use strict";
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PointNode = void 0;
// ******************************************************************************************************
// PointNode.tsx - Gbtc
//
// Copyright © 2020, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this
// file except in compliance with the License. You may obtain a copy of the License at:
//
// http://opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 03/18/2021 - C Lackner
// Generated original version of source code.
//
// ******************************************************************************************************
var helper_functions_1 = require("@gpa-gemstone/helper-functions");
var MaxPoints = 20;
var DefaultMaxTotalPoints = 2000;
/**
*
* Node in a tree.
*/
var PointNode = /** @class */ (function () {
function PointNode(data, maxTotalPoints) {
var _this = this;
// The minimum/maximum time stamp that fits in this node
this.minT = NaN;
this.maxT = NaN;
// Intializing other vars
this.sum = [NaN];
this.count = NaN;
this.minV = [NaN];
this.maxV = [NaN];
this.children = null;
this.points = null;
this.dim = NaN;
if (maxTotalPoints !== undefined) {
this.maxCount = maxTotalPoints;
}
else {
if (data === undefined || data.length < DefaultMaxTotalPoints)
this.maxCount = DefaultMaxTotalPoints;
else {
this.maxCount = data.length;
console.warn("MaxTotalPoints was not provided to PointNode, adding new points will start removing the earliest points.");
}
}
if (data === undefined)
return;
this.dim = data.length === 0 ? NaN : data[0].length;
if (data.length !== 0 && data.some(function (point) { return point.length !== _this.dim; }))
throw new TypeError("Jagged data passed to PointNode. All points should all be ".concat(this.dim, " dimensions."));
// Initialize normally
this.initializeNode(data);
}
PointNode.createNodeWithDesiredTreeSize = function (data, desiredTreeSize) {
var node = new PointNode();
node.dim = data.length;
node.minT = data[0];
node.maxT = data[0];
node.count = 1;
node.sum = data.filter(function (_, i) { return i != 0; });
node.minV = data.filter(function (_, i) { return i != 0; });
node.maxV = data.filter(function (_, i) { return i != 0; });
if (desiredTreeSize === 1)
node.points = [data];
else
node.children = [PointNode.createNodeWithDesiredTreeSize(data, desiredTreeSize - 1)];
return node;
};
PointNode.CreateCopy = function (oldNode) {
var node = new PointNode();
node.dim = oldNode.dim;
node.minT = oldNode.minT;
node.maxT = oldNode.maxT;
node.minV = __spreadArray([], __read(oldNode.minV), false);
node.maxV = __spreadArray([], __read(oldNode.maxV), false);
node.sum = __spreadArray([], __read(oldNode.sum), false);
node.count = oldNode.count;
node.children = oldNode.children != null ? __spreadArray([], __read(oldNode.children), false) : null;
node.points = oldNode.points != null ? __spreadArray([], __read(oldNode.points), false) : null;
return node;
};
/**
* Initializes the node with the provided data points.
* Handles setting points or splitting into children based on the MaxPoints threshold.
* @param data An array of points to initialize the node with.
*/
PointNode.prototype.initializeNode = function (data) {
if (data.length <= MaxPoints) {
this.points = __spreadArray([], __read(data), false);
this.children = null;
}
else {
// Split into children
this.children = PointNode.splitPoints(data);
}
this.RecalculateStats();
};
/**
* Adds one set of points to the tree.
*
* @param newPoints points to add, one array of size dim
*/
PointNode.prototype.AddPoint = function (newPoints) {
if (Number.isNaN(this.dim))
this.dim = newPoints.length;
if (newPoints.length === 0)
throw new Error('No point to add');
if (newPoints.length !== this.dim)
throw new TypeError("Jagged data passed to PointNode.Add(). Points should be ".concat(this.dim, " dimension."));
if (this.TryAddPoints(newPoints)) {
if (this.count > this.maxCount)
this.removeLeftMostPoint();
return;
}
var copiedNode = PointNode.CreateCopy(this);
this.children = [copiedNode, PointNode.createNodeWithDesiredTreeSize(newPoints, this.GetTreeSize())];
this.points = null;
this.RecalculateStats();
if (this.count > this.maxCount)
this.removeLeftMostPoint();
};
/**
* Adds one set of points to the tree.
*
* @param newPoints points to add, one array of size dim
* @returns Success of add operation
*/
PointNode.prototype.TryAddPoints = function (newPoints) {
//Step 1 find tree size
var treeSize = this.GetTreeSize();
// Step 2: If TreeSize > 1, find the right-most child and call TryAddPoints recursively
if (treeSize > 1) {
if (this.children !== null) {
var rightMostChild = this.children[this.children.length - 1];
var result = rightMostChild.TryAddPoints(newPoints);
// Step 2a: If adding to the right-most child failed, check for node space and create a new child if possible
if (!result && this.children.length < MaxPoints) {
var newChild = PointNode.createNodeWithDesiredTreeSize(__spreadArray([], __read(newPoints), false), treeSize - 1);
this.children.push(newChild);
this.IncrementStatsForNewChild(newChild);
return true;
}
//return result of adding to the right-most child
if (result)
this.RecalculateStats();
return result;
}
}
//Step 3: If treesize === 1, check for point space in this node
if (this.points.length < MaxPoints) {
this.points.push(newPoints);
this.IncrementStatsForNewPoint(newPoints);
return true;
}
//Step 5: return results
return false;
};
/**
* Splits the given data points into child nodes based on the MaxPoints threshold.
* @param data An array of sorted points to split into child nodes.
*/
PointNode.splitPoints = function (data) {
var nLevel = 1;
while (Math.pow(MaxPoints, nLevel) < data.length) {
nLevel++;
}
var childBlockSize = Math.pow(MaxPoints, nLevel - 1);
var children = [];
var index = 0;
while (index < data.length) {
children.push(new PointNode(data.slice(index, index + childBlockSize)));
index = index + childBlockSize;
}
return children;
};
PointNode.prototype.removeLeftMostPoint = function () {
// If this is a leaf node, remove the first point
if (this.points !== null) {
if (this.points.length > 0)
this.points.shift();
}
else if (this.children !== null && this.children.length > 0) {
// remove the leftmost point from the first child
this.children[0].removeLeftMostPoint();
// If the first child is empty, remove it
if (this.children[0].count === 0)
this.children.shift();
}
this.RecalculateStats();
};
/**
* Updates the statistical properties of the node based on its current points or children.
*/
PointNode.prototype.RecalculateStats = function () {
if (this.points !== null) {
this.CalculatePointStats();
}
else if (this.children !== null) {
this.AggregateChildStats();
}
};
/**
* Updates statistics based on the current points.
*/
PointNode.prototype.CalculatePointStats = function () {
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
if (this.points === null)
return;
if (this.points.length === 0) {
// Set stats to indicate an empty node
this.count = 0;
this.minT = NaN;
this.maxT = NaN;
this.dim = NaN;
this.minV = [];
this.maxV = [];
this.sum = [];
return;
}
this.count = this.points.length;
this.minT = (_c = (_b = (_a = this.points) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : NaN;
this.maxT = (_f = (_e = (_d = this.points) === null || _d === void 0 ? void 0 : _d[this.points.length - 1]) === null || _e === void 0 ? void 0 : _e[0]) !== null && _f !== void 0 ? _f : NaN;
this.dim = (_j = (_h = (_g = this.points) === null || _g === void 0 ? void 0 : _g[0]) === null || _h === void 0 ? void 0 : _h.length) !== null && _j !== void 0 ? _j : NaN;
var _loop_1 = function (index) {
var values = this_1.points.map(function (pt) { return pt[index]; });
this_1.minV[index - 1] = (0, helper_functions_1.ComputeMin)(values);
this_1.maxV[index - 1] = (0, helper_functions_1.ComputeMax)(values);
this_1.sum[index - 1] = values.reduce(function (sum, val) {
if (isNaN(val))
return sum;
return sum + val;
}, 0);
};
var this_1 = this;
for (var index = 1; index < this.dim; index++) {
_loop_1(index);
}
};
/**
* Updates statistics based on the current children.
*/
PointNode.prototype.AggregateChildStats = function () {
if (this.children === null || this.children.length === 0)
return;
this.minT = (0, helper_functions_1.ComputeMin)(this.children.map(function (node) { return node.minT; }));
this.maxT = (0, helper_functions_1.ComputeMax)(this.children.map(function (node) { return node.maxT; }));
var _loop_2 = function (index) {
this_2.minV[index] = (0, helper_functions_1.ComputeMin)(this_2.children.map(function (node) { return node.minV[index]; }));
this_2.maxV[index] = (0, helper_functions_1.ComputeMax)(this_2.children.map(function (node) { return node.maxV[index]; }));
this_2.sum[index] = this_2.children.reduce(function (s, node) {
if (isNaN(node.sum[index]))
return s;
return s + node.sum[index];
}, 0);
};
var this_2 = this;
for (var index = 0; index < this.dim - 1; index++) {
_loop_2(index);
}
this.count = this.children.reduce(function (acc, node) { return acc + node.count; }, 0);
};
/**
* Updates aggregated statistics for this node to include a newly added child node.
*
* @param {PointNode} newChild - The new child node whose statistics will be merged into this node.
*/
PointNode.prototype.IncrementStatsForNewChild = function (newChild) {
// Update the time range
this.minT = (0, helper_functions_1.ComputeMin)([this.minT, newChild.minT]);
this.maxT = (0, helper_functions_1.ComputeMax)([this.maxT, newChild.maxT]);
// Update value ranges and sums
for (var i = 0; i < this.dim - 1; i++) {
this.minV[i] = (0, helper_functions_1.ComputeMin)([this.minV[i], newChild.minV[i]]);
this.maxV[i] = (0, helper_functions_1.ComputeMax)([this.maxV[i], newChild.maxV[i]]);
this.sum[i] += isNaN(newChild.sum[i]) ? 0 : newChild.sum[i];
}
this.count += newChild.count;
};
/**
* Updates aggregated statistics for this node to include a newly added point.
*
* @param {number[]} newPt - The new point
*/
PointNode.prototype.IncrementStatsForNewPoint = function (newPt) {
// Initialize stats if it's NaN
if (isNaN(this.count))
this.count = 0;
if (isNaN(this.minT))
this.minT = newPt[0];
if (isNaN(this.maxT))
this.maxT = newPt[0];
this.count += 1;
this.minT = (0, helper_functions_1.ComputeMin)([this.minT, newPt[0]]);
this.maxT = (0, helper_functions_1.ComputeMax)([this.maxT, newPt[0]]);
for (var i = 0; i < this.dim - 1; i++) {
var val = newPt[i + 1];
// 1) If the new value is NaN, don’t touch sum/minV/maxV for this dim
if (Number.isNaN(val))
continue;
// Initialize stats if they are NaN
if (isNaN(this.sum[i]))
this.sum[i] = 0;
if (isNaN(this.minV[i]))
this.minV[i] = val;
if (isNaN(this.maxV[i]))
this.maxV[i] = val;
// Update 'minV[i]', 'maxV[i]', and 'sum[i]' based on the condition
if (this.points !== null && this.points.length === 1) {
this.minV[i] = val;
this.maxV[i] = val;
this.sum[i] += val;
}
else {
this.minV[i] = (0, helper_functions_1.ComputeMin)([this.minV[i], val]);
this.maxV[i] = (0, helper_functions_1.ComputeMax)([this.maxV[i], val]);
this.sum[i] += val;
}
}
};
/**
* Retrieves data points within a specified time range.
* @param Tstart Start time of the timerange to be looked at.
* @param Tend End time of the timerange to be looked at.
* @param IncludeEdges Optional parameter to include edge points.
* @returns An array of points within the specified time range.
*/
PointNode.prototype.GetData = function (Tstart, Tend, IncludeEdges) {
var _this = this;
if (this.points != null && Tstart <= this.minT && Tend >= this.maxT)
return this.points;
if (this.points != null && IncludeEdges !== undefined && IncludeEdges)
return this.points.filter(function (pt, i) {
var _a, _b;
return (pt[0] >= Tstart && pt[0] <= Tend) ||
i < (((_b = (_a = _this.points) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) - 1) && (_this.points != null ? _this.points[i + 1][0] : 0) >= Tstart ||
i > 0 && (_this.points != null ? _this.points[i - 1][0] : 0) <= Tend;
});
if (this.points != null)
return this.points.filter(function (pt) { return pt[0] >= Tstart && pt[0] <= Tend; });
var result = [];
return result.concat.apply(result, __spreadArray([], __read(this.children.filter(function (node) {
return (node.minT <= Tstart && node.maxT > Tstart) ||
(node.maxT >= Tend && node.minT < Tend) ||
(node.minT >= Tstart && node.maxT <= Tend);
}).map(function (node) { return node.GetData(Tstart, Tend, IncludeEdges); })), false));
};
/**
* Retrieves all data points stored in the PointNode tree.
* @returns An array of all points in the tre.
*/
PointNode.prototype.GetFullData = function () {
return this.GetData(this.minT, this.maxT);
};
/**
* Retrieves the count of data points within a specified time range.
* @param Tstart Start time of the timerange to be looked at.
* @param Tend End time of the timerange to be looked at.
* @returns The number of points within the specified time range.
*/
PointNode.prototype.GetCount = function (Tstart, Tend) {
// Case 1: Leaf Node with points
if (this.points !== null) {
// Entire node is within the range
if (Tstart <= this.minT && Tend >= this.maxT)
return this.count;
// Standard range filtering
return this.points.reduce(function (acc, pt) { return acc + (pt[0] >= Tstart && pt[0] <= Tend ? 1 : 0); }, 0);
}
// Case 2: Internal Node with children
if (this.children !== null)
return this.children.reduce(function (acc, node) { return acc + (node.minT <= Tend && node.maxT >= Tstart ? node.GetCount(Tstart, Tend) : 0); }, 0);
// Case 3: No points or children match
return 0;
};
/**
* Get Limits for all dimensions
* @param Tstart start time of the timerange to be looked at
* @param Tend end time of the timerange to be looked at
* @returns The min and max value of the data in the given timerange
*/
PointNode.prototype.GetAllLimits = function (Tstart, Tend) {
var result = Array(this.dim - 1);
for (var index = 0; index < this.dim - 1; index++)
result[index] = this.GetLimits(Tstart, Tend, index);
return result;
};
/**
* Retrieves the limits of the data in the given timerange
* @param Tstart start time of the timerange to be looked at
* @param Tend end time of the timerange to be looked at
* @param dimension dimension of the data to be retrieved (x,y,z) to get y use 0
* @returns The min and max value of the data in the given timerange
*/
// Note: Dimension indexing does not include time, I.E. in (x,y), y would be dimension 0;
PointNode.prototype.GetLimits = function (Tstart, Tend, dimension) {
var currentIndex = dimension !== null && dimension !== void 0 ? dimension : 0;
var max = this.maxV[currentIndex];
var min = this.minV[currentIndex];
if (this.points == null && !(Tstart <= this.minT && Tend > this.maxT)) {
// Array represents all limits o nodes
var limits = this.children.filter(function (n) { return n.maxT > Tstart && n.minT < Tend; }).map(function (n) { return n.GetLimits(Tstart, Tend, currentIndex); });
min = (0, helper_functions_1.ComputeMin)(limits.map(function (pt) { return pt[0]; }));
max = (0, helper_functions_1.ComputeMax)(limits.map(function (pt) { return pt[1]; }));
}
if (this.points != null && !(Tstart <= this.minT && Tend > this.maxT)) {
// Array represents all numbers within this node that fall in range
var limits = this.points.filter(function (pt) { return pt[0] > Tstart && pt[0] < Tend; }).map(function (pt) { return pt[currentIndex + 1]; });
min = (0, helper_functions_1.ComputeMin)(limits);
max = (0, helper_functions_1.ComputeMax)(limits);
}
return [min, max];
};
/**
* Retrieves a point from the PointNode tree
* @param {number} tVal - The time value of the point to retrieve from the tree.
*/
PointNode.prototype.GetPoint = function (tVal) {
return this.PointBinarySearch(tVal, 1)[0];
};
/**
* Retrieves a specified number of points from the PointNode tree, centered around a point
* @param {number} tVal - The time value of the center point of the point retrieval.
* @param {number} pointsRetrieved - The number of points to retrieve
*/
PointNode.prototype.GetPoints = function (tVal, pointsRetrieved) {
if (pointsRetrieved === void 0) { pointsRetrieved = 1; }
return this.PointBinarySearch(tVal, pointsRetrieved);
};
/**
* Implements a binary search to locate points within the PointNode tree or across neighboring nodes based on the timestamp.
* @param tVal The time value to search for.
* @param pointsRetrieved The number of points to retrieve.
* @param nodeLowerNeighbor Optional lower neighboring node for spillover.
* @param nodeUpperNeighbor Optional upper neighboring node for spillover.
* @returns An array of points matching the search criteria.
*/
PointNode.prototype.PointBinarySearch = function (tVal, pointsRetrieved, nodeLowerNeighbor, nodeUpperNeighbor) {
if (pointsRetrieved === void 0) { pointsRetrieved = 1; }
if (pointsRetrieved <= 0)
throw new RangeError("Requested number of points must be positive value.");
// round tVal back to whole integer
if (this.points !== null) {
if (this.points.length === 0)
return [[NaN]]; //points should only ever be empty when an empty array is passed into constructor
// if the tVal is less than the minimum value of the subsection, return the first point
if (tVal < this.minT) {
var spillOver = pointsRetrieved - this.points.length;
var spillOverPoints = (spillOver > 0 && nodeUpperNeighbor !== undefined) ? nodeUpperNeighbor.PointBinarySearch(tVal, spillOver, this, undefined) : [];
return this.points.slice(0, pointsRetrieved).concat(spillOverPoints);
}
// if the tVal is greater than the largest value of the subsection, return the last point
if (tVal > this.maxT) {
var spillOver = pointsRetrieved - this.points.length;
var spillOverPoints = (spillOver > 0 && nodeLowerNeighbor !== undefined) ? nodeLowerNeighbor.PointBinarySearch(tVal, spillOver, undefined, this) : [];
return spillOverPoints.concat(this.points.slice(-pointsRetrieved));
}
// Otherwise, perform binary search
var upper = this.points.length - 1;
var lower = 0;
var Tlower = this.minT;
var Tupper = this.maxT;
while (Tupper !== tVal && Tlower !== tVal && upper !== lower && Tupper !== Tlower) {
var center = Math.round((upper + lower) / 2);
var Tcenter = this.points[center][0];
if (center === upper || center === lower)
break;
if (Tcenter <= tVal)
lower = center;
if (Tcenter > tVal)
upper = center;
Tupper = this.points[upper][0];
Tlower = this.points[lower][0];
}
var upperPoints = Math.floor(pointsRetrieved / 2);
var lowerPoints = upperPoints;
// Adjustment for even number of points
var sidingAdjust = pointsRetrieved % 2 === 0 ? 1 : 0;
var centerIndex = void 0;
if (Math.abs(tVal - Tlower) < Math.abs(tVal - Tupper)) {
centerIndex = lower;
lowerPoints -= sidingAdjust;
}
else {
centerIndex = upper;
upperPoints -= sidingAdjust;
}
// Note: If we have spillover and no neighbor on the spillover side, then we discard the idea of spillover, and just return as many as we can on that side
var upperSpillOver = centerIndex + upperPoints + 1 - this.points.length;
var upperNeighborPoints = (upperSpillOver > 0 && nodeUpperNeighbor !== undefined) ? nodeUpperNeighbor.PointBinarySearch(tVal, upperSpillOver, this, undefined) : [];
var lowerSpillOver = lowerPoints - centerIndex;
var lowerNeighborPoints = (lowerSpillOver > 0 && nodeLowerNeighbor !== undefined) ? nodeLowerNeighbor.PointBinarySearch(tVal, lowerSpillOver, undefined, this) : [];
return lowerNeighborPoints.concat(this.points.slice((0, helper_functions_1.ComputeMax)([centerIndex - lowerPoints, 0]), (0, helper_functions_1.ComputeMin)([centerIndex + upperPoints + 1, this.points.length]))).concat(upperNeighborPoints);
}
else if (this.children !== null) {
var childIndex = -1;
// if the subsection is null, and the tVal is less than the minimum value of the subsection, ??Start over again looking for the point in the first subsection??
if (tVal < this.minT)
childIndex = 0;
else if (tVal > this.maxT)
childIndex = this.children.length - 1;
else {
childIndex = this.children.findIndex(function (n) { return n.maxT >= tVal; });
if (childIndex > 0 && this.children[childIndex].minT > tVal) {
var currentChildMinT = this.children[childIndex].minT;
var previousChildMaxT = this.children[childIndex - 1].maxT;
if (Math.abs(tVal - previousChildMaxT) < Math.abs(tVal - currentChildMinT))
childIndex--;
}
}
if (childIndex === -1)
throw new RangeError("Could not find child node with point that has a time value of ".concat(tVal));
// Find neighbors
var upperNeighbor = childIndex !== this.children.length - 1 ? this.children[childIndex + 1] : undefined;
var lowerNeighbor = childIndex !== 0 ? this.children[childIndex - 1] : undefined;
return this.children[childIndex].PointBinarySearch(tVal, pointsRetrieved, lowerNeighbor, upperNeighbor);
}
else
throw new RangeError("Both children and points are null for PointNode, unable to find point with time value of ".concat(tVal));
};
/**
* Returns the size of the Tree below this PointNode
*/
PointNode.prototype.GetTreeSize = function () {
if (this.children == null)
return 1;
return 1 + Math.max.apply(Math, __spreadArray([], __read(this.children.map(function (node) { return node.GetTreeSize(); })), false));
};
return PointNode;
}());
exports.PointNode = PointNode;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUG9pbnROb2RlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL1BvaW50Tm9kZS50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLHlHQUF5RztBQUN6Ryx3QkFBd0I7QUFDeEIsRUFBRTtBQUNGLHFFQUFxRTtBQUNyRSxFQUFFO0FBQ0Ysd0dBQXdHO0FBQ3hHLHdHQUF3RztBQUN4RyxzR0FBc0c7QUFDdEcsd0ZBQXdGO0FBQ3hGLEVBQUU7QUFDRiwwQ0FBMEM7QUFDMUMsRUFBRTtBQUNGLHdHQUF3RztBQUN4Ryx3R0FBd0c7QUFDeEcsNEVBQTRFO0FBQzVFLEVBQUU7QUFDRiw4QkFBOEI7QUFDOUIsd0dBQXdHO0FBQ3hHLDBCQUEwQjtBQUMxQixtREFBbUQ7QUFDbkQsRUFBRTtBQUNGLHlHQUF5RztBQUN6RyxtRUFBdUU7QUFFdkUsSUFBTSxTQUFTLEdBQUcsRUFBRSxDQUFDO0FBQ3JCLElBQU0scUJBQXFCLEdBQUcsSUFBSSxDQUFDO0FBRW5DOzs7R0FHRztBQUNIO0lBY0ksbUJBQVksSUFBaUIsRUFBRSxjQUF1QjtRQUF0RCxpQkFrQ0M7UUFqQ0csd0RBQXdEO1FBQ3hELElBQUksQ0FBQyxJQUFJLEdBQUcsR0FBRyxDQUFDO1FBQ2hCLElBQUksQ0FBQyxJQUFJLEdBQUcsR0FBRyxDQUFDO1FBRWhCLHlCQUF5QjtRQUN6QixJQUFJLENBQUMsR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDakIsSUFBSSxDQUFDLEtBQUssR0FBRyxHQUFHLENBQUM7UUFDakIsSUFBSSxDQUFDLElBQUksR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2xCLElBQUksQ0FBQyxJQUFJLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNsQixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztRQUNyQixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQztRQUNuQixJQUFJLENBQUMs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TUFBTSxJQUFJLElBQUksSUFBSSxNQUFNLElBQUksSUFBSSxDQUFDLElBQUksSUFBSSxJQUFJLElBQUksSUFBSSxDQUFDLElBQUk7WUFDL0QsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQ3ZCLElBQUksSUFBSSxDQUFDLE1BQU0sSUFBSSxJQUFJLElBQUksWUFBWSxLQUFLLFNBQVMsSUFBSSxZQUFZO1lBQ2pFLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsVUFBQyxFQUFFLEVBQUUsQ0FBQzs7Z0JBQUssT0FBQSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxNQUFNLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQztvQkFDbkUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFBLE1BQUEsS0FBSSxDQUFDLE1BQU0sMENBQUUsTUFBTSxtQ0FBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUksQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksTUFBTTtvQkFDbkcsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUksQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFBO2FBQUEsQ0FBQyxDQUFDO1FBQzVFLElBQUksSUFBSSxDQUFDLE1BQU0sSUFBSSxJQUFJO1lBQ25CLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsVUFBQSxFQUFFLElBQUksT0FBQSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksTUFBTSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLEVB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