UNPKG

@gpa-gemstone/react-graph

Version:
568 lines 55.1 kB
"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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