Skip to content

Instantly share code, notes, and snippets.

@linacarrillo23
Last active February 5, 2020 13:16
Show Gist options
  • Select an option

  • Save linacarrillo23/9bcec688e0bab675f08f1d35c6cd2837 to your computer and use it in GitHub Desktop.

Select an option

Save linacarrillo23/9bcec688e0bab675f08f1d35c6cd2837 to your computer and use it in GitHub Desktop.
D3 Liquid Fill Gauge2_lina
license: mit

Liquid Fill Gauge v1.1 - 7/14/2015

Changes:

  • Added support for updating the gauge value after loading is complete. The loadLiquidFillGauge method now returns an object with an update method which allows the gauge value to be changed. Click any of the gauges above to randomly update their value.

Configurable features include:

  • Changeable min/max values.
  • All colors.
  • Outer circle thickness.
  • Gap between the outer circle and inner fill area.
  • Wave height.
  • Wave speed.
  • Wave count.
  • Wave rise time.
  • Wave height scaling on/off. Reduces the wave height near the min/max values so that the wave won't make the fill area appear total full or totally empty.
  • Wave starting offset. Most useful when wave animation is turned off and you want the wave min or max at a specific horizontal position in the fill area.
  • Wave rising upon load on/off.
  • Wave animation on/off.
  • Text height.
  • Text vertical position.
  • Text increment from min value upon loading.
  • Display of % symbol on/off.

Open source under BSD 2-clause
Copyright (c) 2015, Curtis Bratton
All rights reserved.

forked from Ani-Afyan's block: D3 Liquid Fill Gauge

forked from dahlemmab's block: D3 Liquid Fill Gauge

