]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Release 2.8.0 v2.8.0
authorChart.js <chartjs-ci@users.noreply.github.com>
Thu, 14 Mar 2019 13:03:00 +0000 (13:03 +0000)
committerChart.js <chartjs-ci@users.noreply.github.com>
Thu, 14 Mar 2019 13:03:00 +0000 (13:03 +0000)
bower.json [new file with mode: 0644]
dist/Chart.bundle.js [new file with mode: 0644]
dist/Chart.bundle.min.js [new file with mode: 0644]
dist/Chart.css [new file with mode: 0644]
dist/Chart.js [new file with mode: 0644]
dist/Chart.min.css [new file with mode: 0644]
dist/Chart.min.js [new file with mode: 0644]

diff --git a/bower.json b/bower.json
new file mode 100644 (file)
index 0000000..075b049
--- /dev/null
@@ -0,0 +1,16 @@
+{
+  "name": "chart.js",
+  "description": "Simple HTML5 charts using the canvas element.",
+  "homepage": "https://www.chartjs.org",
+  "license": "MIT",
+  "version": "2.8.0",
+  "main": "./dist/Chart.js",
+  "ignore": [
+    ".github",
+    ".codeclimate.yml",
+    ".gitignore",
+    ".npmignore",
+    ".travis.yml",
+    "scripts"
+  ]
+}
\ No newline at end of file
diff --git a/dist/Chart.bundle.js b/dist/Chart.bundle.js
new file mode 100644 (file)
index 0000000..33a955a
--- /dev/null
@@ -0,0 +1,19288 @@
+/*!
+ * Chart.js v2.8.0
+ * https://www.chartjs.org
+ * (c) 2019 Chart.js Contributors
+ * Released under the MIT License
+ */
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+typeof define === 'function' && define.amd ? define(factory) :
+(global.Chart = factory());
+}(this, (function () { 'use strict';
+
+/* MIT license */
+
+var conversions = {
+  rgb2hsl: rgb2hsl,
+  rgb2hsv: rgb2hsv,
+  rgb2hwb: rgb2hwb,
+  rgb2cmyk: rgb2cmyk,
+  rgb2keyword: rgb2keyword,
+  rgb2xyz: rgb2xyz,
+  rgb2lab: rgb2lab,
+  rgb2lch: rgb2lch,
+
+  hsl2rgb: hsl2rgb,
+  hsl2hsv: hsl2hsv,
+  hsl2hwb: hsl2hwb,
+  hsl2cmyk: hsl2cmyk,
+  hsl2keyword: hsl2keyword,
+
+  hsv2rgb: hsv2rgb,
+  hsv2hsl: hsv2hsl,
+  hsv2hwb: hsv2hwb,
+  hsv2cmyk: hsv2cmyk,
+  hsv2keyword: hsv2keyword,
+
+  hwb2rgb: hwb2rgb,
+  hwb2hsl: hwb2hsl,
+  hwb2hsv: hwb2hsv,
+  hwb2cmyk: hwb2cmyk,
+  hwb2keyword: hwb2keyword,
+
+  cmyk2rgb: cmyk2rgb,
+  cmyk2hsl: cmyk2hsl,
+  cmyk2hsv: cmyk2hsv,
+  cmyk2hwb: cmyk2hwb,
+  cmyk2keyword: cmyk2keyword,
+
+  keyword2rgb: keyword2rgb,
+  keyword2hsl: keyword2hsl,
+  keyword2hsv: keyword2hsv,
+  keyword2hwb: keyword2hwb,
+  keyword2cmyk: keyword2cmyk,
+  keyword2lab: keyword2lab,
+  keyword2xyz: keyword2xyz,
+
+  xyz2rgb: xyz2rgb,
+  xyz2lab: xyz2lab,
+  xyz2lch: xyz2lch,
+
+  lab2xyz: lab2xyz,
+  lab2rgb: lab2rgb,
+  lab2lch: lab2lch,
+
+  lch2lab: lch2lab,
+  lch2xyz: lch2xyz,
+  lch2rgb: lch2rgb
+};
+
+
+function rgb2hsl(rgb) {
+  var r = rgb[0]/255,
+      g = rgb[1]/255,
+      b = rgb[2]/255,
+      min = Math.min(r, g, b),
+      max = Math.max(r, g, b),
+      delta = max - min,
+      h, s, l;
+
+  if (max == min)
+    h = 0;
+  else if (r == max)
+    h = (g - b) / delta;
+  else if (g == max)
+    h = 2 + (b - r) / delta;
+  else if (b == max)
+    h = 4 + (r - g)/ delta;
+
+  h = Math.min(h * 60, 360);
+
+  if (h < 0)
+    h += 360;
+
+  l = (min + max) / 2;
+
+  if (max == min)
+    s = 0;
+  else if (l <= 0.5)
+    s = delta / (max + min);
+  else
+    s = delta / (2 - max - min);
+
+  return [h, s * 100, l * 100];
+}
+
+function rgb2hsv(rgb) {
+  var r = rgb[0],
+      g = rgb[1],
+      b = rgb[2],
+      min = Math.min(r, g, b),
+      max = Math.max(r, g, b),
+      delta = max - min,
+      h, s, v;
+
+  if (max == 0)
+    s = 0;
+  else
+    s = (delta/max * 1000)/10;
+
+  if (max == min)
+    h = 0;
+  else if (r == max)
+    h = (g - b) / delta;
+  else if (g == max)
+    h = 2 + (b - r) / delta;
+  else if (b == max)
+    h = 4 + (r - g) / delta;
+
+  h = Math.min(h * 60, 360);
+
+  if (h < 0)
+    h += 360;
+
+  v = ((max / 255) * 1000) / 10;
+
+  return [h, s, v];
+}
+
+function rgb2hwb(rgb) {
+  var r = rgb[0],
+      g = rgb[1],
+      b = rgb[2],
+      h = rgb2hsl(rgb)[0],
+      w = 1/255 * Math.min(r, Math.min(g, b)),
+      b = 1 - 1/255 * Math.max(r, Math.max(g, b));
+
+  return [h, w * 100, b * 100];
+}
+
+function rgb2cmyk(rgb) {
+  var r = rgb[0] / 255,
+      g = rgb[1] / 255,
+      b = rgb[2] / 255,
+      c, m, y, k;
+
+  k = Math.min(1 - r, 1 - g, 1 - b);
+  c = (1 - r - k) / (1 - k) || 0;
+  m = (1 - g - k) / (1 - k) || 0;
+  y = (1 - b - k) / (1 - k) || 0;
+  return [c * 100, m * 100, y * 100, k * 100];
+}
+
+function rgb2keyword(rgb) {
+  return reverseKeywords[JSON.stringify(rgb)];
+}
+
+function rgb2xyz(rgb) {
+  var r = rgb[0] / 255,
+      g = rgb[1] / 255,
+      b = rgb[2] / 255;
+
+  // assume sRGB
+  r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
+  g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
+  b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
+
+  var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
+  var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
+  var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
+
+  return [x * 100, y *100, z * 100];
+}
+
+function rgb2lab(rgb) {
+  var xyz = rgb2xyz(rgb),
+        x = xyz[0],
+        y = xyz[1],
+        z = xyz[2],
+        l, a, b;
+
+  x /= 95.047;
+  y /= 100;
+  z /= 108.883;
+
+  x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
+  y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
+  z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
+
+  l = (116 * y) - 16;
+  a = 500 * (x - y);
+  b = 200 * (y - z);
+
+  return [l, a, b];
+}
+
+function rgb2lch(args) {
+  return lab2lch(rgb2lab(args));
+}
+
+function hsl2rgb(hsl) {
+  var h = hsl[0] / 360,
+      s = hsl[1] / 100,
+      l = hsl[2] / 100,
+      t1, t2, t3, rgb, val;
+
+  if (s == 0) {
+    val = l * 255;
+    return [val, val, val];
+  }
+
+  if (l < 0.5)
+    t2 = l * (1 + s);
+  else
+    t2 = l + s - l * s;
+  t1 = 2 * l - t2;
+
+  rgb = [0, 0, 0];
+  for (var i = 0; i < 3; i++) {
+    t3 = h + 1 / 3 * - (i - 1);
+    t3 < 0 && t3++;
+    t3 > 1 && t3--;
+
+    if (6 * t3 < 1)
+      val = t1 + (t2 - t1) * 6 * t3;
+    else if (2 * t3 < 1)
+      val = t2;
+    else if (3 * t3 < 2)
+      val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
+    else
+      val = t1;
+
+    rgb[i] = val * 255;
+  }
+
+  return rgb;
+}
+
+function hsl2hsv(hsl) {
+  var h = hsl[0],
+      s = hsl[1] / 100,
+      l = hsl[2] / 100,
+      sv, v;
+
+  if(l === 0) {
+      // no need to do calc on black
+      // also avoids divide by 0 error
+      return [0, 0, 0];
+  }
+
+  l *= 2;
+  s *= (l <= 1) ? l : 2 - l;
+  v = (l + s) / 2;
+  sv = (2 * s) / (l + s);
+  return [h, sv * 100, v * 100];
+}
+
+function hsl2hwb(args) {
+  return rgb2hwb(hsl2rgb(args));
+}
+
+function hsl2cmyk(args) {
+  return rgb2cmyk(hsl2rgb(args));
+}
+
+function hsl2keyword(args) {
+  return rgb2keyword(hsl2rgb(args));
+}
+
+
+function hsv2rgb(hsv) {
+  var h = hsv[0] / 60,
+      s = hsv[1] / 100,
+      v = hsv[2] / 100,
+      hi = Math.floor(h) % 6;
+
+  var f = h - Math.floor(h),
+      p = 255 * v * (1 - s),
+      q = 255 * v * (1 - (s * f)),
+      t = 255 * v * (1 - (s * (1 - f))),
+      v = 255 * v;
+
+  switch(hi) {
+    case 0:
+      return [v, t, p];
+    case 1:
+      return [q, v, p];
+    case 2:
+      return [p, v, t];
+    case 3:
+      return [p, q, v];
+    case 4:
+      return [t, p, v];
+    case 5:
+      return [v, p, q];
+  }
+}
+
+function hsv2hsl(hsv) {
+  var h = hsv[0],
+      s = hsv[1] / 100,
+      v = hsv[2] / 100,
+      sl, l;
+
+  l = (2 - s) * v;
+  sl = s * v;
+  sl /= (l <= 1) ? l : 2 - l;
+  sl = sl || 0;
+  l /= 2;
+  return [h, sl * 100, l * 100];
+}
+
+function hsv2hwb(args) {
+  return rgb2hwb(hsv2rgb(args))
+}
+
+function hsv2cmyk(args) {
+  return rgb2cmyk(hsv2rgb(args));
+}
+
+function hsv2keyword(args) {
+  return rgb2keyword(hsv2rgb(args));
+}
+
+// http://dev.w3.org/csswg/css-color/#hwb-to-rgb
+function hwb2rgb(hwb) {
+  var h = hwb[0] / 360,
+      wh = hwb[1] / 100,
+      bl = hwb[2] / 100,
+      ratio = wh + bl,
+      i, v, f, n;
+
+  // wh + bl cant be > 1
+  if (ratio > 1) {
+    wh /= ratio;
+    bl /= ratio;
+  }
+
+  i = Math.floor(6 * h);
+  v = 1 - bl;
+  f = 6 * h - i;
+  if ((i & 0x01) != 0) {
+    f = 1 - f;
+  }
+  n = wh + f * (v - wh);  // linear interpolation
+
+  switch (i) {
+    default:
+    case 6:
+    case 0: r = v; g = n; b = wh; break;
+    case 1: r = n; g = v; b = wh; break;
+    case 2: r = wh; g = v; b = n; break;
+    case 3: r = wh; g = n; b = v; break;
+    case 4: r = n; g = wh; b = v; break;
+    case 5: r = v; g = wh; b = n; break;
+  }
+
+  return [r * 255, g * 255, b * 255];
+}
+
+function hwb2hsl(args) {
+  return rgb2hsl(hwb2rgb(args));
+}
+
+function hwb2hsv(args) {
+  return rgb2hsv(hwb2rgb(args));
+}
+
+function hwb2cmyk(args) {
+  return rgb2cmyk(hwb2rgb(args));
+}
+
+function hwb2keyword(args) {
+  return rgb2keyword(hwb2rgb(args));
+}
+
+function cmyk2rgb(cmyk) {
+  var c = cmyk[0] / 100,
+      m = cmyk[1] / 100,
+      y = cmyk[2] / 100,
+      k = cmyk[3] / 100,
+      r, g, b;
+
+  r = 1 - Math.min(1, c * (1 - k) + k);
+  g = 1 - Math.min(1, m * (1 - k) + k);
+  b = 1 - Math.min(1, y * (1 - k) + k);
+  return [r * 255, g * 255, b * 255];
+}
+
+function cmyk2hsl(args) {
+  return rgb2hsl(cmyk2rgb(args));
+}
+
+function cmyk2hsv(args) {
+  return rgb2hsv(cmyk2rgb(args));
+}
+
+function cmyk2hwb(args) {
+  return rgb2hwb(cmyk2rgb(args));
+}
+
+function cmyk2keyword(args) {
+  return rgb2keyword(cmyk2rgb(args));
+}
+
+
+function xyz2rgb(xyz) {
+  var x = xyz[0] / 100,
+      y = xyz[1] / 100,
+      z = xyz[2] / 100,
+      r, g, b;
+
+  r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
+  g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
+  b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
+
+  // assume sRGB
+  r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
+    : r = (r * 12.92);
+
+  g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
+    : g = (g * 12.92);
+
+  b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
+    : b = (b * 12.92);
+
+  r = Math.min(Math.max(0, r), 1);
+  g = Math.min(Math.max(0, g), 1);
+  b = Math.min(Math.max(0, b), 1);
+
+  return [r * 255, g * 255, b * 255];
+}
+
+function xyz2lab(xyz) {
+  var x = xyz[0],
+      y = xyz[1],
+      z = xyz[2],
+      l, a, b;
+
+  x /= 95.047;
+  y /= 100;
+  z /= 108.883;
+
+  x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
+  y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
+  z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
+
+  l = (116 * y) - 16;
+  a = 500 * (x - y);
+  b = 200 * (y - z);
+
+  return [l, a, b];
+}
+
+function xyz2lch(args) {
+  return lab2lch(xyz2lab(args));
+}
+
+function lab2xyz(lab) {
+  var l = lab[0],
+      a = lab[1],
+      b = lab[2],
+      x, y, z, y2;
+
+  if (l <= 8) {
+    y = (l * 100) / 903.3;
+    y2 = (7.787 * (y / 100)) + (16 / 116);
+  } else {
+    y = 100 * Math.pow((l + 16) / 116, 3);
+    y2 = Math.pow(y / 100, 1/3);
+  }
+
+  x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3);
+
+  z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3);
+
+  return [x, y, z];
+}
+
+function lab2lch(lab) {
+  var l = lab[0],
+      a = lab[1],
+      b = lab[2],
+      hr, h, c;
+
+  hr = Math.atan2(b, a);
+  h = hr * 360 / 2 / Math.PI;
+  if (h < 0) {
+    h += 360;
+  }
+  c = Math.sqrt(a * a + b * b);
+  return [l, c, h];
+}
+
+function lab2rgb(args) {
+  return xyz2rgb(lab2xyz(args));
+}
+
+function lch2lab(lch) {
+  var l = lch[0],
+      c = lch[1],
+      h = lch[2],
+      a, b, hr;
+
+  hr = h / 360 * 2 * Math.PI;
+  a = c * Math.cos(hr);
+  b = c * Math.sin(hr);
+  return [l, a, b];
+}
+
+function lch2xyz(args) {
+  return lab2xyz(lch2lab(args));
+}
+
+function lch2rgb(args) {
+  return lab2rgb(lch2lab(args));
+}
+
+function keyword2rgb(keyword) {
+  return cssKeywords[keyword];
+}
+
+function keyword2hsl(args) {
+  return rgb2hsl(keyword2rgb(args));
+}
+
+function keyword2hsv(args) {
+  return rgb2hsv(keyword2rgb(args));
+}
+
+function keyword2hwb(args) {
+  return rgb2hwb(keyword2rgb(args));
+}
+
+function keyword2cmyk(args) {
+  return rgb2cmyk(keyword2rgb(args));
+}
+
+function keyword2lab(args) {
+  return rgb2lab(keyword2rgb(args));
+}
+
+function keyword2xyz(args) {
+  return rgb2xyz(keyword2rgb(args));
+}
+
+var cssKeywords = {
+  aliceblue:  [240,248,255],
+  antiquewhite: [250,235,215],
+  aqua: [0,255,255],
+  aquamarine: [127,255,212],
+  azure:  [240,255,255],
+  beige:  [245,245,220],
+  bisque: [255,228,196],
+  black:  [0,0,0],
+  blanchedalmond: [255,235,205],
+  blue: [0,0,255],
+  blueviolet: [138,43,226],
+  brown:  [165,42,42],
+  burlywood:  [222,184,135],
+  cadetblue:  [95,158,160],
+  chartreuse: [127,255,0],
+  chocolate:  [210,105,30],
+  coral:  [255,127,80],
+  cornflowerblue: [100,149,237],
+  cornsilk: [255,248,220],
+  crimson:  [220,20,60],
+  cyan: [0,255,255],
+  darkblue: [0,0,139],
+  darkcyan: [0,139,139],
+  darkgoldenrod:  [184,134,11],
+  darkgray: [169,169,169],
+  darkgreen:  [0,100,0],
+  darkgrey: [169,169,169],
+  darkkhaki:  [189,183,107],
+  darkmagenta:  [139,0,139],
+  darkolivegreen: [85,107,47],
+  darkorange: [255,140,0],
+  darkorchid: [153,50,204],
+  darkred:  [139,0,0],
+  darksalmon: [233,150,122],
+  darkseagreen: [143,188,143],
+  darkslateblue:  [72,61,139],
+  darkslategray:  [47,79,79],
+  darkslategrey:  [47,79,79],
+  darkturquoise:  [0,206,209],
+  darkviolet: [148,0,211],
+  deeppink: [255,20,147],
+  deepskyblue:  [0,191,255],
+  dimgray:  [105,105,105],
+  dimgrey:  [105,105,105],
+  dodgerblue: [30,144,255],
+  firebrick:  [178,34,34],
+  floralwhite:  [255,250,240],
+  forestgreen:  [34,139,34],
+  fuchsia:  [255,0,255],
+  gainsboro:  [220,220,220],
+  ghostwhite: [248,248,255],
+  gold: [255,215,0],
+  goldenrod:  [218,165,32],
+  gray: [128,128,128],
+  green:  [0,128,0],
+  greenyellow:  [173,255,47],
+  grey: [128,128,128],
+  honeydew: [240,255,240],
+  hotpink:  [255,105,180],
+  indianred:  [205,92,92],
+  indigo: [75,0,130],
+  ivory:  [255,255,240],
+  khaki:  [240,230,140],
+  lavender: [230,230,250],
+  lavenderblush:  [255,240,245],
+  lawngreen:  [124,252,0],
+  lemonchiffon: [255,250,205],
+  lightblue:  [173,216,230],
+  lightcoral: [240,128,128],
+  lightcyan:  [224,255,255],
+  lightgoldenrodyellow: [250,250,210],
+  lightgray:  [211,211,211],
+  lightgreen: [144,238,144],
+  lightgrey:  [211,211,211],
+  lightpink:  [255,182,193],
+  lightsalmon:  [255,160,122],
+  lightseagreen:  [32,178,170],
+  lightskyblue: [135,206,250],
+  lightslategray: [119,136,153],
+  lightslategrey: [119,136,153],
+  lightsteelblue: [176,196,222],
+  lightyellow:  [255,255,224],
+  lime: [0,255,0],
+  limegreen:  [50,205,50],
+  linen:  [250,240,230],
+  magenta:  [255,0,255],
+  maroon: [128,0,0],
+  mediumaquamarine: [102,205,170],
+  mediumblue: [0,0,205],
+  mediumorchid: [186,85,211],
+  mediumpurple: [147,112,219],
+  mediumseagreen: [60,179,113],
+  mediumslateblue:  [123,104,238],
+  mediumspringgreen:  [0,250,154],
+  mediumturquoise:  [72,209,204],
+  mediumvioletred:  [199,21,133],
+  midnightblue: [25,25,112],
+  mintcream:  [245,255,250],
+  mistyrose:  [255,228,225],
+  moccasin: [255,228,181],
+  navajowhite:  [255,222,173],
+  navy: [0,0,128],
+  oldlace:  [253,245,230],
+  olive:  [128,128,0],
+  olivedrab:  [107,142,35],
+  orange: [255,165,0],
+  orangered:  [255,69,0],
+  orchid: [218,112,214],
+  palegoldenrod:  [238,232,170],
+  palegreen:  [152,251,152],
+  paleturquoise:  [175,238,238],
+  palevioletred:  [219,112,147],
+  papayawhip: [255,239,213],
+  peachpuff:  [255,218,185],
+  peru: [205,133,63],
+  pink: [255,192,203],
+  plum: [221,160,221],
+  powderblue: [176,224,230],
+  purple: [128,0,128],
+  rebeccapurple: [102, 51, 153],
+  red:  [255,0,0],
+  rosybrown:  [188,143,143],
+  royalblue:  [65,105,225],
+  saddlebrown:  [139,69,19],
+  salmon: [250,128,114],
+  sandybrown: [244,164,96],
+  seagreen: [46,139,87],
+  seashell: [255,245,238],
+  sienna: [160,82,45],
+  silver: [192,192,192],
+  skyblue:  [135,206,235],
+  slateblue:  [106,90,205],
+  slategray:  [112,128,144],
+  slategrey:  [112,128,144],
+  snow: [255,250,250],
+  springgreen:  [0,255,127],
+  steelblue:  [70,130,180],
+  tan:  [210,180,140],
+  teal: [0,128,128],
+  thistle:  [216,191,216],
+  tomato: [255,99,71],
+  turquoise:  [64,224,208],
+  violet: [238,130,238],
+  wheat:  [245,222,179],
+  white:  [255,255,255],
+  whitesmoke: [245,245,245],
+  yellow: [255,255,0],
+  yellowgreen:  [154,205,50]
+};
+
+var reverseKeywords = {};
+for (var key in cssKeywords) {
+  reverseKeywords[JSON.stringify(cssKeywords[key])] = key;
+}
+
+var convert = function() {
+   return new Converter();
+};
+
+for (var func in conversions) {
+  // export Raw versions
+  convert[func + "Raw"] =  (function(func) {
+    // accept array or plain args
+    return function(arg) {
+      if (typeof arg == "number")
+        arg = Array.prototype.slice.call(arguments);
+      return conversions[func](arg);
+    }
+  })(func);
+
+  var pair = /(\w+)2(\w+)/.exec(func),
+      from = pair[1],
+      to = pair[2];
+
+  // export rgb2hsl and ["rgb"]["hsl"]
+  convert[from] = convert[from] || {};
+
+  convert[from][to] = convert[func] = (function(func) { 
+    return function(arg) {
+      if (typeof arg == "number")
+        arg = Array.prototype.slice.call(arguments);
+      
+      var val = conversions[func](arg);
+      if (typeof val == "string" || val === undefined)
+        return val; // keyword
+
+      for (var i = 0; i < val.length; i++)
+        val[i] = Math.round(val[i]);
+      return val;
+    }
+  })(func);
+}
+
+
+/* Converter does lazy conversion and caching */
+var Converter = function() {
+   this.convs = {};
+};
+
+/* Either get the values for a space or
+  set the values for a space, depending on args */
+Converter.prototype.routeSpace = function(space, args) {
+   var values = args[0];
+   if (values === undefined) {
+      // color.rgb()
+      return this.getValues(space);
+   }
+   // color.rgb(10, 10, 10)
+   if (typeof values == "number") {
+      values = Array.prototype.slice.call(args);        
+   }
+
+   return this.setValues(space, values);
+};
+  
+/* Set the values for a space, invalidating cache */
+Converter.prototype.setValues = function(space, values) {
+   this.space = space;
+   this.convs = {};
+   this.convs[space] = values;
+   return this;
+};
+
+/* Get the values for a space. If there's already
+  a conversion for the space, fetch it, otherwise
+  compute it */
+Converter.prototype.getValues = function(space) {
+   var vals = this.convs[space];
+   if (!vals) {
+      var fspace = this.space,
+          from = this.convs[fspace];
+      vals = convert[fspace][space](from);
+
+      this.convs[space] = vals;
+   }
+  return vals;
+};
+
+["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) {
+   Converter.prototype[space] = function(vals) {
+      return this.routeSpace(space, arguments);
+   };
+});
+
+var colorConvert = convert;
+
+var colorName = {\r
+       "aliceblue": [240, 248, 255],\r
+       "antiquewhite": [250, 235, 215],\r
+       "aqua": [0, 255, 255],\r
+       "aquamarine": [127, 255, 212],\r
+       "azure": [240, 255, 255],\r
+       "beige": [245, 245, 220],\r
+       "bisque": [255, 228, 196],\r
+       "black": [0, 0, 0],\r
+       "blanchedalmond": [255, 235, 205],\r
+       "blue": [0, 0, 255],\r
+       "blueviolet": [138, 43, 226],\r
+       "brown": [165, 42, 42],\r
+       "burlywood": [222, 184, 135],\r
+       "cadetblue": [95, 158, 160],\r
+       "chartreuse": [127, 255, 0],\r
+       "chocolate": [210, 105, 30],\r
+       "coral": [255, 127, 80],\r
+       "cornflowerblue": [100, 149, 237],\r
+       "cornsilk": [255, 248, 220],\r
+       "crimson": [220, 20, 60],\r
+       "cyan": [0, 255, 255],\r
+       "darkblue": [0, 0, 139],\r
+       "darkcyan": [0, 139, 139],\r
+       "darkgoldenrod": [184, 134, 11],\r
+       "darkgray": [169, 169, 169],\r
+       "darkgreen": [0, 100, 0],\r
+       "darkgrey": [169, 169, 169],\r
+       "darkkhaki": [189, 183, 107],\r
+       "darkmagenta": [139, 0, 139],\r
+       "darkolivegreen": [85, 107, 47],\r
+       "darkorange": [255, 140, 0],\r
+       "darkorchid": [153, 50, 204],\r
+       "darkred": [139, 0, 0],\r
+       "darksalmon": [233, 150, 122],\r
+       "darkseagreen": [143, 188, 143],\r
+       "darkslateblue": [72, 61, 139],\r
+       "darkslategray": [47, 79, 79],\r
+       "darkslategrey": [47, 79, 79],\r
+       "darkturquoise": [0, 206, 209],\r
+       "darkviolet": [148, 0, 211],\r
+       "deeppink": [255, 20, 147],\r
+       "deepskyblue": [0, 191, 255],\r
+       "dimgray": [105, 105, 105],\r
+       "dimgrey": [105, 105, 105],\r
+       "dodgerblue": [30, 144, 255],\r
+       "firebrick": [178, 34, 34],\r
+       "floralwhite": [255, 250, 240],\r
+       "forestgreen": [34, 139, 34],\r
+       "fuchsia": [255, 0, 255],\r
+       "gainsboro": [220, 220, 220],\r
+       "ghostwhite": [248, 248, 255],\r
+       "gold": [255, 215, 0],\r
+       "goldenrod": [218, 165, 32],\r
+       "gray": [128, 128, 128],\r
+       "green": [0, 128, 0],\r
+       "greenyellow": [173, 255, 47],\r
+       "grey": [128, 128, 128],\r
+       "honeydew": [240, 255, 240],\r
+       "hotpink": [255, 105, 180],\r
+       "indianred": [205, 92, 92],\r
+       "indigo": [75, 0, 130],\r
+       "ivory": [255, 255, 240],\r
+       "khaki": [240, 230, 140],\r
+       "lavender": [230, 230, 250],\r
+       "lavenderblush": [255, 240, 245],\r
+       "lawngreen": [124, 252, 0],\r
+       "lemonchiffon": [255, 250, 205],\r
+       "lightblue": [173, 216, 230],\r
+       "lightcoral": [240, 128, 128],\r
+       "lightcyan": [224, 255, 255],\r
+       "lightgoldenrodyellow": [250, 250, 210],\r
+       "lightgray": [211, 211, 211],\r
+       "lightgreen": [144, 238, 144],\r
+       "lightgrey": [211, 211, 211],\r
+       "lightpink": [255, 182, 193],\r
+       "lightsalmon": [255, 160, 122],\r
+       "lightseagreen": [32, 178, 170],\r
+       "lightskyblue": [135, 206, 250],\r
+       "lightslategray": [119, 136, 153],\r
+       "lightslategrey": [119, 136, 153],\r
+       "lightsteelblue": [176, 196, 222],\r
+       "lightyellow": [255, 255, 224],\r
+       "lime": [0, 255, 0],\r
+       "limegreen": [50, 205, 50],\r
+       "linen": [250, 240, 230],\r
+       "magenta": [255, 0, 255],\r
+       "maroon": [128, 0, 0],\r
+       "mediumaquamarine": [102, 205, 170],\r
+       "mediumblue": [0, 0, 205],\r
+       "mediumorchid": [186, 85, 211],\r
+       "mediumpurple": [147, 112, 219],\r
+       "mediumseagreen": [60, 179, 113],\r
+       "mediumslateblue": [123, 104, 238],\r
+       "mediumspringgreen": [0, 250, 154],\r
+       "mediumturquoise": [72, 209, 204],\r
+       "mediumvioletred": [199, 21, 133],\r
+       "midnightblue": [25, 25, 112],\r
+       "mintcream": [245, 255, 250],\r
+       "mistyrose": [255, 228, 225],\r
+       "moccasin": [255, 228, 181],\r
+       "navajowhite": [255, 222, 173],\r
+       "navy": [0, 0, 128],\r
+       "oldlace": [253, 245, 230],\r
+       "olive": [128, 128, 0],\r
+       "olivedrab": [107, 142, 35],\r
+       "orange": [255, 165, 0],\r
+       "orangered": [255, 69, 0],\r
+       "orchid": [218, 112, 214],\r
+       "palegoldenrod": [238, 232, 170],\r
+       "palegreen": [152, 251, 152],\r
+       "paleturquoise": [175, 238, 238],\r
+       "palevioletred": [219, 112, 147],\r
+       "papayawhip": [255, 239, 213],\r
+       "peachpuff": [255, 218, 185],\r
+       "peru": [205, 133, 63],\r
+       "pink": [255, 192, 203],\r
+       "plum": [221, 160, 221],\r
+       "powderblue": [176, 224, 230],\r
+       "purple": [128, 0, 128],\r
+       "rebeccapurple": [102, 51, 153],\r
+       "red": [255, 0, 0],\r
+       "rosybrown": [188, 143, 143],\r
+       "royalblue": [65, 105, 225],\r
+       "saddlebrown": [139, 69, 19],\r
+       "salmon": [250, 128, 114],\r
+       "sandybrown": [244, 164, 96],\r
+       "seagreen": [46, 139, 87],\r
+       "seashell": [255, 245, 238],\r
+       "sienna": [160, 82, 45],\r
+       "silver": [192, 192, 192],\r
+       "skyblue": [135, 206, 235],\r
+       "slateblue": [106, 90, 205],\r
+       "slategray": [112, 128, 144],\r
+       "slategrey": [112, 128, 144],\r
+       "snow": [255, 250, 250],\r
+       "springgreen": [0, 255, 127],\r
+       "steelblue": [70, 130, 180],\r
+       "tan": [210, 180, 140],\r
+       "teal": [0, 128, 128],\r
+       "thistle": [216, 191, 216],\r
+       "tomato": [255, 99, 71],\r
+       "turquoise": [64, 224, 208],\r
+       "violet": [238, 130, 238],\r
+       "wheat": [245, 222, 179],\r
+       "white": [255, 255, 255],\r
+       "whitesmoke": [245, 245, 245],\r
+       "yellow": [255, 255, 0],\r
+       "yellowgreen": [154, 205, 50]\r
+};
+
+/* MIT license */
+
+
+var colorString = {
+   getRgba: getRgba,
+   getHsla: getHsla,
+   getRgb: getRgb,
+   getHsl: getHsl,
+   getHwb: getHwb,
+   getAlpha: getAlpha,
+
+   hexString: hexString,
+   rgbString: rgbString,
+   rgbaString: rgbaString,
+   percentString: percentString,
+   percentaString: percentaString,
+   hslString: hslString,
+   hslaString: hslaString,
+   hwbString: hwbString,
+   keyword: keyword
+};
+
+function getRgba(string) {
+   if (!string) {
+      return;
+   }
+   var abbr =  /^#([a-fA-F0-9]{3,4})$/i,
+       hex =  /^#([a-fA-F0-9]{6}([a-fA-F0-9]{2})?)$/i,
+       rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i,
+       per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i,
+       keyword = /(\w+)/;
+
+   var rgb = [0, 0, 0],
+       a = 1,
+       match = string.match(abbr),
+       hexAlpha = "";
+   if (match) {
+      match = match[1];
+      hexAlpha = match[3];
+      for (var i = 0; i < rgb.length; i++) {
+         rgb[i] = parseInt(match[i] + match[i], 16);
+      }
+      if (hexAlpha) {
+         a = Math.round((parseInt(hexAlpha + hexAlpha, 16) / 255) * 100) / 100;
+      }
+   }
+   else if (match = string.match(hex)) {
+      hexAlpha = match[2];
+      match = match[1];
+      for (var i = 0; i < rgb.length; i++) {
+         rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16);
+      }
+      if (hexAlpha) {
+         a = Math.round((parseInt(hexAlpha, 16) / 255) * 100) / 100;
+      }
+   }
+   else if (match = string.match(rgba)) {
+      for (var i = 0; i < rgb.length; i++) {
+         rgb[i] = parseInt(match[i + 1]);
+      }
+      a = parseFloat(match[4]);
+   }
+   else if (match = string.match(per)) {
+      for (var i = 0; i < rgb.length; i++) {
+         rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
+      }
+      a = parseFloat(match[4]);
+   }
+   else if (match = string.match(keyword)) {
+      if (match[1] == "transparent") {
+         return [0, 0, 0, 0];
+      }
+      rgb = colorName[match[1]];
+      if (!rgb) {
+         return;
+      }
+   }
+
+   for (var i = 0; i < rgb.length; i++) {
+      rgb[i] = scale(rgb[i], 0, 255);
+   }
+   if (!a && a != 0) {
+      a = 1;
+   }
+   else {
+      a = scale(a, 0, 1);
+   }
+   rgb[3] = a;
+   return rgb;
+}
+
+function getHsla(string) {
+   if (!string) {
+      return;
+   }
+   var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
+   var match = string.match(hsl);
+   if (match) {
+      var alpha = parseFloat(match[4]);
+      var h = scale(parseInt(match[1]), 0, 360),
+          s = scale(parseFloat(match[2]), 0, 100),
+          l = scale(parseFloat(match[3]), 0, 100),
+          a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
+      return [h, s, l, a];
+   }
+}
+
+function getHwb(string) {
+   if (!string) {
+      return;
+   }
+   var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
+   var match = string.match(hwb);
+   if (match) {
+    var alpha = parseFloat(match[4]);
+      var h = scale(parseInt(match[1]), 0, 360),
+          w = scale(parseFloat(match[2]), 0, 100),
+          b = scale(parseFloat(match[3]), 0, 100),
+          a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
+      return [h, w, b, a];
+   }
+}
+
+function getRgb(string) {
+   var rgba = getRgba(string);
+   return rgba && rgba.slice(0, 3);
+}
+
+function getHsl(string) {
+  var hsla = getHsla(string);
+  return hsla && hsla.slice(0, 3);
+}
+
+function getAlpha(string) {
+   var vals = getRgba(string);
+   if (vals) {
+      return vals[3];
+   }
+   else if (vals = getHsla(string)) {
+      return vals[3];
+   }
+   else if (vals = getHwb(string)) {
+      return vals[3];
+   }
+}
+
+// generators
+function hexString(rgba, a) {
+   var a = (a !== undefined && rgba.length === 3) ? a : rgba[3];
+   return "#" + hexDouble(rgba[0]) 
+              + hexDouble(rgba[1])
+              + hexDouble(rgba[2])
+              + (
+                 (a >= 0 && a < 1)
+                 ? hexDouble(Math.round(a * 255))
+                 : ""
+              );
+}
+
+function rgbString(rgba, alpha) {
+   if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
+      return rgbaString(rgba, alpha);
+   }
+   return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")";
+}
+
+function rgbaString(rgba, alpha) {
+   if (alpha === undefined) {
+      alpha = (rgba[3] !== undefined ? rgba[3] : 1);
+   }
+   return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2]
+           + ", " + alpha + ")";
+}
+
+function percentString(rgba, alpha) {
+   if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
+      return percentaString(rgba, alpha);
+   }
+   var r = Math.round(rgba[0]/255 * 100),
+       g = Math.round(rgba[1]/255 * 100),
+       b = Math.round(rgba[2]/255 * 100);
+
+   return "rgb(" + r + "%, " + g + "%, " + b + "%)";
+}
+
+function percentaString(rgba, alpha) {
+   var r = Math.round(rgba[0]/255 * 100),
+       g = Math.round(rgba[1]/255 * 100),
+       b = Math.round(rgba[2]/255 * 100);
+   return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")";
+}
+
+function hslString(hsla, alpha) {
+   if (alpha < 1 || (hsla[3] && hsla[3] < 1)) {
+      return hslaString(hsla, alpha);
+   }
+   return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";
+}
+
+function hslaString(hsla, alpha) {
+   if (alpha === undefined) {
+      alpha = (hsla[3] !== undefined ? hsla[3] : 1);
+   }
+   return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, "
+           + alpha + ")";
+}
+
+// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
+// (hwb have alpha optional & 1 is default value)
+function hwbString(hwb, alpha) {
+   if (alpha === undefined) {
+      alpha = (hwb[3] !== undefined ? hwb[3] : 1);
+   }
+   return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%"
+           + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")";
+}
+
+function keyword(rgb) {
+  return reverseNames[rgb.slice(0, 3)];
+}
+
+// helpers
+function scale(num, min, max) {
+   return Math.min(Math.max(min, num), max);
+}
+
+function hexDouble(num) {
+  var str = num.toString(16).toUpperCase();
+  return (str.length < 2) ? "0" + str : str;
+}
+
+
+//create a list of reverse color names
+var reverseNames = {};
+for (var name in colorName) {
+   reverseNames[colorName[name]] = name;
+}
+
+/* MIT license */
+
+
+
+var Color = function (obj) {
+       if (obj instanceof Color) {
+               return obj;
+       }
+       if (!(this instanceof Color)) {
+               return new Color(obj);
+       }
+
+       this.valid = false;
+       this.values = {
+               rgb: [0, 0, 0],
+               hsl: [0, 0, 0],
+               hsv: [0, 0, 0],
+               hwb: [0, 0, 0],
+               cmyk: [0, 0, 0, 0],
+               alpha: 1
+       };
+
+       // parse Color() argument
+       var vals;
+       if (typeof obj === 'string') {
+               vals = colorString.getRgba(obj);
+               if (vals) {
+                       this.setValues('rgb', vals);
+               } else if (vals = colorString.getHsla(obj)) {
+                       this.setValues('hsl', vals);
+               } else if (vals = colorString.getHwb(obj)) {
+                       this.setValues('hwb', vals);
+               }
+       } else if (typeof obj === 'object') {
+               vals = obj;
+               if (vals.r !== undefined || vals.red !== undefined) {
+                       this.setValues('rgb', vals);
+               } else if (vals.l !== undefined || vals.lightness !== undefined) {
+                       this.setValues('hsl', vals);
+               } else if (vals.v !== undefined || vals.value !== undefined) {
+                       this.setValues('hsv', vals);
+               } else if (vals.w !== undefined || vals.whiteness !== undefined) {
+                       this.setValues('hwb', vals);
+               } else if (vals.c !== undefined || vals.cyan !== undefined) {
+                       this.setValues('cmyk', vals);
+               }
+       }
+};
+
+Color.prototype = {
+       isValid: function () {
+               return this.valid;
+       },
+       rgb: function () {
+               return this.setSpace('rgb', arguments);
+       },
+       hsl: function () {
+               return this.setSpace('hsl', arguments);
+       },
+       hsv: function () {
+               return this.setSpace('hsv', arguments);
+       },
+       hwb: function () {
+               return this.setSpace('hwb', arguments);
+       },
+       cmyk: function () {
+               return this.setSpace('cmyk', arguments);
+       },
+
+       rgbArray: function () {
+               return this.values.rgb;
+       },
+       hslArray: function () {
+               return this.values.hsl;
+       },
+       hsvArray: function () {
+               return this.values.hsv;
+       },
+       hwbArray: function () {
+               var values = this.values;
+               if (values.alpha !== 1) {
+                       return values.hwb.concat([values.alpha]);
+               }
+               return values.hwb;
+       },
+       cmykArray: function () {
+               return this.values.cmyk;
+       },
+       rgbaArray: function () {
+               var values = this.values;
+               return values.rgb.concat([values.alpha]);
+       },
+       hslaArray: function () {
+               var values = this.values;
+               return values.hsl.concat([values.alpha]);
+       },
+       alpha: function (val) {
+               if (val === undefined) {
+                       return this.values.alpha;
+               }
+               this.setValues('alpha', val);
+               return this;
+       },
+
+       red: function (val) {
+               return this.setChannel('rgb', 0, val);
+       },
+       green: function (val) {
+               return this.setChannel('rgb', 1, val);
+       },
+       blue: function (val) {
+               return this.setChannel('rgb', 2, val);
+       },
+       hue: function (val) {
+               if (val) {
+                       val %= 360;
+                       val = val < 0 ? 360 + val : val;
+               }
+               return this.setChannel('hsl', 0, val);
+       },
+       saturation: function (val) {
+               return this.setChannel('hsl', 1, val);
+       },
+       lightness: function (val) {
+               return this.setChannel('hsl', 2, val);
+       },
+       saturationv: function (val) {
+               return this.setChannel('hsv', 1, val);
+       },
+       whiteness: function (val) {
+               return this.setChannel('hwb', 1, val);
+       },
+       blackness: function (val) {
+               return this.setChannel('hwb', 2, val);
+       },
+       value: function (val) {
+               return this.setChannel('hsv', 2, val);
+       },
+       cyan: function (val) {
+               return this.setChannel('cmyk', 0, val);
+       },
+       magenta: function (val) {
+               return this.setChannel('cmyk', 1, val);
+       },
+       yellow: function (val) {
+               return this.setChannel('cmyk', 2, val);
+       },
+       black: function (val) {
+               return this.setChannel('cmyk', 3, val);
+       },
+
+       hexString: function () {
+               return colorString.hexString(this.values.rgb);
+       },
+       rgbString: function () {
+               return colorString.rgbString(this.values.rgb, this.values.alpha);
+       },
+       rgbaString: function () {
+               return colorString.rgbaString(this.values.rgb, this.values.alpha);
+       },
+       percentString: function () {
+               return colorString.percentString(this.values.rgb, this.values.alpha);
+       },
+       hslString: function () {
+               return colorString.hslString(this.values.hsl, this.values.alpha);
+       },
+       hslaString: function () {
+               return colorString.hslaString(this.values.hsl, this.values.alpha);
+       },
+       hwbString: function () {
+               return colorString.hwbString(this.values.hwb, this.values.alpha);
+       },
+       keyword: function () {
+               return colorString.keyword(this.values.rgb, this.values.alpha);
+       },
+
+       rgbNumber: function () {
+               var rgb = this.values.rgb;
+               return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
+       },
+
+       luminosity: function () {
+               // http://www.w3.org/TR/WCAG20/#relativeluminancedef
+               var rgb = this.values.rgb;
+               var lum = [];
+               for (var i = 0; i < rgb.length; i++) {
+                       var chan = rgb[i] / 255;
+                       lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4);
+               }
+               return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
+       },
+
+       contrast: function (color2) {
+               // http://www.w3.org/TR/WCAG20/#contrast-ratiodef
+               var lum1 = this.luminosity();
+               var lum2 = color2.luminosity();
+               if (lum1 > lum2) {
+                       return (lum1 + 0.05) / (lum2 + 0.05);
+               }
+               return (lum2 + 0.05) / (lum1 + 0.05);
+       },
+
+       level: function (color2) {
+               var contrastRatio = this.contrast(color2);
+               if (contrastRatio >= 7.1) {
+                       return 'AAA';
+               }
+
+               return (contrastRatio >= 4.5) ? 'AA' : '';
+       },
+
+       dark: function () {
+               // YIQ equation from http://24ways.org/2010/calculating-color-contrast
+               var rgb = this.values.rgb;
+               var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
+               return yiq < 128;
+       },
+
+       light: function () {
+               return !this.dark();
+       },
+
+       negate: function () {
+               var rgb = [];
+               for (var i = 0; i < 3; i++) {
+                       rgb[i] = 255 - this.values.rgb[i];
+               }
+               this.setValues('rgb', rgb);
+               return this;
+       },
+
+       lighten: function (ratio) {
+               var hsl = this.values.hsl;
+               hsl[2] += hsl[2] * ratio;
+               this.setValues('hsl', hsl);
+               return this;
+       },
+
+       darken: function (ratio) {
+               var hsl = this.values.hsl;
+               hsl[2] -= hsl[2] * ratio;
+               this.setValues('hsl', hsl);
+               return this;
+       },
+
+       saturate: function (ratio) {
+               var hsl = this.values.hsl;
+               hsl[1] += hsl[1] * ratio;
+               this.setValues('hsl', hsl);
+               return this;
+       },
+
+       desaturate: function (ratio) {
+               var hsl = this.values.hsl;
+               hsl[1] -= hsl[1] * ratio;
+               this.setValues('hsl', hsl);
+               return this;
+       },
+
+       whiten: function (ratio) {
+               var hwb = this.values.hwb;
+               hwb[1] += hwb[1] * ratio;
+               this.setValues('hwb', hwb);
+               return this;
+       },
+
+       blacken: function (ratio) {
+               var hwb = this.values.hwb;
+               hwb[2] += hwb[2] * ratio;
+               this.setValues('hwb', hwb);
+               return this;
+       },
+
+       greyscale: function () {
+               var rgb = this.values.rgb;
+               // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
+               var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
+               this.setValues('rgb', [val, val, val]);
+               return this;
+       },
+
+       clearer: function (ratio) {
+               var alpha = this.values.alpha;
+               this.setValues('alpha', alpha - (alpha * ratio));
+               return this;
+       },
+
+       opaquer: function (ratio) {
+               var alpha = this.values.alpha;
+               this.setValues('alpha', alpha + (alpha * ratio));
+               return this;
+       },
+
+       rotate: function (degrees) {
+               var hsl = this.values.hsl;
+               var hue = (hsl[0] + degrees) % 360;
+               hsl[0] = hue < 0 ? 360 + hue : hue;
+               this.setValues('hsl', hsl);
+               return this;
+       },
+
+       /**
+        * Ported from sass implementation in C
+        * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209
+        */
+       mix: function (mixinColor, weight) {
+               var color1 = this;
+               var color2 = mixinColor;
+               var p = weight === undefined ? 0.5 : weight;
+
+               var w = 2 * p - 1;
+               var a = color1.alpha() - color2.alpha();
+
+               var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
+               var w2 = 1 - w1;
+
+               return this
+                       .rgb(
+                               w1 * color1.red() + w2 * color2.red(),
+                               w1 * color1.green() + w2 * color2.green(),
+                               w1 * color1.blue() + w2 * color2.blue()
+                       )
+                       .alpha(color1.alpha() * p + color2.alpha() * (1 - p));
+       },
+
+       toJSON: function () {
+               return this.rgb();
+       },
+
+       clone: function () {
+               // NOTE(SB): using node-clone creates a dependency to Buffer when using browserify,
+               // making the final build way to big to embed in Chart.js. So let's do it manually,
+               // assuming that values to clone are 1 dimension arrays containing only numbers,
+               // except 'alpha' which is a number.
+               var result = new Color();
+               var source = this.values;
+               var target = result.values;
+               var value, type;
+
+               for (var prop in source) {
+                       if (source.hasOwnProperty(prop)) {
+                               value = source[prop];
+                               type = ({}).toString.call(value);
+                               if (type === '[object Array]') {
+                                       target[prop] = value.slice(0);
+                               } else if (type === '[object Number]') {
+                                       target[prop] = value;
+                               } else {
+                                       console.error('unexpected color value:', value);
+                               }
+                       }
+               }
+
+               return result;
+       }
+};
+
+Color.prototype.spaces = {
+       rgb: ['red', 'green', 'blue'],
+       hsl: ['hue', 'saturation', 'lightness'],
+       hsv: ['hue', 'saturation', 'value'],
+       hwb: ['hue', 'whiteness', 'blackness'],
+       cmyk: ['cyan', 'magenta', 'yellow', 'black']
+};
+
+Color.prototype.maxes = {
+       rgb: [255, 255, 255],
+       hsl: [360, 100, 100],
+       hsv: [360, 100, 100],
+       hwb: [360, 100, 100],
+       cmyk: [100, 100, 100, 100]
+};
+
+Color.prototype.getValues = function (space) {
+       var values = this.values;
+       var vals = {};
+
+       for (var i = 0; i < space.length; i++) {
+               vals[space.charAt(i)] = values[space][i];
+       }
+
+       if (values.alpha !== 1) {
+               vals.a = values.alpha;
+       }
+
+       // {r: 255, g: 255, b: 255, a: 0.4}
+       return vals;
+};
+
+Color.prototype.setValues = function (space, vals) {
+       var values = this.values;
+       var spaces = this.spaces;
+       var maxes = this.maxes;
+       var alpha = 1;
+       var i;
+
+       this.valid = true;
+
+       if (space === 'alpha') {
+               alpha = vals;
+       } else if (vals.length) {
+               // [10, 10, 10]
+               values[space] = vals.slice(0, space.length);
+               alpha = vals[space.length];
+       } else if (vals[space.charAt(0)] !== undefined) {
+               // {r: 10, g: 10, b: 10}
+               for (i = 0; i < space.length; i++) {
+                       values[space][i] = vals[space.charAt(i)];
+               }
+
+               alpha = vals.a;
+       } else if (vals[spaces[space][0]] !== undefined) {
+               // {red: 10, green: 10, blue: 10}
+               var chans = spaces[space];
+
+               for (i = 0; i < space.length; i++) {
+                       values[space][i] = vals[chans[i]];
+               }
+
+               alpha = vals.alpha;
+       }
+
+       values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha)));
+
+       if (space === 'alpha') {
+               return false;
+       }
+
+       var capped;
+
+       // cap values of the space prior converting all values
+       for (i = 0; i < space.length; i++) {
+               capped = Math.max(0, Math.min(maxes[space][i], values[space][i]));
+               values[space][i] = Math.round(capped);
+       }
+
+       // convert to all the other color spaces
+       for (var sname in spaces) {
+               if (sname !== space) {
+                       values[sname] = colorConvert[space][sname](values[space]);
+               }
+       }
+
+       return true;
+};
+
+Color.prototype.setSpace = function (space, args) {
+       var vals = args[0];
+
+       if (vals === undefined) {
+               // color.rgb()
+               return this.getValues(space);
+       }
+
+       // color.rgb(10, 10, 10)
+       if (typeof vals === 'number') {
+               vals = Array.prototype.slice.call(args);
+       }
+
+       this.setValues(space, vals);
+       return this;
+};
+
+Color.prototype.setChannel = function (space, index, val) {
+       var svalues = this.values[space];
+       if (val === undefined) {
+               // color.red()
+               return svalues[index];
+       } else if (val === svalues[index]) {
+               // color.red(color.red())
+               return this;
+       }
+
+       // color.red(100)
+       svalues[index] = val;
+       this.setValues(space, svalues);
+
+       return this;
+};
+
+if (typeof window !== 'undefined') {
+       window.Color = Color;
+}
+
+var chartjsColor = Color;
+
+/**
+ * @namespace Chart.helpers
+ */
+var helpers = {
+       /**
+        * An empty function that can be used, for example, for optional callback.
+        */
+       noop: function() {},
+
+       /**
+        * Returns a unique id, sequentially generated from a global variable.
+        * @returns {number}
+        * @function
+        */
+       uid: (function() {
+               var id = 0;
+               return function() {
+                       return id++;
+               };
+       }()),
+
+       /**
+        * Returns true if `value` is neither null nor undefined, else returns false.
+        * @param {*} value - The value to test.
+        * @returns {boolean}
+        * @since 2.7.0
+        */
+       isNullOrUndef: function(value) {
+               return value === null || typeof value === 'undefined';
+       },
+
+       /**
+        * Returns true if `value` is an array (including typed arrays), else returns false.
+        * @param {*} value - The value to test.
+        * @returns {boolean}
+        * @function
+        */
+       isArray: function(value) {
+               if (Array.isArray && Array.isArray(value)) {
+                       return true;
+               }
+               var type = Object.prototype.toString.call(value);
+               if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') {
+                       return true;
+               }
+               return false;
+       },
+
+       /**
+        * Returns true if `value` is an object (excluding null), else returns false.
+        * @param {*} value - The value to test.
+        * @returns {boolean}
+        * @since 2.7.0
+        */
+       isObject: function(value) {
+               return value !== null && Object.prototype.toString.call(value) === '[object Object]';
+       },
+
+       /**
+        * Returns true if `value` is a finite number, else returns false
+        * @param {*} value  - The value to test.
+        * @returns {boolean}
+        */
+       isFinite: function(value) {
+               return (typeof value === 'number' || value instanceof Number) && isFinite(value);
+       },
+
+       /**
+        * Returns `value` if defined, else returns `defaultValue`.
+        * @param {*} value - The value to return if defined.
+        * @param {*} defaultValue - The value to return if `value` is undefined.
+        * @returns {*}
+        */
+       valueOrDefault: function(value, defaultValue) {
+               return typeof value === 'undefined' ? defaultValue : value;
+       },
+
+       /**
+        * Returns value at the given `index` in array if defined, else returns `defaultValue`.
+        * @param {Array} value - The array to lookup for value at `index`.
+        * @param {number} index - The index in `value` to lookup for value.
+        * @param {*} defaultValue - The value to return if `value[index]` is undefined.
+        * @returns {*}
+        */
+       valueAtIndexOrDefault: function(value, index, defaultValue) {
+               return helpers.valueOrDefault(helpers.isArray(value) ? value[index] : value, defaultValue);
+       },
+
+       /**
+        * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
+        * value returned by `fn`. If `fn` is not a function, this method returns undefined.
+        * @param {function} fn - The function to call.
+        * @param {Array|undefined|null} args - The arguments with which `fn` should be called.
+        * @param {object} [thisArg] - The value of `this` provided for the call to `fn`.
+        * @returns {*}
+        */
+       callback: function(fn, args, thisArg) {
+               if (fn && typeof fn.call === 'function') {
+                       return fn.apply(thisArg, args);
+               }
+       },
+
+       /**
+        * Note(SB) for performance sake, this method should only be used when loopable type
+        * is unknown or in none intensive code (not called often and small loopable). Else
+        * it's preferable to use a regular for() loop and save extra function calls.
+        * @param {object|Array} loopable - The object or array to be iterated.
+        * @param {function} fn - The function to call for each item.
+        * @param {object} [thisArg] - The value of `this` provided for the call to `fn`.
+        * @param {boolean} [reverse] - If true, iterates backward on the loopable.
+        */
+       each: function(loopable, fn, thisArg, reverse) {
+               var i, len, keys;
+               if (helpers.isArray(loopable)) {
+                       len = loopable.length;
+                       if (reverse) {
+                               for (i = len - 1; i >= 0; i--) {
+                                       fn.call(thisArg, loopable[i], i);
+                               }
+                       } else {
+                               for (i = 0; i < len; i++) {
+                                       fn.call(thisArg, loopable[i], i);
+                               }
+                       }
+               } else if (helpers.isObject(loopable)) {
+                       keys = Object.keys(loopable);
+                       len = keys.length;
+                       for (i = 0; i < len; i++) {
+                               fn.call(thisArg, loopable[keys[i]], keys[i]);
+                       }
+               }
+       },
+
+       /**
+        * Returns true if the `a0` and `a1` arrays have the same content, else returns false.
+        * @see https://stackoverflow.com/a/14853974
+        * @param {Array} a0 - The array to compare
+        * @param {Array} a1 - The array to compare
+        * @returns {boolean}
+        */
+       arrayEquals: function(a0, a1) {
+               var i, ilen, v0, v1;
+
+               if (!a0 || !a1 || a0.length !== a1.length) {
+                       return false;
+               }
+
+               for (i = 0, ilen = a0.length; i < ilen; ++i) {
+                       v0 = a0[i];
+                       v1 = a1[i];
+
+                       if (v0 instanceof Array && v1 instanceof Array) {
+                               if (!helpers.arrayEquals(v0, v1)) {
+                                       return false;
+                               }
+                       } else if (v0 !== v1) {
+                               // NOTE: two different object instances will never be equal: {x:20} != {x:20}
+                               return false;
+                       }
+               }
+
+               return true;
+       },
+
+       /**
+        * Returns a deep copy of `source` without keeping references on objects and arrays.
+        * @param {*} source - The value to clone.
+        * @returns {*}
+        */
+       clone: function(source) {
+               if (helpers.isArray(source)) {
+                       return source.map(helpers.clone);
+               }
+
+               if (helpers.isObject(source)) {
+                       var target = {};
+                       var keys = Object.keys(source);
+                       var klen = keys.length;
+                       var k = 0;
+
+                       for (; k < klen; ++k) {
+                               target[keys[k]] = helpers.clone(source[keys[k]]);
+                       }
+
+                       return target;
+               }
+
+               return source;
+       },
+
+       /**
+        * The default merger when Chart.helpers.merge is called without merger option.
+        * Note(SB): also used by mergeConfig and mergeScaleConfig as fallback.
+        * @private
+        */
+       _merger: function(key, target, source, options) {
+               var tval = target[key];
+               var sval = source[key];
+
+               if (helpers.isObject(tval) && helpers.isObject(sval)) {
+                       helpers.merge(tval, sval, options);
+               } else {
+                       target[key] = helpers.clone(sval);
+               }
+       },
+
+       /**
+        * Merges source[key] in target[key] only if target[key] is undefined.
+        * @private
+        */
+       _mergerIf: function(key, target, source) {
+               var tval = target[key];
+               var sval = source[key];
+
+               if (helpers.isObject(tval) && helpers.isObject(sval)) {
+                       helpers.mergeIf(tval, sval);
+               } else if (!target.hasOwnProperty(key)) {
+                       target[key] = helpers.clone(sval);
+               }
+       },
+
+       /**
+        * Recursively deep copies `source` properties into `target` with the given `options`.
+        * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
+        * @param {object} target - The target object in which all sources are merged into.
+        * @param {object|object[]} source - Object(s) to merge into `target`.
+        * @param {object} [options] - Merging options:
+        * @param {function} [options.merger] - The merge method (key, target, source, options)
+        * @returns {object} The `target` object.
+        */
+       merge: function(target, source, options) {
+               var sources = helpers.isArray(source) ? source : [source];
+               var ilen = sources.length;
+               var merge, i, keys, klen, k;
+
+               if (!helpers.isObject(target)) {
+                       return target;
+               }
+
+               options = options || {};
+               merge = options.merger || helpers._merger;
+
+               for (i = 0; i < ilen; ++i) {
+                       source = sources[i];
+                       if (!helpers.isObject(source)) {
+                               continue;
+                       }
+
+                       keys = Object.keys(source);
+                       for (k = 0, klen = keys.length; k < klen; ++k) {
+                               merge(keys[k], target, source, options);
+                       }
+               }
+
+               return target;
+       },
+
+       /**
+        * Recursively deep copies `source` properties into `target` *only* if not defined in target.
+        * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
+        * @param {object} target - The target object in which all sources are merged into.
+        * @param {object|object[]} source - Object(s) to merge into `target`.
+        * @returns {object} The `target` object.
+        */
+       mergeIf: function(target, source) {
+               return helpers.merge(target, source, {merger: helpers._mergerIf});
+       },
+
+       /**
+        * Applies the contents of two or more objects together into the first object.
+        * @param {object} target - The target object in which all objects are merged into.
+        * @param {object} arg1 - Object containing additional properties to merge in target.
+        * @param {object} argN - Additional objects containing properties to merge in target.
+        * @returns {object} The `target` object.
+        */
+       extend: function(target) {
+               var setFn = function(value, key) {
+                       target[key] = value;
+               };
+               for (var i = 1, ilen = arguments.length; i < ilen; ++i) {
+                       helpers.each(arguments[i], setFn);
+               }
+               return target;
+       },
+
+       /**
+        * Basic javascript inheritance based on the model created in Backbone.js
+        */
+       inherits: function(extensions) {
+               var me = this;
+               var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function() {
+                       return me.apply(this, arguments);
+               };
+
+               var Surrogate = function() {
+                       this.constructor = ChartElement;
+               };
+
+               Surrogate.prototype = me.prototype;
+               ChartElement.prototype = new Surrogate();
+               ChartElement.extend = helpers.inherits;
+
+               if (extensions) {
+                       helpers.extend(ChartElement.prototype, extensions);
+               }
+
+               ChartElement.__super__ = me.prototype;
+               return ChartElement;
+       }
+};
+
+var helpers_core = helpers;
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.callback instead.
+ * @function Chart.helpers.callCallback
+ * @deprecated since version 2.6.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers.callCallback = helpers.callback;
+
+/**
+ * Provided for backward compatibility, use Array.prototype.indexOf instead.
+ * Array.prototype.indexOf compatibility: Chrome, Opera, Safari, FF1.5+, IE9+
+ * @function Chart.helpers.indexOf
+ * @deprecated since version 2.7.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers.indexOf = function(array, item, fromIndex) {
+       return Array.prototype.indexOf.call(array, item, fromIndex);
+};
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.valueOrDefault instead.
+ * @function Chart.helpers.getValueOrDefault
+ * @deprecated since version 2.7.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers.getValueOrDefault = helpers.valueOrDefault;
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.valueAtIndexOrDefault instead.
+ * @function Chart.helpers.getValueAtIndexOrDefault
+ * @deprecated since version 2.7.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers.getValueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
+
+/**
+ * Easing functions adapted from Robert Penner's easing equations.
+ * @namespace Chart.helpers.easingEffects
+ * @see http://www.robertpenner.com/easing/
+ */
+var effects = {
+       linear: function(t) {
+               return t;
+       },
+
+       easeInQuad: function(t) {
+               return t * t;
+       },
+
+       easeOutQuad: function(t) {
+               return -t * (t - 2);
+       },
+
+       easeInOutQuad: function(t) {
+               if ((t /= 0.5) < 1) {
+                       return 0.5 * t * t;
+               }
+               return -0.5 * ((--t) * (t - 2) - 1);
+       },
+
+       easeInCubic: function(t) {
+               return t * t * t;
+       },
+
+       easeOutCubic: function(t) {
+               return (t = t - 1) * t * t + 1;
+       },
+
+       easeInOutCubic: function(t) {
+               if ((t /= 0.5) < 1) {
+                       return 0.5 * t * t * t;
+               }
+               return 0.5 * ((t -= 2) * t * t + 2);
+       },
+
+       easeInQuart: function(t) {
+               return t * t * t * t;
+       },
+
+       easeOutQuart: function(t) {
+               return -((t = t - 1) * t * t * t - 1);
+       },
+
+       easeInOutQuart: function(t) {
+               if ((t /= 0.5) < 1) {
+                       return 0.5 * t * t * t * t;
+               }
+               return -0.5 * ((t -= 2) * t * t * t - 2);
+       },
+
+       easeInQuint: function(t) {
+               return t * t * t * t * t;
+       },
+
+       easeOutQuint: function(t) {
+               return (t = t - 1) * t * t * t * t + 1;
+       },
+
+       easeInOutQuint: function(t) {
+               if ((t /= 0.5) < 1) {
+                       return 0.5 * t * t * t * t * t;
+               }
+               return 0.5 * ((t -= 2) * t * t * t * t + 2);
+       },
+
+       easeInSine: function(t) {
+               return -Math.cos(t * (Math.PI / 2)) + 1;
+       },
+
+       easeOutSine: function(t) {
+               return Math.sin(t * (Math.PI / 2));
+       },
+
+       easeInOutSine: function(t) {
+               return -0.5 * (Math.cos(Math.PI * t) - 1);
+       },
+
+       easeInExpo: function(t) {
+               return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1));
+       },
+
+       easeOutExpo: function(t) {
+               return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1;
+       },
+
+       easeInOutExpo: function(t) {
+               if (t === 0) {
+                       return 0;
+               }
+               if (t === 1) {
+                       return 1;
+               }
+               if ((t /= 0.5) < 1) {
+                       return 0.5 * Math.pow(2, 10 * (t - 1));
+               }
+               return 0.5 * (-Math.pow(2, -10 * --t) + 2);
+       },
+
+       easeInCirc: function(t) {
+               if (t >= 1) {
+                       return t;
+               }
+               return -(Math.sqrt(1 - t * t) - 1);
+       },
+
+       easeOutCirc: function(t) {
+               return Math.sqrt(1 - (t = t - 1) * t);
+       },
+
+       easeInOutCirc: function(t) {
+               if ((t /= 0.5) < 1) {
+                       return -0.5 * (Math.sqrt(1 - t * t) - 1);
+               }
+               return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
+       },
+
+       easeInElastic: function(t) {
+               var s = 1.70158;
+               var p = 0;
+               var a = 1;
+               if (t === 0) {
+                       return 0;
+               }
+               if (t === 1) {
+                       return 1;
+               }
+               if (!p) {
+                       p = 0.3;
+               }
+               if (a < 1) {
+                       a = 1;
+                       s = p / 4;
+               } else {
+                       s = p / (2 * Math.PI) * Math.asin(1 / a);
+               }
+               return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
+       },
+
+       easeOutElastic: function(t) {
+               var s = 1.70158;
+               var p = 0;
+               var a = 1;
+               if (t === 0) {
+                       return 0;
+               }
+               if (t === 1) {
+                       return 1;
+               }
+               if (!p) {
+                       p = 0.3;
+               }
+               if (a < 1) {
+                       a = 1;
+                       s = p / 4;
+               } else {
+                       s = p / (2 * Math.PI) * Math.asin(1 / a);
+               }
+               return a * Math.pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + 1;
+       },
+
+       easeInOutElastic: function(t) {
+               var s = 1.70158;
+               var p = 0;
+               var a = 1;
+               if (t === 0) {
+                       return 0;
+               }
+               if ((t /= 0.5) === 2) {
+                       return 1;
+               }
+               if (!p) {
+                       p = 0.45;
+               }
+               if (a < 1) {
+                       a = 1;
+                       s = p / 4;
+               } else {
+                       s = p / (2 * Math.PI) * Math.asin(1 / a);
+               }
+               if (t < 1) {
+                       return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
+               }
+               return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p) * 0.5 + 1;
+       },
+       easeInBack: function(t) {
+               var s = 1.70158;
+               return t * t * ((s + 1) * t - s);
+       },
+
+       easeOutBack: function(t) {
+               var s = 1.70158;
+               return (t = t - 1) * t * ((s + 1) * t + s) + 1;
+       },
+
+       easeInOutBack: function(t) {
+               var s = 1.70158;
+               if ((t /= 0.5) < 1) {
+                       return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s));
+               }
+               return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
+       },
+
+       easeInBounce: function(t) {
+               return 1 - effects.easeOutBounce(1 - t);
+       },
+
+       easeOutBounce: function(t) {
+               if (t < (1 / 2.75)) {
+                       return 7.5625 * t * t;
+               }
+               if (t < (2 / 2.75)) {
+                       return 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75;
+               }
+               if (t < (2.5 / 2.75)) {
+                       return 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375;
+               }
+               return 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375;
+       },
+
+       easeInOutBounce: function(t) {
+               if (t < 0.5) {
+                       return effects.easeInBounce(t * 2) * 0.5;
+               }
+               return effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5;
+       }
+};
+
+var helpers_easing = {
+       effects: effects
+};
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.easing.effects instead.
+ * @function Chart.helpers.easingEffects
+ * @deprecated since version 2.7.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers_core.easingEffects = effects;
+
+var PI = Math.PI;
+var RAD_PER_DEG = PI / 180;
+var DOUBLE_PI = PI * 2;
+var HALF_PI = PI / 2;
+var QUARTER_PI = PI / 4;
+var TWO_THIRDS_PI = PI * 2 / 3;
+
+/**
+ * @namespace Chart.helpers.canvas
+ */
+var exports$1 = {
+       /**
+        * Clears the entire canvas associated to the given `chart`.
+        * @param {Chart} chart - The chart for which to clear the canvas.
+        */
+       clear: function(chart) {
+               chart.ctx.clearRect(0, 0, chart.width, chart.height);
+       },
+
+       /**
+        * Creates a "path" for a rectangle with rounded corners at position (x, y) with a
+        * given size (width, height) and the same `radius` for all corners.
+        * @param {CanvasRenderingContext2D} ctx - The canvas 2D Context.
+        * @param {number} x - The x axis of the coordinate for the rectangle starting point.
+        * @param {number} y - The y axis of the coordinate for the rectangle starting point.
+        * @param {number} width - The rectangle's width.
+        * @param {number} height - The rectangle's height.
+        * @param {number} radius - The rounded amount (in pixels) for the four corners.
+        * @todo handle `radius` as top-left, top-right, bottom-right, bottom-left array/object?
+        */
+       roundedRect: function(ctx, x, y, width, height, radius) {
+               if (radius) {
+                       var r = Math.min(radius, height / 2, width / 2);
+                       var left = x + r;
+                       var top = y + r;
+                       var right = x + width - r;
+                       var bottom = y + height - r;
+
+                       ctx.moveTo(x, top);
+                       if (left < right && top < bottom) {
+                               ctx.arc(left, top, r, -PI, -HALF_PI);
+                               ctx.arc(right, top, r, -HALF_PI, 0);
+                               ctx.arc(right, bottom, r, 0, HALF_PI);
+                               ctx.arc(left, bottom, r, HALF_PI, PI);
+                       } else if (left < right) {
+                               ctx.moveTo(left, y);
+                               ctx.arc(right, top, r, -HALF_PI, HALF_PI);
+                               ctx.arc(left, top, r, HALF_PI, PI + HALF_PI);
+                       } else if (top < bottom) {
+                               ctx.arc(left, top, r, -PI, 0);
+                               ctx.arc(left, bottom, r, 0, PI);
+                       } else {
+                               ctx.arc(left, top, r, -PI, PI);
+                       }
+                       ctx.closePath();
+                       ctx.moveTo(x, y);
+               } else {
+                       ctx.rect(x, y, width, height);
+               }
+       },
+
+       drawPoint: function(ctx, style, radius, x, y, rotation) {
+               var type, xOffset, yOffset, size, cornerRadius;
+               var rad = (rotation || 0) * RAD_PER_DEG;
+
+               if (style && typeof style === 'object') {
+                       type = style.toString();
+                       if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
+                               ctx.drawImage(style, x - style.width / 2, y - style.height / 2, style.width, style.height);
+                               return;
+                       }
+               }
+
+               if (isNaN(radius) || radius <= 0) {
+                       return;
+               }
+
+               ctx.beginPath();
+
+               switch (style) {
+               // Default includes circle
+               default:
+                       ctx.arc(x, y, radius, 0, DOUBLE_PI);
+                       ctx.closePath();
+                       break;
+               case 'triangle':
+                       ctx.moveTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
+                       rad += TWO_THIRDS_PI;
+                       ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
+                       rad += TWO_THIRDS_PI;
+                       ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
+                       ctx.closePath();
+                       break;
+               case 'rectRounded':
+                       // NOTE: the rounded rect implementation changed to use `arc` instead of
+                       // `quadraticCurveTo` since it generates better results when rect is
+                       // almost a circle. 0.516 (instead of 0.5) produces results with visually
+                       // closer proportion to the previous impl and it is inscribed in the
+                       // circle with `radius`. For more details, see the following PRs:
+                       // https://github.com/chartjs/Chart.js/issues/5597
+                       // https://github.com/chartjs/Chart.js/issues/5858
+                       cornerRadius = radius * 0.516;
+                       size = radius - cornerRadius;
+                       xOffset = Math.cos(rad + QUARTER_PI) * size;
+                       yOffset = Math.sin(rad + QUARTER_PI) * size;
+                       ctx.arc(x - xOffset, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI);
+                       ctx.arc(x + yOffset, y - xOffset, cornerRadius, rad - HALF_PI, rad);
+                       ctx.arc(x + xOffset, y + yOffset, cornerRadius, rad, rad + HALF_PI);
+                       ctx.arc(x - yOffset, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI);
+                       ctx.closePath();
+                       break;
+               case 'rect':
+                       if (!rotation) {
+                               size = Math.SQRT1_2 * radius;
+                               ctx.rect(x - size, y - size, 2 * size, 2 * size);
+                               break;
+                       }
+                       rad += QUARTER_PI;
+                       /* falls through */
+               case 'rectRot':
+                       xOffset = Math.cos(rad) * radius;
+                       yOffset = Math.sin(rad) * radius;
+                       ctx.moveTo(x - xOffset, y - yOffset);
+                       ctx.lineTo(x + yOffset, y - xOffset);
+                       ctx.lineTo(x + xOffset, y + yOffset);
+                       ctx.lineTo(x - yOffset, y + xOffset);
+                       ctx.closePath();
+                       break;
+               case 'crossRot':
+                       rad += QUARTER_PI;
+                       /* falls through */
+               case 'cross':
+                       xOffset = Math.cos(rad) * radius;
+                       yOffset = Math.sin(rad) * radius;
+                       ctx.moveTo(x - xOffset, y - yOffset);
+                       ctx.lineTo(x + xOffset, y + yOffset);
+                       ctx.moveTo(x + yOffset, y - xOffset);
+                       ctx.lineTo(x - yOffset, y + xOffset);
+                       break;
+               case 'star':
+                       xOffset = Math.cos(rad) * radius;
+                       yOffset = Math.sin(rad) * radius;
+                       ctx.moveTo(x - xOffset, y - yOffset);
+                       ctx.lineTo(x + xOffset, y + yOffset);
+                       ctx.moveTo(x + yOffset, y - xOffset);
+                       ctx.lineTo(x - yOffset, y + xOffset);
+                       rad += QUARTER_PI;
+                       xOffset = Math.cos(rad) * radius;
+                       yOffset = Math.sin(rad) * radius;
+                       ctx.moveTo(x - xOffset, y - yOffset);
+                       ctx.lineTo(x + xOffset, y + yOffset);
+                       ctx.moveTo(x + yOffset, y - xOffset);
+                       ctx.lineTo(x - yOffset, y + xOffset);
+                       break;
+               case 'line':
+                       xOffset = Math.cos(rad) * radius;
+                       yOffset = Math.sin(rad) * radius;
+                       ctx.moveTo(x - xOffset, y - yOffset);
+                       ctx.lineTo(x + xOffset, y + yOffset);
+                       break;
+               case 'dash':
+                       ctx.moveTo(x, y);
+                       ctx.lineTo(x + Math.cos(rad) * radius, y + Math.sin(rad) * radius);
+                       break;
+               }
+
+               ctx.fill();
+               ctx.stroke();
+       },
+
+       /**
+        * Returns true if the point is inside the rectangle
+        * @param {object} point - The point to test
+        * @param {object} area - The rectangle
+        * @returns {boolean}
+        * @private
+        */
+       _isPointInArea: function(point, area) {
+               var epsilon = 1e-6; // 1e-6 is margin in pixels for accumulated error.
+
+               return point.x > area.left - epsilon && point.x < area.right + epsilon &&
+                       point.y > area.top - epsilon && point.y < area.bottom + epsilon;
+       },
+
+       clipArea: function(ctx, area) {
+               ctx.save();
+               ctx.beginPath();
+               ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
+               ctx.clip();
+       },
+
+       unclipArea: function(ctx) {
+               ctx.restore();
+       },
+
+       lineTo: function(ctx, previous, target, flip) {
+               var stepped = target.steppedLine;
+               if (stepped) {
+                       if (stepped === 'middle') {
+                               var midpoint = (previous.x + target.x) / 2.0;
+                               ctx.lineTo(midpoint, flip ? target.y : previous.y);
+                               ctx.lineTo(midpoint, flip ? previous.y : target.y);
+                       } else if ((stepped === 'after' && !flip) || (stepped !== 'after' && flip)) {
+                               ctx.lineTo(previous.x, target.y);
+                       } else {
+                               ctx.lineTo(target.x, previous.y);
+                       }
+                       ctx.lineTo(target.x, target.y);
+                       return;
+               }
+
+               if (!target.tension) {
+                       ctx.lineTo(target.x, target.y);
+                       return;
+               }
+
+               ctx.bezierCurveTo(
+                       flip ? previous.controlPointPreviousX : previous.controlPointNextX,
+                       flip ? previous.controlPointPreviousY : previous.controlPointNextY,
+                       flip ? target.controlPointNextX : target.controlPointPreviousX,
+                       flip ? target.controlPointNextY : target.controlPointPreviousY,
+                       target.x,
+                       target.y);
+       }
+};
+
+var helpers_canvas = exports$1;
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.canvas.clear instead.
+ * @namespace Chart.helpers.clear
+ * @deprecated since version 2.7.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers_core.clear = exports$1.clear;
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.canvas.roundedRect instead.
+ * @namespace Chart.helpers.drawRoundedRectangle
+ * @deprecated since version 2.7.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers_core.drawRoundedRectangle = function(ctx) {
+       ctx.beginPath();
+       exports$1.roundedRect.apply(exports$1, arguments);
+};
+
+var defaults = {
+       /**
+        * @private
+        */
+       _set: function(scope, values) {
+               return helpers_core.merge(this[scope] || (this[scope] = {}), values);
+       }
+};
+
+defaults._set('global', {
+       defaultColor: 'rgba(0,0,0,0.1)',
+       defaultFontColor: '#666',
+       defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
+       defaultFontSize: 12,
+       defaultFontStyle: 'normal',
+       defaultLineHeight: 1.2,
+       showLines: true
+});
+
+var core_defaults = defaults;
+
+var valueOrDefault = helpers_core.valueOrDefault;
+
+/**
+ * Converts the given font object into a CSS font string.
+ * @param {object} font - A font object.
+ * @return {string} The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font
+ * @private
+ */
+function toFontString(font) {
+       if (!font || helpers_core.isNullOrUndef(font.size) || helpers_core.isNullOrUndef(font.family)) {
+               return null;
+       }
+
+       return (font.style ? font.style + ' ' : '')
+               + (font.weight ? font.weight + ' ' : '')
+               + font.size + 'px '
+               + font.family;
+}
+
+/**
+ * @alias Chart.helpers.options
+ * @namespace
+ */
+var helpers_options = {
+       /**
+        * Converts the given line height `value` in pixels for a specific font `size`.
+        * @param {number|string} value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').
+        * @param {number} size - The font size (in pixels) used to resolve relative `value`.
+        * @returns {number} The effective line height in pixels (size * 1.2 if value is invalid).
+        * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
+        * @since 2.7.0
+        */
+       toLineHeight: function(value, size) {
+               var matches = ('' + value).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);
+               if (!matches || matches[1] === 'normal') {
+                       return size * 1.2;
+               }
+
+               value = +matches[2];
+
+               switch (matches[3]) {
+               case 'px':
+                       return value;
+               case '%':
+                       value /= 100;
+                       break;
+               default:
+                       break;
+               }
+
+               return size * value;
+       },
+
+       /**
+        * Converts the given value into a padding object with pre-computed width/height.
+        * @param {number|object} value - If a number, set the value to all TRBL component,
+        *  else, if and object, use defined properties and sets undefined ones to 0.
+        * @returns {object} The padding values (top, right, bottom, left, width, height)
+        * @since 2.7.0
+        */
+       toPadding: function(value) {
+               var t, r, b, l;
+
+               if (helpers_core.isObject(value)) {
+                       t = +value.top || 0;
+                       r = +value.right || 0;
+                       b = +value.bottom || 0;
+                       l = +value.left || 0;
+               } else {
+                       t = r = b = l = +value || 0;
+               }
+
+               return {
+                       top: t,
+                       right: r,
+                       bottom: b,
+                       left: l,
+                       height: t + b,
+                       width: l + r
+               };
+       },
+
+       /**
+        * Parses font options and returns the font object.
+        * @param {object} options - A object that contains font options to be parsed.
+        * @return {object} The font object.
+        * @todo Support font.* options and renamed to toFont().
+        * @private
+        */
+       _parseFont: function(options) {
+               var globalDefaults = core_defaults.global;
+               var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize);
+               var font = {
+                       family: valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily),
+                       lineHeight: helpers_core.options.toLineHeight(valueOrDefault(options.lineHeight, globalDefaults.defaultLineHeight), size),
+                       size: size,
+                       style: valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle),
+                       weight: null,
+                       string: ''
+               };
+
+               font.string = toFontString(font);
+               return font;
+       },
+
+       /**
+        * Evaluates the given `inputs` sequentially and returns the first defined value.
+        * @param {Array} inputs - An array of values, falling back to the last value.
+        * @param {object} [context] - If defined and the current value is a function, the value
+        * is called with `context` as first argument and the result becomes the new input.
+        * @param {number} [index] - If defined and the current value is an array, the value
+        * at `index` become the new input.
+        * @since 2.7.0
+        */
+       resolve: function(inputs, context, index) {
+               var i, ilen, value;
+
+               for (i = 0, ilen = inputs.length; i < ilen; ++i) {
+                       value = inputs[i];
+                       if (value === undefined) {
+                               continue;
+                       }
+                       if (context !== undefined && typeof value === 'function') {
+                               value = value(context);
+                       }
+                       if (index !== undefined && helpers_core.isArray(value)) {
+                               value = value[index];
+                       }
+                       if (value !== undefined) {
+                               return value;
+                       }
+               }
+       }
+};
+
+var helpers$1 = helpers_core;
+var easing = helpers_easing;
+var canvas = helpers_canvas;
+var options = helpers_options;
+helpers$1.easing = easing;
+helpers$1.canvas = canvas;
+helpers$1.options = options;
+
+function interpolate(start, view, model, ease) {
+       var keys = Object.keys(model);
+       var i, ilen, key, actual, origin, target, type, c0, c1;
+
+       for (i = 0, ilen = keys.length; i < ilen; ++i) {
+               key = keys[i];
+
+               target = model[key];
+
+               // if a value is added to the model after pivot() has been called, the view
+               // doesn't contain it, so let's initialize the view to the target value.
+               if (!view.hasOwnProperty(key)) {
+                       view[key] = target;
+               }
+
+               actual = view[key];
+
+               if (actual === target || key[0] === '_') {
+                       continue;
+               }
+
+               if (!start.hasOwnProperty(key)) {
+                       start[key] = actual;
+               }
+
+               origin = start[key];
+
+               type = typeof target;
+
+               if (type === typeof origin) {
+                       if (type === 'string') {
+                               c0 = chartjsColor(origin);
+                               if (c0.valid) {
+                                       c1 = chartjsColor(target);
+                                       if (c1.valid) {
+                                               view[key] = c1.mix(c0, ease).rgbString();
+                                               continue;
+                                       }
+                               }
+                       } else if (helpers$1.isFinite(origin) && helpers$1.isFinite(target)) {
+                               view[key] = origin + (target - origin) * ease;
+                               continue;
+                       }
+               }
+
+               view[key] = target;
+       }
+}
+
+var Element = function(configuration) {
+       helpers$1.extend(this, configuration);
+       this.initialize.apply(this, arguments);
+};
+
+helpers$1.extend(Element.prototype, {
+
+       initialize: function() {
+               this.hidden = false;
+       },
+
+       pivot: function() {
+               var me = this;
+               if (!me._view) {
+                       me._view = helpers$1.clone(me._model);
+               }
+               me._start = {};
+               return me;
+       },
+
+       transition: function(ease) {
+               var me = this;
+               var model = me._model;
+               var start = me._start;
+               var view = me._view;
+
+               // No animation -> No Transition
+               if (!model || ease === 1) {
+                       me._view = model;
+                       me._start = null;
+                       return me;
+               }
+
+               if (!view) {
+                       view = me._view = {};
+               }
+
+               if (!start) {
+                       start = me._start = {};
+               }
+
+               interpolate(start, view, model, ease);
+
+               return me;
+       },
+
+       tooltipPosition: function() {
+               return {
+                       x: this._model.x,
+                       y: this._model.y
+               };
+       },
+
+       hasValue: function() {
+               return helpers$1.isNumber(this._model.x) && helpers$1.isNumber(this._model.y);
+       }
+});
+
+Element.extend = helpers$1.inherits;
+
+var core_element = Element;
+
+var exports$2 = core_element.extend({
+       chart: null, // the animation associated chart instance
+       currentStep: 0, // the current animation step
+       numSteps: 60, // default number of steps
+       easing: '', // the easing to use for this animation
+       render: null, // render function used by the animation service
+
+       onAnimationProgress: null, // user specified callback to fire on each step of the animation
+       onAnimationComplete: null, // user specified callback to fire when the animation finishes
+});
+
+var core_animation = exports$2;
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, use Chart.Animation instead
+ * @prop Chart.Animation#animationObject
+ * @deprecated since version 2.6.0
+ * @todo remove at version 3
+ */
+Object.defineProperty(exports$2.prototype, 'animationObject', {
+       get: function() {
+               return this;
+       }
+});
+
+/**
+ * Provided for backward compatibility, use Chart.Animation#chart instead
+ * @prop Chart.Animation#chartInstance
+ * @deprecated since version 2.6.0
+ * @todo remove at version 3
+ */
+Object.defineProperty(exports$2.prototype, 'chartInstance', {
+       get: function() {
+               return this.chart;
+       },
+       set: function(value) {
+               this.chart = value;
+       }
+});
+
+core_defaults._set('global', {
+       animation: {
+               duration: 1000,
+               easing: 'easeOutQuart',
+               onProgress: helpers$1.noop,
+               onComplete: helpers$1.noop
+       }
+});
+
+var core_animations = {
+       animations: [],
+       request: null,
+
+       /**
+        * @param {Chart} chart - The chart to animate.
+        * @param {Chart.Animation} animation - The animation that we will animate.
+        * @param {number} duration - The animation duration in ms.
+        * @param {boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
+        */
+       addAnimation: function(chart, animation, duration, lazy) {
+               var animations = this.animations;
+               var i, ilen;
+
+               animation.chart = chart;
+               animation.startTime = Date.now();
+               animation.duration = duration;
+
+               if (!lazy) {
+                       chart.animating = true;
+               }
+
+               for (i = 0, ilen = animations.length; i < ilen; ++i) {
+                       if (animations[i].chart === chart) {
+                               animations[i] = animation;
+                               return;
+                       }
+               }
+
+               animations.push(animation);
+
+               // If there are no animations queued, manually kickstart a digest, for lack of a better word
+               if (animations.length === 1) {
+                       this.requestAnimationFrame();
+               }
+       },
+
+       cancelAnimation: function(chart) {
+               var index = helpers$1.findIndex(this.animations, function(animation) {
+                       return animation.chart === chart;
+               });
+
+               if (index !== -1) {
+                       this.animations.splice(index, 1);
+                       chart.animating = false;
+               }
+       },
+
+       requestAnimationFrame: function() {
+               var me = this;
+               if (me.request === null) {
+                       // Skip animation frame requests until the active one is executed.
+                       // This can happen when processing mouse events, e.g. 'mousemove'
+                       // and 'mouseout' events will trigger multiple renders.
+                       me.request = helpers$1.requestAnimFrame.call(window, function() {
+                               me.request = null;
+                               me.startDigest();
+                       });
+               }
+       },
+
+       /**
+        * @private
+        */
+       startDigest: function() {
+               var me = this;
+
+               me.advance();
+
+               // Do we have more stuff to animate?
+               if (me.animations.length > 0) {
+                       me.requestAnimationFrame();
+               }
+       },
+
+       /**
+        * @private
+        */
+       advance: function() {
+               var animations = this.animations;
+               var animation, chart, numSteps, nextStep;
+               var i = 0;
+
+               // 1 animation per chart, so we are looping charts here
+               while (i < animations.length) {
+                       animation = animations[i];
+                       chart = animation.chart;
+                       numSteps = animation.numSteps;
+
+                       // Make sure that currentStep starts at 1
+                       // https://github.com/chartjs/Chart.js/issues/6104
+                       nextStep = Math.floor((Date.now() - animation.startTime) / animation.duration * numSteps) + 1;
+                       animation.currentStep = Math.min(nextStep, numSteps);
+
+                       helpers$1.callback(animation.render, [chart, animation], chart);
+                       helpers$1.callback(animation.onAnimationProgress, [animation], chart);
+
+                       if (animation.currentStep >= numSteps) {
+                               helpers$1.callback(animation.onAnimationComplete, [animation], chart);
+                               chart.animating = false;
+                               animations.splice(i, 1);
+                       } else {
+                               ++i;
+                       }
+               }
+       }
+};
+
+var resolve = helpers$1.options.resolve;
+
+var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];
+
+/**
+ * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice',
+ * 'unshift') and notify the listener AFTER the array has been altered. Listeners are
+ * called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same arguments.
+ */
+function listenArrayEvents(array, listener) {
+       if (array._chartjs) {
+               array._chartjs.listeners.push(listener);
+               return;
+       }
+
+       Object.defineProperty(array, '_chartjs', {
+               configurable: true,
+               enumerable: false,
+               value: {
+                       listeners: [listener]
+               }
+       });
+
+       arrayEvents.forEach(function(key) {
+               var method = 'onData' + key.charAt(0).toUpperCase() + key.slice(1);
+               var base = array[key];
+
+               Object.defineProperty(array, key, {
+                       configurable: true,
+                       enumerable: false,
+                       value: function() {
+                               var args = Array.prototype.slice.call(arguments);
+                               var res = base.apply(this, args);
+
+                               helpers$1.each(array._chartjs.listeners, function(object) {
+                                       if (typeof object[method] === 'function') {
+                                               object[method].apply(object, args);
+                                       }
+                               });
+
+                               return res;
+                       }
+               });
+       });
+}
+
+/**
+ * Removes the given array event listener and cleanup extra attached properties (such as
+ * the _chartjs stub and overridden methods) if array doesn't have any more listeners.
+ */
+function unlistenArrayEvents(array, listener) {
+       var stub = array._chartjs;
+       if (!stub) {
+               return;
+       }
+
+       var listeners = stub.listeners;
+       var index = listeners.indexOf(listener);
+       if (index !== -1) {
+               listeners.splice(index, 1);
+       }
+
+       if (listeners.length > 0) {
+               return;
+       }
+
+       arrayEvents.forEach(function(key) {
+               delete array[key];
+       });
+
+       delete array._chartjs;
+}
+
+// Base class for all dataset controllers (line, bar, etc)
+var DatasetController = function(chart, datasetIndex) {
+       this.initialize(chart, datasetIndex);
+};
+
+helpers$1.extend(DatasetController.prototype, {
+
+       /**
+        * Element type used to generate a meta dataset (e.g. Chart.element.Line).
+        * @type {Chart.core.element}
+        */
+       datasetElementType: null,
+
+       /**
+        * Element type used to generate a meta data (e.g. Chart.element.Point).
+        * @type {Chart.core.element}
+        */
+       dataElementType: null,
+
+       initialize: function(chart, datasetIndex) {
+               var me = this;
+               me.chart = chart;
+               me.index = datasetIndex;
+               me.linkScales();
+               me.addElements();
+       },
+
+       updateIndex: function(datasetIndex) {
+               this.index = datasetIndex;
+       },
+
+       linkScales: function() {
+               var me = this;
+               var meta = me.getMeta();
+               var dataset = me.getDataset();
+
+               if (meta.xAxisID === null || !(meta.xAxisID in me.chart.scales)) {
+                       meta.xAxisID = dataset.xAxisID || me.chart.options.scales.xAxes[0].id;
+               }
+               if (meta.yAxisID === null || !(meta.yAxisID in me.chart.scales)) {
+                       meta.yAxisID = dataset.yAxisID || me.chart.options.scales.yAxes[0].id;
+               }
+       },
+
+       getDataset: function() {
+               return this.chart.data.datasets[this.index];
+       },
+
+       getMeta: function() {
+               return this.chart.getDatasetMeta(this.index);
+       },
+
+       getScaleForId: function(scaleID) {
+               return this.chart.scales[scaleID];
+       },
+
+       /**
+        * @private
+        */
+       _getValueScaleId: function() {
+               return this.getMeta().yAxisID;
+       },
+
+       /**
+        * @private
+        */
+       _getIndexScaleId: function() {
+               return this.getMeta().xAxisID;
+       },
+
+       /**
+        * @private
+        */
+       _getValueScale: function() {
+               return this.getScaleForId(this._getValueScaleId());
+       },
+
+       /**
+        * @private
+        */
+       _getIndexScale: function() {
+               return this.getScaleForId(this._getIndexScaleId());
+       },
+
+       reset: function() {
+               this.update(true);
+       },
+
+       /**
+        * @private
+        */
+       destroy: function() {
+               if (this._data) {
+                       unlistenArrayEvents(this._data, this);
+               }
+       },
+
+       createMetaDataset: function() {
+               var me = this;
+               var type = me.datasetElementType;
+               return type && new type({
+                       _chart: me.chart,
+                       _datasetIndex: me.index
+               });
+       },
+
+       createMetaData: function(index) {
+               var me = this;
+               var type = me.dataElementType;
+               return type && new type({
+                       _chart: me.chart,
+                       _datasetIndex: me.index,
+                       _index: index
+               });
+       },
+
+       addElements: function() {
+               var me = this;
+               var meta = me.getMeta();
+               var data = me.getDataset().data || [];
+               var metaData = meta.data;
+               var i, ilen;
+
+               for (i = 0, ilen = data.length; i < ilen; ++i) {
+                       metaData[i] = metaData[i] || me.createMetaData(i);
+               }
+
+               meta.dataset = meta.dataset || me.createMetaDataset();
+       },
+
+       addElementAndReset: function(index) {
+               var element = this.createMetaData(index);
+               this.getMeta().data.splice(index, 0, element);
+               this.updateElement(element, index, true);
+       },
+
+       buildOrUpdateElements: function() {
+               var me = this;
+               var dataset = me.getDataset();
+               var data = dataset.data || (dataset.data = []);
+
+               // In order to correctly handle data addition/deletion animation (an thus simulate
+               // real-time charts), we need to monitor these data modifications and synchronize
+               // the internal meta data accordingly.
+               if (me._data !== data) {
+                       if (me._data) {
+                               // This case happens when the user replaced the data array instance.
+                               unlistenArrayEvents(me._data, me);
+                       }
+
+                       if (data && Object.isExtensible(data)) {
+                               listenArrayEvents(data, me);
+                       }
+                       me._data = data;
+               }
+
+               // Re-sync meta data in case the user replaced the data array or if we missed
+               // any updates and so make sure that we handle number of datapoints changing.
+               me.resyncElements();
+       },
+
+       update: helpers$1.noop,
+
+       transition: function(easingValue) {
+               var meta = this.getMeta();
+               var elements = meta.data || [];
+               var ilen = elements.length;
+               var i = 0;
+
+               for (; i < ilen; ++i) {
+                       elements[i].transition(easingValue);
+               }
+
+               if (meta.dataset) {
+                       meta.dataset.transition(easingValue);
+               }
+       },
+
+       draw: function() {
+               var meta = this.getMeta();
+               var elements = meta.data || [];
+               var ilen = elements.length;
+               var i = 0;
+
+               if (meta.dataset) {
+                       meta.dataset.draw();
+               }
+
+               for (; i < ilen; ++i) {
+                       elements[i].draw();
+               }
+       },
+
+       removeHoverStyle: function(element) {
+               helpers$1.merge(element._model, element.$previousStyle || {});
+               delete element.$previousStyle;
+       },
+
+       setHoverStyle: function(element) {
+               var dataset = this.chart.data.datasets[element._datasetIndex];
+               var index = element._index;
+               var custom = element.custom || {};
+               var model = element._model;
+               var getHoverColor = helpers$1.getHoverColor;
+
+               element.$previousStyle = {
+                       backgroundColor: model.backgroundColor,
+                       borderColor: model.borderColor,
+                       borderWidth: model.borderWidth
+               };
+
+               model.backgroundColor = resolve([custom.hoverBackgroundColor, dataset.hoverBackgroundColor, getHoverColor(model.backgroundColor)], undefined, index);
+               model.borderColor = resolve([custom.hoverBorderColor, dataset.hoverBorderColor, getHoverColor(model.borderColor)], undefined, index);
+               model.borderWidth = resolve([custom.hoverBorderWidth, dataset.hoverBorderWidth, model.borderWidth], undefined, index);
+       },
+
+       /**
+        * @private
+        */
+       resyncElements: function() {
+               var me = this;
+               var meta = me.getMeta();
+               var data = me.getDataset().data;
+               var numMeta = meta.data.length;
+               var numData = data.length;
+
+               if (numData < numMeta) {
+                       meta.data.splice(numData, numMeta - numData);
+               } else if (numData > numMeta) {
+                       me.insertElements(numMeta, numData - numMeta);
+               }
+       },
+
+       /**
+        * @private
+        */
+       insertElements: function(start, count) {
+               for (var i = 0; i < count; ++i) {
+                       this.addElementAndReset(start + i);
+               }
+       },
+
+       /**
+        * @private
+        */
+       onDataPush: function() {
+               var count = arguments.length;
+               this.insertElements(this.getDataset().data.length - count, count);
+       },
+
+       /**
+        * @private
+        */
+       onDataPop: function() {
+               this.getMeta().data.pop();
+       },
+
+       /**
+        * @private
+        */
+       onDataShift: function() {
+               this.getMeta().data.shift();
+       },
+
+       /**
+        * @private
+        */
+       onDataSplice: function(start, count) {
+               this.getMeta().data.splice(start, count);
+               this.insertElements(start, arguments.length - 2);
+       },
+
+       /**
+        * @private
+        */
+       onDataUnshift: function() {
+               this.insertElements(0, arguments.length);
+       }
+});
+
+DatasetController.extend = helpers$1.inherits;
+
+var core_datasetController = DatasetController;
+
+core_defaults._set('global', {
+       elements: {
+               arc: {
+                       backgroundColor: core_defaults.global.defaultColor,
+                       borderColor: '#fff',
+                       borderWidth: 2,
+                       borderAlign: 'center'
+               }
+       }
+});
+
+var element_arc = core_element.extend({
+       inLabelRange: function(mouseX) {
+               var vm = this._view;
+
+               if (vm) {
+                       return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
+               }
+               return false;
+       },
+
+       inRange: function(chartX, chartY) {
+               var vm = this._view;
+
+               if (vm) {
+                       var pointRelativePosition = helpers$1.getAngleFromPoint(vm, {x: chartX, y: chartY});
+                       var     angle = pointRelativePosition.angle;
+                       var distance = pointRelativePosition.distance;
+
+                       // Sanitise angle range
+                       var startAngle = vm.startAngle;
+                       var endAngle = vm.endAngle;
+                       while (endAngle < startAngle) {
+                               endAngle += 2.0 * Math.PI;
+                       }
+                       while (angle > endAngle) {
+                               angle -= 2.0 * Math.PI;
+                       }
+                       while (angle < startAngle) {
+                               angle += 2.0 * Math.PI;
+                       }
+
+                       // Check if within the range of the open/close angle
+                       var betweenAngles = (angle >= startAngle && angle <= endAngle);
+                       var withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);
+
+                       return (betweenAngles && withinRadius);
+               }
+               return false;
+       },
+
+       getCenterPoint: function() {
+               var vm = this._view;
+               var halfAngle = (vm.startAngle + vm.endAngle) / 2;
+               var halfRadius = (vm.innerRadius + vm.outerRadius) / 2;
+               return {
+                       x: vm.x + Math.cos(halfAngle) * halfRadius,
+                       y: vm.y + Math.sin(halfAngle) * halfRadius
+               };
+       },
+
+       getArea: function() {
+               var vm = this._view;
+               return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2));
+       },
+
+       tooltipPosition: function() {
+               var vm = this._view;
+               var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2);
+               var rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
+
+               return {
+                       x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
+                       y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
+               };
+       },
+
+       draw: function() {
+               var ctx = this._chart.ctx;
+               var vm = this._view;
+               var sA = vm.startAngle;
+               var eA = vm.endAngle;
+               var pixelMargin = (vm.borderAlign === 'inner') ? 0.33 : 0;
+               var angleMargin;
+
+               ctx.save();
+
+               ctx.beginPath();
+               ctx.arc(vm.x, vm.y, Math.max(vm.outerRadius - pixelMargin, 0), sA, eA);
+               ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
+               ctx.closePath();
+
+               ctx.fillStyle = vm.backgroundColor;
+               ctx.fill();
+
+               if (vm.borderWidth) {
+                       if (vm.borderAlign === 'inner') {
+                               // Draw an inner border by cliping the arc and drawing a double-width border
+                               // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders
+                               ctx.beginPath();
+                               angleMargin = pixelMargin / vm.outerRadius;
+                               ctx.arc(vm.x, vm.y, vm.outerRadius, sA - angleMargin, eA + angleMargin);
+                               if (vm.innerRadius > pixelMargin) {
+                                       angleMargin = pixelMargin / vm.innerRadius;
+                                       ctx.arc(vm.x, vm.y, vm.innerRadius - pixelMargin, eA + angleMargin, sA - angleMargin, true);
+                               } else {
+                                       ctx.arc(vm.x, vm.y, pixelMargin, eA + Math.PI / 2, sA - Math.PI / 2);
+                               }
+                               ctx.closePath();
+                               ctx.clip();
+
+                               ctx.beginPath();
+                               ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
+                               ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
+                               ctx.closePath();
+
+                               ctx.lineWidth = vm.borderWidth * 2;
+                               ctx.lineJoin = 'round';
+                       } else {
+                               ctx.lineWidth = vm.borderWidth;
+                               ctx.lineJoin = 'bevel';
+                       }
+
+                       ctx.strokeStyle = vm.borderColor;
+                       ctx.stroke();
+               }
+
+               ctx.restore();
+       }
+});
+
+var valueOrDefault$1 = helpers$1.valueOrDefault;
+
+var defaultColor = core_defaults.global.defaultColor;
+
+core_defaults._set('global', {
+       elements: {
+               line: {
+                       tension: 0.4,
+                       backgroundColor: defaultColor,
+                       borderWidth: 3,
+                       borderColor: defaultColor,
+                       borderCapStyle: 'butt',
+                       borderDash: [],
+                       borderDashOffset: 0.0,
+                       borderJoinStyle: 'miter',
+                       capBezierPoints: true,
+                       fill: true, // do we fill in the area between the line and its base axis
+               }
+       }
+});
+
+var element_line = core_element.extend({
+       draw: function() {
+               var me = this;
+               var vm = me._view;
+               var ctx = me._chart.ctx;
+               var spanGaps = vm.spanGaps;
+               var points = me._children.slice(); // clone array
+               var globalDefaults = core_defaults.global;
+               var globalOptionLineElements = globalDefaults.elements.line;
+               var lastDrawnIndex = -1;
+               var index, current, previous, currentVM;
+
+               // If we are looping, adding the first point again
+               if (me._loop && points.length) {
+                       points.push(points[0]);
+               }
+
+               ctx.save();
+
+               // Stroke Line Options
+               ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;
+
+               // IE 9 and 10 do not support line dash
+               if (ctx.setLineDash) {
+                       ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);
+               }
+
+               ctx.lineDashOffset = valueOrDefault$1(vm.borderDashOffset, globalOptionLineElements.borderDashOffset);
+               ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;
+               ctx.lineWidth = valueOrDefault$1(vm.borderWidth, globalOptionLineElements.borderWidth);
+               ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;
+
+               // Stroke Line
+               ctx.beginPath();
+               lastDrawnIndex = -1;
+
+               for (index = 0; index < points.length; ++index) {
+                       current = points[index];
+                       previous = helpers$1.previousItem(points, index);
+                       currentVM = current._view;
+
+                       // First point moves to it's starting position no matter what
+                       if (index === 0) {
+                               if (!currentVM.skip) {
+                                       ctx.moveTo(currentVM.x, currentVM.y);
+                                       lastDrawnIndex = index;
+                               }
+                       } else {
+                               previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];
+
+                               if (!currentVM.skip) {
+                                       if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) {
+                                               // There was a gap and this is the first point after the gap
+                                               ctx.moveTo(currentVM.x, currentVM.y);
+                                       } else {
+                                               // Line to next point
+                                               helpers$1.canvas.lineTo(ctx, previous._view, current._view);
+                                       }
+                                       lastDrawnIndex = index;
+                               }
+                       }
+               }
+
+               ctx.stroke();
+               ctx.restore();
+       }
+});
+
+var valueOrDefault$2 = helpers$1.valueOrDefault;
+
+var defaultColor$1 = core_defaults.global.defaultColor;
+
+core_defaults._set('global', {
+       elements: {
+               point: {
+                       radius: 3,
+                       pointStyle: 'circle',
+                       backgroundColor: defaultColor$1,
+                       borderColor: defaultColor$1,
+                       borderWidth: 1,
+                       // Hover
+                       hitRadius: 1,
+                       hoverRadius: 4,
+                       hoverBorderWidth: 1
+               }
+       }
+});
+
+function xRange(mouseX) {
+       var vm = this._view;
+       return vm ? (Math.abs(mouseX - vm.x) < vm.radius + vm.hitRadius) : false;
+}
+
+function yRange(mouseY) {
+       var vm = this._view;
+       return vm ? (Math.abs(mouseY - vm.y) < vm.radius + vm.hitRadius) : false;
+}
+
+var element_point = core_element.extend({
+       inRange: function(mouseX, mouseY) {
+               var vm = this._view;
+               return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
+       },
+
+       inLabelRange: xRange,
+       inXRange: xRange,
+       inYRange: yRange,
+
+       getCenterPoint: function() {
+               var vm = this._view;
+               return {
+                       x: vm.x,
+                       y: vm.y
+               };
+       },
+
+       getArea: function() {
+               return Math.PI * Math.pow(this._view.radius, 2);
+       },
+
+       tooltipPosition: function() {
+               var vm = this._view;
+               return {
+                       x: vm.x,
+                       y: vm.y,
+                       padding: vm.radius + vm.borderWidth
+               };
+       },
+
+       draw: function(chartArea) {
+               var vm = this._view;
+               var ctx = this._chart.ctx;
+               var pointStyle = vm.pointStyle;
+               var rotation = vm.rotation;
+               var radius = vm.radius;
+               var x = vm.x;
+               var y = vm.y;
+               var globalDefaults = core_defaults.global;
+               var defaultColor = globalDefaults.defaultColor; // eslint-disable-line no-shadow
+
+               if (vm.skip) {
+                       return;
+               }
+
+               // Clipping for Points.
+               if (chartArea === undefined || helpers$1.canvas._isPointInArea(vm, chartArea)) {
+                       ctx.strokeStyle = vm.borderColor || defaultColor;
+                       ctx.lineWidth = valueOrDefault$2(vm.borderWidth, globalDefaults.elements.point.borderWidth);
+                       ctx.fillStyle = vm.backgroundColor || defaultColor;
+                       helpers$1.canvas.drawPoint(ctx, pointStyle, radius, x, y, rotation);
+               }
+       }
+});
+
+var defaultColor$2 = core_defaults.global.defaultColor;
+
+core_defaults._set('global', {
+       elements: {
+               rectangle: {
+                       backgroundColor: defaultColor$2,
+                       borderColor: defaultColor$2,
+                       borderSkipped: 'bottom',
+                       borderWidth: 0
+               }
+       }
+});
+
+function isVertical(vm) {
+       return vm && vm.width !== undefined;
+}
+
+/**
+ * Helper function to get the bounds of the bar regardless of the orientation
+ * @param bar {Chart.Element.Rectangle} the bar
+ * @return {Bounds} bounds of the bar
+ * @private
+ */
+function getBarBounds(vm) {
+       var x1, x2, y1, y2, half;
+
+       if (isVertical(vm)) {
+               half = vm.width / 2;
+               x1 = vm.x - half;
+               x2 = vm.x + half;
+               y1 = Math.min(vm.y, vm.base);
+               y2 = Math.max(vm.y, vm.base);
+       } else {
+               half = vm.height / 2;
+               x1 = Math.min(vm.x, vm.base);
+               x2 = Math.max(vm.x, vm.base);
+               y1 = vm.y - half;
+               y2 = vm.y + half;
+       }
+
+       return {
+               left: x1,
+               top: y1,
+               right: x2,
+               bottom: y2
+       };
+}
+
+function swap(orig, v1, v2) {
+       return orig === v1 ? v2 : orig === v2 ? v1 : orig;
+}
+
+function parseBorderSkipped(vm) {
+       var edge = vm.borderSkipped;
+       var res = {};
+
+       if (!edge) {
+               return res;
+       }
+
+       if (vm.horizontal) {
+               if (vm.base > vm.x) {
+                       edge = swap(edge, 'left', 'right');
+               }
+       } else if (vm.base < vm.y) {
+               edge = swap(edge, 'bottom', 'top');
+       }
+
+       res[edge] = true;
+       return res;
+}
+
+function parseBorderWidth(vm, maxW, maxH) {
+       var value = vm.borderWidth;
+       var skip = parseBorderSkipped(vm);
+       var t, r, b, l;
+
+       if (helpers$1.isObject(value)) {
+               t = +value.top || 0;
+               r = +value.right || 0;
+               b = +value.bottom || 0;
+               l = +value.left || 0;
+       } else {
+               t = r = b = l = +value || 0;
+       }
+
+       return {
+               t: skip.top || (t < 0) ? 0 : t > maxH ? maxH : t,
+               r: skip.right || (r < 0) ? 0 : r > maxW ? maxW : r,
+               b: skip.bottom || (b < 0) ? 0 : b > maxH ? maxH : b,
+               l: skip.left || (l < 0) ? 0 : l > maxW ? maxW : l
+       };
+}
+
+function boundingRects(vm) {
+       var bounds = getBarBounds(vm);
+       var width = bounds.right - bounds.left;
+       var height = bounds.bottom - bounds.top;
+       var border = parseBorderWidth(vm, width / 2, height / 2);
+
+       return {
+               outer: {
+                       x: bounds.left,
+                       y: bounds.top,
+                       w: width,
+                       h: height
+               },
+               inner: {
+                       x: bounds.left + border.l,
+                       y: bounds.top + border.t,
+                       w: width - border.l - border.r,
+                       h: height - border.t - border.b
+               }
+       };
+}
+
+function inRange(vm, x, y) {
+       var skipX = x === null;
+       var skipY = y === null;
+       var bounds = !vm || (skipX && skipY) ? false : getBarBounds(vm);
+
+       return bounds
+               && (skipX || x >= bounds.left && x <= bounds.right)
+               && (skipY || y >= bounds.top && y <= bounds.bottom);
+}
+
+var element_rectangle = core_element.extend({
+       draw: function() {
+               var ctx = this._chart.ctx;
+               var vm = this._view;
+               var rects = boundingRects(vm);
+               var outer = rects.outer;
+               var inner = rects.inner;
+
+               ctx.fillStyle = vm.backgroundColor;
+               ctx.fillRect(outer.x, outer.y, outer.w, outer.h);
+
+               if (outer.w === inner.w && outer.h === inner.h) {
+                       return;
+               }
+
+               ctx.save();
+               ctx.beginPath();
+               ctx.rect(outer.x, outer.y, outer.w, outer.h);
+               ctx.clip();
+               ctx.fillStyle = vm.borderColor;
+               ctx.rect(inner.x, inner.y, inner.w, inner.h);
+               ctx.fill('evenodd');
+               ctx.restore();
+       },
+
+       height: function() {
+               var vm = this._view;
+               return vm.base - vm.y;
+       },
+
+       inRange: function(mouseX, mouseY) {
+               return inRange(this._view, mouseX, mouseY);
+       },
+
+       inLabelRange: function(mouseX, mouseY) {
+               var vm = this._view;
+               return isVertical(vm)
+                       ? inRange(vm, mouseX, null)
+                       : inRange(vm, null, mouseY);
+       },
+
+       inXRange: function(mouseX) {
+               return inRange(this._view, mouseX, null);
+       },
+
+       inYRange: function(mouseY) {
+               return inRange(this._view, null, mouseY);
+       },
+
+       getCenterPoint: function() {
+               var vm = this._view;
+               var x, y;
+               if (isVertical(vm)) {
+                       x = vm.x;
+                       y = (vm.y + vm.base) / 2;
+               } else {
+                       x = (vm.x + vm.base) / 2;
+                       y = vm.y;
+               }
+
+               return {x: x, y: y};
+       },
+
+       getArea: function() {
+               var vm = this._view;
+
+               return isVertical(vm)
+                       ? vm.width * Math.abs(vm.y - vm.base)
+                       : vm.height * Math.abs(vm.x - vm.base);
+       },
+
+       tooltipPosition: function() {
+               var vm = this._view;
+               return {
+                       x: vm.x,
+                       y: vm.y
+               };
+       }
+});
+
+var elements = {};
+var Arc = element_arc;
+var Line = element_line;
+var Point = element_point;
+var Rectangle = element_rectangle;
+elements.Arc = Arc;
+elements.Line = Line;
+elements.Point = Point;
+elements.Rectangle = Rectangle;
+
+var resolve$1 = helpers$1.options.resolve;
+
+core_defaults._set('bar', {
+       hover: {
+               mode: 'label'
+       },
+
+       scales: {
+               xAxes: [{
+                       type: 'category',
+                       categoryPercentage: 0.8,
+                       barPercentage: 0.9,
+                       offset: true,
+                       gridLines: {
+                               offsetGridLines: true
+                       }
+               }],
+
+               yAxes: [{
+                       type: 'linear'
+               }]
+       }
+});
+
+/**
+ * Computes the "optimal" sample size to maintain bars equally sized while preventing overlap.
+ * @private
+ */
+function computeMinSampleSize(scale, pixels) {
+       var min = scale.isHorizontal() ? scale.width : scale.height;
+       var ticks = scale.getTicks();
+       var prev, curr, i, ilen;
+
+       for (i = 1, ilen = pixels.length; i < ilen; ++i) {
+               min = Math.min(min, Math.abs(pixels[i] - pixels[i - 1]));
+       }
+
+       for (i = 0, ilen = ticks.length; i < ilen; ++i) {
+               curr = scale.getPixelForTick(i);
+               min = i > 0 ? Math.min(min, curr - prev) : min;
+               prev = curr;
+       }
+
+       return min;
+}
+
+/**
+ * Computes an "ideal" category based on the absolute bar thickness or, if undefined or null,
+ * uses the smallest interval (see computeMinSampleSize) that prevents bar overlapping. This
+ * mode currently always generates bars equally sized (until we introduce scriptable options?).
+ * @private
+ */
+function computeFitCategoryTraits(index, ruler, options) {
+       var thickness = options.barThickness;
+       var count = ruler.stackCount;
+       var curr = ruler.pixels[index];
+       var size, ratio;
+
+       if (helpers$1.isNullOrUndef(thickness)) {
+               size = ruler.min * options.categoryPercentage;
+               ratio = options.barPercentage;
+       } else {
+               // When bar thickness is enforced, category and bar percentages are ignored.
+               // Note(SB): we could add support for relative bar thickness (e.g. barThickness: '50%')
+               // and deprecate barPercentage since this value is ignored when thickness is absolute.
+               size = thickness * count;
+               ratio = 1;
+       }
+
+       return {
+               chunk: size / count,
+               ratio: ratio,
+               start: curr - (size / 2)
+       };
+}
+
+/**
+ * Computes an "optimal" category that globally arranges bars side by side (no gap when
+ * percentage options are 1), based on the previous and following categories. This mode
+ * generates bars with different widths when data are not evenly spaced.
+ * @private
+ */
+function computeFlexCategoryTraits(index, ruler, options) {
+       var pixels = ruler.pixels;
+       var curr = pixels[index];
+       var prev = index > 0 ? pixels[index - 1] : null;
+       var next = index < pixels.length - 1 ? pixels[index + 1] : null;
+       var percent = options.categoryPercentage;
+       var start, size;
+
+       if (prev === null) {
+               // first data: its size is double based on the next point or,
+               // if it's also the last data, we use the scale size.
+               prev = curr - (next === null ? ruler.end - ruler.start : next - curr);
+       }
+
+       if (next === null) {
+               // last data: its size is also double based on the previous point.
+               next = curr + curr - prev;
+       }
+
+       start = curr - (curr - Math.min(prev, next)) / 2 * percent;
+       size = Math.abs(next - prev) / 2 * percent;
+
+       return {
+               chunk: size / ruler.stackCount,
+               ratio: options.barPercentage,
+               start: start
+       };
+}
+
+var controller_bar = core_datasetController.extend({
+
+       dataElementType: elements.Rectangle,
+
+       initialize: function() {
+               var me = this;
+               var meta;
+
+               core_datasetController.prototype.initialize.apply(me, arguments);
+
+               meta = me.getMeta();
+               meta.stack = me.getDataset().stack;
+               meta.bar = true;
+       },
+
+       update: function(reset) {
+               var me = this;
+               var rects = me.getMeta().data;
+               var i, ilen;
+
+               me._ruler = me.getRuler();
+
+               for (i = 0, ilen = rects.length; i < ilen; ++i) {
+                       me.updateElement(rects[i], i, reset);
+               }
+       },
+
+       updateElement: function(rectangle, index, reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var dataset = me.getDataset();
+               var options = me._resolveElementOptions(rectangle, index);
+
+               rectangle._xScale = me.getScaleForId(meta.xAxisID);
+               rectangle._yScale = me.getScaleForId(meta.yAxisID);
+               rectangle._datasetIndex = me.index;
+               rectangle._index = index;
+               rectangle._model = {
+                       backgroundColor: options.backgroundColor,
+                       borderColor: options.borderColor,
+                       borderSkipped: options.borderSkipped,
+                       borderWidth: options.borderWidth,
+                       datasetLabel: dataset.label,
+                       label: me.chart.data.labels[index]
+               };
+
+               me._updateElementGeometry(rectangle, index, reset);
+
+               rectangle.pivot();
+       },
+
+       /**
+        * @private
+        */
+       _updateElementGeometry: function(rectangle, index, reset) {
+               var me = this;
+               var model = rectangle._model;
+               var vscale = me._getValueScale();
+               var base = vscale.getBasePixel();
+               var horizontal = vscale.isHorizontal();
+               var ruler = me._ruler || me.getRuler();
+               var vpixels = me.calculateBarValuePixels(me.index, index);
+               var ipixels = me.calculateBarIndexPixels(me.index, index, ruler);
+
+               model.horizontal = horizontal;
+               model.base = reset ? base : vpixels.base;
+               model.x = horizontal ? reset ? base : vpixels.head : ipixels.center;
+               model.y = horizontal ? ipixels.center : reset ? base : vpixels.head;
+               model.height = horizontal ? ipixels.size : undefined;
+               model.width = horizontal ? undefined : ipixels.size;
+       },
+
+       /**
+        * Returns the stacks based on groups and bar visibility.
+        * @param {number} [last] - The dataset index
+        * @returns {string[]} The list of stack IDs
+        * @private
+        */
+       _getStacks: function(last) {
+               var me = this;
+               var chart = me.chart;
+               var scale = me._getIndexScale();
+               var stacked = scale.options.stacked;
+               var ilen = last === undefined ? chart.data.datasets.length : last + 1;
+               var stacks = [];
+               var i, meta;
+
+               for (i = 0; i < ilen; ++i) {
+                       meta = chart.getDatasetMeta(i);
+                       if (meta.bar && chart.isDatasetVisible(i) &&
+                               (stacked === false ||
+                               (stacked === true && stacks.indexOf(meta.stack) === -1) ||
+                               (stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) {
+                               stacks.push(meta.stack);
+                       }
+               }
+
+               return stacks;
+       },
+
+       /**
+        * Returns the effective number of stacks based on groups and bar visibility.
+        * @private
+        */
+       getStackCount: function() {
+               return this._getStacks().length;
+       },
+
+       /**
+        * Returns the stack index for the given dataset based on groups and bar visibility.
+        * @param {number} [datasetIndex] - The dataset index
+        * @param {string} [name] - The stack name to find
+        * @returns {number} The stack index
+        * @private
+        */
+       getStackIndex: function(datasetIndex, name) {
+               var stacks = this._getStacks(datasetIndex);
+               var index = (name !== undefined)
+                       ? stacks.indexOf(name)
+                       : -1; // indexOf returns -1 if element is not present
+
+               return (index === -1)
+                       ? stacks.length - 1
+                       : index;
+       },
+
+       /**
+        * @private
+        */
+       getRuler: function() {
+               var me = this;
+               var scale = me._getIndexScale();
+               var stackCount = me.getStackCount();
+               var datasetIndex = me.index;
+               var isHorizontal = scale.isHorizontal();
+               var start = isHorizontal ? scale.left : scale.top;
+               var end = start + (isHorizontal ? scale.width : scale.height);
+               var pixels = [];
+               var i, ilen, min;
+
+               for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) {
+                       pixels.push(scale.getPixelForValue(null, i, datasetIndex));
+               }
+
+               min = helpers$1.isNullOrUndef(scale.options.barThickness)
+                       ? computeMinSampleSize(scale, pixels)
+                       : -1;
+
+               return {
+                       min: min,
+                       pixels: pixels,
+                       start: start,
+                       end: end,
+                       stackCount: stackCount,
+                       scale: scale
+               };
+       },
+
+       /**
+        * Note: pixel values are not clamped to the scale area.
+        * @private
+        */
+       calculateBarValuePixels: function(datasetIndex, index) {
+               var me = this;
+               var chart = me.chart;
+               var meta = me.getMeta();
+               var scale = me._getValueScale();
+               var isHorizontal = scale.isHorizontal();
+               var datasets = chart.data.datasets;
+               var value = +scale.getRightValue(datasets[datasetIndex].data[index]);
+               var minBarLength = scale.options.minBarLength;
+               var stacked = scale.options.stacked;
+               var stack = meta.stack;
+               var start = 0;
+               var i, imeta, ivalue, base, head, size;
+
+               if (stacked || (stacked === undefined && stack !== undefined)) {
+                       for (i = 0; i < datasetIndex; ++i) {
+                               imeta = chart.getDatasetMeta(i);
+
+                               if (imeta.bar &&
+                                       imeta.stack === stack &&
+                                       imeta.controller._getValueScaleId() === scale.id &&
+                                       chart.isDatasetVisible(i)) {
+
+                                       ivalue = +scale.getRightValue(datasets[i].data[index]);
+                                       if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) {
+                                               start += ivalue;
+                                       }
+                               }
+                       }
+               }
+
+               base = scale.getPixelForValue(start);
+               head = scale.getPixelForValue(start + value);
+               size = head - base;
+
+               if (minBarLength !== undefined && Math.abs(size) < minBarLength) {
+                       size = minBarLength;
+                       if (value >= 0 && !isHorizontal || value < 0 && isHorizontal) {
+                               head = base - minBarLength;
+                       } else {
+                               head = base + minBarLength;
+                       }
+               }
+
+               return {
+                       size: size,
+                       base: base,
+                       head: head,
+                       center: head + size / 2
+               };
+       },
+
+       /**
+        * @private
+        */
+       calculateBarIndexPixels: function(datasetIndex, index, ruler) {
+               var me = this;
+               var options = ruler.scale.options;
+               var range = options.barThickness === 'flex'
+                       ? computeFlexCategoryTraits(index, ruler, options)
+                       : computeFitCategoryTraits(index, ruler, options);
+
+               var stackIndex = me.getStackIndex(datasetIndex, me.getMeta().stack);
+               var center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);
+               var size = Math.min(
+                       helpers$1.valueOrDefault(options.maxBarThickness, Infinity),
+                       range.chunk * range.ratio);
+
+               return {
+                       base: center - size / 2,
+                       head: center + size / 2,
+                       center: center,
+                       size: size
+               };
+       },
+
+       draw: function() {
+               var me = this;
+               var chart = me.chart;
+               var scale = me._getValueScale();
+               var rects = me.getMeta().data;
+               var dataset = me.getDataset();
+               var ilen = rects.length;
+               var i = 0;
+
+               helpers$1.canvas.clipArea(chart.ctx, chart.chartArea);
+
+               for (; i < ilen; ++i) {
+                       if (!isNaN(scale.getRightValue(dataset.data[i]))) {
+                               rects[i].draw();
+                       }
+               }
+
+               helpers$1.canvas.unclipArea(chart.ctx);
+       },
+
+       /**
+        * @private
+        */
+       _resolveElementOptions: function(rectangle, index) {
+               var me = this;
+               var chart = me.chart;
+               var datasets = chart.data.datasets;
+               var dataset = datasets[me.index];
+               var custom = rectangle.custom || {};
+               var options = chart.options.elements.rectangle;
+               var values = {};
+               var i, ilen, key;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               var keys = [
+                       'backgroundColor',
+                       'borderColor',
+                       'borderSkipped',
+                       'borderWidth'
+               ];
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve$1([
+                               custom[key],
+                               dataset[key],
+                               options[key]
+                       ], context, index);
+               }
+
+               return values;
+       }
+});
+
+var valueOrDefault$3 = helpers$1.valueOrDefault;
+var resolve$2 = helpers$1.options.resolve;
+
+core_defaults._set('bubble', {
+       hover: {
+               mode: 'single'
+       },
+
+       scales: {
+               xAxes: [{
+                       type: 'linear', // bubble should probably use a linear scale by default
+                       position: 'bottom',
+                       id: 'x-axis-0' // need an ID so datasets can reference the scale
+               }],
+               yAxes: [{
+                       type: 'linear',
+                       position: 'left',
+                       id: 'y-axis-0'
+               }]
+       },
+
+       tooltips: {
+               callbacks: {
+                       title: function() {
+                               // Title doesn't make sense for scatter since we format the data as a point
+                               return '';
+                       },
+                       label: function(item, data) {
+                               var datasetLabel = data.datasets[item.datasetIndex].label || '';
+                               var dataPoint = data.datasets[item.datasetIndex].data[item.index];
+                               return datasetLabel + ': (' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.r + ')';
+                       }
+               }
+       }
+});
+
+var controller_bubble = core_datasetController.extend({
+       /**
+        * @protected
+        */
+       dataElementType: elements.Point,
+
+       /**
+        * @protected
+        */
+       update: function(reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var points = meta.data;
+
+               // Update Points
+               helpers$1.each(points, function(point, index) {
+                       me.updateElement(point, index, reset);
+               });
+       },
+
+       /**
+        * @protected
+        */
+       updateElement: function(point, index, reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var custom = point.custom || {};
+               var xScale = me.getScaleForId(meta.xAxisID);
+               var yScale = me.getScaleForId(meta.yAxisID);
+               var options = me._resolveElementOptions(point, index);
+               var data = me.getDataset().data[index];
+               var dsIndex = me.index;
+
+               var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex);
+               var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex);
+
+               point._xScale = xScale;
+               point._yScale = yScale;
+               point._options = options;
+               point._datasetIndex = dsIndex;
+               point._index = index;
+               point._model = {
+                       backgroundColor: options.backgroundColor,
+                       borderColor: options.borderColor,
+                       borderWidth: options.borderWidth,
+                       hitRadius: options.hitRadius,
+                       pointStyle: options.pointStyle,
+                       rotation: options.rotation,
+                       radius: reset ? 0 : options.radius,
+                       skip: custom.skip || isNaN(x) || isNaN(y),
+                       x: x,
+                       y: y,
+               };
+
+               point.pivot();
+       },
+
+       /**
+        * @protected
+        */
+       setHoverStyle: function(point) {
+               var model = point._model;
+               var options = point._options;
+               var getHoverColor = helpers$1.getHoverColor;
+
+               point.$previousStyle = {
+                       backgroundColor: model.backgroundColor,
+                       borderColor: model.borderColor,
+                       borderWidth: model.borderWidth,
+                       radius: model.radius
+               };
+
+               model.backgroundColor = valueOrDefault$3(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
+               model.borderColor = valueOrDefault$3(options.hoverBorderColor, getHoverColor(options.borderColor));
+               model.borderWidth = valueOrDefault$3(options.hoverBorderWidth, options.borderWidth);
+               model.radius = options.radius + options.hoverRadius;
+       },
+
+       /**
+        * @private
+        */
+       _resolveElementOptions: function(point, index) {
+               var me = this;
+               var chart = me.chart;
+               var datasets = chart.data.datasets;
+               var dataset = datasets[me.index];
+               var custom = point.custom || {};
+               var options = chart.options.elements.point;
+               var data = dataset.data[index];
+               var values = {};
+               var i, ilen, key;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               var keys = [
+                       'backgroundColor',
+                       'borderColor',
+                       'borderWidth',
+                       'hoverBackgroundColor',
+                       'hoverBorderColor',
+                       'hoverBorderWidth',
+                       'hoverRadius',
+                       'hitRadius',
+                       'pointStyle',
+                       'rotation'
+               ];
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve$2([
+                               custom[key],
+                               dataset[key],
+                               options[key]
+                       ], context, index);
+               }
+
+               // Custom radius resolution
+               values.radius = resolve$2([
+                       custom.radius,
+                       data ? data.r : undefined,
+                       dataset.radius,
+                       options.radius
+               ], context, index);
+
+               return values;
+       }
+});
+
+var resolve$3 = helpers$1.options.resolve;
+var valueOrDefault$4 = helpers$1.valueOrDefault;
+
+core_defaults._set('doughnut', {
+       animation: {
+               // Boolean - Whether we animate the rotation of the Doughnut
+               animateRotate: true,
+               // Boolean - Whether we animate scaling the Doughnut from the centre
+               animateScale: false
+       },
+       hover: {
+               mode: 'single'
+       },
+       legendCallback: function(chart) {
+               var text = [];
+               text.push('<ul class="' + chart.id + '-legend">');
+
+               var data = chart.data;
+               var datasets = data.datasets;
+               var labels = data.labels;
+
+               if (datasets.length) {
+                       for (var i = 0; i < datasets[0].data.length; ++i) {
+                               text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
+                               if (labels[i]) {
+                                       text.push(labels[i]);
+                               }
+                               text.push('</li>');
+                       }
+               }
+
+               text.push('</ul>');
+               return text.join('');
+       },
+       legend: {
+               labels: {
+                       generateLabels: function(chart) {
+                               var data = chart.data;
+                               if (data.labels.length && data.datasets.length) {
+                                       return data.labels.map(function(label, i) {
+                                               var meta = chart.getDatasetMeta(0);
+                                               var ds = data.datasets[0];
+                                               var arc = meta.data[i];
+                                               var custom = arc && arc.custom || {};
+                                               var arcOpts = chart.options.elements.arc;
+                                               var fill = resolve$3([custom.backgroundColor, ds.backgroundColor, arcOpts.backgroundColor], undefined, i);
+                                               var stroke = resolve$3([custom.borderColor, ds.borderColor, arcOpts.borderColor], undefined, i);
+                                               var bw = resolve$3([custom.borderWidth, ds.borderWidth, arcOpts.borderWidth], undefined, i);
+
+                                               return {
+                                                       text: label,
+                                                       fillStyle: fill,
+                                                       strokeStyle: stroke,
+                                                       lineWidth: bw,
+                                                       hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
+
+                                                       // Extra data used for toggling the correct item
+                                                       index: i
+                                               };
+                                       });
+                               }
+                               return [];
+                       }
+               },
+
+               onClick: function(e, legendItem) {
+                       var index = legendItem.index;
+                       var chart = this.chart;
+                       var i, ilen, meta;
+
+                       for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
+                               meta = chart.getDatasetMeta(i);
+                               // toggle visibility of index if exists
+                               if (meta.data[index]) {
+                                       meta.data[index].hidden = !meta.data[index].hidden;
+                               }
+                       }
+
+                       chart.update();
+               }
+       },
+
+       // The percentage of the chart that we cut out of the middle.
+       cutoutPercentage: 50,
+
+       // The rotation of the chart, where the first data arc begins.
+       rotation: Math.PI * -0.5,
+
+       // The total circumference of the chart.
+       circumference: Math.PI * 2.0,
+
+       // Need to override these to give a nice default
+       tooltips: {
+               callbacks: {
+                       title: function() {
+                               return '';
+                       },
+                       label: function(tooltipItem, data) {
+                               var dataLabel = data.labels[tooltipItem.index];
+                               var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
+
+                               if (helpers$1.isArray(dataLabel)) {
+                                       // show value on first line of multiline label
+                                       // need to clone because we are changing the value
+                                       dataLabel = dataLabel.slice();
+                                       dataLabel[0] += value;
+                               } else {
+                                       dataLabel += value;
+                               }
+
+                               return dataLabel;
+                       }
+               }
+       }
+});
+
+var controller_doughnut = core_datasetController.extend({
+
+       dataElementType: elements.Arc,
+
+       linkScales: helpers$1.noop,
+
+       // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
+       getRingIndex: function(datasetIndex) {
+               var ringIndex = 0;
+
+               for (var j = 0; j < datasetIndex; ++j) {
+                       if (this.chart.isDatasetVisible(j)) {
+                               ++ringIndex;
+                       }
+               }
+
+               return ringIndex;
+       },
+
+       update: function(reset) {
+               var me = this;
+               var chart = me.chart;
+               var chartArea = chart.chartArea;
+               var opts = chart.options;
+               var availableWidth = chartArea.right - chartArea.left;
+               var availableHeight = chartArea.bottom - chartArea.top;
+               var minSize = Math.min(availableWidth, availableHeight);
+               var offset = {x: 0, y: 0};
+               var meta = me.getMeta();
+               var arcs = meta.data;
+               var cutoutPercentage = opts.cutoutPercentage;
+               var circumference = opts.circumference;
+               var chartWeight = me._getRingWeight(me.index);
+               var i, ilen;
+
+               // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc
+               if (circumference < Math.PI * 2.0) {
+                       var startAngle = opts.rotation % (Math.PI * 2.0);
+                       startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0);
+                       var endAngle = startAngle + circumference;
+                       var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)};
+                       var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)};
+                       var contains0 = (startAngle <= 0 && endAngle >= 0) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle);
+                       var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle);
+                       var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle);
+                       var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle);
+                       var cutout = cutoutPercentage / 100.0;
+                       var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))};
+                       var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))};
+                       var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5};
+                       minSize = Math.min(availableWidth / size.width, availableHeight / size.height);
+                       offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
+               }
+
+               for (i = 0, ilen = arcs.length; i < ilen; ++i) {
+                       arcs[i]._options = me._resolveElementOptions(arcs[i], i);
+               }
+
+               chart.borderWidth = me.getMaxBorderWidth();
+               chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
+               chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
+               chart.radiusLength = (chart.outerRadius - chart.innerRadius) / (me._getVisibleDatasetWeightTotal() || 1);
+               chart.offsetX = offset.x * chart.outerRadius;
+               chart.offsetY = offset.y * chart.outerRadius;
+
+               meta.total = me.calculateTotal();
+
+               me.outerRadius = chart.outerRadius - chart.radiusLength * me._getRingWeightOffset(me.index);
+               me.innerRadius = Math.max(me.outerRadius - chart.radiusLength * chartWeight, 0);
+
+               for (i = 0, ilen = arcs.length; i < ilen; ++i) {
+                       me.updateElement(arcs[i], i, reset);
+               }
+       },
+
+       updateElement: function(arc, index, reset) {
+               var me = this;
+               var chart = me.chart;
+               var chartArea = chart.chartArea;
+               var opts = chart.options;
+               var animationOpts = opts.animation;
+               var centerX = (chartArea.left + chartArea.right) / 2;
+               var centerY = (chartArea.top + chartArea.bottom) / 2;
+               var startAngle = opts.rotation; // non reset case handled later
+               var endAngle = opts.rotation; // non reset case handled later
+               var dataset = me.getDataset();
+               var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI));
+               var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius;
+               var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius;
+               var options = arc._options || {};
+
+               helpers$1.extend(arc, {
+                       // Utility
+                       _datasetIndex: me.index,
+                       _index: index,
+
+                       // Desired view properties
+                       _model: {
+                               backgroundColor: options.backgroundColor,
+                               borderColor: options.borderColor,
+                               borderWidth: options.borderWidth,
+                               borderAlign: options.borderAlign,
+                               x: centerX + chart.offsetX,
+                               y: centerY + chart.offsetY,
+                               startAngle: startAngle,
+                               endAngle: endAngle,
+                               circumference: circumference,
+                               outerRadius: outerRadius,
+                               innerRadius: innerRadius,
+                               label: helpers$1.valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])
+                       }
+               });
+
+               var model = arc._model;
+
+               // Set correct angles if not resetting
+               if (!reset || !animationOpts.animateRotate) {
+                       if (index === 0) {
+                               model.startAngle = opts.rotation;
+                       } else {
+                               model.startAngle = me.getMeta().data[index - 1]._model.endAngle;
+                       }
+
+                       model.endAngle = model.startAngle + model.circumference;
+               }
+
+               arc.pivot();
+       },
+
+       calculateTotal: function() {
+               var dataset = this.getDataset();
+               var meta = this.getMeta();
+               var total = 0;
+               var value;
+
+               helpers$1.each(meta.data, function(element, index) {
+                       value = dataset.data[index];
+                       if (!isNaN(value) && !element.hidden) {
+                               total += Math.abs(value);
+                       }
+               });
+
+               /* if (total === 0) {
+                       total = NaN;
+               }*/
+
+               return total;
+       },
+
+       calculateCircumference: function(value) {
+               var total = this.getMeta().total;
+               if (total > 0 && !isNaN(value)) {
+                       return (Math.PI * 2.0) * (Math.abs(value) / total);
+               }
+               return 0;
+       },
+
+       // gets the max border or hover width to properly scale pie charts
+       getMaxBorderWidth: function(arcs) {
+               var me = this;
+               var max = 0;
+               var chart = me.chart;
+               var i, ilen, meta, arc, controller, options, borderWidth, hoverWidth;
+
+               if (!arcs) {
+                       // Find the outmost visible dataset
+                       for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
+                               if (chart.isDatasetVisible(i)) {
+                                       meta = chart.getDatasetMeta(i);
+                                       arcs = meta.data;
+                                       if (i !== me.index) {
+                                               controller = meta.controller;
+                                       }
+                                       break;
+                               }
+                       }
+               }
+
+               if (!arcs) {
+                       return 0;
+               }
+
+               for (i = 0, ilen = arcs.length; i < ilen; ++i) {
+                       arc = arcs[i];
+                       options = controller ? controller._resolveElementOptions(arc, i) : arc._options;
+                       if (options.borderAlign !== 'inner') {
+                               borderWidth = options.borderWidth;
+                               hoverWidth = options.hoverBorderWidth;
+
+                               max = borderWidth > max ? borderWidth : max;
+                               max = hoverWidth > max ? hoverWidth : max;
+                       }
+               }
+               return max;
+       },
+
+       /**
+        * @protected
+        */
+       setHoverStyle: function(arc) {
+               var model = arc._model;
+               var options = arc._options;
+               var getHoverColor = helpers$1.getHoverColor;
+
+               arc.$previousStyle = {
+                       backgroundColor: model.backgroundColor,
+                       borderColor: model.borderColor,
+                       borderWidth: model.borderWidth,
+               };
+
+               model.backgroundColor = valueOrDefault$4(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
+               model.borderColor = valueOrDefault$4(options.hoverBorderColor, getHoverColor(options.borderColor));
+               model.borderWidth = valueOrDefault$4(options.hoverBorderWidth, options.borderWidth);
+       },
+
+       /**
+        * @private
+        */
+       _resolveElementOptions: function(arc, index) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = me.getDataset();
+               var custom = arc.custom || {};
+               var options = chart.options.elements.arc;
+               var values = {};
+               var i, ilen, key;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               var keys = [
+                       'backgroundColor',
+                       'borderColor',
+                       'borderWidth',
+                       'borderAlign',
+                       'hoverBackgroundColor',
+                       'hoverBorderColor',
+                       'hoverBorderWidth',
+               ];
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve$3([
+                               custom[key],
+                               dataset[key],
+                               options[key]
+                       ], context, index);
+               }
+
+               return values;
+       },
+
+       /**
+        * Get radius length offset of the dataset in relation to the visible datasets weights. This allows determining the inner and outer radius correctly
+        * @private
+        */
+       _getRingWeightOffset: function(datasetIndex) {
+               var ringWeightOffset = 0;
+
+               for (var i = 0; i < datasetIndex; ++i) {
+                       if (this.chart.isDatasetVisible(i)) {
+                               ringWeightOffset += this._getRingWeight(i);
+                       }
+               }
+
+               return ringWeightOffset;
+       },
+
+       /**
+        * @private
+        */
+       _getRingWeight: function(dataSetIndex) {
+               return Math.max(valueOrDefault$4(this.chart.data.datasets[dataSetIndex].weight, 1), 0);
+       },
+
+       /**
+        * Returns the sum of all visibile data set weights.  This value can be 0.
+        * @private
+        */
+       _getVisibleDatasetWeightTotal: function() {
+               return this._getRingWeightOffset(this.chart.data.datasets.length);
+       }
+});
+
+core_defaults._set('horizontalBar', {
+       hover: {
+               mode: 'index',
+               axis: 'y'
+       },
+
+       scales: {
+               xAxes: [{
+                       type: 'linear',
+                       position: 'bottom'
+               }],
+
+               yAxes: [{
+                       type: 'category',
+                       position: 'left',
+                       categoryPercentage: 0.8,
+                       barPercentage: 0.9,
+                       offset: true,
+                       gridLines: {
+                               offsetGridLines: true
+                       }
+               }]
+       },
+
+       elements: {
+               rectangle: {
+                       borderSkipped: 'left'
+               }
+       },
+
+       tooltips: {
+               mode: 'index',
+               axis: 'y'
+       }
+});
+
+var controller_horizontalBar = controller_bar.extend({
+       /**
+        * @private
+        */
+       _getValueScaleId: function() {
+               return this.getMeta().xAxisID;
+       },
+
+       /**
+        * @private
+        */
+       _getIndexScaleId: function() {
+               return this.getMeta().yAxisID;
+       }
+});
+
+var valueOrDefault$5 = helpers$1.valueOrDefault;
+var resolve$4 = helpers$1.options.resolve;
+var isPointInArea = helpers$1.canvas._isPointInArea;
+
+core_defaults._set('line', {
+       showLines: true,
+       spanGaps: false,
+
+       hover: {
+               mode: 'label'
+       },
+
+       scales: {
+               xAxes: [{
+                       type: 'category',
+                       id: 'x-axis-0'
+               }],
+               yAxes: [{
+                       type: 'linear',
+                       id: 'y-axis-0'
+               }]
+       }
+});
+
+function lineEnabled(dataset, options) {
+       return valueOrDefault$5(dataset.showLine, options.showLines);
+}
+
+var controller_line = core_datasetController.extend({
+
+       datasetElementType: elements.Line,
+
+       dataElementType: elements.Point,
+
+       update: function(reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var line = meta.dataset;
+               var points = meta.data || [];
+               var scale = me.getScaleForId(meta.yAxisID);
+               var dataset = me.getDataset();
+               var showLine = lineEnabled(dataset, me.chart.options);
+               var i, ilen;
+
+               // Update Line
+               if (showLine) {
+                       // Compatibility: If the properties are defined with only the old name, use those values
+                       if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
+                               dataset.lineTension = dataset.tension;
+                       }
+
+                       // Utility
+                       line._scale = scale;
+                       line._datasetIndex = me.index;
+                       // Data
+                       line._children = points;
+                       // Model
+                       line._model = me._resolveLineOptions(line);
+
+                       line.pivot();
+               }
+
+               // Update Points
+               for (i = 0, ilen = points.length; i < ilen; ++i) {
+                       me.updateElement(points[i], i, reset);
+               }
+
+               if (showLine && line._model.tension !== 0) {
+                       me.updateBezierControlPoints();
+               }
+
+               // Now pivot the point for animation
+               for (i = 0, ilen = points.length; i < ilen; ++i) {
+                       points[i].pivot();
+               }
+       },
+
+       updateElement: function(point, index, reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var custom = point.custom || {};
+               var dataset = me.getDataset();
+               var datasetIndex = me.index;
+               var value = dataset.data[index];
+               var yScale = me.getScaleForId(meta.yAxisID);
+               var xScale = me.getScaleForId(meta.xAxisID);
+               var lineModel = meta.dataset._model;
+               var x, y;
+
+               var options = me._resolvePointOptions(point, index);
+
+               x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex);
+               y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex);
+
+               // Utility
+               point._xScale = xScale;
+               point._yScale = yScale;
+               point._options = options;
+               point._datasetIndex = datasetIndex;
+               point._index = index;
+
+               // Desired view properties
+               point._model = {
+                       x: x,
+                       y: y,
+                       skip: custom.skip || isNaN(x) || isNaN(y),
+                       // Appearance
+                       radius: options.radius,
+                       pointStyle: options.pointStyle,
+                       rotation: options.rotation,
+                       backgroundColor: options.backgroundColor,
+                       borderColor: options.borderColor,
+                       borderWidth: options.borderWidth,
+                       tension: valueOrDefault$5(custom.tension, lineModel ? lineModel.tension : 0),
+                       steppedLine: lineModel ? lineModel.steppedLine : false,
+                       // Tooltip
+                       hitRadius: options.hitRadius
+               };
+       },
+
+       /**
+        * @private
+        */
+       _resolvePointOptions: function(element, index) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = chart.data.datasets[me.index];
+               var custom = element.custom || {};
+               var options = chart.options.elements.point;
+               var values = {};
+               var i, ilen, key;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               var ELEMENT_OPTIONS = {
+                       backgroundColor: 'pointBackgroundColor',
+                       borderColor: 'pointBorderColor',
+                       borderWidth: 'pointBorderWidth',
+                       hitRadius: 'pointHitRadius',
+                       hoverBackgroundColor: 'pointHoverBackgroundColor',
+                       hoverBorderColor: 'pointHoverBorderColor',
+                       hoverBorderWidth: 'pointHoverBorderWidth',
+                       hoverRadius: 'pointHoverRadius',
+                       pointStyle: 'pointStyle',
+                       radius: 'pointRadius',
+                       rotation: 'pointRotation'
+               };
+               var keys = Object.keys(ELEMENT_OPTIONS);
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve$4([
+                               custom[key],
+                               dataset[ELEMENT_OPTIONS[key]],
+                               dataset[key],
+                               options[key]
+                       ], context, index);
+               }
+
+               return values;
+       },
+
+       /**
+        * @private
+        */
+       _resolveLineOptions: function(element) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = chart.data.datasets[me.index];
+               var custom = element.custom || {};
+               var options = chart.options;
+               var elementOptions = options.elements.line;
+               var values = {};
+               var i, ilen, key;
+
+               var keys = [
+                       'backgroundColor',
+                       'borderWidth',
+                       'borderColor',
+                       'borderCapStyle',
+                       'borderDash',
+                       'borderDashOffset',
+                       'borderJoinStyle',
+                       'fill',
+                       'cubicInterpolationMode'
+               ];
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve$4([
+                               custom[key],
+                               dataset[key],
+                               elementOptions[key]
+                       ]);
+               }
+
+               // The default behavior of lines is to break at null values, according
+               // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
+               // This option gives lines the ability to span gaps
+               values.spanGaps = valueOrDefault$5(dataset.spanGaps, options.spanGaps);
+               values.tension = valueOrDefault$5(dataset.lineTension, elementOptions.tension);
+               values.steppedLine = resolve$4([custom.steppedLine, dataset.steppedLine, elementOptions.stepped]);
+
+               return values;
+       },
+
+       calculatePointY: function(value, index, datasetIndex) {
+               var me = this;
+               var chart = me.chart;
+               var meta = me.getMeta();
+               var yScale = me.getScaleForId(meta.yAxisID);
+               var sumPos = 0;
+               var sumNeg = 0;
+               var i, ds, dsMeta;
+
+               if (yScale.options.stacked) {
+                       for (i = 0; i < datasetIndex; i++) {
+                               ds = chart.data.datasets[i];
+                               dsMeta = chart.getDatasetMeta(i);
+                               if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
+                                       var stackedRightValue = Number(yScale.getRightValue(ds.data[index]));
+                                       if (stackedRightValue < 0) {
+                                               sumNeg += stackedRightValue || 0;
+                                       } else {
+                                               sumPos += stackedRightValue || 0;
+                                       }
+                               }
+                       }
+
+                       var rightValue = Number(yScale.getRightValue(value));
+                       if (rightValue < 0) {
+                               return yScale.getPixelForValue(sumNeg + rightValue);
+                       }
+                       return yScale.getPixelForValue(sumPos + rightValue);
+               }
+
+               return yScale.getPixelForValue(value);
+       },
+
+       updateBezierControlPoints: function() {
+               var me = this;
+               var chart = me.chart;
+               var meta = me.getMeta();
+               var lineModel = meta.dataset._model;
+               var area = chart.chartArea;
+               var points = meta.data || [];
+               var i, ilen, model, controlPoints;
+
+               // Only consider points that are drawn in case the spanGaps option is used
+               if (lineModel.spanGaps) {
+                       points = points.filter(function(pt) {
+                               return !pt._model.skip;
+                       });
+               }
+
+               function capControlPoint(pt, min, max) {
+                       return Math.max(Math.min(pt, max), min);
+               }
+
+               if (lineModel.cubicInterpolationMode === 'monotone') {
+                       helpers$1.splineCurveMonotone(points);
+               } else {
+                       for (i = 0, ilen = points.length; i < ilen; ++i) {
+                               model = points[i]._model;
+                               controlPoints = helpers$1.splineCurve(
+                                       helpers$1.previousItem(points, i)._model,
+                                       model,
+                                       helpers$1.nextItem(points, i)._model,
+                                       lineModel.tension
+                               );
+                               model.controlPointPreviousX = controlPoints.previous.x;
+                               model.controlPointPreviousY = controlPoints.previous.y;
+                               model.controlPointNextX = controlPoints.next.x;
+                               model.controlPointNextY = controlPoints.next.y;
+                       }
+               }
+
+               if (chart.options.elements.line.capBezierPoints) {
+                       for (i = 0, ilen = points.length; i < ilen; ++i) {
+                               model = points[i]._model;
+                               if (isPointInArea(model, area)) {
+                                       if (i > 0 && isPointInArea(points[i - 1]._model, area)) {
+                                               model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);
+                                               model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
+                                       }
+                                       if (i < points.length - 1 && isPointInArea(points[i + 1]._model, area)) {
+                                               model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);
+                                               model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);
+                                       }
+                               }
+                       }
+               }
+       },
+
+       draw: function() {
+               var me = this;
+               var chart = me.chart;
+               var meta = me.getMeta();
+               var points = meta.data || [];
+               var area = chart.chartArea;
+               var ilen = points.length;
+               var halfBorderWidth;
+               var i = 0;
+
+               if (lineEnabled(me.getDataset(), chart.options)) {
+                       halfBorderWidth = (meta.dataset._model.borderWidth || 0) / 2;
+
+                       helpers$1.canvas.clipArea(chart.ctx, {
+                               left: area.left,
+                               right: area.right,
+                               top: area.top - halfBorderWidth,
+                               bottom: area.bottom + halfBorderWidth
+                       });
+
+                       meta.dataset.draw();
+
+                       helpers$1.canvas.unclipArea(chart.ctx);
+               }
+
+               // Draw the points
+               for (; i < ilen; ++i) {
+                       points[i].draw(area);
+               }
+       },
+
+       /**
+        * @protected
+        */
+       setHoverStyle: function(point) {
+               var model = point._model;
+               var options = point._options;
+               var getHoverColor = helpers$1.getHoverColor;
+
+               point.$previousStyle = {
+                       backgroundColor: model.backgroundColor,
+                       borderColor: model.borderColor,
+                       borderWidth: model.borderWidth,
+                       radius: model.radius
+               };
+
+               model.backgroundColor = valueOrDefault$5(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
+               model.borderColor = valueOrDefault$5(options.hoverBorderColor, getHoverColor(options.borderColor));
+               model.borderWidth = valueOrDefault$5(options.hoverBorderWidth, options.borderWidth);
+               model.radius = valueOrDefault$5(options.hoverRadius, options.radius);
+       },
+});
+
+var resolve$5 = helpers$1.options.resolve;
+
+core_defaults._set('polarArea', {
+       scale: {
+               type: 'radialLinear',
+               angleLines: {
+                       display: false
+               },
+               gridLines: {
+                       circular: true
+               },
+               pointLabels: {
+                       display: false
+               },
+               ticks: {
+                       beginAtZero: true
+               }
+       },
+
+       // Boolean - Whether to animate the rotation of the chart
+       animation: {
+               animateRotate: true,
+               animateScale: true
+       },
+
+       startAngle: -0.5 * Math.PI,
+       legendCallback: function(chart) {
+               var text = [];
+               text.push('<ul class="' + chart.id + '-legend">');
+
+               var data = chart.data;
+               var datasets = data.datasets;
+               var labels = data.labels;
+
+               if (datasets.length) {
+                       for (var i = 0; i < datasets[0].data.length; ++i) {
+                               text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
+                               if (labels[i]) {
+                                       text.push(labels[i]);
+                               }
+                               text.push('</li>');
+                       }
+               }
+
+               text.push('</ul>');
+               return text.join('');
+       },
+       legend: {
+               labels: {
+                       generateLabels: function(chart) {
+                               var data = chart.data;
+                               if (data.labels.length && data.datasets.length) {
+                                       return data.labels.map(function(label, i) {
+                                               var meta = chart.getDatasetMeta(0);
+                                               var ds = data.datasets[0];
+                                               var arc = meta.data[i];
+                                               var custom = arc.custom || {};
+                                               var arcOpts = chart.options.elements.arc;
+                                               var fill = resolve$5([custom.backgroundColor, ds.backgroundColor, arcOpts.backgroundColor], undefined, i);
+                                               var stroke = resolve$5([custom.borderColor, ds.borderColor, arcOpts.borderColor], undefined, i);
+                                               var bw = resolve$5([custom.borderWidth, ds.borderWidth, arcOpts.borderWidth], undefined, i);
+
+                                               return {
+                                                       text: label,
+                                                       fillStyle: fill,
+                                                       strokeStyle: stroke,
+                                                       lineWidth: bw,
+                                                       hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
+
+                                                       // Extra data used for toggling the correct item
+                                                       index: i
+                                               };
+                                       });
+                               }
+                               return [];
+                       }
+               },
+
+               onClick: function(e, legendItem) {
+                       var index = legendItem.index;
+                       var chart = this.chart;
+                       var i, ilen, meta;
+
+                       for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
+                               meta = chart.getDatasetMeta(i);
+                               meta.data[index].hidden = !meta.data[index].hidden;
+                       }
+
+                       chart.update();
+               }
+       },
+
+       // Need to override these to give a nice default
+       tooltips: {
+               callbacks: {
+                       title: function() {
+                               return '';
+                       },
+                       label: function(item, data) {
+                               return data.labels[item.index] + ': ' + item.yLabel;
+                       }
+               }
+       }
+});
+
+var controller_polarArea = core_datasetController.extend({
+
+       dataElementType: elements.Arc,
+
+       linkScales: helpers$1.noop,
+
+       update: function(reset) {
+               var me = this;
+               var dataset = me.getDataset();
+               var meta = me.getMeta();
+               var start = me.chart.options.startAngle || 0;
+               var starts = me._starts = [];
+               var angles = me._angles = [];
+               var arcs = meta.data;
+               var i, ilen, angle;
+
+               me._updateRadius();
+
+               meta.count = me.countVisibleElements();
+
+               for (i = 0, ilen = dataset.data.length; i < ilen; i++) {
+                       starts[i] = start;
+                       angle = me._computeAngle(i);
+                       angles[i] = angle;
+                       start += angle;
+               }
+
+               for (i = 0, ilen = arcs.length; i < ilen; ++i) {
+                       arcs[i]._options = me._resolveElementOptions(arcs[i], i);
+                       me.updateElement(arcs[i], i, reset);
+               }
+       },
+
+       /**
+        * @private
+        */
+       _updateRadius: function() {
+               var me = this;
+               var chart = me.chart;
+               var chartArea = chart.chartArea;
+               var opts = chart.options;
+               var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
+
+               chart.outerRadius = Math.max(minSize / 2, 0);
+               chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
+               chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
+
+               me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);
+               me.innerRadius = me.outerRadius - chart.radiusLength;
+       },
+
+       updateElement: function(arc, index, reset) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = me.getDataset();
+               var opts = chart.options;
+               var animationOpts = opts.animation;
+               var scale = chart.scale;
+               var labels = chart.data.labels;
+
+               var centerX = scale.xCenter;
+               var centerY = scale.yCenter;
+
+               // var negHalfPI = -0.5 * Math.PI;
+               var datasetStartAngle = opts.startAngle;
+               var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
+               var startAngle = me._starts[index];
+               var endAngle = startAngle + (arc.hidden ? 0 : me._angles[index]);
+
+               var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
+               var options = arc._options || {};
+
+               helpers$1.extend(arc, {
+                       // Utility
+                       _datasetIndex: me.index,
+                       _index: index,
+                       _scale: scale,
+
+                       // Desired view properties
+                       _model: {
+                               backgroundColor: options.backgroundColor,
+                               borderColor: options.borderColor,
+                               borderWidth: options.borderWidth,
+                               borderAlign: options.borderAlign,
+                               x: centerX,
+                               y: centerY,
+                               innerRadius: 0,
+                               outerRadius: reset ? resetRadius : distance,
+                               startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,
+                               endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle,
+                               label: helpers$1.valueAtIndexOrDefault(labels, index, labels[index])
+                       }
+               });
+
+               arc.pivot();
+       },
+
+       countVisibleElements: function() {
+               var dataset = this.getDataset();
+               var meta = this.getMeta();
+               var count = 0;
+
+               helpers$1.each(meta.data, function(element, index) {
+                       if (!isNaN(dataset.data[index]) && !element.hidden) {
+                               count++;
+                       }
+               });
+
+               return count;
+       },
+
+       /**
+        * @protected
+        */
+       setHoverStyle: function(arc) {
+               var model = arc._model;
+               var options = arc._options;
+               var getHoverColor = helpers$1.getHoverColor;
+               var valueOrDefault = helpers$1.valueOrDefault;
+
+               arc.$previousStyle = {
+                       backgroundColor: model.backgroundColor,
+                       borderColor: model.borderColor,
+                       borderWidth: model.borderWidth,
+               };
+
+               model.backgroundColor = valueOrDefault(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
+               model.borderColor = valueOrDefault(options.hoverBorderColor, getHoverColor(options.borderColor));
+               model.borderWidth = valueOrDefault(options.hoverBorderWidth, options.borderWidth);
+       },
+
+       /**
+        * @private
+        */
+       _resolveElementOptions: function(arc, index) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = me.getDataset();
+               var custom = arc.custom || {};
+               var options = chart.options.elements.arc;
+               var values = {};
+               var i, ilen, key;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               var keys = [
+                       'backgroundColor',
+                       'borderColor',
+                       'borderWidth',
+                       'borderAlign',
+                       'hoverBackgroundColor',
+                       'hoverBorderColor',
+                       'hoverBorderWidth',
+               ];
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve$5([
+                               custom[key],
+                               dataset[key],
+                               options[key]
+                       ], context, index);
+               }
+
+               return values;
+       },
+
+       /**
+        * @private
+        */
+       _computeAngle: function(index) {
+               var me = this;
+               var count = this.getMeta().count;
+               var dataset = me.getDataset();
+               var meta = me.getMeta();
+
+               if (isNaN(dataset.data[index]) || meta.data[index].hidden) {
+                       return 0;
+               }
+
+               // Scriptable options
+               var context = {
+                       chart: me.chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               return resolve$5([
+                       me.chart.options.elements.arc.angle,
+                       (2 * Math.PI) / count
+               ], context, index);
+       }
+});
+
+core_defaults._set('pie', helpers$1.clone(core_defaults.doughnut));
+core_defaults._set('pie', {
+       cutoutPercentage: 0
+});
+
+// Pie charts are Doughnut chart with different defaults
+var controller_pie = controller_doughnut;
+
+var valueOrDefault$6 = helpers$1.valueOrDefault;
+var resolve$6 = helpers$1.options.resolve;
+
+core_defaults._set('radar', {
+       scale: {
+               type: 'radialLinear'
+       },
+       elements: {
+               line: {
+                       tension: 0 // no bezier in radar
+               }
+       }
+});
+
+var controller_radar = core_datasetController.extend({
+
+       datasetElementType: elements.Line,
+
+       dataElementType: elements.Point,
+
+       linkScales: helpers$1.noop,
+
+       update: function(reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var line = meta.dataset;
+               var points = meta.data || [];
+               var scale = me.chart.scale;
+               var dataset = me.getDataset();
+               var i, ilen;
+
+               // Compatibility: If the properties are defined with only the old name, use those values
+               if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
+                       dataset.lineTension = dataset.tension;
+               }
+
+               // Utility
+               line._scale = scale;
+               line._datasetIndex = me.index;
+               // Data
+               line._children = points;
+               line._loop = true;
+               // Model
+               line._model = me._resolveLineOptions(line);
+
+               line.pivot();
+
+               // Update Points
+               for (i = 0, ilen = points.length; i < ilen; ++i) {
+                       me.updateElement(points[i], i, reset);
+               }
+
+               // Update bezier control points
+               me.updateBezierControlPoints();
+
+               // Now pivot the point for animation
+               for (i = 0, ilen = points.length; i < ilen; ++i) {
+                       points[i].pivot();
+               }
+       },
+
+       updateElement: function(point, index, reset) {
+               var me = this;
+               var custom = point.custom || {};
+               var dataset = me.getDataset();
+               var scale = me.chart.scale;
+               var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);
+               var options = me._resolvePointOptions(point, index);
+               var lineModel = me.getMeta().dataset._model;
+               var x = reset ? scale.xCenter : pointPosition.x;
+               var y = reset ? scale.yCenter : pointPosition.y;
+
+               // Utility
+               point._scale = scale;
+               point._options = options;
+               point._datasetIndex = me.index;
+               point._index = index;
+
+               // Desired view properties
+               point._model = {
+                       x: x, // value not used in dataset scale, but we want a consistent API between scales
+                       y: y,
+                       skip: custom.skip || isNaN(x) || isNaN(y),
+                       // Appearance
+                       radius: options.radius,
+                       pointStyle: options.pointStyle,
+                       rotation: options.rotation,
+                       backgroundColor: options.backgroundColor,
+                       borderColor: options.borderColor,
+                       borderWidth: options.borderWidth,
+                       tension: valueOrDefault$6(custom.tension, lineModel ? lineModel.tension : 0),
+
+                       // Tooltip
+                       hitRadius: options.hitRadius
+               };
+       },
+
+       /**
+        * @private
+        */
+       _resolvePointOptions: function(element, index) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = chart.data.datasets[me.index];
+               var custom = element.custom || {};
+               var options = chart.options.elements.point;
+               var values = {};
+               var i, ilen, key;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               var ELEMENT_OPTIONS = {
+                       backgroundColor: 'pointBackgroundColor',
+                       borderColor: 'pointBorderColor',
+                       borderWidth: 'pointBorderWidth',
+                       hitRadius: 'pointHitRadius',
+                       hoverBackgroundColor: 'pointHoverBackgroundColor',
+                       hoverBorderColor: 'pointHoverBorderColor',
+                       hoverBorderWidth: 'pointHoverBorderWidth',
+                       hoverRadius: 'pointHoverRadius',
+                       pointStyle: 'pointStyle',
+                       radius: 'pointRadius',
+                       rotation: 'pointRotation'
+               };
+               var keys = Object.keys(ELEMENT_OPTIONS);
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve$6([
+                               custom[key],
+                               dataset[ELEMENT_OPTIONS[key]],
+                               dataset[key],
+                               options[key]
+                       ], context, index);
+               }
+
+               return values;
+       },
+
+       /**
+        * @private
+        */
+       _resolveLineOptions: function(element) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = chart.data.datasets[me.index];
+               var custom = element.custom || {};
+               var options = chart.options.elements.line;
+               var values = {};
+               var i, ilen, key;
+
+               var keys = [
+                       'backgroundColor',
+                       'borderWidth',
+                       'borderColor',
+                       'borderCapStyle',
+                       'borderDash',
+                       'borderDashOffset',
+                       'borderJoinStyle',
+                       'fill'
+               ];
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve$6([
+                               custom[key],
+                               dataset[key],
+                               options[key]
+                       ]);
+               }
+
+               values.tension = valueOrDefault$6(dataset.lineTension, options.tension);
+
+               return values;
+       },
+
+       updateBezierControlPoints: function() {
+               var me = this;
+               var meta = me.getMeta();
+               var area = me.chart.chartArea;
+               var points = meta.data || [];
+               var i, ilen, model, controlPoints;
+
+               function capControlPoint(pt, min, max) {
+                       return Math.max(Math.min(pt, max), min);
+               }
+
+               for (i = 0, ilen = points.length; i < ilen; ++i) {
+                       model = points[i]._model;
+                       controlPoints = helpers$1.splineCurve(
+                               helpers$1.previousItem(points, i, true)._model,
+                               model,
+                               helpers$1.nextItem(points, i, true)._model,
+                               model.tension
+                       );
+
+                       // Prevent the bezier going outside of the bounds of the graph
+                       model.controlPointPreviousX = capControlPoint(controlPoints.previous.x, area.left, area.right);
+                       model.controlPointPreviousY = capControlPoint(controlPoints.previous.y, area.top, area.bottom);
+                       model.controlPointNextX = capControlPoint(controlPoints.next.x, area.left, area.right);
+                       model.controlPointNextY = capControlPoint(controlPoints.next.y, area.top, area.bottom);
+               }
+       },
+
+       setHoverStyle: function(point) {
+               var model = point._model;
+               var options = point._options;
+               var getHoverColor = helpers$1.getHoverColor;
+
+               point.$previousStyle = {
+                       backgroundColor: model.backgroundColor,
+                       borderColor: model.borderColor,
+                       borderWidth: model.borderWidth,
+                       radius: model.radius
+               };
+
+               model.backgroundColor = valueOrDefault$6(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
+               model.borderColor = valueOrDefault$6(options.hoverBorderColor, getHoverColor(options.borderColor));
+               model.borderWidth = valueOrDefault$6(options.hoverBorderWidth, options.borderWidth);
+               model.radius = valueOrDefault$6(options.hoverRadius, options.radius);
+       }
+});
+
+core_defaults._set('scatter', {
+       hover: {
+               mode: 'single'
+       },
+
+       scales: {
+               xAxes: [{
+                       id: 'x-axis-1',    // need an ID so datasets can reference the scale
+                       type: 'linear',    // scatter should not use a category axis
+                       position: 'bottom'
+               }],
+               yAxes: [{
+                       id: 'y-axis-1',
+                       type: 'linear',
+                       position: 'left'
+               }]
+       },
+
+       showLines: false,
+
+       tooltips: {
+               callbacks: {
+                       title: function() {
+                               return '';     // doesn't make sense for scatter since data are formatted as a point
+                       },
+                       label: function(item) {
+                               return '(' + item.xLabel + ', ' + item.yLabel + ')';
+                       }
+               }
+       }
+});
+
+// Scatter charts use line controllers
+var controller_scatter = controller_line;
+
+// NOTE export a map in which the key represents the controller type, not
+// the class, and so must be CamelCase in order to be correctly retrieved
+// by the controller in core.controller.js (`controllers[meta.type]`).
+
+var controllers = {
+       bar: controller_bar,
+       bubble: controller_bubble,
+       doughnut: controller_doughnut,
+       horizontalBar: controller_horizontalBar,
+       line: controller_line,
+       polarArea: controller_polarArea,
+       pie: controller_pie,
+       radar: controller_radar,
+       scatter: controller_scatter
+};
+
+/**
+ * Helper function to get relative position for an event
+ * @param {Event|IEvent} event - The event to get the position for
+ * @param {Chart} chart - The chart
+ * @returns {object} the event position
+ */
+function getRelativePosition(e, chart) {
+       if (e.native) {
+               return {
+                       x: e.x,
+                       y: e.y
+               };
+       }
+
+       return helpers$1.getRelativePosition(e, chart);
+}
+
+/**
+ * Helper function to traverse all of the visible elements in the chart
+ * @param {Chart} chart - the chart
+ * @param {function} handler - the callback to execute for each visible item
+ */
+function parseVisibleItems(chart, handler) {
+       var datasets = chart.data.datasets;
+       var meta, i, j, ilen, jlen;
+
+       for (i = 0, ilen = datasets.length; i < ilen; ++i) {
+               if (!chart.isDatasetVisible(i)) {
+                       continue;
+               }
+
+               meta = chart.getDatasetMeta(i);
+               for (j = 0, jlen = meta.data.length; j < jlen; ++j) {
+                       var element = meta.data[j];
+                       if (!element._view.skip) {
+                               handler(element);
+                       }
+               }
+       }
+}
+
+/**
+ * Helper function to get the items that intersect the event position
+ * @param {ChartElement[]} items - elements to filter
+ * @param {object} position - the point to be nearest to
+ * @return {ChartElement[]} the nearest items
+ */
+function getIntersectItems(chart, position) {
+       var elements = [];
+
+       parseVisibleItems(chart, function(element) {
+               if (element.inRange(position.x, position.y)) {
+                       elements.push(element);
+               }
+       });
+
+       return elements;
+}
+
+/**
+ * Helper function to get the items nearest to the event position considering all visible items in teh chart
+ * @param {Chart} chart - the chart to look at elements from
+ * @param {object} position - the point to be nearest to
+ * @param {boolean} intersect - if true, only consider items that intersect the position
+ * @param {function} distanceMetric - function to provide the distance between points
+ * @return {ChartElement[]} the nearest items
+ */
+function getNearestItems(chart, position, intersect, distanceMetric) {
+       var minDistance = Number.POSITIVE_INFINITY;
+       var nearestItems = [];
+
+       parseVisibleItems(chart, function(element) {
+               if (intersect && !element.inRange(position.x, position.y)) {
+                       return;
+               }
+
+               var center = element.getCenterPoint();
+               var distance = distanceMetric(position, center);
+               if (distance < minDistance) {
+                       nearestItems = [element];
+                       minDistance = distance;
+               } else if (distance === minDistance) {
+                       // Can have multiple items at the same distance in which case we sort by size
+                       nearestItems.push(element);
+               }
+       });
+
+       return nearestItems;
+}
+
+/**
+ * Get a distance metric function for two points based on the
+ * axis mode setting
+ * @param {string} axis - the axis mode. x|y|xy
+ */
+function getDistanceMetricForAxis(axis) {
+       var useX = axis.indexOf('x') !== -1;
+       var useY = axis.indexOf('y') !== -1;
+
+       return function(pt1, pt2) {
+               var deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
+               var deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
+               return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
+       };
+}
+
+function indexMode(chart, e, options) {
+       var position = getRelativePosition(e, chart);
+       // Default axis for index mode is 'x' to match old behaviour
+       options.axis = options.axis || 'x';
+       var distanceMetric = getDistanceMetricForAxis(options.axis);
+       var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
+       var elements = [];
+
+       if (!items.length) {
+               return [];
+       }
+
+       chart.data.datasets.forEach(function(dataset, datasetIndex) {
+               if (chart.isDatasetVisible(datasetIndex)) {
+                       var meta = chart.getDatasetMeta(datasetIndex);
+                       var element = meta.data[items[0]._index];
+
+                       // don't count items that are skipped (null data)
+                       if (element && !element._view.skip) {
+                               elements.push(element);
+                       }
+               }
+       });
+
+       return elements;
+}
+
+/**
+ * @interface IInteractionOptions
+ */
+/**
+ * If true, only consider items that intersect the point
+ * @name IInterfaceOptions#boolean
+ * @type Boolean
+ */
+
+/**
+ * Contains interaction related functions
+ * @namespace Chart.Interaction
+ */
+var core_interaction = {
+       // Helper function for different modes
+       modes: {
+               single: function(chart, e) {
+                       var position = getRelativePosition(e, chart);
+                       var elements = [];
+
+                       parseVisibleItems(chart, function(element) {
+                               if (element.inRange(position.x, position.y)) {
+                                       elements.push(element);
+                                       return elements;
+                               }
+                       });
+
+                       return elements.slice(0, 1);
+               },
+
+               /**
+                * @function Chart.Interaction.modes.label
+                * @deprecated since version 2.4.0
+                * @todo remove at version 3
+                * @private
+                */
+               label: indexMode,
+
+               /**
+                * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something
+                * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item
+                * @function Chart.Interaction.modes.index
+                * @since v2.4.0
+                * @param {Chart} chart - the chart we are returning items from
+                * @param {Event} e - the event we are find things at
+                * @param {IInteractionOptions} options - options to use during interaction
+                * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+                */
+               index: indexMode,
+
+               /**
+                * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something
+                * If the options.intersect is false, we find the nearest item and return the items in that dataset
+                * @function Chart.Interaction.modes.dataset
+                * @param {Chart} chart - the chart we are returning items from
+                * @param {Event} e - the event we are find things at
+                * @param {IInteractionOptions} options - options to use during interaction
+                * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+                */
+               dataset: function(chart, e, options) {
+                       var position = getRelativePosition(e, chart);
+                       options.axis = options.axis || 'xy';
+                       var distanceMetric = getDistanceMetricForAxis(options.axis);
+                       var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
+
+                       if (items.length > 0) {
+                               items = chart.getDatasetMeta(items[0]._datasetIndex).data;
+                       }
+
+                       return items;
+               },
+
+               /**
+                * @function Chart.Interaction.modes.x-axis
+                * @deprecated since version 2.4.0. Use index mode and intersect == true
+                * @todo remove at version 3
+                * @private
+                */
+               'x-axis': function(chart, e) {
+                       return indexMode(chart, e, {intersect: false});
+               },
+
+               /**
+                * Point mode returns all elements that hit test based on the event position
+                * of the event
+                * @function Chart.Interaction.modes.intersect
+                * @param {Chart} chart - the chart we are returning items from
+                * @param {Event} e - the event we are find things at
+                * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+                */
+               point: function(chart, e) {
+                       var position = getRelativePosition(e, chart);
+                       return getIntersectItems(chart, position);
+               },
+
+               /**
+                * nearest mode returns the element closest to the point
+                * @function Chart.Interaction.modes.intersect
+                * @param {Chart} chart - the chart we are returning items from
+                * @param {Event} e - the event we are find things at
+                * @param {IInteractionOptions} options - options to use
+                * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+                */
+               nearest: function(chart, e, options) {
+                       var position = getRelativePosition(e, chart);
+                       options.axis = options.axis || 'xy';
+                       var distanceMetric = getDistanceMetricForAxis(options.axis);
+                       return getNearestItems(chart, position, options.intersect, distanceMetric);
+               },
+
+               /**
+                * x mode returns the elements that hit-test at the current x coordinate
+                * @function Chart.Interaction.modes.x
+                * @param {Chart} chart - the chart we are returning items from
+                * @param {Event} e - the event we are find things at
+                * @param {IInteractionOptions} options - options to use
+                * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+                */
+               x: function(chart, e, options) {
+                       var position = getRelativePosition(e, chart);
+                       var items = [];
+                       var intersectsItem = false;
+
+                       parseVisibleItems(chart, function(element) {
+                               if (element.inXRange(position.x)) {
+                                       items.push(element);
+                               }
+
+                               if (element.inRange(position.x, position.y)) {
+                                       intersectsItem = true;
+                               }
+                       });
+
+                       // If we want to trigger on an intersect and we don't have any items
+                       // that intersect the position, return nothing
+                       if (options.intersect && !intersectsItem) {
+                               items = [];
+                       }
+                       return items;
+               },
+
+               /**
+                * y mode returns the elements that hit-test at the current y coordinate
+                * @function Chart.Interaction.modes.y
+                * @param {Chart} chart - the chart we are returning items from
+                * @param {Event} e - the event we are find things at
+                * @param {IInteractionOptions} options - options to use
+                * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+                */
+               y: function(chart, e, options) {
+                       var position = getRelativePosition(e, chart);
+                       var items = [];
+                       var intersectsItem = false;
+
+                       parseVisibleItems(chart, function(element) {
+                               if (element.inYRange(position.y)) {
+                                       items.push(element);
+                               }
+
+                               if (element.inRange(position.x, position.y)) {
+                                       intersectsItem = true;
+                               }
+                       });
+
+                       // If we want to trigger on an intersect and we don't have any items
+                       // that intersect the position, return nothing
+                       if (options.intersect && !intersectsItem) {
+                               items = [];
+                       }
+                       return items;
+               }
+       }
+};
+
+function filterByPosition(array, position) {
+       return helpers$1.where(array, function(v) {
+               return v.position === position;
+       });
+}
+
+function sortByWeight(array, reverse) {
+       array.forEach(function(v, i) {
+               v._tmpIndex_ = i;
+               return v;
+       });
+       array.sort(function(a, b) {
+               var v0 = reverse ? b : a;
+               var v1 = reverse ? a : b;
+               return v0.weight === v1.weight ?
+                       v0._tmpIndex_ - v1._tmpIndex_ :
+                       v0.weight - v1.weight;
+       });
+       array.forEach(function(v) {
+               delete v._tmpIndex_;
+       });
+}
+
+function findMaxPadding(boxes) {
+       var top = 0;
+       var left = 0;
+       var bottom = 0;
+       var right = 0;
+       helpers$1.each(boxes, function(box) {
+               if (box.getPadding) {
+                       var boxPadding = box.getPadding();
+                       top = Math.max(top, boxPadding.top);
+                       left = Math.max(left, boxPadding.left);
+                       bottom = Math.max(bottom, boxPadding.bottom);
+                       right = Math.max(right, boxPadding.right);
+               }
+       });
+       return {
+               top: top,
+               left: left,
+               bottom: bottom,
+               right: right
+       };
+}
+
+function addSizeByPosition(boxes, size) {
+       helpers$1.each(boxes, function(box) {
+               size[box.position] += box.isHorizontal() ? box.height : box.width;
+       });
+}
+
+core_defaults._set('global', {
+       layout: {
+               padding: {
+                       top: 0,
+                       right: 0,
+                       bottom: 0,
+                       left: 0
+               }
+       }
+});
+
+/**
+ * @interface ILayoutItem
+ * @prop {string} position - The position of the item in the chart layout. Possible values are
+ * 'left', 'top', 'right', 'bottom', and 'chartArea'
+ * @prop {number} weight - The weight used to sort the item. Higher weights are further away from the chart area
+ * @prop {boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down
+ * @prop {function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom)
+ * @prop {function} update - Takes two parameters: width and height. Returns size of item
+ * @prop {function} getPadding -  Returns an object with padding on the edges
+ * @prop {number} width - Width of item. Must be valid after update()
+ * @prop {number} height - Height of item. Must be valid after update()
+ * @prop {number} left - Left edge of the item. Set by layout system and cannot be used in update
+ * @prop {number} top - Top edge of the item. Set by layout system and cannot be used in update
+ * @prop {number} right - Right edge of the item. Set by layout system and cannot be used in update
+ * @prop {number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update
+ */
+
+// The layout service is very self explanatory.  It's responsible for the layout within a chart.
+// Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
+// It is this service's responsibility of carrying out that layout.
+var core_layouts = {
+       defaults: {},
+
+       /**
+        * Register a box to a chart.
+        * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
+        * @param {Chart} chart - the chart to use
+        * @param {ILayoutItem} item - the item to add to be layed out
+        */
+       addBox: function(chart, item) {
+               if (!chart.boxes) {
+                       chart.boxes = [];
+               }
+
+               // initialize item with default values
+               item.fullWidth = item.fullWidth || false;
+               item.position = item.position || 'top';
+               item.weight = item.weight || 0;
+
+               chart.boxes.push(item);
+       },
+
+       /**
+        * Remove a layoutItem from a chart
+        * @param {Chart} chart - the chart to remove the box from
+        * @param {ILayoutItem} layoutItem - the item to remove from the layout
+        */
+       removeBox: function(chart, layoutItem) {
+               var index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
+               if (index !== -1) {
+                       chart.boxes.splice(index, 1);
+               }
+       },
+
+       /**
+        * Sets (or updates) options on the given `item`.
+        * @param {Chart} chart - the chart in which the item lives (or will be added to)
+        * @param {ILayoutItem} item - the item to configure with the given options
+        * @param {object} options - the new item options.
+        */
+       configure: function(chart, item, options) {
+               var props = ['fullWidth', 'position', 'weight'];
+               var ilen = props.length;
+               var i = 0;
+               var prop;
+
+               for (; i < ilen; ++i) {
+                       prop = props[i];
+                       if (options.hasOwnProperty(prop)) {
+                               item[prop] = options[prop];
+                       }
+               }
+       },
+
+       /**
+        * Fits boxes of the given chart into the given size by having each box measure itself
+        * then running a fitting algorithm
+        * @param {Chart} chart - the chart
+        * @param {number} width - the width to fit into
+        * @param {number} height - the height to fit into
+        */
+       update: function(chart, width, height) {
+               if (!chart) {
+                       return;
+               }
+
+               var layoutOptions = chart.options.layout || {};
+               var padding = helpers$1.options.toPadding(layoutOptions.padding);
+               var leftPadding = padding.left;
+               var rightPadding = padding.right;
+               var topPadding = padding.top;
+               var bottomPadding = padding.bottom;
+
+               var leftBoxes = filterByPosition(chart.boxes, 'left');
+               var rightBoxes = filterByPosition(chart.boxes, 'right');
+               var topBoxes = filterByPosition(chart.boxes, 'top');
+               var bottomBoxes = filterByPosition(chart.boxes, 'bottom');
+               var chartAreaBoxes = filterByPosition(chart.boxes, 'chartArea');
+
+               // Sort boxes by weight. A higher weight is further away from the chart area
+               sortByWeight(leftBoxes, true);
+               sortByWeight(rightBoxes, false);
+               sortByWeight(topBoxes, true);
+               sortByWeight(bottomBoxes, false);
+
+               var verticalBoxes = leftBoxes.concat(rightBoxes);
+               var horizontalBoxes = topBoxes.concat(bottomBoxes);
+               var outerBoxes = verticalBoxes.concat(horizontalBoxes);
+
+               // Essentially we now have any number of boxes on each of the 4 sides.
+               // Our canvas looks like the following.
+               // The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
+               // B1 is the bottom axis
+               // There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
+               // These locations are single-box locations only, when trying to register a chartArea location that is already taken,
+               // an error will be thrown.
+               //
+               // |----------------------------------------------------|
+               // |                  T1 (Full Width)                   |
+               // |----------------------------------------------------|
+               // |    |    |                 T2                  |    |
+               // |    |----|-------------------------------------|----|
+               // |    |    | C1 |                           | C2 |    |
+               // |    |    |----|                           |----|    |
+               // |    |    |                                     |    |
+               // | L1 | L2 |           ChartArea (C0)            | R1 |
+               // |    |    |                                     |    |
+               // |    |    |----|                           |----|    |
+               // |    |    | C3 |                           | C4 |    |
+               // |    |----|-------------------------------------|----|
+               // |    |    |                 B1                  |    |
+               // |----------------------------------------------------|
+               // |                  B2 (Full Width)                   |
+               // |----------------------------------------------------|
+               //
+               // What we do to find the best sizing, we do the following
+               // 1. Determine the minimum size of the chart area.
+               // 2. Split the remaining width equally between each vertical axis
+               // 3. Split the remaining height equally between each horizontal axis
+               // 4. Give each layout the maximum size it can be. The layout will return it's minimum size
+               // 5. Adjust the sizes of each axis based on it's minimum reported size.
+               // 6. Refit each axis
+               // 7. Position each axis in the final location
+               // 8. Tell the chart the final location of the chart area
+               // 9. Tell any axes that overlay the chart area the positions of the chart area
+
+               // Step 1
+               var chartWidth = width - leftPadding - rightPadding;
+               var chartHeight = height - topPadding - bottomPadding;
+               var chartAreaWidth = chartWidth / 2; // min 50%
+
+               // Step 2
+               var verticalBoxWidth = (width - chartAreaWidth) / verticalBoxes.length;
+
+               // Step 3
+               // TODO re-limit horizontal axis height (this limit has affected only padding calculation since PR 1837)
+               // var horizontalBoxHeight = (height - chartAreaHeight) / horizontalBoxes.length;
+
+               // Step 4
+               var maxChartAreaWidth = chartWidth;
+               var maxChartAreaHeight = chartHeight;
+               var outerBoxSizes = {top: topPadding, left: leftPadding, bottom: bottomPadding, right: rightPadding};
+               var minBoxSizes = [];
+               var maxPadding;
+
+               function getMinimumBoxSize(box) {
+                       var minSize;
+                       var isHorizontal = box.isHorizontal();
+
+                       if (isHorizontal) {
+                               minSize = box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2);
+                               maxChartAreaHeight -= minSize.height;
+                       } else {
+                               minSize = box.update(verticalBoxWidth, maxChartAreaHeight);
+                               maxChartAreaWidth -= minSize.width;
+                       }
+
+                       minBoxSizes.push({
+                               horizontal: isHorizontal,
+                               width: minSize.width,
+                               box: box,
+                       });
+               }
+
+               helpers$1.each(outerBoxes, getMinimumBoxSize);
+
+               // If a horizontal box has padding, we move the left boxes over to avoid ugly charts (see issue #2478)
+               maxPadding = findMaxPadding(outerBoxes);
+
+               // At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
+               // be if the axes are drawn at their minimum sizes.
+               // Steps 5 & 6
+
+               // Function to fit a box
+               function fitBox(box) {
+                       var minBoxSize = helpers$1.findNextWhere(minBoxSizes, function(minBox) {
+                               return minBox.box === box;
+                       });
+
+                       if (minBoxSize) {
+                               if (minBoxSize.horizontal) {
+                                       var scaleMargin = {
+                                               left: Math.max(outerBoxSizes.left, maxPadding.left),
+                                               right: Math.max(outerBoxSizes.right, maxPadding.right),
+                                               top: 0,
+                                               bottom: 0
+                                       };
+
+                                       // Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends
+                                       // on the margin. Sometimes they need to increase in size slightly
+                                       box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
+                               } else {
+                                       box.update(minBoxSize.width, maxChartAreaHeight);
+                               }
+                       }
+               }
+
+               // Update, and calculate the left and right margins for the horizontal boxes
+               helpers$1.each(verticalBoxes, fitBox);
+               addSizeByPosition(verticalBoxes, outerBoxSizes);
+
+               // Set the Left and Right margins for the horizontal boxes
+               helpers$1.each(horizontalBoxes, fitBox);
+               addSizeByPosition(horizontalBoxes, outerBoxSizes);
+
+               function finalFitVerticalBox(box) {
+                       var minBoxSize = helpers$1.findNextWhere(minBoxSizes, function(minSize) {
+                               return minSize.box === box;
+                       });
+
+                       var scaleMargin = {
+                               left: 0,
+                               right: 0,
+                               top: outerBoxSizes.top,
+                               bottom: outerBoxSizes.bottom
+                       };
+
+                       if (minBoxSize) {
+                               box.update(minBoxSize.width, maxChartAreaHeight, scaleMargin);
+                       }
+               }
+
+               // Let the left layout know the final margin
+               helpers$1.each(verticalBoxes, finalFitVerticalBox);
+
+               // Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
+               outerBoxSizes = {top: topPadding, left: leftPadding, bottom: bottomPadding, right: rightPadding};
+               addSizeByPosition(outerBoxes, outerBoxSizes);
+
+               // We may be adding some padding to account for rotated x axis labels
+               var leftPaddingAddition = Math.max(maxPadding.left - outerBoxSizes.left, 0);
+               outerBoxSizes.left += leftPaddingAddition;
+               outerBoxSizes.right += Math.max(maxPadding.right - outerBoxSizes.right, 0);
+
+               var topPaddingAddition = Math.max(maxPadding.top - outerBoxSizes.top, 0);
+               outerBoxSizes.top += topPaddingAddition;
+               outerBoxSizes.bottom += Math.max(maxPadding.bottom - outerBoxSizes.bottom, 0);
+
+               // Figure out if our chart area changed. This would occur if the dataset layout label rotation
+               // changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
+               // without calling `fit` again
+               var newMaxChartAreaHeight = height - outerBoxSizes.top - outerBoxSizes.bottom;
+               var newMaxChartAreaWidth = width - outerBoxSizes.left - outerBoxSizes.right;
+
+               if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) {
+                       helpers$1.each(verticalBoxes, function(box) {
+                               box.height = newMaxChartAreaHeight;
+                       });
+
+                       helpers$1.each(horizontalBoxes, function(box) {
+                               if (!box.fullWidth) {
+                                       box.width = newMaxChartAreaWidth;
+                               }
+                       });
+
+                       maxChartAreaHeight = newMaxChartAreaHeight;
+                       maxChartAreaWidth = newMaxChartAreaWidth;
+               }
+
+               // Step 7 - Position the boxes
+               var left = leftPadding + leftPaddingAddition;
+               var top = topPadding + topPaddingAddition;
+
+               function placeBox(box) {
+                       if (box.isHorizontal()) {
+                               box.left = box.fullWidth ? leftPadding : outerBoxSizes.left;
+                               box.right = box.fullWidth ? width - rightPadding : outerBoxSizes.left + maxChartAreaWidth;
+                               box.top = top;
+                               box.bottom = top + box.height;
+
+                               // Move to next point
+                               top = box.bottom;
+
+                       } else {
+
+                               box.left = left;
+                               box.right = left + box.width;
+                               box.top = outerBoxSizes.top;
+                               box.bottom = outerBoxSizes.top + maxChartAreaHeight;
+
+                               // Move to next point
+                               left = box.right;
+                       }
+               }
+
+               helpers$1.each(leftBoxes.concat(topBoxes), placeBox);
+
+               // Account for chart width and height
+               left += maxChartAreaWidth;
+               top += maxChartAreaHeight;
+
+               helpers$1.each(rightBoxes, placeBox);
+               helpers$1.each(bottomBoxes, placeBox);
+
+               // Step 8
+               chart.chartArea = {
+                       left: outerBoxSizes.left,
+                       top: outerBoxSizes.top,
+                       right: outerBoxSizes.left + maxChartAreaWidth,
+                       bottom: outerBoxSizes.top + maxChartAreaHeight
+               };
+
+               // Step 9
+               helpers$1.each(chartAreaBoxes, function(box) {
+                       box.left = chart.chartArea.left;
+                       box.top = chart.chartArea.top;
+                       box.right = chart.chartArea.right;
+                       box.bottom = chart.chartArea.bottom;
+
+                       box.update(maxChartAreaWidth, maxChartAreaHeight);
+               });
+       }
+};
+
+/**
+ * Platform fallback implementation (minimal).
+ * @see https://github.com/chartjs/Chart.js/pull/4591#issuecomment-319575939
+ */
+
+var platform_basic = {
+       acquireContext: function(item) {
+               if (item && item.canvas) {
+                       // Support for any object associated to a canvas (including a context2d)
+                       item = item.canvas;
+               }
+
+               return item && item.getContext('2d') || null;
+       }
+};
+
+var platform_dom = "/*\n * DOM element rendering detection\n * https://davidwalsh.name/detect-node-insertion\n */\n@keyframes chartjs-render-animation {\n\tfrom { opacity: 0.99; }\n\tto { opacity: 1; }\n}\n\n.chartjs-render-monitor {\n\tanimation: chartjs-render-animation 0.001s;\n}\n\n/*\n * DOM element resizing detection\n * https://github.com/marcj/css-element-queries\n */\n.chartjs-size-monitor,\n.chartjs-size-monitor-expand,\n.chartjs-size-monitor-shrink {\n\tposition: absolute;\n\tdirection: ltr;\n\tleft: 0;\n\ttop: 0;\n\tright: 0;\n\tbottom: 0;\n\toverflow: hidden;\n\tpointer-events: none;\n\tvisibility: hidden;\n\tz-index: -1;\n}\n\n.chartjs-size-monitor-expand > div {\n\tposition: absolute;\n\twidth: 1000000px;\n\theight: 1000000px;\n\tleft: 0;\n\ttop: 0;\n}\n\n.chartjs-size-monitor-shrink > div {\n\tposition: absolute;\n\twidth: 200%;\n\theight: 200%;\n\tleft: 0;\n\ttop: 0;\n}\n";
+
+var platform_dom$1 = /*#__PURE__*/Object.freeze({
+default: platform_dom
+});
+
+var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
+
+function commonjsRequire () {
+       throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
+}
+
+function createCommonjsModule(fn, module) {
+       return module = { exports: {} }, fn(module, module.exports), module.exports;
+}
+
+function getCjsExportFromNamespace (n) {
+       return n && n.default || n;
+}
+
+var stylesheet = getCjsExportFromNamespace(platform_dom$1);
+
+var EXPANDO_KEY = '$chartjs';
+var CSS_PREFIX = 'chartjs-';
+var CSS_SIZE_MONITOR = CSS_PREFIX + 'size-monitor';
+var CSS_RENDER_MONITOR = CSS_PREFIX + 'render-monitor';
+var CSS_RENDER_ANIMATION = CSS_PREFIX + 'render-animation';
+var ANIMATION_START_EVENTS = ['animationstart', 'webkitAnimationStart'];
+
+/**
+ * DOM event types -> Chart.js event types.
+ * Note: only events with different types are mapped.
+ * @see https://developer.mozilla.org/en-US/docs/Web/Events
+ */
+var EVENT_TYPES = {
+       touchstart: 'mousedown',
+       touchmove: 'mousemove',
+       touchend: 'mouseup',
+       pointerenter: 'mouseenter',
+       pointerdown: 'mousedown',
+       pointermove: 'mousemove',
+       pointerup: 'mouseup',
+       pointerleave: 'mouseout',
+       pointerout: 'mouseout'
+};
+
+/**
+ * The "used" size is the final value of a dimension property after all calculations have
+ * been performed. This method uses the computed style of `element` but returns undefined
+ * if the computed style is not expressed in pixels. That can happen in some cases where
+ * `element` has a size relative to its parent and this last one is not yet displayed,
+ * for example because of `display: none` on a parent node.
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
+ * @returns {number} Size in pixels or undefined if unknown.
+ */
+function readUsedSize(element, property) {
+       var value = helpers$1.getStyle(element, property);
+       var matches = value && value.match(/^(\d+)(\.\d+)?px$/);
+       return matches ? Number(matches[1]) : undefined;
+}
+
+/**
+ * Initializes the canvas style and render size without modifying the canvas display size,
+ * since responsiveness is handled by the controller.resize() method. The config is used
+ * to determine the aspect ratio to apply in case no explicit height has been specified.
+ */
+function initCanvas(canvas, config) {
+       var style = canvas.style;
+
+       // NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
+       // returns null or '' if no explicit value has been set to the canvas attribute.
+       var renderHeight = canvas.getAttribute('height');
+       var renderWidth = canvas.getAttribute('width');
+
+       // Chart.js modifies some canvas values that we want to restore on destroy
+       canvas[EXPANDO_KEY] = {
+               initial: {
+                       height: renderHeight,
+                       width: renderWidth,
+                       style: {
+                               display: style.display,
+                               height: style.height,
+                               width: style.width
+                       }
+               }
+       };
+
+       // Force canvas to display as block to avoid extra space caused by inline
+       // elements, which would interfere with the responsive resize process.
+       // https://github.com/chartjs/Chart.js/issues/2538
+       style.display = style.display || 'block';
+
+       if (renderWidth === null || renderWidth === '') {
+               var displayWidth = readUsedSize(canvas, 'width');
+               if (displayWidth !== undefined) {
+                       canvas.width = displayWidth;
+               }
+       }
+
+       if (renderHeight === null || renderHeight === '') {
+               if (canvas.style.height === '') {
+                       // If no explicit render height and style height, let's apply the aspect ratio,
+                       // which one can be specified by the user but also by charts as default option
+                       // (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
+                       canvas.height = canvas.width / (config.options.aspectRatio || 2);
+               } else {
+                       var displayHeight = readUsedSize(canvas, 'height');
+                       if (displayWidth !== undefined) {
+                               canvas.height = displayHeight;
+                       }
+               }
+       }
+
+       return canvas;
+}
+
+/**
+ * Detects support for options object argument in addEventListener.
+ * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
+ * @private
+ */
+var supportsEventListenerOptions = (function() {
+       var supports = false;
+       try {
+               var options = Object.defineProperty({}, 'passive', {
+                       // eslint-disable-next-line getter-return
+                       get: function() {
+                               supports = true;
+                       }
+               });
+               window.addEventListener('e', null, options);
+       } catch (e) {
+               // continue regardless of error
+       }
+       return supports;
+}());
+
+// Default passive to true as expected by Chrome for 'touchstart' and 'touchend' events.
+// https://github.com/chartjs/Chart.js/issues/4287
+var eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false;
+
+function addListener(node, type, listener) {
+       node.addEventListener(type, listener, eventListenerOptions);
+}
+
+function removeListener(node, type, listener) {
+       node.removeEventListener(type, listener, eventListenerOptions);
+}
+
+function createEvent(type, chart, x, y, nativeEvent) {
+       return {
+               type: type,
+               chart: chart,
+               native: nativeEvent || null,
+               x: x !== undefined ? x : null,
+               y: y !== undefined ? y : null,
+       };
+}
+
+function fromNativeEvent(event, chart) {
+       var type = EVENT_TYPES[event.type] || event.type;
+       var pos = helpers$1.getRelativePosition(event, chart);
+       return createEvent(type, chart, pos.x, pos.y, event);
+}
+
+function throttled(fn, thisArg) {
+       var ticking = false;
+       var args = [];
+
+       return function() {
+               args = Array.prototype.slice.call(arguments);
+               thisArg = thisArg || this;
+
+               if (!ticking) {
+                       ticking = true;
+                       helpers$1.requestAnimFrame.call(window, function() {
+                               ticking = false;
+                               fn.apply(thisArg, args);
+                       });
+               }
+       };
+}
+
+function createDiv(cls) {
+       var el = document.createElement('div');
+       el.className = cls || '';
+       return el;
+}
+
+// Implementation based on https://github.com/marcj/css-element-queries
+function createResizer(handler) {
+       var maxSize = 1000000;
+
+       // NOTE(SB) Don't use innerHTML because it could be considered unsafe.
+       // https://github.com/chartjs/Chart.js/issues/5902
+       var resizer = createDiv(CSS_SIZE_MONITOR);
+       var expand = createDiv(CSS_SIZE_MONITOR + '-expand');
+       var shrink = createDiv(CSS_SIZE_MONITOR + '-shrink');
+
+       expand.appendChild(createDiv());
+       shrink.appendChild(createDiv());
+
+       resizer.appendChild(expand);
+       resizer.appendChild(shrink);
+       resizer._reset = function() {
+               expand.scrollLeft = maxSize;
+               expand.scrollTop = maxSize;
+               shrink.scrollLeft = maxSize;
+               shrink.scrollTop = maxSize;
+       };
+
+       var onScroll = function() {
+               resizer._reset();
+               handler();
+       };
+
+       addListener(expand, 'scroll', onScroll.bind(expand, 'expand'));
+       addListener(shrink, 'scroll', onScroll.bind(shrink, 'shrink'));
+
+       return resizer;
+}
+
+// https://davidwalsh.name/detect-node-insertion
+function watchForRender(node, handler) {
+       var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});
+       var proxy = expando.renderProxy = function(e) {
+               if (e.animationName === CSS_RENDER_ANIMATION) {
+                       handler();
+               }
+       };
+
+       helpers$1.each(ANIMATION_START_EVENTS, function(type) {
+               addListener(node, type, proxy);
+       });
+
+       // #4737: Chrome might skip the CSS animation when the CSS_RENDER_MONITOR class
+       // is removed then added back immediately (same animation frame?). Accessing the
+       // `offsetParent` property will force a reflow and re-evaluate the CSS animation.
+       // https://gist.github.com/paulirish/5d52fb081b3570c81e3a#box-metrics
+       // https://github.com/chartjs/Chart.js/issues/4737
+       expando.reflow = !!node.offsetParent;
+
+       node.classList.add(CSS_RENDER_MONITOR);
+}
+
+function unwatchForRender(node) {
+       var expando = node[EXPANDO_KEY] || {};
+       var proxy = expando.renderProxy;
+
+       if (proxy) {
+               helpers$1.each(ANIMATION_START_EVENTS, function(type) {
+                       removeListener(node, type, proxy);
+               });
+
+               delete expando.renderProxy;
+       }
+
+       node.classList.remove(CSS_RENDER_MONITOR);
+}
+
+function addResizeListener(node, listener, chart) {
+       var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});
+
+       // Let's keep track of this added resizer and thus avoid DOM query when removing it.
+       var resizer = expando.resizer = createResizer(throttled(function() {
+               if (expando.resizer) {
+                       var container = chart.options.maintainAspectRatio && node.parentNode;
+                       var w = container ? container.clientWidth : 0;
+                       listener(createEvent('resize', chart));
+                       if (container && container.clientWidth < w && chart.canvas) {
+                               // If the container size shrank during chart resize, let's assume
+                               // scrollbar appeared. So we resize again with the scrollbar visible -
+                               // effectively making chart smaller and the scrollbar hidden again.
+                               // Because we are inside `throttled`, and currently `ticking`, scroll
+                               // events are ignored during this whole 2 resize process.
+                               // If we assumed wrong and something else happened, we are resizing
+                               // twice in a frame (potential performance issue)
+                               listener(createEvent('resize', chart));
+                       }
+               }
+       }));
+
+       // The resizer needs to be attached to the node parent, so we first need to be
+       // sure that `node` is attached to the DOM before injecting the resizer element.
+       watchForRender(node, function() {
+               if (expando.resizer) {
+                       var container = node.parentNode;
+                       if (container && container !== resizer.parentNode) {
+                               container.insertBefore(resizer, container.firstChild);
+                       }
+
+                       // The container size might have changed, let's reset the resizer state.
+                       resizer._reset();
+               }
+       });
+}
+
+function removeResizeListener(node) {
+       var expando = node[EXPANDO_KEY] || {};
+       var resizer = expando.resizer;
+
+       delete expando.resizer;
+       unwatchForRender(node);
+
+       if (resizer && resizer.parentNode) {
+               resizer.parentNode.removeChild(resizer);
+       }
+}
+
+function injectCSS(platform, css) {
+       // https://stackoverflow.com/q/3922139
+       var style = platform._style || document.createElement('style');
+       if (!platform._style) {
+               platform._style = style;
+               css = '/* Chart.js */\n' + css;
+               style.setAttribute('type', 'text/css');
+               document.getElementsByTagName('head')[0].appendChild(style);
+       }
+
+       style.appendChild(document.createTextNode(css));
+}
+
+var platform_dom$2 = {
+       /**
+        * When `true`, prevents the automatic injection of the stylesheet required to
+        * correctly detect when the chart is added to the DOM and then resized. This
+        * switch has been added to allow external stylesheet (`dist/Chart(.min)?.js`)
+        * to be manually imported to make this library compatible with any CSP.
+        * See https://github.com/chartjs/Chart.js/issues/5208
+        */
+       disableCSSInjection: false,
+
+       /**
+        * This property holds whether this platform is enabled for the current environment.
+        * Currently used by platform.js to select the proper implementation.
+        * @private
+        */
+       _enabled: typeof window !== 'undefined' && typeof document !== 'undefined',
+
+       /**
+        * @private
+        */
+       _ensureLoaded: function() {
+               if (this._loaded) {
+                       return;
+               }
+
+               this._loaded = true;
+
+               // https://github.com/chartjs/Chart.js/issues/5208
+               if (!this.disableCSSInjection) {
+                       injectCSS(this, stylesheet);
+               }
+       },
+
+       acquireContext: function(item, config) {
+               if (typeof item === 'string') {
+                       item = document.getElementById(item);
+               } else if (item.length) {
+                       // Support for array based queries (such as jQuery)
+                       item = item[0];
+               }
+
+               if (item && item.canvas) {
+                       // Support for any object associated to a canvas (including a context2d)
+                       item = item.canvas;
+               }
+
+               // To prevent canvas fingerprinting, some add-ons undefine the getContext
+               // method, for example: https://github.com/kkapsner/CanvasBlocker
+               // https://github.com/chartjs/Chart.js/issues/2807
+               var context = item && item.getContext && item.getContext('2d');
+
+               // Load platform resources on first chart creation, to make possible to change
+               // platform options after importing the library (e.g. `disableCSSInjection`).
+               this._ensureLoaded();
+
+               // `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
+               // inside an iframe or when running in a protected environment. We could guess the
+               // types from their toString() value but let's keep things flexible and assume it's
+               // a sufficient condition if the item has a context2D which has item as `canvas`.
+               // https://github.com/chartjs/Chart.js/issues/3887
+               // https://github.com/chartjs/Chart.js/issues/4102
+               // https://github.com/chartjs/Chart.js/issues/4152
+               if (context && context.canvas === item) {
+                       initCanvas(item, config);
+                       return context;
+               }
+
+               return null;
+       },
+
+       releaseContext: function(context) {
+               var canvas = context.canvas;
+               if (!canvas[EXPANDO_KEY]) {
+                       return;
+               }
+
+               var initial = canvas[EXPANDO_KEY].initial;
+               ['height', 'width'].forEach(function(prop) {
+                       var value = initial[prop];
+                       if (helpers$1.isNullOrUndef(value)) {
+                               canvas.removeAttribute(prop);
+                       } else {
+                               canvas.setAttribute(prop, value);
+                       }
+               });
+
+               helpers$1.each(initial.style || {}, function(value, key) {
+                       canvas.style[key] = value;
+               });
+
+               // The canvas render size might have been changed (and thus the state stack discarded),
+               // we can't use save() and restore() to restore the initial state. So make sure that at
+               // least the canvas context is reset to the default state by setting the canvas width.
+               // https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
+               // eslint-disable-next-line no-self-assign
+               canvas.width = canvas.width;
+
+               delete canvas[EXPANDO_KEY];
+       },
+
+       addEventListener: function(chart, type, listener) {
+               var canvas = chart.canvas;
+               if (type === 'resize') {
+                       // Note: the resize event is not supported on all browsers.
+                       addResizeListener(canvas, listener, chart);
+                       return;
+               }
+
+               var expando = listener[EXPANDO_KEY] || (listener[EXPANDO_KEY] = {});
+               var proxies = expando.proxies || (expando.proxies = {});
+               var proxy = proxies[chart.id + '_' + type] = function(event) {
+                       listener(fromNativeEvent(event, chart));
+               };
+
+               addListener(canvas, type, proxy);
+       },
+
+       removeEventListener: function(chart, type, listener) {
+               var canvas = chart.canvas;
+               if (type === 'resize') {
+                       // Note: the resize event is not supported on all browsers.
+                       removeResizeListener(canvas);
+                       return;
+               }
+
+               var expando = listener[EXPANDO_KEY] || {};
+               var proxies = expando.proxies || {};
+               var proxy = proxies[chart.id + '_' + type];
+               if (!proxy) {
+                       return;
+               }
+
+               removeListener(canvas, type, proxy);
+       }
+};
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, use EventTarget.addEventListener instead.
+ * EventTarget.addEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
+ * @function Chart.helpers.addEvent
+ * @deprecated since version 2.7.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers$1.addEvent = addListener;
+
+/**
+ * Provided for backward compatibility, use EventTarget.removeEventListener instead.
+ * EventTarget.removeEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
+ * @function Chart.helpers.removeEvent
+ * @deprecated since version 2.7.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers$1.removeEvent = removeListener;
+
+// @TODO Make possible to select another platform at build time.
+var implementation = platform_dom$2._enabled ? platform_dom$2 : platform_basic;
+
+/**
+ * @namespace Chart.platform
+ * @see https://chartjs.gitbooks.io/proposals/content/Platform.html
+ * @since 2.4.0
+ */
+var platform = helpers$1.extend({
+       /**
+        * @since 2.7.0
+        */
+       initialize: function() {},
+
+       /**
+        * Called at chart construction time, returns a context2d instance implementing
+        * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
+        * @param {*} item - The native item from which to acquire context (platform specific)
+        * @param {object} options - The chart options
+        * @returns {CanvasRenderingContext2D} context2d instance
+        */
+       acquireContext: function() {},
+
+       /**
+        * Called at chart destruction time, releases any resources associated to the context
+        * previously returned by the acquireContext() method.
+        * @param {CanvasRenderingContext2D} context - The context2d instance
+        * @returns {boolean} true if the method succeeded, else false
+        */
+       releaseContext: function() {},
+
+       /**
+        * Registers the specified listener on the given chart.
+        * @param {Chart} chart - Chart from which to listen for event
+        * @param {string} type - The ({@link IEvent}) type to listen for
+        * @param {function} listener - Receives a notification (an object that implements
+        * the {@link IEvent} interface) when an event of the specified type occurs.
+        */
+       addEventListener: function() {},
+
+       /**
+        * Removes the specified listener previously registered with addEventListener.
+        * @param {Chart} chart - Chart from which to remove the listener
+        * @param {string} type - The ({@link IEvent}) type to remove
+        * @param {function} listener - The listener function to remove from the event target.
+        */
+       removeEventListener: function() {}
+
+}, implementation);
+
+core_defaults._set('global', {
+       plugins: {}
+});
+
+/**
+ * The plugin service singleton
+ * @namespace Chart.plugins
+ * @since 2.1.0
+ */
+var core_plugins = {
+       /**
+        * Globally registered plugins.
+        * @private
+        */
+       _plugins: [],
+
+       /**
+        * This identifier is used to invalidate the descriptors cache attached to each chart
+        * when a global plugin is registered or unregistered. In this case, the cache ID is
+        * incremented and descriptors are regenerated during following API calls.
+        * @private
+        */
+       _cacheId: 0,
+
+       /**
+        * Registers the given plugin(s) if not already registered.
+        * @param {IPlugin[]|IPlugin} plugins plugin instance(s).
+        */
+       register: function(plugins) {
+               var p = this._plugins;
+               ([]).concat(plugins).forEach(function(plugin) {
+                       if (p.indexOf(plugin) === -1) {
+                               p.push(plugin);
+                       }
+               });
+
+               this._cacheId++;
+       },
+
+       /**
+        * Unregisters the given plugin(s) only if registered.
+        * @param {IPlugin[]|IPlugin} plugins plugin instance(s).
+        */
+       unregister: function(plugins) {
+               var p = this._plugins;
+               ([]).concat(plugins).forEach(function(plugin) {
+                       var idx = p.indexOf(plugin);
+                       if (idx !== -1) {
+                               p.splice(idx, 1);
+                       }
+               });
+
+               this._cacheId++;
+       },
+
+       /**
+        * Remove all registered plugins.
+        * @since 2.1.5
+        */
+       clear: function() {
+               this._plugins = [];
+               this._cacheId++;
+       },
+
+       /**
+        * Returns the number of registered plugins?
+        * @returns {number}
+        * @since 2.1.5
+        */
+       count: function() {
+               return this._plugins.length;
+       },
+
+       /**
+        * Returns all registered plugin instances.
+        * @returns {IPlugin[]} array of plugin objects.
+        * @since 2.1.5
+        */
+       getAll: function() {
+               return this._plugins;
+       },
+
+       /**
+        * Calls enabled plugins for `chart` on the specified hook and with the given args.
+        * This method immediately returns as soon as a plugin explicitly returns false. The
+        * returned value can be used, for instance, to interrupt the current action.
+        * @param {Chart} chart - The chart instance for which plugins should be called.
+        * @param {string} hook - The name of the plugin method to call (e.g. 'beforeUpdate').
+        * @param {Array} [args] - Extra arguments to apply to the hook call.
+        * @returns {boolean} false if any of the plugins return false, else returns true.
+        */
+       notify: function(chart, hook, args) {
+               var descriptors = this.descriptors(chart);
+               var ilen = descriptors.length;
+               var i, descriptor, plugin, params, method;
+
+               for (i = 0; i < ilen; ++i) {
+                       descriptor = descriptors[i];
+                       plugin = descriptor.plugin;
+                       method = plugin[hook];
+                       if (typeof method === 'function') {
+                               params = [chart].concat(args || []);
+                               params.push(descriptor.options);
+                               if (method.apply(plugin, params) === false) {
+                                       return false;
+                               }
+                       }
+               }
+
+               return true;
+       },
+
+       /**
+        * Returns descriptors of enabled plugins for the given chart.
+        * @returns {object[]} [{ plugin, options }]
+        * @private
+        */
+       descriptors: function(chart) {
+               var cache = chart.$plugins || (chart.$plugins = {});
+               if (cache.id === this._cacheId) {
+                       return cache.descriptors;
+               }
+
+               var plugins = [];
+               var descriptors = [];
+               var config = (chart && chart.config) || {};
+               var options = (config.options && config.options.plugins) || {};
+
+               this._plugins.concat(config.plugins || []).forEach(function(plugin) {
+                       var idx = plugins.indexOf(plugin);
+                       if (idx !== -1) {
+                               return;
+                       }
+
+                       var id = plugin.id;
+                       var opts = options[id];
+                       if (opts === false) {
+                               return;
+                       }
+
+                       if (opts === true) {
+                               opts = helpers$1.clone(core_defaults.global.plugins[id]);
+                       }
+
+                       plugins.push(plugin);
+                       descriptors.push({
+                               plugin: plugin,
+                               options: opts || {}
+                       });
+               });
+
+               cache.descriptors = descriptors;
+               cache.id = this._cacheId;
+               return descriptors;
+       },
+
+       /**
+        * Invalidates cache for the given chart: descriptors hold a reference on plugin option,
+        * but in some cases, this reference can be changed by the user when updating options.
+        * https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
+        * @private
+        */
+       _invalidate: function(chart) {
+               delete chart.$plugins;
+       }
+};
+
+var core_scaleService = {
+       // Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
+       // use the new chart options to grab the correct scale
+       constructors: {},
+       // Use a registration function so that we can move to an ES6 map when we no longer need to support
+       // old browsers
+
+       // Scale config defaults
+       defaults: {},
+       registerScaleType: function(type, scaleConstructor, scaleDefaults) {
+               this.constructors[type] = scaleConstructor;
+               this.defaults[type] = helpers$1.clone(scaleDefaults);
+       },
+       getScaleConstructor: function(type) {
+               return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
+       },
+       getScaleDefaults: function(type) {
+               // Return the scale defaults merged with the global settings so that we always use the latest ones
+               return this.defaults.hasOwnProperty(type) ? helpers$1.merge({}, [core_defaults.scale, this.defaults[type]]) : {};
+       },
+       updateScaleDefaults: function(type, additions) {
+               var me = this;
+               if (me.defaults.hasOwnProperty(type)) {
+                       me.defaults[type] = helpers$1.extend(me.defaults[type], additions);
+               }
+       },
+       addScalesToLayout: function(chart) {
+               // Adds each scale to the chart.boxes array to be sized accordingly
+               helpers$1.each(chart.scales, function(scale) {
+                       // Set ILayoutItem parameters for backwards compatibility
+                       scale.fullWidth = scale.options.fullWidth;
+                       scale.position = scale.options.position;
+                       scale.weight = scale.options.weight;
+                       core_layouts.addBox(chart, scale);
+               });
+       }
+};
+
+var valueOrDefault$7 = helpers$1.valueOrDefault;
+
+core_defaults._set('global', {
+       tooltips: {
+               enabled: true,
+               custom: null,
+               mode: 'nearest',
+               position: 'average',
+               intersect: true,
+               backgroundColor: 'rgba(0,0,0,0.8)',
+               titleFontStyle: 'bold',
+               titleSpacing: 2,
+               titleMarginBottom: 6,
+               titleFontColor: '#fff',
+               titleAlign: 'left',
+               bodySpacing: 2,
+               bodyFontColor: '#fff',
+               bodyAlign: 'left',
+               footerFontStyle: 'bold',
+               footerSpacing: 2,
+               footerMarginTop: 6,
+               footerFontColor: '#fff',
+               footerAlign: 'left',
+               yPadding: 6,
+               xPadding: 6,
+               caretPadding: 2,
+               caretSize: 5,
+               cornerRadius: 6,
+               multiKeyBackground: '#fff',
+               displayColors: true,
+               borderColor: 'rgba(0,0,0,0)',
+               borderWidth: 0,
+               callbacks: {
+                       // Args are: (tooltipItems, data)
+                       beforeTitle: helpers$1.noop,
+                       title: function(tooltipItems, data) {
+                               var title = '';
+                               var labels = data.labels;
+                               var labelCount = labels ? labels.length : 0;
+
+                               if (tooltipItems.length > 0) {
+                                       var item = tooltipItems[0];
+                                       if (item.label) {
+                                               title = item.label;
+                                       } else if (item.xLabel) {
+                                               title = item.xLabel;
+                                       } else if (labelCount > 0 && item.index < labelCount) {
+                                               title = labels[item.index];
+                                       }
+                               }
+
+                               return title;
+                       },
+                       afterTitle: helpers$1.noop,
+
+                       // Args are: (tooltipItems, data)
+                       beforeBody: helpers$1.noop,
+
+                       // Args are: (tooltipItem, data)
+                       beforeLabel: helpers$1.noop,
+                       label: function(tooltipItem, data) {
+                               var label = data.datasets[tooltipItem.datasetIndex].label || '';
+
+                               if (label) {
+                                       label += ': ';
+                               }
+                               if (!helpers$1.isNullOrUndef(tooltipItem.value)) {
+                                       label += tooltipItem.value;
+                               } else {
+                                       label += tooltipItem.yLabel;
+                               }
+                               return label;
+                       },
+                       labelColor: function(tooltipItem, chart) {
+                               var meta = chart.getDatasetMeta(tooltipItem.datasetIndex);
+                               var activeElement = meta.data[tooltipItem.index];
+                               var view = activeElement._view;
+                               return {
+                                       borderColor: view.borderColor,
+                                       backgroundColor: view.backgroundColor
+                               };
+                       },
+                       labelTextColor: function() {
+                               return this._options.bodyFontColor;
+                       },
+                       afterLabel: helpers$1.noop,
+
+                       // Args are: (tooltipItems, data)
+                       afterBody: helpers$1.noop,
+
+                       // Args are: (tooltipItems, data)
+                       beforeFooter: helpers$1.noop,
+                       footer: helpers$1.noop,
+                       afterFooter: helpers$1.noop
+               }
+       }
+});
+
+var positioners = {
+       /**
+        * Average mode places the tooltip at the average position of the elements shown
+        * @function Chart.Tooltip.positioners.average
+        * @param elements {ChartElement[]} the elements being displayed in the tooltip
+        * @returns {object} tooltip position
+        */
+       average: function(elements) {
+               if (!elements.length) {
+                       return false;
+               }
+
+               var i, len;
+               var x = 0;
+               var y = 0;
+               var count = 0;
+
+               for (i = 0, len = elements.length; i < len; ++i) {
+                       var el = elements[i];
+                       if (el && el.hasValue()) {
+                               var pos = el.tooltipPosition();
+                               x += pos.x;
+                               y += pos.y;
+                               ++count;
+                       }
+               }
+
+               return {
+                       x: x / count,
+                       y: y / count
+               };
+       },
+
+       /**
+        * Gets the tooltip position nearest of the item nearest to the event position
+        * @function Chart.Tooltip.positioners.nearest
+        * @param elements {Chart.Element[]} the tooltip elements
+        * @param eventPosition {object} the position of the event in canvas coordinates
+        * @returns {object} the tooltip position
+        */
+       nearest: function(elements, eventPosition) {
+               var x = eventPosition.x;
+               var y = eventPosition.y;
+               var minDistance = Number.POSITIVE_INFINITY;
+               var i, len, nearestElement;
+
+               for (i = 0, len = elements.length; i < len; ++i) {
+                       var el = elements[i];
+                       if (el && el.hasValue()) {
+                               var center = el.getCenterPoint();
+                               var d = helpers$1.distanceBetweenPoints(eventPosition, center);
+
+                               if (d < minDistance) {
+                                       minDistance = d;
+                                       nearestElement = el;
+                               }
+                       }
+               }
+
+               if (nearestElement) {
+                       var tp = nearestElement.tooltipPosition();
+                       x = tp.x;
+                       y = tp.y;
+               }
+
+               return {
+                       x: x,
+                       y: y
+               };
+       }
+};
+
+// Helper to push or concat based on if the 2nd parameter is an array or not
+function pushOrConcat(base, toPush) {
+       if (toPush) {
+               if (helpers$1.isArray(toPush)) {
+                       // base = base.concat(toPush);
+                       Array.prototype.push.apply(base, toPush);
+               } else {
+                       base.push(toPush);
+               }
+       }
+
+       return base;
+}
+
+/**
+ * Returns array of strings split by newline
+ * @param {string} value - The value to split by newline.
+ * @returns {string[]} value if newline present - Returned from String split() method
+ * @function
+ */
+function splitNewlines(str) {
+       if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) {
+               return str.split('\n');
+       }
+       return str;
+}
+
+
+/**
+ * Private helper to create a tooltip item model
+ * @param element - the chart element (point, arc, bar) to create the tooltip item for
+ * @return new tooltip item
+ */
+function createTooltipItem(element) {
+       var xScale = element._xScale;
+       var yScale = element._yScale || element._scale; // handle radar || polarArea charts
+       var index = element._index;
+       var datasetIndex = element._datasetIndex;
+       var controller = element._chart.getDatasetMeta(datasetIndex).controller;
+       var indexScale = controller._getIndexScale();
+       var valueScale = controller._getValueScale();
+
+       return {
+               xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '',
+               yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '',
+               label: indexScale ? '' + indexScale.getLabelForIndex(index, datasetIndex) : '',
+               value: valueScale ? '' + valueScale.getLabelForIndex(index, datasetIndex) : '',
+               index: index,
+               datasetIndex: datasetIndex,
+               x: element._model.x,
+               y: element._model.y
+       };
+}
+
+/**
+ * Helper to get the reset model for the tooltip
+ * @param tooltipOpts {object} the tooltip options
+ */
+function getBaseModel(tooltipOpts) {
+       var globalDefaults = core_defaults.global;
+
+       return {
+               // Positioning
+               xPadding: tooltipOpts.xPadding,
+               yPadding: tooltipOpts.yPadding,
+               xAlign: tooltipOpts.xAlign,
+               yAlign: tooltipOpts.yAlign,
+
+               // Body
+               bodyFontColor: tooltipOpts.bodyFontColor,
+               _bodyFontFamily: valueOrDefault$7(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
+               _bodyFontStyle: valueOrDefault$7(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
+               _bodyAlign: tooltipOpts.bodyAlign,
+               bodyFontSize: valueOrDefault$7(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
+               bodySpacing: tooltipOpts.bodySpacing,
+
+               // Title
+               titleFontColor: tooltipOpts.titleFontColor,
+               _titleFontFamily: valueOrDefault$7(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
+               _titleFontStyle: valueOrDefault$7(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
+               titleFontSize: valueOrDefault$7(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
+               _titleAlign: tooltipOpts.titleAlign,
+               titleSpacing: tooltipOpts.titleSpacing,
+               titleMarginBottom: tooltipOpts.titleMarginBottom,
+
+               // Footer
+               footerFontColor: tooltipOpts.footerFontColor,
+               _footerFontFamily: valueOrDefault$7(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
+               _footerFontStyle: valueOrDefault$7(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
+               footerFontSize: valueOrDefault$7(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize),
+               _footerAlign: tooltipOpts.footerAlign,
+               footerSpacing: tooltipOpts.footerSpacing,
+               footerMarginTop: tooltipOpts.footerMarginTop,
+
+               // Appearance
+               caretSize: tooltipOpts.caretSize,
+               cornerRadius: tooltipOpts.cornerRadius,
+               backgroundColor: tooltipOpts.backgroundColor,
+               opacity: 0,
+               legendColorBackground: tooltipOpts.multiKeyBackground,
+               displayColors: tooltipOpts.displayColors,
+               borderColor: tooltipOpts.borderColor,
+               borderWidth: tooltipOpts.borderWidth
+       };
+}
+
+/**
+ * Get the size of the tooltip
+ */
+function getTooltipSize(tooltip, model) {
+       var ctx = tooltip._chart.ctx;
+
+       var height = model.yPadding * 2; // Tooltip Padding
+       var width = 0;
+
+       // Count of all lines in the body
+       var body = model.body;
+       var combinedBodyLength = body.reduce(function(count, bodyItem) {
+               return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length;
+       }, 0);
+       combinedBodyLength += model.beforeBody.length + model.afterBody.length;
+
+       var titleLineCount = model.title.length;
+       var footerLineCount = model.footer.length;
+       var titleFontSize = model.titleFontSize;
+       var bodyFontSize = model.bodyFontSize;
+       var footerFontSize = model.footerFontSize;
+
+       height += titleLineCount * titleFontSize; // Title Lines
+       height += titleLineCount ? (titleLineCount - 1) * model.titleSpacing : 0; // Title Line Spacing
+       height += titleLineCount ? model.titleMarginBottom : 0; // Title's bottom Margin
+       height += combinedBodyLength * bodyFontSize; // Body Lines
+       height += combinedBodyLength ? (combinedBodyLength - 1) * model.bodySpacing : 0; // Body Line Spacing
+       height += footerLineCount ? model.footerMarginTop : 0; // Footer Margin
+       height += footerLineCount * (footerFontSize); // Footer Lines
+       height += footerLineCount ? (footerLineCount - 1) * model.footerSpacing : 0; // Footer Line Spacing
+
+       // Title width
+       var widthPadding = 0;
+       var maxLineWidth = function(line) {
+               width = Math.max(width, ctx.measureText(line).width + widthPadding);
+       };
+
+       ctx.font = helpers$1.fontString(titleFontSize, model._titleFontStyle, model._titleFontFamily);
+       helpers$1.each(model.title, maxLineWidth);
+
+       // Body width
+       ctx.font = helpers$1.fontString(bodyFontSize, model._bodyFontStyle, model._bodyFontFamily);
+       helpers$1.each(model.beforeBody.concat(model.afterBody), maxLineWidth);
+
+       // Body lines may include some extra width due to the color box
+       widthPadding = model.displayColors ? (bodyFontSize + 2) : 0;
+       helpers$1.each(body, function(bodyItem) {
+               helpers$1.each(bodyItem.before, maxLineWidth);
+               helpers$1.each(bodyItem.lines, maxLineWidth);
+               helpers$1.each(bodyItem.after, maxLineWidth);
+       });
+
+       // Reset back to 0
+       widthPadding = 0;
+
+       // Footer width
+       ctx.font = helpers$1.fontString(footerFontSize, model._footerFontStyle, model._footerFontFamily);
+       helpers$1.each(model.footer, maxLineWidth);
+
+       // Add padding
+       width += 2 * model.xPadding;
+
+       return {
+               width: width,
+               height: height
+       };
+}
+
+/**
+ * Helper to get the alignment of a tooltip given the size
+ */
+function determineAlignment(tooltip, size) {
+       var model = tooltip._model;
+       var chart = tooltip._chart;
+       var chartArea = tooltip._chart.chartArea;
+       var xAlign = 'center';
+       var yAlign = 'center';
+
+       if (model.y < size.height) {
+               yAlign = 'top';
+       } else if (model.y > (chart.height - size.height)) {
+               yAlign = 'bottom';
+       }
+
+       var lf, rf; // functions to determine left, right alignment
+       var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart
+       var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges
+       var midX = (chartArea.left + chartArea.right) / 2;
+       var midY = (chartArea.top + chartArea.bottom) / 2;
+
+       if (yAlign === 'center') {
+               lf = function(x) {
+                       return x <= midX;
+               };
+               rf = function(x) {
+                       return x > midX;
+               };
+       } else {
+               lf = function(x) {
+                       return x <= (size.width / 2);
+               };
+               rf = function(x) {
+                       return x >= (chart.width - (size.width / 2));
+               };
+       }
+
+       olf = function(x) {
+               return x + size.width + model.caretSize + model.caretPadding > chart.width;
+       };
+       orf = function(x) {
+               return x - size.width - model.caretSize - model.caretPadding < 0;
+       };
+       yf = function(y) {
+               return y <= midY ? 'top' : 'bottom';
+       };
+
+       if (lf(model.x)) {
+               xAlign = 'left';
+
+               // Is tooltip too wide and goes over the right side of the chart.?
+               if (olf(model.x)) {
+                       xAlign = 'center';
+                       yAlign = yf(model.y);
+               }
+       } else if (rf(model.x)) {
+               xAlign = 'right';
+
+               // Is tooltip too wide and goes outside left edge of canvas?
+               if (orf(model.x)) {
+                       xAlign = 'center';
+                       yAlign = yf(model.y);
+               }
+       }
+
+       var opts = tooltip._options;
+       return {
+               xAlign: opts.xAlign ? opts.xAlign : xAlign,
+               yAlign: opts.yAlign ? opts.yAlign : yAlign
+       };
+}
+
+/**
+ * Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
+ */
+function getBackgroundPoint(vm, size, alignment, chart) {
+       // Background Position
+       var x = vm.x;
+       var y = vm.y;
+
+       var caretSize = vm.caretSize;
+       var caretPadding = vm.caretPadding;
+       var cornerRadius = vm.cornerRadius;
+       var xAlign = alignment.xAlign;
+       var yAlign = alignment.yAlign;
+       var paddingAndSize = caretSize + caretPadding;
+       var radiusAndPadding = cornerRadius + caretPadding;
+
+       if (xAlign === 'right') {
+               x -= size.width;
+       } else if (xAlign === 'center') {
+               x -= (size.width / 2);
+               if (x + size.width > chart.width) {
+                       x = chart.width - size.width;
+               }
+               if (x < 0) {
+                       x = 0;
+               }
+       }
+
+       if (yAlign === 'top') {
+               y += paddingAndSize;
+       } else if (yAlign === 'bottom') {
+               y -= size.height + paddingAndSize;
+       } else {
+               y -= (size.height / 2);
+       }
+
+       if (yAlign === 'center') {
+               if (xAlign === 'left') {
+                       x += paddingAndSize;
+               } else if (xAlign === 'right') {
+                       x -= paddingAndSize;
+               }
+       } else if (xAlign === 'left') {
+               x -= radiusAndPadding;
+       } else if (xAlign === 'right') {
+               x += radiusAndPadding;
+       }
+
+       return {
+               x: x,
+               y: y
+       };
+}
+
+function getAlignedX(vm, align) {
+       return align === 'center'
+               ? vm.x + vm.width / 2
+               : align === 'right'
+                       ? vm.x + vm.width - vm.xPadding
+                       : vm.x + vm.xPadding;
+}
+
+/**
+ * Helper to build before and after body lines
+ */
+function getBeforeAfterBodyLines(callback) {
+       return pushOrConcat([], splitNewlines(callback));
+}
+
+var exports$3 = core_element.extend({
+       initialize: function() {
+               this._model = getBaseModel(this._options);
+               this._lastActive = [];
+       },
+
+       // Get the title
+       // Args are: (tooltipItem, data)
+       getTitle: function() {
+               var me = this;
+               var opts = me._options;
+               var callbacks = opts.callbacks;
+
+               var beforeTitle = callbacks.beforeTitle.apply(me, arguments);
+               var title = callbacks.title.apply(me, arguments);
+               var afterTitle = callbacks.afterTitle.apply(me, arguments);
+
+               var lines = [];
+               lines = pushOrConcat(lines, splitNewlines(beforeTitle));
+               lines = pushOrConcat(lines, splitNewlines(title));
+               lines = pushOrConcat(lines, splitNewlines(afterTitle));
+
+               return lines;
+       },
+
+       // Args are: (tooltipItem, data)
+       getBeforeBody: function() {
+               return getBeforeAfterBodyLines(this._options.callbacks.beforeBody.apply(this, arguments));
+       },
+
+       // Args are: (tooltipItem, data)
+       getBody: function(tooltipItems, data) {
+               var me = this;
+               var callbacks = me._options.callbacks;
+               var bodyItems = [];
+
+               helpers$1.each(tooltipItems, function(tooltipItem) {
+                       var bodyItem = {
+                               before: [],
+                               lines: [],
+                               after: []
+                       };
+                       pushOrConcat(bodyItem.before, splitNewlines(callbacks.beforeLabel.call(me, tooltipItem, data)));
+                       pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data));
+                       pushOrConcat(bodyItem.after, splitNewlines(callbacks.afterLabel.call(me, tooltipItem, data)));
+
+                       bodyItems.push(bodyItem);
+               });
+
+               return bodyItems;
+       },
+
+       // Args are: (tooltipItem, data)
+       getAfterBody: function() {
+               return getBeforeAfterBodyLines(this._options.callbacks.afterBody.apply(this, arguments));
+       },
+
+       // Get the footer and beforeFooter and afterFooter lines
+       // Args are: (tooltipItem, data)
+       getFooter: function() {
+               var me = this;
+               var callbacks = me._options.callbacks;
+
+               var beforeFooter = callbacks.beforeFooter.apply(me, arguments);
+               var footer = callbacks.footer.apply(me, arguments);
+               var afterFooter = callbacks.afterFooter.apply(me, arguments);
+
+               var lines = [];
+               lines = pushOrConcat(lines, splitNewlines(beforeFooter));
+               lines = pushOrConcat(lines, splitNewlines(footer));
+               lines = pushOrConcat(lines, splitNewlines(afterFooter));
+
+               return lines;
+       },
+
+       update: function(changed) {
+               var me = this;
+               var opts = me._options;
+
+               // Need to regenerate the model because its faster than using extend and it is necessary due to the optimization in Chart.Element.transition
+               // that does _view = _model if ease === 1. This causes the 2nd tooltip update to set properties in both the view and model at the same time
+               // which breaks any animations.
+               var existingModel = me._model;
+               var model = me._model = getBaseModel(opts);
+               var active = me._active;
+
+               var data = me._data;
+
+               // In the case where active.length === 0 we need to keep these at existing values for good animations
+               var alignment = {
+                       xAlign: existingModel.xAlign,
+                       yAlign: existingModel.yAlign
+               };
+               var backgroundPoint = {
+                       x: existingModel.x,
+                       y: existingModel.y
+               };
+               var tooltipSize = {
+                       width: existingModel.width,
+                       height: existingModel.height
+               };
+               var tooltipPosition = {
+                       x: existingModel.caretX,
+                       y: existingModel.caretY
+               };
+
+               var i, len;
+
+               if (active.length) {
+                       model.opacity = 1;
+
+                       var labelColors = [];
+                       var labelTextColors = [];
+                       tooltipPosition = positioners[opts.position].call(me, active, me._eventPosition);
+
+                       var tooltipItems = [];
+                       for (i = 0, len = active.length; i < len; ++i) {
+                               tooltipItems.push(createTooltipItem(active[i]));
+                       }
+
+                       // If the user provided a filter function, use it to modify the tooltip items
+                       if (opts.filter) {
+                               tooltipItems = tooltipItems.filter(function(a) {
+                                       return opts.filter(a, data);
+                               });
+                       }
+
+                       // If the user provided a sorting function, use it to modify the tooltip items
+                       if (opts.itemSort) {
+                               tooltipItems = tooltipItems.sort(function(a, b) {
+                                       return opts.itemSort(a, b, data);
+                               });
+                       }
+
+                       // Determine colors for boxes
+                       helpers$1.each(tooltipItems, function(tooltipItem) {
+                               labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, me._chart));
+                               labelTextColors.push(opts.callbacks.labelTextColor.call(me, tooltipItem, me._chart));
+                       });
+
+
+                       // Build the Text Lines
+                       model.title = me.getTitle(tooltipItems, data);
+                       model.beforeBody = me.getBeforeBody(tooltipItems, data);
+                       model.body = me.getBody(tooltipItems, data);
+                       model.afterBody = me.getAfterBody(tooltipItems, data);
+                       model.footer = me.getFooter(tooltipItems, data);
+
+                       // Initial positioning and colors
+                       model.x = tooltipPosition.x;
+                       model.y = tooltipPosition.y;
+                       model.caretPadding = opts.caretPadding;
+                       model.labelColors = labelColors;
+                       model.labelTextColors = labelTextColors;
+
+                       // data points
+                       model.dataPoints = tooltipItems;
+
+                       // We need to determine alignment of the tooltip
+                       tooltipSize = getTooltipSize(this, model);
+                       alignment = determineAlignment(this, tooltipSize);
+                       // Final Size and Position
+                       backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment, me._chart);
+               } else {
+                       model.opacity = 0;
+               }
+
+               model.xAlign = alignment.xAlign;
+               model.yAlign = alignment.yAlign;
+               model.x = backgroundPoint.x;
+               model.y = backgroundPoint.y;
+               model.width = tooltipSize.width;
+               model.height = tooltipSize.height;
+
+               // Point where the caret on the tooltip points to
+               model.caretX = tooltipPosition.x;
+               model.caretY = tooltipPosition.y;
+
+               me._model = model;
+
+               if (changed && opts.custom) {
+                       opts.custom.call(me, model);
+               }
+
+               return me;
+       },
+
+       drawCaret: function(tooltipPoint, size) {
+               var ctx = this._chart.ctx;
+               var vm = this._view;
+               var caretPosition = this.getCaretPosition(tooltipPoint, size, vm);
+
+               ctx.lineTo(caretPosition.x1, caretPosition.y1);
+               ctx.lineTo(caretPosition.x2, caretPosition.y2);
+               ctx.lineTo(caretPosition.x3, caretPosition.y3);
+       },
+       getCaretPosition: function(tooltipPoint, size, vm) {
+               var x1, x2, x3, y1, y2, y3;
+               var caretSize = vm.caretSize;
+               var cornerRadius = vm.cornerRadius;
+               var xAlign = vm.xAlign;
+               var yAlign = vm.yAlign;
+               var ptX = tooltipPoint.x;
+               var ptY = tooltipPoint.y;
+               var width = size.width;
+               var height = size.height;
+
+               if (yAlign === 'center') {
+                       y2 = ptY + (height / 2);
+
+                       if (xAlign === 'left') {
+                               x1 = ptX;
+                               x2 = x1 - caretSize;
+                               x3 = x1;
+
+                               y1 = y2 + caretSize;
+                               y3 = y2 - caretSize;
+                       } else {
+                               x1 = ptX + width;
+                               x2 = x1 + caretSize;
+                               x3 = x1;
+
+                               y1 = y2 - caretSize;
+                               y3 = y2 + caretSize;
+                       }
+               } else {
+                       if (xAlign === 'left') {
+                               x2 = ptX + cornerRadius + (caretSize);
+                               x1 = x2 - caretSize;
+                               x3 = x2 + caretSize;
+                       } else if (xAlign === 'right') {
+                               x2 = ptX + width - cornerRadius - caretSize;
+                               x1 = x2 - caretSize;
+                               x3 = x2 + caretSize;
+                       } else {
+                               x2 = vm.caretX;
+                               x1 = x2 - caretSize;
+                               x3 = x2 + caretSize;
+                       }
+                       if (yAlign === 'top') {
+                               y1 = ptY;
+                               y2 = y1 - caretSize;
+                               y3 = y1;
+                       } else {
+                               y1 = ptY + height;
+                               y2 = y1 + caretSize;
+                               y3 = y1;
+                               // invert drawing order
+                               var tmp = x3;
+                               x3 = x1;
+                               x1 = tmp;
+                       }
+               }
+               return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3};
+       },
+
+       drawTitle: function(pt, vm, ctx) {
+               var title = vm.title;
+
+               if (title.length) {
+                       pt.x = getAlignedX(vm, vm._titleAlign);
+
+                       ctx.textAlign = vm._titleAlign;
+                       ctx.textBaseline = 'top';
+
+                       var titleFontSize = vm.titleFontSize;
+                       var titleSpacing = vm.titleSpacing;
+
+                       ctx.fillStyle = vm.titleFontColor;
+                       ctx.font = helpers$1.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
+
+                       var i, len;
+                       for (i = 0, len = title.length; i < len; ++i) {
+                               ctx.fillText(title[i], pt.x, pt.y);
+                               pt.y += titleFontSize + titleSpacing; // Line Height and spacing
+
+                               if (i + 1 === title.length) {
+                                       pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing
+                               }
+                       }
+               }
+       },
+
+       drawBody: function(pt, vm, ctx) {
+               var bodyFontSize = vm.bodyFontSize;
+               var bodySpacing = vm.bodySpacing;
+               var bodyAlign = vm._bodyAlign;
+               var body = vm.body;
+               var drawColorBoxes = vm.displayColors;
+               var labelColors = vm.labelColors;
+               var xLinePadding = 0;
+               var colorX = drawColorBoxes ? getAlignedX(vm, 'left') : 0;
+               var textColor;
+
+               ctx.textAlign = bodyAlign;
+               ctx.textBaseline = 'top';
+               ctx.font = helpers$1.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
+
+               pt.x = getAlignedX(vm, bodyAlign);
+
+               // Before Body
+               var fillLineOfText = function(line) {
+                       ctx.fillText(line, pt.x + xLinePadding, pt.y);
+                       pt.y += bodyFontSize + bodySpacing;
+               };
+
+               // Before body lines
+               ctx.fillStyle = vm.bodyFontColor;
+               helpers$1.each(vm.beforeBody, fillLineOfText);
+
+               xLinePadding = drawColorBoxes && bodyAlign !== 'right'
+                       ? bodyAlign === 'center' ? (bodyFontSize / 2 + 1) : (bodyFontSize + 2)
+                       : 0;
+
+               // Draw body lines now
+               helpers$1.each(body, function(bodyItem, i) {
+                       textColor = vm.labelTextColors[i];
+                       ctx.fillStyle = textColor;
+                       helpers$1.each(bodyItem.before, fillLineOfText);
+
+                       helpers$1.each(bodyItem.lines, function(line) {
+                               // Draw Legend-like boxes if needed
+                               if (drawColorBoxes) {
+                                       // Fill a white rect so that colours merge nicely if the opacity is < 1
+                                       ctx.fillStyle = vm.legendColorBackground;
+                                       ctx.fillRect(colorX, pt.y, bodyFontSize, bodyFontSize);
+
+                                       // Border
+                                       ctx.lineWidth = 1;
+                                       ctx.strokeStyle = labelColors[i].borderColor;
+                                       ctx.strokeRect(colorX, pt.y, bodyFontSize, bodyFontSize);
+
+                                       // Inner square
+                                       ctx.fillStyle = labelColors[i].backgroundColor;
+                                       ctx.fillRect(colorX + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
+                                       ctx.fillStyle = textColor;
+                               }
+
+                               fillLineOfText(line);
+                       });
+
+                       helpers$1.each(bodyItem.after, fillLineOfText);
+               });
+
+               // Reset back to 0 for after body
+               xLinePadding = 0;
+
+               // After body lines
+               helpers$1.each(vm.afterBody, fillLineOfText);
+               pt.y -= bodySpacing; // Remove last body spacing
+       },
+
+       drawFooter: function(pt, vm, ctx) {
+               var footer = vm.footer;
+
+               if (footer.length) {
+                       pt.x = getAlignedX(vm, vm._footerAlign);
+                       pt.y += vm.footerMarginTop;
+
+                       ctx.textAlign = vm._footerAlign;
+                       ctx.textBaseline = 'top';
+
+                       ctx.fillStyle = vm.footerFontColor;
+                       ctx.font = helpers$1.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
+
+                       helpers$1.each(footer, function(line) {
+                               ctx.fillText(line, pt.x, pt.y);
+                               pt.y += vm.footerFontSize + vm.footerSpacing;
+                       });
+               }
+       },
+
+       drawBackground: function(pt, vm, ctx, tooltipSize) {
+               ctx.fillStyle = vm.backgroundColor;
+               ctx.strokeStyle = vm.borderColor;
+               ctx.lineWidth = vm.borderWidth;
+               var xAlign = vm.xAlign;
+               var yAlign = vm.yAlign;
+               var x = pt.x;
+               var y = pt.y;
+               var width = tooltipSize.width;
+               var height = tooltipSize.height;
+               var radius = vm.cornerRadius;
+
+               ctx.beginPath();
+               ctx.moveTo(x + radius, y);
+               if (yAlign === 'top') {
+                       this.drawCaret(pt, tooltipSize);
+               }
+               ctx.lineTo(x + width - radius, y);
+               ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
+               if (yAlign === 'center' && xAlign === 'right') {
+                       this.drawCaret(pt, tooltipSize);
+               }
+               ctx.lineTo(x + width, y + height - radius);
+               ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
+               if (yAlign === 'bottom') {
+                       this.drawCaret(pt, tooltipSize);
+               }
+               ctx.lineTo(x + radius, y + height);
+               ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
+               if (yAlign === 'center' && xAlign === 'left') {
+                       this.drawCaret(pt, tooltipSize);
+               }
+               ctx.lineTo(x, y + radius);
+               ctx.quadraticCurveTo(x, y, x + radius, y);
+               ctx.closePath();
+
+               ctx.fill();
+
+               if (vm.borderWidth > 0) {
+                       ctx.stroke();
+               }
+       },
+
+       draw: function() {
+               var ctx = this._chart.ctx;
+               var vm = this._view;
+
+               if (vm.opacity === 0) {
+                       return;
+               }
+
+               var tooltipSize = {
+                       width: vm.width,
+                       height: vm.height
+               };
+               var pt = {
+                       x: vm.x,
+                       y: vm.y
+               };
+
+               // IE11/Edge does not like very small opacities, so snap to 0
+               var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
+
+               // Truthy/falsey value for empty tooltip
+               var hasTooltipContent = vm.title.length || vm.beforeBody.length || vm.body.length || vm.afterBody.length || vm.footer.length;
+
+               if (this._options.enabled && hasTooltipContent) {
+                       ctx.save();
+                       ctx.globalAlpha = opacity;
+
+                       // Draw Background
+                       this.drawBackground(pt, vm, ctx, tooltipSize);
+
+                       // Draw Title, Body, and Footer
+                       pt.y += vm.yPadding;
+
+                       // Titles
+                       this.drawTitle(pt, vm, ctx);
+
+                       // Body
+                       this.drawBody(pt, vm, ctx);
+
+                       // Footer
+                       this.drawFooter(pt, vm, ctx);
+
+                       ctx.restore();
+               }
+       },
+
+       /**
+        * Handle an event
+        * @private
+        * @param {IEvent} event - The event to handle
+        * @returns {boolean} true if the tooltip changed
+        */
+       handleEvent: function(e) {
+               var me = this;
+               var options = me._options;
+               var changed = false;
+
+               me._lastActive = me._lastActive || [];
+
+               // Find Active Elements for tooltips
+               if (e.type === 'mouseout') {
+                       me._active = [];
+               } else {
+                       me._active = me._chart.getElementsAtEventForMode(e, options.mode, options);
+               }
+
+               // Remember Last Actives
+               changed = !helpers$1.arrayEquals(me._active, me._lastActive);
+
+               // Only handle target event on tooltip change
+               if (changed) {
+                       me._lastActive = me._active;
+
+                       if (options.enabled || options.custom) {
+                               me._eventPosition = {
+                                       x: e.x,
+                                       y: e.y
+                               };
+
+                               me.update(true);
+                               me.pivot();
+                       }
+               }
+
+               return changed;
+       }
+});
+
+/**
+ * @namespace Chart.Tooltip.positioners
+ */
+var positioners_1 = positioners;
+
+var core_tooltip = exports$3;
+core_tooltip.positioners = positioners_1;
+
+var valueOrDefault$8 = helpers$1.valueOrDefault;
+
+core_defaults._set('global', {
+       elements: {},
+       events: [
+               'mousemove',
+               'mouseout',
+               'click',
+               'touchstart',
+               'touchmove'
+       ],
+       hover: {
+               onHover: null,
+               mode: 'nearest',
+               intersect: true,
+               animationDuration: 400
+       },
+       onClick: null,
+       maintainAspectRatio: true,
+       responsive: true,
+       responsiveAnimationDuration: 0
+});
+
+/**
+ * Recursively merge the given config objects representing the `scales` option
+ * by incorporating scale defaults in `xAxes` and `yAxes` array items, then
+ * returns a deep copy of the result, thus doesn't alter inputs.
+ */
+function mergeScaleConfig(/* config objects ... */) {
+       return helpers$1.merge({}, [].slice.call(arguments), {
+               merger: function(key, target, source, options) {
+                       if (key === 'xAxes' || key === 'yAxes') {
+                               var slen = source[key].length;
+                               var i, type, scale;
+
+                               if (!target[key]) {
+                                       target[key] = [];
+                               }
+
+                               for (i = 0; i < slen; ++i) {
+                                       scale = source[key][i];
+                                       type = valueOrDefault$8(scale.type, key === 'xAxes' ? 'category' : 'linear');
+
+                                       if (i >= target[key].length) {
+                                               target[key].push({});
+                                       }
+
+                                       if (!target[key][i].type || (scale.type && scale.type !== target[key][i].type)) {
+                                               // new/untyped scale or type changed: let's apply the new defaults
+                                               // then merge source scale to correctly overwrite the defaults.
+                                               helpers$1.merge(target[key][i], [core_scaleService.getScaleDefaults(type), scale]);
+                                       } else {
+                                               // scales type are the same
+                                               helpers$1.merge(target[key][i], scale);
+                                       }
+                               }
+                       } else {
+                               helpers$1._merger(key, target, source, options);
+                       }
+               }
+       });
+}
+
+/**
+ * Recursively merge the given config objects as the root options by handling
+ * default scale options for the `scales` and `scale` properties, then returns
+ * a deep copy of the result, thus doesn't alter inputs.
+ */
+function mergeConfig(/* config objects ... */) {
+       return helpers$1.merge({}, [].slice.call(arguments), {
+               merger: function(key, target, source, options) {
+                       var tval = target[key] || {};
+                       var sval = source[key];
+
+                       if (key === 'scales') {
+                               // scale config merging is complex. Add our own function here for that
+                               target[key] = mergeScaleConfig(tval, sval);
+                       } else if (key === 'scale') {
+                               // used in polar area & radar charts since there is only one scale
+                               target[key] = helpers$1.merge(tval, [core_scaleService.getScaleDefaults(sval.type), sval]);
+                       } else {
+                               helpers$1._merger(key, target, source, options);
+                       }
+               }
+       });
+}
+
+function initConfig(config) {
+       config = config || {};
+
+       // Do NOT use mergeConfig for the data object because this method merges arrays
+       // and so would change references to labels and datasets, preventing data updates.
+       var data = config.data = config.data || {};
+       data.datasets = data.datasets || [];
+       data.labels = data.labels || [];
+
+       config.options = mergeConfig(
+               core_defaults.global,
+               core_defaults[config.type],
+               config.options || {});
+
+       return config;
+}
+
+function updateConfig(chart) {
+       var newOptions = chart.options;
+
+       helpers$1.each(chart.scales, function(scale) {
+               core_layouts.removeBox(chart, scale);
+       });
+
+       newOptions = mergeConfig(
+               core_defaults.global,
+               core_defaults[chart.config.type],
+               newOptions);
+
+       chart.options = chart.config.options = newOptions;
+       chart.ensureScalesHaveIDs();
+       chart.buildOrUpdateScales();
+
+       // Tooltip
+       chart.tooltip._options = newOptions.tooltips;
+       chart.tooltip.initialize();
+}
+
+function positionIsHorizontal(position) {
+       return position === 'top' || position === 'bottom';
+}
+
+var Chart = function(item, config) {
+       this.construct(item, config);
+       return this;
+};
+
+helpers$1.extend(Chart.prototype, /** @lends Chart */ {
+       /**
+        * @private
+        */
+       construct: function(item, config) {
+               var me = this;
+
+               config = initConfig(config);
+
+               var context = platform.acquireContext(item, config);
+               var canvas = context && context.canvas;
+               var height = canvas && canvas.height;
+               var width = canvas && canvas.width;
+
+               me.id = helpers$1.uid();
+               me.ctx = context;
+               me.canvas = canvas;
+               me.config = config;
+               me.width = width;
+               me.height = height;
+               me.aspectRatio = height ? width / height : null;
+               me.options = config.options;
+               me._bufferedRender = false;
+
+               /**
+                * Provided for backward compatibility, Chart and Chart.Controller have been merged,
+                * the "instance" still need to be defined since it might be called from plugins.
+                * @prop Chart#chart
+                * @deprecated since version 2.6.0
+                * @todo remove at version 3
+                * @private
+                */
+               me.chart = me;
+               me.controller = me; // chart.chart.controller #inception
+
+               // Add the chart instance to the global namespace
+               Chart.instances[me.id] = me;
+
+               // Define alias to the config data: `chart.data === chart.config.data`
+               Object.defineProperty(me, 'data', {
+                       get: function() {
+                               return me.config.data;
+                       },
+                       set: function(value) {
+                               me.config.data = value;
+                       }
+               });
+
+               if (!context || !canvas) {
+                       // The given item is not a compatible context2d element, let's return before finalizing
+                       // the chart initialization but after setting basic chart / controller properties that
+                       // can help to figure out that the chart is not valid (e.g chart.canvas !== null);
+                       // https://github.com/chartjs/Chart.js/issues/2807
+                       console.error("Failed to create chart: can't acquire context from the given item");
+                       return;
+               }
+
+               me.initialize();
+               me.update();
+       },
+
+       /**
+        * @private
+        */
+       initialize: function() {
+               var me = this;
+
+               // Before init plugin notification
+               core_plugins.notify(me, 'beforeInit');
+
+               helpers$1.retinaScale(me, me.options.devicePixelRatio);
+
+               me.bindEvents();
+
+               if (me.options.responsive) {
+                       // Initial resize before chart draws (must be silent to preserve initial animations).
+                       me.resize(true);
+               }
+
+               // Make sure scales have IDs and are built before we build any controllers.
+               me.ensureScalesHaveIDs();
+               me.buildOrUpdateScales();
+               me.initToolTip();
+
+               // After init plugin notification
+               core_plugins.notify(me, 'afterInit');
+
+               return me;
+       },
+
+       clear: function() {
+               helpers$1.canvas.clear(this);
+               return this;
+       },
+
+       stop: function() {
+               // Stops any current animation loop occurring
+               core_animations.cancelAnimation(this);
+               return this;
+       },
+
+       resize: function(silent) {
+               var me = this;
+               var options = me.options;
+               var canvas = me.canvas;
+               var aspectRatio = (options.maintainAspectRatio && me.aspectRatio) || null;
+
+               // the canvas render width and height will be casted to integers so make sure that
+               // the canvas display style uses the same integer values to avoid blurring effect.
+
+               // Set to 0 instead of canvas.size because the size defaults to 300x150 if the element is collapsed
+               var newWidth = Math.max(0, Math.floor(helpers$1.getMaximumWidth(canvas)));
+               var newHeight = Math.max(0, Math.floor(aspectRatio ? newWidth / aspectRatio : helpers$1.getMaximumHeight(canvas)));
+
+               if (me.width === newWidth && me.height === newHeight) {
+                       return;
+               }
+
+               canvas.width = me.width = newWidth;
+               canvas.height = me.height = newHeight;
+               canvas.style.width = newWidth + 'px';
+               canvas.style.height = newHeight + 'px';
+
+               helpers$1.retinaScale(me, options.devicePixelRatio);
+
+               if (!silent) {
+                       // Notify any plugins about the resize
+                       var newSize = {width: newWidth, height: newHeight};
+                       core_plugins.notify(me, 'resize', [newSize]);
+
+                       // Notify of resize
+                       if (options.onResize) {
+                               options.onResize(me, newSize);
+                       }
+
+                       me.stop();
+                       me.update({
+                               duration: options.responsiveAnimationDuration
+                       });
+               }
+       },
+
+       ensureScalesHaveIDs: function() {
+               var options = this.options;
+               var scalesOptions = options.scales || {};
+               var scaleOptions = options.scale;
+
+               helpers$1.each(scalesOptions.xAxes, function(xAxisOptions, index) {
+                       xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index);
+               });
+
+               helpers$1.each(scalesOptions.yAxes, function(yAxisOptions, index) {
+                       yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index);
+               });
+
+               if (scaleOptions) {
+                       scaleOptions.id = scaleOptions.id || 'scale';
+               }
+       },
+
+       /**
+        * Builds a map of scale ID to scale object for future lookup.
+        */
+       buildOrUpdateScales: function() {
+               var me = this;
+               var options = me.options;
+               var scales = me.scales || {};
+               var items = [];
+               var updated = Object.keys(scales).reduce(function(obj, id) {
+                       obj[id] = false;
+                       return obj;
+               }, {});
+
+               if (options.scales) {
+                       items = items.concat(
+                               (options.scales.xAxes || []).map(function(xAxisOptions) {
+                                       return {options: xAxisOptions, dtype: 'category', dposition: 'bottom'};
+                               }),
+                               (options.scales.yAxes || []).map(function(yAxisOptions) {
+                                       return {options: yAxisOptions, dtype: 'linear', dposition: 'left'};
+                               })
+                       );
+               }
+
+               if (options.scale) {
+                       items.push({
+                               options: options.scale,
+                               dtype: 'radialLinear',
+                               isDefault: true,
+                               dposition: 'chartArea'
+                       });
+               }
+
+               helpers$1.each(items, function(item) {
+                       var scaleOptions = item.options;
+                       var id = scaleOptions.id;
+                       var scaleType = valueOrDefault$8(scaleOptions.type, item.dtype);
+
+                       if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) {
+                               scaleOptions.position = item.dposition;
+                       }
+
+                       updated[id] = true;
+                       var scale = null;
+                       if (id in scales && scales[id].type === scaleType) {
+                               scale = scales[id];
+                               scale.options = scaleOptions;
+                               scale.ctx = me.ctx;
+                               scale.chart = me;
+                       } else {
+                               var scaleClass = core_scaleService.getScaleConstructor(scaleType);
+                               if (!scaleClass) {
+                                       return;
+                               }
+                               scale = new scaleClass({
+                                       id: id,
+                                       type: scaleType,
+                                       options: scaleOptions,
+                                       ctx: me.ctx,
+                                       chart: me
+                               });
+                               scales[scale.id] = scale;
+                       }
+
+                       scale.mergeTicksOptions();
+
+                       // TODO(SB): I think we should be able to remove this custom case (options.scale)
+                       // and consider it as a regular scale part of the "scales"" map only! This would
+                       // make the logic easier and remove some useless? custom code.
+                       if (item.isDefault) {
+                               me.scale = scale;
+                       }
+               });
+               // clear up discarded scales
+               helpers$1.each(updated, function(hasUpdated, id) {
+                       if (!hasUpdated) {
+                               delete scales[id];
+                       }
+               });
+
+               me.scales = scales;
+
+               core_scaleService.addScalesToLayout(this);
+       },
+
+       buildOrUpdateControllers: function() {
+               var me = this;
+               var newControllers = [];
+
+               helpers$1.each(me.data.datasets, function(dataset, datasetIndex) {
+                       var meta = me.getDatasetMeta(datasetIndex);
+                       var type = dataset.type || me.config.type;
+
+                       if (meta.type && meta.type !== type) {
+                               me.destroyDatasetMeta(datasetIndex);
+                               meta = me.getDatasetMeta(datasetIndex);
+                       }
+                       meta.type = type;
+
+                       if (meta.controller) {
+                               meta.controller.updateIndex(datasetIndex);
+                               meta.controller.linkScales();
+                       } else {
+                               var ControllerClass = controllers[meta.type];
+                               if (ControllerClass === undefined) {
+                                       throw new Error('"' + meta.type + '" is not a chart type.');
+                               }
+
+                               meta.controller = new ControllerClass(me, datasetIndex);
+                               newControllers.push(meta.controller);
+                       }
+               }, me);
+
+               return newControllers;
+       },
+
+       /**
+        * Reset the elements of all datasets
+        * @private
+        */
+       resetElements: function() {
+               var me = this;
+               helpers$1.each(me.data.datasets, function(dataset, datasetIndex) {
+                       me.getDatasetMeta(datasetIndex).controller.reset();
+               }, me);
+       },
+
+       /**
+       * Resets the chart back to it's state before the initial animation
+       */
+       reset: function() {
+               this.resetElements();
+               this.tooltip.initialize();
+       },
+
+       update: function(config) {
+               var me = this;
+
+               if (!config || typeof config !== 'object') {
+                       // backwards compatibility
+                       config = {
+                               duration: config,
+                               lazy: arguments[1]
+                       };
+               }
+
+               updateConfig(me);
+
+               // plugins options references might have change, let's invalidate the cache
+               // https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
+               core_plugins._invalidate(me);
+
+               if (core_plugins.notify(me, 'beforeUpdate') === false) {
+                       return;
+               }
+
+               // In case the entire data object changed
+               me.tooltip._data = me.data;
+
+               // Make sure dataset controllers are updated and new controllers are reset
+               var newControllers = me.buildOrUpdateControllers();
+
+               // Make sure all dataset controllers have correct meta data counts
+               helpers$1.each(me.data.datasets, function(dataset, datasetIndex) {
+                       me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements();
+               }, me);
+
+               me.updateLayout();
+
+               // Can only reset the new controllers after the scales have been updated
+               if (me.options.animation && me.options.animation.duration) {
+                       helpers$1.each(newControllers, function(controller) {
+                               controller.reset();
+                       });
+               }
+
+               me.updateDatasets();
+
+               // Need to reset tooltip in case it is displayed with elements that are removed
+               // after update.
+               me.tooltip.initialize();
+
+               // Last active contains items that were previously in the tooltip.
+               // When we reset the tooltip, we need to clear it
+               me.lastActive = [];
+
+               // Do this before render so that any plugins that need final scale updates can use it
+               core_plugins.notify(me, 'afterUpdate');
+
+               if (me._bufferedRender) {
+                       me._bufferedRequest = {
+                               duration: config.duration,
+                               easing: config.easing,
+                               lazy: config.lazy
+                       };
+               } else {
+                       me.render(config);
+               }
+       },
+
+       /**
+        * Updates the chart layout unless a plugin returns `false` to the `beforeLayout`
+        * hook, in which case, plugins will not be called on `afterLayout`.
+        * @private
+        */
+       updateLayout: function() {
+               var me = this;
+
+               if (core_plugins.notify(me, 'beforeLayout') === false) {
+                       return;
+               }
+
+               core_layouts.update(this, this.width, this.height);
+
+               /**
+                * Provided for backward compatibility, use `afterLayout` instead.
+                * @method IPlugin#afterScaleUpdate
+                * @deprecated since version 2.5.0
+                * @todo remove at version 3
+                * @private
+                */
+               core_plugins.notify(me, 'afterScaleUpdate');
+               core_plugins.notify(me, 'afterLayout');
+       },
+
+       /**
+        * Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate`
+        * hook, in which case, plugins will not be called on `afterDatasetsUpdate`.
+        * @private
+        */
+       updateDatasets: function() {
+               var me = this;
+
+               if (core_plugins.notify(me, 'beforeDatasetsUpdate') === false) {
+                       return;
+               }
+
+               for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
+                       me.updateDataset(i);
+               }
+
+               core_plugins.notify(me, 'afterDatasetsUpdate');
+       },
+
+       /**
+        * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate`
+        * hook, in which case, plugins will not be called on `afterDatasetUpdate`.
+        * @private
+        */
+       updateDataset: function(index) {
+               var me = this;
+               var meta = me.getDatasetMeta(index);
+               var args = {
+                       meta: meta,
+                       index: index
+               };
+
+               if (core_plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) {
+                       return;
+               }
+
+               meta.controller.update();
+
+               core_plugins.notify(me, 'afterDatasetUpdate', [args]);
+       },
+
+       render: function(config) {
+               var me = this;
+
+               if (!config || typeof config !== 'object') {
+                       // backwards compatibility
+                       config = {
+                               duration: config,
+                               lazy: arguments[1]
+                       };
+               }
+
+               var animationOptions = me.options.animation;
+               var duration = valueOrDefault$8(config.duration, animationOptions && animationOptions.duration);
+               var lazy = config.lazy;
+
+               if (core_plugins.notify(me, 'beforeRender') === false) {
+                       return;
+               }
+
+               var onComplete = function(animation) {
+                       core_plugins.notify(me, 'afterRender');
+                       helpers$1.callback(animationOptions && animationOptions.onComplete, [animation], me);
+               };
+
+               if (animationOptions && duration) {
+                       var animation = new core_animation({
+                               numSteps: duration / 16.66, // 60 fps
+                               easing: config.easing || animationOptions.easing,
+
+                               render: function(chart, animationObject) {
+                                       var easingFunction = helpers$1.easing.effects[animationObject.easing];
+                                       var currentStep = animationObject.currentStep;
+                                       var stepDecimal = currentStep / animationObject.numSteps;
+
+                                       chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep);
+                               },
+
+                               onAnimationProgress: animationOptions.onProgress,
+                               onAnimationComplete: onComplete
+                       });
+
+                       core_animations.addAnimation(me, animation, duration, lazy);
+               } else {
+                       me.draw();
+
+                       // See https://github.com/chartjs/Chart.js/issues/3781
+                       onComplete(new core_animation({numSteps: 0, chart: me}));
+               }
+
+               return me;
+       },
+
+       draw: function(easingValue) {
+               var me = this;
+
+               me.clear();
+
+               if (helpers$1.isNullOrUndef(easingValue)) {
+                       easingValue = 1;
+               }
+
+               me.transition(easingValue);
+
+               if (me.width <= 0 || me.height <= 0) {
+                       return;
+               }
+
+               if (core_plugins.notify(me, 'beforeDraw', [easingValue]) === false) {
+                       return;
+               }
+
+               // Draw all the scales
+               helpers$1.each(me.boxes, function(box) {
+                       box.draw(me.chartArea);
+               }, me);
+
+               me.drawDatasets(easingValue);
+               me._drawTooltip(easingValue);
+
+               core_plugins.notify(me, 'afterDraw', [easingValue]);
+       },
+
+       /**
+        * @private
+        */
+       transition: function(easingValue) {
+               var me = this;
+
+               for (var i = 0, ilen = (me.data.datasets || []).length; i < ilen; ++i) {
+                       if (me.isDatasetVisible(i)) {
+                               me.getDatasetMeta(i).controller.transition(easingValue);
+                       }
+               }
+
+               me.tooltip.transition(easingValue);
+       },
+
+       /**
+        * Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw`
+        * hook, in which case, plugins will not be called on `afterDatasetsDraw`.
+        * @private
+        */
+       drawDatasets: function(easingValue) {
+               var me = this;
+
+               if (core_plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) {
+                       return;
+               }
+
+               // Draw datasets reversed to support proper line stacking
+               for (var i = (me.data.datasets || []).length - 1; i >= 0; --i) {
+                       if (me.isDatasetVisible(i)) {
+                               me.drawDataset(i, easingValue);
+                       }
+               }
+
+               core_plugins.notify(me, 'afterDatasetsDraw', [easingValue]);
+       },
+
+       /**
+        * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw`
+        * hook, in which case, plugins will not be called on `afterDatasetDraw`.
+        * @private
+        */
+       drawDataset: function(index, easingValue) {
+               var me = this;
+               var meta = me.getDatasetMeta(index);
+               var args = {
+                       meta: meta,
+                       index: index,
+                       easingValue: easingValue
+               };
+
+               if (core_plugins.notify(me, 'beforeDatasetDraw', [args]) === false) {
+                       return;
+               }
+
+               meta.controller.draw(easingValue);
+
+               core_plugins.notify(me, 'afterDatasetDraw', [args]);
+       },
+
+       /**
+        * Draws tooltip unless a plugin returns `false` to the `beforeTooltipDraw`
+        * hook, in which case, plugins will not be called on `afterTooltipDraw`.
+        * @private
+        */
+       _drawTooltip: function(easingValue) {
+               var me = this;
+               var tooltip = me.tooltip;
+               var args = {
+                       tooltip: tooltip,
+                       easingValue: easingValue
+               };
+
+               if (core_plugins.notify(me, 'beforeTooltipDraw', [args]) === false) {
+                       return;
+               }
+
+               tooltip.draw();
+
+               core_plugins.notify(me, 'afterTooltipDraw', [args]);
+       },
+
+       /**
+        * Get the single element that was clicked on
+        * @return An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw
+        */
+       getElementAtEvent: function(e) {
+               return core_interaction.modes.single(this, e);
+       },
+
+       getElementsAtEvent: function(e) {
+               return core_interaction.modes.label(this, e, {intersect: true});
+       },
+
+       getElementsAtXAxis: function(e) {
+               return core_interaction.modes['x-axis'](this, e, {intersect: true});
+       },
+
+       getElementsAtEventForMode: function(e, mode, options) {
+               var method = core_interaction.modes[mode];
+               if (typeof method === 'function') {
+                       return method(this, e, options);
+               }
+
+               return [];
+       },
+
+       getDatasetAtEvent: function(e) {
+               return core_interaction.modes.dataset(this, e, {intersect: true});
+       },
+
+       getDatasetMeta: function(datasetIndex) {
+               var me = this;
+               var dataset = me.data.datasets[datasetIndex];
+               if (!dataset._meta) {
+                       dataset._meta = {};
+               }
+
+               var meta = dataset._meta[me.id];
+               if (!meta) {
+                       meta = dataset._meta[me.id] = {
+                               type: null,
+                               data: [],
+                               dataset: null,
+                               controller: null,
+                               hidden: null,                   // See isDatasetVisible() comment
+                               xAxisID: null,
+                               yAxisID: null
+                       };
+               }
+
+               return meta;
+       },
+
+       getVisibleDatasetCount: function() {
+               var count = 0;
+               for (var i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {
+                       if (this.isDatasetVisible(i)) {
+                               count++;
+                       }
+               }
+               return count;
+       },
+
+       isDatasetVisible: function(datasetIndex) {
+               var meta = this.getDatasetMeta(datasetIndex);
+
+               // meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false,
+               // the dataset.hidden value is ignored, else if null, the dataset hidden state is returned.
+               return typeof meta.hidden === 'boolean' ? !meta.hidden : !this.data.datasets[datasetIndex].hidden;
+       },
+
+       generateLegend: function() {
+               return this.options.legendCallback(this);
+       },
+
+       /**
+        * @private
+        */
+       destroyDatasetMeta: function(datasetIndex) {
+               var id = this.id;
+               var dataset = this.data.datasets[datasetIndex];
+               var meta = dataset._meta && dataset._meta[id];
+
+               if (meta) {
+                       meta.controller.destroy();
+                       delete dataset._meta[id];
+               }
+       },
+
+       destroy: function() {
+               var me = this;
+               var canvas = me.canvas;
+               var i, ilen;
+
+               me.stop();
+
+               // dataset controllers need to cleanup associated data
+               for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
+                       me.destroyDatasetMeta(i);
+               }
+
+               if (canvas) {
+                       me.unbindEvents();
+                       helpers$1.canvas.clear(me);
+                       platform.releaseContext(me.ctx);
+                       me.canvas = null;
+                       me.ctx = null;
+               }
+
+               core_plugins.notify(me, 'destroy');
+
+               delete Chart.instances[me.id];
+       },
+
+       toBase64Image: function() {
+               return this.canvas.toDataURL.apply(this.canvas, arguments);
+       },
+
+       initToolTip: function() {
+               var me = this;
+               me.tooltip = new core_tooltip({
+                       _chart: me,
+                       _chartInstance: me, // deprecated, backward compatibility
+                       _data: me.data,
+                       _options: me.options.tooltips
+               }, me);
+       },
+
+       /**
+        * @private
+        */
+       bindEvents: function() {
+               var me = this;
+               var listeners = me._listeners = {};
+               var listener = function() {
+                       me.eventHandler.apply(me, arguments);
+               };
+
+               helpers$1.each(me.options.events, function(type) {
+                       platform.addEventListener(me, type, listener);
+                       listeners[type] = listener;
+               });
+
+               // Elements used to detect size change should not be injected for non responsive charts.
+               // See https://github.com/chartjs/Chart.js/issues/2210
+               if (me.options.responsive) {
+                       listener = function() {
+                               me.resize();
+                       };
+
+                       platform.addEventListener(me, 'resize', listener);
+                       listeners.resize = listener;
+               }
+       },
+
+       /**
+        * @private
+        */
+       unbindEvents: function() {
+               var me = this;
+               var listeners = me._listeners;
+               if (!listeners) {
+                       return;
+               }
+
+               delete me._listeners;
+               helpers$1.each(listeners, function(listener, type) {
+                       platform.removeEventListener(me, type, listener);
+               });
+       },
+
+       updateHoverStyle: function(elements, mode, enabled) {
+               var method = enabled ? 'setHoverStyle' : 'removeHoverStyle';
+               var element, i, ilen;
+
+               for (i = 0, ilen = elements.length; i < ilen; ++i) {
+                       element = elements[i];
+                       if (element) {
+                               this.getDatasetMeta(element._datasetIndex).controller[method](element);
+                       }
+               }
+       },
+
+       /**
+        * @private
+        */
+       eventHandler: function(e) {
+               var me = this;
+               var tooltip = me.tooltip;
+
+               if (core_plugins.notify(me, 'beforeEvent', [e]) === false) {
+                       return;
+               }
+
+               // Buffer any update calls so that renders do not occur
+               me._bufferedRender = true;
+               me._bufferedRequest = null;
+
+               var changed = me.handleEvent(e);
+               // for smooth tooltip animations issue #4989
+               // the tooltip should be the source of change
+               // Animation check workaround:
+               // tooltip._start will be null when tooltip isn't animating
+               if (tooltip) {
+                       changed = tooltip._start
+                               ? tooltip.handleEvent(e)
+                               : changed | tooltip.handleEvent(e);
+               }
+
+               core_plugins.notify(me, 'afterEvent', [e]);
+
+               var bufferedRequest = me._bufferedRequest;
+               if (bufferedRequest) {
+                       // If we have an update that was triggered, we need to do a normal render
+                       me.render(bufferedRequest);
+               } else if (changed && !me.animating) {
+                       // If entering, leaving, or changing elements, animate the change via pivot
+                       me.stop();
+
+                       // We only need to render at this point. Updating will cause scales to be
+                       // recomputed generating flicker & using more memory than necessary.
+                       me.render({
+                               duration: me.options.hover.animationDuration,
+                               lazy: true
+                       });
+               }
+
+               me._bufferedRender = false;
+               me._bufferedRequest = null;
+
+               return me;
+       },
+
+       /**
+        * Handle an event
+        * @private
+        * @param {IEvent} event the event to handle
+        * @return {boolean} true if the chart needs to re-render
+        */
+       handleEvent: function(e) {
+               var me = this;
+               var options = me.options || {};
+               var hoverOptions = options.hover;
+               var changed = false;
+
+               me.lastActive = me.lastActive || [];
+
+               // Find Active Elements for hover and tooltips
+               if (e.type === 'mouseout') {
+                       me.active = [];
+               } else {
+                       me.active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions);
+               }
+
+               // Invoke onHover hook
+               // Need to call with native event here to not break backwards compatibility
+               helpers$1.callback(options.onHover || options.hover.onHover, [e.native, me.active], me);
+
+               if (e.type === 'mouseup' || e.type === 'click') {
+                       if (options.onClick) {
+                               // Use e.native here for backwards compatibility
+                               options.onClick.call(me, e.native, me.active);
+                       }
+               }
+
+               // Remove styling for last active (even if it may still be active)
+               if (me.lastActive.length) {
+                       me.updateHoverStyle(me.lastActive, hoverOptions.mode, false);
+               }
+
+               // Built in hover styling
+               if (me.active.length && hoverOptions.mode) {
+                       me.updateHoverStyle(me.active, hoverOptions.mode, true);
+               }
+
+               changed = !helpers$1.arrayEquals(me.active, me.lastActive);
+
+               // Remember Last Actives
+               me.lastActive = me.active;
+
+               return changed;
+       }
+});
+
+/**
+ * NOTE(SB) We actually don't use this container anymore but we need to keep it
+ * for backward compatibility. Though, it can still be useful for plugins that
+ * would need to work on multiple charts?!
+ */
+Chart.instances = {};
+
+var core_controller = Chart;
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, use Chart instead.
+ * @class Chart.Controller
+ * @deprecated since version 2.6
+ * @todo remove at version 3
+ * @private
+ */
+Chart.Controller = Chart;
+
+/**
+ * Provided for backward compatibility, not available anymore.
+ * @namespace Chart
+ * @deprecated since version 2.8
+ * @todo remove at version 3
+ * @private
+ */
+Chart.types = {};
+
+/**
+ * Provided for backward compatibility, not available anymore.
+ * @namespace Chart.helpers.configMerge
+ * @deprecated since version 2.8.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers$1.configMerge = mergeConfig;
+
+/**
+ * Provided for backward compatibility, not available anymore.
+ * @namespace Chart.helpers.scaleMerge
+ * @deprecated since version 2.8.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers$1.scaleMerge = mergeScaleConfig;
+
+var core_helpers = function() {
+
+       // -- Basic js utility methods
+
+       helpers$1.where = function(collection, filterCallback) {
+               if (helpers$1.isArray(collection) && Array.prototype.filter) {
+                       return collection.filter(filterCallback);
+               }
+               var filtered = [];
+
+               helpers$1.each(collection, function(item) {
+                       if (filterCallback(item)) {
+                               filtered.push(item);
+                       }
+               });
+
+               return filtered;
+       };
+       helpers$1.findIndex = Array.prototype.findIndex ?
+               function(array, callback, scope) {
+                       return array.findIndex(callback, scope);
+               } :
+               function(array, callback, scope) {
+                       scope = scope === undefined ? array : scope;
+                       for (var i = 0, ilen = array.length; i < ilen; ++i) {
+                               if (callback.call(scope, array[i], i, array)) {
+                                       return i;
+                               }
+                       }
+                       return -1;
+               };
+       helpers$1.findNextWhere = function(arrayToSearch, filterCallback, startIndex) {
+               // Default to start of the array
+               if (helpers$1.isNullOrUndef(startIndex)) {
+                       startIndex = -1;
+               }
+               for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
+                       var currentItem = arrayToSearch[i];
+                       if (filterCallback(currentItem)) {
+                               return currentItem;
+                       }
+               }
+       };
+       helpers$1.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) {
+               // Default to end of the array
+               if (helpers$1.isNullOrUndef(startIndex)) {
+                       startIndex = arrayToSearch.length;
+               }
+               for (var i = startIndex - 1; i >= 0; i--) {
+                       var currentItem = arrayToSearch[i];
+                       if (filterCallback(currentItem)) {
+                               return currentItem;
+                       }
+               }
+       };
+
+       // -- Math methods
+       helpers$1.isNumber = function(n) {
+               return !isNaN(parseFloat(n)) && isFinite(n);
+       };
+       helpers$1.almostEquals = function(x, y, epsilon) {
+               return Math.abs(x - y) < epsilon;
+       };
+       helpers$1.almostWhole = function(x, epsilon) {
+               var rounded = Math.round(x);
+               return (((rounded - epsilon) < x) && ((rounded + epsilon) > x));
+       };
+       helpers$1.max = function(array) {
+               return array.reduce(function(max, value) {
+                       if (!isNaN(value)) {
+                               return Math.max(max, value);
+                       }
+                       return max;
+               }, Number.NEGATIVE_INFINITY);
+       };
+       helpers$1.min = function(array) {
+               return array.reduce(function(min, value) {
+                       if (!isNaN(value)) {
+                               return Math.min(min, value);
+                       }
+                       return min;
+               }, Number.POSITIVE_INFINITY);
+       };
+       helpers$1.sign = Math.sign ?
+               function(x) {
+                       return Math.sign(x);
+               } :
+               function(x) {
+                       x = +x; // convert to a number
+                       if (x === 0 || isNaN(x)) {
+                               return x;
+                       }
+                       return x > 0 ? 1 : -1;
+               };
+       helpers$1.log10 = Math.log10 ?
+               function(x) {
+                       return Math.log10(x);
+               } :
+               function(x) {
+                       var exponent = Math.log(x) * Math.LOG10E; // Math.LOG10E = 1 / Math.LN10.
+                       // Check for whole powers of 10,
+                       // which due to floating point rounding error should be corrected.
+                       var powerOf10 = Math.round(exponent);
+                       var isPowerOf10 = x === Math.pow(10, powerOf10);
+
+                       return isPowerOf10 ? powerOf10 : exponent;
+               };
+       helpers$1.toRadians = function(degrees) {
+               return degrees * (Math.PI / 180);
+       };
+       helpers$1.toDegrees = function(radians) {
+               return radians * (180 / Math.PI);
+       };
+
+       /**
+        * Returns the number of decimal places
+        * i.e. the number of digits after the decimal point, of the value of this Number.
+        * @param {number} x - A number.
+        * @returns {number} The number of decimal places.
+        * @private
+        */
+       helpers$1._decimalPlaces = function(x) {
+               if (!helpers$1.isFinite(x)) {
+                       return;
+               }
+               var e = 1;
+               var p = 0;
+               while (Math.round(x * e) / e !== x) {
+                       e *= 10;
+                       p++;
+               }
+               return p;
+       };
+
+       // Gets the angle from vertical upright to the point about a centre.
+       helpers$1.getAngleFromPoint = function(centrePoint, anglePoint) {
+               var distanceFromXCenter = anglePoint.x - centrePoint.x;
+               var distanceFromYCenter = anglePoint.y - centrePoint.y;
+               var radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
+
+               var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
+
+               if (angle < (-0.5 * Math.PI)) {
+                       angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
+               }
+
+               return {
+                       angle: angle,
+                       distance: radialDistanceFromCenter
+               };
+       };
+       helpers$1.distanceBetweenPoints = function(pt1, pt2) {
+               return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
+       };
+
+       /**
+        * Provided for backward compatibility, not available anymore
+        * @function Chart.helpers.aliasPixel
+        * @deprecated since version 2.8.0
+        * @todo remove at version 3
+        */
+       helpers$1.aliasPixel = function(pixelWidth) {
+               return (pixelWidth % 2 === 0) ? 0 : 0.5;
+       };
+
+       /**
+        * Returns the aligned pixel value to avoid anti-aliasing blur
+        * @param {Chart} chart - The chart instance.
+        * @param {number} pixel - A pixel value.
+        * @param {number} width - The width of the element.
+        * @returns {number} The aligned pixel value.
+        * @private
+        */
+       helpers$1._alignPixel = function(chart, pixel, width) {
+               var devicePixelRatio = chart.currentDevicePixelRatio;
+               var halfWidth = width / 2;
+               return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth;
+       };
+
+       helpers$1.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
+               // Props to Rob Spencer at scaled innovation for his post on splining between points
+               // http://scaledinnovation.com/analytics/splines/aboutSplines.html
+
+               // This function must also respect "skipped" points
+
+               var previous = firstPoint.skip ? middlePoint : firstPoint;
+               var current = middlePoint;
+               var next = afterPoint.skip ? middlePoint : afterPoint;
+
+               var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
+               var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
+
+               var s01 = d01 / (d01 + d12);
+               var s12 = d12 / (d01 + d12);
+
+               // If all points are the same, s01 & s02 will be inf
+               s01 = isNaN(s01) ? 0 : s01;
+               s12 = isNaN(s12) ? 0 : s12;
+
+               var fa = t * s01; // scaling factor for triangle Ta
+               var fb = t * s12;
+
+               return {
+                       previous: {
+                               x: current.x - fa * (next.x - previous.x),
+                               y: current.y - fa * (next.y - previous.y)
+                       },
+                       next: {
+                               x: current.x + fb * (next.x - previous.x),
+                               y: current.y + fb * (next.y - previous.y)
+                       }
+               };
+       };
+       helpers$1.EPSILON = Number.EPSILON || 1e-14;
+       helpers$1.splineCurveMonotone = function(points) {
+               // This function calculates Bézier control points in a similar way than |splineCurve|,
+               // but preserves monotonicity of the provided data and ensures no local extremums are added
+               // between the dataset discrete points due to the interpolation.
+               // See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
+
+               var pointsWithTangents = (points || []).map(function(point) {
+                       return {
+                               model: point._model,
+                               deltaK: 0,
+                               mK: 0
+                       };
+               });
+
+               // Calculate slopes (deltaK) and initialize tangents (mK)
+               var pointsLen = pointsWithTangents.length;
+               var i, pointBefore, pointCurrent, pointAfter;
+               for (i = 0; i < pointsLen; ++i) {
+                       pointCurrent = pointsWithTangents[i];
+                       if (pointCurrent.model.skip) {
+                               continue;
+                       }
+
+                       pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
+                       pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
+                       if (pointAfter && !pointAfter.model.skip) {
+                               var slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x);
+
+                               // In the case of two points that appear at the same x pixel, slopeDeltaX is 0
+                               pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0;
+                       }
+
+                       if (!pointBefore || pointBefore.model.skip) {
+                               pointCurrent.mK = pointCurrent.deltaK;
+                       } else if (!pointAfter || pointAfter.model.skip) {
+                               pointCurrent.mK = pointBefore.deltaK;
+                       } else if (this.sign(pointBefore.deltaK) !== this.sign(pointCurrent.deltaK)) {
+                               pointCurrent.mK = 0;
+                       } else {
+                               pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2;
+                       }
+               }
+
+               // Adjust tangents to ensure monotonic properties
+               var alphaK, betaK, tauK, squaredMagnitude;
+               for (i = 0; i < pointsLen - 1; ++i) {
+                       pointCurrent = pointsWithTangents[i];
+                       pointAfter = pointsWithTangents[i + 1];
+                       if (pointCurrent.model.skip || pointAfter.model.skip) {
+                               continue;
+                       }
+
+                       if (helpers$1.almostEquals(pointCurrent.deltaK, 0, this.EPSILON)) {
+                               pointCurrent.mK = pointAfter.mK = 0;
+                               continue;
+                       }
+
+                       alphaK = pointCurrent.mK / pointCurrent.deltaK;
+                       betaK = pointAfter.mK / pointCurrent.deltaK;
+                       squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
+                       if (squaredMagnitude <= 9) {
+                               continue;
+                       }
+
+                       tauK = 3 / Math.sqrt(squaredMagnitude);
+                       pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK;
+                       pointAfter.mK = betaK * tauK * pointCurrent.deltaK;
+               }
+
+               // Compute control points
+               var deltaX;
+               for (i = 0; i < pointsLen; ++i) {
+                       pointCurrent = pointsWithTangents[i];
+                       if (pointCurrent.model.skip) {
+                               continue;
+                       }
+
+                       pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
+                       pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
+                       if (pointBefore && !pointBefore.model.skip) {
+                               deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3;
+                               pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX;
+                               pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK;
+                       }
+                       if (pointAfter && !pointAfter.model.skip) {
+                               deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3;
+                               pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX;
+                               pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK;
+                       }
+               }
+       };
+       helpers$1.nextItem = function(collection, index, loop) {
+               if (loop) {
+                       return index >= collection.length - 1 ? collection[0] : collection[index + 1];
+               }
+               return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1];
+       };
+       helpers$1.previousItem = function(collection, index, loop) {
+               if (loop) {
+                       return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
+               }
+               return index <= 0 ? collection[0] : collection[index - 1];
+       };
+       // Implementation of the nice number algorithm used in determining where axis labels will go
+       helpers$1.niceNum = function(range, round) {
+               var exponent = Math.floor(helpers$1.log10(range));
+               var fraction = range / Math.pow(10, exponent);
+               var niceFraction;
+
+               if (round) {
+                       if (fraction < 1.5) {
+                               niceFraction = 1;
+                       } else if (fraction < 3) {
+                               niceFraction = 2;
+                       } else if (fraction < 7) {
+                               niceFraction = 5;
+                       } else {
+                               niceFraction = 10;
+                       }
+               } else if (fraction <= 1.0) {
+                       niceFraction = 1;
+               } else if (fraction <= 2) {
+                       niceFraction = 2;
+               } else if (fraction <= 5) {
+                       niceFraction = 5;
+               } else {
+                       niceFraction = 10;
+               }
+
+               return niceFraction * Math.pow(10, exponent);
+       };
+       // Request animation polyfill - https://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
+       helpers$1.requestAnimFrame = (function() {
+               if (typeof window === 'undefined') {
+                       return function(callback) {
+                               callback();
+                       };
+               }
+               return window.requestAnimationFrame ||
+                       window.webkitRequestAnimationFrame ||
+                       window.mozRequestAnimationFrame ||
+                       window.oRequestAnimationFrame ||
+                       window.msRequestAnimationFrame ||
+                       function(callback) {
+                               return window.setTimeout(callback, 1000 / 60);
+                       };
+       }());
+       // -- DOM methods
+       helpers$1.getRelativePosition = function(evt, chart) {
+               var mouseX, mouseY;
+               var e = evt.originalEvent || evt;
+               var canvas = evt.target || evt.srcElement;
+               var boundingRect = canvas.getBoundingClientRect();
+
+               var touches = e.touches;
+               if (touches && touches.length > 0) {
+                       mouseX = touches[0].clientX;
+                       mouseY = touches[0].clientY;
+
+               } else {
+                       mouseX = e.clientX;
+                       mouseY = e.clientY;
+               }
+
+               // Scale mouse coordinates into canvas coordinates
+               // by following the pattern laid out by 'jerryj' in the comments of
+               // https://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
+               var paddingLeft = parseFloat(helpers$1.getStyle(canvas, 'padding-left'));
+               var paddingTop = parseFloat(helpers$1.getStyle(canvas, 'padding-top'));
+               var paddingRight = parseFloat(helpers$1.getStyle(canvas, 'padding-right'));
+               var paddingBottom = parseFloat(helpers$1.getStyle(canvas, 'padding-bottom'));
+               var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;
+               var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;
+
+               // We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
+               // the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
+               mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio);
+               mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio);
+
+               return {
+                       x: mouseX,
+                       y: mouseY
+               };
+
+       };
+
+       // Private helper function to convert max-width/max-height values that may be percentages into a number
+       function parseMaxStyle(styleValue, node, parentProperty) {
+               var valueInPixels;
+               if (typeof styleValue === 'string') {
+                       valueInPixels = parseInt(styleValue, 10);
+
+                       if (styleValue.indexOf('%') !== -1) {
+                               // percentage * size in dimension
+                               valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
+                       }
+               } else {
+                       valueInPixels = styleValue;
+               }
+
+               return valueInPixels;
+       }
+
+       /**
+        * Returns if the given value contains an effective constraint.
+        * @private
+        */
+       function isConstrainedValue(value) {
+               return value !== undefined && value !== null && value !== 'none';
+       }
+
+       /**
+        * Returns the max width or height of the given DOM node in a cross-browser compatible fashion
+        * @param {HTMLElement} domNode - the node to check the constraint on
+        * @param {string} maxStyle - the style that defines the maximum for the direction we are using ('max-width' / 'max-height')
+        * @param {string} percentageProperty - property of parent to use when calculating width as a percentage
+        * @see {@link https://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser}
+        */
+       function getConstraintDimension(domNode, maxStyle, percentageProperty) {
+               var view = document.defaultView;
+               var parentNode = helpers$1._getParentNode(domNode);
+               var constrainedNode = view.getComputedStyle(domNode)[maxStyle];
+               var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];
+               var hasCNode = isConstrainedValue(constrainedNode);
+               var hasCContainer = isConstrainedValue(constrainedContainer);
+               var infinity = Number.POSITIVE_INFINITY;
+
+               if (hasCNode || hasCContainer) {
+                       return Math.min(
+                               hasCNode ? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,
+                               hasCContainer ? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);
+               }
+
+               return 'none';
+       }
+       // returns Number or undefined if no constraint
+       helpers$1.getConstraintWidth = function(domNode) {
+               return getConstraintDimension(domNode, 'max-width', 'clientWidth');
+       };
+       // returns Number or undefined if no constraint
+       helpers$1.getConstraintHeight = function(domNode) {
+               return getConstraintDimension(domNode, 'max-height', 'clientHeight');
+       };
+       /**
+        * @private
+        */
+       helpers$1._calculatePadding = function(container, padding, parentDimension) {
+               padding = helpers$1.getStyle(container, padding);
+
+               return padding.indexOf('%') > -1 ? parentDimension * parseInt(padding, 10) / 100 : parseInt(padding, 10);
+       };
+       /**
+        * @private
+        */
+       helpers$1._getParentNode = function(domNode) {
+               var parent = domNode.parentNode;
+               if (parent && parent.toString() === '[object ShadowRoot]') {
+                       parent = parent.host;
+               }
+               return parent;
+       };
+       helpers$1.getMaximumWidth = function(domNode) {
+               var container = helpers$1._getParentNode(domNode);
+               if (!container) {
+                       return domNode.clientWidth;
+               }
+
+               var clientWidth = container.clientWidth;
+               var paddingLeft = helpers$1._calculatePadding(container, 'padding-left', clientWidth);
+               var paddingRight = helpers$1._calculatePadding(container, 'padding-right', clientWidth);
+
+               var w = clientWidth - paddingLeft - paddingRight;
+               var cw = helpers$1.getConstraintWidth(domNode);
+               return isNaN(cw) ? w : Math.min(w, cw);
+       };
+       helpers$1.getMaximumHeight = function(domNode) {
+               var container = helpers$1._getParentNode(domNode);
+               if (!container) {
+                       return domNode.clientHeight;
+               }
+
+               var clientHeight = container.clientHeight;
+               var paddingTop = helpers$1._calculatePadding(container, 'padding-top', clientHeight);
+               var paddingBottom = helpers$1._calculatePadding(container, 'padding-bottom', clientHeight);
+
+               var h = clientHeight - paddingTop - paddingBottom;
+               var ch = helpers$1.getConstraintHeight(domNode);
+               return isNaN(ch) ? h : Math.min(h, ch);
+       };
+       helpers$1.getStyle = function(el, property) {
+               return el.currentStyle ?
+                       el.currentStyle[property] :
+                       document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
+       };
+       helpers$1.retinaScale = function(chart, forceRatio) {
+               var pixelRatio = chart.currentDevicePixelRatio = forceRatio || (typeof window !== 'undefined' && window.devicePixelRatio) || 1;
+               if (pixelRatio === 1) {
+                       return;
+               }
+
+               var canvas = chart.canvas;
+               var height = chart.height;
+               var width = chart.width;
+
+               canvas.height = height * pixelRatio;
+               canvas.width = width * pixelRatio;
+               chart.ctx.scale(pixelRatio, pixelRatio);
+
+               // If no style has been set on the canvas, the render size is used as display size,
+               // making the chart visually bigger, so let's enforce it to the "correct" values.
+               // See https://github.com/chartjs/Chart.js/issues/3575
+               if (!canvas.style.height && !canvas.style.width) {
+                       canvas.style.height = height + 'px';
+                       canvas.style.width = width + 'px';
+               }
+       };
+       // -- Canvas methods
+       helpers$1.fontString = function(pixelSize, fontStyle, fontFamily) {
+               return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
+       };
+       helpers$1.longestText = function(ctx, font, arrayOfThings, cache) {
+               cache = cache || {};
+               var data = cache.data = cache.data || {};
+               var gc = cache.garbageCollect = cache.garbageCollect || [];
+
+               if (cache.font !== font) {
+                       data = cache.data = {};
+                       gc = cache.garbageCollect = [];
+                       cache.font = font;
+               }
+
+               ctx.font = font;
+               var longest = 0;
+               helpers$1.each(arrayOfThings, function(thing) {
+                       // Undefined strings and arrays should not be measured
+                       if (thing !== undefined && thing !== null && helpers$1.isArray(thing) !== true) {
+                               longest = helpers$1.measureText(ctx, data, gc, longest, thing);
+                       } else if (helpers$1.isArray(thing)) {
+                               // if it is an array lets measure each element
+                               // to do maybe simplify this function a bit so we can do this more recursively?
+                               helpers$1.each(thing, function(nestedThing) {
+                                       // Undefined strings and arrays should not be measured
+                                       if (nestedThing !== undefined && nestedThing !== null && !helpers$1.isArray(nestedThing)) {
+                                               longest = helpers$1.measureText(ctx, data, gc, longest, nestedThing);
+                                       }
+                               });
+                       }
+               });
+
+               var gcLen = gc.length / 2;
+               if (gcLen > arrayOfThings.length) {
+                       for (var i = 0; i < gcLen; i++) {
+                               delete data[gc[i]];
+                       }
+                       gc.splice(0, gcLen);
+               }
+               return longest;
+       };
+       helpers$1.measureText = function(ctx, data, gc, longest, string) {
+               var textWidth = data[string];
+               if (!textWidth) {
+                       textWidth = data[string] = ctx.measureText(string).width;
+                       gc.push(string);
+               }
+               if (textWidth > longest) {
+                       longest = textWidth;
+               }
+               return longest;
+       };
+       helpers$1.numberOfLabelLines = function(arrayOfThings) {
+               var numberOfLines = 1;
+               helpers$1.each(arrayOfThings, function(thing) {
+                       if (helpers$1.isArray(thing)) {
+                               if (thing.length > numberOfLines) {
+                                       numberOfLines = thing.length;
+                               }
+                       }
+               });
+               return numberOfLines;
+       };
+
+       helpers$1.color = !chartjsColor ?
+               function(value) {
+                       console.error('Color.js not found!');
+                       return value;
+               } :
+               function(value) {
+                       /* global CanvasGradient */
+                       if (value instanceof CanvasGradient) {
+                               value = core_defaults.global.defaultColor;
+                       }
+
+                       return chartjsColor(value);
+               };
+
+       helpers$1.getHoverColor = function(colorValue) {
+               /* global CanvasPattern */
+               return (colorValue instanceof CanvasPattern || colorValue instanceof CanvasGradient) ?
+                       colorValue :
+                       helpers$1.color(colorValue).saturate(0.5).darken(0.1).rgbString();
+       };
+};
+
+function abstract() {
+       throw new Error(
+               'This method is not implemented: either no adapter can ' +
+               'be found or an incomplete integration was provided.'
+       );
+}
+
+/**
+ * Date adapter (current used by the time scale)
+ * @namespace Chart._adapters._date
+ * @memberof Chart._adapters
+ * @private
+ */
+
+/**
+ * Currently supported unit string values.
+ * @typedef {('millisecond'|'second'|'minute'|'hour'|'day'|'week'|'month'|'quarter'|'year')}
+ * @memberof Chart._adapters._date
+ * @name Unit
+ */
+
+/**
+ * @class
+ */
+function DateAdapter(options) {
+       this.options = options || {};
+}
+
+helpers$1.extend(DateAdapter.prototype, /** @lends DateAdapter */ {
+       /**
+        * Returns a map of time formats for the supported formatting units defined
+        * in Unit as well as 'datetime' representing a detailed date/time string.
+        * @returns {{string: string}}
+        */
+       formats: abstract,
+
+       /**
+        * Parses the given `value` and return the associated timestamp.
+        * @param {any} value - the value to parse (usually comes from the data)
+        * @param {string} [format] - the expected data format
+        * @returns {(number|null)}
+        * @function
+        */
+       parse: abstract,
+
+       /**
+        * Returns the formatted date in the specified `format` for a given `timestamp`.
+        * @param {number} timestamp - the timestamp to format
+        * @param {string} format - the date/time token
+        * @return {string}
+        * @function
+        */
+       format: abstract,
+
+       /**
+        * Adds the specified `amount` of `unit` to the given `timestamp`.
+        * @param {number} timestamp - the input timestamp
+        * @param {number} amount - the amount to add
+        * @param {Unit} unit - the unit as string
+        * @return {number}
+        * @function
+        */
+       add: abstract,
+
+       /**
+        * Returns the number of `unit` between the given timestamps.
+        * @param {number} max - the input timestamp (reference)
+        * @param {number} min - the timestamp to substract
+        * @param {Unit} unit - the unit as string
+        * @return {number}
+        * @function
+        */
+       diff: abstract,
+
+       /**
+        * Returns start of `unit` for the given `timestamp`.
+        * @param {number} timestamp - the input timestamp
+        * @param {Unit} unit - the unit as string
+        * @param {number} [weekday] - the ISO day of the week with 1 being Monday
+        * and 7 being Sunday (only needed if param *unit* is `isoWeek`).
+        * @function
+        */
+       startOf: abstract,
+
+       /**
+        * Returns end of `unit` for the given `timestamp`.
+        * @param {number} timestamp - the input timestamp
+        * @param {Unit} unit - the unit as string
+        * @function
+        */
+       endOf: abstract,
+
+       // DEPRECATIONS
+
+       /**
+        * Provided for backward compatibility for scale.getValueForPixel(),
+        * this method should be overridden only by the moment adapter.
+        * @deprecated since version 2.8.0
+        * @todo remove at version 3
+        * @private
+        */
+       _create: function(value) {
+               return value;
+       }
+});
+
+DateAdapter.override = function(members) {
+       helpers$1.extend(DateAdapter.prototype, members);
+};
+
+var _date = DateAdapter;
+
+var core_adapters = {
+       _date: _date
+};
+
+/**
+ * Namespace to hold static tick generation functions
+ * @namespace Chart.Ticks
+ */
+var core_ticks = {
+       /**
+        * Namespace to hold formatters for different types of ticks
+        * @namespace Chart.Ticks.formatters
+        */
+       formatters: {
+               /**
+                * Formatter for value labels
+                * @method Chart.Ticks.formatters.values
+                * @param value the value to display
+                * @return {string|string[]} the label to display
+                */
+               values: function(value) {
+                       return helpers$1.isArray(value) ? value : '' + value;
+               },
+
+               /**
+                * Formatter for linear numeric ticks
+                * @method Chart.Ticks.formatters.linear
+                * @param tickValue {number} the value to be formatted
+                * @param index {number} the position of the tickValue parameter in the ticks array
+                * @param ticks {number[]} the list of ticks being converted
+                * @return {string} string representation of the tickValue parameter
+                */
+               linear: function(tickValue, index, ticks) {
+                       // If we have lots of ticks, don't use the ones
+                       var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];
+
+                       // If we have a number like 2.5 as the delta, figure out how many decimal places we need
+                       if (Math.abs(delta) > 1) {
+                               if (tickValue !== Math.floor(tickValue)) {
+                                       // not an integer
+                                       delta = tickValue - Math.floor(tickValue);
+                               }
+                       }
+
+                       var logDelta = helpers$1.log10(Math.abs(delta));
+                       var tickString = '';
+
+                       if (tickValue !== 0) {
+                               var maxTick = Math.max(Math.abs(ticks[0]), Math.abs(ticks[ticks.length - 1]));
+                               if (maxTick < 1e-4) { // all ticks are small numbers; use scientific notation
+                                       var logTick = helpers$1.log10(Math.abs(tickValue));
+                                       tickString = tickValue.toExponential(Math.floor(logTick) - Math.floor(logDelta));
+                               } else {
+                                       var numDecimal = -1 * Math.floor(logDelta);
+                                       numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
+                                       tickString = tickValue.toFixed(numDecimal);
+                               }
+                       } else {
+                               tickString = '0'; // never show decimal places for 0
+                       }
+
+                       return tickString;
+               },
+
+               logarithmic: function(tickValue, index, ticks) {
+                       var remain = tickValue / (Math.pow(10, Math.floor(helpers$1.log10(tickValue))));
+
+                       if (tickValue === 0) {
+                               return '0';
+                       } else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) {
+                               return tickValue.toExponential();
+                       }
+                       return '';
+               }
+       }
+};
+
+var valueOrDefault$9 = helpers$1.valueOrDefault;
+var valueAtIndexOrDefault = helpers$1.valueAtIndexOrDefault;
+
+core_defaults._set('scale', {
+       display: true,
+       position: 'left',
+       offset: false,
+
+       // grid line settings
+       gridLines: {
+               display: true,
+               color: 'rgba(0, 0, 0, 0.1)',
+               lineWidth: 1,
+               drawBorder: true,
+               drawOnChartArea: true,
+               drawTicks: true,
+               tickMarkLength: 10,
+               zeroLineWidth: 1,
+               zeroLineColor: 'rgba(0,0,0,0.25)',
+               zeroLineBorderDash: [],
+               zeroLineBorderDashOffset: 0.0,
+               offsetGridLines: false,
+               borderDash: [],
+               borderDashOffset: 0.0
+       },
+
+       // scale label
+       scaleLabel: {
+               // display property
+               display: false,
+
+               // actual label
+               labelString: '',
+
+               // top/bottom padding
+               padding: {
+                       top: 4,
+                       bottom: 4
+               }
+       },
+
+       // label settings
+       ticks: {
+               beginAtZero: false,
+               minRotation: 0,
+               maxRotation: 50,
+               mirror: false,
+               padding: 0,
+               reverse: false,
+               display: true,
+               autoSkip: true,
+               autoSkipPadding: 0,
+               labelOffset: 0,
+               // We pass through arrays to be rendered as multiline labels, we convert Others to strings here.
+               callback: core_ticks.formatters.values,
+               minor: {},
+               major: {}
+       }
+});
+
+function labelsFromTicks(ticks) {
+       var labels = [];
+       var i, ilen;
+
+       for (i = 0, ilen = ticks.length; i < ilen; ++i) {
+               labels.push(ticks[i].label);
+       }
+
+       return labels;
+}
+
+function getPixelForGridLine(scale, index, offsetGridLines) {
+       var lineValue = scale.getPixelForTick(index);
+
+       if (offsetGridLines) {
+               if (scale.getTicks().length === 1) {
+                       lineValue -= scale.isHorizontal() ?
+                               Math.max(lineValue - scale.left, scale.right - lineValue) :
+                               Math.max(lineValue - scale.top, scale.bottom - lineValue);
+               } else if (index === 0) {
+                       lineValue -= (scale.getPixelForTick(1) - lineValue) / 2;
+               } else {
+                       lineValue -= (lineValue - scale.getPixelForTick(index - 1)) / 2;
+               }
+       }
+       return lineValue;
+}
+
+function computeTextSize(context, tick, font) {
+       return helpers$1.isArray(tick) ?
+               helpers$1.longestText(context, font, tick) :
+               context.measureText(tick).width;
+}
+
+var core_scale = core_element.extend({
+       /**
+        * Get the padding needed for the scale
+        * @method getPadding
+        * @private
+        * @returns {Padding} the necessary padding
+        */
+       getPadding: function() {
+               var me = this;
+               return {
+                       left: me.paddingLeft || 0,
+                       top: me.paddingTop || 0,
+                       right: me.paddingRight || 0,
+                       bottom: me.paddingBottom || 0
+               };
+       },
+
+       /**
+        * Returns the scale tick objects ({label, major})
+        * @since 2.7
+        */
+       getTicks: function() {
+               return this._ticks;
+       },
+
+       // These methods are ordered by lifecyle. Utilities then follow.
+       // Any function defined here is inherited by all scale types.
+       // Any function can be extended by the scale type
+
+       mergeTicksOptions: function() {
+               var ticks = this.options.ticks;
+               if (ticks.minor === false) {
+                       ticks.minor = {
+                               display: false
+                       };
+               }
+               if (ticks.major === false) {
+                       ticks.major = {
+                               display: false
+                       };
+               }
+               for (var key in ticks) {
+                       if (key !== 'major' && key !== 'minor') {
+                               if (typeof ticks.minor[key] === 'undefined') {
+                                       ticks.minor[key] = ticks[key];
+                               }
+                               if (typeof ticks.major[key] === 'undefined') {
+                                       ticks.major[key] = ticks[key];
+                               }
+                       }
+               }
+       },
+       beforeUpdate: function() {
+               helpers$1.callback(this.options.beforeUpdate, [this]);
+       },
+
+       update: function(maxWidth, maxHeight, margins) {
+               var me = this;
+               var i, ilen, labels, label, ticks, tick;
+
+               // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
+               me.beforeUpdate();
+
+               // Absorb the master measurements
+               me.maxWidth = maxWidth;
+               me.maxHeight = maxHeight;
+               me.margins = helpers$1.extend({
+                       left: 0,
+                       right: 0,
+                       top: 0,
+                       bottom: 0
+               }, margins);
+
+               me._maxLabelLines = 0;
+               me.longestLabelWidth = 0;
+               me.longestTextCache = me.longestTextCache || {};
+
+               // Dimensions
+               me.beforeSetDimensions();
+               me.setDimensions();
+               me.afterSetDimensions();
+
+               // Data min/max
+               me.beforeDataLimits();
+               me.determineDataLimits();
+               me.afterDataLimits();
+
+               // Ticks - `this.ticks` is now DEPRECATED!
+               // Internal ticks are now stored as objects in the PRIVATE `this._ticks` member
+               // and must not be accessed directly from outside this class. `this.ticks` being
+               // around for long time and not marked as private, we can't change its structure
+               // without unexpected breaking changes. If you need to access the scale ticks,
+               // use scale.getTicks() instead.
+
+               me.beforeBuildTicks();
+
+               // New implementations should return an array of objects but for BACKWARD COMPAT,
+               // we still support no return (`this.ticks` internally set by calling this method).
+               ticks = me.buildTicks() || [];
+
+               // Allow modification of ticks in callback.
+               ticks = me.afterBuildTicks(ticks) || ticks;
+
+               me.beforeTickToLabelConversion();
+
+               // New implementations should return the formatted tick labels but for BACKWARD
+               // COMPAT, we still support no return (`this.ticks` internally changed by calling
+               // this method and supposed to contain only string values).
+               labels = me.convertTicksToLabels(ticks) || me.ticks;
+
+               me.afterTickToLabelConversion();
+
+               me.ticks = labels;   // BACKWARD COMPATIBILITY
+
+               // IMPORTANT: from this point, we consider that `this.ticks` will NEVER change!
+
+               // BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`)
+               for (i = 0, ilen = labels.length; i < ilen; ++i) {
+                       label = labels[i];
+                       tick = ticks[i];
+                       if (!tick) {
+                               ticks.push(tick = {
+                                       label: label,
+                                       major: false
+                               });
+                       } else {
+                               tick.label = label;
+                       }
+               }
+
+               me._ticks = ticks;
+
+               // Tick Rotation
+               me.beforeCalculateTickRotation();
+               me.calculateTickRotation();
+               me.afterCalculateTickRotation();
+               // Fit
+               me.beforeFit();
+               me.fit();
+               me.afterFit();
+               //
+               me.afterUpdate();
+
+               return me.minSize;
+
+       },
+       afterUpdate: function() {
+               helpers$1.callback(this.options.afterUpdate, [this]);
+       },
+
+       //
+
+       beforeSetDimensions: function() {
+               helpers$1.callback(this.options.beforeSetDimensions, [this]);
+       },
+       setDimensions: function() {
+               var me = this;
+               // Set the unconstrained dimension before label rotation
+               if (me.isHorizontal()) {
+                       // Reset position before calculating rotation
+                       me.width = me.maxWidth;
+                       me.left = 0;
+                       me.right = me.width;
+               } else {
+                       me.height = me.maxHeight;
+
+                       // Reset position before calculating rotation
+                       me.top = 0;
+                       me.bottom = me.height;
+               }
+
+               // Reset padding
+               me.paddingLeft = 0;
+               me.paddingTop = 0;
+               me.paddingRight = 0;
+               me.paddingBottom = 0;
+       },
+       afterSetDimensions: function() {
+               helpers$1.callback(this.options.afterSetDimensions, [this]);
+       },
+
+       // Data limits
+       beforeDataLimits: function() {
+               helpers$1.callback(this.options.beforeDataLimits, [this]);
+       },
+       determineDataLimits: helpers$1.noop,
+       afterDataLimits: function() {
+               helpers$1.callback(this.options.afterDataLimits, [this]);
+       },
+
+       //
+       beforeBuildTicks: function() {
+               helpers$1.callback(this.options.beforeBuildTicks, [this]);
+       },
+       buildTicks: helpers$1.noop,
+       afterBuildTicks: function(ticks) {
+               var me = this;
+               // ticks is empty for old axis implementations here
+               if (helpers$1.isArray(ticks) && ticks.length) {
+                       return helpers$1.callback(me.options.afterBuildTicks, [me, ticks]);
+               }
+               // Support old implementations (that modified `this.ticks` directly in buildTicks)
+               me.ticks = helpers$1.callback(me.options.afterBuildTicks, [me, me.ticks]) || me.ticks;
+               return ticks;
+       },
+
+       beforeTickToLabelConversion: function() {
+               helpers$1.callback(this.options.beforeTickToLabelConversion, [this]);
+       },
+       convertTicksToLabels: function() {
+               var me = this;
+               // Convert ticks to strings
+               var tickOpts = me.options.ticks;
+               me.ticks = me.ticks.map(tickOpts.userCallback || tickOpts.callback, this);
+       },
+       afterTickToLabelConversion: function() {
+               helpers$1.callback(this.options.afterTickToLabelConversion, [this]);
+       },
+
+       //
+
+       beforeCalculateTickRotation: function() {
+               helpers$1.callback(this.options.beforeCalculateTickRotation, [this]);
+       },
+       calculateTickRotation: function() {
+               var me = this;
+               var context = me.ctx;
+               var tickOpts = me.options.ticks;
+               var labels = labelsFromTicks(me._ticks);
+
+               // Get the width of each grid by calculating the difference
+               // between x offsets between 0 and 1.
+               var tickFont = helpers$1.options._parseFont(tickOpts);
+               context.font = tickFont.string;
+
+               var labelRotation = tickOpts.minRotation || 0;
+
+               if (labels.length && me.options.display && me.isHorizontal()) {
+                       var originalLabelWidth = helpers$1.longestText(context, tickFont.string, labels, me.longestTextCache);
+                       var labelWidth = originalLabelWidth;
+                       var cosRotation, sinRotation;
+
+                       // Allow 3 pixels x2 padding either side for label readability
+                       var tickWidth = me.getPixelForTick(1) - me.getPixelForTick(0) - 6;
+
+                       // Max label rotation can be set or default to 90 - also act as a loop counter
+                       while (labelWidth > tickWidth && labelRotation < tickOpts.maxRotation) {
+                               var angleRadians = helpers$1.toRadians(labelRotation);
+                               cosRotation = Math.cos(angleRadians);
+                               sinRotation = Math.sin(angleRadians);
+
+                               if (sinRotation * originalLabelWidth > me.maxHeight) {
+                                       // go back one step
+                                       labelRotation--;
+                                       break;
+                               }
+
+                               labelRotation++;
+                               labelWidth = cosRotation * originalLabelWidth;
+                       }
+               }
+
+               me.labelRotation = labelRotation;
+       },
+       afterCalculateTickRotation: function() {
+               helpers$1.callback(this.options.afterCalculateTickRotation, [this]);
+       },
+
+       //
+
+       beforeFit: function() {
+               helpers$1.callback(this.options.beforeFit, [this]);
+       },
+       fit: function() {
+               var me = this;
+               // Reset
+               var minSize = me.minSize = {
+                       width: 0,
+                       height: 0
+               };
+
+               var labels = labelsFromTicks(me._ticks);
+
+               var opts = me.options;
+               var tickOpts = opts.ticks;
+               var scaleLabelOpts = opts.scaleLabel;
+               var gridLineOpts = opts.gridLines;
+               var display = me._isVisible();
+               var position = opts.position;
+               var isHorizontal = me.isHorizontal();
+
+               var parseFont = helpers$1.options._parseFont;
+               var tickFont = parseFont(tickOpts);
+               var tickMarkLength = opts.gridLines.tickMarkLength;
+
+               // Width
+               if (isHorizontal) {
+                       // subtract the margins to line up with the chartArea if we are a full width scale
+                       minSize.width = me.isFullWidth() ? me.maxWidth - me.margins.left - me.margins.right : me.maxWidth;
+               } else {
+                       minSize.width = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
+               }
+
+               // height
+               if (isHorizontal) {
+                       minSize.height = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
+               } else {
+                       minSize.height = me.maxHeight; // fill all the height
+               }
+
+               // Are we showing a title for the scale?
+               if (scaleLabelOpts.display && display) {
+                       var scaleLabelFont = parseFont(scaleLabelOpts);
+                       var scaleLabelPadding = helpers$1.options.toPadding(scaleLabelOpts.padding);
+                       var deltaHeight = scaleLabelFont.lineHeight + scaleLabelPadding.height;
+
+                       if (isHorizontal) {
+                               minSize.height += deltaHeight;
+                       } else {
+                               minSize.width += deltaHeight;
+                       }
+               }
+
+               // Don't bother fitting the ticks if we are not showing the labels
+               if (tickOpts.display && display) {
+                       var largestTextWidth = helpers$1.longestText(me.ctx, tickFont.string, labels, me.longestTextCache);
+                       var tallestLabelHeightInLines = helpers$1.numberOfLabelLines(labels);
+                       var lineSpace = tickFont.size * 0.5;
+                       var tickPadding = me.options.ticks.padding;
+
+                       // Store max number of lines and widest label for _autoSkip
+                       me._maxLabelLines = tallestLabelHeightInLines;
+                       me.longestLabelWidth = largestTextWidth;
+
+                       if (isHorizontal) {
+                               var angleRadians = helpers$1.toRadians(me.labelRotation);
+                               var cosRotation = Math.cos(angleRadians);
+                               var sinRotation = Math.sin(angleRadians);
+
+                               // TODO - improve this calculation
+                               var labelHeight = (sinRotation * largestTextWidth)
+                                       + (tickFont.lineHeight * tallestLabelHeightInLines)
+                                       + lineSpace; // padding
+
+                               minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding);
+
+                               me.ctx.font = tickFont.string;
+                               var firstLabelWidth = computeTextSize(me.ctx, labels[0], tickFont.string);
+                               var lastLabelWidth = computeTextSize(me.ctx, labels[labels.length - 1], tickFont.string);
+                               var offsetLeft = me.getPixelForTick(0) - me.left;
+                               var offsetRight = me.right - me.getPixelForTick(labels.length - 1);
+                               var paddingLeft, paddingRight;
+
+                               // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned
+                               // which means that the right padding is dominated by the font height
+                               if (me.labelRotation !== 0) {
+                                       paddingLeft = position === 'bottom' ? (cosRotation * firstLabelWidth) : (cosRotation * lineSpace);
+                                       paddingRight = position === 'bottom' ? (cosRotation * lineSpace) : (cosRotation * lastLabelWidth);
+                               } else {
+                                       paddingLeft = firstLabelWidth / 2;
+                                       paddingRight = lastLabelWidth / 2;
+                               }
+                               me.paddingLeft = Math.max(paddingLeft - offsetLeft, 0) + 3; // add 3 px to move away from canvas edges
+                               me.paddingRight = Math.max(paddingRight - offsetRight, 0) + 3;
+                       } else {
+                               // A vertical axis is more constrained by the width. Labels are the
+                               // dominant factor here, so get that length first and account for padding
+                               if (tickOpts.mirror) {
+                                       largestTextWidth = 0;
+                               } else {
+                                       // use lineSpace for consistency with horizontal axis
+                                       // tickPadding is not implemented for horizontal
+                                       largestTextWidth += tickPadding + lineSpace;
+                               }
+
+                               minSize.width = Math.min(me.maxWidth, minSize.width + largestTextWidth);
+
+                               me.paddingTop = tickFont.size / 2;
+                               me.paddingBottom = tickFont.size / 2;
+                       }
+               }
+
+               me.handleMargins();
+
+               me.width = minSize.width;
+               me.height = minSize.height;
+       },
+
+       /**
+        * Handle margins and padding interactions
+        * @private
+        */
+       handleMargins: function() {
+               var me = this;
+               if (me.margins) {
+                       me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
+                       me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0);
+                       me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
+                       me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0);
+               }
+       },
+
+       afterFit: function() {
+               helpers$1.callback(this.options.afterFit, [this]);
+       },
+
+       // Shared Methods
+       isHorizontal: function() {
+               return this.options.position === 'top' || this.options.position === 'bottom';
+       },
+       isFullWidth: function() {
+               return (this.options.fullWidth);
+       },
+
+       // Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
+       getRightValue: function(rawValue) {
+               // Null and undefined values first
+               if (helpers$1.isNullOrUndef(rawValue)) {
+                       return NaN;
+               }
+               // isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values
+               if ((typeof rawValue === 'number' || rawValue instanceof Number) && !isFinite(rawValue)) {
+                       return NaN;
+               }
+               // If it is in fact an object, dive in one more level
+               if (rawValue) {
+                       if (this.isHorizontal()) {
+                               if (rawValue.x !== undefined) {
+                                       return this.getRightValue(rawValue.x);
+                               }
+                       } else if (rawValue.y !== undefined) {
+                               return this.getRightValue(rawValue.y);
+                       }
+               }
+
+               // Value is good, return it
+               return rawValue;
+       },
+
+       /**
+        * Used to get the value to display in the tooltip for the data at the given index
+        * @param index
+        * @param datasetIndex
+        */
+       getLabelForIndex: helpers$1.noop,
+
+       /**
+        * Returns the location of the given data point. Value can either be an index or a numerical value
+        * The coordinate (0, 0) is at the upper-left corner of the canvas
+        * @param value
+        * @param index
+        * @param datasetIndex
+        */
+       getPixelForValue: helpers$1.noop,
+
+       /**
+        * Used to get the data value from a given pixel. This is the inverse of getPixelForValue
+        * The coordinate (0, 0) is at the upper-left corner of the canvas
+        * @param pixel
+        */
+       getValueForPixel: helpers$1.noop,
+
+       /**
+        * Returns the location of the tick at the given index
+        * The coordinate (0, 0) is at the upper-left corner of the canvas
+        */
+       getPixelForTick: function(index) {
+               var me = this;
+               var offset = me.options.offset;
+               if (me.isHorizontal()) {
+                       var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
+                       var tickWidth = innerWidth / Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
+                       var pixel = (tickWidth * index) + me.paddingLeft;
+
+                       if (offset) {
+                               pixel += tickWidth / 2;
+                       }
+
+                       var finalVal = me.left + pixel;
+                       finalVal += me.isFullWidth() ? me.margins.left : 0;
+                       return finalVal;
+               }
+               var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
+               return me.top + (index * (innerHeight / (me._ticks.length - 1)));
+       },
+
+       /**
+        * Utility for getting the pixel location of a percentage of scale
+        * The coordinate (0, 0) is at the upper-left corner of the canvas
+        */
+       getPixelForDecimal: function(decimal) {
+               var me = this;
+               if (me.isHorizontal()) {
+                       var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
+                       var valueOffset = (innerWidth * decimal) + me.paddingLeft;
+
+                       var finalVal = me.left + valueOffset;
+                       finalVal += me.isFullWidth() ? me.margins.left : 0;
+                       return finalVal;
+               }
+               return me.top + (decimal * me.height);
+       },
+
+       /**
+        * Returns the pixel for the minimum chart value
+        * The coordinate (0, 0) is at the upper-left corner of the canvas
+        */
+       getBasePixel: function() {
+               return this.getPixelForValue(this.getBaseValue());
+       },
+
+       getBaseValue: function() {
+               var me = this;
+               var min = me.min;
+               var max = me.max;
+
+               return me.beginAtZero ? 0 :
+                       min < 0 && max < 0 ? max :
+                       min > 0 && max > 0 ? min :
+                       0;
+       },
+
+       /**
+        * Returns a subset of ticks to be plotted to avoid overlapping labels.
+        * @private
+        */
+       _autoSkip: function(ticks) {
+               var me = this;
+               var isHorizontal = me.isHorizontal();
+               var optionTicks = me.options.ticks.minor;
+               var tickCount = ticks.length;
+               var skipRatio = false;
+               var maxTicks = optionTicks.maxTicksLimit;
+
+               // Total space needed to display all ticks. First and last ticks are
+               // drawn as their center at end of axis, so tickCount-1
+               var ticksLength = me._tickSize() * (tickCount - 1);
+
+               // Axis length
+               var axisLength = isHorizontal
+                       ? me.width - (me.paddingLeft + me.paddingRight)
+                       : me.height - (me.paddingTop + me.PaddingBottom);
+
+               var result = [];
+               var i, tick;
+
+               if (ticksLength > axisLength) {
+                       skipRatio = 1 + Math.floor(ticksLength / axisLength);
+               }
+
+               // if they defined a max number of optionTicks,
+               // increase skipRatio until that number is met
+               if (tickCount > maxTicks) {
+                       skipRatio = Math.max(skipRatio, 1 + Math.floor(tickCount / maxTicks));
+               }
+
+               for (i = 0; i < tickCount; i++) {
+                       tick = ticks[i];
+
+                       if (skipRatio > 1 && i % skipRatio > 0) {
+                               // leave tick in place but make sure it's not displayed (#4635)
+                               delete tick.label;
+                       }
+                       result.push(tick);
+               }
+               return result;
+       },
+
+       /**
+        * @private
+        */
+       _tickSize: function() {
+               var me = this;
+               var isHorizontal = me.isHorizontal();
+               var optionTicks = me.options.ticks.minor;
+
+               // Calculate space needed by label in axis direction.
+               var rot = helpers$1.toRadians(me.labelRotation);
+               var cos = Math.abs(Math.cos(rot));
+               var sin = Math.abs(Math.sin(rot));
+
+               var padding = optionTicks.autoSkipPadding || 0;
+               var w = (me.longestLabelWidth + padding) || 0;
+
+               var tickFont = helpers$1.options._parseFont(optionTicks);
+               var h = (me._maxLabelLines * tickFont.lineHeight + padding) || 0;
+
+               // Calculate space needed for 1 tick in axis direction.
+               return isHorizontal
+                       ? h * cos > w * sin ? w / cos : h / sin
+                       : h * sin < w * cos ? h / cos : w / sin;
+       },
+
+       /**
+        * @private
+        */
+       _isVisible: function() {
+               var me = this;
+               var chart = me.chart;
+               var display = me.options.display;
+               var i, ilen, meta;
+
+               if (display !== 'auto') {
+                       return !!display;
+               }
+
+               // When 'auto', the scale is visible if at least one associated dataset is visible.
+               for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
+                       if (chart.isDatasetVisible(i)) {
+                               meta = chart.getDatasetMeta(i);
+                               if (meta.xAxisID === me.id || meta.yAxisID === me.id) {
+                                       return true;
+                               }
+                       }
+               }
+
+               return false;
+       },
+
+       /**
+        * Actually draw the scale on the canvas
+        * @param {object} chartArea - the area of the chart to draw full grid lines on
+        */
+       draw: function(chartArea) {
+               var me = this;
+               var options = me.options;
+
+               if (!me._isVisible()) {
+                       return;
+               }
+
+               var chart = me.chart;
+               var context = me.ctx;
+               var globalDefaults = core_defaults.global;
+               var defaultFontColor = globalDefaults.defaultFontColor;
+               var optionTicks = options.ticks.minor;
+               var optionMajorTicks = options.ticks.major || optionTicks;
+               var gridLines = options.gridLines;
+               var scaleLabel = options.scaleLabel;
+               var position = options.position;
+
+               var isRotated = me.labelRotation !== 0;
+               var isMirrored = optionTicks.mirror;
+               var isHorizontal = me.isHorizontal();
+
+               var parseFont = helpers$1.options._parseFont;
+               var ticks = optionTicks.display && optionTicks.autoSkip ? me._autoSkip(me.getTicks()) : me.getTicks();
+               var tickFontColor = valueOrDefault$9(optionTicks.fontColor, defaultFontColor);
+               var tickFont = parseFont(optionTicks);
+               var lineHeight = tickFont.lineHeight;
+               var majorTickFontColor = valueOrDefault$9(optionMajorTicks.fontColor, defaultFontColor);
+               var majorTickFont = parseFont(optionMajorTicks);
+               var tickPadding = optionTicks.padding;
+               var labelOffset = optionTicks.labelOffset;
+
+               var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;
+
+               var scaleLabelFontColor = valueOrDefault$9(scaleLabel.fontColor, defaultFontColor);
+               var scaleLabelFont = parseFont(scaleLabel);
+               var scaleLabelPadding = helpers$1.options.toPadding(scaleLabel.padding);
+               var labelRotationRadians = helpers$1.toRadians(me.labelRotation);
+
+               var itemsToDraw = [];
+
+               var axisWidth = gridLines.drawBorder ? valueAtIndexOrDefault(gridLines.lineWidth, 0, 0) : 0;
+               var alignPixel = helpers$1._alignPixel;
+               var borderValue, tickStart, tickEnd;
+
+               if (position === 'top') {
+                       borderValue = alignPixel(chart, me.bottom, axisWidth);
+                       tickStart = me.bottom - tl;
+                       tickEnd = borderValue - axisWidth / 2;
+               } else if (position === 'bottom') {
+                       borderValue = alignPixel(chart, me.top, axisWidth);
+                       tickStart = borderValue + axisWidth / 2;
+                       tickEnd = me.top + tl;
+               } else if (position === 'left') {
+                       borderValue = alignPixel(chart, me.right, axisWidth);
+                       tickStart = me.right - tl;
+                       tickEnd = borderValue - axisWidth / 2;
+               } else {
+                       borderValue = alignPixel(chart, me.left, axisWidth);
+                       tickStart = borderValue + axisWidth / 2;
+                       tickEnd = me.left + tl;
+               }
+
+               var epsilon = 0.0000001; // 0.0000001 is margin in pixels for Accumulated error.
+
+               helpers$1.each(ticks, function(tick, index) {
+                       // autoskipper skipped this tick (#4635)
+                       if (helpers$1.isNullOrUndef(tick.label)) {
+                               return;
+                       }
+
+                       var label = tick.label;
+                       var lineWidth, lineColor, borderDash, borderDashOffset;
+                       if (index === me.zeroLineIndex && options.offset === gridLines.offsetGridLines) {
+                               // Draw the first index specially
+                               lineWidth = gridLines.zeroLineWidth;
+                               lineColor = gridLines.zeroLineColor;
+                               borderDash = gridLines.zeroLineBorderDash || [];
+                               borderDashOffset = gridLines.zeroLineBorderDashOffset || 0.0;
+                       } else {
+                               lineWidth = valueAtIndexOrDefault(gridLines.lineWidth, index);
+                               lineColor = valueAtIndexOrDefault(gridLines.color, index);
+                               borderDash = gridLines.borderDash || [];
+                               borderDashOffset = gridLines.borderDashOffset || 0.0;
+                       }
+
+                       // Common properties
+                       var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY, textOffset, textAlign;
+                       var labelCount = helpers$1.isArray(label) ? label.length : 1;
+                       var lineValue = getPixelForGridLine(me, index, gridLines.offsetGridLines);
+
+                       if (isHorizontal) {
+                               var labelYOffset = tl + tickPadding;
+
+                               if (lineValue < me.left - epsilon) {
+                                       lineColor = 'rgba(0,0,0,0)';
+                               }
+
+                               tx1 = tx2 = x1 = x2 = alignPixel(chart, lineValue, lineWidth);
+                               ty1 = tickStart;
+                               ty2 = tickEnd;
+                               labelX = me.getPixelForTick(index) + labelOffset; // x values for optionTicks (need to consider offsetLabel option)
+
+                               if (position === 'top') {
+                                       y1 = alignPixel(chart, chartArea.top, axisWidth) + axisWidth / 2;
+                                       y2 = chartArea.bottom;
+                                       textOffset = ((!isRotated ? 0.5 : 1) - labelCount) * lineHeight;
+                                       textAlign = !isRotated ? 'center' : 'left';
+                                       labelY = me.bottom - labelYOffset;
+                               } else {
+                                       y1 = chartArea.top;
+                                       y2 = alignPixel(chart, chartArea.bottom, axisWidth) - axisWidth / 2;
+                                       textOffset = (!isRotated ? 0.5 : 0) * lineHeight;
+                                       textAlign = !isRotated ? 'center' : 'right';
+                                       labelY = me.top + labelYOffset;
+                               }
+                       } else {
+                               var labelXOffset = (isMirrored ? 0 : tl) + tickPadding;
+
+                               if (lineValue < me.top - epsilon) {
+                                       lineColor = 'rgba(0,0,0,0)';
+                               }
+
+                               tx1 = tickStart;
+                               tx2 = tickEnd;
+                               ty1 = ty2 = y1 = y2 = alignPixel(chart, lineValue, lineWidth);
+                               labelY = me.getPixelForTick(index) + labelOffset;
+                               textOffset = (1 - labelCount) * lineHeight / 2;
+
+                               if (position === 'left') {
+                                       x1 = alignPixel(chart, chartArea.left, axisWidth) + axisWidth / 2;
+                                       x2 = chartArea.right;
+                                       textAlign = isMirrored ? 'left' : 'right';
+                                       labelX = me.right - labelXOffset;
+                               } else {
+                                       x1 = chartArea.left;
+                                       x2 = alignPixel(chart, chartArea.right, axisWidth) - axisWidth / 2;
+                                       textAlign = isMirrored ? 'right' : 'left';
+                                       labelX = me.left + labelXOffset;
+                               }
+                       }
+
+                       itemsToDraw.push({
+                               tx1: tx1,
+                               ty1: ty1,
+                               tx2: tx2,
+                               ty2: ty2,
+                               x1: x1,
+                               y1: y1,
+                               x2: x2,
+                               y2: y2,
+                               labelX: labelX,
+                               labelY: labelY,
+                               glWidth: lineWidth,
+                               glColor: lineColor,
+                               glBorderDash: borderDash,
+                               glBorderDashOffset: borderDashOffset,
+                               rotation: -1 * labelRotationRadians,
+                               label: label,
+                               major: tick.major,
+                               textOffset: textOffset,
+                               textAlign: textAlign
+                       });
+               });
+
+               // Draw all of the tick labels, tick marks, and grid lines at the correct places
+               helpers$1.each(itemsToDraw, function(itemToDraw) {
+                       var glWidth = itemToDraw.glWidth;
+                       var glColor = itemToDraw.glColor;
+
+                       if (gridLines.display && glWidth && glColor) {
+                               context.save();
+                               context.lineWidth = glWidth;
+                               context.strokeStyle = glColor;
+                               if (context.setLineDash) {
+                                       context.setLineDash(itemToDraw.glBorderDash);
+                                       context.lineDashOffset = itemToDraw.glBorderDashOffset;
+                               }
+
+                               context.beginPath();
+
+                               if (gridLines.drawTicks) {
+                                       context.moveTo(itemToDraw.tx1, itemToDraw.ty1);
+                                       context.lineTo(itemToDraw.tx2, itemToDraw.ty2);
+                               }
+
+                               if (gridLines.drawOnChartArea) {
+                                       context.moveTo(itemToDraw.x1, itemToDraw.y1);
+                                       context.lineTo(itemToDraw.x2, itemToDraw.y2);
+                               }
+
+                               context.stroke();
+                               context.restore();
+                       }
+
+                       if (optionTicks.display) {
+                               // Make sure we draw text in the correct color and font
+                               context.save();
+                               context.translate(itemToDraw.labelX, itemToDraw.labelY);
+                               context.rotate(itemToDraw.rotation);
+                               context.font = itemToDraw.major ? majorTickFont.string : tickFont.string;
+                               context.fillStyle = itemToDraw.major ? majorTickFontColor : tickFontColor;
+                               context.textBaseline = 'middle';
+                               context.textAlign = itemToDraw.textAlign;
+
+                               var label = itemToDraw.label;
+                               var y = itemToDraw.textOffset;
+                               if (helpers$1.isArray(label)) {
+                                       for (var i = 0; i < label.length; ++i) {
+                                               // We just make sure the multiline element is a string here..
+                                               context.fillText('' + label[i], 0, y);
+                                               y += lineHeight;
+                                       }
+                               } else {
+                                       context.fillText(label, 0, y);
+                               }
+                               context.restore();
+                       }
+               });
+
+               if (scaleLabel.display) {
+                       // Draw the scale label
+                       var scaleLabelX;
+                       var scaleLabelY;
+                       var rotation = 0;
+                       var halfLineHeight = scaleLabelFont.lineHeight / 2;
+
+                       if (isHorizontal) {
+                               scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
+                               scaleLabelY = position === 'bottom'
+                                       ? me.bottom - halfLineHeight - scaleLabelPadding.bottom
+                                       : me.top + halfLineHeight + scaleLabelPadding.top;
+                       } else {
+                               var isLeft = position === 'left';
+                               scaleLabelX = isLeft
+                                       ? me.left + halfLineHeight + scaleLabelPadding.top
+                                       : me.right - halfLineHeight - scaleLabelPadding.top;
+                               scaleLabelY = me.top + ((me.bottom - me.top) / 2);
+                               rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
+                       }
+
+                       context.save();
+                       context.translate(scaleLabelX, scaleLabelY);
+                       context.rotate(rotation);
+                       context.textAlign = 'center';
+                       context.textBaseline = 'middle';
+                       context.fillStyle = scaleLabelFontColor; // render in correct colour
+                       context.font = scaleLabelFont.string;
+                       context.fillText(scaleLabel.labelString, 0, 0);
+                       context.restore();
+               }
+
+               if (axisWidth) {
+                       // Draw the line at the edge of the axis
+                       var firstLineWidth = axisWidth;
+                       var lastLineWidth = valueAtIndexOrDefault(gridLines.lineWidth, ticks.length - 1, 0);
+                       var x1, x2, y1, y2;
+
+                       if (isHorizontal) {
+                               x1 = alignPixel(chart, me.left, firstLineWidth) - firstLineWidth / 2;
+                               x2 = alignPixel(chart, me.right, lastLineWidth) + lastLineWidth / 2;
+                               y1 = y2 = borderValue;
+                       } else {
+                               y1 = alignPixel(chart, me.top, firstLineWidth) - firstLineWidth / 2;
+                               y2 = alignPixel(chart, me.bottom, lastLineWidth) + lastLineWidth / 2;
+                               x1 = x2 = borderValue;
+                       }
+
+                       context.lineWidth = axisWidth;
+                       context.strokeStyle = valueAtIndexOrDefault(gridLines.color, 0);
+                       context.beginPath();
+                       context.moveTo(x1, y1);
+                       context.lineTo(x2, y2);
+                       context.stroke();
+               }
+       }
+});
+
+var defaultConfig = {
+       position: 'bottom'
+};
+
+var scale_category = core_scale.extend({
+       /**
+       * Internal function to get the correct labels. If data.xLabels or data.yLabels are defined, use those
+       * else fall back to data.labels
+       * @private
+       */
+       getLabels: function() {
+               var data = this.chart.data;
+               return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels;
+       },
+
+       determineDataLimits: function() {
+               var me = this;
+               var labels = me.getLabels();
+               me.minIndex = 0;
+               me.maxIndex = labels.length - 1;
+               var findIndex;
+
+               if (me.options.ticks.min !== undefined) {
+                       // user specified min value
+                       findIndex = labels.indexOf(me.options.ticks.min);
+                       me.minIndex = findIndex !== -1 ? findIndex : me.minIndex;
+               }
+
+               if (me.options.ticks.max !== undefined) {
+                       // user specified max value
+                       findIndex = labels.indexOf(me.options.ticks.max);
+                       me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex;
+               }
+
+               me.min = labels[me.minIndex];
+               me.max = labels[me.maxIndex];
+       },
+
+       buildTicks: function() {
+               var me = this;
+               var labels = me.getLabels();
+               // If we are viewing some subset of labels, slice the original array
+               me.ticks = (me.minIndex === 0 && me.maxIndex === labels.length - 1) ? labels : labels.slice(me.minIndex, me.maxIndex + 1);
+       },
+
+       getLabelForIndex: function(index, datasetIndex) {
+               var me = this;
+               var chart = me.chart;
+
+               if (chart.getDatasetMeta(datasetIndex).controller._getValueScaleId() === me.id) {
+                       return me.getRightValue(chart.data.datasets[datasetIndex].data[index]);
+               }
+
+               return me.ticks[index - me.minIndex];
+       },
+
+       // Used to get data value locations.  Value can either be an index or a numerical value
+       getPixelForValue: function(value, index) {
+               var me = this;
+               var offset = me.options.offset;
+               // 1 is added because we need the length but we have the indexes
+               var offsetAmt = Math.max((me.maxIndex + 1 - me.minIndex - (offset ? 0 : 1)), 1);
+
+               // If value is a data object, then index is the index in the data array,
+               // not the index of the scale. We need to change that.
+               var valueCategory;
+               if (value !== undefined && value !== null) {
+                       valueCategory = me.isHorizontal() ? value.x : value.y;
+               }
+               if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
+                       var labels = me.getLabels();
+                       value = valueCategory || value;
+                       var idx = labels.indexOf(value);
+                       index = idx !== -1 ? idx : index;
+               }
+
+               if (me.isHorizontal()) {
+                       var valueWidth = me.width / offsetAmt;
+                       var widthOffset = (valueWidth * (index - me.minIndex));
+
+                       if (offset) {
+                               widthOffset += (valueWidth / 2);
+                       }
+
+                       return me.left + widthOffset;
+               }
+               var valueHeight = me.height / offsetAmt;
+               var heightOffset = (valueHeight * (index - me.minIndex));
+
+               if (offset) {
+                       heightOffset += (valueHeight / 2);
+               }
+
+               return me.top + heightOffset;
+       },
+
+       getPixelForTick: function(index) {
+               return this.getPixelForValue(this.ticks[index], index + this.minIndex, null);
+       },
+
+       getValueForPixel: function(pixel) {
+               var me = this;
+               var offset = me.options.offset;
+               var value;
+               var offsetAmt = Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
+               var horz = me.isHorizontal();
+               var valueDimension = (horz ? me.width : me.height) / offsetAmt;
+
+               pixel -= horz ? me.left : me.top;
+
+               if (offset) {
+                       pixel -= (valueDimension / 2);
+               }
+
+               if (pixel <= 0) {
+                       value = 0;
+               } else {
+                       value = Math.round(pixel / valueDimension);
+               }
+
+               return value + me.minIndex;
+       },
+
+       getBasePixel: function() {
+               return this.bottom;
+       }
+});
+
+// INTERNAL: static default options, registered in src/index.js
+var _defaults = defaultConfig;
+scale_category._defaults = _defaults;
+
+var noop = helpers$1.noop;
+var isNullOrUndef = helpers$1.isNullOrUndef;
+
+/**
+ * Generate a set of linear ticks
+ * @param generationOptions the options used to generate the ticks
+ * @param dataRange the range of the data
+ * @returns {number[]} array of tick values
+ */
+function generateTicks(generationOptions, dataRange) {
+       var ticks = [];
+       // To get a "nice" value for the tick spacing, we will use the appropriately named
+       // "nice number" algorithm. See https://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
+       // for details.
+
+       var MIN_SPACING = 1e-14;
+       var stepSize = generationOptions.stepSize;
+       var unit = stepSize || 1;
+       var maxNumSpaces = generationOptions.maxTicks - 1;
+       var min = generationOptions.min;
+       var max = generationOptions.max;
+       var precision = generationOptions.precision;
+       var rmin = dataRange.min;
+       var rmax = dataRange.max;
+       var spacing = helpers$1.niceNum((rmax - rmin) / maxNumSpaces / unit) * unit;
+       var factor, niceMin, niceMax, numSpaces;
+
+       // Beyond MIN_SPACING floating point numbers being to lose precision
+       // such that we can't do the math necessary to generate ticks
+       if (spacing < MIN_SPACING && isNullOrUndef(min) && isNullOrUndef(max)) {
+               return [rmin, rmax];
+       }
+
+       numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing);
+       if (numSpaces > maxNumSpaces) {
+               // If the calculated num of spaces exceeds maxNumSpaces, recalculate it
+               spacing = helpers$1.niceNum(numSpaces * spacing / maxNumSpaces / unit) * unit;
+       }
+
+       if (stepSize || isNullOrUndef(precision)) {
+               // If a precision is not specified, calculate factor based on spacing
+               factor = Math.pow(10, helpers$1._decimalPlaces(spacing));
+       } else {
+               // If the user specified a precision, round to that number of decimal places
+               factor = Math.pow(10, precision);
+               spacing = Math.ceil(spacing * factor) / factor;
+       }
+
+       niceMin = Math.floor(rmin / spacing) * spacing;
+       niceMax = Math.ceil(rmax / spacing) * spacing;
+
+       // If min, max and stepSize is set and they make an evenly spaced scale use it.
+       if (stepSize) {
+               // If very close to our whole number, use it.
+               if (!isNullOrUndef(min) && helpers$1.almostWhole(min / spacing, spacing / 1000)) {
+                       niceMin = min;
+               }
+               if (!isNullOrUndef(max) && helpers$1.almostWhole(max / spacing, spacing / 1000)) {
+                       niceMax = max;
+               }
+       }
+
+       numSpaces = (niceMax - niceMin) / spacing;
+       // If very close to our rounded value, use it.
+       if (helpers$1.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
+               numSpaces = Math.round(numSpaces);
+       } else {
+               numSpaces = Math.ceil(numSpaces);
+       }
+
+       niceMin = Math.round(niceMin * factor) / factor;
+       niceMax = Math.round(niceMax * factor) / factor;
+       ticks.push(isNullOrUndef(min) ? niceMin : min);
+       for (var j = 1; j < numSpaces; ++j) {
+               ticks.push(Math.round((niceMin + j * spacing) * factor) / factor);
+       }
+       ticks.push(isNullOrUndef(max) ? niceMax : max);
+
+       return ticks;
+}
+
+var scale_linearbase = core_scale.extend({
+       getRightValue: function(value) {
+               if (typeof value === 'string') {
+                       return +value;
+               }
+               return core_scale.prototype.getRightValue.call(this, value);
+       },
+
+       handleTickRangeOptions: function() {
+               var me = this;
+               var opts = me.options;
+               var tickOpts = opts.ticks;
+
+               // If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
+               // do nothing since that would make the chart weird. If the user really wants a weird chart
+               // axis, they can manually override it
+               if (tickOpts.beginAtZero) {
+                       var minSign = helpers$1.sign(me.min);
+                       var maxSign = helpers$1.sign(me.max);
+
+                       if (minSign < 0 && maxSign < 0) {
+                               // move the top up to 0
+                               me.max = 0;
+                       } else if (minSign > 0 && maxSign > 0) {
+                               // move the bottom down to 0
+                               me.min = 0;
+                       }
+               }
+
+               var setMin = tickOpts.min !== undefined || tickOpts.suggestedMin !== undefined;
+               var setMax = tickOpts.max !== undefined || tickOpts.suggestedMax !== undefined;
+
+               if (tickOpts.min !== undefined) {
+                       me.min = tickOpts.min;
+               } else if (tickOpts.suggestedMin !== undefined) {
+                       if (me.min === null) {
+                               me.min = tickOpts.suggestedMin;
+                       } else {
+                               me.min = Math.min(me.min, tickOpts.suggestedMin);
+                       }
+               }
+
+               if (tickOpts.max !== undefined) {
+                       me.max = tickOpts.max;
+               } else if (tickOpts.suggestedMax !== undefined) {
+                       if (me.max === null) {
+                               me.max = tickOpts.suggestedMax;
+                       } else {
+                               me.max = Math.max(me.max, tickOpts.suggestedMax);
+                       }
+               }
+
+               if (setMin !== setMax) {
+                       // We set the min or the max but not both.
+                       // So ensure that our range is good
+                       // Inverted or 0 length range can happen when
+                       // ticks.min is set, and no datasets are visible
+                       if (me.min >= me.max) {
+                               if (setMin) {
+                                       me.max = me.min + 1;
+                               } else {
+                                       me.min = me.max - 1;
+                               }
+                       }
+               }
+
+               if (me.min === me.max) {
+                       me.max++;
+
+                       if (!tickOpts.beginAtZero) {
+                               me.min--;
+                       }
+               }
+       },
+
+       getTickLimit: function() {
+               var me = this;
+               var tickOpts = me.options.ticks;
+               var stepSize = tickOpts.stepSize;
+               var maxTicksLimit = tickOpts.maxTicksLimit;
+               var maxTicks;
+
+               if (stepSize) {
+                       maxTicks = Math.ceil(me.max / stepSize) - Math.floor(me.min / stepSize) + 1;
+               } else {
+                       maxTicks = me._computeTickLimit();
+                       maxTicksLimit = maxTicksLimit || 11;
+               }
+
+               if (maxTicksLimit) {
+                       maxTicks = Math.min(maxTicksLimit, maxTicks);
+               }
+
+               return maxTicks;
+       },
+
+       _computeTickLimit: function() {
+               return Number.POSITIVE_INFINITY;
+       },
+
+       handleDirectionalChanges: noop,
+
+       buildTicks: function() {
+               var me = this;
+               var opts = me.options;
+               var tickOpts = opts.ticks;
+
+               // Figure out what the max number of ticks we can support it is based on the size of
+               // the axis area. For now, we say that the minimum tick spacing in pixels must be 40
+               // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
+               // the graph. Make sure we always have at least 2 ticks
+               var maxTicks = me.getTickLimit();
+               maxTicks = Math.max(2, maxTicks);
+
+               var numericGeneratorOptions = {
+                       maxTicks: maxTicks,
+                       min: tickOpts.min,
+                       max: tickOpts.max,
+                       precision: tickOpts.precision,
+                       stepSize: helpers$1.valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)
+               };
+               var ticks = me.ticks = generateTicks(numericGeneratorOptions, me);
+
+               me.handleDirectionalChanges();
+
+               // At this point, we need to update our max and min given the tick values since we have expanded the
+               // range of the scale
+               me.max = helpers$1.max(ticks);
+               me.min = helpers$1.min(ticks);
+
+               if (tickOpts.reverse) {
+                       ticks.reverse();
+
+                       me.start = me.max;
+                       me.end = me.min;
+               } else {
+                       me.start = me.min;
+                       me.end = me.max;
+               }
+       },
+
+       convertTicksToLabels: function() {
+               var me = this;
+               me.ticksAsNumbers = me.ticks.slice();
+               me.zeroLineIndex = me.ticks.indexOf(0);
+
+               core_scale.prototype.convertTicksToLabels.call(me);
+       }
+});
+
+var defaultConfig$1 = {
+       position: 'left',
+       ticks: {
+               callback: core_ticks.formatters.linear
+       }
+};
+
+var scale_linear = scale_linearbase.extend({
+       determineDataLimits: function() {
+               var me = this;
+               var opts = me.options;
+               var chart = me.chart;
+               var data = chart.data;
+               var datasets = data.datasets;
+               var isHorizontal = me.isHorizontal();
+               var DEFAULT_MIN = 0;
+               var DEFAULT_MAX = 1;
+
+               function IDMatches(meta) {
+                       return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
+               }
+
+               // First Calculate the range
+               me.min = null;
+               me.max = null;
+
+               var hasStacks = opts.stacked;
+               if (hasStacks === undefined) {
+                       helpers$1.each(datasets, function(dataset, datasetIndex) {
+                               if (hasStacks) {
+                                       return;
+                               }
+
+                               var meta = chart.getDatasetMeta(datasetIndex);
+                               if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
+                                       meta.stack !== undefined) {
+                                       hasStacks = true;
+                               }
+                       });
+               }
+
+               if (opts.stacked || hasStacks) {
+                       var valuesPerStack = {};
+
+                       helpers$1.each(datasets, function(dataset, datasetIndex) {
+                               var meta = chart.getDatasetMeta(datasetIndex);
+                               var key = [
+                                       meta.type,
+                                       // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
+                                       ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
+                                       meta.stack
+                               ].join('.');
+
+                               if (valuesPerStack[key] === undefined) {
+                                       valuesPerStack[key] = {
+                                               positiveValues: [],
+                                               negativeValues: []
+                                       };
+                               }
+
+                               // Store these per type
+                               var positiveValues = valuesPerStack[key].positiveValues;
+                               var negativeValues = valuesPerStack[key].negativeValues;
+
+                               if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+                                       helpers$1.each(dataset.data, function(rawValue, index) {
+                                               var value = +me.getRightValue(rawValue);
+                                               if (isNaN(value) || meta.data[index].hidden) {
+                                                       return;
+                                               }
+
+                                               positiveValues[index] = positiveValues[index] || 0;
+                                               negativeValues[index] = negativeValues[index] || 0;
+
+                                               if (opts.relativePoints) {
+                                                       positiveValues[index] = 100;
+                                               } else if (value < 0) {
+                                                       negativeValues[index] += value;
+                                               } else {
+                                                       positiveValues[index] += value;
+                                               }
+                                       });
+                               }
+                       });
+
+                       helpers$1.each(valuesPerStack, function(valuesForType) {
+                               var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
+                               var minVal = helpers$1.min(values);
+                               var maxVal = helpers$1.max(values);
+                               me.min = me.min === null ? minVal : Math.min(me.min, minVal);
+                               me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
+                       });
+
+               } else {
+                       helpers$1.each(datasets, function(dataset, datasetIndex) {
+                               var meta = chart.getDatasetMeta(datasetIndex);
+                               if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+                                       helpers$1.each(dataset.data, function(rawValue, index) {
+                                               var value = +me.getRightValue(rawValue);
+                                               if (isNaN(value) || meta.data[index].hidden) {
+                                                       return;
+                                               }
+
+                                               if (me.min === null) {
+                                                       me.min = value;
+                                               } else if (value < me.min) {
+                                                       me.min = value;
+                                               }
+
+                                               if (me.max === null) {
+                                                       me.max = value;
+                                               } else if (value > me.max) {
+                                                       me.max = value;
+                                               }
+                                       });
+                               }
+                       });
+               }
+
+               me.min = isFinite(me.min) && !isNaN(me.min) ? me.min : DEFAULT_MIN;
+               me.max = isFinite(me.max) && !isNaN(me.max) ? me.max : DEFAULT_MAX;
+
+               // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
+               this.handleTickRangeOptions();
+       },
+
+       // Returns the maximum number of ticks based on the scale dimension
+       _computeTickLimit: function() {
+               var me = this;
+               var tickFont;
+
+               if (me.isHorizontal()) {
+                       return Math.ceil(me.width / 40);
+               }
+               tickFont = helpers$1.options._parseFont(me.options.ticks);
+               return Math.ceil(me.height / tickFont.lineHeight);
+       },
+
+       // Called after the ticks are built. We need
+       handleDirectionalChanges: function() {
+               if (!this.isHorizontal()) {
+                       // We are in a vertical orientation. The top value is the highest. So reverse the array
+                       this.ticks.reverse();
+               }
+       },
+
+       getLabelForIndex: function(index, datasetIndex) {
+               return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
+       },
+
+       // Utils
+       getPixelForValue: function(value) {
+               // This must be called after fit has been run so that
+               // this.left, this.top, this.right, and this.bottom have been defined
+               var me = this;
+               var start = me.start;
+
+               var rightValue = +me.getRightValue(value);
+               var pixel;
+               var range = me.end - start;
+
+               if (me.isHorizontal()) {
+                       pixel = me.left + (me.width / range * (rightValue - start));
+               } else {
+                       pixel = me.bottom - (me.height / range * (rightValue - start));
+               }
+               return pixel;
+       },
+
+       getValueForPixel: function(pixel) {
+               var me = this;
+               var isHorizontal = me.isHorizontal();
+               var innerDimension = isHorizontal ? me.width : me.height;
+               var offset = (isHorizontal ? pixel - me.left : me.bottom - pixel) / innerDimension;
+               return me.start + ((me.end - me.start) * offset);
+       },
+
+       getPixelForTick: function(index) {
+               return this.getPixelForValue(this.ticksAsNumbers[index]);
+       }
+});
+
+// INTERNAL: static default options, registered in src/index.js
+var _defaults$1 = defaultConfig$1;
+scale_linear._defaults = _defaults$1;
+
+var valueOrDefault$a = helpers$1.valueOrDefault;
+
+/**
+ * Generate a set of logarithmic ticks
+ * @param generationOptions the options used to generate the ticks
+ * @param dataRange the range of the data
+ * @returns {number[]} array of tick values
+ */
+function generateTicks$1(generationOptions, dataRange) {
+       var ticks = [];
+
+       var tickVal = valueOrDefault$a(generationOptions.min, Math.pow(10, Math.floor(helpers$1.log10(dataRange.min))));
+
+       var endExp = Math.floor(helpers$1.log10(dataRange.max));
+       var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
+       var exp, significand;
+
+       if (tickVal === 0) {
+               exp = Math.floor(helpers$1.log10(dataRange.minNotZero));
+               significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));
+
+               ticks.push(tickVal);
+               tickVal = significand * Math.pow(10, exp);
+       } else {
+               exp = Math.floor(helpers$1.log10(tickVal));
+               significand = Math.floor(tickVal / Math.pow(10, exp));
+       }
+       var precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
+
+       do {
+               ticks.push(tickVal);
+
+               ++significand;
+               if (significand === 10) {
+                       significand = 1;
+                       ++exp;
+                       precision = exp >= 0 ? 1 : precision;
+               }
+
+               tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision;
+       } while (exp < endExp || (exp === endExp && significand < endSignificand));
+
+       var lastTick = valueOrDefault$a(generationOptions.max, tickVal);
+       ticks.push(lastTick);
+
+       return ticks;
+}
+
+var defaultConfig$2 = {
+       position: 'left',
+
+       // label settings
+       ticks: {
+               callback: core_ticks.formatters.logarithmic
+       }
+};
+
+// TODO(v3): change this to positiveOrDefault
+function nonNegativeOrDefault(value, defaultValue) {
+       return helpers$1.isFinite(value) && value >= 0 ? value : defaultValue;
+}
+
+var scale_logarithmic = core_scale.extend({
+       determineDataLimits: function() {
+               var me = this;
+               var opts = me.options;
+               var chart = me.chart;
+               var data = chart.data;
+               var datasets = data.datasets;
+               var isHorizontal = me.isHorizontal();
+               function IDMatches(meta) {
+                       return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
+               }
+
+               // Calculate Range
+               me.min = null;
+               me.max = null;
+               me.minNotZero = null;
+
+               var hasStacks = opts.stacked;
+               if (hasStacks === undefined) {
+                       helpers$1.each(datasets, function(dataset, datasetIndex) {
+                               if (hasStacks) {
+                                       return;
+                               }
+
+                               var meta = chart.getDatasetMeta(datasetIndex);
+                               if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
+                                       meta.stack !== undefined) {
+                                       hasStacks = true;
+                               }
+                       });
+               }
+
+               if (opts.stacked || hasStacks) {
+                       var valuesPerStack = {};
+
+                       helpers$1.each(datasets, function(dataset, datasetIndex) {
+                               var meta = chart.getDatasetMeta(datasetIndex);
+                               var key = [
+                                       meta.type,
+                                       // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
+                                       ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
+                                       meta.stack
+                               ].join('.');
+
+                               if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+                                       if (valuesPerStack[key] === undefined) {
+                                               valuesPerStack[key] = [];
+                                       }
+
+                                       helpers$1.each(dataset.data, function(rawValue, index) {
+                                               var values = valuesPerStack[key];
+                                               var value = +me.getRightValue(rawValue);
+                                               // invalid, hidden and negative values are ignored
+                                               if (isNaN(value) || meta.data[index].hidden || value < 0) {
+                                                       return;
+                                               }
+                                               values[index] = values[index] || 0;
+                                               values[index] += value;
+                                       });
+                               }
+                       });
+
+                       helpers$1.each(valuesPerStack, function(valuesForType) {
+                               if (valuesForType.length > 0) {
+                                       var minVal = helpers$1.min(valuesForType);
+                                       var maxVal = helpers$1.max(valuesForType);
+                                       me.min = me.min === null ? minVal : Math.min(me.min, minVal);
+                                       me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
+                               }
+                       });
+
+               } else {
+                       helpers$1.each(datasets, function(dataset, datasetIndex) {
+                               var meta = chart.getDatasetMeta(datasetIndex);
+                               if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+                                       helpers$1.each(dataset.data, function(rawValue, index) {
+                                               var value = +me.getRightValue(rawValue);
+                                               // invalid, hidden and negative values are ignored
+                                               if (isNaN(value) || meta.data[index].hidden || value < 0) {
+                                                       return;
+                                               }
+
+                                               if (me.min === null) {
+                                                       me.min = value;
+                                               } else if (value < me.min) {
+                                                       me.min = value;
+                                               }
+
+                                               if (me.max === null) {
+                                                       me.max = value;
+                                               } else if (value > me.max) {
+                                                       me.max = value;
+                                               }
+
+                                               if (value !== 0 && (me.minNotZero === null || value < me.minNotZero)) {
+                                                       me.minNotZero = value;
+                                               }
+                                       });
+                               }
+                       });
+               }
+
+               // Common base implementation to handle ticks.min, ticks.max
+               this.handleTickRangeOptions();
+       },
+
+       handleTickRangeOptions: function() {
+               var me = this;
+               var tickOpts = me.options.ticks;
+               var DEFAULT_MIN = 1;
+               var DEFAULT_MAX = 10;
+
+               me.min = nonNegativeOrDefault(tickOpts.min, me.min);
+               me.max = nonNegativeOrDefault(tickOpts.max, me.max);
+
+               if (me.min === me.max) {
+                       if (me.min !== 0 && me.min !== null) {
+                               me.min = Math.pow(10, Math.floor(helpers$1.log10(me.min)) - 1);
+                               me.max = Math.pow(10, Math.floor(helpers$1.log10(me.max)) + 1);
+                       } else {
+                               me.min = DEFAULT_MIN;
+                               me.max = DEFAULT_MAX;
+                       }
+               }
+               if (me.min === null) {
+                       me.min = Math.pow(10, Math.floor(helpers$1.log10(me.max)) - 1);
+               }
+               if (me.max === null) {
+                       me.max = me.min !== 0
+                               ? Math.pow(10, Math.floor(helpers$1.log10(me.min)) + 1)
+                               : DEFAULT_MAX;
+               }
+               if (me.minNotZero === null) {
+                       if (me.min > 0) {
+                               me.minNotZero = me.min;
+                       } else if (me.max < 1) {
+                               me.minNotZero = Math.pow(10, Math.floor(helpers$1.log10(me.max)));
+                       } else {
+                               me.minNotZero = DEFAULT_MIN;
+                       }
+               }
+       },
+
+       buildTicks: function() {
+               var me = this;
+               var tickOpts = me.options.ticks;
+               var reverse = !me.isHorizontal();
+
+               var generationOptions = {
+                       min: nonNegativeOrDefault(tickOpts.min),
+                       max: nonNegativeOrDefault(tickOpts.max)
+               };
+               var ticks = me.ticks = generateTicks$1(generationOptions, me);
+
+               // At this point, we need to update our max and min given the tick values since we have expanded the
+               // range of the scale
+               me.max = helpers$1.max(ticks);
+               me.min = helpers$1.min(ticks);
+
+               if (tickOpts.reverse) {
+                       reverse = !reverse;
+                       me.start = me.max;
+                       me.end = me.min;
+               } else {
+                       me.start = me.min;
+                       me.end = me.max;
+               }
+               if (reverse) {
+                       ticks.reverse();
+               }
+       },
+
+       convertTicksToLabels: function() {
+               this.tickValues = this.ticks.slice();
+
+               core_scale.prototype.convertTicksToLabels.call(this);
+       },
+
+       // Get the correct tooltip label
+       getLabelForIndex: function(index, datasetIndex) {
+               return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
+       },
+
+       getPixelForTick: function(index) {
+               return this.getPixelForValue(this.tickValues[index]);
+       },
+
+       /**
+        * Returns the value of the first tick.
+        * @param {number} value - The minimum not zero value.
+        * @return {number} The first tick value.
+        * @private
+        */
+       _getFirstTickValue: function(value) {
+               var exp = Math.floor(helpers$1.log10(value));
+               var significand = Math.floor(value / Math.pow(10, exp));
+
+               return significand * Math.pow(10, exp);
+       },
+
+       getPixelForValue: function(value) {
+               var me = this;
+               var tickOpts = me.options.ticks;
+               var reverse = tickOpts.reverse;
+               var log10 = helpers$1.log10;
+               var firstTickValue = me._getFirstTickValue(me.minNotZero);
+               var offset = 0;
+               var innerDimension, pixel, start, end, sign;
+
+               value = +me.getRightValue(value);
+               if (reverse) {
+                       start = me.end;
+                       end = me.start;
+                       sign = -1;
+               } else {
+                       start = me.start;
+                       end = me.end;
+                       sign = 1;
+               }
+               if (me.isHorizontal()) {
+                       innerDimension = me.width;
+                       pixel = reverse ? me.right : me.left;
+               } else {
+                       innerDimension = me.height;
+                       sign *= -1; // invert, since the upper-left corner of the canvas is at pixel (0, 0)
+                       pixel = reverse ? me.top : me.bottom;
+               }
+               if (value !== start) {
+                       if (start === 0) { // include zero tick
+                               offset = valueOrDefault$a(tickOpts.fontSize, core_defaults.global.defaultFontSize);
+                               innerDimension -= offset;
+                               start = firstTickValue;
+                       }
+                       if (value !== 0) {
+                               offset += innerDimension / (log10(end) - log10(start)) * (log10(value) - log10(start));
+                       }
+                       pixel += sign * offset;
+               }
+               return pixel;
+       },
+
+       getValueForPixel: function(pixel) {
+               var me = this;
+               var tickOpts = me.options.ticks;
+               var reverse = tickOpts.reverse;
+               var log10 = helpers$1.log10;
+               var firstTickValue = me._getFirstTickValue(me.minNotZero);
+               var innerDimension, start, end, value;
+
+               if (reverse) {
+                       start = me.end;
+                       end = me.start;
+               } else {
+                       start = me.start;
+                       end = me.end;
+               }
+               if (me.isHorizontal()) {
+                       innerDimension = me.width;
+                       value = reverse ? me.right - pixel : pixel - me.left;
+               } else {
+                       innerDimension = me.height;
+                       value = reverse ? pixel - me.top : me.bottom - pixel;
+               }
+               if (value !== start) {
+                       if (start === 0) { // include zero tick
+                               var offset = valueOrDefault$a(tickOpts.fontSize, core_defaults.global.defaultFontSize);
+                               value -= offset;
+                               innerDimension -= offset;
+                               start = firstTickValue;
+                       }
+                       value *= log10(end) - log10(start);
+                       value /= innerDimension;
+                       value = Math.pow(10, log10(start) + value);
+               }
+               return value;
+       }
+});
+
+// INTERNAL: static default options, registered in src/index.js
+var _defaults$2 = defaultConfig$2;
+scale_logarithmic._defaults = _defaults$2;
+
+var valueOrDefault$b = helpers$1.valueOrDefault;
+var valueAtIndexOrDefault$1 = helpers$1.valueAtIndexOrDefault;
+var resolve$7 = helpers$1.options.resolve;
+
+var defaultConfig$3 = {
+       display: true,
+
+       // Boolean - Whether to animate scaling the chart from the centre
+       animate: true,
+       position: 'chartArea',
+
+       angleLines: {
+               display: true,
+               color: 'rgba(0, 0, 0, 0.1)',
+               lineWidth: 1,
+               borderDash: [],
+               borderDashOffset: 0.0
+       },
+
+       gridLines: {
+               circular: false
+       },
+
+       // label settings
+       ticks: {
+               // Boolean - Show a backdrop to the scale label
+               showLabelBackdrop: true,
+
+               // String - The colour of the label backdrop
+               backdropColor: 'rgba(255,255,255,0.75)',
+
+               // Number - The backdrop padding above & below the label in pixels
+               backdropPaddingY: 2,
+
+               // Number - The backdrop padding to the side of the label in pixels
+               backdropPaddingX: 2,
+
+               callback: core_ticks.formatters.linear
+       },
+
+       pointLabels: {
+               // Boolean - if true, show point labels
+               display: true,
+
+               // Number - Point label font size in pixels
+               fontSize: 10,
+
+               // Function - Used to convert point labels
+               callback: function(label) {
+                       return label;
+               }
+       }
+};
+
+function getValueCount(scale) {
+       var opts = scale.options;
+       return opts.angleLines.display || opts.pointLabels.display ? scale.chart.data.labels.length : 0;
+}
+
+function getTickBackdropHeight(opts) {
+       var tickOpts = opts.ticks;
+
+       if (tickOpts.display && opts.display) {
+               return valueOrDefault$b(tickOpts.fontSize, core_defaults.global.defaultFontSize) + tickOpts.backdropPaddingY * 2;
+       }
+       return 0;
+}
+
+function measureLabelSize(ctx, lineHeight, label) {
+       if (helpers$1.isArray(label)) {
+               return {
+                       w: helpers$1.longestText(ctx, ctx.font, label),
+                       h: label.length * lineHeight
+               };
+       }
+
+       return {
+               w: ctx.measureText(label).width,
+               h: lineHeight
+       };
+}
+
+function determineLimits(angle, pos, size, min, max) {
+       if (angle === min || angle === max) {
+               return {
+                       start: pos - (size / 2),
+                       end: pos + (size / 2)
+               };
+       } else if (angle < min || angle > max) {
+               return {
+                       start: pos - size,
+                       end: pos
+               };
+       }
+
+       return {
+               start: pos,
+               end: pos + size
+       };
+}
+
+/**
+ * Helper function to fit a radial linear scale with point labels
+ */
+function fitWithPointLabels(scale) {
+
+       // Right, this is really confusing and there is a lot of maths going on here
+       // The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
+       //
+       // Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
+       //
+       // Solution:
+       //
+       // We assume the radius of the polygon is half the size of the canvas at first
+       // at each index we check if the text overlaps.
+       //
+       // Where it does, we store that angle and that index.
+       //
+       // After finding the largest index and angle we calculate how much we need to remove
+       // from the shape radius to move the point inwards by that x.
+       //
+       // We average the left and right distances to get the maximum shape radius that can fit in the box
+       // along with labels.
+       //
+       // Once we have that, we can find the centre point for the chart, by taking the x text protrusion
+       // on each side, removing that from the size, halving it and adding the left x protrusion width.
+       //
+       // This will mean we have a shape fitted to the canvas, as large as it can be with the labels
+       // and position it in the most space efficient manner
+       //
+       // https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
+
+       var plFont = helpers$1.options._parseFont(scale.options.pointLabels);
+
+       // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
+       // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
+       var furthestLimits = {
+               l: 0,
+               r: scale.width,
+               t: 0,
+               b: scale.height - scale.paddingTop
+       };
+       var furthestAngles = {};
+       var i, textSize, pointPosition;
+
+       scale.ctx.font = plFont.string;
+       scale._pointLabelSizes = [];
+
+       var valueCount = getValueCount(scale);
+       for (i = 0; i < valueCount; i++) {
+               pointPosition = scale.getPointPosition(i, scale.drawingArea + 5);
+               textSize = measureLabelSize(scale.ctx, plFont.lineHeight, scale.pointLabels[i] || '');
+               scale._pointLabelSizes[i] = textSize;
+
+               // Add quarter circle to make degree 0 mean top of circle
+               var angleRadians = scale.getIndexAngle(i);
+               var angle = helpers$1.toDegrees(angleRadians) % 360;
+               var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
+               var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
+
+               if (hLimits.start < furthestLimits.l) {
+                       furthestLimits.l = hLimits.start;
+                       furthestAngles.l = angleRadians;
+               }
+
+               if (hLimits.end > furthestLimits.r) {
+                       furthestLimits.r = hLimits.end;
+                       furthestAngles.r = angleRadians;
+               }
+
+               if (vLimits.start < furthestLimits.t) {
+                       furthestLimits.t = vLimits.start;
+                       furthestAngles.t = angleRadians;
+               }
+
+               if (vLimits.end > furthestLimits.b) {
+                       furthestLimits.b = vLimits.end;
+                       furthestAngles.b = angleRadians;
+               }
+       }
+
+       scale.setReductions(scale.drawingArea, furthestLimits, furthestAngles);
+}
+
+function getTextAlignForAngle(angle) {
+       if (angle === 0 || angle === 180) {
+               return 'center';
+       } else if (angle < 180) {
+               return 'left';
+       }
+
+       return 'right';
+}
+
+function fillText(ctx, text, position, lineHeight) {
+       var y = position.y + lineHeight / 2;
+       var i, ilen;
+
+       if (helpers$1.isArray(text)) {
+               for (i = 0, ilen = text.length; i < ilen; ++i) {
+                       ctx.fillText(text[i], position.x, y);
+                       y += lineHeight;
+               }
+       } else {
+               ctx.fillText(text, position.x, y);
+       }
+}
+
+function adjustPointPositionForLabelHeight(angle, textSize, position) {
+       if (angle === 90 || angle === 270) {
+               position.y -= (textSize.h / 2);
+       } else if (angle > 270 || angle < 90) {
+               position.y -= textSize.h;
+       }
+}
+
+function drawPointLabels(scale) {
+       var ctx = scale.ctx;
+       var opts = scale.options;
+       var angleLineOpts = opts.angleLines;
+       var gridLineOpts = opts.gridLines;
+       var pointLabelOpts = opts.pointLabels;
+       var lineWidth = valueOrDefault$b(angleLineOpts.lineWidth, gridLineOpts.lineWidth);
+       var lineColor = valueOrDefault$b(angleLineOpts.color, gridLineOpts.color);
+       var tickBackdropHeight = getTickBackdropHeight(opts);
+
+       ctx.save();
+       ctx.lineWidth = lineWidth;
+       ctx.strokeStyle = lineColor;
+       if (ctx.setLineDash) {
+               ctx.setLineDash(resolve$7([angleLineOpts.borderDash, gridLineOpts.borderDash, []]));
+               ctx.lineDashOffset = resolve$7([angleLineOpts.borderDashOffset, gridLineOpts.borderDashOffset, 0.0]);
+       }
+
+       var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
+
+       // Point Label Font
+       var plFont = helpers$1.options._parseFont(pointLabelOpts);
+
+       ctx.font = plFont.string;
+       ctx.textBaseline = 'middle';
+
+       for (var i = getValueCount(scale) - 1; i >= 0; i--) {
+               if (angleLineOpts.display && lineWidth && lineColor) {
+                       var outerPosition = scale.getPointPosition(i, outerDistance);
+                       ctx.beginPath();
+                       ctx.moveTo(scale.xCenter, scale.yCenter);
+                       ctx.lineTo(outerPosition.x, outerPosition.y);
+                       ctx.stroke();
+               }
+
+               if (pointLabelOpts.display) {
+                       // Extra pixels out for some label spacing
+                       var extra = (i === 0 ? tickBackdropHeight / 2 : 0);
+                       var pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + 5);
+
+                       // Keep this in loop since we may support array properties here
+                       var pointLabelFontColor = valueAtIndexOrDefault$1(pointLabelOpts.fontColor, i, core_defaults.global.defaultFontColor);
+                       ctx.fillStyle = pointLabelFontColor;
+
+                       var angleRadians = scale.getIndexAngle(i);
+                       var angle = helpers$1.toDegrees(angleRadians);
+                       ctx.textAlign = getTextAlignForAngle(angle);
+                       adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
+                       fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.lineHeight);
+               }
+       }
+       ctx.restore();
+}
+
+function drawRadiusLine(scale, gridLineOpts, radius, index) {
+       var ctx = scale.ctx;
+       var circular = gridLineOpts.circular;
+       var valueCount = getValueCount(scale);
+       var lineColor = valueAtIndexOrDefault$1(gridLineOpts.color, index - 1);
+       var lineWidth = valueAtIndexOrDefault$1(gridLineOpts.lineWidth, index - 1);
+       var pointPosition;
+
+       if ((!circular && !valueCount) || !lineColor || !lineWidth) {
+               return;
+       }
+
+       ctx.save();
+       ctx.strokeStyle = lineColor;
+       ctx.lineWidth = lineWidth;
+       if (ctx.setLineDash) {
+               ctx.setLineDash(gridLineOpts.borderDash || []);
+               ctx.lineDashOffset = gridLineOpts.borderDashOffset || 0.0;
+       }
+
+       ctx.beginPath();
+       if (circular) {
+               // Draw circular arcs between the points
+               ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2);
+       } else {
+               // Draw straight lines connecting each index
+               pointPosition = scale.getPointPosition(0, radius);
+               ctx.moveTo(pointPosition.x, pointPosition.y);
+
+               for (var i = 1; i < valueCount; i++) {
+                       pointPosition = scale.getPointPosition(i, radius);
+                       ctx.lineTo(pointPosition.x, pointPosition.y);
+               }
+       }
+       ctx.closePath();
+       ctx.stroke();
+       ctx.restore();
+}
+
+function numberOrZero(param) {
+       return helpers$1.isNumber(param) ? param : 0;
+}
+
+var scale_radialLinear = scale_linearbase.extend({
+       setDimensions: function() {
+               var me = this;
+
+               // Set the unconstrained dimension before label rotation
+               me.width = me.maxWidth;
+               me.height = me.maxHeight;
+               me.paddingTop = getTickBackdropHeight(me.options) / 2;
+               me.xCenter = Math.floor(me.width / 2);
+               me.yCenter = Math.floor((me.height - me.paddingTop) / 2);
+               me.drawingArea = Math.min(me.height - me.paddingTop, me.width) / 2;
+       },
+
+       determineDataLimits: function() {
+               var me = this;
+               var chart = me.chart;
+               var min = Number.POSITIVE_INFINITY;
+               var max = Number.NEGATIVE_INFINITY;
+
+               helpers$1.each(chart.data.datasets, function(dataset, datasetIndex) {
+                       if (chart.isDatasetVisible(datasetIndex)) {
+                               var meta = chart.getDatasetMeta(datasetIndex);
+
+                               helpers$1.each(dataset.data, function(rawValue, index) {
+                                       var value = +me.getRightValue(rawValue);
+                                       if (isNaN(value) || meta.data[index].hidden) {
+                                               return;
+                                       }
+
+                                       min = Math.min(value, min);
+                                       max = Math.max(value, max);
+                               });
+                       }
+               });
+
+               me.min = (min === Number.POSITIVE_INFINITY ? 0 : min);
+               me.max = (max === Number.NEGATIVE_INFINITY ? 0 : max);
+
+               // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
+               me.handleTickRangeOptions();
+       },
+
+       // Returns the maximum number of ticks based on the scale dimension
+       _computeTickLimit: function() {
+               return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options));
+       },
+
+       convertTicksToLabels: function() {
+               var me = this;
+
+               scale_linearbase.prototype.convertTicksToLabels.call(me);
+
+               // Point labels
+               me.pointLabels = me.chart.data.labels.map(me.options.pointLabels.callback, me);
+       },
+
+       getLabelForIndex: function(index, datasetIndex) {
+               return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
+       },
+
+       fit: function() {
+               var me = this;
+               var opts = me.options;
+
+               if (opts.display && opts.pointLabels.display) {
+                       fitWithPointLabels(me);
+               } else {
+                       me.setCenterPoint(0, 0, 0, 0);
+               }
+       },
+
+       /**
+        * Set radius reductions and determine new radius and center point
+        * @private
+        */
+       setReductions: function(largestPossibleRadius, furthestLimits, furthestAngles) {
+               var me = this;
+               var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
+               var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);
+               var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
+               var radiusReductionBottom = -Math.max(furthestLimits.b - (me.height - me.paddingTop), 0) / Math.cos(furthestAngles.b);
+
+               radiusReductionLeft = numberOrZero(radiusReductionLeft);
+               radiusReductionRight = numberOrZero(radiusReductionRight);
+               radiusReductionTop = numberOrZero(radiusReductionTop);
+               radiusReductionBottom = numberOrZero(radiusReductionBottom);
+
+               me.drawingArea = Math.min(
+                       Math.floor(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),
+                       Math.floor(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));
+               me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
+       },
+
+       setCenterPoint: function(leftMovement, rightMovement, topMovement, bottomMovement) {
+               var me = this;
+               var maxRight = me.width - rightMovement - me.drawingArea;
+               var maxLeft = leftMovement + me.drawingArea;
+               var maxTop = topMovement + me.drawingArea;
+               var maxBottom = (me.height - me.paddingTop) - bottomMovement - me.drawingArea;
+
+               me.xCenter = Math.floor(((maxLeft + maxRight) / 2) + me.left);
+               me.yCenter = Math.floor(((maxTop + maxBottom) / 2) + me.top + me.paddingTop);
+       },
+
+       getIndexAngle: function(index) {
+               var angleMultiplier = (Math.PI * 2) / getValueCount(this);
+               var startAngle = this.chart.options && this.chart.options.startAngle ?
+                       this.chart.options.startAngle :
+                       0;
+
+               var startAngleRadians = startAngle * Math.PI * 2 / 360;
+
+               // Start from the top instead of right, so remove a quarter of the circle
+               return index * angleMultiplier + startAngleRadians;
+       },
+
+       getDistanceFromCenterForValue: function(value) {
+               var me = this;
+
+               if (value === null) {
+                       return 0; // null always in center
+               }
+
+               // Take into account half font size + the yPadding of the top value
+               var scalingFactor = me.drawingArea / (me.max - me.min);
+               if (me.options.ticks.reverse) {
+                       return (me.max - value) * scalingFactor;
+               }
+               return (value - me.min) * scalingFactor;
+       },
+
+       getPointPosition: function(index, distanceFromCenter) {
+               var me = this;
+               var thisAngle = me.getIndexAngle(index) - (Math.PI / 2);
+               return {
+                       x: Math.cos(thisAngle) * distanceFromCenter + me.xCenter,
+                       y: Math.sin(thisAngle) * distanceFromCenter + me.yCenter
+               };
+       },
+
+       getPointPositionForValue: function(index, value) {
+               return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
+       },
+
+       getBasePosition: function() {
+               var me = this;
+               var min = me.min;
+               var max = me.max;
+
+               return me.getPointPositionForValue(0,
+                       me.beginAtZero ? 0 :
+                       min < 0 && max < 0 ? max :
+                       min > 0 && max > 0 ? min :
+                       0);
+       },
+
+       draw: function() {
+               var me = this;
+               var opts = me.options;
+               var gridLineOpts = opts.gridLines;
+               var tickOpts = opts.ticks;
+
+               if (opts.display) {
+                       var ctx = me.ctx;
+                       var startAngle = this.getIndexAngle(0);
+                       var tickFont = helpers$1.options._parseFont(tickOpts);
+
+                       if (opts.angleLines.display || opts.pointLabels.display) {
+                               drawPointLabels(me);
+                       }
+
+                       helpers$1.each(me.ticks, function(label, index) {
+                               // Don't draw a centre value (if it is minimum)
+                               if (index > 0 || tickOpts.reverse) {
+                                       var yCenterOffset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
+
+                                       // Draw circular lines around the scale
+                                       if (gridLineOpts.display && index !== 0) {
+                                               drawRadiusLine(me, gridLineOpts, yCenterOffset, index);
+                                       }
+
+                                       if (tickOpts.display) {
+                                               var tickFontColor = valueOrDefault$b(tickOpts.fontColor, core_defaults.global.defaultFontColor);
+                                               ctx.font = tickFont.string;
+
+                                               ctx.save();
+                                               ctx.translate(me.xCenter, me.yCenter);
+                                               ctx.rotate(startAngle);
+
+                                               if (tickOpts.showLabelBackdrop) {
+                                                       var labelWidth = ctx.measureText(label).width;
+                                                       ctx.fillStyle = tickOpts.backdropColor;
+                                                       ctx.fillRect(
+                                                               -labelWidth / 2 - tickOpts.backdropPaddingX,
+                                                               -yCenterOffset - tickFont.size / 2 - tickOpts.backdropPaddingY,
+                                                               labelWidth + tickOpts.backdropPaddingX * 2,
+                                                               tickFont.size + tickOpts.backdropPaddingY * 2
+                                                       );
+                                               }
+
+                                               ctx.textAlign = 'center';
+                                               ctx.textBaseline = 'middle';
+                                               ctx.fillStyle = tickFontColor;
+                                               ctx.fillText(label, 0, -yCenterOffset);
+                                               ctx.restore();
+                                       }
+                               }
+                       });
+               }
+       }
+});
+
+// INTERNAL: static default options, registered in src/index.js
+var _defaults$3 = defaultConfig$3;
+scale_radialLinear._defaults = _defaults$3;
+
+var valueOrDefault$c = helpers$1.valueOrDefault;
+
+// Integer constants are from the ES6 spec.
+var MIN_INTEGER = Number.MIN_SAFE_INTEGER || -9007199254740991;
+var MAX_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
+
+var INTERVALS = {
+       millisecond: {
+               common: true,
+               size: 1,
+               steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
+       },
+       second: {
+               common: true,
+               size: 1000,
+               steps: [1, 2, 5, 10, 15, 30]
+       },
+       minute: {
+               common: true,
+               size: 60000,
+               steps: [1, 2, 5, 10, 15, 30]
+       },
+       hour: {
+               common: true,
+               size: 3600000,
+               steps: [1, 2, 3, 6, 12]
+       },
+       day: {
+               common: true,
+               size: 86400000,
+               steps: [1, 2, 5]
+       },
+       week: {
+               common: false,
+               size: 604800000,
+               steps: [1, 2, 3, 4]
+       },
+       month: {
+               common: true,
+               size: 2.628e9,
+               steps: [1, 2, 3]
+       },
+       quarter: {
+               common: false,
+               size: 7.884e9,
+               steps: [1, 2, 3, 4]
+       },
+       year: {
+               common: true,
+               size: 3.154e10
+       }
+};
+
+var UNITS = Object.keys(INTERVALS);
+
+function sorter(a, b) {
+       return a - b;
+}
+
+function arrayUnique(items) {
+       var hash = {};
+       var out = [];
+       var i, ilen, item;
+
+       for (i = 0, ilen = items.length; i < ilen; ++i) {
+               item = items[i];
+               if (!hash[item]) {
+                       hash[item] = true;
+                       out.push(item);
+               }
+       }
+
+       return out;
+}
+
+/**
+ * Returns an array of {time, pos} objects used to interpolate a specific `time` or position
+ * (`pos`) on the scale, by searching entries before and after the requested value. `pos` is
+ * a decimal between 0 and 1: 0 being the start of the scale (left or top) and 1 the other
+ * extremity (left + width or top + height). Note that it would be more optimized to directly
+ * store pre-computed pixels, but the scale dimensions are not guaranteed at the time we need
+ * to create the lookup table. The table ALWAYS contains at least two items: min and max.
+ *
+ * @param {number[]} timestamps - timestamps sorted from lowest to highest.
+ * @param {string} distribution - If 'linear', timestamps will be spread linearly along the min
+ * and max range, so basically, the table will contains only two items: {min, 0} and {max, 1}.
+ * If 'series', timestamps will be positioned at the same distance from each other. In this
+ * case, only timestamps that break the time linearity are registered, meaning that in the
+ * best case, all timestamps are linear, the table contains only min and max.
+ */
+function buildLookupTable(timestamps, min, max, distribution) {
+       if (distribution === 'linear' || !timestamps.length) {
+               return [
+                       {time: min, pos: 0},
+                       {time: max, pos: 1}
+               ];
+       }
+
+       var table = [];
+       var items = [min];
+       var i, ilen, prev, curr, next;
+
+       for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
+               curr = timestamps[i];
+               if (curr > min && curr < max) {
+                       items.push(curr);
+               }
+       }
+
+       items.push(max);
+
+       for (i = 0, ilen = items.length; i < ilen; ++i) {
+               next = items[i + 1];
+               prev = items[i - 1];
+               curr = items[i];
+
+               // only add points that breaks the scale linearity
+               if (prev === undefined || next === undefined || Math.round((next + prev) / 2) !== curr) {
+                       table.push({time: curr, pos: i / (ilen - 1)});
+               }
+       }
+
+       return table;
+}
+
+// @see adapted from https://www.anujgakhar.com/2014/03/01/binary-search-in-javascript/
+function lookup(table, key, value) {
+       var lo = 0;
+       var hi = table.length - 1;
+       var mid, i0, i1;
+
+       while (lo >= 0 && lo <= hi) {
+               mid = (lo + hi) >> 1;
+               i0 = table[mid - 1] || null;
+               i1 = table[mid];
+
+               if (!i0) {
+                       // given value is outside table (before first item)
+                       return {lo: null, hi: i1};
+               } else if (i1[key] < value) {
+                       lo = mid + 1;
+               } else if (i0[key] > value) {
+                       hi = mid - 1;
+               } else {
+                       return {lo: i0, hi: i1};
+               }
+       }
+
+       // given value is outside table (after last item)
+       return {lo: i1, hi: null};
+}
+
+/**
+ * Linearly interpolates the given source `value` using the table items `skey` values and
+ * returns the associated `tkey` value. For example, interpolate(table, 'time', 42, 'pos')
+ * returns the position for a timestamp equal to 42. If value is out of bounds, values at
+ * index [0, 1] or [n - 1, n] are used for the interpolation.
+ */
+function interpolate$1(table, skey, sval, tkey) {
+       var range = lookup(table, skey, sval);
+
+       // Note: the lookup table ALWAYS contains at least 2 items (min and max)
+       var prev = !range.lo ? table[0] : !range.hi ? table[table.length - 2] : range.lo;
+       var next = !range.lo ? table[1] : !range.hi ? table[table.length - 1] : range.hi;
+
+       var span = next[skey] - prev[skey];
+       var ratio = span ? (sval - prev[skey]) / span : 0;
+       var offset = (next[tkey] - prev[tkey]) * ratio;
+
+       return prev[tkey] + offset;
+}
+
+function toTimestamp(scale, input) {
+       var adapter = scale._adapter;
+       var options = scale.options.time;
+       var parser = options.parser;
+       var format = parser || options.format;
+       var value = input;
+
+       if (typeof parser === 'function') {
+               value = parser(value);
+       }
+
+       // Only parse if its not a timestamp already
+       if (!helpers$1.isFinite(value)) {
+               value = typeof format === 'string'
+                       ? adapter.parse(value, format)
+                       : adapter.parse(value);
+       }
+
+       if (value !== null) {
+               return +value;
+       }
+
+       // Labels are in an incompatible format and no `parser` has been provided.
+       // The user might still use the deprecated `format` option for parsing.
+       if (!parser && typeof format === 'function') {
+               value = format(input);
+
+               // `format` could return something else than a timestamp, if so, parse it
+               if (!helpers$1.isFinite(value)) {
+                       value = adapter.parse(value);
+               }
+       }
+
+       return value;
+}
+
+function parse(scale, input) {
+       if (helpers$1.isNullOrUndef(input)) {
+               return null;
+       }
+
+       var options = scale.options.time;
+       var value = toTimestamp(scale, scale.getRightValue(input));
+       if (value === null) {
+               return value;
+       }
+
+       if (options.round) {
+               value = +scale._adapter.startOf(value, options.round);
+       }
+
+       return value;
+}
+
+/**
+ * Returns the number of unit to skip to be able to display up to `capacity` number of ticks
+ * in `unit` for the given `min` / `max` range and respecting the interval steps constraints.
+ */
+function determineStepSize(min, max, unit, capacity) {
+       var range = max - min;
+       var interval = INTERVALS[unit];
+       var milliseconds = interval.size;
+       var steps = interval.steps;
+       var i, ilen, factor;
+
+       if (!steps) {
+               return Math.ceil(range / (capacity * milliseconds));
+       }
+
+       for (i = 0, ilen = steps.length; i < ilen; ++i) {
+               factor = steps[i];
+               if (Math.ceil(range / (milliseconds * factor)) <= capacity) {
+                       break;
+               }
+       }
+
+       return factor;
+}
+
+/**
+ * Figures out what unit results in an appropriate number of auto-generated ticks
+ */
+function determineUnitForAutoTicks(minUnit, min, max, capacity) {
+       var ilen = UNITS.length;
+       var i, interval, factor;
+
+       for (i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) {
+               interval = INTERVALS[UNITS[i]];
+               factor = interval.steps ? interval.steps[interval.steps.length - 1] : MAX_INTEGER;
+
+               if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
+                       return UNITS[i];
+               }
+       }
+
+       return UNITS[ilen - 1];
+}
+
+/**
+ * Figures out what unit to format a set of ticks with
+ */
+function determineUnitForFormatting(scale, ticks, minUnit, min, max) {
+       var ilen = UNITS.length;
+       var i, unit;
+
+       for (i = ilen - 1; i >= UNITS.indexOf(minUnit); i--) {
+               unit = UNITS[i];
+               if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= ticks.length) {
+                       return unit;
+               }
+       }
+
+       return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];
+}
+
+function determineMajorUnit(unit) {
+       for (var i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) {
+               if (INTERVALS[UNITS[i]].common) {
+                       return UNITS[i];
+               }
+       }
+}
+
+/**
+ * Generates a maximum of `capacity` timestamps between min and max, rounded to the
+ * `minor` unit, aligned on the `major` unit and using the given scale time `options`.
+ * Important: this method can return ticks outside the min and max range, it's the
+ * responsibility of the calling code to clamp values if needed.
+ */
+function generate(scale, min, max, capacity) {
+       var adapter = scale._adapter;
+       var options = scale.options;
+       var timeOpts = options.time;
+       var minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, capacity);
+       var major = determineMajorUnit(minor);
+       var stepSize = valueOrDefault$c(timeOpts.stepSize, timeOpts.unitStepSize);
+       var weekday = minor === 'week' ? timeOpts.isoWeekday : false;
+       var majorTicksEnabled = options.ticks.major.enabled;
+       var interval = INTERVALS[minor];
+       var first = min;
+       var last = max;
+       var ticks = [];
+       var time;
+
+       if (!stepSize) {
+               stepSize = determineStepSize(min, max, minor, capacity);
+       }
+
+       // For 'week' unit, handle the first day of week option
+       if (weekday) {
+               first = +adapter.startOf(first, 'isoWeek', weekday);
+               last = +adapter.startOf(last, 'isoWeek', weekday);
+       }
+
+       // Align first/last ticks on unit
+       first = +adapter.startOf(first, weekday ? 'day' : minor);
+       last = +adapter.startOf(last, weekday ? 'day' : minor);
+
+       // Make sure that the last tick include max
+       if (last < max) {
+               last = +adapter.add(last, 1, minor);
+       }
+
+       time = first;
+
+       if (majorTicksEnabled && major && !weekday && !timeOpts.round) {
+               // Align the first tick on the previous `minor` unit aligned on the `major` unit:
+               // we first aligned time on the previous `major` unit then add the number of full
+               // stepSize there is between first and the previous major time.
+               time = +adapter.startOf(time, major);
+               time = +adapter.add(time, ~~((first - time) / (interval.size * stepSize)) * stepSize, minor);
+       }
+
+       for (; time < last; time = +adapter.add(time, stepSize, minor)) {
+               ticks.push(+time);
+       }
+
+       ticks.push(+time);
+
+       return ticks;
+}
+
+/**
+ * Returns the start and end offsets from edges in the form of {start, end}
+ * where each value is a relative width to the scale and ranges between 0 and 1.
+ * They add extra margins on the both sides by scaling down the original scale.
+ * Offsets are added when the `offset` option is true.
+ */
+function computeOffsets(table, ticks, min, max, options) {
+       var start = 0;
+       var end = 0;
+       var first, last;
+
+       if (options.offset && ticks.length) {
+               if (!options.time.min) {
+                       first = interpolate$1(table, 'time', ticks[0], 'pos');
+                       if (ticks.length === 1) {
+                               start = 1 - first;
+                       } else {
+                               start = (interpolate$1(table, 'time', ticks[1], 'pos') - first) / 2;
+                       }
+               }
+               if (!options.time.max) {
+                       last = interpolate$1(table, 'time', ticks[ticks.length - 1], 'pos');
+                       if (ticks.length === 1) {
+                               end = last;
+                       } else {
+                               end = (last - interpolate$1(table, 'time', ticks[ticks.length - 2], 'pos')) / 2;
+                       }
+               }
+       }
+
+       return {start: start, end: end};
+}
+
+function ticksFromTimestamps(scale, values, majorUnit) {
+       var ticks = [];
+       var i, ilen, value, major;
+
+       for (i = 0, ilen = values.length; i < ilen; ++i) {
+               value = values[i];
+               major = majorUnit ? value === +scale._adapter.startOf(value, majorUnit) : false;
+
+               ticks.push({
+                       value: value,
+                       major: major
+               });
+       }
+
+       return ticks;
+}
+
+var defaultConfig$4 = {
+       position: 'bottom',
+
+       /**
+        * Data distribution along the scale:
+        * - 'linear': data are spread according to their time (distances can vary),
+        * - 'series': data are spread at the same distance from each other.
+        * @see https://github.com/chartjs/Chart.js/pull/4507
+        * @since 2.7.0
+        */
+       distribution: 'linear',
+
+       /**
+        * Scale boundary strategy (bypassed by min/max time options)
+        * - `data`: make sure data are fully visible, ticks outside are removed
+        * - `ticks`: make sure ticks are fully visible, data outside are truncated
+        * @see https://github.com/chartjs/Chart.js/pull/4556
+        * @since 2.7.0
+        */
+       bounds: 'data',
+
+       adapters: {},
+       time: {
+               parser: false, // false == a pattern string from https://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment
+               format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from https://momentjs.com/docs/#/parsing/string-format/
+               unit: false, // false == automatic or override with week, month, year, etc.
+               round: false, // none, or override with week, month, year, etc.
+               displayFormat: false, // DEPRECATED
+               isoWeekday: false, // override week start day - see https://momentjs.com/docs/#/get-set/iso-weekday/
+               minUnit: 'millisecond',
+               displayFormats: {}
+       },
+       ticks: {
+               autoSkip: false,
+
+               /**
+                * Ticks generation input values:
+                * - 'auto': generates "optimal" ticks based on scale size and time options.
+                * - 'data': generates ticks from data (including labels from data {t|x|y} objects).
+                * - 'labels': generates ticks from user given `data.labels` values ONLY.
+                * @see https://github.com/chartjs/Chart.js/pull/4507
+                * @since 2.7.0
+                */
+               source: 'auto',
+
+               major: {
+                       enabled: false
+               }
+       }
+};
+
+var scale_time = core_scale.extend({
+       initialize: function() {
+               this.mergeTicksOptions();
+               core_scale.prototype.initialize.call(this);
+       },
+
+       update: function() {
+               var me = this;
+               var options = me.options;
+               var time = options.time || (options.time = {});
+               var adapter = me._adapter = new core_adapters._date(options.adapters.date);
+
+               // DEPRECATIONS: output a message only one time per update
+               if (time.format) {
+                       console.warn('options.time.format is deprecated and replaced by options.time.parser.');
+               }
+
+               // Backward compatibility: before introducing adapter, `displayFormats` was
+               // supposed to contain *all* unit/string pairs but this can't be resolved
+               // when loading the scale (adapters are loaded afterward), so let's populate
+               // missing formats on update
+               helpers$1.mergeIf(time.displayFormats, adapter.formats());
+
+               return core_scale.prototype.update.apply(me, arguments);
+       },
+
+       /**
+        * Allows data to be referenced via 't' attribute
+        */
+       getRightValue: function(rawValue) {
+               if (rawValue && rawValue.t !== undefined) {
+                       rawValue = rawValue.t;
+               }
+               return core_scale.prototype.getRightValue.call(this, rawValue);
+       },
+
+       determineDataLimits: function() {
+               var me = this;
+               var chart = me.chart;
+               var adapter = me._adapter;
+               var timeOpts = me.options.time;
+               var unit = timeOpts.unit || 'day';
+               var min = MAX_INTEGER;
+               var max = MIN_INTEGER;
+               var timestamps = [];
+               var datasets = [];
+               var labels = [];
+               var i, j, ilen, jlen, data, timestamp;
+               var dataLabels = chart.data.labels || [];
+
+               // Convert labels to timestamps
+               for (i = 0, ilen = dataLabels.length; i < ilen; ++i) {
+                       labels.push(parse(me, dataLabels[i]));
+               }
+
+               // Convert data to timestamps
+               for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
+                       if (chart.isDatasetVisible(i)) {
+                               data = chart.data.datasets[i].data;
+
+                               // Let's consider that all data have the same format.
+                               if (helpers$1.isObject(data[0])) {
+                                       datasets[i] = [];
+
+                                       for (j = 0, jlen = data.length; j < jlen; ++j) {
+                                               timestamp = parse(me, data[j]);
+                                               timestamps.push(timestamp);
+                                               datasets[i][j] = timestamp;
+                                       }
+                               } else {
+                                       for (j = 0, jlen = labels.length; j < jlen; ++j) {
+                                               timestamps.push(labels[j]);
+                                       }
+                                       datasets[i] = labels.slice(0);
+                               }
+                       } else {
+                               datasets[i] = [];
+                       }
+               }
+
+               if (labels.length) {
+                       // Sort labels **after** data have been converted
+                       labels = arrayUnique(labels).sort(sorter);
+                       min = Math.min(min, labels[0]);
+                       max = Math.max(max, labels[labels.length - 1]);
+               }
+
+               if (timestamps.length) {
+                       timestamps = arrayUnique(timestamps).sort(sorter);
+                       min = Math.min(min, timestamps[0]);
+                       max = Math.max(max, timestamps[timestamps.length - 1]);
+               }
+
+               min = parse(me, timeOpts.min) || min;
+               max = parse(me, timeOpts.max) || max;
+
+               // In case there is no valid min/max, set limits based on unit time option
+               min = min === MAX_INTEGER ? +adapter.startOf(Date.now(), unit) : min;
+               max = max === MIN_INTEGER ? +adapter.endOf(Date.now(), unit) + 1 : max;
+
+               // Make sure that max is strictly higher than min (required by the lookup table)
+               me.min = Math.min(min, max);
+               me.max = Math.max(min + 1, max);
+
+               // PRIVATE
+               me._horizontal = me.isHorizontal();
+               me._table = [];
+               me._timestamps = {
+                       data: timestamps,
+                       datasets: datasets,
+                       labels: labels
+               };
+       },
+
+       buildTicks: function() {
+               var me = this;
+               var min = me.min;
+               var max = me.max;
+               var options = me.options;
+               var timeOpts = options.time;
+               var timestamps = [];
+               var ticks = [];
+               var i, ilen, timestamp;
+
+               switch (options.ticks.source) {
+               case 'data':
+                       timestamps = me._timestamps.data;
+                       break;
+               case 'labels':
+                       timestamps = me._timestamps.labels;
+                       break;
+               case 'auto':
+               default:
+                       timestamps = generate(me, min, max, me.getLabelCapacity(min), options);
+               }
+
+               if (options.bounds === 'ticks' && timestamps.length) {
+                       min = timestamps[0];
+                       max = timestamps[timestamps.length - 1];
+               }
+
+               // Enforce limits with user min/max options
+               min = parse(me, timeOpts.min) || min;
+               max = parse(me, timeOpts.max) || max;
+
+               // Remove ticks outside the min/max range
+               for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
+                       timestamp = timestamps[i];
+                       if (timestamp >= min && timestamp <= max) {
+                               ticks.push(timestamp);
+                       }
+               }
+
+               me.min = min;
+               me.max = max;
+
+               // PRIVATE
+               me._unit = timeOpts.unit || determineUnitForFormatting(me, ticks, timeOpts.minUnit, me.min, me.max);
+               me._majorUnit = determineMajorUnit(me._unit);
+               me._table = buildLookupTable(me._timestamps.data, min, max, options.distribution);
+               me._offsets = computeOffsets(me._table, ticks, min, max, options);
+
+               if (options.ticks.reverse) {
+                       ticks.reverse();
+               }
+
+               return ticksFromTimestamps(me, ticks, me._majorUnit);
+       },
+
+       getLabelForIndex: function(index, datasetIndex) {
+               var me = this;
+               var adapter = me._adapter;
+               var data = me.chart.data;
+               var timeOpts = me.options.time;
+               var label = data.labels && index < data.labels.length ? data.labels[index] : '';
+               var value = data.datasets[datasetIndex].data[index];
+
+               if (helpers$1.isObject(value)) {
+                       label = me.getRightValue(value);
+               }
+               if (timeOpts.tooltipFormat) {
+                       return adapter.format(toTimestamp(me, label), timeOpts.tooltipFormat);
+               }
+               if (typeof label === 'string') {
+                       return label;
+               }
+               return adapter.format(toTimestamp(me, label), timeOpts.displayFormats.datetime);
+       },
+
+       /**
+        * Function to format an individual tick mark
+        * @private
+        */
+       tickFormatFunction: function(time, index, ticks, format) {
+               var me = this;
+               var adapter = me._adapter;
+               var options = me.options;
+               var formats = options.time.displayFormats;
+               var minorFormat = formats[me._unit];
+               var majorUnit = me._majorUnit;
+               var majorFormat = formats[majorUnit];
+               var majorTime = +adapter.startOf(time, majorUnit);
+               var majorTickOpts = options.ticks.major;
+               var major = majorTickOpts.enabled && majorUnit && majorFormat && time === majorTime;
+               var label = adapter.format(time, format ? format : major ? majorFormat : minorFormat);
+               var tickOpts = major ? majorTickOpts : options.ticks.minor;
+               var formatter = valueOrDefault$c(tickOpts.callback, tickOpts.userCallback);
+
+               return formatter ? formatter(label, index, ticks) : label;
+       },
+
+       convertTicksToLabels: function(ticks) {
+               var labels = [];
+               var i, ilen;
+
+               for (i = 0, ilen = ticks.length; i < ilen; ++i) {
+                       labels.push(this.tickFormatFunction(ticks[i].value, i, ticks));
+               }
+
+               return labels;
+       },
+
+       /**
+        * @private
+        */
+       getPixelForOffset: function(time) {
+               var me = this;
+               var isReverse = me.options.ticks.reverse;
+               var size = me._horizontal ? me.width : me.height;
+               var start = me._horizontal ? isReverse ? me.right : me.left : isReverse ? me.bottom : me.top;
+               var pos = interpolate$1(me._table, 'time', time, 'pos');
+               var offset = size * (me._offsets.start + pos) / (me._offsets.start + 1 + me._offsets.end);
+
+               return isReverse ? start - offset : start + offset;
+       },
+
+       getPixelForValue: function(value, index, datasetIndex) {
+               var me = this;
+               var time = null;
+
+               if (index !== undefined && datasetIndex !== undefined) {
+                       time = me._timestamps.datasets[datasetIndex][index];
+               }
+
+               if (time === null) {
+                       time = parse(me, value);
+               }
+
+               if (time !== null) {
+                       return me.getPixelForOffset(time);
+               }
+       },
+
+       getPixelForTick: function(index) {
+               var ticks = this.getTicks();
+               return index >= 0 && index < ticks.length ?
+                       this.getPixelForOffset(ticks[index].value) :
+                       null;
+       },
+
+       getValueForPixel: function(pixel) {
+               var me = this;
+               var size = me._horizontal ? me.width : me.height;
+               var start = me._horizontal ? me.left : me.top;
+               var pos = (size ? (pixel - start) / size : 0) * (me._offsets.start + 1 + me._offsets.start) - me._offsets.end;
+               var time = interpolate$1(me._table, 'pos', pos, 'time');
+
+               // DEPRECATION, we should return time directly
+               return me._adapter._create(time);
+       },
+
+       /**
+        * Crude approximation of what the label width might be
+        * @private
+        */
+       getLabelWidth: function(label) {
+               var me = this;
+               var ticksOpts = me.options.ticks;
+               var tickLabelWidth = me.ctx.measureText(label).width;
+               var angle = helpers$1.toRadians(ticksOpts.maxRotation);
+               var cosRotation = Math.cos(angle);
+               var sinRotation = Math.sin(angle);
+               var tickFontSize = valueOrDefault$c(ticksOpts.fontSize, core_defaults.global.defaultFontSize);
+
+               return (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
+       },
+
+       /**
+        * @private
+        */
+       getLabelCapacity: function(exampleTime) {
+               var me = this;
+
+               // pick the longest format (milliseconds) for guestimation
+               var format = me.options.time.displayFormats.millisecond;
+               var exampleLabel = me.tickFormatFunction(exampleTime, 0, [], format);
+               var tickLabelWidth = me.getLabelWidth(exampleLabel);
+               var innerWidth = me.isHorizontal() ? me.width : me.height;
+               var capacity = Math.floor(innerWidth / tickLabelWidth);
+
+               return capacity > 0 ? capacity : 1;
+       }
+});
+
+// INTERNAL: static default options, registered in src/index.js
+var _defaults$4 = defaultConfig$4;
+scale_time._defaults = _defaults$4;
+
+var scales = {
+       category: scale_category,
+       linear: scale_linear,
+       logarithmic: scale_logarithmic,
+       radialLinear: scale_radialLinear,
+       time: scale_time
+};
+
+var moment = createCommonjsModule(function (module, exports) {
+(function (global, factory) {
+    module.exports = factory();
+}(commonjsGlobal, (function () {
+    var hookCallback;
+
+    function hooks () {
+        return hookCallback.apply(null, arguments);
+    }
+
+    // This is done to register the method called with moment()
+    // without creating circular dependencies.
+    function setHookCallback (callback) {
+        hookCallback = callback;
+    }
+
+    function isArray(input) {
+        return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
+    }
+
+    function isObject(input) {
+        // IE8 will treat undefined and null as object if it wasn't for
+        // input != null
+        return input != null && Object.prototype.toString.call(input) === '[object Object]';
+    }
+
+    function isObjectEmpty(obj) {
+        if (Object.getOwnPropertyNames) {
+            return (Object.getOwnPropertyNames(obj).length === 0);
+        } else {
+            var k;
+            for (k in obj) {
+                if (obj.hasOwnProperty(k)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    function isUndefined(input) {
+        return input === void 0;
+    }
+
+    function isNumber(input) {
+        return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';
+    }
+
+    function isDate(input) {
+        return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
+    }
+
+    function map(arr, fn) {
+        var res = [], i;
+        for (i = 0; i < arr.length; ++i) {
+            res.push(fn(arr[i], i));
+        }
+        return res;
+    }
+
+    function hasOwnProp(a, b) {
+        return Object.prototype.hasOwnProperty.call(a, b);
+    }
+
+    function extend(a, b) {
+        for (var i in b) {
+            if (hasOwnProp(b, i)) {
+                a[i] = b[i];
+            }
+        }
+
+        if (hasOwnProp(b, 'toString')) {
+            a.toString = b.toString;
+        }
+
+        if (hasOwnProp(b, 'valueOf')) {
+            a.valueOf = b.valueOf;
+        }
+
+        return a;
+    }
+
+    function createUTC (input, format, locale, strict) {
+        return createLocalOrUTC(input, format, locale, strict, true).utc();
+    }
+
+    function defaultParsingFlags() {
+        // We need to deep clone this object.
+        return {
+            empty           : false,
+            unusedTokens    : [],
+            unusedInput     : [],
+            overflow        : -2,
+            charsLeftOver   : 0,
+            nullInput       : false,
+            invalidMonth    : null,
+            invalidFormat   : false,
+            userInvalidated : false,
+            iso             : false,
+            parsedDateParts : [],
+            meridiem        : null,
+            rfc2822         : false,
+            weekdayMismatch : false
+        };
+    }
+
+    function getParsingFlags(m) {
+        if (m._pf == null) {
+            m._pf = defaultParsingFlags();
+        }
+        return m._pf;
+    }
+
+    var some;
+    if (Array.prototype.some) {
+        some = Array.prototype.some;
+    } else {
+        some = function (fun) {
+            var t = Object(this);
+            var len = t.length >>> 0;
+
+            for (var i = 0; i < len; i++) {
+                if (i in t && fun.call(this, t[i], i, t)) {
+                    return true;
+                }
+            }
+
+            return false;
+        };
+    }
+
+    function isValid(m) {
+        if (m._isValid == null) {
+            var flags = getParsingFlags(m);
+            var parsedParts = some.call(flags.parsedDateParts, function (i) {
+                return i != null;
+            });
+            var isNowValid = !isNaN(m._d.getTime()) &&
+                flags.overflow < 0 &&
+                !flags.empty &&
+                !flags.invalidMonth &&
+                !flags.invalidWeekday &&
+                !flags.weekdayMismatch &&
+                !flags.nullInput &&
+                !flags.invalidFormat &&
+                !flags.userInvalidated &&
+                (!flags.meridiem || (flags.meridiem && parsedParts));
+
+            if (m._strict) {
+                isNowValid = isNowValid &&
+                    flags.charsLeftOver === 0 &&
+                    flags.unusedTokens.length === 0 &&
+                    flags.bigHour === undefined;
+            }
+
+            if (Object.isFrozen == null || !Object.isFrozen(m)) {
+                m._isValid = isNowValid;
+            }
+            else {
+                return isNowValid;
+            }
+        }
+        return m._isValid;
+    }
+
+    function createInvalid (flags) {
+        var m = createUTC(NaN);
+        if (flags != null) {
+            extend(getParsingFlags(m), flags);
+        }
+        else {
+            getParsingFlags(m).userInvalidated = true;
+        }
+
+        return m;
+    }
+
+    // Plugins that add properties should also add the key here (null value),
+    // so we can properly clone ourselves.
+    var momentProperties = hooks.momentProperties = [];
+
+    function copyConfig(to, from) {
+        var i, prop, val;
+
+        if (!isUndefined(from._isAMomentObject)) {
+            to._isAMomentObject = from._isAMomentObject;
+        }
+        if (!isUndefined(from._i)) {
+            to._i = from._i;
+        }
+        if (!isUndefined(from._f)) {
+            to._f = from._f;
+        }
+        if (!isUndefined(from._l)) {
+            to._l = from._l;
+        }
+        if (!isUndefined(from._strict)) {
+            to._strict = from._strict;
+        }
+        if (!isUndefined(from._tzm)) {
+            to._tzm = from._tzm;
+        }
+        if (!isUndefined(from._isUTC)) {
+            to._isUTC = from._isUTC;
+        }
+        if (!isUndefined(from._offset)) {
+            to._offset = from._offset;
+        }
+        if (!isUndefined(from._pf)) {
+            to._pf = getParsingFlags(from);
+        }
+        if (!isUndefined(from._locale)) {
+            to._locale = from._locale;
+        }
+
+        if (momentProperties.length > 0) {
+            for (i = 0; i < momentProperties.length; i++) {
+                prop = momentProperties[i];
+                val = from[prop];
+                if (!isUndefined(val)) {
+                    to[prop] = val;
+                }
+            }
+        }
+
+        return to;
+    }
+
+    var updateInProgress = false;
+
+    // Moment prototype object
+    function Moment(config) {
+        copyConfig(this, config);
+        this._d = new Date(config._d != null ? config._d.getTime() : NaN);
+        if (!this.isValid()) {
+            this._d = new Date(NaN);
+        }
+        // Prevent infinite loop in case updateOffset creates new moment
+        // objects.
+        if (updateInProgress === false) {
+            updateInProgress = true;
+            hooks.updateOffset(this);
+            updateInProgress = false;
+        }
+    }
+
+    function isMoment (obj) {
+        return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
+    }
+
+    function absFloor (number) {
+        if (number < 0) {
+            // -0 -> 0
+            return Math.ceil(number) || 0;
+        } else {
+            return Math.floor(number);
+        }
+    }
+
+    function toInt(argumentForCoercion) {
+        var coercedNumber = +argumentForCoercion,
+            value = 0;
+
+        if (coercedNumber !== 0 && isFinite(coercedNumber)) {
+            value = absFloor(coercedNumber);
+        }
+
+        return value;
+    }
+
+    // compare two arrays, return the number of differences
+    function compareArrays(array1, array2, dontConvert) {
+        var len = Math.min(array1.length, array2.length),
+            lengthDiff = Math.abs(array1.length - array2.length),
+            diffs = 0,
+            i;
+        for (i = 0; i < len; i++) {
+            if ((dontConvert && array1[i] !== array2[i]) ||
+                (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
+                diffs++;
+            }
+        }
+        return diffs + lengthDiff;
+    }
+
+    function warn(msg) {
+        if (hooks.suppressDeprecationWarnings === false &&
+                (typeof console !==  'undefined') && console.warn) {
+            console.warn('Deprecation warning: ' + msg);
+        }
+    }
+
+    function deprecate(msg, fn) {
+        var firstTime = true;
+
+        return extend(function () {
+            if (hooks.deprecationHandler != null) {
+                hooks.deprecationHandler(null, msg);
+            }
+            if (firstTime) {
+                var args = [];
+                var arg;
+                for (var i = 0; i < arguments.length; i++) {
+                    arg = '';
+                    if (typeof arguments[i] === 'object') {
+                        arg += '\n[' + i + '] ';
+                        for (var key in arguments[0]) {
+                            arg += key + ': ' + arguments[0][key] + ', ';
+                        }
+                        arg = arg.slice(0, -2); // Remove trailing comma and space
+                    } else {
+                        arg = arguments[i];
+                    }
+                    args.push(arg);
+                }
+                warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack);
+                firstTime = false;
+            }
+            return fn.apply(this, arguments);
+        }, fn);
+    }
+
+    var deprecations = {};
+
+    function deprecateSimple(name, msg) {
+        if (hooks.deprecationHandler != null) {
+            hooks.deprecationHandler(name, msg);
+        }
+        if (!deprecations[name]) {
+            warn(msg);
+            deprecations[name] = true;
+        }
+    }
+
+    hooks.suppressDeprecationWarnings = false;
+    hooks.deprecationHandler = null;
+
+    function isFunction(input) {
+        return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
+    }
+
+    function set (config) {
+        var prop, i;
+        for (i in config) {
+            prop = config[i];
+            if (isFunction(prop)) {
+                this[i] = prop;
+            } else {
+                this['_' + i] = prop;
+            }
+        }
+        this._config = config;
+        // Lenient ordinal parsing accepts just a number in addition to
+        // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
+        // TODO: Remove "ordinalParse" fallback in next major release.
+        this._dayOfMonthOrdinalParseLenient = new RegExp(
+            (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) +
+                '|' + (/\d{1,2}/).source);
+    }
+
+    function mergeConfigs(parentConfig, childConfig) {
+        var res = extend({}, parentConfig), prop;
+        for (prop in childConfig) {
+            if (hasOwnProp(childConfig, prop)) {
+                if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
+                    res[prop] = {};
+                    extend(res[prop], parentConfig[prop]);
+                    extend(res[prop], childConfig[prop]);
+                } else if (childConfig[prop] != null) {
+                    res[prop] = childConfig[prop];
+                } else {
+                    delete res[prop];
+                }
+            }
+        }
+        for (prop in parentConfig) {
+            if (hasOwnProp(parentConfig, prop) &&
+                    !hasOwnProp(childConfig, prop) &&
+                    isObject(parentConfig[prop])) {
+                // make sure changes to properties don't modify parent config
+                res[prop] = extend({}, res[prop]);
+            }
+        }
+        return res;
+    }
+
+    function Locale(config) {
+        if (config != null) {
+            this.set(config);
+        }
+    }
+
+    var keys;
+
+    if (Object.keys) {
+        keys = Object.keys;
+    } else {
+        keys = function (obj) {
+            var i, res = [];
+            for (i in obj) {
+                if (hasOwnProp(obj, i)) {
+                    res.push(i);
+                }
+            }
+            return res;
+        };
+    }
+
+    var defaultCalendar = {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    };
+
+    function calendar (key, mom, now) {
+        var output = this._calendar[key] || this._calendar['sameElse'];
+        return isFunction(output) ? output.call(mom, now) : output;
+    }
+
+    var defaultLongDateFormat = {
+        LTS  : 'h:mm:ss A',
+        LT   : 'h:mm A',
+        L    : 'MM/DD/YYYY',
+        LL   : 'MMMM D, YYYY',
+        LLL  : 'MMMM D, YYYY h:mm A',
+        LLLL : 'dddd, MMMM D, YYYY h:mm A'
+    };
+
+    function longDateFormat (key) {
+        var format = this._longDateFormat[key],
+            formatUpper = this._longDateFormat[key.toUpperCase()];
+
+        if (format || !formatUpper) {
+            return format;
+        }
+
+        this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
+            return val.slice(1);
+        });
+
+        return this._longDateFormat[key];
+    }
+
+    var defaultInvalidDate = 'Invalid date';
+
+    function invalidDate () {
+        return this._invalidDate;
+    }
+
+    var defaultOrdinal = '%d';
+    var defaultDayOfMonthOrdinalParse = /\d{1,2}/;
+
+    function ordinal (number) {
+        return this._ordinal.replace('%d', number);
+    }
+
+    var defaultRelativeTime = {
+        future : 'in %s',
+        past   : '%s ago',
+        s  : 'a few seconds',
+        ss : '%d seconds',
+        m  : 'a minute',
+        mm : '%d minutes',
+        h  : 'an hour',
+        hh : '%d hours',
+        d  : 'a day',
+        dd : '%d days',
+        M  : 'a month',
+        MM : '%d months',
+        y  : 'a year',
+        yy : '%d years'
+    };
+
+    function relativeTime (number, withoutSuffix, string, isFuture) {
+        var output = this._relativeTime[string];
+        return (isFunction(output)) ?
+            output(number, withoutSuffix, string, isFuture) :
+            output.replace(/%d/i, number);
+    }
+
+    function pastFuture (diff, output) {
+        var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
+        return isFunction(format) ? format(output) : format.replace(/%s/i, output);
+    }
+
+    var aliases = {};
+
+    function addUnitAlias (unit, shorthand) {
+        var lowerCase = unit.toLowerCase();
+        aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
+    }
+
+    function normalizeUnits(units) {
+        return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
+    }
+
+    function normalizeObjectUnits(inputObject) {
+        var normalizedInput = {},
+            normalizedProp,
+            prop;
+
+        for (prop in inputObject) {
+            if (hasOwnProp(inputObject, prop)) {
+                normalizedProp = normalizeUnits(prop);
+                if (normalizedProp) {
+                    normalizedInput[normalizedProp] = inputObject[prop];
+                }
+            }
+        }
+
+        return normalizedInput;
+    }
+
+    var priorities = {};
+
+    function addUnitPriority(unit, priority) {
+        priorities[unit] = priority;
+    }
+
+    function getPrioritizedUnits(unitsObj) {
+        var units = [];
+        for (var u in unitsObj) {
+            units.push({unit: u, priority: priorities[u]});
+        }
+        units.sort(function (a, b) {
+            return a.priority - b.priority;
+        });
+        return units;
+    }
+
+    function zeroFill(number, targetLength, forceSign) {
+        var absNumber = '' + Math.abs(number),
+            zerosToFill = targetLength - absNumber.length,
+            sign = number >= 0;
+        return (sign ? (forceSign ? '+' : '') : '-') +
+            Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
+    }
+
+    var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
+
+    var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
+
+    var formatFunctions = {};
+
+    var formatTokenFunctions = {};
+
+    // token:    'M'
+    // padded:   ['MM', 2]
+    // ordinal:  'Mo'
+    // callback: function () { this.month() + 1 }
+    function addFormatToken (token, padded, ordinal, callback) {
+        var func = callback;
+        if (typeof callback === 'string') {
+            func = function () {
+                return this[callback]();
+            };
+        }
+        if (token) {
+            formatTokenFunctions[token] = func;
+        }
+        if (padded) {
+            formatTokenFunctions[padded[0]] = function () {
+                return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
+            };
+        }
+        if (ordinal) {
+            formatTokenFunctions[ordinal] = function () {
+                return this.localeData().ordinal(func.apply(this, arguments), token);
+            };
+        }
+    }
+
+    function removeFormattingTokens(input) {
+        if (input.match(/\[[\s\S]/)) {
+            return input.replace(/^\[|\]$/g, '');
+        }
+        return input.replace(/\\/g, '');
+    }
+
+    function makeFormatFunction(format) {
+        var array = format.match(formattingTokens), i, length;
+
+        for (i = 0, length = array.length; i < length; i++) {
+            if (formatTokenFunctions[array[i]]) {
+                array[i] = formatTokenFunctions[array[i]];
+            } else {
+                array[i] = removeFormattingTokens(array[i]);
+            }
+        }
+
+        return function (mom) {
+            var output = '', i;
+            for (i = 0; i < length; i++) {
+                output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];
+            }
+            return output;
+        };
+    }
+
+    // format date using native date object
+    function formatMoment(m, format) {
+        if (!m.isValid()) {
+            return m.localeData().invalidDate();
+        }
+
+        format = expandFormat(format, m.localeData());
+        formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
+
+        return formatFunctions[format](m);
+    }
+
+    function expandFormat(format, locale) {
+        var i = 5;
+
+        function replaceLongDateFormatTokens(input) {
+            return locale.longDateFormat(input) || input;
+        }
+
+        localFormattingTokens.lastIndex = 0;
+        while (i >= 0 && localFormattingTokens.test(format)) {
+            format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
+            localFormattingTokens.lastIndex = 0;
+            i -= 1;
+        }
+
+        return format;
+    }
+
+    var match1         = /\d/;            //       0 - 9
+    var match2         = /\d\d/;          //      00 - 99
+    var match3         = /\d{3}/;         //     000 - 999
+    var match4         = /\d{4}/;         //    0000 - 9999
+    var match6         = /[+-]?\d{6}/;    // -999999 - 999999
+    var match1to2      = /\d\d?/;         //       0 - 99
+    var match3to4      = /\d\d\d\d?/;     //     999 - 9999
+    var match5to6      = /\d\d\d\d\d\d?/; //   99999 - 999999
+    var match1to3      = /\d{1,3}/;       //       0 - 999
+    var match1to4      = /\d{1,4}/;       //       0 - 9999
+    var match1to6      = /[+-]?\d{1,6}/;  // -999999 - 999999
+
+    var matchUnsigned  = /\d+/;           //       0 - inf
+    var matchSigned    = /[+-]?\d+/;      //    -inf - inf
+
+    var matchOffset    = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
+    var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
+
+    var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
+
+    // any word (or two) characters or numbers including two/three word month in arabic.
+    // includes scottish gaelic two word and hyphenated months
+    var matchWord = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;
+
+    var regexes = {};
+
+    function addRegexToken (token, regex, strictRegex) {
+        regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
+            return (isStrict && strictRegex) ? strictRegex : regex;
+        };
+    }
+
+    function getParseRegexForToken (token, config) {
+        if (!hasOwnProp(regexes, token)) {
+            return new RegExp(unescapeFormat(token));
+        }
+
+        return regexes[token](config._strict, config._locale);
+    }
+
+    // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
+    function unescapeFormat(s) {
+        return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
+            return p1 || p2 || p3 || p4;
+        }));
+    }
+
+    function regexEscape(s) {
+        return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
+    }
+
+    var tokens = {};
+
+    function addParseToken (token, callback) {
+        var i, func = callback;
+        if (typeof token === 'string') {
+            token = [token];
+        }
+        if (isNumber(callback)) {
+            func = function (input, array) {
+                array[callback] = toInt(input);
+            };
+        }
+        for (i = 0; i < token.length; i++) {
+            tokens[token[i]] = func;
+        }
+    }
+
+    function addWeekParseToken (token, callback) {
+        addParseToken(token, function (input, array, config, token) {
+            config._w = config._w || {};
+            callback(input, config._w, config, token);
+        });
+    }
+
+    function addTimeToArrayFromToken(token, input, config) {
+        if (input != null && hasOwnProp(tokens, token)) {
+            tokens[token](input, config._a, config, token);
+        }
+    }
+
+    var YEAR = 0;
+    var MONTH = 1;
+    var DATE = 2;
+    var HOUR = 3;
+    var MINUTE = 4;
+    var SECOND = 5;
+    var MILLISECOND = 6;
+    var WEEK = 7;
+    var WEEKDAY = 8;
+
+    // FORMATTING
+
+    addFormatToken('Y', 0, 0, function () {
+        var y = this.year();
+        return y <= 9999 ? '' + y : '+' + y;
+    });
+
+    addFormatToken(0, ['YY', 2], 0, function () {
+        return this.year() % 100;
+    });
+
+    addFormatToken(0, ['YYYY',   4],       0, 'year');
+    addFormatToken(0, ['YYYYY',  5],       0, 'year');
+    addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
+
+    // ALIASES
+
+    addUnitAlias('year', 'y');
+
+    // PRIORITIES
+
+    addUnitPriority('year', 1);
+
+    // PARSING
+
+    addRegexToken('Y',      matchSigned);
+    addRegexToken('YY',     match1to2, match2);
+    addRegexToken('YYYY',   match1to4, match4);
+    addRegexToken('YYYYY',  match1to6, match6);
+    addRegexToken('YYYYYY', match1to6, match6);
+
+    addParseToken(['YYYYY', 'YYYYYY'], YEAR);
+    addParseToken('YYYY', function (input, array) {
+        array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
+    });
+    addParseToken('YY', function (input, array) {
+        array[YEAR] = hooks.parseTwoDigitYear(input);
+    });
+    addParseToken('Y', function (input, array) {
+        array[YEAR] = parseInt(input, 10);
+    });
+
+    // HELPERS
+
+    function daysInYear(year) {
+        return isLeapYear(year) ? 366 : 365;
+    }
+
+    function isLeapYear(year) {
+        return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
+    }
+
+    // HOOKS
+
+    hooks.parseTwoDigitYear = function (input) {
+        return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
+    };
+
+    // MOMENTS
+
+    var getSetYear = makeGetSet('FullYear', true);
+
+    function getIsLeapYear () {
+        return isLeapYear(this.year());
+    }
+
+    function makeGetSet (unit, keepTime) {
+        return function (value) {
+            if (value != null) {
+                set$1(this, unit, value);
+                hooks.updateOffset(this, keepTime);
+                return this;
+            } else {
+                return get(this, unit);
+            }
+        };
+    }
+
+    function get (mom, unit) {
+        return mom.isValid() ?
+            mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
+    }
+
+    function set$1 (mom, unit, value) {
+        if (mom.isValid() && !isNaN(value)) {
+            if (unit === 'FullYear' && isLeapYear(mom.year()) && mom.month() === 1 && mom.date() === 29) {
+                mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value, mom.month(), daysInMonth(value, mom.month()));
+            }
+            else {
+                mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
+            }
+        }
+    }
+
+    // MOMENTS
+
+    function stringGet (units) {
+        units = normalizeUnits(units);
+        if (isFunction(this[units])) {
+            return this[units]();
+        }
+        return this;
+    }
+
+
+    function stringSet (units, value) {
+        if (typeof units === 'object') {
+            units = normalizeObjectUnits(units);
+            var prioritized = getPrioritizedUnits(units);
+            for (var i = 0; i < prioritized.length; i++) {
+                this[prioritized[i].unit](units[prioritized[i].unit]);
+            }
+        } else {
+            units = normalizeUnits(units);
+            if (isFunction(this[units])) {
+                return this[units](value);
+            }
+        }
+        return this;
+    }
+
+    function mod(n, x) {
+        return ((n % x) + x) % x;
+    }
+
+    var indexOf;
+
+    if (Array.prototype.indexOf) {
+        indexOf = Array.prototype.indexOf;
+    } else {
+        indexOf = function (o) {
+            // I know
+            var i;
+            for (i = 0; i < this.length; ++i) {
+                if (this[i] === o) {
+                    return i;
+                }
+            }
+            return -1;
+        };
+    }
+
+    function daysInMonth(year, month) {
+        if (isNaN(year) || isNaN(month)) {
+            return NaN;
+        }
+        var modMonth = mod(month, 12);
+        year += (month - modMonth) / 12;
+        return modMonth === 1 ? (isLeapYear(year) ? 29 : 28) : (31 - modMonth % 7 % 2);
+    }
+
+    // FORMATTING
+
+    addFormatToken('M', ['MM', 2], 'Mo', function () {
+        return this.month() + 1;
+    });
+
+    addFormatToken('MMM', 0, 0, function (format) {
+        return this.localeData().monthsShort(this, format);
+    });
+
+    addFormatToken('MMMM', 0, 0, function (format) {
+        return this.localeData().months(this, format);
+    });
+
+    // ALIASES
+
+    addUnitAlias('month', 'M');
+
+    // PRIORITY
+
+    addUnitPriority('month', 8);
+
+    // PARSING
+
+    addRegexToken('M',    match1to2);
+    addRegexToken('MM',   match1to2, match2);
+    addRegexToken('MMM',  function (isStrict, locale) {
+        return locale.monthsShortRegex(isStrict);
+    });
+    addRegexToken('MMMM', function (isStrict, locale) {
+        return locale.monthsRegex(isStrict);
+    });
+
+    addParseToken(['M', 'MM'], function (input, array) {
+        array[MONTH] = toInt(input) - 1;
+    });
+
+    addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
+        var month = config._locale.monthsParse(input, token, config._strict);
+        // if we didn't find a month name, mark the date as invalid.
+        if (month != null) {
+            array[MONTH] = month;
+        } else {
+            getParsingFlags(config).invalidMonth = input;
+        }
+    });
+
+    // LOCALES
+
+    var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
+    var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
+    function localeMonths (m, format) {
+        if (!m) {
+            return isArray(this._months) ? this._months :
+                this._months['standalone'];
+        }
+        return isArray(this._months) ? this._months[m.month()] :
+            this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
+    }
+
+    var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
+    function localeMonthsShort (m, format) {
+        if (!m) {
+            return isArray(this._monthsShort) ? this._monthsShort :
+                this._monthsShort['standalone'];
+        }
+        return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
+            this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
+    }
+
+    function handleStrictParse(monthName, format, strict) {
+        var i, ii, mom, llc = monthName.toLocaleLowerCase();
+        if (!this._monthsParse) {
+            // this is not used
+            this._monthsParse = [];
+            this._longMonthsParse = [];
+            this._shortMonthsParse = [];
+            for (i = 0; i < 12; ++i) {
+                mom = createUTC([2000, i]);
+                this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
+                this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
+            }
+        }
+
+        if (strict) {
+            if (format === 'MMM') {
+                ii = indexOf.call(this._shortMonthsParse, llc);
+                return ii !== -1 ? ii : null;
+            } else {
+                ii = indexOf.call(this._longMonthsParse, llc);
+                return ii !== -1 ? ii : null;
+            }
+        } else {
+            if (format === 'MMM') {
+                ii = indexOf.call(this._shortMonthsParse, llc);
+                if (ii !== -1) {
+                    return ii;
+                }
+                ii = indexOf.call(this._longMonthsParse, llc);
+                return ii !== -1 ? ii : null;
+            } else {
+                ii = indexOf.call(this._longMonthsParse, llc);
+                if (ii !== -1) {
+                    return ii;
+                }
+                ii = indexOf.call(this._shortMonthsParse, llc);
+                return ii !== -1 ? ii : null;
+            }
+        }
+    }
+
+    function localeMonthsParse (monthName, format, strict) {
+        var i, mom, regex;
+
+        if (this._monthsParseExact) {
+            return handleStrictParse.call(this, monthName, format, strict);
+        }
+
+        if (!this._monthsParse) {
+            this._monthsParse = [];
+            this._longMonthsParse = [];
+            this._shortMonthsParse = [];
+        }
+
+        // TODO: add sorting
+        // Sorting makes sure if one month (or abbr) is a prefix of another
+        // see sorting in computeMonthsParse
+        for (i = 0; i < 12; i++) {
+            // make the regex if we don't have it already
+            mom = createUTC([2000, i]);
+            if (strict && !this._longMonthsParse[i]) {
+                this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
+                this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
+            }
+            if (!strict && !this._monthsParse[i]) {
+                regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
+                this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
+            }
+            // test the regex
+            if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
+                return i;
+            } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
+                return i;
+            } else if (!strict && this._monthsParse[i].test(monthName)) {
+                return i;
+            }
+        }
+    }
+
+    // MOMENTS
+
+    function setMonth (mom, value) {
+        var dayOfMonth;
+
+        if (!mom.isValid()) {
+            // No op
+            return mom;
+        }
+
+        if (typeof value === 'string') {
+            if (/^\d+$/.test(value)) {
+                value = toInt(value);
+            } else {
+                value = mom.localeData().monthsParse(value);
+                // TODO: Another silent failure?
+                if (!isNumber(value)) {
+                    return mom;
+                }
+            }
+        }
+
+        dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
+        mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
+        return mom;
+    }
+
+    function getSetMonth (value) {
+        if (value != null) {
+            setMonth(this, value);
+            hooks.updateOffset(this, true);
+            return this;
+        } else {
+            return get(this, 'Month');
+        }
+    }
+
+    function getDaysInMonth () {
+        return daysInMonth(this.year(), this.month());
+    }
+
+    var defaultMonthsShortRegex = matchWord;
+    function monthsShortRegex (isStrict) {
+        if (this._monthsParseExact) {
+            if (!hasOwnProp(this, '_monthsRegex')) {
+                computeMonthsParse.call(this);
+            }
+            if (isStrict) {
+                return this._monthsShortStrictRegex;
+            } else {
+                return this._monthsShortRegex;
+            }
+        } else {
+            if (!hasOwnProp(this, '_monthsShortRegex')) {
+                this._monthsShortRegex = defaultMonthsShortRegex;
+            }
+            return this._monthsShortStrictRegex && isStrict ?
+                this._monthsShortStrictRegex : this._monthsShortRegex;
+        }
+    }
+
+    var defaultMonthsRegex = matchWord;
+    function monthsRegex (isStrict) {
+        if (this._monthsParseExact) {
+            if (!hasOwnProp(this, '_monthsRegex')) {
+                computeMonthsParse.call(this);
+            }
+            if (isStrict) {
+                return this._monthsStrictRegex;
+            } else {
+                return this._monthsRegex;
+            }
+        } else {
+            if (!hasOwnProp(this, '_monthsRegex')) {
+                this._monthsRegex = defaultMonthsRegex;
+            }
+            return this._monthsStrictRegex && isStrict ?
+                this._monthsStrictRegex : this._monthsRegex;
+        }
+    }
+
+    function computeMonthsParse () {
+        function cmpLenRev(a, b) {
+            return b.length - a.length;
+        }
+
+        var shortPieces = [], longPieces = [], mixedPieces = [],
+            i, mom;
+        for (i = 0; i < 12; i++) {
+            // make the regex if we don't have it already
+            mom = createUTC([2000, i]);
+            shortPieces.push(this.monthsShort(mom, ''));
+            longPieces.push(this.months(mom, ''));
+            mixedPieces.push(this.months(mom, ''));
+            mixedPieces.push(this.monthsShort(mom, ''));
+        }
+        // Sorting makes sure if one month (or abbr) is a prefix of another it
+        // will match the longer piece.
+        shortPieces.sort(cmpLenRev);
+        longPieces.sort(cmpLenRev);
+        mixedPieces.sort(cmpLenRev);
+        for (i = 0; i < 12; i++) {
+            shortPieces[i] = regexEscape(shortPieces[i]);
+            longPieces[i] = regexEscape(longPieces[i]);
+        }
+        for (i = 0; i < 24; i++) {
+            mixedPieces[i] = regexEscape(mixedPieces[i]);
+        }
+
+        this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
+        this._monthsShortRegex = this._monthsRegex;
+        this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
+        this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
+    }
+
+    function createDate (y, m, d, h, M, s, ms) {
+        // can't just apply() to create a date:
+        // https://stackoverflow.com/q/181348
+        var date;
+        // the date constructor remaps years 0-99 to 1900-1999
+        if (y < 100 && y >= 0) {
+            // preserve leap years using a full 400 year cycle, then reset
+            date = new Date(y + 400, m, d, h, M, s, ms);
+            if (isFinite(date.getFullYear())) {
+                date.setFullYear(y);
+            }
+        } else {
+            date = new Date(y, m, d, h, M, s, ms);
+        }
+
+        return date;
+    }
+
+    function createUTCDate (y) {
+        var date;
+        // the Date.UTC function remaps years 0-99 to 1900-1999
+        if (y < 100 && y >= 0) {
+            var args = Array.prototype.slice.call(arguments);
+            // preserve leap years using a full 400 year cycle, then reset
+            args[0] = y + 400;
+            date = new Date(Date.UTC.apply(null, args));
+            if (isFinite(date.getUTCFullYear())) {
+                date.setUTCFullYear(y);
+            }
+        } else {
+            date = new Date(Date.UTC.apply(null, arguments));
+        }
+
+        return date;
+    }
+
+    // start-of-first-week - start-of-year
+    function firstWeekOffset(year, dow, doy) {
+        var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
+            fwd = 7 + dow - doy,
+            // first-week day local weekday -- which local weekday is fwd
+            fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
+
+        return -fwdlw + fwd - 1;
+    }
+
+    // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
+    function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
+        var localWeekday = (7 + weekday - dow) % 7,
+            weekOffset = firstWeekOffset(year, dow, doy),
+            dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
+            resYear, resDayOfYear;
+
+        if (dayOfYear <= 0) {
+            resYear = year - 1;
+            resDayOfYear = daysInYear(resYear) + dayOfYear;
+        } else if (dayOfYear > daysInYear(year)) {
+            resYear = year + 1;
+            resDayOfYear = dayOfYear - daysInYear(year);
+        } else {
+            resYear = year;
+            resDayOfYear = dayOfYear;
+        }
+
+        return {
+            year: resYear,
+            dayOfYear: resDayOfYear
+        };
+    }
+
+    function weekOfYear(mom, dow, doy) {
+        var weekOffset = firstWeekOffset(mom.year(), dow, doy),
+            week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
+            resWeek, resYear;
+
+        if (week < 1) {
+            resYear = mom.year() - 1;
+            resWeek = week + weeksInYear(resYear, dow, doy);
+        } else if (week > weeksInYear(mom.year(), dow, doy)) {
+            resWeek = week - weeksInYear(mom.year(), dow, doy);
+            resYear = mom.year() + 1;
+        } else {
+            resYear = mom.year();
+            resWeek = week;
+        }
+
+        return {
+            week: resWeek,
+            year: resYear
+        };
+    }
+
+    function weeksInYear(year, dow, doy) {
+        var weekOffset = firstWeekOffset(year, dow, doy),
+            weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
+        return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
+    }
+
+    // FORMATTING
+
+    addFormatToken('w', ['ww', 2], 'wo', 'week');
+    addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
+
+    // ALIASES
+
+    addUnitAlias('week', 'w');
+    addUnitAlias('isoWeek', 'W');
+
+    // PRIORITIES
+
+    addUnitPriority('week', 5);
+    addUnitPriority('isoWeek', 5);
+
+    // PARSING
+
+    addRegexToken('w',  match1to2);
+    addRegexToken('ww', match1to2, match2);
+    addRegexToken('W',  match1to2);
+    addRegexToken('WW', match1to2, match2);
+
+    addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
+        week[token.substr(0, 1)] = toInt(input);
+    });
+
+    // HELPERS
+
+    // LOCALES
+
+    function localeWeek (mom) {
+        return weekOfYear(mom, this._week.dow, this._week.doy).week;
+    }
+
+    var defaultLocaleWeek = {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 6th is the first week of the year.
+    };
+
+    function localeFirstDayOfWeek () {
+        return this._week.dow;
+    }
+
+    function localeFirstDayOfYear () {
+        return this._week.doy;
+    }
+
+    // MOMENTS
+
+    function getSetWeek (input) {
+        var week = this.localeData().week(this);
+        return input == null ? week : this.add((input - week) * 7, 'd');
+    }
+
+    function getSetISOWeek (input) {
+        var week = weekOfYear(this, 1, 4).week;
+        return input == null ? week : this.add((input - week) * 7, 'd');
+    }
+
+    // FORMATTING
+
+    addFormatToken('d', 0, 'do', 'day');
+
+    addFormatToken('dd', 0, 0, function (format) {
+        return this.localeData().weekdaysMin(this, format);
+    });
+
+    addFormatToken('ddd', 0, 0, function (format) {
+        return this.localeData().weekdaysShort(this, format);
+    });
+
+    addFormatToken('dddd', 0, 0, function (format) {
+        return this.localeData().weekdays(this, format);
+    });
+
+    addFormatToken('e', 0, 0, 'weekday');
+    addFormatToken('E', 0, 0, 'isoWeekday');
+
+    // ALIASES
+
+    addUnitAlias('day', 'd');
+    addUnitAlias('weekday', 'e');
+    addUnitAlias('isoWeekday', 'E');
+
+    // PRIORITY
+    addUnitPriority('day', 11);
+    addUnitPriority('weekday', 11);
+    addUnitPriority('isoWeekday', 11);
+
+    // PARSING
+
+    addRegexToken('d',    match1to2);
+    addRegexToken('e',    match1to2);
+    addRegexToken('E',    match1to2);
+    addRegexToken('dd',   function (isStrict, locale) {
+        return locale.weekdaysMinRegex(isStrict);
+    });
+    addRegexToken('ddd',   function (isStrict, locale) {
+        return locale.weekdaysShortRegex(isStrict);
+    });
+    addRegexToken('dddd',   function (isStrict, locale) {
+        return locale.weekdaysRegex(isStrict);
+    });
+
+    addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
+        var weekday = config._locale.weekdaysParse(input, token, config._strict);
+        // if we didn't get a weekday name, mark the date as invalid
+        if (weekday != null) {
+            week.d = weekday;
+        } else {
+            getParsingFlags(config).invalidWeekday = input;
+        }
+    });
+
+    addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
+        week[token] = toInt(input);
+    });
+
+    // HELPERS
+
+    function parseWeekday(input, locale) {
+        if (typeof input !== 'string') {
+            return input;
+        }
+
+        if (!isNaN(input)) {
+            return parseInt(input, 10);
+        }
+
+        input = locale.weekdaysParse(input);
+        if (typeof input === 'number') {
+            return input;
+        }
+
+        return null;
+    }
+
+    function parseIsoWeekday(input, locale) {
+        if (typeof input === 'string') {
+            return locale.weekdaysParse(input) % 7 || 7;
+        }
+        return isNaN(input) ? null : input;
+    }
+
+    // LOCALES
+    function shiftWeekdays (ws, n) {
+        return ws.slice(n, 7).concat(ws.slice(0, n));
+    }
+
+    var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
+    function localeWeekdays (m, format) {
+        var weekdays = isArray(this._weekdays) ? this._weekdays :
+            this._weekdays[(m && m !== true && this._weekdays.isFormat.test(format)) ? 'format' : 'standalone'];
+        return (m === true) ? shiftWeekdays(weekdays, this._week.dow)
+            : (m) ? weekdays[m.day()] : weekdays;
+    }
+
+    var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
+    function localeWeekdaysShort (m) {
+        return (m === true) ? shiftWeekdays(this._weekdaysShort, this._week.dow)
+            : (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort;
+    }
+
+    var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
+    function localeWeekdaysMin (m) {
+        return (m === true) ? shiftWeekdays(this._weekdaysMin, this._week.dow)
+            : (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin;
+    }
+
+    function handleStrictParse$1(weekdayName, format, strict) {
+        var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
+        if (!this._weekdaysParse) {
+            this._weekdaysParse = [];
+            this._shortWeekdaysParse = [];
+            this._minWeekdaysParse = [];
+
+            for (i = 0; i < 7; ++i) {
+                mom = createUTC([2000, 1]).day(i);
+                this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
+                this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
+                this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
+            }
+        }
+
+        if (strict) {
+            if (format === 'dddd') {
+                ii = indexOf.call(this._weekdaysParse, llc);
+                return ii !== -1 ? ii : null;
+            } else if (format === 'ddd') {
+                ii = indexOf.call(this._shortWeekdaysParse, llc);
+                return ii !== -1 ? ii : null;
+            } else {
+                ii = indexOf.call(this._minWeekdaysParse, llc);
+                return ii !== -1 ? ii : null;
+            }
+        } else {
+            if (format === 'dddd') {
+                ii = indexOf.call(this._weekdaysParse, llc);
+                if (ii !== -1) {
+                    return ii;
+                }
+                ii = indexOf.call(this._shortWeekdaysParse, llc);
+                if (ii !== -1) {
+                    return ii;
+                }
+                ii = indexOf.call(this._minWeekdaysParse, llc);
+                return ii !== -1 ? ii : null;
+            } else if (format === 'ddd') {
+                ii = indexOf.call(this._shortWeekdaysParse, llc);
+                if (ii !== -1) {
+                    return ii;
+                }
+                ii = indexOf.call(this._weekdaysParse, llc);
+                if (ii !== -1) {
+                    return ii;
+                }
+                ii = indexOf.call(this._minWeekdaysParse, llc);
+                return ii !== -1 ? ii : null;
+            } else {
+                ii = indexOf.call(this._minWeekdaysParse, llc);
+                if (ii !== -1) {
+                    return ii;
+                }
+                ii = indexOf.call(this._weekdaysParse, llc);
+                if (ii !== -1) {
+                    return ii;
+                }
+                ii = indexOf.call(this._shortWeekdaysParse, llc);
+                return ii !== -1 ? ii : null;
+            }
+        }
+    }
+
+    function localeWeekdaysParse (weekdayName, format, strict) {
+        var i, mom, regex;
+
+        if (this._weekdaysParseExact) {
+            return handleStrictParse$1.call(this, weekdayName, format, strict);
+        }
+
+        if (!this._weekdaysParse) {
+            this._weekdaysParse = [];
+            this._minWeekdaysParse = [];
+            this._shortWeekdaysParse = [];
+            this._fullWeekdaysParse = [];
+        }
+
+        for (i = 0; i < 7; i++) {
+            // make the regex if we don't have it already
+
+            mom = createUTC([2000, 1]).day(i);
+            if (strict && !this._fullWeekdaysParse[i]) {
+                this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\\.?') + '$', 'i');
+                this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\\.?') + '$', 'i');
+                this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\\.?') + '$', 'i');
+            }
+            if (!this._weekdaysParse[i]) {
+                regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
+                this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
+            }
+            // test the regex
+            if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
+                return i;
+            } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
+                return i;
+            } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
+                return i;
+            } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
+                return i;
+            }
+        }
+    }
+
+    // MOMENTS
+
+    function getSetDayOfWeek (input) {
+        if (!this.isValid()) {
+            return input != null ? this : NaN;
+        }
+        var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
+        if (input != null) {
+            input = parseWeekday(input, this.localeData());
+            return this.add(input - day, 'd');
+        } else {
+            return day;
+        }
+    }
+
+    function getSetLocaleDayOfWeek (input) {
+        if (!this.isValid()) {
+            return input != null ? this : NaN;
+        }
+        var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
+        return input == null ? weekday : this.add(input - weekday, 'd');
+    }
+
+    function getSetISODayOfWeek (input) {
+        if (!this.isValid()) {
+            return input != null ? this : NaN;
+        }
+
+        // behaves the same as moment#day except
+        // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
+        // as a setter, sunday should belong to the previous week.
+
+        if (input != null) {
+            var weekday = parseIsoWeekday(input, this.localeData());
+            return this.day(this.day() % 7 ? weekday : weekday - 7);
+        } else {
+            return this.day() || 7;
+        }
+    }
+
+    var defaultWeekdaysRegex = matchWord;
+    function weekdaysRegex (isStrict) {
+        if (this._weekdaysParseExact) {
+            if (!hasOwnProp(this, '_weekdaysRegex')) {
+                computeWeekdaysParse.call(this);
+            }
+            if (isStrict) {
+                return this._weekdaysStrictRegex;
+            } else {
+                return this._weekdaysRegex;
+            }
+        } else {
+            if (!hasOwnProp(this, '_weekdaysRegex')) {
+                this._weekdaysRegex = defaultWeekdaysRegex;
+            }
+            return this._weekdaysStrictRegex && isStrict ?
+                this._weekdaysStrictRegex : this._weekdaysRegex;
+        }
+    }
+
+    var defaultWeekdaysShortRegex = matchWord;
+    function weekdaysShortRegex (isStrict) {
+        if (this._weekdaysParseExact) {
+            if (!hasOwnProp(this, '_weekdaysRegex')) {
+                computeWeekdaysParse.call(this);
+            }
+            if (isStrict) {
+                return this._weekdaysShortStrictRegex;
+            } else {
+                return this._weekdaysShortRegex;
+            }
+        } else {
+            if (!hasOwnProp(this, '_weekdaysShortRegex')) {
+                this._weekdaysShortRegex = defaultWeekdaysShortRegex;
+            }
+            return this._weekdaysShortStrictRegex && isStrict ?
+                this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
+        }
+    }
+
+    var defaultWeekdaysMinRegex = matchWord;
+    function weekdaysMinRegex (isStrict) {
+        if (this._weekdaysParseExact) {
+            if (!hasOwnProp(this, '_weekdaysRegex')) {
+                computeWeekdaysParse.call(this);
+            }
+            if (isStrict) {
+                return this._weekdaysMinStrictRegex;
+            } else {
+                return this._weekdaysMinRegex;
+            }
+        } else {
+            if (!hasOwnProp(this, '_weekdaysMinRegex')) {
+                this._weekdaysMinRegex = defaultWeekdaysMinRegex;
+            }
+            return this._weekdaysMinStrictRegex && isStrict ?
+                this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
+        }
+    }
+
+
+    function computeWeekdaysParse () {
+        function cmpLenRev(a, b) {
+            return b.length - a.length;
+        }
+
+        var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],
+            i, mom, minp, shortp, longp;
+        for (i = 0; i < 7; i++) {
+            // make the regex if we don't have it already
+            mom = createUTC([2000, 1]).day(i);
+            minp = this.weekdaysMin(mom, '');
+            shortp = this.weekdaysShort(mom, '');
+            longp = this.weekdays(mom, '');
+            minPieces.push(minp);
+            shortPieces.push(shortp);
+            longPieces.push(longp);
+            mixedPieces.push(minp);
+            mixedPieces.push(shortp);
+            mixedPieces.push(longp);
+        }
+        // Sorting makes sure if one weekday (or abbr) is a prefix of another it
+        // will match the longer piece.
+        minPieces.sort(cmpLenRev);
+        shortPieces.sort(cmpLenRev);
+        longPieces.sort(cmpLenRev);
+        mixedPieces.sort(cmpLenRev);
+        for (i = 0; i < 7; i++) {
+            shortPieces[i] = regexEscape(shortPieces[i]);
+            longPieces[i] = regexEscape(longPieces[i]);
+            mixedPieces[i] = regexEscape(mixedPieces[i]);
+        }
+
+        this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
+        this._weekdaysShortRegex = this._weekdaysRegex;
+        this._weekdaysMinRegex = this._weekdaysRegex;
+
+        this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
+        this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
+        this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
+    }
+
+    // FORMATTING
+
+    function hFormat() {
+        return this.hours() % 12 || 12;
+    }
+
+    function kFormat() {
+        return this.hours() || 24;
+    }
+
+    addFormatToken('H', ['HH', 2], 0, 'hour');
+    addFormatToken('h', ['hh', 2], 0, hFormat);
+    addFormatToken('k', ['kk', 2], 0, kFormat);
+
+    addFormatToken('hmm', 0, 0, function () {
+        return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
+    });
+
+    addFormatToken('hmmss', 0, 0, function () {
+        return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
+            zeroFill(this.seconds(), 2);
+    });
+
+    addFormatToken('Hmm', 0, 0, function () {
+        return '' + this.hours() + zeroFill(this.minutes(), 2);
+    });
+
+    addFormatToken('Hmmss', 0, 0, function () {
+        return '' + this.hours() + zeroFill(this.minutes(), 2) +
+            zeroFill(this.seconds(), 2);
+    });
+
+    function meridiem (token, lowercase) {
+        addFormatToken(token, 0, 0, function () {
+            return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
+        });
+    }
+
+    meridiem('a', true);
+    meridiem('A', false);
+
+    // ALIASES
+
+    addUnitAlias('hour', 'h');
+
+    // PRIORITY
+    addUnitPriority('hour', 13);
+
+    // PARSING
+
+    function matchMeridiem (isStrict, locale) {
+        return locale._meridiemParse;
+    }
+
+    addRegexToken('a',  matchMeridiem);
+    addRegexToken('A',  matchMeridiem);
+    addRegexToken('H',  match1to2);
+    addRegexToken('h',  match1to2);
+    addRegexToken('k',  match1to2);
+    addRegexToken('HH', match1to2, match2);
+    addRegexToken('hh', match1to2, match2);
+    addRegexToken('kk', match1to2, match2);
+
+    addRegexToken('hmm', match3to4);
+    addRegexToken('hmmss', match5to6);
+    addRegexToken('Hmm', match3to4);
+    addRegexToken('Hmmss', match5to6);
+
+    addParseToken(['H', 'HH'], HOUR);
+    addParseToken(['k', 'kk'], function (input, array, config) {
+        var kInput = toInt(input);
+        array[HOUR] = kInput === 24 ? 0 : kInput;
+    });
+    addParseToken(['a', 'A'], function (input, array, config) {
+        config._isPm = config._locale.isPM(input);
+        config._meridiem = input;
+    });
+    addParseToken(['h', 'hh'], function (input, array, config) {
+        array[HOUR] = toInt(input);
+        getParsingFlags(config).bigHour = true;
+    });
+    addParseToken('hmm', function (input, array, config) {
+        var pos = input.length - 2;
+        array[HOUR] = toInt(input.substr(0, pos));
+        array[MINUTE] = toInt(input.substr(pos));
+        getParsingFlags(config).bigHour = true;
+    });
+    addParseToken('hmmss', function (input, array, config) {
+        var pos1 = input.length - 4;
+        var pos2 = input.length - 2;
+        array[HOUR] = toInt(input.substr(0, pos1));
+        array[MINUTE] = toInt(input.substr(pos1, 2));
+        array[SECOND] = toInt(input.substr(pos2));
+        getParsingFlags(config).bigHour = true;
+    });
+    addParseToken('Hmm', function (input, array, config) {
+        var pos = input.length - 2;
+        array[HOUR] = toInt(input.substr(0, pos));
+        array[MINUTE] = toInt(input.substr(pos));
+    });
+    addParseToken('Hmmss', function (input, array, config) {
+        var pos1 = input.length - 4;
+        var pos2 = input.length - 2;
+        array[HOUR] = toInt(input.substr(0, pos1));
+        array[MINUTE] = toInt(input.substr(pos1, 2));
+        array[SECOND] = toInt(input.substr(pos2));
+    });
+
+    // LOCALES
+
+    function localeIsPM (input) {
+        // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
+        // Using charAt should be more compatible.
+        return ((input + '').toLowerCase().charAt(0) === 'p');
+    }
+
+    var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
+    function localeMeridiem (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'pm' : 'PM';
+        } else {
+            return isLower ? 'am' : 'AM';
+        }
+    }
+
+
+    // MOMENTS
+
+    // Setting the hour should keep the time, because the user explicitly
+    // specified which hour they want. So trying to maintain the same hour (in
+    // a new timezone) makes sense. Adding/subtracting hours does not follow
+    // this rule.
+    var getSetHour = makeGetSet('Hours', true);
+
+    var baseConfig = {
+        calendar: defaultCalendar,
+        longDateFormat: defaultLongDateFormat,
+        invalidDate: defaultInvalidDate,
+        ordinal: defaultOrdinal,
+        dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
+        relativeTime: defaultRelativeTime,
+
+        months: defaultLocaleMonths,
+        monthsShort: defaultLocaleMonthsShort,
+
+        week: defaultLocaleWeek,
+
+        weekdays: defaultLocaleWeekdays,
+        weekdaysMin: defaultLocaleWeekdaysMin,
+        weekdaysShort: defaultLocaleWeekdaysShort,
+
+        meridiemParse: defaultLocaleMeridiemParse
+    };
+
+    // internal storage for locale config files
+    var locales = {};
+    var localeFamilies = {};
+    var globalLocale;
+
+    function normalizeLocale(key) {
+        return key ? key.toLowerCase().replace('_', '-') : key;
+    }
+
+    // pick the locale from the array
+    // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
+    // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
+    function chooseLocale(names) {
+        var i = 0, j, next, locale, split;
+
+        while (i < names.length) {
+            split = normalizeLocale(names[i]).split('-');
+            j = split.length;
+            next = normalizeLocale(names[i + 1]);
+            next = next ? next.split('-') : null;
+            while (j > 0) {
+                locale = loadLocale(split.slice(0, j).join('-'));
+                if (locale) {
+                    return locale;
+                }
+                if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
+                    //the next array item is better than a shallower substring of this one
+                    break;
+                }
+                j--;
+            }
+            i++;
+        }
+        return globalLocale;
+    }
+
+    function loadLocale(name) {
+        var oldLocale = null;
+        // TODO: Find a better way to register and load all the locales in Node
+        if (!locales[name] && ('object' !== 'undefined') &&
+                module && module.exports) {
+            try {
+                oldLocale = globalLocale._abbr;
+                var aliasedRequire = commonjsRequire;
+                aliasedRequire('./locale/' + name);
+                getSetGlobalLocale(oldLocale);
+            } catch (e) {}
+        }
+        return locales[name];
+    }
+
+    // This function will load locale and then set the global locale.  If
+    // no arguments are passed in, it will simply return the current global
+    // locale key.
+    function getSetGlobalLocale (key, values) {
+        var data;
+        if (key) {
+            if (isUndefined(values)) {
+                data = getLocale(key);
+            }
+            else {
+                data = defineLocale(key, values);
+            }
+
+            if (data) {
+                // moment.duration._locale = moment._locale = data;
+                globalLocale = data;
+            }
+            else {
+                if ((typeof console !==  'undefined') && console.warn) {
+                    //warn user if arguments are passed but the locale could not be set
+                    console.warn('Locale ' + key +  ' not found. Did you forget to load it?');
+                }
+            }
+        }
+
+        return globalLocale._abbr;
+    }
+
+    function defineLocale (name, config) {
+        if (config !== null) {
+            var locale, parentConfig = baseConfig;
+            config.abbr = name;
+            if (locales[name] != null) {
+                deprecateSimple('defineLocaleOverride',
+                        'use moment.updateLocale(localeName, config) to change ' +
+                        'an existing locale. moment.defineLocale(localeName, ' +
+                        'config) should only be used for creating a new locale ' +
+                        'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
+                parentConfig = locales[name]._config;
+            } else if (config.parentLocale != null) {
+                if (locales[config.parentLocale] != null) {
+                    parentConfig = locales[config.parentLocale]._config;
+                } else {
+                    locale = loadLocale(config.parentLocale);
+                    if (locale != null) {
+                        parentConfig = locale._config;
+                    } else {
+                        if (!localeFamilies[config.parentLocale]) {
+                            localeFamilies[config.parentLocale] = [];
+                        }
+                        localeFamilies[config.parentLocale].push({
+                            name: name,
+                            config: config
+                        });
+                        return null;
+                    }
+                }
+            }
+            locales[name] = new Locale(mergeConfigs(parentConfig, config));
+
+            if (localeFamilies[name]) {
+                localeFamilies[name].forEach(function (x) {
+                    defineLocale(x.name, x.config);
+                });
+            }
+
+            // backwards compat for now: also set the locale
+            // make sure we set the locale AFTER all child locales have been
+            // created, so we won't end up with the child locale set.
+            getSetGlobalLocale(name);
+
+
+            return locales[name];
+        } else {
+            // useful for testing
+            delete locales[name];
+            return null;
+        }
+    }
+
+    function updateLocale(name, config) {
+        if (config != null) {
+            var locale, tmpLocale, parentConfig = baseConfig;
+            // MERGE
+            tmpLocale = loadLocale(name);
+            if (tmpLocale != null) {
+                parentConfig = tmpLocale._config;
+            }
+            config = mergeConfigs(parentConfig, config);
+            locale = new Locale(config);
+            locale.parentLocale = locales[name];
+            locales[name] = locale;
+
+            // backwards compat for now: also set the locale
+            getSetGlobalLocale(name);
+        } else {
+            // pass null for config to unupdate, useful for tests
+            if (locales[name] != null) {
+                if (locales[name].parentLocale != null) {
+                    locales[name] = locales[name].parentLocale;
+                } else if (locales[name] != null) {
+                    delete locales[name];
+                }
+            }
+        }
+        return locales[name];
+    }
+
+    // returns locale data
+    function getLocale (key) {
+        var locale;
+
+        if (key && key._locale && key._locale._abbr) {
+            key = key._locale._abbr;
+        }
+
+        if (!key) {
+            return globalLocale;
+        }
+
+        if (!isArray(key)) {
+            //short-circuit everything else
+            locale = loadLocale(key);
+            if (locale) {
+                return locale;
+            }
+            key = [key];
+        }
+
+        return chooseLocale(key);
+    }
+
+    function listLocales() {
+        return keys(locales);
+    }
+
+    function checkOverflow (m) {
+        var overflow;
+        var a = m._a;
+
+        if (a && getParsingFlags(m).overflow === -2) {
+            overflow =
+                a[MONTH]       < 0 || a[MONTH]       > 11  ? MONTH :
+                a[DATE]        < 1 || a[DATE]        > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
+                a[HOUR]        < 0 || a[HOUR]        > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
+                a[MINUTE]      < 0 || a[MINUTE]      > 59  ? MINUTE :
+                a[SECOND]      < 0 || a[SECOND]      > 59  ? SECOND :
+                a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
+                -1;
+
+            if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
+                overflow = DATE;
+            }
+            if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
+                overflow = WEEK;
+            }
+            if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
+                overflow = WEEKDAY;
+            }
+
+            getParsingFlags(m).overflow = overflow;
+        }
+
+        return m;
+    }
+
+    // Pick the first defined of two or three arguments.
+    function defaults(a, b, c) {
+        if (a != null) {
+            return a;
+        }
+        if (b != null) {
+            return b;
+        }
+        return c;
+    }
+
+    function currentDateArray(config) {
+        // hooks is actually the exported moment object
+        var nowValue = new Date(hooks.now());
+        if (config._useUTC) {
+            return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
+        }
+        return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
+    }
+
+    // convert an array to a date.
+    // the array should mirror the parameters below
+    // note: all values past the year are optional and will default to the lowest possible value.
+    // [year, month, day , hour, minute, second, millisecond]
+    function configFromArray (config) {
+        var i, date, input = [], currentDate, expectedWeekday, yearToUse;
+
+        if (config._d) {
+            return;
+        }
+
+        currentDate = currentDateArray(config);
+
+        //compute day of the year from weeks and weekdays
+        if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
+            dayOfYearFromWeekInfo(config);
+        }
+
+        //if the day of the year is set, figure out what it is
+        if (config._dayOfYear != null) {
+            yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
+
+            if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
+                getParsingFlags(config)._overflowDayOfYear = true;
+            }
+
+            date = createUTCDate(yearToUse, 0, config._dayOfYear);
+            config._a[MONTH] = date.getUTCMonth();
+            config._a[DATE] = date.getUTCDate();
+        }
+
+        // Default to current date.
+        // * if no year, month, day of month are given, default to today
+        // * if day of month is given, default month and year
+        // * if month is given, default only year
+        // * if year is given, don't default anything
+        for (i = 0; i < 3 && config._a[i] == null; ++i) {
+            config._a[i] = input[i] = currentDate[i];
+        }
+
+        // Zero out whatever was not defaulted, including time
+        for (; i < 7; i++) {
+            config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
+        }
+
+        // Check for 24:00:00.000
+        if (config._a[HOUR] === 24 &&
+                config._a[MINUTE] === 0 &&
+                config._a[SECOND] === 0 &&
+                config._a[MILLISECOND] === 0) {
+            config._nextDay = true;
+            config._a[HOUR] = 0;
+        }
+
+        config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
+        expectedWeekday = config._useUTC ? config._d.getUTCDay() : config._d.getDay();
+
+        // Apply timezone offset from input. The actual utcOffset can be changed
+        // with parseZone.
+        if (config._tzm != null) {
+            config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
+        }
+
+        if (config._nextDay) {
+            config._a[HOUR] = 24;
+        }
+
+        // check for mismatching day of week
+        if (config._w && typeof config._w.d !== 'undefined' && config._w.d !== expectedWeekday) {
+            getParsingFlags(config).weekdayMismatch = true;
+        }
+    }
+
+    function dayOfYearFromWeekInfo(config) {
+        var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
+
+        w = config._w;
+        if (w.GG != null || w.W != null || w.E != null) {
+            dow = 1;
+            doy = 4;
+
+            // TODO: We need to take the current isoWeekYear, but that depends on
+            // how we interpret now (local, utc, fixed offset). So create
+            // a now version of current config (take local/utc/offset flags, and
+            // create now).
+            weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
+            week = defaults(w.W, 1);
+            weekday = defaults(w.E, 1);
+            if (weekday < 1 || weekday > 7) {
+                weekdayOverflow = true;
+            }
+        } else {
+            dow = config._locale._week.dow;
+            doy = config._locale._week.doy;
+
+            var curWeek = weekOfYear(createLocal(), dow, doy);
+
+            weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);
+
+            // Default to current week.
+            week = defaults(w.w, curWeek.week);
+
+            if (w.d != null) {
+                // weekday -- low day numbers are considered next week
+                weekday = w.d;
+                if (weekday < 0 || weekday > 6) {
+                    weekdayOverflow = true;
+                }
+            } else if (w.e != null) {
+                // local weekday -- counting starts from beginning of week
+                weekday = w.e + dow;
+                if (w.e < 0 || w.e > 6) {
+                    weekdayOverflow = true;
+                }
+            } else {
+                // default to beginning of week
+                weekday = dow;
+            }
+        }
+        if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
+            getParsingFlags(config)._overflowWeeks = true;
+        } else if (weekdayOverflow != null) {
+            getParsingFlags(config)._overflowWeekday = true;
+        } else {
+            temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
+            config._a[YEAR] = temp.year;
+            config._dayOfYear = temp.dayOfYear;
+        }
+    }
+
+    // iso 8601 regex
+    // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
+    var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
+    var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
+
+    var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
+
+    var isoDates = [
+        ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
+        ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
+        ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
+        ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
+        ['YYYY-DDD', /\d{4}-\d{3}/],
+        ['YYYY-MM', /\d{4}-\d\d/, false],
+        ['YYYYYYMMDD', /[+-]\d{10}/],
+        ['YYYYMMDD', /\d{8}/],
+        // YYYYMM is NOT allowed by the standard
+        ['GGGG[W]WWE', /\d{4}W\d{3}/],
+        ['GGGG[W]WW', /\d{4}W\d{2}/, false],
+        ['YYYYDDD', /\d{7}/]
+    ];
+
+    // iso time formats and regexes
+    var isoTimes = [
+        ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
+        ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
+        ['HH:mm:ss', /\d\d:\d\d:\d\d/],
+        ['HH:mm', /\d\d:\d\d/],
+        ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
+        ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
+        ['HHmmss', /\d\d\d\d\d\d/],
+        ['HHmm', /\d\d\d\d/],
+        ['HH', /\d\d/]
+    ];
+
+    var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
+
+    // date from iso format
+    function configFromISO(config) {
+        var i, l,
+            string = config._i,
+            match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
+            allowTime, dateFormat, timeFormat, tzFormat;
+
+        if (match) {
+            getParsingFlags(config).iso = true;
+
+            for (i = 0, l = isoDates.length; i < l; i++) {
+                if (isoDates[i][1].exec(match[1])) {
+                    dateFormat = isoDates[i][0];
+                    allowTime = isoDates[i][2] !== false;
+                    break;
+                }
+            }
+            if (dateFormat == null) {
+                config._isValid = false;
+                return;
+            }
+            if (match[3]) {
+                for (i = 0, l = isoTimes.length; i < l; i++) {
+                    if (isoTimes[i][1].exec(match[3])) {
+                        // match[2] should be 'T' or space
+                        timeFormat = (match[2] || ' ') + isoTimes[i][0];
+                        break;
+                    }
+                }
+                if (timeFormat == null) {
+                    config._isValid = false;
+                    return;
+                }
+            }
+            if (!allowTime && timeFormat != null) {
+                config._isValid = false;
+                return;
+            }
+            if (match[4]) {
+                if (tzRegex.exec(match[4])) {
+                    tzFormat = 'Z';
+                } else {
+                    config._isValid = false;
+                    return;
+                }
+            }
+            config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
+            configFromStringAndFormat(config);
+        } else {
+            config._isValid = false;
+        }
+    }
+
+    // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
+    var rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/;
+
+    function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
+        var result = [
+            untruncateYear(yearStr),
+            defaultLocaleMonthsShort.indexOf(monthStr),
+            parseInt(dayStr, 10),
+            parseInt(hourStr, 10),
+            parseInt(minuteStr, 10)
+        ];
+
+        if (secondStr) {
+            result.push(parseInt(secondStr, 10));
+        }
+
+        return result;
+    }
+
+    function untruncateYear(yearStr) {
+        var year = parseInt(yearStr, 10);
+        if (year <= 49) {
+            return 2000 + year;
+        } else if (year <= 999) {
+            return 1900 + year;
+        }
+        return year;
+    }
+
+    function preprocessRFC2822(s) {
+        // Remove comments and folding whitespace and replace multiple-spaces with a single space
+        return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').replace(/^\s\s*/, '').replace(/\s\s*$/, '');
+    }
+
+    function checkWeekday(weekdayStr, parsedInput, config) {
+        if (weekdayStr) {
+            // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
+            var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
+                weekdayActual = new Date(parsedInput[0], parsedInput[1], parsedInput[2]).getDay();
+            if (weekdayProvided !== weekdayActual) {
+                getParsingFlags(config).weekdayMismatch = true;
+                config._isValid = false;
+                return false;
+            }
+        }
+        return true;
+    }
+
+    var obsOffsets = {
+        UT: 0,
+        GMT: 0,
+        EDT: -4 * 60,
+        EST: -5 * 60,
+        CDT: -5 * 60,
+        CST: -6 * 60,
+        MDT: -6 * 60,
+        MST: -7 * 60,
+        PDT: -7 * 60,
+        PST: -8 * 60
+    };
+
+    function calculateOffset(obsOffset, militaryOffset, numOffset) {
+        if (obsOffset) {
+            return obsOffsets[obsOffset];
+        } else if (militaryOffset) {
+            // the only allowed military tz is Z
+            return 0;
+        } else {
+            var hm = parseInt(numOffset, 10);
+            var m = hm % 100, h = (hm - m) / 100;
+            return h * 60 + m;
+        }
+    }
+
+    // date and time from ref 2822 format
+    function configFromRFC2822(config) {
+        var match = rfc2822.exec(preprocessRFC2822(config._i));
+        if (match) {
+            var parsedArray = extractFromRFC2822Strings(match[4], match[3], match[2], match[5], match[6], match[7]);
+            if (!checkWeekday(match[1], parsedArray, config)) {
+                return;
+            }
+
+            config._a = parsedArray;
+            config._tzm = calculateOffset(match[8], match[9], match[10]);
+
+            config._d = createUTCDate.apply(null, config._a);
+            config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
+
+            getParsingFlags(config).rfc2822 = true;
+        } else {
+            config._isValid = false;
+        }
+    }
+
+    // date from iso format or fallback
+    function configFromString(config) {
+        var matched = aspNetJsonRegex.exec(config._i);
+
+        if (matched !== null) {
+            config._d = new Date(+matched[1]);
+            return;
+        }
+
+        configFromISO(config);
+        if (config._isValid === false) {
+            delete config._isValid;
+        } else {
+            return;
+        }
+
+        configFromRFC2822(config);
+        if (config._isValid === false) {
+            delete config._isValid;
+        } else {
+            return;
+        }
+
+        // Final attempt, use Input Fallback
+        hooks.createFromInputFallback(config);
+    }
+
+    hooks.createFromInputFallback = deprecate(
+        'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +
+        'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +
+        'discouraged and will be removed in an upcoming major release. Please refer to ' +
+        'http://momentjs.com/guides/#/warnings/js-date/ for more info.',
+        function (config) {
+            config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
+        }
+    );
+
+    // constant that refers to the ISO standard
+    hooks.ISO_8601 = function () {};
+
+    // constant that refers to the RFC 2822 form
+    hooks.RFC_2822 = function () {};
+
+    // date from string and format string
+    function configFromStringAndFormat(config) {
+        // TODO: Move this to another part of the creation flow to prevent circular deps
+        if (config._f === hooks.ISO_8601) {
+            configFromISO(config);
+            return;
+        }
+        if (config._f === hooks.RFC_2822) {
+            configFromRFC2822(config);
+            return;
+        }
+        config._a = [];
+        getParsingFlags(config).empty = true;
+
+        // This array is used to make a Date, either with `new Date` or `Date.UTC`
+        var string = '' + config._i,
+            i, parsedInput, tokens, token, skipped,
+            stringLength = string.length,
+            totalParsedInputLength = 0;
+
+        tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
+
+        for (i = 0; i < tokens.length; i++) {
+            token = tokens[i];
+            parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
+            // console.log('token', token, 'parsedInput', parsedInput,
+            //         'regex', getParseRegexForToken(token, config));
+            if (parsedInput) {
+                skipped = string.substr(0, string.indexOf(parsedInput));
+                if (skipped.length > 0) {
+                    getParsingFlags(config).unusedInput.push(skipped);
+                }
+                string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
+                totalParsedInputLength += parsedInput.length;
+            }
+            // don't parse if it's not a known token
+            if (formatTokenFunctions[token]) {
+                if (parsedInput) {
+                    getParsingFlags(config).empty = false;
+                }
+                else {
+                    getParsingFlags(config).unusedTokens.push(token);
+                }
+                addTimeToArrayFromToken(token, parsedInput, config);
+            }
+            else if (config._strict && !parsedInput) {
+                getParsingFlags(config).unusedTokens.push(token);
+            }
+        }
+
+        // add remaining unparsed input length to the string
+        getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
+        if (string.length > 0) {
+            getParsingFlags(config).unusedInput.push(string);
+        }
+
+        // clear _12h flag if hour is <= 12
+        if (config._a[HOUR] <= 12 &&
+            getParsingFlags(config).bigHour === true &&
+            config._a[HOUR] > 0) {
+            getParsingFlags(config).bigHour = undefined;
+        }
+
+        getParsingFlags(config).parsedDateParts = config._a.slice(0);
+        getParsingFlags(config).meridiem = config._meridiem;
+        // handle meridiem
+        config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
+
+        configFromArray(config);
+        checkOverflow(config);
+    }
+
+
+    function meridiemFixWrap (locale, hour, meridiem) {
+        var isPm;
+
+        if (meridiem == null) {
+            // nothing to do
+            return hour;
+        }
+        if (locale.meridiemHour != null) {
+            return locale.meridiemHour(hour, meridiem);
+        } else if (locale.isPM != null) {
+            // Fallback
+            isPm = locale.isPM(meridiem);
+            if (isPm && hour < 12) {
+                hour += 12;
+            }
+            if (!isPm && hour === 12) {
+                hour = 0;
+            }
+            return hour;
+        } else {
+            // this is not supposed to happen
+            return hour;
+        }
+    }
+
+    // date from string and array of format strings
+    function configFromStringAndArray(config) {
+        var tempConfig,
+            bestMoment,
+
+            scoreToBeat,
+            i,
+            currentScore;
+
+        if (config._f.length === 0) {
+            getParsingFlags(config).invalidFormat = true;
+            config._d = new Date(NaN);
+            return;
+        }
+
+        for (i = 0; i < config._f.length; i++) {
+            currentScore = 0;
+            tempConfig = copyConfig({}, config);
+            if (config._useUTC != null) {
+                tempConfig._useUTC = config._useUTC;
+            }
+            tempConfig._f = config._f[i];
+            configFromStringAndFormat(tempConfig);
+
+            if (!isValid(tempConfig)) {
+                continue;
+            }
+
+            // if there is any input that was not parsed add a penalty for that format
+            currentScore += getParsingFlags(tempConfig).charsLeftOver;
+
+            //or tokens
+            currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
+
+            getParsingFlags(tempConfig).score = currentScore;
+
+            if (scoreToBeat == null || currentScore < scoreToBeat) {
+                scoreToBeat = currentScore;
+                bestMoment = tempConfig;
+            }
+        }
+
+        extend(config, bestMoment || tempConfig);
+    }
+
+    function configFromObject(config) {
+        if (config._d) {
+            return;
+        }
+
+        var i = normalizeObjectUnits(config._i);
+        config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
+            return obj && parseInt(obj, 10);
+        });
+
+        configFromArray(config);
+    }
+
+    function createFromConfig (config) {
+        var res = new Moment(checkOverflow(prepareConfig(config)));
+        if (res._nextDay) {
+            // Adding is smart enough around DST
+            res.add(1, 'd');
+            res._nextDay = undefined;
+        }
+
+        return res;
+    }
+
+    function prepareConfig (config) {
+        var input = config._i,
+            format = config._f;
+
+        config._locale = config._locale || getLocale(config._l);
+
+        if (input === null || (format === undefined && input === '')) {
+            return createInvalid({nullInput: true});
+        }
+
+        if (typeof input === 'string') {
+            config._i = input = config._locale.preparse(input);
+        }
+
+        if (isMoment(input)) {
+            return new Moment(checkOverflow(input));
+        } else if (isDate(input)) {
+            config._d = input;
+        } else if (isArray(format)) {
+            configFromStringAndArray(config);
+        } else if (format) {
+            configFromStringAndFormat(config);
+        }  else {
+            configFromInput(config);
+        }
+
+        if (!isValid(config)) {
+            config._d = null;
+        }
+
+        return config;
+    }
+
+    function configFromInput(config) {
+        var input = config._i;
+        if (isUndefined(input)) {
+            config._d = new Date(hooks.now());
+        } else if (isDate(input)) {
+            config._d = new Date(input.valueOf());
+        } else if (typeof input === 'string') {
+            configFromString(config);
+        } else if (isArray(input)) {
+            config._a = map(input.slice(0), function (obj) {
+                return parseInt(obj, 10);
+            });
+            configFromArray(config);
+        } else if (isObject(input)) {
+            configFromObject(config);
+        } else if (isNumber(input)) {
+            // from milliseconds
+            config._d = new Date(input);
+        } else {
+            hooks.createFromInputFallback(config);
+        }
+    }
+
+    function createLocalOrUTC (input, format, locale, strict, isUTC) {
+        var c = {};
+
+        if (locale === true || locale === false) {
+            strict = locale;
+            locale = undefined;
+        }
+
+        if ((isObject(input) && isObjectEmpty(input)) ||
+                (isArray(input) && input.length === 0)) {
+            input = undefined;
+        }
+        // object construction must be done this way.
+        // https://github.com/moment/moment/issues/1423
+        c._isAMomentObject = true;
+        c._useUTC = c._isUTC = isUTC;
+        c._l = locale;
+        c._i = input;
+        c._f = format;
+        c._strict = strict;
+
+        return createFromConfig(c);
+    }
+
+    function createLocal (input, format, locale, strict) {
+        return createLocalOrUTC(input, format, locale, strict, false);
+    }
+
+    var prototypeMin = deprecate(
+        'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
+        function () {
+            var other = createLocal.apply(null, arguments);
+            if (this.isValid() && other.isValid()) {
+                return other < this ? this : other;
+            } else {
+                return createInvalid();
+            }
+        }
+    );
+
+    var prototypeMax = deprecate(
+        'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
+        function () {
+            var other = createLocal.apply(null, arguments);
+            if (this.isValid() && other.isValid()) {
+                return other > this ? this : other;
+            } else {
+                return createInvalid();
+            }
+        }
+    );
+
+    // Pick a moment m from moments so that m[fn](other) is true for all
+    // other. This relies on the function fn to be transitive.
+    //
+    // moments should either be an array of moment objects or an array, whose
+    // first element is an array of moment objects.
+    function pickBy(fn, moments) {
+        var res, i;
+        if (moments.length === 1 && isArray(moments[0])) {
+            moments = moments[0];
+        }
+        if (!moments.length) {
+            return createLocal();
+        }
+        res = moments[0];
+        for (i = 1; i < moments.length; ++i) {
+            if (!moments[i].isValid() || moments[i][fn](res)) {
+                res = moments[i];
+            }
+        }
+        return res;
+    }
+
+    // TODO: Use [].sort instead?
+    function min () {
+        var args = [].slice.call(arguments, 0);
+
+        return pickBy('isBefore', args);
+    }
+
+    function max () {
+        var args = [].slice.call(arguments, 0);
+
+        return pickBy('isAfter', args);
+    }
+
+    var now = function () {
+        return Date.now ? Date.now() : +(new Date());
+    };
+
+    var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];
+
+    function isDurationValid(m) {
+        for (var key in m) {
+            if (!(indexOf.call(ordering, key) !== -1 && (m[key] == null || !isNaN(m[key])))) {
+                return false;
+            }
+        }
+
+        var unitHasDecimal = false;
+        for (var i = 0; i < ordering.length; ++i) {
+            if (m[ordering[i]]) {
+                if (unitHasDecimal) {
+                    return false; // only allow non-integers for smallest unit
+                }
+                if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
+                    unitHasDecimal = true;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    function isValid$1() {
+        return this._isValid;
+    }
+
+    function createInvalid$1() {
+        return createDuration(NaN);
+    }
+
+    function Duration (duration) {
+        var normalizedInput = normalizeObjectUnits(duration),
+            years = normalizedInput.year || 0,
+            quarters = normalizedInput.quarter || 0,
+            months = normalizedInput.month || 0,
+            weeks = normalizedInput.week || normalizedInput.isoWeek || 0,
+            days = normalizedInput.day || 0,
+            hours = normalizedInput.hour || 0,
+            minutes = normalizedInput.minute || 0,
+            seconds = normalizedInput.second || 0,
+            milliseconds = normalizedInput.millisecond || 0;
+
+        this._isValid = isDurationValid(normalizedInput);
+
+        // representation for dateAddRemove
+        this._milliseconds = +milliseconds +
+            seconds * 1e3 + // 1000
+            minutes * 6e4 + // 1000 * 60
+            hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
+        // Because of dateAddRemove treats 24 hours as different from a
+        // day when working around DST, we need to store them separately
+        this._days = +days +
+            weeks * 7;
+        // It is impossible to translate months into days without knowing
+        // which months you are are talking about, so we have to store
+        // it separately.
+        this._months = +months +
+            quarters * 3 +
+            years * 12;
+
+        this._data = {};
+
+        this._locale = getLocale();
+
+        this._bubble();
+    }
+
+    function isDuration (obj) {
+        return obj instanceof Duration;
+    }
+
+    function absRound (number) {
+        if (number < 0) {
+            return Math.round(-1 * number) * -1;
+        } else {
+            return Math.round(number);
+        }
+    }
+
+    // FORMATTING
+
+    function offset (token, separator) {
+        addFormatToken(token, 0, 0, function () {
+            var offset = this.utcOffset();
+            var sign = '+';
+            if (offset < 0) {
+                offset = -offset;
+                sign = '-';
+            }
+            return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
+        });
+    }
+
+    offset('Z', ':');
+    offset('ZZ', '');
+
+    // PARSING
+
+    addRegexToken('Z',  matchShortOffset);
+    addRegexToken('ZZ', matchShortOffset);
+    addParseToken(['Z', 'ZZ'], function (input, array, config) {
+        config._useUTC = true;
+        config._tzm = offsetFromString(matchShortOffset, input);
+    });
+
+    // HELPERS
+
+    // timezone chunker
+    // '+10:00' > ['10',  '00']
+    // '-1530'  > ['-15', '30']
+    var chunkOffset = /([\+\-]|\d\d)/gi;
+
+    function offsetFromString(matcher, string) {
+        var matches = (string || '').match(matcher);
+
+        if (matches === null) {
+            return null;
+        }
+
+        var chunk   = matches[matches.length - 1] || [];
+        var parts   = (chunk + '').match(chunkOffset) || ['-', 0, 0];
+        var minutes = +(parts[1] * 60) + toInt(parts[2]);
+
+        return minutes === 0 ?
+          0 :
+          parts[0] === '+' ? minutes : -minutes;
+    }
+
+    // Return a moment from input, that is local/utc/zone equivalent to model.
+    function cloneWithOffset(input, model) {
+        var res, diff;
+        if (model._isUTC) {
+            res = model.clone();
+            diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();
+            // Use low-level api, because this fn is low-level api.
+            res._d.setTime(res._d.valueOf() + diff);
+            hooks.updateOffset(res, false);
+            return res;
+        } else {
+            return createLocal(input).local();
+        }
+    }
+
+    function getDateOffset (m) {
+        // On Firefox.24 Date#getTimezoneOffset returns a floating point.
+        // https://github.com/moment/moment/pull/1871
+        return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
+    }
+
+    // HOOKS
+
+    // This function will be called whenever a moment is mutated.
+    // It is intended to keep the offset in sync with the timezone.
+    hooks.updateOffset = function () {};
+
+    // MOMENTS
+
+    // keepLocalTime = true means only change the timezone, without
+    // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
+    // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
+    // +0200, so we adjust the time as needed, to be valid.
+    //
+    // Keeping the time actually adds/subtracts (one hour)
+    // from the actual represented time. That is why we call updateOffset
+    // a second time. In case it wants us to change the offset again
+    // _changeInProgress == true case, then we have to adjust, because
+    // there is no such time in the given timezone.
+    function getSetOffset (input, keepLocalTime, keepMinutes) {
+        var offset = this._offset || 0,
+            localAdjust;
+        if (!this.isValid()) {
+            return input != null ? this : NaN;
+        }
+        if (input != null) {
+            if (typeof input === 'string') {
+                input = offsetFromString(matchShortOffset, input);
+                if (input === null) {
+                    return this;
+                }
+            } else if (Math.abs(input) < 16 && !keepMinutes) {
+                input = input * 60;
+            }
+            if (!this._isUTC && keepLocalTime) {
+                localAdjust = getDateOffset(this);
+            }
+            this._offset = input;
+            this._isUTC = true;
+            if (localAdjust != null) {
+                this.add(localAdjust, 'm');
+            }
+            if (offset !== input) {
+                if (!keepLocalTime || this._changeInProgress) {
+                    addSubtract(this, createDuration(input - offset, 'm'), 1, false);
+                } else if (!this._changeInProgress) {
+                    this._changeInProgress = true;
+                    hooks.updateOffset(this, true);
+                    this._changeInProgress = null;
+                }
+            }
+            return this;
+        } else {
+            return this._isUTC ? offset : getDateOffset(this);
+        }
+    }
+
+    function getSetZone (input, keepLocalTime) {
+        if (input != null) {
+            if (typeof input !== 'string') {
+                input = -input;
+            }
+
+            this.utcOffset(input, keepLocalTime);
+
+            return this;
+        } else {
+            return -this.utcOffset();
+        }
+    }
+
+    function setOffsetToUTC (keepLocalTime) {
+        return this.utcOffset(0, keepLocalTime);
+    }
+
+    function setOffsetToLocal (keepLocalTime) {
+        if (this._isUTC) {
+            this.utcOffset(0, keepLocalTime);
+            this._isUTC = false;
+
+            if (keepLocalTime) {
+                this.subtract(getDateOffset(this), 'm');
+            }
+        }
+        return this;
+    }
+
+    function setOffsetToParsedOffset () {
+        if (this._tzm != null) {
+            this.utcOffset(this._tzm, false, true);
+        } else if (typeof this._i === 'string') {
+            var tZone = offsetFromString(matchOffset, this._i);
+            if (tZone != null) {
+                this.utcOffset(tZone);
+            }
+            else {
+                this.utcOffset(0, true);
+            }
+        }
+        return this;
+    }
+
+    function hasAlignedHourOffset (input) {
+        if (!this.isValid()) {
+            return false;
+        }
+        input = input ? createLocal(input).utcOffset() : 0;
+
+        return (this.utcOffset() - input) % 60 === 0;
+    }
+
+    function isDaylightSavingTime () {
+        return (
+            this.utcOffset() > this.clone().month(0).utcOffset() ||
+            this.utcOffset() > this.clone().month(5).utcOffset()
+        );
+    }
+
+    function isDaylightSavingTimeShifted () {
+        if (!isUndefined(this._isDSTShifted)) {
+            return this._isDSTShifted;
+        }
+
+        var c = {};
+
+        copyConfig(c, this);
+        c = prepareConfig(c);
+
+        if (c._a) {
+            var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
+            this._isDSTShifted = this.isValid() &&
+                compareArrays(c._a, other.toArray()) > 0;
+        } else {
+            this._isDSTShifted = false;
+        }
+
+        return this._isDSTShifted;
+    }
+
+    function isLocal () {
+        return this.isValid() ? !this._isUTC : false;
+    }
+
+    function isUtcOffset () {
+        return this.isValid() ? this._isUTC : false;
+    }
+
+    function isUtc () {
+        return this.isValid() ? this._isUTC && this._offset === 0 : false;
+    }
+
+    // ASP.NET json date format regex
+    var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/;
+
+    // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
+    // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
+    // and further modified to allow for strings containing both week and day
+    var isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
+
+    function createDuration (input, key) {
+        var duration = input,
+            // matching against regexp is expensive, do it on demand
+            match = null,
+            sign,
+            ret,
+            diffRes;
+
+        if (isDuration(input)) {
+            duration = {
+                ms : input._milliseconds,
+                d  : input._days,
+                M  : input._months
+            };
+        } else if (isNumber(input)) {
+            duration = {};
+            if (key) {
+                duration[key] = input;
+            } else {
+                duration.milliseconds = input;
+            }
+        } else if (!!(match = aspNetRegex.exec(input))) {
+            sign = (match[1] === '-') ? -1 : 1;
+            duration = {
+                y  : 0,
+                d  : toInt(match[DATE])                         * sign,
+                h  : toInt(match[HOUR])                         * sign,
+                m  : toInt(match[MINUTE])                       * sign,
+                s  : toInt(match[SECOND])                       * sign,
+                ms : toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
+            };
+        } else if (!!(match = isoRegex.exec(input))) {
+            sign = (match[1] === '-') ? -1 : 1;
+            duration = {
+                y : parseIso(match[2], sign),
+                M : parseIso(match[3], sign),
+                w : parseIso(match[4], sign),
+                d : parseIso(match[5], sign),
+                h : parseIso(match[6], sign),
+                m : parseIso(match[7], sign),
+                s : parseIso(match[8], sign)
+            };
+        } else if (duration == null) {// checks for null or undefined
+            duration = {};
+        } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
+            diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
+
+            duration = {};
+            duration.ms = diffRes.milliseconds;
+            duration.M = diffRes.months;
+        }
+
+        ret = new Duration(duration);
+
+        if (isDuration(input) && hasOwnProp(input, '_locale')) {
+            ret._locale = input._locale;
+        }
+
+        return ret;
+    }
+
+    createDuration.fn = Duration.prototype;
+    createDuration.invalid = createInvalid$1;
+
+    function parseIso (inp, sign) {
+        // We'd normally use ~~inp for this, but unfortunately it also
+        // converts floats to ints.
+        // inp may be undefined, so careful calling replace on it.
+        var res = inp && parseFloat(inp.replace(',', '.'));
+        // apply sign while we're at it
+        return (isNaN(res) ? 0 : res) * sign;
+    }
+
+    function positiveMomentsDifference(base, other) {
+        var res = {};
+
+        res.months = other.month() - base.month() +
+            (other.year() - base.year()) * 12;
+        if (base.clone().add(res.months, 'M').isAfter(other)) {
+            --res.months;
+        }
+
+        res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
+
+        return res;
+    }
+
+    function momentsDifference(base, other) {
+        var res;
+        if (!(base.isValid() && other.isValid())) {
+            return {milliseconds: 0, months: 0};
+        }
+
+        other = cloneWithOffset(other, base);
+        if (base.isBefore(other)) {
+            res = positiveMomentsDifference(base, other);
+        } else {
+            res = positiveMomentsDifference(other, base);
+            res.milliseconds = -res.milliseconds;
+            res.months = -res.months;
+        }
+
+        return res;
+    }
+
+    // TODO: remove 'name' arg after deprecation is removed
+    function createAdder(direction, name) {
+        return function (val, period) {
+            var dur, tmp;
+            //invert the arguments, but complain about it
+            if (period !== null && !isNaN(+period)) {
+                deprecateSimple(name, 'moment().' + name  + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' +
+                'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
+                tmp = val; val = period; period = tmp;
+            }
+
+            val = typeof val === 'string' ? +val : val;
+            dur = createDuration(val, period);
+            addSubtract(this, dur, direction);
+            return this;
+        };
+    }
+
+    function addSubtract (mom, duration, isAdding, updateOffset) {
+        var milliseconds = duration._milliseconds,
+            days = absRound(duration._days),
+            months = absRound(duration._months);
+
+        if (!mom.isValid()) {
+            // No op
+            return;
+        }
+
+        updateOffset = updateOffset == null ? true : updateOffset;
+
+        if (months) {
+            setMonth(mom, get(mom, 'Month') + months * isAdding);
+        }
+        if (days) {
+            set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
+        }
+        if (milliseconds) {
+            mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
+        }
+        if (updateOffset) {
+            hooks.updateOffset(mom, days || months);
+        }
+    }
+
+    var add      = createAdder(1, 'add');
+    var subtract = createAdder(-1, 'subtract');
+
+    function getCalendarFormat(myMoment, now) {
+        var diff = myMoment.diff(now, 'days', true);
+        return diff < -6 ? 'sameElse' :
+                diff < -1 ? 'lastWeek' :
+                diff < 0 ? 'lastDay' :
+                diff < 1 ? 'sameDay' :
+                diff < 2 ? 'nextDay' :
+                diff < 7 ? 'nextWeek' : 'sameElse';
+    }
+
+    function calendar$1 (time, formats) {
+        // We want to compare the start of today, vs this.
+        // Getting start-of-today depends on whether we're local/utc/offset or not.
+        var now = time || createLocal(),
+            sod = cloneWithOffset(now, this).startOf('day'),
+            format = hooks.calendarFormat(this, sod) || 'sameElse';
+
+        var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
+
+        return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
+    }
+
+    function clone () {
+        return new Moment(this);
+    }
+
+    function isAfter (input, units) {
+        var localInput = isMoment(input) ? input : createLocal(input);
+        if (!(this.isValid() && localInput.isValid())) {
+            return false;
+        }
+        units = normalizeUnits(units) || 'millisecond';
+        if (units === 'millisecond') {
+            return this.valueOf() > localInput.valueOf();
+        } else {
+            return localInput.valueOf() < this.clone().startOf(units).valueOf();
+        }
+    }
+
+    function isBefore (input, units) {
+        var localInput = isMoment(input) ? input : createLocal(input);
+        if (!(this.isValid() && localInput.isValid())) {
+            return false;
+        }
+        units = normalizeUnits(units) || 'millisecond';
+        if (units === 'millisecond') {
+            return this.valueOf() < localInput.valueOf();
+        } else {
+            return this.clone().endOf(units).valueOf() < localInput.valueOf();
+        }
+    }
+
+    function isBetween (from, to, units, inclusivity) {
+        var localFrom = isMoment(from) ? from : createLocal(from),
+            localTo = isMoment(to) ? to : createLocal(to);
+        if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) {
+            return false;
+        }
+        inclusivity = inclusivity || '()';
+        return (inclusivity[0] === '(' ? this.isAfter(localFrom, units) : !this.isBefore(localFrom, units)) &&
+            (inclusivity[1] === ')' ? this.isBefore(localTo, units) : !this.isAfter(localTo, units));
+    }
+
+    function isSame (input, units) {
+        var localInput = isMoment(input) ? input : createLocal(input),
+            inputMs;
+        if (!(this.isValid() && localInput.isValid())) {
+            return false;
+        }
+        units = normalizeUnits(units) || 'millisecond';
+        if (units === 'millisecond') {
+            return this.valueOf() === localInput.valueOf();
+        } else {
+            inputMs = localInput.valueOf();
+            return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
+        }
+    }
+
+    function isSameOrAfter (input, units) {
+        return this.isSame(input, units) || this.isAfter(input, units);
+    }
+
+    function isSameOrBefore (input, units) {
+        return this.isSame(input, units) || this.isBefore(input, units);
+    }
+
+    function diff (input, units, asFloat) {
+        var that,
+            zoneDelta,
+            output;
+
+        if (!this.isValid()) {
+            return NaN;
+        }
+
+        that = cloneWithOffset(input, this);
+
+        if (!that.isValid()) {
+            return NaN;
+        }
+
+        zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
+
+        units = normalizeUnits(units);
+
+        switch (units) {
+            case 'year': output = monthDiff(this, that) / 12; break;
+            case 'month': output = monthDiff(this, that); break;
+            case 'quarter': output = monthDiff(this, that) / 3; break;
+            case 'second': output = (this - that) / 1e3; break; // 1000
+            case 'minute': output = (this - that) / 6e4; break; // 1000 * 60
+            case 'hour': output = (this - that) / 36e5; break; // 1000 * 60 * 60
+            case 'day': output = (this - that - zoneDelta) / 864e5; break; // 1000 * 60 * 60 * 24, negate dst
+            case 'week': output = (this - that - zoneDelta) / 6048e5; break; // 1000 * 60 * 60 * 24 * 7, negate dst
+            default: output = this - that;
+        }
+
+        return asFloat ? output : absFloor(output);
+    }
+
+    function monthDiff (a, b) {
+        // difference in months
+        var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
+            // b is in (anchor - 1 month, anchor + 1 month)
+            anchor = a.clone().add(wholeMonthDiff, 'months'),
+            anchor2, adjust;
+
+        if (b - anchor < 0) {
+            anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
+            // linear across the month
+            adjust = (b - anchor) / (anchor - anchor2);
+        } else {
+            anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
+            // linear across the month
+            adjust = (b - anchor) / (anchor2 - anchor);
+        }
+
+        //check for negative zero, return zero if negative zero
+        return -(wholeMonthDiff + adjust) || 0;
+    }
+
+    hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
+    hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
+
+    function toString () {
+        return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
+    }
+
+    function toISOString(keepOffset) {
+        if (!this.isValid()) {
+            return null;
+        }
+        var utc = keepOffset !== true;
+        var m = utc ? this.clone().utc() : this;
+        if (m.year() < 0 || m.year() > 9999) {
+            return formatMoment(m, utc ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ');
+        }
+        if (isFunction(Date.prototype.toISOString)) {
+            // native implementation is ~50x faster, use it when we can
+            if (utc) {
+                return this.toDate().toISOString();
+            } else {
+                return new Date(this.valueOf() + this.utcOffset() * 60 * 1000).toISOString().replace('Z', formatMoment(m, 'Z'));
+            }
+        }
+        return formatMoment(m, utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ');
+    }
+
+    /**
+     * Return a human readable representation of a moment that can
+     * also be evaluated to get a new moment which is the same
+     *
+     * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
+     */
+    function inspect () {
+        if (!this.isValid()) {
+            return 'moment.invalid(/* ' + this._i + ' */)';
+        }
+        var func = 'moment';
+        var zone = '';
+        if (!this.isLocal()) {
+            func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
+            zone = 'Z';
+        }
+        var prefix = '[' + func + '("]';
+        var year = (0 <= this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY';
+        var datetime = '-MM-DD[T]HH:mm:ss.SSS';
+        var suffix = zone + '[")]';
+
+        return this.format(prefix + year + datetime + suffix);
+    }
+
+    function format (inputString) {
+        if (!inputString) {
+            inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
+        }
+        var output = formatMoment(this, inputString);
+        return this.localeData().postformat(output);
+    }
+
+    function from (time, withoutSuffix) {
+        if (this.isValid() &&
+                ((isMoment(time) && time.isValid()) ||
+                 createLocal(time).isValid())) {
+            return createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
+        } else {
+            return this.localeData().invalidDate();
+        }
+    }
+
+    function fromNow (withoutSuffix) {
+        return this.from(createLocal(), withoutSuffix);
+    }
+
+    function to (time, withoutSuffix) {
+        if (this.isValid() &&
+                ((isMoment(time) && time.isValid()) ||
+                 createLocal(time).isValid())) {
+            return createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);
+        } else {
+            return this.localeData().invalidDate();
+        }
+    }
+
+    function toNow (withoutSuffix) {
+        return this.to(createLocal(), withoutSuffix);
+    }
+
+    // If passed a locale key, it will set the locale for this
+    // instance.  Otherwise, it will return the locale configuration
+    // variables for this instance.
+    function locale (key) {
+        var newLocaleData;
+
+        if (key === undefined) {
+            return this._locale._abbr;
+        } else {
+            newLocaleData = getLocale(key);
+            if (newLocaleData != null) {
+                this._locale = newLocaleData;
+            }
+            return this;
+        }
+    }
+
+    var lang = deprecate(
+        'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
+        function (key) {
+            if (key === undefined) {
+                return this.localeData();
+            } else {
+                return this.locale(key);
+            }
+        }
+    );
+
+    function localeData () {
+        return this._locale;
+    }
+
+    var MS_PER_SECOND = 1000;
+    var MS_PER_MINUTE = 60 * MS_PER_SECOND;
+    var MS_PER_HOUR = 60 * MS_PER_MINUTE;
+    var MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR;
+
+    // actual modulo - handles negative numbers (for dates before 1970):
+    function mod$1(dividend, divisor) {
+        return (dividend % divisor + divisor) % divisor;
+    }
+
+    function localStartOfDate(y, m, d) {
+        // the date constructor remaps years 0-99 to 1900-1999
+        if (y < 100 && y >= 0) {
+            // preserve leap years using a full 400 year cycle, then reset
+            return new Date(y + 400, m, d) - MS_PER_400_YEARS;
+        } else {
+            return new Date(y, m, d).valueOf();
+        }
+    }
+
+    function utcStartOfDate(y, m, d) {
+        // Date.UTC remaps years 0-99 to 1900-1999
+        if (y < 100 && y >= 0) {
+            // preserve leap years using a full 400 year cycle, then reset
+            return Date.UTC(y + 400, m, d) - MS_PER_400_YEARS;
+        } else {
+            return Date.UTC(y, m, d);
+        }
+    }
+
+    function startOf (units) {
+        var time;
+        units = normalizeUnits(units);
+        if (units === undefined || units === 'millisecond' || !this.isValid()) {
+            return this;
+        }
+
+        var startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;
+
+        switch (units) {
+            case 'year':
+                time = startOfDate(this.year(), 0, 1);
+                break;
+            case 'quarter':
+                time = startOfDate(this.year(), this.month() - this.month() % 3, 1);
+                break;
+            case 'month':
+                time = startOfDate(this.year(), this.month(), 1);
+                break;
+            case 'week':
+                time = startOfDate(this.year(), this.month(), this.date() - this.weekday());
+                break;
+            case 'isoWeek':
+                time = startOfDate(this.year(), this.month(), this.date() - (this.isoWeekday() - 1));
+                break;
+            case 'day':
+            case 'date':
+                time = startOfDate(this.year(), this.month(), this.date());
+                break;
+            case 'hour':
+                time = this._d.valueOf();
+                time -= mod$1(time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), MS_PER_HOUR);
+                break;
+            case 'minute':
+                time = this._d.valueOf();
+                time -= mod$1(time, MS_PER_MINUTE);
+                break;
+            case 'second':
+                time = this._d.valueOf();
+                time -= mod$1(time, MS_PER_SECOND);
+                break;
+        }
+
+        this._d.setTime(time);
+        hooks.updateOffset(this, true);
+        return this;
+    }
+
+    function endOf (units) {
+        var time;
+        units = normalizeUnits(units);
+        if (units === undefined || units === 'millisecond' || !this.isValid()) {
+            return this;
+        }
+
+        var startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;
+
+        switch (units) {
+            case 'year':
+                time = startOfDate(this.year() + 1, 0, 1) - 1;
+                break;
+            case 'quarter':
+                time = startOfDate(this.year(), this.month() - this.month() % 3 + 3, 1) - 1;
+                break;
+            case 'month':
+                time = startOfDate(this.year(), this.month() + 1, 1) - 1;
+                break;
+            case 'week':
+                time = startOfDate(this.year(), this.month(), this.date() - this.weekday() + 7) - 1;
+                break;
+            case 'isoWeek':
+                time = startOfDate(this.year(), this.month(), this.date() - (this.isoWeekday() - 1) + 7) - 1;
+                break;
+            case 'day':
+            case 'date':
+                time = startOfDate(this.year(), this.month(), this.date() + 1) - 1;
+                break;
+            case 'hour':
+                time = this._d.valueOf();
+                time += MS_PER_HOUR - mod$1(time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), MS_PER_HOUR) - 1;
+                break;
+            case 'minute':
+                time = this._d.valueOf();
+                time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1;
+                break;
+            case 'second':
+                time = this._d.valueOf();
+                time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1;
+                break;
+        }
+
+        this._d.setTime(time);
+        hooks.updateOffset(this, true);
+        return this;
+    }
+
+    function valueOf () {
+        return this._d.valueOf() - ((this._offset || 0) * 60000);
+    }
+
+    function unix () {
+        return Math.floor(this.valueOf() / 1000);
+    }
+
+    function toDate () {
+        return new Date(this.valueOf());
+    }
+
+    function toArray () {
+        var m = this;
+        return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
+    }
+
+    function toObject () {
+        var m = this;
+        return {
+            years: m.year(),
+            months: m.month(),
+            date: m.date(),
+            hours: m.hours(),
+            minutes: m.minutes(),
+            seconds: m.seconds(),
+            milliseconds: m.milliseconds()
+        };
+    }
+
+    function toJSON () {
+        // new Date(NaN).toJSON() === null
+        return this.isValid() ? this.toISOString() : null;
+    }
+
+    function isValid$2 () {
+        return isValid(this);
+    }
+
+    function parsingFlags () {
+        return extend({}, getParsingFlags(this));
+    }
+
+    function invalidAt () {
+        return getParsingFlags(this).overflow;
+    }
+
+    function creationData() {
+        return {
+            input: this._i,
+            format: this._f,
+            locale: this._locale,
+            isUTC: this._isUTC,
+            strict: this._strict
+        };
+    }
+
+    // FORMATTING
+
+    addFormatToken(0, ['gg', 2], 0, function () {
+        return this.weekYear() % 100;
+    });
+
+    addFormatToken(0, ['GG', 2], 0, function () {
+        return this.isoWeekYear() % 100;
+    });
+
+    function addWeekYearFormatToken (token, getter) {
+        addFormatToken(0, [token, token.length], 0, getter);
+    }
+
+    addWeekYearFormatToken('gggg',     'weekYear');
+    addWeekYearFormatToken('ggggg',    'weekYear');
+    addWeekYearFormatToken('GGGG',  'isoWeekYear');
+    addWeekYearFormatToken('GGGGG', 'isoWeekYear');
+
+    // ALIASES
+
+    addUnitAlias('weekYear', 'gg');
+    addUnitAlias('isoWeekYear', 'GG');
+
+    // PRIORITY
+
+    addUnitPriority('weekYear', 1);
+    addUnitPriority('isoWeekYear', 1);
+
+
+    // PARSING
+
+    addRegexToken('G',      matchSigned);
+    addRegexToken('g',      matchSigned);
+    addRegexToken('GG',     match1to2, match2);
+    addRegexToken('gg',     match1to2, match2);
+    addRegexToken('GGGG',   match1to4, match4);
+    addRegexToken('gggg',   match1to4, match4);
+    addRegexToken('GGGGG',  match1to6, match6);
+    addRegexToken('ggggg',  match1to6, match6);
+
+    addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
+        week[token.substr(0, 2)] = toInt(input);
+    });
+
+    addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
+        week[token] = hooks.parseTwoDigitYear(input);
+    });
+
+    // MOMENTS
+
+    function getSetWeekYear (input) {
+        return getSetWeekYearHelper.call(this,
+                input,
+                this.week(),
+                this.weekday(),
+                this.localeData()._week.dow,
+                this.localeData()._week.doy);
+    }
+
+    function getSetISOWeekYear (input) {
+        return getSetWeekYearHelper.call(this,
+                input, this.isoWeek(), this.isoWeekday(), 1, 4);
+    }
+
+    function getISOWeeksInYear () {
+        return weeksInYear(this.year(), 1, 4);
+    }
+
+    function getWeeksInYear () {
+        var weekInfo = this.localeData()._week;
+        return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
+    }
+
+    function getSetWeekYearHelper(input, week, weekday, dow, doy) {
+        var weeksTarget;
+        if (input == null) {
+            return weekOfYear(this, dow, doy).year;
+        } else {
+            weeksTarget = weeksInYear(input, dow, doy);
+            if (week > weeksTarget) {
+                week = weeksTarget;
+            }
+            return setWeekAll.call(this, input, week, weekday, dow, doy);
+        }
+    }
+
+    function setWeekAll(weekYear, week, weekday, dow, doy) {
+        var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
+            date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
+
+        this.year(date.getUTCFullYear());
+        this.month(date.getUTCMonth());
+        this.date(date.getUTCDate());
+        return this;
+    }
+
+    // FORMATTING
+
+    addFormatToken('Q', 0, 'Qo', 'quarter');
+
+    // ALIASES
+
+    addUnitAlias('quarter', 'Q');
+
+    // PRIORITY
+
+    addUnitPriority('quarter', 7);
+
+    // PARSING
+
+    addRegexToken('Q', match1);
+    addParseToken('Q', function (input, array) {
+        array[MONTH] = (toInt(input) - 1) * 3;
+    });
+
+    // MOMENTS
+
+    function getSetQuarter (input) {
+        return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
+    }
+
+    // FORMATTING
+
+    addFormatToken('D', ['DD', 2], 'Do', 'date');
+
+    // ALIASES
+
+    addUnitAlias('date', 'D');
+
+    // PRIORITY
+    addUnitPriority('date', 9);
+
+    // PARSING
+
+    addRegexToken('D',  match1to2);
+    addRegexToken('DD', match1to2, match2);
+    addRegexToken('Do', function (isStrict, locale) {
+        // TODO: Remove "ordinalParse" fallback in next major release.
+        return isStrict ?
+          (locale._dayOfMonthOrdinalParse || locale._ordinalParse) :
+          locale._dayOfMonthOrdinalParseLenient;
+    });
+
+    addParseToken(['D', 'DD'], DATE);
+    addParseToken('Do', function (input, array) {
+        array[DATE] = toInt(input.match(match1to2)[0]);
+    });
+
+    // MOMENTS
+
+    var getSetDayOfMonth = makeGetSet('Date', true);
+
+    // FORMATTING
+
+    addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
+
+    // ALIASES
+
+    addUnitAlias('dayOfYear', 'DDD');
+
+    // PRIORITY
+    addUnitPriority('dayOfYear', 4);
+
+    // PARSING
+
+    addRegexToken('DDD',  match1to3);
+    addRegexToken('DDDD', match3);
+    addParseToken(['DDD', 'DDDD'], function (input, array, config) {
+        config._dayOfYear = toInt(input);
+    });
+
+    // HELPERS
+
+    // MOMENTS
+
+    function getSetDayOfYear (input) {
+        var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
+        return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
+    }
+
+    // FORMATTING
+
+    addFormatToken('m', ['mm', 2], 0, 'minute');
+
+    // ALIASES
+
+    addUnitAlias('minute', 'm');
+
+    // PRIORITY
+
+    addUnitPriority('minute', 14);
+
+    // PARSING
+
+    addRegexToken('m',  match1to2);
+    addRegexToken('mm', match1to2, match2);
+    addParseToken(['m', 'mm'], MINUTE);
+
+    // MOMENTS
+
+    var getSetMinute = makeGetSet('Minutes', false);
+
+    // FORMATTING
+
+    addFormatToken('s', ['ss', 2], 0, 'second');
+
+    // ALIASES
+
+    addUnitAlias('second', 's');
+
+    // PRIORITY
+
+    addUnitPriority('second', 15);
+
+    // PARSING
+
+    addRegexToken('s',  match1to2);
+    addRegexToken('ss', match1to2, match2);
+    addParseToken(['s', 'ss'], SECOND);
+
+    // MOMENTS
+
+    var getSetSecond = makeGetSet('Seconds', false);
+
+    // FORMATTING
+
+    addFormatToken('S', 0, 0, function () {
+        return ~~(this.millisecond() / 100);
+    });
+
+    addFormatToken(0, ['SS', 2], 0, function () {
+        return ~~(this.millisecond() / 10);
+    });
+
+    addFormatToken(0, ['SSS', 3], 0, 'millisecond');
+    addFormatToken(0, ['SSSS', 4], 0, function () {
+        return this.millisecond() * 10;
+    });
+    addFormatToken(0, ['SSSSS', 5], 0, function () {
+        return this.millisecond() * 100;
+    });
+    addFormatToken(0, ['SSSSSS', 6], 0, function () {
+        return this.millisecond() * 1000;
+    });
+    addFormatToken(0, ['SSSSSSS', 7], 0, function () {
+        return this.millisecond() * 10000;
+    });
+    addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
+        return this.millisecond() * 100000;
+    });
+    addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
+        return this.millisecond() * 1000000;
+    });
+
+
+    // ALIASES
+
+    addUnitAlias('millisecond', 'ms');
+
+    // PRIORITY
+
+    addUnitPriority('millisecond', 16);
+
+    // PARSING
+
+    addRegexToken('S',    match1to3, match1);
+    addRegexToken('SS',   match1to3, match2);
+    addRegexToken('SSS',  match1to3, match3);
+
+    var token;
+    for (token = 'SSSS'; token.length <= 9; token += 'S') {
+        addRegexToken(token, matchUnsigned);
+    }
+
+    function parseMs(input, array) {
+        array[MILLISECOND] = toInt(('0.' + input) * 1000);
+    }
+
+    for (token = 'S'; token.length <= 9; token += 'S') {
+        addParseToken(token, parseMs);
+    }
+    // MOMENTS
+
+    var getSetMillisecond = makeGetSet('Milliseconds', false);
+
+    // FORMATTING
+
+    addFormatToken('z',  0, 0, 'zoneAbbr');
+    addFormatToken('zz', 0, 0, 'zoneName');
+
+    // MOMENTS
+
+    function getZoneAbbr () {
+        return this._isUTC ? 'UTC' : '';
+    }
+
+    function getZoneName () {
+        return this._isUTC ? 'Coordinated Universal Time' : '';
+    }
+
+    var proto = Moment.prototype;
+
+    proto.add               = add;
+    proto.calendar          = calendar$1;
+    proto.clone             = clone;
+    proto.diff              = diff;
+    proto.endOf             = endOf;
+    proto.format            = format;
+    proto.from              = from;
+    proto.fromNow           = fromNow;
+    proto.to                = to;
+    proto.toNow             = toNow;
+    proto.get               = stringGet;
+    proto.invalidAt         = invalidAt;
+    proto.isAfter           = isAfter;
+    proto.isBefore          = isBefore;
+    proto.isBetween         = isBetween;
+    proto.isSame            = isSame;
+    proto.isSameOrAfter     = isSameOrAfter;
+    proto.isSameOrBefore    = isSameOrBefore;
+    proto.isValid           = isValid$2;
+    proto.lang              = lang;
+    proto.locale            = locale;
+    proto.localeData        = localeData;
+    proto.max               = prototypeMax;
+    proto.min               = prototypeMin;
+    proto.parsingFlags      = parsingFlags;
+    proto.set               = stringSet;
+    proto.startOf           = startOf;
+    proto.subtract          = subtract;
+    proto.toArray           = toArray;
+    proto.toObject          = toObject;
+    proto.toDate            = toDate;
+    proto.toISOString       = toISOString;
+    proto.inspect           = inspect;
+    proto.toJSON            = toJSON;
+    proto.toString          = toString;
+    proto.unix              = unix;
+    proto.valueOf           = valueOf;
+    proto.creationData      = creationData;
+    proto.year       = getSetYear;
+    proto.isLeapYear = getIsLeapYear;
+    proto.weekYear    = getSetWeekYear;
+    proto.isoWeekYear = getSetISOWeekYear;
+    proto.quarter = proto.quarters = getSetQuarter;
+    proto.month       = getSetMonth;
+    proto.daysInMonth = getDaysInMonth;
+    proto.week           = proto.weeks        = getSetWeek;
+    proto.isoWeek        = proto.isoWeeks     = getSetISOWeek;
+    proto.weeksInYear    = getWeeksInYear;
+    proto.isoWeeksInYear = getISOWeeksInYear;
+    proto.date       = getSetDayOfMonth;
+    proto.day        = proto.days             = getSetDayOfWeek;
+    proto.weekday    = getSetLocaleDayOfWeek;
+    proto.isoWeekday = getSetISODayOfWeek;
+    proto.dayOfYear  = getSetDayOfYear;
+    proto.hour = proto.hours = getSetHour;
+    proto.minute = proto.minutes = getSetMinute;
+    proto.second = proto.seconds = getSetSecond;
+    proto.millisecond = proto.milliseconds = getSetMillisecond;
+    proto.utcOffset            = getSetOffset;
+    proto.utc                  = setOffsetToUTC;
+    proto.local                = setOffsetToLocal;
+    proto.parseZone            = setOffsetToParsedOffset;
+    proto.hasAlignedHourOffset = hasAlignedHourOffset;
+    proto.isDST                = isDaylightSavingTime;
+    proto.isLocal              = isLocal;
+    proto.isUtcOffset          = isUtcOffset;
+    proto.isUtc                = isUtc;
+    proto.isUTC                = isUtc;
+    proto.zoneAbbr = getZoneAbbr;
+    proto.zoneName = getZoneName;
+    proto.dates  = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
+    proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
+    proto.years  = deprecate('years accessor is deprecated. Use year instead', getSetYear);
+    proto.zone   = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
+    proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
+
+    function createUnix (input) {
+        return createLocal(input * 1000);
+    }
+
+    function createInZone () {
+        return createLocal.apply(null, arguments).parseZone();
+    }
+
+    function preParsePostFormat (string) {
+        return string;
+    }
+
+    var proto$1 = Locale.prototype;
+
+    proto$1.calendar        = calendar;
+    proto$1.longDateFormat  = longDateFormat;
+    proto$1.invalidDate     = invalidDate;
+    proto$1.ordinal         = ordinal;
+    proto$1.preparse        = preParsePostFormat;
+    proto$1.postformat      = preParsePostFormat;
+    proto$1.relativeTime    = relativeTime;
+    proto$1.pastFuture      = pastFuture;
+    proto$1.set             = set;
+
+    proto$1.months            =        localeMonths;
+    proto$1.monthsShort       =        localeMonthsShort;
+    proto$1.monthsParse       =        localeMonthsParse;
+    proto$1.monthsRegex       = monthsRegex;
+    proto$1.monthsShortRegex  = monthsShortRegex;
+    proto$1.week = localeWeek;
+    proto$1.firstDayOfYear = localeFirstDayOfYear;
+    proto$1.firstDayOfWeek = localeFirstDayOfWeek;
+
+    proto$1.weekdays       =        localeWeekdays;
+    proto$1.weekdaysMin    =        localeWeekdaysMin;
+    proto$1.weekdaysShort  =        localeWeekdaysShort;
+    proto$1.weekdaysParse  =        localeWeekdaysParse;
+
+    proto$1.weekdaysRegex       =        weekdaysRegex;
+    proto$1.weekdaysShortRegex  =        weekdaysShortRegex;
+    proto$1.weekdaysMinRegex    =        weekdaysMinRegex;
+
+    proto$1.isPM = localeIsPM;
+    proto$1.meridiem = localeMeridiem;
+
+    function get$1 (format, index, field, setter) {
+        var locale = getLocale();
+        var utc = createUTC().set(setter, index);
+        return locale[field](utc, format);
+    }
+
+    function listMonthsImpl (format, index, field) {
+        if (isNumber(format)) {
+            index = format;
+            format = undefined;
+        }
+
+        format = format || '';
+
+        if (index != null) {
+            return get$1(format, index, field, 'month');
+        }
+
+        var i;
+        var out = [];
+        for (i = 0; i < 12; i++) {
+            out[i] = get$1(format, i, field, 'month');
+        }
+        return out;
+    }
+
+    // ()
+    // (5)
+    // (fmt, 5)
+    // (fmt)
+    // (true)
+    // (true, 5)
+    // (true, fmt, 5)
+    // (true, fmt)
+    function listWeekdaysImpl (localeSorted, format, index, field) {
+        if (typeof localeSorted === 'boolean') {
+            if (isNumber(format)) {
+                index = format;
+                format = undefined;
+            }
+
+            format = format || '';
+        } else {
+            format = localeSorted;
+            index = format;
+            localeSorted = false;
+
+            if (isNumber(format)) {
+                index = format;
+                format = undefined;
+            }
+
+            format = format || '';
+        }
+
+        var locale = getLocale(),
+            shift = localeSorted ? locale._week.dow : 0;
+
+        if (index != null) {
+            return get$1(format, (index + shift) % 7, field, 'day');
+        }
+
+        var i;
+        var out = [];
+        for (i = 0; i < 7; i++) {
+            out[i] = get$1(format, (i + shift) % 7, field, 'day');
+        }
+        return out;
+    }
+
+    function listMonths (format, index) {
+        return listMonthsImpl(format, index, 'months');
+    }
+
+    function listMonthsShort (format, index) {
+        return listMonthsImpl(format, index, 'monthsShort');
+    }
+
+    function listWeekdays (localeSorted, format, index) {
+        return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
+    }
+
+    function listWeekdaysShort (localeSorted, format, index) {
+        return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
+    }
+
+    function listWeekdaysMin (localeSorted, format, index) {
+        return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
+    }
+
+    getSetGlobalLocale('en', {
+        dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
+        ordinal : function (number) {
+            var b = number % 10,
+                output = (toInt(number % 100 / 10) === 1) ? 'th' :
+                (b === 1) ? 'st' :
+                (b === 2) ? 'nd' :
+                (b === 3) ? 'rd' : 'th';
+            return number + output;
+        }
+    });
+
+    // Side effect imports
+
+    hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
+    hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
+
+    var mathAbs = Math.abs;
+
+    function abs () {
+        var data           = this._data;
+
+        this._milliseconds = mathAbs(this._milliseconds);
+        this._days         = mathAbs(this._days);
+        this._months       = mathAbs(this._months);
+
+        data.milliseconds  = mathAbs(data.milliseconds);
+        data.seconds       = mathAbs(data.seconds);
+        data.minutes       = mathAbs(data.minutes);
+        data.hours         = mathAbs(data.hours);
+        data.months        = mathAbs(data.months);
+        data.years         = mathAbs(data.years);
+
+        return this;
+    }
+
+    function addSubtract$1 (duration, input, value, direction) {
+        var other = createDuration(input, value);
+
+        duration._milliseconds += direction * other._milliseconds;
+        duration._days         += direction * other._days;
+        duration._months       += direction * other._months;
+
+        return duration._bubble();
+    }
+
+    // supports only 2.0-style add(1, 's') or add(duration)
+    function add$1 (input, value) {
+        return addSubtract$1(this, input, value, 1);
+    }
+
+    // supports only 2.0-style subtract(1, 's') or subtract(duration)
+    function subtract$1 (input, value) {
+        return addSubtract$1(this, input, value, -1);
+    }
+
+    function absCeil (number) {
+        if (number < 0) {
+            return Math.floor(number);
+        } else {
+            return Math.ceil(number);
+        }
+    }
+
+    function bubble () {
+        var milliseconds = this._milliseconds;
+        var days         = this._days;
+        var months       = this._months;
+        var data         = this._data;
+        var seconds, minutes, hours, years, monthsFromDays;
+
+        // if we have a mix of positive and negative values, bubble down first
+        // check: https://github.com/moment/moment/issues/2166
+        if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||
+                (milliseconds <= 0 && days <= 0 && months <= 0))) {
+            milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
+            days = 0;
+            months = 0;
+        }
+
+        // The following code bubbles up values, see the tests for
+        // examples of what that means.
+        data.milliseconds = milliseconds % 1000;
+
+        seconds           = absFloor(milliseconds / 1000);
+        data.seconds      = seconds % 60;
+
+        minutes           = absFloor(seconds / 60);
+        data.minutes      = minutes % 60;
+
+        hours             = absFloor(minutes / 60);
+        data.hours        = hours % 24;
+
+        days += absFloor(hours / 24);
+
+        // convert days to months
+        monthsFromDays = absFloor(daysToMonths(days));
+        months += monthsFromDays;
+        days -= absCeil(monthsToDays(monthsFromDays));
+
+        // 12 months -> 1 year
+        years = absFloor(months / 12);
+        months %= 12;
+
+        data.days   = days;
+        data.months = months;
+        data.years  = years;
+
+        return this;
+    }
+
+    function daysToMonths (days) {
+        // 400 years have 146097 days (taking into account leap year rules)
+        // 400 years have 12 months === 4800
+        return days * 4800 / 146097;
+    }
+
+    function monthsToDays (months) {
+        // the reverse of daysToMonths
+        return months * 146097 / 4800;
+    }
+
+    function as (units) {
+        if (!this.isValid()) {
+            return NaN;
+        }
+        var days;
+        var months;
+        var milliseconds = this._milliseconds;
+
+        units = normalizeUnits(units);
+
+        if (units === 'month' || units === 'quarter' || units === 'year') {
+            days = this._days + milliseconds / 864e5;
+            months = this._months + daysToMonths(days);
+            switch (units) {
+                case 'month':   return months;
+                case 'quarter': return months / 3;
+                case 'year':    return months / 12;
+            }
+        } else {
+            // handle milliseconds separately because of floating point math errors (issue #1867)
+            days = this._days + Math.round(monthsToDays(this._months));
+            switch (units) {
+                case 'week'   : return days / 7     + milliseconds / 6048e5;
+                case 'day'    : return days         + milliseconds / 864e5;
+                case 'hour'   : return days * 24    + milliseconds / 36e5;
+                case 'minute' : return days * 1440  + milliseconds / 6e4;
+                case 'second' : return days * 86400 + milliseconds / 1000;
+                // Math.floor prevents floating point math errors here
+                case 'millisecond': return Math.floor(days * 864e5) + milliseconds;
+                default: throw new Error('Unknown unit ' + units);
+            }
+        }
+    }
+
+    // TODO: Use this.as('ms')?
+    function valueOf$1 () {
+        if (!this.isValid()) {
+            return NaN;
+        }
+        return (
+            this._milliseconds +
+            this._days * 864e5 +
+            (this._months % 12) * 2592e6 +
+            toInt(this._months / 12) * 31536e6
+        );
+    }
+
+    function makeAs (alias) {
+        return function () {
+            return this.as(alias);
+        };
+    }
+
+    var asMilliseconds = makeAs('ms');
+    var asSeconds      = makeAs('s');
+    var asMinutes      = makeAs('m');
+    var asHours        = makeAs('h');
+    var asDays         = makeAs('d');
+    var asWeeks        = makeAs('w');
+    var asMonths       = makeAs('M');
+    var asQuarters     = makeAs('Q');
+    var asYears        = makeAs('y');
+
+    function clone$1 () {
+        return createDuration(this);
+    }
+
+    function get$2 (units) {
+        units = normalizeUnits(units);
+        return this.isValid() ? this[units + 's']() : NaN;
+    }
+
+    function makeGetter(name) {
+        return function () {
+            return this.isValid() ? this._data[name] : NaN;
+        };
+    }
+
+    var milliseconds = makeGetter('milliseconds');
+    var seconds      = makeGetter('seconds');
+    var minutes      = makeGetter('minutes');
+    var hours        = makeGetter('hours');
+    var days         = makeGetter('days');
+    var months       = makeGetter('months');
+    var years        = makeGetter('years');
+
+    function weeks () {
+        return absFloor(this.days() / 7);
+    }
+
+    var round = Math.round;
+    var thresholds = {
+        ss: 44,         // a few seconds to seconds
+        s : 45,         // seconds to minute
+        m : 45,         // minutes to hour
+        h : 22,         // hours to day
+        d : 26,         // days to month
+        M : 11          // months to year
+    };
+
+    // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
+    function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
+        return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
+    }
+
+    function relativeTime$1 (posNegDuration, withoutSuffix, locale) {
+        var duration = createDuration(posNegDuration).abs();
+        var seconds  = round(duration.as('s'));
+        var minutes  = round(duration.as('m'));
+        var hours    = round(duration.as('h'));
+        var days     = round(duration.as('d'));
+        var months   = round(duration.as('M'));
+        var years    = round(duration.as('y'));
+
+        var a = seconds <= thresholds.ss && ['s', seconds]  ||
+                seconds < thresholds.s   && ['ss', seconds] ||
+                minutes <= 1             && ['m']           ||
+                minutes < thresholds.m   && ['mm', minutes] ||
+                hours   <= 1             && ['h']           ||
+                hours   < thresholds.h   && ['hh', hours]   ||
+                days    <= 1             && ['d']           ||
+                days    < thresholds.d   && ['dd', days]    ||
+                months  <= 1             && ['M']           ||
+                months  < thresholds.M   && ['MM', months]  ||
+                years   <= 1             && ['y']           || ['yy', years];
+
+        a[2] = withoutSuffix;
+        a[3] = +posNegDuration > 0;
+        a[4] = locale;
+        return substituteTimeAgo.apply(null, a);
+    }
+
+    // This function allows you to set the rounding function for relative time strings
+    function getSetRelativeTimeRounding (roundingFunction) {
+        if (roundingFunction === undefined) {
+            return round;
+        }
+        if (typeof(roundingFunction) === 'function') {
+            round = roundingFunction;
+            return true;
+        }
+        return false;
+    }
+
+    // This function allows you to set a threshold for relative time strings
+    function getSetRelativeTimeThreshold (threshold, limit) {
+        if (thresholds[threshold] === undefined) {
+            return false;
+        }
+        if (limit === undefined) {
+            return thresholds[threshold];
+        }
+        thresholds[threshold] = limit;
+        if (threshold === 's') {
+            thresholds.ss = limit - 1;
+        }
+        return true;
+    }
+
+    function humanize (withSuffix) {
+        if (!this.isValid()) {
+            return this.localeData().invalidDate();
+        }
+
+        var locale = this.localeData();
+        var output = relativeTime$1(this, !withSuffix, locale);
+
+        if (withSuffix) {
+            output = locale.pastFuture(+this, output);
+        }
+
+        return locale.postformat(output);
+    }
+
+    var abs$1 = Math.abs;
+
+    function sign(x) {
+        return ((x > 0) - (x < 0)) || +x;
+    }
+
+    function toISOString$1() {
+        // for ISO strings we do not use the normal bubbling rules:
+        //  * milliseconds bubble up until they become hours
+        //  * days do not bubble at all
+        //  * months bubble up until they become years
+        // This is because there is no context-free conversion between hours and days
+        // (think of clock changes)
+        // and also not between days and months (28-31 days per month)
+        if (!this.isValid()) {
+            return this.localeData().invalidDate();
+        }
+
+        var seconds = abs$1(this._milliseconds) / 1000;
+        var days         = abs$1(this._days);
+        var months       = abs$1(this._months);
+        var minutes, hours, years;
+
+        // 3600 seconds -> 60 minutes -> 1 hour
+        minutes           = absFloor(seconds / 60);
+        hours             = absFloor(minutes / 60);
+        seconds %= 60;
+        minutes %= 60;
+
+        // 12 months -> 1 year
+        years  = absFloor(months / 12);
+        months %= 12;
+
+
+        // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
+        var Y = years;
+        var M = months;
+        var D = days;
+        var h = hours;
+        var m = minutes;
+        var s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';
+        var total = this.asSeconds();
+
+        if (!total) {
+            // this is the same as C#'s (Noda) and python (isodate)...
+            // but not other JS (goog.date)
+            return 'P0D';
+        }
+
+        var totalSign = total < 0 ? '-' : '';
+        var ymSign = sign(this._months) !== sign(total) ? '-' : '';
+        var daysSign = sign(this._days) !== sign(total) ? '-' : '';
+        var hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';
+
+        return totalSign + 'P' +
+            (Y ? ymSign + Y + 'Y' : '') +
+            (M ? ymSign + M + 'M' : '') +
+            (D ? daysSign + D + 'D' : '') +
+            ((h || m || s) ? 'T' : '') +
+            (h ? hmsSign + h + 'H' : '') +
+            (m ? hmsSign + m + 'M' : '') +
+            (s ? hmsSign + s + 'S' : '');
+    }
+
+    var proto$2 = Duration.prototype;
+
+    proto$2.isValid        = isValid$1;
+    proto$2.abs            = abs;
+    proto$2.add            = add$1;
+    proto$2.subtract       = subtract$1;
+    proto$2.as             = as;
+    proto$2.asMilliseconds = asMilliseconds;
+    proto$2.asSeconds      = asSeconds;
+    proto$2.asMinutes      = asMinutes;
+    proto$2.asHours        = asHours;
+    proto$2.asDays         = asDays;
+    proto$2.asWeeks        = asWeeks;
+    proto$2.asMonths       = asMonths;
+    proto$2.asQuarters     = asQuarters;
+    proto$2.asYears        = asYears;
+    proto$2.valueOf        = valueOf$1;
+    proto$2._bubble        = bubble;
+    proto$2.clone          = clone$1;
+    proto$2.get            = get$2;
+    proto$2.milliseconds   = milliseconds;
+    proto$2.seconds        = seconds;
+    proto$2.minutes        = minutes;
+    proto$2.hours          = hours;
+    proto$2.days           = days;
+    proto$2.weeks          = weeks;
+    proto$2.months         = months;
+    proto$2.years          = years;
+    proto$2.humanize       = humanize;
+    proto$2.toISOString    = toISOString$1;
+    proto$2.toString       = toISOString$1;
+    proto$2.toJSON         = toISOString$1;
+    proto$2.locale         = locale;
+    proto$2.localeData     = localeData;
+
+    proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
+    proto$2.lang = lang;
+
+    // Side effect imports
+
+    // FORMATTING
+
+    addFormatToken('X', 0, 0, 'unix');
+    addFormatToken('x', 0, 0, 'valueOf');
+
+    // PARSING
+
+    addRegexToken('x', matchSigned);
+    addRegexToken('X', matchTimestamp);
+    addParseToken('X', function (input, array, config) {
+        config._d = new Date(parseFloat(input, 10) * 1000);
+    });
+    addParseToken('x', function (input, array, config) {
+        config._d = new Date(toInt(input));
+    });
+
+    // Side effect imports
+
+
+    hooks.version = '2.24.0';
+
+    setHookCallback(createLocal);
+
+    hooks.fn                    = proto;
+    hooks.min                   = min;
+    hooks.max                   = max;
+    hooks.now                   = now;
+    hooks.utc                   = createUTC;
+    hooks.unix                  = createUnix;
+    hooks.months                = listMonths;
+    hooks.isDate                = isDate;
+    hooks.locale                = getSetGlobalLocale;
+    hooks.invalid               = createInvalid;
+    hooks.duration              = createDuration;
+    hooks.isMoment              = isMoment;
+    hooks.weekdays              = listWeekdays;
+    hooks.parseZone             = createInZone;
+    hooks.localeData            = getLocale;
+    hooks.isDuration            = isDuration;
+    hooks.monthsShort           = listMonthsShort;
+    hooks.weekdaysMin           = listWeekdaysMin;
+    hooks.defineLocale          = defineLocale;
+    hooks.updateLocale          = updateLocale;
+    hooks.locales               = listLocales;
+    hooks.weekdaysShort         = listWeekdaysShort;
+    hooks.normalizeUnits        = normalizeUnits;
+    hooks.relativeTimeRounding  = getSetRelativeTimeRounding;
+    hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
+    hooks.calendarFormat        = getCalendarFormat;
+    hooks.prototype             = proto;
+
+    // currently HTML5 input type only supports 24-hour formats
+    hooks.HTML5_FMT = {
+        DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm',             // <input type="datetime-local" />
+        DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss',  // <input type="datetime-local" step="1" />
+        DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS',   // <input type="datetime-local" step="0.001" />
+        DATE: 'YYYY-MM-DD',                             // <input type="date" />
+        TIME: 'HH:mm',                                  // <input type="time" />
+        TIME_SECONDS: 'HH:mm:ss',                       // <input type="time" step="1" />
+        TIME_MS: 'HH:mm:ss.SSS',                        // <input type="time" step="0.001" />
+        WEEK: 'GGGG-[W]WW',                             // <input type="week" />
+        MONTH: 'YYYY-MM'                                // <input type="month" />
+    };
+
+    return hooks;
+
+})));
+});
+
+var FORMATS = {
+       datetime: 'MMM D, YYYY, h:mm:ss a',
+       millisecond: 'h:mm:ss.SSS a',
+       second: 'h:mm:ss a',
+       minute: 'h:mm a',
+       hour: 'hA',
+       day: 'MMM D',
+       week: 'll',
+       month: 'MMM YYYY',
+       quarter: '[Q]Q - YYYY',
+       year: 'YYYY'
+};
+
+core_adapters._date.override(typeof moment === 'function' ? {
+       _id: 'moment', // DEBUG ONLY
+
+       formats: function() {
+               return FORMATS;
+       },
+
+       parse: function(value, format) {
+               if (typeof value === 'string' && typeof format === 'string') {
+                       value = moment(value, format);
+               } else if (!(value instanceof moment)) {
+                       value = moment(value);
+               }
+               return value.isValid() ? value.valueOf() : null;
+       },
+
+       format: function(time, format) {
+               return moment(time).format(format);
+       },
+
+       add: function(time, amount, unit) {
+               return moment(time).add(amount, unit).valueOf();
+       },
+
+       diff: function(max, min, unit) {
+               return moment.duration(moment(max).diff(moment(min))).as(unit);
+       },
+
+       startOf: function(time, unit, weekday) {
+               time = moment(time);
+               if (unit === 'isoWeek') {
+                       return time.isoWeekday(weekday).valueOf();
+               }
+               return time.startOf(unit).valueOf();
+       },
+
+       endOf: function(time, unit) {
+               return moment(time).endOf(unit).valueOf();
+       },
+
+       // DEPRECATIONS
+
+       /**
+        * Provided for backward compatibility with scale.getValueForPixel().
+        * @deprecated since version 2.8.0
+        * @todo remove at version 3
+        * @private
+        */
+       _create: function(time) {
+               return moment(time);
+       },
+} : {});
+
+core_defaults._set('global', {
+       plugins: {
+               filler: {
+                       propagate: true
+               }
+       }
+});
+
+var mappers = {
+       dataset: function(source) {
+               var index = source.fill;
+               var chart = source.chart;
+               var meta = chart.getDatasetMeta(index);
+               var visible = meta && chart.isDatasetVisible(index);
+               var points = (visible && meta.dataset._children) || [];
+               var length = points.length || 0;
+
+               return !length ? null : function(point, i) {
+                       return (i < length && points[i]._view) || null;
+               };
+       },
+
+       boundary: function(source) {
+               var boundary = source.boundary;
+               var x = boundary ? boundary.x : null;
+               var y = boundary ? boundary.y : null;
+
+               return function(point) {
+                       return {
+                               x: x === null ? point.x : x,
+                               y: y === null ? point.y : y,
+                       };
+               };
+       }
+};
+
+// @todo if (fill[0] === '#')
+function decodeFill(el, index, count) {
+       var model = el._model || {};
+       var fill = model.fill;
+       var target;
+
+       if (fill === undefined) {
+               fill = !!model.backgroundColor;
+       }
+
+       if (fill === false || fill === null) {
+               return false;
+       }
+
+       if (fill === true) {
+               return 'origin';
+       }
+
+       target = parseFloat(fill, 10);
+       if (isFinite(target) && Math.floor(target) === target) {
+               if (fill[0] === '-' || fill[0] === '+') {
+                       target = index + target;
+               }
+
+               if (target === index || target < 0 || target >= count) {
+                       return false;
+               }
+
+               return target;
+       }
+
+       switch (fill) {
+       // compatibility
+       case 'bottom':
+               return 'start';
+       case 'top':
+               return 'end';
+       case 'zero':
+               return 'origin';
+       // supported boundaries
+       case 'origin':
+       case 'start':
+       case 'end':
+               return fill;
+       // invalid fill values
+       default:
+               return false;
+       }
+}
+
+function computeBoundary(source) {
+       var model = source.el._model || {};
+       var scale = source.el._scale || {};
+       var fill = source.fill;
+       var target = null;
+       var horizontal;
+
+       if (isFinite(fill)) {
+               return null;
+       }
+
+       // Backward compatibility: until v3, we still need to support boundary values set on
+       // the model (scaleTop, scaleBottom and scaleZero) because some external plugins and
+       // controllers might still use it (e.g. the Smith chart).
+
+       if (fill === 'start') {
+               target = model.scaleBottom === undefined ? scale.bottom : model.scaleBottom;
+       } else if (fill === 'end') {
+               target = model.scaleTop === undefined ? scale.top : model.scaleTop;
+       } else if (model.scaleZero !== undefined) {
+               target = model.scaleZero;
+       } else if (scale.getBasePosition) {
+               target = scale.getBasePosition();
+       } else if (scale.getBasePixel) {
+               target = scale.getBasePixel();
+       }
+
+       if (target !== undefined && target !== null) {
+               if (target.x !== undefined && target.y !== undefined) {
+                       return target;
+               }
+
+               if (helpers$1.isFinite(target)) {
+                       horizontal = scale.isHorizontal();
+                       return {
+                               x: horizontal ? target : null,
+                               y: horizontal ? null : target
+                       };
+               }
+       }
+
+       return null;
+}
+
+function resolveTarget(sources, index, propagate) {
+       var source = sources[index];
+       var fill = source.fill;
+       var visited = [index];
+       var target;
+
+       if (!propagate) {
+               return fill;
+       }
+
+       while (fill !== false && visited.indexOf(fill) === -1) {
+               if (!isFinite(fill)) {
+                       return fill;
+               }
+
+               target = sources[fill];
+               if (!target) {
+                       return false;
+               }
+
+               if (target.visible) {
+                       return fill;
+               }
+
+               visited.push(fill);
+               fill = target.fill;
+       }
+
+       return false;
+}
+
+function createMapper(source) {
+       var fill = source.fill;
+       var type = 'dataset';
+
+       if (fill === false) {
+               return null;
+       }
+
+       if (!isFinite(fill)) {
+               type = 'boundary';
+       }
+
+       return mappers[type](source);
+}
+
+function isDrawable(point) {
+       return point && !point.skip;
+}
+
+function drawArea(ctx, curve0, curve1, len0, len1) {
+       var i;
+
+       if (!len0 || !len1) {
+               return;
+       }
+
+       // building first area curve (normal)
+       ctx.moveTo(curve0[0].x, curve0[0].y);
+       for (i = 1; i < len0; ++i) {
+               helpers$1.canvas.lineTo(ctx, curve0[i - 1], curve0[i]);
+       }
+
+       // joining the two area curves
+       ctx.lineTo(curve1[len1 - 1].x, curve1[len1 - 1].y);
+
+       // building opposite area curve (reverse)
+       for (i = len1 - 1; i > 0; --i) {
+               helpers$1.canvas.lineTo(ctx, curve1[i], curve1[i - 1], true);
+       }
+}
+
+function doFill(ctx, points, mapper, view, color, loop) {
+       var count = points.length;
+       var span = view.spanGaps;
+       var curve0 = [];
+       var curve1 = [];
+       var len0 = 0;
+       var len1 = 0;
+       var i, ilen, index, p0, p1, d0, d1;
+
+       ctx.beginPath();
+
+       for (i = 0, ilen = (count + !!loop); i < ilen; ++i) {
+               index = i % count;
+               p0 = points[index]._view;
+               p1 = mapper(p0, index, view);
+               d0 = isDrawable(p0);
+               d1 = isDrawable(p1);
+
+               if (d0 && d1) {
+                       len0 = curve0.push(p0);
+                       len1 = curve1.push(p1);
+               } else if (len0 && len1) {
+                       if (!span) {
+                               drawArea(ctx, curve0, curve1, len0, len1);
+                               len0 = len1 = 0;
+                               curve0 = [];
+                               curve1 = [];
+                       } else {
+                               if (d0) {
+                                       curve0.push(p0);
+                               }
+                               if (d1) {
+                                       curve1.push(p1);
+                               }
+                       }
+               }
+       }
+
+       drawArea(ctx, curve0, curve1, len0, len1);
+
+       ctx.closePath();
+       ctx.fillStyle = color;
+       ctx.fill();
+}
+
+var plugin_filler = {
+       id: 'filler',
+
+       afterDatasetsUpdate: function(chart, options) {
+               var count = (chart.data.datasets || []).length;
+               var propagate = options.propagate;
+               var sources = [];
+               var meta, i, el, source;
+
+               for (i = 0; i < count; ++i) {
+                       meta = chart.getDatasetMeta(i);
+                       el = meta.dataset;
+                       source = null;
+
+                       if (el && el._model && el instanceof elements.Line) {
+                               source = {
+                                       visible: chart.isDatasetVisible(i),
+                                       fill: decodeFill(el, i, count),
+                                       chart: chart,
+                                       el: el
+                               };
+                       }
+
+                       meta.$filler = source;
+                       sources.push(source);
+               }
+
+               for (i = 0; i < count; ++i) {
+                       source = sources[i];
+                       if (!source) {
+                               continue;
+                       }
+
+                       source.fill = resolveTarget(sources, i, propagate);
+                       source.boundary = computeBoundary(source);
+                       source.mapper = createMapper(source);
+               }
+       },
+
+       beforeDatasetDraw: function(chart, args) {
+               var meta = args.meta.$filler;
+               if (!meta) {
+                       return;
+               }
+
+               var ctx = chart.ctx;
+               var el = meta.el;
+               var view = el._view;
+               var points = el._children || [];
+               var mapper = meta.mapper;
+               var color = view.backgroundColor || core_defaults.global.defaultColor;
+
+               if (mapper && color && points.length) {
+                       helpers$1.canvas.clipArea(ctx, chart.chartArea);
+                       doFill(ctx, points, mapper, view, color, el._loop);
+                       helpers$1.canvas.unclipArea(ctx);
+               }
+       }
+};
+
+var noop$1 = helpers$1.noop;
+var valueOrDefault$d = helpers$1.valueOrDefault;
+
+core_defaults._set('global', {
+       legend: {
+               display: true,
+               position: 'top',
+               fullWidth: true,
+               reverse: false,
+               weight: 1000,
+
+               // a callback that will handle
+               onClick: function(e, legendItem) {
+                       var index = legendItem.datasetIndex;
+                       var ci = this.chart;
+                       var meta = ci.getDatasetMeta(index);
+
+                       // See controller.isDatasetVisible comment
+                       meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;
+
+                       // We hid a dataset ... rerender the chart
+                       ci.update();
+               },
+
+               onHover: null,
+               onLeave: null,
+
+               labels: {
+                       boxWidth: 40,
+                       padding: 10,
+                       // Generates labels shown in the legend
+                       // Valid properties to return:
+                       // text : text to display
+                       // fillStyle : fill of coloured box
+                       // strokeStyle: stroke of coloured box
+                       // hidden : if this legend item refers to a hidden item
+                       // lineCap : cap style for line
+                       // lineDash
+                       // lineDashOffset :
+                       // lineJoin :
+                       // lineWidth :
+                       generateLabels: function(chart) {
+                               var data = chart.data;
+                               return helpers$1.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
+                                       return {
+                                               text: dataset.label,
+                                               fillStyle: (!helpers$1.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
+                                               hidden: !chart.isDatasetVisible(i),
+                                               lineCap: dataset.borderCapStyle,
+                                               lineDash: dataset.borderDash,
+                                               lineDashOffset: dataset.borderDashOffset,
+                                               lineJoin: dataset.borderJoinStyle,
+                                               lineWidth: dataset.borderWidth,
+                                               strokeStyle: dataset.borderColor,
+                                               pointStyle: dataset.pointStyle,
+
+                                               // Below is extra data used for toggling the datasets
+                                               datasetIndex: i
+                                       };
+                               }, this) : [];
+                       }
+               }
+       },
+
+       legendCallback: function(chart) {
+               var text = [];
+               text.push('<ul class="' + chart.id + '-legend">');
+               for (var i = 0; i < chart.data.datasets.length; i++) {
+                       text.push('<li><span style="background-color:' + chart.data.datasets[i].backgroundColor + '"></span>');
+                       if (chart.data.datasets[i].label) {
+                               text.push(chart.data.datasets[i].label);
+                       }
+                       text.push('</li>');
+               }
+               text.push('</ul>');
+               return text.join('');
+       }
+});
+
+/**
+ * Helper function to get the box width based on the usePointStyle option
+ * @param {object} labelopts - the label options on the legend
+ * @param {number} fontSize - the label font size
+ * @return {number} width of the color box area
+ */
+function getBoxWidth(labelOpts, fontSize) {
+       return labelOpts.usePointStyle && labelOpts.boxWidth > fontSize ?
+               fontSize :
+               labelOpts.boxWidth;
+}
+
+/**
+ * IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required!
+ */
+var Legend = core_element.extend({
+
+       initialize: function(config) {
+               helpers$1.extend(this, config);
+
+               // Contains hit boxes for each dataset (in dataset order)
+               this.legendHitBoxes = [];
+
+               /**
+                * @private
+                */
+               this._hoveredItem = null;
+
+               // Are we in doughnut mode which has a different data type
+               this.doughnutMode = false;
+       },
+
+       // These methods are ordered by lifecycle. Utilities then follow.
+       // Any function defined here is inherited by all legend types.
+       // Any function can be extended by the legend type
+
+       beforeUpdate: noop$1,
+       update: function(maxWidth, maxHeight, margins) {
+               var me = this;
+
+               // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
+               me.beforeUpdate();
+
+               // Absorb the master measurements
+               me.maxWidth = maxWidth;
+               me.maxHeight = maxHeight;
+               me.margins = margins;
+
+               // Dimensions
+               me.beforeSetDimensions();
+               me.setDimensions();
+               me.afterSetDimensions();
+               // Labels
+               me.beforeBuildLabels();
+               me.buildLabels();
+               me.afterBuildLabels();
+
+               // Fit
+               me.beforeFit();
+               me.fit();
+               me.afterFit();
+               //
+               me.afterUpdate();
+
+               return me.minSize;
+       },
+       afterUpdate: noop$1,
+
+       //
+
+       beforeSetDimensions: noop$1,
+       setDimensions: function() {
+               var me = this;
+               // Set the unconstrained dimension before label rotation
+               if (me.isHorizontal()) {
+                       // Reset position before calculating rotation
+                       me.width = me.maxWidth;
+                       me.left = 0;
+                       me.right = me.width;
+               } else {
+                       me.height = me.maxHeight;
+
+                       // Reset position before calculating rotation
+                       me.top = 0;
+                       me.bottom = me.height;
+               }
+
+               // Reset padding
+               me.paddingLeft = 0;
+               me.paddingTop = 0;
+               me.paddingRight = 0;
+               me.paddingBottom = 0;
+
+               // Reset minSize
+               me.minSize = {
+                       width: 0,
+                       height: 0
+               };
+       },
+       afterSetDimensions: noop$1,
+
+       //
+
+       beforeBuildLabels: noop$1,
+       buildLabels: function() {
+               var me = this;
+               var labelOpts = me.options.labels || {};
+               var legendItems = helpers$1.callback(labelOpts.generateLabels, [me.chart], me) || [];
+
+               if (labelOpts.filter) {
+                       legendItems = legendItems.filter(function(item) {
+                               return labelOpts.filter(item, me.chart.data);
+                       });
+               }
+
+               if (me.options.reverse) {
+                       legendItems.reverse();
+               }
+
+               me.legendItems = legendItems;
+       },
+       afterBuildLabels: noop$1,
+
+       //
+
+       beforeFit: noop$1,
+       fit: function() {
+               var me = this;
+               var opts = me.options;
+               var labelOpts = opts.labels;
+               var display = opts.display;
+
+               var ctx = me.ctx;
+
+               var labelFont = helpers$1.options._parseFont(labelOpts);
+               var fontSize = labelFont.size;
+
+               // Reset hit boxes
+               var hitboxes = me.legendHitBoxes = [];
+
+               var minSize = me.minSize;
+               var isHorizontal = me.isHorizontal();
+
+               if (isHorizontal) {
+                       minSize.width = me.maxWidth; // fill all the width
+                       minSize.height = display ? 10 : 0;
+               } else {
+                       minSize.width = display ? 10 : 0;
+                       minSize.height = me.maxHeight; // fill all the height
+               }
+
+               // Increase sizes here
+               if (display) {
+                       ctx.font = labelFont.string;
+
+                       if (isHorizontal) {
+                               // Labels
+
+                               // Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
+                               var lineWidths = me.lineWidths = [0];
+                               var totalHeight = 0;
+
+                               ctx.textAlign = 'left';
+                               ctx.textBaseline = 'top';
+
+                               helpers$1.each(me.legendItems, function(legendItem, i) {
+                                       var boxWidth = getBoxWidth(labelOpts, fontSize);
+                                       var width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
+
+                                       if (i === 0 || lineWidths[lineWidths.length - 1] + width + labelOpts.padding > minSize.width) {
+                                               totalHeight += fontSize + labelOpts.padding;
+                                               lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = labelOpts.padding;
+                                       }
+
+                                       // Store the hitbox width and height here. Final position will be updated in `draw`
+                                       hitboxes[i] = {
+                                               left: 0,
+                                               top: 0,
+                                               width: width,
+                                               height: fontSize
+                                       };
+
+                                       lineWidths[lineWidths.length - 1] += width + labelOpts.padding;
+                               });
+
+                               minSize.height += totalHeight;
+
+                       } else {
+                               var vPadding = labelOpts.padding;
+                               var columnWidths = me.columnWidths = [];
+                               var totalWidth = labelOpts.padding;
+                               var currentColWidth = 0;
+                               var currentColHeight = 0;
+                               var itemHeight = fontSize + vPadding;
+
+                               helpers$1.each(me.legendItems, function(legendItem, i) {
+                                       var boxWidth = getBoxWidth(labelOpts, fontSize);
+                                       var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
+
+                                       // If too tall, go to new column
+                                       if (i > 0 && currentColHeight + itemHeight > minSize.height - vPadding) {
+                                               totalWidth += currentColWidth + labelOpts.padding;
+                                               columnWidths.push(currentColWidth); // previous column width
+
+                                               currentColWidth = 0;
+                                               currentColHeight = 0;
+                                       }
+
+                                       // Get max width
+                                       currentColWidth = Math.max(currentColWidth, itemWidth);
+                                       currentColHeight += itemHeight;
+
+                                       // Store the hitbox width and height here. Final position will be updated in `draw`
+                                       hitboxes[i] = {
+                                               left: 0,
+                                               top: 0,
+                                               width: itemWidth,
+                                               height: fontSize
+                                       };
+                               });
+
+                               totalWidth += currentColWidth;
+                               columnWidths.push(currentColWidth);
+                               minSize.width += totalWidth;
+                       }
+               }
+
+               me.width = minSize.width;
+               me.height = minSize.height;
+       },
+       afterFit: noop$1,
+
+       // Shared Methods
+       isHorizontal: function() {
+               return this.options.position === 'top' || this.options.position === 'bottom';
+       },
+
+       // Actually draw the legend on the canvas
+       draw: function() {
+               var me = this;
+               var opts = me.options;
+               var labelOpts = opts.labels;
+               var globalDefaults = core_defaults.global;
+               var defaultColor = globalDefaults.defaultColor;
+               var lineDefault = globalDefaults.elements.line;
+               var legendWidth = me.width;
+               var lineWidths = me.lineWidths;
+
+               if (opts.display) {
+                       var ctx = me.ctx;
+                       var fontColor = valueOrDefault$d(labelOpts.fontColor, globalDefaults.defaultFontColor);
+                       var labelFont = helpers$1.options._parseFont(labelOpts);
+                       var fontSize = labelFont.size;
+                       var cursor;
+
+                       // Canvas setup
+                       ctx.textAlign = 'left';
+                       ctx.textBaseline = 'middle';
+                       ctx.lineWidth = 0.5;
+                       ctx.strokeStyle = fontColor; // for strikethrough effect
+                       ctx.fillStyle = fontColor; // render in correct colour
+                       ctx.font = labelFont.string;
+
+                       var boxWidth = getBoxWidth(labelOpts, fontSize);
+                       var hitboxes = me.legendHitBoxes;
+
+                       // current position
+                       var drawLegendBox = function(x, y, legendItem) {
+                               if (isNaN(boxWidth) || boxWidth <= 0) {
+                                       return;
+                               }
+
+                               // Set the ctx for the box
+                               ctx.save();
+
+                               var lineWidth = valueOrDefault$d(legendItem.lineWidth, lineDefault.borderWidth);
+                               ctx.fillStyle = valueOrDefault$d(legendItem.fillStyle, defaultColor);
+                               ctx.lineCap = valueOrDefault$d(legendItem.lineCap, lineDefault.borderCapStyle);
+                               ctx.lineDashOffset = valueOrDefault$d(legendItem.lineDashOffset, lineDefault.borderDashOffset);
+                               ctx.lineJoin = valueOrDefault$d(legendItem.lineJoin, lineDefault.borderJoinStyle);
+                               ctx.lineWidth = lineWidth;
+                               ctx.strokeStyle = valueOrDefault$d(legendItem.strokeStyle, defaultColor);
+
+                               if (ctx.setLineDash) {
+                                       // IE 9 and 10 do not support line dash
+                                       ctx.setLineDash(valueOrDefault$d(legendItem.lineDash, lineDefault.borderDash));
+                               }
+
+                               if (opts.labels && opts.labels.usePointStyle) {
+                                       // Recalculate x and y for drawPoint() because its expecting
+                                       // x and y to be center of figure (instead of top left)
+                                       var radius = boxWidth * Math.SQRT2 / 2;
+                                       var centerX = x + boxWidth / 2;
+                                       var centerY = y + fontSize / 2;
+
+                                       // Draw pointStyle as legend symbol
+                                       helpers$1.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
+                               } else {
+                                       // Draw box as legend symbol
+                                       if (lineWidth !== 0) {
+                                               ctx.strokeRect(x, y, boxWidth, fontSize);
+                                       }
+                                       ctx.fillRect(x, y, boxWidth, fontSize);
+                               }
+
+                               ctx.restore();
+                       };
+                       var fillText = function(x, y, legendItem, textWidth) {
+                               var halfFontSize = fontSize / 2;
+                               var xLeft = boxWidth + halfFontSize + x;
+                               var yMiddle = y + halfFontSize;
+
+                               ctx.fillText(legendItem.text, xLeft, yMiddle);
+
+                               if (legendItem.hidden) {
+                                       // Strikethrough the text if hidden
+                                       ctx.beginPath();
+                                       ctx.lineWidth = 2;
+                                       ctx.moveTo(xLeft, yMiddle);
+                                       ctx.lineTo(xLeft + textWidth, yMiddle);
+                                       ctx.stroke();
+                               }
+                       };
+
+                       // Horizontal
+                       var isHorizontal = me.isHorizontal();
+                       if (isHorizontal) {
+                               cursor = {
+                                       x: me.left + ((legendWidth - lineWidths[0]) / 2) + labelOpts.padding,
+                                       y: me.top + labelOpts.padding,
+                                       line: 0
+                               };
+                       } else {
+                               cursor = {
+                                       x: me.left + labelOpts.padding,
+                                       y: me.top + labelOpts.padding,
+                                       line: 0
+                               };
+                       }
+
+                       var itemHeight = fontSize + labelOpts.padding;
+                       helpers$1.each(me.legendItems, function(legendItem, i) {
+                               var textWidth = ctx.measureText(legendItem.text).width;
+                               var width = boxWidth + (fontSize / 2) + textWidth;
+                               var x = cursor.x;
+                               var y = cursor.y;
+
+                               // Use (me.left + me.minSize.width) and (me.top + me.minSize.height)
+                               // instead of me.right and me.bottom because me.width and me.height
+                               // may have been changed since me.minSize was calculated
+                               if (isHorizontal) {
+                                       if (i > 0 && x + width + labelOpts.padding > me.left + me.minSize.width) {
+                                               y = cursor.y += itemHeight;
+                                               cursor.line++;
+                                               x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2) + labelOpts.padding;
+                                       }
+                               } else if (i > 0 && y + itemHeight > me.top + me.minSize.height) {
+                                       x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
+                                       y = cursor.y = me.top + labelOpts.padding;
+                                       cursor.line++;
+                               }
+
+                               drawLegendBox(x, y, legendItem);
+
+                               hitboxes[i].left = x;
+                               hitboxes[i].top = y;
+
+                               // Fill the actual label
+                               fillText(x, y, legendItem, textWidth);
+
+                               if (isHorizontal) {
+                                       cursor.x += width + labelOpts.padding;
+                               } else {
+                                       cursor.y += itemHeight;
+                               }
+
+                       });
+               }
+       },
+
+       /**
+        * @private
+        */
+       _getLegendItemAt: function(x, y) {
+               var me = this;
+               var i, hitBox, lh;
+
+               if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
+                       // See if we are touching one of the dataset boxes
+                       lh = me.legendHitBoxes;
+                       for (i = 0; i < lh.length; ++i) {
+                               hitBox = lh[i];
+
+                               if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
+                                       // Touching an element
+                                       return me.legendItems[i];
+                               }
+                       }
+               }
+
+               return null;
+       },
+
+       /**
+        * Handle an event
+        * @private
+        * @param {IEvent} event - The event to handle
+        */
+       handleEvent: function(e) {
+               var me = this;
+               var opts = me.options;
+               var type = e.type === 'mouseup' ? 'click' : e.type;
+               var hoveredItem;
+
+               if (type === 'mousemove') {
+                       if (!opts.onHover && !opts.onLeave) {
+                               return;
+                       }
+               } else if (type === 'click') {
+                       if (!opts.onClick) {
+                               return;
+                       }
+               } else {
+                       return;
+               }
+
+               // Chart event already has relative position in it
+               hoveredItem = me._getLegendItemAt(e.x, e.y);
+
+               if (type === 'click') {
+                       if (hoveredItem && opts.onClick) {
+                               // use e.native for backwards compatibility
+                               opts.onClick.call(me, e.native, hoveredItem);
+                       }
+               } else {
+                       if (opts.onLeave && hoveredItem !== me._hoveredItem) {
+                               if (me._hoveredItem) {
+                                       opts.onLeave.call(me, e.native, me._hoveredItem);
+                               }
+                               me._hoveredItem = hoveredItem;
+                       }
+
+                       if (opts.onHover && hoveredItem) {
+                               // use e.native for backwards compatibility
+                               opts.onHover.call(me, e.native, hoveredItem);
+                       }
+               }
+       }
+});
+
+function createNewLegendAndAttach(chart, legendOpts) {
+       var legend = new Legend({
+               ctx: chart.ctx,
+               options: legendOpts,
+               chart: chart
+       });
+
+       core_layouts.configure(chart, legend, legendOpts);
+       core_layouts.addBox(chart, legend);
+       chart.legend = legend;
+}
+
+var plugin_legend = {
+       id: 'legend',
+
+       /**
+        * Backward compatibility: since 2.1.5, the legend is registered as a plugin, making
+        * Chart.Legend obsolete. To avoid a breaking change, we export the Legend as part of
+        * the plugin, which one will be re-exposed in the chart.js file.
+        * https://github.com/chartjs/Chart.js/pull/2640
+        * @private
+        */
+       _element: Legend,
+
+       beforeInit: function(chart) {
+               var legendOpts = chart.options.legend;
+
+               if (legendOpts) {
+                       createNewLegendAndAttach(chart, legendOpts);
+               }
+       },
+
+       beforeUpdate: function(chart) {
+               var legendOpts = chart.options.legend;
+               var legend = chart.legend;
+
+               if (legendOpts) {
+                       helpers$1.mergeIf(legendOpts, core_defaults.global.legend);
+
+                       if (legend) {
+                               core_layouts.configure(chart, legend, legendOpts);
+                               legend.options = legendOpts;
+                       } else {
+                               createNewLegendAndAttach(chart, legendOpts);
+                       }
+               } else if (legend) {
+                       core_layouts.removeBox(chart, legend);
+                       delete chart.legend;
+               }
+       },
+
+       afterEvent: function(chart, e) {
+               var legend = chart.legend;
+               if (legend) {
+                       legend.handleEvent(e);
+               }
+       }
+};
+
+var noop$2 = helpers$1.noop;
+
+core_defaults._set('global', {
+       title: {
+               display: false,
+               fontStyle: 'bold',
+               fullWidth: true,
+               padding: 10,
+               position: 'top',
+               text: '',
+               weight: 2000         // by default greater than legend (1000) to be above
+       }
+});
+
+/**
+ * IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required!
+ */
+var Title = core_element.extend({
+       initialize: function(config) {
+               var me = this;
+               helpers$1.extend(me, config);
+
+               // Contains hit boxes for each dataset (in dataset order)
+               me.legendHitBoxes = [];
+       },
+
+       // These methods are ordered by lifecycle. Utilities then follow.
+
+       beforeUpdate: noop$2,
+       update: function(maxWidth, maxHeight, margins) {
+               var me = this;
+
+               // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
+               me.beforeUpdate();
+
+               // Absorb the master measurements
+               me.maxWidth = maxWidth;
+               me.maxHeight = maxHeight;
+               me.margins = margins;
+
+               // Dimensions
+               me.beforeSetDimensions();
+               me.setDimensions();
+               me.afterSetDimensions();
+               // Labels
+               me.beforeBuildLabels();
+               me.buildLabels();
+               me.afterBuildLabels();
+
+               // Fit
+               me.beforeFit();
+               me.fit();
+               me.afterFit();
+               //
+               me.afterUpdate();
+
+               return me.minSize;
+
+       },
+       afterUpdate: noop$2,
+
+       //
+
+       beforeSetDimensions: noop$2,
+       setDimensions: function() {
+               var me = this;
+               // Set the unconstrained dimension before label rotation
+               if (me.isHorizontal()) {
+                       // Reset position before calculating rotation
+                       me.width = me.maxWidth;
+                       me.left = 0;
+                       me.right = me.width;
+               } else {
+                       me.height = me.maxHeight;
+
+                       // Reset position before calculating rotation
+                       me.top = 0;
+                       me.bottom = me.height;
+               }
+
+               // Reset padding
+               me.paddingLeft = 0;
+               me.paddingTop = 0;
+               me.paddingRight = 0;
+               me.paddingBottom = 0;
+
+               // Reset minSize
+               me.minSize = {
+                       width: 0,
+                       height: 0
+               };
+       },
+       afterSetDimensions: noop$2,
+
+       //
+
+       beforeBuildLabels: noop$2,
+       buildLabels: noop$2,
+       afterBuildLabels: noop$2,
+
+       //
+
+       beforeFit: noop$2,
+       fit: function() {
+               var me = this;
+               var opts = me.options;
+               var display = opts.display;
+               var minSize = me.minSize;
+               var lineCount = helpers$1.isArray(opts.text) ? opts.text.length : 1;
+               var fontOpts = helpers$1.options._parseFont(opts);
+               var textSize = display ? (lineCount * fontOpts.lineHeight) + (opts.padding * 2) : 0;
+
+               if (me.isHorizontal()) {
+                       minSize.width = me.maxWidth; // fill all the width
+                       minSize.height = textSize;
+               } else {
+                       minSize.width = textSize;
+                       minSize.height = me.maxHeight; // fill all the height
+               }
+
+               me.width = minSize.width;
+               me.height = minSize.height;
+
+       },
+       afterFit: noop$2,
+
+       // Shared Methods
+       isHorizontal: function() {
+               var pos = this.options.position;
+               return pos === 'top' || pos === 'bottom';
+       },
+
+       // Actually draw the title block on the canvas
+       draw: function() {
+               var me = this;
+               var ctx = me.ctx;
+               var opts = me.options;
+
+               if (opts.display) {
+                       var fontOpts = helpers$1.options._parseFont(opts);
+                       var lineHeight = fontOpts.lineHeight;
+                       var offset = lineHeight / 2 + opts.padding;
+                       var rotation = 0;
+                       var top = me.top;
+                       var left = me.left;
+                       var bottom = me.bottom;
+                       var right = me.right;
+                       var maxWidth, titleX, titleY;
+
+                       ctx.fillStyle = helpers$1.valueOrDefault(opts.fontColor, core_defaults.global.defaultFontColor); // render in correct colour
+                       ctx.font = fontOpts.string;
+
+                       // Horizontal
+                       if (me.isHorizontal()) {
+                               titleX = left + ((right - left) / 2); // midpoint of the width
+                               titleY = top + offset;
+                               maxWidth = right - left;
+                       } else {
+                               titleX = opts.position === 'left' ? left + offset : right - offset;
+                               titleY = top + ((bottom - top) / 2);
+                               maxWidth = bottom - top;
+                               rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);
+                       }
+
+                       ctx.save();
+                       ctx.translate(titleX, titleY);
+                       ctx.rotate(rotation);
+                       ctx.textAlign = 'center';
+                       ctx.textBaseline = 'middle';
+
+                       var text = opts.text;
+                       if (helpers$1.isArray(text)) {
+                               var y = 0;
+                               for (var i = 0; i < text.length; ++i) {
+                                       ctx.fillText(text[i], 0, y, maxWidth);
+                                       y += lineHeight;
+                               }
+                       } else {
+                               ctx.fillText(text, 0, 0, maxWidth);
+                       }
+
+                       ctx.restore();
+               }
+       }
+});
+
+function createNewTitleBlockAndAttach(chart, titleOpts) {
+       var title = new Title({
+               ctx: chart.ctx,
+               options: titleOpts,
+               chart: chart
+       });
+
+       core_layouts.configure(chart, title, titleOpts);
+       core_layouts.addBox(chart, title);
+       chart.titleBlock = title;
+}
+
+var plugin_title = {
+       id: 'title',
+
+       /**
+        * Backward compatibility: since 2.1.5, the title is registered as a plugin, making
+        * Chart.Title obsolete. To avoid a breaking change, we export the Title as part of
+        * the plugin, which one will be re-exposed in the chart.js file.
+        * https://github.com/chartjs/Chart.js/pull/2640
+        * @private
+        */
+       _element: Title,
+
+       beforeInit: function(chart) {
+               var titleOpts = chart.options.title;
+
+               if (titleOpts) {
+                       createNewTitleBlockAndAttach(chart, titleOpts);
+               }
+       },
+
+       beforeUpdate: function(chart) {
+               var titleOpts = chart.options.title;
+               var titleBlock = chart.titleBlock;
+
+               if (titleOpts) {
+                       helpers$1.mergeIf(titleOpts, core_defaults.global.title);
+
+                       if (titleBlock) {
+                               core_layouts.configure(chart, titleBlock, titleOpts);
+                               titleBlock.options = titleOpts;
+                       } else {
+                               createNewTitleBlockAndAttach(chart, titleOpts);
+                       }
+               } else if (titleBlock) {
+                       core_layouts.removeBox(chart, titleBlock);
+                       delete chart.titleBlock;
+               }
+       }
+};
+
+var plugins = {};
+var filler = plugin_filler;
+var legend = plugin_legend;
+var title = plugin_title;
+plugins.filler = filler;
+plugins.legend = legend;
+plugins.title = title;
+
+/**
+ * @namespace Chart
+ */
+
+
+core_controller.helpers = helpers$1;
+
+// @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests!
+core_helpers(core_controller);
+
+core_controller._adapters = core_adapters;
+core_controller.Animation = core_animation;
+core_controller.animationService = core_animations;
+core_controller.controllers = controllers;
+core_controller.DatasetController = core_datasetController;
+core_controller.defaults = core_defaults;
+core_controller.Element = core_element;
+core_controller.elements = elements;
+core_controller.Interaction = core_interaction;
+core_controller.layouts = core_layouts;
+core_controller.platform = platform;
+core_controller.plugins = core_plugins;
+core_controller.Scale = core_scale;
+core_controller.scaleService = core_scaleService;
+core_controller.Ticks = core_ticks;
+core_controller.Tooltip = core_tooltip;
+
+// Register built-in scales
+
+core_controller.helpers.each(scales, function(scale, type) {
+       core_controller.scaleService.registerScaleType(type, scale, scale._defaults);
+});
+
+// Load to register built-in adapters (as side effects)
+
+
+// Loading built-in plugins
+
+for (var k in plugins) {
+       if (plugins.hasOwnProperty(k)) {
+               core_controller.plugins.register(plugins[k]);
+       }
+}
+
+core_controller.platform.initialize();
+
+var src = core_controller;
+if (typeof window !== 'undefined') {
+       window.Chart = core_controller;
+}
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, not available anymore
+ * @namespace Chart.Chart
+ * @deprecated since version 2.8.0
+ * @todo remove at version 3
+ * @private
+ */
+core_controller.Chart = core_controller;
+
+/**
+ * Provided for backward compatibility, not available anymore
+ * @namespace Chart.Legend
+ * @deprecated since version 2.1.5
+ * @todo remove at version 3
+ * @private
+ */
+core_controller.Legend = plugins.legend._element;
+
+/**
+ * Provided for backward compatibility, not available anymore
+ * @namespace Chart.Title
+ * @deprecated since version 2.1.5
+ * @todo remove at version 3
+ * @private
+ */
+core_controller.Title = plugins.title._element;
+
+/**
+ * Provided for backward compatibility, use Chart.plugins instead
+ * @namespace Chart.pluginService
+ * @deprecated since version 2.1.5
+ * @todo remove at version 3
+ * @private
+ */
+core_controller.pluginService = core_controller.plugins;
+
+/**
+ * Provided for backward compatibility, inheriting from Chart.PlugingBase has no
+ * effect, instead simply create/register plugins via plain JavaScript objects.
+ * @interface Chart.PluginBase
+ * @deprecated since version 2.5.0
+ * @todo remove at version 3
+ * @private
+ */
+core_controller.PluginBase = core_controller.Element.extend({});
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.canvas instead.
+ * @namespace Chart.canvasHelpers
+ * @deprecated since version 2.6.0
+ * @todo remove at version 3
+ * @private
+ */
+core_controller.canvasHelpers = core_controller.helpers.canvas;
+
+/**
+ * Provided for backward compatibility, use Chart.layouts instead.
+ * @namespace Chart.layoutService
+ * @deprecated since version 2.7.3
+ * @todo remove at version 3
+ * @private
+ */
+core_controller.layoutService = core_controller.layouts;
+
+/**
+ * Provided for backward compatibility, not available anymore.
+ * @namespace Chart.LinearScaleBase
+ * @deprecated since version 2.8
+ * @todo remove at version 3
+ * @private
+ */
+core_controller.LinearScaleBase = scale_linearbase;
+
+/**
+ * Provided for backward compatibility, instead we should create a new Chart
+ * by setting the type in the config (`new Chart(id, {type: '{chart-type}'}`).
+ * @deprecated since version 2.8.0
+ * @todo remove at version 3
+ */
+core_controller.helpers.each(
+       [
+               'Bar',
+               'Bubble',
+               'Doughnut',
+               'Line',
+               'PolarArea',
+               'Radar',
+               'Scatter'
+       ],
+       function(klass) {
+               core_controller[klass] = function(ctx, cfg) {
+                       return new core_controller(ctx, core_controller.helpers.merge(cfg || {}, {
+                               type: klass.charAt(0).toLowerCase() + klass.slice(1)
+                       }));
+               };
+       }
+);
+
+return src;
+
+})));
diff --git a/dist/Chart.bundle.min.js b/dist/Chart.bundle.min.js
new file mode 100644 (file)
index 0000000..0bf9ea9
--- /dev/null
@@ -0,0 +1,7 @@
+/*!
+ * Chart.js v2.8.0
+ * https://www.chartjs.org
+ * (c) 2019 Chart.js Contributors
+ * Released under the MIT License
+ */
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.Chart=e()}(this,function(){"use strict";var t={rgb2hsl:e,rgb2hsv:i,rgb2hwb:n,rgb2cmyk:a,rgb2keyword:o,rgb2xyz:s,rgb2lab:l,rgb2lch:function(t){return v(l(t))},hsl2rgb:u,hsl2hsv:function(t){var e=t[0],i=t[1]/100,n=t[2]/100;if(0===n)return[0,0,0];return[e,100*(2*(i*=(n*=2)<=1?n:2-n)/(n+i)),100*((n+i)/2)]},hsl2hwb:function(t){return n(u(t))},hsl2cmyk:function(t){return a(u(t))},hsl2keyword:function(t){return o(u(t))},hsv2rgb:d,hsv2hsl:function(t){var e,i,n=t[0],a=t[1]/100,r=t[2]/100;return e=a*r,[n,100*(e=(e/=(i=(2-a)*r)<=1?i:2-i)||0),100*(i/=2)]},hsv2hwb:function(t){return n(d(t))},hsv2cmyk:function(t){return a(d(t))},hsv2keyword:function(t){return o(d(t))},hwb2rgb:h,hwb2hsl:function(t){return e(h(t))},hwb2hsv:function(t){return i(h(t))},hwb2cmyk:function(t){return a(h(t))},hwb2keyword:function(t){return o(h(t))},cmyk2rgb:c,cmyk2hsl:function(t){return e(c(t))},cmyk2hsv:function(t){return i(c(t))},cmyk2hwb:function(t){return n(c(t))},cmyk2keyword:function(t){return o(c(t))},keyword2rgb:_,keyword2hsl:function(t){return e(_(t))},keyword2hsv:function(t){return i(_(t))},keyword2hwb:function(t){return n(_(t))},keyword2cmyk:function(t){return a(_(t))},keyword2lab:function(t){return l(_(t))},keyword2xyz:function(t){return s(_(t))},xyz2rgb:f,xyz2lab:m,xyz2lch:function(t){return v(m(t))},lab2xyz:p,lab2rgb:y,lab2lch:v,lch2lab:x,lch2xyz:function(t){return p(x(t))},lch2rgb:function(t){return y(x(t))}};function e(t){var e,i,n=t[0]/255,a=t[1]/255,r=t[2]/255,o=Math.min(n,a,r),s=Math.max(n,a,r),l=s-o;return s==o?e=0:n==s?e=(a-r)/l:a==s?e=2+(r-n)/l:r==s&&(e=4+(n-a)/l),(e=Math.min(60*e,360))<0&&(e+=360),i=(o+s)/2,[e,100*(s==o?0:i<=.5?l/(s+o):l/(2-s-o)),100*i]}function i(t){var e,i,n=t[0],a=t[1],r=t[2],o=Math.min(n,a,r),s=Math.max(n,a,r),l=s-o;return i=0==s?0:l/s*1e3/10,s==o?e=0:n==s?e=(a-r)/l:a==s?e=2+(r-n)/l:r==s&&(e=4+(n-a)/l),(e=Math.min(60*e,360))<0&&(e+=360),[e,i,s/255*1e3/10]}function n(t){var i=t[0],n=t[1],a=t[2];return[e(t)[0],100*(1/255*Math.min(i,Math.min(n,a))),100*(a=1-1/255*Math.max(i,Math.max(n,a)))]}function a(t){var e,i=t[0]/255,n=t[1]/255,a=t[2]/255;return[100*((1-i-(e=Math.min(1-i,1-n,1-a)))/(1-e)||0),100*((1-n-e)/(1-e)||0),100*((1-a-e)/(1-e)||0),100*e]}function o(t){return w[JSON.stringify(t)]}function s(t){var e=t[0]/255,i=t[1]/255,n=t[2]/255;return[100*(.4124*(e=e>.04045?Math.pow((e+.055)/1.055,2.4):e/12.92)+.3576*(i=i>.04045?Math.pow((i+.055)/1.055,2.4):i/12.92)+.1805*(n=n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92)),100*(.2126*e+.7152*i+.0722*n),100*(.0193*e+.1192*i+.9505*n)]}function l(t){var e=s(t),i=e[0],n=e[1],a=e[2];return n/=100,a/=108.883,i=(i/=95.047)>.008856?Math.pow(i,1/3):7.787*i+16/116,[116*(n=n>.008856?Math.pow(n,1/3):7.787*n+16/116)-16,500*(i-n),200*(n-(a=a>.008856?Math.pow(a,1/3):7.787*a+16/116))]}function u(t){var e,i,n,a,r,o=t[0]/360,s=t[1]/100,l=t[2]/100;if(0==s)return[r=255*l,r,r];e=2*l-(i=l<.5?l*(1+s):l+s-l*s),a=[0,0,0];for(var u=0;u<3;u++)(n=o+1/3*-(u-1))<0&&n++,n>1&&n--,r=6*n<1?e+6*(i-e)*n:2*n<1?i:3*n<2?e+(i-e)*(2/3-n)*6:e,a[u]=255*r;return a}function d(t){var e=t[0]/60,i=t[1]/100,n=t[2]/100,a=Math.floor(e)%6,r=e-Math.floor(e),o=255*n*(1-i),s=255*n*(1-i*r),l=255*n*(1-i*(1-r));n*=255;switch(a){case 0:return[n,l,o];case 1:return[s,n,o];case 2:return[o,n,l];case 3:return[o,s,n];case 4:return[l,o,n];case 5:return[n,o,s]}}function h(t){var e,i,n,a,o=t[0]/360,s=t[1]/100,l=t[2]/100,u=s+l;switch(u>1&&(s/=u,l/=u),n=6*o-(e=Math.floor(6*o)),0!=(1&e)&&(n=1-n),a=s+n*((i=1-l)-s),e){default:case 6:case 0:r=i,g=a,b=s;break;case 1:r=a,g=i,b=s;break;case 2:r=s,g=i,b=a;break;case 3:r=s,g=a,b=i;break;case 4:r=a,g=s,b=i;break;case 5:r=i,g=s,b=a}return[255*r,255*g,255*b]}function c(t){var e=t[0]/100,i=t[1]/100,n=t[2]/100,a=t[3]/100;return[255*(1-Math.min(1,e*(1-a)+a)),255*(1-Math.min(1,i*(1-a)+a)),255*(1-Math.min(1,n*(1-a)+a))]}function f(t){var e,i,n,a=t[0]/100,r=t[1]/100,o=t[2]/100;return i=-.9689*a+1.8758*r+.0415*o,n=.0557*a+-.204*r+1.057*o,e=(e=3.2406*a+-1.5372*r+-.4986*o)>.0031308?1.055*Math.pow(e,1/2.4)-.055:e*=12.92,i=i>.0031308?1.055*Math.pow(i,1/2.4)-.055:i*=12.92,n=n>.0031308?1.055*Math.pow(n,1/2.4)-.055:n*=12.92,[255*(e=Math.min(Math.max(0,e),1)),255*(i=Math.min(Math.max(0,i),1)),255*(n=Math.min(Math.max(0,n),1))]}function m(t){var e=t[0],i=t[1],n=t[2];return i/=100,n/=108.883,e=(e/=95.047)>.008856?Math.pow(e,1/3):7.787*e+16/116,[116*(i=i>.008856?Math.pow(i,1/3):7.787*i+16/116)-16,500*(e-i),200*(i-(n=n>.008856?Math.pow(n,1/3):7.787*n+16/116))]}function p(t){var e,i,n,a,r=t[0],o=t[1],s=t[2];return r<=8?a=(i=100*r/903.3)/100*7.787+16/116:(i=100*Math.pow((r+16)/116,3),a=Math.pow(i/100,1/3)),[e=e/95.047<=.008856?e=95.047*(o/500+a-16/116)/7.787:95.047*Math.pow(o/500+a,3),i,n=n/108.883<=.008859?n=108.883*(a-s/200-16/116)/7.787:108.883*Math.pow(a-s/200,3)]}function v(t){var e,i=t[0],n=t[1],a=t[2];return(e=360*Math.atan2(a,n)/2/Math.PI)<0&&(e+=360),[i,Math.sqrt(n*n+a*a),e]}function y(t){return f(p(t))}function x(t){var e,i=t[0],n=t[1];return e=t[2]/360*2*Math.PI,[i,n*Math.cos(e),n*Math.sin(e)]}function _(t){return k[t]}var k={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},w={};for(var M in k)w[JSON.stringify(k[M])]=M;var S=function(){return new O};for(var D in t){S[D+"Raw"]=function(e){return function(i){return"number"==typeof i&&(i=Array.prototype.slice.call(arguments)),t[e](i)}}(D);var C=/(\w+)2(\w+)/.exec(D),P=C[1],T=C[2];(S[P]=S[P]||{})[T]=S[D]=function(e){return function(i){"number"==typeof i&&(i=Array.prototype.slice.call(arguments));var n=t[e](i);if("string"==typeof n||void 0===n)return n;for(var a=0;a<n.length;a++)n[a]=Math.round(n[a]);return n}}(D)}var O=function(){this.convs={}};O.prototype.routeSpace=function(t,e){var i=e[0];return void 0===i?this.getValues(t):("number"==typeof i&&(i=Array.prototype.slice.call(e)),this.setValues(t,i))},O.prototype.setValues=function(t,e){return this.space=t,this.convs={},this.convs[t]=e,this},O.prototype.getValues=function(t){var e=this.convs[t];if(!e){var i=this.space,n=this.convs[i];e=S[i][t](n),this.convs[t]=e}return e},["rgb","hsl","hsv","cmyk","keyword"].forEach(function(t){O.prototype[t]=function(e){return this.routeSpace(t,arguments)}});var I=S,A={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},F={getRgba:R,getHsla:L,getRgb:function(t){var e=R(t);return e&&e.slice(0,3)},getHsl:function(t){var e=L(t);return e&&e.slice(0,3)},getHwb:W,getAlpha:function(t){var e=R(t);if(e)return e[3];if(e=L(t))return e[3];if(e=W(t))return e[3]},hexString:function(t,e){var e=void 0!==e&&3===t.length?e:t[3];return"#"+H(t[0])+H(t[1])+H(t[2])+(e>=0&&e<1?H(Math.round(255*e)):"")},rgbString:function(t,e){if(e<1||t[3]&&t[3]<1)return Y(t,e);return"rgb("+t[0]+", "+t[1]+", "+t[2]+")"},rgbaString:Y,percentString:function(t,e){if(e<1||t[3]&&t[3]<1)return N(t,e);var i=Math.round(t[0]/255*100),n=Math.round(t[1]/255*100),a=Math.round(t[2]/255*100);return"rgb("+i+"%, "+n+"%, "+a+"%)"},percentaString:N,hslString:function(t,e){if(e<1||t[3]&&t[3]<1)return z(t,e);return"hsl("+t[0]+", "+t[1]+"%, "+t[2]+"%)"},hslaString:z,hwbString:function(t,e){void 0===e&&(e=void 0!==t[3]?t[3]:1);return"hwb("+t[0]+", "+t[1]+"%, "+t[2]+"%"+(void 0!==e&&1!==e?", "+e:"")+")"},keyword:function(t){return E[t.slice(0,3)]}};function R(t){if(t){var e=[0,0,0],i=1,n=t.match(/^#([a-fA-F0-9]{3,4})$/i),a="";if(n){a=(n=n[1])[3];for(var r=0;r<e.length;r++)e[r]=parseInt(n[r]+n[r],16);a&&(i=Math.round(parseInt(a+a,16)/255*100)/100)}else if(n=t.match(/^#([a-fA-F0-9]{6}([a-fA-F0-9]{2})?)$/i)){a=n[2],n=n[1];for(r=0;r<e.length;r++)e[r]=parseInt(n.slice(2*r,2*r+2),16);a&&(i=Math.round(parseInt(a,16)/255*100)/100)}else if(n=t.match(/^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i)){for(r=0;r<e.length;r++)e[r]=parseInt(n[r+1]);i=parseFloat(n[4])}else if(n=t.match(/^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i)){for(r=0;r<e.length;r++)e[r]=Math.round(2.55*parseFloat(n[r+1]));i=parseFloat(n[4])}else if(n=t.match(/(\w+)/)){if("transparent"==n[1])return[0,0,0,0];if(!(e=A[n[1]]))return}for(r=0;r<e.length;r++)e[r]=V(e[r],0,255);return i=i||0==i?V(i,0,1):1,e[3]=i,e}}function L(t){if(t){var e=t.match(/^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/);if(e){var i=parseFloat(e[4]);return[V(parseInt(e[1]),0,360),V(parseFloat(e[2]),0,100),V(parseFloat(e[3]),0,100),V(isNaN(i)?1:i,0,1)]}}}function W(t){if(t){var e=t.match(/^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/);if(e){var i=parseFloat(e[4]);return[V(parseInt(e[1]),0,360),V(parseFloat(e[2]),0,100),V(parseFloat(e[3]),0,100),V(isNaN(i)?1:i,0,1)]}}}function Y(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"rgba("+t[0]+", "+t[1]+", "+t[2]+", "+e+")"}function N(t,e){return"rgba("+Math.round(t[0]/255*100)+"%, "+Math.round(t[1]/255*100)+"%, "+Math.round(t[2]/255*100)+"%, "+(e||t[3]||1)+")"}function z(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"hsla("+t[0]+", "+t[1]+"%, "+t[2]+"%, "+e+")"}function V(t,e,i){return Math.min(Math.max(e,t),i)}function H(t){var e=t.toString(16).toUpperCase();return e.length<2?"0"+e:e}var E={};for(var B in A)E[A[B]]=B;var j=function(t){return t instanceof j?t:this instanceof j?(this.valid=!1,this.values={rgb:[0,0,0],hsl:[0,0,0],hsv:[0,0,0],hwb:[0,0,0],cmyk:[0,0,0,0],alpha:1},void("string"==typeof t?(e=F.getRgba(t))?this.setValues("rgb",e):(e=F.getHsla(t))?this.setValues("hsl",e):(e=F.getHwb(t))&&this.setValues("hwb",e):"object"==typeof t&&(void 0!==(e=t).r||void 0!==e.red?this.setValues("rgb",e):void 0!==e.l||void 0!==e.lightness?this.setValues("hsl",e):void 0!==e.v||void 0!==e.value?this.setValues("hsv",e):void 0!==e.w||void 0!==e.whiteness?this.setValues("hwb",e):void 0===e.c&&void 0===e.cyan||this.setValues("cmyk",e)))):new j(t);var e};j.prototype={isValid:function(){return this.valid},rgb:function(){return this.setSpace("rgb",arguments)},hsl:function(){return this.setSpace("hsl",arguments)},hsv:function(){return this.setSpace("hsv",arguments)},hwb:function(){return this.setSpace("hwb",arguments)},cmyk:function(){return this.setSpace("cmyk",arguments)},rgbArray:function(){return this.values.rgb},hslArray:function(){return this.values.hsl},hsvArray:function(){return this.values.hsv},hwbArray:function(){var t=this.values;return 1!==t.alpha?t.hwb.concat([t.alpha]):t.hwb},cmykArray:function(){return this.values.cmyk},rgbaArray:function(){var t=this.values;return t.rgb.concat([t.alpha])},hslaArray:function(){var t=this.values;return t.hsl.concat([t.alpha])},alpha:function(t){return void 0===t?this.values.alpha:(this.setValues("alpha",t),this)},red:function(t){return this.setChannel("rgb",0,t)},green:function(t){return this.setChannel("rgb",1,t)},blue:function(t){return this.setChannel("rgb",2,t)},hue:function(t){return t&&(t=(t%=360)<0?360+t:t),this.setChannel("hsl",0,t)},saturation:function(t){return this.setChannel("hsl",1,t)},lightness:function(t){return this.setChannel("hsl",2,t)},saturationv:function(t){return this.setChannel("hsv",1,t)},whiteness:function(t){return this.setChannel("hwb",1,t)},blackness:function(t){return this.setChannel("hwb",2,t)},value:function(t){return this.setChannel("hsv",2,t)},cyan:function(t){return this.setChannel("cmyk",0,t)},magenta:function(t){return this.setChannel("cmyk",1,t)},yellow:function(t){return this.setChannel("cmyk",2,t)},black:function(t){return this.setChannel("cmyk",3,t)},hexString:function(){return F.hexString(this.values.rgb)},rgbString:function(){return F.rgbString(this.values.rgb,this.values.alpha)},rgbaString:function(){return F.rgbaString(this.values.rgb,this.values.alpha)},percentString:function(){return F.percentString(this.values.rgb,this.values.alpha)},hslString:function(){return F.hslString(this.values.hsl,this.values.alpha)},hslaString:function(){return F.hslaString(this.values.hsl,this.values.alpha)},hwbString:function(){return F.hwbString(this.values.hwb,this.values.alpha)},keyword:function(){return F.keyword(this.values.rgb,this.values.alpha)},rgbNumber:function(){var t=this.values.rgb;return t[0]<<16|t[1]<<8|t[2]},luminosity:function(){for(var t=this.values.rgb,e=[],i=0;i<t.length;i++){var n=t[i]/255;e[i]=n<=.03928?n/12.92:Math.pow((n+.055)/1.055,2.4)}return.2126*e[0]+.7152*e[1]+.0722*e[2]},contrast:function(t){var e=this.luminosity(),i=t.luminosity();return e>i?(e+.05)/(i+.05):(i+.05)/(e+.05)},level:function(t){var e=this.contrast(t);return e>=7.1?"AAA":e>=4.5?"AA":""},dark:function(){var t=this.values.rgb;return(299*t[0]+587*t[1]+114*t[2])/1e3<128},light:function(){return!this.dark()},negate:function(){for(var t=[],e=0;e<3;e++)t[e]=255-this.values.rgb[e];return this.setValues("rgb",t),this},lighten:function(t){var e=this.values.hsl;return e[2]+=e[2]*t,this.setValues("hsl",e),this},darken:function(t){var e=this.values.hsl;return e[2]-=e[2]*t,this.setValues("hsl",e),this},saturate:function(t){var e=this.values.hsl;return e[1]+=e[1]*t,this.setValues("hsl",e),this},desaturate:function(t){var e=this.values.hsl;return e[1]-=e[1]*t,this.setValues("hsl",e),this},whiten:function(t){var e=this.values.hwb;return e[1]+=e[1]*t,this.setValues("hwb",e),this},blacken:function(t){var e=this.values.hwb;return e[2]+=e[2]*t,this.setValues("hwb",e),this},greyscale:function(){var t=this.values.rgb,e=.3*t[0]+.59*t[1]+.11*t[2];return this.setValues("rgb",[e,e,e]),this},clearer:function(t){var e=this.values.alpha;return this.setValues("alpha",e-e*t),this},opaquer:function(t){var e=this.values.alpha;return this.setValues("alpha",e+e*t),this},rotate:function(t){var e=this.values.hsl,i=(e[0]+t)%360;return e[0]=i<0?360+i:i,this.setValues("hsl",e),this},mix:function(t,e){var i=t,n=void 0===e?.5:e,a=2*n-1,r=this.alpha()-i.alpha(),o=((a*r==-1?a:(a+r)/(1+a*r))+1)/2,s=1-o;return this.rgb(o*this.red()+s*i.red(),o*this.green()+s*i.green(),o*this.blue()+s*i.blue()).alpha(this.alpha()*n+i.alpha()*(1-n))},toJSON:function(){return this.rgb()},clone:function(){var t,e,i=new j,n=this.values,a=i.values;for(var r in n)n.hasOwnProperty(r)&&(t=n[r],"[object Array]"===(e={}.toString.call(t))?a[r]=t.slice(0):"[object Number]"===e?a[r]=t:console.error("unexpected color value:",t));return i}},j.prototype.spaces={rgb:["red","green","blue"],hsl:["hue","saturation","lightness"],hsv:["hue","saturation","value"],hwb:["hue","whiteness","blackness"],cmyk:["cyan","magenta","yellow","black"]},j.prototype.maxes={rgb:[255,255,255],hsl:[360,100,100],hsv:[360,100,100],hwb:[360,100,100],cmyk:[100,100,100,100]},j.prototype.getValues=function(t){for(var e=this.values,i={},n=0;n<t.length;n++)i[t.charAt(n)]=e[t][n];return 1!==e.alpha&&(i.a=e.alpha),i},j.prototype.setValues=function(t,e){var i,n,a=this.values,r=this.spaces,o=this.maxes,s=1;if(this.valid=!0,"alpha"===t)s=e;else if(e.length)a[t]=e.slice(0,t.length),s=e[t.length];else if(void 0!==e[t.charAt(0)]){for(i=0;i<t.length;i++)a[t][i]=e[t.charAt(i)];s=e.a}else if(void 0!==e[r[t][0]]){var l=r[t];for(i=0;i<t.length;i++)a[t][i]=e[l[i]];s=e.alpha}if(a.alpha=Math.max(0,Math.min(1,void 0===s?a.alpha:s)),"alpha"===t)return!1;for(i=0;i<t.length;i++)n=Math.max(0,Math.min(o[t][i],a[t][i])),a[t][i]=Math.round(n);for(var u in r)u!==t&&(a[u]=I[t][u](a[t]));return!0},j.prototype.setSpace=function(t,e){var i=e[0];return void 0===i?this.getValues(t):("number"==typeof i&&(i=Array.prototype.slice.call(e)),this.setValues(t,i),this)},j.prototype.setChannel=function(t,e,i){var n=this.values[t];return void 0===i?n[e]:i===n[e]?this:(n[e]=i,this.setValues(t,n),this)},"undefined"!=typeof window&&(window.Color=j);var U,G=j,q={noop:function(){},uid:(U=0,function(){return U++}),isNullOrUndef:function(t){return null==t},isArray:function(t){if(Array.isArray&&Array.isArray(t))return!0;var e=Object.prototype.toString.call(t);return"[object"===e.substr(0,7)&&"Array]"===e.substr(-6)},isObject:function(t){return null!==t&&"[object Object]"===Object.prototype.toString.call(t)},isFinite:function(t){return("number"==typeof t||t instanceof Number)&&isFinite(t)},valueOrDefault:function(t,e){return void 0===t?e:t},valueAtIndexOrDefault:function(t,e,i){return q.valueOrDefault(q.isArray(t)?t[e]:t,i)},callback:function(t,e,i){if(t&&"function"==typeof t.call)return t.apply(i,e)},each:function(t,e,i,n){var a,r,o;if(q.isArray(t))if(r=t.length,n)for(a=r-1;a>=0;a--)e.call(i,t[a],a);else for(a=0;a<r;a++)e.call(i,t[a],a);else if(q.isObject(t))for(r=(o=Object.keys(t)).length,a=0;a<r;a++)e.call(i,t[o[a]],o[a])},arrayEquals:function(t,e){var i,n,a,r;if(!t||!e||t.length!==e.length)return!1;for(i=0,n=t.length;i<n;++i)if(a=t[i],r=e[i],a instanceof Array&&r instanceof Array){if(!q.arrayEquals(a,r))return!1}else if(a!==r)return!1;return!0},clone:function(t){if(q.isArray(t))return t.map(q.clone);if(q.isObject(t)){for(var e={},i=Object.keys(t),n=i.length,a=0;a<n;++a)e[i[a]]=q.clone(t[i[a]]);return e}return t},_merger:function(t,e,i,n){var a=e[t],r=i[t];q.isObject(a)&&q.isObject(r)?q.merge(a,r,n):e[t]=q.clone(r)},_mergerIf:function(t,e,i){var n=e[t],a=i[t];q.isObject(n)&&q.isObject(a)?q.mergeIf(n,a):e.hasOwnProperty(t)||(e[t]=q.clone(a))},merge:function(t,e,i){var n,a,r,o,s,l=q.isArray(e)?e:[e],u=l.length;if(!q.isObject(t))return t;for(n=(i=i||{}).merger||q._merger,a=0;a<u;++a)if(e=l[a],q.isObject(e))for(s=0,o=(r=Object.keys(e)).length;s<o;++s)n(r[s],t,e,i);return t},mergeIf:function(t,e){return q.merge(t,e,{merger:q._mergerIf})},extend:function(t){for(var e=function(e,i){t[i]=e},i=1,n=arguments.length;i<n;++i)q.each(arguments[i],e);return t},inherits:function(t){var e=this,i=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return e.apply(this,arguments)},n=function(){this.constructor=i};return n.prototype=e.prototype,i.prototype=new n,i.extend=q.inherits,t&&q.extend(i.prototype,t),i.__super__=e.prototype,i}},Z=q;q.callCallback=q.callback,q.indexOf=function(t,e,i){return Array.prototype.indexOf.call(t,e,i)},q.getValueOrDefault=q.valueOrDefault,q.getValueAtIndexOrDefault=q.valueAtIndexOrDefault;var $={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return(t-=1)*t*t+1},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-((t-=1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return t*t*t*t*t},easeOutQuint:function(t){return(t-=1)*t*t*t*t+1},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return 1-Math.cos(t*(Math.PI/2))},easeOutSine:function(t){return Math.sin(t*(Math.PI/2))},easeInOutSine:function(t){return-.5*(Math.cos(Math.PI*t)-1)},easeInExpo:function(t){return 0===t?0:Math.pow(2,10*(t-1))},easeOutExpo:function(t){return 1===t?1:1-Math.pow(2,-10*t)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(2-Math.pow(2,-10*--t))},easeInCirc:function(t){return t>=1?t:-(Math.sqrt(1-t*t)-1)},easeOutCirc:function(t){return Math.sqrt(1-(t-=1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var e=1.70158,i=0,n=1;return 0===t?0:1===t?1:(i||(i=.3),n<1?(n=1,e=i/4):e=i/(2*Math.PI)*Math.asin(1/n),-n*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/i))},easeOutElastic:function(t){var e=1.70158,i=0,n=1;return 0===t?0:1===t?1:(i||(i=.3),n<1?(n=1,e=i/4):e=i/(2*Math.PI)*Math.asin(1/n),n*Math.pow(2,-10*t)*Math.sin((t-e)*(2*Math.PI)/i)+1)},easeInOutElastic:function(t){var e=1.70158,i=0,n=1;return 0===t?0:2==(t/=.5)?1:(i||(i=.45),n<1?(n=1,e=i/4):e=i/(2*Math.PI)*Math.asin(1/n),t<1?n*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/i)*-.5:n*Math.pow(2,-10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/i)*.5+1)},easeInBack:function(t){var e=1.70158;return t*t*((e+1)*t-e)},easeOutBack:function(t){var e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},easeInOutBack:function(t){var e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},easeInBounce:function(t){return 1-$.easeOutBounce(1-t)},easeOutBounce:function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375},easeInOutBounce:function(t){return t<.5?.5*$.easeInBounce(2*t):.5*$.easeOutBounce(2*t-1)+.5}},X={effects:$};Z.easingEffects=$;var K=Math.PI,J=K/180,Q=2*K,tt=K/2,et=K/4,it=2*K/3,nt={clear:function(t){t.ctx.clearRect(0,0,t.width,t.height)},roundedRect:function(t,e,i,n,a,r){if(r){var o=Math.min(r,a/2,n/2),s=e+o,l=i+o,u=e+n-o,d=i+a-o;t.moveTo(e,l),s<u&&l<d?(t.arc(s,l,o,-K,-tt),t.arc(u,l,o,-tt,0),t.arc(u,d,o,0,tt),t.arc(s,d,o,tt,K)):s<u?(t.moveTo(s,i),t.arc(u,l,o,-tt,tt),t.arc(s,l,o,tt,K+tt)):l<d?(t.arc(s,l,o,-K,0),t.arc(s,d,o,0,K)):t.arc(s,l,o,-K,K),t.closePath(),t.moveTo(e,i)}else t.rect(e,i,n,a)},drawPoint:function(t,e,i,n,a,r){var o,s,l,u,d,h=(r||0)*J;if(!e||"object"!=typeof e||"[object HTMLImageElement]"!==(o=e.toString())&&"[object HTMLCanvasElement]"!==o){if(!(isNaN(i)||i<=0)){switch(t.beginPath(),e){default:t.arc(n,a,i,0,Q),t.closePath();break;case"triangle":t.moveTo(n+Math.sin(h)*i,a-Math.cos(h)*i),h+=it,t.lineTo(n+Math.sin(h)*i,a-Math.cos(h)*i),h+=it,t.lineTo(n+Math.sin(h)*i,a-Math.cos(h)*i),t.closePath();break;case"rectRounded":u=i-(d=.516*i),s=Math.cos(h+et)*u,l=Math.sin(h+et)*u,t.arc(n-s,a-l,d,h-K,h-tt),t.arc(n+l,a-s,d,h-tt,h),t.arc(n+s,a+l,d,h,h+tt),t.arc(n-l,a+s,d,h+tt,h+K),t.closePath();break;case"rect":if(!r){u=Math.SQRT1_2*i,t.rect(n-u,a-u,2*u,2*u);break}h+=et;case"rectRot":s=Math.cos(h)*i,l=Math.sin(h)*i,t.moveTo(n-s,a-l),t.lineTo(n+l,a-s),t.lineTo(n+s,a+l),t.lineTo(n-l,a+s),t.closePath();break;case"crossRot":h+=et;case"cross":s=Math.cos(h)*i,l=Math.sin(h)*i,t.moveTo(n-s,a-l),t.lineTo(n+s,a+l),t.moveTo(n+l,a-s),t.lineTo(n-l,a+s);break;case"star":s=Math.cos(h)*i,l=Math.sin(h)*i,t.moveTo(n-s,a-l),t.lineTo(n+s,a+l),t.moveTo(n+l,a-s),t.lineTo(n-l,a+s),h+=et,s=Math.cos(h)*i,l=Math.sin(h)*i,t.moveTo(n-s,a-l),t.lineTo(n+s,a+l),t.moveTo(n+l,a-s),t.lineTo(n-l,a+s);break;case"line":s=Math.cos(h)*i,l=Math.sin(h)*i,t.moveTo(n-s,a-l),t.lineTo(n+s,a+l);break;case"dash":t.moveTo(n,a),t.lineTo(n+Math.cos(h)*i,a+Math.sin(h)*i)}t.fill(),t.stroke()}}else t.drawImage(e,n-e.width/2,a-e.height/2,e.width,e.height)},_isPointInArea:function(t,e){return t.x>e.left-1e-6&&t.x<e.right+1e-6&&t.y>e.top-1e-6&&t.y<e.bottom+1e-6},clipArea:function(t,e){t.save(),t.beginPath(),t.rect(e.left,e.top,e.right-e.left,e.bottom-e.top),t.clip()},unclipArea:function(t){t.restore()},lineTo:function(t,e,i,n){var a=i.steppedLine;if(a){if("middle"===a){var r=(e.x+i.x)/2;t.lineTo(r,n?i.y:e.y),t.lineTo(r,n?e.y:i.y)}else"after"===a&&!n||"after"!==a&&n?t.lineTo(e.x,i.y):t.lineTo(i.x,e.y);t.lineTo(i.x,i.y)}else i.tension?t.bezierCurveTo(n?e.controlPointPreviousX:e.controlPointNextX,n?e.controlPointPreviousY:e.controlPointNextY,n?i.controlPointNextX:i.controlPointPreviousX,n?i.controlPointNextY:i.controlPointPreviousY,i.x,i.y):t.lineTo(i.x,i.y)}},at=nt;Z.clear=nt.clear,Z.drawRoundedRectangle=function(t){t.beginPath(),nt.roundedRect.apply(nt,arguments)};var rt={_set:function(t,e){return Z.merge(this[t]||(this[t]={}),e)}};rt._set("global",{defaultColor:"rgba(0,0,0,0.1)",defaultFontColor:"#666",defaultFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",defaultFontSize:12,defaultFontStyle:"normal",defaultLineHeight:1.2,showLines:!0});var ot=rt,st=Z.valueOrDefault;var lt={toLineHeight:function(t,e){var i=(""+t).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);if(!i||"normal"===i[1])return 1.2*e;switch(t=+i[2],i[3]){case"px":return t;case"%":t/=100}return e*t},toPadding:function(t){var e,i,n,a;return Z.isObject(t)?(e=+t.top||0,i=+t.right||0,n=+t.bottom||0,a=+t.left||0):e=i=n=a=+t||0,{top:e,right:i,bottom:n,left:a,height:e+n,width:a+i}},_parseFont:function(t){var e=ot.global,i=st(t.fontSize,e.defaultFontSize),n={family:st(t.fontFamily,e.defaultFontFamily),lineHeight:Z.options.toLineHeight(st(t.lineHeight,e.defaultLineHeight),i),size:i,style:st(t.fontStyle,e.defaultFontStyle),weight:null,string:""};return n.string=function(t){return!t||Z.isNullOrUndef(t.size)||Z.isNullOrUndef(t.family)?null:(t.style?t.style+" ":"")+(t.weight?t.weight+" ":"")+t.size+"px "+t.family}(n),n},resolve:function(t,e,i){var n,a,r;for(n=0,a=t.length;n<a;++n)if(void 0!==(r=t[n])&&(void 0!==e&&"function"==typeof r&&(r=r(e)),void 0!==i&&Z.isArray(r)&&(r=r[i]),void 0!==r))return r}},ut=Z,dt=X,ht=at,ct=lt;ut.easing=dt,ut.canvas=ht,ut.options=ct;var ft=function(t){ut.extend(this,t),this.initialize.apply(this,arguments)};ut.extend(ft.prototype,{initialize:function(){this.hidden=!1},pivot:function(){var t=this;return t._view||(t._view=ut.clone(t._model)),t._start={},t},transition:function(t){var e=this,i=e._model,n=e._start,a=e._view;return i&&1!==t?(a||(a=e._view={}),n||(n=e._start={}),function(t,e,i,n){var a,r,o,s,l,u,d,h,c,f=Object.keys(i);for(a=0,r=f.length;a<r;++a)if(u=i[o=f[a]],e.hasOwnProperty(o)||(e[o]=u),(s=e[o])!==u&&"_"!==o[0]){if(t.hasOwnProperty(o)||(t[o]=s),(d=typeof u)==typeof(l=t[o]))if("string"===d){if((h=G(l)).valid&&(c=G(u)).valid){e[o]=c.mix(h,n).rgbString();continue}}else if(ut.isFinite(l)&&ut.isFinite(u)){e[o]=l+(u-l)*n;continue}e[o]=u}}(n,a,i,t),e):(e._view=i,e._start=null,e)},tooltipPosition:function(){return{x:this._model.x,y:this._model.y}},hasValue:function(){return ut.isNumber(this._model.x)&&ut.isNumber(this._model.y)}}),ft.extend=ut.inherits;var gt=ft,mt=gt.extend({chart:null,currentStep:0,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null}),pt=mt;Object.defineProperty(mt.prototype,"animationObject",{get:function(){return this}}),Object.defineProperty(mt.prototype,"chartInstance",{get:function(){return this.chart},set:function(t){this.chart=t}}),ot._set("global",{animation:{duration:1e3,easing:"easeOutQuart",onProgress:ut.noop,onComplete:ut.noop}});var vt={animations:[],request:null,addAnimation:function(t,e,i,n){var a,r,o=this.animations;for(e.chart=t,e.startTime=Date.now(),e.duration=i,n||(t.animating=!0),a=0,r=o.length;a<r;++a)if(o[a].chart===t)return void(o[a]=e);o.push(e),1===o.length&&this.requestAnimationFrame()},cancelAnimation:function(t){var e=ut.findIndex(this.animations,function(e){return e.chart===t});-1!==e&&(this.animations.splice(e,1),t.animating=!1)},requestAnimationFrame:function(){var t=this;null===t.request&&(t.request=ut.requestAnimFrame.call(window,function(){t.request=null,t.startDigest()}))},startDigest:function(){this.advance(),this.animations.length>0&&this.requestAnimationFrame()},advance:function(){for(var t,e,i,n,a=this.animations,r=0;r<a.length;)e=(t=a[r]).chart,i=t.numSteps,n=Math.floor((Date.now()-t.startTime)/t.duration*i)+1,t.currentStep=Math.min(n,i),ut.callback(t.render,[e,t],e),ut.callback(t.onAnimationProgress,[t],e),t.currentStep>=i?(ut.callback(t.onAnimationComplete,[t],e),e.animating=!1,a.splice(r,1)):++r}},yt=ut.options.resolve,bt=["push","pop","shift","splice","unshift"];function xt(t,e){var i=t._chartjs;if(i){var n=i.listeners,a=n.indexOf(e);-1!==a&&n.splice(a,1),n.length>0||(bt.forEach(function(e){delete t[e]}),delete t._chartjs)}}var _t=function(t,e){this.initialize(t,e)};ut.extend(_t.prototype,{datasetElementType:null,dataElementType:null,initialize:function(t,e){this.chart=t,this.index=e,this.linkScales(),this.addElements()},updateIndex:function(t){this.index=t},linkScales:function(){var t=this,e=t.getMeta(),i=t.getDataset();null!==e.xAxisID&&e.xAxisID in t.chart.scales||(e.xAxisID=i.xAxisID||t.chart.options.scales.xAxes[0].id),null!==e.yAxisID&&e.yAxisID in t.chart.scales||(e.yAxisID=i.yAxisID||t.chart.options.scales.yAxes[0].id)},getDataset:function(){return this.chart.data.datasets[this.index]},getMeta:function(){return this.chart.getDatasetMeta(this.index)},getScaleForId:function(t){return this.chart.scales[t]},_getValueScaleId:function(){return this.getMeta().yAxisID},_getIndexScaleId:function(){return this.getMeta().xAxisID},_getValueScale:function(){return this.getScaleForId(this._getValueScaleId())},_getIndexScale:function(){return this.getScaleForId(this._getIndexScaleId())},reset:function(){this.update(!0)},destroy:function(){this._data&&xt(this._data,this)},createMetaDataset:function(){var t=this.datasetElementType;return t&&new t({_chart:this.chart,_datasetIndex:this.index})},createMetaData:function(t){var e=this.dataElementType;return e&&new e({_chart:this.chart,_datasetIndex:this.index,_index:t})},addElements:function(){var t,e,i=this.getMeta(),n=this.getDataset().data||[],a=i.data;for(t=0,e=n.length;t<e;++t)a[t]=a[t]||this.createMetaData(t);i.dataset=i.dataset||this.createMetaDataset()},addElementAndReset:function(t){var e=this.createMetaData(t);this.getMeta().data.splice(t,0,e),this.updateElement(e,t,!0)},buildOrUpdateElements:function(){var t,e,i=this,n=i.getDataset(),a=n.data||(n.data=[]);i._data!==a&&(i._data&&xt(i._data,i),a&&Object.isExtensible(a)&&(e=i,(t=a)._chartjs?t._chartjs.listeners.push(e):(Object.defineProperty(t,"_chartjs",{configurable:!0,enumerable:!1,value:{listeners:[e]}}),bt.forEach(function(e){var i="onData"+e.charAt(0).toUpperCase()+e.slice(1),n=t[e];Object.defineProperty(t,e,{configurable:!0,enumerable:!1,value:function(){var e=Array.prototype.slice.call(arguments),a=n.apply(this,e);return ut.each(t._chartjs.listeners,function(t){"function"==typeof t[i]&&t[i].apply(t,e)}),a}})}))),i._data=a),i.resyncElements()},update:ut.noop,transition:function(t){for(var e=this.getMeta(),i=e.data||[],n=i.length,a=0;a<n;++a)i[a].transition(t);e.dataset&&e.dataset.transition(t)},draw:function(){var t=this.getMeta(),e=t.data||[],i=e.length,n=0;for(t.dataset&&t.dataset.draw();n<i;++n)e[n].draw()},removeHoverStyle:function(t){ut.merge(t._model,t.$previousStyle||{}),delete t.$previousStyle},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],i=t._index,n=t.custom||{},a=t._model,r=ut.getHoverColor;t.$previousStyle={backgroundColor:a.backgroundColor,borderColor:a.borderColor,borderWidth:a.borderWidth},a.backgroundColor=yt([n.hoverBackgroundColor,e.hoverBackgroundColor,r(a.backgroundColor)],void 0,i),a.borderColor=yt([n.hoverBorderColor,e.hoverBorderColor,r(a.borderColor)],void 0,i),a.borderWidth=yt([n.hoverBorderWidth,e.hoverBorderWidth,a.borderWidth],void 0,i)},resyncElements:function(){var t=this.getMeta(),e=this.getDataset().data,i=t.data.length,n=e.length;n<i?t.data.splice(n,i-n):n>i&&this.insertElements(i,n-i)},insertElements:function(t,e){for(var i=0;i<e;++i)this.addElementAndReset(t+i)},onDataPush:function(){var t=arguments.length;this.insertElements(this.getDataset().data.length-t,t)},onDataPop:function(){this.getMeta().data.pop()},onDataShift:function(){this.getMeta().data.shift()},onDataSplice:function(t,e){this.getMeta().data.splice(t,e),this.insertElements(t,arguments.length-2)},onDataUnshift:function(){this.insertElements(0,arguments.length)}}),_t.extend=ut.inherits;var kt=_t;ot._set("global",{elements:{arc:{backgroundColor:ot.global.defaultColor,borderColor:"#fff",borderWidth:2,borderAlign:"center"}}});var wt=gt.extend({inLabelRange:function(t){var e=this._view;return!!e&&Math.pow(t-e.x,2)<Math.pow(e.radius+e.hoverRadius,2)},inRange:function(t,e){var i=this._view;if(i){for(var n=ut.getAngleFromPoint(i,{x:t,y:e}),a=n.angle,r=n.distance,o=i.startAngle,s=i.endAngle;s<o;)s+=2*Math.PI;for(;a>s;)a-=2*Math.PI;for(;a<o;)a+=2*Math.PI;var l=a>=o&&a<=s,u=r>=i.innerRadius&&r<=i.outerRadius;return l&&u}return!1},getCenterPoint:function(){var t=this._view,e=(t.startAngle+t.endAngle)/2,i=(t.innerRadius+t.outerRadius)/2;return{x:t.x+Math.cos(e)*i,y:t.y+Math.sin(e)*i}},getArea:function(){var t=this._view;return Math.PI*((t.endAngle-t.startAngle)/(2*Math.PI))*(Math.pow(t.outerRadius,2)-Math.pow(t.innerRadius,2))},tooltipPosition:function(){var t=this._view,e=t.startAngle+(t.endAngle-t.startAngle)/2,i=(t.outerRadius-t.innerRadius)/2+t.innerRadius;return{x:t.x+Math.cos(e)*i,y:t.y+Math.sin(e)*i}},draw:function(){var t,e=this._chart.ctx,i=this._view,n=i.startAngle,a=i.endAngle,r="inner"===i.borderAlign?.33:0;e.save(),e.beginPath(),e.arc(i.x,i.y,Math.max(i.outerRadius-r,0),n,a),e.arc(i.x,i.y,i.innerRadius,a,n,!0),e.closePath(),e.fillStyle=i.backgroundColor,e.fill(),i.borderWidth&&("inner"===i.borderAlign?(e.beginPath(),t=r/i.outerRadius,e.arc(i.x,i.y,i.outerRadius,n-t,a+t),i.innerRadius>r?(t=r/i.innerRadius,e.arc(i.x,i.y,i.innerRadius-r,a+t,n-t,!0)):e.arc(i.x,i.y,r,a+Math.PI/2,n-Math.PI/2),e.closePath(),e.clip(),e.beginPath(),e.arc(i.x,i.y,i.outerRadius,n,a),e.arc(i.x,i.y,i.innerRadius,a,n,!0),e.closePath(),e.lineWidth=2*i.borderWidth,e.lineJoin="round"):(e.lineWidth=i.borderWidth,e.lineJoin="bevel"),e.strokeStyle=i.borderColor,e.stroke()),e.restore()}}),Mt=ut.valueOrDefault,St=ot.global.defaultColor;ot._set("global",{elements:{line:{tension:.4,backgroundColor:St,borderWidth:3,borderColor:St,borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",capBezierPoints:!0,fill:!0}}});var Dt=gt.extend({draw:function(){var t,e,i,n,a=this._view,r=this._chart.ctx,o=a.spanGaps,s=this._children.slice(),l=ot.global,u=l.elements.line,d=-1;for(this._loop&&s.length&&s.push(s[0]),r.save(),r.lineCap=a.borderCapStyle||u.borderCapStyle,r.setLineDash&&r.setLineDash(a.borderDash||u.borderDash),r.lineDashOffset=Mt(a.borderDashOffset,u.borderDashOffset),r.lineJoin=a.borderJoinStyle||u.borderJoinStyle,r.lineWidth=Mt(a.borderWidth,u.borderWidth),r.strokeStyle=a.borderColor||l.defaultColor,r.beginPath(),d=-1,t=0;t<s.length;++t)e=s[t],i=ut.previousItem(s,t),n=e._view,0===t?n.skip||(r.moveTo(n.x,n.y),d=t):(i=-1===d?i:s[d],n.skip||(d!==t-1&&!o||-1===d?r.moveTo(n.x,n.y):ut.canvas.lineTo(r,i._view,e._view),d=t));r.stroke(),r.restore()}}),Ct=ut.valueOrDefault,Pt=ot.global.defaultColor;function Tt(t){var e=this._view;return!!e&&Math.abs(t-e.x)<e.radius+e.hitRadius}ot._set("global",{elements:{point:{radius:3,pointStyle:"circle",backgroundColor:Pt,borderColor:Pt,borderWidth:1,hitRadius:1,hoverRadius:4,hoverBorderWidth:1}}});var Ot=gt.extend({inRange:function(t,e){var i=this._view;return!!i&&Math.pow(t-i.x,2)+Math.pow(e-i.y,2)<Math.pow(i.hitRadius+i.radius,2)},inLabelRange:Tt,inXRange:Tt,inYRange:function(t){var e=this._view;return!!e&&Math.abs(t-e.y)<e.radius+e.hitRadius},getCenterPoint:function(){var t=this._view;return{x:t.x,y:t.y}},getArea:function(){return Math.PI*Math.pow(this._view.radius,2)},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y,padding:t.radius+t.borderWidth}},draw:function(t){var e=this._view,i=this._chart.ctx,n=e.pointStyle,a=e.rotation,r=e.radius,o=e.x,s=e.y,l=ot.global,u=l.defaultColor;e.skip||(void 0===t||ut.canvas._isPointInArea(e,t))&&(i.strokeStyle=e.borderColor||u,i.lineWidth=Ct(e.borderWidth,l.elements.point.borderWidth),i.fillStyle=e.backgroundColor||u,ut.canvas.drawPoint(i,n,r,o,s,a))}}),It=ot.global.defaultColor;function At(t){return t&&void 0!==t.width}function Ft(t){var e,i,n,a,r;return At(t)?(r=t.width/2,e=t.x-r,i=t.x+r,n=Math.min(t.y,t.base),a=Math.max(t.y,t.base)):(r=t.height/2,e=Math.min(t.x,t.base),i=Math.max(t.x,t.base),n=t.y-r,a=t.y+r),{left:e,top:n,right:i,bottom:a}}function Rt(t,e,i){return t===e?i:t===i?e:t}function Lt(t,e,i){var n,a,r,o,s=t.borderWidth,l=function(t){var e=t.borderSkipped,i={};return e?(t.horizontal?t.base>t.x&&(e=Rt(e,"left","right")):t.base<t.y&&(e=Rt(e,"bottom","top")),i[e]=!0,i):i}(t);return ut.isObject(s)?(n=+s.top||0,a=+s.right||0,r=+s.bottom||0,o=+s.left||0):n=a=r=o=+s||0,{t:l.top||n<0?0:n>i?i:n,r:l.right||a<0?0:a>e?e:a,b:l.bottom||r<0?0:r>i?i:r,l:l.left||o<0?0:o>e?e:o}}function Wt(t,e,i){var n=null===e,a=null===i,r=!(!t||n&&a)&&Ft(t);return r&&(n||e>=r.left&&e<=r.right)&&(a||i>=r.top&&i<=r.bottom)}ot._set("global",{elements:{rectangle:{backgroundColor:It,borderColor:It,borderSkipped:"bottom",borderWidth:0}}});var Yt=gt.extend({draw:function(){var t=this._chart.ctx,e=this._view,i=function(t){var e=Ft(t),i=e.right-e.left,n=e.bottom-e.top,a=Lt(t,i/2,n/2);return{outer:{x:e.left,y:e.top,w:i,h:n},inner:{x:e.left+a.l,y:e.top+a.t,w:i-a.l-a.r,h:n-a.t-a.b}}}(e),n=i.outer,a=i.inner;t.fillStyle=e.backgroundColor,t.fillRect(n.x,n.y,n.w,n.h),n.w===a.w&&n.h===a.h||(t.save(),t.beginPath(),t.rect(n.x,n.y,n.w,n.h),t.clip(),t.fillStyle=e.borderColor,t.rect(a.x,a.y,a.w,a.h),t.fill("evenodd"),t.restore())},height:function(){var t=this._view;return t.base-t.y},inRange:function(t,e){return Wt(this._view,t,e)},inLabelRange:function(t,e){var i=this._view;return At(i)?Wt(i,t,null):Wt(i,null,e)},inXRange:function(t){return Wt(this._view,t,null)},inYRange:function(t){return Wt(this._view,null,t)},getCenterPoint:function(){var t,e,i=this._view;return At(i)?(t=i.x,e=(i.y+i.base)/2):(t=(i.x+i.base)/2,e=i.y),{x:t,y:e}},getArea:function(){var t=this._view;return At(t)?t.width*Math.abs(t.y-t.base):t.height*Math.abs(t.x-t.base)},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y}}}),Nt={},zt=wt,Vt=Dt,Ht=Ot,Et=Yt;Nt.Arc=zt,Nt.Line=Vt,Nt.Point=Ht,Nt.Rectangle=Et;var Bt=ut.options.resolve;ot._set("bar",{hover:{mode:"label"},scales:{xAxes:[{type:"category",categoryPercentage:.8,barPercentage:.9,offset:!0,gridLines:{offsetGridLines:!0}}],yAxes:[{type:"linear"}]}});var jt=kt.extend({dataElementType:Nt.Rectangle,initialize:function(){var t;kt.prototype.initialize.apply(this,arguments),(t=this.getMeta()).stack=this.getDataset().stack,t.bar=!0},update:function(t){var e,i,n=this.getMeta().data;for(this._ruler=this.getRuler(),e=0,i=n.length;e<i;++e)this.updateElement(n[e],e,t)},updateElement:function(t,e,i){var n=this,a=n.getMeta(),r=n.getDataset(),o=n._resolveElementOptions(t,e);t._xScale=n.getScaleForId(a.xAxisID),t._yScale=n.getScaleForId(a.yAxisID),t._datasetIndex=n.index,t._index=e,t._model={backgroundColor:o.backgroundColor,borderColor:o.borderColor,borderSkipped:o.borderSkipped,borderWidth:o.borderWidth,datasetLabel:r.label,label:n.chart.data.labels[e]},n._updateElementGeometry(t,e,i),t.pivot()},_updateElementGeometry:function(t,e,i){var n=this,a=t._model,r=n._getValueScale(),o=r.getBasePixel(),s=r.isHorizontal(),l=n._ruler||n.getRuler(),u=n.calculateBarValuePixels(n.index,e),d=n.calculateBarIndexPixels(n.index,e,l);a.horizontal=s,a.base=i?o:u.base,a.x=s?i?o:u.head:d.center,a.y=s?d.center:i?o:u.head,a.height=s?d.size:void 0,a.width=s?void 0:d.size},_getStacks:function(t){var e,i,n=this.chart,a=this._getIndexScale().options.stacked,r=void 0===t?n.data.datasets.length:t+1,o=[];for(e=0;e<r;++e)(i=n.getDatasetMeta(e)).bar&&n.isDatasetVisible(e)&&(!1===a||!0===a&&-1===o.indexOf(i.stack)||void 0===a&&(void 0===i.stack||-1===o.indexOf(i.stack)))&&o.push(i.stack);return o},getStackCount:function(){return this._getStacks().length},getStackIndex:function(t,e){var i=this._getStacks(t),n=void 0!==e?i.indexOf(e):-1;return-1===n?i.length-1:n},getRuler:function(){var t,e,i=this._getIndexScale(),n=this.getStackCount(),a=this.index,r=i.isHorizontal(),o=r?i.left:i.top,s=o+(r?i.width:i.height),l=[];for(t=0,e=this.getMeta().data.length;t<e;++t)l.push(i.getPixelForValue(null,t,a));return{min:ut.isNullOrUndef(i.options.barThickness)?function(t,e){var i,n,a,r,o=t.isHorizontal()?t.width:t.height,s=t.getTicks();for(a=1,r=e.length;a<r;++a)o=Math.min(o,Math.abs(e[a]-e[a-1]));for(a=0,r=s.length;a<r;++a)n=t.getPixelForTick(a),o=a>0?Math.min(o,n-i):o,i=n;return o}(i,l):-1,pixels:l,start:o,end:s,stackCount:n,scale:i}},calculateBarValuePixels:function(t,e){var i,n,a,r,o,s,l=this.chart,u=this.getMeta(),d=this._getValueScale(),h=d.isHorizontal(),c=l.data.datasets,f=+d.getRightValue(c[t].data[e]),g=d.options.minBarLength,m=d.options.stacked,p=u.stack,v=0;if(m||void 0===m&&void 0!==p)for(i=0;i<t;++i)(n=l.getDatasetMeta(i)).bar&&n.stack===p&&n.controller._getValueScaleId()===d.id&&l.isDatasetVisible(i)&&(a=+d.getRightValue(c[i].data[e]),(f<0&&a<0||f>=0&&a>0)&&(v+=a));return r=d.getPixelForValue(v),s=(o=d.getPixelForValue(v+f))-r,void 0!==g&&Math.abs(s)<g&&(s=g,o=f>=0&&!h||f<0&&h?r-g:r+g),{size:s,base:r,head:o,center:o+s/2}},calculateBarIndexPixels:function(t,e,i){var n=i.scale.options,a="flex"===n.barThickness?function(t,e,i){var n,a=e.pixels,r=a[t],o=t>0?a[t-1]:null,s=t<a.length-1?a[t+1]:null,l=i.categoryPercentage;return null===o&&(o=r-(null===s?e.end-e.start:s-r)),null===s&&(s=r+r-o),n=r-(r-Math.min(o,s))/2*l,{chunk:Math.abs(s-o)/2*l/e.stackCount,ratio:i.barPercentage,start:n}}(e,i,n):function(t,e,i){var n,a,r=i.barThickness,o=e.stackCount,s=e.pixels[t];return ut.isNullOrUndef(r)?(n=e.min*i.categoryPercentage,a=i.barPercentage):(n=r*o,a=1),{chunk:n/o,ratio:a,start:s-n/2}}(e,i,n),r=this.getStackIndex(t,this.getMeta().stack),o=a.start+a.chunk*r+a.chunk/2,s=Math.min(ut.valueOrDefault(n.maxBarThickness,1/0),a.chunk*a.ratio);return{base:o-s/2,head:o+s/2,center:o,size:s}},draw:function(){var t=this.chart,e=this._getValueScale(),i=this.getMeta().data,n=this.getDataset(),a=i.length,r=0;for(ut.canvas.clipArea(t.ctx,t.chartArea);r<a;++r)isNaN(e.getRightValue(n.data[r]))||i[r].draw();ut.canvas.unclipArea(t.ctx)},_resolveElementOptions:function(t,e){var i,n,a,r=this.chart,o=r.data.datasets[this.index],s=t.custom||{},l=r.options.elements.rectangle,u={},d={chart:r,dataIndex:e,dataset:o,datasetIndex:this.index},h=["backgroundColor","borderColor","borderSkipped","borderWidth"];for(i=0,n=h.length;i<n;++i)u[a=h[i]]=Bt([s[a],o[a],l[a]],d,e);return u}}),Ut=ut.valueOrDefault,Gt=ut.options.resolve;ot._set("bubble",{hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-0"}],yAxes:[{type:"linear",position:"left",id:"y-axis-0"}]},tooltips:{callbacks:{title:function(){return""},label:function(t,e){var i=e.datasets[t.datasetIndex].label||"",n=e.datasets[t.datasetIndex].data[t.index];return i+": ("+t.xLabel+", "+t.yLabel+", "+n.r+")"}}}});var qt=kt.extend({dataElementType:Nt.Point,update:function(t){var e=this,i=e.getMeta().data;ut.each(i,function(i,n){e.updateElement(i,n,t)})},updateElement:function(t,e,i){var n=this,a=n.getMeta(),r=t.custom||{},o=n.getScaleForId(a.xAxisID),s=n.getScaleForId(a.yAxisID),l=n._resolveElementOptions(t,e),u=n.getDataset().data[e],d=n.index,h=i?o.getPixelForDecimal(.5):o.getPixelForValue("object"==typeof u?u:NaN,e,d),c=i?s.getBasePixel():s.getPixelForValue(u,e,d);t._xScale=o,t._yScale=s,t._options=l,t._datasetIndex=d,t._index=e,t._model={backgroundColor:l.backgroundColor,borderColor:l.borderColor,borderWidth:l.borderWidth,hitRadius:l.hitRadius,pointStyle:l.pointStyle,rotation:l.rotation,radius:i?0:l.radius,skip:r.skip||isNaN(h)||isNaN(c),x:h,y:c},t.pivot()},setHoverStyle:function(t){var e=t._model,i=t._options,n=ut.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=Ut(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=Ut(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=Ut(i.hoverBorderWidth,i.borderWidth),e.radius=i.radius+i.hoverRadius},_resolveElementOptions:function(t,e){var i,n,a,r=this.chart,o=r.data.datasets[this.index],s=t.custom||{},l=r.options.elements.point,u=o.data[e],d={},h={chart:r,dataIndex:e,dataset:o,datasetIndex:this.index},c=["backgroundColor","borderColor","borderWidth","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth","hoverRadius","hitRadius","pointStyle","rotation"];for(i=0,n=c.length;i<n;++i)d[a=c[i]]=Gt([s[a],o[a],l[a]],h,e);return d.radius=Gt([s.radius,u?u.r:void 0,o.radius,l.radius],h,e),d}}),Zt=ut.options.resolve,$t=ut.valueOrDefault;ot._set("doughnut",{animation:{animateRotate:!0,animateScale:!1},hover:{mode:"single"},legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');var i=t.data,n=i.datasets,a=i.labels;if(n.length)for(var r=0;r<n[0].data.length;++r)e.push('<li><span style="background-color:'+n[0].backgroundColor[r]+'"></span>'),a[r]&&e.push(a[r]),e.push("</li>");return e.push("</ul>"),e.join("")},legend:{labels:{generateLabels:function(t){var e=t.data;return e.labels.length&&e.datasets.length?e.labels.map(function(i,n){var a=t.getDatasetMeta(0),r=e.datasets[0],o=a.data[n],s=o&&o.custom||{},l=t.options.elements.arc;return{text:i,fillStyle:Zt([s.backgroundColor,r.backgroundColor,l.backgroundColor],void 0,n),strokeStyle:Zt([s.borderColor,r.borderColor,l.borderColor],void 0,n),lineWidth:Zt([s.borderWidth,r.borderWidth,l.borderWidth],void 0,n),hidden:isNaN(r.data[n])||a.data[n].hidden,index:n}}):[]}},onClick:function(t,e){var i,n,a,r=e.index,o=this.chart;for(i=0,n=(o.data.datasets||[]).length;i<n;++i)(a=o.getDatasetMeta(i)).data[r]&&(a.data[r].hidden=!a.data[r].hidden);o.update()}},cutoutPercentage:50,rotation:-.5*Math.PI,circumference:2*Math.PI,tooltips:{callbacks:{title:function(){return""},label:function(t,e){var i=e.labels[t.index],n=": "+e.datasets[t.datasetIndex].data[t.index];return ut.isArray(i)?(i=i.slice())[0]+=n:i+=n,i}}}});var Xt=kt.extend({dataElementType:Nt.Arc,linkScales:ut.noop,getRingIndex:function(t){for(var e=0,i=0;i<t;++i)this.chart.isDatasetVisible(i)&&++e;return e},update:function(t){var e,i,n=this,a=n.chart,r=a.chartArea,o=a.options,s=r.right-r.left,l=r.bottom-r.top,u=Math.min(s,l),d={x:0,y:0},h=n.getMeta(),c=h.data,f=o.cutoutPercentage,g=o.circumference,m=n._getRingWeight(n.index);if(g<2*Math.PI){var p=o.rotation%(2*Math.PI),v=(p+=2*Math.PI*(p>=Math.PI?-1:p<-Math.PI?1:0))+g,y={x:Math.cos(p),y:Math.sin(p)},b={x:Math.cos(v),y:Math.sin(v)},x=p<=0&&v>=0||p<=2*Math.PI&&2*Math.PI<=v,_=p<=.5*Math.PI&&.5*Math.PI<=v||p<=2.5*Math.PI&&2.5*Math.PI<=v,k=p<=-Math.PI&&-Math.PI<=v||p<=Math.PI&&Math.PI<=v,w=p<=.5*-Math.PI&&.5*-Math.PI<=v||p<=1.5*Math.PI&&1.5*Math.PI<=v,M=f/100,S={x:k?-1:Math.min(y.x*(y.x<0?1:M),b.x*(b.x<0?1:M)),y:w?-1:Math.min(y.y*(y.y<0?1:M),b.y*(b.y<0?1:M))},D={x:x?1:Math.max(y.x*(y.x>0?1:M),b.x*(b.x>0?1:M)),y:_?1:Math.max(y.y*(y.y>0?1:M),b.y*(b.y>0?1:M))},C={width:.5*(D.x-S.x),height:.5*(D.y-S.y)};u=Math.min(s/C.width,l/C.height),d={x:-.5*(D.x+S.x),y:-.5*(D.y+S.y)}}for(e=0,i=c.length;e<i;++e)c[e]._options=n._resolveElementOptions(c[e],e);for(a.borderWidth=n.getMaxBorderWidth(),a.outerRadius=Math.max((u-a.borderWidth)/2,0),a.innerRadius=Math.max(f?a.outerRadius/100*f:0,0),a.radiusLength=(a.outerRadius-a.innerRadius)/(n._getVisibleDatasetWeightTotal()||1),a.offsetX=d.x*a.outerRadius,a.offsetY=d.y*a.outerRadius,h.total=n.calculateTotal(),n.outerRadius=a.outerRadius-a.radiusLength*n._getRingWeightOffset(n.index),n.innerRadius=Math.max(n.outerRadius-a.radiusLength*m,0),e=0,i=c.length;e<i;++e)n.updateElement(c[e],e,t)},updateElement:function(t,e,i){var n=this,a=n.chart,r=a.chartArea,o=a.options,s=o.animation,l=(r.left+r.right)/2,u=(r.top+r.bottom)/2,d=o.rotation,h=o.rotation,c=n.getDataset(),f=i&&s.animateRotate?0:t.hidden?0:n.calculateCircumference(c.data[e])*(o.circumference/(2*Math.PI)),g=i&&s.animateScale?0:n.innerRadius,m=i&&s.animateScale?0:n.outerRadius,p=t._options||{};ut.extend(t,{_datasetIndex:n.index,_index:e,_model:{backgroundColor:p.backgroundColor,borderColor:p.borderColor,borderWidth:p.borderWidth,borderAlign:p.borderAlign,x:l+a.offsetX,y:u+a.offsetY,startAngle:d,endAngle:h,circumference:f,outerRadius:m,innerRadius:g,label:ut.valueAtIndexOrDefault(c.label,e,a.data.labels[e])}});var v=t._model;i&&s.animateRotate||(v.startAngle=0===e?o.rotation:n.getMeta().data[e-1]._model.endAngle,v.endAngle=v.startAngle+v.circumference),t.pivot()},calculateTotal:function(){var t,e=this.getDataset(),i=this.getMeta(),n=0;return ut.each(i.data,function(i,a){t=e.data[a],isNaN(t)||i.hidden||(n+=Math.abs(t))}),n},calculateCircumference:function(t){var e=this.getMeta().total;return e>0&&!isNaN(t)?2*Math.PI*(Math.abs(t)/e):0},getMaxBorderWidth:function(t){var e,i,n,a,r,o,s,l,u=0,d=this.chart;if(!t)for(e=0,i=d.data.datasets.length;e<i;++e)if(d.isDatasetVisible(e)){t=(n=d.getDatasetMeta(e)).data,e!==this.index&&(r=n.controller);break}if(!t)return 0;for(e=0,i=t.length;e<i;++e)a=t[e],"inner"!==(o=r?r._resolveElementOptions(a,e):a._options).borderAlign&&(s=o.borderWidth,u=(l=o.hoverBorderWidth)>(u=s>u?s:u)?l:u);return u},setHoverStyle:function(t){var e=t._model,i=t._options,n=ut.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth},e.backgroundColor=$t(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=$t(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=$t(i.hoverBorderWidth,i.borderWidth)},_resolveElementOptions:function(t,e){var i,n,a,r=this.chart,o=this.getDataset(),s=t.custom||{},l=r.options.elements.arc,u={},d={chart:r,dataIndex:e,dataset:o,datasetIndex:this.index},h=["backgroundColor","borderColor","borderWidth","borderAlign","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth"];for(i=0,n=h.length;i<n;++i)u[a=h[i]]=Zt([s[a],o[a],l[a]],d,e);return u},_getRingWeightOffset:function(t){for(var e=0,i=0;i<t;++i)this.chart.isDatasetVisible(i)&&(e+=this._getRingWeight(i));return e},_getRingWeight:function(t){return Math.max($t(this.chart.data.datasets[t].weight,1),0)},_getVisibleDatasetWeightTotal:function(){return this._getRingWeightOffset(this.chart.data.datasets.length)}});ot._set("horizontalBar",{hover:{mode:"index",axis:"y"},scales:{xAxes:[{type:"linear",position:"bottom"}],yAxes:[{type:"category",position:"left",categoryPercentage:.8,barPercentage:.9,offset:!0,gridLines:{offsetGridLines:!0}}]},elements:{rectangle:{borderSkipped:"left"}},tooltips:{mode:"index",axis:"y"}});var Kt=jt.extend({_getValueScaleId:function(){return this.getMeta().xAxisID},_getIndexScaleId:function(){return this.getMeta().yAxisID}}),Jt=ut.valueOrDefault,Qt=ut.options.resolve,te=ut.canvas._isPointInArea;function ee(t,e){return Jt(t.showLine,e.showLines)}ot._set("line",{showLines:!0,spanGaps:!1,hover:{mode:"label"},scales:{xAxes:[{type:"category",id:"x-axis-0"}],yAxes:[{type:"linear",id:"y-axis-0"}]}});var ie=kt.extend({datasetElementType:Nt.Line,dataElementType:Nt.Point,update:function(t){var e,i,n=this,a=n.getMeta(),r=a.dataset,o=a.data||[],s=n.getScaleForId(a.yAxisID),l=n.getDataset(),u=ee(l,n.chart.options);for(u&&(void 0!==l.tension&&void 0===l.lineTension&&(l.lineTension=l.tension),r._scale=s,r._datasetIndex=n.index,r._children=o,r._model=n._resolveLineOptions(r),r.pivot()),e=0,i=o.length;e<i;++e)n.updateElement(o[e],e,t);for(u&&0!==r._model.tension&&n.updateBezierControlPoints(),e=0,i=o.length;e<i;++e)o[e].pivot()},updateElement:function(t,e,i){var n,a,r=this,o=r.getMeta(),s=t.custom||{},l=r.getDataset(),u=r.index,d=l.data[e],h=r.getScaleForId(o.yAxisID),c=r.getScaleForId(o.xAxisID),f=o.dataset._model,g=r._resolvePointOptions(t,e);n=c.getPixelForValue("object"==typeof d?d:NaN,e,u),a=i?h.getBasePixel():r.calculatePointY(d,e,u),t._xScale=c,t._yScale=h,t._options=g,t._datasetIndex=u,t._index=e,t._model={x:n,y:a,skip:s.skip||isNaN(n)||isNaN(a),radius:g.radius,pointStyle:g.pointStyle,rotation:g.rotation,backgroundColor:g.backgroundColor,borderColor:g.borderColor,borderWidth:g.borderWidth,tension:Jt(s.tension,f?f.tension:0),steppedLine:!!f&&f.steppedLine,hitRadius:g.hitRadius}},_resolvePointOptions:function(t,e){var i,n,a,r=this.chart,o=r.data.datasets[this.index],s=t.custom||{},l=r.options.elements.point,u={},d={chart:r,dataIndex:e,dataset:o,datasetIndex:this.index},h={backgroundColor:"pointBackgroundColor",borderColor:"pointBorderColor",borderWidth:"pointBorderWidth",hitRadius:"pointHitRadius",hoverBackgroundColor:"pointHoverBackgroundColor",hoverBorderColor:"pointHoverBorderColor",hoverBorderWidth:"pointHoverBorderWidth",hoverRadius:"pointHoverRadius",pointStyle:"pointStyle",radius:"pointRadius",rotation:"pointRotation"},c=Object.keys(h);for(i=0,n=c.length;i<n;++i)u[a=c[i]]=Qt([s[a],o[h[a]],o[a],l[a]],d,e);return u},_resolveLineOptions:function(t){var e,i,n,a=this.chart,r=a.data.datasets[this.index],o=t.custom||{},s=a.options,l=s.elements.line,u={},d=["backgroundColor","borderWidth","borderColor","borderCapStyle","borderDash","borderDashOffset","borderJoinStyle","fill","cubicInterpolationMode"];for(e=0,i=d.length;e<i;++e)u[n=d[e]]=Qt([o[n],r[n],l[n]]);return u.spanGaps=Jt(r.spanGaps,s.spanGaps),u.tension=Jt(r.lineTension,l.tension),u.steppedLine=Qt([o.steppedLine,r.steppedLine,l.stepped]),u},calculatePointY:function(t,e,i){var n,a,r,o=this.chart,s=this.getMeta(),l=this.getScaleForId(s.yAxisID),u=0,d=0;if(l.options.stacked){for(n=0;n<i;n++)if(a=o.data.datasets[n],"line"===(r=o.getDatasetMeta(n)).type&&r.yAxisID===l.id&&o.isDatasetVisible(n)){var h=Number(l.getRightValue(a.data[e]));h<0?d+=h||0:u+=h||0}var c=Number(l.getRightValue(t));return c<0?l.getPixelForValue(d+c):l.getPixelForValue(u+c)}return l.getPixelForValue(t)},updateBezierControlPoints:function(){var t,e,i,n,a=this.chart,r=this.getMeta(),o=r.dataset._model,s=a.chartArea,l=r.data||[];function u(t,e,i){return Math.max(Math.min(t,i),e)}if(o.spanGaps&&(l=l.filter(function(t){return!t._model.skip})),"monotone"===o.cubicInterpolationMode)ut.splineCurveMonotone(l);else for(t=0,e=l.length;t<e;++t)i=l[t]._model,n=ut.splineCurve(ut.previousItem(l,t)._model,i,ut.nextItem(l,t)._model,o.tension),i.controlPointPreviousX=n.previous.x,i.controlPointPreviousY=n.previous.y,i.controlPointNextX=n.next.x,i.controlPointNextY=n.next.y;if(a.options.elements.line.capBezierPoints)for(t=0,e=l.length;t<e;++t)i=l[t]._model,te(i,s)&&(t>0&&te(l[t-1]._model,s)&&(i.controlPointPreviousX=u(i.controlPointPreviousX,s.left,s.right),i.controlPointPreviousY=u(i.controlPointPreviousY,s.top,s.bottom)),t<l.length-1&&te(l[t+1]._model,s)&&(i.controlPointNextX=u(i.controlPointNextX,s.left,s.right),i.controlPointNextY=u(i.controlPointNextY,s.top,s.bottom)))},draw:function(){var t,e=this.chart,i=this.getMeta(),n=i.data||[],a=e.chartArea,r=n.length,o=0;for(ee(this.getDataset(),e.options)&&(t=(i.dataset._model.borderWidth||0)/2,ut.canvas.clipArea(e.ctx,{left:a.left,right:a.right,top:a.top-t,bottom:a.bottom+t}),i.dataset.draw(),ut.canvas.unclipArea(e.ctx));o<r;++o)n[o].draw(a)},setHoverStyle:function(t){var e=t._model,i=t._options,n=ut.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=Jt(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=Jt(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=Jt(i.hoverBorderWidth,i.borderWidth),e.radius=Jt(i.hoverRadius,i.radius)}}),ne=ut.options.resolve;ot._set("polarArea",{scale:{type:"radialLinear",angleLines:{display:!1},gridLines:{circular:!0},pointLabels:{display:!1},ticks:{beginAtZero:!0}},animation:{animateRotate:!0,animateScale:!0},startAngle:-.5*Math.PI,legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');var i=t.data,n=i.datasets,a=i.labels;if(n.length)for(var r=0;r<n[0].data.length;++r)e.push('<li><span style="background-color:'+n[0].backgroundColor[r]+'"></span>'),a[r]&&e.push(a[r]),e.push("</li>");return e.push("</ul>"),e.join("")},legend:{labels:{generateLabels:function(t){var e=t.data;return e.labels.length&&e.datasets.length?e.labels.map(function(i,n){var a=t.getDatasetMeta(0),r=e.datasets[0],o=a.data[n].custom||{},s=t.options.elements.arc;return{text:i,fillStyle:ne([o.backgroundColor,r.backgroundColor,s.backgroundColor],void 0,n),strokeStyle:ne([o.borderColor,r.borderColor,s.borderColor],void 0,n),lineWidth:ne([o.borderWidth,r.borderWidth,s.borderWidth],void 0,n),hidden:isNaN(r.data[n])||a.data[n].hidden,index:n}}):[]}},onClick:function(t,e){var i,n,a,r=e.index,o=this.chart;for(i=0,n=(o.data.datasets||[]).length;i<n;++i)(a=o.getDatasetMeta(i)).data[r].hidden=!a.data[r].hidden;o.update()}},tooltips:{callbacks:{title:function(){return""},label:function(t,e){return e.labels[t.index]+": "+t.yLabel}}}});var ae=kt.extend({dataElementType:Nt.Arc,linkScales:ut.noop,update:function(t){var e,i,n,a=this,r=a.getDataset(),o=a.getMeta(),s=a.chart.options.startAngle||0,l=a._starts=[],u=a._angles=[],d=o.data;for(a._updateRadius(),o.count=a.countVisibleElements(),e=0,i=r.data.length;e<i;e++)l[e]=s,n=a._computeAngle(e),u[e]=n,s+=n;for(e=0,i=d.length;e<i;++e)d[e]._options=a._resolveElementOptions(d[e],e),a.updateElement(d[e],e,t)},_updateRadius:function(){var t=this,e=t.chart,i=e.chartArea,n=e.options,a=Math.min(i.right-i.left,i.bottom-i.top);e.outerRadius=Math.max(a/2,0),e.innerRadius=Math.max(n.cutoutPercentage?e.outerRadius/100*n.cutoutPercentage:1,0),e.radiusLength=(e.outerRadius-e.innerRadius)/e.getVisibleDatasetCount(),t.outerRadius=e.outerRadius-e.radiusLength*t.index,t.innerRadius=t.outerRadius-e.radiusLength},updateElement:function(t,e,i){var n=this,a=n.chart,r=n.getDataset(),o=a.options,s=o.animation,l=a.scale,u=a.data.labels,d=l.xCenter,h=l.yCenter,c=o.startAngle,f=t.hidden?0:l.getDistanceFromCenterForValue(r.data[e]),g=n._starts[e],m=g+(t.hidden?0:n._angles[e]),p=s.animateScale?0:l.getDistanceFromCenterForValue(r.data[e]),v=t._options||{};ut.extend(t,{_datasetIndex:n.index,_index:e,_scale:l,_model:{backgroundColor:v.backgroundColor,borderColor:v.borderColor,borderWidth:v.borderWidth,borderAlign:v.borderAlign,x:d,y:h,innerRadius:0,outerRadius:i?p:f,startAngle:i&&s.animateRotate?c:g,endAngle:i&&s.animateRotate?c:m,label:ut.valueAtIndexOrDefault(u,e,u[e])}}),t.pivot()},countVisibleElements:function(){var t=this.getDataset(),e=this.getMeta(),i=0;return ut.each(e.data,function(e,n){isNaN(t.data[n])||e.hidden||i++}),i},setHoverStyle:function(t){var e=t._model,i=t._options,n=ut.getHoverColor,a=ut.valueOrDefault;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth},e.backgroundColor=a(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=a(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=a(i.hoverBorderWidth,i.borderWidth)},_resolveElementOptions:function(t,e){var i,n,a,r=this.chart,o=this.getDataset(),s=t.custom||{},l=r.options.elements.arc,u={},d={chart:r,dataIndex:e,dataset:o,datasetIndex:this.index},h=["backgroundColor","borderColor","borderWidth","borderAlign","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth"];for(i=0,n=h.length;i<n;++i)u[a=h[i]]=ne([s[a],o[a],l[a]],d,e);return u},_computeAngle:function(t){var e=this,i=this.getMeta().count,n=e.getDataset(),a=e.getMeta();if(isNaN(n.data[t])||a.data[t].hidden)return 0;var r={chart:e.chart,dataIndex:t,dataset:n,datasetIndex:e.index};return ne([e.chart.options.elements.arc.angle,2*Math.PI/i],r,t)}});ot._set("pie",ut.clone(ot.doughnut)),ot._set("pie",{cutoutPercentage:0});var re=Xt,oe=ut.valueOrDefault,se=ut.options.resolve;ot._set("radar",{scale:{type:"radialLinear"},elements:{line:{tension:0}}});var le=kt.extend({datasetElementType:Nt.Line,dataElementType:Nt.Point,linkScales:ut.noop,update:function(t){var e,i,n=this,a=n.getMeta(),r=a.dataset,o=a.data||[],s=n.chart.scale,l=n.getDataset();for(void 0!==l.tension&&void 0===l.lineTension&&(l.lineTension=l.tension),r._scale=s,r._datasetIndex=n.index,r._children=o,r._loop=!0,r._model=n._resolveLineOptions(r),r.pivot(),e=0,i=o.length;e<i;++e)n.updateElement(o[e],e,t);for(n.updateBezierControlPoints(),e=0,i=o.length;e<i;++e)o[e].pivot()},updateElement:function(t,e,i){var n=this,a=t.custom||{},r=n.getDataset(),o=n.chart.scale,s=o.getPointPositionForValue(e,r.data[e]),l=n._resolvePointOptions(t,e),u=n.getMeta().dataset._model,d=i?o.xCenter:s.x,h=i?o.yCenter:s.y;t._scale=o,t._options=l,t._datasetIndex=n.index,t._index=e,t._model={x:d,y:h,skip:a.skip||isNaN(d)||isNaN(h),radius:l.radius,pointStyle:l.pointStyle,rotation:l.rotation,backgroundColor:l.backgroundColor,borderColor:l.borderColor,borderWidth:l.borderWidth,tension:oe(a.tension,u?u.tension:0),hitRadius:l.hitRadius}},_resolvePointOptions:function(t,e){var i,n,a,r=this.chart,o=r.data.datasets[this.index],s=t.custom||{},l=r.options.elements.point,u={},d={chart:r,dataIndex:e,dataset:o,datasetIndex:this.index},h={backgroundColor:"pointBackgroundColor",borderColor:"pointBorderColor",borderWidth:"pointBorderWidth",hitRadius:"pointHitRadius",hoverBackgroundColor:"pointHoverBackgroundColor",hoverBorderColor:"pointHoverBorderColor",hoverBorderWidth:"pointHoverBorderWidth",hoverRadius:"pointHoverRadius",pointStyle:"pointStyle",radius:"pointRadius",rotation:"pointRotation"},c=Object.keys(h);for(i=0,n=c.length;i<n;++i)u[a=c[i]]=se([s[a],o[h[a]],o[a],l[a]],d,e);return u},_resolveLineOptions:function(t){var e,i,n,a=this.chart,r=a.data.datasets[this.index],o=t.custom||{},s=a.options.elements.line,l={},u=["backgroundColor","borderWidth","borderColor","borderCapStyle","borderDash","borderDashOffset","borderJoinStyle","fill"];for(e=0,i=u.length;e<i;++e)l[n=u[e]]=se([o[n],r[n],s[n]]);return l.tension=oe(r.lineTension,s.tension),l},updateBezierControlPoints:function(){var t,e,i,n,a=this.getMeta(),r=this.chart.chartArea,o=a.data||[];function s(t,e,i){return Math.max(Math.min(t,i),e)}for(t=0,e=o.length;t<e;++t)i=o[t]._model,n=ut.splineCurve(ut.previousItem(o,t,!0)._model,i,ut.nextItem(o,t,!0)._model,i.tension),i.controlPointPreviousX=s(n.previous.x,r.left,r.right),i.controlPointPreviousY=s(n.previous.y,r.top,r.bottom),i.controlPointNextX=s(n.next.x,r.left,r.right),i.controlPointNextY=s(n.next.y,r.top,r.bottom)},setHoverStyle:function(t){var e=t._model,i=t._options,n=ut.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=oe(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=oe(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=oe(i.hoverBorderWidth,i.borderWidth),e.radius=oe(i.hoverRadius,i.radius)}});ot._set("scatter",{hover:{mode:"single"},scales:{xAxes:[{id:"x-axis-1",type:"linear",position:"bottom"}],yAxes:[{id:"y-axis-1",type:"linear",position:"left"}]},showLines:!1,tooltips:{callbacks:{title:function(){return""},label:function(t){return"("+t.xLabel+", "+t.yLabel+")"}}}});var ue={bar:jt,bubble:qt,doughnut:Xt,horizontalBar:Kt,line:ie,polarArea:ae,pie:re,radar:le,scatter:ie};function de(t,e){return t.native?{x:t.x,y:t.y}:ut.getRelativePosition(t,e)}function he(t,e){var i,n,a,r,o;for(n=0,r=t.data.datasets.length;n<r;++n)if(t.isDatasetVisible(n))for(a=0,o=(i=t.getDatasetMeta(n)).data.length;a<o;++a){var s=i.data[a];s._view.skip||e(s)}}function ce(t,e){var i=[];return he(t,function(t){t.inRange(e.x,e.y)&&i.push(t)}),i}function fe(t,e,i,n){var a=Number.POSITIVE_INFINITY,r=[];return he(t,function(t){if(!i||t.inRange(e.x,e.y)){var o=t.getCenterPoint(),s=n(e,o);s<a?(r=[t],a=s):s===a&&r.push(t)}}),r}function ge(t){var e=-1!==t.indexOf("x"),i=-1!==t.indexOf("y");return function(t,n){var a=e?Math.abs(t.x-n.x):0,r=i?Math.abs(t.y-n.y):0;return Math.sqrt(Math.pow(a,2)+Math.pow(r,2))}}function me(t,e,i){var n=de(e,t);i.axis=i.axis||"x";var a=ge(i.axis),r=i.intersect?ce(t,n):fe(t,n,!1,a),o=[];return r.length?(t.data.datasets.forEach(function(e,i){if(t.isDatasetVisible(i)){var n=t.getDatasetMeta(i).data[r[0]._index];n&&!n._view.skip&&o.push(n)}}),o):[]}var pe={modes:{single:function(t,e){var i=de(e,t),n=[];return he(t,function(t){if(t.inRange(i.x,i.y))return n.push(t),n}),n.slice(0,1)},label:me,index:me,dataset:function(t,e,i){var n=de(e,t);i.axis=i.axis||"xy";var a=ge(i.axis),r=i.intersect?ce(t,n):fe(t,n,!1,a);return r.length>0&&(r=t.getDatasetMeta(r[0]._datasetIndex).data),r},"x-axis":function(t,e){return me(t,e,{intersect:!1})},point:function(t,e){return ce(t,de(e,t))},nearest:function(t,e,i){var n=de(e,t);i.axis=i.axis||"xy";var a=ge(i.axis);return fe(t,n,i.intersect,a)},x:function(t,e,i){var n=de(e,t),a=[],r=!1;return he(t,function(t){t.inXRange(n.x)&&a.push(t),t.inRange(n.x,n.y)&&(r=!0)}),i.intersect&&!r&&(a=[]),a},y:function(t,e,i){var n=de(e,t),a=[],r=!1;return he(t,function(t){t.inYRange(n.y)&&a.push(t),t.inRange(n.x,n.y)&&(r=!0)}),i.intersect&&!r&&(a=[]),a}}};function ve(t,e){return ut.where(t,function(t){return t.position===e})}function ye(t,e){t.forEach(function(t,e){return t._tmpIndex_=e,t}),t.sort(function(t,i){var n=e?i:t,a=e?t:i;return n.weight===a.weight?n._tmpIndex_-a._tmpIndex_:n.weight-a.weight}),t.forEach(function(t){delete t._tmpIndex_})}function be(t,e){ut.each(t,function(t){e[t.position]+=t.isHorizontal()?t.height:t.width})}ot._set("global",{layout:{padding:{top:0,right:0,bottom:0,left:0}}});var xe={defaults:{},addBox:function(t,e){t.boxes||(t.boxes=[]),e.fullWidth=e.fullWidth||!1,e.position=e.position||"top",e.weight=e.weight||0,t.boxes.push(e)},removeBox:function(t,e){var i=t.boxes?t.boxes.indexOf(e):-1;-1!==i&&t.boxes.splice(i,1)},configure:function(t,e,i){for(var n,a=["fullWidth","position","weight"],r=a.length,o=0;o<r;++o)n=a[o],i.hasOwnProperty(n)&&(e[n]=i[n])},update:function(t,e,i){if(t){var n=t.options.layout||{},a=ut.options.toPadding(n.padding),r=a.left,o=a.right,s=a.top,l=a.bottom,u=ve(t.boxes,"left"),d=ve(t.boxes,"right"),h=ve(t.boxes,"top"),c=ve(t.boxes,"bottom"),f=ve(t.boxes,"chartArea");ye(u,!0),ye(d,!1),ye(h,!0),ye(c,!1);var g,m=u.concat(d),p=h.concat(c),v=m.concat(p),y=e-r-o,b=i-s-l,x=(e-y/2)/m.length,_=y,k=b,w={top:s,left:r,bottom:l,right:o},M=[];ut.each(v,function(t){var e,i=t.isHorizontal();i?(e=t.update(t.fullWidth?y:_,b/2),k-=e.height):(e=t.update(x,k),_-=e.width),M.push({horizontal:i,width:e.width,box:t})}),g=function(t){var e=0,i=0,n=0,a=0;return ut.each(t,function(t){if(t.getPadding){var r=t.getPadding();e=Math.max(e,r.top),i=Math.max(i,r.left),n=Math.max(n,r.bottom),a=Math.max(a,r.right)}}),{top:e,left:i,bottom:n,right:a}}(v),ut.each(m,I),be(m,w),ut.each(p,I),be(p,w),ut.each(m,function(t){var e=ut.findNextWhere(M,function(e){return e.box===t}),i={left:0,right:0,top:w.top,bottom:w.bottom};e&&t.update(e.width,k,i)}),be(v,w={top:s,left:r,bottom:l,right:o});var S=Math.max(g.left-w.left,0);w.left+=S,w.right+=Math.max(g.right-w.right,0);var D=Math.max(g.top-w.top,0);w.top+=D,w.bottom+=Math.max(g.bottom-w.bottom,0);var C=i-w.top-w.bottom,P=e-w.left-w.right;P===_&&C===k||(ut.each(m,function(t){t.height=C}),ut.each(p,function(t){t.fullWidth||(t.width=P)}),k=C,_=P);var T=r+S,O=s+D;ut.each(u.concat(h),A),T+=_,O+=k,ut.each(d,A),ut.each(c,A),t.chartArea={left:w.left,top:w.top,right:w.left+_,bottom:w.top+k},ut.each(f,function(e){e.left=t.chartArea.left,e.top=t.chartArea.top,e.right=t.chartArea.right,e.bottom=t.chartArea.bottom,e.update(_,k)})}function I(t){var e=ut.findNextWhere(M,function(e){return e.box===t});if(e)if(e.horizontal){var i={left:Math.max(w.left,g.left),right:Math.max(w.right,g.right),top:0,bottom:0};t.update(t.fullWidth?y:_,b/2,i)}else t.update(e.width,k)}function A(t){t.isHorizontal()?(t.left=t.fullWidth?r:w.left,t.right=t.fullWidth?e-o:w.left+_,t.top=O,t.bottom=O+t.height,O=t.bottom):(t.left=T,t.right=T+t.width,t.top=w.top,t.bottom=w.top+k,T=t.right)}}};"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self&&self;function _e(){throw new Error("Dynamic requires are not currently supported by rollup-plugin-commonjs")}var ke,we=(ke=Object.freeze({default:"@keyframes chartjs-render-animation{from{opacity:.99}to{opacity:1}}.chartjs-render-monitor{animation:chartjs-render-animation 1ms}.chartjs-size-monitor,.chartjs-size-monitor-expand,.chartjs-size-monitor-shrink{position:absolute;direction:ltr;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1}.chartjs-size-monitor-expand>div{position:absolute;width:1000000px;height:1000000px;left:0;top:0}.chartjs-size-monitor-shrink>div{position:absolute;width:200%;height:200%;left:0;top:0}"}))&&ke.default||ke,Me="$chartjs",Se="chartjs-size-monitor",De="chartjs-render-monitor",Ce="chartjs-render-animation",Pe=["animationstart","webkitAnimationStart"],Te={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"};function Oe(t,e){var i=ut.getStyle(t,e),n=i&&i.match(/^(\d+)(\.\d+)?px$/);return n?Number(n[1]):void 0}var Ie=!!function(){var t=!1;try{var e=Object.defineProperty({},"passive",{get:function(){t=!0}});window.addEventListener("e",null,e)}catch(t){}return t}()&&{passive:!0};function Ae(t,e,i){t.addEventListener(e,i,Ie)}function Fe(t,e,i){t.removeEventListener(e,i,Ie)}function Re(t,e,i,n,a){return{type:t,chart:e,native:a||null,x:void 0!==i?i:null,y:void 0!==n?n:null}}function Le(t){var e=document.createElement("div");return e.className=t||"",e}function We(t,e,i){var n,a,r,o,s=t[Me]||(t[Me]={}),l=s.resizer=function(t){var e=Le(Se),i=Le(Se+"-expand"),n=Le(Se+"-shrink");i.appendChild(Le()),n.appendChild(Le()),e.appendChild(i),e.appendChild(n),e._reset=function(){i.scrollLeft=1e6,i.scrollTop=1e6,n.scrollLeft=1e6,n.scrollTop=1e6};var a=function(){e._reset(),t()};return Ae(i,"scroll",a.bind(i,"expand")),Ae(n,"scroll",a.bind(n,"shrink")),e}((n=function(){if(s.resizer){var n=i.options.maintainAspectRatio&&t.parentNode,a=n?n.clientWidth:0;e(Re("resize",i)),n&&n.clientWidth<a&&i.canvas&&e(Re("resize",i))}},r=!1,o=[],function(){o=Array.prototype.slice.call(arguments),a=a||this,r||(r=!0,ut.requestAnimFrame.call(window,function(){r=!1,n.apply(a,o)}))}));!function(t,e){var i=t[Me]||(t[Me]={}),n=i.renderProxy=function(t){t.animationName===Ce&&e()};ut.each(Pe,function(e){Ae(t,e,n)}),i.reflow=!!t.offsetParent,t.classList.add(De)}(t,function(){if(s.resizer){var e=t.parentNode;e&&e!==l.parentNode&&e.insertBefore(l,e.firstChild),l._reset()}})}function Ye(t){var e=t[Me]||{},i=e.resizer;delete e.resizer,function(t){var e=t[Me]||{},i=e.renderProxy;i&&(ut.each(Pe,function(e){Fe(t,e,i)}),delete e.renderProxy),t.classList.remove(De)}(t),i&&i.parentNode&&i.parentNode.removeChild(i)}var Ne={disableCSSInjection:!1,_enabled:"undefined"!=typeof window&&"undefined"!=typeof document,_ensureLoaded:function(){var t,e,i;this._loaded||(this._loaded=!0,this.disableCSSInjection||(e=we,i=(t=this)._style||document.createElement("style"),t._style||(t._style=i,e="/* Chart.js */\n"+e,i.setAttribute("type","text/css"),document.getElementsByTagName("head")[0].appendChild(i)),i.appendChild(document.createTextNode(e))))},acquireContext:function(t,e){"string"==typeof t?t=document.getElementById(t):t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas);var i=t&&t.getContext&&t.getContext("2d");return this._ensureLoaded(),i&&i.canvas===t?(function(t,e){var i=t.style,n=t.getAttribute("height"),a=t.getAttribute("width");if(t[Me]={initial:{height:n,width:a,style:{display:i.display,height:i.height,width:i.width}}},i.display=i.display||"block",null===a||""===a){var r=Oe(t,"width");void 0!==r&&(t.width=r)}if(null===n||""===n)if(""===t.style.height)t.height=t.width/(e.options.aspectRatio||2);else{var o=Oe(t,"height");void 0!==r&&(t.height=o)}}(t,e),i):null},releaseContext:function(t){var e=t.canvas;if(e[Me]){var i=e[Me].initial;["height","width"].forEach(function(t){var n=i[t];ut.isNullOrUndef(n)?e.removeAttribute(t):e.setAttribute(t,n)}),ut.each(i.style||{},function(t,i){e.style[i]=t}),e.width=e.width,delete e[Me]}},addEventListener:function(t,e,i){var n=t.canvas;if("resize"!==e){var a=i[Me]||(i[Me]={});Ae(n,e,(a.proxies||(a.proxies={}))[t.id+"_"+e]=function(e){i(function(t,e){var i=Te[t.type]||t.type,n=ut.getRelativePosition(t,e);return Re(i,e,n.x,n.y,t)}(e,t))})}else We(n,i,t)},removeEventListener:function(t,e,i){var n=t.canvas;if("resize"!==e){var a=((i[Me]||{}).proxies||{})[t.id+"_"+e];a&&Fe(n,e,a)}else Ye(n)}};ut.addEvent=Ae,ut.removeEvent=Fe;var ze=Ne._enabled?Ne:{acquireContext:function(t){return t&&t.canvas&&(t=t.canvas),t&&t.getContext("2d")||null}},Ve=ut.extend({initialize:function(){},acquireContext:function(){},releaseContext:function(){},addEventListener:function(){},removeEventListener:function(){}},ze);ot._set("global",{plugins:{}});var He={_plugins:[],_cacheId:0,register:function(t){var e=this._plugins;[].concat(t).forEach(function(t){-1===e.indexOf(t)&&e.push(t)}),this._cacheId++},unregister:function(t){var e=this._plugins;[].concat(t).forEach(function(t){var i=e.indexOf(t);-1!==i&&e.splice(i,1)}),this._cacheId++},clear:function(){this._plugins=[],this._cacheId++},count:function(){return this._plugins.length},getAll:function(){return this._plugins},notify:function(t,e,i){var n,a,r,o,s,l=this.descriptors(t),u=l.length;for(n=0;n<u;++n)if("function"==typeof(s=(r=(a=l[n]).plugin)[e])&&((o=[t].concat(i||[])).push(a.options),!1===s.apply(r,o)))return!1;return!0},descriptors:function(t){var e=t.$plugins||(t.$plugins={});if(e.id===this._cacheId)return e.descriptors;var i=[],n=[],a=t&&t.config||{},r=a.options&&a.options.plugins||{};return this._plugins.concat(a.plugins||[]).forEach(function(t){if(-1===i.indexOf(t)){var e=t.id,a=r[e];!1!==a&&(!0===a&&(a=ut.clone(ot.global.plugins[e])),i.push(t),n.push({plugin:t,options:a||{}}))}}),e.descriptors=n,e.id=this._cacheId,n},_invalidate:function(t){delete t.$plugins}},Ee={constructors:{},defaults:{},registerScaleType:function(t,e,i){this.constructors[t]=e,this.defaults[t]=ut.clone(i)},getScaleConstructor:function(t){return this.constructors.hasOwnProperty(t)?this.constructors[t]:void 0},getScaleDefaults:function(t){return this.defaults.hasOwnProperty(t)?ut.merge({},[ot.scale,this.defaults[t]]):{}},updateScaleDefaults:function(t,e){this.defaults.hasOwnProperty(t)&&(this.defaults[t]=ut.extend(this.defaults[t],e))},addScalesToLayout:function(t){ut.each(t.scales,function(e){e.fullWidth=e.options.fullWidth,e.position=e.options.position,e.weight=e.options.weight,xe.addBox(t,e)})}},Be=ut.valueOrDefault;ot._set("global",{tooltips:{enabled:!0,custom:null,mode:"nearest",position:"average",intersect:!0,backgroundColor:"rgba(0,0,0,0.8)",titleFontStyle:"bold",titleSpacing:2,titleMarginBottom:6,titleFontColor:"#fff",titleAlign:"left",bodySpacing:2,bodyFontColor:"#fff",bodyAlign:"left",footerFontStyle:"bold",footerSpacing:2,footerMarginTop:6,footerFontColor:"#fff",footerAlign:"left",yPadding:6,xPadding:6,caretPadding:2,caretSize:5,cornerRadius:6,multiKeyBackground:"#fff",displayColors:!0,borderColor:"rgba(0,0,0,0)",borderWidth:0,callbacks:{beforeTitle:ut.noop,title:function(t,e){var i="",n=e.labels,a=n?n.length:0;if(t.length>0){var r=t[0];r.label?i=r.label:r.xLabel?i=r.xLabel:a>0&&r.index<a&&(i=n[r.index])}return i},afterTitle:ut.noop,beforeBody:ut.noop,beforeLabel:ut.noop,label:function(t,e){var i=e.datasets[t.datasetIndex].label||"";return i&&(i+=": "),ut.isNullOrUndef(t.value)?i+=t.yLabel:i+=t.value,i},labelColor:function(t,e){var i=e.getDatasetMeta(t.datasetIndex).data[t.index]._view;return{borderColor:i.borderColor,backgroundColor:i.backgroundColor}},labelTextColor:function(){return this._options.bodyFontColor},afterLabel:ut.noop,afterBody:ut.noop,beforeFooter:ut.noop,footer:ut.noop,afterFooter:ut.noop}}});var je={average:function(t){if(!t.length)return!1;var e,i,n=0,a=0,r=0;for(e=0,i=t.length;e<i;++e){var o=t[e];if(o&&o.hasValue()){var s=o.tooltipPosition();n+=s.x,a+=s.y,++r}}return{x:n/r,y:a/r}},nearest:function(t,e){var i,n,a,r=e.x,o=e.y,s=Number.POSITIVE_INFINITY;for(i=0,n=t.length;i<n;++i){var l=t[i];if(l&&l.hasValue()){var u=l.getCenterPoint(),d=ut.distanceBetweenPoints(e,u);d<s&&(s=d,a=l)}}if(a){var h=a.tooltipPosition();r=h.x,o=h.y}return{x:r,y:o}}};function Ue(t,e){return e&&(ut.isArray(e)?Array.prototype.push.apply(t,e):t.push(e)),t}function Ge(t){return("string"==typeof t||t instanceof String)&&t.indexOf("\n")>-1?t.split("\n"):t}function qe(t){var e=ot.global;return{xPadding:t.xPadding,yPadding:t.yPadding,xAlign:t.xAlign,yAlign:t.yAlign,bodyFontColor:t.bodyFontColor,_bodyFontFamily:Be(t.bodyFontFamily,e.defaultFontFamily),_bodyFontStyle:Be(t.bodyFontStyle,e.defaultFontStyle),_bodyAlign:t.bodyAlign,bodyFontSize:Be(t.bodyFontSize,e.defaultFontSize),bodySpacing:t.bodySpacing,titleFontColor:t.titleFontColor,_titleFontFamily:Be(t.titleFontFamily,e.defaultFontFamily),_titleFontStyle:Be(t.titleFontStyle,e.defaultFontStyle),titleFontSize:Be(t.titleFontSize,e.defaultFontSize),_titleAlign:t.titleAlign,titleSpacing:t.titleSpacing,titleMarginBottom:t.titleMarginBottom,footerFontColor:t.footerFontColor,_footerFontFamily:Be(t.footerFontFamily,e.defaultFontFamily),_footerFontStyle:Be(t.footerFontStyle,e.defaultFontStyle),footerFontSize:Be(t.footerFontSize,e.defaultFontSize),_footerAlign:t.footerAlign,footerSpacing:t.footerSpacing,footerMarginTop:t.footerMarginTop,caretSize:t.caretSize,cornerRadius:t.cornerRadius,backgroundColor:t.backgroundColor,opacity:0,legendColorBackground:t.multiKeyBackground,displayColors:t.displayColors,borderColor:t.borderColor,borderWidth:t.borderWidth}}function Ze(t,e){return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-t.xPadding:t.x+t.xPadding}function $e(t){return Ue([],Ge(t))}var Xe=gt.extend({initialize:function(){this._model=qe(this._options),this._lastActive=[]},getTitle:function(){var t=this._options.callbacks,e=t.beforeTitle.apply(this,arguments),i=t.title.apply(this,arguments),n=t.afterTitle.apply(this,arguments),a=[];return a=Ue(a,Ge(e)),a=Ue(a,Ge(i)),a=Ue(a,Ge(n))},getBeforeBody:function(){return $e(this._options.callbacks.beforeBody.apply(this,arguments))},getBody:function(t,e){var i=this,n=i._options.callbacks,a=[];return ut.each(t,function(t){var r={before:[],lines:[],after:[]};Ue(r.before,Ge(n.beforeLabel.call(i,t,e))),Ue(r.lines,n.label.call(i,t,e)),Ue(r.after,Ge(n.afterLabel.call(i,t,e))),a.push(r)}),a},getAfterBody:function(){return $e(this._options.callbacks.afterBody.apply(this,arguments))},getFooter:function(){var t=this._options.callbacks,e=t.beforeFooter.apply(this,arguments),i=t.footer.apply(this,arguments),n=t.afterFooter.apply(this,arguments),a=[];return a=Ue(a,Ge(e)),a=Ue(a,Ge(i)),a=Ue(a,Ge(n))},update:function(t){var e,i,n,a,r,o,s,l,u,d,h=this,c=h._options,f=h._model,g=h._model=qe(c),m=h._active,p=h._data,v={xAlign:f.xAlign,yAlign:f.yAlign},y={x:f.x,y:f.y},b={width:f.width,height:f.height},x={x:f.caretX,y:f.caretY};if(m.length){g.opacity=1;var _=[],k=[];x=je[c.position].call(h,m,h._eventPosition);var w=[];for(e=0,i=m.length;e<i;++e)w.push((n=m[e],a=void 0,r=void 0,o=void 0,s=void 0,l=void 0,u=void 0,d=void 0,a=n._xScale,r=n._yScale||n._scale,o=n._index,s=n._datasetIndex,l=n._chart.getDatasetMeta(s).controller,u=l._getIndexScale(),d=l._getValueScale(),{xLabel:a?a.getLabelForIndex(o,s):"",yLabel:r?r.getLabelForIndex(o,s):"",label:u?""+u.getLabelForIndex(o,s):"",value:d?""+d.getLabelForIndex(o,s):"",index:o,datasetIndex:s,x:n._model.x,y:n._model.y}));c.filter&&(w=w.filter(function(t){return c.filter(t,p)})),c.itemSort&&(w=w.sort(function(t,e){return c.itemSort(t,e,p)})),ut.each(w,function(t){_.push(c.callbacks.labelColor.call(h,t,h._chart)),k.push(c.callbacks.labelTextColor.call(h,t,h._chart))}),g.title=h.getTitle(w,p),g.beforeBody=h.getBeforeBody(w,p),g.body=h.getBody(w,p),g.afterBody=h.getAfterBody(w,p),g.footer=h.getFooter(w,p),g.x=x.x,g.y=x.y,g.caretPadding=c.caretPadding,g.labelColors=_,g.labelTextColors=k,g.dataPoints=w,b=function(t,e){var i=t._chart.ctx,n=2*e.yPadding,a=0,r=e.body,o=r.reduce(function(t,e){return t+e.before.length+e.lines.length+e.after.length},0);o+=e.beforeBody.length+e.afterBody.length;var s=e.title.length,l=e.footer.length,u=e.titleFontSize,d=e.bodyFontSize,h=e.footerFontSize;n+=s*u,n+=s?(s-1)*e.titleSpacing:0,n+=s?e.titleMarginBottom:0,n+=o*d,n+=o?(o-1)*e.bodySpacing:0,n+=l?e.footerMarginTop:0,n+=l*h,n+=l?(l-1)*e.footerSpacing:0;var c=0,f=function(t){a=Math.max(a,i.measureText(t).width+c)};return i.font=ut.fontString(u,e._titleFontStyle,e._titleFontFamily),ut.each(e.title,f),i.font=ut.fontString(d,e._bodyFontStyle,e._bodyFontFamily),ut.each(e.beforeBody.concat(e.afterBody),f),c=e.displayColors?d+2:0,ut.each(r,function(t){ut.each(t.before,f),ut.each(t.lines,f),ut.each(t.after,f)}),c=0,i.font=ut.fontString(h,e._footerFontStyle,e._footerFontFamily),ut.each(e.footer,f),{width:a+=2*e.xPadding,height:n}}(this,g),y=function(t,e,i,n){var a=t.x,r=t.y,o=t.caretSize,s=t.caretPadding,l=t.cornerRadius,u=i.xAlign,d=i.yAlign,h=o+s,c=l+s;return"right"===u?a-=e.width:"center"===u&&((a-=e.width/2)+e.width>n.width&&(a=n.width-e.width),a<0&&(a=0)),"top"===d?r+=h:r-="bottom"===d?e.height+h:e.height/2,"center"===d?"left"===u?a+=h:"right"===u&&(a-=h):"left"===u?a-=c:"right"===u&&(a+=c),{x:a,y:r}}(g,b,v=function(t,e){var i,n,a,r,o,s=t._model,l=t._chart,u=t._chart.chartArea,d="center",h="center";s.y<e.height?h="top":s.y>l.height-e.height&&(h="bottom");var c=(u.left+u.right)/2,f=(u.top+u.bottom)/2;"center"===h?(i=function(t){return t<=c},n=function(t){return t>c}):(i=function(t){return t<=e.width/2},n=function(t){return t>=l.width-e.width/2}),a=function(t){return t+e.width+s.caretSize+s.caretPadding>l.width},r=function(t){return t-e.width-s.caretSize-s.caretPadding<0},o=function(t){return t<=f?"top":"bottom"},i(s.x)?(d="left",a(s.x)&&(d="center",h=o(s.y))):n(s.x)&&(d="right",r(s.x)&&(d="center",h=o(s.y)));var g=t._options;return{xAlign:g.xAlign?g.xAlign:d,yAlign:g.yAlign?g.yAlign:h}}(this,b),h._chart)}else g.opacity=0;return g.xAlign=v.xAlign,g.yAlign=v.yAlign,g.x=y.x,g.y=y.y,g.width=b.width,g.height=b.height,g.caretX=x.x,g.caretY=x.y,h._model=g,t&&c.custom&&c.custom.call(h,g),h},drawCaret:function(t,e){var i=this._chart.ctx,n=this._view,a=this.getCaretPosition(t,e,n);i.lineTo(a.x1,a.y1),i.lineTo(a.x2,a.y2),i.lineTo(a.x3,a.y3)},getCaretPosition:function(t,e,i){var n,a,r,o,s,l,u=i.caretSize,d=i.cornerRadius,h=i.xAlign,c=i.yAlign,f=t.x,g=t.y,m=e.width,p=e.height;if("center"===c)s=g+p/2,"left"===h?(a=(n=f)-u,r=n,o=s+u,l=s-u):(a=(n=f+m)+u,r=n,o=s-u,l=s+u);else if("left"===h?(n=(a=f+d+u)-u,r=a+u):"right"===h?(n=(a=f+m-d-u)-u,r=a+u):(n=(a=i.caretX)-u,r=a+u),"top"===c)s=(o=g)-u,l=o;else{s=(o=g+p)+u,l=o;var v=r;r=n,n=v}return{x1:n,x2:a,x3:r,y1:o,y2:s,y3:l}},drawTitle:function(t,e,i){var n=e.title;if(n.length){t.x=Ze(e,e._titleAlign),i.textAlign=e._titleAlign,i.textBaseline="top";var a,r,o=e.titleFontSize,s=e.titleSpacing;for(i.fillStyle=e.titleFontColor,i.font=ut.fontString(o,e._titleFontStyle,e._titleFontFamily),a=0,r=n.length;a<r;++a)i.fillText(n[a],t.x,t.y),t.y+=o+s,a+1===n.length&&(t.y+=e.titleMarginBottom-s)}},drawBody:function(t,e,i){var n,a=e.bodyFontSize,r=e.bodySpacing,o=e._bodyAlign,s=e.body,l=e.displayColors,u=e.labelColors,d=0,h=l?Ze(e,"left"):0;i.textAlign=o,i.textBaseline="top",i.font=ut.fontString(a,e._bodyFontStyle,e._bodyFontFamily),t.x=Ze(e,o);var c=function(e){i.fillText(e,t.x+d,t.y),t.y+=a+r};i.fillStyle=e.bodyFontColor,ut.each(e.beforeBody,c),d=l&&"right"!==o?"center"===o?a/2+1:a+2:0,ut.each(s,function(r,o){n=e.labelTextColors[o],i.fillStyle=n,ut.each(r.before,c),ut.each(r.lines,function(r){l&&(i.fillStyle=e.legendColorBackground,i.fillRect(h,t.y,a,a),i.lineWidth=1,i.strokeStyle=u[o].borderColor,i.strokeRect(h,t.y,a,a),i.fillStyle=u[o].backgroundColor,i.fillRect(h+1,t.y+1,a-2,a-2),i.fillStyle=n),c(r)}),ut.each(r.after,c)}),d=0,ut.each(e.afterBody,c),t.y-=r},drawFooter:function(t,e,i){var n=e.footer;n.length&&(t.x=Ze(e,e._footerAlign),t.y+=e.footerMarginTop,i.textAlign=e._footerAlign,i.textBaseline="top",i.fillStyle=e.footerFontColor,i.font=ut.fontString(e.footerFontSize,e._footerFontStyle,e._footerFontFamily),ut.each(n,function(n){i.fillText(n,t.x,t.y),t.y+=e.footerFontSize+e.footerSpacing}))},drawBackground:function(t,e,i,n){i.fillStyle=e.backgroundColor,i.strokeStyle=e.borderColor,i.lineWidth=e.borderWidth;var a=e.xAlign,r=e.yAlign,o=t.x,s=t.y,l=n.width,u=n.height,d=e.cornerRadius;i.beginPath(),i.moveTo(o+d,s),"top"===r&&this.drawCaret(t,n),i.lineTo(o+l-d,s),i.quadraticCurveTo(o+l,s,o+l,s+d),"center"===r&&"right"===a&&this.drawCaret(t,n),i.lineTo(o+l,s+u-d),i.quadraticCurveTo(o+l,s+u,o+l-d,s+u),"bottom"===r&&this.drawCaret(t,n),i.lineTo(o+d,s+u),i.quadraticCurveTo(o,s+u,o,s+u-d),"center"===r&&"left"===a&&this.drawCaret(t,n),i.lineTo(o,s+d),i.quadraticCurveTo(o,s,o+d,s),i.closePath(),i.fill(),e.borderWidth>0&&i.stroke()},draw:function(){var t=this._chart.ctx,e=this._view;if(0!==e.opacity){var i={width:e.width,height:e.height},n={x:e.x,y:e.y},a=Math.abs(e.opacity<.001)?0:e.opacity,r=e.title.length||e.beforeBody.length||e.body.length||e.afterBody.length||e.footer.length;this._options.enabled&&r&&(t.save(),t.globalAlpha=a,this.drawBackground(n,e,t,i),n.y+=e.yPadding,this.drawTitle(n,e,t),this.drawBody(n,e,t),this.drawFooter(n,e,t),t.restore())}},handleEvent:function(t){var e,i=this,n=i._options;return i._lastActive=i._lastActive||[],"mouseout"===t.type?i._active=[]:i._active=i._chart.getElementsAtEventForMode(t,n.mode,n),(e=!ut.arrayEquals(i._active,i._lastActive))&&(i._lastActive=i._active,(n.enabled||n.custom)&&(i._eventPosition={x:t.x,y:t.y},i.update(!0),i.pivot())),e}}),Ke=je,Je=Xe;Je.positioners=Ke;var Qe=ut.valueOrDefault;function ti(){return ut.merge({},[].slice.call(arguments),{merger:function(t,e,i,n){if("xAxes"===t||"yAxes"===t){var a,r,o,s=i[t].length;for(e[t]||(e[t]=[]),a=0;a<s;++a)o=i[t][a],r=Qe(o.type,"xAxes"===t?"category":"linear"),a>=e[t].length&&e[t].push({}),!e[t][a].type||o.type&&o.type!==e[t][a].type?ut.merge(e[t][a],[Ee.getScaleDefaults(r),o]):ut.merge(e[t][a],o)}else ut._merger(t,e,i,n)}})}function ei(){return ut.merge({},[].slice.call(arguments),{merger:function(t,e,i,n){var a=e[t]||{},r=i[t];"scales"===t?e[t]=ti(a,r):"scale"===t?e[t]=ut.merge(a,[Ee.getScaleDefaults(r.type),r]):ut._merger(t,e,i,n)}})}function ii(t){return"top"===t||"bottom"===t}ot._set("global",{elements:{},events:["mousemove","mouseout","click","touchstart","touchmove"],hover:{onHover:null,mode:"nearest",intersect:!0,animationDuration:400},onClick:null,maintainAspectRatio:!0,responsive:!0,responsiveAnimationDuration:0});var ni=function(t,e){return this.construct(t,e),this};ut.extend(ni.prototype,{construct:function(t,e){var i=this;e=function(t){var e=(t=t||{}).data=t.data||{};return e.datasets=e.datasets||[],e.labels=e.labels||[],t.options=ei(ot.global,ot[t.type],t.options||{}),t}(e);var n=Ve.acquireContext(t,e),a=n&&n.canvas,r=a&&a.height,o=a&&a.width;i.id=ut.uid(),i.ctx=n,i.canvas=a,i.config=e,i.width=o,i.height=r,i.aspectRatio=r?o/r:null,i.options=e.options,i._bufferedRender=!1,i.chart=i,i.controller=i,ni.instances[i.id]=i,Object.defineProperty(i,"data",{get:function(){return i.config.data},set:function(t){i.config.data=t}}),n&&a?(i.initialize(),i.update()):console.error("Failed to create chart: can't acquire context from the given item")},initialize:function(){var t=this;return He.notify(t,"beforeInit"),ut.retinaScale(t,t.options.devicePixelRatio),t.bindEvents(),t.options.responsive&&t.resize(!0),t.ensureScalesHaveIDs(),t.buildOrUpdateScales(),t.initToolTip(),He.notify(t,"afterInit"),t},clear:function(){return ut.canvas.clear(this),this},stop:function(){return vt.cancelAnimation(this),this},resize:function(t){var e=this,i=e.options,n=e.canvas,a=i.maintainAspectRatio&&e.aspectRatio||null,r=Math.max(0,Math.floor(ut.getMaximumWidth(n))),o=Math.max(0,Math.floor(a?r/a:ut.getMaximumHeight(n)));if((e.width!==r||e.height!==o)&&(n.width=e.width=r,n.height=e.height=o,n.style.width=r+"px",n.style.height=o+"px",ut.retinaScale(e,i.devicePixelRatio),!t)){var s={width:r,height:o};He.notify(e,"resize",[s]),i.onResize&&i.onResize(e,s),e.stop(),e.update({duration:i.responsiveAnimationDuration})}},ensureScalesHaveIDs:function(){var t=this.options,e=t.scales||{},i=t.scale;ut.each(e.xAxes,function(t,e){t.id=t.id||"x-axis-"+e}),ut.each(e.yAxes,function(t,e){t.id=t.id||"y-axis-"+e}),i&&(i.id=i.id||"scale")},buildOrUpdateScales:function(){var t=this,e=t.options,i=t.scales||{},n=[],a=Object.keys(i).reduce(function(t,e){return t[e]=!1,t},{});e.scales&&(n=n.concat((e.scales.xAxes||[]).map(function(t){return{options:t,dtype:"category",dposition:"bottom"}}),(e.scales.yAxes||[]).map(function(t){return{options:t,dtype:"linear",dposition:"left"}}))),e.scale&&n.push({options:e.scale,dtype:"radialLinear",isDefault:!0,dposition:"chartArea"}),ut.each(n,function(e){var n=e.options,r=n.id,o=Qe(n.type,e.dtype);ii(n.position)!==ii(e.dposition)&&(n.position=e.dposition),a[r]=!0;var s=null;if(r in i&&i[r].type===o)(s=i[r]).options=n,s.ctx=t.ctx,s.chart=t;else{var l=Ee.getScaleConstructor(o);if(!l)return;s=new l({id:r,type:o,options:n,ctx:t.ctx,chart:t}),i[s.id]=s}s.mergeTicksOptions(),e.isDefault&&(t.scale=s)}),ut.each(a,function(t,e){t||delete i[e]}),t.scales=i,Ee.addScalesToLayout(this)},buildOrUpdateControllers:function(){var t=this,e=[];return ut.each(t.data.datasets,function(i,n){var a=t.getDatasetMeta(n),r=i.type||t.config.type;if(a.type&&a.type!==r&&(t.destroyDatasetMeta(n),a=t.getDatasetMeta(n)),a.type=r,a.controller)a.controller.updateIndex(n),a.controller.linkScales();else{var o=ue[a.type];if(void 0===o)throw new Error('"'+a.type+'" is not a chart type.');a.controller=new o(t,n),e.push(a.controller)}},t),e},resetElements:function(){var t=this;ut.each(t.data.datasets,function(e,i){t.getDatasetMeta(i).controller.reset()},t)},reset:function(){this.resetElements(),this.tooltip.initialize()},update:function(t){var e,i,n=this;if(t&&"object"==typeof t||(t={duration:t,lazy:arguments[1]}),i=(e=n).options,ut.each(e.scales,function(t){xe.removeBox(e,t)}),i=ei(ot.global,ot[e.config.type],i),e.options=e.config.options=i,e.ensureScalesHaveIDs(),e.buildOrUpdateScales(),e.tooltip._options=i.tooltips,e.tooltip.initialize(),He._invalidate(n),!1!==He.notify(n,"beforeUpdate")){n.tooltip._data=n.data;var a=n.buildOrUpdateControllers();ut.each(n.data.datasets,function(t,e){n.getDatasetMeta(e).controller.buildOrUpdateElements()},n),n.updateLayout(),n.options.animation&&n.options.animation.duration&&ut.each(a,function(t){t.reset()}),n.updateDatasets(),n.tooltip.initialize(),n.lastActive=[],He.notify(n,"afterUpdate"),n._bufferedRender?n._bufferedRequest={duration:t.duration,easing:t.easing,lazy:t.lazy}:n.render(t)}},updateLayout:function(){!1!==He.notify(this,"beforeLayout")&&(xe.update(this,this.width,this.height),He.notify(this,"afterScaleUpdate"),He.notify(this,"afterLayout"))},updateDatasets:function(){if(!1!==He.notify(this,"beforeDatasetsUpdate")){for(var t=0,e=this.data.datasets.length;t<e;++t)this.updateDataset(t);He.notify(this,"afterDatasetsUpdate")}},updateDataset:function(t){var e=this.getDatasetMeta(t),i={meta:e,index:t};!1!==He.notify(this,"beforeDatasetUpdate",[i])&&(e.controller.update(),He.notify(this,"afterDatasetUpdate",[i]))},render:function(t){var e=this;t&&"object"==typeof t||(t={duration:t,lazy:arguments[1]});var i=e.options.animation,n=Qe(t.duration,i&&i.duration),a=t.lazy;if(!1!==He.notify(e,"beforeRender")){var r=function(t){He.notify(e,"afterRender"),ut.callback(i&&i.onComplete,[t],e)};if(i&&n){var o=new pt({numSteps:n/16.66,easing:t.easing||i.easing,render:function(t,e){var i=ut.easing.effects[e.easing],n=e.currentStep,a=n/e.numSteps;t.draw(i(a),a,n)},onAnimationProgress:i.onProgress,onAnimationComplete:r});vt.addAnimation(e,o,n,a)}else e.draw(),r(new pt({numSteps:0,chart:e}));return e}},draw:function(t){var e=this;e.clear(),ut.isNullOrUndef(t)&&(t=1),e.transition(t),e.width<=0||e.height<=0||!1!==He.notify(e,"beforeDraw",[t])&&(ut.each(e.boxes,function(t){t.draw(e.chartArea)},e),e.drawDatasets(t),e._drawTooltip(t),He.notify(e,"afterDraw",[t]))},transition:function(t){for(var e=0,i=(this.data.datasets||[]).length;e<i;++e)this.isDatasetVisible(e)&&this.getDatasetMeta(e).controller.transition(t);this.tooltip.transition(t)},drawDatasets:function(t){var e=this;if(!1!==He.notify(e,"beforeDatasetsDraw",[t])){for(var i=(e.data.datasets||[]).length-1;i>=0;--i)e.isDatasetVisible(i)&&e.drawDataset(i,t);He.notify(e,"afterDatasetsDraw",[t])}},drawDataset:function(t,e){var i=this.getDatasetMeta(t),n={meta:i,index:t,easingValue:e};!1!==He.notify(this,"beforeDatasetDraw",[n])&&(i.controller.draw(e),He.notify(this,"afterDatasetDraw",[n]))},_drawTooltip:function(t){var e=this.tooltip,i={tooltip:e,easingValue:t};!1!==He.notify(this,"beforeTooltipDraw",[i])&&(e.draw(),He.notify(this,"afterTooltipDraw",[i]))},getElementAtEvent:function(t){return pe.modes.single(this,t)},getElementsAtEvent:function(t){return pe.modes.label(this,t,{intersect:!0})},getElementsAtXAxis:function(t){return pe.modes["x-axis"](this,t,{intersect:!0})},getElementsAtEventForMode:function(t,e,i){var n=pe.modes[e];return"function"==typeof n?n(this,t,i):[]},getDatasetAtEvent:function(t){return pe.modes.dataset(this,t,{intersect:!0})},getDatasetMeta:function(t){var e=this.data.datasets[t];e._meta||(e._meta={});var i=e._meta[this.id];return i||(i=e._meta[this.id]={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null}),i},getVisibleDatasetCount:function(){for(var t=0,e=0,i=this.data.datasets.length;e<i;++e)this.isDatasetVisible(e)&&t++;return t},isDatasetVisible:function(t){var e=this.getDatasetMeta(t);return"boolean"==typeof e.hidden?!e.hidden:!this.data.datasets[t].hidden},generateLegend:function(){return this.options.legendCallback(this)},destroyDatasetMeta:function(t){var e=this.id,i=this.data.datasets[t],n=i._meta&&i._meta[e];n&&(n.controller.destroy(),delete i._meta[e])},destroy:function(){var t,e,i=this,n=i.canvas;for(i.stop(),t=0,e=i.data.datasets.length;t<e;++t)i.destroyDatasetMeta(t);n&&(i.unbindEvents(),ut.canvas.clear(i),Ve.releaseContext(i.ctx),i.canvas=null,i.ctx=null),He.notify(i,"destroy"),delete ni.instances[i.id]},toBase64Image:function(){return this.canvas.toDataURL.apply(this.canvas,arguments)},initToolTip:function(){var t=this;t.tooltip=new Je({_chart:t,_chartInstance:t,_data:t.data,_options:t.options.tooltips},t)},bindEvents:function(){var t=this,e=t._listeners={},i=function(){t.eventHandler.apply(t,arguments)};ut.each(t.options.events,function(n){Ve.addEventListener(t,n,i),e[n]=i}),t.options.responsive&&(i=function(){t.resize()},Ve.addEventListener(t,"resize",i),e.resize=i)},unbindEvents:function(){var t=this,e=t._listeners;e&&(delete t._listeners,ut.each(e,function(e,i){Ve.removeEventListener(t,i,e)}))},updateHoverStyle:function(t,e,i){var n,a,r,o=i?"setHoverStyle":"removeHoverStyle";for(a=0,r=t.length;a<r;++a)(n=t[a])&&this.getDatasetMeta(n._datasetIndex).controller[o](n)},eventHandler:function(t){var e=this,i=e.tooltip;if(!1!==He.notify(e,"beforeEvent",[t])){e._bufferedRender=!0,e._bufferedRequest=null;var n=e.handleEvent(t);i&&(n=i._start?i.handleEvent(t):n|i.handleEvent(t)),He.notify(e,"afterEvent",[t]);var a=e._bufferedRequest;return a?e.render(a):n&&!e.animating&&(e.stop(),e.render({duration:e.options.hover.animationDuration,lazy:!0})),e._bufferedRender=!1,e._bufferedRequest=null,e}},handleEvent:function(t){var e,i=this,n=i.options||{},a=n.hover;return i.lastActive=i.lastActive||[],"mouseout"===t.type?i.active=[]:i.active=i.getElementsAtEventForMode(t,a.mode,a),ut.callback(n.onHover||n.hover.onHover,[t.native,i.active],i),"mouseup"!==t.type&&"click"!==t.type||n.onClick&&n.onClick.call(i,t.native,i.active),i.lastActive.length&&i.updateHoverStyle(i.lastActive,a.mode,!1),i.active.length&&a.mode&&i.updateHoverStyle(i.active,a.mode,!0),e=!ut.arrayEquals(i.active,i.lastActive),i.lastActive=i.active,e}}),ni.instances={};var ai=ni;ni.Controller=ni,ni.types={},ut.configMerge=ei,ut.scaleMerge=ti;function ri(){throw new Error("This method is not implemented: either no adapter can be found or an incomplete integration was provided.")}function oi(t){this.options=t||{}}ut.extend(oi.prototype,{formats:ri,parse:ri,format:ri,add:ri,diff:ri,startOf:ri,endOf:ri,_create:function(t){return t}}),oi.override=function(t){ut.extend(oi.prototype,t)};var si={_date:oi},li={formatters:{values:function(t){return ut.isArray(t)?t:""+t},linear:function(t,e,i){var n=i.length>3?i[2]-i[1]:i[1]-i[0];Math.abs(n)>1&&t!==Math.floor(t)&&(n=t-Math.floor(t));var a=ut.log10(Math.abs(n)),r="";if(0!==t)if(Math.max(Math.abs(i[0]),Math.abs(i[i.length-1]))<1e-4){var o=ut.log10(Math.abs(t));r=t.toExponential(Math.floor(o)-Math.floor(a))}else{var s=-1*Math.floor(a);s=Math.max(Math.min(s,20),0),r=t.toFixed(s)}else r="0";return r},logarithmic:function(t,e,i){var n=t/Math.pow(10,Math.floor(ut.log10(t)));return 0===t?"0":1===n||2===n||5===n||0===e||e===i.length-1?t.toExponential():""}}},ui=ut.valueOrDefault,di=ut.valueAtIndexOrDefault;function hi(t){var e,i,n=[];for(e=0,i=t.length;e<i;++e)n.push(t[e].label);return n}function ci(t,e,i){return ut.isArray(e)?ut.longestText(t,i,e):t.measureText(e).width}ot._set("scale",{display:!0,position:"left",offset:!1,gridLines:{display:!0,color:"rgba(0, 0, 0, 0.1)",lineWidth:1,drawBorder:!0,drawOnChartArea:!0,drawTicks:!0,tickMarkLength:10,zeroLineWidth:1,zeroLineColor:"rgba(0,0,0,0.25)",zeroLineBorderDash:[],zeroLineBorderDashOffset:0,offsetGridLines:!1,borderDash:[],borderDashOffset:0},scaleLabel:{display:!1,labelString:"",padding:{top:4,bottom:4}},ticks:{beginAtZero:!1,minRotation:0,maxRotation:50,mirror:!1,padding:0,reverse:!1,display:!0,autoSkip:!0,autoSkipPadding:0,labelOffset:0,callback:li.formatters.values,minor:{},major:{}}});var fi=gt.extend({getPadding:function(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}},getTicks:function(){return this._ticks},mergeTicksOptions:function(){var t=this.options.ticks;for(var e in!1===t.minor&&(t.minor={display:!1}),!1===t.major&&(t.major={display:!1}),t)"major"!==e&&"minor"!==e&&(void 0===t.minor[e]&&(t.minor[e]=t[e]),void 0===t.major[e]&&(t.major[e]=t[e]))},beforeUpdate:function(){ut.callback(this.options.beforeUpdate,[this])},update:function(t,e,i){var n,a,r,o,s,l,u=this;for(u.beforeUpdate(),u.maxWidth=t,u.maxHeight=e,u.margins=ut.extend({left:0,right:0,top:0,bottom:0},i),u._maxLabelLines=0,u.longestLabelWidth=0,u.longestTextCache=u.longestTextCache||{},u.beforeSetDimensions(),u.setDimensions(),u.afterSetDimensions(),u.beforeDataLimits(),u.determineDataLimits(),u.afterDataLimits(),u.beforeBuildTicks(),s=u.buildTicks()||[],s=u.afterBuildTicks(s)||s,u.beforeTickToLabelConversion(),r=u.convertTicksToLabels(s)||u.ticks,u.afterTickToLabelConversion(),u.ticks=r,n=0,a=r.length;n<a;++n)o=r[n],(l=s[n])?l.label=o:s.push(l={label:o,major:!1});return u._ticks=s,u.beforeCalculateTickRotation(),u.calculateTickRotation(),u.afterCalculateTickRotation(),u.beforeFit(),u.fit(),u.afterFit(),u.afterUpdate(),u.minSize},afterUpdate:function(){ut.callback(this.options.afterUpdate,[this])},beforeSetDimensions:function(){ut.callback(this.options.beforeSetDimensions,[this])},setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0},afterSetDimensions:function(){ut.callback(this.options.afterSetDimensions,[this])},beforeDataLimits:function(){ut.callback(this.options.beforeDataLimits,[this])},determineDataLimits:ut.noop,afterDataLimits:function(){ut.callback(this.options.afterDataLimits,[this])},beforeBuildTicks:function(){ut.callback(this.options.beforeBuildTicks,[this])},buildTicks:ut.noop,afterBuildTicks:function(t){var e=this;return ut.isArray(t)&&t.length?ut.callback(e.options.afterBuildTicks,[e,t]):(e.ticks=ut.callback(e.options.afterBuildTicks,[e,e.ticks])||e.ticks,t)},beforeTickToLabelConversion:function(){ut.callback(this.options.beforeTickToLabelConversion,[this])},convertTicksToLabels:function(){var t=this.options.ticks;this.ticks=this.ticks.map(t.userCallback||t.callback,this)},afterTickToLabelConversion:function(){ut.callback(this.options.afterTickToLabelConversion,[this])},beforeCalculateTickRotation:function(){ut.callback(this.options.beforeCalculateTickRotation,[this])},calculateTickRotation:function(){var t=this,e=t.ctx,i=t.options.ticks,n=hi(t._ticks),a=ut.options._parseFont(i);e.font=a.string;var r=i.minRotation||0;if(n.length&&t.options.display&&t.isHorizontal())for(var o,s=ut.longestText(e,a.string,n,t.longestTextCache),l=s,u=t.getPixelForTick(1)-t.getPixelForTick(0)-6;l>u&&r<i.maxRotation;){var d=ut.toRadians(r);if(o=Math.cos(d),Math.sin(d)*s>t.maxHeight){r--;break}r++,l=o*s}t.labelRotation=r},afterCalculateTickRotation:function(){ut.callback(this.options.afterCalculateTickRotation,[this])},beforeFit:function(){ut.callback(this.options.beforeFit,[this])},fit:function(){var t=this,e=t.minSize={width:0,height:0},i=hi(t._ticks),n=t.options,a=n.ticks,r=n.scaleLabel,o=n.gridLines,s=t._isVisible(),l=n.position,u=t.isHorizontal(),d=ut.options._parseFont,h=d(a),c=n.gridLines.tickMarkLength;if(e.width=u?t.isFullWidth()?t.maxWidth-t.margins.left-t.margins.right:t.maxWidth:s&&o.drawTicks?c:0,e.height=u?s&&o.drawTicks?c:0:t.maxHeight,r.display&&s){var f=d(r),g=ut.options.toPadding(r.padding),m=f.lineHeight+g.height;u?e.height+=m:e.width+=m}if(a.display&&s){var p=ut.longestText(t.ctx,h.string,i,t.longestTextCache),v=ut.numberOfLabelLines(i),y=.5*h.size,b=t.options.ticks.padding;if(t._maxLabelLines=v,t.longestLabelWidth=p,u){var x=ut.toRadians(t.labelRotation),_=Math.cos(x),k=Math.sin(x)*p+h.lineHeight*v+y;e.height=Math.min(t.maxHeight,e.height+k+b),t.ctx.font=h.string;var w,M,S=ci(t.ctx,i[0],h.string),D=ci(t.ctx,i[i.length-1],h.string),C=t.getPixelForTick(0)-t.left,P=t.right-t.getPixelForTick(i.length-1);0!==t.labelRotation?(w="bottom"===l?_*S:_*y,M="bottom"===l?_*y:_*D):(w=S/2,M=D/2),t.paddingLeft=Math.max(w-C,0)+3,t.paddingRight=Math.max(M-P,0)+3}else a.mirror?p=0:p+=b+y,e.width=Math.min(t.maxWidth,e.width+p),t.paddingTop=h.size/2,t.paddingBottom=h.size/2}t.handleMargins(),t.width=e.width,t.height=e.height},handleMargins:function(){var t=this;t.margins&&(t.paddingLeft=Math.max(t.paddingLeft-t.margins.left,0),t.paddingTop=Math.max(t.paddingTop-t.margins.top,0),t.paddingRight=Math.max(t.paddingRight-t.margins.right,0),t.paddingBottom=Math.max(t.paddingBottom-t.margins.bottom,0))},afterFit:function(){ut.callback(this.options.afterFit,[this])},isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},isFullWidth:function(){return this.options.fullWidth},getRightValue:function(t){if(ut.isNullOrUndef(t))return NaN;if(("number"==typeof t||t instanceof Number)&&!isFinite(t))return NaN;if(t)if(this.isHorizontal()){if(void 0!==t.x)return this.getRightValue(t.x)}else if(void 0!==t.y)return this.getRightValue(t.y);return t},getLabelForIndex:ut.noop,getPixelForValue:ut.noop,getValueForPixel:ut.noop,getPixelForTick:function(t){var e=this,i=e.options.offset;if(e.isHorizontal()){var n=(e.width-(e.paddingLeft+e.paddingRight))/Math.max(e._ticks.length-(i?0:1),1),a=n*t+e.paddingLeft;i&&(a+=n/2);var r=e.left+a;return r+=e.isFullWidth()?e.margins.left:0}var o=e.height-(e.paddingTop+e.paddingBottom);return e.top+t*(o/(e._ticks.length-1))},getPixelForDecimal:function(t){var e=this;if(e.isHorizontal()){var i=(e.width-(e.paddingLeft+e.paddingRight))*t+e.paddingLeft,n=e.left+i;return n+=e.isFullWidth()?e.margins.left:0}return e.top+t*e.height},getBasePixel:function(){return this.getPixelForValue(this.getBaseValue())},getBaseValue:function(){var t=this.min,e=this.max;return this.beginAtZero?0:t<0&&e<0?e:t>0&&e>0?t:0},_autoSkip:function(t){var e,i,n=this,a=n.isHorizontal(),r=n.options.ticks.minor,o=t.length,s=!1,l=r.maxTicksLimit,u=n._tickSize()*(o-1),d=a?n.width-(n.paddingLeft+n.paddingRight):n.height-(n.paddingTop+n.PaddingBottom),h=[];for(u>d&&(s=1+Math.floor(u/d)),o>l&&(s=Math.max(s,1+Math.floor(o/l))),e=0;e<o;e++)i=t[e],s>1&&e%s>0&&delete i.label,h.push(i);return h},_tickSize:function(){var t=this,e=t.isHorizontal(),i=t.options.ticks.minor,n=ut.toRadians(t.labelRotation),a=Math.abs(Math.cos(n)),r=Math.abs(Math.sin(n)),o=i.autoSkipPadding||0,s=t.longestLabelWidth+o||0,l=ut.options._parseFont(i),u=t._maxLabelLines*l.lineHeight+o||0;return e?u*a>s*r?s/a:u/r:u*r<s*a?u/a:s/r},_isVisible:function(){var t,e,i,n=this.chart,a=this.options.display;if("auto"!==a)return!!a;for(t=0,e=n.data.datasets.length;t<e;++t)if(n.isDatasetVisible(t)&&((i=n.getDatasetMeta(t)).xAxisID===this.id||i.yAxisID===this.id))return!0;return!1},draw:function(t){var e=this,i=e.options;if(e._isVisible()){var n,a,r,o=e.chart,s=e.ctx,l=ot.global.defaultFontColor,u=i.ticks.minor,d=i.ticks.major||u,h=i.gridLines,c=i.scaleLabel,f=i.position,g=0!==e.labelRotation,m=u.mirror,p=e.isHorizontal(),v=ut.options._parseFont,y=u.display&&u.autoSkip?e._autoSkip(e.getTicks()):e.getTicks(),b=ui(u.fontColor,l),x=v(u),_=x.lineHeight,k=ui(d.fontColor,l),w=v(d),M=u.padding,S=u.labelOffset,D=h.drawTicks?h.tickMarkLength:0,C=ui(c.fontColor,l),P=v(c),T=ut.options.toPadding(c.padding),O=ut.toRadians(e.labelRotation),I=[],A=h.drawBorder?di(h.lineWidth,0,0):0,F=ut._alignPixel;"top"===f?(n=F(o,e.bottom,A),a=e.bottom-D,r=n-A/2):"bottom"===f?(n=F(o,e.top,A),a=n+A/2,r=e.top+D):"left"===f?(n=F(o,e.right,A),a=e.right-D,r=n-A/2):(n=F(o,e.left,A),a=n+A/2,r=e.left+D);if(ut.each(y,function(n,s){if(!ut.isNullOrUndef(n.label)){var l,u,d,c,v,y,b,x,k,w,C,P,T,R,L,W,Y=n.label;s===e.zeroLineIndex&&i.offset===h.offsetGridLines?(l=h.zeroLineWidth,u=h.zeroLineColor,d=h.zeroLineBorderDash||[],c=h.zeroLineBorderDashOffset||0):(l=di(h.lineWidth,s),u=di(h.color,s),d=h.borderDash||[],c=h.borderDashOffset||0);var N=ut.isArray(Y)?Y.length:1,z=function(t,e,i){var n=t.getPixelForTick(e);return i&&(1===t.getTicks().length?n-=t.isHorizontal()?Math.max(n-t.left,t.right-n):Math.max(n-t.top,t.bottom-n):n-=0===e?(t.getPixelForTick(1)-n)/2:(n-t.getPixelForTick(e-1))/2),n}(e,s,h.offsetGridLines);if(p){var V=D+M;z<e.left-1e-7&&(u="rgba(0,0,0,0)"),v=b=k=C=F(o,z,l),y=a,x=r,T=e.getPixelForTick(s)+S,"top"===f?(w=F(o,t.top,A)+A/2,P=t.bottom,L=((g?1:.5)-N)*_,W=g?"left":"center",R=e.bottom-V):(w=t.top,P=F(o,t.bottom,A)-A/2,L=(g?0:.5)*_,W=g?"right":"center",R=e.top+V)}else{var H=(m?0:D)+M;z<e.top-1e-7&&(u="rgba(0,0,0,0)"),v=a,b=r,y=x=w=P=F(o,z,l),R=e.getPixelForTick(s)+S,L=(1-N)*_/2,"left"===f?(k=F(o,t.left,A)+A/2,C=t.right,W=m?"left":"right",T=e.right-H):(k=t.left,C=F(o,t.right,A)-A/2,W=m?"right":"left",T=e.left+H)}I.push({tx1:v,ty1:y,tx2:b,ty2:x,x1:k,y1:w,x2:C,y2:P,labelX:T,labelY:R,glWidth:l,glColor:u,glBorderDash:d,glBorderDashOffset:c,rotation:-1*O,label:Y,major:n.major,textOffset:L,textAlign:W})}}),ut.each(I,function(t){var e=t.glWidth,i=t.glColor;if(h.display&&e&&i&&(s.save(),s.lineWidth=e,s.strokeStyle=i,s.setLineDash&&(s.setLineDash(t.glBorderDash),s.lineDashOffset=t.glBorderDashOffset),s.beginPath(),h.drawTicks&&(s.moveTo(t.tx1,t.ty1),s.lineTo(t.tx2,t.ty2)),h.drawOnChartArea&&(s.moveTo(t.x1,t.y1),s.lineTo(t.x2,t.y2)),s.stroke(),s.restore()),u.display){s.save(),s.translate(t.labelX,t.labelY),s.rotate(t.rotation),s.font=t.major?w.string:x.string,s.fillStyle=t.major?k:b,s.textBaseline="middle",s.textAlign=t.textAlign;var n=t.label,a=t.textOffset;if(ut.isArray(n))for(var r=0;r<n.length;++r)s.fillText(""+n[r],0,a),a+=_;else s.fillText(n,0,a);s.restore()}}),c.display){var R,L,W=0,Y=P.lineHeight/2;if(p)R=e.left+(e.right-e.left)/2,L="bottom"===f?e.bottom-Y-T.bottom:e.top+Y+T.top;else{var N="left"===f;R=N?e.left+Y+T.top:e.right-Y-T.top,L=e.top+(e.bottom-e.top)/2,W=N?-.5*Math.PI:.5*Math.PI}s.save(),s.translate(R,L),s.rotate(W),s.textAlign="center",s.textBaseline="middle",s.fillStyle=C,s.font=P.string,s.fillText(c.labelString,0,0),s.restore()}if(A){var z,V,H,E,B=A,j=di(h.lineWidth,y.length-1,0);p?(z=F(o,e.left,B)-B/2,V=F(o,e.right,j)+j/2,H=E=n):(H=F(o,e.top,B)-B/2,E=F(o,e.bottom,j)+j/2,z=V=n),s.lineWidth=A,s.strokeStyle=di(h.color,0),s.beginPath(),s.moveTo(z,H),s.lineTo(V,E),s.stroke()}}}}),gi=fi.extend({getLabels:function(){var t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels},determineDataLimits:function(){var t,e=this,i=e.getLabels();e.minIndex=0,e.maxIndex=i.length-1,void 0!==e.options.ticks.min&&(t=i.indexOf(e.options.ticks.min),e.minIndex=-1!==t?t:e.minIndex),void 0!==e.options.ticks.max&&(t=i.indexOf(e.options.ticks.max),e.maxIndex=-1!==t?t:e.maxIndex),e.min=i[e.minIndex],e.max=i[e.maxIndex]},buildTicks:function(){var t=this,e=t.getLabels();t.ticks=0===t.minIndex&&t.maxIndex===e.length-1?e:e.slice(t.minIndex,t.maxIndex+1)},getLabelForIndex:function(t,e){var i=this,n=i.chart;return n.getDatasetMeta(e).controller._getValueScaleId()===i.id?i.getRightValue(n.data.datasets[e].data[t]):i.ticks[t-i.minIndex]},getPixelForValue:function(t,e){var i,n=this,a=n.options.offset,r=Math.max(n.maxIndex+1-n.minIndex-(a?0:1),1);if(null!=t&&(i=n.isHorizontal()?t.x:t.y),void 0!==i||void 0!==t&&isNaN(e)){t=i||t;var o=n.getLabels().indexOf(t);e=-1!==o?o:e}if(n.isHorizontal()){var s=n.width/r,l=s*(e-n.minIndex);return a&&(l+=s/2),n.left+l}var u=n.height/r,d=u*(e-n.minIndex);return a&&(d+=u/2),n.top+d},getPixelForTick:function(t){return this.getPixelForValue(this.ticks[t],t+this.minIndex,null)},getValueForPixel:function(t){var e=this,i=e.options.offset,n=Math.max(e._ticks.length-(i?0:1),1),a=e.isHorizontal(),r=(a?e.width:e.height)/n;return t-=a?e.left:e.top,i&&(t-=r/2),(t<=0?0:Math.round(t/r))+e.minIndex},getBasePixel:function(){return this.bottom}}),mi={position:"bottom"};gi._defaults=mi;var pi=ut.noop,vi=ut.isNullOrUndef;var yi=fi.extend({getRightValue:function(t){return"string"==typeof t?+t:fi.prototype.getRightValue.call(this,t)},handleTickRangeOptions:function(){var t=this,e=t.options.ticks;if(e.beginAtZero){var i=ut.sign(t.min),n=ut.sign(t.max);i<0&&n<0?t.max=0:i>0&&n>0&&(t.min=0)}var a=void 0!==e.min||void 0!==e.suggestedMin,r=void 0!==e.max||void 0!==e.suggestedMax;void 0!==e.min?t.min=e.min:void 0!==e.suggestedMin&&(null===t.min?t.min=e.suggestedMin:t.min=Math.min(t.min,e.suggestedMin)),void 0!==e.max?t.max=e.max:void 0!==e.suggestedMax&&(null===t.max?t.max=e.suggestedMax:t.max=Math.max(t.max,e.suggestedMax)),a!==r&&t.min>=t.max&&(a?t.max=t.min+1:t.min=t.max-1),t.min===t.max&&(t.max++,e.beginAtZero||t.min--)},getTickLimit:function(){var t,e=this.options.ticks,i=e.stepSize,n=e.maxTicksLimit;return i?t=Math.ceil(this.max/i)-Math.floor(this.min/i)+1:(t=this._computeTickLimit(),n=n||11),n&&(t=Math.min(n,t)),t},_computeTickLimit:function(){return Number.POSITIVE_INFINITY},handleDirectionalChanges:pi,buildTicks:function(){var t=this,e=t.options.ticks,i=t.getTickLimit(),n={maxTicks:i=Math.max(2,i),min:e.min,max:e.max,precision:e.precision,stepSize:ut.valueOrDefault(e.fixedStepSize,e.stepSize)},a=t.ticks=function(t,e){var i,n,a,r,o=[],s=t.stepSize,l=s||1,u=t.maxTicks-1,d=t.min,h=t.max,c=t.precision,f=e.min,g=e.max,m=ut.niceNum((g-f)/u/l)*l;if(m<1e-14&&vi(d)&&vi(h))return[f,g];(r=Math.ceil(g/m)-Math.floor(f/m))>u&&(m=ut.niceNum(r*m/u/l)*l),s||vi(c)?i=Math.pow(10,ut._decimalPlaces(m)):(i=Math.pow(10,c),m=Math.ceil(m*i)/i),n=Math.floor(f/m)*m,a=Math.ceil(g/m)*m,s&&(!vi(d)&&ut.almostWhole(d/m,m/1e3)&&(n=d),!vi(h)&&ut.almostWhole(h/m,m/1e3)&&(a=h)),r=(a-n)/m,r=ut.almostEquals(r,Math.round(r),m/1e3)?Math.round(r):Math.ceil(r),n=Math.round(n*i)/i,a=Math.round(a*i)/i,o.push(vi(d)?n:d);for(var p=1;p<r;++p)o.push(Math.round((n+p*m)*i)/i);return o.push(vi(h)?a:h),o}(n,t);t.handleDirectionalChanges(),t.max=ut.max(a),t.min=ut.min(a),e.reverse?(a.reverse(),t.start=t.max,t.end=t.min):(t.start=t.min,t.end=t.max)},convertTicksToLabels:function(){var t=this;t.ticksAsNumbers=t.ticks.slice(),t.zeroLineIndex=t.ticks.indexOf(0),fi.prototype.convertTicksToLabels.call(t)}}),bi={position:"left",ticks:{callback:li.formatters.linear}},xi=yi.extend({determineDataLimits:function(){var t=this,e=t.options,i=t.chart,n=i.data.datasets,a=t.isHorizontal();function r(e){return a?e.xAxisID===t.id:e.yAxisID===t.id}t.min=null,t.max=null;var o=e.stacked;if(void 0===o&&ut.each(n,function(t,e){if(!o){var n=i.getDatasetMeta(e);i.isDatasetVisible(e)&&r(n)&&void 0!==n.stack&&(o=!0)}}),e.stacked||o){var s={};ut.each(n,function(n,a){var o=i.getDatasetMeta(a),l=[o.type,void 0===e.stacked&&void 0===o.stack?a:"",o.stack].join(".");void 0===s[l]&&(s[l]={positiveValues:[],negativeValues:[]});var u=s[l].positiveValues,d=s[l].negativeValues;i.isDatasetVisible(a)&&r(o)&&ut.each(n.data,function(i,n){var a=+t.getRightValue(i);isNaN(a)||o.data[n].hidden||(u[n]=u[n]||0,d[n]=d[n]||0,e.relativePoints?u[n]=100:a<0?d[n]+=a:u[n]+=a)})}),ut.each(s,function(e){var i=e.positiveValues.concat(e.negativeValues),n=ut.min(i),a=ut.max(i);t.min=null===t.min?n:Math.min(t.min,n),t.max=null===t.max?a:Math.max(t.max,a)})}else ut.each(n,function(e,n){var a=i.getDatasetMeta(n);i.isDatasetVisible(n)&&r(a)&&ut.each(e.data,function(e,i){var n=+t.getRightValue(e);isNaN(n)||a.data[i].hidden||(null===t.min?t.min=n:n<t.min&&(t.min=n),null===t.max?t.max=n:n>t.max&&(t.max=n))})});t.min=isFinite(t.min)&&!isNaN(t.min)?t.min:0,t.max=isFinite(t.max)&&!isNaN(t.max)?t.max:1,this.handleTickRangeOptions()},_computeTickLimit:function(){var t;return this.isHorizontal()?Math.ceil(this.width/40):(t=ut.options._parseFont(this.options.ticks),Math.ceil(this.height/t.lineHeight))},handleDirectionalChanges:function(){this.isHorizontal()||this.ticks.reverse()},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForValue:function(t){var e=this,i=e.start,n=+e.getRightValue(t),a=e.end-i;return e.isHorizontal()?e.left+e.width/a*(n-i):e.bottom-e.height/a*(n-i)},getValueForPixel:function(t){var e=this,i=e.isHorizontal(),n=i?e.width:e.height,a=(i?t-e.left:e.bottom-t)/n;return e.start+(e.end-e.start)*a},getPixelForTick:function(t){return this.getPixelForValue(this.ticksAsNumbers[t])}}),_i=bi;xi._defaults=_i;var ki=ut.valueOrDefault;var wi={position:"left",ticks:{callback:li.formatters.logarithmic}};function Mi(t,e){return ut.isFinite(t)&&t>=0?t:e}var Si=fi.extend({determineDataLimits:function(){var t=this,e=t.options,i=t.chart,n=i.data.datasets,a=t.isHorizontal();function r(e){return a?e.xAxisID===t.id:e.yAxisID===t.id}t.min=null,t.max=null,t.minNotZero=null;var o=e.stacked;if(void 0===o&&ut.each(n,function(t,e){if(!o){var n=i.getDatasetMeta(e);i.isDatasetVisible(e)&&r(n)&&void 0!==n.stack&&(o=!0)}}),e.stacked||o){var s={};ut.each(n,function(n,a){var o=i.getDatasetMeta(a),l=[o.type,void 0===e.stacked&&void 0===o.stack?a:"",o.stack].join(".");i.isDatasetVisible(a)&&r(o)&&(void 0===s[l]&&(s[l]=[]),ut.each(n.data,function(e,i){var n=s[l],a=+t.getRightValue(e);isNaN(a)||o.data[i].hidden||a<0||(n[i]=n[i]||0,n[i]+=a)}))}),ut.each(s,function(e){if(e.length>0){var i=ut.min(e),n=ut.max(e);t.min=null===t.min?i:Math.min(t.min,i),t.max=null===t.max?n:Math.max(t.max,n)}})}else ut.each(n,function(e,n){var a=i.getDatasetMeta(n);i.isDatasetVisible(n)&&r(a)&&ut.each(e.data,function(e,i){var n=+t.getRightValue(e);isNaN(n)||a.data[i].hidden||n<0||(null===t.min?t.min=n:n<t.min&&(t.min=n),null===t.max?t.max=n:n>t.max&&(t.max=n),0!==n&&(null===t.minNotZero||n<t.minNotZero)&&(t.minNotZero=n))})});this.handleTickRangeOptions()},handleTickRangeOptions:function(){var t=this,e=t.options.ticks;t.min=Mi(e.min,t.min),t.max=Mi(e.max,t.max),t.min===t.max&&(0!==t.min&&null!==t.min?(t.min=Math.pow(10,Math.floor(ut.log10(t.min))-1),t.max=Math.pow(10,Math.floor(ut.log10(t.max))+1)):(t.min=1,t.max=10)),null===t.min&&(t.min=Math.pow(10,Math.floor(ut.log10(t.max))-1)),null===t.max&&(t.max=0!==t.min?Math.pow(10,Math.floor(ut.log10(t.min))+1):10),null===t.minNotZero&&(t.min>0?t.minNotZero=t.min:t.max<1?t.minNotZero=Math.pow(10,Math.floor(ut.log10(t.max))):t.minNotZero=1)},buildTicks:function(){var t=this,e=t.options.ticks,i=!t.isHorizontal(),n={min:Mi(e.min),max:Mi(e.max)},a=t.ticks=function(t,e){var i,n,a=[],r=ki(t.min,Math.pow(10,Math.floor(ut.log10(e.min)))),o=Math.floor(ut.log10(e.max)),s=Math.ceil(e.max/Math.pow(10,o));0===r?(i=Math.floor(ut.log10(e.minNotZero)),n=Math.floor(e.minNotZero/Math.pow(10,i)),a.push(r),r=n*Math.pow(10,i)):(i=Math.floor(ut.log10(r)),n=Math.floor(r/Math.pow(10,i)));var l=i<0?Math.pow(10,Math.abs(i)):1;do{a.push(r),10==++n&&(n=1,l=++i>=0?1:l),r=Math.round(n*Math.pow(10,i)*l)/l}while(i<o||i===o&&n<s);var u=ki(t.max,r);return a.push(u),a}(n,t);t.max=ut.max(a),t.min=ut.min(a),e.reverse?(i=!i,t.start=t.max,t.end=t.min):(t.start=t.min,t.end=t.max),i&&a.reverse()},convertTicksToLabels:function(){this.tickValues=this.ticks.slice(),fi.prototype.convertTicksToLabels.call(this)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForTick:function(t){return this.getPixelForValue(this.tickValues[t])},_getFirstTickValue:function(t){var e=Math.floor(ut.log10(t));return Math.floor(t/Math.pow(10,e))*Math.pow(10,e)},getPixelForValue:function(t){var e,i,n,a,r,o=this,s=o.options.ticks,l=s.reverse,u=ut.log10,d=o._getFirstTickValue(o.minNotZero),h=0;return t=+o.getRightValue(t),l?(n=o.end,a=o.start,r=-1):(n=o.start,a=o.end,r=1),o.isHorizontal()?(e=o.width,i=l?o.right:o.left):(e=o.height,r*=-1,i=l?o.top:o.bottom),t!==n&&(0===n&&(e-=h=ki(s.fontSize,ot.global.defaultFontSize),n=d),0!==t&&(h+=e/(u(a)-u(n))*(u(t)-u(n))),i+=r*h),i},getValueForPixel:function(t){var e,i,n,a,r=this,o=r.options.ticks,s=o.reverse,l=ut.log10,u=r._getFirstTickValue(r.minNotZero);if(s?(i=r.end,n=r.start):(i=r.start,n=r.end),r.isHorizontal()?(e=r.width,a=s?r.right-t:t-r.left):(e=r.height,a=s?t-r.top:r.bottom-t),a!==i){if(0===i){var d=ki(o.fontSize,ot.global.defaultFontSize);a-=d,e-=d,i=u}a*=l(n)-l(i),a/=e,a=Math.pow(10,l(i)+a)}return a}}),Di=wi;Si._defaults=Di;var Ci=ut.valueOrDefault,Pi=ut.valueAtIndexOrDefault,Ti=ut.options.resolve,Oi={display:!0,animate:!0,position:"chartArea",angleLines:{display:!0,color:"rgba(0, 0, 0, 0.1)",lineWidth:1,borderDash:[],borderDashOffset:0},gridLines:{circular:!1},ticks:{showLabelBackdrop:!0,backdropColor:"rgba(255,255,255,0.75)",backdropPaddingY:2,backdropPaddingX:2,callback:li.formatters.linear},pointLabels:{display:!0,fontSize:10,callback:function(t){return t}}};function Ii(t){var e=t.options;return e.angleLines.display||e.pointLabels.display?t.chart.data.labels.length:0}function Ai(t){var e=t.ticks;return e.display&&t.display?Ci(e.fontSize,ot.global.defaultFontSize)+2*e.backdropPaddingY:0}function Fi(t,e,i,n,a){return t===n||t===a?{start:e-i/2,end:e+i/2}:t<n||t>a?{start:e-i,end:e}:{start:e,end:e+i}}function Ri(t){return 0===t||180===t?"center":t<180?"left":"right"}function Li(t,e,i,n){var a,r,o=i.y+n/2;if(ut.isArray(e))for(a=0,r=e.length;a<r;++a)t.fillText(e[a],i.x,o),o+=n;else t.fillText(e,i.x,o)}function Wi(t,e,i){90===t||270===t?i.y-=e.h/2:(t>270||t<90)&&(i.y-=e.h)}function Yi(t){return ut.isNumber(t)?t:0}var Ni=yi.extend({setDimensions:function(){var t=this;t.width=t.maxWidth,t.height=t.maxHeight,t.paddingTop=Ai(t.options)/2,t.xCenter=Math.floor(t.width/2),t.yCenter=Math.floor((t.height-t.paddingTop)/2),t.drawingArea=Math.min(t.height-t.paddingTop,t.width)/2},determineDataLimits:function(){var t=this,e=t.chart,i=Number.POSITIVE_INFINITY,n=Number.NEGATIVE_INFINITY;ut.each(e.data.datasets,function(a,r){if(e.isDatasetVisible(r)){var o=e.getDatasetMeta(r);ut.each(a.data,function(e,a){var r=+t.getRightValue(e);isNaN(r)||o.data[a].hidden||(i=Math.min(r,i),n=Math.max(r,n))})}}),t.min=i===Number.POSITIVE_INFINITY?0:i,t.max=n===Number.NEGATIVE_INFINITY?0:n,t.handleTickRangeOptions()},_computeTickLimit:function(){return Math.ceil(this.drawingArea/Ai(this.options))},convertTicksToLabels:function(){var t=this;yi.prototype.convertTicksToLabels.call(t),t.pointLabels=t.chart.data.labels.map(t.options.pointLabels.callback,t)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},fit:function(){var t=this.options;t.display&&t.pointLabels.display?function(t){var e,i,n,a=ut.options._parseFont(t.options.pointLabels),r={l:0,r:t.width,t:0,b:t.height-t.paddingTop},o={};t.ctx.font=a.string,t._pointLabelSizes=[];var s,l,u,d=Ii(t);for(e=0;e<d;e++){n=t.getPointPosition(e,t.drawingArea+5),s=t.ctx,l=a.lineHeight,u=t.pointLabels[e]||"",i=ut.isArray(u)?{w:ut.longestText(s,s.font,u),h:u.length*l}:{w:s.measureText(u).width,h:l},t._pointLabelSizes[e]=i;var h=t.getIndexAngle(e),c=ut.toDegrees(h)%360,f=Fi(c,n.x,i.w,0,180),g=Fi(c,n.y,i.h,90,270);f.start<r.l&&(r.l=f.start,o.l=h),f.end>r.r&&(r.r=f.end,o.r=h),g.start<r.t&&(r.t=g.start,o.t=h),g.end>r.b&&(r.b=g.end,o.b=h)}t.setReductions(t.drawingArea,r,o)}(this):this.setCenterPoint(0,0,0,0)},setReductions:function(t,e,i){var n=this,a=e.l/Math.sin(i.l),r=Math.max(e.r-n.width,0)/Math.sin(i.r),o=-e.t/Math.cos(i.t),s=-Math.max(e.b-(n.height-n.paddingTop),0)/Math.cos(i.b);a=Yi(a),r=Yi(r),o=Yi(o),s=Yi(s),n.drawingArea=Math.min(Math.floor(t-(a+r)/2),Math.floor(t-(o+s)/2)),n.setCenterPoint(a,r,o,s)},setCenterPoint:function(t,e,i,n){var a=this,r=a.width-e-a.drawingArea,o=t+a.drawingArea,s=i+a.drawingArea,l=a.height-a.paddingTop-n-a.drawingArea;a.xCenter=Math.floor((o+r)/2+a.left),a.yCenter=Math.floor((s+l)/2+a.top+a.paddingTop)},getIndexAngle:function(t){return t*(2*Math.PI/Ii(this))+(this.chart.options&&this.chart.options.startAngle?this.chart.options.startAngle:0)*Math.PI*2/360},getDistanceFromCenterForValue:function(t){var e=this;if(null===t)return 0;var i=e.drawingArea/(e.max-e.min);return e.options.ticks.reverse?(e.max-t)*i:(t-e.min)*i},getPointPosition:function(t,e){var i=this.getIndexAngle(t)-Math.PI/2;return{x:Math.cos(i)*e+this.xCenter,y:Math.sin(i)*e+this.yCenter}},getPointPositionForValue:function(t,e){return this.getPointPosition(t,this.getDistanceFromCenterForValue(e))},getBasePosition:function(){var t=this.min,e=this.max;return this.getPointPositionForValue(0,this.beginAtZero?0:t<0&&e<0?e:t>0&&e>0?t:0)},draw:function(){var t=this,e=t.options,i=e.gridLines,n=e.ticks;if(e.display){var a=t.ctx,r=this.getIndexAngle(0),o=ut.options._parseFont(n);(e.angleLines.display||e.pointLabels.display)&&function(t){var e=t.ctx,i=t.options,n=i.angleLines,a=i.gridLines,r=i.pointLabels,o=Ci(n.lineWidth,a.lineWidth),s=Ci(n.color,a.color),l=Ai(i);e.save(),e.lineWidth=o,e.strokeStyle=s,e.setLineDash&&(e.setLineDash(Ti([n.borderDash,a.borderDash,[]])),e.lineDashOffset=Ti([n.borderDashOffset,a.borderDashOffset,0]));var u=t.getDistanceFromCenterForValue(i.ticks.reverse?t.min:t.max),d=ut.options._parseFont(r);e.font=d.string,e.textBaseline="middle";for(var h=Ii(t)-1;h>=0;h--){if(n.display&&o&&s){var c=t.getPointPosition(h,u);e.beginPath(),e.moveTo(t.xCenter,t.yCenter),e.lineTo(c.x,c.y),e.stroke()}if(r.display){var f=0===h?l/2:0,g=t.getPointPosition(h,u+f+5),m=Pi(r.fontColor,h,ot.global.defaultFontColor);e.fillStyle=m;var p=t.getIndexAngle(h),v=ut.toDegrees(p);e.textAlign=Ri(v),Wi(v,t._pointLabelSizes[h],g),Li(e,t.pointLabels[h]||"",g,d.lineHeight)}}e.restore()}(t),ut.each(t.ticks,function(e,s){if(s>0||n.reverse){var l=t.getDistanceFromCenterForValue(t.ticksAsNumbers[s]);if(i.display&&0!==s&&function(t,e,i,n){var a,r=t.ctx,o=e.circular,s=Ii(t),l=Pi(e.color,n-1),u=Pi(e.lineWidth,n-1);if((o||s)&&l&&u){if(r.save(),r.strokeStyle=l,r.lineWidth=u,r.setLineDash&&(r.setLineDash(e.borderDash||[]),r.lineDashOffset=e.borderDashOffset||0),r.beginPath(),o)r.arc(t.xCenter,t.yCenter,i,0,2*Math.PI);else{a=t.getPointPosition(0,i),r.moveTo(a.x,a.y);for(var d=1;d<s;d++)a=t.getPointPosition(d,i),r.lineTo(a.x,a.y)}r.closePath(),r.stroke(),r.restore()}}(t,i,l,s),n.display){var u=Ci(n.fontColor,ot.global.defaultFontColor);if(a.font=o.string,a.save(),a.translate(t.xCenter,t.yCenter),a.rotate(r),n.showLabelBackdrop){var d=a.measureText(e).width;a.fillStyle=n.backdropColor,a.fillRect(-d/2-n.backdropPaddingX,-l-o.size/2-n.backdropPaddingY,d+2*n.backdropPaddingX,o.size+2*n.backdropPaddingY)}a.textAlign="center",a.textBaseline="middle",a.fillStyle=u,a.fillText(e,0,-l),a.restore()}}})}}}),zi=Oi;Ni._defaults=zi;var Vi=ut.valueOrDefault,Hi=Number.MIN_SAFE_INTEGER||-9007199254740991,Ei=Number.MAX_SAFE_INTEGER||9007199254740991,Bi={millisecond:{common:!0,size:1,steps:[1,2,5,10,20,50,100,250,500]},second:{common:!0,size:1e3,steps:[1,2,5,10,15,30]},minute:{common:!0,size:6e4,steps:[1,2,5,10,15,30]},hour:{common:!0,size:36e5,steps:[1,2,3,6,12]},day:{common:!0,size:864e5,steps:[1,2,5]},week:{common:!1,size:6048e5,steps:[1,2,3,4]},month:{common:!0,size:2628e6,steps:[1,2,3]},quarter:{common:!1,size:7884e6,steps:[1,2,3,4]},year:{common:!0,size:3154e7}},ji=Object.keys(Bi);function Ui(t,e){return t-e}function Gi(t){var e,i,n,a={},r=[];for(e=0,i=t.length;e<i;++e)a[n=t[e]]||(a[n]=!0,r.push(n));return r}function qi(t,e,i,n){var a=function(t,e,i){for(var n,a,r,o=0,s=t.length-1;o>=0&&o<=s;){if(a=t[(n=o+s>>1)-1]||null,r=t[n],!a)return{lo:null,hi:r};if(r[e]<i)o=n+1;else{if(!(a[e]>i))return{lo:a,hi:r};s=n-1}}return{lo:r,hi:null}}(t,e,i),r=a.lo?a.hi?a.lo:t[t.length-2]:t[0],o=a.lo?a.hi?a.hi:t[t.length-1]:t[1],s=o[e]-r[e],l=s?(i-r[e])/s:0,u=(o[n]-r[n])*l;return r[n]+u}function Zi(t,e){var i=t._adapter,n=t.options.time,a=n.parser,r=a||n.format,o=e;return"function"==typeof a&&(o=a(o)),ut.isFinite(o)||(o="string"==typeof r?i.parse(o,r):i.parse(o)),null!==o?+o:(a||"function"!=typeof r||(o=r(e),ut.isFinite(o)||(o=i.parse(o))),o)}function $i(t,e){if(ut.isNullOrUndef(e))return null;var i=t.options.time,n=Zi(t,t.getRightValue(e));return null===n?n:(i.round&&(n=+t._adapter.startOf(n,i.round)),n)}function Xi(t){for(var e=ji.indexOf(t)+1,i=ji.length;e<i;++e)if(Bi[ji[e]].common)return ji[e]}function Ki(t,e,i,n){var a,r=t._adapter,o=t.options,s=o.time,l=s.unit||function(t,e,i,n){var a,r,o,s=ji.length;for(a=ji.indexOf(t);a<s-1;++a)if(o=(r=Bi[ji[a]]).steps?r.steps[r.steps.length-1]:Ei,r.common&&Math.ceil((i-e)/(o*r.size))<=n)return ji[a];return ji[s-1]}(s.minUnit,e,i,n),u=Xi(l),d=Vi(s.stepSize,s.unitStepSize),h="week"===l&&s.isoWeekday,c=o.ticks.major.enabled,f=Bi[l],g=e,m=i,p=[];for(d||(d=function(t,e,i,n){var a,r,o,s=e-t,l=Bi[i],u=l.size,d=l.steps;if(!d)return Math.ceil(s/(n*u));for(a=0,r=d.length;a<r&&(o=d[a],!(Math.ceil(s/(u*o))<=n));++a);return o}(e,i,l,n)),h&&(g=+r.startOf(g,"isoWeek",h),m=+r.startOf(m,"isoWeek",h)),g=+r.startOf(g,h?"day":l),(m=+r.startOf(m,h?"day":l))<i&&(m=+r.add(m,1,l)),a=g,c&&u&&!h&&!s.round&&(a=+r.startOf(a,u),a=+r.add(a,~~((g-a)/(f.size*d))*d,l));a<m;a=+r.add(a,d,l))p.push(+a);return p.push(+a),p}var Ji=fi.extend({initialize:function(){this.mergeTicksOptions(),fi.prototype.initialize.call(this)},update:function(){var t=this.options,e=t.time||(t.time={}),i=this._adapter=new si._date(t.adapters.date);return e.format&&console.warn("options.time.format is deprecated and replaced by options.time.parser."),ut.mergeIf(e.displayFormats,i.formats()),fi.prototype.update.apply(this,arguments)},getRightValue:function(t){return t&&void 0!==t.t&&(t=t.t),fi.prototype.getRightValue.call(this,t)},determineDataLimits:function(){var t,e,i,n,a,r,o=this,s=o.chart,l=o._adapter,u=o.options.time,d=u.unit||"day",h=Ei,c=Hi,f=[],g=[],m=[],p=s.data.labels||[];for(t=0,i=p.length;t<i;++t)m.push($i(o,p[t]));for(t=0,i=(s.data.datasets||[]).length;t<i;++t)if(s.isDatasetVisible(t))if(a=s.data.datasets[t].data,ut.isObject(a[0]))for(g[t]=[],e=0,n=a.length;e<n;++e)r=$i(o,a[e]),f.push(r),g[t][e]=r;else{for(e=0,n=m.length;e<n;++e)f.push(m[e]);g[t]=m.slice(0)}else g[t]=[];m.length&&(m=Gi(m).sort(Ui),h=Math.min(h,m[0]),c=Math.max(c,m[m.length-1])),f.length&&(f=Gi(f).sort(Ui),h=Math.min(h,f[0]),c=Math.max(c,f[f.length-1])),h=$i(o,u.min)||h,c=$i(o,u.max)||c,h=h===Ei?+l.startOf(Date.now(),d):h,c=c===Hi?+l.endOf(Date.now(),d)+1:c,o.min=Math.min(h,c),o.max=Math.max(h+1,c),o._horizontal=o.isHorizontal(),o._table=[],o._timestamps={data:f,datasets:g,labels:m}},buildTicks:function(){var t,e,i,n=this,a=n.min,r=n.max,o=n.options,s=o.time,l=[],u=[];switch(o.ticks.source){case"data":l=n._timestamps.data;break;case"labels":l=n._timestamps.labels;break;case"auto":default:l=Ki(n,a,r,n.getLabelCapacity(a))}for("ticks"===o.bounds&&l.length&&(a=l[0],r=l[l.length-1]),a=$i(n,s.min)||a,r=$i(n,s.max)||r,t=0,e=l.length;t<e;++t)(i=l[t])>=a&&i<=r&&u.push(i);return n.min=a,n.max=r,n._unit=s.unit||function(t,e,i,n,a){var r,o;for(r=ji.length-1;r>=ji.indexOf(i);r--)if(o=ji[r],Bi[o].common&&t._adapter.diff(a,n,o)>=e.length)return o;return ji[i?ji.indexOf(i):0]}(n,u,s.minUnit,n.min,n.max),n._majorUnit=Xi(n._unit),n._table=function(t,e,i,n){if("linear"===n||!t.length)return[{time:e,pos:0},{time:i,pos:1}];var a,r,o,s,l,u=[],d=[e];for(a=0,r=t.length;a<r;++a)(s=t[a])>e&&s<i&&d.push(s);for(d.push(i),a=0,r=d.length;a<r;++a)l=d[a+1],o=d[a-1],s=d[a],void 0!==o&&void 0!==l&&Math.round((l+o)/2)===s||u.push({time:s,pos:a/(r-1)});return u}(n._timestamps.data,a,r,o.distribution),n._offsets=function(t,e,i,n,a){var r,o,s=0,l=0;return a.offset&&e.length&&(a.time.min||(r=qi(t,"time",e[0],"pos"),s=1===e.length?1-r:(qi(t,"time",e[1],"pos")-r)/2),a.time.max||(o=qi(t,"time",e[e.length-1],"pos"),l=1===e.length?o:(o-qi(t,"time",e[e.length-2],"pos"))/2)),{start:s,end:l}}(n._table,u,0,0,o),o.ticks.reverse&&u.reverse(),function(t,e,i){var n,a,r,o,s=[];for(n=0,a=e.length;n<a;++n)r=e[n],o=!!i&&r===+t._adapter.startOf(r,i),s.push({value:r,major:o});return s}(n,u,n._majorUnit)},getLabelForIndex:function(t,e){var i=this,n=i._adapter,a=i.chart.data,r=i.options.time,o=a.labels&&t<a.labels.length?a.labels[t]:"",s=a.datasets[e].data[t];return ut.isObject(s)&&(o=i.getRightValue(s)),r.tooltipFormat?n.format(Zi(i,o),r.tooltipFormat):"string"==typeof o?o:n.format(Zi(i,o),r.displayFormats.datetime)},tickFormatFunction:function(t,e,i,n){var a=this._adapter,r=this.options,o=r.time.displayFormats,s=o[this._unit],l=this._majorUnit,u=o[l],d=+a.startOf(t,l),h=r.ticks.major,c=h.enabled&&l&&u&&t===d,f=a.format(t,n||(c?u:s)),g=c?h:r.ticks.minor,m=Vi(g.callback,g.userCallback);return m?m(f,e,i):f},convertTicksToLabels:function(t){var e,i,n=[];for(e=0,i=t.length;e<i;++e)n.push(this.tickFormatFunction(t[e].value,e,t));return n},getPixelForOffset:function(t){var e=this,i=e.options.ticks.reverse,n=e._horizontal?e.width:e.height,a=e._horizontal?i?e.right:e.left:i?e.bottom:e.top,r=qi(e._table,"time",t,"pos"),o=n*(e._offsets.start+r)/(e._offsets.start+1+e._offsets.end);return i?a-o:a+o},getPixelForValue:function(t,e,i){var n=null;if(void 0!==e&&void 0!==i&&(n=this._timestamps.datasets[i][e]),null===n&&(n=$i(this,t)),null!==n)return this.getPixelForOffset(n)},getPixelForTick:function(t){var e=this.getTicks();return t>=0&&t<e.length?this.getPixelForOffset(e[t].value):null},getValueForPixel:function(t){var e=this,i=e._horizontal?e.width:e.height,n=e._horizontal?e.left:e.top,a=(i?(t-n)/i:0)*(e._offsets.start+1+e._offsets.start)-e._offsets.end,r=qi(e._table,"pos",a,"time");return e._adapter._create(r)},getLabelWidth:function(t){var e=this.options.ticks,i=this.ctx.measureText(t).width,n=ut.toRadians(e.maxRotation),a=Math.cos(n),r=Math.sin(n);return i*a+Vi(e.fontSize,ot.global.defaultFontSize)*r},getLabelCapacity:function(t){var e=this,i=e.options.time.displayFormats.millisecond,n=e.tickFormatFunction(t,0,[],i),a=e.getLabelWidth(n),r=e.isHorizontal()?e.width:e.height,o=Math.floor(r/a);return o>0?o:1}}),Qi={position:"bottom",distribution:"linear",bounds:"data",adapters:{},time:{parser:!1,format:!1,unit:!1,round:!1,displayFormat:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{autoSkip:!1,source:"auto",major:{enabled:!1}}};Ji._defaults=Qi;var tn,en={category:gi,linear:xi,logarithmic:Si,radialLinear:Ni,time:Ji},nn=(function(t,e){t.exports=function(){var e,i;function n(){return e.apply(null,arguments)}function a(t){return t instanceof Array||"[object Array]"===Object.prototype.toString.call(t)}function r(t){return null!=t&&"[object Object]"===Object.prototype.toString.call(t)}function o(t){return void 0===t}function s(t){return"number"==typeof t||"[object Number]"===Object.prototype.toString.call(t)}function l(t){return t instanceof Date||"[object Date]"===Object.prototype.toString.call(t)}function u(t,e){var i,n=[];for(i=0;i<t.length;++i)n.push(e(t[i],i));return n}function d(t,e){return Object.prototype.hasOwnProperty.call(t,e)}function h(t,e){for(var i in e)d(e,i)&&(t[i]=e[i]);return d(e,"toString")&&(t.toString=e.toString),d(e,"valueOf")&&(t.valueOf=e.valueOf),t}function c(t,e,i,n){return Oe(t,e,i,n,!0).utc()}function f(t){return null==t._pf&&(t._pf={empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],meridiem:null,rfc2822:!1,weekdayMismatch:!1}),t._pf}function g(t){if(null==t._isValid){var e=f(t),n=i.call(e.parsedDateParts,function(t){return null!=t}),a=!isNaN(t._d.getTime())&&e.overflow<0&&!e.empty&&!e.invalidMonth&&!e.invalidWeekday&&!e.weekdayMismatch&&!e.nullInput&&!e.invalidFormat&&!e.userInvalidated&&(!e.meridiem||e.meridiem&&n);if(t._strict&&(a=a&&0===e.charsLeftOver&&0===e.unusedTokens.length&&void 0===e.bigHour),null!=Object.isFrozen&&Object.isFrozen(t))return a;t._isValid=a}return t._isValid}function m(t){var e=c(NaN);return null!=t?h(f(e),t):f(e).userInvalidated=!0,e}i=Array.prototype.some?Array.prototype.some:function(t){for(var e=Object(this),i=e.length>>>0,n=0;n<i;n++)if(n in e&&t.call(this,e[n],n,e))return!0;return!1};var p=n.momentProperties=[];function v(t,e){var i,n,a;if(o(e._isAMomentObject)||(t._isAMomentObject=e._isAMomentObject),o(e._i)||(t._i=e._i),o(e._f)||(t._f=e._f),o(e._l)||(t._l=e._l),o(e._strict)||(t._strict=e._strict),o(e._tzm)||(t._tzm=e._tzm),o(e._isUTC)||(t._isUTC=e._isUTC),o(e._offset)||(t._offset=e._offset),o(e._pf)||(t._pf=f(e)),o(e._locale)||(t._locale=e._locale),p.length>0)for(i=0;i<p.length;i++)n=p[i],o(a=e[n])||(t[n]=a);return t}var y=!1;function b(t){v(this,t),this._d=new Date(null!=t._d?t._d.getTime():NaN),this.isValid()||(this._d=new Date(NaN)),!1===y&&(y=!0,n.updateOffset(this),y=!1)}function x(t){return t instanceof b||null!=t&&null!=t._isAMomentObject}function _(t){return t<0?Math.ceil(t)||0:Math.floor(t)}function k(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=_(e)),i}function w(t,e,i){var n,a=Math.min(t.length,e.length),r=Math.abs(t.length-e.length),o=0;for(n=0;n<a;n++)(i&&t[n]!==e[n]||!i&&k(t[n])!==k(e[n]))&&o++;return o+r}function M(t){!1===n.suppressDeprecationWarnings&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+t)}function S(t,e){var i=!0;return h(function(){if(null!=n.deprecationHandler&&n.deprecationHandler(null,t),i){for(var a,r=[],o=0;o<arguments.length;o++){if(a="","object"==typeof arguments[o]){for(var s in a+="\n["+o+"] ",arguments[0])a+=s+": "+arguments[0][s]+", ";a=a.slice(0,-2)}else a=arguments[o];r.push(a)}M(t+"\nArguments: "+Array.prototype.slice.call(r).join("")+"\n"+(new Error).stack),i=!1}return e.apply(this,arguments)},e)}var D,C={};function P(t,e){null!=n.deprecationHandler&&n.deprecationHandler(t,e),C[t]||(M(e),C[t]=!0)}function T(t){return t instanceof Function||"[object Function]"===Object.prototype.toString.call(t)}function O(t,e){var i,n=h({},t);for(i in e)d(e,i)&&(r(t[i])&&r(e[i])?(n[i]={},h(n[i],t[i]),h(n[i],e[i])):null!=e[i]?n[i]=e[i]:delete n[i]);for(i in t)d(t,i)&&!d(e,i)&&r(t[i])&&(n[i]=h({},n[i]));return n}function I(t){null!=t&&this.set(t)}n.suppressDeprecationWarnings=!1,n.deprecationHandler=null,D=Object.keys?Object.keys:function(t){var e,i=[];for(e in t)d(t,e)&&i.push(e);return i};var A={};function F(t,e){var i=t.toLowerCase();A[i]=A[i+"s"]=A[e]=t}function R(t){return"string"==typeof t?A[t]||A[t.toLowerCase()]:void 0}function L(t){var e,i,n={};for(i in t)d(t,i)&&(e=R(i))&&(n[e]=t[i]);return n}var W={};function Y(t,e){W[t]=e}function N(t,e,i){var n=""+Math.abs(t),a=e-n.length,r=t>=0;return(r?i?"+":"":"-")+Math.pow(10,Math.max(0,a)).toString().substr(1)+n}var z=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,V=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,H={},E={};function B(t,e,i,n){var a=n;"string"==typeof n&&(a=function(){return this[n]()}),t&&(E[t]=a),e&&(E[e[0]]=function(){return N(a.apply(this,arguments),e[1],e[2])}),i&&(E[i]=function(){return this.localeData().ordinal(a.apply(this,arguments),t)})}function j(t,e){return t.isValid()?(e=U(e,t.localeData()),H[e]=H[e]||function(t){var e,i,n,a=t.match(z);for(e=0,i=a.length;e<i;e++)E[a[e]]?a[e]=E[a[e]]:a[e]=(n=a[e]).match(/\[[\s\S]/)?n.replace(/^\[|\]$/g,""):n.replace(/\\/g,"");return function(e){var n,r="";for(n=0;n<i;n++)r+=T(a[n])?a[n].call(e,t):a[n];return r}}(e),H[e](t)):t.localeData().invalidDate()}function U(t,e){var i=5;function n(t){return e.longDateFormat(t)||t}for(V.lastIndex=0;i>=0&&V.test(t);)t=t.replace(V,n),V.lastIndex=0,i-=1;return t}var G=/\d/,q=/\d\d/,Z=/\d{3}/,$=/\d{4}/,X=/[+-]?\d{6}/,K=/\d\d?/,J=/\d\d\d\d?/,Q=/\d\d\d\d\d\d?/,tt=/\d{1,3}/,et=/\d{1,4}/,it=/[+-]?\d{1,6}/,nt=/\d+/,at=/[+-]?\d+/,rt=/Z|[+-]\d\d:?\d\d/gi,ot=/Z|[+-]\d\d(?::?\d\d)?/gi,st=/[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i,lt={};function ut(t,e,i){lt[t]=T(e)?e:function(t,n){return t&&i?i:e}}function dt(t,e){return d(lt,t)?lt[t](e._strict,e._locale):new RegExp(ht(t.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,a){return e||i||n||a})))}function ht(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}var ct={};function ft(t,e){var i,n=e;for("string"==typeof t&&(t=[t]),s(e)&&(n=function(t,i){i[e]=k(t)}),i=0;i<t.length;i++)ct[t[i]]=n}function gt(t,e){ft(t,function(t,i,n,a){n._w=n._w||{},e(t,n._w,n,a)})}function mt(t,e,i){null!=e&&d(ct,t)&&ct[t](e,i._a,i,t)}var pt=0,vt=1,yt=2,bt=3,xt=4,_t=5,kt=6,wt=7,Mt=8;function St(t){return Dt(t)?366:365}function Dt(t){return t%4==0&&t%100!=0||t%400==0}B("Y",0,0,function(){var t=this.year();return t<=9999?""+t:"+"+t}),B(0,["YY",2],0,function(){return this.year()%100}),B(0,["YYYY",4],0,"year"),B(0,["YYYYY",5],0,"year"),B(0,["YYYYYY",6,!0],0,"year"),F("year","y"),Y("year",1),ut("Y",at),ut("YY",K,q),ut("YYYY",et,$),ut("YYYYY",it,X),ut("YYYYYY",it,X),ft(["YYYYY","YYYYYY"],pt),ft("YYYY",function(t,e){e[pt]=2===t.length?n.parseTwoDigitYear(t):k(t)}),ft("YY",function(t,e){e[pt]=n.parseTwoDigitYear(t)}),ft("Y",function(t,e){e[pt]=parseInt(t,10)}),n.parseTwoDigitYear=function(t){return k(t)+(k(t)>68?1900:2e3)};var Ct,Pt=Tt("FullYear",!0);function Tt(t,e){return function(i){return null!=i?(It(this,t,i),n.updateOffset(this,e),this):Ot(this,t)}}function Ot(t,e){return t.isValid()?t._d["get"+(t._isUTC?"UTC":"")+e]():NaN}function It(t,e,i){t.isValid()&&!isNaN(i)&&("FullYear"===e&&Dt(t.year())&&1===t.month()&&29===t.date()?t._d["set"+(t._isUTC?"UTC":"")+e](i,t.month(),At(i,t.month())):t._d["set"+(t._isUTC?"UTC":"")+e](i))}function At(t,e){if(isNaN(t)||isNaN(e))return NaN;var i,n=(e%(i=12)+i)%i;return t+=(e-n)/12,1===n?Dt(t)?29:28:31-n%7%2}Ct=Array.prototype.indexOf?Array.prototype.indexOf:function(t){var e;for(e=0;e<this.length;++e)if(this[e]===t)return e;return-1},B("M",["MM",2],"Mo",function(){return this.month()+1}),B("MMM",0,0,function(t){return this.localeData().monthsShort(this,t)}),B("MMMM",0,0,function(t){return this.localeData().months(this,t)}),F("month","M"),Y("month",8),ut("M",K),ut("MM",K,q),ut("MMM",function(t,e){return e.monthsShortRegex(t)}),ut("MMMM",function(t,e){return e.monthsRegex(t)}),ft(["M","MM"],function(t,e){e[vt]=k(t)-1}),ft(["MMM","MMMM"],function(t,e,i,n){var a=i._locale.monthsParse(t,n,i._strict);null!=a?e[vt]=a:f(i).invalidMonth=t});var Ft=/D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/,Rt="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),Lt="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_");function Wt(t,e){var i;if(!t.isValid())return t;if("string"==typeof e)if(/^\d+$/.test(e))e=k(e);else if(!s(e=t.localeData().monthsParse(e)))return t;return i=Math.min(t.date(),At(t.year(),e)),t._d["set"+(t._isUTC?"UTC":"")+"Month"](e,i),t}function Yt(t){return null!=t?(Wt(this,t),n.updateOffset(this,!0),this):Ot(this,"Month")}var Nt=st,zt=st;function Vt(){function t(t,e){return e.length-t.length}var e,i,n=[],a=[],r=[];for(e=0;e<12;e++)i=c([2e3,e]),n.push(this.monthsShort(i,"")),a.push(this.months(i,"")),r.push(this.months(i,"")),r.push(this.monthsShort(i,""));for(n.sort(t),a.sort(t),r.sort(t),e=0;e<12;e++)n[e]=ht(n[e]),a[e]=ht(a[e]);for(e=0;e<24;e++)r[e]=ht(r[e]);this._monthsRegex=new RegExp("^("+r.join("|")+")","i"),this._monthsShortRegex=this._monthsRegex,this._monthsStrictRegex=new RegExp("^("+a.join("|")+")","i"),this._monthsShortStrictRegex=new RegExp("^("+n.join("|")+")","i")}function Ht(t){var e;if(t<100&&t>=0){var i=Array.prototype.slice.call(arguments);i[0]=t+400,e=new Date(Date.UTC.apply(null,i)),isFinite(e.getUTCFullYear())&&e.setUTCFullYear(t)}else e=new Date(Date.UTC.apply(null,arguments));return e}function Et(t,e,i){var n=7+e-i,a=(7+Ht(t,0,n).getUTCDay()-e)%7;return-a+n-1}function Bt(t,e,i,n,a){var r,o,s=(7+i-n)%7,l=Et(t,n,a),u=1+7*(e-1)+s+l;return u<=0?o=St(r=t-1)+u:u>St(t)?(r=t+1,o=u-St(t)):(r=t,o=u),{year:r,dayOfYear:o}}function jt(t,e,i){var n,a,r=Et(t.year(),e,i),o=Math.floor((t.dayOfYear()-r-1)/7)+1;return o<1?(a=t.year()-1,n=o+Ut(a,e,i)):o>Ut(t.year(),e,i)?(n=o-Ut(t.year(),e,i),a=t.year()+1):(a=t.year(),n=o),{week:n,year:a}}function Ut(t,e,i){var n=Et(t,e,i),a=Et(t+1,e,i);return(St(t)-n+a)/7}function Gt(t,e){return t.slice(e,7).concat(t.slice(0,e))}B("w",["ww",2],"wo","week"),B("W",["WW",2],"Wo","isoWeek"),F("week","w"),F("isoWeek","W"),Y("week",5),Y("isoWeek",5),ut("w",K),ut("ww",K,q),ut("W",K),ut("WW",K,q),gt(["w","ww","W","WW"],function(t,e,i,n){e[n.substr(0,1)]=k(t)}),B("d",0,"do","day"),B("dd",0,0,function(t){return this.localeData().weekdaysMin(this,t)}),B("ddd",0,0,function(t){return this.localeData().weekdaysShort(this,t)}),B("dddd",0,0,function(t){return this.localeData().weekdays(this,t)}),B("e",0,0,"weekday"),B("E",0,0,"isoWeekday"),F("day","d"),F("weekday","e"),F("isoWeekday","E"),Y("day",11),Y("weekday",11),Y("isoWeekday",11),ut("d",K),ut("e",K),ut("E",K),ut("dd",function(t,e){return e.weekdaysMinRegex(t)}),ut("ddd",function(t,e){return e.weekdaysShortRegex(t)}),ut("dddd",function(t,e){return e.weekdaysRegex(t)}),gt(["dd","ddd","dddd"],function(t,e,i,n){var a=i._locale.weekdaysParse(t,n,i._strict);null!=a?e.d=a:f(i).invalidWeekday=t}),gt(["d","e","E"],function(t,e,i,n){e[n]=k(t)});var qt="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Zt="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),$t="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),Xt=st,Kt=st,Jt=st;function Qt(){function t(t,e){return e.length-t.length}var e,i,n,a,r,o=[],s=[],l=[],u=[];for(e=0;e<7;e++)i=c([2e3,1]).day(e),n=this.weekdaysMin(i,""),a=this.weekdaysShort(i,""),r=this.weekdays(i,""),o.push(n),s.push(a),l.push(r),u.push(n),u.push(a),u.push(r);for(o.sort(t),s.sort(t),l.sort(t),u.sort(t),e=0;e<7;e++)s[e]=ht(s[e]),l[e]=ht(l[e]),u[e]=ht(u[e]);this._weekdaysRegex=new RegExp("^("+u.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+l.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+s.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+o.join("|")+")","i")}function te(){return this.hours()%12||12}function ee(t,e){B(t,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),e)})}function ie(t,e){return e._meridiemParse}B("H",["HH",2],0,"hour"),B("h",["hh",2],0,te),B("k",["kk",2],0,function(){return this.hours()||24}),B("hmm",0,0,function(){return""+te.apply(this)+N(this.minutes(),2)}),B("hmmss",0,0,function(){return""+te.apply(this)+N(this.minutes(),2)+N(this.seconds(),2)}),B("Hmm",0,0,function(){return""+this.hours()+N(this.minutes(),2)}),B("Hmmss",0,0,function(){return""+this.hours()+N(this.minutes(),2)+N(this.seconds(),2)}),ee("a",!0),ee("A",!1),F("hour","h"),Y("hour",13),ut("a",ie),ut("A",ie),ut("H",K),ut("h",K),ut("k",K),ut("HH",K,q),ut("hh",K,q),ut("kk",K,q),ut("hmm",J),ut("hmmss",Q),ut("Hmm",J),ut("Hmmss",Q),ft(["H","HH"],bt),ft(["k","kk"],function(t,e,i){var n=k(t);e[bt]=24===n?0:n}),ft(["a","A"],function(t,e,i){i._isPm=i._locale.isPM(t),i._meridiem=t}),ft(["h","hh"],function(t,e,i){e[bt]=k(t),f(i).bigHour=!0}),ft("hmm",function(t,e,i){var n=t.length-2;e[bt]=k(t.substr(0,n)),e[xt]=k(t.substr(n)),f(i).bigHour=!0}),ft("hmmss",function(t,e,i){var n=t.length-4,a=t.length-2;e[bt]=k(t.substr(0,n)),e[xt]=k(t.substr(n,2)),e[_t]=k(t.substr(a)),f(i).bigHour=!0}),ft("Hmm",function(t,e,i){var n=t.length-2;e[bt]=k(t.substr(0,n)),e[xt]=k(t.substr(n))}),ft("Hmmss",function(t,e,i){var n=t.length-4,a=t.length-2;e[bt]=k(t.substr(0,n)),e[xt]=k(t.substr(n,2)),e[_t]=k(t.substr(a))});var ne,ae=Tt("Hours",!0),re={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:Rt,monthsShort:Lt,week:{dow:0,doy:6},weekdays:qt,weekdaysMin:$t,weekdaysShort:Zt,meridiemParse:/[ap]\.?m?\.?/i},oe={},se={};function le(t){return t?t.toLowerCase().replace("_","-"):t}function ue(e){var i=null;if(!oe[e]&&t&&t.exports)try{i=ne._abbr;var n=_e;n("./locale/"+e),de(i)}catch(t){}return oe[e]}function de(t,e){var i;return t&&((i=o(e)?ce(t):he(t,e))?ne=i:"undefined"!=typeof console&&console.warn&&console.warn("Locale "+t+" not found. Did you forget to load it?")),ne._abbr}function he(t,e){if(null!==e){var i,n=re;if(e.abbr=t,null!=oe[t])P("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),n=oe[t]._config;else if(null!=e.parentLocale)if(null!=oe[e.parentLocale])n=oe[e.parentLocale]._config;else{if(null==(i=ue(e.parentLocale)))return se[e.parentLocale]||(se[e.parentLocale]=[]),se[e.parentLocale].push({name:t,config:e}),null;n=i._config}return oe[t]=new I(O(n,e)),se[t]&&se[t].forEach(function(t){he(t.name,t.config)}),de(t),oe[t]}return delete oe[t],null}function ce(t){var e;if(t&&t._locale&&t._locale._abbr&&(t=t._locale._abbr),!t)return ne;if(!a(t)){if(e=ue(t))return e;t=[t]}return function(t){for(var e,i,n,a,r=0;r<t.length;){for(a=le(t[r]).split("-"),e=a.length,i=(i=le(t[r+1]))?i.split("-"):null;e>0;){if(n=ue(a.slice(0,e).join("-")))return n;if(i&&i.length>=e&&w(a,i,!0)>=e-1)break;e--}r++}return ne}(t)}function fe(t){var e,i=t._a;return i&&-2===f(t).overflow&&(e=i[vt]<0||i[vt]>11?vt:i[yt]<1||i[yt]>At(i[pt],i[vt])?yt:i[bt]<0||i[bt]>24||24===i[bt]&&(0!==i[xt]||0!==i[_t]||0!==i[kt])?bt:i[xt]<0||i[xt]>59?xt:i[_t]<0||i[_t]>59?_t:i[kt]<0||i[kt]>999?kt:-1,f(t)._overflowDayOfYear&&(e<pt||e>yt)&&(e=yt),f(t)._overflowWeeks&&-1===e&&(e=wt),f(t)._overflowWeekday&&-1===e&&(e=Mt),f(t).overflow=e),t}function ge(t,e,i){return null!=t?t:null!=e?e:i}function me(t){var e,i,a,r,o,s=[];if(!t._d){for(a=function(t){var e=new Date(n.now());return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}(t),t._w&&null==t._a[yt]&&null==t._a[vt]&&function(t){var e,i,n,a,r,o,s,l;if(null!=(e=t._w).GG||null!=e.W||null!=e.E)r=1,o=4,i=ge(e.GG,t._a[pt],jt(Ie(),1,4).year),n=ge(e.W,1),((a=ge(e.E,1))<1||a>7)&&(l=!0);else{r=t._locale._week.dow,o=t._locale._week.doy;var u=jt(Ie(),r,o);i=ge(e.gg,t._a[pt],u.year),n=ge(e.w,u.week),null!=e.d?((a=e.d)<0||a>6)&&(l=!0):null!=e.e?(a=e.e+r,(e.e<0||e.e>6)&&(l=!0)):a=r}n<1||n>Ut(i,r,o)?f(t)._overflowWeeks=!0:null!=l?f(t)._overflowWeekday=!0:(s=Bt(i,n,a,r,o),t._a[pt]=s.year,t._dayOfYear=s.dayOfYear)}(t),null!=t._dayOfYear&&(o=ge(t._a[pt],a[pt]),(t._dayOfYear>St(o)||0===t._dayOfYear)&&(f(t)._overflowDayOfYear=!0),i=Ht(o,0,t._dayOfYear),t._a[vt]=i.getUTCMonth(),t._a[yt]=i.getUTCDate()),e=0;e<3&&null==t._a[e];++e)t._a[e]=s[e]=a[e];for(;e<7;e++)t._a[e]=s[e]=null==t._a[e]?2===e?1:0:t._a[e];24===t._a[bt]&&0===t._a[xt]&&0===t._a[_t]&&0===t._a[kt]&&(t._nextDay=!0,t._a[bt]=0),t._d=(t._useUTC?Ht:function(t,e,i,n,a,r,o){var s;return t<100&&t>=0?(s=new Date(t+400,e,i,n,a,r,o),isFinite(s.getFullYear())&&s.setFullYear(t)):s=new Date(t,e,i,n,a,r,o),s}).apply(null,s),r=t._useUTC?t._d.getUTCDay():t._d.getDay(),null!=t._tzm&&t._d.setUTCMinutes(t._d.getUTCMinutes()-t._tzm),t._nextDay&&(t._a[bt]=24),t._w&&void 0!==t._w.d&&t._w.d!==r&&(f(t).weekdayMismatch=!0)}}var pe=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,ve=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,ye=/Z|[+-]\d\d(?::?\d\d)?/,be=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],xe=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],ke=/^\/?Date\((\-?\d+)/i;function we(t){var e,i,n,a,r,o,s=t._i,l=pe.exec(s)||ve.exec(s);if(l){for(f(t).iso=!0,e=0,i=be.length;e<i;e++)if(be[e][1].exec(l[1])){a=be[e][0],n=!1!==be[e][2];break}if(null==a)return void(t._isValid=!1);if(l[3]){for(e=0,i=xe.length;e<i;e++)if(xe[e][1].exec(l[3])){r=(l[2]||" ")+xe[e][0];break}if(null==r)return void(t._isValid=!1)}if(!n&&null!=r)return void(t._isValid=!1);if(l[4]){if(!ye.exec(l[4]))return void(t._isValid=!1);o="Z"}t._f=a+(r||"")+(o||""),Pe(t)}else t._isValid=!1}var Me=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/;function Se(t){var e=parseInt(t,10);return e<=49?2e3+e:e<=999?1900+e:e}var De={UT:0,GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function Ce(t){var e,i,n,a,r,o,s,l=Me.exec(t._i.replace(/\([^)]*\)|[\n\t]/g," ").replace(/(\s\s+)/g," ").replace(/^\s\s*/,"").replace(/\s\s*$/,""));if(l){var u=(e=l[4],i=l[3],n=l[2],a=l[5],r=l[6],o=l[7],s=[Se(e),Lt.indexOf(i),parseInt(n,10),parseInt(a,10),parseInt(r,10)],o&&s.push(parseInt(o,10)),s);if(!function(t,e,i){if(t){var n=Zt.indexOf(t),a=new Date(e[0],e[1],e[2]).getDay();if(n!==a)return f(i).weekdayMismatch=!0,i._isValid=!1,!1}return!0}(l[1],u,t))return;t._a=u,t._tzm=function(t,e,i){if(t)return De[t];if(e)return 0;var n=parseInt(i,10),a=n%100,r=(n-a)/100;return 60*r+a}(l[8],l[9],l[10]),t._d=Ht.apply(null,t._a),t._d.setUTCMinutes(t._d.getUTCMinutes()-t._tzm),f(t).rfc2822=!0}else t._isValid=!1}function Pe(t){if(t._f!==n.ISO_8601)if(t._f!==n.RFC_2822){t._a=[],f(t).empty=!0;var e,i,a,r,o,s=""+t._i,l=s.length,u=0;for(a=U(t._f,t._locale).match(z)||[],e=0;e<a.length;e++)r=a[e],(i=(s.match(dt(r,t))||[])[0])&&((o=s.substr(0,s.indexOf(i))).length>0&&f(t).unusedInput.push(o),s=s.slice(s.indexOf(i)+i.length),u+=i.length),E[r]?(i?f(t).empty=!1:f(t).unusedTokens.push(r),mt(r,i,t)):t._strict&&!i&&f(t).unusedTokens.push(r);f(t).charsLeftOver=l-u,s.length>0&&f(t).unusedInput.push(s),t._a[bt]<=12&&!0===f(t).bigHour&&t._a[bt]>0&&(f(t).bigHour=void 0),f(t).parsedDateParts=t._a.slice(0),f(t).meridiem=t._meridiem,t._a[bt]=(d=t._locale,h=t._a[bt],null==(c=t._meridiem)?h:null!=d.meridiemHour?d.meridiemHour(h,c):null!=d.isPM?((g=d.isPM(c))&&h<12&&(h+=12),g||12!==h||(h=0),h):h),me(t),fe(t)}else Ce(t);else we(t);var d,h,c,g}function Te(t){var e=t._i,i=t._f;return t._locale=t._locale||ce(t._l),null===e||void 0===i&&""===e?m({nullInput:!0}):("string"==typeof e&&(t._i=e=t._locale.preparse(e)),x(e)?new b(fe(e)):(l(e)?t._d=e:a(i)?function(t){var e,i,n,a,r;if(0===t._f.length)return f(t).invalidFormat=!0,void(t._d=new Date(NaN));for(a=0;a<t._f.length;a++)r=0,e=v({},t),null!=t._useUTC&&(e._useUTC=t._useUTC),e._f=t._f[a],Pe(e),g(e)&&(r+=f(e).charsLeftOver,r+=10*f(e).unusedTokens.length,f(e).score=r,(null==n||r<n)&&(n=r,i=e));h(t,i||e)}(t):i?Pe(t):function(t){var e=t._i;o(e)?t._d=new Date(n.now()):l(e)?t._d=new Date(e.valueOf()):"string"==typeof e?function(t){var e=ke.exec(t._i);null===e?(we(t),!1===t._isValid&&(delete t._isValid,Ce(t),!1===t._isValid&&(delete t._isValid,n.createFromInputFallback(t)))):t._d=new Date(+e[1])}(t):a(e)?(t._a=u(e.slice(0),function(t){return parseInt(t,10)}),me(t)):r(e)?function(t){if(!t._d){var e=L(t._i);t._a=u([e.year,e.month,e.day||e.date,e.hour,e.minute,e.second,e.millisecond],function(t){return t&&parseInt(t,10)}),me(t)}}(t):s(e)?t._d=new Date(e):n.createFromInputFallback(t)}(t),g(t)||(t._d=null),t))}function Oe(t,e,i,n,o){var s,l={};return!0!==i&&!1!==i||(n=i,i=void 0),(r(t)&&function(t){if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(t).length;var e;for(e in t)if(t.hasOwnProperty(e))return!1;return!0}(t)||a(t)&&0===t.length)&&(t=void 0),l._isAMomentObject=!0,l._useUTC=l._isUTC=o,l._l=i,l._i=t,l._f=e,l._strict=n,(s=new b(fe(Te(l))))._nextDay&&(s.add(1,"d"),s._nextDay=void 0),s}function Ie(t,e,i,n){return Oe(t,e,i,n,!1)}n.createFromInputFallback=S("value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",function(t){t._d=new Date(t._i+(t._useUTC?" UTC":""))}),n.ISO_8601=function(){},n.RFC_2822=function(){};var Ae=S("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var t=Ie.apply(null,arguments);return this.isValid()&&t.isValid()?t<this?this:t:m()}),Fe=S("moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var t=Ie.apply(null,arguments);return this.isValid()&&t.isValid()?t>this?this:t:m()});function Re(t,e){var i,n;if(1===e.length&&a(e[0])&&(e=e[0]),!e.length)return Ie();for(i=e[0],n=1;n<e.length;++n)e[n].isValid()&&!e[n][t](i)||(i=e[n]);return i}var Le=["year","quarter","month","week","day","hour","minute","second","millisecond"];function We(t){var e=L(t),i=e.year||0,n=e.quarter||0,a=e.month||0,r=e.week||e.isoWeek||0,o=e.day||0,s=e.hour||0,l=e.minute||0,u=e.second||0,d=e.millisecond||0;this._isValid=function(t){for(var e in t)if(-1===Ct.call(Le,e)||null!=t[e]&&isNaN(t[e]))return!1;for(var i=!1,n=0;n<Le.length;++n)if(t[Le[n]]){if(i)return!1;parseFloat(t[Le[n]])!==k(t[Le[n]])&&(i=!0)}return!0}(e),this._milliseconds=+d+1e3*u+6e4*l+1e3*s*60*60,this._days=+o+7*r,this._months=+a+3*n+12*i,this._data={},this._locale=ce(),this._bubble()}function Ye(t){return t instanceof We}function Ne(t){return t<0?-1*Math.round(-1*t):Math.round(t)}function ze(t,e){B(t,0,0,function(){var t=this.utcOffset(),i="+";return t<0&&(t=-t,i="-"),i+N(~~(t/60),2)+e+N(~~t%60,2)})}ze("Z",":"),ze("ZZ",""),ut("Z",ot),ut("ZZ",ot),ft(["Z","ZZ"],function(t,e,i){i._useUTC=!0,i._tzm=He(ot,t)});var Ve=/([\+\-]|\d\d)/gi;function He(t,e){var i=(e||"").match(t);if(null===i)return null;var n=i[i.length-1]||[],a=(n+"").match(Ve)||["-",0,0],r=60*a[1]+k(a[2]);return 0===r?0:"+"===a[0]?r:-r}function Ee(t,e){var i,a;return e._isUTC?(i=e.clone(),a=(x(t)||l(t)?t.valueOf():Ie(t).valueOf())-i.valueOf(),i._d.setTime(i._d.valueOf()+a),n.updateOffset(i,!1),i):Ie(t).local()}function Be(t){return 15*-Math.round(t._d.getTimezoneOffset()/15)}function je(){return!!this.isValid()&&this._isUTC&&0===this._offset}n.updateOffset=function(){};var Ue=/^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,Ge=/^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;function qe(t,e){var i,n,a,r,o,l,u=t,h=null;return Ye(t)?u={ms:t._milliseconds,d:t._days,M:t._months}:s(t)?(u={},e?u[e]=t:u.milliseconds=t):(h=Ue.exec(t))?(i="-"===h[1]?-1:1,u={y:0,d:k(h[yt])*i,h:k(h[bt])*i,m:k(h[xt])*i,s:k(h[_t])*i,ms:k(Ne(1e3*h[kt]))*i}):(h=Ge.exec(t))?(i="-"===h[1]?-1:1,u={y:Ze(h[2],i),M:Ze(h[3],i),w:Ze(h[4],i),d:Ze(h[5],i),h:Ze(h[6],i),m:Ze(h[7],i),s:Ze(h[8],i)}):null==u?u={}:"object"==typeof u&&("from"in u||"to"in u)&&(r=Ie(u.from),o=Ie(u.to),a=r.isValid()&&o.isValid()?(o=Ee(o,r),r.isBefore(o)?l=$e(r,o):((l=$e(o,r)).milliseconds=-l.milliseconds,l.months=-l.months),l):{milliseconds:0,months:0},(u={}).ms=a.milliseconds,u.M=a.months),n=new We(u),Ye(t)&&d(t,"_locale")&&(n._locale=t._locale),n}function Ze(t,e){var i=t&&parseFloat(t.replace(",","."));return(isNaN(i)?0:i)*e}function $e(t,e){var i={};return i.months=e.month()-t.month()+12*(e.year()-t.year()),t.clone().add(i.months,"M").isAfter(e)&&--i.months,i.milliseconds=+e-+t.clone().add(i.months,"M"),i}function Xe(t,e){return function(i,n){var a;return null===n||isNaN(+n)||(P(e,"moment()."+e+"(period, number) is deprecated. Please use moment()."+e+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),a=i,i=n,n=a),Ke(this,qe(i="string"==typeof i?+i:i,n),t),this}}function Ke(t,e,i,a){var r=e._milliseconds,o=Ne(e._days),s=Ne(e._months);t.isValid()&&(a=null==a||a,s&&Wt(t,Ot(t,"Month")+s*i),o&&It(t,"Date",Ot(t,"Date")+o*i),r&&t._d.setTime(t._d.valueOf()+r*i),a&&n.updateOffset(t,o||s))}qe.fn=We.prototype,qe.invalid=function(){return qe(NaN)};var Je=Xe(1,"add"),Qe=Xe(-1,"subtract");function ti(t,e){var i,n,a=12*(e.year()-t.year())+(e.month()-t.month()),r=t.clone().add(a,"months");return e-r<0?(i=t.clone().add(a-1,"months"),n=(e-r)/(r-i)):(i=t.clone().add(a+1,"months"),n=(e-r)/(i-r)),-(a+n)||0}function ei(t){var e;return void 0===t?this._locale._abbr:(null!=(e=ce(t))&&(this._locale=e),this)}n.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",n.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var ii=S("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(t){return void 0===t?this.localeData():this.locale(t)});function ni(){return this._locale}var ai=1e3,ri=60*ai,oi=60*ri,si=3506328*oi;function li(t,e){return(t%e+e)%e}function ui(t,e,i){return t<100&&t>=0?new Date(t+400,e,i)-si:new Date(t,e,i).valueOf()}function di(t,e,i){return t<100&&t>=0?Date.UTC(t+400,e,i)-si:Date.UTC(t,e,i)}function hi(t,e){B(0,[t,t.length],0,e)}function ci(t,e,i,n,a){var r;return null==t?jt(this,n,a).year:(r=Ut(t,n,a),e>r&&(e=r),function(t,e,i,n,a){var r=Bt(t,e,i,n,a),o=Ht(r.year,0,r.dayOfYear);return this.year(o.getUTCFullYear()),this.month(o.getUTCMonth()),this.date(o.getUTCDate()),this}.call(this,t,e,i,n,a))}B(0,["gg",2],0,function(){return this.weekYear()%100}),B(0,["GG",2],0,function(){return this.isoWeekYear()%100}),hi("gggg","weekYear"),hi("ggggg","weekYear"),hi("GGGG","isoWeekYear"),hi("GGGGG","isoWeekYear"),F("weekYear","gg"),F("isoWeekYear","GG"),Y("weekYear",1),Y("isoWeekYear",1),ut("G",at),ut("g",at),ut("GG",K,q),ut("gg",K,q),ut("GGGG",et,$),ut("gggg",et,$),ut("GGGGG",it,X),ut("ggggg",it,X),gt(["gggg","ggggg","GGGG","GGGGG"],function(t,e,i,n){e[n.substr(0,2)]=k(t)}),gt(["gg","GG"],function(t,e,i,a){e[a]=n.parseTwoDigitYear(t)}),B("Q",0,"Qo","quarter"),F("quarter","Q"),Y("quarter",7),ut("Q",G),ft("Q",function(t,e){e[vt]=3*(k(t)-1)}),B("D",["DD",2],"Do","date"),F("date","D"),Y("date",9),ut("D",K),ut("DD",K,q),ut("Do",function(t,e){return t?e._dayOfMonthOrdinalParse||e._ordinalParse:e._dayOfMonthOrdinalParseLenient}),ft(["D","DD"],yt),ft("Do",function(t,e){e[yt]=k(t.match(K)[0])});var fi=Tt("Date",!0);B("DDD",["DDDD",3],"DDDo","dayOfYear"),F("dayOfYear","DDD"),Y("dayOfYear",4),ut("DDD",tt),ut("DDDD",Z),ft(["DDD","DDDD"],function(t,e,i){i._dayOfYear=k(t)}),B("m",["mm",2],0,"minute"),F("minute","m"),Y("minute",14),ut("m",K),ut("mm",K,q),ft(["m","mm"],xt);var gi=Tt("Minutes",!1);B("s",["ss",2],0,"second"),F("second","s"),Y("second",15),ut("s",K),ut("ss",K,q),ft(["s","ss"],_t);var mi,pi=Tt("Seconds",!1);for(B("S",0,0,function(){return~~(this.millisecond()/100)}),B(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),B(0,["SSS",3],0,"millisecond"),B(0,["SSSS",4],0,function(){return 10*this.millisecond()}),B(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),B(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),B(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),B(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),B(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),F("millisecond","ms"),Y("millisecond",16),ut("S",tt,G),ut("SS",tt,q),ut("SSS",tt,Z),mi="SSSS";mi.length<=9;mi+="S")ut(mi,nt);function vi(t,e){e[kt]=k(1e3*("0."+t))}for(mi="S";mi.length<=9;mi+="S")ft(mi,vi);var yi=Tt("Milliseconds",!1);B("z",0,0,"zoneAbbr"),B("zz",0,0,"zoneName");var bi=b.prototype;function xi(t){return t}bi.add=Je,bi.calendar=function(t,e){var i=t||Ie(),a=Ee(i,this).startOf("day"),r=n.calendarFormat(this,a)||"sameElse",o=e&&(T(e[r])?e[r].call(this,i):e[r]);return this.format(o||this.localeData().calendar(r,this,Ie(i)))},bi.clone=function(){return new b(this)},bi.diff=function(t,e,i){var n,a,r;if(!this.isValid())return NaN;if(!(n=Ee(t,this)).isValid())return NaN;switch(a=6e4*(n.utcOffset()-this.utcOffset()),e=R(e)){case"year":r=ti(this,n)/12;break;case"month":r=ti(this,n);break;case"quarter":r=ti(this,n)/3;break;case"second":r=(this-n)/1e3;break;case"minute":r=(this-n)/6e4;break;case"hour":r=(this-n)/36e5;break;case"day":r=(this-n-a)/864e5;break;case"week":r=(this-n-a)/6048e5;break;default:r=this-n}return i?r:_(r)},bi.endOf=function(t){var e;if(void 0===(t=R(t))||"millisecond"===t||!this.isValid())return this;var i=this._isUTC?di:ui;switch(t){case"year":e=i(this.year()+1,0,1)-1;break;case"quarter":e=i(this.year(),this.month()-this.month()%3+3,1)-1;break;case"month":e=i(this.year(),this.month()+1,1)-1;break;case"week":e=i(this.year(),this.month(),this.date()-this.weekday()+7)-1;break;case"isoWeek":e=i(this.year(),this.month(),this.date()-(this.isoWeekday()-1)+7)-1;break;case"day":case"date":e=i(this.year(),this.month(),this.date()+1)-1;break;case"hour":e=this._d.valueOf(),e+=oi-li(e+(this._isUTC?0:this.utcOffset()*ri),oi)-1;break;case"minute":e=this._d.valueOf(),e+=ri-li(e,ri)-1;break;case"second":e=this._d.valueOf(),e+=ai-li(e,ai)-1}return this._d.setTime(e),n.updateOffset(this,!0),this},bi.format=function(t){t||(t=this.isUtc()?n.defaultFormatUtc:n.defaultFormat);var e=j(this,t);return this.localeData().postformat(e)},bi.from=function(t,e){return this.isValid()&&(x(t)&&t.isValid()||Ie(t).isValid())?qe({to:this,from:t}).locale(this.locale()).humanize(!e):this.localeData().invalidDate()},bi.fromNow=function(t){return this.from(Ie(),t)},bi.to=function(t,e){return this.isValid()&&(x(t)&&t.isValid()||Ie(t).isValid())?qe({from:this,to:t}).locale(this.locale()).humanize(!e):this.localeData().invalidDate()},bi.toNow=function(t){return this.to(Ie(),t)},bi.get=function(t){return T(this[t=R(t)])?this[t]():this},bi.invalidAt=function(){return f(this).overflow},bi.isAfter=function(t,e){var i=x(t)?t:Ie(t);return!(!this.isValid()||!i.isValid())&&("millisecond"===(e=R(e)||"millisecond")?this.valueOf()>i.valueOf():i.valueOf()<this.clone().startOf(e).valueOf())},bi.isBefore=function(t,e){var i=x(t)?t:Ie(t);return!(!this.isValid()||!i.isValid())&&("millisecond"===(e=R(e)||"millisecond")?this.valueOf()<i.valueOf():this.clone().endOf(e).valueOf()<i.valueOf())},bi.isBetween=function(t,e,i,n){var a=x(t)?t:Ie(t),r=x(e)?e:Ie(e);return!!(this.isValid()&&a.isValid()&&r.isValid())&&(("("===(n=n||"()")[0]?this.isAfter(a,i):!this.isBefore(a,i))&&(")"===n[1]?this.isBefore(r,i):!this.isAfter(r,i)))},bi.isSame=function(t,e){var i,n=x(t)?t:Ie(t);return!(!this.isValid()||!n.isValid())&&("millisecond"===(e=R(e)||"millisecond")?this.valueOf()===n.valueOf():(i=n.valueOf(),this.clone().startOf(e).valueOf()<=i&&i<=this.clone().endOf(e).valueOf()))},bi.isSameOrAfter=function(t,e){return this.isSame(t,e)||this.isAfter(t,e)},bi.isSameOrBefore=function(t,e){return this.isSame(t,e)||this.isBefore(t,e)},bi.isValid=function(){return g(this)},bi.lang=ii,bi.locale=ei,bi.localeData=ni,bi.max=Fe,bi.min=Ae,bi.parsingFlags=function(){return h({},f(this))},bi.set=function(t,e){if("object"==typeof t)for(var i=function(t){var e=[];for(var i in t)e.push({unit:i,priority:W[i]});return e.sort(function(t,e){return t.priority-e.priority}),e}(t=L(t)),n=0;n<i.length;n++)this[i[n].unit](t[i[n].unit]);else if(T(this[t=R(t)]))return this[t](e);return this},bi.startOf=function(t){var e;if(void 0===(t=R(t))||"millisecond"===t||!this.isValid())return this;var i=this._isUTC?di:ui;switch(t){case"year":e=i(this.year(),0,1);break;case"quarter":e=i(this.year(),this.month()-this.month()%3,1);break;case"month":e=i(this.year(),this.month(),1);break;case"week":e=i(this.year(),this.month(),this.date()-this.weekday());break;case"isoWeek":e=i(this.year(),this.month(),this.date()-(this.isoWeekday()-1));break;case"day":case"date":e=i(this.year(),this.month(),this.date());break;case"hour":e=this._d.valueOf(),e-=li(e+(this._isUTC?0:this.utcOffset()*ri),oi);break;case"minute":e=this._d.valueOf(),e-=li(e,ri);break;case"second":e=this._d.valueOf(),e-=li(e,ai)}return this._d.setTime(e),n.updateOffset(this,!0),this},bi.subtract=Qe,bi.toArray=function(){var t=this;return[t.year(),t.month(),t.date(),t.hour(),t.minute(),t.second(),t.millisecond()]},bi.toObject=function(){var t=this;return{years:t.year(),months:t.month(),date:t.date(),hours:t.hours(),minutes:t.minutes(),seconds:t.seconds(),milliseconds:t.milliseconds()}},bi.toDate=function(){return new Date(this.valueOf())},bi.toISOString=function(t){if(!this.isValid())return null;var e=!0!==t,i=e?this.clone().utc():this;return i.year()<0||i.year()>9999?j(i,e?"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ"):T(Date.prototype.toISOString)?e?this.toDate().toISOString():new Date(this.valueOf()+60*this.utcOffset()*1e3).toISOString().replace("Z",j(i,"Z")):j(i,e?"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYY-MM-DD[T]HH:mm:ss.SSSZ")},bi.inspect=function(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var t="moment",e="";this.isLocal()||(t=0===this.utcOffset()?"moment.utc":"moment.parseZone",e="Z");var i="["+t+'("]',n=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",a=e+'[")]';return this.format(i+n+"-MM-DD[T]HH:mm:ss.SSS"+a)},bi.toJSON=function(){return this.isValid()?this.toISOString():null},bi.toString=function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},bi.unix=function(){return Math.floor(this.valueOf()/1e3)},bi.valueOf=function(){return this._d.valueOf()-6e4*(this._offset||0)},bi.creationData=function(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},bi.year=Pt,bi.isLeapYear=function(){return Dt(this.year())},bi.weekYear=function(t){return ci.call(this,t,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)},bi.isoWeekYear=function(t){return ci.call(this,t,this.isoWeek(),this.isoWeekday(),1,4)},bi.quarter=bi.quarters=function(t){return null==t?Math.ceil((this.month()+1)/3):this.month(3*(t-1)+this.month()%3)},bi.month=Yt,bi.daysInMonth=function(){return At(this.year(),this.month())},bi.week=bi.weeks=function(t){var e=this.localeData().week(this);return null==t?e:this.add(7*(t-e),"d")},bi.isoWeek=bi.isoWeeks=function(t){var e=jt(this,1,4).week;return null==t?e:this.add(7*(t-e),"d")},bi.weeksInYear=function(){var t=this.localeData()._week;return Ut(this.year(),t.dow,t.doy)},bi.isoWeeksInYear=function(){return Ut(this.year(),1,4)},bi.date=fi,bi.day=bi.days=function(t){if(!this.isValid())return null!=t?this:NaN;var e=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=t?(t=function(t,e){return"string"!=typeof t?t:isNaN(t)?"number"==typeof(t=e.weekdaysParse(t))?t:null:parseInt(t,10)}(t,this.localeData()),this.add(t-e,"d")):e},bi.weekday=function(t){if(!this.isValid())return null!=t?this:NaN;var e=(this.day()+7-this.localeData()._week.dow)%7;return null==t?e:this.add(t-e,"d")},bi.isoWeekday=function(t){if(!this.isValid())return null!=t?this:NaN;if(null!=t){var e=function(t,e){return"string"==typeof t?e.weekdaysParse(t)%7||7:isNaN(t)?null:t}(t,this.localeData());return this.day(this.day()%7?e:e-7)}return this.day()||7},bi.dayOfYear=function(t){var e=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==t?e:this.add(t-e,"d")},bi.hour=bi.hours=ae,bi.minute=bi.minutes=gi,bi.second=bi.seconds=pi,bi.millisecond=bi.milliseconds=yi,bi.utcOffset=function(t,e,i){var a,r=this._offset||0;if(!this.isValid())return null!=t?this:NaN;if(null!=t){if("string"==typeof t){if(null===(t=He(ot,t)))return this}else Math.abs(t)<16&&!i&&(t*=60);return!this._isUTC&&e&&(a=Be(this)),this._offset=t,this._isUTC=!0,null!=a&&this.add(a,"m"),r!==t&&(!e||this._changeInProgress?Ke(this,qe(t-r,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,n.updateOffset(this,!0),this._changeInProgress=null)),this}return this._isUTC?r:Be(this)},bi.utc=function(t){return this.utcOffset(0,t)},bi.local=function(t){return this._isUTC&&(this.utcOffset(0,t),this._isUTC=!1,t&&this.subtract(Be(this),"m")),this},bi.parseZone=function(){if(null!=this._tzm)this.utcOffset(this._tzm,!1,!0);else if("string"==typeof this._i){var t=He(rt,this._i);null!=t?this.utcOffset(t):this.utcOffset(0,!0)}return this},bi.hasAlignedHourOffset=function(t){return!!this.isValid()&&(t=t?Ie(t).utcOffset():0,(this.utcOffset()-t)%60==0)},bi.isDST=function(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},bi.isLocal=function(){return!!this.isValid()&&!this._isUTC},bi.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},bi.isUtc=je,bi.isUTC=je,bi.zoneAbbr=function(){return this._isUTC?"UTC":""},bi.zoneName=function(){return this._isUTC?"Coordinated Universal Time":""},bi.dates=S("dates accessor is deprecated. Use date instead.",fi),bi.months=S("months accessor is deprecated. Use month instead",Yt),bi.years=S("years accessor is deprecated. Use year instead",Pt),bi.zone=S("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",function(t,e){return null!=t?("string"!=typeof t&&(t=-t),this.utcOffset(t,e),this):-this.utcOffset()}),bi.isDSTShifted=S("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",function(){if(!o(this._isDSTShifted))return this._isDSTShifted;var t={};if(v(t,this),(t=Te(t))._a){var e=t._isUTC?c(t._a):Ie(t._a);this._isDSTShifted=this.isValid()&&w(t._a,e.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted});var _i=I.prototype;function ki(t,e,i,n){var a=ce(),r=c().set(n,e);return a[i](r,t)}function wi(t,e,i){if(s(t)&&(e=t,t=void 0),t=t||"",null!=e)return ki(t,e,i,"month");var n,a=[];for(n=0;n<12;n++)a[n]=ki(t,n,i,"month");return a}function Mi(t,e,i,n){"boolean"==typeof t?(s(e)&&(i=e,e=void 0),e=e||""):(i=e=t,t=!1,s(e)&&(i=e,e=void 0),e=e||"");var a,r=ce(),o=t?r._week.dow:0;if(null!=i)return ki(e,(i+o)%7,n,"day");var l=[];for(a=0;a<7;a++)l[a]=ki(e,(a+o)%7,n,"day");return l}_i.calendar=function(t,e,i){var n=this._calendar[t]||this._calendar.sameElse;return T(n)?n.call(e,i):n},_i.longDateFormat=function(t){var e=this._longDateFormat[t],i=this._longDateFormat[t.toUpperCase()];return e||!i?e:(this._longDateFormat[t]=i.replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t])},_i.invalidDate=function(){return this._invalidDate},_i.ordinal=function(t){return this._ordinal.replace("%d",t)},_i.preparse=xi,_i.postformat=xi,_i.relativeTime=function(t,e,i,n){var a=this._relativeTime[i];return T(a)?a(t,e,i,n):a.replace(/%d/i,t)},_i.pastFuture=function(t,e){var i=this._relativeTime[t>0?"future":"past"];return T(i)?i(e):i.replace(/%s/i,e)},_i.set=function(t){var e,i;for(i in t)T(e=t[i])?this[i]=e:this["_"+i]=e;this._config=t,this._dayOfMonthOrdinalParseLenient=new RegExp((this._dayOfMonthOrdinalParse.source||this._ordinalParse.source)+"|"+/\d{1,2}/.source)},_i.months=function(t,e){return t?a(this._months)?this._months[t.month()]:this._months[(this._months.isFormat||Ft).test(e)?"format":"standalone"][t.month()]:a(this._months)?this._months:this._months.standalone},_i.monthsShort=function(t,e){return t?a(this._monthsShort)?this._monthsShort[t.month()]:this._monthsShort[Ft.test(e)?"format":"standalone"][t.month()]:a(this._monthsShort)?this._monthsShort:this._monthsShort.standalone},_i.monthsParse=function(t,e,i){var n,a,r;if(this._monthsParseExact)return function(t,e,i){var n,a,r,o=t.toLocaleLowerCase();if(!this._monthsParse)for(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[],n=0;n<12;++n)r=c([2e3,n]),this._shortMonthsParse[n]=this.monthsShort(r,"").toLocaleLowerCase(),this._longMonthsParse[n]=this.months(r,"").toLocaleLowerCase();return i?"MMM"===e?-1!==(a=Ct.call(this._shortMonthsParse,o))?a:null:-1!==(a=Ct.call(this._longMonthsParse,o))?a:null:"MMM"===e?-1!==(a=Ct.call(this._shortMonthsParse,o))?a:-1!==(a=Ct.call(this._longMonthsParse,o))?a:null:-1!==(a=Ct.call(this._longMonthsParse,o))?a:-1!==(a=Ct.call(this._shortMonthsParse,o))?a:null}.call(this,t,e,i);for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),n=0;n<12;n++){if(a=c([2e3,n]),i&&!this._longMonthsParse[n]&&(this._longMonthsParse[n]=new RegExp("^"+this.months(a,"").replace(".","")+"$","i"),this._shortMonthsParse[n]=new RegExp("^"+this.monthsShort(a,"").replace(".","")+"$","i")),i||this._monthsParse[n]||(r="^"+this.months(a,"")+"|^"+this.monthsShort(a,""),this._monthsParse[n]=new RegExp(r.replace(".",""),"i")),i&&"MMMM"===e&&this._longMonthsParse[n].test(t))return n;if(i&&"MMM"===e&&this._shortMonthsParse[n].test(t))return n;if(!i&&this._monthsParse[n].test(t))return n}},_i.monthsRegex=function(t){return this._monthsParseExact?(d(this,"_monthsRegex")||Vt.call(this),t?this._monthsStrictRegex:this._monthsRegex):(d(this,"_monthsRegex")||(this._monthsRegex=zt),this._monthsStrictRegex&&t?this._monthsStrictRegex:this._monthsRegex)},_i.monthsShortRegex=function(t){return this._monthsParseExact?(d(this,"_monthsRegex")||Vt.call(this),t?this._monthsShortStrictRegex:this._monthsShortRegex):(d(this,"_monthsShortRegex")||(this._monthsShortRegex=Nt),this._monthsShortStrictRegex&&t?this._monthsShortStrictRegex:this._monthsShortRegex)},_i.week=function(t){return jt(t,this._week.dow,this._week.doy).week},_i.firstDayOfYear=function(){return this._week.doy},_i.firstDayOfWeek=function(){return this._week.dow},_i.weekdays=function(t,e){var i=a(this._weekdays)?this._weekdays:this._weekdays[t&&!0!==t&&this._weekdays.isFormat.test(e)?"format":"standalone"];return!0===t?Gt(i,this._week.dow):t?i[t.day()]:i},_i.weekdaysMin=function(t){return!0===t?Gt(this._weekdaysMin,this._week.dow):t?this._weekdaysMin[t.day()]:this._weekdaysMin},_i.weekdaysShort=function(t){return!0===t?Gt(this._weekdaysShort,this._week.dow):t?this._weekdaysShort[t.day()]:this._weekdaysShort},_i.weekdaysParse=function(t,e,i){var n,a,r;if(this._weekdaysParseExact)return function(t,e,i){var n,a,r,o=t.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],n=0;n<7;++n)r=c([2e3,1]).day(n),this._minWeekdaysParse[n]=this.weekdaysMin(r,"").toLocaleLowerCase(),this._shortWeekdaysParse[n]=this.weekdaysShort(r,"").toLocaleLowerCase(),this._weekdaysParse[n]=this.weekdays(r,"").toLocaleLowerCase();return i?"dddd"===e?-1!==(a=Ct.call(this._weekdaysParse,o))?a:null:"ddd"===e?-1!==(a=Ct.call(this._shortWeekdaysParse,o))?a:null:-1!==(a=Ct.call(this._minWeekdaysParse,o))?a:null:"dddd"===e?-1!==(a=Ct.call(this._weekdaysParse,o))?a:-1!==(a=Ct.call(this._shortWeekdaysParse,o))?a:-1!==(a=Ct.call(this._minWeekdaysParse,o))?a:null:"ddd"===e?-1!==(a=Ct.call(this._shortWeekdaysParse,o))?a:-1!==(a=Ct.call(this._weekdaysParse,o))?a:-1!==(a=Ct.call(this._minWeekdaysParse,o))?a:null:-1!==(a=Ct.call(this._minWeekdaysParse,o))?a:-1!==(a=Ct.call(this._weekdaysParse,o))?a:-1!==(a=Ct.call(this._shortWeekdaysParse,o))?a:null}.call(this,t,e,i);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),n=0;n<7;n++){if(a=c([2e3,1]).day(n),i&&!this._fullWeekdaysParse[n]&&(this._fullWeekdaysParse[n]=new RegExp("^"+this.weekdays(a,"").replace(".","\\.?")+"$","i"),this._shortWeekdaysParse[n]=new RegExp("^"+this.weekdaysShort(a,"").replace(".","\\.?")+"$","i"),this._minWeekdaysParse[n]=new RegExp("^"+this.weekdaysMin(a,"").replace(".","\\.?")+"$","i")),this._weekdaysParse[n]||(r="^"+this.weekdays(a,"")+"|^"+this.weekdaysShort(a,"")+"|^"+this.weekdaysMin(a,""),this._weekdaysParse[n]=new RegExp(r.replace(".",""),"i")),i&&"dddd"===e&&this._fullWeekdaysParse[n].test(t))return n;if(i&&"ddd"===e&&this._shortWeekdaysParse[n].test(t))return n;if(i&&"dd"===e&&this._minWeekdaysParse[n].test(t))return n;if(!i&&this._weekdaysParse[n].test(t))return n}},_i.weekdaysRegex=function(t){return this._weekdaysParseExact?(d(this,"_weekdaysRegex")||Qt.call(this),t?this._weekdaysStrictRegex:this._weekdaysRegex):(d(this,"_weekdaysRegex")||(this._weekdaysRegex=Xt),this._weekdaysStrictRegex&&t?this._weekdaysStrictRegex:this._weekdaysRegex)},_i.weekdaysShortRegex=function(t){return this._weekdaysParseExact?(d(this,"_weekdaysRegex")||Qt.call(this),t?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(d(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=Kt),this._weekdaysShortStrictRegex&&t?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)},_i.weekdaysMinRegex=function(t){return this._weekdaysParseExact?(d(this,"_weekdaysRegex")||Qt.call(this),t?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(d(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=Jt),this._weekdaysMinStrictRegex&&t?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)},_i.isPM=function(t){return"p"===(t+"").toLowerCase().charAt(0)},_i.meridiem=function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},de("en",{dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(t){var e=t%10,i=1===k(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+i}}),n.lang=S("moment.lang is deprecated. Use moment.locale instead.",de),n.langData=S("moment.langData is deprecated. Use moment.localeData instead.",ce);var Si=Math.abs;function Di(t,e,i,n){var a=qe(e,i);return t._milliseconds+=n*a._milliseconds,t._days+=n*a._days,t._months+=n*a._months,t._bubble()}function Ci(t){return t<0?Math.floor(t):Math.ceil(t)}function Pi(t){return 4800*t/146097}function Ti(t){return 146097*t/4800}function Oi(t){return function(){return this.as(t)}}var Ii=Oi("ms"),Ai=Oi("s"),Fi=Oi("m"),Ri=Oi("h"),Li=Oi("d"),Wi=Oi("w"),Yi=Oi("M"),Ni=Oi("Q"),zi=Oi("y");function Vi(t){return function(){return this.isValid()?this._data[t]:NaN}}var Hi=Vi("milliseconds"),Ei=Vi("seconds"),Bi=Vi("minutes"),ji=Vi("hours"),Ui=Vi("days"),Gi=Vi("months"),qi=Vi("years"),Zi=Math.round,$i={ss:44,s:45,m:45,h:22,d:26,M:11},Xi=Math.abs;function Ki(t){return(t>0)-(t<0)||+t}function Ji(){if(!this.isValid())return this.localeData().invalidDate();var t,e,i=Xi(this._milliseconds)/1e3,n=Xi(this._days),a=Xi(this._months);t=_(i/60),e=_(t/60),i%=60,t%=60;var r=_(a/12),o=a%=12,s=n,l=e,u=t,d=i?i.toFixed(3).replace(/\.?0+$/,""):"",h=this.asSeconds();if(!h)return"P0D";var c=h<0?"-":"",f=Ki(this._months)!==Ki(h)?"-":"",g=Ki(this._days)!==Ki(h)?"-":"",m=Ki(this._milliseconds)!==Ki(h)?"-":"";return c+"P"+(r?f+r+"Y":"")+(o?f+o+"M":"")+(s?g+s+"D":"")+(l||u||d?"T":"")+(l?m+l+"H":"")+(u?m+u+"M":"")+(d?m+d+"S":"")}var Qi=We.prototype;return Qi.isValid=function(){return this._isValid},Qi.abs=function(){var t=this._data;return this._milliseconds=Si(this._milliseconds),this._days=Si(this._days),this._months=Si(this._months),t.milliseconds=Si(t.milliseconds),t.seconds=Si(t.seconds),t.minutes=Si(t.minutes),t.hours=Si(t.hours),t.months=Si(t.months),t.years=Si(t.years),this},Qi.add=function(t,e){return Di(this,t,e,1)},Qi.subtract=function(t,e){return Di(this,t,e,-1)},Qi.as=function(t){if(!this.isValid())return NaN;var e,i,n=this._milliseconds;if("month"===(t=R(t))||"quarter"===t||"year"===t)switch(e=this._days+n/864e5,i=this._months+Pi(e),t){case"month":return i;case"quarter":return i/3;case"year":return i/12}else switch(e=this._days+Math.round(Ti(this._months)),t){case"week":return e/7+n/6048e5;case"day":return e+n/864e5;case"hour":return 24*e+n/36e5;case"minute":return 1440*e+n/6e4;case"second":return 86400*e+n/1e3;case"millisecond":return Math.floor(864e5*e)+n;default:throw new Error("Unknown unit "+t)}},Qi.asMilliseconds=Ii,Qi.asSeconds=Ai,Qi.asMinutes=Fi,Qi.asHours=Ri,Qi.asDays=Li,Qi.asWeeks=Wi,Qi.asMonths=Yi,Qi.asQuarters=Ni,Qi.asYears=zi,Qi.valueOf=function(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*k(this._months/12):NaN},Qi._bubble=function(){var t,e,i,n,a,r=this._milliseconds,o=this._days,s=this._months,l=this._data;return r>=0&&o>=0&&s>=0||r<=0&&o<=0&&s<=0||(r+=864e5*Ci(Ti(s)+o),o=0,s=0),l.milliseconds=r%1e3,t=_(r/1e3),l.seconds=t%60,e=_(t/60),l.minutes=e%60,i=_(e/60),l.hours=i%24,o+=_(i/24),a=_(Pi(o)),s+=a,o-=Ci(Ti(a)),n=_(s/12),s%=12,l.days=o,l.months=s,l.years=n,this},Qi.clone=function(){return qe(this)},Qi.get=function(t){return t=R(t),this.isValid()?this[t+"s"]():NaN},Qi.milliseconds=Hi,Qi.seconds=Ei,Qi.minutes=Bi,Qi.hours=ji,Qi.days=Ui,Qi.weeks=function(){return _(this.days()/7)},Qi.months=Gi,Qi.years=qi,Qi.humanize=function(t){if(!this.isValid())return this.localeData().invalidDate();var e=this.localeData(),i=function(t,e,i){var n=qe(t).abs(),a=Zi(n.as("s")),r=Zi(n.as("m")),o=Zi(n.as("h")),s=Zi(n.as("d")),l=Zi(n.as("M")),u=Zi(n.as("y")),d=a<=$i.ss&&["s",a]||a<$i.s&&["ss",a]||r<=1&&["m"]||r<$i.m&&["mm",r]||o<=1&&["h"]||o<$i.h&&["hh",o]||s<=1&&["d"]||s<$i.d&&["dd",s]||l<=1&&["M"]||l<$i.M&&["MM",l]||u<=1&&["y"]||["yy",u];return d[2]=e,d[3]=+t>0,d[4]=i,function(t,e,i,n,a){return a.relativeTime(e||1,!!i,t,n)}.apply(null,d)}(this,!t,e);return t&&(i=e.pastFuture(+this,i)),e.postformat(i)},Qi.toISOString=Ji,Qi.toString=Ji,Qi.toJSON=Ji,Qi.locale=ei,Qi.localeData=ni,Qi.toIsoString=S("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",Ji),Qi.lang=ii,B("X",0,0,"unix"),B("x",0,0,"valueOf"),ut("x",at),ut("X",/[+-]?\d+(\.\d{1,3})?/),ft("X",function(t,e,i){i._d=new Date(1e3*parseFloat(t,10))}),ft("x",function(t,e,i){i._d=new Date(k(t))}),n.version="2.24.0",e=Ie,n.fn=bi,n.min=function(){return Re("isBefore",[].slice.call(arguments,0))},n.max=function(){return Re("isAfter",[].slice.call(arguments,0))},n.now=function(){return Date.now?Date.now():+new Date},n.utc=c,n.unix=function(t){return Ie(1e3*t)},n.months=function(t,e){return wi(t,e,"months")},n.isDate=l,n.locale=de,n.invalid=m,n.duration=qe,n.isMoment=x,n.weekdays=function(t,e,i){return Mi(t,e,i,"weekdays")},n.parseZone=function(){return Ie.apply(null,arguments).parseZone()},n.localeData=ce,n.isDuration=Ye,n.monthsShort=function(t,e){return wi(t,e,"monthsShort")},n.weekdaysMin=function(t,e,i){return Mi(t,e,i,"weekdaysMin")},n.defineLocale=he,n.updateLocale=function(t,e){if(null!=e){var i,n,a=re;null!=(n=ue(t))&&(a=n._config),e=O(a,e),(i=new I(e)).parentLocale=oe[t],oe[t]=i,de(t)}else null!=oe[t]&&(null!=oe[t].parentLocale?oe[t]=oe[t].parentLocale:null!=oe[t]&&delete oe[t]);return oe[t]},n.locales=function(){return D(oe)},n.weekdaysShort=function(t,e,i){return Mi(t,e,i,"weekdaysShort")},n.normalizeUnits=R,n.relativeTimeRounding=function(t){return void 0===t?Zi:"function"==typeof t&&(Zi=t,!0)},n.relativeTimeThreshold=function(t,e){return void 0!==$i[t]&&(void 0===e?$i[t]:($i[t]=e,"s"===t&&($i.ss=e-1),!0))},n.calendarFormat=function(t,e){var i=t.diff(e,"days",!0);return i<-6?"sameElse":i<-1?"lastWeek":i<0?"lastDay":i<1?"sameDay":i<2?"nextDay":i<7?"nextWeek":"sameElse"},n.prototype=bi,n.HTML5_FMT={DATETIME_LOCAL:"YYYY-MM-DDTHH:mm",DATETIME_LOCAL_SECONDS:"YYYY-MM-DDTHH:mm:ss",DATETIME_LOCAL_MS:"YYYY-MM-DDTHH:mm:ss.SSS",DATE:"YYYY-MM-DD",TIME:"HH:mm",TIME_SECONDS:"HH:mm:ss",TIME_MS:"HH:mm:ss.SSS",WEEK:"GGGG-[W]WW",MONTH:"YYYY-MM"},n}()}(tn={exports:{}},tn.exports),tn.exports),an={datetime:"MMM D, YYYY, h:mm:ss a",millisecond:"h:mm:ss.SSS a",second:"h:mm:ss a",minute:"h:mm a",hour:"hA",day:"MMM D",week:"ll",month:"MMM YYYY",quarter:"[Q]Q - YYYY",year:"YYYY"};si._date.override("function"==typeof nn?{_id:"moment",formats:function(){return an},parse:function(t,e){return"string"==typeof t&&"string"==typeof e?t=nn(t,e):t instanceof nn||(t=nn(t)),t.isValid()?t.valueOf():null},format:function(t,e){return nn(t).format(e)},add:function(t,e,i){return nn(t).add(e,i).valueOf()},diff:function(t,e,i){return nn.duration(nn(t).diff(nn(e))).as(i)},startOf:function(t,e,i){return t=nn(t),"isoWeek"===e?t.isoWeekday(i).valueOf():t.startOf(e).valueOf()},endOf:function(t,e){return nn(t).endOf(e).valueOf()},_create:function(t){return nn(t)}}:{}),ot._set("global",{plugins:{filler:{propagate:!0}}});var rn={dataset:function(t){var e=t.fill,i=t.chart,n=i.getDatasetMeta(e),a=n&&i.isDatasetVisible(e)&&n.dataset._children||[],r=a.length||0;return r?function(t,e){return e<r&&a[e]._view||null}:null},boundary:function(t){var e=t.boundary,i=e?e.x:null,n=e?e.y:null;return function(t){return{x:null===i?t.x:i,y:null===n?t.y:n}}}};function on(t,e,i){var n,a=t._model||{},r=a.fill;if(void 0===r&&(r=!!a.backgroundColor),!1===r||null===r)return!1;if(!0===r)return"origin";if(n=parseFloat(r,10),isFinite(n)&&Math.floor(n)===n)return"-"!==r[0]&&"+"!==r[0]||(n=e+n),!(n===e||n<0||n>=i)&&n;switch(r){case"bottom":return"start";case"top":return"end";case"zero":return"origin";case"origin":case"start":case"end":return r;default:return!1}}function sn(t){var e,i=t.el._model||{},n=t.el._scale||{},a=t.fill,r=null;if(isFinite(a))return null;if("start"===a?r=void 0===i.scaleBottom?n.bottom:i.scaleBottom:"end"===a?r=void 0===i.scaleTop?n.top:i.scaleTop:void 0!==i.scaleZero?r=i.scaleZero:n.getBasePosition?r=n.getBasePosition():n.getBasePixel&&(r=n.getBasePixel()),null!=r){if(void 0!==r.x&&void 0!==r.y)return r;if(ut.isFinite(r))return{x:(e=n.isHorizontal())?r:null,y:e?null:r}}return null}function ln(t,e,i){var n,a=t[e].fill,r=[e];if(!i)return a;for(;!1!==a&&-1===r.indexOf(a);){if(!isFinite(a))return a;if(!(n=t[a]))return!1;if(n.visible)return a;r.push(a),a=n.fill}return!1}function un(t){var e=t.fill,i="dataset";return!1===e?null:(isFinite(e)||(i="boundary"),rn[i](t))}function dn(t){return t&&!t.skip}function hn(t,e,i,n,a){var r;if(n&&a){for(t.moveTo(e[0].x,e[0].y),r=1;r<n;++r)ut.canvas.lineTo(t,e[r-1],e[r]);for(t.lineTo(i[a-1].x,i[a-1].y),r=a-1;r>0;--r)ut.canvas.lineTo(t,i[r],i[r-1],!0)}}var cn={id:"filler",afterDatasetsUpdate:function(t,e){var i,n,a,r,o=(t.data.datasets||[]).length,s=e.propagate,l=[];for(n=0;n<o;++n)r=null,(a=(i=t.getDatasetMeta(n)).dataset)&&a._model&&a instanceof Nt.Line&&(r={visible:t.isDatasetVisible(n),fill:on(a,n,o),chart:t,el:a}),i.$filler=r,l.push(r);for(n=0;n<o;++n)(r=l[n])&&(r.fill=ln(l,n,s),r.boundary=sn(r),r.mapper=un(r))},beforeDatasetDraw:function(t,e){var i=e.meta.$filler;if(i){var n=t.ctx,a=i.el,r=a._view,o=a._children||[],s=i.mapper,l=r.backgroundColor||ot.global.defaultColor;s&&l&&o.length&&(ut.canvas.clipArea(n,t.chartArea),function(t,e,i,n,a,r){var o,s,l,u,d,h,c,f=e.length,g=n.spanGaps,m=[],p=[],v=0,y=0;for(t.beginPath(),o=0,s=f+!!r;o<s;++o)d=i(u=e[l=o%f]._view,l,n),h=dn(u),c=dn(d),h&&c?(v=m.push(u),y=p.push(d)):v&&y&&(g?(h&&m.push(u),c&&p.push(d)):(hn(t,m,p,v,y),v=y=0,m=[],p=[]));hn(t,m,p,v,y),t.closePath(),t.fillStyle=a,t.fill()}(n,o,s,r,l,a._loop),ut.canvas.unclipArea(n))}}},fn=ut.noop,gn=ut.valueOrDefault;function mn(t,e){return t.usePointStyle&&t.boxWidth>e?e:t.boxWidth}ot._set("global",{legend:{display:!0,position:"top",fullWidth:!0,reverse:!1,weight:1e3,onClick:function(t,e){var i=e.datasetIndex,n=this.chart,a=n.getDatasetMeta(i);a.hidden=null===a.hidden?!n.data.datasets[i].hidden:null,n.update()},onHover:null,onLeave:null,labels:{boxWidth:40,padding:10,generateLabels:function(t){var e=t.data;return ut.isArray(e.datasets)?e.datasets.map(function(e,i){return{text:e.label,fillStyle:ut.isArray(e.backgroundColor)?e.backgroundColor[0]:e.backgroundColor,hidden:!t.isDatasetVisible(i),lineCap:e.borderCapStyle,lineDash:e.borderDash,lineDashOffset:e.borderDashOffset,lineJoin:e.borderJoinStyle,lineWidth:e.borderWidth,strokeStyle:e.borderColor,pointStyle:e.pointStyle,datasetIndex:i}},this):[]}}},legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');for(var i=0;i<t.data.datasets.length;i++)e.push('<li><span style="background-color:'+t.data.datasets[i].backgroundColor+'"></span>'),t.data.datasets[i].label&&e.push(t.data.datasets[i].label),e.push("</li>");return e.push("</ul>"),e.join("")}});var pn=gt.extend({initialize:function(t){ut.extend(this,t),this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1},beforeUpdate:fn,update:function(t,e,i){var n=this;return n.beforeUpdate(),n.maxWidth=t,n.maxHeight=e,n.margins=i,n.beforeSetDimensions(),n.setDimensions(),n.afterSetDimensions(),n.beforeBuildLabels(),n.buildLabels(),n.afterBuildLabels(),n.beforeFit(),n.fit(),n.afterFit(),n.afterUpdate(),n.minSize},afterUpdate:fn,beforeSetDimensions:fn,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:fn,beforeBuildLabels:fn,buildLabels:function(){var t=this,e=t.options.labels||{},i=ut.callback(e.generateLabels,[t.chart],t)||[];e.filter&&(i=i.filter(function(i){return e.filter(i,t.chart.data)})),t.options.reverse&&i.reverse(),t.legendItems=i},afterBuildLabels:fn,beforeFit:fn,fit:function(){var t=this,e=t.options,i=e.labels,n=e.display,a=t.ctx,r=ut.options._parseFont(i),o=r.size,s=t.legendHitBoxes=[],l=t.minSize,u=t.isHorizontal();if(u?(l.width=t.maxWidth,l.height=n?10:0):(l.width=n?10:0,l.height=t.maxHeight),n)if(a.font=r.string,u){var d=t.lineWidths=[0],h=0;a.textAlign="left",a.textBaseline="top",ut.each(t.legendItems,function(t,e){var n=mn(i,o)+o/2+a.measureText(t.text).width;(0===e||d[d.length-1]+n+i.padding>l.width)&&(h+=o+i.padding,d[d.length-(e>0?0:1)]=i.padding),s[e]={left:0,top:0,width:n,height:o},d[d.length-1]+=n+i.padding}),l.height+=h}else{var c=i.padding,f=t.columnWidths=[],g=i.padding,m=0,p=0,v=o+c;ut.each(t.legendItems,function(t,e){var n=mn(i,o)+o/2+a.measureText(t.text).width;e>0&&p+v>l.height-c&&(g+=m+i.padding,f.push(m),m=0,p=0),m=Math.max(m,n),p+=v,s[e]={left:0,top:0,width:n,height:o}}),g+=m,f.push(m),l.width+=g}t.width=l.width,t.height=l.height},afterFit:fn,isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},draw:function(){var t=this,e=t.options,i=e.labels,n=ot.global,a=n.defaultColor,r=n.elements.line,o=t.width,s=t.lineWidths;if(e.display){var l,u=t.ctx,d=gn(i.fontColor,n.defaultFontColor),h=ut.options._parseFont(i),c=h.size;u.textAlign="left",u.textBaseline="middle",u.lineWidth=.5,u.strokeStyle=d,u.fillStyle=d,u.font=h.string;var f=mn(i,c),g=t.legendHitBoxes,m=t.isHorizontal();l=m?{x:t.left+(o-s[0])/2+i.padding,y:t.top+i.padding,line:0}:{x:t.left+i.padding,y:t.top+i.padding,line:0};var p=c+i.padding;ut.each(t.legendItems,function(n,d){var h=u.measureText(n.text).width,v=f+c/2+h,y=l.x,b=l.y;m?d>0&&y+v+i.padding>t.left+t.minSize.width&&(b=l.y+=p,l.line++,y=l.x=t.left+(o-s[l.line])/2+i.padding):d>0&&b+p>t.top+t.minSize.height&&(y=l.x=y+t.columnWidths[l.line]+i.padding,b=l.y=t.top+i.padding,l.line++),function(t,i,n){if(!(isNaN(f)||f<=0)){u.save();var o=gn(n.lineWidth,r.borderWidth);if(u.fillStyle=gn(n.fillStyle,a),u.lineCap=gn(n.lineCap,r.borderCapStyle),u.lineDashOffset=gn(n.lineDashOffset,r.borderDashOffset),u.lineJoin=gn(n.lineJoin,r.borderJoinStyle),u.lineWidth=o,u.strokeStyle=gn(n.strokeStyle,a),u.setLineDash&&u.setLineDash(gn(n.lineDash,r.borderDash)),e.labels&&e.labels.usePointStyle){var s=f*Math.SQRT2/2,l=t+f/2,d=i+c/2;ut.canvas.drawPoint(u,n.pointStyle,s,l,d)}else 0!==o&&u.strokeRect(t,i,f,c),u.fillRect(t,i,f,c);u.restore()}}(y,b,n),g[d].left=y,g[d].top=b,function(t,e,i,n){var a=c/2,r=f+a+t,o=e+a;u.fillText(i.text,r,o),i.hidden&&(u.beginPath(),u.lineWidth=2,u.moveTo(r,o),u.lineTo(r+n,o),u.stroke())}(y,b,n,h),m?l.x+=v+i.padding:l.y+=p})}},_getLegendItemAt:function(t,e){var i,n,a,r=this;if(t>=r.left&&t<=r.right&&e>=r.top&&e<=r.bottom)for(a=r.legendHitBoxes,i=0;i<a.length;++i)if(t>=(n=a[i]).left&&t<=n.left+n.width&&e>=n.top&&e<=n.top+n.height)return r.legendItems[i];return null},handleEvent:function(t){var e,i=this,n=i.options,a="mouseup"===t.type?"click":t.type;if("mousemove"===a){if(!n.onHover&&!n.onLeave)return}else{if("click"!==a)return;if(!n.onClick)return}e=i._getLegendItemAt(t.x,t.y),"click"===a?e&&n.onClick&&n.onClick.call(i,t.native,e):(n.onLeave&&e!==i._hoveredItem&&(i._hoveredItem&&n.onLeave.call(i,t.native,i._hoveredItem),i._hoveredItem=e),n.onHover&&e&&n.onHover.call(i,t.native,e))}});function vn(t,e){var i=new pn({ctx:t.ctx,options:e,chart:t});xe.configure(t,i,e),xe.addBox(t,i),t.legend=i}var yn={id:"legend",_element:pn,beforeInit:function(t){var e=t.options.legend;e&&vn(t,e)},beforeUpdate:function(t){var e=t.options.legend,i=t.legend;e?(ut.mergeIf(e,ot.global.legend),i?(xe.configure(t,i,e),i.options=e):vn(t,e)):i&&(xe.removeBox(t,i),delete t.legend)},afterEvent:function(t,e){var i=t.legend;i&&i.handleEvent(e)}},bn=ut.noop;ot._set("global",{title:{display:!1,fontStyle:"bold",fullWidth:!0,padding:10,position:"top",text:"",weight:2e3}});var xn=gt.extend({initialize:function(t){ut.extend(this,t),this.legendHitBoxes=[]},beforeUpdate:bn,update:function(t,e,i){var n=this;return n.beforeUpdate(),n.maxWidth=t,n.maxHeight=e,n.margins=i,n.beforeSetDimensions(),n.setDimensions(),n.afterSetDimensions(),n.beforeBuildLabels(),n.buildLabels(),n.afterBuildLabels(),n.beforeFit(),n.fit(),n.afterFit(),n.afterUpdate(),n.minSize},afterUpdate:bn,beforeSetDimensions:bn,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:bn,beforeBuildLabels:bn,buildLabels:bn,afterBuildLabels:bn,beforeFit:bn,fit:function(){var t=this,e=t.options,i=e.display,n=t.minSize,a=ut.isArray(e.text)?e.text.length:1,r=ut.options._parseFont(e),o=i?a*r.lineHeight+2*e.padding:0;t.isHorizontal()?(n.width=t.maxWidth,n.height=o):(n.width=o,n.height=t.maxHeight),t.width=n.width,t.height=n.height},afterFit:bn,isHorizontal:function(){var t=this.options.position;return"top"===t||"bottom"===t},draw:function(){var t=this,e=t.ctx,i=t.options;if(i.display){var n,a,r,o=ut.options._parseFont(i),s=o.lineHeight,l=s/2+i.padding,u=0,d=t.top,h=t.left,c=t.bottom,f=t.right;e.fillStyle=ut.valueOrDefault(i.fontColor,ot.global.defaultFontColor),e.font=o.string,t.isHorizontal()?(a=h+(f-h)/2,r=d+l,n=f-h):(a="left"===i.position?h+l:f-l,r=d+(c-d)/2,n=c-d,u=Math.PI*("left"===i.position?-.5:.5)),e.save(),e.translate(a,r),e.rotate(u),e.textAlign="center",e.textBaseline="middle";var g=i.text;if(ut.isArray(g))for(var m=0,p=0;p<g.length;++p)e.fillText(g[p],0,m,n),m+=s;else e.fillText(g,0,0,n);e.restore()}}});function _n(t,e){var i=new xn({ctx:t.ctx,options:e,chart:t});xe.configure(t,i,e),xe.addBox(t,i),t.titleBlock=i}var kn={},wn=cn,Mn=yn,Sn={id:"title",_element:xn,beforeInit:function(t){var e=t.options.title;e&&_n(t,e)},beforeUpdate:function(t){var e=t.options.title,i=t.titleBlock;e?(ut.mergeIf(e,ot.global.title),i?(xe.configure(t,i,e),i.options=e):_n(t,e)):i&&(xe.removeBox(t,i),delete t.titleBlock)}};for(var Dn in kn.filler=wn,kn.legend=Mn,kn.title=Sn,ai.helpers=ut,function(){function t(t,e,i){var n;return"string"==typeof t?(n=parseInt(t,10),-1!==t.indexOf("%")&&(n=n/100*e.parentNode[i])):n=t,n}function e(t){return null!=t&&"none"!==t}function i(i,n,a){var r=document.defaultView,o=ut._getParentNode(i),s=r.getComputedStyle(i)[n],l=r.getComputedStyle(o)[n],u=e(s),d=e(l),h=Number.POSITIVE_INFINITY;return u||d?Math.min(u?t(s,i,a):h,d?t(l,o,a):h):"none"}ut.where=function(t,e){if(ut.isArray(t)&&Array.prototype.filter)return t.filter(e);var i=[];return ut.each(t,function(t){e(t)&&i.push(t)}),i},ut.findIndex=Array.prototype.findIndex?function(t,e,i){return t.findIndex(e,i)}:function(t,e,i){i=void 0===i?t:i;for(var n=0,a=t.length;n<a;++n)if(e.call(i,t[n],n,t))return n;return-1},ut.findNextWhere=function(t,e,i){ut.isNullOrUndef(i)&&(i=-1);for(var n=i+1;n<t.length;n++){var a=t[n];if(e(a))return a}},ut.findPreviousWhere=function(t,e,i){ut.isNullOrUndef(i)&&(i=t.length);for(var n=i-1;n>=0;n--){var a=t[n];if(e(a))return a}},ut.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},ut.almostEquals=function(t,e,i){return Math.abs(t-e)<i},ut.almostWhole=function(t,e){var i=Math.round(t);return i-e<t&&i+e>t},ut.max=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.max(t,e)},Number.NEGATIVE_INFINITY)},ut.min=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.min(t,e)},Number.POSITIVE_INFINITY)},ut.sign=Math.sign?function(t){return Math.sign(t)}:function(t){return 0==(t=+t)||isNaN(t)?t:t>0?1:-1},ut.log10=Math.log10?function(t){return Math.log10(t)}:function(t){var e=Math.log(t)*Math.LOG10E,i=Math.round(e);return t===Math.pow(10,i)?i:e},ut.toRadians=function(t){return t*(Math.PI/180)},ut.toDegrees=function(t){return t*(180/Math.PI)},ut._decimalPlaces=function(t){if(ut.isFinite(t)){for(var e=1,i=0;Math.round(t*e)/e!==t;)e*=10,i++;return i}},ut.getAngleFromPoint=function(t,e){var i=e.x-t.x,n=e.y-t.y,a=Math.sqrt(i*i+n*n),r=Math.atan2(n,i);return r<-.5*Math.PI&&(r+=2*Math.PI),{angle:r,distance:a}},ut.distanceBetweenPoints=function(t,e){return Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))},ut.aliasPixel=function(t){return t%2==0?0:.5},ut._alignPixel=function(t,e,i){var n=t.currentDevicePixelRatio,a=i/2;return Math.round((e-a)*n)/n+a},ut.splineCurve=function(t,e,i,n){var a=t.skip?e:t,r=e,o=i.skip?e:i,s=Math.sqrt(Math.pow(r.x-a.x,2)+Math.pow(r.y-a.y,2)),l=Math.sqrt(Math.pow(o.x-r.x,2)+Math.pow(o.y-r.y,2)),u=s/(s+l),d=l/(s+l),h=n*(u=isNaN(u)?0:u),c=n*(d=isNaN(d)?0:d);return{previous:{x:r.x-h*(o.x-a.x),y:r.y-h*(o.y-a.y)},next:{x:r.x+c*(o.x-a.x),y:r.y+c*(o.y-a.y)}}},ut.EPSILON=Number.EPSILON||1e-14,ut.splineCurveMonotone=function(t){var e,i,n,a,r,o,s,l,u,d=(t||[]).map(function(t){return{model:t._model,deltaK:0,mK:0}}),h=d.length;for(e=0;e<h;++e)if(!(n=d[e]).model.skip){if(i=e>0?d[e-1]:null,(a=e<h-1?d[e+1]:null)&&!a.model.skip){var c=a.model.x-n.model.x;n.deltaK=0!==c?(a.model.y-n.model.y)/c:0}!i||i.model.skip?n.mK=n.deltaK:!a||a.model.skip?n.mK=i.deltaK:this.sign(i.deltaK)!==this.sign(n.deltaK)?n.mK=0:n.mK=(i.deltaK+n.deltaK)/2}for(e=0;e<h-1;++e)n=d[e],a=d[e+1],n.model.skip||a.model.skip||(ut.almostEquals(n.deltaK,0,this.EPSILON)?n.mK=a.mK=0:(r=n.mK/n.deltaK,o=a.mK/n.deltaK,(l=Math.pow(r,2)+Math.pow(o,2))<=9||(s=3/Math.sqrt(l),n.mK=r*s*n.deltaK,a.mK=o*s*n.deltaK)));for(e=0;e<h;++e)(n=d[e]).model.skip||(i=e>0?d[e-1]:null,a=e<h-1?d[e+1]:null,i&&!i.model.skip&&(u=(n.model.x-i.model.x)/3,n.model.controlPointPreviousX=n.model.x-u,n.model.controlPointPreviousY=n.model.y-u*n.mK),a&&!a.model.skip&&(u=(a.model.x-n.model.x)/3,n.model.controlPointNextX=n.model.x+u,n.model.controlPointNextY=n.model.y+u*n.mK))},ut.nextItem=function(t,e,i){return i?e>=t.length-1?t[0]:t[e+1]:e>=t.length-1?t[t.length-1]:t[e+1]},ut.previousItem=function(t,e,i){return i?e<=0?t[t.length-1]:t[e-1]:e<=0?t[0]:t[e-1]},ut.niceNum=function(t,e){var i=Math.floor(ut.log10(t)),n=t/Math.pow(10,i);return(e?n<1.5?1:n<3?2:n<7?5:10:n<=1?1:n<=2?2:n<=5?5:10)*Math.pow(10,i)},ut.requestAnimFrame="undefined"==typeof window?function(t){t()}:window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)},ut.getRelativePosition=function(t,e){var i,n,a=t.originalEvent||t,r=t.target||t.srcElement,o=r.getBoundingClientRect(),s=a.touches;s&&s.length>0?(i=s[0].clientX,n=s[0].clientY):(i=a.clientX,n=a.clientY);var l=parseFloat(ut.getStyle(r,"padding-left")),u=parseFloat(ut.getStyle(r,"padding-top")),d=parseFloat(ut.getStyle(r,"padding-right")),h=parseFloat(ut.getStyle(r,"padding-bottom")),c=o.right-o.left-l-d,f=o.bottom-o.top-u-h;return{x:i=Math.round((i-o.left-l)/c*r.width/e.currentDevicePixelRatio),y:n=Math.round((n-o.top-u)/f*r.height/e.currentDevicePixelRatio)}},ut.getConstraintWidth=function(t){return i(t,"max-width","clientWidth")},ut.getConstraintHeight=function(t){return i(t,"max-height","clientHeight")},ut._calculatePadding=function(t,e,i){return(e=ut.getStyle(t,e)).indexOf("%")>-1?i*parseInt(e,10)/100:parseInt(e,10)},ut._getParentNode=function(t){var e=t.parentNode;return e&&"[object ShadowRoot]"===e.toString()&&(e=e.host),e},ut.getMaximumWidth=function(t){var e=ut._getParentNode(t);if(!e)return t.clientWidth;var i=e.clientWidth,n=i-ut._calculatePadding(e,"padding-left",i)-ut._calculatePadding(e,"padding-right",i),a=ut.getConstraintWidth(t);return isNaN(a)?n:Math.min(n,a)},ut.getMaximumHeight=function(t){var e=ut._getParentNode(t);if(!e)return t.clientHeight;var i=e.clientHeight,n=i-ut._calculatePadding(e,"padding-top",i)-ut._calculatePadding(e,"padding-bottom",i),a=ut.getConstraintHeight(t);return isNaN(a)?n:Math.min(n,a)},ut.getStyle=function(t,e){return t.currentStyle?t.currentStyle[e]:document.defaultView.getComputedStyle(t,null).getPropertyValue(e)},ut.retinaScale=function(t,e){var i=t.currentDevicePixelRatio=e||"undefined"!=typeof window&&window.devicePixelRatio||1;if(1!==i){var n=t.canvas,a=t.height,r=t.width;n.height=a*i,n.width=r*i,t.ctx.scale(i,i),n.style.height||n.style.width||(n.style.height=a+"px",n.style.width=r+"px")}},ut.fontString=function(t,e,i){return e+" "+t+"px "+i},ut.longestText=function(t,e,i,n){var a=(n=n||{}).data=n.data||{},r=n.garbageCollect=n.garbageCollect||[];n.font!==e&&(a=n.data={},r=n.garbageCollect=[],n.font=e),t.font=e;var o=0;ut.each(i,function(e){null!=e&&!0!==ut.isArray(e)?o=ut.measureText(t,a,r,o,e):ut.isArray(e)&&ut.each(e,function(e){null==e||ut.isArray(e)||(o=ut.measureText(t,a,r,o,e))})});var s=r.length/2;if(s>i.length){for(var l=0;l<s;l++)delete a[r[l]];r.splice(0,s)}return o},ut.measureText=function(t,e,i,n,a){var r=e[a];return r||(r=e[a]=t.measureText(a).width,i.push(a)),r>n&&(n=r),n},ut.numberOfLabelLines=function(t){var e=1;return ut.each(t,function(t){ut.isArray(t)&&t.length>e&&(e=t.length)}),e},ut.color=G?function(t){return t instanceof CanvasGradient&&(t=ot.global.defaultColor),G(t)}:function(t){return console.error("Color.js not found!"),t},ut.getHoverColor=function(t){return t instanceof CanvasPattern||t instanceof CanvasGradient?t:ut.color(t).saturate(.5).darken(.1).rgbString()}}(),ai._adapters=si,ai.Animation=pt,ai.animationService=vt,ai.controllers=ue,ai.DatasetController=kt,ai.defaults=ot,ai.Element=gt,ai.elements=Nt,ai.Interaction=pe,ai.layouts=xe,ai.platform=Ve,ai.plugins=He,ai.Scale=fi,ai.scaleService=Ee,ai.Ticks=li,ai.Tooltip=Je,ai.helpers.each(en,function(t,e){ai.scaleService.registerScaleType(e,t,t._defaults)}),kn)kn.hasOwnProperty(Dn)&&ai.plugins.register(kn[Dn]);ai.platform.initialize();var Cn=ai;return"undefined"!=typeof window&&(window.Chart=ai),ai.Chart=ai,ai.Legend=kn.legend._element,ai.Title=kn.title._element,ai.pluginService=ai.plugins,ai.PluginBase=ai.Element.extend({}),ai.canvasHelpers=ai.helpers.canvas,ai.layoutService=ai.layouts,ai.LinearScaleBase=yi,ai.helpers.each(["Bar","Bubble","Doughnut","Line","PolarArea","Radar","Scatter"],function(t){ai[t]=function(e,i){return new ai(e,ai.helpers.merge(i||{},{type:t.charAt(0).toLowerCase()+t.slice(1)}))}}),Cn});
diff --git a/dist/Chart.css b/dist/Chart.css
new file mode 100644 (file)
index 0000000..5e74959
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * DOM element rendering detection
+ * https://davidwalsh.name/detect-node-insertion
+ */
+@keyframes chartjs-render-animation {
+       from { opacity: 0.99; }
+       to { opacity: 1; }
+}
+
+.chartjs-render-monitor {
+       animation: chartjs-render-animation 0.001s;
+}
+
+/*
+ * DOM element resizing detection
+ * https://github.com/marcj/css-element-queries
+ */
+.chartjs-size-monitor,
+.chartjs-size-monitor-expand,
+.chartjs-size-monitor-shrink {
+       position: absolute;
+       direction: ltr;
+       left: 0;
+       top: 0;
+       right: 0;
+       bottom: 0;
+       overflow: hidden;
+       pointer-events: none;
+       visibility: hidden;
+       z-index: -1;
+}
+
+.chartjs-size-monitor-expand > div {
+       position: absolute;
+       width: 1000000px;
+       height: 1000000px;
+       left: 0;
+       top: 0;
+}
+
+.chartjs-size-monitor-shrink > div {
+       position: absolute;
+       width: 200%;
+       height: 200%;
+       left: 0;
+       top: 0;
+}
diff --git a/dist/Chart.js b/dist/Chart.js
new file mode 100644 (file)
index 0000000..4c50e09
--- /dev/null
@@ -0,0 +1,14680 @@
+/*!
+ * Chart.js v2.8.0
+ * https://www.chartjs.org
+ * (c) 2019 Chart.js Contributors
+ * Released under the MIT License
+ */
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(function() { try { return require('moment'); } catch(e) { } }()) :
+typeof define === 'function' && define.amd ? define(['require'], function(require) { return factory(function() { try { return require('moment'); } catch(e) { } }()); }) :
+(global.Chart = factory(global.moment));
+}(this, (function (moment) { 'use strict';
+
+moment = moment && moment.hasOwnProperty('default') ? moment['default'] : moment;
+
+/* MIT license */
+
+var conversions = {
+  rgb2hsl: rgb2hsl,
+  rgb2hsv: rgb2hsv,
+  rgb2hwb: rgb2hwb,
+  rgb2cmyk: rgb2cmyk,
+  rgb2keyword: rgb2keyword,
+  rgb2xyz: rgb2xyz,
+  rgb2lab: rgb2lab,
+  rgb2lch: rgb2lch,
+
+  hsl2rgb: hsl2rgb,
+  hsl2hsv: hsl2hsv,
+  hsl2hwb: hsl2hwb,
+  hsl2cmyk: hsl2cmyk,
+  hsl2keyword: hsl2keyword,
+
+  hsv2rgb: hsv2rgb,
+  hsv2hsl: hsv2hsl,
+  hsv2hwb: hsv2hwb,
+  hsv2cmyk: hsv2cmyk,
+  hsv2keyword: hsv2keyword,
+
+  hwb2rgb: hwb2rgb,
+  hwb2hsl: hwb2hsl,
+  hwb2hsv: hwb2hsv,
+  hwb2cmyk: hwb2cmyk,
+  hwb2keyword: hwb2keyword,
+
+  cmyk2rgb: cmyk2rgb,
+  cmyk2hsl: cmyk2hsl,
+  cmyk2hsv: cmyk2hsv,
+  cmyk2hwb: cmyk2hwb,
+  cmyk2keyword: cmyk2keyword,
+
+  keyword2rgb: keyword2rgb,
+  keyword2hsl: keyword2hsl,
+  keyword2hsv: keyword2hsv,
+  keyword2hwb: keyword2hwb,
+  keyword2cmyk: keyword2cmyk,
+  keyword2lab: keyword2lab,
+  keyword2xyz: keyword2xyz,
+
+  xyz2rgb: xyz2rgb,
+  xyz2lab: xyz2lab,
+  xyz2lch: xyz2lch,
+
+  lab2xyz: lab2xyz,
+  lab2rgb: lab2rgb,
+  lab2lch: lab2lch,
+
+  lch2lab: lch2lab,
+  lch2xyz: lch2xyz,
+  lch2rgb: lch2rgb
+};
+
+
+function rgb2hsl(rgb) {
+  var r = rgb[0]/255,
+      g = rgb[1]/255,
+      b = rgb[2]/255,
+      min = Math.min(r, g, b),
+      max = Math.max(r, g, b),
+      delta = max - min,
+      h, s, l;
+
+  if (max == min)
+    h = 0;
+  else if (r == max)
+    h = (g - b) / delta;
+  else if (g == max)
+    h = 2 + (b - r) / delta;
+  else if (b == max)
+    h = 4 + (r - g)/ delta;
+
+  h = Math.min(h * 60, 360);
+
+  if (h < 0)
+    h += 360;
+
+  l = (min + max) / 2;
+
+  if (max == min)
+    s = 0;
+  else if (l <= 0.5)
+    s = delta / (max + min);
+  else
+    s = delta / (2 - max - min);
+
+  return [h, s * 100, l * 100];
+}
+
+function rgb2hsv(rgb) {
+  var r = rgb[0],
+      g = rgb[1],
+      b = rgb[2],
+      min = Math.min(r, g, b),
+      max = Math.max(r, g, b),
+      delta = max - min,
+      h, s, v;
+
+  if (max == 0)
+    s = 0;
+  else
+    s = (delta/max * 1000)/10;
+
+  if (max == min)
+    h = 0;
+  else if (r == max)
+    h = (g - b) / delta;
+  else if (g == max)
+    h = 2 + (b - r) / delta;
+  else if (b == max)
+    h = 4 + (r - g) / delta;
+
+  h = Math.min(h * 60, 360);
+
+  if (h < 0)
+    h += 360;
+
+  v = ((max / 255) * 1000) / 10;
+
+  return [h, s, v];
+}
+
+function rgb2hwb(rgb) {
+  var r = rgb[0],
+      g = rgb[1],
+      b = rgb[2],
+      h = rgb2hsl(rgb)[0],
+      w = 1/255 * Math.min(r, Math.min(g, b)),
+      b = 1 - 1/255 * Math.max(r, Math.max(g, b));
+
+  return [h, w * 100, b * 100];
+}
+
+function rgb2cmyk(rgb) {
+  var r = rgb[0] / 255,
+      g = rgb[1] / 255,
+      b = rgb[2] / 255,
+      c, m, y, k;
+
+  k = Math.min(1 - r, 1 - g, 1 - b);
+  c = (1 - r - k) / (1 - k) || 0;
+  m = (1 - g - k) / (1 - k) || 0;
+  y = (1 - b - k) / (1 - k) || 0;
+  return [c * 100, m * 100, y * 100, k * 100];
+}
+
+function rgb2keyword(rgb) {
+  return reverseKeywords[JSON.stringify(rgb)];
+}
+
+function rgb2xyz(rgb) {
+  var r = rgb[0] / 255,
+      g = rgb[1] / 255,
+      b = rgb[2] / 255;
+
+  // assume sRGB
+  r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
+  g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
+  b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
+
+  var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
+  var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
+  var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
+
+  return [x * 100, y *100, z * 100];
+}
+
+function rgb2lab(rgb) {
+  var xyz = rgb2xyz(rgb),
+        x = xyz[0],
+        y = xyz[1],
+        z = xyz[2],
+        l, a, b;
+
+  x /= 95.047;
+  y /= 100;
+  z /= 108.883;
+
+  x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
+  y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
+  z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
+
+  l = (116 * y) - 16;
+  a = 500 * (x - y);
+  b = 200 * (y - z);
+
+  return [l, a, b];
+}
+
+function rgb2lch(args) {
+  return lab2lch(rgb2lab(args));
+}
+
+function hsl2rgb(hsl) {
+  var h = hsl[0] / 360,
+      s = hsl[1] / 100,
+      l = hsl[2] / 100,
+      t1, t2, t3, rgb, val;
+
+  if (s == 0) {
+    val = l * 255;
+    return [val, val, val];
+  }
+
+  if (l < 0.5)
+    t2 = l * (1 + s);
+  else
+    t2 = l + s - l * s;
+  t1 = 2 * l - t2;
+
+  rgb = [0, 0, 0];
+  for (var i = 0; i < 3; i++) {
+    t3 = h + 1 / 3 * - (i - 1);
+    t3 < 0 && t3++;
+    t3 > 1 && t3--;
+
+    if (6 * t3 < 1)
+      val = t1 + (t2 - t1) * 6 * t3;
+    else if (2 * t3 < 1)
+      val = t2;
+    else if (3 * t3 < 2)
+      val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
+    else
+      val = t1;
+
+    rgb[i] = val * 255;
+  }
+
+  return rgb;
+}
+
+function hsl2hsv(hsl) {
+  var h = hsl[0],
+      s = hsl[1] / 100,
+      l = hsl[2] / 100,
+      sv, v;
+
+  if(l === 0) {
+      // no need to do calc on black
+      // also avoids divide by 0 error
+      return [0, 0, 0];
+  }
+
+  l *= 2;
+  s *= (l <= 1) ? l : 2 - l;
+  v = (l + s) / 2;
+  sv = (2 * s) / (l + s);
+  return [h, sv * 100, v * 100];
+}
+
+function hsl2hwb(args) {
+  return rgb2hwb(hsl2rgb(args));
+}
+
+function hsl2cmyk(args) {
+  return rgb2cmyk(hsl2rgb(args));
+}
+
+function hsl2keyword(args) {
+  return rgb2keyword(hsl2rgb(args));
+}
+
+
+function hsv2rgb(hsv) {
+  var h = hsv[0] / 60,
+      s = hsv[1] / 100,
+      v = hsv[2] / 100,
+      hi = Math.floor(h) % 6;
+
+  var f = h - Math.floor(h),
+      p = 255 * v * (1 - s),
+      q = 255 * v * (1 - (s * f)),
+      t = 255 * v * (1 - (s * (1 - f))),
+      v = 255 * v;
+
+  switch(hi) {
+    case 0:
+      return [v, t, p];
+    case 1:
+      return [q, v, p];
+    case 2:
+      return [p, v, t];
+    case 3:
+      return [p, q, v];
+    case 4:
+      return [t, p, v];
+    case 5:
+      return [v, p, q];
+  }
+}
+
+function hsv2hsl(hsv) {
+  var h = hsv[0],
+      s = hsv[1] / 100,
+      v = hsv[2] / 100,
+      sl, l;
+
+  l = (2 - s) * v;
+  sl = s * v;
+  sl /= (l <= 1) ? l : 2 - l;
+  sl = sl || 0;
+  l /= 2;
+  return [h, sl * 100, l * 100];
+}
+
+function hsv2hwb(args) {
+  return rgb2hwb(hsv2rgb(args))
+}
+
+function hsv2cmyk(args) {
+  return rgb2cmyk(hsv2rgb(args));
+}
+
+function hsv2keyword(args) {
+  return rgb2keyword(hsv2rgb(args));
+}
+
+// http://dev.w3.org/csswg/css-color/#hwb-to-rgb
+function hwb2rgb(hwb) {
+  var h = hwb[0] / 360,
+      wh = hwb[1] / 100,
+      bl = hwb[2] / 100,
+      ratio = wh + bl,
+      i, v, f, n;
+
+  // wh + bl cant be > 1
+  if (ratio > 1) {
+    wh /= ratio;
+    bl /= ratio;
+  }
+
+  i = Math.floor(6 * h);
+  v = 1 - bl;
+  f = 6 * h - i;
+  if ((i & 0x01) != 0) {
+    f = 1 - f;
+  }
+  n = wh + f * (v - wh);  // linear interpolation
+
+  switch (i) {
+    default:
+    case 6:
+    case 0: r = v; g = n; b = wh; break;
+    case 1: r = n; g = v; b = wh; break;
+    case 2: r = wh; g = v; b = n; break;
+    case 3: r = wh; g = n; b = v; break;
+    case 4: r = n; g = wh; b = v; break;
+    case 5: r = v; g = wh; b = n; break;
+  }
+
+  return [r * 255, g * 255, b * 255];
+}
+
+function hwb2hsl(args) {
+  return rgb2hsl(hwb2rgb(args));
+}
+
+function hwb2hsv(args) {
+  return rgb2hsv(hwb2rgb(args));
+}
+
+function hwb2cmyk(args) {
+  return rgb2cmyk(hwb2rgb(args));
+}
+
+function hwb2keyword(args) {
+  return rgb2keyword(hwb2rgb(args));
+}
+
+function cmyk2rgb(cmyk) {
+  var c = cmyk[0] / 100,
+      m = cmyk[1] / 100,
+      y = cmyk[2] / 100,
+      k = cmyk[3] / 100,
+      r, g, b;
+
+  r = 1 - Math.min(1, c * (1 - k) + k);
+  g = 1 - Math.min(1, m * (1 - k) + k);
+  b = 1 - Math.min(1, y * (1 - k) + k);
+  return [r * 255, g * 255, b * 255];
+}
+
+function cmyk2hsl(args) {
+  return rgb2hsl(cmyk2rgb(args));
+}
+
+function cmyk2hsv(args) {
+  return rgb2hsv(cmyk2rgb(args));
+}
+
+function cmyk2hwb(args) {
+  return rgb2hwb(cmyk2rgb(args));
+}
+
+function cmyk2keyword(args) {
+  return rgb2keyword(cmyk2rgb(args));
+}
+
+
+function xyz2rgb(xyz) {
+  var x = xyz[0] / 100,
+      y = xyz[1] / 100,
+      z = xyz[2] / 100,
+      r, g, b;
+
+  r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
+  g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
+  b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
+
+  // assume sRGB
+  r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
+    : r = (r * 12.92);
+
+  g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
+    : g = (g * 12.92);
+
+  b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
+    : b = (b * 12.92);
+
+  r = Math.min(Math.max(0, r), 1);
+  g = Math.min(Math.max(0, g), 1);
+  b = Math.min(Math.max(0, b), 1);
+
+  return [r * 255, g * 255, b * 255];
+}
+
+function xyz2lab(xyz) {
+  var x = xyz[0],
+      y = xyz[1],
+      z = xyz[2],
+      l, a, b;
+
+  x /= 95.047;
+  y /= 100;
+  z /= 108.883;
+
+  x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
+  y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
+  z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
+
+  l = (116 * y) - 16;
+  a = 500 * (x - y);
+  b = 200 * (y - z);
+
+  return [l, a, b];
+}
+
+function xyz2lch(args) {
+  return lab2lch(xyz2lab(args));
+}
+
+function lab2xyz(lab) {
+  var l = lab[0],
+      a = lab[1],
+      b = lab[2],
+      x, y, z, y2;
+
+  if (l <= 8) {
+    y = (l * 100) / 903.3;
+    y2 = (7.787 * (y / 100)) + (16 / 116);
+  } else {
+    y = 100 * Math.pow((l + 16) / 116, 3);
+    y2 = Math.pow(y / 100, 1/3);
+  }
+
+  x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3);
+
+  z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3);
+
+  return [x, y, z];
+}
+
+function lab2lch(lab) {
+  var l = lab[0],
+      a = lab[1],
+      b = lab[2],
+      hr, h, c;
+
+  hr = Math.atan2(b, a);
+  h = hr * 360 / 2 / Math.PI;
+  if (h < 0) {
+    h += 360;
+  }
+  c = Math.sqrt(a * a + b * b);
+  return [l, c, h];
+}
+
+function lab2rgb(args) {
+  return xyz2rgb(lab2xyz(args));
+}
+
+function lch2lab(lch) {
+  var l = lch[0],
+      c = lch[1],
+      h = lch[2],
+      a, b, hr;
+
+  hr = h / 360 * 2 * Math.PI;
+  a = c * Math.cos(hr);
+  b = c * Math.sin(hr);
+  return [l, a, b];
+}
+
+function lch2xyz(args) {
+  return lab2xyz(lch2lab(args));
+}
+
+function lch2rgb(args) {
+  return lab2rgb(lch2lab(args));
+}
+
+function keyword2rgb(keyword) {
+  return cssKeywords[keyword];
+}
+
+function keyword2hsl(args) {
+  return rgb2hsl(keyword2rgb(args));
+}
+
+function keyword2hsv(args) {
+  return rgb2hsv(keyword2rgb(args));
+}
+
+function keyword2hwb(args) {
+  return rgb2hwb(keyword2rgb(args));
+}
+
+function keyword2cmyk(args) {
+  return rgb2cmyk(keyword2rgb(args));
+}
+
+function keyword2lab(args) {
+  return rgb2lab(keyword2rgb(args));
+}
+
+function keyword2xyz(args) {
+  return rgb2xyz(keyword2rgb(args));
+}
+
+var cssKeywords = {
+  aliceblue:  [240,248,255],
+  antiquewhite: [250,235,215],
+  aqua: [0,255,255],
+  aquamarine: [127,255,212],
+  azure:  [240,255,255],
+  beige:  [245,245,220],
+  bisque: [255,228,196],
+  black:  [0,0,0],
+  blanchedalmond: [255,235,205],
+  blue: [0,0,255],
+  blueviolet: [138,43,226],
+  brown:  [165,42,42],
+  burlywood:  [222,184,135],
+  cadetblue:  [95,158,160],
+  chartreuse: [127,255,0],
+  chocolate:  [210,105,30],
+  coral:  [255,127,80],
+  cornflowerblue: [100,149,237],
+  cornsilk: [255,248,220],
+  crimson:  [220,20,60],
+  cyan: [0,255,255],
+  darkblue: [0,0,139],
+  darkcyan: [0,139,139],
+  darkgoldenrod:  [184,134,11],
+  darkgray: [169,169,169],
+  darkgreen:  [0,100,0],
+  darkgrey: [169,169,169],
+  darkkhaki:  [189,183,107],
+  darkmagenta:  [139,0,139],
+  darkolivegreen: [85,107,47],
+  darkorange: [255,140,0],
+  darkorchid: [153,50,204],
+  darkred:  [139,0,0],
+  darksalmon: [233,150,122],
+  darkseagreen: [143,188,143],
+  darkslateblue:  [72,61,139],
+  darkslategray:  [47,79,79],
+  darkslategrey:  [47,79,79],
+  darkturquoise:  [0,206,209],
+  darkviolet: [148,0,211],
+  deeppink: [255,20,147],
+  deepskyblue:  [0,191,255],
+  dimgray:  [105,105,105],
+  dimgrey:  [105,105,105],
+  dodgerblue: [30,144,255],
+  firebrick:  [178,34,34],
+  floralwhite:  [255,250,240],
+  forestgreen:  [34,139,34],
+  fuchsia:  [255,0,255],
+  gainsboro:  [220,220,220],
+  ghostwhite: [248,248,255],
+  gold: [255,215,0],
+  goldenrod:  [218,165,32],
+  gray: [128,128,128],
+  green:  [0,128,0],
+  greenyellow:  [173,255,47],
+  grey: [128,128,128],
+  honeydew: [240,255,240],
+  hotpink:  [255,105,180],
+  indianred:  [205,92,92],
+  indigo: [75,0,130],
+  ivory:  [255,255,240],
+  khaki:  [240,230,140],
+  lavender: [230,230,250],
+  lavenderblush:  [255,240,245],
+  lawngreen:  [124,252,0],
+  lemonchiffon: [255,250,205],
+  lightblue:  [173,216,230],
+  lightcoral: [240,128,128],
+  lightcyan:  [224,255,255],
+  lightgoldenrodyellow: [250,250,210],
+  lightgray:  [211,211,211],
+  lightgreen: [144,238,144],
+  lightgrey:  [211,211,211],
+  lightpink:  [255,182,193],
+  lightsalmon:  [255,160,122],
+  lightseagreen:  [32,178,170],
+  lightskyblue: [135,206,250],
+  lightslategray: [119,136,153],
+  lightslategrey: [119,136,153],
+  lightsteelblue: [176,196,222],
+  lightyellow:  [255,255,224],
+  lime: [0,255,0],
+  limegreen:  [50,205,50],
+  linen:  [250,240,230],
+  magenta:  [255,0,255],
+  maroon: [128,0,0],
+  mediumaquamarine: [102,205,170],
+  mediumblue: [0,0,205],
+  mediumorchid: [186,85,211],
+  mediumpurple: [147,112,219],
+  mediumseagreen: [60,179,113],
+  mediumslateblue:  [123,104,238],
+  mediumspringgreen:  [0,250,154],
+  mediumturquoise:  [72,209,204],
+  mediumvioletred:  [199,21,133],
+  midnightblue: [25,25,112],
+  mintcream:  [245,255,250],
+  mistyrose:  [255,228,225],
+  moccasin: [255,228,181],
+  navajowhite:  [255,222,173],
+  navy: [0,0,128],
+  oldlace:  [253,245,230],
+  olive:  [128,128,0],
+  olivedrab:  [107,142,35],
+  orange: [255,165,0],
+  orangered:  [255,69,0],
+  orchid: [218,112,214],
+  palegoldenrod:  [238,232,170],
+  palegreen:  [152,251,152],
+  paleturquoise:  [175,238,238],
+  palevioletred:  [219,112,147],
+  papayawhip: [255,239,213],
+  peachpuff:  [255,218,185],
+  peru: [205,133,63],
+  pink: [255,192,203],
+  plum: [221,160,221],
+  powderblue: [176,224,230],
+  purple: [128,0,128],
+  rebeccapurple: [102, 51, 153],
+  red:  [255,0,0],
+  rosybrown:  [188,143,143],
+  royalblue:  [65,105,225],
+  saddlebrown:  [139,69,19],
+  salmon: [250,128,114],
+  sandybrown: [244,164,96],
+  seagreen: [46,139,87],
+  seashell: [255,245,238],
+  sienna: [160,82,45],
+  silver: [192,192,192],
+  skyblue:  [135,206,235],
+  slateblue:  [106,90,205],
+  slategray:  [112,128,144],
+  slategrey:  [112,128,144],
+  snow: [255,250,250],
+  springgreen:  [0,255,127],
+  steelblue:  [70,130,180],
+  tan:  [210,180,140],
+  teal: [0,128,128],
+  thistle:  [216,191,216],
+  tomato: [255,99,71],
+  turquoise:  [64,224,208],
+  violet: [238,130,238],
+  wheat:  [245,222,179],
+  white:  [255,255,255],
+  whitesmoke: [245,245,245],
+  yellow: [255,255,0],
+  yellowgreen:  [154,205,50]
+};
+
+var reverseKeywords = {};
+for (var key in cssKeywords) {
+  reverseKeywords[JSON.stringify(cssKeywords[key])] = key;
+}
+
+var convert = function() {
+   return new Converter();
+};
+
+for (var func in conversions) {
+  // export Raw versions
+  convert[func + "Raw"] =  (function(func) {
+    // accept array or plain args
+    return function(arg) {
+      if (typeof arg == "number")
+        arg = Array.prototype.slice.call(arguments);
+      return conversions[func](arg);
+    }
+  })(func);
+
+  var pair = /(\w+)2(\w+)/.exec(func),
+      from = pair[1],
+      to = pair[2];
+
+  // export rgb2hsl and ["rgb"]["hsl"]
+  convert[from] = convert[from] || {};
+
+  convert[from][to] = convert[func] = (function(func) { 
+    return function(arg) {
+      if (typeof arg == "number")
+        arg = Array.prototype.slice.call(arguments);
+      
+      var val = conversions[func](arg);
+      if (typeof val == "string" || val === undefined)
+        return val; // keyword
+
+      for (var i = 0; i < val.length; i++)
+        val[i] = Math.round(val[i]);
+      return val;
+    }
+  })(func);
+}
+
+
+/* Converter does lazy conversion and caching */
+var Converter = function() {
+   this.convs = {};
+};
+
+/* Either get the values for a space or
+  set the values for a space, depending on args */
+Converter.prototype.routeSpace = function(space, args) {
+   var values = args[0];
+   if (values === undefined) {
+      // color.rgb()
+      return this.getValues(space);
+   }
+   // color.rgb(10, 10, 10)
+   if (typeof values == "number") {
+      values = Array.prototype.slice.call(args);        
+   }
+
+   return this.setValues(space, values);
+};
+  
+/* Set the values for a space, invalidating cache */
+Converter.prototype.setValues = function(space, values) {
+   this.space = space;
+   this.convs = {};
+   this.convs[space] = values;
+   return this;
+};
+
+/* Get the values for a space. If there's already
+  a conversion for the space, fetch it, otherwise
+  compute it */
+Converter.prototype.getValues = function(space) {
+   var vals = this.convs[space];
+   if (!vals) {
+      var fspace = this.space,
+          from = this.convs[fspace];
+      vals = convert[fspace][space](from);
+
+      this.convs[space] = vals;
+   }
+  return vals;
+};
+
+["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) {
+   Converter.prototype[space] = function(vals) {
+      return this.routeSpace(space, arguments);
+   };
+});
+
+var colorConvert = convert;
+
+var colorName = {\r
+       "aliceblue": [240, 248, 255],\r
+       "antiquewhite": [250, 235, 215],\r
+       "aqua": [0, 255, 255],\r
+       "aquamarine": [127, 255, 212],\r
+       "azure": [240, 255, 255],\r
+       "beige": [245, 245, 220],\r
+       "bisque": [255, 228, 196],\r
+       "black": [0, 0, 0],\r
+       "blanchedalmond": [255, 235, 205],\r
+       "blue": [0, 0, 255],\r
+       "blueviolet": [138, 43, 226],\r
+       "brown": [165, 42, 42],\r
+       "burlywood": [222, 184, 135],\r
+       "cadetblue": [95, 158, 160],\r
+       "chartreuse": [127, 255, 0],\r
+       "chocolate": [210, 105, 30],\r
+       "coral": [255, 127, 80],\r
+       "cornflowerblue": [100, 149, 237],\r
+       "cornsilk": [255, 248, 220],\r
+       "crimson": [220, 20, 60],\r
+       "cyan": [0, 255, 255],\r
+       "darkblue": [0, 0, 139],\r
+       "darkcyan": [0, 139, 139],\r
+       "darkgoldenrod": [184, 134, 11],\r
+       "darkgray": [169, 169, 169],\r
+       "darkgreen": [0, 100, 0],\r
+       "darkgrey": [169, 169, 169],\r
+       "darkkhaki": [189, 183, 107],\r
+       "darkmagenta": [139, 0, 139],\r
+       "darkolivegreen": [85, 107, 47],\r
+       "darkorange": [255, 140, 0],\r
+       "darkorchid": [153, 50, 204],\r
+       "darkred": [139, 0, 0],\r
+       "darksalmon": [233, 150, 122],\r
+       "darkseagreen": [143, 188, 143],\r
+       "darkslateblue": [72, 61, 139],\r
+       "darkslategray": [47, 79, 79],\r
+       "darkslategrey": [47, 79, 79],\r
+       "darkturquoise": [0, 206, 209],\r
+       "darkviolet": [148, 0, 211],\r
+       "deeppink": [255, 20, 147],\r
+       "deepskyblue": [0, 191, 255],\r
+       "dimgray": [105, 105, 105],\r
+       "dimgrey": [105, 105, 105],\r
+       "dodgerblue": [30, 144, 255],\r
+       "firebrick": [178, 34, 34],\r
+       "floralwhite": [255, 250, 240],\r
+       "forestgreen": [34, 139, 34],\r
+       "fuchsia": [255, 0, 255],\r
+       "gainsboro": [220, 220, 220],\r
+       "ghostwhite": [248, 248, 255],\r
+       "gold": [255, 215, 0],\r
+       "goldenrod": [218, 165, 32],\r
+       "gray": [128, 128, 128],\r
+       "green": [0, 128, 0],\r
+       "greenyellow": [173, 255, 47],\r
+       "grey": [128, 128, 128],\r
+       "honeydew": [240, 255, 240],\r
+       "hotpink": [255, 105, 180],\r
+       "indianred": [205, 92, 92],\r
+       "indigo": [75, 0, 130],\r
+       "ivory": [255, 255, 240],\r
+       "khaki": [240, 230, 140],\r
+       "lavender": [230, 230, 250],\r
+       "lavenderblush": [255, 240, 245],\r
+       "lawngreen": [124, 252, 0],\r
+       "lemonchiffon": [255, 250, 205],\r
+       "lightblue": [173, 216, 230],\r
+       "lightcoral": [240, 128, 128],\r
+       "lightcyan": [224, 255, 255],\r
+       "lightgoldenrodyellow": [250, 250, 210],\r
+       "lightgray": [211, 211, 211],\r
+       "lightgreen": [144, 238, 144],\r
+       "lightgrey": [211, 211, 211],\r
+       "lightpink": [255, 182, 193],\r
+       "lightsalmon": [255, 160, 122],\r
+       "lightseagreen": [32, 178, 170],\r
+       "lightskyblue": [135, 206, 250],\r
+       "lightslategray": [119, 136, 153],\r
+       "lightslategrey": [119, 136, 153],\r
+       "lightsteelblue": [176, 196, 222],\r
+       "lightyellow": [255, 255, 224],\r
+       "lime": [0, 255, 0],\r
+       "limegreen": [50, 205, 50],\r
+       "linen": [250, 240, 230],\r
+       "magenta": [255, 0, 255],\r
+       "maroon": [128, 0, 0],\r
+       "mediumaquamarine": [102, 205, 170],\r
+       "mediumblue": [0, 0, 205],\r
+       "mediumorchid": [186, 85, 211],\r
+       "mediumpurple": [147, 112, 219],\r
+       "mediumseagreen": [60, 179, 113],\r
+       "mediumslateblue": [123, 104, 238],\r
+       "mediumspringgreen": [0, 250, 154],\r
+       "mediumturquoise": [72, 209, 204],\r
+       "mediumvioletred": [199, 21, 133],\r
+       "midnightblue": [25, 25, 112],\r
+       "mintcream": [245, 255, 250],\r
+       "mistyrose": [255, 228, 225],\r
+       "moccasin": [255, 228, 181],\r
+       "navajowhite": [255, 222, 173],\r
+       "navy": [0, 0, 128],\r
+       "oldlace": [253, 245, 230],\r
+       "olive": [128, 128, 0],\r
+       "olivedrab": [107, 142, 35],\r
+       "orange": [255, 165, 0],\r
+       "orangered": [255, 69, 0],\r
+       "orchid": [218, 112, 214],\r
+       "palegoldenrod": [238, 232, 170],\r
+       "palegreen": [152, 251, 152],\r
+       "paleturquoise": [175, 238, 238],\r
+       "palevioletred": [219, 112, 147],\r
+       "papayawhip": [255, 239, 213],\r
+       "peachpuff": [255, 218, 185],\r
+       "peru": [205, 133, 63],\r
+       "pink": [255, 192, 203],\r
+       "plum": [221, 160, 221],\r
+       "powderblue": [176, 224, 230],\r
+       "purple": [128, 0, 128],\r
+       "rebeccapurple": [102, 51, 153],\r
+       "red": [255, 0, 0],\r
+       "rosybrown": [188, 143, 143],\r
+       "royalblue": [65, 105, 225],\r
+       "saddlebrown": [139, 69, 19],\r
+       "salmon": [250, 128, 114],\r
+       "sandybrown": [244, 164, 96],\r
+       "seagreen": [46, 139, 87],\r
+       "seashell": [255, 245, 238],\r
+       "sienna": [160, 82, 45],\r
+       "silver": [192, 192, 192],\r
+       "skyblue": [135, 206, 235],\r
+       "slateblue": [106, 90, 205],\r
+       "slategray": [112, 128, 144],\r
+       "slategrey": [112, 128, 144],\r
+       "snow": [255, 250, 250],\r
+       "springgreen": [0, 255, 127],\r
+       "steelblue": [70, 130, 180],\r
+       "tan": [210, 180, 140],\r
+       "teal": [0, 128, 128],\r
+       "thistle": [216, 191, 216],\r
+       "tomato": [255, 99, 71],\r
+       "turquoise": [64, 224, 208],\r
+       "violet": [238, 130, 238],\r
+       "wheat": [245, 222, 179],\r
+       "white": [255, 255, 255],\r
+       "whitesmoke": [245, 245, 245],\r
+       "yellow": [255, 255, 0],\r
+       "yellowgreen": [154, 205, 50]\r
+};
+
+/* MIT license */
+
+
+var colorString = {
+   getRgba: getRgba,
+   getHsla: getHsla,
+   getRgb: getRgb,
+   getHsl: getHsl,
+   getHwb: getHwb,
+   getAlpha: getAlpha,
+
+   hexString: hexString,
+   rgbString: rgbString,
+   rgbaString: rgbaString,
+   percentString: percentString,
+   percentaString: percentaString,
+   hslString: hslString,
+   hslaString: hslaString,
+   hwbString: hwbString,
+   keyword: keyword
+};
+
+function getRgba(string) {
+   if (!string) {
+      return;
+   }
+   var abbr =  /^#([a-fA-F0-9]{3,4})$/i,
+       hex =  /^#([a-fA-F0-9]{6}([a-fA-F0-9]{2})?)$/i,
+       rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i,
+       per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i,
+       keyword = /(\w+)/;
+
+   var rgb = [0, 0, 0],
+       a = 1,
+       match = string.match(abbr),
+       hexAlpha = "";
+   if (match) {
+      match = match[1];
+      hexAlpha = match[3];
+      for (var i = 0; i < rgb.length; i++) {
+         rgb[i] = parseInt(match[i] + match[i], 16);
+      }
+      if (hexAlpha) {
+         a = Math.round((parseInt(hexAlpha + hexAlpha, 16) / 255) * 100) / 100;
+      }
+   }
+   else if (match = string.match(hex)) {
+      hexAlpha = match[2];
+      match = match[1];
+      for (var i = 0; i < rgb.length; i++) {
+         rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16);
+      }
+      if (hexAlpha) {
+         a = Math.round((parseInt(hexAlpha, 16) / 255) * 100) / 100;
+      }
+   }
+   else if (match = string.match(rgba)) {
+      for (var i = 0; i < rgb.length; i++) {
+         rgb[i] = parseInt(match[i + 1]);
+      }
+      a = parseFloat(match[4]);
+   }
+   else if (match = string.match(per)) {
+      for (var i = 0; i < rgb.length; i++) {
+         rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
+      }
+      a = parseFloat(match[4]);
+   }
+   else if (match = string.match(keyword)) {
+      if (match[1] == "transparent") {
+         return [0, 0, 0, 0];
+      }
+      rgb = colorName[match[1]];
+      if (!rgb) {
+         return;
+      }
+   }
+
+   for (var i = 0; i < rgb.length; i++) {
+      rgb[i] = scale(rgb[i], 0, 255);
+   }
+   if (!a && a != 0) {
+      a = 1;
+   }
+   else {
+      a = scale(a, 0, 1);
+   }
+   rgb[3] = a;
+   return rgb;
+}
+
+function getHsla(string) {
+   if (!string) {
+      return;
+   }
+   var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
+   var match = string.match(hsl);
+   if (match) {
+      var alpha = parseFloat(match[4]);
+      var h = scale(parseInt(match[1]), 0, 360),
+          s = scale(parseFloat(match[2]), 0, 100),
+          l = scale(parseFloat(match[3]), 0, 100),
+          a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
+      return [h, s, l, a];
+   }
+}
+
+function getHwb(string) {
+   if (!string) {
+      return;
+   }
+   var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
+   var match = string.match(hwb);
+   if (match) {
+    var alpha = parseFloat(match[4]);
+      var h = scale(parseInt(match[1]), 0, 360),
+          w = scale(parseFloat(match[2]), 0, 100),
+          b = scale(parseFloat(match[3]), 0, 100),
+          a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
+      return [h, w, b, a];
+   }
+}
+
+function getRgb(string) {
+   var rgba = getRgba(string);
+   return rgba && rgba.slice(0, 3);
+}
+
+function getHsl(string) {
+  var hsla = getHsla(string);
+  return hsla && hsla.slice(0, 3);
+}
+
+function getAlpha(string) {
+   var vals = getRgba(string);
+   if (vals) {
+      return vals[3];
+   }
+   else if (vals = getHsla(string)) {
+      return vals[3];
+   }
+   else if (vals = getHwb(string)) {
+      return vals[3];
+   }
+}
+
+// generators
+function hexString(rgba, a) {
+   var a = (a !== undefined && rgba.length === 3) ? a : rgba[3];
+   return "#" + hexDouble(rgba[0]) 
+              + hexDouble(rgba[1])
+              + hexDouble(rgba[2])
+              + (
+                 (a >= 0 && a < 1)
+                 ? hexDouble(Math.round(a * 255))
+                 : ""
+              );
+}
+
+function rgbString(rgba, alpha) {
+   if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
+      return rgbaString(rgba, alpha);
+   }
+   return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")";
+}
+
+function rgbaString(rgba, alpha) {
+   if (alpha === undefined) {
+      alpha = (rgba[3] !== undefined ? rgba[3] : 1);
+   }
+   return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2]
+           + ", " + alpha + ")";
+}
+
+function percentString(rgba, alpha) {
+   if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
+      return percentaString(rgba, alpha);
+   }
+   var r = Math.round(rgba[0]/255 * 100),
+       g = Math.round(rgba[1]/255 * 100),
+       b = Math.round(rgba[2]/255 * 100);
+
+   return "rgb(" + r + "%, " + g + "%, " + b + "%)";
+}
+
+function percentaString(rgba, alpha) {
+   var r = Math.round(rgba[0]/255 * 100),
+       g = Math.round(rgba[1]/255 * 100),
+       b = Math.round(rgba[2]/255 * 100);
+   return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")";
+}
+
+function hslString(hsla, alpha) {
+   if (alpha < 1 || (hsla[3] && hsla[3] < 1)) {
+      return hslaString(hsla, alpha);
+   }
+   return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";
+}
+
+function hslaString(hsla, alpha) {
+   if (alpha === undefined) {
+      alpha = (hsla[3] !== undefined ? hsla[3] : 1);
+   }
+   return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, "
+           + alpha + ")";
+}
+
+// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
+// (hwb have alpha optional & 1 is default value)
+function hwbString(hwb, alpha) {
+   if (alpha === undefined) {
+      alpha = (hwb[3] !== undefined ? hwb[3] : 1);
+   }
+   return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%"
+           + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")";
+}
+
+function keyword(rgb) {
+  return reverseNames[rgb.slice(0, 3)];
+}
+
+// helpers
+function scale(num, min, max) {
+   return Math.min(Math.max(min, num), max);
+}
+
+function hexDouble(num) {
+  var str = num.toString(16).toUpperCase();
+  return (str.length < 2) ? "0" + str : str;
+}
+
+
+//create a list of reverse color names
+var reverseNames = {};
+for (var name in colorName) {
+   reverseNames[colorName[name]] = name;
+}
+
+/* MIT license */
+
+
+
+var Color = function (obj) {
+       if (obj instanceof Color) {
+               return obj;
+       }
+       if (!(this instanceof Color)) {
+               return new Color(obj);
+       }
+
+       this.valid = false;
+       this.values = {
+               rgb: [0, 0, 0],
+               hsl: [0, 0, 0],
+               hsv: [0, 0, 0],
+               hwb: [0, 0, 0],
+               cmyk: [0, 0, 0, 0],
+               alpha: 1
+       };
+
+       // parse Color() argument
+       var vals;
+       if (typeof obj === 'string') {
+               vals = colorString.getRgba(obj);
+               if (vals) {
+                       this.setValues('rgb', vals);
+               } else if (vals = colorString.getHsla(obj)) {
+                       this.setValues('hsl', vals);
+               } else if (vals = colorString.getHwb(obj)) {
+                       this.setValues('hwb', vals);
+               }
+       } else if (typeof obj === 'object') {
+               vals = obj;
+               if (vals.r !== undefined || vals.red !== undefined) {
+                       this.setValues('rgb', vals);
+               } else if (vals.l !== undefined || vals.lightness !== undefined) {
+                       this.setValues('hsl', vals);
+               } else if (vals.v !== undefined || vals.value !== undefined) {
+                       this.setValues('hsv', vals);
+               } else if (vals.w !== undefined || vals.whiteness !== undefined) {
+                       this.setValues('hwb', vals);
+               } else if (vals.c !== undefined || vals.cyan !== undefined) {
+                       this.setValues('cmyk', vals);
+               }
+       }
+};
+
+Color.prototype = {
+       isValid: function () {
+               return this.valid;
+       },
+       rgb: function () {
+               return this.setSpace('rgb', arguments);
+       },
+       hsl: function () {
+               return this.setSpace('hsl', arguments);
+       },
+       hsv: function () {
+               return this.setSpace('hsv', arguments);
+       },
+       hwb: function () {
+               return this.setSpace('hwb', arguments);
+       },
+       cmyk: function () {
+               return this.setSpace('cmyk', arguments);
+       },
+
+       rgbArray: function () {
+               return this.values.rgb;
+       },
+       hslArray: function () {
+               return this.values.hsl;
+       },
+       hsvArray: function () {
+               return this.values.hsv;
+       },
+       hwbArray: function () {
+               var values = this.values;
+               if (values.alpha !== 1) {
+                       return values.hwb.concat([values.alpha]);
+               }
+               return values.hwb;
+       },
+       cmykArray: function () {
+               return this.values.cmyk;
+       },
+       rgbaArray: function () {
+               var values = this.values;
+               return values.rgb.concat([values.alpha]);
+       },
+       hslaArray: function () {
+               var values = this.values;
+               return values.hsl.concat([values.alpha]);
+       },
+       alpha: function (val) {
+               if (val === undefined) {
+                       return this.values.alpha;
+               }
+               this.setValues('alpha', val);
+               return this;
+       },
+
+       red: function (val) {
+               return this.setChannel('rgb', 0, val);
+       },
+       green: function (val) {
+               return this.setChannel('rgb', 1, val);
+       },
+       blue: function (val) {
+               return this.setChannel('rgb', 2, val);
+       },
+       hue: function (val) {
+               if (val) {
+                       val %= 360;
+                       val = val < 0 ? 360 + val : val;
+               }
+               return this.setChannel('hsl', 0, val);
+       },
+       saturation: function (val) {
+               return this.setChannel('hsl', 1, val);
+       },
+       lightness: function (val) {
+               return this.setChannel('hsl', 2, val);
+       },
+       saturationv: function (val) {
+               return this.setChannel('hsv', 1, val);
+       },
+       whiteness: function (val) {
+               return this.setChannel('hwb', 1, val);
+       },
+       blackness: function (val) {
+               return this.setChannel('hwb', 2, val);
+       },
+       value: function (val) {
+               return this.setChannel('hsv', 2, val);
+       },
+       cyan: function (val) {
+               return this.setChannel('cmyk', 0, val);
+       },
+       magenta: function (val) {
+               return this.setChannel('cmyk', 1, val);
+       },
+       yellow: function (val) {
+               return this.setChannel('cmyk', 2, val);
+       },
+       black: function (val) {
+               return this.setChannel('cmyk', 3, val);
+       },
+
+       hexString: function () {
+               return colorString.hexString(this.values.rgb);
+       },
+       rgbString: function () {
+               return colorString.rgbString(this.values.rgb, this.values.alpha);
+       },
+       rgbaString: function () {
+               return colorString.rgbaString(this.values.rgb, this.values.alpha);
+       },
+       percentString: function () {
+               return colorString.percentString(this.values.rgb, this.values.alpha);
+       },
+       hslString: function () {
+               return colorString.hslString(this.values.hsl, this.values.alpha);
+       },
+       hslaString: function () {
+               return colorString.hslaString(this.values.hsl, this.values.alpha);
+       },
+       hwbString: function () {
+               return colorString.hwbString(this.values.hwb, this.values.alpha);
+       },
+       keyword: function () {
+               return colorString.keyword(this.values.rgb, this.values.alpha);
+       },
+
+       rgbNumber: function () {
+               var rgb = this.values.rgb;
+               return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
+       },
+
+       luminosity: function () {
+               // http://www.w3.org/TR/WCAG20/#relativeluminancedef
+               var rgb = this.values.rgb;
+               var lum = [];
+               for (var i = 0; i < rgb.length; i++) {
+                       var chan = rgb[i] / 255;
+                       lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4);
+               }
+               return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
+       },
+
+       contrast: function (color2) {
+               // http://www.w3.org/TR/WCAG20/#contrast-ratiodef
+               var lum1 = this.luminosity();
+               var lum2 = color2.luminosity();
+               if (lum1 > lum2) {
+                       return (lum1 + 0.05) / (lum2 + 0.05);
+               }
+               return (lum2 + 0.05) / (lum1 + 0.05);
+       },
+
+       level: function (color2) {
+               var contrastRatio = this.contrast(color2);
+               if (contrastRatio >= 7.1) {
+                       return 'AAA';
+               }
+
+               return (contrastRatio >= 4.5) ? 'AA' : '';
+       },
+
+       dark: function () {
+               // YIQ equation from http://24ways.org/2010/calculating-color-contrast
+               var rgb = this.values.rgb;
+               var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
+               return yiq < 128;
+       },
+
+       light: function () {
+               return !this.dark();
+       },
+
+       negate: function () {
+               var rgb = [];
+               for (var i = 0; i < 3; i++) {
+                       rgb[i] = 255 - this.values.rgb[i];
+               }
+               this.setValues('rgb', rgb);
+               return this;
+       },
+
+       lighten: function (ratio) {
+               var hsl = this.values.hsl;
+               hsl[2] += hsl[2] * ratio;
+               this.setValues('hsl', hsl);
+               return this;
+       },
+
+       darken: function (ratio) {
+               var hsl = this.values.hsl;
+               hsl[2] -= hsl[2] * ratio;
+               this.setValues('hsl', hsl);
+               return this;
+       },
+
+       saturate: function (ratio) {
+               var hsl = this.values.hsl;
+               hsl[1] += hsl[1] * ratio;
+               this.setValues('hsl', hsl);
+               return this;
+       },
+
+       desaturate: function (ratio) {
+               var hsl = this.values.hsl;
+               hsl[1] -= hsl[1] * ratio;
+               this.setValues('hsl', hsl);
+               return this;
+       },
+
+       whiten: function (ratio) {
+               var hwb = this.values.hwb;
+               hwb[1] += hwb[1] * ratio;
+               this.setValues('hwb', hwb);
+               return this;
+       },
+
+       blacken: function (ratio) {
+               var hwb = this.values.hwb;
+               hwb[2] += hwb[2] * ratio;
+               this.setValues('hwb', hwb);
+               return this;
+       },
+
+       greyscale: function () {
+               var rgb = this.values.rgb;
+               // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
+               var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
+               this.setValues('rgb', [val, val, val]);
+               return this;
+       },
+
+       clearer: function (ratio) {
+               var alpha = this.values.alpha;
+               this.setValues('alpha', alpha - (alpha * ratio));
+               return this;
+       },
+
+       opaquer: function (ratio) {
+               var alpha = this.values.alpha;
+               this.setValues('alpha', alpha + (alpha * ratio));
+               return this;
+       },
+
+       rotate: function (degrees) {
+               var hsl = this.values.hsl;
+               var hue = (hsl[0] + degrees) % 360;
+               hsl[0] = hue < 0 ? 360 + hue : hue;
+               this.setValues('hsl', hsl);
+               return this;
+       },
+
+       /**
+        * Ported from sass implementation in C
+        * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209
+        */
+       mix: function (mixinColor, weight) {
+               var color1 = this;
+               var color2 = mixinColor;
+               var p = weight === undefined ? 0.5 : weight;
+
+               var w = 2 * p - 1;
+               var a = color1.alpha() - color2.alpha();
+
+               var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
+               var w2 = 1 - w1;
+
+               return this
+                       .rgb(
+                               w1 * color1.red() + w2 * color2.red(),
+                               w1 * color1.green() + w2 * color2.green(),
+                               w1 * color1.blue() + w2 * color2.blue()
+                       )
+                       .alpha(color1.alpha() * p + color2.alpha() * (1 - p));
+       },
+
+       toJSON: function () {
+               return this.rgb();
+       },
+
+       clone: function () {
+               // NOTE(SB): using node-clone creates a dependency to Buffer when using browserify,
+               // making the final build way to big to embed in Chart.js. So let's do it manually,
+               // assuming that values to clone are 1 dimension arrays containing only numbers,
+               // except 'alpha' which is a number.
+               var result = new Color();
+               var source = this.values;
+               var target = result.values;
+               var value, type;
+
+               for (var prop in source) {
+                       if (source.hasOwnProperty(prop)) {
+                               value = source[prop];
+                               type = ({}).toString.call(value);
+                               if (type === '[object Array]') {
+                                       target[prop] = value.slice(0);
+                               } else if (type === '[object Number]') {
+                                       target[prop] = value;
+                               } else {
+                                       console.error('unexpected color value:', value);
+                               }
+                       }
+               }
+
+               return result;
+       }
+};
+
+Color.prototype.spaces = {
+       rgb: ['red', 'green', 'blue'],
+       hsl: ['hue', 'saturation', 'lightness'],
+       hsv: ['hue', 'saturation', 'value'],
+       hwb: ['hue', 'whiteness', 'blackness'],
+       cmyk: ['cyan', 'magenta', 'yellow', 'black']
+};
+
+Color.prototype.maxes = {
+       rgb: [255, 255, 255],
+       hsl: [360, 100, 100],
+       hsv: [360, 100, 100],
+       hwb: [360, 100, 100],
+       cmyk: [100, 100, 100, 100]
+};
+
+Color.prototype.getValues = function (space) {
+       var values = this.values;
+       var vals = {};
+
+       for (var i = 0; i < space.length; i++) {
+               vals[space.charAt(i)] = values[space][i];
+       }
+
+       if (values.alpha !== 1) {
+               vals.a = values.alpha;
+       }
+
+       // {r: 255, g: 255, b: 255, a: 0.4}
+       return vals;
+};
+
+Color.prototype.setValues = function (space, vals) {
+       var values = this.values;
+       var spaces = this.spaces;
+       var maxes = this.maxes;
+       var alpha = 1;
+       var i;
+
+       this.valid = true;
+
+       if (space === 'alpha') {
+               alpha = vals;
+       } else if (vals.length) {
+               // [10, 10, 10]
+               values[space] = vals.slice(0, space.length);
+               alpha = vals[space.length];
+       } else if (vals[space.charAt(0)] !== undefined) {
+               // {r: 10, g: 10, b: 10}
+               for (i = 0; i < space.length; i++) {
+                       values[space][i] = vals[space.charAt(i)];
+               }
+
+               alpha = vals.a;
+       } else if (vals[spaces[space][0]] !== undefined) {
+               // {red: 10, green: 10, blue: 10}
+               var chans = spaces[space];
+
+               for (i = 0; i < space.length; i++) {
+                       values[space][i] = vals[chans[i]];
+               }
+
+               alpha = vals.alpha;
+       }
+
+       values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha)));
+
+       if (space === 'alpha') {
+               return false;
+       }
+
+       var capped;
+
+       // cap values of the space prior converting all values
+       for (i = 0; i < space.length; i++) {
+               capped = Math.max(0, Math.min(maxes[space][i], values[space][i]));
+               values[space][i] = Math.round(capped);
+       }
+
+       // convert to all the other color spaces
+       for (var sname in spaces) {
+               if (sname !== space) {
+                       values[sname] = colorConvert[space][sname](values[space]);
+               }
+       }
+
+       return true;
+};
+
+Color.prototype.setSpace = function (space, args) {
+       var vals = args[0];
+
+       if (vals === undefined) {
+               // color.rgb()
+               return this.getValues(space);
+       }
+
+       // color.rgb(10, 10, 10)
+       if (typeof vals === 'number') {
+               vals = Array.prototype.slice.call(args);
+       }
+
+       this.setValues(space, vals);
+       return this;
+};
+
+Color.prototype.setChannel = function (space, index, val) {
+       var svalues = this.values[space];
+       if (val === undefined) {
+               // color.red()
+               return svalues[index];
+       } else if (val === svalues[index]) {
+               // color.red(color.red())
+               return this;
+       }
+
+       // color.red(100)
+       svalues[index] = val;
+       this.setValues(space, svalues);
+
+       return this;
+};
+
+if (typeof window !== 'undefined') {
+       window.Color = Color;
+}
+
+var chartjsColor = Color;
+
+/**
+ * @namespace Chart.helpers
+ */
+var helpers = {
+       /**
+        * An empty function that can be used, for example, for optional callback.
+        */
+       noop: function() {},
+
+       /**
+        * Returns a unique id, sequentially generated from a global variable.
+        * @returns {number}
+        * @function
+        */
+       uid: (function() {
+               var id = 0;
+               return function() {
+                       return id++;
+               };
+       }()),
+
+       /**
+        * Returns true if `value` is neither null nor undefined, else returns false.
+        * @param {*} value - The value to test.
+        * @returns {boolean}
+        * @since 2.7.0
+        */
+       isNullOrUndef: function(value) {
+               return value === null || typeof value === 'undefined';
+       },
+
+       /**
+        * Returns true if `value` is an array (including typed arrays), else returns false.
+        * @param {*} value - The value to test.
+        * @returns {boolean}
+        * @function
+        */
+       isArray: function(value) {
+               if (Array.isArray && Array.isArray(value)) {
+                       return true;
+               }
+               var type = Object.prototype.toString.call(value);
+               if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') {
+                       return true;
+               }
+               return false;
+       },
+
+       /**
+        * Returns true if `value` is an object (excluding null), else returns false.
+        * @param {*} value - The value to test.
+        * @returns {boolean}
+        * @since 2.7.0
+        */
+       isObject: function(value) {
+               return value !== null && Object.prototype.toString.call(value) === '[object Object]';
+       },
+
+       /**
+        * Returns true if `value` is a finite number, else returns false
+        * @param {*} value  - The value to test.
+        * @returns {boolean}
+        */
+       isFinite: function(value) {
+               return (typeof value === 'number' || value instanceof Number) && isFinite(value);
+       },
+
+       /**
+        * Returns `value` if defined, else returns `defaultValue`.
+        * @param {*} value - The value to return if defined.
+        * @param {*} defaultValue - The value to return if `value` is undefined.
+        * @returns {*}
+        */
+       valueOrDefault: function(value, defaultValue) {
+               return typeof value === 'undefined' ? defaultValue : value;
+       },
+
+       /**
+        * Returns value at the given `index` in array if defined, else returns `defaultValue`.
+        * @param {Array} value - The array to lookup for value at `index`.
+        * @param {number} index - The index in `value` to lookup for value.
+        * @param {*} defaultValue - The value to return if `value[index]` is undefined.
+        * @returns {*}
+        */
+       valueAtIndexOrDefault: function(value, index, defaultValue) {
+               return helpers.valueOrDefault(helpers.isArray(value) ? value[index] : value, defaultValue);
+       },
+
+       /**
+        * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
+        * value returned by `fn`. If `fn` is not a function, this method returns undefined.
+        * @param {function} fn - The function to call.
+        * @param {Array|undefined|null} args - The arguments with which `fn` should be called.
+        * @param {object} [thisArg] - The value of `this` provided for the call to `fn`.
+        * @returns {*}
+        */
+       callback: function(fn, args, thisArg) {
+               if (fn && typeof fn.call === 'function') {
+                       return fn.apply(thisArg, args);
+               }
+       },
+
+       /**
+        * Note(SB) for performance sake, this method should only be used when loopable type
+        * is unknown or in none intensive code (not called often and small loopable). Else
+        * it's preferable to use a regular for() loop and save extra function calls.
+        * @param {object|Array} loopable - The object or array to be iterated.
+        * @param {function} fn - The function to call for each item.
+        * @param {object} [thisArg] - The value of `this` provided for the call to `fn`.
+        * @param {boolean} [reverse] - If true, iterates backward on the loopable.
+        */
+       each: function(loopable, fn, thisArg, reverse) {
+               var i, len, keys;
+               if (helpers.isArray(loopable)) {
+                       len = loopable.length;
+                       if (reverse) {
+                               for (i = len - 1; i >= 0; i--) {
+                                       fn.call(thisArg, loopable[i], i);
+                               }
+                       } else {
+                               for (i = 0; i < len; i++) {
+                                       fn.call(thisArg, loopable[i], i);
+                               }
+                       }
+               } else if (helpers.isObject(loopable)) {
+                       keys = Object.keys(loopable);
+                       len = keys.length;
+                       for (i = 0; i < len; i++) {
+                               fn.call(thisArg, loopable[keys[i]], keys[i]);
+                       }
+               }
+       },
+
+       /**
+        * Returns true if the `a0` and `a1` arrays have the same content, else returns false.
+        * @see https://stackoverflow.com/a/14853974
+        * @param {Array} a0 - The array to compare
+        * @param {Array} a1 - The array to compare
+        * @returns {boolean}
+        */
+       arrayEquals: function(a0, a1) {
+               var i, ilen, v0, v1;
+
+               if (!a0 || !a1 || a0.length !== a1.length) {
+                       return false;
+               }
+
+               for (i = 0, ilen = a0.length; i < ilen; ++i) {
+                       v0 = a0[i];
+                       v1 = a1[i];
+
+                       if (v0 instanceof Array && v1 instanceof Array) {
+                               if (!helpers.arrayEquals(v0, v1)) {
+                                       return false;
+                               }
+                       } else if (v0 !== v1) {
+                               // NOTE: two different object instances will never be equal: {x:20} != {x:20}
+                               return false;
+                       }
+               }
+
+               return true;
+       },
+
+       /**
+        * Returns a deep copy of `source` without keeping references on objects and arrays.
+        * @param {*} source - The value to clone.
+        * @returns {*}
+        */
+       clone: function(source) {
+               if (helpers.isArray(source)) {
+                       return source.map(helpers.clone);
+               }
+
+               if (helpers.isObject(source)) {
+                       var target = {};
+                       var keys = Object.keys(source);
+                       var klen = keys.length;
+                       var k = 0;
+
+                       for (; k < klen; ++k) {
+                               target[keys[k]] = helpers.clone(source[keys[k]]);
+                       }
+
+                       return target;
+               }
+
+               return source;
+       },
+
+       /**
+        * The default merger when Chart.helpers.merge is called without merger option.
+        * Note(SB): also used by mergeConfig and mergeScaleConfig as fallback.
+        * @private
+        */
+       _merger: function(key, target, source, options) {
+               var tval = target[key];
+               var sval = source[key];
+
+               if (helpers.isObject(tval) && helpers.isObject(sval)) {
+                       helpers.merge(tval, sval, options);
+               } else {
+                       target[key] = helpers.clone(sval);
+               }
+       },
+
+       /**
+        * Merges source[key] in target[key] only if target[key] is undefined.
+        * @private
+        */
+       _mergerIf: function(key, target, source) {
+               var tval = target[key];
+               var sval = source[key];
+
+               if (helpers.isObject(tval) && helpers.isObject(sval)) {
+                       helpers.mergeIf(tval, sval);
+               } else if (!target.hasOwnProperty(key)) {
+                       target[key] = helpers.clone(sval);
+               }
+       },
+
+       /**
+        * Recursively deep copies `source` properties into `target` with the given `options`.
+        * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
+        * @param {object} target - The target object in which all sources are merged into.
+        * @param {object|object[]} source - Object(s) to merge into `target`.
+        * @param {object} [options] - Merging options:
+        * @param {function} [options.merger] - The merge method (key, target, source, options)
+        * @returns {object} The `target` object.
+        */
+       merge: function(target, source, options) {
+               var sources = helpers.isArray(source) ? source : [source];
+               var ilen = sources.length;
+               var merge, i, keys, klen, k;
+
+               if (!helpers.isObject(target)) {
+                       return target;
+               }
+
+               options = options || {};
+               merge = options.merger || helpers._merger;
+
+               for (i = 0; i < ilen; ++i) {
+                       source = sources[i];
+                       if (!helpers.isObject(source)) {
+                               continue;
+                       }
+
+                       keys = Object.keys(source);
+                       for (k = 0, klen = keys.length; k < klen; ++k) {
+                               merge(keys[k], target, source, options);
+                       }
+               }
+
+               return target;
+       },
+
+       /**
+        * Recursively deep copies `source` properties into `target` *only* if not defined in target.
+        * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
+        * @param {object} target - The target object in which all sources are merged into.
+        * @param {object|object[]} source - Object(s) to merge into `target`.
+        * @returns {object} The `target` object.
+        */
+       mergeIf: function(target, source) {
+               return helpers.merge(target, source, {merger: helpers._mergerIf});
+       },
+
+       /**
+        * Applies the contents of two or more objects together into the first object.
+        * @param {object} target - The target object in which all objects are merged into.
+        * @param {object} arg1 - Object containing additional properties to merge in target.
+        * @param {object} argN - Additional objects containing properties to merge in target.
+        * @returns {object} The `target` object.
+        */
+       extend: function(target) {
+               var setFn = function(value, key) {
+                       target[key] = value;
+               };
+               for (var i = 1, ilen = arguments.length; i < ilen; ++i) {
+                       helpers.each(arguments[i], setFn);
+               }
+               return target;
+       },
+
+       /**
+        * Basic javascript inheritance based on the model created in Backbone.js
+        */
+       inherits: function(extensions) {
+               var me = this;
+               var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function() {
+                       return me.apply(this, arguments);
+               };
+
+               var Surrogate = function() {
+                       this.constructor = ChartElement;
+               };
+
+               Surrogate.prototype = me.prototype;
+               ChartElement.prototype = new Surrogate();
+               ChartElement.extend = helpers.inherits;
+
+               if (extensions) {
+                       helpers.extend(ChartElement.prototype, extensions);
+               }
+
+               ChartElement.__super__ = me.prototype;
+               return ChartElement;
+       }
+};
+
+var helpers_core = helpers;
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.callback instead.
+ * @function Chart.helpers.callCallback
+ * @deprecated since version 2.6.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers.callCallback = helpers.callback;
+
+/**
+ * Provided for backward compatibility, use Array.prototype.indexOf instead.
+ * Array.prototype.indexOf compatibility: Chrome, Opera, Safari, FF1.5+, IE9+
+ * @function Chart.helpers.indexOf
+ * @deprecated since version 2.7.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers.indexOf = function(array, item, fromIndex) {
+       return Array.prototype.indexOf.call(array, item, fromIndex);
+};
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.valueOrDefault instead.
+ * @function Chart.helpers.getValueOrDefault
+ * @deprecated since version 2.7.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers.getValueOrDefault = helpers.valueOrDefault;
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.valueAtIndexOrDefault instead.
+ * @function Chart.helpers.getValueAtIndexOrDefault
+ * @deprecated since version 2.7.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers.getValueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
+
+/**
+ * Easing functions adapted from Robert Penner's easing equations.
+ * @namespace Chart.helpers.easingEffects
+ * @see http://www.robertpenner.com/easing/
+ */
+var effects = {
+       linear: function(t) {
+               return t;
+       },
+
+       easeInQuad: function(t) {
+               return t * t;
+       },
+
+       easeOutQuad: function(t) {
+               return -t * (t - 2);
+       },
+
+       easeInOutQuad: function(t) {
+               if ((t /= 0.5) < 1) {
+                       return 0.5 * t * t;
+               }
+               return -0.5 * ((--t) * (t - 2) - 1);
+       },
+
+       easeInCubic: function(t) {
+               return t * t * t;
+       },
+
+       easeOutCubic: function(t) {
+               return (t = t - 1) * t * t + 1;
+       },
+
+       easeInOutCubic: function(t) {
+               if ((t /= 0.5) < 1) {
+                       return 0.5 * t * t * t;
+               }
+               return 0.5 * ((t -= 2) * t * t + 2);
+       },
+
+       easeInQuart: function(t) {
+               return t * t * t * t;
+       },
+
+       easeOutQuart: function(t) {
+               return -((t = t - 1) * t * t * t - 1);
+       },
+
+       easeInOutQuart: function(t) {
+               if ((t /= 0.5) < 1) {
+                       return 0.5 * t * t * t * t;
+               }
+               return -0.5 * ((t -= 2) * t * t * t - 2);
+       },
+
+       easeInQuint: function(t) {
+               return t * t * t * t * t;
+       },
+
+       easeOutQuint: function(t) {
+               return (t = t - 1) * t * t * t * t + 1;
+       },
+
+       easeInOutQuint: function(t) {
+               if ((t /= 0.5) < 1) {
+                       return 0.5 * t * t * t * t * t;
+               }
+               return 0.5 * ((t -= 2) * t * t * t * t + 2);
+       },
+
+       easeInSine: function(t) {
+               return -Math.cos(t * (Math.PI / 2)) + 1;
+       },
+
+       easeOutSine: function(t) {
+               return Math.sin(t * (Math.PI / 2));
+       },
+
+       easeInOutSine: function(t) {
+               return -0.5 * (Math.cos(Math.PI * t) - 1);
+       },
+
+       easeInExpo: function(t) {
+               return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1));
+       },
+
+       easeOutExpo: function(t) {
+               return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1;
+       },
+
+       easeInOutExpo: function(t) {
+               if (t === 0) {
+                       return 0;
+               }
+               if (t === 1) {
+                       return 1;
+               }
+               if ((t /= 0.5) < 1) {
+                       return 0.5 * Math.pow(2, 10 * (t - 1));
+               }
+               return 0.5 * (-Math.pow(2, -10 * --t) + 2);
+       },
+
+       easeInCirc: function(t) {
+               if (t >= 1) {
+                       return t;
+               }
+               return -(Math.sqrt(1 - t * t) - 1);
+       },
+
+       easeOutCirc: function(t) {
+               return Math.sqrt(1 - (t = t - 1) * t);
+       },
+
+       easeInOutCirc: function(t) {
+               if ((t /= 0.5) < 1) {
+                       return -0.5 * (Math.sqrt(1 - t * t) - 1);
+               }
+               return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
+       },
+
+       easeInElastic: function(t) {
+               var s = 1.70158;
+               var p = 0;
+               var a = 1;
+               if (t === 0) {
+                       return 0;
+               }
+               if (t === 1) {
+                       return 1;
+               }
+               if (!p) {
+                       p = 0.3;
+               }
+               if (a < 1) {
+                       a = 1;
+                       s = p / 4;
+               } else {
+                       s = p / (2 * Math.PI) * Math.asin(1 / a);
+               }
+               return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
+       },
+
+       easeOutElastic: function(t) {
+               var s = 1.70158;
+               var p = 0;
+               var a = 1;
+               if (t === 0) {
+                       return 0;
+               }
+               if (t === 1) {
+                       return 1;
+               }
+               if (!p) {
+                       p = 0.3;
+               }
+               if (a < 1) {
+                       a = 1;
+                       s = p / 4;
+               } else {
+                       s = p / (2 * Math.PI) * Math.asin(1 / a);
+               }
+               return a * Math.pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + 1;
+       },
+
+       easeInOutElastic: function(t) {
+               var s = 1.70158;
+               var p = 0;
+               var a = 1;
+               if (t === 0) {
+                       return 0;
+               }
+               if ((t /= 0.5) === 2) {
+                       return 1;
+               }
+               if (!p) {
+                       p = 0.45;
+               }
+               if (a < 1) {
+                       a = 1;
+                       s = p / 4;
+               } else {
+                       s = p / (2 * Math.PI) * Math.asin(1 / a);
+               }
+               if (t < 1) {
+                       return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
+               }
+               return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p) * 0.5 + 1;
+       },
+       easeInBack: function(t) {
+               var s = 1.70158;
+               return t * t * ((s + 1) * t - s);
+       },
+
+       easeOutBack: function(t) {
+               var s = 1.70158;
+               return (t = t - 1) * t * ((s + 1) * t + s) + 1;
+       },
+
+       easeInOutBack: function(t) {
+               var s = 1.70158;
+               if ((t /= 0.5) < 1) {
+                       return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s));
+               }
+               return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
+       },
+
+       easeInBounce: function(t) {
+               return 1 - effects.easeOutBounce(1 - t);
+       },
+
+       easeOutBounce: function(t) {
+               if (t < (1 / 2.75)) {
+                       return 7.5625 * t * t;
+               }
+               if (t < (2 / 2.75)) {
+                       return 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75;
+               }
+               if (t < (2.5 / 2.75)) {
+                       return 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375;
+               }
+               return 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375;
+       },
+
+       easeInOutBounce: function(t) {
+               if (t < 0.5) {
+                       return effects.easeInBounce(t * 2) * 0.5;
+               }
+               return effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5;
+       }
+};
+
+var helpers_easing = {
+       effects: effects
+};
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.easing.effects instead.
+ * @function Chart.helpers.easingEffects
+ * @deprecated since version 2.7.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers_core.easingEffects = effects;
+
+var PI = Math.PI;
+var RAD_PER_DEG = PI / 180;
+var DOUBLE_PI = PI * 2;
+var HALF_PI = PI / 2;
+var QUARTER_PI = PI / 4;
+var TWO_THIRDS_PI = PI * 2 / 3;
+
+/**
+ * @namespace Chart.helpers.canvas
+ */
+var exports$1 = {
+       /**
+        * Clears the entire canvas associated to the given `chart`.
+        * @param {Chart} chart - The chart for which to clear the canvas.
+        */
+       clear: function(chart) {
+               chart.ctx.clearRect(0, 0, chart.width, chart.height);
+       },
+
+       /**
+        * Creates a "path" for a rectangle with rounded corners at position (x, y) with a
+        * given size (width, height) and the same `radius` for all corners.
+        * @param {CanvasRenderingContext2D} ctx - The canvas 2D Context.
+        * @param {number} x - The x axis of the coordinate for the rectangle starting point.
+        * @param {number} y - The y axis of the coordinate for the rectangle starting point.
+        * @param {number} width - The rectangle's width.
+        * @param {number} height - The rectangle's height.
+        * @param {number} radius - The rounded amount (in pixels) for the four corners.
+        * @todo handle `radius` as top-left, top-right, bottom-right, bottom-left array/object?
+        */
+       roundedRect: function(ctx, x, y, width, height, radius) {
+               if (radius) {
+                       var r = Math.min(radius, height / 2, width / 2);
+                       var left = x + r;
+                       var top = y + r;
+                       var right = x + width - r;
+                       var bottom = y + height - r;
+
+                       ctx.moveTo(x, top);
+                       if (left < right && top < bottom) {
+                               ctx.arc(left, top, r, -PI, -HALF_PI);
+                               ctx.arc(right, top, r, -HALF_PI, 0);
+                               ctx.arc(right, bottom, r, 0, HALF_PI);
+                               ctx.arc(left, bottom, r, HALF_PI, PI);
+                       } else if (left < right) {
+                               ctx.moveTo(left, y);
+                               ctx.arc(right, top, r, -HALF_PI, HALF_PI);
+                               ctx.arc(left, top, r, HALF_PI, PI + HALF_PI);
+                       } else if (top < bottom) {
+                               ctx.arc(left, top, r, -PI, 0);
+                               ctx.arc(left, bottom, r, 0, PI);
+                       } else {
+                               ctx.arc(left, top, r, -PI, PI);
+                       }
+                       ctx.closePath();
+                       ctx.moveTo(x, y);
+               } else {
+                       ctx.rect(x, y, width, height);
+               }
+       },
+
+       drawPoint: function(ctx, style, radius, x, y, rotation) {
+               var type, xOffset, yOffset, size, cornerRadius;
+               var rad = (rotation || 0) * RAD_PER_DEG;
+
+               if (style && typeof style === 'object') {
+                       type = style.toString();
+                       if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
+                               ctx.drawImage(style, x - style.width / 2, y - style.height / 2, style.width, style.height);
+                               return;
+                       }
+               }
+
+               if (isNaN(radius) || radius <= 0) {
+                       return;
+               }
+
+               ctx.beginPath();
+
+               switch (style) {
+               // Default includes circle
+               default:
+                       ctx.arc(x, y, radius, 0, DOUBLE_PI);
+                       ctx.closePath();
+                       break;
+               case 'triangle':
+                       ctx.moveTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
+                       rad += TWO_THIRDS_PI;
+                       ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
+                       rad += TWO_THIRDS_PI;
+                       ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
+                       ctx.closePath();
+                       break;
+               case 'rectRounded':
+                       // NOTE: the rounded rect implementation changed to use `arc` instead of
+                       // `quadraticCurveTo` since it generates better results when rect is
+                       // almost a circle. 0.516 (instead of 0.5) produces results with visually
+                       // closer proportion to the previous impl and it is inscribed in the
+                       // circle with `radius`. For more details, see the following PRs:
+                       // https://github.com/chartjs/Chart.js/issues/5597
+                       // https://github.com/chartjs/Chart.js/issues/5858
+                       cornerRadius = radius * 0.516;
+                       size = radius - cornerRadius;
+                       xOffset = Math.cos(rad + QUARTER_PI) * size;
+                       yOffset = Math.sin(rad + QUARTER_PI) * size;
+                       ctx.arc(x - xOffset, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI);
+                       ctx.arc(x + yOffset, y - xOffset, cornerRadius, rad - HALF_PI, rad);
+                       ctx.arc(x + xOffset, y + yOffset, cornerRadius, rad, rad + HALF_PI);
+                       ctx.arc(x - yOffset, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI);
+                       ctx.closePath();
+                       break;
+               case 'rect':
+                       if (!rotation) {
+                               size = Math.SQRT1_2 * radius;
+                               ctx.rect(x - size, y - size, 2 * size, 2 * size);
+                               break;
+                       }
+                       rad += QUARTER_PI;
+                       /* falls through */
+               case 'rectRot':
+                       xOffset = Math.cos(rad) * radius;
+                       yOffset = Math.sin(rad) * radius;
+                       ctx.moveTo(x - xOffset, y - yOffset);
+                       ctx.lineTo(x + yOffset, y - xOffset);
+                       ctx.lineTo(x + xOffset, y + yOffset);
+                       ctx.lineTo(x - yOffset, y + xOffset);
+                       ctx.closePath();
+                       break;
+               case 'crossRot':
+                       rad += QUARTER_PI;
+                       /* falls through */
+               case 'cross':
+                       xOffset = Math.cos(rad) * radius;
+                       yOffset = Math.sin(rad) * radius;
+                       ctx.moveTo(x - xOffset, y - yOffset);
+                       ctx.lineTo(x + xOffset, y + yOffset);
+                       ctx.moveTo(x + yOffset, y - xOffset);
+                       ctx.lineTo(x - yOffset, y + xOffset);
+                       break;
+               case 'star':
+                       xOffset = Math.cos(rad) * radius;
+                       yOffset = Math.sin(rad) * radius;
+                       ctx.moveTo(x - xOffset, y - yOffset);
+                       ctx.lineTo(x + xOffset, y + yOffset);
+                       ctx.moveTo(x + yOffset, y - xOffset);
+                       ctx.lineTo(x - yOffset, y + xOffset);
+                       rad += QUARTER_PI;
+                       xOffset = Math.cos(rad) * radius;
+                       yOffset = Math.sin(rad) * radius;
+                       ctx.moveTo(x - xOffset, y - yOffset);
+                       ctx.lineTo(x + xOffset, y + yOffset);
+                       ctx.moveTo(x + yOffset, y - xOffset);
+                       ctx.lineTo(x - yOffset, y + xOffset);
+                       break;
+               case 'line':
+                       xOffset = Math.cos(rad) * radius;
+                       yOffset = Math.sin(rad) * radius;
+                       ctx.moveTo(x - xOffset, y - yOffset);
+                       ctx.lineTo(x + xOffset, y + yOffset);
+                       break;
+               case 'dash':
+                       ctx.moveTo(x, y);
+                       ctx.lineTo(x + Math.cos(rad) * radius, y + Math.sin(rad) * radius);
+                       break;
+               }
+
+               ctx.fill();
+               ctx.stroke();
+       },
+
+       /**
+        * Returns true if the point is inside the rectangle
+        * @param {object} point - The point to test
+        * @param {object} area - The rectangle
+        * @returns {boolean}
+        * @private
+        */
+       _isPointInArea: function(point, area) {
+               var epsilon = 1e-6; // 1e-6 is margin in pixels for accumulated error.
+
+               return point.x > area.left - epsilon && point.x < area.right + epsilon &&
+                       point.y > area.top - epsilon && point.y < area.bottom + epsilon;
+       },
+
+       clipArea: function(ctx, area) {
+               ctx.save();
+               ctx.beginPath();
+               ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
+               ctx.clip();
+       },
+
+       unclipArea: function(ctx) {
+               ctx.restore();
+       },
+
+       lineTo: function(ctx, previous, target, flip) {
+               var stepped = target.steppedLine;
+               if (stepped) {
+                       if (stepped === 'middle') {
+                               var midpoint = (previous.x + target.x) / 2.0;
+                               ctx.lineTo(midpoint, flip ? target.y : previous.y);
+                               ctx.lineTo(midpoint, flip ? previous.y : target.y);
+                       } else if ((stepped === 'after' && !flip) || (stepped !== 'after' && flip)) {
+                               ctx.lineTo(previous.x, target.y);
+                       } else {
+                               ctx.lineTo(target.x, previous.y);
+                       }
+                       ctx.lineTo(target.x, target.y);
+                       return;
+               }
+
+               if (!target.tension) {
+                       ctx.lineTo(target.x, target.y);
+                       return;
+               }
+
+               ctx.bezierCurveTo(
+                       flip ? previous.controlPointPreviousX : previous.controlPointNextX,
+                       flip ? previous.controlPointPreviousY : previous.controlPointNextY,
+                       flip ? target.controlPointNextX : target.controlPointPreviousX,
+                       flip ? target.controlPointNextY : target.controlPointPreviousY,
+                       target.x,
+                       target.y);
+       }
+};
+
+var helpers_canvas = exports$1;
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.canvas.clear instead.
+ * @namespace Chart.helpers.clear
+ * @deprecated since version 2.7.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers_core.clear = exports$1.clear;
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.canvas.roundedRect instead.
+ * @namespace Chart.helpers.drawRoundedRectangle
+ * @deprecated since version 2.7.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers_core.drawRoundedRectangle = function(ctx) {
+       ctx.beginPath();
+       exports$1.roundedRect.apply(exports$1, arguments);
+};
+
+var defaults = {
+       /**
+        * @private
+        */
+       _set: function(scope, values) {
+               return helpers_core.merge(this[scope] || (this[scope] = {}), values);
+       }
+};
+
+defaults._set('global', {
+       defaultColor: 'rgba(0,0,0,0.1)',
+       defaultFontColor: '#666',
+       defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
+       defaultFontSize: 12,
+       defaultFontStyle: 'normal',
+       defaultLineHeight: 1.2,
+       showLines: true
+});
+
+var core_defaults = defaults;
+
+var valueOrDefault = helpers_core.valueOrDefault;
+
+/**
+ * Converts the given font object into a CSS font string.
+ * @param {object} font - A font object.
+ * @return {string} The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font
+ * @private
+ */
+function toFontString(font) {
+       if (!font || helpers_core.isNullOrUndef(font.size) || helpers_core.isNullOrUndef(font.family)) {
+               return null;
+       }
+
+       return (font.style ? font.style + ' ' : '')
+               + (font.weight ? font.weight + ' ' : '')
+               + font.size + 'px '
+               + font.family;
+}
+
+/**
+ * @alias Chart.helpers.options
+ * @namespace
+ */
+var helpers_options = {
+       /**
+        * Converts the given line height `value` in pixels for a specific font `size`.
+        * @param {number|string} value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').
+        * @param {number} size - The font size (in pixels) used to resolve relative `value`.
+        * @returns {number} The effective line height in pixels (size * 1.2 if value is invalid).
+        * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
+        * @since 2.7.0
+        */
+       toLineHeight: function(value, size) {
+               var matches = ('' + value).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);
+               if (!matches || matches[1] === 'normal') {
+                       return size * 1.2;
+               }
+
+               value = +matches[2];
+
+               switch (matches[3]) {
+               case 'px':
+                       return value;
+               case '%':
+                       value /= 100;
+                       break;
+               default:
+                       break;
+               }
+
+               return size * value;
+       },
+
+       /**
+        * Converts the given value into a padding object with pre-computed width/height.
+        * @param {number|object} value - If a number, set the value to all TRBL component,
+        *  else, if and object, use defined properties and sets undefined ones to 0.
+        * @returns {object} The padding values (top, right, bottom, left, width, height)
+        * @since 2.7.0
+        */
+       toPadding: function(value) {
+               var t, r, b, l;
+
+               if (helpers_core.isObject(value)) {
+                       t = +value.top || 0;
+                       r = +value.right || 0;
+                       b = +value.bottom || 0;
+                       l = +value.left || 0;
+               } else {
+                       t = r = b = l = +value || 0;
+               }
+
+               return {
+                       top: t,
+                       right: r,
+                       bottom: b,
+                       left: l,
+                       height: t + b,
+                       width: l + r
+               };
+       },
+
+       /**
+        * Parses font options and returns the font object.
+        * @param {object} options - A object that contains font options to be parsed.
+        * @return {object} The font object.
+        * @todo Support font.* options and renamed to toFont().
+        * @private
+        */
+       _parseFont: function(options) {
+               var globalDefaults = core_defaults.global;
+               var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize);
+               var font = {
+                       family: valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily),
+                       lineHeight: helpers_core.options.toLineHeight(valueOrDefault(options.lineHeight, globalDefaults.defaultLineHeight), size),
+                       size: size,
+                       style: valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle),
+                       weight: null,
+                       string: ''
+               };
+
+               font.string = toFontString(font);
+               return font;
+       },
+
+       /**
+        * Evaluates the given `inputs` sequentially and returns the first defined value.
+        * @param {Array} inputs - An array of values, falling back to the last value.
+        * @param {object} [context] - If defined and the current value is a function, the value
+        * is called with `context` as first argument and the result becomes the new input.
+        * @param {number} [index] - If defined and the current value is an array, the value
+        * at `index` become the new input.
+        * @since 2.7.0
+        */
+       resolve: function(inputs, context, index) {
+               var i, ilen, value;
+
+               for (i = 0, ilen = inputs.length; i < ilen; ++i) {
+                       value = inputs[i];
+                       if (value === undefined) {
+                               continue;
+                       }
+                       if (context !== undefined && typeof value === 'function') {
+                               value = value(context);
+                       }
+                       if (index !== undefined && helpers_core.isArray(value)) {
+                               value = value[index];
+                       }
+                       if (value !== undefined) {
+                               return value;
+                       }
+               }
+       }
+};
+
+var helpers$1 = helpers_core;
+var easing = helpers_easing;
+var canvas = helpers_canvas;
+var options = helpers_options;
+helpers$1.easing = easing;
+helpers$1.canvas = canvas;
+helpers$1.options = options;
+
+function interpolate(start, view, model, ease) {
+       var keys = Object.keys(model);
+       var i, ilen, key, actual, origin, target, type, c0, c1;
+
+       for (i = 0, ilen = keys.length; i < ilen; ++i) {
+               key = keys[i];
+
+               target = model[key];
+
+               // if a value is added to the model after pivot() has been called, the view
+               // doesn't contain it, so let's initialize the view to the target value.
+               if (!view.hasOwnProperty(key)) {
+                       view[key] = target;
+               }
+
+               actual = view[key];
+
+               if (actual === target || key[0] === '_') {
+                       continue;
+               }
+
+               if (!start.hasOwnProperty(key)) {
+                       start[key] = actual;
+               }
+
+               origin = start[key];
+
+               type = typeof target;
+
+               if (type === typeof origin) {
+                       if (type === 'string') {
+                               c0 = chartjsColor(origin);
+                               if (c0.valid) {
+                                       c1 = chartjsColor(target);
+                                       if (c1.valid) {
+                                               view[key] = c1.mix(c0, ease).rgbString();
+                                               continue;
+                                       }
+                               }
+                       } else if (helpers$1.isFinite(origin) && helpers$1.isFinite(target)) {
+                               view[key] = origin + (target - origin) * ease;
+                               continue;
+                       }
+               }
+
+               view[key] = target;
+       }
+}
+
+var Element = function(configuration) {
+       helpers$1.extend(this, configuration);
+       this.initialize.apply(this, arguments);
+};
+
+helpers$1.extend(Element.prototype, {
+
+       initialize: function() {
+               this.hidden = false;
+       },
+
+       pivot: function() {
+               var me = this;
+               if (!me._view) {
+                       me._view = helpers$1.clone(me._model);
+               }
+               me._start = {};
+               return me;
+       },
+
+       transition: function(ease) {
+               var me = this;
+               var model = me._model;
+               var start = me._start;
+               var view = me._view;
+
+               // No animation -> No Transition
+               if (!model || ease === 1) {
+                       me._view = model;
+                       me._start = null;
+                       return me;
+               }
+
+               if (!view) {
+                       view = me._view = {};
+               }
+
+               if (!start) {
+                       start = me._start = {};
+               }
+
+               interpolate(start, view, model, ease);
+
+               return me;
+       },
+
+       tooltipPosition: function() {
+               return {
+                       x: this._model.x,
+                       y: this._model.y
+               };
+       },
+
+       hasValue: function() {
+               return helpers$1.isNumber(this._model.x) && helpers$1.isNumber(this._model.y);
+       }
+});
+
+Element.extend = helpers$1.inherits;
+
+var core_element = Element;
+
+var exports$2 = core_element.extend({
+       chart: null, // the animation associated chart instance
+       currentStep: 0, // the current animation step
+       numSteps: 60, // default number of steps
+       easing: '', // the easing to use for this animation
+       render: null, // render function used by the animation service
+
+       onAnimationProgress: null, // user specified callback to fire on each step of the animation
+       onAnimationComplete: null, // user specified callback to fire when the animation finishes
+});
+
+var core_animation = exports$2;
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, use Chart.Animation instead
+ * @prop Chart.Animation#animationObject
+ * @deprecated since version 2.6.0
+ * @todo remove at version 3
+ */
+Object.defineProperty(exports$2.prototype, 'animationObject', {
+       get: function() {
+               return this;
+       }
+});
+
+/**
+ * Provided for backward compatibility, use Chart.Animation#chart instead
+ * @prop Chart.Animation#chartInstance
+ * @deprecated since version 2.6.0
+ * @todo remove at version 3
+ */
+Object.defineProperty(exports$2.prototype, 'chartInstance', {
+       get: function() {
+               return this.chart;
+       },
+       set: function(value) {
+               this.chart = value;
+       }
+});
+
+core_defaults._set('global', {
+       animation: {
+               duration: 1000,
+               easing: 'easeOutQuart',
+               onProgress: helpers$1.noop,
+               onComplete: helpers$1.noop
+       }
+});
+
+var core_animations = {
+       animations: [],
+       request: null,
+
+       /**
+        * @param {Chart} chart - The chart to animate.
+        * @param {Chart.Animation} animation - The animation that we will animate.
+        * @param {number} duration - The animation duration in ms.
+        * @param {boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
+        */
+       addAnimation: function(chart, animation, duration, lazy) {
+               var animations = this.animations;
+               var i, ilen;
+
+               animation.chart = chart;
+               animation.startTime = Date.now();
+               animation.duration = duration;
+
+               if (!lazy) {
+                       chart.animating = true;
+               }
+
+               for (i = 0, ilen = animations.length; i < ilen; ++i) {
+                       if (animations[i].chart === chart) {
+                               animations[i] = animation;
+                               return;
+                       }
+               }
+
+               animations.push(animation);
+
+               // If there are no animations queued, manually kickstart a digest, for lack of a better word
+               if (animations.length === 1) {
+                       this.requestAnimationFrame();
+               }
+       },
+
+       cancelAnimation: function(chart) {
+               var index = helpers$1.findIndex(this.animations, function(animation) {
+                       return animation.chart === chart;
+               });
+
+               if (index !== -1) {
+                       this.animations.splice(index, 1);
+                       chart.animating = false;
+               }
+       },
+
+       requestAnimationFrame: function() {
+               var me = this;
+               if (me.request === null) {
+                       // Skip animation frame requests until the active one is executed.
+                       // This can happen when processing mouse events, e.g. 'mousemove'
+                       // and 'mouseout' events will trigger multiple renders.
+                       me.request = helpers$1.requestAnimFrame.call(window, function() {
+                               me.request = null;
+                               me.startDigest();
+                       });
+               }
+       },
+
+       /**
+        * @private
+        */
+       startDigest: function() {
+               var me = this;
+
+               me.advance();
+
+               // Do we have more stuff to animate?
+               if (me.animations.length > 0) {
+                       me.requestAnimationFrame();
+               }
+       },
+
+       /**
+        * @private
+        */
+       advance: function() {
+               var animations = this.animations;
+               var animation, chart, numSteps, nextStep;
+               var i = 0;
+
+               // 1 animation per chart, so we are looping charts here
+               while (i < animations.length) {
+                       animation = animations[i];
+                       chart = animation.chart;
+                       numSteps = animation.numSteps;
+
+                       // Make sure that currentStep starts at 1
+                       // https://github.com/chartjs/Chart.js/issues/6104
+                       nextStep = Math.floor((Date.now() - animation.startTime) / animation.duration * numSteps) + 1;
+                       animation.currentStep = Math.min(nextStep, numSteps);
+
+                       helpers$1.callback(animation.render, [chart, animation], chart);
+                       helpers$1.callback(animation.onAnimationProgress, [animation], chart);
+
+                       if (animation.currentStep >= numSteps) {
+                               helpers$1.callback(animation.onAnimationComplete, [animation], chart);
+                               chart.animating = false;
+                               animations.splice(i, 1);
+                       } else {
+                               ++i;
+                       }
+               }
+       }
+};
+
+var resolve = helpers$1.options.resolve;
+
+var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];
+
+/**
+ * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice',
+ * 'unshift') and notify the listener AFTER the array has been altered. Listeners are
+ * called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same arguments.
+ */
+function listenArrayEvents(array, listener) {
+       if (array._chartjs) {
+               array._chartjs.listeners.push(listener);
+               return;
+       }
+
+       Object.defineProperty(array, '_chartjs', {
+               configurable: true,
+               enumerable: false,
+               value: {
+                       listeners: [listener]
+               }
+       });
+
+       arrayEvents.forEach(function(key) {
+               var method = 'onData' + key.charAt(0).toUpperCase() + key.slice(1);
+               var base = array[key];
+
+               Object.defineProperty(array, key, {
+                       configurable: true,
+                       enumerable: false,
+                       value: function() {
+                               var args = Array.prototype.slice.call(arguments);
+                               var res = base.apply(this, args);
+
+                               helpers$1.each(array._chartjs.listeners, function(object) {
+                                       if (typeof object[method] === 'function') {
+                                               object[method].apply(object, args);
+                                       }
+                               });
+
+                               return res;
+                       }
+               });
+       });
+}
+
+/**
+ * Removes the given array event listener and cleanup extra attached properties (such as
+ * the _chartjs stub and overridden methods) if array doesn't have any more listeners.
+ */
+function unlistenArrayEvents(array, listener) {
+       var stub = array._chartjs;
+       if (!stub) {
+               return;
+       }
+
+       var listeners = stub.listeners;
+       var index = listeners.indexOf(listener);
+       if (index !== -1) {
+               listeners.splice(index, 1);
+       }
+
+       if (listeners.length > 0) {
+               return;
+       }
+
+       arrayEvents.forEach(function(key) {
+               delete array[key];
+       });
+
+       delete array._chartjs;
+}
+
+// Base class for all dataset controllers (line, bar, etc)
+var DatasetController = function(chart, datasetIndex) {
+       this.initialize(chart, datasetIndex);
+};
+
+helpers$1.extend(DatasetController.prototype, {
+
+       /**
+        * Element type used to generate a meta dataset (e.g. Chart.element.Line).
+        * @type {Chart.core.element}
+        */
+       datasetElementType: null,
+
+       /**
+        * Element type used to generate a meta data (e.g. Chart.element.Point).
+        * @type {Chart.core.element}
+        */
+       dataElementType: null,
+
+       initialize: function(chart, datasetIndex) {
+               var me = this;
+               me.chart = chart;
+               me.index = datasetIndex;
+               me.linkScales();
+               me.addElements();
+       },
+
+       updateIndex: function(datasetIndex) {
+               this.index = datasetIndex;
+       },
+
+       linkScales: function() {
+               var me = this;
+               var meta = me.getMeta();
+               var dataset = me.getDataset();
+
+               if (meta.xAxisID === null || !(meta.xAxisID in me.chart.scales)) {
+                       meta.xAxisID = dataset.xAxisID || me.chart.options.scales.xAxes[0].id;
+               }
+               if (meta.yAxisID === null || !(meta.yAxisID in me.chart.scales)) {
+                       meta.yAxisID = dataset.yAxisID || me.chart.options.scales.yAxes[0].id;
+               }
+       },
+
+       getDataset: function() {
+               return this.chart.data.datasets[this.index];
+       },
+
+       getMeta: function() {
+               return this.chart.getDatasetMeta(this.index);
+       },
+
+       getScaleForId: function(scaleID) {
+               return this.chart.scales[scaleID];
+       },
+
+       /**
+        * @private
+        */
+       _getValueScaleId: function() {
+               return this.getMeta().yAxisID;
+       },
+
+       /**
+        * @private
+        */
+       _getIndexScaleId: function() {
+               return this.getMeta().xAxisID;
+       },
+
+       /**
+        * @private
+        */
+       _getValueScale: function() {
+               return this.getScaleForId(this._getValueScaleId());
+       },
+
+       /**
+        * @private
+        */
+       _getIndexScale: function() {
+               return this.getScaleForId(this._getIndexScaleId());
+       },
+
+       reset: function() {
+               this.update(true);
+       },
+
+       /**
+        * @private
+        */
+       destroy: function() {
+               if (this._data) {
+                       unlistenArrayEvents(this._data, this);
+               }
+       },
+
+       createMetaDataset: function() {
+               var me = this;
+               var type = me.datasetElementType;
+               return type && new type({
+                       _chart: me.chart,
+                       _datasetIndex: me.index
+               });
+       },
+
+       createMetaData: function(index) {
+               var me = this;
+               var type = me.dataElementType;
+               return type && new type({
+                       _chart: me.chart,
+                       _datasetIndex: me.index,
+                       _index: index
+               });
+       },
+
+       addElements: function() {
+               var me = this;
+               var meta = me.getMeta();
+               var data = me.getDataset().data || [];
+               var metaData = meta.data;
+               var i, ilen;
+
+               for (i = 0, ilen = data.length; i < ilen; ++i) {
+                       metaData[i] = metaData[i] || me.createMetaData(i);
+               }
+
+               meta.dataset = meta.dataset || me.createMetaDataset();
+       },
+
+       addElementAndReset: function(index) {
+               var element = this.createMetaData(index);
+               this.getMeta().data.splice(index, 0, element);
+               this.updateElement(element, index, true);
+       },
+
+       buildOrUpdateElements: function() {
+               var me = this;
+               var dataset = me.getDataset();
+               var data = dataset.data || (dataset.data = []);
+
+               // In order to correctly handle data addition/deletion animation (an thus simulate
+               // real-time charts), we need to monitor these data modifications and synchronize
+               // the internal meta data accordingly.
+               if (me._data !== data) {
+                       if (me._data) {
+                               // This case happens when the user replaced the data array instance.
+                               unlistenArrayEvents(me._data, me);
+                       }
+
+                       if (data && Object.isExtensible(data)) {
+                               listenArrayEvents(data, me);
+                       }
+                       me._data = data;
+               }
+
+               // Re-sync meta data in case the user replaced the data array or if we missed
+               // any updates and so make sure that we handle number of datapoints changing.
+               me.resyncElements();
+       },
+
+       update: helpers$1.noop,
+
+       transition: function(easingValue) {
+               var meta = this.getMeta();
+               var elements = meta.data || [];
+               var ilen = elements.length;
+               var i = 0;
+
+               for (; i < ilen; ++i) {
+                       elements[i].transition(easingValue);
+               }
+
+               if (meta.dataset) {
+                       meta.dataset.transition(easingValue);
+               }
+       },
+
+       draw: function() {
+               var meta = this.getMeta();
+               var elements = meta.data || [];
+               var ilen = elements.length;
+               var i = 0;
+
+               if (meta.dataset) {
+                       meta.dataset.draw();
+               }
+
+               for (; i < ilen; ++i) {
+                       elements[i].draw();
+               }
+       },
+
+       removeHoverStyle: function(element) {
+               helpers$1.merge(element._model, element.$previousStyle || {});
+               delete element.$previousStyle;
+       },
+
+       setHoverStyle: function(element) {
+               var dataset = this.chart.data.datasets[element._datasetIndex];
+               var index = element._index;
+               var custom = element.custom || {};
+               var model = element._model;
+               var getHoverColor = helpers$1.getHoverColor;
+
+               element.$previousStyle = {
+                       backgroundColor: model.backgroundColor,
+                       borderColor: model.borderColor,
+                       borderWidth: model.borderWidth
+               };
+
+               model.backgroundColor = resolve([custom.hoverBackgroundColor, dataset.hoverBackgroundColor, getHoverColor(model.backgroundColor)], undefined, index);
+               model.borderColor = resolve([custom.hoverBorderColor, dataset.hoverBorderColor, getHoverColor(model.borderColor)], undefined, index);
+               model.borderWidth = resolve([custom.hoverBorderWidth, dataset.hoverBorderWidth, model.borderWidth], undefined, index);
+       },
+
+       /**
+        * @private
+        */
+       resyncElements: function() {
+               var me = this;
+               var meta = me.getMeta();
+               var data = me.getDataset().data;
+               var numMeta = meta.data.length;
+               var numData = data.length;
+
+               if (numData < numMeta) {
+                       meta.data.splice(numData, numMeta - numData);
+               } else if (numData > numMeta) {
+                       me.insertElements(numMeta, numData - numMeta);
+               }
+       },
+
+       /**
+        * @private
+        */
+       insertElements: function(start, count) {
+               for (var i = 0; i < count; ++i) {
+                       this.addElementAndReset(start + i);
+               }
+       },
+
+       /**
+        * @private
+        */
+       onDataPush: function() {
+               var count = arguments.length;
+               this.insertElements(this.getDataset().data.length - count, count);
+       },
+
+       /**
+        * @private
+        */
+       onDataPop: function() {
+               this.getMeta().data.pop();
+       },
+
+       /**
+        * @private
+        */
+       onDataShift: function() {
+               this.getMeta().data.shift();
+       },
+
+       /**
+        * @private
+        */
+       onDataSplice: function(start, count) {
+               this.getMeta().data.splice(start, count);
+               this.insertElements(start, arguments.length - 2);
+       },
+
+       /**
+        * @private
+        */
+       onDataUnshift: function() {
+               this.insertElements(0, arguments.length);
+       }
+});
+
+DatasetController.extend = helpers$1.inherits;
+
+var core_datasetController = DatasetController;
+
+core_defaults._set('global', {
+       elements: {
+               arc: {
+                       backgroundColor: core_defaults.global.defaultColor,
+                       borderColor: '#fff',
+                       borderWidth: 2,
+                       borderAlign: 'center'
+               }
+       }
+});
+
+var element_arc = core_element.extend({
+       inLabelRange: function(mouseX) {
+               var vm = this._view;
+
+               if (vm) {
+                       return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
+               }
+               return false;
+       },
+
+       inRange: function(chartX, chartY) {
+               var vm = this._view;
+
+               if (vm) {
+                       var pointRelativePosition = helpers$1.getAngleFromPoint(vm, {x: chartX, y: chartY});
+                       var     angle = pointRelativePosition.angle;
+                       var distance = pointRelativePosition.distance;
+
+                       // Sanitise angle range
+                       var startAngle = vm.startAngle;
+                       var endAngle = vm.endAngle;
+                       while (endAngle < startAngle) {
+                               endAngle += 2.0 * Math.PI;
+                       }
+                       while (angle > endAngle) {
+                               angle -= 2.0 * Math.PI;
+                       }
+                       while (angle < startAngle) {
+                               angle += 2.0 * Math.PI;
+                       }
+
+                       // Check if within the range of the open/close angle
+                       var betweenAngles = (angle >= startAngle && angle <= endAngle);
+                       var withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);
+
+                       return (betweenAngles && withinRadius);
+               }
+               return false;
+       },
+
+       getCenterPoint: function() {
+               var vm = this._view;
+               var halfAngle = (vm.startAngle + vm.endAngle) / 2;
+               var halfRadius = (vm.innerRadius + vm.outerRadius) / 2;
+               return {
+                       x: vm.x + Math.cos(halfAngle) * halfRadius,
+                       y: vm.y + Math.sin(halfAngle) * halfRadius
+               };
+       },
+
+       getArea: function() {
+               var vm = this._view;
+               return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2));
+       },
+
+       tooltipPosition: function() {
+               var vm = this._view;
+               var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2);
+               var rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
+
+               return {
+                       x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
+                       y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
+               };
+       },
+
+       draw: function() {
+               var ctx = this._chart.ctx;
+               var vm = this._view;
+               var sA = vm.startAngle;
+               var eA = vm.endAngle;
+               var pixelMargin = (vm.borderAlign === 'inner') ? 0.33 : 0;
+               var angleMargin;
+
+               ctx.save();
+
+               ctx.beginPath();
+               ctx.arc(vm.x, vm.y, Math.max(vm.outerRadius - pixelMargin, 0), sA, eA);
+               ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
+               ctx.closePath();
+
+               ctx.fillStyle = vm.backgroundColor;
+               ctx.fill();
+
+               if (vm.borderWidth) {
+                       if (vm.borderAlign === 'inner') {
+                               // Draw an inner border by cliping the arc and drawing a double-width border
+                               // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders
+                               ctx.beginPath();
+                               angleMargin = pixelMargin / vm.outerRadius;
+                               ctx.arc(vm.x, vm.y, vm.outerRadius, sA - angleMargin, eA + angleMargin);
+                               if (vm.innerRadius > pixelMargin) {
+                                       angleMargin = pixelMargin / vm.innerRadius;
+                                       ctx.arc(vm.x, vm.y, vm.innerRadius - pixelMargin, eA + angleMargin, sA - angleMargin, true);
+                               } else {
+                                       ctx.arc(vm.x, vm.y, pixelMargin, eA + Math.PI / 2, sA - Math.PI / 2);
+                               }
+                               ctx.closePath();
+                               ctx.clip();
+
+                               ctx.beginPath();
+                               ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
+                               ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
+                               ctx.closePath();
+
+                               ctx.lineWidth = vm.borderWidth * 2;
+                               ctx.lineJoin = 'round';
+                       } else {
+                               ctx.lineWidth = vm.borderWidth;
+                               ctx.lineJoin = 'bevel';
+                       }
+
+                       ctx.strokeStyle = vm.borderColor;
+                       ctx.stroke();
+               }
+
+               ctx.restore();
+       }
+});
+
+var valueOrDefault$1 = helpers$1.valueOrDefault;
+
+var defaultColor = core_defaults.global.defaultColor;
+
+core_defaults._set('global', {
+       elements: {
+               line: {
+                       tension: 0.4,
+                       backgroundColor: defaultColor,
+                       borderWidth: 3,
+                       borderColor: defaultColor,
+                       borderCapStyle: 'butt',
+                       borderDash: [],
+                       borderDashOffset: 0.0,
+                       borderJoinStyle: 'miter',
+                       capBezierPoints: true,
+                       fill: true, // do we fill in the area between the line and its base axis
+               }
+       }
+});
+
+var element_line = core_element.extend({
+       draw: function() {
+               var me = this;
+               var vm = me._view;
+               var ctx = me._chart.ctx;
+               var spanGaps = vm.spanGaps;
+               var points = me._children.slice(); // clone array
+               var globalDefaults = core_defaults.global;
+               var globalOptionLineElements = globalDefaults.elements.line;
+               var lastDrawnIndex = -1;
+               var index, current, previous, currentVM;
+
+               // If we are looping, adding the first point again
+               if (me._loop && points.length) {
+                       points.push(points[0]);
+               }
+
+               ctx.save();
+
+               // Stroke Line Options
+               ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;
+
+               // IE 9 and 10 do not support line dash
+               if (ctx.setLineDash) {
+                       ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);
+               }
+
+               ctx.lineDashOffset = valueOrDefault$1(vm.borderDashOffset, globalOptionLineElements.borderDashOffset);
+               ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;
+               ctx.lineWidth = valueOrDefault$1(vm.borderWidth, globalOptionLineElements.borderWidth);
+               ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;
+
+               // Stroke Line
+               ctx.beginPath();
+               lastDrawnIndex = -1;
+
+               for (index = 0; index < points.length; ++index) {
+                       current = points[index];
+                       previous = helpers$1.previousItem(points, index);
+                       currentVM = current._view;
+
+                       // First point moves to it's starting position no matter what
+                       if (index === 0) {
+                               if (!currentVM.skip) {
+                                       ctx.moveTo(currentVM.x, currentVM.y);
+                                       lastDrawnIndex = index;
+                               }
+                       } else {
+                               previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];
+
+                               if (!currentVM.skip) {
+                                       if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) {
+                                               // There was a gap and this is the first point after the gap
+                                               ctx.moveTo(currentVM.x, currentVM.y);
+                                       } else {
+                                               // Line to next point
+                                               helpers$1.canvas.lineTo(ctx, previous._view, current._view);
+                                       }
+                                       lastDrawnIndex = index;
+                               }
+                       }
+               }
+
+               ctx.stroke();
+               ctx.restore();
+       }
+});
+
+var valueOrDefault$2 = helpers$1.valueOrDefault;
+
+var defaultColor$1 = core_defaults.global.defaultColor;
+
+core_defaults._set('global', {
+       elements: {
+               point: {
+                       radius: 3,
+                       pointStyle: 'circle',
+                       backgroundColor: defaultColor$1,
+                       borderColor: defaultColor$1,
+                       borderWidth: 1,
+                       // Hover
+                       hitRadius: 1,
+                       hoverRadius: 4,
+                       hoverBorderWidth: 1
+               }
+       }
+});
+
+function xRange(mouseX) {
+       var vm = this._view;
+       return vm ? (Math.abs(mouseX - vm.x) < vm.radius + vm.hitRadius) : false;
+}
+
+function yRange(mouseY) {
+       var vm = this._view;
+       return vm ? (Math.abs(mouseY - vm.y) < vm.radius + vm.hitRadius) : false;
+}
+
+var element_point = core_element.extend({
+       inRange: function(mouseX, mouseY) {
+               var vm = this._view;
+               return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
+       },
+
+       inLabelRange: xRange,
+       inXRange: xRange,
+       inYRange: yRange,
+
+       getCenterPoint: function() {
+               var vm = this._view;
+               return {
+                       x: vm.x,
+                       y: vm.y
+               };
+       },
+
+       getArea: function() {
+               return Math.PI * Math.pow(this._view.radius, 2);
+       },
+
+       tooltipPosition: function() {
+               var vm = this._view;
+               return {
+                       x: vm.x,
+                       y: vm.y,
+                       padding: vm.radius + vm.borderWidth
+               };
+       },
+
+       draw: function(chartArea) {
+               var vm = this._view;
+               var ctx = this._chart.ctx;
+               var pointStyle = vm.pointStyle;
+               var rotation = vm.rotation;
+               var radius = vm.radius;
+               var x = vm.x;
+               var y = vm.y;
+               var globalDefaults = core_defaults.global;
+               var defaultColor = globalDefaults.defaultColor; // eslint-disable-line no-shadow
+
+               if (vm.skip) {
+                       return;
+               }
+
+               // Clipping for Points.
+               if (chartArea === undefined || helpers$1.canvas._isPointInArea(vm, chartArea)) {
+                       ctx.strokeStyle = vm.borderColor || defaultColor;
+                       ctx.lineWidth = valueOrDefault$2(vm.borderWidth, globalDefaults.elements.point.borderWidth);
+                       ctx.fillStyle = vm.backgroundColor || defaultColor;
+                       helpers$1.canvas.drawPoint(ctx, pointStyle, radius, x, y, rotation);
+               }
+       }
+});
+
+var defaultColor$2 = core_defaults.global.defaultColor;
+
+core_defaults._set('global', {
+       elements: {
+               rectangle: {
+                       backgroundColor: defaultColor$2,
+                       borderColor: defaultColor$2,
+                       borderSkipped: 'bottom',
+                       borderWidth: 0
+               }
+       }
+});
+
+function isVertical(vm) {
+       return vm && vm.width !== undefined;
+}
+
+/**
+ * Helper function to get the bounds of the bar regardless of the orientation
+ * @param bar {Chart.Element.Rectangle} the bar
+ * @return {Bounds} bounds of the bar
+ * @private
+ */
+function getBarBounds(vm) {
+       var x1, x2, y1, y2, half;
+
+       if (isVertical(vm)) {
+               half = vm.width / 2;
+               x1 = vm.x - half;
+               x2 = vm.x + half;
+               y1 = Math.min(vm.y, vm.base);
+               y2 = Math.max(vm.y, vm.base);
+       } else {
+               half = vm.height / 2;
+               x1 = Math.min(vm.x, vm.base);
+               x2 = Math.max(vm.x, vm.base);
+               y1 = vm.y - half;
+               y2 = vm.y + half;
+       }
+
+       return {
+               left: x1,
+               top: y1,
+               right: x2,
+               bottom: y2
+       };
+}
+
+function swap(orig, v1, v2) {
+       return orig === v1 ? v2 : orig === v2 ? v1 : orig;
+}
+
+function parseBorderSkipped(vm) {
+       var edge = vm.borderSkipped;
+       var res = {};
+
+       if (!edge) {
+               return res;
+       }
+
+       if (vm.horizontal) {
+               if (vm.base > vm.x) {
+                       edge = swap(edge, 'left', 'right');
+               }
+       } else if (vm.base < vm.y) {
+               edge = swap(edge, 'bottom', 'top');
+       }
+
+       res[edge] = true;
+       return res;
+}
+
+function parseBorderWidth(vm, maxW, maxH) {
+       var value = vm.borderWidth;
+       var skip = parseBorderSkipped(vm);
+       var t, r, b, l;
+
+       if (helpers$1.isObject(value)) {
+               t = +value.top || 0;
+               r = +value.right || 0;
+               b = +value.bottom || 0;
+               l = +value.left || 0;
+       } else {
+               t = r = b = l = +value || 0;
+       }
+
+       return {
+               t: skip.top || (t < 0) ? 0 : t > maxH ? maxH : t,
+               r: skip.right || (r < 0) ? 0 : r > maxW ? maxW : r,
+               b: skip.bottom || (b < 0) ? 0 : b > maxH ? maxH : b,
+               l: skip.left || (l < 0) ? 0 : l > maxW ? maxW : l
+       };
+}
+
+function boundingRects(vm) {
+       var bounds = getBarBounds(vm);
+       var width = bounds.right - bounds.left;
+       var height = bounds.bottom - bounds.top;
+       var border = parseBorderWidth(vm, width / 2, height / 2);
+
+       return {
+               outer: {
+                       x: bounds.left,
+                       y: bounds.top,
+                       w: width,
+                       h: height
+               },
+               inner: {
+                       x: bounds.left + border.l,
+                       y: bounds.top + border.t,
+                       w: width - border.l - border.r,
+                       h: height - border.t - border.b
+               }
+       };
+}
+
+function inRange(vm, x, y) {
+       var skipX = x === null;
+       var skipY = y === null;
+       var bounds = !vm || (skipX && skipY) ? false : getBarBounds(vm);
+
+       return bounds
+               && (skipX || x >= bounds.left && x <= bounds.right)
+               && (skipY || y >= bounds.top && y <= bounds.bottom);
+}
+
+var element_rectangle = core_element.extend({
+       draw: function() {
+               var ctx = this._chart.ctx;
+               var vm = this._view;
+               var rects = boundingRects(vm);
+               var outer = rects.outer;
+               var inner = rects.inner;
+
+               ctx.fillStyle = vm.backgroundColor;
+               ctx.fillRect(outer.x, outer.y, outer.w, outer.h);
+
+               if (outer.w === inner.w && outer.h === inner.h) {
+                       return;
+               }
+
+               ctx.save();
+               ctx.beginPath();
+               ctx.rect(outer.x, outer.y, outer.w, outer.h);
+               ctx.clip();
+               ctx.fillStyle = vm.borderColor;
+               ctx.rect(inner.x, inner.y, inner.w, inner.h);
+               ctx.fill('evenodd');
+               ctx.restore();
+       },
+
+       height: function() {
+               var vm = this._view;
+               return vm.base - vm.y;
+       },
+
+       inRange: function(mouseX, mouseY) {
+               return inRange(this._view, mouseX, mouseY);
+       },
+
+       inLabelRange: function(mouseX, mouseY) {
+               var vm = this._view;
+               return isVertical(vm)
+                       ? inRange(vm, mouseX, null)
+                       : inRange(vm, null, mouseY);
+       },
+
+       inXRange: function(mouseX) {
+               return inRange(this._view, mouseX, null);
+       },
+
+       inYRange: function(mouseY) {
+               return inRange(this._view, null, mouseY);
+       },
+
+       getCenterPoint: function() {
+               var vm = this._view;
+               var x, y;
+               if (isVertical(vm)) {
+                       x = vm.x;
+                       y = (vm.y + vm.base) / 2;
+               } else {
+                       x = (vm.x + vm.base) / 2;
+                       y = vm.y;
+               }
+
+               return {x: x, y: y};
+       },
+
+       getArea: function() {
+               var vm = this._view;
+
+               return isVertical(vm)
+                       ? vm.width * Math.abs(vm.y - vm.base)
+                       : vm.height * Math.abs(vm.x - vm.base);
+       },
+
+       tooltipPosition: function() {
+               var vm = this._view;
+               return {
+                       x: vm.x,
+                       y: vm.y
+               };
+       }
+});
+
+var elements = {};
+var Arc = element_arc;
+var Line = element_line;
+var Point = element_point;
+var Rectangle = element_rectangle;
+elements.Arc = Arc;
+elements.Line = Line;
+elements.Point = Point;
+elements.Rectangle = Rectangle;
+
+var resolve$1 = helpers$1.options.resolve;
+
+core_defaults._set('bar', {
+       hover: {
+               mode: 'label'
+       },
+
+       scales: {
+               xAxes: [{
+                       type: 'category',
+                       categoryPercentage: 0.8,
+                       barPercentage: 0.9,
+                       offset: true,
+                       gridLines: {
+                               offsetGridLines: true
+                       }
+               }],
+
+               yAxes: [{
+                       type: 'linear'
+               }]
+       }
+});
+
+/**
+ * Computes the "optimal" sample size to maintain bars equally sized while preventing overlap.
+ * @private
+ */
+function computeMinSampleSize(scale, pixels) {
+       var min = scale.isHorizontal() ? scale.width : scale.height;
+       var ticks = scale.getTicks();
+       var prev, curr, i, ilen;
+
+       for (i = 1, ilen = pixels.length; i < ilen; ++i) {
+               min = Math.min(min, Math.abs(pixels[i] - pixels[i - 1]));
+       }
+
+       for (i = 0, ilen = ticks.length; i < ilen; ++i) {
+               curr = scale.getPixelForTick(i);
+               min = i > 0 ? Math.min(min, curr - prev) : min;
+               prev = curr;
+       }
+
+       return min;
+}
+
+/**
+ * Computes an "ideal" category based on the absolute bar thickness or, if undefined or null,
+ * uses the smallest interval (see computeMinSampleSize) that prevents bar overlapping. This
+ * mode currently always generates bars equally sized (until we introduce scriptable options?).
+ * @private
+ */
+function computeFitCategoryTraits(index, ruler, options) {
+       var thickness = options.barThickness;
+       var count = ruler.stackCount;
+       var curr = ruler.pixels[index];
+       var size, ratio;
+
+       if (helpers$1.isNullOrUndef(thickness)) {
+               size = ruler.min * options.categoryPercentage;
+               ratio = options.barPercentage;
+       } else {
+               // When bar thickness is enforced, category and bar percentages are ignored.
+               // Note(SB): we could add support for relative bar thickness (e.g. barThickness: '50%')
+               // and deprecate barPercentage since this value is ignored when thickness is absolute.
+               size = thickness * count;
+               ratio = 1;
+       }
+
+       return {
+               chunk: size / count,
+               ratio: ratio,
+               start: curr - (size / 2)
+       };
+}
+
+/**
+ * Computes an "optimal" category that globally arranges bars side by side (no gap when
+ * percentage options are 1), based on the previous and following categories. This mode
+ * generates bars with different widths when data are not evenly spaced.
+ * @private
+ */
+function computeFlexCategoryTraits(index, ruler, options) {
+       var pixels = ruler.pixels;
+       var curr = pixels[index];
+       var prev = index > 0 ? pixels[index - 1] : null;
+       var next = index < pixels.length - 1 ? pixels[index + 1] : null;
+       var percent = options.categoryPercentage;
+       var start, size;
+
+       if (prev === null) {
+               // first data: its size is double based on the next point or,
+               // if it's also the last data, we use the scale size.
+               prev = curr - (next === null ? ruler.end - ruler.start : next - curr);
+       }
+
+       if (next === null) {
+               // last data: its size is also double based on the previous point.
+               next = curr + curr - prev;
+       }
+
+       start = curr - (curr - Math.min(prev, next)) / 2 * percent;
+       size = Math.abs(next - prev) / 2 * percent;
+
+       return {
+               chunk: size / ruler.stackCount,
+               ratio: options.barPercentage,
+               start: start
+       };
+}
+
+var controller_bar = core_datasetController.extend({
+
+       dataElementType: elements.Rectangle,
+
+       initialize: function() {
+               var me = this;
+               var meta;
+
+               core_datasetController.prototype.initialize.apply(me, arguments);
+
+               meta = me.getMeta();
+               meta.stack = me.getDataset().stack;
+               meta.bar = true;
+       },
+
+       update: function(reset) {
+               var me = this;
+               var rects = me.getMeta().data;
+               var i, ilen;
+
+               me._ruler = me.getRuler();
+
+               for (i = 0, ilen = rects.length; i < ilen; ++i) {
+                       me.updateElement(rects[i], i, reset);
+               }
+       },
+
+       updateElement: function(rectangle, index, reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var dataset = me.getDataset();
+               var options = me._resolveElementOptions(rectangle, index);
+
+               rectangle._xScale = me.getScaleForId(meta.xAxisID);
+               rectangle._yScale = me.getScaleForId(meta.yAxisID);
+               rectangle._datasetIndex = me.index;
+               rectangle._index = index;
+               rectangle._model = {
+                       backgroundColor: options.backgroundColor,
+                       borderColor: options.borderColor,
+                       borderSkipped: options.borderSkipped,
+                       borderWidth: options.borderWidth,
+                       datasetLabel: dataset.label,
+                       label: me.chart.data.labels[index]
+               };
+
+               me._updateElementGeometry(rectangle, index, reset);
+
+               rectangle.pivot();
+       },
+
+       /**
+        * @private
+        */
+       _updateElementGeometry: function(rectangle, index, reset) {
+               var me = this;
+               var model = rectangle._model;
+               var vscale = me._getValueScale();
+               var base = vscale.getBasePixel();
+               var horizontal = vscale.isHorizontal();
+               var ruler = me._ruler || me.getRuler();
+               var vpixels = me.calculateBarValuePixels(me.index, index);
+               var ipixels = me.calculateBarIndexPixels(me.index, index, ruler);
+
+               model.horizontal = horizontal;
+               model.base = reset ? base : vpixels.base;
+               model.x = horizontal ? reset ? base : vpixels.head : ipixels.center;
+               model.y = horizontal ? ipixels.center : reset ? base : vpixels.head;
+               model.height = horizontal ? ipixels.size : undefined;
+               model.width = horizontal ? undefined : ipixels.size;
+       },
+
+       /**
+        * Returns the stacks based on groups and bar visibility.
+        * @param {number} [last] - The dataset index
+        * @returns {string[]} The list of stack IDs
+        * @private
+        */
+       _getStacks: function(last) {
+               var me = this;
+               var chart = me.chart;
+               var scale = me._getIndexScale();
+               var stacked = scale.options.stacked;
+               var ilen = last === undefined ? chart.data.datasets.length : last + 1;
+               var stacks = [];
+               var i, meta;
+
+               for (i = 0; i < ilen; ++i) {
+                       meta = chart.getDatasetMeta(i);
+                       if (meta.bar && chart.isDatasetVisible(i) &&
+                               (stacked === false ||
+                               (stacked === true && stacks.indexOf(meta.stack) === -1) ||
+                               (stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) {
+                               stacks.push(meta.stack);
+                       }
+               }
+
+               return stacks;
+       },
+
+       /**
+        * Returns the effective number of stacks based on groups and bar visibility.
+        * @private
+        */
+       getStackCount: function() {
+               return this._getStacks().length;
+       },
+
+       /**
+        * Returns the stack index for the given dataset based on groups and bar visibility.
+        * @param {number} [datasetIndex] - The dataset index
+        * @param {string} [name] - The stack name to find
+        * @returns {number} The stack index
+        * @private
+        */
+       getStackIndex: function(datasetIndex, name) {
+               var stacks = this._getStacks(datasetIndex);
+               var index = (name !== undefined)
+                       ? stacks.indexOf(name)
+                       : -1; // indexOf returns -1 if element is not present
+
+               return (index === -1)
+                       ? stacks.length - 1
+                       : index;
+       },
+
+       /**
+        * @private
+        */
+       getRuler: function() {
+               var me = this;
+               var scale = me._getIndexScale();
+               var stackCount = me.getStackCount();
+               var datasetIndex = me.index;
+               var isHorizontal = scale.isHorizontal();
+               var start = isHorizontal ? scale.left : scale.top;
+               var end = start + (isHorizontal ? scale.width : scale.height);
+               var pixels = [];
+               var i, ilen, min;
+
+               for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) {
+                       pixels.push(scale.getPixelForValue(null, i, datasetIndex));
+               }
+
+               min = helpers$1.isNullOrUndef(scale.options.barThickness)
+                       ? computeMinSampleSize(scale, pixels)
+                       : -1;
+
+               return {
+                       min: min,
+                       pixels: pixels,
+                       start: start,
+                       end: end,
+                       stackCount: stackCount,
+                       scale: scale
+               };
+       },
+
+       /**
+        * Note: pixel values are not clamped to the scale area.
+        * @private
+        */
+       calculateBarValuePixels: function(datasetIndex, index) {
+               var me = this;
+               var chart = me.chart;
+               var meta = me.getMeta();
+               var scale = me._getValueScale();
+               var isHorizontal = scale.isHorizontal();
+               var datasets = chart.data.datasets;
+               var value = +scale.getRightValue(datasets[datasetIndex].data[index]);
+               var minBarLength = scale.options.minBarLength;
+               var stacked = scale.options.stacked;
+               var stack = meta.stack;
+               var start = 0;
+               var i, imeta, ivalue, base, head, size;
+
+               if (stacked || (stacked === undefined && stack !== undefined)) {
+                       for (i = 0; i < datasetIndex; ++i) {
+                               imeta = chart.getDatasetMeta(i);
+
+                               if (imeta.bar &&
+                                       imeta.stack === stack &&
+                                       imeta.controller._getValueScaleId() === scale.id &&
+                                       chart.isDatasetVisible(i)) {
+
+                                       ivalue = +scale.getRightValue(datasets[i].data[index]);
+                                       if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) {
+                                               start += ivalue;
+                                       }
+                               }
+                       }
+               }
+
+               base = scale.getPixelForValue(start);
+               head = scale.getPixelForValue(start + value);
+               size = head - base;
+
+               if (minBarLength !== undefined && Math.abs(size) < minBarLength) {
+                       size = minBarLength;
+                       if (value >= 0 && !isHorizontal || value < 0 && isHorizontal) {
+                               head = base - minBarLength;
+                       } else {
+                               head = base + minBarLength;
+                       }
+               }
+
+               return {
+                       size: size,
+                       base: base,
+                       head: head,
+                       center: head + size / 2
+               };
+       },
+
+       /**
+        * @private
+        */
+       calculateBarIndexPixels: function(datasetIndex, index, ruler) {
+               var me = this;
+               var options = ruler.scale.options;
+               var range = options.barThickness === 'flex'
+                       ? computeFlexCategoryTraits(index, ruler, options)
+                       : computeFitCategoryTraits(index, ruler, options);
+
+               var stackIndex = me.getStackIndex(datasetIndex, me.getMeta().stack);
+               var center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);
+               var size = Math.min(
+                       helpers$1.valueOrDefault(options.maxBarThickness, Infinity),
+                       range.chunk * range.ratio);
+
+               return {
+                       base: center - size / 2,
+                       head: center + size / 2,
+                       center: center,
+                       size: size
+               };
+       },
+
+       draw: function() {
+               var me = this;
+               var chart = me.chart;
+               var scale = me._getValueScale();
+               var rects = me.getMeta().data;
+               var dataset = me.getDataset();
+               var ilen = rects.length;
+               var i = 0;
+
+               helpers$1.canvas.clipArea(chart.ctx, chart.chartArea);
+
+               for (; i < ilen; ++i) {
+                       if (!isNaN(scale.getRightValue(dataset.data[i]))) {
+                               rects[i].draw();
+                       }
+               }
+
+               helpers$1.canvas.unclipArea(chart.ctx);
+       },
+
+       /**
+        * @private
+        */
+       _resolveElementOptions: function(rectangle, index) {
+               var me = this;
+               var chart = me.chart;
+               var datasets = chart.data.datasets;
+               var dataset = datasets[me.index];
+               var custom = rectangle.custom || {};
+               var options = chart.options.elements.rectangle;
+               var values = {};
+               var i, ilen, key;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               var keys = [
+                       'backgroundColor',
+                       'borderColor',
+                       'borderSkipped',
+                       'borderWidth'
+               ];
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve$1([
+                               custom[key],
+                               dataset[key],
+                               options[key]
+                       ], context, index);
+               }
+
+               return values;
+       }
+});
+
+var valueOrDefault$3 = helpers$1.valueOrDefault;
+var resolve$2 = helpers$1.options.resolve;
+
+core_defaults._set('bubble', {
+       hover: {
+               mode: 'single'
+       },
+
+       scales: {
+               xAxes: [{
+                       type: 'linear', // bubble should probably use a linear scale by default
+                       position: 'bottom',
+                       id: 'x-axis-0' // need an ID so datasets can reference the scale
+               }],
+               yAxes: [{
+                       type: 'linear',
+                       position: 'left',
+                       id: 'y-axis-0'
+               }]
+       },
+
+       tooltips: {
+               callbacks: {
+                       title: function() {
+                               // Title doesn't make sense for scatter since we format the data as a point
+                               return '';
+                       },
+                       label: function(item, data) {
+                               var datasetLabel = data.datasets[item.datasetIndex].label || '';
+                               var dataPoint = data.datasets[item.datasetIndex].data[item.index];
+                               return datasetLabel + ': (' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.r + ')';
+                       }
+               }
+       }
+});
+
+var controller_bubble = core_datasetController.extend({
+       /**
+        * @protected
+        */
+       dataElementType: elements.Point,
+
+       /**
+        * @protected
+        */
+       update: function(reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var points = meta.data;
+
+               // Update Points
+               helpers$1.each(points, function(point, index) {
+                       me.updateElement(point, index, reset);
+               });
+       },
+
+       /**
+        * @protected
+        */
+       updateElement: function(point, index, reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var custom = point.custom || {};
+               var xScale = me.getScaleForId(meta.xAxisID);
+               var yScale = me.getScaleForId(meta.yAxisID);
+               var options = me._resolveElementOptions(point, index);
+               var data = me.getDataset().data[index];
+               var dsIndex = me.index;
+
+               var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex);
+               var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex);
+
+               point._xScale = xScale;
+               point._yScale = yScale;
+               point._options = options;
+               point._datasetIndex = dsIndex;
+               point._index = index;
+               point._model = {
+                       backgroundColor: options.backgroundColor,
+                       borderColor: options.borderColor,
+                       borderWidth: options.borderWidth,
+                       hitRadius: options.hitRadius,
+                       pointStyle: options.pointStyle,
+                       rotation: options.rotation,
+                       radius: reset ? 0 : options.radius,
+                       skip: custom.skip || isNaN(x) || isNaN(y),
+                       x: x,
+                       y: y,
+               };
+
+               point.pivot();
+       },
+
+       /**
+        * @protected
+        */
+       setHoverStyle: function(point) {
+               var model = point._model;
+               var options = point._options;
+               var getHoverColor = helpers$1.getHoverColor;
+
+               point.$previousStyle = {
+                       backgroundColor: model.backgroundColor,
+                       borderColor: model.borderColor,
+                       borderWidth: model.borderWidth,
+                       radius: model.radius
+               };
+
+               model.backgroundColor = valueOrDefault$3(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
+               model.borderColor = valueOrDefault$3(options.hoverBorderColor, getHoverColor(options.borderColor));
+               model.borderWidth = valueOrDefault$3(options.hoverBorderWidth, options.borderWidth);
+               model.radius = options.radius + options.hoverRadius;
+       },
+
+       /**
+        * @private
+        */
+       _resolveElementOptions: function(point, index) {
+               var me = this;
+               var chart = me.chart;
+               var datasets = chart.data.datasets;
+               var dataset = datasets[me.index];
+               var custom = point.custom || {};
+               var options = chart.options.elements.point;
+               var data = dataset.data[index];
+               var values = {};
+               var i, ilen, key;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               var keys = [
+                       'backgroundColor',
+                       'borderColor',
+                       'borderWidth',
+                       'hoverBackgroundColor',
+                       'hoverBorderColor',
+                       'hoverBorderWidth',
+                       'hoverRadius',
+                       'hitRadius',
+                       'pointStyle',
+                       'rotation'
+               ];
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve$2([
+                               custom[key],
+                               dataset[key],
+                               options[key]
+                       ], context, index);
+               }
+
+               // Custom radius resolution
+               values.radius = resolve$2([
+                       custom.radius,
+                       data ? data.r : undefined,
+                       dataset.radius,
+                       options.radius
+               ], context, index);
+
+               return values;
+       }
+});
+
+var resolve$3 = helpers$1.options.resolve;
+var valueOrDefault$4 = helpers$1.valueOrDefault;
+
+core_defaults._set('doughnut', {
+       animation: {
+               // Boolean - Whether we animate the rotation of the Doughnut
+               animateRotate: true,
+               // Boolean - Whether we animate scaling the Doughnut from the centre
+               animateScale: false
+       },
+       hover: {
+               mode: 'single'
+       },
+       legendCallback: function(chart) {
+               var text = [];
+               text.push('<ul class="' + chart.id + '-legend">');
+
+               var data = chart.data;
+               var datasets = data.datasets;
+               var labels = data.labels;
+
+               if (datasets.length) {
+                       for (var i = 0; i < datasets[0].data.length; ++i) {
+                               text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
+                               if (labels[i]) {
+                                       text.push(labels[i]);
+                               }
+                               text.push('</li>');
+                       }
+               }
+
+               text.push('</ul>');
+               return text.join('');
+       },
+       legend: {
+               labels: {
+                       generateLabels: function(chart) {
+                               var data = chart.data;
+                               if (data.labels.length && data.datasets.length) {
+                                       return data.labels.map(function(label, i) {
+                                               var meta = chart.getDatasetMeta(0);
+                                               var ds = data.datasets[0];
+                                               var arc = meta.data[i];
+                                               var custom = arc && arc.custom || {};
+                                               var arcOpts = chart.options.elements.arc;
+                                               var fill = resolve$3([custom.backgroundColor, ds.backgroundColor, arcOpts.backgroundColor], undefined, i);
+                                               var stroke = resolve$3([custom.borderColor, ds.borderColor, arcOpts.borderColor], undefined, i);
+                                               var bw = resolve$3([custom.borderWidth, ds.borderWidth, arcOpts.borderWidth], undefined, i);
+
+                                               return {
+                                                       text: label,
+                                                       fillStyle: fill,
+                                                       strokeStyle: stroke,
+                                                       lineWidth: bw,
+                                                       hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
+
+                                                       // Extra data used for toggling the correct item
+                                                       index: i
+                                               };
+                                       });
+                               }
+                               return [];
+                       }
+               },
+
+               onClick: function(e, legendItem) {
+                       var index = legendItem.index;
+                       var chart = this.chart;
+                       var i, ilen, meta;
+
+                       for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
+                               meta = chart.getDatasetMeta(i);
+                               // toggle visibility of index if exists
+                               if (meta.data[index]) {
+                                       meta.data[index].hidden = !meta.data[index].hidden;
+                               }
+                       }
+
+                       chart.update();
+               }
+       },
+
+       // The percentage of the chart that we cut out of the middle.
+       cutoutPercentage: 50,
+
+       // The rotation of the chart, where the first data arc begins.
+       rotation: Math.PI * -0.5,
+
+       // The total circumference of the chart.
+       circumference: Math.PI * 2.0,
+
+       // Need to override these to give a nice default
+       tooltips: {
+               callbacks: {
+                       title: function() {
+                               return '';
+                       },
+                       label: function(tooltipItem, data) {
+                               var dataLabel = data.labels[tooltipItem.index];
+                               var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
+
+                               if (helpers$1.isArray(dataLabel)) {
+                                       // show value on first line of multiline label
+                                       // need to clone because we are changing the value
+                                       dataLabel = dataLabel.slice();
+                                       dataLabel[0] += value;
+                               } else {
+                                       dataLabel += value;
+                               }
+
+                               return dataLabel;
+                       }
+               }
+       }
+});
+
+var controller_doughnut = core_datasetController.extend({
+
+       dataElementType: elements.Arc,
+
+       linkScales: helpers$1.noop,
+
+       // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
+       getRingIndex: function(datasetIndex) {
+               var ringIndex = 0;
+
+               for (var j = 0; j < datasetIndex; ++j) {
+                       if (this.chart.isDatasetVisible(j)) {
+                               ++ringIndex;
+                       }
+               }
+
+               return ringIndex;
+       },
+
+       update: function(reset) {
+               var me = this;
+               var chart = me.chart;
+               var chartArea = chart.chartArea;
+               var opts = chart.options;
+               var availableWidth = chartArea.right - chartArea.left;
+               var availableHeight = chartArea.bottom - chartArea.top;
+               var minSize = Math.min(availableWidth, availableHeight);
+               var offset = {x: 0, y: 0};
+               var meta = me.getMeta();
+               var arcs = meta.data;
+               var cutoutPercentage = opts.cutoutPercentage;
+               var circumference = opts.circumference;
+               var chartWeight = me._getRingWeight(me.index);
+               var i, ilen;
+
+               // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc
+               if (circumference < Math.PI * 2.0) {
+                       var startAngle = opts.rotation % (Math.PI * 2.0);
+                       startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0);
+                       var endAngle = startAngle + circumference;
+                       var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)};
+                       var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)};
+                       var contains0 = (startAngle <= 0 && endAngle >= 0) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle);
+                       var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle);
+                       var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle);
+                       var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle);
+                       var cutout = cutoutPercentage / 100.0;
+                       var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))};
+                       var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))};
+                       var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5};
+                       minSize = Math.min(availableWidth / size.width, availableHeight / size.height);
+                       offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
+               }
+
+               for (i = 0, ilen = arcs.length; i < ilen; ++i) {
+                       arcs[i]._options = me._resolveElementOptions(arcs[i], i);
+               }
+
+               chart.borderWidth = me.getMaxBorderWidth();
+               chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
+               chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
+               chart.radiusLength = (chart.outerRadius - chart.innerRadius) / (me._getVisibleDatasetWeightTotal() || 1);
+               chart.offsetX = offset.x * chart.outerRadius;
+               chart.offsetY = offset.y * chart.outerRadius;
+
+               meta.total = me.calculateTotal();
+
+               me.outerRadius = chart.outerRadius - chart.radiusLength * me._getRingWeightOffset(me.index);
+               me.innerRadius = Math.max(me.outerRadius - chart.radiusLength * chartWeight, 0);
+
+               for (i = 0, ilen = arcs.length; i < ilen; ++i) {
+                       me.updateElement(arcs[i], i, reset);
+               }
+       },
+
+       updateElement: function(arc, index, reset) {
+               var me = this;
+               var chart = me.chart;
+               var chartArea = chart.chartArea;
+               var opts = chart.options;
+               var animationOpts = opts.animation;
+               var centerX = (chartArea.left + chartArea.right) / 2;
+               var centerY = (chartArea.top + chartArea.bottom) / 2;
+               var startAngle = opts.rotation; // non reset case handled later
+               var endAngle = opts.rotation; // non reset case handled later
+               var dataset = me.getDataset();
+               var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI));
+               var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius;
+               var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius;
+               var options = arc._options || {};
+
+               helpers$1.extend(arc, {
+                       // Utility
+                       _datasetIndex: me.index,
+                       _index: index,
+
+                       // Desired view properties
+                       _model: {
+                               backgroundColor: options.backgroundColor,
+                               borderColor: options.borderColor,
+                               borderWidth: options.borderWidth,
+                               borderAlign: options.borderAlign,
+                               x: centerX + chart.offsetX,
+                               y: centerY + chart.offsetY,
+                               startAngle: startAngle,
+                               endAngle: endAngle,
+                               circumference: circumference,
+                               outerRadius: outerRadius,
+                               innerRadius: innerRadius,
+                               label: helpers$1.valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])
+                       }
+               });
+
+               var model = arc._model;
+
+               // Set correct angles if not resetting
+               if (!reset || !animationOpts.animateRotate) {
+                       if (index === 0) {
+                               model.startAngle = opts.rotation;
+                       } else {
+                               model.startAngle = me.getMeta().data[index - 1]._model.endAngle;
+                       }
+
+                       model.endAngle = model.startAngle + model.circumference;
+               }
+
+               arc.pivot();
+       },
+
+       calculateTotal: function() {
+               var dataset = this.getDataset();
+               var meta = this.getMeta();
+               var total = 0;
+               var value;
+
+               helpers$1.each(meta.data, function(element, index) {
+                       value = dataset.data[index];
+                       if (!isNaN(value) && !element.hidden) {
+                               total += Math.abs(value);
+                       }
+               });
+
+               /* if (total === 0) {
+                       total = NaN;
+               }*/
+
+               return total;
+       },
+
+       calculateCircumference: function(value) {
+               var total = this.getMeta().total;
+               if (total > 0 && !isNaN(value)) {
+                       return (Math.PI * 2.0) * (Math.abs(value) / total);
+               }
+               return 0;
+       },
+
+       // gets the max border or hover width to properly scale pie charts
+       getMaxBorderWidth: function(arcs) {
+               var me = this;
+               var max = 0;
+               var chart = me.chart;
+               var i, ilen, meta, arc, controller, options, borderWidth, hoverWidth;
+
+               if (!arcs) {
+                       // Find the outmost visible dataset
+                       for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
+                               if (chart.isDatasetVisible(i)) {
+                                       meta = chart.getDatasetMeta(i);
+                                       arcs = meta.data;
+                                       if (i !== me.index) {
+                                               controller = meta.controller;
+                                       }
+                                       break;
+                               }
+                       }
+               }
+
+               if (!arcs) {
+                       return 0;
+               }
+
+               for (i = 0, ilen = arcs.length; i < ilen; ++i) {
+                       arc = arcs[i];
+                       options = controller ? controller._resolveElementOptions(arc, i) : arc._options;
+                       if (options.borderAlign !== 'inner') {
+                               borderWidth = options.borderWidth;
+                               hoverWidth = options.hoverBorderWidth;
+
+                               max = borderWidth > max ? borderWidth : max;
+                               max = hoverWidth > max ? hoverWidth : max;
+                       }
+               }
+               return max;
+       },
+
+       /**
+        * @protected
+        */
+       setHoverStyle: function(arc) {
+               var model = arc._model;
+               var options = arc._options;
+               var getHoverColor = helpers$1.getHoverColor;
+
+               arc.$previousStyle = {
+                       backgroundColor: model.backgroundColor,
+                       borderColor: model.borderColor,
+                       borderWidth: model.borderWidth,
+               };
+
+               model.backgroundColor = valueOrDefault$4(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
+               model.borderColor = valueOrDefault$4(options.hoverBorderColor, getHoverColor(options.borderColor));
+               model.borderWidth = valueOrDefault$4(options.hoverBorderWidth, options.borderWidth);
+       },
+
+       /**
+        * @private
+        */
+       _resolveElementOptions: function(arc, index) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = me.getDataset();
+               var custom = arc.custom || {};
+               var options = chart.options.elements.arc;
+               var values = {};
+               var i, ilen, key;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               var keys = [
+                       'backgroundColor',
+                       'borderColor',
+                       'borderWidth',
+                       'borderAlign',
+                       'hoverBackgroundColor',
+                       'hoverBorderColor',
+                       'hoverBorderWidth',
+               ];
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve$3([
+                               custom[key],
+                               dataset[key],
+                               options[key]
+                       ], context, index);
+               }
+
+               return values;
+       },
+
+       /**
+        * Get radius length offset of the dataset in relation to the visible datasets weights. This allows determining the inner and outer radius correctly
+        * @private
+        */
+       _getRingWeightOffset: function(datasetIndex) {
+               var ringWeightOffset = 0;
+
+               for (var i = 0; i < datasetIndex; ++i) {
+                       if (this.chart.isDatasetVisible(i)) {
+                               ringWeightOffset += this._getRingWeight(i);
+                       }
+               }
+
+               return ringWeightOffset;
+       },
+
+       /**
+        * @private
+        */
+       _getRingWeight: function(dataSetIndex) {
+               return Math.max(valueOrDefault$4(this.chart.data.datasets[dataSetIndex].weight, 1), 0);
+       },
+
+       /**
+        * Returns the sum of all visibile data set weights.  This value can be 0.
+        * @private
+        */
+       _getVisibleDatasetWeightTotal: function() {
+               return this._getRingWeightOffset(this.chart.data.datasets.length);
+       }
+});
+
+core_defaults._set('horizontalBar', {
+       hover: {
+               mode: 'index',
+               axis: 'y'
+       },
+
+       scales: {
+               xAxes: [{
+                       type: 'linear',
+                       position: 'bottom'
+               }],
+
+               yAxes: [{
+                       type: 'category',
+                       position: 'left',
+                       categoryPercentage: 0.8,
+                       barPercentage: 0.9,
+                       offset: true,
+                       gridLines: {
+                               offsetGridLines: true
+                       }
+               }]
+       },
+
+       elements: {
+               rectangle: {
+                       borderSkipped: 'left'
+               }
+       },
+
+       tooltips: {
+               mode: 'index',
+               axis: 'y'
+       }
+});
+
+var controller_horizontalBar = controller_bar.extend({
+       /**
+        * @private
+        */
+       _getValueScaleId: function() {
+               return this.getMeta().xAxisID;
+       },
+
+       /**
+        * @private
+        */
+       _getIndexScaleId: function() {
+               return this.getMeta().yAxisID;
+       }
+});
+
+var valueOrDefault$5 = helpers$1.valueOrDefault;
+var resolve$4 = helpers$1.options.resolve;
+var isPointInArea = helpers$1.canvas._isPointInArea;
+
+core_defaults._set('line', {
+       showLines: true,
+       spanGaps: false,
+
+       hover: {
+               mode: 'label'
+       },
+
+       scales: {
+               xAxes: [{
+                       type: 'category',
+                       id: 'x-axis-0'
+               }],
+               yAxes: [{
+                       type: 'linear',
+                       id: 'y-axis-0'
+               }]
+       }
+});
+
+function lineEnabled(dataset, options) {
+       return valueOrDefault$5(dataset.showLine, options.showLines);
+}
+
+var controller_line = core_datasetController.extend({
+
+       datasetElementType: elements.Line,
+
+       dataElementType: elements.Point,
+
+       update: function(reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var line = meta.dataset;
+               var points = meta.data || [];
+               var scale = me.getScaleForId(meta.yAxisID);
+               var dataset = me.getDataset();
+               var showLine = lineEnabled(dataset, me.chart.options);
+               var i, ilen;
+
+               // Update Line
+               if (showLine) {
+                       // Compatibility: If the properties are defined with only the old name, use those values
+                       if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
+                               dataset.lineTension = dataset.tension;
+                       }
+
+                       // Utility
+                       line._scale = scale;
+                       line._datasetIndex = me.index;
+                       // Data
+                       line._children = points;
+                       // Model
+                       line._model = me._resolveLineOptions(line);
+
+                       line.pivot();
+               }
+
+               // Update Points
+               for (i = 0, ilen = points.length; i < ilen; ++i) {
+                       me.updateElement(points[i], i, reset);
+               }
+
+               if (showLine && line._model.tension !== 0) {
+                       me.updateBezierControlPoints();
+               }
+
+               // Now pivot the point for animation
+               for (i = 0, ilen = points.length; i < ilen; ++i) {
+                       points[i].pivot();
+               }
+       },
+
+       updateElement: function(point, index, reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var custom = point.custom || {};
+               var dataset = me.getDataset();
+               var datasetIndex = me.index;
+               var value = dataset.data[index];
+               var yScale = me.getScaleForId(meta.yAxisID);
+               var xScale = me.getScaleForId(meta.xAxisID);
+               var lineModel = meta.dataset._model;
+               var x, y;
+
+               var options = me._resolvePointOptions(point, index);
+
+               x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex);
+               y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex);
+
+               // Utility
+               point._xScale = xScale;
+               point._yScale = yScale;
+               point._options = options;
+               point._datasetIndex = datasetIndex;
+               point._index = index;
+
+               // Desired view properties
+               point._model = {
+                       x: x,
+                       y: y,
+                       skip: custom.skip || isNaN(x) || isNaN(y),
+                       // Appearance
+                       radius: options.radius,
+                       pointStyle: options.pointStyle,
+                       rotation: options.rotation,
+                       backgroundColor: options.backgroundColor,
+                       borderColor: options.borderColor,
+                       borderWidth: options.borderWidth,
+                       tension: valueOrDefault$5(custom.tension, lineModel ? lineModel.tension : 0),
+                       steppedLine: lineModel ? lineModel.steppedLine : false,
+                       // Tooltip
+                       hitRadius: options.hitRadius
+               };
+       },
+
+       /**
+        * @private
+        */
+       _resolvePointOptions: function(element, index) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = chart.data.datasets[me.index];
+               var custom = element.custom || {};
+               var options = chart.options.elements.point;
+               var values = {};
+               var i, ilen, key;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               var ELEMENT_OPTIONS = {
+                       backgroundColor: 'pointBackgroundColor',
+                       borderColor: 'pointBorderColor',
+                       borderWidth: 'pointBorderWidth',
+                       hitRadius: 'pointHitRadius',
+                       hoverBackgroundColor: 'pointHoverBackgroundColor',
+                       hoverBorderColor: 'pointHoverBorderColor',
+                       hoverBorderWidth: 'pointHoverBorderWidth',
+                       hoverRadius: 'pointHoverRadius',
+                       pointStyle: 'pointStyle',
+                       radius: 'pointRadius',
+                       rotation: 'pointRotation'
+               };
+               var keys = Object.keys(ELEMENT_OPTIONS);
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve$4([
+                               custom[key],
+                               dataset[ELEMENT_OPTIONS[key]],
+                               dataset[key],
+                               options[key]
+                       ], context, index);
+               }
+
+               return values;
+       },
+
+       /**
+        * @private
+        */
+       _resolveLineOptions: function(element) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = chart.data.datasets[me.index];
+               var custom = element.custom || {};
+               var options = chart.options;
+               var elementOptions = options.elements.line;
+               var values = {};
+               var i, ilen, key;
+
+               var keys = [
+                       'backgroundColor',
+                       'borderWidth',
+                       'borderColor',
+                       'borderCapStyle',
+                       'borderDash',
+                       'borderDashOffset',
+                       'borderJoinStyle',
+                       'fill',
+                       'cubicInterpolationMode'
+               ];
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve$4([
+                               custom[key],
+                               dataset[key],
+                               elementOptions[key]
+                       ]);
+               }
+
+               // The default behavior of lines is to break at null values, according
+               // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
+               // This option gives lines the ability to span gaps
+               values.spanGaps = valueOrDefault$5(dataset.spanGaps, options.spanGaps);
+               values.tension = valueOrDefault$5(dataset.lineTension, elementOptions.tension);
+               values.steppedLine = resolve$4([custom.steppedLine, dataset.steppedLine, elementOptions.stepped]);
+
+               return values;
+       },
+
+       calculatePointY: function(value, index, datasetIndex) {
+               var me = this;
+               var chart = me.chart;
+               var meta = me.getMeta();
+               var yScale = me.getScaleForId(meta.yAxisID);
+               var sumPos = 0;
+               var sumNeg = 0;
+               var i, ds, dsMeta;
+
+               if (yScale.options.stacked) {
+                       for (i = 0; i < datasetIndex; i++) {
+                               ds = chart.data.datasets[i];
+                               dsMeta = chart.getDatasetMeta(i);
+                               if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
+                                       var stackedRightValue = Number(yScale.getRightValue(ds.data[index]));
+                                       if (stackedRightValue < 0) {
+                                               sumNeg += stackedRightValue || 0;
+                                       } else {
+                                               sumPos += stackedRightValue || 0;
+                                       }
+                               }
+                       }
+
+                       var rightValue = Number(yScale.getRightValue(value));
+                       if (rightValue < 0) {
+                               return yScale.getPixelForValue(sumNeg + rightValue);
+                       }
+                       return yScale.getPixelForValue(sumPos + rightValue);
+               }
+
+               return yScale.getPixelForValue(value);
+       },
+
+       updateBezierControlPoints: function() {
+               var me = this;
+               var chart = me.chart;
+               var meta = me.getMeta();
+               var lineModel = meta.dataset._model;
+               var area = chart.chartArea;
+               var points = meta.data || [];
+               var i, ilen, model, controlPoints;
+
+               // Only consider points that are drawn in case the spanGaps option is used
+               if (lineModel.spanGaps) {
+                       points = points.filter(function(pt) {
+                               return !pt._model.skip;
+                       });
+               }
+
+               function capControlPoint(pt, min, max) {
+                       return Math.max(Math.min(pt, max), min);
+               }
+
+               if (lineModel.cubicInterpolationMode === 'monotone') {
+                       helpers$1.splineCurveMonotone(points);
+               } else {
+                       for (i = 0, ilen = points.length; i < ilen; ++i) {
+                               model = points[i]._model;
+                               controlPoints = helpers$1.splineCurve(
+                                       helpers$1.previousItem(points, i)._model,
+                                       model,
+                                       helpers$1.nextItem(points, i)._model,
+                                       lineModel.tension
+                               );
+                               model.controlPointPreviousX = controlPoints.previous.x;
+                               model.controlPointPreviousY = controlPoints.previous.y;
+                               model.controlPointNextX = controlPoints.next.x;
+                               model.controlPointNextY = controlPoints.next.y;
+                       }
+               }
+
+               if (chart.options.elements.line.capBezierPoints) {
+                       for (i = 0, ilen = points.length; i < ilen; ++i) {
+                               model = points[i]._model;
+                               if (isPointInArea(model, area)) {
+                                       if (i > 0 && isPointInArea(points[i - 1]._model, area)) {
+                                               model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);
+                                               model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
+                                       }
+                                       if (i < points.length - 1 && isPointInArea(points[i + 1]._model, area)) {
+                                               model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);
+                                               model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);
+                                       }
+                               }
+                       }
+               }
+       },
+
+       draw: function() {
+               var me = this;
+               var chart = me.chart;
+               var meta = me.getMeta();
+               var points = meta.data || [];
+               var area = chart.chartArea;
+               var ilen = points.length;
+               var halfBorderWidth;
+               var i = 0;
+
+               if (lineEnabled(me.getDataset(), chart.options)) {
+                       halfBorderWidth = (meta.dataset._model.borderWidth || 0) / 2;
+
+                       helpers$1.canvas.clipArea(chart.ctx, {
+                               left: area.left,
+                               right: area.right,
+                               top: area.top - halfBorderWidth,
+                               bottom: area.bottom + halfBorderWidth
+                       });
+
+                       meta.dataset.draw();
+
+                       helpers$1.canvas.unclipArea(chart.ctx);
+               }
+
+               // Draw the points
+               for (; i < ilen; ++i) {
+                       points[i].draw(area);
+               }
+       },
+
+       /**
+        * @protected
+        */
+       setHoverStyle: function(point) {
+               var model = point._model;
+               var options = point._options;
+               var getHoverColor = helpers$1.getHoverColor;
+
+               point.$previousStyle = {
+                       backgroundColor: model.backgroundColor,
+                       borderColor: model.borderColor,
+                       borderWidth: model.borderWidth,
+                       radius: model.radius
+               };
+
+               model.backgroundColor = valueOrDefault$5(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
+               model.borderColor = valueOrDefault$5(options.hoverBorderColor, getHoverColor(options.borderColor));
+               model.borderWidth = valueOrDefault$5(options.hoverBorderWidth, options.borderWidth);
+               model.radius = valueOrDefault$5(options.hoverRadius, options.radius);
+       },
+});
+
+var resolve$5 = helpers$1.options.resolve;
+
+core_defaults._set('polarArea', {
+       scale: {
+               type: 'radialLinear',
+               angleLines: {
+                       display: false
+               },
+               gridLines: {
+                       circular: true
+               },
+               pointLabels: {
+                       display: false
+               },
+               ticks: {
+                       beginAtZero: true
+               }
+       },
+
+       // Boolean - Whether to animate the rotation of the chart
+       animation: {
+               animateRotate: true,
+               animateScale: true
+       },
+
+       startAngle: -0.5 * Math.PI,
+       legendCallback: function(chart) {
+               var text = [];
+               text.push('<ul class="' + chart.id + '-legend">');
+
+               var data = chart.data;
+               var datasets = data.datasets;
+               var labels = data.labels;
+
+               if (datasets.length) {
+                       for (var i = 0; i < datasets[0].data.length; ++i) {
+                               text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
+                               if (labels[i]) {
+                                       text.push(labels[i]);
+                               }
+                               text.push('</li>');
+                       }
+               }
+
+               text.push('</ul>');
+               return text.join('');
+       },
+       legend: {
+               labels: {
+                       generateLabels: function(chart) {
+                               var data = chart.data;
+                               if (data.labels.length && data.datasets.length) {
+                                       return data.labels.map(function(label, i) {
+                                               var meta = chart.getDatasetMeta(0);
+                                               var ds = data.datasets[0];
+                                               var arc = meta.data[i];
+                                               var custom = arc.custom || {};
+                                               var arcOpts = chart.options.elements.arc;
+                                               var fill = resolve$5([custom.backgroundColor, ds.backgroundColor, arcOpts.backgroundColor], undefined, i);
+                                               var stroke = resolve$5([custom.borderColor, ds.borderColor, arcOpts.borderColor], undefined, i);
+                                               var bw = resolve$5([custom.borderWidth, ds.borderWidth, arcOpts.borderWidth], undefined, i);
+
+                                               return {
+                                                       text: label,
+                                                       fillStyle: fill,
+                                                       strokeStyle: stroke,
+                                                       lineWidth: bw,
+                                                       hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
+
+                                                       // Extra data used for toggling the correct item
+                                                       index: i
+                                               };
+                                       });
+                               }
+                               return [];
+                       }
+               },
+
+               onClick: function(e, legendItem) {
+                       var index = legendItem.index;
+                       var chart = this.chart;
+                       var i, ilen, meta;
+
+                       for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
+                               meta = chart.getDatasetMeta(i);
+                               meta.data[index].hidden = !meta.data[index].hidden;
+                       }
+
+                       chart.update();
+               }
+       },
+
+       // Need to override these to give a nice default
+       tooltips: {
+               callbacks: {
+                       title: function() {
+                               return '';
+                       },
+                       label: function(item, data) {
+                               return data.labels[item.index] + ': ' + item.yLabel;
+                       }
+               }
+       }
+});
+
+var controller_polarArea = core_datasetController.extend({
+
+       dataElementType: elements.Arc,
+
+       linkScales: helpers$1.noop,
+
+       update: function(reset) {
+               var me = this;
+               var dataset = me.getDataset();
+               var meta = me.getMeta();
+               var start = me.chart.options.startAngle || 0;
+               var starts = me._starts = [];
+               var angles = me._angles = [];
+               var arcs = meta.data;
+               var i, ilen, angle;
+
+               me._updateRadius();
+
+               meta.count = me.countVisibleElements();
+
+               for (i = 0, ilen = dataset.data.length; i < ilen; i++) {
+                       starts[i] = start;
+                       angle = me._computeAngle(i);
+                       angles[i] = angle;
+                       start += angle;
+               }
+
+               for (i = 0, ilen = arcs.length; i < ilen; ++i) {
+                       arcs[i]._options = me._resolveElementOptions(arcs[i], i);
+                       me.updateElement(arcs[i], i, reset);
+               }
+       },
+
+       /**
+        * @private
+        */
+       _updateRadius: function() {
+               var me = this;
+               var chart = me.chart;
+               var chartArea = chart.chartArea;
+               var opts = chart.options;
+               var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
+
+               chart.outerRadius = Math.max(minSize / 2, 0);
+               chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
+               chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
+
+               me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);
+               me.innerRadius = me.outerRadius - chart.radiusLength;
+       },
+
+       updateElement: function(arc, index, reset) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = me.getDataset();
+               var opts = chart.options;
+               var animationOpts = opts.animation;
+               var scale = chart.scale;
+               var labels = chart.data.labels;
+
+               var centerX = scale.xCenter;
+               var centerY = scale.yCenter;
+
+               // var negHalfPI = -0.5 * Math.PI;
+               var datasetStartAngle = opts.startAngle;
+               var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
+               var startAngle = me._starts[index];
+               var endAngle = startAngle + (arc.hidden ? 0 : me._angles[index]);
+
+               var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
+               var options = arc._options || {};
+
+               helpers$1.extend(arc, {
+                       // Utility
+                       _datasetIndex: me.index,
+                       _index: index,
+                       _scale: scale,
+
+                       // Desired view properties
+                       _model: {
+                               backgroundColor: options.backgroundColor,
+                               borderColor: options.borderColor,
+                               borderWidth: options.borderWidth,
+                               borderAlign: options.borderAlign,
+                               x: centerX,
+                               y: centerY,
+                               innerRadius: 0,
+                               outerRadius: reset ? resetRadius : distance,
+                               startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,
+                               endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle,
+                               label: helpers$1.valueAtIndexOrDefault(labels, index, labels[index])
+                       }
+               });
+
+               arc.pivot();
+       },
+
+       countVisibleElements: function() {
+               var dataset = this.getDataset();
+               var meta = this.getMeta();
+               var count = 0;
+
+               helpers$1.each(meta.data, function(element, index) {
+                       if (!isNaN(dataset.data[index]) && !element.hidden) {
+                               count++;
+                       }
+               });
+
+               return count;
+       },
+
+       /**
+        * @protected
+        */
+       setHoverStyle: function(arc) {
+               var model = arc._model;
+               var options = arc._options;
+               var getHoverColor = helpers$1.getHoverColor;
+               var valueOrDefault = helpers$1.valueOrDefault;
+
+               arc.$previousStyle = {
+                       backgroundColor: model.backgroundColor,
+                       borderColor: model.borderColor,
+                       borderWidth: model.borderWidth,
+               };
+
+               model.backgroundColor = valueOrDefault(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
+               model.borderColor = valueOrDefault(options.hoverBorderColor, getHoverColor(options.borderColor));
+               model.borderWidth = valueOrDefault(options.hoverBorderWidth, options.borderWidth);
+       },
+
+       /**
+        * @private
+        */
+       _resolveElementOptions: function(arc, index) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = me.getDataset();
+               var custom = arc.custom || {};
+               var options = chart.options.elements.arc;
+               var values = {};
+               var i, ilen, key;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               var keys = [
+                       'backgroundColor',
+                       'borderColor',
+                       'borderWidth',
+                       'borderAlign',
+                       'hoverBackgroundColor',
+                       'hoverBorderColor',
+                       'hoverBorderWidth',
+               ];
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve$5([
+                               custom[key],
+                               dataset[key],
+                               options[key]
+                       ], context, index);
+               }
+
+               return values;
+       },
+
+       /**
+        * @private
+        */
+       _computeAngle: function(index) {
+               var me = this;
+               var count = this.getMeta().count;
+               var dataset = me.getDataset();
+               var meta = me.getMeta();
+
+               if (isNaN(dataset.data[index]) || meta.data[index].hidden) {
+                       return 0;
+               }
+
+               // Scriptable options
+               var context = {
+                       chart: me.chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               return resolve$5([
+                       me.chart.options.elements.arc.angle,
+                       (2 * Math.PI) / count
+               ], context, index);
+       }
+});
+
+core_defaults._set('pie', helpers$1.clone(core_defaults.doughnut));
+core_defaults._set('pie', {
+       cutoutPercentage: 0
+});
+
+// Pie charts are Doughnut chart with different defaults
+var controller_pie = controller_doughnut;
+
+var valueOrDefault$6 = helpers$1.valueOrDefault;
+var resolve$6 = helpers$1.options.resolve;
+
+core_defaults._set('radar', {
+       scale: {
+               type: 'radialLinear'
+       },
+       elements: {
+               line: {
+                       tension: 0 // no bezier in radar
+               }
+       }
+});
+
+var controller_radar = core_datasetController.extend({
+
+       datasetElementType: elements.Line,
+
+       dataElementType: elements.Point,
+
+       linkScales: helpers$1.noop,
+
+       update: function(reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var line = meta.dataset;
+               var points = meta.data || [];
+               var scale = me.chart.scale;
+               var dataset = me.getDataset();
+               var i, ilen;
+
+               // Compatibility: If the properties are defined with only the old name, use those values
+               if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
+                       dataset.lineTension = dataset.tension;
+               }
+
+               // Utility
+               line._scale = scale;
+               line._datasetIndex = me.index;
+               // Data
+               line._children = points;
+               line._loop = true;
+               // Model
+               line._model = me._resolveLineOptions(line);
+
+               line.pivot();
+
+               // Update Points
+               for (i = 0, ilen = points.length; i < ilen; ++i) {
+                       me.updateElement(points[i], i, reset);
+               }
+
+               // Update bezier control points
+               me.updateBezierControlPoints();
+
+               // Now pivot the point for animation
+               for (i = 0, ilen = points.length; i < ilen; ++i) {
+                       points[i].pivot();
+               }
+       },
+
+       updateElement: function(point, index, reset) {
+               var me = this;
+               var custom = point.custom || {};
+               var dataset = me.getDataset();
+               var scale = me.chart.scale;
+               var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);
+               var options = me._resolvePointOptions(point, index);
+               var lineModel = me.getMeta().dataset._model;
+               var x = reset ? scale.xCenter : pointPosition.x;
+               var y = reset ? scale.yCenter : pointPosition.y;
+
+               // Utility
+               point._scale = scale;
+               point._options = options;
+               point._datasetIndex = me.index;
+               point._index = index;
+
+               // Desired view properties
+               point._model = {
+                       x: x, // value not used in dataset scale, but we want a consistent API between scales
+                       y: y,
+                       skip: custom.skip || isNaN(x) || isNaN(y),
+                       // Appearance
+                       radius: options.radius,
+                       pointStyle: options.pointStyle,
+                       rotation: options.rotation,
+                       backgroundColor: options.backgroundColor,
+                       borderColor: options.borderColor,
+                       borderWidth: options.borderWidth,
+                       tension: valueOrDefault$6(custom.tension, lineModel ? lineModel.tension : 0),
+
+                       // Tooltip
+                       hitRadius: options.hitRadius
+               };
+       },
+
+       /**
+        * @private
+        */
+       _resolvePointOptions: function(element, index) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = chart.data.datasets[me.index];
+               var custom = element.custom || {};
+               var options = chart.options.elements.point;
+               var values = {};
+               var i, ilen, key;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               var ELEMENT_OPTIONS = {
+                       backgroundColor: 'pointBackgroundColor',
+                       borderColor: 'pointBorderColor',
+                       borderWidth: 'pointBorderWidth',
+                       hitRadius: 'pointHitRadius',
+                       hoverBackgroundColor: 'pointHoverBackgroundColor',
+                       hoverBorderColor: 'pointHoverBorderColor',
+                       hoverBorderWidth: 'pointHoverBorderWidth',
+                       hoverRadius: 'pointHoverRadius',
+                       pointStyle: 'pointStyle',
+                       radius: 'pointRadius',
+                       rotation: 'pointRotation'
+               };
+               var keys = Object.keys(ELEMENT_OPTIONS);
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve$6([
+                               custom[key],
+                               dataset[ELEMENT_OPTIONS[key]],
+                               dataset[key],
+                               options[key]
+                       ], context, index);
+               }
+
+               return values;
+       },
+
+       /**
+        * @private
+        */
+       _resolveLineOptions: function(element) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = chart.data.datasets[me.index];
+               var custom = element.custom || {};
+               var options = chart.options.elements.line;
+               var values = {};
+               var i, ilen, key;
+
+               var keys = [
+                       'backgroundColor',
+                       'borderWidth',
+                       'borderColor',
+                       'borderCapStyle',
+                       'borderDash',
+                       'borderDashOffset',
+                       'borderJoinStyle',
+                       'fill'
+               ];
+
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       values[key] = resolve$6([
+                               custom[key],
+                               dataset[key],
+                               options[key]
+                       ]);
+               }
+
+               values.tension = valueOrDefault$6(dataset.lineTension, options.tension);
+
+               return values;
+       },
+
+       updateBezierControlPoints: function() {
+               var me = this;
+               var meta = me.getMeta();
+               var area = me.chart.chartArea;
+               var points = meta.data || [];
+               var i, ilen, model, controlPoints;
+
+               function capControlPoint(pt, min, max) {
+                       return Math.max(Math.min(pt, max), min);
+               }
+
+               for (i = 0, ilen = points.length; i < ilen; ++i) {
+                       model = points[i]._model;
+                       controlPoints = helpers$1.splineCurve(
+                               helpers$1.previousItem(points, i, true)._model,
+                               model,
+                               helpers$1.nextItem(points, i, true)._model,
+                               model.tension
+                       );
+
+                       // Prevent the bezier going outside of the bounds of the graph
+                       model.controlPointPreviousX = capControlPoint(controlPoints.previous.x, area.left, area.right);
+                       model.controlPointPreviousY = capControlPoint(controlPoints.previous.y, area.top, area.bottom);
+                       model.controlPointNextX = capControlPoint(controlPoints.next.x, area.left, area.right);
+                       model.controlPointNextY = capControlPoint(controlPoints.next.y, area.top, area.bottom);
+               }
+       },
+
+       setHoverStyle: function(point) {
+               var model = point._model;
+               var options = point._options;
+               var getHoverColor = helpers$1.getHoverColor;
+
+               point.$previousStyle = {
+                       backgroundColor: model.backgroundColor,
+                       borderColor: model.borderColor,
+                       borderWidth: model.borderWidth,
+                       radius: model.radius
+               };
+
+               model.backgroundColor = valueOrDefault$6(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
+               model.borderColor = valueOrDefault$6(options.hoverBorderColor, getHoverColor(options.borderColor));
+               model.borderWidth = valueOrDefault$6(options.hoverBorderWidth, options.borderWidth);
+               model.radius = valueOrDefault$6(options.hoverRadius, options.radius);
+       }
+});
+
+core_defaults._set('scatter', {
+       hover: {
+               mode: 'single'
+       },
+
+       scales: {
+               xAxes: [{
+                       id: 'x-axis-1',    // need an ID so datasets can reference the scale
+                       type: 'linear',    // scatter should not use a category axis
+                       position: 'bottom'
+               }],
+               yAxes: [{
+                       id: 'y-axis-1',
+                       type: 'linear',
+                       position: 'left'
+               }]
+       },
+
+       showLines: false,
+
+       tooltips: {
+               callbacks: {
+                       title: function() {
+                               return '';     // doesn't make sense for scatter since data are formatted as a point
+                       },
+                       label: function(item) {
+                               return '(' + item.xLabel + ', ' + item.yLabel + ')';
+                       }
+               }
+       }
+});
+
+// Scatter charts use line controllers
+var controller_scatter = controller_line;
+
+// NOTE export a map in which the key represents the controller type, not
+// the class, and so must be CamelCase in order to be correctly retrieved
+// by the controller in core.controller.js (`controllers[meta.type]`).
+
+var controllers = {
+       bar: controller_bar,
+       bubble: controller_bubble,
+       doughnut: controller_doughnut,
+       horizontalBar: controller_horizontalBar,
+       line: controller_line,
+       polarArea: controller_polarArea,
+       pie: controller_pie,
+       radar: controller_radar,
+       scatter: controller_scatter
+};
+
+/**
+ * Helper function to get relative position for an event
+ * @param {Event|IEvent} event - The event to get the position for
+ * @param {Chart} chart - The chart
+ * @returns {object} the event position
+ */
+function getRelativePosition(e, chart) {
+       if (e.native) {
+               return {
+                       x: e.x,
+                       y: e.y
+               };
+       }
+
+       return helpers$1.getRelativePosition(e, chart);
+}
+
+/**
+ * Helper function to traverse all of the visible elements in the chart
+ * @param {Chart} chart - the chart
+ * @param {function} handler - the callback to execute for each visible item
+ */
+function parseVisibleItems(chart, handler) {
+       var datasets = chart.data.datasets;
+       var meta, i, j, ilen, jlen;
+
+       for (i = 0, ilen = datasets.length; i < ilen; ++i) {
+               if (!chart.isDatasetVisible(i)) {
+                       continue;
+               }
+
+               meta = chart.getDatasetMeta(i);
+               for (j = 0, jlen = meta.data.length; j < jlen; ++j) {
+                       var element = meta.data[j];
+                       if (!element._view.skip) {
+                               handler(element);
+                       }
+               }
+       }
+}
+
+/**
+ * Helper function to get the items that intersect the event position
+ * @param {ChartElement[]} items - elements to filter
+ * @param {object} position - the point to be nearest to
+ * @return {ChartElement[]} the nearest items
+ */
+function getIntersectItems(chart, position) {
+       var elements = [];
+
+       parseVisibleItems(chart, function(element) {
+               if (element.inRange(position.x, position.y)) {
+                       elements.push(element);
+               }
+       });
+
+       return elements;
+}
+
+/**
+ * Helper function to get the items nearest to the event position considering all visible items in teh chart
+ * @param {Chart} chart - the chart to look at elements from
+ * @param {object} position - the point to be nearest to
+ * @param {boolean} intersect - if true, only consider items that intersect the position
+ * @param {function} distanceMetric - function to provide the distance between points
+ * @return {ChartElement[]} the nearest items
+ */
+function getNearestItems(chart, position, intersect, distanceMetric) {
+       var minDistance = Number.POSITIVE_INFINITY;
+       var nearestItems = [];
+
+       parseVisibleItems(chart, function(element) {
+               if (intersect && !element.inRange(position.x, position.y)) {
+                       return;
+               }
+
+               var center = element.getCenterPoint();
+               var distance = distanceMetric(position, center);
+               if (distance < minDistance) {
+                       nearestItems = [element];
+                       minDistance = distance;
+               } else if (distance === minDistance) {
+                       // Can have multiple items at the same distance in which case we sort by size
+                       nearestItems.push(element);
+               }
+       });
+
+       return nearestItems;
+}
+
+/**
+ * Get a distance metric function for two points based on the
+ * axis mode setting
+ * @param {string} axis - the axis mode. x|y|xy
+ */
+function getDistanceMetricForAxis(axis) {
+       var useX = axis.indexOf('x') !== -1;
+       var useY = axis.indexOf('y') !== -1;
+
+       return function(pt1, pt2) {
+               var deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
+               var deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
+               return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
+       };
+}
+
+function indexMode(chart, e, options) {
+       var position = getRelativePosition(e, chart);
+       // Default axis for index mode is 'x' to match old behaviour
+       options.axis = options.axis || 'x';
+       var distanceMetric = getDistanceMetricForAxis(options.axis);
+       var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
+       var elements = [];
+
+       if (!items.length) {
+               return [];
+       }
+
+       chart.data.datasets.forEach(function(dataset, datasetIndex) {
+               if (chart.isDatasetVisible(datasetIndex)) {
+                       var meta = chart.getDatasetMeta(datasetIndex);
+                       var element = meta.data[items[0]._index];
+
+                       // don't count items that are skipped (null data)
+                       if (element && !element._view.skip) {
+                               elements.push(element);
+                       }
+               }
+       });
+
+       return elements;
+}
+
+/**
+ * @interface IInteractionOptions
+ */
+/**
+ * If true, only consider items that intersect the point
+ * @name IInterfaceOptions#boolean
+ * @type Boolean
+ */
+
+/**
+ * Contains interaction related functions
+ * @namespace Chart.Interaction
+ */
+var core_interaction = {
+       // Helper function for different modes
+       modes: {
+               single: function(chart, e) {
+                       var position = getRelativePosition(e, chart);
+                       var elements = [];
+
+                       parseVisibleItems(chart, function(element) {
+                               if (element.inRange(position.x, position.y)) {
+                                       elements.push(element);
+                                       return elements;
+                               }
+                       });
+
+                       return elements.slice(0, 1);
+               },
+
+               /**
+                * @function Chart.Interaction.modes.label
+                * @deprecated since version 2.4.0
+                * @todo remove at version 3
+                * @private
+                */
+               label: indexMode,
+
+               /**
+                * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something
+                * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item
+                * @function Chart.Interaction.modes.index
+                * @since v2.4.0
+                * @param {Chart} chart - the chart we are returning items from
+                * @param {Event} e - the event we are find things at
+                * @param {IInteractionOptions} options - options to use during interaction
+                * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+                */
+               index: indexMode,
+
+               /**
+                * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something
+                * If the options.intersect is false, we find the nearest item and return the items in that dataset
+                * @function Chart.Interaction.modes.dataset
+                * @param {Chart} chart - the chart we are returning items from
+                * @param {Event} e - the event we are find things at
+                * @param {IInteractionOptions} options - options to use during interaction
+                * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+                */
+               dataset: function(chart, e, options) {
+                       var position = getRelativePosition(e, chart);
+                       options.axis = options.axis || 'xy';
+                       var distanceMetric = getDistanceMetricForAxis(options.axis);
+                       var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
+
+                       if (items.length > 0) {
+                               items = chart.getDatasetMeta(items[0]._datasetIndex).data;
+                       }
+
+                       return items;
+               },
+
+               /**
+                * @function Chart.Interaction.modes.x-axis
+                * @deprecated since version 2.4.0. Use index mode and intersect == true
+                * @todo remove at version 3
+                * @private
+                */
+               'x-axis': function(chart, e) {
+                       return indexMode(chart, e, {intersect: false});
+               },
+
+               /**
+                * Point mode returns all elements that hit test based on the event position
+                * of the event
+                * @function Chart.Interaction.modes.intersect
+                * @param {Chart} chart - the chart we are returning items from
+                * @param {Event} e - the event we are find things at
+                * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+                */
+               point: function(chart, e) {
+                       var position = getRelativePosition(e, chart);
+                       return getIntersectItems(chart, position);
+               },
+
+               /**
+                * nearest mode returns the element closest to the point
+                * @function Chart.Interaction.modes.intersect
+                * @param {Chart} chart - the chart we are returning items from
+                * @param {Event} e - the event we are find things at
+                * @param {IInteractionOptions} options - options to use
+                * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+                */
+               nearest: function(chart, e, options) {
+                       var position = getRelativePosition(e, chart);
+                       options.axis = options.axis || 'xy';
+                       var distanceMetric = getDistanceMetricForAxis(options.axis);
+                       return getNearestItems(chart, position, options.intersect, distanceMetric);
+               },
+
+               /**
+                * x mode returns the elements that hit-test at the current x coordinate
+                * @function Chart.Interaction.modes.x
+                * @param {Chart} chart - the chart we are returning items from
+                * @param {Event} e - the event we are find things at
+                * @param {IInteractionOptions} options - options to use
+                * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+                */
+               x: function(chart, e, options) {
+                       var position = getRelativePosition(e, chart);
+                       var items = [];
+                       var intersectsItem = false;
+
+                       parseVisibleItems(chart, function(element) {
+                               if (element.inXRange(position.x)) {
+                                       items.push(element);
+                               }
+
+                               if (element.inRange(position.x, position.y)) {
+                                       intersectsItem = true;
+                               }
+                       });
+
+                       // If we want to trigger on an intersect and we don't have any items
+                       // that intersect the position, return nothing
+                       if (options.intersect && !intersectsItem) {
+                               items = [];
+                       }
+                       return items;
+               },
+
+               /**
+                * y mode returns the elements that hit-test at the current y coordinate
+                * @function Chart.Interaction.modes.y
+                * @param {Chart} chart - the chart we are returning items from
+                * @param {Event} e - the event we are find things at
+                * @param {IInteractionOptions} options - options to use
+                * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+                */
+               y: function(chart, e, options) {
+                       var position = getRelativePosition(e, chart);
+                       var items = [];
+                       var intersectsItem = false;
+
+                       parseVisibleItems(chart, function(element) {
+                               if (element.inYRange(position.y)) {
+                                       items.push(element);
+                               }
+
+                               if (element.inRange(position.x, position.y)) {
+                                       intersectsItem = true;
+                               }
+                       });
+
+                       // If we want to trigger on an intersect and we don't have any items
+                       // that intersect the position, return nothing
+                       if (options.intersect && !intersectsItem) {
+                               items = [];
+                       }
+                       return items;
+               }
+       }
+};
+
+function filterByPosition(array, position) {
+       return helpers$1.where(array, function(v) {
+               return v.position === position;
+       });
+}
+
+function sortByWeight(array, reverse) {
+       array.forEach(function(v, i) {
+               v._tmpIndex_ = i;
+               return v;
+       });
+       array.sort(function(a, b) {
+               var v0 = reverse ? b : a;
+               var v1 = reverse ? a : b;
+               return v0.weight === v1.weight ?
+                       v0._tmpIndex_ - v1._tmpIndex_ :
+                       v0.weight - v1.weight;
+       });
+       array.forEach(function(v) {
+               delete v._tmpIndex_;
+       });
+}
+
+function findMaxPadding(boxes) {
+       var top = 0;
+       var left = 0;
+       var bottom = 0;
+       var right = 0;
+       helpers$1.each(boxes, function(box) {
+               if (box.getPadding) {
+                       var boxPadding = box.getPadding();
+                       top = Math.max(top, boxPadding.top);
+                       left = Math.max(left, boxPadding.left);
+                       bottom = Math.max(bottom, boxPadding.bottom);
+                       right = Math.max(right, boxPadding.right);
+               }
+       });
+       return {
+               top: top,
+               left: left,
+               bottom: bottom,
+               right: right
+       };
+}
+
+function addSizeByPosition(boxes, size) {
+       helpers$1.each(boxes, function(box) {
+               size[box.position] += box.isHorizontal() ? box.height : box.width;
+       });
+}
+
+core_defaults._set('global', {
+       layout: {
+               padding: {
+                       top: 0,
+                       right: 0,
+                       bottom: 0,
+                       left: 0
+               }
+       }
+});
+
+/**
+ * @interface ILayoutItem
+ * @prop {string} position - The position of the item in the chart layout. Possible values are
+ * 'left', 'top', 'right', 'bottom', and 'chartArea'
+ * @prop {number} weight - The weight used to sort the item. Higher weights are further away from the chart area
+ * @prop {boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down
+ * @prop {function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom)
+ * @prop {function} update - Takes two parameters: width and height. Returns size of item
+ * @prop {function} getPadding -  Returns an object with padding on the edges
+ * @prop {number} width - Width of item. Must be valid after update()
+ * @prop {number} height - Height of item. Must be valid after update()
+ * @prop {number} left - Left edge of the item. Set by layout system and cannot be used in update
+ * @prop {number} top - Top edge of the item. Set by layout system and cannot be used in update
+ * @prop {number} right - Right edge of the item. Set by layout system and cannot be used in update
+ * @prop {number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update
+ */
+
+// The layout service is very self explanatory.  It's responsible for the layout within a chart.
+// Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
+// It is this service's responsibility of carrying out that layout.
+var core_layouts = {
+       defaults: {},
+
+       /**
+        * Register a box to a chart.
+        * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
+        * @param {Chart} chart - the chart to use
+        * @param {ILayoutItem} item - the item to add to be layed out
+        */
+       addBox: function(chart, item) {
+               if (!chart.boxes) {
+                       chart.boxes = [];
+               }
+
+               // initialize item with default values
+               item.fullWidth = item.fullWidth || false;
+               item.position = item.position || 'top';
+               item.weight = item.weight || 0;
+
+               chart.boxes.push(item);
+       },
+
+       /**
+        * Remove a layoutItem from a chart
+        * @param {Chart} chart - the chart to remove the box from
+        * @param {ILayoutItem} layoutItem - the item to remove from the layout
+        */
+       removeBox: function(chart, layoutItem) {
+               var index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
+               if (index !== -1) {
+                       chart.boxes.splice(index, 1);
+               }
+       },
+
+       /**
+        * Sets (or updates) options on the given `item`.
+        * @param {Chart} chart - the chart in which the item lives (or will be added to)
+        * @param {ILayoutItem} item - the item to configure with the given options
+        * @param {object} options - the new item options.
+        */
+       configure: function(chart, item, options) {
+               var props = ['fullWidth', 'position', 'weight'];
+               var ilen = props.length;
+               var i = 0;
+               var prop;
+
+               for (; i < ilen; ++i) {
+                       prop = props[i];
+                       if (options.hasOwnProperty(prop)) {
+                               item[prop] = options[prop];
+                       }
+               }
+       },
+
+       /**
+        * Fits boxes of the given chart into the given size by having each box measure itself
+        * then running a fitting algorithm
+        * @param {Chart} chart - the chart
+        * @param {number} width - the width to fit into
+        * @param {number} height - the height to fit into
+        */
+       update: function(chart, width, height) {
+               if (!chart) {
+                       return;
+               }
+
+               var layoutOptions = chart.options.layout || {};
+               var padding = helpers$1.options.toPadding(layoutOptions.padding);
+               var leftPadding = padding.left;
+               var rightPadding = padding.right;
+               var topPadding = padding.top;
+               var bottomPadding = padding.bottom;
+
+               var leftBoxes = filterByPosition(chart.boxes, 'left');
+               var rightBoxes = filterByPosition(chart.boxes, 'right');
+               var topBoxes = filterByPosition(chart.boxes, 'top');
+               var bottomBoxes = filterByPosition(chart.boxes, 'bottom');
+               var chartAreaBoxes = filterByPosition(chart.boxes, 'chartArea');
+
+               // Sort boxes by weight. A higher weight is further away from the chart area
+               sortByWeight(leftBoxes, true);
+               sortByWeight(rightBoxes, false);
+               sortByWeight(topBoxes, true);
+               sortByWeight(bottomBoxes, false);
+
+               var verticalBoxes = leftBoxes.concat(rightBoxes);
+               var horizontalBoxes = topBoxes.concat(bottomBoxes);
+               var outerBoxes = verticalBoxes.concat(horizontalBoxes);
+
+               // Essentially we now have any number of boxes on each of the 4 sides.
+               // Our canvas looks like the following.
+               // The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
+               // B1 is the bottom axis
+               // There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
+               // These locations are single-box locations only, when trying to register a chartArea location that is already taken,
+               // an error will be thrown.
+               //
+               // |----------------------------------------------------|
+               // |                  T1 (Full Width)                   |
+               // |----------------------------------------------------|
+               // |    |    |                 T2                  |    |
+               // |    |----|-------------------------------------|----|
+               // |    |    | C1 |                           | C2 |    |
+               // |    |    |----|                           |----|    |
+               // |    |    |                                     |    |
+               // | L1 | L2 |           ChartArea (C0)            | R1 |
+               // |    |    |                                     |    |
+               // |    |    |----|                           |----|    |
+               // |    |    | C3 |                           | C4 |    |
+               // |    |----|-------------------------------------|----|
+               // |    |    |                 B1                  |    |
+               // |----------------------------------------------------|
+               // |                  B2 (Full Width)                   |
+               // |----------------------------------------------------|
+               //
+               // What we do to find the best sizing, we do the following
+               // 1. Determine the minimum size of the chart area.
+               // 2. Split the remaining width equally between each vertical axis
+               // 3. Split the remaining height equally between each horizontal axis
+               // 4. Give each layout the maximum size it can be. The layout will return it's minimum size
+               // 5. Adjust the sizes of each axis based on it's minimum reported size.
+               // 6. Refit each axis
+               // 7. Position each axis in the final location
+               // 8. Tell the chart the final location of the chart area
+               // 9. Tell any axes that overlay the chart area the positions of the chart area
+
+               // Step 1
+               var chartWidth = width - leftPadding - rightPadding;
+               var chartHeight = height - topPadding - bottomPadding;
+               var chartAreaWidth = chartWidth / 2; // min 50%
+
+               // Step 2
+               var verticalBoxWidth = (width - chartAreaWidth) / verticalBoxes.length;
+
+               // Step 3
+               // TODO re-limit horizontal axis height (this limit has affected only padding calculation since PR 1837)
+               // var horizontalBoxHeight = (height - chartAreaHeight) / horizontalBoxes.length;
+
+               // Step 4
+               var maxChartAreaWidth = chartWidth;
+               var maxChartAreaHeight = chartHeight;
+               var outerBoxSizes = {top: topPadding, left: leftPadding, bottom: bottomPadding, right: rightPadding};
+               var minBoxSizes = [];
+               var maxPadding;
+
+               function getMinimumBoxSize(box) {
+                       var minSize;
+                       var isHorizontal = box.isHorizontal();
+
+                       if (isHorizontal) {
+                               minSize = box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2);
+                               maxChartAreaHeight -= minSize.height;
+                       } else {
+                               minSize = box.update(verticalBoxWidth, maxChartAreaHeight);
+                               maxChartAreaWidth -= minSize.width;
+                       }
+
+                       minBoxSizes.push({
+                               horizontal: isHorizontal,
+                               width: minSize.width,
+                               box: box,
+                       });
+               }
+
+               helpers$1.each(outerBoxes, getMinimumBoxSize);
+
+               // If a horizontal box has padding, we move the left boxes over to avoid ugly charts (see issue #2478)
+               maxPadding = findMaxPadding(outerBoxes);
+
+               // At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
+               // be if the axes are drawn at their minimum sizes.
+               // Steps 5 & 6
+
+               // Function to fit a box
+               function fitBox(box) {
+                       var minBoxSize = helpers$1.findNextWhere(minBoxSizes, function(minBox) {
+                               return minBox.box === box;
+                       });
+
+                       if (minBoxSize) {
+                               if (minBoxSize.horizontal) {
+                                       var scaleMargin = {
+                                               left: Math.max(outerBoxSizes.left, maxPadding.left),
+                                               right: Math.max(outerBoxSizes.right, maxPadding.right),
+                                               top: 0,
+                                               bottom: 0
+                                       };
+
+                                       // Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends
+                                       // on the margin. Sometimes they need to increase in size slightly
+                                       box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
+                               } else {
+                                       box.update(minBoxSize.width, maxChartAreaHeight);
+                               }
+                       }
+               }
+
+               // Update, and calculate the left and right margins for the horizontal boxes
+               helpers$1.each(verticalBoxes, fitBox);
+               addSizeByPosition(verticalBoxes, outerBoxSizes);
+
+               // Set the Left and Right margins for the horizontal boxes
+               helpers$1.each(horizontalBoxes, fitBox);
+               addSizeByPosition(horizontalBoxes, outerBoxSizes);
+
+               function finalFitVerticalBox(box) {
+                       var minBoxSize = helpers$1.findNextWhere(minBoxSizes, function(minSize) {
+                               return minSize.box === box;
+                       });
+
+                       var scaleMargin = {
+                               left: 0,
+                               right: 0,
+                               top: outerBoxSizes.top,
+                               bottom: outerBoxSizes.bottom
+                       };
+
+                       if (minBoxSize) {
+                               box.update(minBoxSize.width, maxChartAreaHeight, scaleMargin);
+                       }
+               }
+
+               // Let the left layout know the final margin
+               helpers$1.each(verticalBoxes, finalFitVerticalBox);
+
+               // Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
+               outerBoxSizes = {top: topPadding, left: leftPadding, bottom: bottomPadding, right: rightPadding};
+               addSizeByPosition(outerBoxes, outerBoxSizes);
+
+               // We may be adding some padding to account for rotated x axis labels
+               var leftPaddingAddition = Math.max(maxPadding.left - outerBoxSizes.left, 0);
+               outerBoxSizes.left += leftPaddingAddition;
+               outerBoxSizes.right += Math.max(maxPadding.right - outerBoxSizes.right, 0);
+
+               var topPaddingAddition = Math.max(maxPadding.top - outerBoxSizes.top, 0);
+               outerBoxSizes.top += topPaddingAddition;
+               outerBoxSizes.bottom += Math.max(maxPadding.bottom - outerBoxSizes.bottom, 0);
+
+               // Figure out if our chart area changed. This would occur if the dataset layout label rotation
+               // changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
+               // without calling `fit` again
+               var newMaxChartAreaHeight = height - outerBoxSizes.top - outerBoxSizes.bottom;
+               var newMaxChartAreaWidth = width - outerBoxSizes.left - outerBoxSizes.right;
+
+               if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) {
+                       helpers$1.each(verticalBoxes, function(box) {
+                               box.height = newMaxChartAreaHeight;
+                       });
+
+                       helpers$1.each(horizontalBoxes, function(box) {
+                               if (!box.fullWidth) {
+                                       box.width = newMaxChartAreaWidth;
+                               }
+                       });
+
+                       maxChartAreaHeight = newMaxChartAreaHeight;
+                       maxChartAreaWidth = newMaxChartAreaWidth;
+               }
+
+               // Step 7 - Position the boxes
+               var left = leftPadding + leftPaddingAddition;
+               var top = topPadding + topPaddingAddition;
+
+               function placeBox(box) {
+                       if (box.isHorizontal()) {
+                               box.left = box.fullWidth ? leftPadding : outerBoxSizes.left;
+                               box.right = box.fullWidth ? width - rightPadding : outerBoxSizes.left + maxChartAreaWidth;
+                               box.top = top;
+                               box.bottom = top + box.height;
+
+                               // Move to next point
+                               top = box.bottom;
+
+                       } else {
+
+                               box.left = left;
+                               box.right = left + box.width;
+                               box.top = outerBoxSizes.top;
+                               box.bottom = outerBoxSizes.top + maxChartAreaHeight;
+
+                               // Move to next point
+                               left = box.right;
+                       }
+               }
+
+               helpers$1.each(leftBoxes.concat(topBoxes), placeBox);
+
+               // Account for chart width and height
+               left += maxChartAreaWidth;
+               top += maxChartAreaHeight;
+
+               helpers$1.each(rightBoxes, placeBox);
+               helpers$1.each(bottomBoxes, placeBox);
+
+               // Step 8
+               chart.chartArea = {
+                       left: outerBoxSizes.left,
+                       top: outerBoxSizes.top,
+                       right: outerBoxSizes.left + maxChartAreaWidth,
+                       bottom: outerBoxSizes.top + maxChartAreaHeight
+               };
+
+               // Step 9
+               helpers$1.each(chartAreaBoxes, function(box) {
+                       box.left = chart.chartArea.left;
+                       box.top = chart.chartArea.top;
+                       box.right = chart.chartArea.right;
+                       box.bottom = chart.chartArea.bottom;
+
+                       box.update(maxChartAreaWidth, maxChartAreaHeight);
+               });
+       }
+};
+
+/**
+ * Platform fallback implementation (minimal).
+ * @see https://github.com/chartjs/Chart.js/pull/4591#issuecomment-319575939
+ */
+
+var platform_basic = {
+       acquireContext: function(item) {
+               if (item && item.canvas) {
+                       // Support for any object associated to a canvas (including a context2d)
+                       item = item.canvas;
+               }
+
+               return item && item.getContext('2d') || null;
+       }
+};
+
+var platform_dom = "/*\n * DOM element rendering detection\n * https://davidwalsh.name/detect-node-insertion\n */\n@keyframes chartjs-render-animation {\n\tfrom { opacity: 0.99; }\n\tto { opacity: 1; }\n}\n\n.chartjs-render-monitor {\n\tanimation: chartjs-render-animation 0.001s;\n}\n\n/*\n * DOM element resizing detection\n * https://github.com/marcj/css-element-queries\n */\n.chartjs-size-monitor,\n.chartjs-size-monitor-expand,\n.chartjs-size-monitor-shrink {\n\tposition: absolute;\n\tdirection: ltr;\n\tleft: 0;\n\ttop: 0;\n\tright: 0;\n\tbottom: 0;\n\toverflow: hidden;\n\tpointer-events: none;\n\tvisibility: hidden;\n\tz-index: -1;\n}\n\n.chartjs-size-monitor-expand > div {\n\tposition: absolute;\n\twidth: 1000000px;\n\theight: 1000000px;\n\tleft: 0;\n\ttop: 0;\n}\n\n.chartjs-size-monitor-shrink > div {\n\tposition: absolute;\n\twidth: 200%;\n\theight: 200%;\n\tleft: 0;\n\ttop: 0;\n}\n";
+
+var platform_dom$1 = /*#__PURE__*/Object.freeze({
+default: platform_dom
+});
+
+function getCjsExportFromNamespace (n) {
+       return n && n.default || n;
+}
+
+var stylesheet = getCjsExportFromNamespace(platform_dom$1);
+
+var EXPANDO_KEY = '$chartjs';
+var CSS_PREFIX = 'chartjs-';
+var CSS_SIZE_MONITOR = CSS_PREFIX + 'size-monitor';
+var CSS_RENDER_MONITOR = CSS_PREFIX + 'render-monitor';
+var CSS_RENDER_ANIMATION = CSS_PREFIX + 'render-animation';
+var ANIMATION_START_EVENTS = ['animationstart', 'webkitAnimationStart'];
+
+/**
+ * DOM event types -> Chart.js event types.
+ * Note: only events with different types are mapped.
+ * @see https://developer.mozilla.org/en-US/docs/Web/Events
+ */
+var EVENT_TYPES = {
+       touchstart: 'mousedown',
+       touchmove: 'mousemove',
+       touchend: 'mouseup',
+       pointerenter: 'mouseenter',
+       pointerdown: 'mousedown',
+       pointermove: 'mousemove',
+       pointerup: 'mouseup',
+       pointerleave: 'mouseout',
+       pointerout: 'mouseout'
+};
+
+/**
+ * The "used" size is the final value of a dimension property after all calculations have
+ * been performed. This method uses the computed style of `element` but returns undefined
+ * if the computed style is not expressed in pixels. That can happen in some cases where
+ * `element` has a size relative to its parent and this last one is not yet displayed,
+ * for example because of `display: none` on a parent node.
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
+ * @returns {number} Size in pixels or undefined if unknown.
+ */
+function readUsedSize(element, property) {
+       var value = helpers$1.getStyle(element, property);
+       var matches = value && value.match(/^(\d+)(\.\d+)?px$/);
+       return matches ? Number(matches[1]) : undefined;
+}
+
+/**
+ * Initializes the canvas style and render size without modifying the canvas display size,
+ * since responsiveness is handled by the controller.resize() method. The config is used
+ * to determine the aspect ratio to apply in case no explicit height has been specified.
+ */
+function initCanvas(canvas, config) {
+       var style = canvas.style;
+
+       // NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
+       // returns null or '' if no explicit value has been set to the canvas attribute.
+       var renderHeight = canvas.getAttribute('height');
+       var renderWidth = canvas.getAttribute('width');
+
+       // Chart.js modifies some canvas values that we want to restore on destroy
+       canvas[EXPANDO_KEY] = {
+               initial: {
+                       height: renderHeight,
+                       width: renderWidth,
+                       style: {
+                               display: style.display,
+                               height: style.height,
+                               width: style.width
+                       }
+               }
+       };
+
+       // Force canvas to display as block to avoid extra space caused by inline
+       // elements, which would interfere with the responsive resize process.
+       // https://github.com/chartjs/Chart.js/issues/2538
+       style.display = style.display || 'block';
+
+       if (renderWidth === null || renderWidth === '') {
+               var displayWidth = readUsedSize(canvas, 'width');
+               if (displayWidth !== undefined) {
+                       canvas.width = displayWidth;
+               }
+       }
+
+       if (renderHeight === null || renderHeight === '') {
+               if (canvas.style.height === '') {
+                       // If no explicit render height and style height, let's apply the aspect ratio,
+                       // which one can be specified by the user but also by charts as default option
+                       // (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
+                       canvas.height = canvas.width / (config.options.aspectRatio || 2);
+               } else {
+                       var displayHeight = readUsedSize(canvas, 'height');
+                       if (displayWidth !== undefined) {
+                               canvas.height = displayHeight;
+                       }
+               }
+       }
+
+       return canvas;
+}
+
+/**
+ * Detects support for options object argument in addEventListener.
+ * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
+ * @private
+ */
+var supportsEventListenerOptions = (function() {
+       var supports = false;
+       try {
+               var options = Object.defineProperty({}, 'passive', {
+                       // eslint-disable-next-line getter-return
+                       get: function() {
+                               supports = true;
+                       }
+               });
+               window.addEventListener('e', null, options);
+       } catch (e) {
+               // continue regardless of error
+       }
+       return supports;
+}());
+
+// Default passive to true as expected by Chrome for 'touchstart' and 'touchend' events.
+// https://github.com/chartjs/Chart.js/issues/4287
+var eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false;
+
+function addListener(node, type, listener) {
+       node.addEventListener(type, listener, eventListenerOptions);
+}
+
+function removeListener(node, type, listener) {
+       node.removeEventListener(type, listener, eventListenerOptions);
+}
+
+function createEvent(type, chart, x, y, nativeEvent) {
+       return {
+               type: type,
+               chart: chart,
+               native: nativeEvent || null,
+               x: x !== undefined ? x : null,
+               y: y !== undefined ? y : null,
+       };
+}
+
+function fromNativeEvent(event, chart) {
+       var type = EVENT_TYPES[event.type] || event.type;
+       var pos = helpers$1.getRelativePosition(event, chart);
+       return createEvent(type, chart, pos.x, pos.y, event);
+}
+
+function throttled(fn, thisArg) {
+       var ticking = false;
+       var args = [];
+
+       return function() {
+               args = Array.prototype.slice.call(arguments);
+               thisArg = thisArg || this;
+
+               if (!ticking) {
+                       ticking = true;
+                       helpers$1.requestAnimFrame.call(window, function() {
+                               ticking = false;
+                               fn.apply(thisArg, args);
+                       });
+               }
+       };
+}
+
+function createDiv(cls) {
+       var el = document.createElement('div');
+       el.className = cls || '';
+       return el;
+}
+
+// Implementation based on https://github.com/marcj/css-element-queries
+function createResizer(handler) {
+       var maxSize = 1000000;
+
+       // NOTE(SB) Don't use innerHTML because it could be considered unsafe.
+       // https://github.com/chartjs/Chart.js/issues/5902
+       var resizer = createDiv(CSS_SIZE_MONITOR);
+       var expand = createDiv(CSS_SIZE_MONITOR + '-expand');
+       var shrink = createDiv(CSS_SIZE_MONITOR + '-shrink');
+
+       expand.appendChild(createDiv());
+       shrink.appendChild(createDiv());
+
+       resizer.appendChild(expand);
+       resizer.appendChild(shrink);
+       resizer._reset = function() {
+               expand.scrollLeft = maxSize;
+               expand.scrollTop = maxSize;
+               shrink.scrollLeft = maxSize;
+               shrink.scrollTop = maxSize;
+       };
+
+       var onScroll = function() {
+               resizer._reset();
+               handler();
+       };
+
+       addListener(expand, 'scroll', onScroll.bind(expand, 'expand'));
+       addListener(shrink, 'scroll', onScroll.bind(shrink, 'shrink'));
+
+       return resizer;
+}
+
+// https://davidwalsh.name/detect-node-insertion
+function watchForRender(node, handler) {
+       var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});
+       var proxy = expando.renderProxy = function(e) {
+               if (e.animationName === CSS_RENDER_ANIMATION) {
+                       handler();
+               }
+       };
+
+       helpers$1.each(ANIMATION_START_EVENTS, function(type) {
+               addListener(node, type, proxy);
+       });
+
+       // #4737: Chrome might skip the CSS animation when the CSS_RENDER_MONITOR class
+       // is removed then added back immediately (same animation frame?). Accessing the
+       // `offsetParent` property will force a reflow and re-evaluate the CSS animation.
+       // https://gist.github.com/paulirish/5d52fb081b3570c81e3a#box-metrics
+       // https://github.com/chartjs/Chart.js/issues/4737
+       expando.reflow = !!node.offsetParent;
+
+       node.classList.add(CSS_RENDER_MONITOR);
+}
+
+function unwatchForRender(node) {
+       var expando = node[EXPANDO_KEY] || {};
+       var proxy = expando.renderProxy;
+
+       if (proxy) {
+               helpers$1.each(ANIMATION_START_EVENTS, function(type) {
+                       removeListener(node, type, proxy);
+               });
+
+               delete expando.renderProxy;
+       }
+
+       node.classList.remove(CSS_RENDER_MONITOR);
+}
+
+function addResizeListener(node, listener, chart) {
+       var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});
+
+       // Let's keep track of this added resizer and thus avoid DOM query when removing it.
+       var resizer = expando.resizer = createResizer(throttled(function() {
+               if (expando.resizer) {
+                       var container = chart.options.maintainAspectRatio && node.parentNode;
+                       var w = container ? container.clientWidth : 0;
+                       listener(createEvent('resize', chart));
+                       if (container && container.clientWidth < w && chart.canvas) {
+                               // If the container size shrank during chart resize, let's assume
+                               // scrollbar appeared. So we resize again with the scrollbar visible -
+                               // effectively making chart smaller and the scrollbar hidden again.
+                               // Because we are inside `throttled`, and currently `ticking`, scroll
+                               // events are ignored during this whole 2 resize process.
+                               // If we assumed wrong and something else happened, we are resizing
+                               // twice in a frame (potential performance issue)
+                               listener(createEvent('resize', chart));
+                       }
+               }
+       }));
+
+       // The resizer needs to be attached to the node parent, so we first need to be
+       // sure that `node` is attached to the DOM before injecting the resizer element.
+       watchForRender(node, function() {
+               if (expando.resizer) {
+                       var container = node.parentNode;
+                       if (container && container !== resizer.parentNode) {
+                               container.insertBefore(resizer, container.firstChild);
+                       }
+
+                       // The container size might have changed, let's reset the resizer state.
+                       resizer._reset();
+               }
+       });
+}
+
+function removeResizeListener(node) {
+       var expando = node[EXPANDO_KEY] || {};
+       var resizer = expando.resizer;
+
+       delete expando.resizer;
+       unwatchForRender(node);
+
+       if (resizer && resizer.parentNode) {
+               resizer.parentNode.removeChild(resizer);
+       }
+}
+
+function injectCSS(platform, css) {
+       // https://stackoverflow.com/q/3922139
+       var style = platform._style || document.createElement('style');
+       if (!platform._style) {
+               platform._style = style;
+               css = '/* Chart.js */\n' + css;
+               style.setAttribute('type', 'text/css');
+               document.getElementsByTagName('head')[0].appendChild(style);
+       }
+
+       style.appendChild(document.createTextNode(css));
+}
+
+var platform_dom$2 = {
+       /**
+        * When `true`, prevents the automatic injection of the stylesheet required to
+        * correctly detect when the chart is added to the DOM and then resized. This
+        * switch has been added to allow external stylesheet (`dist/Chart(.min)?.js`)
+        * to be manually imported to make this library compatible with any CSP.
+        * See https://github.com/chartjs/Chart.js/issues/5208
+        */
+       disableCSSInjection: false,
+
+       /**
+        * This property holds whether this platform is enabled for the current environment.
+        * Currently used by platform.js to select the proper implementation.
+        * @private
+        */
+       _enabled: typeof window !== 'undefined' && typeof document !== 'undefined',
+
+       /**
+        * @private
+        */
+       _ensureLoaded: function() {
+               if (this._loaded) {
+                       return;
+               }
+
+               this._loaded = true;
+
+               // https://github.com/chartjs/Chart.js/issues/5208
+               if (!this.disableCSSInjection) {
+                       injectCSS(this, stylesheet);
+               }
+       },
+
+       acquireContext: function(item, config) {
+               if (typeof item === 'string') {
+                       item = document.getElementById(item);
+               } else if (item.length) {
+                       // Support for array based queries (such as jQuery)
+                       item = item[0];
+               }
+
+               if (item && item.canvas) {
+                       // Support for any object associated to a canvas (including a context2d)
+                       item = item.canvas;
+               }
+
+               // To prevent canvas fingerprinting, some add-ons undefine the getContext
+               // method, for example: https://github.com/kkapsner/CanvasBlocker
+               // https://github.com/chartjs/Chart.js/issues/2807
+               var context = item && item.getContext && item.getContext('2d');
+
+               // Load platform resources on first chart creation, to make possible to change
+               // platform options after importing the library (e.g. `disableCSSInjection`).
+               this._ensureLoaded();
+
+               // `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
+               // inside an iframe or when running in a protected environment. We could guess the
+               // types from their toString() value but let's keep things flexible and assume it's
+               // a sufficient condition if the item has a context2D which has item as `canvas`.
+               // https://github.com/chartjs/Chart.js/issues/3887
+               // https://github.com/chartjs/Chart.js/issues/4102
+               // https://github.com/chartjs/Chart.js/issues/4152
+               if (context && context.canvas === item) {
+                       initCanvas(item, config);
+                       return context;
+               }
+
+               return null;
+       },
+
+       releaseContext: function(context) {
+               var canvas = context.canvas;
+               if (!canvas[EXPANDO_KEY]) {
+                       return;
+               }
+
+               var initial = canvas[EXPANDO_KEY].initial;
+               ['height', 'width'].forEach(function(prop) {
+                       var value = initial[prop];
+                       if (helpers$1.isNullOrUndef(value)) {
+                               canvas.removeAttribute(prop);
+                       } else {
+                               canvas.setAttribute(prop, value);
+                       }
+               });
+
+               helpers$1.each(initial.style || {}, function(value, key) {
+                       canvas.style[key] = value;
+               });
+
+               // The canvas render size might have been changed (and thus the state stack discarded),
+               // we can't use save() and restore() to restore the initial state. So make sure that at
+               // least the canvas context is reset to the default state by setting the canvas width.
+               // https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
+               // eslint-disable-next-line no-self-assign
+               canvas.width = canvas.width;
+
+               delete canvas[EXPANDO_KEY];
+       },
+
+       addEventListener: function(chart, type, listener) {
+               var canvas = chart.canvas;
+               if (type === 'resize') {
+                       // Note: the resize event is not supported on all browsers.
+                       addResizeListener(canvas, listener, chart);
+                       return;
+               }
+
+               var expando = listener[EXPANDO_KEY] || (listener[EXPANDO_KEY] = {});
+               var proxies = expando.proxies || (expando.proxies = {});
+               var proxy = proxies[chart.id + '_' + type] = function(event) {
+                       listener(fromNativeEvent(event, chart));
+               };
+
+               addListener(canvas, type, proxy);
+       },
+
+       removeEventListener: function(chart, type, listener) {
+               var canvas = chart.canvas;
+               if (type === 'resize') {
+                       // Note: the resize event is not supported on all browsers.
+                       removeResizeListener(canvas);
+                       return;
+               }
+
+               var expando = listener[EXPANDO_KEY] || {};
+               var proxies = expando.proxies || {};
+               var proxy = proxies[chart.id + '_' + type];
+               if (!proxy) {
+                       return;
+               }
+
+               removeListener(canvas, type, proxy);
+       }
+};
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, use EventTarget.addEventListener instead.
+ * EventTarget.addEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
+ * @function Chart.helpers.addEvent
+ * @deprecated since version 2.7.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers$1.addEvent = addListener;
+
+/**
+ * Provided for backward compatibility, use EventTarget.removeEventListener instead.
+ * EventTarget.removeEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
+ * @function Chart.helpers.removeEvent
+ * @deprecated since version 2.7.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers$1.removeEvent = removeListener;
+
+// @TODO Make possible to select another platform at build time.
+var implementation = platform_dom$2._enabled ? platform_dom$2 : platform_basic;
+
+/**
+ * @namespace Chart.platform
+ * @see https://chartjs.gitbooks.io/proposals/content/Platform.html
+ * @since 2.4.0
+ */
+var platform = helpers$1.extend({
+       /**
+        * @since 2.7.0
+        */
+       initialize: function() {},
+
+       /**
+        * Called at chart construction time, returns a context2d instance implementing
+        * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
+        * @param {*} item - The native item from which to acquire context (platform specific)
+        * @param {object} options - The chart options
+        * @returns {CanvasRenderingContext2D} context2d instance
+        */
+       acquireContext: function() {},
+
+       /**
+        * Called at chart destruction time, releases any resources associated to the context
+        * previously returned by the acquireContext() method.
+        * @param {CanvasRenderingContext2D} context - The context2d instance
+        * @returns {boolean} true if the method succeeded, else false
+        */
+       releaseContext: function() {},
+
+       /**
+        * Registers the specified listener on the given chart.
+        * @param {Chart} chart - Chart from which to listen for event
+        * @param {string} type - The ({@link IEvent}) type to listen for
+        * @param {function} listener - Receives a notification (an object that implements
+        * the {@link IEvent} interface) when an event of the specified type occurs.
+        */
+       addEventListener: function() {},
+
+       /**
+        * Removes the specified listener previously registered with addEventListener.
+        * @param {Chart} chart - Chart from which to remove the listener
+        * @param {string} type - The ({@link IEvent}) type to remove
+        * @param {function} listener - The listener function to remove from the event target.
+        */
+       removeEventListener: function() {}
+
+}, implementation);
+
+core_defaults._set('global', {
+       plugins: {}
+});
+
+/**
+ * The plugin service singleton
+ * @namespace Chart.plugins
+ * @since 2.1.0
+ */
+var core_plugins = {
+       /**
+        * Globally registered plugins.
+        * @private
+        */
+       _plugins: [],
+
+       /**
+        * This identifier is used to invalidate the descriptors cache attached to each chart
+        * when a global plugin is registered or unregistered. In this case, the cache ID is
+        * incremented and descriptors are regenerated during following API calls.
+        * @private
+        */
+       _cacheId: 0,
+
+       /**
+        * Registers the given plugin(s) if not already registered.
+        * @param {IPlugin[]|IPlugin} plugins plugin instance(s).
+        */
+       register: function(plugins) {
+               var p = this._plugins;
+               ([]).concat(plugins).forEach(function(plugin) {
+                       if (p.indexOf(plugin) === -1) {
+                               p.push(plugin);
+                       }
+               });
+
+               this._cacheId++;
+       },
+
+       /**
+        * Unregisters the given plugin(s) only if registered.
+        * @param {IPlugin[]|IPlugin} plugins plugin instance(s).
+        */
+       unregister: function(plugins) {
+               var p = this._plugins;
+               ([]).concat(plugins).forEach(function(plugin) {
+                       var idx = p.indexOf(plugin);
+                       if (idx !== -1) {
+                               p.splice(idx, 1);
+                       }
+               });
+
+               this._cacheId++;
+       },
+
+       /**
+        * Remove all registered plugins.
+        * @since 2.1.5
+        */
+       clear: function() {
+               this._plugins = [];
+               this._cacheId++;
+       },
+
+       /**
+        * Returns the number of registered plugins?
+        * @returns {number}
+        * @since 2.1.5
+        */
+       count: function() {
+               return this._plugins.length;
+       },
+
+       /**
+        * Returns all registered plugin instances.
+        * @returns {IPlugin[]} array of plugin objects.
+        * @since 2.1.5
+        */
+       getAll: function() {
+               return this._plugins;
+       },
+
+       /**
+        * Calls enabled plugins for `chart` on the specified hook and with the given args.
+        * This method immediately returns as soon as a plugin explicitly returns false. The
+        * returned value can be used, for instance, to interrupt the current action.
+        * @param {Chart} chart - The chart instance for which plugins should be called.
+        * @param {string} hook - The name of the plugin method to call (e.g. 'beforeUpdate').
+        * @param {Array} [args] - Extra arguments to apply to the hook call.
+        * @returns {boolean} false if any of the plugins return false, else returns true.
+        */
+       notify: function(chart, hook, args) {
+               var descriptors = this.descriptors(chart);
+               var ilen = descriptors.length;
+               var i, descriptor, plugin, params, method;
+
+               for (i = 0; i < ilen; ++i) {
+                       descriptor = descriptors[i];
+                       plugin = descriptor.plugin;
+                       method = plugin[hook];
+                       if (typeof method === 'function') {
+                               params = [chart].concat(args || []);
+                               params.push(descriptor.options);
+                               if (method.apply(plugin, params) === false) {
+                                       return false;
+                               }
+                       }
+               }
+
+               return true;
+       },
+
+       /**
+        * Returns descriptors of enabled plugins for the given chart.
+        * @returns {object[]} [{ plugin, options }]
+        * @private
+        */
+       descriptors: function(chart) {
+               var cache = chart.$plugins || (chart.$plugins = {});
+               if (cache.id === this._cacheId) {
+                       return cache.descriptors;
+               }
+
+               var plugins = [];
+               var descriptors = [];
+               var config = (chart && chart.config) || {};
+               var options = (config.options && config.options.plugins) || {};
+
+               this._plugins.concat(config.plugins || []).forEach(function(plugin) {
+                       var idx = plugins.indexOf(plugin);
+                       if (idx !== -1) {
+                               return;
+                       }
+
+                       var id = plugin.id;
+                       var opts = options[id];
+                       if (opts === false) {
+                               return;
+                       }
+
+                       if (opts === true) {
+                               opts = helpers$1.clone(core_defaults.global.plugins[id]);
+                       }
+
+                       plugins.push(plugin);
+                       descriptors.push({
+                               plugin: plugin,
+                               options: opts || {}
+                       });
+               });
+
+               cache.descriptors = descriptors;
+               cache.id = this._cacheId;
+               return descriptors;
+       },
+
+       /**
+        * Invalidates cache for the given chart: descriptors hold a reference on plugin option,
+        * but in some cases, this reference can be changed by the user when updating options.
+        * https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
+        * @private
+        */
+       _invalidate: function(chart) {
+               delete chart.$plugins;
+       }
+};
+
+var core_scaleService = {
+       // Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
+       // use the new chart options to grab the correct scale
+       constructors: {},
+       // Use a registration function so that we can move to an ES6 map when we no longer need to support
+       // old browsers
+
+       // Scale config defaults
+       defaults: {},
+       registerScaleType: function(type, scaleConstructor, scaleDefaults) {
+               this.constructors[type] = scaleConstructor;
+               this.defaults[type] = helpers$1.clone(scaleDefaults);
+       },
+       getScaleConstructor: function(type) {
+               return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
+       },
+       getScaleDefaults: function(type) {
+               // Return the scale defaults merged with the global settings so that we always use the latest ones
+               return this.defaults.hasOwnProperty(type) ? helpers$1.merge({}, [core_defaults.scale, this.defaults[type]]) : {};
+       },
+       updateScaleDefaults: function(type, additions) {
+               var me = this;
+               if (me.defaults.hasOwnProperty(type)) {
+                       me.defaults[type] = helpers$1.extend(me.defaults[type], additions);
+               }
+       },
+       addScalesToLayout: function(chart) {
+               // Adds each scale to the chart.boxes array to be sized accordingly
+               helpers$1.each(chart.scales, function(scale) {
+                       // Set ILayoutItem parameters for backwards compatibility
+                       scale.fullWidth = scale.options.fullWidth;
+                       scale.position = scale.options.position;
+                       scale.weight = scale.options.weight;
+                       core_layouts.addBox(chart, scale);
+               });
+       }
+};
+
+var valueOrDefault$7 = helpers$1.valueOrDefault;
+
+core_defaults._set('global', {
+       tooltips: {
+               enabled: true,
+               custom: null,
+               mode: 'nearest',
+               position: 'average',
+               intersect: true,
+               backgroundColor: 'rgba(0,0,0,0.8)',
+               titleFontStyle: 'bold',
+               titleSpacing: 2,
+               titleMarginBottom: 6,
+               titleFontColor: '#fff',
+               titleAlign: 'left',
+               bodySpacing: 2,
+               bodyFontColor: '#fff',
+               bodyAlign: 'left',
+               footerFontStyle: 'bold',
+               footerSpacing: 2,
+               footerMarginTop: 6,
+               footerFontColor: '#fff',
+               footerAlign: 'left',
+               yPadding: 6,
+               xPadding: 6,
+               caretPadding: 2,
+               caretSize: 5,
+               cornerRadius: 6,
+               multiKeyBackground: '#fff',
+               displayColors: true,
+               borderColor: 'rgba(0,0,0,0)',
+               borderWidth: 0,
+               callbacks: {
+                       // Args are: (tooltipItems, data)
+                       beforeTitle: helpers$1.noop,
+                       title: function(tooltipItems, data) {
+                               var title = '';
+                               var labels = data.labels;
+                               var labelCount = labels ? labels.length : 0;
+
+                               if (tooltipItems.length > 0) {
+                                       var item = tooltipItems[0];
+                                       if (item.label) {
+                                               title = item.label;
+                                       } else if (item.xLabel) {
+                                               title = item.xLabel;
+                                       } else if (labelCount > 0 && item.index < labelCount) {
+                                               title = labels[item.index];
+                                       }
+                               }
+
+                               return title;
+                       },
+                       afterTitle: helpers$1.noop,
+
+                       // Args are: (tooltipItems, data)
+                       beforeBody: helpers$1.noop,
+
+                       // Args are: (tooltipItem, data)
+                       beforeLabel: helpers$1.noop,
+                       label: function(tooltipItem, data) {
+                               var label = data.datasets[tooltipItem.datasetIndex].label || '';
+
+                               if (label) {
+                                       label += ': ';
+                               }
+                               if (!helpers$1.isNullOrUndef(tooltipItem.value)) {
+                                       label += tooltipItem.value;
+                               } else {
+                                       label += tooltipItem.yLabel;
+                               }
+                               return label;
+                       },
+                       labelColor: function(tooltipItem, chart) {
+                               var meta = chart.getDatasetMeta(tooltipItem.datasetIndex);
+                               var activeElement = meta.data[tooltipItem.index];
+                               var view = activeElement._view;
+                               return {
+                                       borderColor: view.borderColor,
+                                       backgroundColor: view.backgroundColor
+                               };
+                       },
+                       labelTextColor: function() {
+                               return this._options.bodyFontColor;
+                       },
+                       afterLabel: helpers$1.noop,
+
+                       // Args are: (tooltipItems, data)
+                       afterBody: helpers$1.noop,
+
+                       // Args are: (tooltipItems, data)
+                       beforeFooter: helpers$1.noop,
+                       footer: helpers$1.noop,
+                       afterFooter: helpers$1.noop
+               }
+       }
+});
+
+var positioners = {
+       /**
+        * Average mode places the tooltip at the average position of the elements shown
+        * @function Chart.Tooltip.positioners.average
+        * @param elements {ChartElement[]} the elements being displayed in the tooltip
+        * @returns {object} tooltip position
+        */
+       average: function(elements) {
+               if (!elements.length) {
+                       return false;
+               }
+
+               var i, len;
+               var x = 0;
+               var y = 0;
+               var count = 0;
+
+               for (i = 0, len = elements.length; i < len; ++i) {
+                       var el = elements[i];
+                       if (el && el.hasValue()) {
+                               var pos = el.tooltipPosition();
+                               x += pos.x;
+                               y += pos.y;
+                               ++count;
+                       }
+               }
+
+               return {
+                       x: x / count,
+                       y: y / count
+               };
+       },
+
+       /**
+        * Gets the tooltip position nearest of the item nearest to the event position
+        * @function Chart.Tooltip.positioners.nearest
+        * @param elements {Chart.Element[]} the tooltip elements
+        * @param eventPosition {object} the position of the event in canvas coordinates
+        * @returns {object} the tooltip position
+        */
+       nearest: function(elements, eventPosition) {
+               var x = eventPosition.x;
+               var y = eventPosition.y;
+               var minDistance = Number.POSITIVE_INFINITY;
+               var i, len, nearestElement;
+
+               for (i = 0, len = elements.length; i < len; ++i) {
+                       var el = elements[i];
+                       if (el && el.hasValue()) {
+                               var center = el.getCenterPoint();
+                               var d = helpers$1.distanceBetweenPoints(eventPosition, center);
+
+                               if (d < minDistance) {
+                                       minDistance = d;
+                                       nearestElement = el;
+                               }
+                       }
+               }
+
+               if (nearestElement) {
+                       var tp = nearestElement.tooltipPosition();
+                       x = tp.x;
+                       y = tp.y;
+               }
+
+               return {
+                       x: x,
+                       y: y
+               };
+       }
+};
+
+// Helper to push or concat based on if the 2nd parameter is an array or not
+function pushOrConcat(base, toPush) {
+       if (toPush) {
+               if (helpers$1.isArray(toPush)) {
+                       // base = base.concat(toPush);
+                       Array.prototype.push.apply(base, toPush);
+               } else {
+                       base.push(toPush);
+               }
+       }
+
+       return base;
+}
+
+/**
+ * Returns array of strings split by newline
+ * @param {string} value - The value to split by newline.
+ * @returns {string[]} value if newline present - Returned from String split() method
+ * @function
+ */
+function splitNewlines(str) {
+       if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) {
+               return str.split('\n');
+       }
+       return str;
+}
+
+
+/**
+ * Private helper to create a tooltip item model
+ * @param element - the chart element (point, arc, bar) to create the tooltip item for
+ * @return new tooltip item
+ */
+function createTooltipItem(element) {
+       var xScale = element._xScale;
+       var yScale = element._yScale || element._scale; // handle radar || polarArea charts
+       var index = element._index;
+       var datasetIndex = element._datasetIndex;
+       var controller = element._chart.getDatasetMeta(datasetIndex).controller;
+       var indexScale = controller._getIndexScale();
+       var valueScale = controller._getValueScale();
+
+       return {
+               xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '',
+               yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '',
+               label: indexScale ? '' + indexScale.getLabelForIndex(index, datasetIndex) : '',
+               value: valueScale ? '' + valueScale.getLabelForIndex(index, datasetIndex) : '',
+               index: index,
+               datasetIndex: datasetIndex,
+               x: element._model.x,
+               y: element._model.y
+       };
+}
+
+/**
+ * Helper to get the reset model for the tooltip
+ * @param tooltipOpts {object} the tooltip options
+ */
+function getBaseModel(tooltipOpts) {
+       var globalDefaults = core_defaults.global;
+
+       return {
+               // Positioning
+               xPadding: tooltipOpts.xPadding,
+               yPadding: tooltipOpts.yPadding,
+               xAlign: tooltipOpts.xAlign,
+               yAlign: tooltipOpts.yAlign,
+
+               // Body
+               bodyFontColor: tooltipOpts.bodyFontColor,
+               _bodyFontFamily: valueOrDefault$7(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
+               _bodyFontStyle: valueOrDefault$7(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
+               _bodyAlign: tooltipOpts.bodyAlign,
+               bodyFontSize: valueOrDefault$7(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
+               bodySpacing: tooltipOpts.bodySpacing,
+
+               // Title
+               titleFontColor: tooltipOpts.titleFontColor,
+               _titleFontFamily: valueOrDefault$7(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
+               _titleFontStyle: valueOrDefault$7(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
+               titleFontSize: valueOrDefault$7(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
+               _titleAlign: tooltipOpts.titleAlign,
+               titleSpacing: tooltipOpts.titleSpacing,
+               titleMarginBottom: tooltipOpts.titleMarginBottom,
+
+               // Footer
+               footerFontColor: tooltipOpts.footerFontColor,
+               _footerFontFamily: valueOrDefault$7(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
+               _footerFontStyle: valueOrDefault$7(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
+               footerFontSize: valueOrDefault$7(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize),
+               _footerAlign: tooltipOpts.footerAlign,
+               footerSpacing: tooltipOpts.footerSpacing,
+               footerMarginTop: tooltipOpts.footerMarginTop,
+
+               // Appearance
+               caretSize: tooltipOpts.caretSize,
+               cornerRadius: tooltipOpts.cornerRadius,
+               backgroundColor: tooltipOpts.backgroundColor,
+               opacity: 0,
+               legendColorBackground: tooltipOpts.multiKeyBackground,
+               displayColors: tooltipOpts.displayColors,
+               borderColor: tooltipOpts.borderColor,
+               borderWidth: tooltipOpts.borderWidth
+       };
+}
+
+/**
+ * Get the size of the tooltip
+ */
+function getTooltipSize(tooltip, model) {
+       var ctx = tooltip._chart.ctx;
+
+       var height = model.yPadding * 2; // Tooltip Padding
+       var width = 0;
+
+       // Count of all lines in the body
+       var body = model.body;
+       var combinedBodyLength = body.reduce(function(count, bodyItem) {
+               return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length;
+       }, 0);
+       combinedBodyLength += model.beforeBody.length + model.afterBody.length;
+
+       var titleLineCount = model.title.length;
+       var footerLineCount = model.footer.length;
+       var titleFontSize = model.titleFontSize;
+       var bodyFontSize = model.bodyFontSize;
+       var footerFontSize = model.footerFontSize;
+
+       height += titleLineCount * titleFontSize; // Title Lines
+       height += titleLineCount ? (titleLineCount - 1) * model.titleSpacing : 0; // Title Line Spacing
+       height += titleLineCount ? model.titleMarginBottom : 0; // Title's bottom Margin
+       height += combinedBodyLength * bodyFontSize; // Body Lines
+       height += combinedBodyLength ? (combinedBodyLength - 1) * model.bodySpacing : 0; // Body Line Spacing
+       height += footerLineCount ? model.footerMarginTop : 0; // Footer Margin
+       height += footerLineCount * (footerFontSize); // Footer Lines
+       height += footerLineCount ? (footerLineCount - 1) * model.footerSpacing : 0; // Footer Line Spacing
+
+       // Title width
+       var widthPadding = 0;
+       var maxLineWidth = function(line) {
+               width = Math.max(width, ctx.measureText(line).width + widthPadding);
+       };
+
+       ctx.font = helpers$1.fontString(titleFontSize, model._titleFontStyle, model._titleFontFamily);
+       helpers$1.each(model.title, maxLineWidth);
+
+       // Body width
+       ctx.font = helpers$1.fontString(bodyFontSize, model._bodyFontStyle, model._bodyFontFamily);
+       helpers$1.each(model.beforeBody.concat(model.afterBody), maxLineWidth);
+
+       // Body lines may include some extra width due to the color box
+       widthPadding = model.displayColors ? (bodyFontSize + 2) : 0;
+       helpers$1.each(body, function(bodyItem) {
+               helpers$1.each(bodyItem.before, maxLineWidth);
+               helpers$1.each(bodyItem.lines, maxLineWidth);
+               helpers$1.each(bodyItem.after, maxLineWidth);
+       });
+
+       // Reset back to 0
+       widthPadding = 0;
+
+       // Footer width
+       ctx.font = helpers$1.fontString(footerFontSize, model._footerFontStyle, model._footerFontFamily);
+       helpers$1.each(model.footer, maxLineWidth);
+
+       // Add padding
+       width += 2 * model.xPadding;
+
+       return {
+               width: width,
+               height: height
+       };
+}
+
+/**
+ * Helper to get the alignment of a tooltip given the size
+ */
+function determineAlignment(tooltip, size) {
+       var model = tooltip._model;
+       var chart = tooltip._chart;
+       var chartArea = tooltip._chart.chartArea;
+       var xAlign = 'center';
+       var yAlign = 'center';
+
+       if (model.y < size.height) {
+               yAlign = 'top';
+       } else if (model.y > (chart.height - size.height)) {
+               yAlign = 'bottom';
+       }
+
+       var lf, rf; // functions to determine left, right alignment
+       var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart
+       var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges
+       var midX = (chartArea.left + chartArea.right) / 2;
+       var midY = (chartArea.top + chartArea.bottom) / 2;
+
+       if (yAlign === 'center') {
+               lf = function(x) {
+                       return x <= midX;
+               };
+               rf = function(x) {
+                       return x > midX;
+               };
+       } else {
+               lf = function(x) {
+                       return x <= (size.width / 2);
+               };
+               rf = function(x) {
+                       return x >= (chart.width - (size.width / 2));
+               };
+       }
+
+       olf = function(x) {
+               return x + size.width + model.caretSize + model.caretPadding > chart.width;
+       };
+       orf = function(x) {
+               return x - size.width - model.caretSize - model.caretPadding < 0;
+       };
+       yf = function(y) {
+               return y <= midY ? 'top' : 'bottom';
+       };
+
+       if (lf(model.x)) {
+               xAlign = 'left';
+
+               // Is tooltip too wide and goes over the right side of the chart.?
+               if (olf(model.x)) {
+                       xAlign = 'center';
+                       yAlign = yf(model.y);
+               }
+       } else if (rf(model.x)) {
+               xAlign = 'right';
+
+               // Is tooltip too wide and goes outside left edge of canvas?
+               if (orf(model.x)) {
+                       xAlign = 'center';
+                       yAlign = yf(model.y);
+               }
+       }
+
+       var opts = tooltip._options;
+       return {
+               xAlign: opts.xAlign ? opts.xAlign : xAlign,
+               yAlign: opts.yAlign ? opts.yAlign : yAlign
+       };
+}
+
+/**
+ * Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
+ */
+function getBackgroundPoint(vm, size, alignment, chart) {
+       // Background Position
+       var x = vm.x;
+       var y = vm.y;
+
+       var caretSize = vm.caretSize;
+       var caretPadding = vm.caretPadding;
+       var cornerRadius = vm.cornerRadius;
+       var xAlign = alignment.xAlign;
+       var yAlign = alignment.yAlign;
+       var paddingAndSize = caretSize + caretPadding;
+       var radiusAndPadding = cornerRadius + caretPadding;
+
+       if (xAlign === 'right') {
+               x -= size.width;
+       } else if (xAlign === 'center') {
+               x -= (size.width / 2);
+               if (x + size.width > chart.width) {
+                       x = chart.width - size.width;
+               }
+               if (x < 0) {
+                       x = 0;
+               }
+       }
+
+       if (yAlign === 'top') {
+               y += paddingAndSize;
+       } else if (yAlign === 'bottom') {
+               y -= size.height + paddingAndSize;
+       } else {
+               y -= (size.height / 2);
+       }
+
+       if (yAlign === 'center') {
+               if (xAlign === 'left') {
+                       x += paddingAndSize;
+               } else if (xAlign === 'right') {
+                       x -= paddingAndSize;
+               }
+       } else if (xAlign === 'left') {
+               x -= radiusAndPadding;
+       } else if (xAlign === 'right') {
+               x += radiusAndPadding;
+       }
+
+       return {
+               x: x,
+               y: y
+       };
+}
+
+function getAlignedX(vm, align) {
+       return align === 'center'
+               ? vm.x + vm.width / 2
+               : align === 'right'
+                       ? vm.x + vm.width - vm.xPadding
+                       : vm.x + vm.xPadding;
+}
+
+/**
+ * Helper to build before and after body lines
+ */
+function getBeforeAfterBodyLines(callback) {
+       return pushOrConcat([], splitNewlines(callback));
+}
+
+var exports$3 = core_element.extend({
+       initialize: function() {
+               this._model = getBaseModel(this._options);
+               this._lastActive = [];
+       },
+
+       // Get the title
+       // Args are: (tooltipItem, data)
+       getTitle: function() {
+               var me = this;
+               var opts = me._options;
+               var callbacks = opts.callbacks;
+
+               var beforeTitle = callbacks.beforeTitle.apply(me, arguments);
+               var title = callbacks.title.apply(me, arguments);
+               var afterTitle = callbacks.afterTitle.apply(me, arguments);
+
+               var lines = [];
+               lines = pushOrConcat(lines, splitNewlines(beforeTitle));
+               lines = pushOrConcat(lines, splitNewlines(title));
+               lines = pushOrConcat(lines, splitNewlines(afterTitle));
+
+               return lines;
+       },
+
+       // Args are: (tooltipItem, data)
+       getBeforeBody: function() {
+               return getBeforeAfterBodyLines(this._options.callbacks.beforeBody.apply(this, arguments));
+       },
+
+       // Args are: (tooltipItem, data)
+       getBody: function(tooltipItems, data) {
+               var me = this;
+               var callbacks = me._options.callbacks;
+               var bodyItems = [];
+
+               helpers$1.each(tooltipItems, function(tooltipItem) {
+                       var bodyItem = {
+                               before: [],
+                               lines: [],
+                               after: []
+                       };
+                       pushOrConcat(bodyItem.before, splitNewlines(callbacks.beforeLabel.call(me, tooltipItem, data)));
+                       pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data));
+                       pushOrConcat(bodyItem.after, splitNewlines(callbacks.afterLabel.call(me, tooltipItem, data)));
+
+                       bodyItems.push(bodyItem);
+               });
+
+               return bodyItems;
+       },
+
+       // Args are: (tooltipItem, data)
+       getAfterBody: function() {
+               return getBeforeAfterBodyLines(this._options.callbacks.afterBody.apply(this, arguments));
+       },
+
+       // Get the footer and beforeFooter and afterFooter lines
+       // Args are: (tooltipItem, data)
+       getFooter: function() {
+               var me = this;
+               var callbacks = me._options.callbacks;
+
+               var beforeFooter = callbacks.beforeFooter.apply(me, arguments);
+               var footer = callbacks.footer.apply(me, arguments);
+               var afterFooter = callbacks.afterFooter.apply(me, arguments);
+
+               var lines = [];
+               lines = pushOrConcat(lines, splitNewlines(beforeFooter));
+               lines = pushOrConcat(lines, splitNewlines(footer));
+               lines = pushOrConcat(lines, splitNewlines(afterFooter));
+
+               return lines;
+       },
+
+       update: function(changed) {
+               var me = this;
+               var opts = me._options;
+
+               // Need to regenerate the model because its faster than using extend and it is necessary due to the optimization in Chart.Element.transition
+               // that does _view = _model if ease === 1. This causes the 2nd tooltip update to set properties in both the view and model at the same time
+               // which breaks any animations.
+               var existingModel = me._model;
+               var model = me._model = getBaseModel(opts);
+               var active = me._active;
+
+               var data = me._data;
+
+               // In the case where active.length === 0 we need to keep these at existing values for good animations
+               var alignment = {
+                       xAlign: existingModel.xAlign,
+                       yAlign: existingModel.yAlign
+               };
+               var backgroundPoint = {
+                       x: existingModel.x,
+                       y: existingModel.y
+               };
+               var tooltipSize = {
+                       width: existingModel.width,
+                       height: existingModel.height
+               };
+               var tooltipPosition = {
+                       x: existingModel.caretX,
+                       y: existingModel.caretY
+               };
+
+               var i, len;
+
+               if (active.length) {
+                       model.opacity = 1;
+
+                       var labelColors = [];
+                       var labelTextColors = [];
+                       tooltipPosition = positioners[opts.position].call(me, active, me._eventPosition);
+
+                       var tooltipItems = [];
+                       for (i = 0, len = active.length; i < len; ++i) {
+                               tooltipItems.push(createTooltipItem(active[i]));
+                       }
+
+                       // If the user provided a filter function, use it to modify the tooltip items
+                       if (opts.filter) {
+                               tooltipItems = tooltipItems.filter(function(a) {
+                                       return opts.filter(a, data);
+                               });
+                       }
+
+                       // If the user provided a sorting function, use it to modify the tooltip items
+                       if (opts.itemSort) {
+                               tooltipItems = tooltipItems.sort(function(a, b) {
+                                       return opts.itemSort(a, b, data);
+                               });
+                       }
+
+                       // Determine colors for boxes
+                       helpers$1.each(tooltipItems, function(tooltipItem) {
+                               labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, me._chart));
+                               labelTextColors.push(opts.callbacks.labelTextColor.call(me, tooltipItem, me._chart));
+                       });
+
+
+                       // Build the Text Lines
+                       model.title = me.getTitle(tooltipItems, data);
+                       model.beforeBody = me.getBeforeBody(tooltipItems, data);
+                       model.body = me.getBody(tooltipItems, data);
+                       model.afterBody = me.getAfterBody(tooltipItems, data);
+                       model.footer = me.getFooter(tooltipItems, data);
+
+                       // Initial positioning and colors
+                       model.x = tooltipPosition.x;
+                       model.y = tooltipPosition.y;
+                       model.caretPadding = opts.caretPadding;
+                       model.labelColors = labelColors;
+                       model.labelTextColors = labelTextColors;
+
+                       // data points
+                       model.dataPoints = tooltipItems;
+
+                       // We need to determine alignment of the tooltip
+                       tooltipSize = getTooltipSize(this, model);
+                       alignment = determineAlignment(this, tooltipSize);
+                       // Final Size and Position
+                       backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment, me._chart);
+               } else {
+                       model.opacity = 0;
+               }
+
+               model.xAlign = alignment.xAlign;
+               model.yAlign = alignment.yAlign;
+               model.x = backgroundPoint.x;
+               model.y = backgroundPoint.y;
+               model.width = tooltipSize.width;
+               model.height = tooltipSize.height;
+
+               // Point where the caret on the tooltip points to
+               model.caretX = tooltipPosition.x;
+               model.caretY = tooltipPosition.y;
+
+               me._model = model;
+
+               if (changed && opts.custom) {
+                       opts.custom.call(me, model);
+               }
+
+               return me;
+       },
+
+       drawCaret: function(tooltipPoint, size) {
+               var ctx = this._chart.ctx;
+               var vm = this._view;
+               var caretPosition = this.getCaretPosition(tooltipPoint, size, vm);
+
+               ctx.lineTo(caretPosition.x1, caretPosition.y1);
+               ctx.lineTo(caretPosition.x2, caretPosition.y2);
+               ctx.lineTo(caretPosition.x3, caretPosition.y3);
+       },
+       getCaretPosition: function(tooltipPoint, size, vm) {
+               var x1, x2, x3, y1, y2, y3;
+               var caretSize = vm.caretSize;
+               var cornerRadius = vm.cornerRadius;
+               var xAlign = vm.xAlign;
+               var yAlign = vm.yAlign;
+               var ptX = tooltipPoint.x;
+               var ptY = tooltipPoint.y;
+               var width = size.width;
+               var height = size.height;
+
+               if (yAlign === 'center') {
+                       y2 = ptY + (height / 2);
+
+                       if (xAlign === 'left') {
+                               x1 = ptX;
+                               x2 = x1 - caretSize;
+                               x3 = x1;
+
+                               y1 = y2 + caretSize;
+                               y3 = y2 - caretSize;
+                       } else {
+                               x1 = ptX + width;
+                               x2 = x1 + caretSize;
+                               x3 = x1;
+
+                               y1 = y2 - caretSize;
+                               y3 = y2 + caretSize;
+                       }
+               } else {
+                       if (xAlign === 'left') {
+                               x2 = ptX + cornerRadius + (caretSize);
+                               x1 = x2 - caretSize;
+                               x3 = x2 + caretSize;
+                       } else if (xAlign === 'right') {
+                               x2 = ptX + width - cornerRadius - caretSize;
+                               x1 = x2 - caretSize;
+                               x3 = x2 + caretSize;
+                       } else {
+                               x2 = vm.caretX;
+                               x1 = x2 - caretSize;
+                               x3 = x2 + caretSize;
+                       }
+                       if (yAlign === 'top') {
+                               y1 = ptY;
+                               y2 = y1 - caretSize;
+                               y3 = y1;
+                       } else {
+                               y1 = ptY + height;
+                               y2 = y1 + caretSize;
+                               y3 = y1;
+                               // invert drawing order
+                               var tmp = x3;
+                               x3 = x1;
+                               x1 = tmp;
+                       }
+               }
+               return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3};
+       },
+
+       drawTitle: function(pt, vm, ctx) {
+               var title = vm.title;
+
+               if (title.length) {
+                       pt.x = getAlignedX(vm, vm._titleAlign);
+
+                       ctx.textAlign = vm._titleAlign;
+                       ctx.textBaseline = 'top';
+
+                       var titleFontSize = vm.titleFontSize;
+                       var titleSpacing = vm.titleSpacing;
+
+                       ctx.fillStyle = vm.titleFontColor;
+                       ctx.font = helpers$1.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
+
+                       var i, len;
+                       for (i = 0, len = title.length; i < len; ++i) {
+                               ctx.fillText(title[i], pt.x, pt.y);
+                               pt.y += titleFontSize + titleSpacing; // Line Height and spacing
+
+                               if (i + 1 === title.length) {
+                                       pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing
+                               }
+                       }
+               }
+       },
+
+       drawBody: function(pt, vm, ctx) {
+               var bodyFontSize = vm.bodyFontSize;
+               var bodySpacing = vm.bodySpacing;
+               var bodyAlign = vm._bodyAlign;
+               var body = vm.body;
+               var drawColorBoxes = vm.displayColors;
+               var labelColors = vm.labelColors;
+               var xLinePadding = 0;
+               var colorX = drawColorBoxes ? getAlignedX(vm, 'left') : 0;
+               var textColor;
+
+               ctx.textAlign = bodyAlign;
+               ctx.textBaseline = 'top';
+               ctx.font = helpers$1.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
+
+               pt.x = getAlignedX(vm, bodyAlign);
+
+               // Before Body
+               var fillLineOfText = function(line) {
+                       ctx.fillText(line, pt.x + xLinePadding, pt.y);
+                       pt.y += bodyFontSize + bodySpacing;
+               };
+
+               // Before body lines
+               ctx.fillStyle = vm.bodyFontColor;
+               helpers$1.each(vm.beforeBody, fillLineOfText);
+
+               xLinePadding = drawColorBoxes && bodyAlign !== 'right'
+                       ? bodyAlign === 'center' ? (bodyFontSize / 2 + 1) : (bodyFontSize + 2)
+                       : 0;
+
+               // Draw body lines now
+               helpers$1.each(body, function(bodyItem, i) {
+                       textColor = vm.labelTextColors[i];
+                       ctx.fillStyle = textColor;
+                       helpers$1.each(bodyItem.before, fillLineOfText);
+
+                       helpers$1.each(bodyItem.lines, function(line) {
+                               // Draw Legend-like boxes if needed
+                               if (drawColorBoxes) {
+                                       // Fill a white rect so that colours merge nicely if the opacity is < 1
+                                       ctx.fillStyle = vm.legendColorBackground;
+                                       ctx.fillRect(colorX, pt.y, bodyFontSize, bodyFontSize);
+
+                                       // Border
+                                       ctx.lineWidth = 1;
+                                       ctx.strokeStyle = labelColors[i].borderColor;
+                                       ctx.strokeRect(colorX, pt.y, bodyFontSize, bodyFontSize);
+
+                                       // Inner square
+                                       ctx.fillStyle = labelColors[i].backgroundColor;
+                                       ctx.fillRect(colorX + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
+                                       ctx.fillStyle = textColor;
+                               }
+
+                               fillLineOfText(line);
+                       });
+
+                       helpers$1.each(bodyItem.after, fillLineOfText);
+               });
+
+               // Reset back to 0 for after body
+               xLinePadding = 0;
+
+               // After body lines
+               helpers$1.each(vm.afterBody, fillLineOfText);
+               pt.y -= bodySpacing; // Remove last body spacing
+       },
+
+       drawFooter: function(pt, vm, ctx) {
+               var footer = vm.footer;
+
+               if (footer.length) {
+                       pt.x = getAlignedX(vm, vm._footerAlign);
+                       pt.y += vm.footerMarginTop;
+
+                       ctx.textAlign = vm._footerAlign;
+                       ctx.textBaseline = 'top';
+
+                       ctx.fillStyle = vm.footerFontColor;
+                       ctx.font = helpers$1.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
+
+                       helpers$1.each(footer, function(line) {
+                               ctx.fillText(line, pt.x, pt.y);
+                               pt.y += vm.footerFontSize + vm.footerSpacing;
+                       });
+               }
+       },
+
+       drawBackground: function(pt, vm, ctx, tooltipSize) {
+               ctx.fillStyle = vm.backgroundColor;
+               ctx.strokeStyle = vm.borderColor;
+               ctx.lineWidth = vm.borderWidth;
+               var xAlign = vm.xAlign;
+               var yAlign = vm.yAlign;
+               var x = pt.x;
+               var y = pt.y;
+               var width = tooltipSize.width;
+               var height = tooltipSize.height;
+               var radius = vm.cornerRadius;
+
+               ctx.beginPath();
+               ctx.moveTo(x + radius, y);
+               if (yAlign === 'top') {
+                       this.drawCaret(pt, tooltipSize);
+               }
+               ctx.lineTo(x + width - radius, y);
+               ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
+               if (yAlign === 'center' && xAlign === 'right') {
+                       this.drawCaret(pt, tooltipSize);
+               }
+               ctx.lineTo(x + width, y + height - radius);
+               ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
+               if (yAlign === 'bottom') {
+                       this.drawCaret(pt, tooltipSize);
+               }
+               ctx.lineTo(x + radius, y + height);
+               ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
+               if (yAlign === 'center' && xAlign === 'left') {
+                       this.drawCaret(pt, tooltipSize);
+               }
+               ctx.lineTo(x, y + radius);
+               ctx.quadraticCurveTo(x, y, x + radius, y);
+               ctx.closePath();
+
+               ctx.fill();
+
+               if (vm.borderWidth > 0) {
+                       ctx.stroke();
+               }
+       },
+
+       draw: function() {
+               var ctx = this._chart.ctx;
+               var vm = this._view;
+
+               if (vm.opacity === 0) {
+                       return;
+               }
+
+               var tooltipSize = {
+                       width: vm.width,
+                       height: vm.height
+               };
+               var pt = {
+                       x: vm.x,
+                       y: vm.y
+               };
+
+               // IE11/Edge does not like very small opacities, so snap to 0
+               var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
+
+               // Truthy/falsey value for empty tooltip
+               var hasTooltipContent = vm.title.length || vm.beforeBody.length || vm.body.length || vm.afterBody.length || vm.footer.length;
+
+               if (this._options.enabled && hasTooltipContent) {
+                       ctx.save();
+                       ctx.globalAlpha = opacity;
+
+                       // Draw Background
+                       this.drawBackground(pt, vm, ctx, tooltipSize);
+
+                       // Draw Title, Body, and Footer
+                       pt.y += vm.yPadding;
+
+                       // Titles
+                       this.drawTitle(pt, vm, ctx);
+
+                       // Body
+                       this.drawBody(pt, vm, ctx);
+
+                       // Footer
+                       this.drawFooter(pt, vm, ctx);
+
+                       ctx.restore();
+               }
+       },
+
+       /**
+        * Handle an event
+        * @private
+        * @param {IEvent} event - The event to handle
+        * @returns {boolean} true if the tooltip changed
+        */
+       handleEvent: function(e) {
+               var me = this;
+               var options = me._options;
+               var changed = false;
+
+               me._lastActive = me._lastActive || [];
+
+               // Find Active Elements for tooltips
+               if (e.type === 'mouseout') {
+                       me._active = [];
+               } else {
+                       me._active = me._chart.getElementsAtEventForMode(e, options.mode, options);
+               }
+
+               // Remember Last Actives
+               changed = !helpers$1.arrayEquals(me._active, me._lastActive);
+
+               // Only handle target event on tooltip change
+               if (changed) {
+                       me._lastActive = me._active;
+
+                       if (options.enabled || options.custom) {
+                               me._eventPosition = {
+                                       x: e.x,
+                                       y: e.y
+                               };
+
+                               me.update(true);
+                               me.pivot();
+                       }
+               }
+
+               return changed;
+       }
+});
+
+/**
+ * @namespace Chart.Tooltip.positioners
+ */
+var positioners_1 = positioners;
+
+var core_tooltip = exports$3;
+core_tooltip.positioners = positioners_1;
+
+var valueOrDefault$8 = helpers$1.valueOrDefault;
+
+core_defaults._set('global', {
+       elements: {},
+       events: [
+               'mousemove',
+               'mouseout',
+               'click',
+               'touchstart',
+               'touchmove'
+       ],
+       hover: {
+               onHover: null,
+               mode: 'nearest',
+               intersect: true,
+               animationDuration: 400
+       },
+       onClick: null,
+       maintainAspectRatio: true,
+       responsive: true,
+       responsiveAnimationDuration: 0
+});
+
+/**
+ * Recursively merge the given config objects representing the `scales` option
+ * by incorporating scale defaults in `xAxes` and `yAxes` array items, then
+ * returns a deep copy of the result, thus doesn't alter inputs.
+ */
+function mergeScaleConfig(/* config objects ... */) {
+       return helpers$1.merge({}, [].slice.call(arguments), {
+               merger: function(key, target, source, options) {
+                       if (key === 'xAxes' || key === 'yAxes') {
+                               var slen = source[key].length;
+                               var i, type, scale;
+
+                               if (!target[key]) {
+                                       target[key] = [];
+                               }
+
+                               for (i = 0; i < slen; ++i) {
+                                       scale = source[key][i];
+                                       type = valueOrDefault$8(scale.type, key === 'xAxes' ? 'category' : 'linear');
+
+                                       if (i >= target[key].length) {
+                                               target[key].push({});
+                                       }
+
+                                       if (!target[key][i].type || (scale.type && scale.type !== target[key][i].type)) {
+                                               // new/untyped scale or type changed: let's apply the new defaults
+                                               // then merge source scale to correctly overwrite the defaults.
+                                               helpers$1.merge(target[key][i], [core_scaleService.getScaleDefaults(type), scale]);
+                                       } else {
+                                               // scales type are the same
+                                               helpers$1.merge(target[key][i], scale);
+                                       }
+                               }
+                       } else {
+                               helpers$1._merger(key, target, source, options);
+                       }
+               }
+       });
+}
+
+/**
+ * Recursively merge the given config objects as the root options by handling
+ * default scale options for the `scales` and `scale` properties, then returns
+ * a deep copy of the result, thus doesn't alter inputs.
+ */
+function mergeConfig(/* config objects ... */) {
+       return helpers$1.merge({}, [].slice.call(arguments), {
+               merger: function(key, target, source, options) {
+                       var tval = target[key] || {};
+                       var sval = source[key];
+
+                       if (key === 'scales') {
+                               // scale config merging is complex. Add our own function here for that
+                               target[key] = mergeScaleConfig(tval, sval);
+                       } else if (key === 'scale') {
+                               // used in polar area & radar charts since there is only one scale
+                               target[key] = helpers$1.merge(tval, [core_scaleService.getScaleDefaults(sval.type), sval]);
+                       } else {
+                               helpers$1._merger(key, target, source, options);
+                       }
+               }
+       });
+}
+
+function initConfig(config) {
+       config = config || {};
+
+       // Do NOT use mergeConfig for the data object because this method merges arrays
+       // and so would change references to labels and datasets, preventing data updates.
+       var data = config.data = config.data || {};
+       data.datasets = data.datasets || [];
+       data.labels = data.labels || [];
+
+       config.options = mergeConfig(
+               core_defaults.global,
+               core_defaults[config.type],
+               config.options || {});
+
+       return config;
+}
+
+function updateConfig(chart) {
+       var newOptions = chart.options;
+
+       helpers$1.each(chart.scales, function(scale) {
+               core_layouts.removeBox(chart, scale);
+       });
+
+       newOptions = mergeConfig(
+               core_defaults.global,
+               core_defaults[chart.config.type],
+               newOptions);
+
+       chart.options = chart.config.options = newOptions;
+       chart.ensureScalesHaveIDs();
+       chart.buildOrUpdateScales();
+
+       // Tooltip
+       chart.tooltip._options = newOptions.tooltips;
+       chart.tooltip.initialize();
+}
+
+function positionIsHorizontal(position) {
+       return position === 'top' || position === 'bottom';
+}
+
+var Chart = function(item, config) {
+       this.construct(item, config);
+       return this;
+};
+
+helpers$1.extend(Chart.prototype, /** @lends Chart */ {
+       /**
+        * @private
+        */
+       construct: function(item, config) {
+               var me = this;
+
+               config = initConfig(config);
+
+               var context = platform.acquireContext(item, config);
+               var canvas = context && context.canvas;
+               var height = canvas && canvas.height;
+               var width = canvas && canvas.width;
+
+               me.id = helpers$1.uid();
+               me.ctx = context;
+               me.canvas = canvas;
+               me.config = config;
+               me.width = width;
+               me.height = height;
+               me.aspectRatio = height ? width / height : null;
+               me.options = config.options;
+               me._bufferedRender = false;
+
+               /**
+                * Provided for backward compatibility, Chart and Chart.Controller have been merged,
+                * the "instance" still need to be defined since it might be called from plugins.
+                * @prop Chart#chart
+                * @deprecated since version 2.6.0
+                * @todo remove at version 3
+                * @private
+                */
+               me.chart = me;
+               me.controller = me; // chart.chart.controller #inception
+
+               // Add the chart instance to the global namespace
+               Chart.instances[me.id] = me;
+
+               // Define alias to the config data: `chart.data === chart.config.data`
+               Object.defineProperty(me, 'data', {
+                       get: function() {
+                               return me.config.data;
+                       },
+                       set: function(value) {
+                               me.config.data = value;
+                       }
+               });
+
+               if (!context || !canvas) {
+                       // The given item is not a compatible context2d element, let's return before finalizing
+                       // the chart initialization but after setting basic chart / controller properties that
+                       // can help to figure out that the chart is not valid (e.g chart.canvas !== null);
+                       // https://github.com/chartjs/Chart.js/issues/2807
+                       console.error("Failed to create chart: can't acquire context from the given item");
+                       return;
+               }
+
+               me.initialize();
+               me.update();
+       },
+
+       /**
+        * @private
+        */
+       initialize: function() {
+               var me = this;
+
+               // Before init plugin notification
+               core_plugins.notify(me, 'beforeInit');
+
+               helpers$1.retinaScale(me, me.options.devicePixelRatio);
+
+               me.bindEvents();
+
+               if (me.options.responsive) {
+                       // Initial resize before chart draws (must be silent to preserve initial animations).
+                       me.resize(true);
+               }
+
+               // Make sure scales have IDs and are built before we build any controllers.
+               me.ensureScalesHaveIDs();
+               me.buildOrUpdateScales();
+               me.initToolTip();
+
+               // After init plugin notification
+               core_plugins.notify(me, 'afterInit');
+
+               return me;
+       },
+
+       clear: function() {
+               helpers$1.canvas.clear(this);
+               return this;
+       },
+
+       stop: function() {
+               // Stops any current animation loop occurring
+               core_animations.cancelAnimation(this);
+               return this;
+       },
+
+       resize: function(silent) {
+               var me = this;
+               var options = me.options;
+               var canvas = me.canvas;
+               var aspectRatio = (options.maintainAspectRatio && me.aspectRatio) || null;
+
+               // the canvas render width and height will be casted to integers so make sure that
+               // the canvas display style uses the same integer values to avoid blurring effect.
+
+               // Set to 0 instead of canvas.size because the size defaults to 300x150 if the element is collapsed
+               var newWidth = Math.max(0, Math.floor(helpers$1.getMaximumWidth(canvas)));
+               var newHeight = Math.max(0, Math.floor(aspectRatio ? newWidth / aspectRatio : helpers$1.getMaximumHeight(canvas)));
+
+               if (me.width === newWidth && me.height === newHeight) {
+                       return;
+               }
+
+               canvas.width = me.width = newWidth;
+               canvas.height = me.height = newHeight;
+               canvas.style.width = newWidth + 'px';
+               canvas.style.height = newHeight + 'px';
+
+               helpers$1.retinaScale(me, options.devicePixelRatio);
+
+               if (!silent) {
+                       // Notify any plugins about the resize
+                       var newSize = {width: newWidth, height: newHeight};
+                       core_plugins.notify(me, 'resize', [newSize]);
+
+                       // Notify of resize
+                       if (options.onResize) {
+                               options.onResize(me, newSize);
+                       }
+
+                       me.stop();
+                       me.update({
+                               duration: options.responsiveAnimationDuration
+                       });
+               }
+       },
+
+       ensureScalesHaveIDs: function() {
+               var options = this.options;
+               var scalesOptions = options.scales || {};
+               var scaleOptions = options.scale;
+
+               helpers$1.each(scalesOptions.xAxes, function(xAxisOptions, index) {
+                       xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index);
+               });
+
+               helpers$1.each(scalesOptions.yAxes, function(yAxisOptions, index) {
+                       yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index);
+               });
+
+               if (scaleOptions) {
+                       scaleOptions.id = scaleOptions.id || 'scale';
+               }
+       },
+
+       /**
+        * Builds a map of scale ID to scale object for future lookup.
+        */
+       buildOrUpdateScales: function() {
+               var me = this;
+               var options = me.options;
+               var scales = me.scales || {};
+               var items = [];
+               var updated = Object.keys(scales).reduce(function(obj, id) {
+                       obj[id] = false;
+                       return obj;
+               }, {});
+
+               if (options.scales) {
+                       items = items.concat(
+                               (options.scales.xAxes || []).map(function(xAxisOptions) {
+                                       return {options: xAxisOptions, dtype: 'category', dposition: 'bottom'};
+                               }),
+                               (options.scales.yAxes || []).map(function(yAxisOptions) {
+                                       return {options: yAxisOptions, dtype: 'linear', dposition: 'left'};
+                               })
+                       );
+               }
+
+               if (options.scale) {
+                       items.push({
+                               options: options.scale,
+                               dtype: 'radialLinear',
+                               isDefault: true,
+                               dposition: 'chartArea'
+                       });
+               }
+
+               helpers$1.each(items, function(item) {
+                       var scaleOptions = item.options;
+                       var id = scaleOptions.id;
+                       var scaleType = valueOrDefault$8(scaleOptions.type, item.dtype);
+
+                       if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) {
+                               scaleOptions.position = item.dposition;
+                       }
+
+                       updated[id] = true;
+                       var scale = null;
+                       if (id in scales && scales[id].type === scaleType) {
+                               scale = scales[id];
+                               scale.options = scaleOptions;
+                               scale.ctx = me.ctx;
+                               scale.chart = me;
+                       } else {
+                               var scaleClass = core_scaleService.getScaleConstructor(scaleType);
+                               if (!scaleClass) {
+                                       return;
+                               }
+                               scale = new scaleClass({
+                                       id: id,
+                                       type: scaleType,
+                                       options: scaleOptions,
+                                       ctx: me.ctx,
+                                       chart: me
+                               });
+                               scales[scale.id] = scale;
+                       }
+
+                       scale.mergeTicksOptions();
+
+                       // TODO(SB): I think we should be able to remove this custom case (options.scale)
+                       // and consider it as a regular scale part of the "scales"" map only! This would
+                       // make the logic easier and remove some useless? custom code.
+                       if (item.isDefault) {
+                               me.scale = scale;
+                       }
+               });
+               // clear up discarded scales
+               helpers$1.each(updated, function(hasUpdated, id) {
+                       if (!hasUpdated) {
+                               delete scales[id];
+                       }
+               });
+
+               me.scales = scales;
+
+               core_scaleService.addScalesToLayout(this);
+       },
+
+       buildOrUpdateControllers: function() {
+               var me = this;
+               var newControllers = [];
+
+               helpers$1.each(me.data.datasets, function(dataset, datasetIndex) {
+                       var meta = me.getDatasetMeta(datasetIndex);
+                       var type = dataset.type || me.config.type;
+
+                       if (meta.type && meta.type !== type) {
+                               me.destroyDatasetMeta(datasetIndex);
+                               meta = me.getDatasetMeta(datasetIndex);
+                       }
+                       meta.type = type;
+
+                       if (meta.controller) {
+                               meta.controller.updateIndex(datasetIndex);
+                               meta.controller.linkScales();
+                       } else {
+                               var ControllerClass = controllers[meta.type];
+                               if (ControllerClass === undefined) {
+                                       throw new Error('"' + meta.type + '" is not a chart type.');
+                               }
+
+                               meta.controller = new ControllerClass(me, datasetIndex);
+                               newControllers.push(meta.controller);
+                       }
+               }, me);
+
+               return newControllers;
+       },
+
+       /**
+        * Reset the elements of all datasets
+        * @private
+        */
+       resetElements: function() {
+               var me = this;
+               helpers$1.each(me.data.datasets, function(dataset, datasetIndex) {
+                       me.getDatasetMeta(datasetIndex).controller.reset();
+               }, me);
+       },
+
+       /**
+       * Resets the chart back to it's state before the initial animation
+       */
+       reset: function() {
+               this.resetElements();
+               this.tooltip.initialize();
+       },
+
+       update: function(config) {
+               var me = this;
+
+               if (!config || typeof config !== 'object') {
+                       // backwards compatibility
+                       config = {
+                               duration: config,
+                               lazy: arguments[1]
+                       };
+               }
+
+               updateConfig(me);
+
+               // plugins options references might have change, let's invalidate the cache
+               // https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
+               core_plugins._invalidate(me);
+
+               if (core_plugins.notify(me, 'beforeUpdate') === false) {
+                       return;
+               }
+
+               // In case the entire data object changed
+               me.tooltip._data = me.data;
+
+               // Make sure dataset controllers are updated and new controllers are reset
+               var newControllers = me.buildOrUpdateControllers();
+
+               // Make sure all dataset controllers have correct meta data counts
+               helpers$1.each(me.data.datasets, function(dataset, datasetIndex) {
+                       me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements();
+               }, me);
+
+               me.updateLayout();
+
+               // Can only reset the new controllers after the scales have been updated
+               if (me.options.animation && me.options.animation.duration) {
+                       helpers$1.each(newControllers, function(controller) {
+                               controller.reset();
+                       });
+               }
+
+               me.updateDatasets();
+
+               // Need to reset tooltip in case it is displayed with elements that are removed
+               // after update.
+               me.tooltip.initialize();
+
+               // Last active contains items that were previously in the tooltip.
+               // When we reset the tooltip, we need to clear it
+               me.lastActive = [];
+
+               // Do this before render so that any plugins that need final scale updates can use it
+               core_plugins.notify(me, 'afterUpdate');
+
+               if (me._bufferedRender) {
+                       me._bufferedRequest = {
+                               duration: config.duration,
+                               easing: config.easing,
+                               lazy: config.lazy
+                       };
+               } else {
+                       me.render(config);
+               }
+       },
+
+       /**
+        * Updates the chart layout unless a plugin returns `false` to the `beforeLayout`
+        * hook, in which case, plugins will not be called on `afterLayout`.
+        * @private
+        */
+       updateLayout: function() {
+               var me = this;
+
+               if (core_plugins.notify(me, 'beforeLayout') === false) {
+                       return;
+               }
+
+               core_layouts.update(this, this.width, this.height);
+
+               /**
+                * Provided for backward compatibility, use `afterLayout` instead.
+                * @method IPlugin#afterScaleUpdate
+                * @deprecated since version 2.5.0
+                * @todo remove at version 3
+                * @private
+                */
+               core_plugins.notify(me, 'afterScaleUpdate');
+               core_plugins.notify(me, 'afterLayout');
+       },
+
+       /**
+        * Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate`
+        * hook, in which case, plugins will not be called on `afterDatasetsUpdate`.
+        * @private
+        */
+       updateDatasets: function() {
+               var me = this;
+
+               if (core_plugins.notify(me, 'beforeDatasetsUpdate') === false) {
+                       return;
+               }
+
+               for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
+                       me.updateDataset(i);
+               }
+
+               core_plugins.notify(me, 'afterDatasetsUpdate');
+       },
+
+       /**
+        * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate`
+        * hook, in which case, plugins will not be called on `afterDatasetUpdate`.
+        * @private
+        */
+       updateDataset: function(index) {
+               var me = this;
+               var meta = me.getDatasetMeta(index);
+               var args = {
+                       meta: meta,
+                       index: index
+               };
+
+               if (core_plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) {
+                       return;
+               }
+
+               meta.controller.update();
+
+               core_plugins.notify(me, 'afterDatasetUpdate', [args]);
+       },
+
+       render: function(config) {
+               var me = this;
+
+               if (!config || typeof config !== 'object') {
+                       // backwards compatibility
+                       config = {
+                               duration: config,
+                               lazy: arguments[1]
+                       };
+               }
+
+               var animationOptions = me.options.animation;
+               var duration = valueOrDefault$8(config.duration, animationOptions && animationOptions.duration);
+               var lazy = config.lazy;
+
+               if (core_plugins.notify(me, 'beforeRender') === false) {
+                       return;
+               }
+
+               var onComplete = function(animation) {
+                       core_plugins.notify(me, 'afterRender');
+                       helpers$1.callback(animationOptions && animationOptions.onComplete, [animation], me);
+               };
+
+               if (animationOptions && duration) {
+                       var animation = new core_animation({
+                               numSteps: duration / 16.66, // 60 fps
+                               easing: config.easing || animationOptions.easing,
+
+                               render: function(chart, animationObject) {
+                                       var easingFunction = helpers$1.easing.effects[animationObject.easing];
+                                       var currentStep = animationObject.currentStep;
+                                       var stepDecimal = currentStep / animationObject.numSteps;
+
+                                       chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep);
+                               },
+
+                               onAnimationProgress: animationOptions.onProgress,
+                               onAnimationComplete: onComplete
+                       });
+
+                       core_animations.addAnimation(me, animation, duration, lazy);
+               } else {
+                       me.draw();
+
+                       // See https://github.com/chartjs/Chart.js/issues/3781
+                       onComplete(new core_animation({numSteps: 0, chart: me}));
+               }
+
+               return me;
+       },
+
+       draw: function(easingValue) {
+               var me = this;
+
+               me.clear();
+
+               if (helpers$1.isNullOrUndef(easingValue)) {
+                       easingValue = 1;
+               }
+
+               me.transition(easingValue);
+
+               if (me.width <= 0 || me.height <= 0) {
+                       return;
+               }
+
+               if (core_plugins.notify(me, 'beforeDraw', [easingValue]) === false) {
+                       return;
+               }
+
+               // Draw all the scales
+               helpers$1.each(me.boxes, function(box) {
+                       box.draw(me.chartArea);
+               }, me);
+
+               me.drawDatasets(easingValue);
+               me._drawTooltip(easingValue);
+
+               core_plugins.notify(me, 'afterDraw', [easingValue]);
+       },
+
+       /**
+        * @private
+        */
+       transition: function(easingValue) {
+               var me = this;
+
+               for (var i = 0, ilen = (me.data.datasets || []).length; i < ilen; ++i) {
+                       if (me.isDatasetVisible(i)) {
+                               me.getDatasetMeta(i).controller.transition(easingValue);
+                       }
+               }
+
+               me.tooltip.transition(easingValue);
+       },
+
+       /**
+        * Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw`
+        * hook, in which case, plugins will not be called on `afterDatasetsDraw`.
+        * @private
+        */
+       drawDatasets: function(easingValue) {
+               var me = this;
+
+               if (core_plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) {
+                       return;
+               }
+
+               // Draw datasets reversed to support proper line stacking
+               for (var i = (me.data.datasets || []).length - 1; i >= 0; --i) {
+                       if (me.isDatasetVisible(i)) {
+                               me.drawDataset(i, easingValue);
+                       }
+               }
+
+               core_plugins.notify(me, 'afterDatasetsDraw', [easingValue]);
+       },
+
+       /**
+        * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw`
+        * hook, in which case, plugins will not be called on `afterDatasetDraw`.
+        * @private
+        */
+       drawDataset: function(index, easingValue) {
+               var me = this;
+               var meta = me.getDatasetMeta(index);
+               var args = {
+                       meta: meta,
+                       index: index,
+                       easingValue: easingValue
+               };
+
+               if (core_plugins.notify(me, 'beforeDatasetDraw', [args]) === false) {
+                       return;
+               }
+
+               meta.controller.draw(easingValue);
+
+               core_plugins.notify(me, 'afterDatasetDraw', [args]);
+       },
+
+       /**
+        * Draws tooltip unless a plugin returns `false` to the `beforeTooltipDraw`
+        * hook, in which case, plugins will not be called on `afterTooltipDraw`.
+        * @private
+        */
+       _drawTooltip: function(easingValue) {
+               var me = this;
+               var tooltip = me.tooltip;
+               var args = {
+                       tooltip: tooltip,
+                       easingValue: easingValue
+               };
+
+               if (core_plugins.notify(me, 'beforeTooltipDraw', [args]) === false) {
+                       return;
+               }
+
+               tooltip.draw();
+
+               core_plugins.notify(me, 'afterTooltipDraw', [args]);
+       },
+
+       /**
+        * Get the single element that was clicked on
+        * @return An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw
+        */
+       getElementAtEvent: function(e) {
+               return core_interaction.modes.single(this, e);
+       },
+
+       getElementsAtEvent: function(e) {
+               return core_interaction.modes.label(this, e, {intersect: true});
+       },
+
+       getElementsAtXAxis: function(e) {
+               return core_interaction.modes['x-axis'](this, e, {intersect: true});
+       },
+
+       getElementsAtEventForMode: function(e, mode, options) {
+               var method = core_interaction.modes[mode];
+               if (typeof method === 'function') {
+                       return method(this, e, options);
+               }
+
+               return [];
+       },
+
+       getDatasetAtEvent: function(e) {
+               return core_interaction.modes.dataset(this, e, {intersect: true});
+       },
+
+       getDatasetMeta: function(datasetIndex) {
+               var me = this;
+               var dataset = me.data.datasets[datasetIndex];
+               if (!dataset._meta) {
+                       dataset._meta = {};
+               }
+
+               var meta = dataset._meta[me.id];
+               if (!meta) {
+                       meta = dataset._meta[me.id] = {
+                               type: null,
+                               data: [],
+                               dataset: null,
+                               controller: null,
+                               hidden: null,                   // See isDatasetVisible() comment
+                               xAxisID: null,
+                               yAxisID: null
+                       };
+               }
+
+               return meta;
+       },
+
+       getVisibleDatasetCount: function() {
+               var count = 0;
+               for (var i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {
+                       if (this.isDatasetVisible(i)) {
+                               count++;
+                       }
+               }
+               return count;
+       },
+
+       isDatasetVisible: function(datasetIndex) {
+               var meta = this.getDatasetMeta(datasetIndex);
+
+               // meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false,
+               // the dataset.hidden value is ignored, else if null, the dataset hidden state is returned.
+               return typeof meta.hidden === 'boolean' ? !meta.hidden : !this.data.datasets[datasetIndex].hidden;
+       },
+
+       generateLegend: function() {
+               return this.options.legendCallback(this);
+       },
+
+       /**
+        * @private
+        */
+       destroyDatasetMeta: function(datasetIndex) {
+               var id = this.id;
+               var dataset = this.data.datasets[datasetIndex];
+               var meta = dataset._meta && dataset._meta[id];
+
+               if (meta) {
+                       meta.controller.destroy();
+                       delete dataset._meta[id];
+               }
+       },
+
+       destroy: function() {
+               var me = this;
+               var canvas = me.canvas;
+               var i, ilen;
+
+               me.stop();
+
+               // dataset controllers need to cleanup associated data
+               for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
+                       me.destroyDatasetMeta(i);
+               }
+
+               if (canvas) {
+                       me.unbindEvents();
+                       helpers$1.canvas.clear(me);
+                       platform.releaseContext(me.ctx);
+                       me.canvas = null;
+                       me.ctx = null;
+               }
+
+               core_plugins.notify(me, 'destroy');
+
+               delete Chart.instances[me.id];
+       },
+
+       toBase64Image: function() {
+               return this.canvas.toDataURL.apply(this.canvas, arguments);
+       },
+
+       initToolTip: function() {
+               var me = this;
+               me.tooltip = new core_tooltip({
+                       _chart: me,
+                       _chartInstance: me, // deprecated, backward compatibility
+                       _data: me.data,
+                       _options: me.options.tooltips
+               }, me);
+       },
+
+       /**
+        * @private
+        */
+       bindEvents: function() {
+               var me = this;
+               var listeners = me._listeners = {};
+               var listener = function() {
+                       me.eventHandler.apply(me, arguments);
+               };
+
+               helpers$1.each(me.options.events, function(type) {
+                       platform.addEventListener(me, type, listener);
+                       listeners[type] = listener;
+               });
+
+               // Elements used to detect size change should not be injected for non responsive charts.
+               // See https://github.com/chartjs/Chart.js/issues/2210
+               if (me.options.responsive) {
+                       listener = function() {
+                               me.resize();
+                       };
+
+                       platform.addEventListener(me, 'resize', listener);
+                       listeners.resize = listener;
+               }
+       },
+
+       /**
+        * @private
+        */
+       unbindEvents: function() {
+               var me = this;
+               var listeners = me._listeners;
+               if (!listeners) {
+                       return;
+               }
+
+               delete me._listeners;
+               helpers$1.each(listeners, function(listener, type) {
+                       platform.removeEventListener(me, type, listener);
+               });
+       },
+
+       updateHoverStyle: function(elements, mode, enabled) {
+               var method = enabled ? 'setHoverStyle' : 'removeHoverStyle';
+               var element, i, ilen;
+
+               for (i = 0, ilen = elements.length; i < ilen; ++i) {
+                       element = elements[i];
+                       if (element) {
+                               this.getDatasetMeta(element._datasetIndex).controller[method](element);
+                       }
+               }
+       },
+
+       /**
+        * @private
+        */
+       eventHandler: function(e) {
+               var me = this;
+               var tooltip = me.tooltip;
+
+               if (core_plugins.notify(me, 'beforeEvent', [e]) === false) {
+                       return;
+               }
+
+               // Buffer any update calls so that renders do not occur
+               me._bufferedRender = true;
+               me._bufferedRequest = null;
+
+               var changed = me.handleEvent(e);
+               // for smooth tooltip animations issue #4989
+               // the tooltip should be the source of change
+               // Animation check workaround:
+               // tooltip._start will be null when tooltip isn't animating
+               if (tooltip) {
+                       changed = tooltip._start
+                               ? tooltip.handleEvent(e)
+                               : changed | tooltip.handleEvent(e);
+               }
+
+               core_plugins.notify(me, 'afterEvent', [e]);
+
+               var bufferedRequest = me._bufferedRequest;
+               if (bufferedRequest) {
+                       // If we have an update that was triggered, we need to do a normal render
+                       me.render(bufferedRequest);
+               } else if (changed && !me.animating) {
+                       // If entering, leaving, or changing elements, animate the change via pivot
+                       me.stop();
+
+                       // We only need to render at this point. Updating will cause scales to be
+                       // recomputed generating flicker & using more memory than necessary.
+                       me.render({
+                               duration: me.options.hover.animationDuration,
+                               lazy: true
+                       });
+               }
+
+               me._bufferedRender = false;
+               me._bufferedRequest = null;
+
+               return me;
+       },
+
+       /**
+        * Handle an event
+        * @private
+        * @param {IEvent} event the event to handle
+        * @return {boolean} true if the chart needs to re-render
+        */
+       handleEvent: function(e) {
+               var me = this;
+               var options = me.options || {};
+               var hoverOptions = options.hover;
+               var changed = false;
+
+               me.lastActive = me.lastActive || [];
+
+               // Find Active Elements for hover and tooltips
+               if (e.type === 'mouseout') {
+                       me.active = [];
+               } else {
+                       me.active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions);
+               }
+
+               // Invoke onHover hook
+               // Need to call with native event here to not break backwards compatibility
+               helpers$1.callback(options.onHover || options.hover.onHover, [e.native, me.active], me);
+
+               if (e.type === 'mouseup' || e.type === 'click') {
+                       if (options.onClick) {
+                               // Use e.native here for backwards compatibility
+                               options.onClick.call(me, e.native, me.active);
+                       }
+               }
+
+               // Remove styling for last active (even if it may still be active)
+               if (me.lastActive.length) {
+                       me.updateHoverStyle(me.lastActive, hoverOptions.mode, false);
+               }
+
+               // Built in hover styling
+               if (me.active.length && hoverOptions.mode) {
+                       me.updateHoverStyle(me.active, hoverOptions.mode, true);
+               }
+
+               changed = !helpers$1.arrayEquals(me.active, me.lastActive);
+
+               // Remember Last Actives
+               me.lastActive = me.active;
+
+               return changed;
+       }
+});
+
+/**
+ * NOTE(SB) We actually don't use this container anymore but we need to keep it
+ * for backward compatibility. Though, it can still be useful for plugins that
+ * would need to work on multiple charts?!
+ */
+Chart.instances = {};
+
+var core_controller = Chart;
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, use Chart instead.
+ * @class Chart.Controller
+ * @deprecated since version 2.6
+ * @todo remove at version 3
+ * @private
+ */
+Chart.Controller = Chart;
+
+/**
+ * Provided for backward compatibility, not available anymore.
+ * @namespace Chart
+ * @deprecated since version 2.8
+ * @todo remove at version 3
+ * @private
+ */
+Chart.types = {};
+
+/**
+ * Provided for backward compatibility, not available anymore.
+ * @namespace Chart.helpers.configMerge
+ * @deprecated since version 2.8.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers$1.configMerge = mergeConfig;
+
+/**
+ * Provided for backward compatibility, not available anymore.
+ * @namespace Chart.helpers.scaleMerge
+ * @deprecated since version 2.8.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers$1.scaleMerge = mergeScaleConfig;
+
+var core_helpers = function() {
+
+       // -- Basic js utility methods
+
+       helpers$1.where = function(collection, filterCallback) {
+               if (helpers$1.isArray(collection) && Array.prototype.filter) {
+                       return collection.filter(filterCallback);
+               }
+               var filtered = [];
+
+               helpers$1.each(collection, function(item) {
+                       if (filterCallback(item)) {
+                               filtered.push(item);
+                       }
+               });
+
+               return filtered;
+       };
+       helpers$1.findIndex = Array.prototype.findIndex ?
+               function(array, callback, scope) {
+                       return array.findIndex(callback, scope);
+               } :
+               function(array, callback, scope) {
+                       scope = scope === undefined ? array : scope;
+                       for (var i = 0, ilen = array.length; i < ilen; ++i) {
+                               if (callback.call(scope, array[i], i, array)) {
+                                       return i;
+                               }
+                       }
+                       return -1;
+               };
+       helpers$1.findNextWhere = function(arrayToSearch, filterCallback, startIndex) {
+               // Default to start of the array
+               if (helpers$1.isNullOrUndef(startIndex)) {
+                       startIndex = -1;
+               }
+               for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
+                       var currentItem = arrayToSearch[i];
+                       if (filterCallback(currentItem)) {
+                               return currentItem;
+                       }
+               }
+       };
+       helpers$1.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) {
+               // Default to end of the array
+               if (helpers$1.isNullOrUndef(startIndex)) {
+                       startIndex = arrayToSearch.length;
+               }
+               for (var i = startIndex - 1; i >= 0; i--) {
+                       var currentItem = arrayToSearch[i];
+                       if (filterCallback(currentItem)) {
+                               return currentItem;
+                       }
+               }
+       };
+
+       // -- Math methods
+       helpers$1.isNumber = function(n) {
+               return !isNaN(parseFloat(n)) && isFinite(n);
+       };
+       helpers$1.almostEquals = function(x, y, epsilon) {
+               return Math.abs(x - y) < epsilon;
+       };
+       helpers$1.almostWhole = function(x, epsilon) {
+               var rounded = Math.round(x);
+               return (((rounded - epsilon) < x) && ((rounded + epsilon) > x));
+       };
+       helpers$1.max = function(array) {
+               return array.reduce(function(max, value) {
+                       if (!isNaN(value)) {
+                               return Math.max(max, value);
+                       }
+                       return max;
+               }, Number.NEGATIVE_INFINITY);
+       };
+       helpers$1.min = function(array) {
+               return array.reduce(function(min, value) {
+                       if (!isNaN(value)) {
+                               return Math.min(min, value);
+                       }
+                       return min;
+               }, Number.POSITIVE_INFINITY);
+       };
+       helpers$1.sign = Math.sign ?
+               function(x) {
+                       return Math.sign(x);
+               } :
+               function(x) {
+                       x = +x; // convert to a number
+                       if (x === 0 || isNaN(x)) {
+                               return x;
+                       }
+                       return x > 0 ? 1 : -1;
+               };
+       helpers$1.log10 = Math.log10 ?
+               function(x) {
+                       return Math.log10(x);
+               } :
+               function(x) {
+                       var exponent = Math.log(x) * Math.LOG10E; // Math.LOG10E = 1 / Math.LN10.
+                       // Check for whole powers of 10,
+                       // which due to floating point rounding error should be corrected.
+                       var powerOf10 = Math.round(exponent);
+                       var isPowerOf10 = x === Math.pow(10, powerOf10);
+
+                       return isPowerOf10 ? powerOf10 : exponent;
+               };
+       helpers$1.toRadians = function(degrees) {
+               return degrees * (Math.PI / 180);
+       };
+       helpers$1.toDegrees = function(radians) {
+               return radians * (180 / Math.PI);
+       };
+
+       /**
+        * Returns the number of decimal places
+        * i.e. the number of digits after the decimal point, of the value of this Number.
+        * @param {number} x - A number.
+        * @returns {number} The number of decimal places.
+        * @private
+        */
+       helpers$1._decimalPlaces = function(x) {
+               if (!helpers$1.isFinite(x)) {
+                       return;
+               }
+               var e = 1;
+               var p = 0;
+               while (Math.round(x * e) / e !== x) {
+                       e *= 10;
+                       p++;
+               }
+               return p;
+       };
+
+       // Gets the angle from vertical upright to the point about a centre.
+       helpers$1.getAngleFromPoint = function(centrePoint, anglePoint) {
+               var distanceFromXCenter = anglePoint.x - centrePoint.x;
+               var distanceFromYCenter = anglePoint.y - centrePoint.y;
+               var radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
+
+               var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
+
+               if (angle < (-0.5 * Math.PI)) {
+                       angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
+               }
+
+               return {
+                       angle: angle,
+                       distance: radialDistanceFromCenter
+               };
+       };
+       helpers$1.distanceBetweenPoints = function(pt1, pt2) {
+               return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
+       };
+
+       /**
+        * Provided for backward compatibility, not available anymore
+        * @function Chart.helpers.aliasPixel
+        * @deprecated since version 2.8.0
+        * @todo remove at version 3
+        */
+       helpers$1.aliasPixel = function(pixelWidth) {
+               return (pixelWidth % 2 === 0) ? 0 : 0.5;
+       };
+
+       /**
+        * Returns the aligned pixel value to avoid anti-aliasing blur
+        * @param {Chart} chart - The chart instance.
+        * @param {number} pixel - A pixel value.
+        * @param {number} width - The width of the element.
+        * @returns {number} The aligned pixel value.
+        * @private
+        */
+       helpers$1._alignPixel = function(chart, pixel, width) {
+               var devicePixelRatio = chart.currentDevicePixelRatio;
+               var halfWidth = width / 2;
+               return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth;
+       };
+
+       helpers$1.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
+               // Props to Rob Spencer at scaled innovation for his post on splining between points
+               // http://scaledinnovation.com/analytics/splines/aboutSplines.html
+
+               // This function must also respect "skipped" points
+
+               var previous = firstPoint.skip ? middlePoint : firstPoint;
+               var current = middlePoint;
+               var next = afterPoint.skip ? middlePoint : afterPoint;
+
+               var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
+               var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
+
+               var s01 = d01 / (d01 + d12);
+               var s12 = d12 / (d01 + d12);
+
+               // If all points are the same, s01 & s02 will be inf
+               s01 = isNaN(s01) ? 0 : s01;
+               s12 = isNaN(s12) ? 0 : s12;
+
+               var fa = t * s01; // scaling factor for triangle Ta
+               var fb = t * s12;
+
+               return {
+                       previous: {
+                               x: current.x - fa * (next.x - previous.x),
+                               y: current.y - fa * (next.y - previous.y)
+                       },
+                       next: {
+                               x: current.x + fb * (next.x - previous.x),
+                               y: current.y + fb * (next.y - previous.y)
+                       }
+               };
+       };
+       helpers$1.EPSILON = Number.EPSILON || 1e-14;
+       helpers$1.splineCurveMonotone = function(points) {
+               // This function calculates Bézier control points in a similar way than |splineCurve|,
+               // but preserves monotonicity of the provided data and ensures no local extremums are added
+               // between the dataset discrete points due to the interpolation.
+               // See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
+
+               var pointsWithTangents = (points || []).map(function(point) {
+                       return {
+                               model: point._model,
+                               deltaK: 0,
+                               mK: 0
+                       };
+               });
+
+               // Calculate slopes (deltaK) and initialize tangents (mK)
+               var pointsLen = pointsWithTangents.length;
+               var i, pointBefore, pointCurrent, pointAfter;
+               for (i = 0; i < pointsLen; ++i) {
+                       pointCurrent = pointsWithTangents[i];
+                       if (pointCurrent.model.skip) {
+                               continue;
+                       }
+
+                       pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
+                       pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
+                       if (pointAfter && !pointAfter.model.skip) {
+                               var slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x);
+
+                               // In the case of two points that appear at the same x pixel, slopeDeltaX is 0
+                               pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0;
+                       }
+
+                       if (!pointBefore || pointBefore.model.skip) {
+                               pointCurrent.mK = pointCurrent.deltaK;
+                       } else if (!pointAfter || pointAfter.model.skip) {
+                               pointCurrent.mK = pointBefore.deltaK;
+                       } else if (this.sign(pointBefore.deltaK) !== this.sign(pointCurrent.deltaK)) {
+                               pointCurrent.mK = 0;
+                       } else {
+                               pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2;
+                       }
+               }
+
+               // Adjust tangents to ensure monotonic properties
+               var alphaK, betaK, tauK, squaredMagnitude;
+               for (i = 0; i < pointsLen - 1; ++i) {
+                       pointCurrent = pointsWithTangents[i];
+                       pointAfter = pointsWithTangents[i + 1];
+                       if (pointCurrent.model.skip || pointAfter.model.skip) {
+                               continue;
+                       }
+
+                       if (helpers$1.almostEquals(pointCurrent.deltaK, 0, this.EPSILON)) {
+                               pointCurrent.mK = pointAfter.mK = 0;
+                               continue;
+                       }
+
+                       alphaK = pointCurrent.mK / pointCurrent.deltaK;
+                       betaK = pointAfter.mK / pointCurrent.deltaK;
+                       squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
+                       if (squaredMagnitude <= 9) {
+                               continue;
+                       }
+
+                       tauK = 3 / Math.sqrt(squaredMagnitude);
+                       pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK;
+                       pointAfter.mK = betaK * tauK * pointCurrent.deltaK;
+               }
+
+               // Compute control points
+               var deltaX;
+               for (i = 0; i < pointsLen; ++i) {
+                       pointCurrent = pointsWithTangents[i];
+                       if (pointCurrent.model.skip) {
+                               continue;
+                       }
+
+                       pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
+                       pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
+                       if (pointBefore && !pointBefore.model.skip) {
+                               deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3;
+                               pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX;
+                               pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK;
+                       }
+                       if (pointAfter && !pointAfter.model.skip) {
+                               deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3;
+                               pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX;
+                               pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK;
+                       }
+               }
+       };
+       helpers$1.nextItem = function(collection, index, loop) {
+               if (loop) {
+                       return index >= collection.length - 1 ? collection[0] : collection[index + 1];
+               }
+               return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1];
+       };
+       helpers$1.previousItem = function(collection, index, loop) {
+               if (loop) {
+                       return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
+               }
+               return index <= 0 ? collection[0] : collection[index - 1];
+       };
+       // Implementation of the nice number algorithm used in determining where axis labels will go
+       helpers$1.niceNum = function(range, round) {
+               var exponent = Math.floor(helpers$1.log10(range));
+               var fraction = range / Math.pow(10, exponent);
+               var niceFraction;
+
+               if (round) {
+                       if (fraction < 1.5) {
+                               niceFraction = 1;
+                       } else if (fraction < 3) {
+                               niceFraction = 2;
+                       } else if (fraction < 7) {
+                               niceFraction = 5;
+                       } else {
+                               niceFraction = 10;
+                       }
+               } else if (fraction <= 1.0) {
+                       niceFraction = 1;
+               } else if (fraction <= 2) {
+                       niceFraction = 2;
+               } else if (fraction <= 5) {
+                       niceFraction = 5;
+               } else {
+                       niceFraction = 10;
+               }
+
+               return niceFraction * Math.pow(10, exponent);
+       };
+       // Request animation polyfill - https://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
+       helpers$1.requestAnimFrame = (function() {
+               if (typeof window === 'undefined') {
+                       return function(callback) {
+                               callback();
+                       };
+               }
+               return window.requestAnimationFrame ||
+                       window.webkitRequestAnimationFrame ||
+                       window.mozRequestAnimationFrame ||
+                       window.oRequestAnimationFrame ||
+                       window.msRequestAnimationFrame ||
+                       function(callback) {
+                               return window.setTimeout(callback, 1000 / 60);
+                       };
+       }());
+       // -- DOM methods
+       helpers$1.getRelativePosition = function(evt, chart) {
+               var mouseX, mouseY;
+               var e = evt.originalEvent || evt;
+               var canvas = evt.target || evt.srcElement;
+               var boundingRect = canvas.getBoundingClientRect();
+
+               var touches = e.touches;
+               if (touches && touches.length > 0) {
+                       mouseX = touches[0].clientX;
+                       mouseY = touches[0].clientY;
+
+               } else {
+                       mouseX = e.clientX;
+                       mouseY = e.clientY;
+               }
+
+               // Scale mouse coordinates into canvas coordinates
+               // by following the pattern laid out by 'jerryj' in the comments of
+               // https://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
+               var paddingLeft = parseFloat(helpers$1.getStyle(canvas, 'padding-left'));
+               var paddingTop = parseFloat(helpers$1.getStyle(canvas, 'padding-top'));
+               var paddingRight = parseFloat(helpers$1.getStyle(canvas, 'padding-right'));
+               var paddingBottom = parseFloat(helpers$1.getStyle(canvas, 'padding-bottom'));
+               var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;
+               var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;
+
+               // We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
+               // the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
+               mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio);
+               mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio);
+
+               return {
+                       x: mouseX,
+                       y: mouseY
+               };
+
+       };
+
+       // Private helper function to convert max-width/max-height values that may be percentages into a number
+       function parseMaxStyle(styleValue, node, parentProperty) {
+               var valueInPixels;
+               if (typeof styleValue === 'string') {
+                       valueInPixels = parseInt(styleValue, 10);
+
+                       if (styleValue.indexOf('%') !== -1) {
+                               // percentage * size in dimension
+                               valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
+                       }
+               } else {
+                       valueInPixels = styleValue;
+               }
+
+               return valueInPixels;
+       }
+
+       /**
+        * Returns if the given value contains an effective constraint.
+        * @private
+        */
+       function isConstrainedValue(value) {
+               return value !== undefined && value !== null && value !== 'none';
+       }
+
+       /**
+        * Returns the max width or height of the given DOM node in a cross-browser compatible fashion
+        * @param {HTMLElement} domNode - the node to check the constraint on
+        * @param {string} maxStyle - the style that defines the maximum for the direction we are using ('max-width' / 'max-height')
+        * @param {string} percentageProperty - property of parent to use when calculating width as a percentage
+        * @see {@link https://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser}
+        */
+       function getConstraintDimension(domNode, maxStyle, percentageProperty) {
+               var view = document.defaultView;
+               var parentNode = helpers$1._getParentNode(domNode);
+               var constrainedNode = view.getComputedStyle(domNode)[maxStyle];
+               var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];
+               var hasCNode = isConstrainedValue(constrainedNode);
+               var hasCContainer = isConstrainedValue(constrainedContainer);
+               var infinity = Number.POSITIVE_INFINITY;
+
+               if (hasCNode || hasCContainer) {
+                       return Math.min(
+                               hasCNode ? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,
+                               hasCContainer ? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);
+               }
+
+               return 'none';
+       }
+       // returns Number or undefined if no constraint
+       helpers$1.getConstraintWidth = function(domNode) {
+               return getConstraintDimension(domNode, 'max-width', 'clientWidth');
+       };
+       // returns Number or undefined if no constraint
+       helpers$1.getConstraintHeight = function(domNode) {
+               return getConstraintDimension(domNode, 'max-height', 'clientHeight');
+       };
+       /**
+        * @private
+        */
+       helpers$1._calculatePadding = function(container, padding, parentDimension) {
+               padding = helpers$1.getStyle(container, padding);
+
+               return padding.indexOf('%') > -1 ? parentDimension * parseInt(padding, 10) / 100 : parseInt(padding, 10);
+       };
+       /**
+        * @private
+        */
+       helpers$1._getParentNode = function(domNode) {
+               var parent = domNode.parentNode;
+               if (parent && parent.toString() === '[object ShadowRoot]') {
+                       parent = parent.host;
+               }
+               return parent;
+       };
+       helpers$1.getMaximumWidth = function(domNode) {
+               var container = helpers$1._getParentNode(domNode);
+               if (!container) {
+                       return domNode.clientWidth;
+               }
+
+               var clientWidth = container.clientWidth;
+               var paddingLeft = helpers$1._calculatePadding(container, 'padding-left', clientWidth);
+               var paddingRight = helpers$1._calculatePadding(container, 'padding-right', clientWidth);
+
+               var w = clientWidth - paddingLeft - paddingRight;
+               var cw = helpers$1.getConstraintWidth(domNode);
+               return isNaN(cw) ? w : Math.min(w, cw);
+       };
+       helpers$1.getMaximumHeight = function(domNode) {
+               var container = helpers$1._getParentNode(domNode);
+               if (!container) {
+                       return domNode.clientHeight;
+               }
+
+               var clientHeight = container.clientHeight;
+               var paddingTop = helpers$1._calculatePadding(container, 'padding-top', clientHeight);
+               var paddingBottom = helpers$1._calculatePadding(container, 'padding-bottom', clientHeight);
+
+               var h = clientHeight - paddingTop - paddingBottom;
+               var ch = helpers$1.getConstraintHeight(domNode);
+               return isNaN(ch) ? h : Math.min(h, ch);
+       };
+       helpers$1.getStyle = function(el, property) {
+               return el.currentStyle ?
+                       el.currentStyle[property] :
+                       document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
+       };
+       helpers$1.retinaScale = function(chart, forceRatio) {
+               var pixelRatio = chart.currentDevicePixelRatio = forceRatio || (typeof window !== 'undefined' && window.devicePixelRatio) || 1;
+               if (pixelRatio === 1) {
+                       return;
+               }
+
+               var canvas = chart.canvas;
+               var height = chart.height;
+               var width = chart.width;
+
+               canvas.height = height * pixelRatio;
+               canvas.width = width * pixelRatio;
+               chart.ctx.scale(pixelRatio, pixelRatio);
+
+               // If no style has been set on the canvas, the render size is used as display size,
+               // making the chart visually bigger, so let's enforce it to the "correct" values.
+               // See https://github.com/chartjs/Chart.js/issues/3575
+               if (!canvas.style.height && !canvas.style.width) {
+                       canvas.style.height = height + 'px';
+                       canvas.style.width = width + 'px';
+               }
+       };
+       // -- Canvas methods
+       helpers$1.fontString = function(pixelSize, fontStyle, fontFamily) {
+               return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
+       };
+       helpers$1.longestText = function(ctx, font, arrayOfThings, cache) {
+               cache = cache || {};
+               var data = cache.data = cache.data || {};
+               var gc = cache.garbageCollect = cache.garbageCollect || [];
+
+               if (cache.font !== font) {
+                       data = cache.data = {};
+                       gc = cache.garbageCollect = [];
+                       cache.font = font;
+               }
+
+               ctx.font = font;
+               var longest = 0;
+               helpers$1.each(arrayOfThings, function(thing) {
+                       // Undefined strings and arrays should not be measured
+                       if (thing !== undefined && thing !== null && helpers$1.isArray(thing) !== true) {
+                               longest = helpers$1.measureText(ctx, data, gc, longest, thing);
+                       } else if (helpers$1.isArray(thing)) {
+                               // if it is an array lets measure each element
+                               // to do maybe simplify this function a bit so we can do this more recursively?
+                               helpers$1.each(thing, function(nestedThing) {
+                                       // Undefined strings and arrays should not be measured
+                                       if (nestedThing !== undefined && nestedThing !== null && !helpers$1.isArray(nestedThing)) {
+                                               longest = helpers$1.measureText(ctx, data, gc, longest, nestedThing);
+                                       }
+                               });
+                       }
+               });
+
+               var gcLen = gc.length / 2;
+               if (gcLen > arrayOfThings.length) {
+                       for (var i = 0; i < gcLen; i++) {
+                               delete data[gc[i]];
+                       }
+                       gc.splice(0, gcLen);
+               }
+               return longest;
+       };
+       helpers$1.measureText = function(ctx, data, gc, longest, string) {
+               var textWidth = data[string];
+               if (!textWidth) {
+                       textWidth = data[string] = ctx.measureText(string).width;
+                       gc.push(string);
+               }
+               if (textWidth > longest) {
+                       longest = textWidth;
+               }
+               return longest;
+       };
+       helpers$1.numberOfLabelLines = function(arrayOfThings) {
+               var numberOfLines = 1;
+               helpers$1.each(arrayOfThings, function(thing) {
+                       if (helpers$1.isArray(thing)) {
+                               if (thing.length > numberOfLines) {
+                                       numberOfLines = thing.length;
+                               }
+                       }
+               });
+               return numberOfLines;
+       };
+
+       helpers$1.color = !chartjsColor ?
+               function(value) {
+                       console.error('Color.js not found!');
+                       return value;
+               } :
+               function(value) {
+                       /* global CanvasGradient */
+                       if (value instanceof CanvasGradient) {
+                               value = core_defaults.global.defaultColor;
+                       }
+
+                       return chartjsColor(value);
+               };
+
+       helpers$1.getHoverColor = function(colorValue) {
+               /* global CanvasPattern */
+               return (colorValue instanceof CanvasPattern || colorValue instanceof CanvasGradient) ?
+                       colorValue :
+                       helpers$1.color(colorValue).saturate(0.5).darken(0.1).rgbString();
+       };
+};
+
+function abstract() {
+       throw new Error(
+               'This method is not implemented: either no adapter can ' +
+               'be found or an incomplete integration was provided.'
+       );
+}
+
+/**
+ * Date adapter (current used by the time scale)
+ * @namespace Chart._adapters._date
+ * @memberof Chart._adapters
+ * @private
+ */
+
+/**
+ * Currently supported unit string values.
+ * @typedef {('millisecond'|'second'|'minute'|'hour'|'day'|'week'|'month'|'quarter'|'year')}
+ * @memberof Chart._adapters._date
+ * @name Unit
+ */
+
+/**
+ * @class
+ */
+function DateAdapter(options) {
+       this.options = options || {};
+}
+
+helpers$1.extend(DateAdapter.prototype, /** @lends DateAdapter */ {
+       /**
+        * Returns a map of time formats for the supported formatting units defined
+        * in Unit as well as 'datetime' representing a detailed date/time string.
+        * @returns {{string: string}}
+        */
+       formats: abstract,
+
+       /**
+        * Parses the given `value` and return the associated timestamp.
+        * @param {any} value - the value to parse (usually comes from the data)
+        * @param {string} [format] - the expected data format
+        * @returns {(number|null)}
+        * @function
+        */
+       parse: abstract,
+
+       /**
+        * Returns the formatted date in the specified `format` for a given `timestamp`.
+        * @param {number} timestamp - the timestamp to format
+        * @param {string} format - the date/time token
+        * @return {string}
+        * @function
+        */
+       format: abstract,
+
+       /**
+        * Adds the specified `amount` of `unit` to the given `timestamp`.
+        * @param {number} timestamp - the input timestamp
+        * @param {number} amount - the amount to add
+        * @param {Unit} unit - the unit as string
+        * @return {number}
+        * @function
+        */
+       add: abstract,
+
+       /**
+        * Returns the number of `unit` between the given timestamps.
+        * @param {number} max - the input timestamp (reference)
+        * @param {number} min - the timestamp to substract
+        * @param {Unit} unit - the unit as string
+        * @return {number}
+        * @function
+        */
+       diff: abstract,
+
+       /**
+        * Returns start of `unit` for the given `timestamp`.
+        * @param {number} timestamp - the input timestamp
+        * @param {Unit} unit - the unit as string
+        * @param {number} [weekday] - the ISO day of the week with 1 being Monday
+        * and 7 being Sunday (only needed if param *unit* is `isoWeek`).
+        * @function
+        */
+       startOf: abstract,
+
+       /**
+        * Returns end of `unit` for the given `timestamp`.
+        * @param {number} timestamp - the input timestamp
+        * @param {Unit} unit - the unit as string
+        * @function
+        */
+       endOf: abstract,
+
+       // DEPRECATIONS
+
+       /**
+        * Provided for backward compatibility for scale.getValueForPixel(),
+        * this method should be overridden only by the moment adapter.
+        * @deprecated since version 2.8.0
+        * @todo remove at version 3
+        * @private
+        */
+       _create: function(value) {
+               return value;
+       }
+});
+
+DateAdapter.override = function(members) {
+       helpers$1.extend(DateAdapter.prototype, members);
+};
+
+var _date = DateAdapter;
+
+var core_adapters = {
+       _date: _date
+};
+
+/**
+ * Namespace to hold static tick generation functions
+ * @namespace Chart.Ticks
+ */
+var core_ticks = {
+       /**
+        * Namespace to hold formatters for different types of ticks
+        * @namespace Chart.Ticks.formatters
+        */
+       formatters: {
+               /**
+                * Formatter for value labels
+                * @method Chart.Ticks.formatters.values
+                * @param value the value to display
+                * @return {string|string[]} the label to display
+                */
+               values: function(value) {
+                       return helpers$1.isArray(value) ? value : '' + value;
+               },
+
+               /**
+                * Formatter for linear numeric ticks
+                * @method Chart.Ticks.formatters.linear
+                * @param tickValue {number} the value to be formatted
+                * @param index {number} the position of the tickValue parameter in the ticks array
+                * @param ticks {number[]} the list of ticks being converted
+                * @return {string} string representation of the tickValue parameter
+                */
+               linear: function(tickValue, index, ticks) {
+                       // If we have lots of ticks, don't use the ones
+                       var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];
+
+                       // If we have a number like 2.5 as the delta, figure out how many decimal places we need
+                       if (Math.abs(delta) > 1) {
+                               if (tickValue !== Math.floor(tickValue)) {
+                                       // not an integer
+                                       delta = tickValue - Math.floor(tickValue);
+                               }
+                       }
+
+                       var logDelta = helpers$1.log10(Math.abs(delta));
+                       var tickString = '';
+
+                       if (tickValue !== 0) {
+                               var maxTick = Math.max(Math.abs(ticks[0]), Math.abs(ticks[ticks.length - 1]));
+                               if (maxTick < 1e-4) { // all ticks are small numbers; use scientific notation
+                                       var logTick = helpers$1.log10(Math.abs(tickValue));
+                                       tickString = tickValue.toExponential(Math.floor(logTick) - Math.floor(logDelta));
+                               } else {
+                                       var numDecimal = -1 * Math.floor(logDelta);
+                                       numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
+                                       tickString = tickValue.toFixed(numDecimal);
+                               }
+                       } else {
+                               tickString = '0'; // never show decimal places for 0
+                       }
+
+                       return tickString;
+               },
+
+               logarithmic: function(tickValue, index, ticks) {
+                       var remain = tickValue / (Math.pow(10, Math.floor(helpers$1.log10(tickValue))));
+
+                       if (tickValue === 0) {
+                               return '0';
+                       } else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) {
+                               return tickValue.toExponential();
+                       }
+                       return '';
+               }
+       }
+};
+
+var valueOrDefault$9 = helpers$1.valueOrDefault;
+var valueAtIndexOrDefault = helpers$1.valueAtIndexOrDefault;
+
+core_defaults._set('scale', {
+       display: true,
+       position: 'left',
+       offset: false,
+
+       // grid line settings
+       gridLines: {
+               display: true,
+               color: 'rgba(0, 0, 0, 0.1)',
+               lineWidth: 1,
+               drawBorder: true,
+               drawOnChartArea: true,
+               drawTicks: true,
+               tickMarkLength: 10,
+               zeroLineWidth: 1,
+               zeroLineColor: 'rgba(0,0,0,0.25)',
+               zeroLineBorderDash: [],
+               zeroLineBorderDashOffset: 0.0,
+               offsetGridLines: false,
+               borderDash: [],
+               borderDashOffset: 0.0
+       },
+
+       // scale label
+       scaleLabel: {
+               // display property
+               display: false,
+
+               // actual label
+               labelString: '',
+
+               // top/bottom padding
+               padding: {
+                       top: 4,
+                       bottom: 4
+               }
+       },
+
+       // label settings
+       ticks: {
+               beginAtZero: false,
+               minRotation: 0,
+               maxRotation: 50,
+               mirror: false,
+               padding: 0,
+               reverse: false,
+               display: true,
+               autoSkip: true,
+               autoSkipPadding: 0,
+               labelOffset: 0,
+               // We pass through arrays to be rendered as multiline labels, we convert Others to strings here.
+               callback: core_ticks.formatters.values,
+               minor: {},
+               major: {}
+       }
+});
+
+function labelsFromTicks(ticks) {
+       var labels = [];
+       var i, ilen;
+
+       for (i = 0, ilen = ticks.length; i < ilen; ++i) {
+               labels.push(ticks[i].label);
+       }
+
+       return labels;
+}
+
+function getPixelForGridLine(scale, index, offsetGridLines) {
+       var lineValue = scale.getPixelForTick(index);
+
+       if (offsetGridLines) {
+               if (scale.getTicks().length === 1) {
+                       lineValue -= scale.isHorizontal() ?
+                               Math.max(lineValue - scale.left, scale.right - lineValue) :
+                               Math.max(lineValue - scale.top, scale.bottom - lineValue);
+               } else if (index === 0) {
+                       lineValue -= (scale.getPixelForTick(1) - lineValue) / 2;
+               } else {
+                       lineValue -= (lineValue - scale.getPixelForTick(index - 1)) / 2;
+               }
+       }
+       return lineValue;
+}
+
+function computeTextSize(context, tick, font) {
+       return helpers$1.isArray(tick) ?
+               helpers$1.longestText(context, font, tick) :
+               context.measureText(tick).width;
+}
+
+var core_scale = core_element.extend({
+       /**
+        * Get the padding needed for the scale
+        * @method getPadding
+        * @private
+        * @returns {Padding} the necessary padding
+        */
+       getPadding: function() {
+               var me = this;
+               return {
+                       left: me.paddingLeft || 0,
+                       top: me.paddingTop || 0,
+                       right: me.paddingRight || 0,
+                       bottom: me.paddingBottom || 0
+               };
+       },
+
+       /**
+        * Returns the scale tick objects ({label, major})
+        * @since 2.7
+        */
+       getTicks: function() {
+               return this._ticks;
+       },
+
+       // These methods are ordered by lifecyle. Utilities then follow.
+       // Any function defined here is inherited by all scale types.
+       // Any function can be extended by the scale type
+
+       mergeTicksOptions: function() {
+               var ticks = this.options.ticks;
+               if (ticks.minor === false) {
+                       ticks.minor = {
+                               display: false
+                       };
+               }
+               if (ticks.major === false) {
+                       ticks.major = {
+                               display: false
+                       };
+               }
+               for (var key in ticks) {
+                       if (key !== 'major' && key !== 'minor') {
+                               if (typeof ticks.minor[key] === 'undefined') {
+                                       ticks.minor[key] = ticks[key];
+                               }
+                               if (typeof ticks.major[key] === 'undefined') {
+                                       ticks.major[key] = ticks[key];
+                               }
+                       }
+               }
+       },
+       beforeUpdate: function() {
+               helpers$1.callback(this.options.beforeUpdate, [this]);
+       },
+
+       update: function(maxWidth, maxHeight, margins) {
+               var me = this;
+               var i, ilen, labels, label, ticks, tick;
+
+               // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
+               me.beforeUpdate();
+
+               // Absorb the master measurements
+               me.maxWidth = maxWidth;
+               me.maxHeight = maxHeight;
+               me.margins = helpers$1.extend({
+                       left: 0,
+                       right: 0,
+                       top: 0,
+                       bottom: 0
+               }, margins);
+
+               me._maxLabelLines = 0;
+               me.longestLabelWidth = 0;
+               me.longestTextCache = me.longestTextCache || {};
+
+               // Dimensions
+               me.beforeSetDimensions();
+               me.setDimensions();
+               me.afterSetDimensions();
+
+               // Data min/max
+               me.beforeDataLimits();
+               me.determineDataLimits();
+               me.afterDataLimits();
+
+               // Ticks - `this.ticks` is now DEPRECATED!
+               // Internal ticks are now stored as objects in the PRIVATE `this._ticks` member
+               // and must not be accessed directly from outside this class. `this.ticks` being
+               // around for long time and not marked as private, we can't change its structure
+               // without unexpected breaking changes. If you need to access the scale ticks,
+               // use scale.getTicks() instead.
+
+               me.beforeBuildTicks();
+
+               // New implementations should return an array of objects but for BACKWARD COMPAT,
+               // we still support no return (`this.ticks` internally set by calling this method).
+               ticks = me.buildTicks() || [];
+
+               // Allow modification of ticks in callback.
+               ticks = me.afterBuildTicks(ticks) || ticks;
+
+               me.beforeTickToLabelConversion();
+
+               // New implementations should return the formatted tick labels but for BACKWARD
+               // COMPAT, we still support no return (`this.ticks` internally changed by calling
+               // this method and supposed to contain only string values).
+               labels = me.convertTicksToLabels(ticks) || me.ticks;
+
+               me.afterTickToLabelConversion();
+
+               me.ticks = labels;   // BACKWARD COMPATIBILITY
+
+               // IMPORTANT: from this point, we consider that `this.ticks` will NEVER change!
+
+               // BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`)
+               for (i = 0, ilen = labels.length; i < ilen; ++i) {
+                       label = labels[i];
+                       tick = ticks[i];
+                       if (!tick) {
+                               ticks.push(tick = {
+                                       label: label,
+                                       major: false
+                               });
+                       } else {
+                               tick.label = label;
+                       }
+               }
+
+               me._ticks = ticks;
+
+               // Tick Rotation
+               me.beforeCalculateTickRotation();
+               me.calculateTickRotation();
+               me.afterCalculateTickRotation();
+               // Fit
+               me.beforeFit();
+               me.fit();
+               me.afterFit();
+               //
+               me.afterUpdate();
+
+               return me.minSize;
+
+       },
+       afterUpdate: function() {
+               helpers$1.callback(this.options.afterUpdate, [this]);
+       },
+
+       //
+
+       beforeSetDimensions: function() {
+               helpers$1.callback(this.options.beforeSetDimensions, [this]);
+       },
+       setDimensions: function() {
+               var me = this;
+               // Set the unconstrained dimension before label rotation
+               if (me.isHorizontal()) {
+                       // Reset position before calculating rotation
+                       me.width = me.maxWidth;
+                       me.left = 0;
+                       me.right = me.width;
+               } else {
+                       me.height = me.maxHeight;
+
+                       // Reset position before calculating rotation
+                       me.top = 0;
+                       me.bottom = me.height;
+               }
+
+               // Reset padding
+               me.paddingLeft = 0;
+               me.paddingTop = 0;
+               me.paddingRight = 0;
+               me.paddingBottom = 0;
+       },
+       afterSetDimensions: function() {
+               helpers$1.callback(this.options.afterSetDimensions, [this]);
+       },
+
+       // Data limits
+       beforeDataLimits: function() {
+               helpers$1.callback(this.options.beforeDataLimits, [this]);
+       },
+       determineDataLimits: helpers$1.noop,
+       afterDataLimits: function() {
+               helpers$1.callback(this.options.afterDataLimits, [this]);
+       },
+
+       //
+       beforeBuildTicks: function() {
+               helpers$1.callback(this.options.beforeBuildTicks, [this]);
+       },
+       buildTicks: helpers$1.noop,
+       afterBuildTicks: function(ticks) {
+               var me = this;
+               // ticks is empty for old axis implementations here
+               if (helpers$1.isArray(ticks) && ticks.length) {
+                       return helpers$1.callback(me.options.afterBuildTicks, [me, ticks]);
+               }
+               // Support old implementations (that modified `this.ticks` directly in buildTicks)
+               me.ticks = helpers$1.callback(me.options.afterBuildTicks, [me, me.ticks]) || me.ticks;
+               return ticks;
+       },
+
+       beforeTickToLabelConversion: function() {
+               helpers$1.callback(this.options.beforeTickToLabelConversion, [this]);
+       },
+       convertTicksToLabels: function() {
+               var me = this;
+               // Convert ticks to strings
+               var tickOpts = me.options.ticks;
+               me.ticks = me.ticks.map(tickOpts.userCallback || tickOpts.callback, this);
+       },
+       afterTickToLabelConversion: function() {
+               helpers$1.callback(this.options.afterTickToLabelConversion, [this]);
+       },
+
+       //
+
+       beforeCalculateTickRotation: function() {
+               helpers$1.callback(this.options.beforeCalculateTickRotation, [this]);
+       },
+       calculateTickRotation: function() {
+               var me = this;
+               var context = me.ctx;
+               var tickOpts = me.options.ticks;
+               var labels = labelsFromTicks(me._ticks);
+
+               // Get the width of each grid by calculating the difference
+               // between x offsets between 0 and 1.
+               var tickFont = helpers$1.options._parseFont(tickOpts);
+               context.font = tickFont.string;
+
+               var labelRotation = tickOpts.minRotation || 0;
+
+               if (labels.length && me.options.display && me.isHorizontal()) {
+                       var originalLabelWidth = helpers$1.longestText(context, tickFont.string, labels, me.longestTextCache);
+                       var labelWidth = originalLabelWidth;
+                       var cosRotation, sinRotation;
+
+                       // Allow 3 pixels x2 padding either side for label readability
+                       var tickWidth = me.getPixelForTick(1) - me.getPixelForTick(0) - 6;
+
+                       // Max label rotation can be set or default to 90 - also act as a loop counter
+                       while (labelWidth > tickWidth && labelRotation < tickOpts.maxRotation) {
+                               var angleRadians = helpers$1.toRadians(labelRotation);
+                               cosRotation = Math.cos(angleRadians);
+                               sinRotation = Math.sin(angleRadians);
+
+                               if (sinRotation * originalLabelWidth > me.maxHeight) {
+                                       // go back one step
+                                       labelRotation--;
+                                       break;
+                               }
+
+                               labelRotation++;
+                               labelWidth = cosRotation * originalLabelWidth;
+                       }
+               }
+
+               me.labelRotation = labelRotation;
+       },
+       afterCalculateTickRotation: function() {
+               helpers$1.callback(this.options.afterCalculateTickRotation, [this]);
+       },
+
+       //
+
+       beforeFit: function() {
+               helpers$1.callback(this.options.beforeFit, [this]);
+       },
+       fit: function() {
+               var me = this;
+               // Reset
+               var minSize = me.minSize = {
+                       width: 0,
+                       height: 0
+               };
+
+               var labels = labelsFromTicks(me._ticks);
+
+               var opts = me.options;
+               var tickOpts = opts.ticks;
+               var scaleLabelOpts = opts.scaleLabel;
+               var gridLineOpts = opts.gridLines;
+               var display = me._isVisible();
+               var position = opts.position;
+               var isHorizontal = me.isHorizontal();
+
+               var parseFont = helpers$1.options._parseFont;
+               var tickFont = parseFont(tickOpts);
+               var tickMarkLength = opts.gridLines.tickMarkLength;
+
+               // Width
+               if (isHorizontal) {
+                       // subtract the margins to line up with the chartArea if we are a full width scale
+                       minSize.width = me.isFullWidth() ? me.maxWidth - me.margins.left - me.margins.right : me.maxWidth;
+               } else {
+                       minSize.width = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
+               }
+
+               // height
+               if (isHorizontal) {
+                       minSize.height = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
+               } else {
+                       minSize.height = me.maxHeight; // fill all the height
+               }
+
+               // Are we showing a title for the scale?
+               if (scaleLabelOpts.display && display) {
+                       var scaleLabelFont = parseFont(scaleLabelOpts);
+                       var scaleLabelPadding = helpers$1.options.toPadding(scaleLabelOpts.padding);
+                       var deltaHeight = scaleLabelFont.lineHeight + scaleLabelPadding.height;
+
+                       if (isHorizontal) {
+                               minSize.height += deltaHeight;
+                       } else {
+                               minSize.width += deltaHeight;
+                       }
+               }
+
+               // Don't bother fitting the ticks if we are not showing the labels
+               if (tickOpts.display && display) {
+                       var largestTextWidth = helpers$1.longestText(me.ctx, tickFont.string, labels, me.longestTextCache);
+                       var tallestLabelHeightInLines = helpers$1.numberOfLabelLines(labels);
+                       var lineSpace = tickFont.size * 0.5;
+                       var tickPadding = me.options.ticks.padding;
+
+                       // Store max number of lines and widest label for _autoSkip
+                       me._maxLabelLines = tallestLabelHeightInLines;
+                       me.longestLabelWidth = largestTextWidth;
+
+                       if (isHorizontal) {
+                               var angleRadians = helpers$1.toRadians(me.labelRotation);
+                               var cosRotation = Math.cos(angleRadians);
+                               var sinRotation = Math.sin(angleRadians);
+
+                               // TODO - improve this calculation
+                               var labelHeight = (sinRotation * largestTextWidth)
+                                       + (tickFont.lineHeight * tallestLabelHeightInLines)
+                                       + lineSpace; // padding
+
+                               minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding);
+
+                               me.ctx.font = tickFont.string;
+                               var firstLabelWidth = computeTextSize(me.ctx, labels[0], tickFont.string);
+                               var lastLabelWidth = computeTextSize(me.ctx, labels[labels.length - 1], tickFont.string);
+                               var offsetLeft = me.getPixelForTick(0) - me.left;
+                               var offsetRight = me.right - me.getPixelForTick(labels.length - 1);
+                               var paddingLeft, paddingRight;
+
+                               // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned
+                               // which means that the right padding is dominated by the font height
+                               if (me.labelRotation !== 0) {
+                                       paddingLeft = position === 'bottom' ? (cosRotation * firstLabelWidth) : (cosRotation * lineSpace);
+                                       paddingRight = position === 'bottom' ? (cosRotation * lineSpace) : (cosRotation * lastLabelWidth);
+                               } else {
+                                       paddingLeft = firstLabelWidth / 2;
+                                       paddingRight = lastLabelWidth / 2;
+                               }
+                               me.paddingLeft = Math.max(paddingLeft - offsetLeft, 0) + 3; // add 3 px to move away from canvas edges
+                               me.paddingRight = Math.max(paddingRight - offsetRight, 0) + 3;
+                       } else {
+                               // A vertical axis is more constrained by the width. Labels are the
+                               // dominant factor here, so get that length first and account for padding
+                               if (tickOpts.mirror) {
+                                       largestTextWidth = 0;
+                               } else {
+                                       // use lineSpace for consistency with horizontal axis
+                                       // tickPadding is not implemented for horizontal
+                                       largestTextWidth += tickPadding + lineSpace;
+                               }
+
+                               minSize.width = Math.min(me.maxWidth, minSize.width + largestTextWidth);
+
+                               me.paddingTop = tickFont.size / 2;
+                               me.paddingBottom = tickFont.size / 2;
+                       }
+               }
+
+               me.handleMargins();
+
+               me.width = minSize.width;
+               me.height = minSize.height;
+       },
+
+       /**
+        * Handle margins and padding interactions
+        * @private
+        */
+       handleMargins: function() {
+               var me = this;
+               if (me.margins) {
+                       me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
+                       me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0);
+                       me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
+                       me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0);
+               }
+       },
+
+       afterFit: function() {
+               helpers$1.callback(this.options.afterFit, [this]);
+       },
+
+       // Shared Methods
+       isHorizontal: function() {
+               return this.options.position === 'top' || this.options.position === 'bottom';
+       },
+       isFullWidth: function() {
+               return (this.options.fullWidth);
+       },
+
+       // Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
+       getRightValue: function(rawValue) {
+               // Null and undefined values first
+               if (helpers$1.isNullOrUndef(rawValue)) {
+                       return NaN;
+               }
+               // isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values
+               if ((typeof rawValue === 'number' || rawValue instanceof Number) && !isFinite(rawValue)) {
+                       return NaN;
+               }
+               // If it is in fact an object, dive in one more level
+               if (rawValue) {
+                       if (this.isHorizontal()) {
+                               if (rawValue.x !== undefined) {
+                                       return this.getRightValue(rawValue.x);
+                               }
+                       } else if (rawValue.y !== undefined) {
+                               return this.getRightValue(rawValue.y);
+                       }
+               }
+
+               // Value is good, return it
+               return rawValue;
+       },
+
+       /**
+        * Used to get the value to display in the tooltip for the data at the given index
+        * @param index
+        * @param datasetIndex
+        */
+       getLabelForIndex: helpers$1.noop,
+
+       /**
+        * Returns the location of the given data point. Value can either be an index or a numerical value
+        * The coordinate (0, 0) is at the upper-left corner of the canvas
+        * @param value
+        * @param index
+        * @param datasetIndex
+        */
+       getPixelForValue: helpers$1.noop,
+
+       /**
+        * Used to get the data value from a given pixel. This is the inverse of getPixelForValue
+        * The coordinate (0, 0) is at the upper-left corner of the canvas
+        * @param pixel
+        */
+       getValueForPixel: helpers$1.noop,
+
+       /**
+        * Returns the location of the tick at the given index
+        * The coordinate (0, 0) is at the upper-left corner of the canvas
+        */
+       getPixelForTick: function(index) {
+               var me = this;
+               var offset = me.options.offset;
+               if (me.isHorizontal()) {
+                       var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
+                       var tickWidth = innerWidth / Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
+                       var pixel = (tickWidth * index) + me.paddingLeft;
+
+                       if (offset) {
+                               pixel += tickWidth / 2;
+                       }
+
+                       var finalVal = me.left + pixel;
+                       finalVal += me.isFullWidth() ? me.margins.left : 0;
+                       return finalVal;
+               }
+               var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
+               return me.top + (index * (innerHeight / (me._ticks.length - 1)));
+       },
+
+       /**
+        * Utility for getting the pixel location of a percentage of scale
+        * The coordinate (0, 0) is at the upper-left corner of the canvas
+        */
+       getPixelForDecimal: function(decimal) {
+               var me = this;
+               if (me.isHorizontal()) {
+                       var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
+                       var valueOffset = (innerWidth * decimal) + me.paddingLeft;
+
+                       var finalVal = me.left + valueOffset;
+                       finalVal += me.isFullWidth() ? me.margins.left : 0;
+                       return finalVal;
+               }
+               return me.top + (decimal * me.height);
+       },
+
+       /**
+        * Returns the pixel for the minimum chart value
+        * The coordinate (0, 0) is at the upper-left corner of the canvas
+        */
+       getBasePixel: function() {
+               return this.getPixelForValue(this.getBaseValue());
+       },
+
+       getBaseValue: function() {
+               var me = this;
+               var min = me.min;
+               var max = me.max;
+
+               return me.beginAtZero ? 0 :
+                       min < 0 && max < 0 ? max :
+                       min > 0 && max > 0 ? min :
+                       0;
+       },
+
+       /**
+        * Returns a subset of ticks to be plotted to avoid overlapping labels.
+        * @private
+        */
+       _autoSkip: function(ticks) {
+               var me = this;
+               var isHorizontal = me.isHorizontal();
+               var optionTicks = me.options.ticks.minor;
+               var tickCount = ticks.length;
+               var skipRatio = false;
+               var maxTicks = optionTicks.maxTicksLimit;
+
+               // Total space needed to display all ticks. First and last ticks are
+               // drawn as their center at end of axis, so tickCount-1
+               var ticksLength = me._tickSize() * (tickCount - 1);
+
+               // Axis length
+               var axisLength = isHorizontal
+                       ? me.width - (me.paddingLeft + me.paddingRight)
+                       : me.height - (me.paddingTop + me.PaddingBottom);
+
+               var result = [];
+               var i, tick;
+
+               if (ticksLength > axisLength) {
+                       skipRatio = 1 + Math.floor(ticksLength / axisLength);
+               }
+
+               // if they defined a max number of optionTicks,
+               // increase skipRatio until that number is met
+               if (tickCount > maxTicks) {
+                       skipRatio = Math.max(skipRatio, 1 + Math.floor(tickCount / maxTicks));
+               }
+
+               for (i = 0; i < tickCount; i++) {
+                       tick = ticks[i];
+
+                       if (skipRatio > 1 && i % skipRatio > 0) {
+                               // leave tick in place but make sure it's not displayed (#4635)
+                               delete tick.label;
+                       }
+                       result.push(tick);
+               }
+               return result;
+       },
+
+       /**
+        * @private
+        */
+       _tickSize: function() {
+               var me = this;
+               var isHorizontal = me.isHorizontal();
+               var optionTicks = me.options.ticks.minor;
+
+               // Calculate space needed by label in axis direction.
+               var rot = helpers$1.toRadians(me.labelRotation);
+               var cos = Math.abs(Math.cos(rot));
+               var sin = Math.abs(Math.sin(rot));
+
+               var padding = optionTicks.autoSkipPadding || 0;
+               var w = (me.longestLabelWidth + padding) || 0;
+
+               var tickFont = helpers$1.options._parseFont(optionTicks);
+               var h = (me._maxLabelLines * tickFont.lineHeight + padding) || 0;
+
+               // Calculate space needed for 1 tick in axis direction.
+               return isHorizontal
+                       ? h * cos > w * sin ? w / cos : h / sin
+                       : h * sin < w * cos ? h / cos : w / sin;
+       },
+
+       /**
+        * @private
+        */
+       _isVisible: function() {
+               var me = this;
+               var chart = me.chart;
+               var display = me.options.display;
+               var i, ilen, meta;
+
+               if (display !== 'auto') {
+                       return !!display;
+               }
+
+               // When 'auto', the scale is visible if at least one associated dataset is visible.
+               for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
+                       if (chart.isDatasetVisible(i)) {
+                               meta = chart.getDatasetMeta(i);
+                               if (meta.xAxisID === me.id || meta.yAxisID === me.id) {
+                                       return true;
+                               }
+                       }
+               }
+
+               return false;
+       },
+
+       /**
+        * Actually draw the scale on the canvas
+        * @param {object} chartArea - the area of the chart to draw full grid lines on
+        */
+       draw: function(chartArea) {
+               var me = this;
+               var options = me.options;
+
+               if (!me._isVisible()) {
+                       return;
+               }
+
+               var chart = me.chart;
+               var context = me.ctx;
+               var globalDefaults = core_defaults.global;
+               var defaultFontColor = globalDefaults.defaultFontColor;
+               var optionTicks = options.ticks.minor;
+               var optionMajorTicks = options.ticks.major || optionTicks;
+               var gridLines = options.gridLines;
+               var scaleLabel = options.scaleLabel;
+               var position = options.position;
+
+               var isRotated = me.labelRotation !== 0;
+               var isMirrored = optionTicks.mirror;
+               var isHorizontal = me.isHorizontal();
+
+               var parseFont = helpers$1.options._parseFont;
+               var ticks = optionTicks.display && optionTicks.autoSkip ? me._autoSkip(me.getTicks()) : me.getTicks();
+               var tickFontColor = valueOrDefault$9(optionTicks.fontColor, defaultFontColor);
+               var tickFont = parseFont(optionTicks);
+               var lineHeight = tickFont.lineHeight;
+               var majorTickFontColor = valueOrDefault$9(optionMajorTicks.fontColor, defaultFontColor);
+               var majorTickFont = parseFont(optionMajorTicks);
+               var tickPadding = optionTicks.padding;
+               var labelOffset = optionTicks.labelOffset;
+
+               var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;
+
+               var scaleLabelFontColor = valueOrDefault$9(scaleLabel.fontColor, defaultFontColor);
+               var scaleLabelFont = parseFont(scaleLabel);
+               var scaleLabelPadding = helpers$1.options.toPadding(scaleLabel.padding);
+               var labelRotationRadians = helpers$1.toRadians(me.labelRotation);
+
+               var itemsToDraw = [];
+
+               var axisWidth = gridLines.drawBorder ? valueAtIndexOrDefault(gridLines.lineWidth, 0, 0) : 0;
+               var alignPixel = helpers$1._alignPixel;
+               var borderValue, tickStart, tickEnd;
+
+               if (position === 'top') {
+                       borderValue = alignPixel(chart, me.bottom, axisWidth);
+                       tickStart = me.bottom - tl;
+                       tickEnd = borderValue - axisWidth / 2;
+               } else if (position === 'bottom') {
+                       borderValue = alignPixel(chart, me.top, axisWidth);
+                       tickStart = borderValue + axisWidth / 2;
+                       tickEnd = me.top + tl;
+               } else if (position === 'left') {
+                       borderValue = alignPixel(chart, me.right, axisWidth);
+                       tickStart = me.right - tl;
+                       tickEnd = borderValue - axisWidth / 2;
+               } else {
+                       borderValue = alignPixel(chart, me.left, axisWidth);
+                       tickStart = borderValue + axisWidth / 2;
+                       tickEnd = me.left + tl;
+               }
+
+               var epsilon = 0.0000001; // 0.0000001 is margin in pixels for Accumulated error.
+
+               helpers$1.each(ticks, function(tick, index) {
+                       // autoskipper skipped this tick (#4635)
+                       if (helpers$1.isNullOrUndef(tick.label)) {
+                               return;
+                       }
+
+                       var label = tick.label;
+                       var lineWidth, lineColor, borderDash, borderDashOffset;
+                       if (index === me.zeroLineIndex && options.offset === gridLines.offsetGridLines) {
+                               // Draw the first index specially
+                               lineWidth = gridLines.zeroLineWidth;
+                               lineColor = gridLines.zeroLineColor;
+                               borderDash = gridLines.zeroLineBorderDash || [];
+                               borderDashOffset = gridLines.zeroLineBorderDashOffset || 0.0;
+                       } else {
+                               lineWidth = valueAtIndexOrDefault(gridLines.lineWidth, index);
+                               lineColor = valueAtIndexOrDefault(gridLines.color, index);
+                               borderDash = gridLines.borderDash || [];
+                               borderDashOffset = gridLines.borderDashOffset || 0.0;
+                       }
+
+                       // Common properties
+                       var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY, textOffset, textAlign;
+                       var labelCount = helpers$1.isArray(label) ? label.length : 1;
+                       var lineValue = getPixelForGridLine(me, index, gridLines.offsetGridLines);
+
+                       if (isHorizontal) {
+                               var labelYOffset = tl + tickPadding;
+
+                               if (lineValue < me.left - epsilon) {
+                                       lineColor = 'rgba(0,0,0,0)';
+                               }
+
+                               tx1 = tx2 = x1 = x2 = alignPixel(chart, lineValue, lineWidth);
+                               ty1 = tickStart;
+                               ty2 = tickEnd;
+                               labelX = me.getPixelForTick(index) + labelOffset; // x values for optionTicks (need to consider offsetLabel option)
+
+                               if (position === 'top') {
+                                       y1 = alignPixel(chart, chartArea.top, axisWidth) + axisWidth / 2;
+                                       y2 = chartArea.bottom;
+                                       textOffset = ((!isRotated ? 0.5 : 1) - labelCount) * lineHeight;
+                                       textAlign = !isRotated ? 'center' : 'left';
+                                       labelY = me.bottom - labelYOffset;
+                               } else {
+                                       y1 = chartArea.top;
+                                       y2 = alignPixel(chart, chartArea.bottom, axisWidth) - axisWidth / 2;
+                                       textOffset = (!isRotated ? 0.5 : 0) * lineHeight;
+                                       textAlign = !isRotated ? 'center' : 'right';
+                                       labelY = me.top + labelYOffset;
+                               }
+                       } else {
+                               var labelXOffset = (isMirrored ? 0 : tl) + tickPadding;
+
+                               if (lineValue < me.top - epsilon) {
+                                       lineColor = 'rgba(0,0,0,0)';
+                               }
+
+                               tx1 = tickStart;
+                               tx2 = tickEnd;
+                               ty1 = ty2 = y1 = y2 = alignPixel(chart, lineValue, lineWidth);
+                               labelY = me.getPixelForTick(index) + labelOffset;
+                               textOffset = (1 - labelCount) * lineHeight / 2;
+
+                               if (position === 'left') {
+                                       x1 = alignPixel(chart, chartArea.left, axisWidth) + axisWidth / 2;
+                                       x2 = chartArea.right;
+                                       textAlign = isMirrored ? 'left' : 'right';
+                                       labelX = me.right - labelXOffset;
+                               } else {
+                                       x1 = chartArea.left;
+                                       x2 = alignPixel(chart, chartArea.right, axisWidth) - axisWidth / 2;
+                                       textAlign = isMirrored ? 'right' : 'left';
+                                       labelX = me.left + labelXOffset;
+                               }
+                       }
+
+                       itemsToDraw.push({
+                               tx1: tx1,
+                               ty1: ty1,
+                               tx2: tx2,
+                               ty2: ty2,
+                               x1: x1,
+                               y1: y1,
+                               x2: x2,
+                               y2: y2,
+                               labelX: labelX,
+                               labelY: labelY,
+                               glWidth: lineWidth,
+                               glColor: lineColor,
+                               glBorderDash: borderDash,
+                               glBorderDashOffset: borderDashOffset,
+                               rotation: -1 * labelRotationRadians,
+                               label: label,
+                               major: tick.major,
+                               textOffset: textOffset,
+                               textAlign: textAlign
+                       });
+               });
+
+               // Draw all of the tick labels, tick marks, and grid lines at the correct places
+               helpers$1.each(itemsToDraw, function(itemToDraw) {
+                       var glWidth = itemToDraw.glWidth;
+                       var glColor = itemToDraw.glColor;
+
+                       if (gridLines.display && glWidth && glColor) {
+                               context.save();
+                               context.lineWidth = glWidth;
+                               context.strokeStyle = glColor;
+                               if (context.setLineDash) {
+                                       context.setLineDash(itemToDraw.glBorderDash);
+                                       context.lineDashOffset = itemToDraw.glBorderDashOffset;
+                               }
+
+                               context.beginPath();
+
+                               if (gridLines.drawTicks) {
+                                       context.moveTo(itemToDraw.tx1, itemToDraw.ty1);
+                                       context.lineTo(itemToDraw.tx2, itemToDraw.ty2);
+                               }
+
+                               if (gridLines.drawOnChartArea) {
+                                       context.moveTo(itemToDraw.x1, itemToDraw.y1);
+                                       context.lineTo(itemToDraw.x2, itemToDraw.y2);
+                               }
+
+                               context.stroke();
+                               context.restore();
+                       }
+
+                       if (optionTicks.display) {
+                               // Make sure we draw text in the correct color and font
+                               context.save();
+                               context.translate(itemToDraw.labelX, itemToDraw.labelY);
+                               context.rotate(itemToDraw.rotation);
+                               context.font = itemToDraw.major ? majorTickFont.string : tickFont.string;
+                               context.fillStyle = itemToDraw.major ? majorTickFontColor : tickFontColor;
+                               context.textBaseline = 'middle';
+                               context.textAlign = itemToDraw.textAlign;
+
+                               var label = itemToDraw.label;
+                               var y = itemToDraw.textOffset;
+                               if (helpers$1.isArray(label)) {
+                                       for (var i = 0; i < label.length; ++i) {
+                                               // We just make sure the multiline element is a string here..
+                                               context.fillText('' + label[i], 0, y);
+                                               y += lineHeight;
+                                       }
+                               } else {
+                                       context.fillText(label, 0, y);
+                               }
+                               context.restore();
+                       }
+               });
+
+               if (scaleLabel.display) {
+                       // Draw the scale label
+                       var scaleLabelX;
+                       var scaleLabelY;
+                       var rotation = 0;
+                       var halfLineHeight = scaleLabelFont.lineHeight / 2;
+
+                       if (isHorizontal) {
+                               scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
+                               scaleLabelY = position === 'bottom'
+                                       ? me.bottom - halfLineHeight - scaleLabelPadding.bottom
+                                       : me.top + halfLineHeight + scaleLabelPadding.top;
+                       } else {
+                               var isLeft = position === 'left';
+                               scaleLabelX = isLeft
+                                       ? me.left + halfLineHeight + scaleLabelPadding.top
+                                       : me.right - halfLineHeight - scaleLabelPadding.top;
+                               scaleLabelY = me.top + ((me.bottom - me.top) / 2);
+                               rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
+                       }
+
+                       context.save();
+                       context.translate(scaleLabelX, scaleLabelY);
+                       context.rotate(rotation);
+                       context.textAlign = 'center';
+                       context.textBaseline = 'middle';
+                       context.fillStyle = scaleLabelFontColor; // render in correct colour
+                       context.font = scaleLabelFont.string;
+                       context.fillText(scaleLabel.labelString, 0, 0);
+                       context.restore();
+               }
+
+               if (axisWidth) {
+                       // Draw the line at the edge of the axis
+                       var firstLineWidth = axisWidth;
+                       var lastLineWidth = valueAtIndexOrDefault(gridLines.lineWidth, ticks.length - 1, 0);
+                       var x1, x2, y1, y2;
+
+                       if (isHorizontal) {
+                               x1 = alignPixel(chart, me.left, firstLineWidth) - firstLineWidth / 2;
+                               x2 = alignPixel(chart, me.right, lastLineWidth) + lastLineWidth / 2;
+                               y1 = y2 = borderValue;
+                       } else {
+                               y1 = alignPixel(chart, me.top, firstLineWidth) - firstLineWidth / 2;
+                               y2 = alignPixel(chart, me.bottom, lastLineWidth) + lastLineWidth / 2;
+                               x1 = x2 = borderValue;
+                       }
+
+                       context.lineWidth = axisWidth;
+                       context.strokeStyle = valueAtIndexOrDefault(gridLines.color, 0);
+                       context.beginPath();
+                       context.moveTo(x1, y1);
+                       context.lineTo(x2, y2);
+                       context.stroke();
+               }
+       }
+});
+
+var defaultConfig = {
+       position: 'bottom'
+};
+
+var scale_category = core_scale.extend({
+       /**
+       * Internal function to get the correct labels. If data.xLabels or data.yLabels are defined, use those
+       * else fall back to data.labels
+       * @private
+       */
+       getLabels: function() {
+               var data = this.chart.data;
+               return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels;
+       },
+
+       determineDataLimits: function() {
+               var me = this;
+               var labels = me.getLabels();
+               me.minIndex = 0;
+               me.maxIndex = labels.length - 1;
+               var findIndex;
+
+               if (me.options.ticks.min !== undefined) {
+                       // user specified min value
+                       findIndex = labels.indexOf(me.options.ticks.min);
+                       me.minIndex = findIndex !== -1 ? findIndex : me.minIndex;
+               }
+
+               if (me.options.ticks.max !== undefined) {
+                       // user specified max value
+                       findIndex = labels.indexOf(me.options.ticks.max);
+                       me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex;
+               }
+
+               me.min = labels[me.minIndex];
+               me.max = labels[me.maxIndex];
+       },
+
+       buildTicks: function() {
+               var me = this;
+               var labels = me.getLabels();
+               // If we are viewing some subset of labels, slice the original array
+               me.ticks = (me.minIndex === 0 && me.maxIndex === labels.length - 1) ? labels : labels.slice(me.minIndex, me.maxIndex + 1);
+       },
+
+       getLabelForIndex: function(index, datasetIndex) {
+               var me = this;
+               var chart = me.chart;
+
+               if (chart.getDatasetMeta(datasetIndex).controller._getValueScaleId() === me.id) {
+                       return me.getRightValue(chart.data.datasets[datasetIndex].data[index]);
+               }
+
+               return me.ticks[index - me.minIndex];
+       },
+
+       // Used to get data value locations.  Value can either be an index or a numerical value
+       getPixelForValue: function(value, index) {
+               var me = this;
+               var offset = me.options.offset;
+               // 1 is added because we need the length but we have the indexes
+               var offsetAmt = Math.max((me.maxIndex + 1 - me.minIndex - (offset ? 0 : 1)), 1);
+
+               // If value is a data object, then index is the index in the data array,
+               // not the index of the scale. We need to change that.
+               var valueCategory;
+               if (value !== undefined && value !== null) {
+                       valueCategory = me.isHorizontal() ? value.x : value.y;
+               }
+               if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
+                       var labels = me.getLabels();
+                       value = valueCategory || value;
+                       var idx = labels.indexOf(value);
+                       index = idx !== -1 ? idx : index;
+               }
+
+               if (me.isHorizontal()) {
+                       var valueWidth = me.width / offsetAmt;
+                       var widthOffset = (valueWidth * (index - me.minIndex));
+
+                       if (offset) {
+                               widthOffset += (valueWidth / 2);
+                       }
+
+                       return me.left + widthOffset;
+               }
+               var valueHeight = me.height / offsetAmt;
+               var heightOffset = (valueHeight * (index - me.minIndex));
+
+               if (offset) {
+                       heightOffset += (valueHeight / 2);
+               }
+
+               return me.top + heightOffset;
+       },
+
+       getPixelForTick: function(index) {
+               return this.getPixelForValue(this.ticks[index], index + this.minIndex, null);
+       },
+
+       getValueForPixel: function(pixel) {
+               var me = this;
+               var offset = me.options.offset;
+               var value;
+               var offsetAmt = Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
+               var horz = me.isHorizontal();
+               var valueDimension = (horz ? me.width : me.height) / offsetAmt;
+
+               pixel -= horz ? me.left : me.top;
+
+               if (offset) {
+                       pixel -= (valueDimension / 2);
+               }
+
+               if (pixel <= 0) {
+                       value = 0;
+               } else {
+                       value = Math.round(pixel / valueDimension);
+               }
+
+               return value + me.minIndex;
+       },
+
+       getBasePixel: function() {
+               return this.bottom;
+       }
+});
+
+// INTERNAL: static default options, registered in src/index.js
+var _defaults = defaultConfig;
+scale_category._defaults = _defaults;
+
+var noop = helpers$1.noop;
+var isNullOrUndef = helpers$1.isNullOrUndef;
+
+/**
+ * Generate a set of linear ticks
+ * @param generationOptions the options used to generate the ticks
+ * @param dataRange the range of the data
+ * @returns {number[]} array of tick values
+ */
+function generateTicks(generationOptions, dataRange) {
+       var ticks = [];
+       // To get a "nice" value for the tick spacing, we will use the appropriately named
+       // "nice number" algorithm. See https://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
+       // for details.
+
+       var MIN_SPACING = 1e-14;
+       var stepSize = generationOptions.stepSize;
+       var unit = stepSize || 1;
+       var maxNumSpaces = generationOptions.maxTicks - 1;
+       var min = generationOptions.min;
+       var max = generationOptions.max;
+       var precision = generationOptions.precision;
+       var rmin = dataRange.min;
+       var rmax = dataRange.max;
+       var spacing = helpers$1.niceNum((rmax - rmin) / maxNumSpaces / unit) * unit;
+       var factor, niceMin, niceMax, numSpaces;
+
+       // Beyond MIN_SPACING floating point numbers being to lose precision
+       // such that we can't do the math necessary to generate ticks
+       if (spacing < MIN_SPACING && isNullOrUndef(min) && isNullOrUndef(max)) {
+               return [rmin, rmax];
+       }
+
+       numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing);
+       if (numSpaces > maxNumSpaces) {
+               // If the calculated num of spaces exceeds maxNumSpaces, recalculate it
+               spacing = helpers$1.niceNum(numSpaces * spacing / maxNumSpaces / unit) * unit;
+       }
+
+       if (stepSize || isNullOrUndef(precision)) {
+               // If a precision is not specified, calculate factor based on spacing
+               factor = Math.pow(10, helpers$1._decimalPlaces(spacing));
+       } else {
+               // If the user specified a precision, round to that number of decimal places
+               factor = Math.pow(10, precision);
+               spacing = Math.ceil(spacing * factor) / factor;
+       }
+
+       niceMin = Math.floor(rmin / spacing) * spacing;
+       niceMax = Math.ceil(rmax / spacing) * spacing;
+
+       // If min, max and stepSize is set and they make an evenly spaced scale use it.
+       if (stepSize) {
+               // If very close to our whole number, use it.
+               if (!isNullOrUndef(min) && helpers$1.almostWhole(min / spacing, spacing / 1000)) {
+                       niceMin = min;
+               }
+               if (!isNullOrUndef(max) && helpers$1.almostWhole(max / spacing, spacing / 1000)) {
+                       niceMax = max;
+               }
+       }
+
+       numSpaces = (niceMax - niceMin) / spacing;
+       // If very close to our rounded value, use it.
+       if (helpers$1.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
+               numSpaces = Math.round(numSpaces);
+       } else {
+               numSpaces = Math.ceil(numSpaces);
+       }
+
+       niceMin = Math.round(niceMin * factor) / factor;
+       niceMax = Math.round(niceMax * factor) / factor;
+       ticks.push(isNullOrUndef(min) ? niceMin : min);
+       for (var j = 1; j < numSpaces; ++j) {
+               ticks.push(Math.round((niceMin + j * spacing) * factor) / factor);
+       }
+       ticks.push(isNullOrUndef(max) ? niceMax : max);
+
+       return ticks;
+}
+
+var scale_linearbase = core_scale.extend({
+       getRightValue: function(value) {
+               if (typeof value === 'string') {
+                       return +value;
+               }
+               return core_scale.prototype.getRightValue.call(this, value);
+       },
+
+       handleTickRangeOptions: function() {
+               var me = this;
+               var opts = me.options;
+               var tickOpts = opts.ticks;
+
+               // If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
+               // do nothing since that would make the chart weird. If the user really wants a weird chart
+               // axis, they can manually override it
+               if (tickOpts.beginAtZero) {
+                       var minSign = helpers$1.sign(me.min);
+                       var maxSign = helpers$1.sign(me.max);
+
+                       if (minSign < 0 && maxSign < 0) {
+                               // move the top up to 0
+                               me.max = 0;
+                       } else if (minSign > 0 && maxSign > 0) {
+                               // move the bottom down to 0
+                               me.min = 0;
+                       }
+               }
+
+               var setMin = tickOpts.min !== undefined || tickOpts.suggestedMin !== undefined;
+               var setMax = tickOpts.max !== undefined || tickOpts.suggestedMax !== undefined;
+
+               if (tickOpts.min !== undefined) {
+                       me.min = tickOpts.min;
+               } else if (tickOpts.suggestedMin !== undefined) {
+                       if (me.min === null) {
+                               me.min = tickOpts.suggestedMin;
+                       } else {
+                               me.min = Math.min(me.min, tickOpts.suggestedMin);
+                       }
+               }
+
+               if (tickOpts.max !== undefined) {
+                       me.max = tickOpts.max;
+               } else if (tickOpts.suggestedMax !== undefined) {
+                       if (me.max === null) {
+                               me.max = tickOpts.suggestedMax;
+                       } else {
+                               me.max = Math.max(me.max, tickOpts.suggestedMax);
+                       }
+               }
+
+               if (setMin !== setMax) {
+                       // We set the min or the max but not both.
+                       // So ensure that our range is good
+                       // Inverted or 0 length range can happen when
+                       // ticks.min is set, and no datasets are visible
+                       if (me.min >= me.max) {
+                               if (setMin) {
+                                       me.max = me.min + 1;
+                               } else {
+                                       me.min = me.max - 1;
+                               }
+                       }
+               }
+
+               if (me.min === me.max) {
+                       me.max++;
+
+                       if (!tickOpts.beginAtZero) {
+                               me.min--;
+                       }
+               }
+       },
+
+       getTickLimit: function() {
+               var me = this;
+               var tickOpts = me.options.ticks;
+               var stepSize = tickOpts.stepSize;
+               var maxTicksLimit = tickOpts.maxTicksLimit;
+               var maxTicks;
+
+               if (stepSize) {
+                       maxTicks = Math.ceil(me.max / stepSize) - Math.floor(me.min / stepSize) + 1;
+               } else {
+                       maxTicks = me._computeTickLimit();
+                       maxTicksLimit = maxTicksLimit || 11;
+               }
+
+               if (maxTicksLimit) {
+                       maxTicks = Math.min(maxTicksLimit, maxTicks);
+               }
+
+               return maxTicks;
+       },
+
+       _computeTickLimit: function() {
+               return Number.POSITIVE_INFINITY;
+       },
+
+       handleDirectionalChanges: noop,
+
+       buildTicks: function() {
+               var me = this;
+               var opts = me.options;
+               var tickOpts = opts.ticks;
+
+               // Figure out what the max number of ticks we can support it is based on the size of
+               // the axis area. For now, we say that the minimum tick spacing in pixels must be 40
+               // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
+               // the graph. Make sure we always have at least 2 ticks
+               var maxTicks = me.getTickLimit();
+               maxTicks = Math.max(2, maxTicks);
+
+               var numericGeneratorOptions = {
+                       maxTicks: maxTicks,
+                       min: tickOpts.min,
+                       max: tickOpts.max,
+                       precision: tickOpts.precision,
+                       stepSize: helpers$1.valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)
+               };
+               var ticks = me.ticks = generateTicks(numericGeneratorOptions, me);
+
+               me.handleDirectionalChanges();
+
+               // At this point, we need to update our max and min given the tick values since we have expanded the
+               // range of the scale
+               me.max = helpers$1.max(ticks);
+               me.min = helpers$1.min(ticks);
+
+               if (tickOpts.reverse) {
+                       ticks.reverse();
+
+                       me.start = me.max;
+                       me.end = me.min;
+               } else {
+                       me.start = me.min;
+                       me.end = me.max;
+               }
+       },
+
+       convertTicksToLabels: function() {
+               var me = this;
+               me.ticksAsNumbers = me.ticks.slice();
+               me.zeroLineIndex = me.ticks.indexOf(0);
+
+               core_scale.prototype.convertTicksToLabels.call(me);
+       }
+});
+
+var defaultConfig$1 = {
+       position: 'left',
+       ticks: {
+               callback: core_ticks.formatters.linear
+       }
+};
+
+var scale_linear = scale_linearbase.extend({
+       determineDataLimits: function() {
+               var me = this;
+               var opts = me.options;
+               var chart = me.chart;
+               var data = chart.data;
+               var datasets = data.datasets;
+               var isHorizontal = me.isHorizontal();
+               var DEFAULT_MIN = 0;
+               var DEFAULT_MAX = 1;
+
+               function IDMatches(meta) {
+                       return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
+               }
+
+               // First Calculate the range
+               me.min = null;
+               me.max = null;
+
+               var hasStacks = opts.stacked;
+               if (hasStacks === undefined) {
+                       helpers$1.each(datasets, function(dataset, datasetIndex) {
+                               if (hasStacks) {
+                                       return;
+                               }
+
+                               var meta = chart.getDatasetMeta(datasetIndex);
+                               if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
+                                       meta.stack !== undefined) {
+                                       hasStacks = true;
+                               }
+                       });
+               }
+
+               if (opts.stacked || hasStacks) {
+                       var valuesPerStack = {};
+
+                       helpers$1.each(datasets, function(dataset, datasetIndex) {
+                               var meta = chart.getDatasetMeta(datasetIndex);
+                               var key = [
+                                       meta.type,
+                                       // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
+                                       ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
+                                       meta.stack
+                               ].join('.');
+
+                               if (valuesPerStack[key] === undefined) {
+                                       valuesPerStack[key] = {
+                                               positiveValues: [],
+                                               negativeValues: []
+                                       };
+                               }
+
+                               // Store these per type
+                               var positiveValues = valuesPerStack[key].positiveValues;
+                               var negativeValues = valuesPerStack[key].negativeValues;
+
+                               if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+                                       helpers$1.each(dataset.data, function(rawValue, index) {
+                                               var value = +me.getRightValue(rawValue);
+                                               if (isNaN(value) || meta.data[index].hidden) {
+                                                       return;
+                                               }
+
+                                               positiveValues[index] = positiveValues[index] || 0;
+                                               negativeValues[index] = negativeValues[index] || 0;
+
+                                               if (opts.relativePoints) {
+                                                       positiveValues[index] = 100;
+                                               } else if (value < 0) {
+                                                       negativeValues[index] += value;
+                                               } else {
+                                                       positiveValues[index] += value;
+                                               }
+                                       });
+                               }
+                       });
+
+                       helpers$1.each(valuesPerStack, function(valuesForType) {
+                               var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
+                               var minVal = helpers$1.min(values);
+                               var maxVal = helpers$1.max(values);
+                               me.min = me.min === null ? minVal : Math.min(me.min, minVal);
+                               me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
+                       });
+
+               } else {
+                       helpers$1.each(datasets, function(dataset, datasetIndex) {
+                               var meta = chart.getDatasetMeta(datasetIndex);
+                               if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+                                       helpers$1.each(dataset.data, function(rawValue, index) {
+                                               var value = +me.getRightValue(rawValue);
+                                               if (isNaN(value) || meta.data[index].hidden) {
+                                                       return;
+                                               }
+
+                                               if (me.min === null) {
+                                                       me.min = value;
+                                               } else if (value < me.min) {
+                                                       me.min = value;
+                                               }
+
+                                               if (me.max === null) {
+                                                       me.max = value;
+                                               } else if (value > me.max) {
+                                                       me.max = value;
+                                               }
+                                       });
+                               }
+                       });
+               }
+
+               me.min = isFinite(me.min) && !isNaN(me.min) ? me.min : DEFAULT_MIN;
+               me.max = isFinite(me.max) && !isNaN(me.max) ? me.max : DEFAULT_MAX;
+
+               // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
+               this.handleTickRangeOptions();
+       },
+
+       // Returns the maximum number of ticks based on the scale dimension
+       _computeTickLimit: function() {
+               var me = this;
+               var tickFont;
+
+               if (me.isHorizontal()) {
+                       return Math.ceil(me.width / 40);
+               }
+               tickFont = helpers$1.options._parseFont(me.options.ticks);
+               return Math.ceil(me.height / tickFont.lineHeight);
+       },
+
+       // Called after the ticks are built. We need
+       handleDirectionalChanges: function() {
+               if (!this.isHorizontal()) {
+                       // We are in a vertical orientation. The top value is the highest. So reverse the array
+                       this.ticks.reverse();
+               }
+       },
+
+       getLabelForIndex: function(index, datasetIndex) {
+               return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
+       },
+
+       // Utils
+       getPixelForValue: function(value) {
+               // This must be called after fit has been run so that
+               // this.left, this.top, this.right, and this.bottom have been defined
+               var me = this;
+               var start = me.start;
+
+               var rightValue = +me.getRightValue(value);
+               var pixel;
+               var range = me.end - start;
+
+               if (me.isHorizontal()) {
+                       pixel = me.left + (me.width / range * (rightValue - start));
+               } else {
+                       pixel = me.bottom - (me.height / range * (rightValue - start));
+               }
+               return pixel;
+       },
+
+       getValueForPixel: function(pixel) {
+               var me = this;
+               var isHorizontal = me.isHorizontal();
+               var innerDimension = isHorizontal ? me.width : me.height;
+               var offset = (isHorizontal ? pixel - me.left : me.bottom - pixel) / innerDimension;
+               return me.start + ((me.end - me.start) * offset);
+       },
+
+       getPixelForTick: function(index) {
+               return this.getPixelForValue(this.ticksAsNumbers[index]);
+       }
+});
+
+// INTERNAL: static default options, registered in src/index.js
+var _defaults$1 = defaultConfig$1;
+scale_linear._defaults = _defaults$1;
+
+var valueOrDefault$a = helpers$1.valueOrDefault;
+
+/**
+ * Generate a set of logarithmic ticks
+ * @param generationOptions the options used to generate the ticks
+ * @param dataRange the range of the data
+ * @returns {number[]} array of tick values
+ */
+function generateTicks$1(generationOptions, dataRange) {
+       var ticks = [];
+
+       var tickVal = valueOrDefault$a(generationOptions.min, Math.pow(10, Math.floor(helpers$1.log10(dataRange.min))));
+
+       var endExp = Math.floor(helpers$1.log10(dataRange.max));
+       var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
+       var exp, significand;
+
+       if (tickVal === 0) {
+               exp = Math.floor(helpers$1.log10(dataRange.minNotZero));
+               significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));
+
+               ticks.push(tickVal);
+               tickVal = significand * Math.pow(10, exp);
+       } else {
+               exp = Math.floor(helpers$1.log10(tickVal));
+               significand = Math.floor(tickVal / Math.pow(10, exp));
+       }
+       var precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
+
+       do {
+               ticks.push(tickVal);
+
+               ++significand;
+               if (significand === 10) {
+                       significand = 1;
+                       ++exp;
+                       precision = exp >= 0 ? 1 : precision;
+               }
+
+               tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision;
+       } while (exp < endExp || (exp === endExp && significand < endSignificand));
+
+       var lastTick = valueOrDefault$a(generationOptions.max, tickVal);
+       ticks.push(lastTick);
+
+       return ticks;
+}
+
+var defaultConfig$2 = {
+       position: 'left',
+
+       // label settings
+       ticks: {
+               callback: core_ticks.formatters.logarithmic
+       }
+};
+
+// TODO(v3): change this to positiveOrDefault
+function nonNegativeOrDefault(value, defaultValue) {
+       return helpers$1.isFinite(value) && value >= 0 ? value : defaultValue;
+}
+
+var scale_logarithmic = core_scale.extend({
+       determineDataLimits: function() {
+               var me = this;
+               var opts = me.options;
+               var chart = me.chart;
+               var data = chart.data;
+               var datasets = data.datasets;
+               var isHorizontal = me.isHorizontal();
+               function IDMatches(meta) {
+                       return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
+               }
+
+               // Calculate Range
+               me.min = null;
+               me.max = null;
+               me.minNotZero = null;
+
+               var hasStacks = opts.stacked;
+               if (hasStacks === undefined) {
+                       helpers$1.each(datasets, function(dataset, datasetIndex) {
+                               if (hasStacks) {
+                                       return;
+                               }
+
+                               var meta = chart.getDatasetMeta(datasetIndex);
+                               if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
+                                       meta.stack !== undefined) {
+                                       hasStacks = true;
+                               }
+                       });
+               }
+
+               if (opts.stacked || hasStacks) {
+                       var valuesPerStack = {};
+
+                       helpers$1.each(datasets, function(dataset, datasetIndex) {
+                               var meta = chart.getDatasetMeta(datasetIndex);
+                               var key = [
+                                       meta.type,
+                                       // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
+                                       ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
+                                       meta.stack
+                               ].join('.');
+
+                               if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+                                       if (valuesPerStack[key] === undefined) {
+                                               valuesPerStack[key] = [];
+                                       }
+
+                                       helpers$1.each(dataset.data, function(rawValue, index) {
+                                               var values = valuesPerStack[key];
+                                               var value = +me.getRightValue(rawValue);
+                                               // invalid, hidden and negative values are ignored
+                                               if (isNaN(value) || meta.data[index].hidden || value < 0) {
+                                                       return;
+                                               }
+                                               values[index] = values[index] || 0;
+                                               values[index] += value;
+                                       });
+                               }
+                       });
+
+                       helpers$1.each(valuesPerStack, function(valuesForType) {
+                               if (valuesForType.length > 0) {
+                                       var minVal = helpers$1.min(valuesForType);
+                                       var maxVal = helpers$1.max(valuesForType);
+                                       me.min = me.min === null ? minVal : Math.min(me.min, minVal);
+                                       me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
+                               }
+                       });
+
+               } else {
+                       helpers$1.each(datasets, function(dataset, datasetIndex) {
+                               var meta = chart.getDatasetMeta(datasetIndex);
+                               if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+                                       helpers$1.each(dataset.data, function(rawValue, index) {
+                                               var value = +me.getRightValue(rawValue);
+                                               // invalid, hidden and negative values are ignored
+                                               if (isNaN(value) || meta.data[index].hidden || value < 0) {
+                                                       return;
+                                               }
+
+                                               if (me.min === null) {
+                                                       me.min = value;
+                                               } else if (value < me.min) {
+                                                       me.min = value;
+                                               }
+
+                                               if (me.max === null) {
+                                                       me.max = value;
+                                               } else if (value > me.max) {
+                                                       me.max = value;
+                                               }
+
+                                               if (value !== 0 && (me.minNotZero === null || value < me.minNotZero)) {
+                                                       me.minNotZero = value;
+                                               }
+                                       });
+                               }
+                       });
+               }
+
+               // Common base implementation to handle ticks.min, ticks.max
+               this.handleTickRangeOptions();
+       },
+
+       handleTickRangeOptions: function() {
+               var me = this;
+               var tickOpts = me.options.ticks;
+               var DEFAULT_MIN = 1;
+               var DEFAULT_MAX = 10;
+
+               me.min = nonNegativeOrDefault(tickOpts.min, me.min);
+               me.max = nonNegativeOrDefault(tickOpts.max, me.max);
+
+               if (me.min === me.max) {
+                       if (me.min !== 0 && me.min !== null) {
+                               me.min = Math.pow(10, Math.floor(helpers$1.log10(me.min)) - 1);
+                               me.max = Math.pow(10, Math.floor(helpers$1.log10(me.max)) + 1);
+                       } else {
+                               me.min = DEFAULT_MIN;
+                               me.max = DEFAULT_MAX;
+                       }
+               }
+               if (me.min === null) {
+                       me.min = Math.pow(10, Math.floor(helpers$1.log10(me.max)) - 1);
+               }
+               if (me.max === null) {
+                       me.max = me.min !== 0
+                               ? Math.pow(10, Math.floor(helpers$1.log10(me.min)) + 1)
+                               : DEFAULT_MAX;
+               }
+               if (me.minNotZero === null) {
+                       if (me.min > 0) {
+                               me.minNotZero = me.min;
+                       } else if (me.max < 1) {
+                               me.minNotZero = Math.pow(10, Math.floor(helpers$1.log10(me.max)));
+                       } else {
+                               me.minNotZero = DEFAULT_MIN;
+                       }
+               }
+       },
+
+       buildTicks: function() {
+               var me = this;
+               var tickOpts = me.options.ticks;
+               var reverse = !me.isHorizontal();
+
+               var generationOptions = {
+                       min: nonNegativeOrDefault(tickOpts.min),
+                       max: nonNegativeOrDefault(tickOpts.max)
+               };
+               var ticks = me.ticks = generateTicks$1(generationOptions, me);
+
+               // At this point, we need to update our max and min given the tick values since we have expanded the
+               // range of the scale
+               me.max = helpers$1.max(ticks);
+               me.min = helpers$1.min(ticks);
+
+               if (tickOpts.reverse) {
+                       reverse = !reverse;
+                       me.start = me.max;
+                       me.end = me.min;
+               } else {
+                       me.start = me.min;
+                       me.end = me.max;
+               }
+               if (reverse) {
+                       ticks.reverse();
+               }
+       },
+
+       convertTicksToLabels: function() {
+               this.tickValues = this.ticks.slice();
+
+               core_scale.prototype.convertTicksToLabels.call(this);
+       },
+
+       // Get the correct tooltip label
+       getLabelForIndex: function(index, datasetIndex) {
+               return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
+       },
+
+       getPixelForTick: function(index) {
+               return this.getPixelForValue(this.tickValues[index]);
+       },
+
+       /**
+        * Returns the value of the first tick.
+        * @param {number} value - The minimum not zero value.
+        * @return {number} The first tick value.
+        * @private
+        */
+       _getFirstTickValue: function(value) {
+               var exp = Math.floor(helpers$1.log10(value));
+               var significand = Math.floor(value / Math.pow(10, exp));
+
+               return significand * Math.pow(10, exp);
+       },
+
+       getPixelForValue: function(value) {
+               var me = this;
+               var tickOpts = me.options.ticks;
+               var reverse = tickOpts.reverse;
+               var log10 = helpers$1.log10;
+               var firstTickValue = me._getFirstTickValue(me.minNotZero);
+               var offset = 0;
+               var innerDimension, pixel, start, end, sign;
+
+               value = +me.getRightValue(value);
+               if (reverse) {
+                       start = me.end;
+                       end = me.start;
+                       sign = -1;
+               } else {
+                       start = me.start;
+                       end = me.end;
+                       sign = 1;
+               }
+               if (me.isHorizontal()) {
+                       innerDimension = me.width;
+                       pixel = reverse ? me.right : me.left;
+               } else {
+                       innerDimension = me.height;
+                       sign *= -1; // invert, since the upper-left corner of the canvas is at pixel (0, 0)
+                       pixel = reverse ? me.top : me.bottom;
+               }
+               if (value !== start) {
+                       if (start === 0) { // include zero tick
+                               offset = valueOrDefault$a(tickOpts.fontSize, core_defaults.global.defaultFontSize);
+                               innerDimension -= offset;
+                               start = firstTickValue;
+                       }
+                       if (value !== 0) {
+                               offset += innerDimension / (log10(end) - log10(start)) * (log10(value) - log10(start));
+                       }
+                       pixel += sign * offset;
+               }
+               return pixel;
+       },
+
+       getValueForPixel: function(pixel) {
+               var me = this;
+               var tickOpts = me.options.ticks;
+               var reverse = tickOpts.reverse;
+               var log10 = helpers$1.log10;
+               var firstTickValue = me._getFirstTickValue(me.minNotZero);
+               var innerDimension, start, end, value;
+
+               if (reverse) {
+                       start = me.end;
+                       end = me.start;
+               } else {
+                       start = me.start;
+                       end = me.end;
+               }
+               if (me.isHorizontal()) {
+                       innerDimension = me.width;
+                       value = reverse ? me.right - pixel : pixel - me.left;
+               } else {
+                       innerDimension = me.height;
+                       value = reverse ? pixel - me.top : me.bottom - pixel;
+               }
+               if (value !== start) {
+                       if (start === 0) { // include zero tick
+                               var offset = valueOrDefault$a(tickOpts.fontSize, core_defaults.global.defaultFontSize);
+                               value -= offset;
+                               innerDimension -= offset;
+                               start = firstTickValue;
+                       }
+                       value *= log10(end) - log10(start);
+                       value /= innerDimension;
+                       value = Math.pow(10, log10(start) + value);
+               }
+               return value;
+       }
+});
+
+// INTERNAL: static default options, registered in src/index.js
+var _defaults$2 = defaultConfig$2;
+scale_logarithmic._defaults = _defaults$2;
+
+var valueOrDefault$b = helpers$1.valueOrDefault;
+var valueAtIndexOrDefault$1 = helpers$1.valueAtIndexOrDefault;
+var resolve$7 = helpers$1.options.resolve;
+
+var defaultConfig$3 = {
+       display: true,
+
+       // Boolean - Whether to animate scaling the chart from the centre
+       animate: true,
+       position: 'chartArea',
+
+       angleLines: {
+               display: true,
+               color: 'rgba(0, 0, 0, 0.1)',
+               lineWidth: 1,
+               borderDash: [],
+               borderDashOffset: 0.0
+       },
+
+       gridLines: {
+               circular: false
+       },
+
+       // label settings
+       ticks: {
+               // Boolean - Show a backdrop to the scale label
+               showLabelBackdrop: true,
+
+               // String - The colour of the label backdrop
+               backdropColor: 'rgba(255,255,255,0.75)',
+
+               // Number - The backdrop padding above & below the label in pixels
+               backdropPaddingY: 2,
+
+               // Number - The backdrop padding to the side of the label in pixels
+               backdropPaddingX: 2,
+
+               callback: core_ticks.formatters.linear
+       },
+
+       pointLabels: {
+               // Boolean - if true, show point labels
+               display: true,
+
+               // Number - Point label font size in pixels
+               fontSize: 10,
+
+               // Function - Used to convert point labels
+               callback: function(label) {
+                       return label;
+               }
+       }
+};
+
+function getValueCount(scale) {
+       var opts = scale.options;
+       return opts.angleLines.display || opts.pointLabels.display ? scale.chart.data.labels.length : 0;
+}
+
+function getTickBackdropHeight(opts) {
+       var tickOpts = opts.ticks;
+
+       if (tickOpts.display && opts.display) {
+               return valueOrDefault$b(tickOpts.fontSize, core_defaults.global.defaultFontSize) + tickOpts.backdropPaddingY * 2;
+       }
+       return 0;
+}
+
+function measureLabelSize(ctx, lineHeight, label) {
+       if (helpers$1.isArray(label)) {
+               return {
+                       w: helpers$1.longestText(ctx, ctx.font, label),
+                       h: label.length * lineHeight
+               };
+       }
+
+       return {
+               w: ctx.measureText(label).width,
+               h: lineHeight
+       };
+}
+
+function determineLimits(angle, pos, size, min, max) {
+       if (angle === min || angle === max) {
+               return {
+                       start: pos - (size / 2),
+                       end: pos + (size / 2)
+               };
+       } else if (angle < min || angle > max) {
+               return {
+                       start: pos - size,
+                       end: pos
+               };
+       }
+
+       return {
+               start: pos,
+               end: pos + size
+       };
+}
+
+/**
+ * Helper function to fit a radial linear scale with point labels
+ */
+function fitWithPointLabels(scale) {
+
+       // Right, this is really confusing and there is a lot of maths going on here
+       // The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
+       //
+       // Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
+       //
+       // Solution:
+       //
+       // We assume the radius of the polygon is half the size of the canvas at first
+       // at each index we check if the text overlaps.
+       //
+       // Where it does, we store that angle and that index.
+       //
+       // After finding the largest index and angle we calculate how much we need to remove
+       // from the shape radius to move the point inwards by that x.
+       //
+       // We average the left and right distances to get the maximum shape radius that can fit in the box
+       // along with labels.
+       //
+       // Once we have that, we can find the centre point for the chart, by taking the x text protrusion
+       // on each side, removing that from the size, halving it and adding the left x protrusion width.
+       //
+       // This will mean we have a shape fitted to the canvas, as large as it can be with the labels
+       // and position it in the most space efficient manner
+       //
+       // https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
+
+       var plFont = helpers$1.options._parseFont(scale.options.pointLabels);
+
+       // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
+       // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
+       var furthestLimits = {
+               l: 0,
+               r: scale.width,
+               t: 0,
+               b: scale.height - scale.paddingTop
+       };
+       var furthestAngles = {};
+       var i, textSize, pointPosition;
+
+       scale.ctx.font = plFont.string;
+       scale._pointLabelSizes = [];
+
+       var valueCount = getValueCount(scale);
+       for (i = 0; i < valueCount; i++) {
+               pointPosition = scale.getPointPosition(i, scale.drawingArea + 5);
+               textSize = measureLabelSize(scale.ctx, plFont.lineHeight, scale.pointLabels[i] || '');
+               scale._pointLabelSizes[i] = textSize;
+
+               // Add quarter circle to make degree 0 mean top of circle
+               var angleRadians = scale.getIndexAngle(i);
+               var angle = helpers$1.toDegrees(angleRadians) % 360;
+               var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
+               var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
+
+               if (hLimits.start < furthestLimits.l) {
+                       furthestLimits.l = hLimits.start;
+                       furthestAngles.l = angleRadians;
+               }
+
+               if (hLimits.end > furthestLimits.r) {
+                       furthestLimits.r = hLimits.end;
+                       furthestAngles.r = angleRadians;
+               }
+
+               if (vLimits.start < furthestLimits.t) {
+                       furthestLimits.t = vLimits.start;
+                       furthestAngles.t = angleRadians;
+               }
+
+               if (vLimits.end > furthestLimits.b) {
+                       furthestLimits.b = vLimits.end;
+                       furthestAngles.b = angleRadians;
+               }
+       }
+
+       scale.setReductions(scale.drawingArea, furthestLimits, furthestAngles);
+}
+
+function getTextAlignForAngle(angle) {
+       if (angle === 0 || angle === 180) {
+               return 'center';
+       } else if (angle < 180) {
+               return 'left';
+       }
+
+       return 'right';
+}
+
+function fillText(ctx, text, position, lineHeight) {
+       var y = position.y + lineHeight / 2;
+       var i, ilen;
+
+       if (helpers$1.isArray(text)) {
+               for (i = 0, ilen = text.length; i < ilen; ++i) {
+                       ctx.fillText(text[i], position.x, y);
+                       y += lineHeight;
+               }
+       } else {
+               ctx.fillText(text, position.x, y);
+       }
+}
+
+function adjustPointPositionForLabelHeight(angle, textSize, position) {
+       if (angle === 90 || angle === 270) {
+               position.y -= (textSize.h / 2);
+       } else if (angle > 270 || angle < 90) {
+               position.y -= textSize.h;
+       }
+}
+
+function drawPointLabels(scale) {
+       var ctx = scale.ctx;
+       var opts = scale.options;
+       var angleLineOpts = opts.angleLines;
+       var gridLineOpts = opts.gridLines;
+       var pointLabelOpts = opts.pointLabels;
+       var lineWidth = valueOrDefault$b(angleLineOpts.lineWidth, gridLineOpts.lineWidth);
+       var lineColor = valueOrDefault$b(angleLineOpts.color, gridLineOpts.color);
+       var tickBackdropHeight = getTickBackdropHeight(opts);
+
+       ctx.save();
+       ctx.lineWidth = lineWidth;
+       ctx.strokeStyle = lineColor;
+       if (ctx.setLineDash) {
+               ctx.setLineDash(resolve$7([angleLineOpts.borderDash, gridLineOpts.borderDash, []]));
+               ctx.lineDashOffset = resolve$7([angleLineOpts.borderDashOffset, gridLineOpts.borderDashOffset, 0.0]);
+       }
+
+       var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
+
+       // Point Label Font
+       var plFont = helpers$1.options._parseFont(pointLabelOpts);
+
+       ctx.font = plFont.string;
+       ctx.textBaseline = 'middle';
+
+       for (var i = getValueCount(scale) - 1; i >= 0; i--) {
+               if (angleLineOpts.display && lineWidth && lineColor) {
+                       var outerPosition = scale.getPointPosition(i, outerDistance);
+                       ctx.beginPath();
+                       ctx.moveTo(scale.xCenter, scale.yCenter);
+                       ctx.lineTo(outerPosition.x, outerPosition.y);
+                       ctx.stroke();
+               }
+
+               if (pointLabelOpts.display) {
+                       // Extra pixels out for some label spacing
+                       var extra = (i === 0 ? tickBackdropHeight / 2 : 0);
+                       var pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + 5);
+
+                       // Keep this in loop since we may support array properties here
+                       var pointLabelFontColor = valueAtIndexOrDefault$1(pointLabelOpts.fontColor, i, core_defaults.global.defaultFontColor);
+                       ctx.fillStyle = pointLabelFontColor;
+
+                       var angleRadians = scale.getIndexAngle(i);
+                       var angle = helpers$1.toDegrees(angleRadians);
+                       ctx.textAlign = getTextAlignForAngle(angle);
+                       adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
+                       fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.lineHeight);
+               }
+       }
+       ctx.restore();
+}
+
+function drawRadiusLine(scale, gridLineOpts, radius, index) {
+       var ctx = scale.ctx;
+       var circular = gridLineOpts.circular;
+       var valueCount = getValueCount(scale);
+       var lineColor = valueAtIndexOrDefault$1(gridLineOpts.color, index - 1);
+       var lineWidth = valueAtIndexOrDefault$1(gridLineOpts.lineWidth, index - 1);
+       var pointPosition;
+
+       if ((!circular && !valueCount) || !lineColor || !lineWidth) {
+               return;
+       }
+
+       ctx.save();
+       ctx.strokeStyle = lineColor;
+       ctx.lineWidth = lineWidth;
+       if (ctx.setLineDash) {
+               ctx.setLineDash(gridLineOpts.borderDash || []);
+               ctx.lineDashOffset = gridLineOpts.borderDashOffset || 0.0;
+       }
+
+       ctx.beginPath();
+       if (circular) {
+               // Draw circular arcs between the points
+               ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2);
+       } else {
+               // Draw straight lines connecting each index
+               pointPosition = scale.getPointPosition(0, radius);
+               ctx.moveTo(pointPosition.x, pointPosition.y);
+
+               for (var i = 1; i < valueCount; i++) {
+                       pointPosition = scale.getPointPosition(i, radius);
+                       ctx.lineTo(pointPosition.x, pointPosition.y);
+               }
+       }
+       ctx.closePath();
+       ctx.stroke();
+       ctx.restore();
+}
+
+function numberOrZero(param) {
+       return helpers$1.isNumber(param) ? param : 0;
+}
+
+var scale_radialLinear = scale_linearbase.extend({
+       setDimensions: function() {
+               var me = this;
+
+               // Set the unconstrained dimension before label rotation
+               me.width = me.maxWidth;
+               me.height = me.maxHeight;
+               me.paddingTop = getTickBackdropHeight(me.options) / 2;
+               me.xCenter = Math.floor(me.width / 2);
+               me.yCenter = Math.floor((me.height - me.paddingTop) / 2);
+               me.drawingArea = Math.min(me.height - me.paddingTop, me.width) / 2;
+       },
+
+       determineDataLimits: function() {
+               var me = this;
+               var chart = me.chart;
+               var min = Number.POSITIVE_INFINITY;
+               var max = Number.NEGATIVE_INFINITY;
+
+               helpers$1.each(chart.data.datasets, function(dataset, datasetIndex) {
+                       if (chart.isDatasetVisible(datasetIndex)) {
+                               var meta = chart.getDatasetMeta(datasetIndex);
+
+                               helpers$1.each(dataset.data, function(rawValue, index) {
+                                       var value = +me.getRightValue(rawValue);
+                                       if (isNaN(value) || meta.data[index].hidden) {
+                                               return;
+                                       }
+
+                                       min = Math.min(value, min);
+                                       max = Math.max(value, max);
+                               });
+                       }
+               });
+
+               me.min = (min === Number.POSITIVE_INFINITY ? 0 : min);
+               me.max = (max === Number.NEGATIVE_INFINITY ? 0 : max);
+
+               // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
+               me.handleTickRangeOptions();
+       },
+
+       // Returns the maximum number of ticks based on the scale dimension
+       _computeTickLimit: function() {
+               return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options));
+       },
+
+       convertTicksToLabels: function() {
+               var me = this;
+
+               scale_linearbase.prototype.convertTicksToLabels.call(me);
+
+               // Point labels
+               me.pointLabels = me.chart.data.labels.map(me.options.pointLabels.callback, me);
+       },
+
+       getLabelForIndex: function(index, datasetIndex) {
+               return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
+       },
+
+       fit: function() {
+               var me = this;
+               var opts = me.options;
+
+               if (opts.display && opts.pointLabels.display) {
+                       fitWithPointLabels(me);
+               } else {
+                       me.setCenterPoint(0, 0, 0, 0);
+               }
+       },
+
+       /**
+        * Set radius reductions and determine new radius and center point
+        * @private
+        */
+       setReductions: function(largestPossibleRadius, furthestLimits, furthestAngles) {
+               var me = this;
+               var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
+               var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);
+               var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
+               var radiusReductionBottom = -Math.max(furthestLimits.b - (me.height - me.paddingTop), 0) / Math.cos(furthestAngles.b);
+
+               radiusReductionLeft = numberOrZero(radiusReductionLeft);
+               radiusReductionRight = numberOrZero(radiusReductionRight);
+               radiusReductionTop = numberOrZero(radiusReductionTop);
+               radiusReductionBottom = numberOrZero(radiusReductionBottom);
+
+               me.drawingArea = Math.min(
+                       Math.floor(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),
+                       Math.floor(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));
+               me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
+       },
+
+       setCenterPoint: function(leftMovement, rightMovement, topMovement, bottomMovement) {
+               var me = this;
+               var maxRight = me.width - rightMovement - me.drawingArea;
+               var maxLeft = leftMovement + me.drawingArea;
+               var maxTop = topMovement + me.drawingArea;
+               var maxBottom = (me.height - me.paddingTop) - bottomMovement - me.drawingArea;
+
+               me.xCenter = Math.floor(((maxLeft + maxRight) / 2) + me.left);
+               me.yCenter = Math.floor(((maxTop + maxBottom) / 2) + me.top + me.paddingTop);
+       },
+
+       getIndexAngle: function(index) {
+               var angleMultiplier = (Math.PI * 2) / getValueCount(this);
+               var startAngle = this.chart.options && this.chart.options.startAngle ?
+                       this.chart.options.startAngle :
+                       0;
+
+               var startAngleRadians = startAngle * Math.PI * 2 / 360;
+
+               // Start from the top instead of right, so remove a quarter of the circle
+               return index * angleMultiplier + startAngleRadians;
+       },
+
+       getDistanceFromCenterForValue: function(value) {
+               var me = this;
+
+               if (value === null) {
+                       return 0; // null always in center
+               }
+
+               // Take into account half font size + the yPadding of the top value
+               var scalingFactor = me.drawingArea / (me.max - me.min);
+               if (me.options.ticks.reverse) {
+                       return (me.max - value) * scalingFactor;
+               }
+               return (value - me.min) * scalingFactor;
+       },
+
+       getPointPosition: function(index, distanceFromCenter) {
+               var me = this;
+               var thisAngle = me.getIndexAngle(index) - (Math.PI / 2);
+               return {
+                       x: Math.cos(thisAngle) * distanceFromCenter + me.xCenter,
+                       y: Math.sin(thisAngle) * distanceFromCenter + me.yCenter
+               };
+       },
+
+       getPointPositionForValue: function(index, value) {
+               return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
+       },
+
+       getBasePosition: function() {
+               var me = this;
+               var min = me.min;
+               var max = me.max;
+
+               return me.getPointPositionForValue(0,
+                       me.beginAtZero ? 0 :
+                       min < 0 && max < 0 ? max :
+                       min > 0 && max > 0 ? min :
+                       0);
+       },
+
+       draw: function() {
+               var me = this;
+               var opts = me.options;
+               var gridLineOpts = opts.gridLines;
+               var tickOpts = opts.ticks;
+
+               if (opts.display) {
+                       var ctx = me.ctx;
+                       var startAngle = this.getIndexAngle(0);
+                       var tickFont = helpers$1.options._parseFont(tickOpts);
+
+                       if (opts.angleLines.display || opts.pointLabels.display) {
+                               drawPointLabels(me);
+                       }
+
+                       helpers$1.each(me.ticks, function(label, index) {
+                               // Don't draw a centre value (if it is minimum)
+                               if (index > 0 || tickOpts.reverse) {
+                                       var yCenterOffset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
+
+                                       // Draw circular lines around the scale
+                                       if (gridLineOpts.display && index !== 0) {
+                                               drawRadiusLine(me, gridLineOpts, yCenterOffset, index);
+                                       }
+
+                                       if (tickOpts.display) {
+                                               var tickFontColor = valueOrDefault$b(tickOpts.fontColor, core_defaults.global.defaultFontColor);
+                                               ctx.font = tickFont.string;
+
+                                               ctx.save();
+                                               ctx.translate(me.xCenter, me.yCenter);
+                                               ctx.rotate(startAngle);
+
+                                               if (tickOpts.showLabelBackdrop) {
+                                                       var labelWidth = ctx.measureText(label).width;
+                                                       ctx.fillStyle = tickOpts.backdropColor;
+                                                       ctx.fillRect(
+                                                               -labelWidth / 2 - tickOpts.backdropPaddingX,
+                                                               -yCenterOffset - tickFont.size / 2 - tickOpts.backdropPaddingY,
+                                                               labelWidth + tickOpts.backdropPaddingX * 2,
+                                                               tickFont.size + tickOpts.backdropPaddingY * 2
+                                                       );
+                                               }
+
+                                               ctx.textAlign = 'center';
+                                               ctx.textBaseline = 'middle';
+                                               ctx.fillStyle = tickFontColor;
+                                               ctx.fillText(label, 0, -yCenterOffset);
+                                               ctx.restore();
+                                       }
+                               }
+                       });
+               }
+       }
+});
+
+// INTERNAL: static default options, registered in src/index.js
+var _defaults$3 = defaultConfig$3;
+scale_radialLinear._defaults = _defaults$3;
+
+var valueOrDefault$c = helpers$1.valueOrDefault;
+
+// Integer constants are from the ES6 spec.
+var MIN_INTEGER = Number.MIN_SAFE_INTEGER || -9007199254740991;
+var MAX_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
+
+var INTERVALS = {
+       millisecond: {
+               common: true,
+               size: 1,
+               steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
+       },
+       second: {
+               common: true,
+               size: 1000,
+               steps: [1, 2, 5, 10, 15, 30]
+       },
+       minute: {
+               common: true,
+               size: 60000,
+               steps: [1, 2, 5, 10, 15, 30]
+       },
+       hour: {
+               common: true,
+               size: 3600000,
+               steps: [1, 2, 3, 6, 12]
+       },
+       day: {
+               common: true,
+               size: 86400000,
+               steps: [1, 2, 5]
+       },
+       week: {
+               common: false,
+               size: 604800000,
+               steps: [1, 2, 3, 4]
+       },
+       month: {
+               common: true,
+               size: 2.628e9,
+               steps: [1, 2, 3]
+       },
+       quarter: {
+               common: false,
+               size: 7.884e9,
+               steps: [1, 2, 3, 4]
+       },
+       year: {
+               common: true,
+               size: 3.154e10
+       }
+};
+
+var UNITS = Object.keys(INTERVALS);
+
+function sorter(a, b) {
+       return a - b;
+}
+
+function arrayUnique(items) {
+       var hash = {};
+       var out = [];
+       var i, ilen, item;
+
+       for (i = 0, ilen = items.length; i < ilen; ++i) {
+               item = items[i];
+               if (!hash[item]) {
+                       hash[item] = true;
+                       out.push(item);
+               }
+       }
+
+       return out;
+}
+
+/**
+ * Returns an array of {time, pos} objects used to interpolate a specific `time` or position
+ * (`pos`) on the scale, by searching entries before and after the requested value. `pos` is
+ * a decimal between 0 and 1: 0 being the start of the scale (left or top) and 1 the other
+ * extremity (left + width or top + height). Note that it would be more optimized to directly
+ * store pre-computed pixels, but the scale dimensions are not guaranteed at the time we need
+ * to create the lookup table. The table ALWAYS contains at least two items: min and max.
+ *
+ * @param {number[]} timestamps - timestamps sorted from lowest to highest.
+ * @param {string} distribution - If 'linear', timestamps will be spread linearly along the min
+ * and max range, so basically, the table will contains only two items: {min, 0} and {max, 1}.
+ * If 'series', timestamps will be positioned at the same distance from each other. In this
+ * case, only timestamps that break the time linearity are registered, meaning that in the
+ * best case, all timestamps are linear, the table contains only min and max.
+ */
+function buildLookupTable(timestamps, min, max, distribution) {
+       if (distribution === 'linear' || !timestamps.length) {
+               return [
+                       {time: min, pos: 0},
+                       {time: max, pos: 1}
+               ];
+       }
+
+       var table = [];
+       var items = [min];
+       var i, ilen, prev, curr, next;
+
+       for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
+               curr = timestamps[i];
+               if (curr > min && curr < max) {
+                       items.push(curr);
+               }
+       }
+
+       items.push(max);
+
+       for (i = 0, ilen = items.length; i < ilen; ++i) {
+               next = items[i + 1];
+               prev = items[i - 1];
+               curr = items[i];
+
+               // only add points that breaks the scale linearity
+               if (prev === undefined || next === undefined || Math.round((next + prev) / 2) !== curr) {
+                       table.push({time: curr, pos: i / (ilen - 1)});
+               }
+       }
+
+       return table;
+}
+
+// @see adapted from https://www.anujgakhar.com/2014/03/01/binary-search-in-javascript/
+function lookup(table, key, value) {
+       var lo = 0;
+       var hi = table.length - 1;
+       var mid, i0, i1;
+
+       while (lo >= 0 && lo <= hi) {
+               mid = (lo + hi) >> 1;
+               i0 = table[mid - 1] || null;
+               i1 = table[mid];
+
+               if (!i0) {
+                       // given value is outside table (before first item)
+                       return {lo: null, hi: i1};
+               } else if (i1[key] < value) {
+                       lo = mid + 1;
+               } else if (i0[key] > value) {
+                       hi = mid - 1;
+               } else {
+                       return {lo: i0, hi: i1};
+               }
+       }
+
+       // given value is outside table (after last item)
+       return {lo: i1, hi: null};
+}
+
+/**
+ * Linearly interpolates the given source `value` using the table items `skey` values and
+ * returns the associated `tkey` value. For example, interpolate(table, 'time', 42, 'pos')
+ * returns the position for a timestamp equal to 42. If value is out of bounds, values at
+ * index [0, 1] or [n - 1, n] are used for the interpolation.
+ */
+function interpolate$1(table, skey, sval, tkey) {
+       var range = lookup(table, skey, sval);
+
+       // Note: the lookup table ALWAYS contains at least 2 items (min and max)
+       var prev = !range.lo ? table[0] : !range.hi ? table[table.length - 2] : range.lo;
+       var next = !range.lo ? table[1] : !range.hi ? table[table.length - 1] : range.hi;
+
+       var span = next[skey] - prev[skey];
+       var ratio = span ? (sval - prev[skey]) / span : 0;
+       var offset = (next[tkey] - prev[tkey]) * ratio;
+
+       return prev[tkey] + offset;
+}
+
+function toTimestamp(scale, input) {
+       var adapter = scale._adapter;
+       var options = scale.options.time;
+       var parser = options.parser;
+       var format = parser || options.format;
+       var value = input;
+
+       if (typeof parser === 'function') {
+               value = parser(value);
+       }
+
+       // Only parse if its not a timestamp already
+       if (!helpers$1.isFinite(value)) {
+               value = typeof format === 'string'
+                       ? adapter.parse(value, format)
+                       : adapter.parse(value);
+       }
+
+       if (value !== null) {
+               return +value;
+       }
+
+       // Labels are in an incompatible format and no `parser` has been provided.
+       // The user might still use the deprecated `format` option for parsing.
+       if (!parser && typeof format === 'function') {
+               value = format(input);
+
+               // `format` could return something else than a timestamp, if so, parse it
+               if (!helpers$1.isFinite(value)) {
+                       value = adapter.parse(value);
+               }
+       }
+
+       return value;
+}
+
+function parse(scale, input) {
+       if (helpers$1.isNullOrUndef(input)) {
+               return null;
+       }
+
+       var options = scale.options.time;
+       var value = toTimestamp(scale, scale.getRightValue(input));
+       if (value === null) {
+               return value;
+       }
+
+       if (options.round) {
+               value = +scale._adapter.startOf(value, options.round);
+       }
+
+       return value;
+}
+
+/**
+ * Returns the number of unit to skip to be able to display up to `capacity` number of ticks
+ * in `unit` for the given `min` / `max` range and respecting the interval steps constraints.
+ */
+function determineStepSize(min, max, unit, capacity) {
+       var range = max - min;
+       var interval = INTERVALS[unit];
+       var milliseconds = interval.size;
+       var steps = interval.steps;
+       var i, ilen, factor;
+
+       if (!steps) {
+               return Math.ceil(range / (capacity * milliseconds));
+       }
+
+       for (i = 0, ilen = steps.length; i < ilen; ++i) {
+               factor = steps[i];
+               if (Math.ceil(range / (milliseconds * factor)) <= capacity) {
+                       break;
+               }
+       }
+
+       return factor;
+}
+
+/**
+ * Figures out what unit results in an appropriate number of auto-generated ticks
+ */
+function determineUnitForAutoTicks(minUnit, min, max, capacity) {
+       var ilen = UNITS.length;
+       var i, interval, factor;
+
+       for (i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) {
+               interval = INTERVALS[UNITS[i]];
+               factor = interval.steps ? interval.steps[interval.steps.length - 1] : MAX_INTEGER;
+
+               if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
+                       return UNITS[i];
+               }
+       }
+
+       return UNITS[ilen - 1];
+}
+
+/**
+ * Figures out what unit to format a set of ticks with
+ */
+function determineUnitForFormatting(scale, ticks, minUnit, min, max) {
+       var ilen = UNITS.length;
+       var i, unit;
+
+       for (i = ilen - 1; i >= UNITS.indexOf(minUnit); i--) {
+               unit = UNITS[i];
+               if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= ticks.length) {
+                       return unit;
+               }
+       }
+
+       return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];
+}
+
+function determineMajorUnit(unit) {
+       for (var i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) {
+               if (INTERVALS[UNITS[i]].common) {
+                       return UNITS[i];
+               }
+       }
+}
+
+/**
+ * Generates a maximum of `capacity` timestamps between min and max, rounded to the
+ * `minor` unit, aligned on the `major` unit and using the given scale time `options`.
+ * Important: this method can return ticks outside the min and max range, it's the
+ * responsibility of the calling code to clamp values if needed.
+ */
+function generate(scale, min, max, capacity) {
+       var adapter = scale._adapter;
+       var options = scale.options;
+       var timeOpts = options.time;
+       var minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, capacity);
+       var major = determineMajorUnit(minor);
+       var stepSize = valueOrDefault$c(timeOpts.stepSize, timeOpts.unitStepSize);
+       var weekday = minor === 'week' ? timeOpts.isoWeekday : false;
+       var majorTicksEnabled = options.ticks.major.enabled;
+       var interval = INTERVALS[minor];
+       var first = min;
+       var last = max;
+       var ticks = [];
+       var time;
+
+       if (!stepSize) {
+               stepSize = determineStepSize(min, max, minor, capacity);
+       }
+
+       // For 'week' unit, handle the first day of week option
+       if (weekday) {
+               first = +adapter.startOf(first, 'isoWeek', weekday);
+               last = +adapter.startOf(last, 'isoWeek', weekday);
+       }
+
+       // Align first/last ticks on unit
+       first = +adapter.startOf(first, weekday ? 'day' : minor);
+       last = +adapter.startOf(last, weekday ? 'day' : minor);
+
+       // Make sure that the last tick include max
+       if (last < max) {
+               last = +adapter.add(last, 1, minor);
+       }
+
+       time = first;
+
+       if (majorTicksEnabled && major && !weekday && !timeOpts.round) {
+               // Align the first tick on the previous `minor` unit aligned on the `major` unit:
+               // we first aligned time on the previous `major` unit then add the number of full
+               // stepSize there is between first and the previous major time.
+               time = +adapter.startOf(time, major);
+               time = +adapter.add(time, ~~((first - time) / (interval.size * stepSize)) * stepSize, minor);
+       }
+
+       for (; time < last; time = +adapter.add(time, stepSize, minor)) {
+               ticks.push(+time);
+       }
+
+       ticks.push(+time);
+
+       return ticks;
+}
+
+/**
+ * Returns the start and end offsets from edges in the form of {start, end}
+ * where each value is a relative width to the scale and ranges between 0 and 1.
+ * They add extra margins on the both sides by scaling down the original scale.
+ * Offsets are added when the `offset` option is true.
+ */
+function computeOffsets(table, ticks, min, max, options) {
+       var start = 0;
+       var end = 0;
+       var first, last;
+
+       if (options.offset && ticks.length) {
+               if (!options.time.min) {
+                       first = interpolate$1(table, 'time', ticks[0], 'pos');
+                       if (ticks.length === 1) {
+                               start = 1 - first;
+                       } else {
+                               start = (interpolate$1(table, 'time', ticks[1], 'pos') - first) / 2;
+                       }
+               }
+               if (!options.time.max) {
+                       last = interpolate$1(table, 'time', ticks[ticks.length - 1], 'pos');
+                       if (ticks.length === 1) {
+                               end = last;
+                       } else {
+                               end = (last - interpolate$1(table, 'time', ticks[ticks.length - 2], 'pos')) / 2;
+                       }
+               }
+       }
+
+       return {start: start, end: end};
+}
+
+function ticksFromTimestamps(scale, values, majorUnit) {
+       var ticks = [];
+       var i, ilen, value, major;
+
+       for (i = 0, ilen = values.length; i < ilen; ++i) {
+               value = values[i];
+               major = majorUnit ? value === +scale._adapter.startOf(value, majorUnit) : false;
+
+               ticks.push({
+                       value: value,
+                       major: major
+               });
+       }
+
+       return ticks;
+}
+
+var defaultConfig$4 = {
+       position: 'bottom',
+
+       /**
+        * Data distribution along the scale:
+        * - 'linear': data are spread according to their time (distances can vary),
+        * - 'series': data are spread at the same distance from each other.
+        * @see https://github.com/chartjs/Chart.js/pull/4507
+        * @since 2.7.0
+        */
+       distribution: 'linear',
+
+       /**
+        * Scale boundary strategy (bypassed by min/max time options)
+        * - `data`: make sure data are fully visible, ticks outside are removed
+        * - `ticks`: make sure ticks are fully visible, data outside are truncated
+        * @see https://github.com/chartjs/Chart.js/pull/4556
+        * @since 2.7.0
+        */
+       bounds: 'data',
+
+       adapters: {},
+       time: {
+               parser: false, // false == a pattern string from https://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment
+               format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from https://momentjs.com/docs/#/parsing/string-format/
+               unit: false, // false == automatic or override with week, month, year, etc.
+               round: false, // none, or override with week, month, year, etc.
+               displayFormat: false, // DEPRECATED
+               isoWeekday: false, // override week start day - see https://momentjs.com/docs/#/get-set/iso-weekday/
+               minUnit: 'millisecond',
+               displayFormats: {}
+       },
+       ticks: {
+               autoSkip: false,
+
+               /**
+                * Ticks generation input values:
+                * - 'auto': generates "optimal" ticks based on scale size and time options.
+                * - 'data': generates ticks from data (including labels from data {t|x|y} objects).
+                * - 'labels': generates ticks from user given `data.labels` values ONLY.
+                * @see https://github.com/chartjs/Chart.js/pull/4507
+                * @since 2.7.0
+                */
+               source: 'auto',
+
+               major: {
+                       enabled: false
+               }
+       }
+};
+
+var scale_time = core_scale.extend({
+       initialize: function() {
+               this.mergeTicksOptions();
+               core_scale.prototype.initialize.call(this);
+       },
+
+       update: function() {
+               var me = this;
+               var options = me.options;
+               var time = options.time || (options.time = {});
+               var adapter = me._adapter = new core_adapters._date(options.adapters.date);
+
+               // DEPRECATIONS: output a message only one time per update
+               if (time.format) {
+                       console.warn('options.time.format is deprecated and replaced by options.time.parser.');
+               }
+
+               // Backward compatibility: before introducing adapter, `displayFormats` was
+               // supposed to contain *all* unit/string pairs but this can't be resolved
+               // when loading the scale (adapters are loaded afterward), so let's populate
+               // missing formats on update
+               helpers$1.mergeIf(time.displayFormats, adapter.formats());
+
+               return core_scale.prototype.update.apply(me, arguments);
+       },
+
+       /**
+        * Allows data to be referenced via 't' attribute
+        */
+       getRightValue: function(rawValue) {
+               if (rawValue && rawValue.t !== undefined) {
+                       rawValue = rawValue.t;
+               }
+               return core_scale.prototype.getRightValue.call(this, rawValue);
+       },
+
+       determineDataLimits: function() {
+               var me = this;
+               var chart = me.chart;
+               var adapter = me._adapter;
+               var timeOpts = me.options.time;
+               var unit = timeOpts.unit || 'day';
+               var min = MAX_INTEGER;
+               var max = MIN_INTEGER;
+               var timestamps = [];
+               var datasets = [];
+               var labels = [];
+               var i, j, ilen, jlen, data, timestamp;
+               var dataLabels = chart.data.labels || [];
+
+               // Convert labels to timestamps
+               for (i = 0, ilen = dataLabels.length; i < ilen; ++i) {
+                       labels.push(parse(me, dataLabels[i]));
+               }
+
+               // Convert data to timestamps
+               for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
+                       if (chart.isDatasetVisible(i)) {
+                               data = chart.data.datasets[i].data;
+
+                               // Let's consider that all data have the same format.
+                               if (helpers$1.isObject(data[0])) {
+                                       datasets[i] = [];
+
+                                       for (j = 0, jlen = data.length; j < jlen; ++j) {
+                                               timestamp = parse(me, data[j]);
+                                               timestamps.push(timestamp);
+                                               datasets[i][j] = timestamp;
+                                       }
+                               } else {
+                                       for (j = 0, jlen = labels.length; j < jlen; ++j) {
+                                               timestamps.push(labels[j]);
+                                       }
+                                       datasets[i] = labels.slice(0);
+                               }
+                       } else {
+                               datasets[i] = [];
+                       }
+               }
+
+               if (labels.length) {
+                       // Sort labels **after** data have been converted
+                       labels = arrayUnique(labels).sort(sorter);
+                       min = Math.min(min, labels[0]);
+                       max = Math.max(max, labels[labels.length - 1]);
+               }
+
+               if (timestamps.length) {
+                       timestamps = arrayUnique(timestamps).sort(sorter);
+                       min = Math.min(min, timestamps[0]);
+                       max = Math.max(max, timestamps[timestamps.length - 1]);
+               }
+
+               min = parse(me, timeOpts.min) || min;
+               max = parse(me, timeOpts.max) || max;
+
+               // In case there is no valid min/max, set limits based on unit time option
+               min = min === MAX_INTEGER ? +adapter.startOf(Date.now(), unit) : min;
+               max = max === MIN_INTEGER ? +adapter.endOf(Date.now(), unit) + 1 : max;
+
+               // Make sure that max is strictly higher than min (required by the lookup table)
+               me.min = Math.min(min, max);
+               me.max = Math.max(min + 1, max);
+
+               // PRIVATE
+               me._horizontal = me.isHorizontal();
+               me._table = [];
+               me._timestamps = {
+                       data: timestamps,
+                       datasets: datasets,
+                       labels: labels
+               };
+       },
+
+       buildTicks: function() {
+               var me = this;
+               var min = me.min;
+               var max = me.max;
+               var options = me.options;
+               var timeOpts = options.time;
+               var timestamps = [];
+               var ticks = [];
+               var i, ilen, timestamp;
+
+               switch (options.ticks.source) {
+               case 'data':
+                       timestamps = me._timestamps.data;
+                       break;
+               case 'labels':
+                       timestamps = me._timestamps.labels;
+                       break;
+               case 'auto':
+               default:
+                       timestamps = generate(me, min, max, me.getLabelCapacity(min), options);
+               }
+
+               if (options.bounds === 'ticks' && timestamps.length) {
+                       min = timestamps[0];
+                       max = timestamps[timestamps.length - 1];
+               }
+
+               // Enforce limits with user min/max options
+               min = parse(me, timeOpts.min) || min;
+               max = parse(me, timeOpts.max) || max;
+
+               // Remove ticks outside the min/max range
+               for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
+                       timestamp = timestamps[i];
+                       if (timestamp >= min && timestamp <= max) {
+                               ticks.push(timestamp);
+                       }
+               }
+
+               me.min = min;
+               me.max = max;
+
+               // PRIVATE
+               me._unit = timeOpts.unit || determineUnitForFormatting(me, ticks, timeOpts.minUnit, me.min, me.max);
+               me._majorUnit = determineMajorUnit(me._unit);
+               me._table = buildLookupTable(me._timestamps.data, min, max, options.distribution);
+               me._offsets = computeOffsets(me._table, ticks, min, max, options);
+
+               if (options.ticks.reverse) {
+                       ticks.reverse();
+               }
+
+               return ticksFromTimestamps(me, ticks, me._majorUnit);
+       },
+
+       getLabelForIndex: function(index, datasetIndex) {
+               var me = this;
+               var adapter = me._adapter;
+               var data = me.chart.data;
+               var timeOpts = me.options.time;
+               var label = data.labels && index < data.labels.length ? data.labels[index] : '';
+               var value = data.datasets[datasetIndex].data[index];
+
+               if (helpers$1.isObject(value)) {
+                       label = me.getRightValue(value);
+               }
+               if (timeOpts.tooltipFormat) {
+                       return adapter.format(toTimestamp(me, label), timeOpts.tooltipFormat);
+               }
+               if (typeof label === 'string') {
+                       return label;
+               }
+               return adapter.format(toTimestamp(me, label), timeOpts.displayFormats.datetime);
+       },
+
+       /**
+        * Function to format an individual tick mark
+        * @private
+        */
+       tickFormatFunction: function(time, index, ticks, format) {
+               var me = this;
+               var adapter = me._adapter;
+               var options = me.options;
+               var formats = options.time.displayFormats;
+               var minorFormat = formats[me._unit];
+               var majorUnit = me._majorUnit;
+               var majorFormat = formats[majorUnit];
+               var majorTime = +adapter.startOf(time, majorUnit);
+               var majorTickOpts = options.ticks.major;
+               var major = majorTickOpts.enabled && majorUnit && majorFormat && time === majorTime;
+               var label = adapter.format(time, format ? format : major ? majorFormat : minorFormat);
+               var tickOpts = major ? majorTickOpts : options.ticks.minor;
+               var formatter = valueOrDefault$c(tickOpts.callback, tickOpts.userCallback);
+
+               return formatter ? formatter(label, index, ticks) : label;
+       },
+
+       convertTicksToLabels: function(ticks) {
+               var labels = [];
+               var i, ilen;
+
+               for (i = 0, ilen = ticks.length; i < ilen; ++i) {
+                       labels.push(this.tickFormatFunction(ticks[i].value, i, ticks));
+               }
+
+               return labels;
+       },
+
+       /**
+        * @private
+        */
+       getPixelForOffset: function(time) {
+               var me = this;
+               var isReverse = me.options.ticks.reverse;
+               var size = me._horizontal ? me.width : me.height;
+               var start = me._horizontal ? isReverse ? me.right : me.left : isReverse ? me.bottom : me.top;
+               var pos = interpolate$1(me._table, 'time', time, 'pos');
+               var offset = size * (me._offsets.start + pos) / (me._offsets.start + 1 + me._offsets.end);
+
+               return isReverse ? start - offset : start + offset;
+       },
+
+       getPixelForValue: function(value, index, datasetIndex) {
+               var me = this;
+               var time = null;
+
+               if (index !== undefined && datasetIndex !== undefined) {
+                       time = me._timestamps.datasets[datasetIndex][index];
+               }
+
+               if (time === null) {
+                       time = parse(me, value);
+               }
+
+               if (time !== null) {
+                       return me.getPixelForOffset(time);
+               }
+       },
+
+       getPixelForTick: function(index) {
+               var ticks = this.getTicks();
+               return index >= 0 && index < ticks.length ?
+                       this.getPixelForOffset(ticks[index].value) :
+                       null;
+       },
+
+       getValueForPixel: function(pixel) {
+               var me = this;
+               var size = me._horizontal ? me.width : me.height;
+               var start = me._horizontal ? me.left : me.top;
+               var pos = (size ? (pixel - start) / size : 0) * (me._offsets.start + 1 + me._offsets.start) - me._offsets.end;
+               var time = interpolate$1(me._table, 'pos', pos, 'time');
+
+               // DEPRECATION, we should return time directly
+               return me._adapter._create(time);
+       },
+
+       /**
+        * Crude approximation of what the label width might be
+        * @private
+        */
+       getLabelWidth: function(label) {
+               var me = this;
+               var ticksOpts = me.options.ticks;
+               var tickLabelWidth = me.ctx.measureText(label).width;
+               var angle = helpers$1.toRadians(ticksOpts.maxRotation);
+               var cosRotation = Math.cos(angle);
+               var sinRotation = Math.sin(angle);
+               var tickFontSize = valueOrDefault$c(ticksOpts.fontSize, core_defaults.global.defaultFontSize);
+
+               return (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
+       },
+
+       /**
+        * @private
+        */
+       getLabelCapacity: function(exampleTime) {
+               var me = this;
+
+               // pick the longest format (milliseconds) for guestimation
+               var format = me.options.time.displayFormats.millisecond;
+               var exampleLabel = me.tickFormatFunction(exampleTime, 0, [], format);
+               var tickLabelWidth = me.getLabelWidth(exampleLabel);
+               var innerWidth = me.isHorizontal() ? me.width : me.height;
+               var capacity = Math.floor(innerWidth / tickLabelWidth);
+
+               return capacity > 0 ? capacity : 1;
+       }
+});
+
+// INTERNAL: static default options, registered in src/index.js
+var _defaults$4 = defaultConfig$4;
+scale_time._defaults = _defaults$4;
+
+var scales = {
+       category: scale_category,
+       linear: scale_linear,
+       logarithmic: scale_logarithmic,
+       radialLinear: scale_radialLinear,
+       time: scale_time
+};
+
+var FORMATS = {
+       datetime: 'MMM D, YYYY, h:mm:ss a',
+       millisecond: 'h:mm:ss.SSS a',
+       second: 'h:mm:ss a',
+       minute: 'h:mm a',
+       hour: 'hA',
+       day: 'MMM D',
+       week: 'll',
+       month: 'MMM YYYY',
+       quarter: '[Q]Q - YYYY',
+       year: 'YYYY'
+};
+
+core_adapters._date.override(typeof moment === 'function' ? {
+       _id: 'moment', // DEBUG ONLY
+
+       formats: function() {
+               return FORMATS;
+       },
+
+       parse: function(value, format) {
+               if (typeof value === 'string' && typeof format === 'string') {
+                       value = moment(value, format);
+               } else if (!(value instanceof moment)) {
+                       value = moment(value);
+               }
+               return value.isValid() ? value.valueOf() : null;
+       },
+
+       format: function(time, format) {
+               return moment(time).format(format);
+       },
+
+       add: function(time, amount, unit) {
+               return moment(time).add(amount, unit).valueOf();
+       },
+
+       diff: function(max, min, unit) {
+               return moment.duration(moment(max).diff(moment(min))).as(unit);
+       },
+
+       startOf: function(time, unit, weekday) {
+               time = moment(time);
+               if (unit === 'isoWeek') {
+                       return time.isoWeekday(weekday).valueOf();
+               }
+               return time.startOf(unit).valueOf();
+       },
+
+       endOf: function(time, unit) {
+               return moment(time).endOf(unit).valueOf();
+       },
+
+       // DEPRECATIONS
+
+       /**
+        * Provided for backward compatibility with scale.getValueForPixel().
+        * @deprecated since version 2.8.0
+        * @todo remove at version 3
+        * @private
+        */
+       _create: function(time) {
+               return moment(time);
+       },
+} : {});
+
+core_defaults._set('global', {
+       plugins: {
+               filler: {
+                       propagate: true
+               }
+       }
+});
+
+var mappers = {
+       dataset: function(source) {
+               var index = source.fill;
+               var chart = source.chart;
+               var meta = chart.getDatasetMeta(index);
+               var visible = meta && chart.isDatasetVisible(index);
+               var points = (visible && meta.dataset._children) || [];
+               var length = points.length || 0;
+
+               return !length ? null : function(point, i) {
+                       return (i < length && points[i]._view) || null;
+               };
+       },
+
+       boundary: function(source) {
+               var boundary = source.boundary;
+               var x = boundary ? boundary.x : null;
+               var y = boundary ? boundary.y : null;
+
+               return function(point) {
+                       return {
+                               x: x === null ? point.x : x,
+                               y: y === null ? point.y : y,
+                       };
+               };
+       }
+};
+
+// @todo if (fill[0] === '#')
+function decodeFill(el, index, count) {
+       var model = el._model || {};
+       var fill = model.fill;
+       var target;
+
+       if (fill === undefined) {
+               fill = !!model.backgroundColor;
+       }
+
+       if (fill === false || fill === null) {
+               return false;
+       }
+
+       if (fill === true) {
+               return 'origin';
+       }
+
+       target = parseFloat(fill, 10);
+       if (isFinite(target) && Math.floor(target) === target) {
+               if (fill[0] === '-' || fill[0] === '+') {
+                       target = index + target;
+               }
+
+               if (target === index || target < 0 || target >= count) {
+                       return false;
+               }
+
+               return target;
+       }
+
+       switch (fill) {
+       // compatibility
+       case 'bottom':
+               return 'start';
+       case 'top':
+               return 'end';
+       case 'zero':
+               return 'origin';
+       // supported boundaries
+       case 'origin':
+       case 'start':
+       case 'end':
+               return fill;
+       // invalid fill values
+       default:
+               return false;
+       }
+}
+
+function computeBoundary(source) {
+       var model = source.el._model || {};
+       var scale = source.el._scale || {};
+       var fill = source.fill;
+       var target = null;
+       var horizontal;
+
+       if (isFinite(fill)) {
+               return null;
+       }
+
+       // Backward compatibility: until v3, we still need to support boundary values set on
+       // the model (scaleTop, scaleBottom and scaleZero) because some external plugins and
+       // controllers might still use it (e.g. the Smith chart).
+
+       if (fill === 'start') {
+               target = model.scaleBottom === undefined ? scale.bottom : model.scaleBottom;
+       } else if (fill === 'end') {
+               target = model.scaleTop === undefined ? scale.top : model.scaleTop;
+       } else if (model.scaleZero !== undefined) {
+               target = model.scaleZero;
+       } else if (scale.getBasePosition) {
+               target = scale.getBasePosition();
+       } else if (scale.getBasePixel) {
+               target = scale.getBasePixel();
+       }
+
+       if (target !== undefined && target !== null) {
+               if (target.x !== undefined && target.y !== undefined) {
+                       return target;
+               }
+
+               if (helpers$1.isFinite(target)) {
+                       horizontal = scale.isHorizontal();
+                       return {
+                               x: horizontal ? target : null,
+                               y: horizontal ? null : target
+                       };
+               }
+       }
+
+       return null;
+}
+
+function resolveTarget(sources, index, propagate) {
+       var source = sources[index];
+       var fill = source.fill;
+       var visited = [index];
+       var target;
+
+       if (!propagate) {
+               return fill;
+       }
+
+       while (fill !== false && visited.indexOf(fill) === -1) {
+               if (!isFinite(fill)) {
+                       return fill;
+               }
+
+               target = sources[fill];
+               if (!target) {
+                       return false;
+               }
+
+               if (target.visible) {
+                       return fill;
+               }
+
+               visited.push(fill);
+               fill = target.fill;
+       }
+
+       return false;
+}
+
+function createMapper(source) {
+       var fill = source.fill;
+       var type = 'dataset';
+
+       if (fill === false) {
+               return null;
+       }
+
+       if (!isFinite(fill)) {
+               type = 'boundary';
+       }
+
+       return mappers[type](source);
+}
+
+function isDrawable(point) {
+       return point && !point.skip;
+}
+
+function drawArea(ctx, curve0, curve1, len0, len1) {
+       var i;
+
+       if (!len0 || !len1) {
+               return;
+       }
+
+       // building first area curve (normal)
+       ctx.moveTo(curve0[0].x, curve0[0].y);
+       for (i = 1; i < len0; ++i) {
+               helpers$1.canvas.lineTo(ctx, curve0[i - 1], curve0[i]);
+       }
+
+       // joining the two area curves
+       ctx.lineTo(curve1[len1 - 1].x, curve1[len1 - 1].y);
+
+       // building opposite area curve (reverse)
+       for (i = len1 - 1; i > 0; --i) {
+               helpers$1.canvas.lineTo(ctx, curve1[i], curve1[i - 1], true);
+       }
+}
+
+function doFill(ctx, points, mapper, view, color, loop) {
+       var count = points.length;
+       var span = view.spanGaps;
+       var curve0 = [];
+       var curve1 = [];
+       var len0 = 0;
+       var len1 = 0;
+       var i, ilen, index, p0, p1, d0, d1;
+
+       ctx.beginPath();
+
+       for (i = 0, ilen = (count + !!loop); i < ilen; ++i) {
+               index = i % count;
+               p0 = points[index]._view;
+               p1 = mapper(p0, index, view);
+               d0 = isDrawable(p0);
+               d1 = isDrawable(p1);
+
+               if (d0 && d1) {
+                       len0 = curve0.push(p0);
+                       len1 = curve1.push(p1);
+               } else if (len0 && len1) {
+                       if (!span) {
+                               drawArea(ctx, curve0, curve1, len0, len1);
+                               len0 = len1 = 0;
+                               curve0 = [];
+                               curve1 = [];
+                       } else {
+                               if (d0) {
+                                       curve0.push(p0);
+                               }
+                               if (d1) {
+                                       curve1.push(p1);
+                               }
+                       }
+               }
+       }
+
+       drawArea(ctx, curve0, curve1, len0, len1);
+
+       ctx.closePath();
+       ctx.fillStyle = color;
+       ctx.fill();
+}
+
+var plugin_filler = {
+       id: 'filler',
+
+       afterDatasetsUpdate: function(chart, options) {
+               var count = (chart.data.datasets || []).length;
+               var propagate = options.propagate;
+               var sources = [];
+               var meta, i, el, source;
+
+               for (i = 0; i < count; ++i) {
+                       meta = chart.getDatasetMeta(i);
+                       el = meta.dataset;
+                       source = null;
+
+                       if (el && el._model && el instanceof elements.Line) {
+                               source = {
+                                       visible: chart.isDatasetVisible(i),
+                                       fill: decodeFill(el, i, count),
+                                       chart: chart,
+                                       el: el
+                               };
+                       }
+
+                       meta.$filler = source;
+                       sources.push(source);
+               }
+
+               for (i = 0; i < count; ++i) {
+                       source = sources[i];
+                       if (!source) {
+                               continue;
+                       }
+
+                       source.fill = resolveTarget(sources, i, propagate);
+                       source.boundary = computeBoundary(source);
+                       source.mapper = createMapper(source);
+               }
+       },
+
+       beforeDatasetDraw: function(chart, args) {
+               var meta = args.meta.$filler;
+               if (!meta) {
+                       return;
+               }
+
+               var ctx = chart.ctx;
+               var el = meta.el;
+               var view = el._view;
+               var points = el._children || [];
+               var mapper = meta.mapper;
+               var color = view.backgroundColor || core_defaults.global.defaultColor;
+
+               if (mapper && color && points.length) {
+                       helpers$1.canvas.clipArea(ctx, chart.chartArea);
+                       doFill(ctx, points, mapper, view, color, el._loop);
+                       helpers$1.canvas.unclipArea(ctx);
+               }
+       }
+};
+
+var noop$1 = helpers$1.noop;
+var valueOrDefault$d = helpers$1.valueOrDefault;
+
+core_defaults._set('global', {
+       legend: {
+               display: true,
+               position: 'top',
+               fullWidth: true,
+               reverse: false,
+               weight: 1000,
+
+               // a callback that will handle
+               onClick: function(e, legendItem) {
+                       var index = legendItem.datasetIndex;
+                       var ci = this.chart;
+                       var meta = ci.getDatasetMeta(index);
+
+                       // See controller.isDatasetVisible comment
+                       meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;
+
+                       // We hid a dataset ... rerender the chart
+                       ci.update();
+               },
+
+               onHover: null,
+               onLeave: null,
+
+               labels: {
+                       boxWidth: 40,
+                       padding: 10,
+                       // Generates labels shown in the legend
+                       // Valid properties to return:
+                       // text : text to display
+                       // fillStyle : fill of coloured box
+                       // strokeStyle: stroke of coloured box
+                       // hidden : if this legend item refers to a hidden item
+                       // lineCap : cap style for line
+                       // lineDash
+                       // lineDashOffset :
+                       // lineJoin :
+                       // lineWidth :
+                       generateLabels: function(chart) {
+                               var data = chart.data;
+                               return helpers$1.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
+                                       return {
+                                               text: dataset.label,
+                                               fillStyle: (!helpers$1.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
+                                               hidden: !chart.isDatasetVisible(i),
+                                               lineCap: dataset.borderCapStyle,
+                                               lineDash: dataset.borderDash,
+                                               lineDashOffset: dataset.borderDashOffset,
+                                               lineJoin: dataset.borderJoinStyle,
+                                               lineWidth: dataset.borderWidth,
+                                               strokeStyle: dataset.borderColor,
+                                               pointStyle: dataset.pointStyle,
+
+                                               // Below is extra data used for toggling the datasets
+                                               datasetIndex: i
+                                       };
+                               }, this) : [];
+                       }
+               }
+       },
+
+       legendCallback: function(chart) {
+               var text = [];
+               text.push('<ul class="' + chart.id + '-legend">');
+               for (var i = 0; i < chart.data.datasets.length; i++) {
+                       text.push('<li><span style="background-color:' + chart.data.datasets[i].backgroundColor + '"></span>');
+                       if (chart.data.datasets[i].label) {
+                               text.push(chart.data.datasets[i].label);
+                       }
+                       text.push('</li>');
+               }
+               text.push('</ul>');
+               return text.join('');
+       }
+});
+
+/**
+ * Helper function to get the box width based on the usePointStyle option
+ * @param {object} labelopts - the label options on the legend
+ * @param {number} fontSize - the label font size
+ * @return {number} width of the color box area
+ */
+function getBoxWidth(labelOpts, fontSize) {
+       return labelOpts.usePointStyle && labelOpts.boxWidth > fontSize ?
+               fontSize :
+               labelOpts.boxWidth;
+}
+
+/**
+ * IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required!
+ */
+var Legend = core_element.extend({
+
+       initialize: function(config) {
+               helpers$1.extend(this, config);
+
+               // Contains hit boxes for each dataset (in dataset order)
+               this.legendHitBoxes = [];
+
+               /**
+                * @private
+                */
+               this._hoveredItem = null;
+
+               // Are we in doughnut mode which has a different data type
+               this.doughnutMode = false;
+       },
+
+       // These methods are ordered by lifecycle. Utilities then follow.
+       // Any function defined here is inherited by all legend types.
+       // Any function can be extended by the legend type
+
+       beforeUpdate: noop$1,
+       update: function(maxWidth, maxHeight, margins) {
+               var me = this;
+
+               // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
+               me.beforeUpdate();
+
+               // Absorb the master measurements
+               me.maxWidth = maxWidth;
+               me.maxHeight = maxHeight;
+               me.margins = margins;
+
+               // Dimensions
+               me.beforeSetDimensions();
+               me.setDimensions();
+               me.afterSetDimensions();
+               // Labels
+               me.beforeBuildLabels();
+               me.buildLabels();
+               me.afterBuildLabels();
+
+               // Fit
+               me.beforeFit();
+               me.fit();
+               me.afterFit();
+               //
+               me.afterUpdate();
+
+               return me.minSize;
+       },
+       afterUpdate: noop$1,
+
+       //
+
+       beforeSetDimensions: noop$1,
+       setDimensions: function() {
+               var me = this;
+               // Set the unconstrained dimension before label rotation
+               if (me.isHorizontal()) {
+                       // Reset position before calculating rotation
+                       me.width = me.maxWidth;
+                       me.left = 0;
+                       me.right = me.width;
+               } else {
+                       me.height = me.maxHeight;
+
+                       // Reset position before calculating rotation
+                       me.top = 0;
+                       me.bottom = me.height;
+               }
+
+               // Reset padding
+               me.paddingLeft = 0;
+               me.paddingTop = 0;
+               me.paddingRight = 0;
+               me.paddingBottom = 0;
+
+               // Reset minSize
+               me.minSize = {
+                       width: 0,
+                       height: 0
+               };
+       },
+       afterSetDimensions: noop$1,
+
+       //
+
+       beforeBuildLabels: noop$1,
+       buildLabels: function() {
+               var me = this;
+               var labelOpts = me.options.labels || {};
+               var legendItems = helpers$1.callback(labelOpts.generateLabels, [me.chart], me) || [];
+
+               if (labelOpts.filter) {
+                       legendItems = legendItems.filter(function(item) {
+                               return labelOpts.filter(item, me.chart.data);
+                       });
+               }
+
+               if (me.options.reverse) {
+                       legendItems.reverse();
+               }
+
+               me.legendItems = legendItems;
+       },
+       afterBuildLabels: noop$1,
+
+       //
+
+       beforeFit: noop$1,
+       fit: function() {
+               var me = this;
+               var opts = me.options;
+               var labelOpts = opts.labels;
+               var display = opts.display;
+
+               var ctx = me.ctx;
+
+               var labelFont = helpers$1.options._parseFont(labelOpts);
+               var fontSize = labelFont.size;
+
+               // Reset hit boxes
+               var hitboxes = me.legendHitBoxes = [];
+
+               var minSize = me.minSize;
+               var isHorizontal = me.isHorizontal();
+
+               if (isHorizontal) {
+                       minSize.width = me.maxWidth; // fill all the width
+                       minSize.height = display ? 10 : 0;
+               } else {
+                       minSize.width = display ? 10 : 0;
+                       minSize.height = me.maxHeight; // fill all the height
+               }
+
+               // Increase sizes here
+               if (display) {
+                       ctx.font = labelFont.string;
+
+                       if (isHorizontal) {
+                               // Labels
+
+                               // Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
+                               var lineWidths = me.lineWidths = [0];
+                               var totalHeight = 0;
+
+                               ctx.textAlign = 'left';
+                               ctx.textBaseline = 'top';
+
+                               helpers$1.each(me.legendItems, function(legendItem, i) {
+                                       var boxWidth = getBoxWidth(labelOpts, fontSize);
+                                       var width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
+
+                                       if (i === 0 || lineWidths[lineWidths.length - 1] + width + labelOpts.padding > minSize.width) {
+                                               totalHeight += fontSize + labelOpts.padding;
+                                               lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = labelOpts.padding;
+                                       }
+
+                                       // Store the hitbox width and height here. Final position will be updated in `draw`
+                                       hitboxes[i] = {
+                                               left: 0,
+                                               top: 0,
+                                               width: width,
+                                               height: fontSize
+                                       };
+
+                                       lineWidths[lineWidths.length - 1] += width + labelOpts.padding;
+                               });
+
+                               minSize.height += totalHeight;
+
+                       } else {
+                               var vPadding = labelOpts.padding;
+                               var columnWidths = me.columnWidths = [];
+                               var totalWidth = labelOpts.padding;
+                               var currentColWidth = 0;
+                               var currentColHeight = 0;
+                               var itemHeight = fontSize + vPadding;
+
+                               helpers$1.each(me.legendItems, function(legendItem, i) {
+                                       var boxWidth = getBoxWidth(labelOpts, fontSize);
+                                       var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
+
+                                       // If too tall, go to new column
+                                       if (i > 0 && currentColHeight + itemHeight > minSize.height - vPadding) {
+                                               totalWidth += currentColWidth + labelOpts.padding;
+                                               columnWidths.push(currentColWidth); // previous column width
+
+                                               currentColWidth = 0;
+                                               currentColHeight = 0;
+                                       }
+
+                                       // Get max width
+                                       currentColWidth = Math.max(currentColWidth, itemWidth);
+                                       currentColHeight += itemHeight;
+
+                                       // Store the hitbox width and height here. Final position will be updated in `draw`
+                                       hitboxes[i] = {
+                                               left: 0,
+                                               top: 0,
+                                               width: itemWidth,
+                                               height: fontSize
+                                       };
+                               });
+
+                               totalWidth += currentColWidth;
+                               columnWidths.push(currentColWidth);
+                               minSize.width += totalWidth;
+                       }
+               }
+
+               me.width = minSize.width;
+               me.height = minSize.height;
+       },
+       afterFit: noop$1,
+
+       // Shared Methods
+       isHorizontal: function() {
+               return this.options.position === 'top' || this.options.position === 'bottom';
+       },
+
+       // Actually draw the legend on the canvas
+       draw: function() {
+               var me = this;
+               var opts = me.options;
+               var labelOpts = opts.labels;
+               var globalDefaults = core_defaults.global;
+               var defaultColor = globalDefaults.defaultColor;
+               var lineDefault = globalDefaults.elements.line;
+               var legendWidth = me.width;
+               var lineWidths = me.lineWidths;
+
+               if (opts.display) {
+                       var ctx = me.ctx;
+                       var fontColor = valueOrDefault$d(labelOpts.fontColor, globalDefaults.defaultFontColor);
+                       var labelFont = helpers$1.options._parseFont(labelOpts);
+                       var fontSize = labelFont.size;
+                       var cursor;
+
+                       // Canvas setup
+                       ctx.textAlign = 'left';
+                       ctx.textBaseline = 'middle';
+                       ctx.lineWidth = 0.5;
+                       ctx.strokeStyle = fontColor; // for strikethrough effect
+                       ctx.fillStyle = fontColor; // render in correct colour
+                       ctx.font = labelFont.string;
+
+                       var boxWidth = getBoxWidth(labelOpts, fontSize);
+                       var hitboxes = me.legendHitBoxes;
+
+                       // current position
+                       var drawLegendBox = function(x, y, legendItem) {
+                               if (isNaN(boxWidth) || boxWidth <= 0) {
+                                       return;
+                               }
+
+                               // Set the ctx for the box
+                               ctx.save();
+
+                               var lineWidth = valueOrDefault$d(legendItem.lineWidth, lineDefault.borderWidth);
+                               ctx.fillStyle = valueOrDefault$d(legendItem.fillStyle, defaultColor);
+                               ctx.lineCap = valueOrDefault$d(legendItem.lineCap, lineDefault.borderCapStyle);
+                               ctx.lineDashOffset = valueOrDefault$d(legendItem.lineDashOffset, lineDefault.borderDashOffset);
+                               ctx.lineJoin = valueOrDefault$d(legendItem.lineJoin, lineDefault.borderJoinStyle);
+                               ctx.lineWidth = lineWidth;
+                               ctx.strokeStyle = valueOrDefault$d(legendItem.strokeStyle, defaultColor);
+
+                               if (ctx.setLineDash) {
+                                       // IE 9 and 10 do not support line dash
+                                       ctx.setLineDash(valueOrDefault$d(legendItem.lineDash, lineDefault.borderDash));
+                               }
+
+                               if (opts.labels && opts.labels.usePointStyle) {
+                                       // Recalculate x and y for drawPoint() because its expecting
+                                       // x and y to be center of figure (instead of top left)
+                                       var radius = boxWidth * Math.SQRT2 / 2;
+                                       var centerX = x + boxWidth / 2;
+                                       var centerY = y + fontSize / 2;
+
+                                       // Draw pointStyle as legend symbol
+                                       helpers$1.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
+                               } else {
+                                       // Draw box as legend symbol
+                                       if (lineWidth !== 0) {
+                                               ctx.strokeRect(x, y, boxWidth, fontSize);
+                                       }
+                                       ctx.fillRect(x, y, boxWidth, fontSize);
+                               }
+
+                               ctx.restore();
+                       };
+                       var fillText = function(x, y, legendItem, textWidth) {
+                               var halfFontSize = fontSize / 2;
+                               var xLeft = boxWidth + halfFontSize + x;
+                               var yMiddle = y + halfFontSize;
+
+                               ctx.fillText(legendItem.text, xLeft, yMiddle);
+
+                               if (legendItem.hidden) {
+                                       // Strikethrough the text if hidden
+                                       ctx.beginPath();
+                                       ctx.lineWidth = 2;
+                                       ctx.moveTo(xLeft, yMiddle);
+                                       ctx.lineTo(xLeft + textWidth, yMiddle);
+                                       ctx.stroke();
+                               }
+                       };
+
+                       // Horizontal
+                       var isHorizontal = me.isHorizontal();
+                       if (isHorizontal) {
+                               cursor = {
+                                       x: me.left + ((legendWidth - lineWidths[0]) / 2) + labelOpts.padding,
+                                       y: me.top + labelOpts.padding,
+                                       line: 0
+                               };
+                       } else {
+                               cursor = {
+                                       x: me.left + labelOpts.padding,
+                                       y: me.top + labelOpts.padding,
+                                       line: 0
+                               };
+                       }
+
+                       var itemHeight = fontSize + labelOpts.padding;
+                       helpers$1.each(me.legendItems, function(legendItem, i) {
+                               var textWidth = ctx.measureText(legendItem.text).width;
+                               var width = boxWidth + (fontSize / 2) + textWidth;
+                               var x = cursor.x;
+                               var y = cursor.y;
+
+                               // Use (me.left + me.minSize.width) and (me.top + me.minSize.height)
+                               // instead of me.right and me.bottom because me.width and me.height
+                               // may have been changed since me.minSize was calculated
+                               if (isHorizontal) {
+                                       if (i > 0 && x + width + labelOpts.padding > me.left + me.minSize.width) {
+                                               y = cursor.y += itemHeight;
+                                               cursor.line++;
+                                               x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2) + labelOpts.padding;
+                                       }
+                               } else if (i > 0 && y + itemHeight > me.top + me.minSize.height) {
+                                       x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
+                                       y = cursor.y = me.top + labelOpts.padding;
+                                       cursor.line++;
+                               }
+
+                               drawLegendBox(x, y, legendItem);
+
+                               hitboxes[i].left = x;
+                               hitboxes[i].top = y;
+
+                               // Fill the actual label
+                               fillText(x, y, legendItem, textWidth);
+
+                               if (isHorizontal) {
+                                       cursor.x += width + labelOpts.padding;
+                               } else {
+                                       cursor.y += itemHeight;
+                               }
+
+                       });
+               }
+       },
+
+       /**
+        * @private
+        */
+       _getLegendItemAt: function(x, y) {
+               var me = this;
+               var i, hitBox, lh;
+
+               if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
+                       // See if we are touching one of the dataset boxes
+                       lh = me.legendHitBoxes;
+                       for (i = 0; i < lh.length; ++i) {
+                               hitBox = lh[i];
+
+                               if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
+                                       // Touching an element
+                                       return me.legendItems[i];
+                               }
+                       }
+               }
+
+               return null;
+       },
+
+       /**
+        * Handle an event
+        * @private
+        * @param {IEvent} event - The event to handle
+        */
+       handleEvent: function(e) {
+               var me = this;
+               var opts = me.options;
+               var type = e.type === 'mouseup' ? 'click' : e.type;
+               var hoveredItem;
+
+               if (type === 'mousemove') {
+                       if (!opts.onHover && !opts.onLeave) {
+                               return;
+                       }
+               } else if (type === 'click') {
+                       if (!opts.onClick) {
+                               return;
+                       }
+               } else {
+                       return;
+               }
+
+               // Chart event already has relative position in it
+               hoveredItem = me._getLegendItemAt(e.x, e.y);
+
+               if (type === 'click') {
+                       if (hoveredItem && opts.onClick) {
+                               // use e.native for backwards compatibility
+                               opts.onClick.call(me, e.native, hoveredItem);
+                       }
+               } else {
+                       if (opts.onLeave && hoveredItem !== me._hoveredItem) {
+                               if (me._hoveredItem) {
+                                       opts.onLeave.call(me, e.native, me._hoveredItem);
+                               }
+                               me._hoveredItem = hoveredItem;
+                       }
+
+                       if (opts.onHover && hoveredItem) {
+                               // use e.native for backwards compatibility
+                               opts.onHover.call(me, e.native, hoveredItem);
+                       }
+               }
+       }
+});
+
+function createNewLegendAndAttach(chart, legendOpts) {
+       var legend = new Legend({
+               ctx: chart.ctx,
+               options: legendOpts,
+               chart: chart
+       });
+
+       core_layouts.configure(chart, legend, legendOpts);
+       core_layouts.addBox(chart, legend);
+       chart.legend = legend;
+}
+
+var plugin_legend = {
+       id: 'legend',
+
+       /**
+        * Backward compatibility: since 2.1.5, the legend is registered as a plugin, making
+        * Chart.Legend obsolete. To avoid a breaking change, we export the Legend as part of
+        * the plugin, which one will be re-exposed in the chart.js file.
+        * https://github.com/chartjs/Chart.js/pull/2640
+        * @private
+        */
+       _element: Legend,
+
+       beforeInit: function(chart) {
+               var legendOpts = chart.options.legend;
+
+               if (legendOpts) {
+                       createNewLegendAndAttach(chart, legendOpts);
+               }
+       },
+
+       beforeUpdate: function(chart) {
+               var legendOpts = chart.options.legend;
+               var legend = chart.legend;
+
+               if (legendOpts) {
+                       helpers$1.mergeIf(legendOpts, core_defaults.global.legend);
+
+                       if (legend) {
+                               core_layouts.configure(chart, legend, legendOpts);
+                               legend.options = legendOpts;
+                       } else {
+                               createNewLegendAndAttach(chart, legendOpts);
+                       }
+               } else if (legend) {
+                       core_layouts.removeBox(chart, legend);
+                       delete chart.legend;
+               }
+       },
+
+       afterEvent: function(chart, e) {
+               var legend = chart.legend;
+               if (legend) {
+                       legend.handleEvent(e);
+               }
+       }
+};
+
+var noop$2 = helpers$1.noop;
+
+core_defaults._set('global', {
+       title: {
+               display: false,
+               fontStyle: 'bold',
+               fullWidth: true,
+               padding: 10,
+               position: 'top',
+               text: '',
+               weight: 2000         // by default greater than legend (1000) to be above
+       }
+});
+
+/**
+ * IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required!
+ */
+var Title = core_element.extend({
+       initialize: function(config) {
+               var me = this;
+               helpers$1.extend(me, config);
+
+               // Contains hit boxes for each dataset (in dataset order)
+               me.legendHitBoxes = [];
+       },
+
+       // These methods are ordered by lifecycle. Utilities then follow.
+
+       beforeUpdate: noop$2,
+       update: function(maxWidth, maxHeight, margins) {
+               var me = this;
+
+               // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
+               me.beforeUpdate();
+
+               // Absorb the master measurements
+               me.maxWidth = maxWidth;
+               me.maxHeight = maxHeight;
+               me.margins = margins;
+
+               // Dimensions
+               me.beforeSetDimensions();
+               me.setDimensions();
+               me.afterSetDimensions();
+               // Labels
+               me.beforeBuildLabels();
+               me.buildLabels();
+               me.afterBuildLabels();
+
+               // Fit
+               me.beforeFit();
+               me.fit();
+               me.afterFit();
+               //
+               me.afterUpdate();
+
+               return me.minSize;
+
+       },
+       afterUpdate: noop$2,
+
+       //
+
+       beforeSetDimensions: noop$2,
+       setDimensions: function() {
+               var me = this;
+               // Set the unconstrained dimension before label rotation
+               if (me.isHorizontal()) {
+                       // Reset position before calculating rotation
+                       me.width = me.maxWidth;
+                       me.left = 0;
+                       me.right = me.width;
+               } else {
+                       me.height = me.maxHeight;
+
+                       // Reset position before calculating rotation
+                       me.top = 0;
+                       me.bottom = me.height;
+               }
+
+               // Reset padding
+               me.paddingLeft = 0;
+               me.paddingTop = 0;
+               me.paddingRight = 0;
+               me.paddingBottom = 0;
+
+               // Reset minSize
+               me.minSize = {
+                       width: 0,
+                       height: 0
+               };
+       },
+       afterSetDimensions: noop$2,
+
+       //
+
+       beforeBuildLabels: noop$2,
+       buildLabels: noop$2,
+       afterBuildLabels: noop$2,
+
+       //
+
+       beforeFit: noop$2,
+       fit: function() {
+               var me = this;
+               var opts = me.options;
+               var display = opts.display;
+               var minSize = me.minSize;
+               var lineCount = helpers$1.isArray(opts.text) ? opts.text.length : 1;
+               var fontOpts = helpers$1.options._parseFont(opts);
+               var textSize = display ? (lineCount * fontOpts.lineHeight) + (opts.padding * 2) : 0;
+
+               if (me.isHorizontal()) {
+                       minSize.width = me.maxWidth; // fill all the width
+                       minSize.height = textSize;
+               } else {
+                       minSize.width = textSize;
+                       minSize.height = me.maxHeight; // fill all the height
+               }
+
+               me.width = minSize.width;
+               me.height = minSize.height;
+
+       },
+       afterFit: noop$2,
+
+       // Shared Methods
+       isHorizontal: function() {
+               var pos = this.options.position;
+               return pos === 'top' || pos === 'bottom';
+       },
+
+       // Actually draw the title block on the canvas
+       draw: function() {
+               var me = this;
+               var ctx = me.ctx;
+               var opts = me.options;
+
+               if (opts.display) {
+                       var fontOpts = helpers$1.options._parseFont(opts);
+                       var lineHeight = fontOpts.lineHeight;
+                       var offset = lineHeight / 2 + opts.padding;
+                       var rotation = 0;
+                       var top = me.top;
+                       var left = me.left;
+                       var bottom = me.bottom;
+                       var right = me.right;
+                       var maxWidth, titleX, titleY;
+
+                       ctx.fillStyle = helpers$1.valueOrDefault(opts.fontColor, core_defaults.global.defaultFontColor); // render in correct colour
+                       ctx.font = fontOpts.string;
+
+                       // Horizontal
+                       if (me.isHorizontal()) {
+                               titleX = left + ((right - left) / 2); // midpoint of the width
+                               titleY = top + offset;
+                               maxWidth = right - left;
+                       } else {
+                               titleX = opts.position === 'left' ? left + offset : right - offset;
+                               titleY = top + ((bottom - top) / 2);
+                               maxWidth = bottom - top;
+                               rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);
+                       }
+
+                       ctx.save();
+                       ctx.translate(titleX, titleY);
+                       ctx.rotate(rotation);
+                       ctx.textAlign = 'center';
+                       ctx.textBaseline = 'middle';
+
+                       var text = opts.text;
+                       if (helpers$1.isArray(text)) {
+                               var y = 0;
+                               for (var i = 0; i < text.length; ++i) {
+                                       ctx.fillText(text[i], 0, y, maxWidth);
+                                       y += lineHeight;
+                               }
+                       } else {
+                               ctx.fillText(text, 0, 0, maxWidth);
+                       }
+
+                       ctx.restore();
+               }
+       }
+});
+
+function createNewTitleBlockAndAttach(chart, titleOpts) {
+       var title = new Title({
+               ctx: chart.ctx,
+               options: titleOpts,
+               chart: chart
+       });
+
+       core_layouts.configure(chart, title, titleOpts);
+       core_layouts.addBox(chart, title);
+       chart.titleBlock = title;
+}
+
+var plugin_title = {
+       id: 'title',
+
+       /**
+        * Backward compatibility: since 2.1.5, the title is registered as a plugin, making
+        * Chart.Title obsolete. To avoid a breaking change, we export the Title as part of
+        * the plugin, which one will be re-exposed in the chart.js file.
+        * https://github.com/chartjs/Chart.js/pull/2640
+        * @private
+        */
+       _element: Title,
+
+       beforeInit: function(chart) {
+               var titleOpts = chart.options.title;
+
+               if (titleOpts) {
+                       createNewTitleBlockAndAttach(chart, titleOpts);
+               }
+       },
+
+       beforeUpdate: function(chart) {
+               var titleOpts = chart.options.title;
+               var titleBlock = chart.titleBlock;
+
+               if (titleOpts) {
+                       helpers$1.mergeIf(titleOpts, core_defaults.global.title);
+
+                       if (titleBlock) {
+                               core_layouts.configure(chart, titleBlock, titleOpts);
+                               titleBlock.options = titleOpts;
+                       } else {
+                               createNewTitleBlockAndAttach(chart, titleOpts);
+                       }
+               } else if (titleBlock) {
+                       core_layouts.removeBox(chart, titleBlock);
+                       delete chart.titleBlock;
+               }
+       }
+};
+
+var plugins = {};
+var filler = plugin_filler;
+var legend = plugin_legend;
+var title = plugin_title;
+plugins.filler = filler;
+plugins.legend = legend;
+plugins.title = title;
+
+/**
+ * @namespace Chart
+ */
+
+
+core_controller.helpers = helpers$1;
+
+// @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests!
+core_helpers(core_controller);
+
+core_controller._adapters = core_adapters;
+core_controller.Animation = core_animation;
+core_controller.animationService = core_animations;
+core_controller.controllers = controllers;
+core_controller.DatasetController = core_datasetController;
+core_controller.defaults = core_defaults;
+core_controller.Element = core_element;
+core_controller.elements = elements;
+core_controller.Interaction = core_interaction;
+core_controller.layouts = core_layouts;
+core_controller.platform = platform;
+core_controller.plugins = core_plugins;
+core_controller.Scale = core_scale;
+core_controller.scaleService = core_scaleService;
+core_controller.Ticks = core_ticks;
+core_controller.Tooltip = core_tooltip;
+
+// Register built-in scales
+
+core_controller.helpers.each(scales, function(scale, type) {
+       core_controller.scaleService.registerScaleType(type, scale, scale._defaults);
+});
+
+// Load to register built-in adapters (as side effects)
+
+
+// Loading built-in plugins
+
+for (var k in plugins) {
+       if (plugins.hasOwnProperty(k)) {
+               core_controller.plugins.register(plugins[k]);
+       }
+}
+
+core_controller.platform.initialize();
+
+var src = core_controller;
+if (typeof window !== 'undefined') {
+       window.Chart = core_controller;
+}
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, not available anymore
+ * @namespace Chart.Chart
+ * @deprecated since version 2.8.0
+ * @todo remove at version 3
+ * @private
+ */
+core_controller.Chart = core_controller;
+
+/**
+ * Provided for backward compatibility, not available anymore
+ * @namespace Chart.Legend
+ * @deprecated since version 2.1.5
+ * @todo remove at version 3
+ * @private
+ */
+core_controller.Legend = plugins.legend._element;
+
+/**
+ * Provided for backward compatibility, not available anymore
+ * @namespace Chart.Title
+ * @deprecated since version 2.1.5
+ * @todo remove at version 3
+ * @private
+ */
+core_controller.Title = plugins.title._element;
+
+/**
+ * Provided for backward compatibility, use Chart.plugins instead
+ * @namespace Chart.pluginService
+ * @deprecated since version 2.1.5
+ * @todo remove at version 3
+ * @private
+ */
+core_controller.pluginService = core_controller.plugins;
+
+/**
+ * Provided for backward compatibility, inheriting from Chart.PlugingBase has no
+ * effect, instead simply create/register plugins via plain JavaScript objects.
+ * @interface Chart.PluginBase
+ * @deprecated since version 2.5.0
+ * @todo remove at version 3
+ * @private
+ */
+core_controller.PluginBase = core_controller.Element.extend({});
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.canvas instead.
+ * @namespace Chart.canvasHelpers
+ * @deprecated since version 2.6.0
+ * @todo remove at version 3
+ * @private
+ */
+core_controller.canvasHelpers = core_controller.helpers.canvas;
+
+/**
+ * Provided for backward compatibility, use Chart.layouts instead.
+ * @namespace Chart.layoutService
+ * @deprecated since version 2.7.3
+ * @todo remove at version 3
+ * @private
+ */
+core_controller.layoutService = core_controller.layouts;
+
+/**
+ * Provided for backward compatibility, not available anymore.
+ * @namespace Chart.LinearScaleBase
+ * @deprecated since version 2.8
+ * @todo remove at version 3
+ * @private
+ */
+core_controller.LinearScaleBase = scale_linearbase;
+
+/**
+ * Provided for backward compatibility, instead we should create a new Chart
+ * by setting the type in the config (`new Chart(id, {type: '{chart-type}'}`).
+ * @deprecated since version 2.8.0
+ * @todo remove at version 3
+ */
+core_controller.helpers.each(
+       [
+               'Bar',
+               'Bubble',
+               'Doughnut',
+               'Line',
+               'PolarArea',
+               'Radar',
+               'Scatter'
+       ],
+       function(klass) {
+               core_controller[klass] = function(ctx, cfg) {
+                       return new core_controller(ctx, core_controller.helpers.merge(cfg || {}, {
+                               type: klass.charAt(0).toLowerCase() + klass.slice(1)
+                       }));
+               };
+       }
+);
+
+return src;
+
+})));
diff --git a/dist/Chart.min.css b/dist/Chart.min.css
new file mode 100644 (file)
index 0000000..9dc5ac2
--- /dev/null
@@ -0,0 +1 @@
+@keyframes chartjs-render-animation{from{opacity:.99}to{opacity:1}}.chartjs-render-monitor{animation:chartjs-render-animation 1ms}.chartjs-size-monitor,.chartjs-size-monitor-expand,.chartjs-size-monitor-shrink{position:absolute;direction:ltr;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1}.chartjs-size-monitor-expand>div{position:absolute;width:1000000px;height:1000000px;left:0;top:0}.chartjs-size-monitor-shrink>div{position:absolute;width:200%;height:200%;left:0;top:0}
\ No newline at end of file
diff --git a/dist/Chart.min.js b/dist/Chart.min.js
new file mode 100644 (file)
index 0000000..c74a791
--- /dev/null
@@ -0,0 +1,7 @@
+/*!
+ * Chart.js v2.8.0
+ * https://www.chartjs.org
+ * (c) 2019 Chart.js Contributors
+ * Released under the MIT License
+ */
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(function(){try{return require("moment")}catch(t){}}()):"function"==typeof define&&define.amd?define(["require"],function(t){return e(function(){try{return t("moment")}catch(t){}}())}):t.Chart=e(t.moment)}(this,function(t){"use strict";t=t&&t.hasOwnProperty("default")?t.default:t;var e={rgb2hsl:i,rgb2hsv:n,rgb2hwb:a,rgb2cmyk:o,rgb2keyword:s,rgb2xyz:l,rgb2lab:d,rgb2lch:function(t){return x(d(t))},hsl2rgb:u,hsl2hsv:function(t){var e=t[0],i=t[1]/100,n=t[2]/100;if(0===n)return[0,0,0];return[e,100*(2*(i*=(n*=2)<=1?n:2-n)/(n+i)),100*((n+i)/2)]},hsl2hwb:function(t){return a(u(t))},hsl2cmyk:function(t){return o(u(t))},hsl2keyword:function(t){return s(u(t))},hsv2rgb:h,hsv2hsl:function(t){var e,i,n=t[0],a=t[1]/100,o=t[2]/100;return e=a*o,[n,100*(e=(e/=(i=(2-a)*o)<=1?i:2-i)||0),100*(i/=2)]},hsv2hwb:function(t){return a(h(t))},hsv2cmyk:function(t){return o(h(t))},hsv2keyword:function(t){return s(h(t))},hwb2rgb:c,hwb2hsl:function(t){return i(c(t))},hwb2hsv:function(t){return n(c(t))},hwb2cmyk:function(t){return o(c(t))},hwb2keyword:function(t){return s(c(t))},cmyk2rgb:f,cmyk2hsl:function(t){return i(f(t))},cmyk2hsv:function(t){return n(f(t))},cmyk2hwb:function(t){return a(f(t))},cmyk2keyword:function(t){return s(f(t))},keyword2rgb:w,keyword2hsl:function(t){return i(w(t))},keyword2hsv:function(t){return n(w(t))},keyword2hwb:function(t){return a(w(t))},keyword2cmyk:function(t){return o(w(t))},keyword2lab:function(t){return d(w(t))},keyword2xyz:function(t){return l(w(t))},xyz2rgb:p,xyz2lab:m,xyz2lch:function(t){return x(m(t))},lab2xyz:v,lab2rgb:y,lab2lch:x,lch2lab:k,lch2xyz:function(t){return v(k(t))},lch2rgb:function(t){return y(k(t))}};function i(t){var e,i,n=t[0]/255,a=t[1]/255,o=t[2]/255,r=Math.min(n,a,o),s=Math.max(n,a,o),l=s-r;return s==r?e=0:n==s?e=(a-o)/l:a==s?e=2+(o-n)/l:o==s&&(e=4+(n-a)/l),(e=Math.min(60*e,360))<0&&(e+=360),i=(r+s)/2,[e,100*(s==r?0:i<=.5?l/(s+r):l/(2-s-r)),100*i]}function n(t){var e,i,n=t[0],a=t[1],o=t[2],r=Math.min(n,a,o),s=Math.max(n,a,o),l=s-r;return i=0==s?0:l/s*1e3/10,s==r?e=0:n==s?e=(a-o)/l:a==s?e=2+(o-n)/l:o==s&&(e=4+(n-a)/l),(e=Math.min(60*e,360))<0&&(e+=360),[e,i,s/255*1e3/10]}function a(t){var e=t[0],n=t[1],a=t[2];return[i(t)[0],100*(1/255*Math.min(e,Math.min(n,a))),100*(a=1-1/255*Math.max(e,Math.max(n,a)))]}function o(t){var e,i=t[0]/255,n=t[1]/255,a=t[2]/255;return[100*((1-i-(e=Math.min(1-i,1-n,1-a)))/(1-e)||0),100*((1-n-e)/(1-e)||0),100*((1-a-e)/(1-e)||0),100*e]}function s(t){return _[JSON.stringify(t)]}function l(t){var e=t[0]/255,i=t[1]/255,n=t[2]/255;return[100*(.4124*(e=e>.04045?Math.pow((e+.055)/1.055,2.4):e/12.92)+.3576*(i=i>.04045?Math.pow((i+.055)/1.055,2.4):i/12.92)+.1805*(n=n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92)),100*(.2126*e+.7152*i+.0722*n),100*(.0193*e+.1192*i+.9505*n)]}function d(t){var e=l(t),i=e[0],n=e[1],a=e[2];return n/=100,a/=108.883,i=(i/=95.047)>.008856?Math.pow(i,1/3):7.787*i+16/116,[116*(n=n>.008856?Math.pow(n,1/3):7.787*n+16/116)-16,500*(i-n),200*(n-(a=a>.008856?Math.pow(a,1/3):7.787*a+16/116))]}function u(t){var e,i,n,a,o,r=t[0]/360,s=t[1]/100,l=t[2]/100;if(0==s)return[o=255*l,o,o];e=2*l-(i=l<.5?l*(1+s):l+s-l*s),a=[0,0,0];for(var d=0;d<3;d++)(n=r+1/3*-(d-1))<0&&n++,n>1&&n--,o=6*n<1?e+6*(i-e)*n:2*n<1?i:3*n<2?e+(i-e)*(2/3-n)*6:e,a[d]=255*o;return a}function h(t){var e=t[0]/60,i=t[1]/100,n=t[2]/100,a=Math.floor(e)%6,o=e-Math.floor(e),r=255*n*(1-i),s=255*n*(1-i*o),l=255*n*(1-i*(1-o));n*=255;switch(a){case 0:return[n,l,r];case 1:return[s,n,r];case 2:return[r,n,l];case 3:return[r,s,n];case 4:return[l,r,n];case 5:return[n,r,s]}}function c(t){var e,i,n,a,o=t[0]/360,s=t[1]/100,l=t[2]/100,d=s+l;switch(d>1&&(s/=d,l/=d),n=6*o-(e=Math.floor(6*o)),0!=(1&e)&&(n=1-n),a=s+n*((i=1-l)-s),e){default:case 6:case 0:r=i,g=a,b=s;break;case 1:r=a,g=i,b=s;break;case 2:r=s,g=i,b=a;break;case 3:r=s,g=a,b=i;break;case 4:r=a,g=s,b=i;break;case 5:r=i,g=s,b=a}return[255*r,255*g,255*b]}function f(t){var e=t[0]/100,i=t[1]/100,n=t[2]/100,a=t[3]/100;return[255*(1-Math.min(1,e*(1-a)+a)),255*(1-Math.min(1,i*(1-a)+a)),255*(1-Math.min(1,n*(1-a)+a))]}function p(t){var e,i,n,a=t[0]/100,o=t[1]/100,r=t[2]/100;return i=-.9689*a+1.8758*o+.0415*r,n=.0557*a+-.204*o+1.057*r,e=(e=3.2406*a+-1.5372*o+-.4986*r)>.0031308?1.055*Math.pow(e,1/2.4)-.055:e*=12.92,i=i>.0031308?1.055*Math.pow(i,1/2.4)-.055:i*=12.92,n=n>.0031308?1.055*Math.pow(n,1/2.4)-.055:n*=12.92,[255*(e=Math.min(Math.max(0,e),1)),255*(i=Math.min(Math.max(0,i),1)),255*(n=Math.min(Math.max(0,n),1))]}function m(t){var e=t[0],i=t[1],n=t[2];return i/=100,n/=108.883,e=(e/=95.047)>.008856?Math.pow(e,1/3):7.787*e+16/116,[116*(i=i>.008856?Math.pow(i,1/3):7.787*i+16/116)-16,500*(e-i),200*(i-(n=n>.008856?Math.pow(n,1/3):7.787*n+16/116))]}function v(t){var e,i,n,a,o=t[0],r=t[1],s=t[2];return o<=8?a=(i=100*o/903.3)/100*7.787+16/116:(i=100*Math.pow((o+16)/116,3),a=Math.pow(i/100,1/3)),[e=e/95.047<=.008856?e=95.047*(r/500+a-16/116)/7.787:95.047*Math.pow(r/500+a,3),i,n=n/108.883<=.008859?n=108.883*(a-s/200-16/116)/7.787:108.883*Math.pow(a-s/200,3)]}function x(t){var e,i=t[0],n=t[1],a=t[2];return(e=360*Math.atan2(a,n)/2/Math.PI)<0&&(e+=360),[i,Math.sqrt(n*n+a*a),e]}function y(t){return p(v(t))}function k(t){var e,i=t[0],n=t[1];return e=t[2]/360*2*Math.PI,[i,n*Math.cos(e),n*Math.sin(e)]}function w(t){return M[t]}var M={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},_={};for(var C in M)_[JSON.stringify(M[C])]=C;var S=function(){return new T};for(var P in e){S[P+"Raw"]=function(t){return function(i){return"number"==typeof i&&(i=Array.prototype.slice.call(arguments)),e[t](i)}}(P);var I=/(\w+)2(\w+)/.exec(P),A=I[1],D=I[2];(S[A]=S[A]||{})[D]=S[P]=function(t){return function(i){"number"==typeof i&&(i=Array.prototype.slice.call(arguments));var n=e[t](i);if("string"==typeof n||void 0===n)return n;for(var a=0;a<n.length;a++)n[a]=Math.round(n[a]);return n}}(P)}var T=function(){this.convs={}};T.prototype.routeSpace=function(t,e){var i=e[0];return void 0===i?this.getValues(t):("number"==typeof i&&(i=Array.prototype.slice.call(e)),this.setValues(t,i))},T.prototype.setValues=function(t,e){return this.space=t,this.convs={},this.convs[t]=e,this},T.prototype.getValues=function(t){var e=this.convs[t];if(!e){var i=this.space,n=this.convs[i];e=S[i][t](n),this.convs[t]=e}return e},["rgb","hsl","hsv","cmyk","keyword"].forEach(function(t){T.prototype[t]=function(e){return this.routeSpace(t,arguments)}});var F=S,L={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},R={getRgba:O,getHsla:z,getRgb:function(t){var e=O(t);return e&&e.slice(0,3)},getHsl:function(t){var e=z(t);return e&&e.slice(0,3)},getHwb:B,getAlpha:function(t){var e=O(t);if(e)return e[3];if(e=z(t))return e[3];if(e=B(t))return e[3]},hexString:function(t,e){var e=void 0!==e&&3===t.length?e:t[3];return"#"+H(t[0])+H(t[1])+H(t[2])+(e>=0&&e<1?H(Math.round(255*e)):"")},rgbString:function(t,e){if(e<1||t[3]&&t[3]<1)return N(t,e);return"rgb("+t[0]+", "+t[1]+", "+t[2]+")"},rgbaString:N,percentString:function(t,e){if(e<1||t[3]&&t[3]<1)return W(t,e);var i=Math.round(t[0]/255*100),n=Math.round(t[1]/255*100),a=Math.round(t[2]/255*100);return"rgb("+i+"%, "+n+"%, "+a+"%)"},percentaString:W,hslString:function(t,e){if(e<1||t[3]&&t[3]<1)return V(t,e);return"hsl("+t[0]+", "+t[1]+"%, "+t[2]+"%)"},hslaString:V,hwbString:function(t,e){void 0===e&&(e=void 0!==t[3]?t[3]:1);return"hwb("+t[0]+", "+t[1]+"%, "+t[2]+"%"+(void 0!==e&&1!==e?", "+e:"")+")"},keyword:function(t){return j[t.slice(0,3)]}};function O(t){if(t){var e=[0,0,0],i=1,n=t.match(/^#([a-fA-F0-9]{3,4})$/i),a="";if(n){a=(n=n[1])[3];for(var o=0;o<e.length;o++)e[o]=parseInt(n[o]+n[o],16);a&&(i=Math.round(parseInt(a+a,16)/255*100)/100)}else if(n=t.match(/^#([a-fA-F0-9]{6}([a-fA-F0-9]{2})?)$/i)){a=n[2],n=n[1];for(o=0;o<e.length;o++)e[o]=parseInt(n.slice(2*o,2*o+2),16);a&&(i=Math.round(parseInt(a,16)/255*100)/100)}else if(n=t.match(/^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i)){for(o=0;o<e.length;o++)e[o]=parseInt(n[o+1]);i=parseFloat(n[4])}else if(n=t.match(/^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i)){for(o=0;o<e.length;o++)e[o]=Math.round(2.55*parseFloat(n[o+1]));i=parseFloat(n[4])}else if(n=t.match(/(\w+)/)){if("transparent"==n[1])return[0,0,0,0];if(!(e=L[n[1]]))return}for(o=0;o<e.length;o++)e[o]=E(e[o],0,255);return i=i||0==i?E(i,0,1):1,e[3]=i,e}}function z(t){if(t){var e=t.match(/^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/);if(e){var i=parseFloat(e[4]);return[E(parseInt(e[1]),0,360),E(parseFloat(e[2]),0,100),E(parseFloat(e[3]),0,100),E(isNaN(i)?1:i,0,1)]}}}function B(t){if(t){var e=t.match(/^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/);if(e){var i=parseFloat(e[4]);return[E(parseInt(e[1]),0,360),E(parseFloat(e[2]),0,100),E(parseFloat(e[3]),0,100),E(isNaN(i)?1:i,0,1)]}}}function N(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"rgba("+t[0]+", "+t[1]+", "+t[2]+", "+e+")"}function W(t,e){return"rgba("+Math.round(t[0]/255*100)+"%, "+Math.round(t[1]/255*100)+"%, "+Math.round(t[2]/255*100)+"%, "+(e||t[3]||1)+")"}function V(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"hsla("+t[0]+", "+t[1]+"%, "+t[2]+"%, "+e+")"}function E(t,e,i){return Math.min(Math.max(e,t),i)}function H(t){var e=t.toString(16).toUpperCase();return e.length<2?"0"+e:e}var j={};for(var q in L)j[L[q]]=q;var Y=function(t){return t instanceof Y?t:this instanceof Y?(this.valid=!1,this.values={rgb:[0,0,0],hsl:[0,0,0],hsv:[0,0,0],hwb:[0,0,0],cmyk:[0,0,0,0],alpha:1},void("string"==typeof t?(e=R.getRgba(t))?this.setValues("rgb",e):(e=R.getHsla(t))?this.setValues("hsl",e):(e=R.getHwb(t))&&this.setValues("hwb",e):"object"==typeof t&&(void 0!==(e=t).r||void 0!==e.red?this.setValues("rgb",e):void 0!==e.l||void 0!==e.lightness?this.setValues("hsl",e):void 0!==e.v||void 0!==e.value?this.setValues("hsv",e):void 0!==e.w||void 0!==e.whiteness?this.setValues("hwb",e):void 0===e.c&&void 0===e.cyan||this.setValues("cmyk",e)))):new Y(t);var e};Y.prototype={isValid:function(){return this.valid},rgb:function(){return this.setSpace("rgb",arguments)},hsl:function(){return this.setSpace("hsl",arguments)},hsv:function(){return this.setSpace("hsv",arguments)},hwb:function(){return this.setSpace("hwb",arguments)},cmyk:function(){return this.setSpace("cmyk",arguments)},rgbArray:function(){return this.values.rgb},hslArray:function(){return this.values.hsl},hsvArray:function(){return this.values.hsv},hwbArray:function(){var t=this.values;return 1!==t.alpha?t.hwb.concat([t.alpha]):t.hwb},cmykArray:function(){return this.values.cmyk},rgbaArray:function(){var t=this.values;return t.rgb.concat([t.alpha])},hslaArray:function(){var t=this.values;return t.hsl.concat([t.alpha])},alpha:function(t){return void 0===t?this.values.alpha:(this.setValues("alpha",t),this)},red:function(t){return this.setChannel("rgb",0,t)},green:function(t){return this.setChannel("rgb",1,t)},blue:function(t){return this.setChannel("rgb",2,t)},hue:function(t){return t&&(t=(t%=360)<0?360+t:t),this.setChannel("hsl",0,t)},saturation:function(t){return this.setChannel("hsl",1,t)},lightness:function(t){return this.setChannel("hsl",2,t)},saturationv:function(t){return this.setChannel("hsv",1,t)},whiteness:function(t){return this.setChannel("hwb",1,t)},blackness:function(t){return this.setChannel("hwb",2,t)},value:function(t){return this.setChannel("hsv",2,t)},cyan:function(t){return this.setChannel("cmyk",0,t)},magenta:function(t){return this.setChannel("cmyk",1,t)},yellow:function(t){return this.setChannel("cmyk",2,t)},black:function(t){return this.setChannel("cmyk",3,t)},hexString:function(){return R.hexString(this.values.rgb)},rgbString:function(){return R.rgbString(this.values.rgb,this.values.alpha)},rgbaString:function(){return R.rgbaString(this.values.rgb,this.values.alpha)},percentString:function(){return R.percentString(this.values.rgb,this.values.alpha)},hslString:function(){return R.hslString(this.values.hsl,this.values.alpha)},hslaString:function(){return R.hslaString(this.values.hsl,this.values.alpha)},hwbString:function(){return R.hwbString(this.values.hwb,this.values.alpha)},keyword:function(){return R.keyword(this.values.rgb,this.values.alpha)},rgbNumber:function(){var t=this.values.rgb;return t[0]<<16|t[1]<<8|t[2]},luminosity:function(){for(var t=this.values.rgb,e=[],i=0;i<t.length;i++){var n=t[i]/255;e[i]=n<=.03928?n/12.92:Math.pow((n+.055)/1.055,2.4)}return.2126*e[0]+.7152*e[1]+.0722*e[2]},contrast:function(t){var e=this.luminosity(),i=t.luminosity();return e>i?(e+.05)/(i+.05):(i+.05)/(e+.05)},level:function(t){var e=this.contrast(t);return e>=7.1?"AAA":e>=4.5?"AA":""},dark:function(){var t=this.values.rgb;return(299*t[0]+587*t[1]+114*t[2])/1e3<128},light:function(){return!this.dark()},negate:function(){for(var t=[],e=0;e<3;e++)t[e]=255-this.values.rgb[e];return this.setValues("rgb",t),this},lighten:function(t){var e=this.values.hsl;return e[2]+=e[2]*t,this.setValues("hsl",e),this},darken:function(t){var e=this.values.hsl;return e[2]-=e[2]*t,this.setValues("hsl",e),this},saturate:function(t){var e=this.values.hsl;return e[1]+=e[1]*t,this.setValues("hsl",e),this},desaturate:function(t){var e=this.values.hsl;return e[1]-=e[1]*t,this.setValues("hsl",e),this},whiten:function(t){var e=this.values.hwb;return e[1]+=e[1]*t,this.setValues("hwb",e),this},blacken:function(t){var e=this.values.hwb;return e[2]+=e[2]*t,this.setValues("hwb",e),this},greyscale:function(){var t=this.values.rgb,e=.3*t[0]+.59*t[1]+.11*t[2];return this.setValues("rgb",[e,e,e]),this},clearer:function(t){var e=this.values.alpha;return this.setValues("alpha",e-e*t),this},opaquer:function(t){var e=this.values.alpha;return this.setValues("alpha",e+e*t),this},rotate:function(t){var e=this.values.hsl,i=(e[0]+t)%360;return e[0]=i<0?360+i:i,this.setValues("hsl",e),this},mix:function(t,e){var i=t,n=void 0===e?.5:e,a=2*n-1,o=this.alpha()-i.alpha(),r=((a*o==-1?a:(a+o)/(1+a*o))+1)/2,s=1-r;return this.rgb(r*this.red()+s*i.red(),r*this.green()+s*i.green(),r*this.blue()+s*i.blue()).alpha(this.alpha()*n+i.alpha()*(1-n))},toJSON:function(){return this.rgb()},clone:function(){var t,e,i=new Y,n=this.values,a=i.values;for(var o in n)n.hasOwnProperty(o)&&(t=n[o],"[object Array]"===(e={}.toString.call(t))?a[o]=t.slice(0):"[object Number]"===e?a[o]=t:console.error("unexpected color value:",t));return i}},Y.prototype.spaces={rgb:["red","green","blue"],hsl:["hue","saturation","lightness"],hsv:["hue","saturation","value"],hwb:["hue","whiteness","blackness"],cmyk:["cyan","magenta","yellow","black"]},Y.prototype.maxes={rgb:[255,255,255],hsl:[360,100,100],hsv:[360,100,100],hwb:[360,100,100],cmyk:[100,100,100,100]},Y.prototype.getValues=function(t){for(var e=this.values,i={},n=0;n<t.length;n++)i[t.charAt(n)]=e[t][n];return 1!==e.alpha&&(i.a=e.alpha),i},Y.prototype.setValues=function(t,e){var i,n,a=this.values,o=this.spaces,r=this.maxes,s=1;if(this.valid=!0,"alpha"===t)s=e;else if(e.length)a[t]=e.slice(0,t.length),s=e[t.length];else if(void 0!==e[t.charAt(0)]){for(i=0;i<t.length;i++)a[t][i]=e[t.charAt(i)];s=e.a}else if(void 0!==e[o[t][0]]){var l=o[t];for(i=0;i<t.length;i++)a[t][i]=e[l[i]];s=e.alpha}if(a.alpha=Math.max(0,Math.min(1,void 0===s?a.alpha:s)),"alpha"===t)return!1;for(i=0;i<t.length;i++)n=Math.max(0,Math.min(r[t][i],a[t][i])),a[t][i]=Math.round(n);for(var d in o)d!==t&&(a[d]=F[t][d](a[t]));return!0},Y.prototype.setSpace=function(t,e){var i=e[0];return void 0===i?this.getValues(t):("number"==typeof i&&(i=Array.prototype.slice.call(e)),this.setValues(t,i),this)},Y.prototype.setChannel=function(t,e,i){var n=this.values[t];return void 0===i?n[e]:i===n[e]?this:(n[e]=i,this.setValues(t,n),this)},"undefined"!=typeof window&&(window.Color=Y);var U,X=Y,K={noop:function(){},uid:(U=0,function(){return U++}),isNullOrUndef:function(t){return null==t},isArray:function(t){if(Array.isArray&&Array.isArray(t))return!0;var e=Object.prototype.toString.call(t);return"[object"===e.substr(0,7)&&"Array]"===e.substr(-6)},isObject:function(t){return null!==t&&"[object Object]"===Object.prototype.toString.call(t)},isFinite:function(t){return("number"==typeof t||t instanceof Number)&&isFinite(t)},valueOrDefault:function(t,e){return void 0===t?e:t},valueAtIndexOrDefault:function(t,e,i){return K.valueOrDefault(K.isArray(t)?t[e]:t,i)},callback:function(t,e,i){if(t&&"function"==typeof t.call)return t.apply(i,e)},each:function(t,e,i,n){var a,o,r;if(K.isArray(t))if(o=t.length,n)for(a=o-1;a>=0;a--)e.call(i,t[a],a);else for(a=0;a<o;a++)e.call(i,t[a],a);else if(K.isObject(t))for(o=(r=Object.keys(t)).length,a=0;a<o;a++)e.call(i,t[r[a]],r[a])},arrayEquals:function(t,e){var i,n,a,o;if(!t||!e||t.length!==e.length)return!1;for(i=0,n=t.length;i<n;++i)if(a=t[i],o=e[i],a instanceof Array&&o instanceof Array){if(!K.arrayEquals(a,o))return!1}else if(a!==o)return!1;return!0},clone:function(t){if(K.isArray(t))return t.map(K.clone);if(K.isObject(t)){for(var e={},i=Object.keys(t),n=i.length,a=0;a<n;++a)e[i[a]]=K.clone(t[i[a]]);return e}return t},_merger:function(t,e,i,n){var a=e[t],o=i[t];K.isObject(a)&&K.isObject(o)?K.merge(a,o,n):e[t]=K.clone(o)},_mergerIf:function(t,e,i){var n=e[t],a=i[t];K.isObject(n)&&K.isObject(a)?K.mergeIf(n,a):e.hasOwnProperty(t)||(e[t]=K.clone(a))},merge:function(t,e,i){var n,a,o,r,s,l=K.isArray(e)?e:[e],d=l.length;if(!K.isObject(t))return t;for(n=(i=i||{}).merger||K._merger,a=0;a<d;++a)if(e=l[a],K.isObject(e))for(s=0,r=(o=Object.keys(e)).length;s<r;++s)n(o[s],t,e,i);return t},mergeIf:function(t,e){return K.merge(t,e,{merger:K._mergerIf})},extend:function(t){for(var e=function(e,i){t[i]=e},i=1,n=arguments.length;i<n;++i)K.each(arguments[i],e);return t},inherits:function(t){var e=this,i=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return e.apply(this,arguments)},n=function(){this.constructor=i};return n.prototype=e.prototype,i.prototype=new n,i.extend=K.inherits,t&&K.extend(i.prototype,t),i.__super__=e.prototype,i}},G=K;K.callCallback=K.callback,K.indexOf=function(t,e,i){return Array.prototype.indexOf.call(t,e,i)},K.getValueOrDefault=K.valueOrDefault,K.getValueAtIndexOrDefault=K.valueAtIndexOrDefault;var Z={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return(t-=1)*t*t+1},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-((t-=1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return t*t*t*t*t},easeOutQuint:function(t){return(t-=1)*t*t*t*t+1},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return 1-Math.cos(t*(Math.PI/2))},easeOutSine:function(t){return Math.sin(t*(Math.PI/2))},easeInOutSine:function(t){return-.5*(Math.cos(Math.PI*t)-1)},easeInExpo:function(t){return 0===t?0:Math.pow(2,10*(t-1))},easeOutExpo:function(t){return 1===t?1:1-Math.pow(2,-10*t)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(2-Math.pow(2,-10*--t))},easeInCirc:function(t){return t>=1?t:-(Math.sqrt(1-t*t)-1)},easeOutCirc:function(t){return Math.sqrt(1-(t-=1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var e=1.70158,i=0,n=1;return 0===t?0:1===t?1:(i||(i=.3),n<1?(n=1,e=i/4):e=i/(2*Math.PI)*Math.asin(1/n),-n*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/i))},easeOutElastic:function(t){var e=1.70158,i=0,n=1;return 0===t?0:1===t?1:(i||(i=.3),n<1?(n=1,e=i/4):e=i/(2*Math.PI)*Math.asin(1/n),n*Math.pow(2,-10*t)*Math.sin((t-e)*(2*Math.PI)/i)+1)},easeInOutElastic:function(t){var e=1.70158,i=0,n=1;return 0===t?0:2==(t/=.5)?1:(i||(i=.45),n<1?(n=1,e=i/4):e=i/(2*Math.PI)*Math.asin(1/n),t<1?n*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/i)*-.5:n*Math.pow(2,-10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/i)*.5+1)},easeInBack:function(t){var e=1.70158;return t*t*((e+1)*t-e)},easeOutBack:function(t){var e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},easeInOutBack:function(t){var e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},easeInBounce:function(t){return 1-Z.easeOutBounce(1-t)},easeOutBounce:function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375},easeInOutBounce:function(t){return t<.5?.5*Z.easeInBounce(2*t):.5*Z.easeOutBounce(2*t-1)+.5}},$={effects:Z};G.easingEffects=Z;var J=Math.PI,Q=J/180,tt=2*J,et=J/2,it=J/4,nt=2*J/3,at={clear:function(t){t.ctx.clearRect(0,0,t.width,t.height)},roundedRect:function(t,e,i,n,a,o){if(o){var r=Math.min(o,a/2,n/2),s=e+r,l=i+r,d=e+n-r,u=i+a-r;t.moveTo(e,l),s<d&&l<u?(t.arc(s,l,r,-J,-et),t.arc(d,l,r,-et,0),t.arc(d,u,r,0,et),t.arc(s,u,r,et,J)):s<d?(t.moveTo(s,i),t.arc(d,l,r,-et,et),t.arc(s,l,r,et,J+et)):l<u?(t.arc(s,l,r,-J,0),t.arc(s,u,r,0,J)):t.arc(s,l,r,-J,J),t.closePath(),t.moveTo(e,i)}else t.rect(e,i,n,a)},drawPoint:function(t,e,i,n,a,o){var r,s,l,d,u,h=(o||0)*Q;if(!e||"object"!=typeof e||"[object HTMLImageElement]"!==(r=e.toString())&&"[object HTMLCanvasElement]"!==r){if(!(isNaN(i)||i<=0)){switch(t.beginPath(),e){default:t.arc(n,a,i,0,tt),t.closePath();break;case"triangle":t.moveTo(n+Math.sin(h)*i,a-Math.cos(h)*i),h+=nt,t.lineTo(n+Math.sin(h)*i,a-Math.cos(h)*i),h+=nt,t.lineTo(n+Math.sin(h)*i,a-Math.cos(h)*i),t.closePath();break;case"rectRounded":d=i-(u=.516*i),s=Math.cos(h+it)*d,l=Math.sin(h+it)*d,t.arc(n-s,a-l,u,h-J,h-et),t.arc(n+l,a-s,u,h-et,h),t.arc(n+s,a+l,u,h,h+et),t.arc(n-l,a+s,u,h+et,h+J),t.closePath();break;case"rect":if(!o){d=Math.SQRT1_2*i,t.rect(n-d,a-d,2*d,2*d);break}h+=it;case"rectRot":s=Math.cos(h)*i,l=Math.sin(h)*i,t.moveTo(n-s,a-l),t.lineTo(n+l,a-s),t.lineTo(n+s,a+l),t.lineTo(n-l,a+s),t.closePath();break;case"crossRot":h+=it;case"cross":s=Math.cos(h)*i,l=Math.sin(h)*i,t.moveTo(n-s,a-l),t.lineTo(n+s,a+l),t.moveTo(n+l,a-s),t.lineTo(n-l,a+s);break;case"star":s=Math.cos(h)*i,l=Math.sin(h)*i,t.moveTo(n-s,a-l),t.lineTo(n+s,a+l),t.moveTo(n+l,a-s),t.lineTo(n-l,a+s),h+=it,s=Math.cos(h)*i,l=Math.sin(h)*i,t.moveTo(n-s,a-l),t.lineTo(n+s,a+l),t.moveTo(n+l,a-s),t.lineTo(n-l,a+s);break;case"line":s=Math.cos(h)*i,l=Math.sin(h)*i,t.moveTo(n-s,a-l),t.lineTo(n+s,a+l);break;case"dash":t.moveTo(n,a),t.lineTo(n+Math.cos(h)*i,a+Math.sin(h)*i)}t.fill(),t.stroke()}}else t.drawImage(e,n-e.width/2,a-e.height/2,e.width,e.height)},_isPointInArea:function(t,e){return t.x>e.left-1e-6&&t.x<e.right+1e-6&&t.y>e.top-1e-6&&t.y<e.bottom+1e-6},clipArea:function(t,e){t.save(),t.beginPath(),t.rect(e.left,e.top,e.right-e.left,e.bottom-e.top),t.clip()},unclipArea:function(t){t.restore()},lineTo:function(t,e,i,n){var a=i.steppedLine;if(a){if("middle"===a){var o=(e.x+i.x)/2;t.lineTo(o,n?i.y:e.y),t.lineTo(o,n?e.y:i.y)}else"after"===a&&!n||"after"!==a&&n?t.lineTo(e.x,i.y):t.lineTo(i.x,e.y);t.lineTo(i.x,i.y)}else i.tension?t.bezierCurveTo(n?e.controlPointPreviousX:e.controlPointNextX,n?e.controlPointPreviousY:e.controlPointNextY,n?i.controlPointNextX:i.controlPointPreviousX,n?i.controlPointNextY:i.controlPointPreviousY,i.x,i.y):t.lineTo(i.x,i.y)}},ot=at;G.clear=at.clear,G.drawRoundedRectangle=function(t){t.beginPath(),at.roundedRect.apply(at,arguments)};var rt={_set:function(t,e){return G.merge(this[t]||(this[t]={}),e)}};rt._set("global",{defaultColor:"rgba(0,0,0,0.1)",defaultFontColor:"#666",defaultFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",defaultFontSize:12,defaultFontStyle:"normal",defaultLineHeight:1.2,showLines:!0});var st=rt,lt=G.valueOrDefault;var dt={toLineHeight:function(t,e){var i=(""+t).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);if(!i||"normal"===i[1])return 1.2*e;switch(t=+i[2],i[3]){case"px":return t;case"%":t/=100}return e*t},toPadding:function(t){var e,i,n,a;return G.isObject(t)?(e=+t.top||0,i=+t.right||0,n=+t.bottom||0,a=+t.left||0):e=i=n=a=+t||0,{top:e,right:i,bottom:n,left:a,height:e+n,width:a+i}},_parseFont:function(t){var e=st.global,i=lt(t.fontSize,e.defaultFontSize),n={family:lt(t.fontFamily,e.defaultFontFamily),lineHeight:G.options.toLineHeight(lt(t.lineHeight,e.defaultLineHeight),i),size:i,style:lt(t.fontStyle,e.defaultFontStyle),weight:null,string:""};return n.string=function(t){return!t||G.isNullOrUndef(t.size)||G.isNullOrUndef(t.family)?null:(t.style?t.style+" ":"")+(t.weight?t.weight+" ":"")+t.size+"px "+t.family}(n),n},resolve:function(t,e,i){var n,a,o;for(n=0,a=t.length;n<a;++n)if(void 0!==(o=t[n])&&(void 0!==e&&"function"==typeof o&&(o=o(e)),void 0!==i&&G.isArray(o)&&(o=o[i]),void 0!==o))return o}},ut=G,ht=$,ct=ot,ft=dt;ut.easing=ht,ut.canvas=ct,ut.options=ft;var gt=function(t){ut.extend(this,t),this.initialize.apply(this,arguments)};ut.extend(gt.prototype,{initialize:function(){this.hidden=!1},pivot:function(){var t=this;return t._view||(t._view=ut.clone(t._model)),t._start={},t},transition:function(t){var e=this,i=e._model,n=e._start,a=e._view;return i&&1!==t?(a||(a=e._view={}),n||(n=e._start={}),function(t,e,i,n){var a,o,r,s,l,d,u,h,c,f=Object.keys(i);for(a=0,o=f.length;a<o;++a)if(d=i[r=f[a]],e.hasOwnProperty(r)||(e[r]=d),(s=e[r])!==d&&"_"!==r[0]){if(t.hasOwnProperty(r)||(t[r]=s),(u=typeof d)==typeof(l=t[r]))if("string"===u){if((h=X(l)).valid&&(c=X(d)).valid){e[r]=c.mix(h,n).rgbString();continue}}else if(ut.isFinite(l)&&ut.isFinite(d)){e[r]=l+(d-l)*n;continue}e[r]=d}}(n,a,i,t),e):(e._view=i,e._start=null,e)},tooltipPosition:function(){return{x:this._model.x,y:this._model.y}},hasValue:function(){return ut.isNumber(this._model.x)&&ut.isNumber(this._model.y)}}),gt.extend=ut.inherits;var pt=gt,mt=pt.extend({chart:null,currentStep:0,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null}),vt=mt;Object.defineProperty(mt.prototype,"animationObject",{get:function(){return this}}),Object.defineProperty(mt.prototype,"chartInstance",{get:function(){return this.chart},set:function(t){this.chart=t}}),st._set("global",{animation:{duration:1e3,easing:"easeOutQuart",onProgress:ut.noop,onComplete:ut.noop}});var bt={animations:[],request:null,addAnimation:function(t,e,i,n){var a,o,r=this.animations;for(e.chart=t,e.startTime=Date.now(),e.duration=i,n||(t.animating=!0),a=0,o=r.length;a<o;++a)if(r[a].chart===t)return void(r[a]=e);r.push(e),1===r.length&&this.requestAnimationFrame()},cancelAnimation:function(t){var e=ut.findIndex(this.animations,function(e){return e.chart===t});-1!==e&&(this.animations.splice(e,1),t.animating=!1)},requestAnimationFrame:function(){var t=this;null===t.request&&(t.request=ut.requestAnimFrame.call(window,function(){t.request=null,t.startDigest()}))},startDigest:function(){this.advance(),this.animations.length>0&&this.requestAnimationFrame()},advance:function(){for(var t,e,i,n,a=this.animations,o=0;o<a.length;)e=(t=a[o]).chart,i=t.numSteps,n=Math.floor((Date.now()-t.startTime)/t.duration*i)+1,t.currentStep=Math.min(n,i),ut.callback(t.render,[e,t],e),ut.callback(t.onAnimationProgress,[t],e),t.currentStep>=i?(ut.callback(t.onAnimationComplete,[t],e),e.animating=!1,a.splice(o,1)):++o}},xt=ut.options.resolve,yt=["push","pop","shift","splice","unshift"];function kt(t,e){var i=t._chartjs;if(i){var n=i.listeners,a=n.indexOf(e);-1!==a&&n.splice(a,1),n.length>0||(yt.forEach(function(e){delete t[e]}),delete t._chartjs)}}var wt=function(t,e){this.initialize(t,e)};ut.extend(wt.prototype,{datasetElementType:null,dataElementType:null,initialize:function(t,e){this.chart=t,this.index=e,this.linkScales(),this.addElements()},updateIndex:function(t){this.index=t},linkScales:function(){var t=this,e=t.getMeta(),i=t.getDataset();null!==e.xAxisID&&e.xAxisID in t.chart.scales||(e.xAxisID=i.xAxisID||t.chart.options.scales.xAxes[0].id),null!==e.yAxisID&&e.yAxisID in t.chart.scales||(e.yAxisID=i.yAxisID||t.chart.options.scales.yAxes[0].id)},getDataset:function(){return this.chart.data.datasets[this.index]},getMeta:function(){return this.chart.getDatasetMeta(this.index)},getScaleForId:function(t){return this.chart.scales[t]},_getValueScaleId:function(){return this.getMeta().yAxisID},_getIndexScaleId:function(){return this.getMeta().xAxisID},_getValueScale:function(){return this.getScaleForId(this._getValueScaleId())},_getIndexScale:function(){return this.getScaleForId(this._getIndexScaleId())},reset:function(){this.update(!0)},destroy:function(){this._data&&kt(this._data,this)},createMetaDataset:function(){var t=this.datasetElementType;return t&&new t({_chart:this.chart,_datasetIndex:this.index})},createMetaData:function(t){var e=this.dataElementType;return e&&new e({_chart:this.chart,_datasetIndex:this.index,_index:t})},addElements:function(){var t,e,i=this.getMeta(),n=this.getDataset().data||[],a=i.data;for(t=0,e=n.length;t<e;++t)a[t]=a[t]||this.createMetaData(t);i.dataset=i.dataset||this.createMetaDataset()},addElementAndReset:function(t){var e=this.createMetaData(t);this.getMeta().data.splice(t,0,e),this.updateElement(e,t,!0)},buildOrUpdateElements:function(){var t,e,i=this,n=i.getDataset(),a=n.data||(n.data=[]);i._data!==a&&(i._data&&kt(i._data,i),a&&Object.isExtensible(a)&&(e=i,(t=a)._chartjs?t._chartjs.listeners.push(e):(Object.defineProperty(t,"_chartjs",{configurable:!0,enumerable:!1,value:{listeners:[e]}}),yt.forEach(function(e){var i="onData"+e.charAt(0).toUpperCase()+e.slice(1),n=t[e];Object.defineProperty(t,e,{configurable:!0,enumerable:!1,value:function(){var e=Array.prototype.slice.call(arguments),a=n.apply(this,e);return ut.each(t._chartjs.listeners,function(t){"function"==typeof t[i]&&t[i].apply(t,e)}),a}})}))),i._data=a),i.resyncElements()},update:ut.noop,transition:function(t){for(var e=this.getMeta(),i=e.data||[],n=i.length,a=0;a<n;++a)i[a].transition(t);e.dataset&&e.dataset.transition(t)},draw:function(){var t=this.getMeta(),e=t.data||[],i=e.length,n=0;for(t.dataset&&t.dataset.draw();n<i;++n)e[n].draw()},removeHoverStyle:function(t){ut.merge(t._model,t.$previousStyle||{}),delete t.$previousStyle},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],i=t._index,n=t.custom||{},a=t._model,o=ut.getHoverColor;t.$previousStyle={backgroundColor:a.backgroundColor,borderColor:a.borderColor,borderWidth:a.borderWidth},a.backgroundColor=xt([n.hoverBackgroundColor,e.hoverBackgroundColor,o(a.backgroundColor)],void 0,i),a.borderColor=xt([n.hoverBorderColor,e.hoverBorderColor,o(a.borderColor)],void 0,i),a.borderWidth=xt([n.hoverBorderWidth,e.hoverBorderWidth,a.borderWidth],void 0,i)},resyncElements:function(){var t=this.getMeta(),e=this.getDataset().data,i=t.data.length,n=e.length;n<i?t.data.splice(n,i-n):n>i&&this.insertElements(i,n-i)},insertElements:function(t,e){for(var i=0;i<e;++i)this.addElementAndReset(t+i)},onDataPush:function(){var t=arguments.length;this.insertElements(this.getDataset().data.length-t,t)},onDataPop:function(){this.getMeta().data.pop()},onDataShift:function(){this.getMeta().data.shift()},onDataSplice:function(t,e){this.getMeta().data.splice(t,e),this.insertElements(t,arguments.length-2)},onDataUnshift:function(){this.insertElements(0,arguments.length)}}),wt.extend=ut.inherits;var Mt=wt;st._set("global",{elements:{arc:{backgroundColor:st.global.defaultColor,borderColor:"#fff",borderWidth:2,borderAlign:"center"}}});var _t=pt.extend({inLabelRange:function(t){var e=this._view;return!!e&&Math.pow(t-e.x,2)<Math.pow(e.radius+e.hoverRadius,2)},inRange:function(t,e){var i=this._view;if(i){for(var n=ut.getAngleFromPoint(i,{x:t,y:e}),a=n.angle,o=n.distance,r=i.startAngle,s=i.endAngle;s<r;)s+=2*Math.PI;for(;a>s;)a-=2*Math.PI;for(;a<r;)a+=2*Math.PI;var l=a>=r&&a<=s,d=o>=i.innerRadius&&o<=i.outerRadius;return l&&d}return!1},getCenterPoint:function(){var t=this._view,e=(t.startAngle+t.endAngle)/2,i=(t.innerRadius+t.outerRadius)/2;return{x:t.x+Math.cos(e)*i,y:t.y+Math.sin(e)*i}},getArea:function(){var t=this._view;return Math.PI*((t.endAngle-t.startAngle)/(2*Math.PI))*(Math.pow(t.outerRadius,2)-Math.pow(t.innerRadius,2))},tooltipPosition:function(){var t=this._view,e=t.startAngle+(t.endAngle-t.startAngle)/2,i=(t.outerRadius-t.innerRadius)/2+t.innerRadius;return{x:t.x+Math.cos(e)*i,y:t.y+Math.sin(e)*i}},draw:function(){var t,e=this._chart.ctx,i=this._view,n=i.startAngle,a=i.endAngle,o="inner"===i.borderAlign?.33:0;e.save(),e.beginPath(),e.arc(i.x,i.y,Math.max(i.outerRadius-o,0),n,a),e.arc(i.x,i.y,i.innerRadius,a,n,!0),e.closePath(),e.fillStyle=i.backgroundColor,e.fill(),i.borderWidth&&("inner"===i.borderAlign?(e.beginPath(),t=o/i.outerRadius,e.arc(i.x,i.y,i.outerRadius,n-t,a+t),i.innerRadius>o?(t=o/i.innerRadius,e.arc(i.x,i.y,i.innerRadius-o,a+t,n-t,!0)):e.arc(i.x,i.y,o,a+Math.PI/2,n-Math.PI/2),e.closePath(),e.clip(),e.beginPath(),e.arc(i.x,i.y,i.outerRadius,n,a),e.arc(i.x,i.y,i.innerRadius,a,n,!0),e.closePath(),e.lineWidth=2*i.borderWidth,e.lineJoin="round"):(e.lineWidth=i.borderWidth,e.lineJoin="bevel"),e.strokeStyle=i.borderColor,e.stroke()),e.restore()}}),Ct=ut.valueOrDefault,St=st.global.defaultColor;st._set("global",{elements:{line:{tension:.4,backgroundColor:St,borderWidth:3,borderColor:St,borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",capBezierPoints:!0,fill:!0}}});var Pt=pt.extend({draw:function(){var t,e,i,n,a=this._view,o=this._chart.ctx,r=a.spanGaps,s=this._children.slice(),l=st.global,d=l.elements.line,u=-1;for(this._loop&&s.length&&s.push(s[0]),o.save(),o.lineCap=a.borderCapStyle||d.borderCapStyle,o.setLineDash&&o.setLineDash(a.borderDash||d.borderDash),o.lineDashOffset=Ct(a.borderDashOffset,d.borderDashOffset),o.lineJoin=a.borderJoinStyle||d.borderJoinStyle,o.lineWidth=Ct(a.borderWidth,d.borderWidth),o.strokeStyle=a.borderColor||l.defaultColor,o.beginPath(),u=-1,t=0;t<s.length;++t)e=s[t],i=ut.previousItem(s,t),n=e._view,0===t?n.skip||(o.moveTo(n.x,n.y),u=t):(i=-1===u?i:s[u],n.skip||(u!==t-1&&!r||-1===u?o.moveTo(n.x,n.y):ut.canvas.lineTo(o,i._view,e._view),u=t));o.stroke(),o.restore()}}),It=ut.valueOrDefault,At=st.global.defaultColor;function Dt(t){var e=this._view;return!!e&&Math.abs(t-e.x)<e.radius+e.hitRadius}st._set("global",{elements:{point:{radius:3,pointStyle:"circle",backgroundColor:At,borderColor:At,borderWidth:1,hitRadius:1,hoverRadius:4,hoverBorderWidth:1}}});var Tt=pt.extend({inRange:function(t,e){var i=this._view;return!!i&&Math.pow(t-i.x,2)+Math.pow(e-i.y,2)<Math.pow(i.hitRadius+i.radius,2)},inLabelRange:Dt,inXRange:Dt,inYRange:function(t){var e=this._view;return!!e&&Math.abs(t-e.y)<e.radius+e.hitRadius},getCenterPoint:function(){var t=this._view;return{x:t.x,y:t.y}},getArea:function(){return Math.PI*Math.pow(this._view.radius,2)},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y,padding:t.radius+t.borderWidth}},draw:function(t){var e=this._view,i=this._chart.ctx,n=e.pointStyle,a=e.rotation,o=e.radius,r=e.x,s=e.y,l=st.global,d=l.defaultColor;e.skip||(void 0===t||ut.canvas._isPointInArea(e,t))&&(i.strokeStyle=e.borderColor||d,i.lineWidth=It(e.borderWidth,l.elements.point.borderWidth),i.fillStyle=e.backgroundColor||d,ut.canvas.drawPoint(i,n,o,r,s,a))}}),Ft=st.global.defaultColor;function Lt(t){return t&&void 0!==t.width}function Rt(t){var e,i,n,a,o;return Lt(t)?(o=t.width/2,e=t.x-o,i=t.x+o,n=Math.min(t.y,t.base),a=Math.max(t.y,t.base)):(o=t.height/2,e=Math.min(t.x,t.base),i=Math.max(t.x,t.base),n=t.y-o,a=t.y+o),{left:e,top:n,right:i,bottom:a}}function Ot(t,e,i){return t===e?i:t===i?e:t}function zt(t,e,i){var n,a,o,r,s=t.borderWidth,l=function(t){var e=t.borderSkipped,i={};return e?(t.horizontal?t.base>t.x&&(e=Ot(e,"left","right")):t.base<t.y&&(e=Ot(e,"bottom","top")),i[e]=!0,i):i}(t);return ut.isObject(s)?(n=+s.top||0,a=+s.right||0,o=+s.bottom||0,r=+s.left||0):n=a=o=r=+s||0,{t:l.top||n<0?0:n>i?i:n,r:l.right||a<0?0:a>e?e:a,b:l.bottom||o<0?0:o>i?i:o,l:l.left||r<0?0:r>e?e:r}}function Bt(t,e,i){var n=null===e,a=null===i,o=!(!t||n&&a)&&Rt(t);return o&&(n||e>=o.left&&e<=o.right)&&(a||i>=o.top&&i<=o.bottom)}st._set("global",{elements:{rectangle:{backgroundColor:Ft,borderColor:Ft,borderSkipped:"bottom",borderWidth:0}}});var Nt=pt.extend({draw:function(){var t=this._chart.ctx,e=this._view,i=function(t){var e=Rt(t),i=e.right-e.left,n=e.bottom-e.top,a=zt(t,i/2,n/2);return{outer:{x:e.left,y:e.top,w:i,h:n},inner:{x:e.left+a.l,y:e.top+a.t,w:i-a.l-a.r,h:n-a.t-a.b}}}(e),n=i.outer,a=i.inner;t.fillStyle=e.backgroundColor,t.fillRect(n.x,n.y,n.w,n.h),n.w===a.w&&n.h===a.h||(t.save(),t.beginPath(),t.rect(n.x,n.y,n.w,n.h),t.clip(),t.fillStyle=e.borderColor,t.rect(a.x,a.y,a.w,a.h),t.fill("evenodd"),t.restore())},height:function(){var t=this._view;return t.base-t.y},inRange:function(t,e){return Bt(this._view,t,e)},inLabelRange:function(t,e){var i=this._view;return Lt(i)?Bt(i,t,null):Bt(i,null,e)},inXRange:function(t){return Bt(this._view,t,null)},inYRange:function(t){return Bt(this._view,null,t)},getCenterPoint:function(){var t,e,i=this._view;return Lt(i)?(t=i.x,e=(i.y+i.base)/2):(t=(i.x+i.base)/2,e=i.y),{x:t,y:e}},getArea:function(){var t=this._view;return Lt(t)?t.width*Math.abs(t.y-t.base):t.height*Math.abs(t.x-t.base)},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y}}}),Wt={},Vt=_t,Et=Pt,Ht=Tt,jt=Nt;Wt.Arc=Vt,Wt.Line=Et,Wt.Point=Ht,Wt.Rectangle=jt;var qt=ut.options.resolve;st._set("bar",{hover:{mode:"label"},scales:{xAxes:[{type:"category",categoryPercentage:.8,barPercentage:.9,offset:!0,gridLines:{offsetGridLines:!0}}],yAxes:[{type:"linear"}]}});var Yt=Mt.extend({dataElementType:Wt.Rectangle,initialize:function(){var t;Mt.prototype.initialize.apply(this,arguments),(t=this.getMeta()).stack=this.getDataset().stack,t.bar=!0},update:function(t){var e,i,n=this.getMeta().data;for(this._ruler=this.getRuler(),e=0,i=n.length;e<i;++e)this.updateElement(n[e],e,t)},updateElement:function(t,e,i){var n=this,a=n.getMeta(),o=n.getDataset(),r=n._resolveElementOptions(t,e);t._xScale=n.getScaleForId(a.xAxisID),t._yScale=n.getScaleForId(a.yAxisID),t._datasetIndex=n.index,t._index=e,t._model={backgroundColor:r.backgroundColor,borderColor:r.borderColor,borderSkipped:r.borderSkipped,borderWidth:r.borderWidth,datasetLabel:o.label,label:n.chart.data.labels[e]},n._updateElementGeometry(t,e,i),t.pivot()},_updateElementGeometry:function(t,e,i){var n=this,a=t._model,o=n._getValueScale(),r=o.getBasePixel(),s=o.isHorizontal(),l=n._ruler||n.getRuler(),d=n.calculateBarValuePixels(n.index,e),u=n.calculateBarIndexPixels(n.index,e,l);a.horizontal=s,a.base=i?r:d.base,a.x=s?i?r:d.head:u.center,a.y=s?u.center:i?r:d.head,a.height=s?u.size:void 0,a.width=s?void 0:u.size},_getStacks:function(t){var e,i,n=this.chart,a=this._getIndexScale().options.stacked,o=void 0===t?n.data.datasets.length:t+1,r=[];for(e=0;e<o;++e)(i=n.getDatasetMeta(e)).bar&&n.isDatasetVisible(e)&&(!1===a||!0===a&&-1===r.indexOf(i.stack)||void 0===a&&(void 0===i.stack||-1===r.indexOf(i.stack)))&&r.push(i.stack);return r},getStackCount:function(){return this._getStacks().length},getStackIndex:function(t,e){var i=this._getStacks(t),n=void 0!==e?i.indexOf(e):-1;return-1===n?i.length-1:n},getRuler:function(){var t,e,i=this._getIndexScale(),n=this.getStackCount(),a=this.index,o=i.isHorizontal(),r=o?i.left:i.top,s=r+(o?i.width:i.height),l=[];for(t=0,e=this.getMeta().data.length;t<e;++t)l.push(i.getPixelForValue(null,t,a));return{min:ut.isNullOrUndef(i.options.barThickness)?function(t,e){var i,n,a,o,r=t.isHorizontal()?t.width:t.height,s=t.getTicks();for(a=1,o=e.length;a<o;++a)r=Math.min(r,Math.abs(e[a]-e[a-1]));for(a=0,o=s.length;a<o;++a)n=t.getPixelForTick(a),r=a>0?Math.min(r,n-i):r,i=n;return r}(i,l):-1,pixels:l,start:r,end:s,stackCount:n,scale:i}},calculateBarValuePixels:function(t,e){var i,n,a,o,r,s,l=this.chart,d=this.getMeta(),u=this._getValueScale(),h=u.isHorizontal(),c=l.data.datasets,f=+u.getRightValue(c[t].data[e]),g=u.options.minBarLength,p=u.options.stacked,m=d.stack,v=0;if(p||void 0===p&&void 0!==m)for(i=0;i<t;++i)(n=l.getDatasetMeta(i)).bar&&n.stack===m&&n.controller._getValueScaleId()===u.id&&l.isDatasetVisible(i)&&(a=+u.getRightValue(c[i].data[e]),(f<0&&a<0||f>=0&&a>0)&&(v+=a));return o=u.getPixelForValue(v),s=(r=u.getPixelForValue(v+f))-o,void 0!==g&&Math.abs(s)<g&&(s=g,r=f>=0&&!h||f<0&&h?o-g:o+g),{size:s,base:o,head:r,center:r+s/2}},calculateBarIndexPixels:function(t,e,i){var n=i.scale.options,a="flex"===n.barThickness?function(t,e,i){var n,a=e.pixels,o=a[t],r=t>0?a[t-1]:null,s=t<a.length-1?a[t+1]:null,l=i.categoryPercentage;return null===r&&(r=o-(null===s?e.end-e.start:s-o)),null===s&&(s=o+o-r),n=o-(o-Math.min(r,s))/2*l,{chunk:Math.abs(s-r)/2*l/e.stackCount,ratio:i.barPercentage,start:n}}(e,i,n):function(t,e,i){var n,a,o=i.barThickness,r=e.stackCount,s=e.pixels[t];return ut.isNullOrUndef(o)?(n=e.min*i.categoryPercentage,a=i.barPercentage):(n=o*r,a=1),{chunk:n/r,ratio:a,start:s-n/2}}(e,i,n),o=this.getStackIndex(t,this.getMeta().stack),r=a.start+a.chunk*o+a.chunk/2,s=Math.min(ut.valueOrDefault(n.maxBarThickness,1/0),a.chunk*a.ratio);return{base:r-s/2,head:r+s/2,center:r,size:s}},draw:function(){var t=this.chart,e=this._getValueScale(),i=this.getMeta().data,n=this.getDataset(),a=i.length,o=0;for(ut.canvas.clipArea(t.ctx,t.chartArea);o<a;++o)isNaN(e.getRightValue(n.data[o]))||i[o].draw();ut.canvas.unclipArea(t.ctx)},_resolveElementOptions:function(t,e){var i,n,a,o=this.chart,r=o.data.datasets[this.index],s=t.custom||{},l=o.options.elements.rectangle,d={},u={chart:o,dataIndex:e,dataset:r,datasetIndex:this.index},h=["backgroundColor","borderColor","borderSkipped","borderWidth"];for(i=0,n=h.length;i<n;++i)d[a=h[i]]=qt([s[a],r[a],l[a]],u,e);return d}}),Ut=ut.valueOrDefault,Xt=ut.options.resolve;st._set("bubble",{hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-0"}],yAxes:[{type:"linear",position:"left",id:"y-axis-0"}]},tooltips:{callbacks:{title:function(){return""},label:function(t,e){var i=e.datasets[t.datasetIndex].label||"",n=e.datasets[t.datasetIndex].data[t.index];return i+": ("+t.xLabel+", "+t.yLabel+", "+n.r+")"}}}});var Kt=Mt.extend({dataElementType:Wt.Point,update:function(t){var e=this,i=e.getMeta().data;ut.each(i,function(i,n){e.updateElement(i,n,t)})},updateElement:function(t,e,i){var n=this,a=n.getMeta(),o=t.custom||{},r=n.getScaleForId(a.xAxisID),s=n.getScaleForId(a.yAxisID),l=n._resolveElementOptions(t,e),d=n.getDataset().data[e],u=n.index,h=i?r.getPixelForDecimal(.5):r.getPixelForValue("object"==typeof d?d:NaN,e,u),c=i?s.getBasePixel():s.getPixelForValue(d,e,u);t._xScale=r,t._yScale=s,t._options=l,t._datasetIndex=u,t._index=e,t._model={backgroundColor:l.backgroundColor,borderColor:l.borderColor,borderWidth:l.borderWidth,hitRadius:l.hitRadius,pointStyle:l.pointStyle,rotation:l.rotation,radius:i?0:l.radius,skip:o.skip||isNaN(h)||isNaN(c),x:h,y:c},t.pivot()},setHoverStyle:function(t){var e=t._model,i=t._options,n=ut.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=Ut(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=Ut(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=Ut(i.hoverBorderWidth,i.borderWidth),e.radius=i.radius+i.hoverRadius},_resolveElementOptions:function(t,e){var i,n,a,o=this.chart,r=o.data.datasets[this.index],s=t.custom||{},l=o.options.elements.point,d=r.data[e],u={},h={chart:o,dataIndex:e,dataset:r,datasetIndex:this.index},c=["backgroundColor","borderColor","borderWidth","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth","hoverRadius","hitRadius","pointStyle","rotation"];for(i=0,n=c.length;i<n;++i)u[a=c[i]]=Xt([s[a],r[a],l[a]],h,e);return u.radius=Xt([s.radius,d?d.r:void 0,r.radius,l.radius],h,e),u}}),Gt=ut.options.resolve,Zt=ut.valueOrDefault;st._set("doughnut",{animation:{animateRotate:!0,animateScale:!1},hover:{mode:"single"},legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');var i=t.data,n=i.datasets,a=i.labels;if(n.length)for(var o=0;o<n[0].data.length;++o)e.push('<li><span style="background-color:'+n[0].backgroundColor[o]+'"></span>'),a[o]&&e.push(a[o]),e.push("</li>");return e.push("</ul>"),e.join("")},legend:{labels:{generateLabels:function(t){var e=t.data;return e.labels.length&&e.datasets.length?e.labels.map(function(i,n){var a=t.getDatasetMeta(0),o=e.datasets[0],r=a.data[n],s=r&&r.custom||{},l=t.options.elements.arc;return{text:i,fillStyle:Gt([s.backgroundColor,o.backgroundColor,l.backgroundColor],void 0,n),strokeStyle:Gt([s.borderColor,o.borderColor,l.borderColor],void 0,n),lineWidth:Gt([s.borderWidth,o.borderWidth,l.borderWidth],void 0,n),hidden:isNaN(o.data[n])||a.data[n].hidden,index:n}}):[]}},onClick:function(t,e){var i,n,a,o=e.index,r=this.chart;for(i=0,n=(r.data.datasets||[]).length;i<n;++i)(a=r.getDatasetMeta(i)).data[o]&&(a.data[o].hidden=!a.data[o].hidden);r.update()}},cutoutPercentage:50,rotation:-.5*Math.PI,circumference:2*Math.PI,tooltips:{callbacks:{title:function(){return""},label:function(t,e){var i=e.labels[t.index],n=": "+e.datasets[t.datasetIndex].data[t.index];return ut.isArray(i)?(i=i.slice())[0]+=n:i+=n,i}}}});var $t=Mt.extend({dataElementType:Wt.Arc,linkScales:ut.noop,getRingIndex:function(t){for(var e=0,i=0;i<t;++i)this.chart.isDatasetVisible(i)&&++e;return e},update:function(t){var e,i,n=this,a=n.chart,o=a.chartArea,r=a.options,s=o.right-o.left,l=o.bottom-o.top,d=Math.min(s,l),u={x:0,y:0},h=n.getMeta(),c=h.data,f=r.cutoutPercentage,g=r.circumference,p=n._getRingWeight(n.index);if(g<2*Math.PI){var m=r.rotation%(2*Math.PI),v=(m+=2*Math.PI*(m>=Math.PI?-1:m<-Math.PI?1:0))+g,b={x:Math.cos(m),y:Math.sin(m)},x={x:Math.cos(v),y:Math.sin(v)},y=m<=0&&v>=0||m<=2*Math.PI&&2*Math.PI<=v,k=m<=.5*Math.PI&&.5*Math.PI<=v||m<=2.5*Math.PI&&2.5*Math.PI<=v,w=m<=-Math.PI&&-Math.PI<=v||m<=Math.PI&&Math.PI<=v,M=m<=.5*-Math.PI&&.5*-Math.PI<=v||m<=1.5*Math.PI&&1.5*Math.PI<=v,_=f/100,C={x:w?-1:Math.min(b.x*(b.x<0?1:_),x.x*(x.x<0?1:_)),y:M?-1:Math.min(b.y*(b.y<0?1:_),x.y*(x.y<0?1:_))},S={x:y?1:Math.max(b.x*(b.x>0?1:_),x.x*(x.x>0?1:_)),y:k?1:Math.max(b.y*(b.y>0?1:_),x.y*(x.y>0?1:_))},P={width:.5*(S.x-C.x),height:.5*(S.y-C.y)};d=Math.min(s/P.width,l/P.height),u={x:-.5*(S.x+C.x),y:-.5*(S.y+C.y)}}for(e=0,i=c.length;e<i;++e)c[e]._options=n._resolveElementOptions(c[e],e);for(a.borderWidth=n.getMaxBorderWidth(),a.outerRadius=Math.max((d-a.borderWidth)/2,0),a.innerRadius=Math.max(f?a.outerRadius/100*f:0,0),a.radiusLength=(a.outerRadius-a.innerRadius)/(n._getVisibleDatasetWeightTotal()||1),a.offsetX=u.x*a.outerRadius,a.offsetY=u.y*a.outerRadius,h.total=n.calculateTotal(),n.outerRadius=a.outerRadius-a.radiusLength*n._getRingWeightOffset(n.index),n.innerRadius=Math.max(n.outerRadius-a.radiusLength*p,0),e=0,i=c.length;e<i;++e)n.updateElement(c[e],e,t)},updateElement:function(t,e,i){var n=this,a=n.chart,o=a.chartArea,r=a.options,s=r.animation,l=(o.left+o.right)/2,d=(o.top+o.bottom)/2,u=r.rotation,h=r.rotation,c=n.getDataset(),f=i&&s.animateRotate?0:t.hidden?0:n.calculateCircumference(c.data[e])*(r.circumference/(2*Math.PI)),g=i&&s.animateScale?0:n.innerRadius,p=i&&s.animateScale?0:n.outerRadius,m=t._options||{};ut.extend(t,{_datasetIndex:n.index,_index:e,_model:{backgroundColor:m.backgroundColor,borderColor:m.borderColor,borderWidth:m.borderWidth,borderAlign:m.borderAlign,x:l+a.offsetX,y:d+a.offsetY,startAngle:u,endAngle:h,circumference:f,outerRadius:p,innerRadius:g,label:ut.valueAtIndexOrDefault(c.label,e,a.data.labels[e])}});var v=t._model;i&&s.animateRotate||(v.startAngle=0===e?r.rotation:n.getMeta().data[e-1]._model.endAngle,v.endAngle=v.startAngle+v.circumference),t.pivot()},calculateTotal:function(){var t,e=this.getDataset(),i=this.getMeta(),n=0;return ut.each(i.data,function(i,a){t=e.data[a],isNaN(t)||i.hidden||(n+=Math.abs(t))}),n},calculateCircumference:function(t){var e=this.getMeta().total;return e>0&&!isNaN(t)?2*Math.PI*(Math.abs(t)/e):0},getMaxBorderWidth:function(t){var e,i,n,a,o,r,s,l,d=0,u=this.chart;if(!t)for(e=0,i=u.data.datasets.length;e<i;++e)if(u.isDatasetVisible(e)){t=(n=u.getDatasetMeta(e)).data,e!==this.index&&(o=n.controller);break}if(!t)return 0;for(e=0,i=t.length;e<i;++e)a=t[e],"inner"!==(r=o?o._resolveElementOptions(a,e):a._options).borderAlign&&(s=r.borderWidth,d=(l=r.hoverBorderWidth)>(d=s>d?s:d)?l:d);return d},setHoverStyle:function(t){var e=t._model,i=t._options,n=ut.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth},e.backgroundColor=Zt(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=Zt(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=Zt(i.hoverBorderWidth,i.borderWidth)},_resolveElementOptions:function(t,e){var i,n,a,o=this.chart,r=this.getDataset(),s=t.custom||{},l=o.options.elements.arc,d={},u={chart:o,dataIndex:e,dataset:r,datasetIndex:this.index},h=["backgroundColor","borderColor","borderWidth","borderAlign","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth"];for(i=0,n=h.length;i<n;++i)d[a=h[i]]=Gt([s[a],r[a],l[a]],u,e);return d},_getRingWeightOffset:function(t){for(var e=0,i=0;i<t;++i)this.chart.isDatasetVisible(i)&&(e+=this._getRingWeight(i));return e},_getRingWeight:function(t){return Math.max(Zt(this.chart.data.datasets[t].weight,1),0)},_getVisibleDatasetWeightTotal:function(){return this._getRingWeightOffset(this.chart.data.datasets.length)}});st._set("horizontalBar",{hover:{mode:"index",axis:"y"},scales:{xAxes:[{type:"linear",position:"bottom"}],yAxes:[{type:"category",position:"left",categoryPercentage:.8,barPercentage:.9,offset:!0,gridLines:{offsetGridLines:!0}}]},elements:{rectangle:{borderSkipped:"left"}},tooltips:{mode:"index",axis:"y"}});var Jt=Yt.extend({_getValueScaleId:function(){return this.getMeta().xAxisID},_getIndexScaleId:function(){return this.getMeta().yAxisID}}),Qt=ut.valueOrDefault,te=ut.options.resolve,ee=ut.canvas._isPointInArea;function ie(t,e){return Qt(t.showLine,e.showLines)}st._set("line",{showLines:!0,spanGaps:!1,hover:{mode:"label"},scales:{xAxes:[{type:"category",id:"x-axis-0"}],yAxes:[{type:"linear",id:"y-axis-0"}]}});var ne=Mt.extend({datasetElementType:Wt.Line,dataElementType:Wt.Point,update:function(t){var e,i,n=this,a=n.getMeta(),o=a.dataset,r=a.data||[],s=n.getScaleForId(a.yAxisID),l=n.getDataset(),d=ie(l,n.chart.options);for(d&&(void 0!==l.tension&&void 0===l.lineTension&&(l.lineTension=l.tension),o._scale=s,o._datasetIndex=n.index,o._children=r,o._model=n._resolveLineOptions(o),o.pivot()),e=0,i=r.length;e<i;++e)n.updateElement(r[e],e,t);for(d&&0!==o._model.tension&&n.updateBezierControlPoints(),e=0,i=r.length;e<i;++e)r[e].pivot()},updateElement:function(t,e,i){var n,a,o=this,r=o.getMeta(),s=t.custom||{},l=o.getDataset(),d=o.index,u=l.data[e],h=o.getScaleForId(r.yAxisID),c=o.getScaleForId(r.xAxisID),f=r.dataset._model,g=o._resolvePointOptions(t,e);n=c.getPixelForValue("object"==typeof u?u:NaN,e,d),a=i?h.getBasePixel():o.calculatePointY(u,e,d),t._xScale=c,t._yScale=h,t._options=g,t._datasetIndex=d,t._index=e,t._model={x:n,y:a,skip:s.skip||isNaN(n)||isNaN(a),radius:g.radius,pointStyle:g.pointStyle,rotation:g.rotation,backgroundColor:g.backgroundColor,borderColor:g.borderColor,borderWidth:g.borderWidth,tension:Qt(s.tension,f?f.tension:0),steppedLine:!!f&&f.steppedLine,hitRadius:g.hitRadius}},_resolvePointOptions:function(t,e){var i,n,a,o=this.chart,r=o.data.datasets[this.index],s=t.custom||{},l=o.options.elements.point,d={},u={chart:o,dataIndex:e,dataset:r,datasetIndex:this.index},h={backgroundColor:"pointBackgroundColor",borderColor:"pointBorderColor",borderWidth:"pointBorderWidth",hitRadius:"pointHitRadius",hoverBackgroundColor:"pointHoverBackgroundColor",hoverBorderColor:"pointHoverBorderColor",hoverBorderWidth:"pointHoverBorderWidth",hoverRadius:"pointHoverRadius",pointStyle:"pointStyle",radius:"pointRadius",rotation:"pointRotation"},c=Object.keys(h);for(i=0,n=c.length;i<n;++i)d[a=c[i]]=te([s[a],r[h[a]],r[a],l[a]],u,e);return d},_resolveLineOptions:function(t){var e,i,n,a=this.chart,o=a.data.datasets[this.index],r=t.custom||{},s=a.options,l=s.elements.line,d={},u=["backgroundColor","borderWidth","borderColor","borderCapStyle","borderDash","borderDashOffset","borderJoinStyle","fill","cubicInterpolationMode"];for(e=0,i=u.length;e<i;++e)d[n=u[e]]=te([r[n],o[n],l[n]]);return d.spanGaps=Qt(o.spanGaps,s.spanGaps),d.tension=Qt(o.lineTension,l.tension),d.steppedLine=te([r.steppedLine,o.steppedLine,l.stepped]),d},calculatePointY:function(t,e,i){var n,a,o,r=this.chart,s=this.getMeta(),l=this.getScaleForId(s.yAxisID),d=0,u=0;if(l.options.stacked){for(n=0;n<i;n++)if(a=r.data.datasets[n],"line"===(o=r.getDatasetMeta(n)).type&&o.yAxisID===l.id&&r.isDatasetVisible(n)){var h=Number(l.getRightValue(a.data[e]));h<0?u+=h||0:d+=h||0}var c=Number(l.getRightValue(t));return c<0?l.getPixelForValue(u+c):l.getPixelForValue(d+c)}return l.getPixelForValue(t)},updateBezierControlPoints:function(){var t,e,i,n,a=this.chart,o=this.getMeta(),r=o.dataset._model,s=a.chartArea,l=o.data||[];function d(t,e,i){return Math.max(Math.min(t,i),e)}if(r.spanGaps&&(l=l.filter(function(t){return!t._model.skip})),"monotone"===r.cubicInterpolationMode)ut.splineCurveMonotone(l);else for(t=0,e=l.length;t<e;++t)i=l[t]._model,n=ut.splineCurve(ut.previousItem(l,t)._model,i,ut.nextItem(l,t)._model,r.tension),i.controlPointPreviousX=n.previous.x,i.controlPointPreviousY=n.previous.y,i.controlPointNextX=n.next.x,i.controlPointNextY=n.next.y;if(a.options.elements.line.capBezierPoints)for(t=0,e=l.length;t<e;++t)i=l[t]._model,ee(i,s)&&(t>0&&ee(l[t-1]._model,s)&&(i.controlPointPreviousX=d(i.controlPointPreviousX,s.left,s.right),i.controlPointPreviousY=d(i.controlPointPreviousY,s.top,s.bottom)),t<l.length-1&&ee(l[t+1]._model,s)&&(i.controlPointNextX=d(i.controlPointNextX,s.left,s.right),i.controlPointNextY=d(i.controlPointNextY,s.top,s.bottom)))},draw:function(){var t,e=this.chart,i=this.getMeta(),n=i.data||[],a=e.chartArea,o=n.length,r=0;for(ie(this.getDataset(),e.options)&&(t=(i.dataset._model.borderWidth||0)/2,ut.canvas.clipArea(e.ctx,{left:a.left,right:a.right,top:a.top-t,bottom:a.bottom+t}),i.dataset.draw(),ut.canvas.unclipArea(e.ctx));r<o;++r)n[r].draw(a)},setHoverStyle:function(t){var e=t._model,i=t._options,n=ut.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=Qt(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=Qt(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=Qt(i.hoverBorderWidth,i.borderWidth),e.radius=Qt(i.hoverRadius,i.radius)}}),ae=ut.options.resolve;st._set("polarArea",{scale:{type:"radialLinear",angleLines:{display:!1},gridLines:{circular:!0},pointLabels:{display:!1},ticks:{beginAtZero:!0}},animation:{animateRotate:!0,animateScale:!0},startAngle:-.5*Math.PI,legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');var i=t.data,n=i.datasets,a=i.labels;if(n.length)for(var o=0;o<n[0].data.length;++o)e.push('<li><span style="background-color:'+n[0].backgroundColor[o]+'"></span>'),a[o]&&e.push(a[o]),e.push("</li>");return e.push("</ul>"),e.join("")},legend:{labels:{generateLabels:function(t){var e=t.data;return e.labels.length&&e.datasets.length?e.labels.map(function(i,n){var a=t.getDatasetMeta(0),o=e.datasets[0],r=a.data[n].custom||{},s=t.options.elements.arc;return{text:i,fillStyle:ae([r.backgroundColor,o.backgroundColor,s.backgroundColor],void 0,n),strokeStyle:ae([r.borderColor,o.borderColor,s.borderColor],void 0,n),lineWidth:ae([r.borderWidth,o.borderWidth,s.borderWidth],void 0,n),hidden:isNaN(o.data[n])||a.data[n].hidden,index:n}}):[]}},onClick:function(t,e){var i,n,a,o=e.index,r=this.chart;for(i=0,n=(r.data.datasets||[]).length;i<n;++i)(a=r.getDatasetMeta(i)).data[o].hidden=!a.data[o].hidden;r.update()}},tooltips:{callbacks:{title:function(){return""},label:function(t,e){return e.labels[t.index]+": "+t.yLabel}}}});var oe=Mt.extend({dataElementType:Wt.Arc,linkScales:ut.noop,update:function(t){var e,i,n,a=this,o=a.getDataset(),r=a.getMeta(),s=a.chart.options.startAngle||0,l=a._starts=[],d=a._angles=[],u=r.data;for(a._updateRadius(),r.count=a.countVisibleElements(),e=0,i=o.data.length;e<i;e++)l[e]=s,n=a._computeAngle(e),d[e]=n,s+=n;for(e=0,i=u.length;e<i;++e)u[e]._options=a._resolveElementOptions(u[e],e),a.updateElement(u[e],e,t)},_updateRadius:function(){var t=this,e=t.chart,i=e.chartArea,n=e.options,a=Math.min(i.right-i.left,i.bottom-i.top);e.outerRadius=Math.max(a/2,0),e.innerRadius=Math.max(n.cutoutPercentage?e.outerRadius/100*n.cutoutPercentage:1,0),e.radiusLength=(e.outerRadius-e.innerRadius)/e.getVisibleDatasetCount(),t.outerRadius=e.outerRadius-e.radiusLength*t.index,t.innerRadius=t.outerRadius-e.radiusLength},updateElement:function(t,e,i){var n=this,a=n.chart,o=n.getDataset(),r=a.options,s=r.animation,l=a.scale,d=a.data.labels,u=l.xCenter,h=l.yCenter,c=r.startAngle,f=t.hidden?0:l.getDistanceFromCenterForValue(o.data[e]),g=n._starts[e],p=g+(t.hidden?0:n._angles[e]),m=s.animateScale?0:l.getDistanceFromCenterForValue(o.data[e]),v=t._options||{};ut.extend(t,{_datasetIndex:n.index,_index:e,_scale:l,_model:{backgroundColor:v.backgroundColor,borderColor:v.borderColor,borderWidth:v.borderWidth,borderAlign:v.borderAlign,x:u,y:h,innerRadius:0,outerRadius:i?m:f,startAngle:i&&s.animateRotate?c:g,endAngle:i&&s.animateRotate?c:p,label:ut.valueAtIndexOrDefault(d,e,d[e])}}),t.pivot()},countVisibleElements:function(){var t=this.getDataset(),e=this.getMeta(),i=0;return ut.each(e.data,function(e,n){isNaN(t.data[n])||e.hidden||i++}),i},setHoverStyle:function(t){var e=t._model,i=t._options,n=ut.getHoverColor,a=ut.valueOrDefault;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth},e.backgroundColor=a(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=a(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=a(i.hoverBorderWidth,i.borderWidth)},_resolveElementOptions:function(t,e){var i,n,a,o=this.chart,r=this.getDataset(),s=t.custom||{},l=o.options.elements.arc,d={},u={chart:o,dataIndex:e,dataset:r,datasetIndex:this.index},h=["backgroundColor","borderColor","borderWidth","borderAlign","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth"];for(i=0,n=h.length;i<n;++i)d[a=h[i]]=ae([s[a],r[a],l[a]],u,e);return d},_computeAngle:function(t){var e=this,i=this.getMeta().count,n=e.getDataset(),a=e.getMeta();if(isNaN(n.data[t])||a.data[t].hidden)return 0;var o={chart:e.chart,dataIndex:t,dataset:n,datasetIndex:e.index};return ae([e.chart.options.elements.arc.angle,2*Math.PI/i],o,t)}});st._set("pie",ut.clone(st.doughnut)),st._set("pie",{cutoutPercentage:0});var re=$t,se=ut.valueOrDefault,le=ut.options.resolve;st._set("radar",{scale:{type:"radialLinear"},elements:{line:{tension:0}}});var de=Mt.extend({datasetElementType:Wt.Line,dataElementType:Wt.Point,linkScales:ut.noop,update:function(t){var e,i,n=this,a=n.getMeta(),o=a.dataset,r=a.data||[],s=n.chart.scale,l=n.getDataset();for(void 0!==l.tension&&void 0===l.lineTension&&(l.lineTension=l.tension),o._scale=s,o._datasetIndex=n.index,o._children=r,o._loop=!0,o._model=n._resolveLineOptions(o),o.pivot(),e=0,i=r.length;e<i;++e)n.updateElement(r[e],e,t);for(n.updateBezierControlPoints(),e=0,i=r.length;e<i;++e)r[e].pivot()},updateElement:function(t,e,i){var n=this,a=t.custom||{},o=n.getDataset(),r=n.chart.scale,s=r.getPointPositionForValue(e,o.data[e]),l=n._resolvePointOptions(t,e),d=n.getMeta().dataset._model,u=i?r.xCenter:s.x,h=i?r.yCenter:s.y;t._scale=r,t._options=l,t._datasetIndex=n.index,t._index=e,t._model={x:u,y:h,skip:a.skip||isNaN(u)||isNaN(h),radius:l.radius,pointStyle:l.pointStyle,rotation:l.rotation,backgroundColor:l.backgroundColor,borderColor:l.borderColor,borderWidth:l.borderWidth,tension:se(a.tension,d?d.tension:0),hitRadius:l.hitRadius}},_resolvePointOptions:function(t,e){var i,n,a,o=this.chart,r=o.data.datasets[this.index],s=t.custom||{},l=o.options.elements.point,d={},u={chart:o,dataIndex:e,dataset:r,datasetIndex:this.index},h={backgroundColor:"pointBackgroundColor",borderColor:"pointBorderColor",borderWidth:"pointBorderWidth",hitRadius:"pointHitRadius",hoverBackgroundColor:"pointHoverBackgroundColor",hoverBorderColor:"pointHoverBorderColor",hoverBorderWidth:"pointHoverBorderWidth",hoverRadius:"pointHoverRadius",pointStyle:"pointStyle",radius:"pointRadius",rotation:"pointRotation"},c=Object.keys(h);for(i=0,n=c.length;i<n;++i)d[a=c[i]]=le([s[a],r[h[a]],r[a],l[a]],u,e);return d},_resolveLineOptions:function(t){var e,i,n,a=this.chart,o=a.data.datasets[this.index],r=t.custom||{},s=a.options.elements.line,l={},d=["backgroundColor","borderWidth","borderColor","borderCapStyle","borderDash","borderDashOffset","borderJoinStyle","fill"];for(e=0,i=d.length;e<i;++e)l[n=d[e]]=le([r[n],o[n],s[n]]);return l.tension=se(o.lineTension,s.tension),l},updateBezierControlPoints:function(){var t,e,i,n,a=this.getMeta(),o=this.chart.chartArea,r=a.data||[];function s(t,e,i){return Math.max(Math.min(t,i),e)}for(t=0,e=r.length;t<e;++t)i=r[t]._model,n=ut.splineCurve(ut.previousItem(r,t,!0)._model,i,ut.nextItem(r,t,!0)._model,i.tension),i.controlPointPreviousX=s(n.previous.x,o.left,o.right),i.controlPointPreviousY=s(n.previous.y,o.top,o.bottom),i.controlPointNextX=s(n.next.x,o.left,o.right),i.controlPointNextY=s(n.next.y,o.top,o.bottom)},setHoverStyle:function(t){var e=t._model,i=t._options,n=ut.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=se(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=se(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=se(i.hoverBorderWidth,i.borderWidth),e.radius=se(i.hoverRadius,i.radius)}});st._set("scatter",{hover:{mode:"single"},scales:{xAxes:[{id:"x-axis-1",type:"linear",position:"bottom"}],yAxes:[{id:"y-axis-1",type:"linear",position:"left"}]},showLines:!1,tooltips:{callbacks:{title:function(){return""},label:function(t){return"("+t.xLabel+", "+t.yLabel+")"}}}});var ue={bar:Yt,bubble:Kt,doughnut:$t,horizontalBar:Jt,line:ne,polarArea:oe,pie:re,radar:de,scatter:ne};function he(t,e){return t.native?{x:t.x,y:t.y}:ut.getRelativePosition(t,e)}function ce(t,e){var i,n,a,o,r;for(n=0,o=t.data.datasets.length;n<o;++n)if(t.isDatasetVisible(n))for(a=0,r=(i=t.getDatasetMeta(n)).data.length;a<r;++a){var s=i.data[a];s._view.skip||e(s)}}function fe(t,e){var i=[];return ce(t,function(t){t.inRange(e.x,e.y)&&i.push(t)}),i}function ge(t,e,i,n){var a=Number.POSITIVE_INFINITY,o=[];return ce(t,function(t){if(!i||t.inRange(e.x,e.y)){var r=t.getCenterPoint(),s=n(e,r);s<a?(o=[t],a=s):s===a&&o.push(t)}}),o}function pe(t){var e=-1!==t.indexOf("x"),i=-1!==t.indexOf("y");return function(t,n){var a=e?Math.abs(t.x-n.x):0,o=i?Math.abs(t.y-n.y):0;return Math.sqrt(Math.pow(a,2)+Math.pow(o,2))}}function me(t,e,i){var n=he(e,t);i.axis=i.axis||"x";var a=pe(i.axis),o=i.intersect?fe(t,n):ge(t,n,!1,a),r=[];return o.length?(t.data.datasets.forEach(function(e,i){if(t.isDatasetVisible(i)){var n=t.getDatasetMeta(i).data[o[0]._index];n&&!n._view.skip&&r.push(n)}}),r):[]}var ve={modes:{single:function(t,e){var i=he(e,t),n=[];return ce(t,function(t){if(t.inRange(i.x,i.y))return n.push(t),n}),n.slice(0,1)},label:me,index:me,dataset:function(t,e,i){var n=he(e,t);i.axis=i.axis||"xy";var a=pe(i.axis),o=i.intersect?fe(t,n):ge(t,n,!1,a);return o.length>0&&(o=t.getDatasetMeta(o[0]._datasetIndex).data),o},"x-axis":function(t,e){return me(t,e,{intersect:!1})},point:function(t,e){return fe(t,he(e,t))},nearest:function(t,e,i){var n=he(e,t);i.axis=i.axis||"xy";var a=pe(i.axis);return ge(t,n,i.intersect,a)},x:function(t,e,i){var n=he(e,t),a=[],o=!1;return ce(t,function(t){t.inXRange(n.x)&&a.push(t),t.inRange(n.x,n.y)&&(o=!0)}),i.intersect&&!o&&(a=[]),a},y:function(t,e,i){var n=he(e,t),a=[],o=!1;return ce(t,function(t){t.inYRange(n.y)&&a.push(t),t.inRange(n.x,n.y)&&(o=!0)}),i.intersect&&!o&&(a=[]),a}}};function be(t,e){return ut.where(t,function(t){return t.position===e})}function xe(t,e){t.forEach(function(t,e){return t._tmpIndex_=e,t}),t.sort(function(t,i){var n=e?i:t,a=e?t:i;return n.weight===a.weight?n._tmpIndex_-a._tmpIndex_:n.weight-a.weight}),t.forEach(function(t){delete t._tmpIndex_})}function ye(t,e){ut.each(t,function(t){e[t.position]+=t.isHorizontal()?t.height:t.width})}st._set("global",{layout:{padding:{top:0,right:0,bottom:0,left:0}}});var ke={defaults:{},addBox:function(t,e){t.boxes||(t.boxes=[]),e.fullWidth=e.fullWidth||!1,e.position=e.position||"top",e.weight=e.weight||0,t.boxes.push(e)},removeBox:function(t,e){var i=t.boxes?t.boxes.indexOf(e):-1;-1!==i&&t.boxes.splice(i,1)},configure:function(t,e,i){for(var n,a=["fullWidth","position","weight"],o=a.length,r=0;r<o;++r)n=a[r],i.hasOwnProperty(n)&&(e[n]=i[n])},update:function(t,e,i){if(t){var n=t.options.layout||{},a=ut.options.toPadding(n.padding),o=a.left,r=a.right,s=a.top,l=a.bottom,d=be(t.boxes,"left"),u=be(t.boxes,"right"),h=be(t.boxes,"top"),c=be(t.boxes,"bottom"),f=be(t.boxes,"chartArea");xe(d,!0),xe(u,!1),xe(h,!0),xe(c,!1);var g,p=d.concat(u),m=h.concat(c),v=p.concat(m),b=e-o-r,x=i-s-l,y=(e-b/2)/p.length,k=b,w=x,M={top:s,left:o,bottom:l,right:r},_=[];ut.each(v,function(t){var e,i=t.isHorizontal();i?(e=t.update(t.fullWidth?b:k,x/2),w-=e.height):(e=t.update(y,w),k-=e.width),_.push({horizontal:i,width:e.width,box:t})}),g=function(t){var e=0,i=0,n=0,a=0;return ut.each(t,function(t){if(t.getPadding){var o=t.getPadding();e=Math.max(e,o.top),i=Math.max(i,o.left),n=Math.max(n,o.bottom),a=Math.max(a,o.right)}}),{top:e,left:i,bottom:n,right:a}}(v),ut.each(p,T),ye(p,M),ut.each(m,T),ye(m,M),ut.each(p,function(t){var e=ut.findNextWhere(_,function(e){return e.box===t}),i={left:0,right:0,top:M.top,bottom:M.bottom};e&&t.update(e.width,w,i)}),ye(v,M={top:s,left:o,bottom:l,right:r});var C=Math.max(g.left-M.left,0);M.left+=C,M.right+=Math.max(g.right-M.right,0);var S=Math.max(g.top-M.top,0);M.top+=S,M.bottom+=Math.max(g.bottom-M.bottom,0);var P=i-M.top-M.bottom,I=e-M.left-M.right;I===k&&P===w||(ut.each(p,function(t){t.height=P}),ut.each(m,function(t){t.fullWidth||(t.width=I)}),w=P,k=I);var A=o+C,D=s+S;ut.each(d.concat(h),F),A+=k,D+=w,ut.each(u,F),ut.each(c,F),t.chartArea={left:M.left,top:M.top,right:M.left+k,bottom:M.top+w},ut.each(f,function(e){e.left=t.chartArea.left,e.top=t.chartArea.top,e.right=t.chartArea.right,e.bottom=t.chartArea.bottom,e.update(k,w)})}function T(t){var e=ut.findNextWhere(_,function(e){return e.box===t});if(e)if(e.horizontal){var i={left:Math.max(M.left,g.left),right:Math.max(M.right,g.right),top:0,bottom:0};t.update(t.fullWidth?b:k,x/2,i)}else t.update(e.width,w)}function F(t){t.isHorizontal()?(t.left=t.fullWidth?o:M.left,t.right=t.fullWidth?e-r:M.left+k,t.top=D,t.bottom=D+t.height,D=t.bottom):(t.left=A,t.right=A+t.width,t.top=M.top,t.bottom=M.top+w,A=t.right)}}};var we,Me=(we=Object.freeze({default:"@keyframes chartjs-render-animation{from{opacity:.99}to{opacity:1}}.chartjs-render-monitor{animation:chartjs-render-animation 1ms}.chartjs-size-monitor,.chartjs-size-monitor-expand,.chartjs-size-monitor-shrink{position:absolute;direction:ltr;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1}.chartjs-size-monitor-expand>div{position:absolute;width:1000000px;height:1000000px;left:0;top:0}.chartjs-size-monitor-shrink>div{position:absolute;width:200%;height:200%;left:0;top:0}"}))&&we.default||we,_e="$chartjs",Ce="chartjs-size-monitor",Se="chartjs-render-monitor",Pe="chartjs-render-animation",Ie=["animationstart","webkitAnimationStart"],Ae={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"};function De(t,e){var i=ut.getStyle(t,e),n=i&&i.match(/^(\d+)(\.\d+)?px$/);return n?Number(n[1]):void 0}var Te=!!function(){var t=!1;try{var e=Object.defineProperty({},"passive",{get:function(){t=!0}});window.addEventListener("e",null,e)}catch(t){}return t}()&&{passive:!0};function Fe(t,e,i){t.addEventListener(e,i,Te)}function Le(t,e,i){t.removeEventListener(e,i,Te)}function Re(t,e,i,n,a){return{type:t,chart:e,native:a||null,x:void 0!==i?i:null,y:void 0!==n?n:null}}function Oe(t){var e=document.createElement("div");return e.className=t||"",e}function ze(t,e,i){var n,a,o,r,s=t[_e]||(t[_e]={}),l=s.resizer=function(t){var e=Oe(Ce),i=Oe(Ce+"-expand"),n=Oe(Ce+"-shrink");i.appendChild(Oe()),n.appendChild(Oe()),e.appendChild(i),e.appendChild(n),e._reset=function(){i.scrollLeft=1e6,i.scrollTop=1e6,n.scrollLeft=1e6,n.scrollTop=1e6};var a=function(){e._reset(),t()};return Fe(i,"scroll",a.bind(i,"expand")),Fe(n,"scroll",a.bind(n,"shrink")),e}((n=function(){if(s.resizer){var n=i.options.maintainAspectRatio&&t.parentNode,a=n?n.clientWidth:0;e(Re("resize",i)),n&&n.clientWidth<a&&i.canvas&&e(Re("resize",i))}},o=!1,r=[],function(){r=Array.prototype.slice.call(arguments),a=a||this,o||(o=!0,ut.requestAnimFrame.call(window,function(){o=!1,n.apply(a,r)}))}));!function(t,e){var i=t[_e]||(t[_e]={}),n=i.renderProxy=function(t){t.animationName===Pe&&e()};ut.each(Ie,function(e){Fe(t,e,n)}),i.reflow=!!t.offsetParent,t.classList.add(Se)}(t,function(){if(s.resizer){var e=t.parentNode;e&&e!==l.parentNode&&e.insertBefore(l,e.firstChild),l._reset()}})}function Be(t){var e=t[_e]||{},i=e.resizer;delete e.resizer,function(t){var e=t[_e]||{},i=e.renderProxy;i&&(ut.each(Ie,function(e){Le(t,e,i)}),delete e.renderProxy),t.classList.remove(Se)}(t),i&&i.parentNode&&i.parentNode.removeChild(i)}var Ne={disableCSSInjection:!1,_enabled:"undefined"!=typeof window&&"undefined"!=typeof document,_ensureLoaded:function(){var t,e,i;this._loaded||(this._loaded=!0,this.disableCSSInjection||(e=Me,i=(t=this)._style||document.createElement("style"),t._style||(t._style=i,e="/* Chart.js */\n"+e,i.setAttribute("type","text/css"),document.getElementsByTagName("head")[0].appendChild(i)),i.appendChild(document.createTextNode(e))))},acquireContext:function(t,e){"string"==typeof t?t=document.getElementById(t):t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas);var i=t&&t.getContext&&t.getContext("2d");return this._ensureLoaded(),i&&i.canvas===t?(function(t,e){var i=t.style,n=t.getAttribute("height"),a=t.getAttribute("width");if(t[_e]={initial:{height:n,width:a,style:{display:i.display,height:i.height,width:i.width}}},i.display=i.display||"block",null===a||""===a){var o=De(t,"width");void 0!==o&&(t.width=o)}if(null===n||""===n)if(""===t.style.height)t.height=t.width/(e.options.aspectRatio||2);else{var r=De(t,"height");void 0!==o&&(t.height=r)}}(t,e),i):null},releaseContext:function(t){var e=t.canvas;if(e[_e]){var i=e[_e].initial;["height","width"].forEach(function(t){var n=i[t];ut.isNullOrUndef(n)?e.removeAttribute(t):e.setAttribute(t,n)}),ut.each(i.style||{},function(t,i){e.style[i]=t}),e.width=e.width,delete e[_e]}},addEventListener:function(t,e,i){var n=t.canvas;if("resize"!==e){var a=i[_e]||(i[_e]={});Fe(n,e,(a.proxies||(a.proxies={}))[t.id+"_"+e]=function(e){i(function(t,e){var i=Ae[t.type]||t.type,n=ut.getRelativePosition(t,e);return Re(i,e,n.x,n.y,t)}(e,t))})}else ze(n,i,t)},removeEventListener:function(t,e,i){var n=t.canvas;if("resize"!==e){var a=((i[_e]||{}).proxies||{})[t.id+"_"+e];a&&Le(n,e,a)}else Be(n)}};ut.addEvent=Fe,ut.removeEvent=Le;var We=Ne._enabled?Ne:{acquireContext:function(t){return t&&t.canvas&&(t=t.canvas),t&&t.getContext("2d")||null}},Ve=ut.extend({initialize:function(){},acquireContext:function(){},releaseContext:function(){},addEventListener:function(){},removeEventListener:function(){}},We);st._set("global",{plugins:{}});var Ee={_plugins:[],_cacheId:0,register:function(t){var e=this._plugins;[].concat(t).forEach(function(t){-1===e.indexOf(t)&&e.push(t)}),this._cacheId++},unregister:function(t){var e=this._plugins;[].concat(t).forEach(function(t){var i=e.indexOf(t);-1!==i&&e.splice(i,1)}),this._cacheId++},clear:function(){this._plugins=[],this._cacheId++},count:function(){return this._plugins.length},getAll:function(){return this._plugins},notify:function(t,e,i){var n,a,o,r,s,l=this.descriptors(t),d=l.length;for(n=0;n<d;++n)if("function"==typeof(s=(o=(a=l[n]).plugin)[e])&&((r=[t].concat(i||[])).push(a.options),!1===s.apply(o,r)))return!1;return!0},descriptors:function(t){var e=t.$plugins||(t.$plugins={});if(e.id===this._cacheId)return e.descriptors;var i=[],n=[],a=t&&t.config||{},o=a.options&&a.options.plugins||{};return this._plugins.concat(a.plugins||[]).forEach(function(t){if(-1===i.indexOf(t)){var e=t.id,a=o[e];!1!==a&&(!0===a&&(a=ut.clone(st.global.plugins[e])),i.push(t),n.push({plugin:t,options:a||{}}))}}),e.descriptors=n,e.id=this._cacheId,n},_invalidate:function(t){delete t.$plugins}},He={constructors:{},defaults:{},registerScaleType:function(t,e,i){this.constructors[t]=e,this.defaults[t]=ut.clone(i)},getScaleConstructor:function(t){return this.constructors.hasOwnProperty(t)?this.constructors[t]:void 0},getScaleDefaults:function(t){return this.defaults.hasOwnProperty(t)?ut.merge({},[st.scale,this.defaults[t]]):{}},updateScaleDefaults:function(t,e){this.defaults.hasOwnProperty(t)&&(this.defaults[t]=ut.extend(this.defaults[t],e))},addScalesToLayout:function(t){ut.each(t.scales,function(e){e.fullWidth=e.options.fullWidth,e.position=e.options.position,e.weight=e.options.weight,ke.addBox(t,e)})}},je=ut.valueOrDefault;st._set("global",{tooltips:{enabled:!0,custom:null,mode:"nearest",position:"average",intersect:!0,backgroundColor:"rgba(0,0,0,0.8)",titleFontStyle:"bold",titleSpacing:2,titleMarginBottom:6,titleFontColor:"#fff",titleAlign:"left",bodySpacing:2,bodyFontColor:"#fff",bodyAlign:"left",footerFontStyle:"bold",footerSpacing:2,footerMarginTop:6,footerFontColor:"#fff",footerAlign:"left",yPadding:6,xPadding:6,caretPadding:2,caretSize:5,cornerRadius:6,multiKeyBackground:"#fff",displayColors:!0,borderColor:"rgba(0,0,0,0)",borderWidth:0,callbacks:{beforeTitle:ut.noop,title:function(t,e){var i="",n=e.labels,a=n?n.length:0;if(t.length>0){var o=t[0];o.label?i=o.label:o.xLabel?i=o.xLabel:a>0&&o.index<a&&(i=n[o.index])}return i},afterTitle:ut.noop,beforeBody:ut.noop,beforeLabel:ut.noop,label:function(t,e){var i=e.datasets[t.datasetIndex].label||"";return i&&(i+=": "),ut.isNullOrUndef(t.value)?i+=t.yLabel:i+=t.value,i},labelColor:function(t,e){var i=e.getDatasetMeta(t.datasetIndex).data[t.index]._view;return{borderColor:i.borderColor,backgroundColor:i.backgroundColor}},labelTextColor:function(){return this._options.bodyFontColor},afterLabel:ut.noop,afterBody:ut.noop,beforeFooter:ut.noop,footer:ut.noop,afterFooter:ut.noop}}});var qe={average:function(t){if(!t.length)return!1;var e,i,n=0,a=0,o=0;for(e=0,i=t.length;e<i;++e){var r=t[e];if(r&&r.hasValue()){var s=r.tooltipPosition();n+=s.x,a+=s.y,++o}}return{x:n/o,y:a/o}},nearest:function(t,e){var i,n,a,o=e.x,r=e.y,s=Number.POSITIVE_INFINITY;for(i=0,n=t.length;i<n;++i){var l=t[i];if(l&&l.hasValue()){var d=l.getCenterPoint(),u=ut.distanceBetweenPoints(e,d);u<s&&(s=u,a=l)}}if(a){var h=a.tooltipPosition();o=h.x,r=h.y}return{x:o,y:r}}};function Ye(t,e){return e&&(ut.isArray(e)?Array.prototype.push.apply(t,e):t.push(e)),t}function Ue(t){return("string"==typeof t||t instanceof String)&&t.indexOf("\n")>-1?t.split("\n"):t}function Xe(t){var e=st.global;return{xPadding:t.xPadding,yPadding:t.yPadding,xAlign:t.xAlign,yAlign:t.yAlign,bodyFontColor:t.bodyFontColor,_bodyFontFamily:je(t.bodyFontFamily,e.defaultFontFamily),_bodyFontStyle:je(t.bodyFontStyle,e.defaultFontStyle),_bodyAlign:t.bodyAlign,bodyFontSize:je(t.bodyFontSize,e.defaultFontSize),bodySpacing:t.bodySpacing,titleFontColor:t.titleFontColor,_titleFontFamily:je(t.titleFontFamily,e.defaultFontFamily),_titleFontStyle:je(t.titleFontStyle,e.defaultFontStyle),titleFontSize:je(t.titleFontSize,e.defaultFontSize),_titleAlign:t.titleAlign,titleSpacing:t.titleSpacing,titleMarginBottom:t.titleMarginBottom,footerFontColor:t.footerFontColor,_footerFontFamily:je(t.footerFontFamily,e.defaultFontFamily),_footerFontStyle:je(t.footerFontStyle,e.defaultFontStyle),footerFontSize:je(t.footerFontSize,e.defaultFontSize),_footerAlign:t.footerAlign,footerSpacing:t.footerSpacing,footerMarginTop:t.footerMarginTop,caretSize:t.caretSize,cornerRadius:t.cornerRadius,backgroundColor:t.backgroundColor,opacity:0,legendColorBackground:t.multiKeyBackground,displayColors:t.displayColors,borderColor:t.borderColor,borderWidth:t.borderWidth}}function Ke(t,e){return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-t.xPadding:t.x+t.xPadding}function Ge(t){return Ye([],Ue(t))}var Ze=pt.extend({initialize:function(){this._model=Xe(this._options),this._lastActive=[]},getTitle:function(){var t=this._options.callbacks,e=t.beforeTitle.apply(this,arguments),i=t.title.apply(this,arguments),n=t.afterTitle.apply(this,arguments),a=[];return a=Ye(a,Ue(e)),a=Ye(a,Ue(i)),a=Ye(a,Ue(n))},getBeforeBody:function(){return Ge(this._options.callbacks.beforeBody.apply(this,arguments))},getBody:function(t,e){var i=this,n=i._options.callbacks,a=[];return ut.each(t,function(t){var o={before:[],lines:[],after:[]};Ye(o.before,Ue(n.beforeLabel.call(i,t,e))),Ye(o.lines,n.label.call(i,t,e)),Ye(o.after,Ue(n.afterLabel.call(i,t,e))),a.push(o)}),a},getAfterBody:function(){return Ge(this._options.callbacks.afterBody.apply(this,arguments))},getFooter:function(){var t=this._options.callbacks,e=t.beforeFooter.apply(this,arguments),i=t.footer.apply(this,arguments),n=t.afterFooter.apply(this,arguments),a=[];return a=Ye(a,Ue(e)),a=Ye(a,Ue(i)),a=Ye(a,Ue(n))},update:function(t){var e,i,n,a,o,r,s,l,d,u,h=this,c=h._options,f=h._model,g=h._model=Xe(c),p=h._active,m=h._data,v={xAlign:f.xAlign,yAlign:f.yAlign},b={x:f.x,y:f.y},x={width:f.width,height:f.height},y={x:f.caretX,y:f.caretY};if(p.length){g.opacity=1;var k=[],w=[];y=qe[c.position].call(h,p,h._eventPosition);var M=[];for(e=0,i=p.length;e<i;++e)M.push((n=p[e],a=void 0,o=void 0,r=void 0,s=void 0,l=void 0,d=void 0,u=void 0,a=n._xScale,o=n._yScale||n._scale,r=n._index,s=n._datasetIndex,l=n._chart.getDatasetMeta(s).controller,d=l._getIndexScale(),u=l._getValueScale(),{xLabel:a?a.getLabelForIndex(r,s):"",yLabel:o?o.getLabelForIndex(r,s):"",label:d?""+d.getLabelForIndex(r,s):"",value:u?""+u.getLabelForIndex(r,s):"",index:r,datasetIndex:s,x:n._model.x,y:n._model.y}));c.filter&&(M=M.filter(function(t){return c.filter(t,m)})),c.itemSort&&(M=M.sort(function(t,e){return c.itemSort(t,e,m)})),ut.each(M,function(t){k.push(c.callbacks.labelColor.call(h,t,h._chart)),w.push(c.callbacks.labelTextColor.call(h,t,h._chart))}),g.title=h.getTitle(M,m),g.beforeBody=h.getBeforeBody(M,m),g.body=h.getBody(M,m),g.afterBody=h.getAfterBody(M,m),g.footer=h.getFooter(M,m),g.x=y.x,g.y=y.y,g.caretPadding=c.caretPadding,g.labelColors=k,g.labelTextColors=w,g.dataPoints=M,x=function(t,e){var i=t._chart.ctx,n=2*e.yPadding,a=0,o=e.body,r=o.reduce(function(t,e){return t+e.before.length+e.lines.length+e.after.length},0);r+=e.beforeBody.length+e.afterBody.length;var s=e.title.length,l=e.footer.length,d=e.titleFontSize,u=e.bodyFontSize,h=e.footerFontSize;n+=s*d,n+=s?(s-1)*e.titleSpacing:0,n+=s?e.titleMarginBottom:0,n+=r*u,n+=r?(r-1)*e.bodySpacing:0,n+=l?e.footerMarginTop:0,n+=l*h,n+=l?(l-1)*e.footerSpacing:0;var c=0,f=function(t){a=Math.max(a,i.measureText(t).width+c)};return i.font=ut.fontString(d,e._titleFontStyle,e._titleFontFamily),ut.each(e.title,f),i.font=ut.fontString(u,e._bodyFontStyle,e._bodyFontFamily),ut.each(e.beforeBody.concat(e.afterBody),f),c=e.displayColors?u+2:0,ut.each(o,function(t){ut.each(t.before,f),ut.each(t.lines,f),ut.each(t.after,f)}),c=0,i.font=ut.fontString(h,e._footerFontStyle,e._footerFontFamily),ut.each(e.footer,f),{width:a+=2*e.xPadding,height:n}}(this,g),b=function(t,e,i,n){var a=t.x,o=t.y,r=t.caretSize,s=t.caretPadding,l=t.cornerRadius,d=i.xAlign,u=i.yAlign,h=r+s,c=l+s;return"right"===d?a-=e.width:"center"===d&&((a-=e.width/2)+e.width>n.width&&(a=n.width-e.width),a<0&&(a=0)),"top"===u?o+=h:o-="bottom"===u?e.height+h:e.height/2,"center"===u?"left"===d?a+=h:"right"===d&&(a-=h):"left"===d?a-=c:"right"===d&&(a+=c),{x:a,y:o}}(g,x,v=function(t,e){var i,n,a,o,r,s=t._model,l=t._chart,d=t._chart.chartArea,u="center",h="center";s.y<e.height?h="top":s.y>l.height-e.height&&(h="bottom");var c=(d.left+d.right)/2,f=(d.top+d.bottom)/2;"center"===h?(i=function(t){return t<=c},n=function(t){return t>c}):(i=function(t){return t<=e.width/2},n=function(t){return t>=l.width-e.width/2}),a=function(t){return t+e.width+s.caretSize+s.caretPadding>l.width},o=function(t){return t-e.width-s.caretSize-s.caretPadding<0},r=function(t){return t<=f?"top":"bottom"},i(s.x)?(u="left",a(s.x)&&(u="center",h=r(s.y))):n(s.x)&&(u="right",o(s.x)&&(u="center",h=r(s.y)));var g=t._options;return{xAlign:g.xAlign?g.xAlign:u,yAlign:g.yAlign?g.yAlign:h}}(this,x),h._chart)}else g.opacity=0;return g.xAlign=v.xAlign,g.yAlign=v.yAlign,g.x=b.x,g.y=b.y,g.width=x.width,g.height=x.height,g.caretX=y.x,g.caretY=y.y,h._model=g,t&&c.custom&&c.custom.call(h,g),h},drawCaret:function(t,e){var i=this._chart.ctx,n=this._view,a=this.getCaretPosition(t,e,n);i.lineTo(a.x1,a.y1),i.lineTo(a.x2,a.y2),i.lineTo(a.x3,a.y3)},getCaretPosition:function(t,e,i){var n,a,o,r,s,l,d=i.caretSize,u=i.cornerRadius,h=i.xAlign,c=i.yAlign,f=t.x,g=t.y,p=e.width,m=e.height;if("center"===c)s=g+m/2,"left"===h?(a=(n=f)-d,o=n,r=s+d,l=s-d):(a=(n=f+p)+d,o=n,r=s-d,l=s+d);else if("left"===h?(n=(a=f+u+d)-d,o=a+d):"right"===h?(n=(a=f+p-u-d)-d,o=a+d):(n=(a=i.caretX)-d,o=a+d),"top"===c)s=(r=g)-d,l=r;else{s=(r=g+m)+d,l=r;var v=o;o=n,n=v}return{x1:n,x2:a,x3:o,y1:r,y2:s,y3:l}},drawTitle:function(t,e,i){var n=e.title;if(n.length){t.x=Ke(e,e._titleAlign),i.textAlign=e._titleAlign,i.textBaseline="top";var a,o,r=e.titleFontSize,s=e.titleSpacing;for(i.fillStyle=e.titleFontColor,i.font=ut.fontString(r,e._titleFontStyle,e._titleFontFamily),a=0,o=n.length;a<o;++a)i.fillText(n[a],t.x,t.y),t.y+=r+s,a+1===n.length&&(t.y+=e.titleMarginBottom-s)}},drawBody:function(t,e,i){var n,a=e.bodyFontSize,o=e.bodySpacing,r=e._bodyAlign,s=e.body,l=e.displayColors,d=e.labelColors,u=0,h=l?Ke(e,"left"):0;i.textAlign=r,i.textBaseline="top",i.font=ut.fontString(a,e._bodyFontStyle,e._bodyFontFamily),t.x=Ke(e,r);var c=function(e){i.fillText(e,t.x+u,t.y),t.y+=a+o};i.fillStyle=e.bodyFontColor,ut.each(e.beforeBody,c),u=l&&"right"!==r?"center"===r?a/2+1:a+2:0,ut.each(s,function(o,r){n=e.labelTextColors[r],i.fillStyle=n,ut.each(o.before,c),ut.each(o.lines,function(o){l&&(i.fillStyle=e.legendColorBackground,i.fillRect(h,t.y,a,a),i.lineWidth=1,i.strokeStyle=d[r].borderColor,i.strokeRect(h,t.y,a,a),i.fillStyle=d[r].backgroundColor,i.fillRect(h+1,t.y+1,a-2,a-2),i.fillStyle=n),c(o)}),ut.each(o.after,c)}),u=0,ut.each(e.afterBody,c),t.y-=o},drawFooter:function(t,e,i){var n=e.footer;n.length&&(t.x=Ke(e,e._footerAlign),t.y+=e.footerMarginTop,i.textAlign=e._footerAlign,i.textBaseline="top",i.fillStyle=e.footerFontColor,i.font=ut.fontString(e.footerFontSize,e._footerFontStyle,e._footerFontFamily),ut.each(n,function(n){i.fillText(n,t.x,t.y),t.y+=e.footerFontSize+e.footerSpacing}))},drawBackground:function(t,e,i,n){i.fillStyle=e.backgroundColor,i.strokeStyle=e.borderColor,i.lineWidth=e.borderWidth;var a=e.xAlign,o=e.yAlign,r=t.x,s=t.y,l=n.width,d=n.height,u=e.cornerRadius;i.beginPath(),i.moveTo(r+u,s),"top"===o&&this.drawCaret(t,n),i.lineTo(r+l-u,s),i.quadraticCurveTo(r+l,s,r+l,s+u),"center"===o&&"right"===a&&this.drawCaret(t,n),i.lineTo(r+l,s+d-u),i.quadraticCurveTo(r+l,s+d,r+l-u,s+d),"bottom"===o&&this.drawCaret(t,n),i.lineTo(r+u,s+d),i.quadraticCurveTo(r,s+d,r,s+d-u),"center"===o&&"left"===a&&this.drawCaret(t,n),i.lineTo(r,s+u),i.quadraticCurveTo(r,s,r+u,s),i.closePath(),i.fill(),e.borderWidth>0&&i.stroke()},draw:function(){var t=this._chart.ctx,e=this._view;if(0!==e.opacity){var i={width:e.width,height:e.height},n={x:e.x,y:e.y},a=Math.abs(e.opacity<.001)?0:e.opacity,o=e.title.length||e.beforeBody.length||e.body.length||e.afterBody.length||e.footer.length;this._options.enabled&&o&&(t.save(),t.globalAlpha=a,this.drawBackground(n,e,t,i),n.y+=e.yPadding,this.drawTitle(n,e,t),this.drawBody(n,e,t),this.drawFooter(n,e,t),t.restore())}},handleEvent:function(t){var e,i=this,n=i._options;return i._lastActive=i._lastActive||[],"mouseout"===t.type?i._active=[]:i._active=i._chart.getElementsAtEventForMode(t,n.mode,n),(e=!ut.arrayEquals(i._active,i._lastActive))&&(i._lastActive=i._active,(n.enabled||n.custom)&&(i._eventPosition={x:t.x,y:t.y},i.update(!0),i.pivot())),e}}),$e=qe,Je=Ze;Je.positioners=$e;var Qe=ut.valueOrDefault;function ti(){return ut.merge({},[].slice.call(arguments),{merger:function(t,e,i,n){if("xAxes"===t||"yAxes"===t){var a,o,r,s=i[t].length;for(e[t]||(e[t]=[]),a=0;a<s;++a)r=i[t][a],o=Qe(r.type,"xAxes"===t?"category":"linear"),a>=e[t].length&&e[t].push({}),!e[t][a].type||r.type&&r.type!==e[t][a].type?ut.merge(e[t][a],[He.getScaleDefaults(o),r]):ut.merge(e[t][a],r)}else ut._merger(t,e,i,n)}})}function ei(){return ut.merge({},[].slice.call(arguments),{merger:function(t,e,i,n){var a=e[t]||{},o=i[t];"scales"===t?e[t]=ti(a,o):"scale"===t?e[t]=ut.merge(a,[He.getScaleDefaults(o.type),o]):ut._merger(t,e,i,n)}})}function ii(t){return"top"===t||"bottom"===t}st._set("global",{elements:{},events:["mousemove","mouseout","click","touchstart","touchmove"],hover:{onHover:null,mode:"nearest",intersect:!0,animationDuration:400},onClick:null,maintainAspectRatio:!0,responsive:!0,responsiveAnimationDuration:0});var ni=function(t,e){return this.construct(t,e),this};ut.extend(ni.prototype,{construct:function(t,e){var i=this;e=function(t){var e=(t=t||{}).data=t.data||{};return e.datasets=e.datasets||[],e.labels=e.labels||[],t.options=ei(st.global,st[t.type],t.options||{}),t}(e);var n=Ve.acquireContext(t,e),a=n&&n.canvas,o=a&&a.height,r=a&&a.width;i.id=ut.uid(),i.ctx=n,i.canvas=a,i.config=e,i.width=r,i.height=o,i.aspectRatio=o?r/o:null,i.options=e.options,i._bufferedRender=!1,i.chart=i,i.controller=i,ni.instances[i.id]=i,Object.defineProperty(i,"data",{get:function(){return i.config.data},set:function(t){i.config.data=t}}),n&&a?(i.initialize(),i.update()):console.error("Failed to create chart: can't acquire context from the given item")},initialize:function(){var t=this;return Ee.notify(t,"beforeInit"),ut.retinaScale(t,t.options.devicePixelRatio),t.bindEvents(),t.options.responsive&&t.resize(!0),t.ensureScalesHaveIDs(),t.buildOrUpdateScales(),t.initToolTip(),Ee.notify(t,"afterInit"),t},clear:function(){return ut.canvas.clear(this),this},stop:function(){return bt.cancelAnimation(this),this},resize:function(t){var e=this,i=e.options,n=e.canvas,a=i.maintainAspectRatio&&e.aspectRatio||null,o=Math.max(0,Math.floor(ut.getMaximumWidth(n))),r=Math.max(0,Math.floor(a?o/a:ut.getMaximumHeight(n)));if((e.width!==o||e.height!==r)&&(n.width=e.width=o,n.height=e.height=r,n.style.width=o+"px",n.style.height=r+"px",ut.retinaScale(e,i.devicePixelRatio),!t)){var s={width:o,height:r};Ee.notify(e,"resize",[s]),i.onResize&&i.onResize(e,s),e.stop(),e.update({duration:i.responsiveAnimationDuration})}},ensureScalesHaveIDs:function(){var t=this.options,e=t.scales||{},i=t.scale;ut.each(e.xAxes,function(t,e){t.id=t.id||"x-axis-"+e}),ut.each(e.yAxes,function(t,e){t.id=t.id||"y-axis-"+e}),i&&(i.id=i.id||"scale")},buildOrUpdateScales:function(){var t=this,e=t.options,i=t.scales||{},n=[],a=Object.keys(i).reduce(function(t,e){return t[e]=!1,t},{});e.scales&&(n=n.concat((e.scales.xAxes||[]).map(function(t){return{options:t,dtype:"category",dposition:"bottom"}}),(e.scales.yAxes||[]).map(function(t){return{options:t,dtype:"linear",dposition:"left"}}))),e.scale&&n.push({options:e.scale,dtype:"radialLinear",isDefault:!0,dposition:"chartArea"}),ut.each(n,function(e){var n=e.options,o=n.id,r=Qe(n.type,e.dtype);ii(n.position)!==ii(e.dposition)&&(n.position=e.dposition),a[o]=!0;var s=null;if(o in i&&i[o].type===r)(s=i[o]).options=n,s.ctx=t.ctx,s.chart=t;else{var l=He.getScaleConstructor(r);if(!l)return;s=new l({id:o,type:r,options:n,ctx:t.ctx,chart:t}),i[s.id]=s}s.mergeTicksOptions(),e.isDefault&&(t.scale=s)}),ut.each(a,function(t,e){t||delete i[e]}),t.scales=i,He.addScalesToLayout(this)},buildOrUpdateControllers:function(){var t=this,e=[];return ut.each(t.data.datasets,function(i,n){var a=t.getDatasetMeta(n),o=i.type||t.config.type;if(a.type&&a.type!==o&&(t.destroyDatasetMeta(n),a=t.getDatasetMeta(n)),a.type=o,a.controller)a.controller.updateIndex(n),a.controller.linkScales();else{var r=ue[a.type];if(void 0===r)throw new Error('"'+a.type+'" is not a chart type.');a.controller=new r(t,n),e.push(a.controller)}},t),e},resetElements:function(){var t=this;ut.each(t.data.datasets,function(e,i){t.getDatasetMeta(i).controller.reset()},t)},reset:function(){this.resetElements(),this.tooltip.initialize()},update:function(t){var e,i,n=this;if(t&&"object"==typeof t||(t={duration:t,lazy:arguments[1]}),i=(e=n).options,ut.each(e.scales,function(t){ke.removeBox(e,t)}),i=ei(st.global,st[e.config.type],i),e.options=e.config.options=i,e.ensureScalesHaveIDs(),e.buildOrUpdateScales(),e.tooltip._options=i.tooltips,e.tooltip.initialize(),Ee._invalidate(n),!1!==Ee.notify(n,"beforeUpdate")){n.tooltip._data=n.data;var a=n.buildOrUpdateControllers();ut.each(n.data.datasets,function(t,e){n.getDatasetMeta(e).controller.buildOrUpdateElements()},n),n.updateLayout(),n.options.animation&&n.options.animation.duration&&ut.each(a,function(t){t.reset()}),n.updateDatasets(),n.tooltip.initialize(),n.lastActive=[],Ee.notify(n,"afterUpdate"),n._bufferedRender?n._bufferedRequest={duration:t.duration,easing:t.easing,lazy:t.lazy}:n.render(t)}},updateLayout:function(){!1!==Ee.notify(this,"beforeLayout")&&(ke.update(this,this.width,this.height),Ee.notify(this,"afterScaleUpdate"),Ee.notify(this,"afterLayout"))},updateDatasets:function(){if(!1!==Ee.notify(this,"beforeDatasetsUpdate")){for(var t=0,e=this.data.datasets.length;t<e;++t)this.updateDataset(t);Ee.notify(this,"afterDatasetsUpdate")}},updateDataset:function(t){var e=this.getDatasetMeta(t),i={meta:e,index:t};!1!==Ee.notify(this,"beforeDatasetUpdate",[i])&&(e.controller.update(),Ee.notify(this,"afterDatasetUpdate",[i]))},render:function(t){var e=this;t&&"object"==typeof t||(t={duration:t,lazy:arguments[1]});var i=e.options.animation,n=Qe(t.duration,i&&i.duration),a=t.lazy;if(!1!==Ee.notify(e,"beforeRender")){var o=function(t){Ee.notify(e,"afterRender"),ut.callback(i&&i.onComplete,[t],e)};if(i&&n){var r=new vt({numSteps:n/16.66,easing:t.easing||i.easing,render:function(t,e){var i=ut.easing.effects[e.easing],n=e.currentStep,a=n/e.numSteps;t.draw(i(a),a,n)},onAnimationProgress:i.onProgress,onAnimationComplete:o});bt.addAnimation(e,r,n,a)}else e.draw(),o(new vt({numSteps:0,chart:e}));return e}},draw:function(t){var e=this;e.clear(),ut.isNullOrUndef(t)&&(t=1),e.transition(t),e.width<=0||e.height<=0||!1!==Ee.notify(e,"beforeDraw",[t])&&(ut.each(e.boxes,function(t){t.draw(e.chartArea)},e),e.drawDatasets(t),e._drawTooltip(t),Ee.notify(e,"afterDraw",[t]))},transition:function(t){for(var e=0,i=(this.data.datasets||[]).length;e<i;++e)this.isDatasetVisible(e)&&this.getDatasetMeta(e).controller.transition(t);this.tooltip.transition(t)},drawDatasets:function(t){var e=this;if(!1!==Ee.notify(e,"beforeDatasetsDraw",[t])){for(var i=(e.data.datasets||[]).length-1;i>=0;--i)e.isDatasetVisible(i)&&e.drawDataset(i,t);Ee.notify(e,"afterDatasetsDraw",[t])}},drawDataset:function(t,e){var i=this.getDatasetMeta(t),n={meta:i,index:t,easingValue:e};!1!==Ee.notify(this,"beforeDatasetDraw",[n])&&(i.controller.draw(e),Ee.notify(this,"afterDatasetDraw",[n]))},_drawTooltip:function(t){var e=this.tooltip,i={tooltip:e,easingValue:t};!1!==Ee.notify(this,"beforeTooltipDraw",[i])&&(e.draw(),Ee.notify(this,"afterTooltipDraw",[i]))},getElementAtEvent:function(t){return ve.modes.single(this,t)},getElementsAtEvent:function(t){return ve.modes.label(this,t,{intersect:!0})},getElementsAtXAxis:function(t){return ve.modes["x-axis"](this,t,{intersect:!0})},getElementsAtEventForMode:function(t,e,i){var n=ve.modes[e];return"function"==typeof n?n(this,t,i):[]},getDatasetAtEvent:function(t){return ve.modes.dataset(this,t,{intersect:!0})},getDatasetMeta:function(t){var e=this.data.datasets[t];e._meta||(e._meta={});var i=e._meta[this.id];return i||(i=e._meta[this.id]={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null}),i},getVisibleDatasetCount:function(){for(var t=0,e=0,i=this.data.datasets.length;e<i;++e)this.isDatasetVisible(e)&&t++;return t},isDatasetVisible:function(t){var e=this.getDatasetMeta(t);return"boolean"==typeof e.hidden?!e.hidden:!this.data.datasets[t].hidden},generateLegend:function(){return this.options.legendCallback(this)},destroyDatasetMeta:function(t){var e=this.id,i=this.data.datasets[t],n=i._meta&&i._meta[e];n&&(n.controller.destroy(),delete i._meta[e])},destroy:function(){var t,e,i=this,n=i.canvas;for(i.stop(),t=0,e=i.data.datasets.length;t<e;++t)i.destroyDatasetMeta(t);n&&(i.unbindEvents(),ut.canvas.clear(i),Ve.releaseContext(i.ctx),i.canvas=null,i.ctx=null),Ee.notify(i,"destroy"),delete ni.instances[i.id]},toBase64Image:function(){return this.canvas.toDataURL.apply(this.canvas,arguments)},initToolTip:function(){var t=this;t.tooltip=new Je({_chart:t,_chartInstance:t,_data:t.data,_options:t.options.tooltips},t)},bindEvents:function(){var t=this,e=t._listeners={},i=function(){t.eventHandler.apply(t,arguments)};ut.each(t.options.events,function(n){Ve.addEventListener(t,n,i),e[n]=i}),t.options.responsive&&(i=function(){t.resize()},Ve.addEventListener(t,"resize",i),e.resize=i)},unbindEvents:function(){var t=this,e=t._listeners;e&&(delete t._listeners,ut.each(e,function(e,i){Ve.removeEventListener(t,i,e)}))},updateHoverStyle:function(t,e,i){var n,a,o,r=i?"setHoverStyle":"removeHoverStyle";for(a=0,o=t.length;a<o;++a)(n=t[a])&&this.getDatasetMeta(n._datasetIndex).controller[r](n)},eventHandler:function(t){var e=this,i=e.tooltip;if(!1!==Ee.notify(e,"beforeEvent",[t])){e._bufferedRender=!0,e._bufferedRequest=null;var n=e.handleEvent(t);i&&(n=i._start?i.handleEvent(t):n|i.handleEvent(t)),Ee.notify(e,"afterEvent",[t]);var a=e._bufferedRequest;return a?e.render(a):n&&!e.animating&&(e.stop(),e.render({duration:e.options.hover.animationDuration,lazy:!0})),e._bufferedRender=!1,e._bufferedRequest=null,e}},handleEvent:function(t){var e,i=this,n=i.options||{},a=n.hover;return i.lastActive=i.lastActive||[],"mouseout"===t.type?i.active=[]:i.active=i.getElementsAtEventForMode(t,a.mode,a),ut.callback(n.onHover||n.hover.onHover,[t.native,i.active],i),"mouseup"!==t.type&&"click"!==t.type||n.onClick&&n.onClick.call(i,t.native,i.active),i.lastActive.length&&i.updateHoverStyle(i.lastActive,a.mode,!1),i.active.length&&a.mode&&i.updateHoverStyle(i.active,a.mode,!0),e=!ut.arrayEquals(i.active,i.lastActive),i.lastActive=i.active,e}}),ni.instances={};var ai=ni;ni.Controller=ni,ni.types={},ut.configMerge=ei,ut.scaleMerge=ti;function oi(){throw new Error("This method is not implemented: either no adapter can be found or an incomplete integration was provided.")}function ri(t){this.options=t||{}}ut.extend(ri.prototype,{formats:oi,parse:oi,format:oi,add:oi,diff:oi,startOf:oi,endOf:oi,_create:function(t){return t}}),ri.override=function(t){ut.extend(ri.prototype,t)};var si={_date:ri},li={formatters:{values:function(t){return ut.isArray(t)?t:""+t},linear:function(t,e,i){var n=i.length>3?i[2]-i[1]:i[1]-i[0];Math.abs(n)>1&&t!==Math.floor(t)&&(n=t-Math.floor(t));var a=ut.log10(Math.abs(n)),o="";if(0!==t)if(Math.max(Math.abs(i[0]),Math.abs(i[i.length-1]))<1e-4){var r=ut.log10(Math.abs(t));o=t.toExponential(Math.floor(r)-Math.floor(a))}else{var s=-1*Math.floor(a);s=Math.max(Math.min(s,20),0),o=t.toFixed(s)}else o="0";return o},logarithmic:function(t,e,i){var n=t/Math.pow(10,Math.floor(ut.log10(t)));return 0===t?"0":1===n||2===n||5===n||0===e||e===i.length-1?t.toExponential():""}}},di=ut.valueOrDefault,ui=ut.valueAtIndexOrDefault;function hi(t){var e,i,n=[];for(e=0,i=t.length;e<i;++e)n.push(t[e].label);return n}function ci(t,e,i){return ut.isArray(e)?ut.longestText(t,i,e):t.measureText(e).width}st._set("scale",{display:!0,position:"left",offset:!1,gridLines:{display:!0,color:"rgba(0, 0, 0, 0.1)",lineWidth:1,drawBorder:!0,drawOnChartArea:!0,drawTicks:!0,tickMarkLength:10,zeroLineWidth:1,zeroLineColor:"rgba(0,0,0,0.25)",zeroLineBorderDash:[],zeroLineBorderDashOffset:0,offsetGridLines:!1,borderDash:[],borderDashOffset:0},scaleLabel:{display:!1,labelString:"",padding:{top:4,bottom:4}},ticks:{beginAtZero:!1,minRotation:0,maxRotation:50,mirror:!1,padding:0,reverse:!1,display:!0,autoSkip:!0,autoSkipPadding:0,labelOffset:0,callback:li.formatters.values,minor:{},major:{}}});var fi=pt.extend({getPadding:function(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}},getTicks:function(){return this._ticks},mergeTicksOptions:function(){var t=this.options.ticks;for(var e in!1===t.minor&&(t.minor={display:!1}),!1===t.major&&(t.major={display:!1}),t)"major"!==e&&"minor"!==e&&(void 0===t.minor[e]&&(t.minor[e]=t[e]),void 0===t.major[e]&&(t.major[e]=t[e]))},beforeUpdate:function(){ut.callback(this.options.beforeUpdate,[this])},update:function(t,e,i){var n,a,o,r,s,l,d=this;for(d.beforeUpdate(),d.maxWidth=t,d.maxHeight=e,d.margins=ut.extend({left:0,right:0,top:0,bottom:0},i),d._maxLabelLines=0,d.longestLabelWidth=0,d.longestTextCache=d.longestTextCache||{},d.beforeSetDimensions(),d.setDimensions(),d.afterSetDimensions(),d.beforeDataLimits(),d.determineDataLimits(),d.afterDataLimits(),d.beforeBuildTicks(),s=d.buildTicks()||[],s=d.afterBuildTicks(s)||s,d.beforeTickToLabelConversion(),o=d.convertTicksToLabels(s)||d.ticks,d.afterTickToLabelConversion(),d.ticks=o,n=0,a=o.length;n<a;++n)r=o[n],(l=s[n])?l.label=r:s.push(l={label:r,major:!1});return d._ticks=s,d.beforeCalculateTickRotation(),d.calculateTickRotation(),d.afterCalculateTickRotation(),d.beforeFit(),d.fit(),d.afterFit(),d.afterUpdate(),d.minSize},afterUpdate:function(){ut.callback(this.options.afterUpdate,[this])},beforeSetDimensions:function(){ut.callback(this.options.beforeSetDimensions,[this])},setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0},afterSetDimensions:function(){ut.callback(this.options.afterSetDimensions,[this])},beforeDataLimits:function(){ut.callback(this.options.beforeDataLimits,[this])},determineDataLimits:ut.noop,afterDataLimits:function(){ut.callback(this.options.afterDataLimits,[this])},beforeBuildTicks:function(){ut.callback(this.options.beforeBuildTicks,[this])},buildTicks:ut.noop,afterBuildTicks:function(t){var e=this;return ut.isArray(t)&&t.length?ut.callback(e.options.afterBuildTicks,[e,t]):(e.ticks=ut.callback(e.options.afterBuildTicks,[e,e.ticks])||e.ticks,t)},beforeTickToLabelConversion:function(){ut.callback(this.options.beforeTickToLabelConversion,[this])},convertTicksToLabels:function(){var t=this.options.ticks;this.ticks=this.ticks.map(t.userCallback||t.callback,this)},afterTickToLabelConversion:function(){ut.callback(this.options.afterTickToLabelConversion,[this])},beforeCalculateTickRotation:function(){ut.callback(this.options.beforeCalculateTickRotation,[this])},calculateTickRotation:function(){var t=this,e=t.ctx,i=t.options.ticks,n=hi(t._ticks),a=ut.options._parseFont(i);e.font=a.string;var o=i.minRotation||0;if(n.length&&t.options.display&&t.isHorizontal())for(var r,s=ut.longestText(e,a.string,n,t.longestTextCache),l=s,d=t.getPixelForTick(1)-t.getPixelForTick(0)-6;l>d&&o<i.maxRotation;){var u=ut.toRadians(o);if(r=Math.cos(u),Math.sin(u)*s>t.maxHeight){o--;break}o++,l=r*s}t.labelRotation=o},afterCalculateTickRotation:function(){ut.callback(this.options.afterCalculateTickRotation,[this])},beforeFit:function(){ut.callback(this.options.beforeFit,[this])},fit:function(){var t=this,e=t.minSize={width:0,height:0},i=hi(t._ticks),n=t.options,a=n.ticks,o=n.scaleLabel,r=n.gridLines,s=t._isVisible(),l=n.position,d=t.isHorizontal(),u=ut.options._parseFont,h=u(a),c=n.gridLines.tickMarkLength;if(e.width=d?t.isFullWidth()?t.maxWidth-t.margins.left-t.margins.right:t.maxWidth:s&&r.drawTicks?c:0,e.height=d?s&&r.drawTicks?c:0:t.maxHeight,o.display&&s){var f=u(o),g=ut.options.toPadding(o.padding),p=f.lineHeight+g.height;d?e.height+=p:e.width+=p}if(a.display&&s){var m=ut.longestText(t.ctx,h.string,i,t.longestTextCache),v=ut.numberOfLabelLines(i),b=.5*h.size,x=t.options.ticks.padding;if(t._maxLabelLines=v,t.longestLabelWidth=m,d){var y=ut.toRadians(t.labelRotation),k=Math.cos(y),w=Math.sin(y)*m+h.lineHeight*v+b;e.height=Math.min(t.maxHeight,e.height+w+x),t.ctx.font=h.string;var M,_,C=ci(t.ctx,i[0],h.string),S=ci(t.ctx,i[i.length-1],h.string),P=t.getPixelForTick(0)-t.left,I=t.right-t.getPixelForTick(i.length-1);0!==t.labelRotation?(M="bottom"===l?k*C:k*b,_="bottom"===l?k*b:k*S):(M=C/2,_=S/2),t.paddingLeft=Math.max(M-P,0)+3,t.paddingRight=Math.max(_-I,0)+3}else a.mirror?m=0:m+=x+b,e.width=Math.min(t.maxWidth,e.width+m),t.paddingTop=h.size/2,t.paddingBottom=h.size/2}t.handleMargins(),t.width=e.width,t.height=e.height},handleMargins:function(){var t=this;t.margins&&(t.paddingLeft=Math.max(t.paddingLeft-t.margins.left,0),t.paddingTop=Math.max(t.paddingTop-t.margins.top,0),t.paddingRight=Math.max(t.paddingRight-t.margins.right,0),t.paddingBottom=Math.max(t.paddingBottom-t.margins.bottom,0))},afterFit:function(){ut.callback(this.options.afterFit,[this])},isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},isFullWidth:function(){return this.options.fullWidth},getRightValue:function(t){if(ut.isNullOrUndef(t))return NaN;if(("number"==typeof t||t instanceof Number)&&!isFinite(t))return NaN;if(t)if(this.isHorizontal()){if(void 0!==t.x)return this.getRightValue(t.x)}else if(void 0!==t.y)return this.getRightValue(t.y);return t},getLabelForIndex:ut.noop,getPixelForValue:ut.noop,getValueForPixel:ut.noop,getPixelForTick:function(t){var e=this,i=e.options.offset;if(e.isHorizontal()){var n=(e.width-(e.paddingLeft+e.paddingRight))/Math.max(e._ticks.length-(i?0:1),1),a=n*t+e.paddingLeft;i&&(a+=n/2);var o=e.left+a;return o+=e.isFullWidth()?e.margins.left:0}var r=e.height-(e.paddingTop+e.paddingBottom);return e.top+t*(r/(e._ticks.length-1))},getPixelForDecimal:function(t){var e=this;if(e.isHorizontal()){var i=(e.width-(e.paddingLeft+e.paddingRight))*t+e.paddingLeft,n=e.left+i;return n+=e.isFullWidth()?e.margins.left:0}return e.top+t*e.height},getBasePixel:function(){return this.getPixelForValue(this.getBaseValue())},getBaseValue:function(){var t=this.min,e=this.max;return this.beginAtZero?0:t<0&&e<0?e:t>0&&e>0?t:0},_autoSkip:function(t){var e,i,n=this,a=n.isHorizontal(),o=n.options.ticks.minor,r=t.length,s=!1,l=o.maxTicksLimit,d=n._tickSize()*(r-1),u=a?n.width-(n.paddingLeft+n.paddingRight):n.height-(n.paddingTop+n.PaddingBottom),h=[];for(d>u&&(s=1+Math.floor(d/u)),r>l&&(s=Math.max(s,1+Math.floor(r/l))),e=0;e<r;e++)i=t[e],s>1&&e%s>0&&delete i.label,h.push(i);return h},_tickSize:function(){var t=this,e=t.isHorizontal(),i=t.options.ticks.minor,n=ut.toRadians(t.labelRotation),a=Math.abs(Math.cos(n)),o=Math.abs(Math.sin(n)),r=i.autoSkipPadding||0,s=t.longestLabelWidth+r||0,l=ut.options._parseFont(i),d=t._maxLabelLines*l.lineHeight+r||0;return e?d*a>s*o?s/a:d/o:d*o<s*a?d/a:s/o},_isVisible:function(){var t,e,i,n=this.chart,a=this.options.display;if("auto"!==a)return!!a;for(t=0,e=n.data.datasets.length;t<e;++t)if(n.isDatasetVisible(t)&&((i=n.getDatasetMeta(t)).xAxisID===this.id||i.yAxisID===this.id))return!0;return!1},draw:function(t){var e=this,i=e.options;if(e._isVisible()){var n,a,o,r=e.chart,s=e.ctx,l=st.global.defaultFontColor,d=i.ticks.minor,u=i.ticks.major||d,h=i.gridLines,c=i.scaleLabel,f=i.position,g=0!==e.labelRotation,p=d.mirror,m=e.isHorizontal(),v=ut.options._parseFont,b=d.display&&d.autoSkip?e._autoSkip(e.getTicks()):e.getTicks(),x=di(d.fontColor,l),y=v(d),k=y.lineHeight,w=di(u.fontColor,l),M=v(u),_=d.padding,C=d.labelOffset,S=h.drawTicks?h.tickMarkLength:0,P=di(c.fontColor,l),I=v(c),A=ut.options.toPadding(c.padding),D=ut.toRadians(e.labelRotation),T=[],F=h.drawBorder?ui(h.lineWidth,0,0):0,L=ut._alignPixel;"top"===f?(n=L(r,e.bottom,F),a=e.bottom-S,o=n-F/2):"bottom"===f?(n=L(r,e.top,F),a=n+F/2,o=e.top+S):"left"===f?(n=L(r,e.right,F),a=e.right-S,o=n-F/2):(n=L(r,e.left,F),a=n+F/2,o=e.left+S);if(ut.each(b,function(n,s){if(!ut.isNullOrUndef(n.label)){var l,d,u,c,v,b,x,y,w,M,P,I,A,R,O,z,B=n.label;s===e.zeroLineIndex&&i.offset===h.offsetGridLines?(l=h.zeroLineWidth,d=h.zeroLineColor,u=h.zeroLineBorderDash||[],c=h.zeroLineBorderDashOffset||0):(l=ui(h.lineWidth,s),d=ui(h.color,s),u=h.borderDash||[],c=h.borderDashOffset||0);var N=ut.isArray(B)?B.length:1,W=function(t,e,i){var n=t.getPixelForTick(e);return i&&(1===t.getTicks().length?n-=t.isHorizontal()?Math.max(n-t.left,t.right-n):Math.max(n-t.top,t.bottom-n):n-=0===e?(t.getPixelForTick(1)-n)/2:(n-t.getPixelForTick(e-1))/2),n}(e,s,h.offsetGridLines);if(m){var V=S+_;W<e.left-1e-7&&(d="rgba(0,0,0,0)"),v=x=w=P=L(r,W,l),b=a,y=o,A=e.getPixelForTick(s)+C,"top"===f?(M=L(r,t.top,F)+F/2,I=t.bottom,O=((g?1:.5)-N)*k,z=g?"left":"center",R=e.bottom-V):(M=t.top,I=L(r,t.bottom,F)-F/2,O=(g?0:.5)*k,z=g?"right":"center",R=e.top+V)}else{var E=(p?0:S)+_;W<e.top-1e-7&&(d="rgba(0,0,0,0)"),v=a,x=o,b=y=M=I=L(r,W,l),R=e.getPixelForTick(s)+C,O=(1-N)*k/2,"left"===f?(w=L(r,t.left,F)+F/2,P=t.right,z=p?"left":"right",A=e.right-E):(w=t.left,P=L(r,t.right,F)-F/2,z=p?"right":"left",A=e.left+E)}T.push({tx1:v,ty1:b,tx2:x,ty2:y,x1:w,y1:M,x2:P,y2:I,labelX:A,labelY:R,glWidth:l,glColor:d,glBorderDash:u,glBorderDashOffset:c,rotation:-1*D,label:B,major:n.major,textOffset:O,textAlign:z})}}),ut.each(T,function(t){var e=t.glWidth,i=t.glColor;if(h.display&&e&&i&&(s.save(),s.lineWidth=e,s.strokeStyle=i,s.setLineDash&&(s.setLineDash(t.glBorderDash),s.lineDashOffset=t.glBorderDashOffset),s.beginPath(),h.drawTicks&&(s.moveTo(t.tx1,t.ty1),s.lineTo(t.tx2,t.ty2)),h.drawOnChartArea&&(s.moveTo(t.x1,t.y1),s.lineTo(t.x2,t.y2)),s.stroke(),s.restore()),d.display){s.save(),s.translate(t.labelX,t.labelY),s.rotate(t.rotation),s.font=t.major?M.string:y.string,s.fillStyle=t.major?w:x,s.textBaseline="middle",s.textAlign=t.textAlign;var n=t.label,a=t.textOffset;if(ut.isArray(n))for(var o=0;o<n.length;++o)s.fillText(""+n[o],0,a),a+=k;else s.fillText(n,0,a);s.restore()}}),c.display){var R,O,z=0,B=I.lineHeight/2;if(m)R=e.left+(e.right-e.left)/2,O="bottom"===f?e.bottom-B-A.bottom:e.top+B+A.top;else{var N="left"===f;R=N?e.left+B+A.top:e.right-B-A.top,O=e.top+(e.bottom-e.top)/2,z=N?-.5*Math.PI:.5*Math.PI}s.save(),s.translate(R,O),s.rotate(z),s.textAlign="center",s.textBaseline="middle",s.fillStyle=P,s.font=I.string,s.fillText(c.labelString,0,0),s.restore()}if(F){var W,V,E,H,j=F,q=ui(h.lineWidth,b.length-1,0);m?(W=L(r,e.left,j)-j/2,V=L(r,e.right,q)+q/2,E=H=n):(E=L(r,e.top,j)-j/2,H=L(r,e.bottom,q)+q/2,W=V=n),s.lineWidth=F,s.strokeStyle=ui(h.color,0),s.beginPath(),s.moveTo(W,E),s.lineTo(V,H),s.stroke()}}}}),gi=fi.extend({getLabels:function(){var t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels},determineDataLimits:function(){var t,e=this,i=e.getLabels();e.minIndex=0,e.maxIndex=i.length-1,void 0!==e.options.ticks.min&&(t=i.indexOf(e.options.ticks.min),e.minIndex=-1!==t?t:e.minIndex),void 0!==e.options.ticks.max&&(t=i.indexOf(e.options.ticks.max),e.maxIndex=-1!==t?t:e.maxIndex),e.min=i[e.minIndex],e.max=i[e.maxIndex]},buildTicks:function(){var t=this,e=t.getLabels();t.ticks=0===t.minIndex&&t.maxIndex===e.length-1?e:e.slice(t.minIndex,t.maxIndex+1)},getLabelForIndex:function(t,e){var i=this,n=i.chart;return n.getDatasetMeta(e).controller._getValueScaleId()===i.id?i.getRightValue(n.data.datasets[e].data[t]):i.ticks[t-i.minIndex]},getPixelForValue:function(t,e){var i,n=this,a=n.options.offset,o=Math.max(n.maxIndex+1-n.minIndex-(a?0:1),1);if(null!=t&&(i=n.isHorizontal()?t.x:t.y),void 0!==i||void 0!==t&&isNaN(e)){t=i||t;var r=n.getLabels().indexOf(t);e=-1!==r?r:e}if(n.isHorizontal()){var s=n.width/o,l=s*(e-n.minIndex);return a&&(l+=s/2),n.left+l}var d=n.height/o,u=d*(e-n.minIndex);return a&&(u+=d/2),n.top+u},getPixelForTick:function(t){return this.getPixelForValue(this.ticks[t],t+this.minIndex,null)},getValueForPixel:function(t){var e=this,i=e.options.offset,n=Math.max(e._ticks.length-(i?0:1),1),a=e.isHorizontal(),o=(a?e.width:e.height)/n;return t-=a?e.left:e.top,i&&(t-=o/2),(t<=0?0:Math.round(t/o))+e.minIndex},getBasePixel:function(){return this.bottom}}),pi={position:"bottom"};gi._defaults=pi;var mi=ut.noop,vi=ut.isNullOrUndef;var bi=fi.extend({getRightValue:function(t){return"string"==typeof t?+t:fi.prototype.getRightValue.call(this,t)},handleTickRangeOptions:function(){var t=this,e=t.options.ticks;if(e.beginAtZero){var i=ut.sign(t.min),n=ut.sign(t.max);i<0&&n<0?t.max=0:i>0&&n>0&&(t.min=0)}var a=void 0!==e.min||void 0!==e.suggestedMin,o=void 0!==e.max||void 0!==e.suggestedMax;void 0!==e.min?t.min=e.min:void 0!==e.suggestedMin&&(null===t.min?t.min=e.suggestedMin:t.min=Math.min(t.min,e.suggestedMin)),void 0!==e.max?t.max=e.max:void 0!==e.suggestedMax&&(null===t.max?t.max=e.suggestedMax:t.max=Math.max(t.max,e.suggestedMax)),a!==o&&t.min>=t.max&&(a?t.max=t.min+1:t.min=t.max-1),t.min===t.max&&(t.max++,e.beginAtZero||t.min--)},getTickLimit:function(){var t,e=this.options.ticks,i=e.stepSize,n=e.maxTicksLimit;return i?t=Math.ceil(this.max/i)-Math.floor(this.min/i)+1:(t=this._computeTickLimit(),n=n||11),n&&(t=Math.min(n,t)),t},_computeTickLimit:function(){return Number.POSITIVE_INFINITY},handleDirectionalChanges:mi,buildTicks:function(){var t=this,e=t.options.ticks,i=t.getTickLimit(),n={maxTicks:i=Math.max(2,i),min:e.min,max:e.max,precision:e.precision,stepSize:ut.valueOrDefault(e.fixedStepSize,e.stepSize)},a=t.ticks=function(t,e){var i,n,a,o,r=[],s=t.stepSize,l=s||1,d=t.maxTicks-1,u=t.min,h=t.max,c=t.precision,f=e.min,g=e.max,p=ut.niceNum((g-f)/d/l)*l;if(p<1e-14&&vi(u)&&vi(h))return[f,g];(o=Math.ceil(g/p)-Math.floor(f/p))>d&&(p=ut.niceNum(o*p/d/l)*l),s||vi(c)?i=Math.pow(10,ut._decimalPlaces(p)):(i=Math.pow(10,c),p=Math.ceil(p*i)/i),n=Math.floor(f/p)*p,a=Math.ceil(g/p)*p,s&&(!vi(u)&&ut.almostWhole(u/p,p/1e3)&&(n=u),!vi(h)&&ut.almostWhole(h/p,p/1e3)&&(a=h)),o=(a-n)/p,o=ut.almostEquals(o,Math.round(o),p/1e3)?Math.round(o):Math.ceil(o),n=Math.round(n*i)/i,a=Math.round(a*i)/i,r.push(vi(u)?n:u);for(var m=1;m<o;++m)r.push(Math.round((n+m*p)*i)/i);return r.push(vi(h)?a:h),r}(n,t);t.handleDirectionalChanges(),t.max=ut.max(a),t.min=ut.min(a),e.reverse?(a.reverse(),t.start=t.max,t.end=t.min):(t.start=t.min,t.end=t.max)},convertTicksToLabels:function(){var t=this;t.ticksAsNumbers=t.ticks.slice(),t.zeroLineIndex=t.ticks.indexOf(0),fi.prototype.convertTicksToLabels.call(t)}}),xi={position:"left",ticks:{callback:li.formatters.linear}},yi=bi.extend({determineDataLimits:function(){var t=this,e=t.options,i=t.chart,n=i.data.datasets,a=t.isHorizontal();function o(e){return a?e.xAxisID===t.id:e.yAxisID===t.id}t.min=null,t.max=null;var r=e.stacked;if(void 0===r&&ut.each(n,function(t,e){if(!r){var n=i.getDatasetMeta(e);i.isDatasetVisible(e)&&o(n)&&void 0!==n.stack&&(r=!0)}}),e.stacked||r){var s={};ut.each(n,function(n,a){var r=i.getDatasetMeta(a),l=[r.type,void 0===e.stacked&&void 0===r.stack?a:"",r.stack].join(".");void 0===s[l]&&(s[l]={positiveValues:[],negativeValues:[]});var d=s[l].positiveValues,u=s[l].negativeValues;i.isDatasetVisible(a)&&o(r)&&ut.each(n.data,function(i,n){var a=+t.getRightValue(i);isNaN(a)||r.data[n].hidden||(d[n]=d[n]||0,u[n]=u[n]||0,e.relativePoints?d[n]=100:a<0?u[n]+=a:d[n]+=a)})}),ut.each(s,function(e){var i=e.positiveValues.concat(e.negativeValues),n=ut.min(i),a=ut.max(i);t.min=null===t.min?n:Math.min(t.min,n),t.max=null===t.max?a:Math.max(t.max,a)})}else ut.each(n,function(e,n){var a=i.getDatasetMeta(n);i.isDatasetVisible(n)&&o(a)&&ut.each(e.data,function(e,i){var n=+t.getRightValue(e);isNaN(n)||a.data[i].hidden||(null===t.min?t.min=n:n<t.min&&(t.min=n),null===t.max?t.max=n:n>t.max&&(t.max=n))})});t.min=isFinite(t.min)&&!isNaN(t.min)?t.min:0,t.max=isFinite(t.max)&&!isNaN(t.max)?t.max:1,this.handleTickRangeOptions()},_computeTickLimit:function(){var t;return this.isHorizontal()?Math.ceil(this.width/40):(t=ut.options._parseFont(this.options.ticks),Math.ceil(this.height/t.lineHeight))},handleDirectionalChanges:function(){this.isHorizontal()||this.ticks.reverse()},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForValue:function(t){var e=this,i=e.start,n=+e.getRightValue(t),a=e.end-i;return e.isHorizontal()?e.left+e.width/a*(n-i):e.bottom-e.height/a*(n-i)},getValueForPixel:function(t){var e=this,i=e.isHorizontal(),n=i?e.width:e.height,a=(i?t-e.left:e.bottom-t)/n;return e.start+(e.end-e.start)*a},getPixelForTick:function(t){return this.getPixelForValue(this.ticksAsNumbers[t])}}),ki=xi;yi._defaults=ki;var wi=ut.valueOrDefault;var Mi={position:"left",ticks:{callback:li.formatters.logarithmic}};function _i(t,e){return ut.isFinite(t)&&t>=0?t:e}var Ci=fi.extend({determineDataLimits:function(){var t=this,e=t.options,i=t.chart,n=i.data.datasets,a=t.isHorizontal();function o(e){return a?e.xAxisID===t.id:e.yAxisID===t.id}t.min=null,t.max=null,t.minNotZero=null;var r=e.stacked;if(void 0===r&&ut.each(n,function(t,e){if(!r){var n=i.getDatasetMeta(e);i.isDatasetVisible(e)&&o(n)&&void 0!==n.stack&&(r=!0)}}),e.stacked||r){var s={};ut.each(n,function(n,a){var r=i.getDatasetMeta(a),l=[r.type,void 0===e.stacked&&void 0===r.stack?a:"",r.stack].join(".");i.isDatasetVisible(a)&&o(r)&&(void 0===s[l]&&(s[l]=[]),ut.each(n.data,function(e,i){var n=s[l],a=+t.getRightValue(e);isNaN(a)||r.data[i].hidden||a<0||(n[i]=n[i]||0,n[i]+=a)}))}),ut.each(s,function(e){if(e.length>0){var i=ut.min(e),n=ut.max(e);t.min=null===t.min?i:Math.min(t.min,i),t.max=null===t.max?n:Math.max(t.max,n)}})}else ut.each(n,function(e,n){var a=i.getDatasetMeta(n);i.isDatasetVisible(n)&&o(a)&&ut.each(e.data,function(e,i){var n=+t.getRightValue(e);isNaN(n)||a.data[i].hidden||n<0||(null===t.min?t.min=n:n<t.min&&(t.min=n),null===t.max?t.max=n:n>t.max&&(t.max=n),0!==n&&(null===t.minNotZero||n<t.minNotZero)&&(t.minNotZero=n))})});this.handleTickRangeOptions()},handleTickRangeOptions:function(){var t=this,e=t.options.ticks;t.min=_i(e.min,t.min),t.max=_i(e.max,t.max),t.min===t.max&&(0!==t.min&&null!==t.min?(t.min=Math.pow(10,Math.floor(ut.log10(t.min))-1),t.max=Math.pow(10,Math.floor(ut.log10(t.max))+1)):(t.min=1,t.max=10)),null===t.min&&(t.min=Math.pow(10,Math.floor(ut.log10(t.max))-1)),null===t.max&&(t.max=0!==t.min?Math.pow(10,Math.floor(ut.log10(t.min))+1):10),null===t.minNotZero&&(t.min>0?t.minNotZero=t.min:t.max<1?t.minNotZero=Math.pow(10,Math.floor(ut.log10(t.max))):t.minNotZero=1)},buildTicks:function(){var t=this,e=t.options.ticks,i=!t.isHorizontal(),n={min:_i(e.min),max:_i(e.max)},a=t.ticks=function(t,e){var i,n,a=[],o=wi(t.min,Math.pow(10,Math.floor(ut.log10(e.min)))),r=Math.floor(ut.log10(e.max)),s=Math.ceil(e.max/Math.pow(10,r));0===o?(i=Math.floor(ut.log10(e.minNotZero)),n=Math.floor(e.minNotZero/Math.pow(10,i)),a.push(o),o=n*Math.pow(10,i)):(i=Math.floor(ut.log10(o)),n=Math.floor(o/Math.pow(10,i)));var l=i<0?Math.pow(10,Math.abs(i)):1;do{a.push(o),10==++n&&(n=1,l=++i>=0?1:l),o=Math.round(n*Math.pow(10,i)*l)/l}while(i<r||i===r&&n<s);var d=wi(t.max,o);return a.push(d),a}(n,t);t.max=ut.max(a),t.min=ut.min(a),e.reverse?(i=!i,t.start=t.max,t.end=t.min):(t.start=t.min,t.end=t.max),i&&a.reverse()},convertTicksToLabels:function(){this.tickValues=this.ticks.slice(),fi.prototype.convertTicksToLabels.call(this)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForTick:function(t){return this.getPixelForValue(this.tickValues[t])},_getFirstTickValue:function(t){var e=Math.floor(ut.log10(t));return Math.floor(t/Math.pow(10,e))*Math.pow(10,e)},getPixelForValue:function(t){var e,i,n,a,o,r=this,s=r.options.ticks,l=s.reverse,d=ut.log10,u=r._getFirstTickValue(r.minNotZero),h=0;return t=+r.getRightValue(t),l?(n=r.end,a=r.start,o=-1):(n=r.start,a=r.end,o=1),r.isHorizontal()?(e=r.width,i=l?r.right:r.left):(e=r.height,o*=-1,i=l?r.top:r.bottom),t!==n&&(0===n&&(e-=h=wi(s.fontSize,st.global.defaultFontSize),n=u),0!==t&&(h+=e/(d(a)-d(n))*(d(t)-d(n))),i+=o*h),i},getValueForPixel:function(t){var e,i,n,a,o=this,r=o.options.ticks,s=r.reverse,l=ut.log10,d=o._getFirstTickValue(o.minNotZero);if(s?(i=o.end,n=o.start):(i=o.start,n=o.end),o.isHorizontal()?(e=o.width,a=s?o.right-t:t-o.left):(e=o.height,a=s?t-o.top:o.bottom-t),a!==i){if(0===i){var u=wi(r.fontSize,st.global.defaultFontSize);a-=u,e-=u,i=d}a*=l(n)-l(i),a/=e,a=Math.pow(10,l(i)+a)}return a}}),Si=Mi;Ci._defaults=Si;var Pi=ut.valueOrDefault,Ii=ut.valueAtIndexOrDefault,Ai=ut.options.resolve,Di={display:!0,animate:!0,position:"chartArea",angleLines:{display:!0,color:"rgba(0, 0, 0, 0.1)",lineWidth:1,borderDash:[],borderDashOffset:0},gridLines:{circular:!1},ticks:{showLabelBackdrop:!0,backdropColor:"rgba(255,255,255,0.75)",backdropPaddingY:2,backdropPaddingX:2,callback:li.formatters.linear},pointLabels:{display:!0,fontSize:10,callback:function(t){return t}}};function Ti(t){var e=t.options;return e.angleLines.display||e.pointLabels.display?t.chart.data.labels.length:0}function Fi(t){var e=t.ticks;return e.display&&t.display?Pi(e.fontSize,st.global.defaultFontSize)+2*e.backdropPaddingY:0}function Li(t,e,i,n,a){return t===n||t===a?{start:e-i/2,end:e+i/2}:t<n||t>a?{start:e-i,end:e}:{start:e,end:e+i}}function Ri(t){return 0===t||180===t?"center":t<180?"left":"right"}function Oi(t,e,i,n){var a,o,r=i.y+n/2;if(ut.isArray(e))for(a=0,o=e.length;a<o;++a)t.fillText(e[a],i.x,r),r+=n;else t.fillText(e,i.x,r)}function zi(t,e,i){90===t||270===t?i.y-=e.h/2:(t>270||t<90)&&(i.y-=e.h)}function Bi(t){return ut.isNumber(t)?t:0}var Ni=bi.extend({setDimensions:function(){var t=this;t.width=t.maxWidth,t.height=t.maxHeight,t.paddingTop=Fi(t.options)/2,t.xCenter=Math.floor(t.width/2),t.yCenter=Math.floor((t.height-t.paddingTop)/2),t.drawingArea=Math.min(t.height-t.paddingTop,t.width)/2},determineDataLimits:function(){var t=this,e=t.chart,i=Number.POSITIVE_INFINITY,n=Number.NEGATIVE_INFINITY;ut.each(e.data.datasets,function(a,o){if(e.isDatasetVisible(o)){var r=e.getDatasetMeta(o);ut.each(a.data,function(e,a){var o=+t.getRightValue(e);isNaN(o)||r.data[a].hidden||(i=Math.min(o,i),n=Math.max(o,n))})}}),t.min=i===Number.POSITIVE_INFINITY?0:i,t.max=n===Number.NEGATIVE_INFINITY?0:n,t.handleTickRangeOptions()},_computeTickLimit:function(){return Math.ceil(this.drawingArea/Fi(this.options))},convertTicksToLabels:function(){var t=this;bi.prototype.convertTicksToLabels.call(t),t.pointLabels=t.chart.data.labels.map(t.options.pointLabels.callback,t)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},fit:function(){var t=this.options;t.display&&t.pointLabels.display?function(t){var e,i,n,a=ut.options._parseFont(t.options.pointLabels),o={l:0,r:t.width,t:0,b:t.height-t.paddingTop},r={};t.ctx.font=a.string,t._pointLabelSizes=[];var s,l,d,u=Ti(t);for(e=0;e<u;e++){n=t.getPointPosition(e,t.drawingArea+5),s=t.ctx,l=a.lineHeight,d=t.pointLabels[e]||"",i=ut.isArray(d)?{w:ut.longestText(s,s.font,d),h:d.length*l}:{w:s.measureText(d).width,h:l},t._pointLabelSizes[e]=i;var h=t.getIndexAngle(e),c=ut.toDegrees(h)%360,f=Li(c,n.x,i.w,0,180),g=Li(c,n.y,i.h,90,270);f.start<o.l&&(o.l=f.start,r.l=h),f.end>o.r&&(o.r=f.end,r.r=h),g.start<o.t&&(o.t=g.start,r.t=h),g.end>o.b&&(o.b=g.end,r.b=h)}t.setReductions(t.drawingArea,o,r)}(this):this.setCenterPoint(0,0,0,0)},setReductions:function(t,e,i){var n=this,a=e.l/Math.sin(i.l),o=Math.max(e.r-n.width,0)/Math.sin(i.r),r=-e.t/Math.cos(i.t),s=-Math.max(e.b-(n.height-n.paddingTop),0)/Math.cos(i.b);a=Bi(a),o=Bi(o),r=Bi(r),s=Bi(s),n.drawingArea=Math.min(Math.floor(t-(a+o)/2),Math.floor(t-(r+s)/2)),n.setCenterPoint(a,o,r,s)},setCenterPoint:function(t,e,i,n){var a=this,o=a.width-e-a.drawingArea,r=t+a.drawingArea,s=i+a.drawingArea,l=a.height-a.paddingTop-n-a.drawingArea;a.xCenter=Math.floor((r+o)/2+a.left),a.yCenter=Math.floor((s+l)/2+a.top+a.paddingTop)},getIndexAngle:function(t){return t*(2*Math.PI/Ti(this))+(this.chart.options&&this.chart.options.startAngle?this.chart.options.startAngle:0)*Math.PI*2/360},getDistanceFromCenterForValue:function(t){var e=this;if(null===t)return 0;var i=e.drawingArea/(e.max-e.min);return e.options.ticks.reverse?(e.max-t)*i:(t-e.min)*i},getPointPosition:function(t,e){var i=this.getIndexAngle(t)-Math.PI/2;return{x:Math.cos(i)*e+this.xCenter,y:Math.sin(i)*e+this.yCenter}},getPointPositionForValue:function(t,e){return this.getPointPosition(t,this.getDistanceFromCenterForValue(e))},getBasePosition:function(){var t=this.min,e=this.max;return this.getPointPositionForValue(0,this.beginAtZero?0:t<0&&e<0?e:t>0&&e>0?t:0)},draw:function(){var t=this,e=t.options,i=e.gridLines,n=e.ticks;if(e.display){var a=t.ctx,o=this.getIndexAngle(0),r=ut.options._parseFont(n);(e.angleLines.display||e.pointLabels.display)&&function(t){var e=t.ctx,i=t.options,n=i.angleLines,a=i.gridLines,o=i.pointLabels,r=Pi(n.lineWidth,a.lineWidth),s=Pi(n.color,a.color),l=Fi(i);e.save(),e.lineWidth=r,e.strokeStyle=s,e.setLineDash&&(e.setLineDash(Ai([n.borderDash,a.borderDash,[]])),e.lineDashOffset=Ai([n.borderDashOffset,a.borderDashOffset,0]));var d=t.getDistanceFromCenterForValue(i.ticks.reverse?t.min:t.max),u=ut.options._parseFont(o);e.font=u.string,e.textBaseline="middle";for(var h=Ti(t)-1;h>=0;h--){if(n.display&&r&&s){var c=t.getPointPosition(h,d);e.beginPath(),e.moveTo(t.xCenter,t.yCenter),e.lineTo(c.x,c.y),e.stroke()}if(o.display){var f=0===h?l/2:0,g=t.getPointPosition(h,d+f+5),p=Ii(o.fontColor,h,st.global.defaultFontColor);e.fillStyle=p;var m=t.getIndexAngle(h),v=ut.toDegrees(m);e.textAlign=Ri(v),zi(v,t._pointLabelSizes[h],g),Oi(e,t.pointLabels[h]||"",g,u.lineHeight)}}e.restore()}(t),ut.each(t.ticks,function(e,s){if(s>0||n.reverse){var l=t.getDistanceFromCenterForValue(t.ticksAsNumbers[s]);if(i.display&&0!==s&&function(t,e,i,n){var a,o=t.ctx,r=e.circular,s=Ti(t),l=Ii(e.color,n-1),d=Ii(e.lineWidth,n-1);if((r||s)&&l&&d){if(o.save(),o.strokeStyle=l,o.lineWidth=d,o.setLineDash&&(o.setLineDash(e.borderDash||[]),o.lineDashOffset=e.borderDashOffset||0),o.beginPath(),r)o.arc(t.xCenter,t.yCenter,i,0,2*Math.PI);else{a=t.getPointPosition(0,i),o.moveTo(a.x,a.y);for(var u=1;u<s;u++)a=t.getPointPosition(u,i),o.lineTo(a.x,a.y)}o.closePath(),o.stroke(),o.restore()}}(t,i,l,s),n.display){var d=Pi(n.fontColor,st.global.defaultFontColor);if(a.font=r.string,a.save(),a.translate(t.xCenter,t.yCenter),a.rotate(o),n.showLabelBackdrop){var u=a.measureText(e).width;a.fillStyle=n.backdropColor,a.fillRect(-u/2-n.backdropPaddingX,-l-r.size/2-n.backdropPaddingY,u+2*n.backdropPaddingX,r.size+2*n.backdropPaddingY)}a.textAlign="center",a.textBaseline="middle",a.fillStyle=d,a.fillText(e,0,-l),a.restore()}}})}}}),Wi=Di;Ni._defaults=Wi;var Vi=ut.valueOrDefault,Ei=Number.MIN_SAFE_INTEGER||-9007199254740991,Hi=Number.MAX_SAFE_INTEGER||9007199254740991,ji={millisecond:{common:!0,size:1,steps:[1,2,5,10,20,50,100,250,500]},second:{common:!0,size:1e3,steps:[1,2,5,10,15,30]},minute:{common:!0,size:6e4,steps:[1,2,5,10,15,30]},hour:{common:!0,size:36e5,steps:[1,2,3,6,12]},day:{common:!0,size:864e5,steps:[1,2,5]},week:{common:!1,size:6048e5,steps:[1,2,3,4]},month:{common:!0,size:2628e6,steps:[1,2,3]},quarter:{common:!1,size:7884e6,steps:[1,2,3,4]},year:{common:!0,size:3154e7}},qi=Object.keys(ji);function Yi(t,e){return t-e}function Ui(t){var e,i,n,a={},o=[];for(e=0,i=t.length;e<i;++e)a[n=t[e]]||(a[n]=!0,o.push(n));return o}function Xi(t,e,i,n){var a=function(t,e,i){for(var n,a,o,r=0,s=t.length-1;r>=0&&r<=s;){if(a=t[(n=r+s>>1)-1]||null,o=t[n],!a)return{lo:null,hi:o};if(o[e]<i)r=n+1;else{if(!(a[e]>i))return{lo:a,hi:o};s=n-1}}return{lo:o,hi:null}}(t,e,i),o=a.lo?a.hi?a.lo:t[t.length-2]:t[0],r=a.lo?a.hi?a.hi:t[t.length-1]:t[1],s=r[e]-o[e],l=s?(i-o[e])/s:0,d=(r[n]-o[n])*l;return o[n]+d}function Ki(t,e){var i=t._adapter,n=t.options.time,a=n.parser,o=a||n.format,r=e;return"function"==typeof a&&(r=a(r)),ut.isFinite(r)||(r="string"==typeof o?i.parse(r,o):i.parse(r)),null!==r?+r:(a||"function"!=typeof o||(r=o(e),ut.isFinite(r)||(r=i.parse(r))),r)}function Gi(t,e){if(ut.isNullOrUndef(e))return null;var i=t.options.time,n=Ki(t,t.getRightValue(e));return null===n?n:(i.round&&(n=+t._adapter.startOf(n,i.round)),n)}function Zi(t){for(var e=qi.indexOf(t)+1,i=qi.length;e<i;++e)if(ji[qi[e]].common)return qi[e]}function $i(t,e,i,n){var a,o=t._adapter,r=t.options,s=r.time,l=s.unit||function(t,e,i,n){var a,o,r,s=qi.length;for(a=qi.indexOf(t);a<s-1;++a)if(r=(o=ji[qi[a]]).steps?o.steps[o.steps.length-1]:Hi,o.common&&Math.ceil((i-e)/(r*o.size))<=n)return qi[a];return qi[s-1]}(s.minUnit,e,i,n),d=Zi(l),u=Vi(s.stepSize,s.unitStepSize),h="week"===l&&s.isoWeekday,c=r.ticks.major.enabled,f=ji[l],g=e,p=i,m=[];for(u||(u=function(t,e,i,n){var a,o,r,s=e-t,l=ji[i],d=l.size,u=l.steps;if(!u)return Math.ceil(s/(n*d));for(a=0,o=u.length;a<o&&(r=u[a],!(Math.ceil(s/(d*r))<=n));++a);return r}(e,i,l,n)),h&&(g=+o.startOf(g,"isoWeek",h),p=+o.startOf(p,"isoWeek",h)),g=+o.startOf(g,h?"day":l),(p=+o.startOf(p,h?"day":l))<i&&(p=+o.add(p,1,l)),a=g,c&&d&&!h&&!s.round&&(a=+o.startOf(a,d),a=+o.add(a,~~((g-a)/(f.size*u))*u,l));a<p;a=+o.add(a,u,l))m.push(+a);return m.push(+a),m}var Ji=fi.extend({initialize:function(){this.mergeTicksOptions(),fi.prototype.initialize.call(this)},update:function(){var t=this.options,e=t.time||(t.time={}),i=this._adapter=new si._date(t.adapters.date);return e.format&&console.warn("options.time.format is deprecated and replaced by options.time.parser."),ut.mergeIf(e.displayFormats,i.formats()),fi.prototype.update.apply(this,arguments)},getRightValue:function(t){return t&&void 0!==t.t&&(t=t.t),fi.prototype.getRightValue.call(this,t)},determineDataLimits:function(){var t,e,i,n,a,o,r=this,s=r.chart,l=r._adapter,d=r.options.time,u=d.unit||"day",h=Hi,c=Ei,f=[],g=[],p=[],m=s.data.labels||[];for(t=0,i=m.length;t<i;++t)p.push(Gi(r,m[t]));for(t=0,i=(s.data.datasets||[]).length;t<i;++t)if(s.isDatasetVisible(t))if(a=s.data.datasets[t].data,ut.isObject(a[0]))for(g[t]=[],e=0,n=a.length;e<n;++e)o=Gi(r,a[e]),f.push(o),g[t][e]=o;else{for(e=0,n=p.length;e<n;++e)f.push(p[e]);g[t]=p.slice(0)}else g[t]=[];p.length&&(p=Ui(p).sort(Yi),h=Math.min(h,p[0]),c=Math.max(c,p[p.length-1])),f.length&&(f=Ui(f).sort(Yi),h=Math.min(h,f[0]),c=Math.max(c,f[f.length-1])),h=Gi(r,d.min)||h,c=Gi(r,d.max)||c,h=h===Hi?+l.startOf(Date.now(),u):h,c=c===Ei?+l.endOf(Date.now(),u)+1:c,r.min=Math.min(h,c),r.max=Math.max(h+1,c),r._horizontal=r.isHorizontal(),r._table=[],r._timestamps={data:f,datasets:g,labels:p}},buildTicks:function(){var t,e,i,n=this,a=n.min,o=n.max,r=n.options,s=r.time,l=[],d=[];switch(r.ticks.source){case"data":l=n._timestamps.data;break;case"labels":l=n._timestamps.labels;break;case"auto":default:l=$i(n,a,o,n.getLabelCapacity(a))}for("ticks"===r.bounds&&l.length&&(a=l[0],o=l[l.length-1]),a=Gi(n,s.min)||a,o=Gi(n,s.max)||o,t=0,e=l.length;t<e;++t)(i=l[t])>=a&&i<=o&&d.push(i);return n.min=a,n.max=o,n._unit=s.unit||function(t,e,i,n,a){var o,r;for(o=qi.length-1;o>=qi.indexOf(i);o--)if(r=qi[o],ji[r].common&&t._adapter.diff(a,n,r)>=e.length)return r;return qi[i?qi.indexOf(i):0]}(n,d,s.minUnit,n.min,n.max),n._majorUnit=Zi(n._unit),n._table=function(t,e,i,n){if("linear"===n||!t.length)return[{time:e,pos:0},{time:i,pos:1}];var a,o,r,s,l,d=[],u=[e];for(a=0,o=t.length;a<o;++a)(s=t[a])>e&&s<i&&u.push(s);for(u.push(i),a=0,o=u.length;a<o;++a)l=u[a+1],r=u[a-1],s=u[a],void 0!==r&&void 0!==l&&Math.round((l+r)/2)===s||d.push({time:s,pos:a/(o-1)});return d}(n._timestamps.data,a,o,r.distribution),n._offsets=function(t,e,i,n,a){var o,r,s=0,l=0;return a.offset&&e.length&&(a.time.min||(o=Xi(t,"time",e[0],"pos"),s=1===e.length?1-o:(Xi(t,"time",e[1],"pos")-o)/2),a.time.max||(r=Xi(t,"time",e[e.length-1],"pos"),l=1===e.length?r:(r-Xi(t,"time",e[e.length-2],"pos"))/2)),{start:s,end:l}}(n._table,d,0,0,r),r.ticks.reverse&&d.reverse(),function(t,e,i){var n,a,o,r,s=[];for(n=0,a=e.length;n<a;++n)o=e[n],r=!!i&&o===+t._adapter.startOf(o,i),s.push({value:o,major:r});return s}(n,d,n._majorUnit)},getLabelForIndex:function(t,e){var i=this,n=i._adapter,a=i.chart.data,o=i.options.time,r=a.labels&&t<a.labels.length?a.labels[t]:"",s=a.datasets[e].data[t];return ut.isObject(s)&&(r=i.getRightValue(s)),o.tooltipFormat?n.format(Ki(i,r),o.tooltipFormat):"string"==typeof r?r:n.format(Ki(i,r),o.displayFormats.datetime)},tickFormatFunction:function(t,e,i,n){var a=this._adapter,o=this.options,r=o.time.displayFormats,s=r[this._unit],l=this._majorUnit,d=r[l],u=+a.startOf(t,l),h=o.ticks.major,c=h.enabled&&l&&d&&t===u,f=a.format(t,n||(c?d:s)),g=c?h:o.ticks.minor,p=Vi(g.callback,g.userCallback);return p?p(f,e,i):f},convertTicksToLabels:function(t){var e,i,n=[];for(e=0,i=t.length;e<i;++e)n.push(this.tickFormatFunction(t[e].value,e,t));return n},getPixelForOffset:function(t){var e=this,i=e.options.ticks.reverse,n=e._horizontal?e.width:e.height,a=e._horizontal?i?e.right:e.left:i?e.bottom:e.top,o=Xi(e._table,"time",t,"pos"),r=n*(e._offsets.start+o)/(e._offsets.start+1+e._offsets.end);return i?a-r:a+r},getPixelForValue:function(t,e,i){var n=null;if(void 0!==e&&void 0!==i&&(n=this._timestamps.datasets[i][e]),null===n&&(n=Gi(this,t)),null!==n)return this.getPixelForOffset(n)},getPixelForTick:function(t){var e=this.getTicks();return t>=0&&t<e.length?this.getPixelForOffset(e[t].value):null},getValueForPixel:function(t){var e=this,i=e._horizontal?e.width:e.height,n=e._horizontal?e.left:e.top,a=(i?(t-n)/i:0)*(e._offsets.start+1+e._offsets.start)-e._offsets.end,o=Xi(e._table,"pos",a,"time");return e._adapter._create(o)},getLabelWidth:function(t){var e=this.options.ticks,i=this.ctx.measureText(t).width,n=ut.toRadians(e.maxRotation),a=Math.cos(n),o=Math.sin(n);return i*a+Vi(e.fontSize,st.global.defaultFontSize)*o},getLabelCapacity:function(t){var e=this,i=e.options.time.displayFormats.millisecond,n=e.tickFormatFunction(t,0,[],i),a=e.getLabelWidth(n),o=e.isHorizontal()?e.width:e.height,r=Math.floor(o/a);return r>0?r:1}}),Qi={position:"bottom",distribution:"linear",bounds:"data",adapters:{},time:{parser:!1,format:!1,unit:!1,round:!1,displayFormat:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{autoSkip:!1,source:"auto",major:{enabled:!1}}};Ji._defaults=Qi;var tn={category:gi,linear:yi,logarithmic:Ci,radialLinear:Ni,time:Ji},en={datetime:"MMM D, YYYY, h:mm:ss a",millisecond:"h:mm:ss.SSS a",second:"h:mm:ss a",minute:"h:mm a",hour:"hA",day:"MMM D",week:"ll",month:"MMM YYYY",quarter:"[Q]Q - YYYY",year:"YYYY"};si._date.override("function"==typeof t?{_id:"moment",formats:function(){return en},parse:function(e,i){return"string"==typeof e&&"string"==typeof i?e=t(e,i):e instanceof t||(e=t(e)),e.isValid()?e.valueOf():null},format:function(e,i){return t(e).format(i)},add:function(e,i,n){return t(e).add(i,n).valueOf()},diff:function(e,i,n){return t.duration(t(e).diff(t(i))).as(n)},startOf:function(e,i,n){return e=t(e),"isoWeek"===i?e.isoWeekday(n).valueOf():e.startOf(i).valueOf()},endOf:function(e,i){return t(e).endOf(i).valueOf()},_create:function(e){return t(e)}}:{}),st._set("global",{plugins:{filler:{propagate:!0}}});var nn={dataset:function(t){var e=t.fill,i=t.chart,n=i.getDatasetMeta(e),a=n&&i.isDatasetVisible(e)&&n.dataset._children||[],o=a.length||0;return o?function(t,e){return e<o&&a[e]._view||null}:null},boundary:function(t){var e=t.boundary,i=e?e.x:null,n=e?e.y:null;return function(t){return{x:null===i?t.x:i,y:null===n?t.y:n}}}};function an(t,e,i){var n,a=t._model||{},o=a.fill;if(void 0===o&&(o=!!a.backgroundColor),!1===o||null===o)return!1;if(!0===o)return"origin";if(n=parseFloat(o,10),isFinite(n)&&Math.floor(n)===n)return"-"!==o[0]&&"+"!==o[0]||(n=e+n),!(n===e||n<0||n>=i)&&n;switch(o){case"bottom":return"start";case"top":return"end";case"zero":return"origin";case"origin":case"start":case"end":return o;default:return!1}}function on(t){var e,i=t.el._model||{},n=t.el._scale||{},a=t.fill,o=null;if(isFinite(a))return null;if("start"===a?o=void 0===i.scaleBottom?n.bottom:i.scaleBottom:"end"===a?o=void 0===i.scaleTop?n.top:i.scaleTop:void 0!==i.scaleZero?o=i.scaleZero:n.getBasePosition?o=n.getBasePosition():n.getBasePixel&&(o=n.getBasePixel()),null!=o){if(void 0!==o.x&&void 0!==o.y)return o;if(ut.isFinite(o))return{x:(e=n.isHorizontal())?o:null,y:e?null:o}}return null}function rn(t,e,i){var n,a=t[e].fill,o=[e];if(!i)return a;for(;!1!==a&&-1===o.indexOf(a);){if(!isFinite(a))return a;if(!(n=t[a]))return!1;if(n.visible)return a;o.push(a),a=n.fill}return!1}function sn(t){var e=t.fill,i="dataset";return!1===e?null:(isFinite(e)||(i="boundary"),nn[i](t))}function ln(t){return t&&!t.skip}function dn(t,e,i,n,a){var o;if(n&&a){for(t.moveTo(e[0].x,e[0].y),o=1;o<n;++o)ut.canvas.lineTo(t,e[o-1],e[o]);for(t.lineTo(i[a-1].x,i[a-1].y),o=a-1;o>0;--o)ut.canvas.lineTo(t,i[o],i[o-1],!0)}}var un={id:"filler",afterDatasetsUpdate:function(t,e){var i,n,a,o,r=(t.data.datasets||[]).length,s=e.propagate,l=[];for(n=0;n<r;++n)o=null,(a=(i=t.getDatasetMeta(n)).dataset)&&a._model&&a instanceof Wt.Line&&(o={visible:t.isDatasetVisible(n),fill:an(a,n,r),chart:t,el:a}),i.$filler=o,l.push(o);for(n=0;n<r;++n)(o=l[n])&&(o.fill=rn(l,n,s),o.boundary=on(o),o.mapper=sn(o))},beforeDatasetDraw:function(t,e){var i=e.meta.$filler;if(i){var n=t.ctx,a=i.el,o=a._view,r=a._children||[],s=i.mapper,l=o.backgroundColor||st.global.defaultColor;s&&l&&r.length&&(ut.canvas.clipArea(n,t.chartArea),function(t,e,i,n,a,o){var r,s,l,d,u,h,c,f=e.length,g=n.spanGaps,p=[],m=[],v=0,b=0;for(t.beginPath(),r=0,s=f+!!o;r<s;++r)u=i(d=e[l=r%f]._view,l,n),h=ln(d),c=ln(u),h&&c?(v=p.push(d),b=m.push(u)):v&&b&&(g?(h&&p.push(d),c&&m.push(u)):(dn(t,p,m,v,b),v=b=0,p=[],m=[]));dn(t,p,m,v,b),t.closePath(),t.fillStyle=a,t.fill()}(n,r,s,o,l,a._loop),ut.canvas.unclipArea(n))}}},hn=ut.noop,cn=ut.valueOrDefault;function fn(t,e){return t.usePointStyle&&t.boxWidth>e?e:t.boxWidth}st._set("global",{legend:{display:!0,position:"top",fullWidth:!0,reverse:!1,weight:1e3,onClick:function(t,e){var i=e.datasetIndex,n=this.chart,a=n.getDatasetMeta(i);a.hidden=null===a.hidden?!n.data.datasets[i].hidden:null,n.update()},onHover:null,onLeave:null,labels:{boxWidth:40,padding:10,generateLabels:function(t){var e=t.data;return ut.isArray(e.datasets)?e.datasets.map(function(e,i){return{text:e.label,fillStyle:ut.isArray(e.backgroundColor)?e.backgroundColor[0]:e.backgroundColor,hidden:!t.isDatasetVisible(i),lineCap:e.borderCapStyle,lineDash:e.borderDash,lineDashOffset:e.borderDashOffset,lineJoin:e.borderJoinStyle,lineWidth:e.borderWidth,strokeStyle:e.borderColor,pointStyle:e.pointStyle,datasetIndex:i}},this):[]}}},legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');for(var i=0;i<t.data.datasets.length;i++)e.push('<li><span style="background-color:'+t.data.datasets[i].backgroundColor+'"></span>'),t.data.datasets[i].label&&e.push(t.data.datasets[i].label),e.push("</li>");return e.push("</ul>"),e.join("")}});var gn=pt.extend({initialize:function(t){ut.extend(this,t),this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1},beforeUpdate:hn,update:function(t,e,i){var n=this;return n.beforeUpdate(),n.maxWidth=t,n.maxHeight=e,n.margins=i,n.beforeSetDimensions(),n.setDimensions(),n.afterSetDimensions(),n.beforeBuildLabels(),n.buildLabels(),n.afterBuildLabels(),n.beforeFit(),n.fit(),n.afterFit(),n.afterUpdate(),n.minSize},afterUpdate:hn,beforeSetDimensions:hn,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:hn,beforeBuildLabels:hn,buildLabels:function(){var t=this,e=t.options.labels||{},i=ut.callback(e.generateLabels,[t.chart],t)||[];e.filter&&(i=i.filter(function(i){return e.filter(i,t.chart.data)})),t.options.reverse&&i.reverse(),t.legendItems=i},afterBuildLabels:hn,beforeFit:hn,fit:function(){var t=this,e=t.options,i=e.labels,n=e.display,a=t.ctx,o=ut.options._parseFont(i),r=o.size,s=t.legendHitBoxes=[],l=t.minSize,d=t.isHorizontal();if(d?(l.width=t.maxWidth,l.height=n?10:0):(l.width=n?10:0,l.height=t.maxHeight),n)if(a.font=o.string,d){var u=t.lineWidths=[0],h=0;a.textAlign="left",a.textBaseline="top",ut.each(t.legendItems,function(t,e){var n=fn(i,r)+r/2+a.measureText(t.text).width;(0===e||u[u.length-1]+n+i.padding>l.width)&&(h+=r+i.padding,u[u.length-(e>0?0:1)]=i.padding),s[e]={left:0,top:0,width:n,height:r},u[u.length-1]+=n+i.padding}),l.height+=h}else{var c=i.padding,f=t.columnWidths=[],g=i.padding,p=0,m=0,v=r+c;ut.each(t.legendItems,function(t,e){var n=fn(i,r)+r/2+a.measureText(t.text).width;e>0&&m+v>l.height-c&&(g+=p+i.padding,f.push(p),p=0,m=0),p=Math.max(p,n),m+=v,s[e]={left:0,top:0,width:n,height:r}}),g+=p,f.push(p),l.width+=g}t.width=l.width,t.height=l.height},afterFit:hn,isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},draw:function(){var t=this,e=t.options,i=e.labels,n=st.global,a=n.defaultColor,o=n.elements.line,r=t.width,s=t.lineWidths;if(e.display){var l,d=t.ctx,u=cn(i.fontColor,n.defaultFontColor),h=ut.options._parseFont(i),c=h.size;d.textAlign="left",d.textBaseline="middle",d.lineWidth=.5,d.strokeStyle=u,d.fillStyle=u,d.font=h.string;var f=fn(i,c),g=t.legendHitBoxes,p=t.isHorizontal();l=p?{x:t.left+(r-s[0])/2+i.padding,y:t.top+i.padding,line:0}:{x:t.left+i.padding,y:t.top+i.padding,line:0};var m=c+i.padding;ut.each(t.legendItems,function(n,u){var h=d.measureText(n.text).width,v=f+c/2+h,b=l.x,x=l.y;p?u>0&&b+v+i.padding>t.left+t.minSize.width&&(x=l.y+=m,l.line++,b=l.x=t.left+(r-s[l.line])/2+i.padding):u>0&&x+m>t.top+t.minSize.height&&(b=l.x=b+t.columnWidths[l.line]+i.padding,x=l.y=t.top+i.padding,l.line++),function(t,i,n){if(!(isNaN(f)||f<=0)){d.save();var r=cn(n.lineWidth,o.borderWidth);if(d.fillStyle=cn(n.fillStyle,a),d.lineCap=cn(n.lineCap,o.borderCapStyle),d.lineDashOffset=cn(n.lineDashOffset,o.borderDashOffset),d.lineJoin=cn(n.lineJoin,o.borderJoinStyle),d.lineWidth=r,d.strokeStyle=cn(n.strokeStyle,a),d.setLineDash&&d.setLineDash(cn(n.lineDash,o.borderDash)),e.labels&&e.labels.usePointStyle){var s=f*Math.SQRT2/2,l=t+f/2,u=i+c/2;ut.canvas.drawPoint(d,n.pointStyle,s,l,u)}else 0!==r&&d.strokeRect(t,i,f,c),d.fillRect(t,i,f,c);d.restore()}}(b,x,n),g[u].left=b,g[u].top=x,function(t,e,i,n){var a=c/2,o=f+a+t,r=e+a;d.fillText(i.text,o,r),i.hidden&&(d.beginPath(),d.lineWidth=2,d.moveTo(o,r),d.lineTo(o+n,r),d.stroke())}(b,x,n,h),p?l.x+=v+i.padding:l.y+=m})}},_getLegendItemAt:function(t,e){var i,n,a,o=this;if(t>=o.left&&t<=o.right&&e>=o.top&&e<=o.bottom)for(a=o.legendHitBoxes,i=0;i<a.length;++i)if(t>=(n=a[i]).left&&t<=n.left+n.width&&e>=n.top&&e<=n.top+n.height)return o.legendItems[i];return null},handleEvent:function(t){var e,i=this,n=i.options,a="mouseup"===t.type?"click":t.type;if("mousemove"===a){if(!n.onHover&&!n.onLeave)return}else{if("click"!==a)return;if(!n.onClick)return}e=i._getLegendItemAt(t.x,t.y),"click"===a?e&&n.onClick&&n.onClick.call(i,t.native,e):(n.onLeave&&e!==i._hoveredItem&&(i._hoveredItem&&n.onLeave.call(i,t.native,i._hoveredItem),i._hoveredItem=e),n.onHover&&e&&n.onHover.call(i,t.native,e))}});function pn(t,e){var i=new gn({ctx:t.ctx,options:e,chart:t});ke.configure(t,i,e),ke.addBox(t,i),t.legend=i}var mn={id:"legend",_element:gn,beforeInit:function(t){var e=t.options.legend;e&&pn(t,e)},beforeUpdate:function(t){var e=t.options.legend,i=t.legend;e?(ut.mergeIf(e,st.global.legend),i?(ke.configure(t,i,e),i.options=e):pn(t,e)):i&&(ke.removeBox(t,i),delete t.legend)},afterEvent:function(t,e){var i=t.legend;i&&i.handleEvent(e)}},vn=ut.noop;st._set("global",{title:{display:!1,fontStyle:"bold",fullWidth:!0,padding:10,position:"top",text:"",weight:2e3}});var bn=pt.extend({initialize:function(t){ut.extend(this,t),this.legendHitBoxes=[]},beforeUpdate:vn,update:function(t,e,i){var n=this;return n.beforeUpdate(),n.maxWidth=t,n.maxHeight=e,n.margins=i,n.beforeSetDimensions(),n.setDimensions(),n.afterSetDimensions(),n.beforeBuildLabels(),n.buildLabels(),n.afterBuildLabels(),n.beforeFit(),n.fit(),n.afterFit(),n.afterUpdate(),n.minSize},afterUpdate:vn,beforeSetDimensions:vn,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:vn,beforeBuildLabels:vn,buildLabels:vn,afterBuildLabels:vn,beforeFit:vn,fit:function(){var t=this,e=t.options,i=e.display,n=t.minSize,a=ut.isArray(e.text)?e.text.length:1,o=ut.options._parseFont(e),r=i?a*o.lineHeight+2*e.padding:0;t.isHorizontal()?(n.width=t.maxWidth,n.height=r):(n.width=r,n.height=t.maxHeight),t.width=n.width,t.height=n.height},afterFit:vn,isHorizontal:function(){var t=this.options.position;return"top"===t||"bottom"===t},draw:function(){var t=this,e=t.ctx,i=t.options;if(i.display){var n,a,o,r=ut.options._parseFont(i),s=r.lineHeight,l=s/2+i.padding,d=0,u=t.top,h=t.left,c=t.bottom,f=t.right;e.fillStyle=ut.valueOrDefault(i.fontColor,st.global.defaultFontColor),e.font=r.string,t.isHorizontal()?(a=h+(f-h)/2,o=u+l,n=f-h):(a="left"===i.position?h+l:f-l,o=u+(c-u)/2,n=c-u,d=Math.PI*("left"===i.position?-.5:.5)),e.save(),e.translate(a,o),e.rotate(d),e.textAlign="center",e.textBaseline="middle";var g=i.text;if(ut.isArray(g))for(var p=0,m=0;m<g.length;++m)e.fillText(g[m],0,p,n),p+=s;else e.fillText(g,0,0,n);e.restore()}}});function xn(t,e){var i=new bn({ctx:t.ctx,options:e,chart:t});ke.configure(t,i,e),ke.addBox(t,i),t.titleBlock=i}var yn={},kn=un,wn=mn,Mn={id:"title",_element:bn,beforeInit:function(t){var e=t.options.title;e&&xn(t,e)},beforeUpdate:function(t){var e=t.options.title,i=t.titleBlock;e?(ut.mergeIf(e,st.global.title),i?(ke.configure(t,i,e),i.options=e):xn(t,e)):i&&(ke.removeBox(t,i),delete t.titleBlock)}};for(var _n in yn.filler=kn,yn.legend=wn,yn.title=Mn,ai.helpers=ut,function(){function t(t,e,i){var n;return"string"==typeof t?(n=parseInt(t,10),-1!==t.indexOf("%")&&(n=n/100*e.parentNode[i])):n=t,n}function e(t){return null!=t&&"none"!==t}function i(i,n,a){var o=document.defaultView,r=ut._getParentNode(i),s=o.getComputedStyle(i)[n],l=o.getComputedStyle(r)[n],d=e(s),u=e(l),h=Number.POSITIVE_INFINITY;return d||u?Math.min(d?t(s,i,a):h,u?t(l,r,a):h):"none"}ut.where=function(t,e){if(ut.isArray(t)&&Array.prototype.filter)return t.filter(e);var i=[];return ut.each(t,function(t){e(t)&&i.push(t)}),i},ut.findIndex=Array.prototype.findIndex?function(t,e,i){return t.findIndex(e,i)}:function(t,e,i){i=void 0===i?t:i;for(var n=0,a=t.length;n<a;++n)if(e.call(i,t[n],n,t))return n;return-1},ut.findNextWhere=function(t,e,i){ut.isNullOrUndef(i)&&(i=-1);for(var n=i+1;n<t.length;n++){var a=t[n];if(e(a))return a}},ut.findPreviousWhere=function(t,e,i){ut.isNullOrUndef(i)&&(i=t.length);for(var n=i-1;n>=0;n--){var a=t[n];if(e(a))return a}},ut.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},ut.almostEquals=function(t,e,i){return Math.abs(t-e)<i},ut.almostWhole=function(t,e){var i=Math.round(t);return i-e<t&&i+e>t},ut.max=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.max(t,e)},Number.NEGATIVE_INFINITY)},ut.min=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.min(t,e)},Number.POSITIVE_INFINITY)},ut.sign=Math.sign?function(t){return Math.sign(t)}:function(t){return 0==(t=+t)||isNaN(t)?t:t>0?1:-1},ut.log10=Math.log10?function(t){return Math.log10(t)}:function(t){var e=Math.log(t)*Math.LOG10E,i=Math.round(e);return t===Math.pow(10,i)?i:e},ut.toRadians=function(t){return t*(Math.PI/180)},ut.toDegrees=function(t){return t*(180/Math.PI)},ut._decimalPlaces=function(t){if(ut.isFinite(t)){for(var e=1,i=0;Math.round(t*e)/e!==t;)e*=10,i++;return i}},ut.getAngleFromPoint=function(t,e){var i=e.x-t.x,n=e.y-t.y,a=Math.sqrt(i*i+n*n),o=Math.atan2(n,i);return o<-.5*Math.PI&&(o+=2*Math.PI),{angle:o,distance:a}},ut.distanceBetweenPoints=function(t,e){return Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))},ut.aliasPixel=function(t){return t%2==0?0:.5},ut._alignPixel=function(t,e,i){var n=t.currentDevicePixelRatio,a=i/2;return Math.round((e-a)*n)/n+a},ut.splineCurve=function(t,e,i,n){var a=t.skip?e:t,o=e,r=i.skip?e:i,s=Math.sqrt(Math.pow(o.x-a.x,2)+Math.pow(o.y-a.y,2)),l=Math.sqrt(Math.pow(r.x-o.x,2)+Math.pow(r.y-o.y,2)),d=s/(s+l),u=l/(s+l),h=n*(d=isNaN(d)?0:d),c=n*(u=isNaN(u)?0:u);return{previous:{x:o.x-h*(r.x-a.x),y:o.y-h*(r.y-a.y)},next:{x:o.x+c*(r.x-a.x),y:o.y+c*(r.y-a.y)}}},ut.EPSILON=Number.EPSILON||1e-14,ut.splineCurveMonotone=function(t){var e,i,n,a,o,r,s,l,d,u=(t||[]).map(function(t){return{model:t._model,deltaK:0,mK:0}}),h=u.length;for(e=0;e<h;++e)if(!(n=u[e]).model.skip){if(i=e>0?u[e-1]:null,(a=e<h-1?u[e+1]:null)&&!a.model.skip){var c=a.model.x-n.model.x;n.deltaK=0!==c?(a.model.y-n.model.y)/c:0}!i||i.model.skip?n.mK=n.deltaK:!a||a.model.skip?n.mK=i.deltaK:this.sign(i.deltaK)!==this.sign(n.deltaK)?n.mK=0:n.mK=(i.deltaK+n.deltaK)/2}for(e=0;e<h-1;++e)n=u[e],a=u[e+1],n.model.skip||a.model.skip||(ut.almostEquals(n.deltaK,0,this.EPSILON)?n.mK=a.mK=0:(o=n.mK/n.deltaK,r=a.mK/n.deltaK,(l=Math.pow(o,2)+Math.pow(r,2))<=9||(s=3/Math.sqrt(l),n.mK=o*s*n.deltaK,a.mK=r*s*n.deltaK)));for(e=0;e<h;++e)(n=u[e]).model.skip||(i=e>0?u[e-1]:null,a=e<h-1?u[e+1]:null,i&&!i.model.skip&&(d=(n.model.x-i.model.x)/3,n.model.controlPointPreviousX=n.model.x-d,n.model.controlPointPreviousY=n.model.y-d*n.mK),a&&!a.model.skip&&(d=(a.model.x-n.model.x)/3,n.model.controlPointNextX=n.model.x+d,n.model.controlPointNextY=n.model.y+d*n.mK))},ut.nextItem=function(t,e,i){return i?e>=t.length-1?t[0]:t[e+1]:e>=t.length-1?t[t.length-1]:t[e+1]},ut.previousItem=function(t,e,i){return i?e<=0?t[t.length-1]:t[e-1]:e<=0?t[0]:t[e-1]},ut.niceNum=function(t,e){var i=Math.floor(ut.log10(t)),n=t/Math.pow(10,i);return(e?n<1.5?1:n<3?2:n<7?5:10:n<=1?1:n<=2?2:n<=5?5:10)*Math.pow(10,i)},ut.requestAnimFrame="undefined"==typeof window?function(t){t()}:window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)},ut.getRelativePosition=function(t,e){var i,n,a=t.originalEvent||t,o=t.target||t.srcElement,r=o.getBoundingClientRect(),s=a.touches;s&&s.length>0?(i=s[0].clientX,n=s[0].clientY):(i=a.clientX,n=a.clientY);var l=parseFloat(ut.getStyle(o,"padding-left")),d=parseFloat(ut.getStyle(o,"padding-top")),u=parseFloat(ut.getStyle(o,"padding-right")),h=parseFloat(ut.getStyle(o,"padding-bottom")),c=r.right-r.left-l-u,f=r.bottom-r.top-d-h;return{x:i=Math.round((i-r.left-l)/c*o.width/e.currentDevicePixelRatio),y:n=Math.round((n-r.top-d)/f*o.height/e.currentDevicePixelRatio)}},ut.getConstraintWidth=function(t){return i(t,"max-width","clientWidth")},ut.getConstraintHeight=function(t){return i(t,"max-height","clientHeight")},ut._calculatePadding=function(t,e,i){return(e=ut.getStyle(t,e)).indexOf("%")>-1?i*parseInt(e,10)/100:parseInt(e,10)},ut._getParentNode=function(t){var e=t.parentNode;return e&&"[object ShadowRoot]"===e.toString()&&(e=e.host),e},ut.getMaximumWidth=function(t){var e=ut._getParentNode(t);if(!e)return t.clientWidth;var i=e.clientWidth,n=i-ut._calculatePadding(e,"padding-left",i)-ut._calculatePadding(e,"padding-right",i),a=ut.getConstraintWidth(t);return isNaN(a)?n:Math.min(n,a)},ut.getMaximumHeight=function(t){var e=ut._getParentNode(t);if(!e)return t.clientHeight;var i=e.clientHeight,n=i-ut._calculatePadding(e,"padding-top",i)-ut._calculatePadding(e,"padding-bottom",i),a=ut.getConstraintHeight(t);return isNaN(a)?n:Math.min(n,a)},ut.getStyle=function(t,e){return t.currentStyle?t.currentStyle[e]:document.defaultView.getComputedStyle(t,null).getPropertyValue(e)},ut.retinaScale=function(t,e){var i=t.currentDevicePixelRatio=e||"undefined"!=typeof window&&window.devicePixelRatio||1;if(1!==i){var n=t.canvas,a=t.height,o=t.width;n.height=a*i,n.width=o*i,t.ctx.scale(i,i),n.style.height||n.style.width||(n.style.height=a+"px",n.style.width=o+"px")}},ut.fontString=function(t,e,i){return e+" "+t+"px "+i},ut.longestText=function(t,e,i,n){var a=(n=n||{}).data=n.data||{},o=n.garbageCollect=n.garbageCollect||[];n.font!==e&&(a=n.data={},o=n.garbageCollect=[],n.font=e),t.font=e;var r=0;ut.each(i,function(e){null!=e&&!0!==ut.isArray(e)?r=ut.measureText(t,a,o,r,e):ut.isArray(e)&&ut.each(e,function(e){null==e||ut.isArray(e)||(r=ut.measureText(t,a,o,r,e))})});var s=o.length/2;if(s>i.length){for(var l=0;l<s;l++)delete a[o[l]];o.splice(0,s)}return r},ut.measureText=function(t,e,i,n,a){var o=e[a];return o||(o=e[a]=t.measureText(a).width,i.push(a)),o>n&&(n=o),n},ut.numberOfLabelLines=function(t){var e=1;return ut.each(t,function(t){ut.isArray(t)&&t.length>e&&(e=t.length)}),e},ut.color=X?function(t){return t instanceof CanvasGradient&&(t=st.global.defaultColor),X(t)}:function(t){return console.error("Color.js not found!"),t},ut.getHoverColor=function(t){return t instanceof CanvasPattern||t instanceof CanvasGradient?t:ut.color(t).saturate(.5).darken(.1).rgbString()}}(),ai._adapters=si,ai.Animation=vt,ai.animationService=bt,ai.controllers=ue,ai.DatasetController=Mt,ai.defaults=st,ai.Element=pt,ai.elements=Wt,ai.Interaction=ve,ai.layouts=ke,ai.platform=Ve,ai.plugins=Ee,ai.Scale=fi,ai.scaleService=He,ai.Ticks=li,ai.Tooltip=Je,ai.helpers.each(tn,function(t,e){ai.scaleService.registerScaleType(e,t,t._defaults)}),yn)yn.hasOwnProperty(_n)&&ai.plugins.register(yn[_n]);ai.platform.initialize();var Cn=ai;return"undefined"!=typeof window&&(window.Chart=ai),ai.Chart=ai,ai.Legend=yn.legend._element,ai.Title=yn.title._element,ai.pluginService=ai.plugins,ai.PluginBase=ai.Element.extend({}),ai.canvasHelpers=ai.helpers.canvas,ai.layoutService=ai.layouts,ai.LinearScaleBase=bi,ai.helpers.each(["Bar","Bubble","Doughnut","Line","PolarArea","Radar","Scatter"],function(t){ai[t]=function(e,i){return new ai(e,ai.helpers.merge(i||{},{type:t.charAt(0).toLowerCase()+t.slice(1)}))}}),Cn});