dygraphs
Version:
dygraphs is a fast, flexible open source JavaScript charting library.
154 lines (142 loc) • 19.1 kB
JavaScript
/**
* @license
* Part of dygraphs, see top-level LICENSE.txt file
* MIT-licenced: https://opensource.org/licenses/MIT
*/
/* loader wrapper to allow browser use and ES6 imports */
(function _extras_smoothPlotter_closure() {
'use strict';
var Dygraph;
if (window.Dygraph) {
Dygraph = window.Dygraph;
} else if (typeof module !== 'undefined') {
Dygraph = require('../dygraph');
if (typeof Dygraph.NAME === 'undefined' && typeof Dygraph["default"] !== 'undefined') Dygraph = Dygraph["default"];
}
/* end of loader wrapper header */
/**
* Given three sequential points, p0, p1 and p2, find the left and right
* control points for p1.
*
* The three points are expected to have x and y properties.
*
* The alpha parameter controls the amount of smoothing.
* If α=0, then both control points will be the same as p1 (i.e. no smoothing).
*
* Returns [l1x, l1y, r1x, r1y]
*
* It's guaranteed that the line from (l1x, l1y)-(r1x, r1y) passes through p1.
* Unless allowFalseExtrema is set, then it's also guaranteed that:
* l1y ∈ [p0.y, p1.y]
* r1y ∈ [p1.y, p2.y]
*
* The basic algorithm is:
* 1. Put the control points l1 and r1 α of the way down (p0, p1) and (p1, p2).
* 2. Shift l1 and r2 so that the line l1–r1 passes through p1
* 3. Adjust to prevent false extrema while keeping p1 on the l1–r1 line.
*
* This is loosely based on the HighCharts algorithm.
*/
function getControlPoints(p0, p1, p2, opt_alpha, opt_allowFalseExtrema) {
var alpha = opt_alpha !== undefined ? opt_alpha : 1 / 3; // 0=no smoothing, 1=crazy smoothing
var allowFalseExtrema = opt_allowFalseExtrema || false;
if (!p2) {
return [p1.x, p1.y, null, null];
}
// Step 1: Position the control points along each line segment.
var l1x = (1 - alpha) * p1.x + alpha * p0.x,
l1y = (1 - alpha) * p1.y + alpha * p0.y,
r1x = (1 - alpha) * p1.x + alpha * p2.x,
r1y = (1 - alpha) * p1.y + alpha * p2.y;
// Step 2: shift the points up so that p1 is on the l1–r1 line.
if (l1x != r1x) {
// This can be derived w/ some basic algebra.
var deltaY = p1.y - r1y - (p1.x - r1x) * (l1y - r1y) / (l1x - r1x);
l1y += deltaY;
r1y += deltaY;
}
// Step 3: correct to avoid false extrema.
if (!allowFalseExtrema) {
if (l1y > p0.y && l1y > p1.y) {
l1y = Math.max(p0.y, p1.y);
r1y = 2 * p1.y - l1y;
} else if (l1y < p0.y && l1y < p1.y) {
l1y = Math.min(p0.y, p1.y);
r1y = 2 * p1.y - l1y;
}
if (r1y > p1.y && r1y > p2.y) {
r1y = Math.max(p1.y, p2.y);
l1y = 2 * p1.y - r1y;
} else if (r1y < p1.y && r1y < p2.y) {
r1y = Math.min(p1.y, p2.y);
l1y = 2 * p1.y - r1y;
}
}
return [l1x, l1y, r1x, r1y];
}
// i.e. is none of (null, undefined, NaN)
function isOK(x) {
return !!x && !isNaN(x);
}
;
// A plotter which uses splines to create a smooth curve.
// See tests/plotters.html for a demo.
// Can be controlled via smoothPlotter.smoothing
function smoothPlotter(e) {
var ctx = e.drawingContext,
points = e.points;
ctx.beginPath();
ctx.moveTo(points[0].canvasx, points[0].canvasy);
// right control point for previous point
var lastRightX = points[0].canvasx,
lastRightY = points[0].canvasy;
for (var i = 1; i < points.length; i++) {
var p0 = points[i - 1],
p1 = points[i],
p2 = points[i + 1];
p0 = p0 && isOK(p0.canvasy) ? p0 : null;
p1 = p1 && isOK(p1.canvasy) ? p1 : null;
p2 = p2 && isOK(p2.canvasy) ? p2 : null;
if (p0 && p1) {
var controls = getControlPoints({
x: p0.canvasx,
y: p0.canvasy
}, {
x: p1.canvasx,
y: p1.canvasy
}, p2 && {
x: p2.canvasx,
y: p2.canvasy
}, smoothPlotter.smoothing);
// Uncomment to show the control points:
// ctx.lineTo(lastRightX, lastRightY);
// ctx.lineTo(controls[0], controls[1]);
// ctx.lineTo(p1.canvasx, p1.canvasy);
lastRightX = lastRightX !== null ? lastRightX : p0.canvasx;
lastRightY = lastRightY !== null ? lastRightY : p0.canvasy;
ctx.bezierCurveTo(lastRightX, lastRightY, controls[0], controls[1], p1.canvasx, p1.canvasy);
lastRightX = controls[2];
lastRightY = controls[3];
} else if (p1) {
// We're starting again after a missing point.
ctx.moveTo(p1.canvasx, p1.canvasy);
lastRightX = p1.canvasx;
lastRightY = p1.canvasy;
} else {
lastRightX = lastRightY = null;
}
}
ctx.stroke();
}
smoothPlotter.smoothing = 1 / 3;
smoothPlotter._getControlPoints = getControlPoints; // for testing
// older versions exported a global.
// This will be removed in the future.
// The preferred way to access smoothPlotter is via Dygraph.smoothPlotter.
window.smoothPlotter = smoothPlotter;
Dygraph.smoothPlotter = smoothPlotter;
/* closure and loader wrapper */
Dygraph._require.add('dygraphs/src/extras/smooth-plotter.js', /* exports */{});
})();
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfZXh0cmFzX3Ntb290aFBsb3R0ZXJfY2xvc3VyZSIsIkR5Z3JhcGgiLCJ3aW5kb3ciLCJtb2R1bGUiLCJyZXF1aXJlIiwiTkFNRSIsImdldENvbnRyb2xQb2ludHMiLCJwMCIsInAxIiwicDIiLCJvcHRfYWxwaGEiLCJvcHRfYWxsb3dGYWxzZUV4dHJlbWEiLCJhbHBoYSIsInVuZGVmaW5lZCIsImFsbG93RmFsc2VFeHRyZW1hIiwieCIsInkiLCJsMXgiLCJsMXkiLCJyMXgiLCJyMXkiLCJkZWx0YVkiLCJNYXRoIiwibWF4IiwibWluIiwiaXNPSyIsImlzTmFOIiwic21vb3RoUGxvdHRlciIsImUiLCJjdHgiLCJkcmF3aW5nQ29udGV4dCIsInBvaW50cyIsImJlZ2luUGF0aCIsIm1vdmVUbyIsImNhbnZhc3giLCJjYW52YXN5IiwibGFzdFJpZ2h0WCIsImxhc3RSaWdodFkiLCJpIiwibGVuZ3RoIiwiY29udHJvbHMiLCJzbW9vdGhpbmciLCJiZXppZXJDdXJ2ZVRvIiwic3Ryb2tlIiwiX2dldENvbnRyb2xQb2ludHMiLCJfcmVxdWlyZSIsImFkZCJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9leHRyYXMvc21vb3RoLXBsb3R0ZXIuanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogUGFydCBvZiBkeWdyYXBocywgc2VlIHRvcC1sZXZlbCBMSUNFTlNFLnR4dCBmaWxlXG4gKiBNSVQtbGljZW5jZWQ6IGh0dHBzOi8vb3BlbnNvdXJjZS5vcmcvbGljZW5zZXMvTUlUXG4gKi9cblxuLyogbG9hZGVyIHdyYXBwZXIgdG8gYWxsb3cgYnJvd3NlciB1c2UgYW5kIEVTNiBpbXBvcnRzICovXG4oZnVuY3Rpb24gX2V4dHJhc19zbW9vdGhQbG90dGVyX2Nsb3N1cmUoKSB7XG4ndXNlIHN0cmljdCc7XG52YXIgRHlncmFwaDtcbmlmICh3aW5kb3cuRHlncmFwaCkge1xuICBEeWdyYXBoID0gd2luZG93LkR5Z3JhcGg7XG59IGVsc2UgaWYgKHR5cGVvZihtb2R1bGUpICE9PSAndW5kZWZpbmVkJykge1xuICBEeWdyYXBoID0gcmVxdWlyZSgnLi4vZHlncmFwaCcpO1xuICBpZiAodHlwZW9mKER5Z3JhcGguTkFNRSkgPT09ICd1bmRlZmluZWQnICYmIHR5cGVvZihEeWdyYXBoLmRlZmF1bHQpICE9PSAndW5kZWZpbmVkJylcbiAgICBEeWdyYXBoID0gRHlncmFwaC5kZWZhdWx0O1xufVxuLyogZW5kIG9mIGxvYWRlciB3cmFwcGVyIGhlYWRlciAqL1xuXG4vKipcbiAqIEdpdmVuIHRocmVlIHNlcXVlbnRpYWwgcG9pbnRzLCBwMCwgcDEgYW5kIHAyLCBmaW5kIHRoZSBsZWZ0IGFuZCByaWdodFxuICogY29udHJvbCBwb2ludHMgZm9yIHAxLlxuICpcbiAqIFRoZSB0aHJlZSBwb2ludHMgYXJlIGV4cGVjdGVkIHRvIGhhdmUgeCBhbmQgeSBwcm9wZXJ0aWVzLlxuICpcbiAqIFRoZSBhbHBoYSBwYXJhbWV0ZXIgY29udHJvbHMgdGhlIGFtb3VudCBvZiBzbW9vdGhpbmcuXG4gKiBJZiDOsT0wLCB0aGVuIGJvdGggY29udHJvbCBwb2ludHMgd2lsbCBiZSB0aGUgc2FtZSBhcyBwMSAoaS5lLiBubyBzbW9vdGhpbmcpLlxuICpcbiAqIFJldHVybnMgW2wxeCwgbDF5LCByMXgsIHIxeV1cbiAqXG4gKiBJdCdzIGd1YXJhbnRlZWQgdGhhdCB0aGUgbGluZSBmcm9tIChsMXgsIGwxeSktKHIxeCwgcjF5KSBwYXNzZXMgdGhyb3VnaCBwMS5cbiAqIFVubGVzcyBhbGxvd0ZhbHNlRXh0cmVtYSBpcyBzZXQsIHRoZW4gaXQncyBhbHNvIGd1YXJhbnRlZWQgdGhhdDpcbiAqICAgbDF5IOKIiCBbcDAueSwgcDEueV1cbiAqICAgcjF5IOKIiCBbcDEueSwgcDIueV1cbiAqXG4gKiBUaGUgYmFzaWMgYWxnb3JpdGhtIGlzOlxuICogMS4gUHV0IHRoZSBjb250cm9sIHBvaW50cyBsMSBhbmQgcjEgzrEgb2YgdGhlIHdheSBkb3duIChwMCwgcDEpIGFuZCAocDEsIHAyKS5cbiAqIDIuIFNoaWZ0IGwxIGFuZCByMiBzbyB0aGF0IHRoZSBsaW5lIGwx4oCTcjEgcGFzc2VzIHRocm91Z2ggcDFcbiAqIDMuIEFkanVzdCB0byBwcmV2ZW50IGZhbHNlIGV4dHJlbWEgd2hpbGUga2VlcGluZyBwMSBvbiB0aGUgbDHigJNyMSBsaW5lLlxuICpcbiAqIFRoaXMgaXMgbG9vc2VseSBiYXNlZCBvbiB0aGUgSGlnaENoYXJ0cyBhbGdvcml0aG0uXG4gKi9cbmZ1bmN0aW9uIGdldENvbnRyb2xQb2ludHMocDAsIHAxLCBwMiwgb3B0X2FscGhhLCBvcHRfYWxsb3dGYWxzZUV4dHJlbWEpIHtcbiAgdmFyIGFscGhhID0gKG9wdF9hbHBoYSAhPT0gdW5kZWZpbmVkKSA/IG9wdF9hbHBoYSA6IDEvMzsgIC8vIDA9bm8gc21vb3RoaW5nLCAxPWNyYXp5IHNtb290aGluZ1xuICB2YXIgYWxsb3dGYWxzZUV4dHJlbWEgPSBvcHRfYWxsb3dGYWxzZUV4dHJlbWEgfHwgZmFsc2U7XG5cbiAgaWYgKCFwMikge1xuICAgIHJldHVybiBbcDEueCwgcDEueSwgbnVsbCwgbnVsbF07XG4gIH1cblxuICAvLyBTdGVwIDE6IFBvc2l0aW9uIHRoZSBjb250cm9sIHBvaW50cyBhbG9uZyBlYWNoIGxpbmUgc2VnbWVudC5cbiAgdmFyIGwxeCA9ICgxIC0gYWxwaGEpICogcDEueCArIGFscGhhICogcDAueCxcbiAgICAgIGwxeSA9ICgxIC0gYWxwaGEpICogcDEueSArIGFscGhhICogcDAueSxcbiAgICAgIHIxeCA9ICgxIC0gYWxwaGEpICogcDEueCArIGFscGhhICogcDIueCxcbiAgICAgIHIxeSA9ICgxIC0gYWxwaGEpICogcDEueSArIGFscGhhICogcDIueTtcblxuICAvLyBTdGVwIDI6IHNoaWZ0IHRoZSBwb2ludHMgdXAgc28gdGhhdCBwMSBpcyBvbiB0aGUgbDHigJNyMSBsaW5lLlxuICBpZiAobDF4ICE9IHIxeCkge1xuICAgIC8vIFRoaXMgY2FuIGJlIGRlcml2ZWQgdy8gc29tZSBiYXNpYyBhbGdlYnJhLlxuICAgIHZhciBkZWx0YVkgPSBwMS55IC0gcjF5IC0gKHAxLnggLSByMXgpICogKGwxeSAtIHIxeSkgLyAobDF4IC0gcjF4KTtcbiAgICBsMXkgKz0gZGVsdGFZO1xuICAgIHIxeSArPSBkZWx0YVk7XG4gIH1cblxuICAvLyBTdGVwIDM6IGNvcnJlY3QgdG8gYXZvaWQgZmFsc2UgZXh0cmVtYS5cbiAgaWYgKCFhbGxvd0ZhbHNlRXh0cmVtYSkge1xuICAgIGlmIChsMXkgPiBwMC55ICYmIGwxeSA+IHAxLnkpIHtcbiAgICAgIGwxeSA9IE1hdGgubWF4KHAwLnksIHAxLnkpO1xuICAgICAgcjF5ID0gMiAqIHAxLnkgLSBsMXk7XG4gICAgfSBlbHNlIGlmIChsMXkgPCBwMC55ICYmIGwxeSA8IHAxLnkpIHtcbiAgICAgIGwxeSA9IE1hdGgubWluKHAwLnksIHAxLnkpO1xuICAgICAgcjF5ID0gMiAqIHAxLnkgLSBsMXk7XG4gICAgfVxuXG4gICAgaWYgKHIxeSA+IHAxLnkgJiYgcjF5ID4gcDIueSkge1xuICAgICAgcjF5ID0gTWF0aC5tYXgocDEueSwgcDIueSk7XG4gICAgICBsMXkgPSAyICogcDEueSAtIHIxeTtcbiAgICB9IGVsc2UgaWYgKHIxeSA8IHAxLnkgJiYgcjF5IDwgcDIueSkge1xuICAgICAgcjF5ID0gTWF0aC5taW4ocDEueSwgcDIueSk7XG4gICAgICBsMXkgPSAyICogcDEueSAtIHIxeTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gW2wxeCwgbDF5LCByMXgsIHIxeV07XG59XG5cbi8vIGkuZS4gaXMgbm9uZSBvZiAobnVsbCwgdW5kZWZpbmVkLCBOYU4pXG5mdW5jdGlvbiBpc09LKHgpIHtcbiAgcmV0dXJuICEheCAmJiAhaXNOYU4oeCk7XG59O1xuXG4vLyBBIHBsb3R0ZXIgd2hpY2ggdXNlcyBzcGxpbmVzIHRvIGNyZWF0ZSBhIHNtb290aCBjdXJ2ZS5cbi8vIFNlZSB0ZXN0cy9wbG90dGVycy5odG1sIGZvciBhIGRlbW8uXG4vLyBDYW4gYmUgY29udHJvbGxlZCB2aWEgc21vb3RoUGxvdHRlci5zbW9vdGhpbmdcbmZ1bmN0aW9uIHNtb290aFBsb3R0ZXIoZSkge1xuICB2YXIgY3R4ID0gZS5kcmF3aW5nQ29udGV4dCxcbiAgICAgIHBvaW50cyA9IGUucG9pbnRzO1xuXG4gIGN0eC5iZWdpblBhdGgoKTtcbiAgY3R4Lm1vdmVUbyhwb2ludHNbMF0uY2FudmFzeCwgcG9pbnRzWzBdLmNhbnZhc3kpO1xuXG4gIC8vIHJpZ2h0IGNvbnRyb2wgcG9pbnQgZm9yIHByZXZpb3VzIHBvaW50XG4gIHZhciBsYXN0UmlnaHRYID0gcG9pbnRzWzBdLmNhbnZhc3gsIGxhc3RSaWdodFkgPSBwb2ludHNbMF0uY2FudmFzeTtcblxuICBmb3IgKHZhciBpID0gMTsgaSA8IHBvaW50cy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBwMCA9IHBvaW50c1tpIC0gMV0sXG4gICAgICAgIHAxID0gcG9pbnRzW2ldLFxuICAgICAgICBwMiA9IHBvaW50c1tpICsgMV07XG4gICAgcDAgPSBwMCAmJiBpc09LKHAwLmNhbnZhc3kpID8gcDAgOiBudWxsO1xuICAgIHAxID0gcDEgJiYgaXNPSyhwMS5jYW52YXN5KSA/IHAxIDogbnVsbDtcbiAgICBwMiA9IHAyICYmIGlzT0socDIuY2FudmFzeSkgPyBwMiA6IG51bGw7XG4gICAgaWYgKHAwICYmIHAxKSB7XG4gICAgICB2YXIgY29udHJvbHMgPSBnZXRDb250cm9sUG9pbnRzKHt4OiBwMC5jYW52YXN4LCB5OiBwMC5jYW52YXN5fSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3g6IHAxLmNhbnZhc3gsIHk6IHAxLmNhbnZhc3l9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwMiAmJiB7eDogcDIuY2FudmFzeCwgeTogcDIuY2FudmFzeX0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNtb290aFBsb3R0ZXIuc21vb3RoaW5nKTtcbiAgICAgIC8vIFVuY29tbWVudCB0byBzaG93IHRoZSBjb250cm9sIHBvaW50czpcbiAgICAgIC8vIGN0eC5saW5lVG8obGFzdFJpZ2h0WCwgbGFzdFJpZ2h0WSk7XG4gICAgICAvLyBjdHgubGluZVRvKGNvbnRyb2xzWzBdLCBjb250cm9sc1sxXSk7XG4gICAgICAvLyBjdHgubGluZVRvKHAxLmNhbnZhc3gsIHAxLmNhbnZhc3kpO1xuICAgICAgbGFzdFJpZ2h0WCA9IChsYXN0UmlnaHRYICE9PSBudWxsKSA/IGxhc3RSaWdodFggOiBwMC5jYW52YXN4O1xuICAgICAgbGFzdFJpZ2h0WSA9IChsYXN0UmlnaHRZICE9PSBudWxsKSA/IGxhc3RSaWdodFkgOiBwMC5jYW52YXN5O1xuICAgICAgY3R4LmJlemllckN1cnZlVG8obGFzdFJpZ2h0WCwgbGFzdFJpZ2h0WSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2xzWzBdLCBjb250cm9sc1sxXSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHAxLmNhbnZhc3gsIHAxLmNhbnZhc3kpO1xuICAgICAgbGFzdFJpZ2h0WCA9IGNvbnRyb2xzWzJdO1xuICAgICAgbGFzdFJpZ2h0WSA9IGNvbnRyb2xzWzNdO1xuICAgIH0gZWxzZSBpZiAocDEpIHtcbiAgICAgIC8vIFdlJ3JlIHN0YXJ0aW5nIGFnYWluIGFmdGVyIGEgbWlzc2luZyBwb2ludC5cbiAgICAgIGN0eC5tb3ZlVG8ocDEuY2FudmFzeCwgcDEuY2FudmFzeSk7XG4gICAgICBsYXN0UmlnaHRYID0gcDEuY2FudmFzeDtcbiAgICAgIGxhc3RSaWdodFkgPSBwMS5jYW52YXN5O1xuICAgIH0gZWxzZSB7XG4gICAgICBsYXN0UmlnaHRYID0gbGFzdFJpZ2h0WSA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgY3R4LnN0cm9rZSgpO1xufVxuc21vb3RoUGxvdHRlci5zbW9vdGhpbmcgPSAxLzM7XG5zbW9vdGhQbG90dGVyLl9nZXRDb250cm9sUG9pbnRzID0gZ2V0Q29udHJvbFBvaW50czsgIC8vIGZvciB0ZXN0aW5nXG5cbi8vIG9sZGVyIHZlcnNpb25zIGV4cG9ydGVkIGEgZ2xvYmFsLlxuLy8gVGhpcyB3aWxsIGJlIHJlbW92ZWQgaW4gdGhlIGZ1dHVyZS5cbi8vIFRoZSBwcmVmZXJyZWQgd2F5IHRvIGFjY2VzcyBzbW9vdGhQbG90dGVyIGlzIHZpYSBEeWdyYXBoLnNtb290aFBsb3R0ZXIuXG53aW5kb3cuc21vb3RoUGxvdHRlciA9IHNtb290aFBsb3R0ZXI7XG5EeWdyYXBoLnNtb290aFBsb3R0ZXIgPSBzbW9vdGhQbG90dGVyO1xuXG4vKiBjbG9zdXJlIGFuZCBsb2FkZXIgd3JhcHBlciAqL1xuRHlncmFwaC5fcmVxdWlyZS5hZGQoJ2R5Z3JhcGhzL3NyYy9leHRyYXMvc21vb3RoLXBsb3R0ZXIuanMnLCAvKiBleHBvcnRzICovIHt9KTtcbn0pKCk7XG4iXSwibWFwcGluZ3MiOiI7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLENBQUMsU0FBU0EsNkJBQTZCLEdBQUc7RUFDMUMsWUFBWTs7RUFDWixJQUFJQyxPQUFPO0VBQ1gsSUFBSUMsTUFBTSxDQUFDRCxPQUFPLEVBQUU7SUFDbEJBLE9BQU8sR0FBR0MsTUFBTSxDQUFDRCxPQUFPO0VBQzFCLENBQUMsTUFBTSxJQUFJLE9BQU9FLE1BQU8sS0FBSyxXQUFXLEVBQUU7SUFDekNGLE9BQU8sR0FBR0csT0FBTyxDQUFDLFlBQVksQ0FBQztJQUMvQixJQUFJLE9BQU9ILE9BQU8sQ0FBQ0ksSUFBSyxLQUFLLFdBQVcsSUFBSSxPQUFPSixPQUFPLFdBQVMsS0FBSyxXQUFXLEVBQ2pGQSxPQUFPLEdBQUdBLE9BQU8sV0FBUTtFQUM3QjtFQUNBOztFQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7RUFDQSxTQUFTSyxnQkFBZ0IsQ0FBQ0MsRUFBRSxFQUFFQyxFQUFFLEVBQUVDLEVBQUUsRUFBRUMsU0FBUyxFQUFF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
;