forked from dahlemmab's block: D3 Liquid Fill Gauge2_lina

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script src="https://d3js.org/d3.v4.min.js" language="JavaScript"></script>
<script src="liquidFillGauge.js" language="JavaScript"></script>
<style>
body {
background-color:#111111;
}
.lines {
fill-opacity:0.3;
stroke-width:0.1;
}
.liquidFillGaugeText { font-family: Helvetica; font-weight: bold; }
</style>
</head>
<body>
<svg id="top_fill_box" width="1%", height="10"> </svg>
<svg id="long_left_fill_box" width="1%", height="90"> </svg>
<svg id="fillgauge2" width="9%" height="120" onclick="gauge2.update(NewValue());"> <line x1="10", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> </svg>
<svg id="fillgauge3" width="9%" height="120" onclick="gauge3.update(NewValue());"> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> </svg>
<svg id="fillgauge4" width="9%" height="120" onclick="gauge4.update(NewValue());"> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> </svg>
<svg id="fillgauge5" width="9%" height="120" onclick="gauge5.update(NewValue());"> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> </svg>
<svg id="fillgauge6" width="9%" height="120" onclick="gauge5.update(NewValue());"> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> </svg>
<svg id="fillgauge7" width="9%" height="120" onclick="gauge5.update(NewValue());"> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> </svg>
<svg id="fillgauge8" width="9%" height="120" onclick="gauge5.update(NewValue());"> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> </svg>
<svg id="fillgauge9" width="9%" height="120" onclick="gauge5.update(NewValue());"> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> </svg>
<svg id="fillgauge10" width="9%" height="120" onclick="gauge5.update(NewValue());"> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> </svg>
<svg id="fillgauge11" width="9%" height="120" onclick="gauge5.update(NewValue());"> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> <line x1="0", y1="0", x2="0", y2="0" width="0" stroke="grey" stroke-width="4" ></line> </svg>
<script language="JavaScript">
var xColumn = "average_price";
var yColumn = "average_points";
var rColumn = "average_price";
var colorColumn = "species";
var config1 = liquidFillGaugeDefaultSettings();
config1.circleColor = "#FFFFFF";
config1.textColor = "#756900";
config1.waveTextColor = "#eec252";
config1.waveColor = "#f8e5b3";
config1.circleThickness = 0.2;
config1.textVertPosition = 0.6;
config1.waveAnimateTime = 1000; config1.displayPercent = false
var gauge2= loadLiquidFillGauge("fillgauge2", 60, config1);
var config2 = liquidFillGaugeDefaultSettings();
config2.circleColor = "#ffffff";
config2.textColor = "#756900";
config2.waveTextColor = "#e2c463";
config2.waveColor = "#f2e4b7";
config2.circleThickness = 0.2;
config2.circleFillGap = 0.0;
config2.textVertPosition = 0.6;
config2.displayPercent = false
config2.waveAnimateTime = 1000;
config2.waveHeight = 0.05;
config2.waveCount = 1;
var gauge3 = loadLiquidFillGauge("fillgauge3", 59, config2);
var config3 = liquidFillGaugeDefaultSettings();
config3.textVertPosition = 0.6;
config3.circleColor = "#FFFFFF";
config3.textColor = "#756900";
config3.circleThickness = 0.2;
config3.waveTextColor = "#dedc62";
config3.waveColor = "#f0efb6"
config3.waveAnimateTime = 1000;
config3.waveHeight = 0.05;
config3.waveAnimatetime = 1000;
config3.circleThickness = 0.2
config3.waveOffset = 0.25;
config3.valueCountUp = false;
config3.displayPercent = false;
var gauge4 = loadLiquidFillGauge("fillgauge4", 58, config3);
var config4 = liquidFillGaugeDefaultSettings();
config4.circleThickness = 0.2;
config4.circleColor = "#ffffff";
config4.circleThickness = 0.2;
config4.textColor = "#a30000";
config4.waveTextColor = "#ffdbdb";
config4.waveColor = "#fda4a4";
config4.textVertPosition = 0.6;
config4.displayPercent = false
config4.waveAnimateTime = 1000;
config4.waveHeight = 0.05;
config4.waveCount = 1;
var gauge5= loadLiquidFillGauge("fillgauge5", 55, config4);
var config5 = liquidFillGaugeDefaultSettings();
config5.circleColor = "#ffffff";
config5.textColor = "#a30000";
config5.waveTextColor = "#fe7070";
config5.waveColor = "#ea0000";
config5.circleThickness = 0.2;
config5.circleFillGap = 0.0;
config5.textVertPosition = 0.6;
config5.waveOffset = 0.4;
config5.displayPercent = false
config5.waveAnimateTime = 1000;
config5.waveHeight = 0.05;
config5.waveCount = 1;
var gauge6= loadLiquidFillGauge("fillgauge6", 60, config5);
var config6 = liquidFillGaugeDefaultSettings();
config6.circleColor = "#ffffff";
config6.textColor = "#a30000";
config6.waveTextColor = "#FFAAAA";
config6.waveColor = "#ff5900";
config6.circleThickness = 0.2;
config6.circleFillGap = 0.0;
config6.textVertPosition = 0.6;
config6.waveOffset = 0.7;
config6.displayPercent = false
config6.waveAnimateTime = 1000;
config6.waveHeight = 0.05;
config6.waveCount = 1;
var gauge7= loadLiquidFillGauge("fillgauge7", 70, config6);
var config7 = liquidFillGaugeDefaultSettings();
config7.circleColor = "#fdfcfb";
config7.textColor = "#a30000";
config7.waveTextColor = "#FFDDDD";
config7.waveColor = "#ff6565";
config7.circleThickness = 0.2;
config7.circleFillGap = 0.0;
config7.textVertPosition = 0.6;
config7.displayPercent = false
config7.waveAnimateTime = 1000;
config7.waveHeight = 0.05;
config7.waveCount = 1;
var gauge8= loadLiquidFillGauge("fillgauge8", 63, config7);
var config8 = liquidFillGaugeDefaultSettings();
config8.circleColor = "#ffffff";
config8.textColor = "#a30000";
config8.waveTextColor = "#ef2349";
config8.waveColor = "#a20b26";
config8.circleThickness = 0.2;
config8.circleFillGap = 0.0;
config8.textVertPosition = 0.6;
config8.waveOffset = 0.2;
config8.displayPercent = false
config8.waveAnimateTime = 1000;
config8.waveHeight = 0.05;
config8.waveCount = 1;
var gauge9= loadLiquidFillGauge("fillgauge9", 57, config8);
var config9 = liquidFillGaugeDefaultSettings();
config9.circleColor = "#ffffff";
config9.textColor = "#a30000";
config9.waveTextColor = "#fff9f9";
config9.waveColor = "#FFDDDD";
config9.circleThickness = 0.2;
config9.circleFillGap = 0.0;
config9.textVertPosition = 0.6;
config3.waveOffset = 0.7;
config9.displayPercent = false
config9.waveAnimateTime = 1030;
config9.waveHeight = 0.05;
config9.waveCount = 1;
var gauge10= loadLiquidFillGauge("fillgauge10", 54, config9);
var config10 = liquidFillGaugeDefaultSettings();
config10.circleColor = "#ffffff";
config10.textColor = "#a30000";
config10.waveTextColor = "#e27377";
config10.waveColor = "#ba262b";
config10.circleThickness = 0.2;
config10.circleFillGap = 0.0;
config10.textVertPosition = 0.6;
config10.displayPercent = false
config10.waveAnimateTime = 1000;
config10.waveHeight = 0.05;
config10.waveCount = 1;
var gauge11= loadLiquidFillGauge("fillgauge11", 48, config10);
var config11 = liquidFillGaugeDefaultSettings();
config11.circleColor = "#ffffff";
config11.textColor = "#a30000";
config11.waveTextColor = "#f8f9c7";
config11.waveColor = "#f1f285";
config11.circleThickness = 0.2;
config11.circleFillGap = 0.0;
config11.textVertPosition = 0.6;
config11.waveOffset = 0.5;
config11.displayPercent = false
config11.waveAnimateTime = 950;
config11.waveHeight = 0.2;
config11.waveCount = 1;
function render(data){
//X scale domain
x.domain(d3.extent(data,d=> d[xColumn]));
//Y scale domain
y.domain(d3.extent(data,d=> d[yColumn]));
//Size scale domain
r.domain(d3.extent(data,d=> d[rColumn]));
//Data binding
var lines = svg.selectAll("lines")
.data(data)
.enter()
.append("lines")
.attr("class", "line")
.attr("cx",(d, i) => 250+i*30)
.attr("cy",(d, i) => 300+i*30)
.attr("fill",d=> color(d[colorColumn]))
}
function type(d){
d.average_price = +d.average_price;
d.obs = +d.obs;
d.average_points = +d.average_points;
return d;
}
d3.csv("https://gist.githubusercontent.com/linacarrillo23/daa16fcf9134d4312df63552544ef798/raw/5be5f9c6236a3b361d5ebf52cf376a880c0df6e8/wine_variety_10.csv", type, render)
</script>
</body>
</html>
/*!
* @license Open source under BSD 2-clause (http://choosealicense.com/licenses/bsd-2-clause/)
* Copyright (c) 2015, Curtis Bratton
* All rights reserved.
*
* Liquid Fill Gauge v1.1
*/
function liquidFillGaugeDefaultSettings() {
return {
minValue: 0, // The gauge minimum value.
maxValue: 100, // The gauge maximum value.
circleThickness: 0.05, // The outer circle thickness as a percentage of it's radius.
circleFillGap: 0.05, // The size of the gap between the outer circle and wave circle as a percentage of the outer circles radius.
circleColor: "#178BCA", // The color of the outer circle.
waveHeight: 0.05, // The wave height as a percentage of the radius of the wave circle.
waveCount: 1, // The number of full waves per width of the wave circle.
waveRiseTime: 1000, // The amount of time in milliseconds for the wave to rise from 0 to it's final height.
waveAnimateTime: 18000, // The amount of time in milliseconds for a full wave to enter the wave circle.
waveRise: true, // Control if the wave should rise from 0 to it's full height, or start at it's full height.
waveHeightScaling: true, // Controls wave size scaling at low and high fill percentages. When true, wave height reaches it's maximum at 50% fill, and minimum at 0% and 100% fill. This helps to prevent the wave from making the wave circle from appear totally full or empty when near it's minimum or maximum fill.
waveAnimate: true, // Controls if the wave scrolls or is static.
waveColor: "#178BCA", // The color of the fill wave.
waveOffset: 0, // The amount to initially offset the wave. 0 = no offset. 1 = offset of one full wave.
textVertPosition: .5, // The height at which to display the percentage text withing the wave circle. 0 = bottom, 1 = top.
textSize: 1, // The relative height of the text to display in the wave circle. 1 = 50%
valueCountUp: true, // If true, the displayed value counts up from 0 to it's final value upon loading. If false, the final value is displayed.
displayPercent: true, // If true, a % symbol is displayed after the value.
textColor: "#045681", // The color of the value text when the wave does not overlap it.
waveTextColor: "#A4DBf8" // The color of the value text when the wave overlaps it.
};
}
function loadLiquidFillGauge(elementId, value, config) {
if (config == null) config = liquidFillGaugeDefaultSettings();
const gauge = d3.select("#" + elementId);
const radius = Math.min(parseInt(gauge.style("width")), parseInt(gauge.style("height"))) / 2;
const locationX = parseInt(gauge.style("width")) / 2 - radius;
const locationY = parseInt(gauge.style("height")) / 2 - radius;
const fillPercent = Math.max(config.minValue, Math.min(config.maxValue, value)) / config.maxValue;
let waveHeightScale = null;
if (config.waveHeightScaling) {
waveHeightScale = d3.scaleLinear()
.range([0, config.waveHeight, 0])
.domain([0, 50, 100]);
} else {
waveHeightScale = d3.scaleLinear()
.range([config.waveHeight, config.waveHeight])
.domain([0, 100]);
}
const textPixels = (config.textSize * radius / 2);
const textFinalValue = parseFloat(value).toFixed(2);
const textStartValue = config.valueCountUp ? config.minValue : textFinalValue;
const percentText = config.displayPercent ? "%" : "";
const circleThickness = config.circleThickness * radius;
const circleFillGap = config.circleFillGap * radius;
const fillCircleMargin = circleThickness + circleFillGap;
const fillCircleRadius = radius - fillCircleMargin;
const waveHeight = fillCircleRadius * waveHeightScale(fillPercent * 100);
const waveLength = fillCircleRadius * 2 / config.waveCount;
const waveClipCount = 1 + config.waveCount;
const waveClipWidth = waveLength * waveClipCount;
// Rounding functions so that the correct number of decimal places is always displayed as the value counts up.
let textRounder = function (value) { return Math.round(value); };
if (parseFloat(textFinalValue) != parseFloat(textRounder(textFinalValue))) {
textRounder = function (value) { return parseFloat(value).toFixed(1); };
}
if (parseFloat(textFinalValue) != parseFloat(textRounder(textFinalValue))) {
textRounder = function (value) { return parseFloat(value).toFixed(2); };
}
// Data for building the clip wave area.
const data = [];
for (let i = 0; i <= 40 * waveClipCount; i++) {
data.push({ x: i / (40 * waveClipCount), y: (i / (40)) });
}
// Scales for drawing the outer circle.
const gaugeCircleX = d3.scaleLinear().range([0, 2 * Math.PI]).domain([0, 1]);
const gaugeCircleY = d3.scaleLinear().range([0, radius]).domain([0, radius]);
// Scales for controlling the size of the clipping path.
const waveScaleX = d3.scaleLinear().range([0, waveClipWidth]).domain([0, 1]);
const waveScaleY = d3.scaleLinear().range([0, waveHeight]).domain([0, 1]);
// Scales for controlling the position of the clipping path.
const waveRiseScale = d3.scaleLinear()
// The clipping area size is the height of the fill circle + the wave height, so we position the clip wave
// such that the it will overlap the fill circle at all when at 0%, and will totally cover the fill
// circle at 100%.
.range([(fillCircleMargin + fillCircleRadius * 2 + waveHeight), (fillCircleMargin - waveHeight)])
.domain([0, 1]);
const waveAnimateScale = d3.scaleLinear()
.range([0, waveClipWidth - fillCircleRadius * 2]) // Push the clip area one full wave then snap back.
.domain([0, 1]);
// Scale for controlling the position of the text within the gauge.
const textRiseScaleY = d3.scaleLinear()
.range([fillCircleMargin + fillCircleRadius * 2, (fillCircleMargin + textPixels * 0.7)])
.domain([0, 1]);
// Center the gauge within the parent SVG.
const gaugeGroup = gauge.append("g")
.attr('transform', 'translate(' + locationX + ',' + locationY + ')');
// Draw the outer circle.
const gaugeCircleArc = d3.arc()
.startAngle(gaugeCircleX(0))
.endAngle(gaugeCircleX(1))
.outerRadius(gaugeCircleY(radius))
.innerRadius(gaugeCircleY(radius - circleThickness));
gaugeGroup.append("path")
.attr("d", gaugeCircleArc)
.style("fill", config.circleColor)
.attr('transform', 'translate(' + radius + ',' + radius + ')');
// Text where the wave does not overlap.
const text1 = gaugeGroup.append("text")
.text(textRounder(textStartValue) + percentText)
.attr("class", "liquidFillGaugeText")
.attr("text-anchor", "middle")
.attr("font-size", textPixels + "px")
.style("fill", config.textColor)
.attr('transform', 'translate(' + radius + ',' + textRiseScaleY(config.textVertPosition) + ')');
let text1InterpolatorValue = textStartValue;
// The clipping wave area.
const clipArea = d3.area()
.x(function (d) { return waveScaleX(d.x); })
.y0(function (d) { return waveScaleY(Math.sin(Math.PI * 2 * config.waveOffset * -1 + Math.PI * 2 * (1 - config.waveCount) + d.y * 2 * Math.PI)); })
.y1(function (d) { return (fillCircleRadius * 2 + waveHeight); });
const waveGroup = gaugeGroup.append("defs")
.append("clipPath")
.attr("id", "clipWave" + elementId);
const wave = waveGroup.append("path")
.datum(data)
.attr("d", clipArea)
.attr("T", 0);
// The inner circle with the clipping wave attached.
const fillCircleGroup = gaugeGroup.append("g")
.attr("clip-path", "url(#clipWave" + elementId + ")");
fillCircleGroup.append("circle")
.attr("cx", radius)
.attr("cy", radius)
.attr("r", fillCircleRadius)
.style("fill", config.waveColor);
// Text where the wave does overlap.
const text2 = fillCircleGroup.append("text")
.text(textRounder(textStartValue))
.attr("class", "liquidFillGaugeText")
.attr("text-anchor", "middle")
.attr("font-size", textPixels + "px")
.style("fill", config.waveTextColor)
.attr('transform', 'translate(' + radius + ',' + textRiseScaleY(config.textVertPosition) + ')');
let text2InterpolatorValue = textStartValue;
// Make the value count up.
if (config.valueCountUp) {
text1.transition()
.duration(config.waveRiseTime)
.tween("text", function () {
const i = d3.interpolateNumber(text1InterpolatorValue, textFinalValue);
return function (t) {
text1InterpolatorValue = textRounder(i(t));
// Set the gauge's text with the new value and append the % sign
// to the end
text1.text(text1InterpolatorValue + percentText);
}
});
text2.transition()
.duration(config.waveRiseTime)
.tween("text", function () {
const i = d3.interpolateNumber(text2InterpolatorValue, textFinalValue);
return function (t) {
text2InterpolatorValue = textRounder(i(t));
// Set the gauge's text with the new value and append the % sign
// to the end
text2.text(text2InterpolatorValue + percentText);
}
});
//var textTween = function () {
// var i = d3.interpolate(this.textContent, textFinalValue);
// return function (t) { this.textContent = textRounder(i(t)) + percentText; }
//};
//text1.transition()
// .duration(config.waveRiseTime)
// .tween("text", textTween);
//text2.transition()
// .duration(config.waveRiseTime)
// .tween("text", textTween);
}
// Make the wave rise. wave and waveGroup are separate so that horizontal and vertical movement can be controlled independently.
var waveGroupXPosition = fillCircleMargin + fillCircleRadius * 2 - waveClipWidth;
if (config.waveRise) {
waveGroup.attr('transform', 'translate(' + waveGroupXPosition + ',' + waveRiseScale(0) + ')')
.transition()
.duration(config.waveRiseTime)
.attr('transform', 'translate(' + waveGroupXPosition + ',' + waveRiseScale(fillPercent) + ')')
// .each("start", function () { wave.attr('transform', 'translate(1,0)'); }); // This transform is necessary to get the clip wave positioned correctly when waveRise=true and waveAnimate=false. The wave will not position correctly without this, but it's not clear why this is actually necessary.
.on("start", function () { wave.attr('transform', 'translate(1,0)'); }); // This transform is necessary to get the clip wave positioned correctly when waveRise=true and waveAnimate=false. The wave will not position correctly without this, but it's not clear why this is actually necessary.
} else {
waveGroup.attr('transform', 'translate(' + waveGroupXPosition + ',' + waveRiseScale(fillPercent) + ')');
}
if (config.waveAnimate) animateWave();
function animateWave() {
wave.attr('transform', 'translate(' + waveAnimateScale(wave.attr('T')) + ',0)');
wave.transition()
.duration(config.waveAnimateTime * (1 - wave.attr('T')))
.ease(d3.easeLinear)
.attr('transform', 'translate(' + waveAnimateScale(1) + ',0)')
.attr('T', 1)
.on('end', function () {
wave.attr('T', 0);
animateWave(config.waveAnimateTime);
});
}
function GaugeUpdater() {
this.update = function (value) {
var newFinalValue = parseFloat(value).toFixed(2);
var textRounderUpdater = function (value) { return Math.round(value); };
if (parseFloat(newFinalValue) != parseFloat(textRounderUpdater(newFinalValue))) {
textRounderUpdater = function (value) { return parseFloat(value).toFixed(1); };
}
if (parseFloat(newFinalValue) != parseFloat(textRounderUpdater(newFinalValue))) {
textRounderUpdater = function (value) { return parseFloat(value).toFixed(2); };
}
text1.transition()
.duration(config.waveRiseTime)
.tween("text", function () {
const i = d3.interpolateNumber(text1InterpolatorValue, newFinalValue);
return function (t) {
text1InterpolatorValue = textRounder(i(t));
// Set the gauge's text with the new value and append the % sign
// to the end
text1.text(text1InterpolatorValue + percentText);
}
});
text2.transition()
.duration(config.waveRiseTime)
.tween("text", function () {
const i = d3.interpolateNumber(text2InterpolatorValue, newFinalValue);
return function (t) {
text2InterpolatorValue = textRounder(i(t));
// Set the gauge's text with the new value and append the % sign
// to the end
text2.text(text2InterpolatorValue + percentText);
}
});
//var textTween = function () {
// var i = d3.interpolate(this.textContent, parseFloat(value).toFixed(2));
// return function (t) { this.textContent = textRounderUpdater(i(t)) + percentText; }
//};
//text1.transition()
// .duration(config.waveRiseTime)
// .tween("text", textTween);
//text2.transition()
// .duration(config.waveRiseTime)
// .tween("text", textTween);
var fillPercent = Math.max(config.minValue, Math.min(config.maxValue, value)) / config.maxValue;
var waveHeight = fillCircleRadius * waveHeightScale(fillPercent * 100);
var waveRiseScale = d3.scaleLinear()
// The clipping area size is the height of the fill circle + the wave height, so we position the clip wave
// such that the it will overlap the fill circle at all when at 0%, and will totally cover the fill
// circle at 100%.
.range([(fillCircleMargin + fillCircleRadius * 2 + waveHeight), (fillCircleMargin - waveHeight)])
.domain([0, 1]);
var newHeight = waveRiseScale(fillPercent);
var waveScaleX = d3.scaleLinear().range([0, waveClipWidth]).domain([0, 1]);
var waveScaleY = d3.scaleLinear().range([0, waveHeight]).domain([0, 1]);
var newClipArea;
if (config.waveHeightScaling) {
newClipArea = d3.area()
.x(function (d) { return waveScaleX(d.x); })
.y0(function (d) { return waveScaleY(Math.sin(Math.PI * 2 * config.waveOffset * -1 + Math.PI * 2 * (1 - config.waveCount) + d.y * 2 * Math.PI)); })
.y1(function (d) { return (fillCircleRadius * 2 + waveHeight); });
} else {
newClipArea = clipArea;
}
var newWavePosition = config.waveAnimate ? waveAnimateScale(1) : 0;
wave.transition()
.duration(0)
.transition()
.duration(config.waveAnimate ? (config.waveAnimateTime * (1 - wave.attr('T'))) : (config.waveRiseTime))
.ease(d3.easeLinear)
.attr('d', newClipArea)
.attr('transform', 'translate(' + newWavePosition + ',0)')
.attr('T', '1')
.on("end", function () {
if (config.waveAnimate) {
wave.attr('transform', 'translate(' + waveAnimateScale(0) + ',0)');
animateWave(config.waveAnimateTime);
}
});
waveGroup.transition()
.duration(config.waveRiseTime)
.attr('transform', 'translate(' + waveGroupXPosition + ',' + newHeight + ')')
}
}
return new GaugeUpdater();
}
GIF89a��w!� NETSCAPE2.0!�,���V� Z�^�_� a�b�e�k� i�%l�)o�+p�2u�8y�/�A�B�;������#��)��)��/��2��3��9��<��D��J��O��D��O��W��Y��]��`��g��l��y��M��@��@��D��O��H��L��X��P��S��T��[��]��]��[��a��a��l��u��b��f��k��q��r��z��u��{�ꀩ������ƒ�ȗ�˝�Π�φ���������������������������Ы�ԯ�׵�ڻ�ݡ�������������������������������������������������������������n�����������������������������������������������������������id�M�50�������5�M�di����ֶd_M@0)�������)0@M_d�����g�������0�_g���e�!% |*#G2kJ�Hә(50,�ȱ�1 5���H�$ɁMz\ɒ#�gMʜI� o-s�ܘ��@��J�q�ѣCJʴ�'��J���O�X�B����ׯ�(�����Y���c�]�-���)��kK0 lY�'��ٿ4Ѫ��"��h�|���"�׾�#O<�#-�����$ΩbGJmm͖�F)�x+���,,M�%&�۷(�։y�҉i�x>�qXk��n����k���I�����4ٽ�纳7uRh��yN�sR���v��;�(��$2*WZ�n� ����}2��Y��g��[(�!�Ă
� � A���vT܇sU摇$b�� U�b#�-�~�(~"A���4B����-�B�BR���t��a�4��G�AyISn��uV���F����$��h�xc���FD�e��$Ǣ=4��i�'K6��Ӭ���ɚ 5񦡸�1'9(2J� aP���H�!���B)B@,�i+_�9N�����=Ԙ*+iԠ����eB5�Y�����宩h�P������ ��g����$>5��,&�V�괨�Z���v2hB�vۊ�
5!.&i�H ��{J�ړB��*�E��PE��D�o2p�/#Yޓ���ĚP+�.B�6,K��+q�!d��̯ �,����v ������k�f���g�+��/���=), �K���9�rƣ���q\�.��#p�;����0��� ��X�r4> �F��J�-k�̐�p>|�k_>w
4�%�]�������
�7.5�j���ד܇ﲆ�I�89eG�O��n'����Dw�2�Z�3����^��6�>NĬK:9��(�8��N����>���N��^ ���m|E�[�8n����&M~���U����gO9�2�/�/�ዿ}�i�y��� ������������v8��t�'��k��W���j���D@��fw|����/�� ��`S�� �̈́�(���B��~���
ÿ�|,x3�
�Q��,t9,K�ȡ2��� "V�Ѥ}�SbY`�; �D~��S��%JO�C�Wi��d��L!��ErX�Zb�"?�Q2n�P  (���C��H�#v΄�, ���� ҃�tJ?�Gj�0c��Y���Vd��B��&�F�� ��4�"gg�j\�L�Y��C��Î��M�q�j��W�˥{�)JZp���č�!:xr�L�m^��FB i(�4e�KHi��4�6��̛�c���8�YT��k�:��F�\���(�<o��q��H��>��K�U#�Ȑ�@���p�2S�z�B��~�� �D���eRl���F�Jw����H J6��+�NC�� ��1�LF]Z�If3����8��
�I��TO��T� ��xjS�3I ̢�S�5�Tc�լ���W���V�u���d
^��pX�N%QCaS ��Z��7x���&C�x5��ʉ�B5�f�$NE��"��� l&*���⦟ ��~jY�n�����Q;���v�%�u;���¯S-v2j�GdT��e
k}U
��%���%gE1��7+�%�(p\�ʵ���1��\���U�m�{�J���x.w���P�5��$c�cW��3�b-!_�ǽ�8o �KN�v�o�/n5�I�
��uv(rd7����& a���@p�#�`�mB��x��'#�Kt�##035�( ��/'6(���bҴ�-f�U�ۘ�����1��c�YD��<�I^��1�I��p��1���bKP��[�J��D�0ʢ��7�,�2K��e�Vv9ZD�Y�IG�Qb<gʓ�.h� �58X;�#��B9 3��^�L��dF<*����"a�qH9���28��f�Z+��2��ن,�`�� ���H���w}����щ8f��h�`�ȖuL��N��ɖ5�p�Fz�ĴI���h{����$a�p��� P�#�0�c�(B4�ko[����s" 4$��O��#A��\��v�<ppx@ݗ@�� �w���d��{�����pF���@�-a�o��<�f��l�*�� Wxn~�+� "��M �{��硜H�`mɜ����y#̀����H�ՓP��ۻ>G����[�RgD�n���Pg��#�d#�<��!vye��al�v�q���{�톨�� �r5����F�$�헟���з!"�2����"L�d#�l��� 0�BP>�Ӧ���nq�z͍�xd�^zd�m�@�w}�A�A�>�!�����G����E`^ƀ)��w���+`���!
�m<����2΅8�/��o�a,cܡ����g�Eİ�(�b��%~��}�0�~�'�m ~����Vn0�� � B� �!�{� P Π}�
|�Ml |������m���wp�9 B��+0"(�R�%�`�� l�c�F�v�4H����f�0ڐ5�K(�S����k�$��+�/�T�
5Z��Dž�@7����k��9��rR� H2pI�MH�Ra���eT��@9+X�npk����ƃ�@Z07P�k(㠆�(���q��X�� d b�Gs��y��t��f�
Tnʧ f�0`;�rX���6`��R���)��xXI�� �P}!r��Ԇ
n� a�@�h�;���h����(��W�����p�Ȑm��4�;n$�
6n���Mp� ������`�Yݸ��8�(9��� -קy�D M��� e`�F�@z��s7�d�s"���X�����P�]�Ђ��UI�8���{���Pv��`@���2@�H�!i��8%��'�t� �C��@��e���@~�w~� ���(�> S���i�����n9��Д"��uI�2����P`�t-q���� <�m
�� J0���qȖ^���L0���m��)�นu�PX�{��Q8���
�n�����i�Q���`���O`�`��(G(���)�P�Plj�����h�R����}�F����ghӘ��������������Lh�깞�iN�pd�sd�h�w p d�h7b� �4p=�14�0I��)�N0]��S0L�N�� �K >�Ap�֘����YFz'�Y��}��7�Dx�W*�;�Np���]�.�������i�S��6ॳ���PP��BƠ!8�R��0�o���{�?ʆ_�c�x��S���*�Tm��Y��0=`�=
�����}�g:TS��uH����K���o����S����T��B�q� ��yꠦ
�W)���<�:�Q��
�R� ��ͪ�]r���:�S��P���������4eg�.��Ӫ�L�����zA�������J��`�� �����j��Jۈ��{�N��P���f�˯�ை���P� 1� ��oiН��L��+@��z�ᰨ��������@�����%{��z���)�j���*0˩���8[�̵o���Q �M;`�@��'K�Y��!{��*�� .�U�R+km��� �]��Gi�s;����L��q��j��
�%�����Sk��{��z��ޘ�Hɸ�X�a;���]��;��p�I��TA��H�nK��+<@�R�*`����� ˳B�=:3�����k52 Rp���=�[�����x�͛�P�"�Kท��{�,*��riCk�
�����K �k�� �̻y� �lk�������˻Jyd? ����0A���(�O�������� � I�����K=�6
���.;�p��˛�Z �l��^q�})��:�
���i�K��� �;P�6*,z ����٢�=�9��3�� �j���������+��P���m7� ��ٳjѿ��*� %L�` �V� XL���:a��`���j�`�� �ӊ�U\����VF�p�#��ڹ��� e<�L �N|�k�W����\�+aLJJ�`!�<��HQ���I,�B�����e+���R�<ș����c�� �(|g����K(�{��!HŰ �W<��w��& �NP�rk�#<ʹ�޻�� ������꧄,N����^0�{Q͖J-��i� A���� ���Ǟ(ΈP���Q�쟇�����|�;qƐ���P�����
��\�� �������+�?�ijzΏ���` =�5ژ̍ �h��̛�| Œ��l����)��`�?��2�|� ��
�X��PB���9���k�F�гi�������<����z|ɱ�l� Q��� ���S�����˹G1Ӽ<j̈́t� ��U{�n,ցlׇ�����K��/����_Z�L���X�����K��� � ����Ɉ ]f��,��|�ݻJ{���M�Sa�U]�ǀ�"�����Ü��b*Dc����y흯<t*�-��}�����k��9QٽM���� � �$ݴ| ��������٩���p�y����Q-�ͨ�}�ޛ�ɰ�^��8����gY��l�>{ό:���[k57M�GAݨL��=���;��i���N���p2���M���>�9,̳���}�n���� )^݉˙�}X�p��-m�F�#�ͪ�� ��Z��,!�!���P� ({�����8�y�x�����ތ���&�L��XN�N`��;P����� �/~ W�]�։�����О���]�񌯐;�l�P~�9��9��}������φP�1�֋~��p֋��;�8�� ����8}���O�p}N�]�;P�@���P�<������ Q�Kȴ�\�W^����=�ϛ������؋�H]�x��n����R^����&��Ő����L٤���CK�z��>���<�C>������N�K��
a�0��<��L�ʬ �� �\��ֆ��ik�N�R�a�����ٌ�^��]���N���[L�~��麳T���/�
�����3v��Z�|�%�����&�����T��.��������="�2 ����-5�+��*2��<��"�� ��0,� �1gCߴ`O��r�y��+�T�?�����u�u��1��-܇�t�\�����+2��S���l(Lp�l�7�O��i��y3 a�]� ��Y���^ ��� M���b��o�_���+�0m�}�E?�&�|�
y�ڿ���.n�g����?������!�o��P��_����I��V�pL85������L-n��n[�����d������������������������g���[���g�k�n������������i�����_�,��������Т,�_���ɒ@�M�������M�@��خޒ���������Ǯڑ���f��G�����d�2����I�Z�CH��ŋ�ࡒ'IaCF)&qs�ɓ(1FA��c+w�R̂���͛���
)ɟKB�&�t�
�ѣHu-rl���(�r�#�իX9�lehTT堖��ٳ�"����+����CK�.Nb&�t;��$��j�L�b ����T4�VTp K�\oo+���.�N�fTM)��mh�Ɛ/�I1XҰc�������̓�n��U��ߤ���I.nA�!}f����(xD�Z��A�[�J���Dc]��$�xsLj�����Hӏ �L������3����u� ��~��!�A��q�E^+�(�d�1�]"����5��ӄ �%�+k4Ƀ���#��tY�Jv
�H������<��� 0Xc#!&b�Z=&�����ސ�D�ȁ�8��(�Ȁ�@9ȇ�d��db�c+8&2���H5KPeƉ�m\�ɦ%N1`��g=k��'�?�X$�"B㟌��"!R�wg_�0�_������L�%��d*j422GI��.��O��9��H�*��jq��q(���B� ���+�\&�h�i��l(��D ��Z�Ȧ���쵠@{�P�Zh�C�b+�%��9���F���X;h�J��2�#t�モP+���V�������X_��K�,�%,��m�����P�����Kݷ�!�r/��
�h�!cl�(��񶒔|�����|1/{���� tfĤnϘ��*�:��,1�!�j����,��q ;�Ԍ�l��9_MT�Ĩ˵��r: �b�[I�՞�������>��r����A�t7��� T�~>��FNU�����?3�3���a���=��J���#h�y������ �l�!t�,$o�:�� ���լ7߷{�7ԕ,Ȼɔ�^[�� ,�^/��9b3:��QX%�KO����<��E/���=�8+O���;��׻��{$�3�~��)>������X��ͯW�� �}`�ߧ��bs�z 1�'���1�s�K�8�h�|�� B�8OQ�� ��.cu-�K�^' ΐ��cI �@`�M|?$D
�@B�l�ei������X�X�֠x� � 1V���� g!m2²yN�ctO%���2�1)g�b����-��8�cM���9��#���6$ȣ�nDD��@���j�E)KJ��DR�Ψ+Mք�h�*C�>?bx�Ȥ) �ʽ��l��,��Y^����$s�J����%=�KK���/�D��Le������
���%b1�մ�7�y0*r*z,;)�r��|� �9?�Fa����$��9
�r��!)әOp�B �'@UG��1'���AQ�O�-*�S.��͈���"/��xⲔ]�* z.�⦚eJy�R��7,�DL]4S]O0=�M��������iN3#ԡb��k;�'��
(���t�u��ӓr����* ��P��㫐0j_�V3Z��fՐc�U��u]�\j㚢���wńZ���񵯗+;"�CLs�����a�2U
�rql��e�5Jv��ńd�`׈���C�(h54U �X�L�cQ'�ˮv1dP�*;�YeZ�#��aYo���U��k
��0 ���U�_��Y���U,tٔ\r}���-gո��֪��xm�J;��6$���y��� u ��u�Q�6u�ש�t����o� 9Ca� ��1V�YÃC���Q$ Yk��T2��u�n&>�a7�Í���F�mB��-q��`W�*�}��G.�S����} |�
2,�k)�x�Kh ���m�%�m���Q@���,��<�g�Ɉ r�j@d�Y�J�r�h\�)�Ȉ�@�1��Ӫ�t83�Pee]�'i83"f{狁-���pdea` �cf�[h�uC�l�G�h�����|n�6�G4!҅�4�R@b`E9�� �3�7剣b���h9����� D�2�k�� ����_ �Й��WȀ�������}�@k��_IC�A��2;�ϛ 3���eMt�+k؂� TH�e �������M�;�Q���sRs�N�:�wg��$/& @Pu~�`pWx��V8%���H���B� C [Q˾�5��4�_��GF~
��\�8 *��~A���K�k@�P���f�;Q��_�fҰ�H�&��x.����'���[�,Y���0nD��.5�'`slP'H
���2�`���>F�{���=`ߓ^4�Bׄ����no(�� Mh��w��7� �vI����g������S_\2���g����0��P��A=�s/������}�{8��z����&D!��o�"�� �[�{"�?��_��>� �} �ެd�4ޯ��R�GW�v�NtR����Ti�u��wJ�'~a�~��w~Bvz�7C���� �瀱v��w}Mi�x
x.���o#h 0�[p|-s[`���S�g�
�}3X09�_��Pr��8
%׀6�e_0sʀ+ȃ��-g�y��X7w�ꗄ9� 05�|ׇ}ò�GQ�|5Ѕ�`�s8�����†n8��W�h�ws���f5Ppz��w�၂x�zc{/�,pz���a{5`��_X��(�d9���ח���!@�9����;؃�؊wB�1�x�h �ǂd0���������W�}��_�|[�zF��ʸ��،������8��X��x��!� ,�g�V� [�^� a�b�e�k� i�%l�)o�+p�2u�8y�/�A�B�<��9������#��)��)��/��3��4��:��;��H��O��C��W��`��g��k��y��M��A��@��C��O��K��X��P��S��]��[��[��d��c��e��k��t��w��{��c��f��l��r��s��{��u��z��|�鄬���ǒ�ȗ�˝�΄��������������������������Ы�յ�ں�ܨ�������������������������������������������������������f������������A�������B��` ����
b�C�[�D�C��` �����c\�\LH��.+���%�����3��U�\����Ԍ!�ؠ��[�ߕ��ז ��ݗ!�B�QՃ_��3������������x�b�+̠*͸|�ǰ�"2�I��M����!"���Db\�@FӫX�����0cʜI�$��!qfС�i``�X���5
yI�ƈ��.jg�!y�~ݣɵ�W�6]̤��� �E�ERpE��x�Mj�.�,�Tj�]��� ^��*^�X� 3(cX��٘�?�|
��"��>z����A".̈��$T���DG�۸s�Caf�n`g��Mkħ^��r���f�x�z(��S��!��#ɕ��4Ѡ��y�%̜�Wb/��}��d�AZ|�>Z��)�Xg �f���K��ނ��������?� �rb0� ��'�)�߀R�@*�0���Ă��7�~A�L"��Z]� �� `@7b%�2� (�@[xV����0~���X��E�^�U�Ms�%RiF|Bt��eF� �K1�Uy�,��b�2r�'cU��X{�A�H)��J�Ly��y0��*��Õ�\Є�w���Ub*�3�D�o�!aX�Bz�@�A�yI��YE2�P�G�)�NlЏ�v�y�����z��C `ɚA�YI� Ƀ��hL�ک��l�'�|ʩ�˶k���g¹�%��*�� ��H����b+ Jpj,>,<�i�C,���k��3\|^Ü~�C1���>�0C�-�`1D�%`�K4�Ђl���7d��0F�������j|ldJ�C��ݐBV@}�G��S2\��l���x9� l|�B�v�1>,��b�31� 7��޹m��V���Ww��p��=�C�\��)��L�C�M�����%ͷ�Lo�ˆ���s���;�)M���D�n��v� 1����9�/�8�7qBW��=�-S�����sj{�vN=W)����u�t���QzoL=���̃���ZϾL/���R�dA��[��2�
���G�3����}���g5��D�b`ǎ@�� ������&�������$��ńc$��f� �� �^�B�@!�,�f�V� [�^�b�e�k� i�%l�)o�+p�2u�8y�$v�/�A�B�3������#��)��/��3��9��I��O��D��C��W��`��g��k��r��y��M��A��@��C��O��J��X��P��Q��T��]��c��a��l��t��b��f��m��s��{��u��v��{��|�鄬���ǒ�ȗ�̝�Π�τ�������������������������Ы�յ�ڹ�ܧ���������������������������������������������������X��)���)/B��RU�U_����������;�������<��Y���� [�=�T�>�=��Y
������ǛZ�UF����XU�������5�O�\���尩�T�쥲�� ×��<�L����Ҫ8bqh���"\Ȑ�!��h��� �vE�#�$��w��88�AӖ�0t!�+=�0;EjV�Р�8�5�ɳ�CܼM���nj{�8�d���>��h�i'}�����%R#�7}��&��سh-,bD"2*���K���\vV/YYg�n%/TK�ҫe)a\�yr��k/L<��v-$p���
0%qő�Jz�˷��JN �
k��7IkF���k& ��}6D��B�2p%��+^�0^ɉ+��R����0�yƽ� ˻{!��Ï����L9X�Ӕ��w~��&��_=;f)B����h��g]�D F1D(������P�}���~�X7
v�( ���� ��D�0�hC
�T���_�g�YX�a)�]��(n�)�u�E�O���PF)%51�he2X� #�q�E��d�^��Fɐ��Ɖ���h�l�=9�tByÕ0*�N�4bc?P��Ϙ��b&`� �ɑ���d�)pW礔"8� &AZ}
�*d�����"U&���/�0��(���H\P魸"X���F�D����nQ�)M�(I&�d���D�dM3`JC��f� I����)�@
(l�zi�f�]�T�=����-Р�����핵j��g��m�L�BH�I �� L&����^ �C @pn(����h� @P��{�7����lsC2xE ' ��Pq�c�z[�
��� +@��.��gSC�Ba�5�����s!� ,�f�V�^� a�b�e� i�)o�+p�2u�8y�/�;~�A�B�9������#��)��)��/��3��3��8��;��I��C��W��`��g��k��y��A��@��F��O��K��X��P��Q��S��]��_��[��a��l��r��y��c��f��l��s��{��v��z��}�脬���Œ�ȗ�˝�Π�υ����������������������յ�ں�ܦ������������������������������������������������Y�������RO�O?��4&���&����4���OR�9�������:��S����U�Y;�N�<�;��S� ��������чV�M�����������'37%�
�쩯�N�󫸺� ʅ��:Z�F������,r�Bҥp#J���&3f,r�F�s��;����(M�Ct�A� ��h��J3c��!�ɳgj�~8�H��Qp"�h\�T#Gs%҉lU���(W���� �� �j�ϳh��8ʶ�[L+��4�KW#�,�*�Zu�#��"�U�AX��"��U��J�\���JF���9���W�a�(]-k����0UXZ h����s#\ Ķ�; ���"$�?���G�'VE)P�C�$�����ײǪ��� 菆�W��� ��Xh��D��
�N+ �����y���e)�@߂ js�Eu�^�̠� 3���Hޱ�]+�!�+!�^*�(�BC�� �0ˆ���#&��e�
? ��}X�����m� �"�B,
�ލP6hL�p��Eې��";�f��̦ˉ����3���M�pBYhF�p#J�m�f?B#�*� �X+�)�� =�b��))�@3�Ȗ�=� W�xu��գS!h��撋<jɤ��jQ|\�8%hV'Is>>�+��*5��d*JRF����d��BB�t� t��`A<��^
,p� ���O,Ǭ��A��Ы��+�6��e�r(�@�KA� $����U�` EȅQE��|ma;�X�m"�#.h�NH� �H)�$;M(�]3Լ,��M T�@׵�ɵ5k]D\ �� �Qq�u���H ]K��@��`CGTSmC��D�r��!�,�h�V�^� a�b�e�k�)o�+p�2u�8y�$v�/�A�B�9������#��)��(��/��3��4��8��<��I��C��W��g��j��M��A��@��D��O��K��X��P��T��]��[��d��a��e��l��t��z��c��f��l��r��{��v��y��}�蒶ȗ�˝�Π�υ������������������������۫�չ�ܦ������������������������������������������������W������������RN�N<�<,$6���6AJ����*$��.�P�Q�������S�8�M�9�8��Q� ���������ы�K�'%%���=�������6��%�H�L������� ɅM�8,��ˈ��*\��
�I,�EPG��6
B�i�X.�Eu0<a�ajA{(�!��@�DS��PeX�c����s�Cش}:4��H9z$����!�F9X %,��b��2�.���2س�ٳ�V�Q�ӷp�Q$IJ��R�|�Ć% &��-����x�E��*c����LY!I@K���y[ �(:��f!�F�~(1��'�
�B�����������ߌ�T�(t��;��8.z�Q�;��;�CG��=d�/F7g�N���J%&2_w�^�B,�ߌ�c���JP��#�tG �a��[y2�<\�߃�]`�9>��G2l�Dhz�=�@���B w�-�,�%�b3�0�`�4�e�U�7�i4D;n�a9!���*�(��w��&ˁ/F��@��L � Xv3���A��7�sW����m�!�b,-J)� PP�D�xE�FD���<wN���]a$I$*@cM8��1��^5f�M8>��g��Hc��DG��a�@��&,qNz�e@�WE�h�+������pyei���a���j���U�@)�B��ʖf��k� jN�:�Q�X����Jd��Q +L�RL�P$�\k!{�l�����c� B��B�0�́��`CC���hC���|lj[Άex yL� ��Mk���ufE����s�,���!m��=X�Q;,w�a^��� ���e&��H��9I�P�����*�#��dg�3S"!� ,�h�V�^� a�b�l�%l�+p�2u�8y�/�B�9������#��)��(��/��3��4��9��<��H��B��D��g��M��A��@��B��O��K��X��P��S��]��[��c��l��t��c��f��l��r��z��v��{��}�菴ǒ�ȗ�˝�Π�σ��������������������������է����������������������������������������������P������������0�������1�LH�H7��5./���<C�����% �� DI�2�G�3�2��K�
M���������ы�տ �&!! ����"?������>��!�%��ȆG��b\"����*<�Ă5K��2A�Ǻ�2�K���Gu�4���#�%nA„P�,<F�ؾ�8s�ܙpIkA�B�F�_]�1��
��/���M2ps�@Ky�K�,��"j+�ӏG������9�˱�;.BIU<^��a��F5+3˸��I���t ��3�$�1͠E꽈���"l������h<�M�� $Enp�ΆGB ��!*��Ó�訢4;!�5�qc��������ܺC8@
�n���G�c�����C�|~��C^��!��(`2�q�! G�_��0|��t�&�:�d��u`:=P�Zu, h"w��`� ������T0bv�:�i�a:ʅ_:+�4�H�r�8E�I��8΍��$h0�NL)�9�i�jryx%�I��JH�)L��=��F-x�rA� �9��&��ח�!�#:AVuD�����ozf�#HD��G|Ej�T~Z�^��N�tN� '��ʼn�,tc�z���O~$%����F��:kR�Jk8��p*N�J`'��*ް5r�:8@+Π�����JfF|���H��C���uC]k%r�D'�"���n� 8 � ='�=��A�,60i:NU�>ю6���ت��P8�ӂ��� aU�}Bd'����(�ÑG(|��������
Ӯ�
�G��@p8�����ʹ) �<PG-5��x!� ,�h�V� [�^� a�b�e�k� i�%l�)o�2u�8y�/�A�B�<��9������#��)��)��/��3��4��9��<��H��W��`��g��y��M��A��@��C��O��K��X��P��S��\��[��b��m��p��v��c��f��l��r��s��z��u��|�鄬���ǒ�ȗ�˅������������������������������յ�ڽ�ާ��������������������������������������������������[������������8�������9��V ����NR�>��4'16���E*�'���+&-���U�V
�X���������ϋ�Ӡ��Qԗ &߭DM�F��?���E�(G��?���'>-&�MB����*<�e�����iJ2m�o,X�DZ]�|�0�8H�|6�,bd�*=ڠ���+ s���Ӡ�B���$��Lh$ɔ�G�)��ia�Ss.��`#_�~>�H�ҳ�ٳ9��h�,R���Xac]ӻx����U����: �J �х8Qs�X��#KF��S(9�H1u"�,�wM&��/I� ��x+I� /����۸s~�t�
4�O|�81!k��$��^~�EӮ��2�E�p�w�cת)�l���5q��@K2�K|�8�]^�ٗ;g�¥�� ��;��'���cޅg�wX,�I���{��"�]�EH�|$��}i�uag�(N�h�|r!WH!���Rw1���a�|�p�N�Y��Q<&��b>q��P"��'ܸ��gJ�T`+��e<�u�چL ��������f[�p"�$0� 2ؠ��k�US��yN���NUe���� )裴��$�q©ٌ)ȀGF�)��4e��v�\<�^��������"��RT
)3�9�2����H ��F�h����0ڎ��F�b5�Z����%Ep��Ri"l���F�l=|B:���������Y�Y}USX�\�X�8�˵ iKJz����*�(�PDLLQ�� %�k�:9b�A ?�;F�� �Ex�8D�3!S5��r��k3s As�����@�r����� %�02�=�`a�+e��������BAҥ�!�M�K�٣��3گ�L2^!:���*��Q����9��T)�3s�l'�ڊ?�.ސ����iy�F(��G�p�6l�� cG��鋯�z�~_�w;2'��3QC׉�����2E���3���ю����h<�=P>Z �?[z�X �����^�xA�h��=N�?�DԴ�0:3��}�ؿ����.apY�T�W�䄛��'?�����Q��r;�4l���]V4�?�����7�@!�,�h�V� [�^� a�b�e�k� i�%l�)o�+p�8y�/�A�4������#��)��)��/��3��4��:��<��I��C��W��`��g��k��y��A��C��O��K��X��P��S��[��^��\��^��[��d��m��c��f��l��r��s��{��u��z��{�鄬���Ώ�ǒ�ȗ�˝�Ί�އ�������������������������������Ь�յ�ڽ�ާ��������������������������������������������������������a������������9�������:��[ ����
]�;�U�<�8V�VA��%��*56�GQ�QH���3��S�Y��������Ќ�Ԡ��U�ە��Ӗ ���E'$$1��B����6���0������O��DH������d��P�5MMJ��K�I0 ��Ŭ�0$�W �}�B�$��ʗ0Q�JQ�
�8s�4��Ć��ɐ�!+RP�XW�>
HX�J�!�;zR�Y��5_�Ì �I���0U������h�2%Ȍ ��P"5���Q�*1aU�T_]+�W�D� o��Ly�O�Tc�ӆfY^�so߿���l+��c��lc�s������X|���n���E�>�R���i�%� ��k�׏&���������T|bBȋq� �/��%t��a�& {����@�6�g 3],� �-���D
%(�|���\~(UG�u�(bmA(ف(rE�ܐ�����`�D"^Ȝs��G�t���_�D�XB�V S�x)��(MP�,��=&��iR���j�u�҇�ii&�� ��;"�d��� ��ąOWB|��\��%K^��/�gϐg6�c](uK+p>�' lMhF��K�vy��R9�ϡRQ%�ae:ꪅ�(V�cATi"`,�I�5�J�wU��}�p���4���j�I�(Z��V�]���TS�)r����
,��韴��ffC�b>���>b٪�����~e,��$N�h���,e �E`� H� EH�0��;�Ap%I�� �I@�KI�K��� ���� (������ �� ��������g.� ��B�١��0��\0H�
H�1<�)�SoI��l6L"�|��2�<�L�66�|�͋4X���� �!���4�mx<iN$�v7^�z'���'fWm+�ؐ5K2�-5ي���ڦ��7�#�cb���84l]��Gqc�}����������Waw���U40�K��=UU�+|�ڭ ��JL��8�~?��n�t�C��̾so��˿����nL$�_@�_��G9���x�Þ��&�@;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment