UNPKG

43.4 kBJavaScriptView Raw
1"use strict";
2/*
3 * I need to do the following:
4 * diff angles between vectors
5 * find perpendicular vector to a point on a path
6 * find tangent to a point on a path
7 * transform (translate, rotate) for nodes and edges
8 * es modules so I can pull out just what I need
9 *
10 * Specs to compare:
11 * tests
12 * typescript
13 * maintained (open issues unresolved for a long time?)
14 * node and browser
15 */
16Object.defineProperty(exports, "__esModule", { value: true });
17exports.transform = exports.sameSide = exports.multiplyMatrixByVector = exports.getTransformationMatrix = exports.translate = exports.scale = exports.rotate = exports.multiplyMatrices = exports.invertMatrix = exports.getStartSideByOrientation = exports.getAngleFromPointToPoint = exports.getAngleAtPoint = exports.reverseAngle = exports.getAngleOfEmanationFromPoint = exports.getMinimumAngleBetweenVectors = exports.flipSide = exports.flipOrientation = exports.crossProduct = exports.addAngles = exports.SmartPath = exports.SmartVector = exports.SmartPoint = exports.START_SEGMENT_DETAILS_MAPS = exports.EMANATION_ANGLE_TO_START_SIDE_MAPPINGS = exports.START_SIDE_TO_EMANATION_ANGLE_MAPPINGS = exports.START_SIDE_TO_ORIENTATION_MAP = void 0;
18var lodash_1 = require("lodash");
19var fp_1 = require("lodash/fp");
20var Angle_1 = require("./spinoffs/Angle");
21var points_1 = require("points");
22// TODO why doesn't the following work?
23// Also, why doesn't ../node_modules/kaavio/lib/drawers/edges/ exist?
24//import * as edgeDrawers from "kaavio/src/drawers/edges/index";
25//import * as edgeDrawers from "../node_modules/kaavio/src/drawers/edges/index";
26//import * as edgeDrawers from "kaavio/src/drawers/edges/index";
27//import * as edgeDrawers from "kaavio/lib/drawers/edges/index";
28var edgeDrawers = require("./edge/edgeDrawers");
29// We are using the standard SVG coordinate system where:
30// the origin is the upper-left-most point
31// positive x is to the right
32// positive y is down
33// uses left hand rule, so positive angle is clockwise,
34// starting with 0 pointing to the right
35// The orientation is a unit vector that indicates the orientation of an
36// at a point. When it is attached to a rectangle, we almost always want it to
37// point away from the side to which it is attached.
38exports.START_SIDE_TO_ORIENTATION_MAP = {
39 right: [1, 0],
40 bottom: [0, 1],
41 left: [-1, 0],
42 top: [0, -1]
43};
44exports.START_SIDE_TO_EMANATION_ANGLE_MAPPINGS = fp_1.fromPairs(fp_1.toPairs(exports.START_SIDE_TO_ORIENTATION_MAP).map(function (_a) {
45 var startSide = _a[0], orientation = _a[1];
46 return [startSide, Angle_1.fromSlope([0, 0], orientation)];
47}));
48exports.EMANATION_ANGLE_TO_START_SIDE_MAPPINGS = fp_1.toPairs(exports.START_SIDE_TO_EMANATION_ANGLE_MAPPINGS).reduce(function (acc, _a) {
49 var side = _a[0], angle = _a[1];
50 acc.set(angle, side);
51 return acc;
52}, new Map());
53exports.START_SEGMENT_DETAILS_MAPS = fp_1.toPairs(exports.START_SIDE_TO_ORIENTATION_MAP).map(function (_a) {
54 var startSide = _a[0], orientation = _a[1];
55 var orientationX = orientation[0], orientationY = orientation[1];
56 return {
57 sideAttachedTo: startSide,
58 orientation: orientation,
59 angle: Angle_1.normalize(Math.atan2(orientationY, orientationX))
60 };
61});
62var SmartPoint = /** @class */ (function () {
63 //orientationVector?: SmartVector;
64 function SmartPoint(point) {
65 var _this = this;
66 this.angle = function () {
67 return Angle_1.fromSlope([0, 0], _this.orientation);
68 };
69 this.fromArray = function (_a) {
70 var x = _a[0], y = _a[1];
71 _this.x = x;
72 _this.y = y;
73 };
74 this.toArray = function () {
75 return [_this.x, _this.y];
76 };
77 lodash_1.assign(this, point);
78 /*
79 if (!isUndefined(this.orientation)) {
80 this.orientationVector = new SmartVector(
81 { x: 0, y: 0 },
82 { x: this.orientation[0], y: this.orientation[1] }
83 );
84 }
85 //*/
86 }
87 return SmartPoint;
88}());
89exports.SmartPoint = SmartPoint;
90var SmartVector = /** @class */ (function () {
91 function SmartVector(p0, p1) {
92 var _this = this;
93 this.angleDistance = function (vector2) {
94 return Angle_1.distance(_this.angle, vector2.angle);
95 };
96 this.p0 = new SmartPoint(p0);
97 this.p1 = new SmartPoint(p1);
98 this.angle = Angle_1.fromSlope(this.p0.toArray(), this.p1.toArray());
99 }
100 return SmartVector;
101}());
102exports.SmartVector = SmartVector;
103var SmartPath = /** @class */ (function () {
104 function SmartPath(points, edge) {
105 var _this = this;
106 this.position = function (scalar, accuracy) {
107 var _a = points_1.position(_this.path.points, scalar, accuracy), x = _a.x, y = _a.y, degreesFromNorth = _a.angle;
108 /* the points library returns the angle from north, in degrees, increasing CW, so
109 * this has an angle of 0 deg.:
110 *
111 * ^
112 * |
113 * |
114 * |
115 *
116 * and this has an angle of 90 deg.:
117 *
118 * ------->
119 */
120 return {
121 x: x,
122 y: y,
123 // convert to radians and use angle orientation of SVG coordinate system
124 angle: Angle_1.normalize(Angle_1.degreesToRadians(degreesFromNorth + 270))
125 };
126 };
127 var smartPoints = points.map(function (point) { return new SmartPoint(point); });
128 this.points = smartPoints;
129 this.sum = new SmartVector(smartPoints[0], fp_1.last(smartPoints));
130 if (!fp_1.isUndefined(edge)) {
131 var points_2 = edge.points, markerStart = edge.markerStart, markerEnd = edge.markerEnd;
132 this.path = new edgeDrawers[edge.drawAs](smartPoints, markerStart, markerEnd);
133 }
134 }
135 return SmartPath;
136}());
137exports.SmartPath = SmartPath;
138// TODO explore using the packages points and angles (and maybe vectory) together
139var smartPath1 = new SmartPath([
140 { x: 50, y: 30, moveTo: true },
141 { x: 50, y: 70, curve: { type: "arc", rx: 20, ry: 20, sweepFlag: 1 } },
142 { x: 150, y: 100, curve: { type: "arc", rx: 20, ry: 20, sweepFlag: 1 } }
143]);
144var smartPath2 = new SmartPath([
145 { x: 100, y: 50, moveTo: true },
146 { x: 50, y: 70, curve: { type: "arc", rx: 20, ry: 20, sweepFlag: 1 } }
147 //{ x: 200, y: 100 }
148]);
149/* OLD CODE BELOW */
150function addAngles(angle1, angle2) {
151 var sum = angle1 + angle2;
152 var singleRevolutionSum = sum % (2 * Math.PI);
153 return Math.sign(singleRevolutionSum) === -1
154 ? 2 * Math.PI + singleRevolutionSum
155 : singleRevolutionSum;
156}
157exports.addAngles = addAngles;
158// see https://gist.github.com/ahwolf/4349166 and
159// http://www.blackpawn.com/texts/pointinpoly/default.html
160function crossProduct(u, v) {
161 return u[0] * v[1] - v[0] * u[1];
162}
163exports.crossProduct = crossProduct;
164function flipOrientation(orientation) {
165 return orientation.map(function (orientationScalar) { return -1 * orientationScalar; });
166}
167exports.flipOrientation = flipOrientation;
168function flipSide(side) {
169 return exports.EMANATION_ANGLE_TO_START_SIDE_MAPPINGS.get(reverseAngle(exports.START_SIDE_TO_EMANATION_ANGLE_MAPPINGS[side]));
170}
171exports.flipSide = flipSide;
172function getMinimumAngleBetweenVectors(vectorDirectionAngle1, vectorDirectionAngle2) {
173 var vectors = [vectorDirectionAngle1, vectorDirectionAngle2];
174 var minVector = Math.min.apply(undefined, vectors);
175 var maxVector = Math.max.apply(undefined, vectors);
176 if (minVector < 0 || maxVector >= 2 * Math.PI) {
177 throw new Error("getMinimumAngleBetweenVectors(" + vectorDirectionAngle1 + ", " + vectorDirectionAngle2 + ")\n\t\t\t\t\t\t\t\t\t\tinputs must be in interval [0, 2 * Math.PI).");
178 }
179 return (Math.max(vectorDirectionAngle1, vectorDirectionAngle2) -
180 Math.min(vectorDirectionAngle1, vectorDirectionAngle2));
181 /*
182 const diff = addAngles(vectorDirectionAngle1, -1 * vectorDirectionAngle2);
183 return diff <= Math.PI ? diff : diff % Math.PI;
184 //*/
185 //return diff > Math.PI ? diff - Math.PI : diff;
186}
187exports.getMinimumAngleBetweenVectors = getMinimumAngleBetweenVectors;
188function getAngleOfEmanationFromPoint(point) {
189 var _a = point.orientation, orientationX = _a[0], orientationY = _a[1];
190 return Math.atan2(orientationY, orientationX);
191}
192exports.getAngleOfEmanationFromPoint = getAngleOfEmanationFromPoint;
193function reverseAngle(angle) {
194 return addAngles(angle, Math.PI);
195}
196exports.reverseAngle = reverseAngle;
197function getAngleAtPoint(edge, positionX) {
198 var id = edge.id, points = edge.points, markerStart = edge.markerStart, markerEnd = edge.markerEnd;
199 var referencedPath = new edgeDrawers[edge.drawAs.toLowerCase()](points, markerStart, markerEnd);
200 var tangentLength = 0.02;
201 var firstPointOfTangent = referencedPath.getPointAtPosition(Math.max(0, positionX - tangentLength / 2));
202 var lastPointOfTangent = referencedPath.getPointAtPosition(Math.min(1, positionX + tangentLength / 2));
203 return getAngleFromPointToPoint(firstPointOfTangent, lastPointOfTangent);
204}
205exports.getAngleAtPoint = getAngleAtPoint;
206function getAngleFromPointToPoint(_a, _b) {
207 var x0 = _a.x, y0 = _a.y;
208 var x1 = _b.x, y1 = _b.y;
209 return Math.atan2(y1 - y0, x1 - x0);
210}
211exports.getAngleFromPointToPoint = getAngleFromPointToPoint;
212function getStartSideByOrientation(_a) {
213 var orientationX = _a[0], orientationY = _a[1];
214 if (Math.abs(orientationX) > Math.abs(orientationY)) {
215 if (orientationX > 0) {
216 return "right"; //East
217 }
218 else {
219 return "left"; //West
220 }
221 }
222 else {
223 if (orientationY > 0) {
224 return "bottom"; //South
225 }
226 else {
227 return "top"; //North
228 }
229 }
230}
231exports.getStartSideByOrientation = getStartSideByOrientation;
232// see http://blog.acipo.com/matrix-inversion-in-javascript/
233/**
234 * Calculate the inverse matrix.
235 * @returns {Matrix}
236 */
237function invertMatrix(M) {
238 // I use Guassian Elimination to calculate the inverse:
239 // (1) 'augment' the matrix (left) by the identity (on the right)
240 // (2) Turn the matrix on the left into the identity by elemetry row ops
241 // (3) The matrix on the right is the inverse (was the identity matrix)
242 // There are 3 elemtary row ops: (I combine b and c in my code)
243 // (a) Swap 2 rows
244 // (b) Multiply a row by a scalar
245 // (c) Add 2 rows
246 //if the matrix isn't square: exit (error)
247 if (M.length !== M[0].length) {
248 return;
249 }
250 //create the identity matrix (I), and a copy (C) of the original
251 var i = 0, ii = 0, j = 0, dim = M.length, e = 0, t = 0;
252 var I = [], C = [];
253 for (i = 0; i < dim; i += 1) {
254 // Create the row
255 I[I.length] = [];
256 C[C.length] = [];
257 for (j = 0; j < dim; j += 1) {
258 //if we're on the diagonal, put a 1 (for identity)
259 if (i === j) {
260 I[i][j] = 1;
261 }
262 else {
263 I[i][j] = 0;
264 }
265 // Also, make the copy of the original
266 C[i][j] = M[i][j];
267 }
268 }
269 // Perform elementary row operations
270 for (i = 0; i < dim; i += 1) {
271 // get the element e on the diagonal
272 e = C[i][i];
273 // if we have a 0 on the diagonal (we'll need to swap with a lower row)
274 if (e === 0) {
275 //look through every row below the i'th row
276 for (ii = i + 1; ii < dim; ii += 1) {
277 //if the ii'th row has a non-0 in the i'th col
278 if (C[ii][i] !== 0) {
279 //it would make the diagonal have a non-0 so swap it
280 for (j = 0; j < dim; j++) {
281 e = C[i][j]; //temp store i'th row
282 C[i][j] = C[ii][j]; //replace i'th row by ii'th
283 C[ii][j] = e; //repace ii'th by temp
284 e = I[i][j]; //temp store i'th row
285 I[i][j] = I[ii][j]; //replace i'th row by ii'th
286 I[ii][j] = e; //repace ii'th by temp
287 }
288 //don't bother checking other rows since we've swapped
289 break;
290 }
291 }
292 //get the new diagonal
293 e = C[i][i];
294 //if it's still 0, not invertable (error)
295 if (e === 0) {
296 return;
297 }
298 }
299 // Scale this row down by e (so we have a 1 on the diagonal)
300 for (j = 0; j < dim; j++) {
301 C[i][j] = C[i][j] / e; //apply to original matrix
302 I[i][j] = I[i][j] / e; //apply to identity
303 }
304 // Subtract this row (scaled appropriately for each row) from ALL of
305 // the other rows so that there will be 0's in this column in the
306 // rows above and below this one
307 for (ii = 0; ii < dim; ii++) {
308 // Only apply to other rows (we want a 1 on the diagonal)
309 if (ii === i) {
310 continue;
311 }
312 // We want to change this element to 0
313 e = C[ii][i];
314 // Subtract (the row above(or below) scaled by e) from (the
315 // current row) but start at the i'th column and assume all the
316 // stuff left of diagonal is 0 (which it should be if we made this
317 // algorithm correctly)
318 for (j = 0; j < dim; j++) {
319 C[ii][j] -= e * C[i][j]; //apply to original matrix
320 I[ii][j] -= e * I[i][j]; //apply to identity
321 }
322 }
323 }
324 //we've done all operations, C should be the identity
325 //matrix I should be the inverse:
326 return I;
327}
328exports.invertMatrix = invertMatrix;
329// from http://tech.pro/tutorial/1527/matrix-multiplication-in-functional-javascript
330function multiplyMatrices(m1, m2) {
331 var result = [];
332 for (var i = 0; i < m1.length; i++) {
333 result[i] = [];
334 for (var j = 0; j < m2[0].length; j++) {
335 var sum = 0;
336 for (var k = 0; k < m1[0].length; k++) {
337 sum += m1[i][k] * m2[k][j];
338 }
339 result[i][j] = sum;
340 }
341 }
342 return result;
343}
344exports.multiplyMatrices = multiplyMatrices;
345/**
346 * rotate
347 *
348 * @param theta (float): rotation angle in radians, measured clockwise
349 * @return transformation matrix for rotation
350 *
351 * Note that for Canvas and SVG, the y axis points down:
352 *
353 * *---------> x
354 * |
355 * |
356 * |
357 * v
358 *
359 * y
360 *
361 * The transformation matrix returned takes this into account and is intentionally
362 * different from the transformation matrix that would be returned if the y-axis
363 * pointed up, as is common in many math classes.
364 */
365function rotate(theta) {
366 if (!fp_1.isFinite(theta)) {
367 throw new Error("Invalid input: rotate(" + theta + "). Requires a finite number.");
368 }
369 return [
370 [Math.cos(theta), -1 * Math.sin(theta), 0],
371 [Math.sin(theta), Math.cos(theta), 0],
372 [0, 0, 1]
373 ];
374}
375exports.rotate = rotate;
376function scale(_a) {
377 var xScale = _a[0], yScale = _a[1];
378 if (!fp_1.isFinite(xScale) || !fp_1.isFinite(yScale)) {
379 throw new Error("Invalid input: rotate([" + xScale + ", " + yScale + "]). Requires array of two finite numbers.");
380 }
381 return [[xScale, 0, 0], [0, yScale, 0], [0, 0, 1]];
382}
383exports.scale = scale;
384function translate(_a) {
385 var xTranslation = _a[0], yTranslation = _a[1];
386 if (!fp_1.isFinite(xTranslation) || !fp_1.isFinite(yTranslation)) {
387 throw new Error("Invalid input: translate([" + xTranslation + ", " + yTranslation + "]). Requires array of two finite numbers.");
388 }
389 return [[1, 0, xTranslation], [0, 1, yTranslation], [0, 0, 1]];
390}
391exports.translate = translate;
392var transformations = {
393 rotate: rotate,
394 scale: scale,
395 translate: translate
396};
397function getTransformationMatrix(transformationSequence) {
398 // Start with identity matrix
399 var concatenatedTransformationMatrix = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
400 transformationSequence.forEach(function (transformation) {
401 var thisTransformationMatrix = transformations[transformation.key](transformation.value);
402 concatenatedTransformationMatrix = multiplyMatrices(concatenatedTransformationMatrix, thisTransformationMatrix);
403 });
404 return concatenatedTransformationMatrix;
405}
406exports.getTransformationMatrix = getTransformationMatrix;
407function multiplyMatrixByVector(transformationMatrix, vector) {
408 var x = vector[0][0] * transformationMatrix[0][0] +
409 vector[1][0] * transformationMatrix[0][1] +
410 vector[2][0] * transformationMatrix[0][2], y = vector[0][0] * transformationMatrix[1][0] +
411 vector[1][0] * transformationMatrix[1][1] +
412 vector[2][0] * transformationMatrix[1][2], z = vector[0][0] * transformationMatrix[2][0] +
413 vector[1][0] * transformationMatrix[2][1] +
414 vector[2][0] * transformationMatrix[2][2];
415 return [[x], [y], [z]];
416}
417exports.multiplyMatrixByVector = multiplyMatrixByVector;
418/**
419 * sameSide
420 *
421 * Calculate whether the current edge's second point, a, (end of first segment)
422 * and its final point, b, are both on the same side of the referenced edge.
423 *
424 * current edge: pipes/hyphens
425 * referenced edge: dots
426 *
427 * Example of True
428 *
429 * p1
430 * .
431 * .
432 * *------------a
433 * . |
434 * . |
435 * . |
436 * . |
437 * . |
438 * . |
439 * . |
440 * . |
441 * . |
442 * . |
443 * . *-----b
444 * .
445 * .
446 * p2
447 *
448 *
449 * Example of False
450 *
451 * p1
452 * .
453 * *------------a
454 * . |
455 * . |
456 * . |
457 * . |
458 * . |
459 * .|
460 * |.
461 * | .
462 * | .
463 * | .
464 * *-----b .
465 * .
466 * p2
467 *
468 *
469 * @param {Object} p1 - first point of the referenced edge
470 * @param {Object} p2 - last point of the referenced edge
471 * @param {Object} a - last point of the first segment of the current edge (the point following the start point)
472 * @param {Object} b - point where the current edge ends
473 * @return {Boolean) - whether the last point of the first segment of the current edge is on the same side as the last point of the current edge
474 */
475function sameSide(p1, p2, a, b) {
476 var bMinusA = [b.x - a.x, b.y - a.y];
477 var p1MinusA = [p1.x - a.x, p1.y - a.y];
478 var p2MinusA = [p2.x - a.x, p2.y - a.y];
479 var crossProduct1 = crossProduct(bMinusA, p1MinusA);
480 var crossProduct2 = crossProduct(bMinusA, p2MinusA);
481 return Math.sign(crossProduct1) === Math.sign(crossProduct2);
482}
483exports.sameSide = sameSide;
484function transform(_a) {
485 var element = _a.element, transformOrigin = _a.transformOrigin, transformationSequence = _a.transformationSequence;
486 var x = element.x, y = element.y, width = element.width, height = element.height;
487 (transformOrigin = transformOrigin || "50% 50%"),
488 (transformationSequence = transformationSequence || []);
489 var transformOriginKeywordMappings = {
490 left: "0%",
491 center: "50%",
492 right: "100%",
493 top: "0%",
494 bottom: "100%"
495 };
496 var transformOriginKeywordMappingsKeys = Object.keys(transformOriginKeywordMappings);
497 var transformOriginPoint = transformOrigin
498 .split(" ")
499 .map(function (value, i) {
500 var numericOrPctValue;
501 var numericValue;
502 if (transformOriginKeywordMappingsKeys.indexOf(value) > -1) {
503 numericOrPctValue = transformOriginKeywordMappings[value];
504 }
505 else {
506 numericOrPctValue = value;
507 }
508 if (numericOrPctValue.indexOf("%") > -1) {
509 var decimalPercent = parseFloat(numericOrPctValue) / 100;
510 if (i === 0) {
511 numericValue = decimalPercent * width;
512 }
513 else {
514 numericValue = decimalPercent * height;
515 }
516 }
517 else if (value.indexOf("em") > -1) {
518 // TODO refactor. this is hacky.
519 numericValue = parseFloat(numericOrPctValue) * 12;
520 }
521 else {
522 numericValue = parseFloat(numericOrPctValue);
523 }
524 if (i === 0) {
525 numericValue += x;
526 }
527 else {
528 numericValue += y;
529 }
530 return numericValue;
531 });
532 // shift origin from top left corner of element bounding box to point specified by transformOrigin (default: center of bounding box)
533 transformationSequence.unshift({
534 key: "translate",
535 value: [transformOriginPoint[0], transformOriginPoint[1]]
536 });
537 // shift origin back to top left corner of element bounding box
538 transformationSequence.push({
539 key: "translate",
540 value: [-1 * transformOriginPoint[0], -1 * transformOriginPoint[1]]
541 });
542 var transformationMatrix = getTransformationMatrix(transformationSequence);
543 var topLeftPoint = [[x], [y], [1]];
544 var bottomRightPoint = [[x + width], [y + height], [1]];
545 var topLeftPointTransformed = multiplyMatrixByVector(transformationMatrix, topLeftPoint);
546 var bottomRightPointTransformed = multiplyMatrixByVector(transformationMatrix, bottomRightPoint);
547 element.x = topLeftPointTransformed[0][0];
548 element.y = topLeftPointTransformed[1][0];
549 element.width = bottomRightPointTransformed[0][0] - element.x;
550 element.height = bottomRightPointTransformed[1][0] - element.y;
551 return element;
552}
553exports.transform = transform;
554//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VvbS11dGlscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9nZW9tLXV0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7Ozs7OztHQWFHOzs7QUFFSCxpQ0FBMkM7QUFDM0MsZ0NBQTRFO0FBRTVFLDBDQUswQjtBQUMxQixpQ0FBa0M7QUFDbEMsdUNBQXVDO0FBQ3ZDLHFFQUFxRTtBQUNyRSxnRUFBZ0U7QUFDaEUsZ0ZBQWdGO0FBQ2hGLGdFQUFnRTtBQUNoRSxnRUFBZ0U7QUFDaEUsZ0RBQWtEO0FBV2xELHlEQUF5RDtBQUN6RCw0Q0FBNEM7QUFDNUMsK0JBQStCO0FBQy9CLHVCQUF1QjtBQUN2Qix5REFBeUQ7QUFDekQsNENBQTRDO0FBRTVDLHdFQUF3RTtBQUN4RSw4RUFBOEU7QUFDOUUsb0RBQW9EO0FBQ3ZDLFFBQUEsNkJBQTZCLEdBQUc7SUFDM0MsS0FBSyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNiLE1BQU0sRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDZCxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDYixHQUFHLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7Q0FDYixDQUFDO0FBRVcsUUFBQSxzQ0FBc0MsR0FBRyxjQUFTLENBQzdELFlBQU8sQ0FBQyxxQ0FBNkIsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxVQUFTLEVBR25EO1FBRkMsU0FBUyxRQUFBLEVBQ1QsV0FBVyxRQUFBO0lBRVgsT0FBTyxDQUFDLFNBQVMsRUFBRSxpQkFBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLFdBQVcsQ0FBQyxDQUFDLENBQUM7QUFDckQsQ0FBQyxDQUFDLENBQ0gsQ0FBQztBQUVXLFFBQUEsc0NBQXNDLEdBQUcsWUFBTyxDQUMzRCw4Q0FBc0MsQ0FDdkMsQ0FBQyxNQUFNLENBQUMsVUFBUyxHQUFHLEVBQUUsRUFB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
\No newline at end of file