]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Release 2.9.1 v2.9.1
authorChart.js <chartjs-ci@users.noreply.github.com>
Sun, 27 Oct 2019 19:17:04 +0000 (19:17 +0000)
committerChart.js <chartjs-ci@users.noreply.github.com>
Sun, 27 Oct 2019 19:17:04 +0000 (19:17 +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..c2e061c
--- /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.9.1",
+  "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..9b45615
--- /dev/null
@@ -0,0 +1,20289 @@
+/*!
+ * Chart.js v2.9.1
+ * 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 = global || self, 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: Object.assign || function(target) {
+               return helpers.merge(target, [].slice.call(arguments, 1), {
+                       merger: function(key, dst, src) {
+                               dst[key] = src[key];
+                       }
+               });
+       },
+
+       /**
+        * 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;
+       },
+
+       _deprecated: function(scope, value, previous, current) {
+               if (value !== undefined) {
+                       console.warn(scope + ': "' + previous +
+                               '" is deprecated. Please use "' + current + '" instead');
+               }
+       }
+};
+
+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.save();
+                               ctx.translate(x, y);
+                               ctx.rotate(rad);
+                               ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height);
+                               ctx.restore();
+                               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);
+       }
+};
+
+// TODO(v3): remove 'global' from namespace.  all default are global and
+// there's inconsistency around which options are under 'global'
+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.
+        * @param {object} [info] - object to return information about resolution in
+        * @param {boolean} [info.cacheable] - Will be set to `false` if option is not cacheable.
+        * @since 2.7.0
+        */
+       resolve: function(inputs, context, index, info) {
+               var cacheable = true;
+               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);
+                               cacheable = false;
+                       }
+                       if (index !== undefined && helpers_core.isArray(value)) {
+                               value = value[index];
+                               cacheable = false;
+                       }
+                       if (value !== undefined) {
+                               if (info && !cacheable) {
+                                       info.cacheable = false;
+                               }
+                               return value;
+                       }
+               }
+       }
+};
+
+/**
+ * @alias Chart.helpers.math
+ * @namespace
+ */
+var exports$2 = {
+       /**
+        * Returns an array of factors sorted from 1 to sqrt(value)
+        * @private
+        */
+       _factorize: function(value) {
+               var result = [];
+               var sqrt = Math.sqrt(value);
+               var i;
+
+               for (i = 1; i < sqrt; i++) {
+                       if (value % i === 0) {
+                               result.push(i);
+                               result.push(value / i);
+                       }
+               }
+               if (sqrt === (sqrt | 0)) { // if value is a square number
+                       result.push(sqrt);
+               }
+
+               result.sort(function(a, b) {
+                       return a - b;
+               }).pop();
+               return result;
+       },
+
+       log10: Math.log10 || 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;
+       }
+};
+
+var helpers_math = exports$2;
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.math.log10 instead.
+ * @namespace Chart.helpers.log10
+ * @deprecated since version 2.9.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers_core.log10 = exports$2.log10;
+
+var getRtlAdapter = function(rectX, width) {
+       return {
+               x: function(x) {
+                       return rectX + rectX + width - x;
+               },
+               setWidth: function(w) {
+                       width = w;
+               },
+               textAlign: function(align) {
+                       if (align === 'center') {
+                               return align;
+                       }
+                       return align === 'right' ? 'left' : 'right';
+               },
+               xPlus: function(x, value) {
+                       return x - value;
+               },
+               leftForLtr: function(x, itemWidth) {
+                       return x - itemWidth;
+               },
+       };
+};
+
+var getLtrAdapter = function() {
+       return {
+               x: function(x) {
+                       return x;
+               },
+               setWidth: function(w) { // eslint-disable-line no-unused-vars
+               },
+               textAlign: function(align) {
+                       return align;
+               },
+               xPlus: function(x, value) {
+                       return x + value;
+               },
+               leftForLtr: function(x, _itemWidth) { // eslint-disable-line no-unused-vars
+                       return x;
+               },
+       };
+};
+
+var getAdapter = function(rtl, rectX, width) {
+       return rtl ? getRtlAdapter(rectX, width) : getLtrAdapter();
+};
+
+var overrideTextDirection = function(ctx, direction) {
+       var style, original;
+       if (direction === 'ltr' || direction === 'rtl') {
+               style = ctx.canvas.style;
+               original = [
+                       style.getPropertyValue('direction'),
+                       style.getPropertyPriority('direction'),
+               ];
+
+               style.setProperty('direction', direction, 'important');
+               ctx.prevTextDirection = original;
+       }
+};
+
+var restoreTextDirection = function(ctx) {
+       var original = ctx.prevTextDirection;
+       if (original !== undefined) {
+               delete ctx.prevTextDirection;
+               ctx.canvas.style.setProperty('direction', original[0], original[1]);
+       }
+};
+
+var helpers_rtl = {
+       getRtlAdapter: getAdapter,
+       overrideTextDirection: overrideTextDirection,
+       restoreTextDirection: restoreTextDirection,
+};
+
+var helpers$1 = helpers_core;
+var easing = helpers_easing;
+var canvas = helpers_canvas;
+var options = helpers_options;
+var math = helpers_math;
+var rtl = helpers_rtl;
+helpers$1.easing = easing;
+helpers$1.canvas = canvas;
+helpers$1.options = options;
+helpers$1.math = math;
+helpers$1.rtl = rtl;
+
+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, {
+       _type: undefined,
+
+       initialize: function() {
+               this.hidden = false;
+       },
+
+       pivot: function() {
+               var me = this;
+               if (!me._view) {
+                       me._view = helpers$1.extend({}, 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 = helpers$1.extend({}, 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$3 = 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$3;
+
+// 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$3.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$3.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,
+
+       /**
+        * Dataset element option keys to be resolved in _resolveDatasetElementOptions.
+        * A derived controller may override this to resolve controller-specific options.
+        * The keys defined here are for backward compatibility for legend styles.
+        * @private
+        */
+       _datasetElementOptions: [
+               'backgroundColor',
+               'borderCapStyle',
+               'borderColor',
+               'borderDash',
+               'borderDashOffset',
+               'borderJoinStyle',
+               'borderWidth'
+       ],
+
+       /**
+        * Data element option keys to be resolved in _resolveDataElementOptions.
+        * A derived controller may override this to resolve controller-specific options.
+        * The keys defined here are for backward compatibility for legend styles.
+        * @private
+        */
+       _dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderWidth',
+               'pointStyle'
+       ],
+
+       initialize: function(chart, datasetIndex) {
+               var me = this;
+               me.chart = chart;
+               me.index = datasetIndex;
+               me.linkScales();
+               me.addElements();
+               me._type = me.getMeta().type;
+       },
+
+       updateIndex: function(datasetIndex) {
+               this.index = datasetIndex;
+       },
+
+       linkScales: function() {
+               var me = this;
+               var meta = me.getMeta();
+               var chart = me.chart;
+               var scales = chart.scales;
+               var dataset = me.getDataset();
+               var scalesOpts = chart.options.scales;
+
+               if (meta.xAxisID === null || !(meta.xAxisID in scales) || dataset.xAxisID) {
+                       meta.xAxisID = dataset.xAxisID || scalesOpts.xAxes[0].id;
+               }
+               if (meta.yAxisID === null || !(meta.yAxisID in scales) || dataset.yAxisID) {
+                       meta.yAxisID = dataset.yAxisID || scalesOpts.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();
+       },
+
+       /**
+        * Returns the merged user-supplied and default dataset-level options
+        * @private
+        */
+       _configure: function() {
+               var me = this;
+               me._config = helpers$1.merge({}, [
+                       me.chart.options.datasets[me._type],
+                       me.getDataset(),
+               ], {
+                       merger: function(key, target, source) {
+                               if (key !== '_meta' && key !== 'data') {
+                                       helpers$1._merger(key, target, source);
+                               }
+                       }
+               });
+       },
+
+       _update: function(reset) {
+               var me = this;
+               me._configure();
+               me._cachedDataOpts = null;
+               me.update(reset);
+       },
+
+       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();
+               }
+       },
+
+       /**
+        * Returns a set of predefined style properties that should be used to represent the dataset
+        * or the data if the index is specified
+        * @param {number} index - data index
+        * @return {IStyleInterface} style object
+        */
+       getStyle: function(index) {
+               var me = this;
+               var meta = me.getMeta();
+               var dataset = meta.dataset;
+               var style;
+
+               me._configure();
+               if (dataset && index === undefined) {
+                       style = me._resolveDatasetElementOptions(dataset || {});
+               } else {
+                       index = index || 0;
+                       style = me._resolveDataElementOptions(meta.data[index] || {}, index);
+               }
+
+               if (style.fill === false || style.fill === null) {
+                       style.backgroundColor = 'rgba(0,0,0,0)';
+               }
+
+               return style;
+       },
+
+       /**
+        * @private
+        */
+       _resolveDatasetElementOptions: function(element, hover) {
+               var me = this;
+               var chart = me.chart;
+               var datasetOpts = me._config;
+               var custom = element.custom || {};
+               var options = chart.options.elements[me.datasetElementType.prototype._type] || {};
+               var elementOptions = me._datasetElementOptions;
+               var values = {};
+               var i, ilen, key, readKey;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataset: me.getDataset(),
+                       datasetIndex: me.index,
+                       hover: hover
+               };
+
+               for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {
+                       key = elementOptions[i];
+                       readKey = hover ? 'hover' + key.charAt(0).toUpperCase() + key.slice(1) : key;
+                       values[key] = resolve([
+                               custom[readKey],
+                               datasetOpts[readKey],
+                               options[readKey]
+                       ], context);
+               }
+
+               return values;
+       },
+
+       /**
+        * @private
+        */
+       _resolveDataElementOptions: function(element, index) {
+               var me = this;
+               var custom = element && element.custom;
+               var cached = me._cachedDataOpts;
+               if (cached && !custom) {
+                       return cached;
+               }
+               var chart = me.chart;
+               var datasetOpts = me._config;
+               var options = chart.options.elements[me.dataElementType.prototype._type] || {};
+               var elementOptions = me._dataElementOptions;
+               var values = {};
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: me.getDataset(),
+                       datasetIndex: me.index
+               };
+
+               // `resolve` sets cacheable to `false` if any option is indexed or scripted
+               var info = {cacheable: !custom};
+
+               var keys, i, ilen, key;
+
+               custom = custom || {};
+
+               if (helpers$1.isArray(elementOptions)) {
+                       for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {
+                               key = elementOptions[i];
+                               values[key] = resolve([
+                                       custom[key],
+                                       datasetOpts[key],
+                                       options[key]
+                               ], context, index, info);
+                       }
+               } else {
+                       keys = Object.keys(elementOptions);
+                       for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                               key = keys[i];
+                               values[key] = resolve([
+                                       custom[key],
+                                       datasetOpts[elementOptions[key]],
+                                       datasetOpts[key],
+                                       options[key]
+                               ], context, index, info);
+                       }
+               }
+
+               if (info.cacheable) {
+                       me._cachedDataOpts = Object.freeze(values);
+               }
+
+               return values;
+       },
+
+       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
+        */
+       _removeDatasetHoverStyle: function() {
+               var element = this.getMeta().dataset;
+
+               if (element) {
+                       this.removeHoverStyle(element);
+               }
+       },
+
+       /**
+        * @private
+        */
+       _setDatasetHoverStyle: function() {
+               var element = this.getMeta().dataset;
+               var prev = {};
+               var i, ilen, key, keys, hoverOptions, model;
+
+               if (!element) {
+                       return;
+               }
+
+               model = element._model;
+               hoverOptions = this._resolveDatasetElementOptions(element, true);
+
+               keys = Object.keys(hoverOptions);
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       prev[key] = model[key];
+                       model[key] = hoverOptions[key];
+               }
+
+               element.$previousStyle = prev;
+       },
+
+       /**
+        * @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;
+
+var TAU = Math.PI * 2;
+
+core_defaults._set('global', {
+       elements: {
+               arc: {
+                       backgroundColor: core_defaults.global.defaultColor,
+                       borderColor: '#fff',
+                       borderWidth: 2,
+                       borderAlign: 'center'
+               }
+       }
+});
+
+function clipArc(ctx, arc) {
+       var startAngle = arc.startAngle;
+       var endAngle = arc.endAngle;
+       var pixelMargin = arc.pixelMargin;
+       var angleMargin = pixelMargin / arc.outerRadius;
+       var x = arc.x;
+       var y = arc.y;
+
+       // 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();
+       ctx.arc(x, y, arc.outerRadius, startAngle - angleMargin, endAngle + angleMargin);
+       if (arc.innerRadius > pixelMargin) {
+               angleMargin = pixelMargin / arc.innerRadius;
+               ctx.arc(x, y, arc.innerRadius - pixelMargin, endAngle + angleMargin, startAngle - angleMargin, true);
+       } else {
+               ctx.arc(x, y, pixelMargin, endAngle + Math.PI / 2, startAngle - Math.PI / 2);
+       }
+       ctx.closePath();
+       ctx.clip();
+}
+
+function drawFullCircleBorders(ctx, vm, arc, inner) {
+       var endAngle = arc.endAngle;
+       var i;
+
+       if (inner) {
+               arc.endAngle = arc.startAngle + TAU;
+               clipArc(ctx, arc);
+               arc.endAngle = endAngle;
+               if (arc.endAngle === arc.startAngle && arc.fullCircles) {
+                       arc.endAngle += TAU;
+                       arc.fullCircles--;
+               }
+       }
+
+       ctx.beginPath();
+       ctx.arc(arc.x, arc.y, arc.innerRadius, arc.startAngle + TAU, arc.startAngle, true);
+       for (i = 0; i < arc.fullCircles; ++i) {
+               ctx.stroke();
+       }
+
+       ctx.beginPath();
+       ctx.arc(arc.x, arc.y, vm.outerRadius, arc.startAngle, arc.startAngle + TAU);
+       for (i = 0; i < arc.fullCircles; ++i) {
+               ctx.stroke();
+       }
+}
+
+function drawBorder(ctx, vm, arc) {
+       var inner = vm.borderAlign === 'inner';
+
+       if (inner) {
+               ctx.lineWidth = vm.borderWidth * 2;
+               ctx.lineJoin = 'round';
+       } else {
+               ctx.lineWidth = vm.borderWidth;
+               ctx.lineJoin = 'bevel';
+       }
+
+       if (arc.fullCircles) {
+               drawFullCircleBorders(ctx, vm, arc, inner);
+       }
+
+       if (inner) {
+               clipArc(ctx, arc);
+       }
+
+       ctx.beginPath();
+       ctx.arc(arc.x, arc.y, vm.outerRadius, arc.startAngle, arc.endAngle);
+       ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true);
+       ctx.closePath();
+       ctx.stroke();
+}
+
+var element_arc = core_element.extend({
+       _type: 'arc',
+
+       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 += TAU;
+                       }
+                       while (angle > endAngle) {
+                               angle -= TAU;
+                       }
+                       while (angle < startAngle) {
+                               angle += TAU;
+                       }
+
+                       // 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 pixelMargin = (vm.borderAlign === 'inner') ? 0.33 : 0;
+               var arc = {
+                       x: vm.x,
+                       y: vm.y,
+                       innerRadius: vm.innerRadius,
+                       outerRadius: Math.max(vm.outerRadius - pixelMargin, 0),
+                       pixelMargin: pixelMargin,
+                       startAngle: vm.startAngle,
+                       endAngle: vm.endAngle,
+                       fullCircles: Math.floor(vm.circumference / TAU)
+               };
+               var i;
+
+               ctx.save();
+
+               ctx.fillStyle = vm.backgroundColor;
+               ctx.strokeStyle = vm.borderColor;
+
+               if (arc.fullCircles) {
+                       arc.endAngle = arc.startAngle + TAU;
+                       ctx.beginPath();
+                       ctx.arc(arc.x, arc.y, arc.outerRadius, arc.startAngle, arc.endAngle);
+                       ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true);
+                       ctx.closePath();
+                       for (i = 0; i < arc.fullCircles; ++i) {
+                               ctx.fill();
+                       }
+                       arc.endAngle = arc.startAngle + vm.circumference % TAU;
+               }
+
+               ctx.beginPath();
+               ctx.arc(arc.x, arc.y, arc.outerRadius, arc.startAngle, arc.endAngle);
+               ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true);
+               ctx.closePath();
+               ctx.fill();
+
+               if (vm.borderWidth) {
+                       drawBorder(ctx, vm, arc);
+               }
+
+               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({
+       _type: 'line',
+
+       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 closePath = me._loop;
+               var index, previous, currentVM;
+
+               if (!points.length) {
+                       return;
+               }
+
+               if (me._loop) {
+                       for (index = 0; index < points.length; ++index) {
+                               previous = helpers$1.previousItem(points, index);
+                               // If the line has an open path, shift the point array
+                               if (!points[index]._view.skip && previous._view.skip) {
+                                       points = points.slice(index).concat(points.slice(0, index));
+                                       closePath = spanGaps;
+                                       break;
+                               }
+                       }
+                       // If the line has a close path, add the first point again
+                       if (closePath) {
+                               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();
+
+               // First point moves to it's starting position no matter what
+               currentVM = points[0]._view;
+               if (!currentVM.skip) {
+                       ctx.moveTo(currentVM.x, currentVM.y);
+                       lastDrawnIndex = 0;
+               }
+
+               for (index = 1; index < points.length; ++index) {
+                       currentVM = points[index]._view;
+                       previous = lastDrawnIndex === -1 ? helpers$1.previousItem(points, index) : 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, currentVM);
+                               }
+                               lastDrawnIndex = index;
+                       }
+               }
+
+               if (closePath) {
+                       ctx.closePath();
+               }
+
+               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({
+       _type: 'point',
+
+       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({
+       _type: 'rectangle',
+
+       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 deprecated = helpers$1._deprecated;
+var valueOrDefault$3 = helpers$1.valueOrDefault;
+
+core_defaults._set('bar', {
+       hover: {
+               mode: 'label'
+       },
+
+       scales: {
+               xAxes: [{
+                       type: 'category',
+                       offset: true,
+                       gridLines: {
+                               offsetGridLines: true
+                       }
+               }],
+
+               yAxes: [{
+                       type: 'linear'
+               }]
+       }
+});
+
+core_defaults._set('global', {
+       datasets: {
+               bar: {
+                       categoryPercentage: 0.8,
+                       barPercentage: 0.9
+               }
+       }
+});
+
+/**
+ * Computes the "optimal" sample size to maintain bars equally sized while preventing overlap.
+ * @private
+ */
+function computeMinSampleSize(scale, pixels) {
+       var min = scale._length;
+       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 = scale.getTicks().length; i < ilen; ++i) {
+               curr = scale.getPixelForTick(i);
+               min = i > 0 ? Math.min(min, Math.abs(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 min = helpers$1.isNullOrUndef(thickness)
+               ? computeMinSampleSize(ruler.scale, ruler.pixels)
+               : -1;
+       var size, ratio;
+
+       if (helpers$1.isNullOrUndef(thickness)) {
+               size = 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,
+
+       /**
+        * @private
+        */
+       _dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderSkipped',
+               'borderWidth',
+               'barPercentage',
+               'barThickness',
+               'categoryPercentage',
+               'maxBarThickness',
+               'minBarLength'
+       ],
+
+       initialize: function() {
+               var me = this;
+               var meta, scaleOpts;
+
+               core_datasetController.prototype.initialize.apply(me, arguments);
+
+               meta = me.getMeta();
+               meta.stack = me.getDataset().stack;
+               meta.bar = true;
+
+               scaleOpts = me._getIndexScale().options;
+               deprecated('bar chart', scaleOpts.barPercentage, 'scales.[x/y]Axes.barPercentage', 'dataset.barPercentage');
+               deprecated('bar chart', scaleOpts.barThickness, 'scales.[x/y]Axes.barThickness', 'dataset.barThickness');
+               deprecated('bar chart', scaleOpts.categoryPercentage, 'scales.[x/y]Axes.categoryPercentage', 'dataset.categoryPercentage');
+               deprecated('bar chart', me._getValueScale().options.minBarLength, 'scales.[x/y]Axes.minBarLength', 'dataset.minBarLength');
+               deprecated('bar chart', scaleOpts.maxBarThickness, 'scales.[x/y]Axes.maxBarThickness', 'dataset.maxBarThickness');
+       },
+
+       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._resolveDataElementOptions(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]
+               };
+
+               if (helpers$1.isArray(dataset.data[index])) {
+                       rectangle._model.borderSkipped = null;
+               }
+
+               me._updateElementGeometry(rectangle, index, reset, options);
+
+               rectangle.pivot();
+       },
+
+       /**
+        * @private
+        */
+       _updateElementGeometry: function(rectangle, index, reset, options) {
+               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, options);
+               var ipixels = me.calculateBarIndexPixels(me.index, index, ruler, options);
+
+               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 scale = me._getIndexScale();
+               var metasets = scale._getMatchingVisibleMetas(me._type);
+               var stacked = scale.options.stacked;
+               var ilen = metasets.length;
+               var stacks = [];
+               var i, meta;
+
+               for (i = 0; i < ilen; ++i) {
+                       meta = metasets[i];
+                       // stacked   | meta.stack
+                       //           | found | not found | undefined
+                       // false     |   x   |     x     |     x
+                       // true      |       |     x     |
+                       // undefined |       |     x     |     x
+                       if (stacked === false || stacks.indexOf(meta.stack) === -1 ||
+                               (stacked === undefined && meta.stack === undefined)) {
+                               stacks.push(meta.stack);
+                       }
+                       if (meta.index === last) {
+                               break;
+                       }
+               }
+
+               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 pixels = [];
+               var i, ilen;
+
+               for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) {
+                       pixels.push(scale.getPixelForValue(null, i, me.index));
+               }
+
+               return {
+                       pixels: pixels,
+                       start: scale._startPixel,
+                       end: scale._endPixel,
+                       stackCount: me.getStackCount(),
+                       scale: scale
+               };
+       },
+
+       /**
+        * Note: pixel values are not clamped to the scale area.
+        * @private
+        */
+       calculateBarValuePixels: function(datasetIndex, index, options) {
+               var me = this;
+               var chart = me.chart;
+               var scale = me._getValueScale();
+               var isHorizontal = scale.isHorizontal();
+               var datasets = chart.data.datasets;
+               var metasets = scale._getMatchingVisibleMetas(me._type);
+               var value = scale._parseValue(datasets[datasetIndex].data[index]);
+               var minBarLength = options.minBarLength;
+               var stacked = scale.options.stacked;
+               var stack = me.getMeta().stack;
+               var start = value.start === undefined ? 0 : value.max >= 0 && value.min >= 0 ? value.min : value.max;
+               var length = value.start === undefined ? value.end : value.max >= 0 && value.min >= 0 ? value.max - value.min : value.min - value.max;
+               var ilen = metasets.length;
+               var i, imeta, ivalue, base, head, size, stackLength;
+
+               if (stacked || (stacked === undefined && stack !== undefined)) {
+                       for (i = 0; i < ilen; ++i) {
+                               imeta = metasets[i];
+
+                               if (imeta.index === datasetIndex) {
+                                       break;
+                               }
+
+                               if (imeta.stack === stack) {
+                                       stackLength = scale._parseValue(datasets[imeta.index].data[index]);
+                                       ivalue = stackLength.start === undefined ? stackLength.end : stackLength.min >= 0 && stackLength.max >= 0 ? stackLength.max : stackLength.min;
+
+                                       if ((value.min < 0 && ivalue < 0) || (value.max >= 0 && ivalue > 0)) {
+                                               start += ivalue;
+                                       }
+                               }
+                       }
+               }
+
+               base = scale.getPixelForValue(start);
+               head = scale.getPixelForValue(start + length);
+               size = head - base;
+
+               if (minBarLength !== undefined && Math.abs(size) < minBarLength) {
+                       size = minBarLength;
+                       if (length >= 0 && !isHorizontal || length < 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, options) {
+               var me = this;
+               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(
+                       valueOrDefault$3(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) {
+                       var val = scale._parseValue(dataset.data[i]);
+                       if (!isNaN(val.min) && !isNaN(val.max)) {
+                               rects[i].draw();
+                       }
+               }
+
+               helpers$1.canvas.unclipArea(chart.ctx);
+       },
+
+       /**
+        * @private
+        */
+       _resolveDataElementOptions: function() {
+               var me = this;
+               var values = helpers$1.extend({}, core_datasetController.prototype._resolveDataElementOptions.apply(me, arguments));
+               var indexOpts = me._getIndexScale().options;
+               var valueOpts = me._getValueScale().options;
+
+               values.barPercentage = valueOrDefault$3(indexOpts.barPercentage, values.barPercentage);
+               values.barThickness = valueOrDefault$3(indexOpts.barThickness, values.barThickness);
+               values.categoryPercentage = valueOrDefault$3(indexOpts.categoryPercentage, values.categoryPercentage);
+               values.maxBarThickness = valueOrDefault$3(indexOpts.maxBarThickness, values.maxBarThickness);
+               values.minBarLength = valueOrDefault$3(valueOpts.minBarLength, values.minBarLength);
+
+               return values;
+       }
+
+});
+
+var valueOrDefault$4 = helpers$1.valueOrDefault;
+var resolve$1 = 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,
+
+       /**
+        * @private
+        */
+       _dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderWidth',
+               'hoverBackgroundColor',
+               'hoverBorderColor',
+               'hoverBorderWidth',
+               'hoverRadius',
+               'hitRadius',
+               'pointStyle',
+               'rotation'
+       ],
+
+       /**
+        * @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._resolveDataElementOptions(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$4(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
+               model.borderColor = valueOrDefault$4(options.hoverBorderColor, getHoverColor(options.borderColor));
+               model.borderWidth = valueOrDefault$4(options.hoverBorderWidth, options.borderWidth);
+               model.radius = options.radius + options.hoverRadius;
+       },
+
+       /**
+        * @private
+        */
+       _resolveDataElementOptions: function(point, index) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = me.getDataset();
+               var custom = point.custom || {};
+               var data = dataset.data[index] || {};
+               var values = core_datasetController.prototype._resolveDataElementOptions.apply(me, arguments);
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               // In case values were cached (and thus frozen), we need to clone the values
+               if (me._cachedDataOpts === values) {
+                       values = helpers$1.extend({}, values);
+               }
+
+               // Custom radius resolution
+               values.radius = resolve$1([
+                       custom.radius,
+                       data.r,
+                       me._config.radius,
+                       chart.options.elements.point.radius
+               ], context, index);
+
+               return values;
+       }
+});
+
+var valueOrDefault$5 = helpers$1.valueOrDefault;
+
+var PI$1 = Math.PI;
+var DOUBLE_PI$1 = PI$1 * 2;
+var HALF_PI$1 = PI$1 / 2;
+
+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 list = document.createElement('ul');
+               var data = chart.data;
+               var datasets = data.datasets;
+               var labels = data.labels;
+               var i, ilen, listItem, listItemSpan;
+
+               list.setAttribute('class', chart.id + '-legend');
+               if (datasets.length) {
+                       for (i = 0, ilen = datasets[0].data.length; i < ilen; ++i) {
+                               listItem = list.appendChild(document.createElement('li'));
+                               listItemSpan = listItem.appendChild(document.createElement('span'));
+                               listItemSpan.style.backgroundColor = datasets[0].backgroundColor[i];
+                               if (labels[i]) {
+                                       listItem.appendChild(document.createTextNode(labels[i]));
+                               }
+                       }
+               }
+
+               return list.outerHTML;
+       },
+       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 style = meta.controller.getStyle(i);
+
+                                               return {
+                                                       text: label,
+                                                       fillStyle: style.backgroundColor,
+                                                       strokeStyle: style.borderColor,
+                                                       lineWidth: style.borderWidth,
+                                                       hidden: isNaN(data.datasets[0].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: -HALF_PI$1,
+
+       // The total circumference of the chart.
+       circumference: DOUBLE_PI$1,
+
+       // 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,
+
+       /**
+        * @private
+        */
+       _dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderWidth',
+               'borderAlign',
+               'hoverBackgroundColor',
+               'hoverBorderColor',
+               'hoverBorderWidth',
+       ],
+
+       // 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 ratioX = 1;
+               var ratioY = 1;
+               var offsetX = 0;
+               var offsetY = 0;
+               var meta = me.getMeta();
+               var arcs = meta.data;
+               var cutout = opts.cutoutPercentage / 100 || 0;
+               var circumference = opts.circumference;
+               var chartWeight = me._getRingWeight(me.index);
+               var maxWidth, maxHeight, i, ilen;
+
+               // If the chart's circumference isn't a full circle, calculate size as a ratio of the width/height of the arc
+               if (circumference < DOUBLE_PI$1) {
+                       var startAngle = opts.rotation % DOUBLE_PI$1;
+                       startAngle += startAngle >= PI$1 ? -DOUBLE_PI$1 : startAngle < -PI$1 ? DOUBLE_PI$1 : 0;
+                       var endAngle = startAngle + circumference;
+                       var startX = Math.cos(startAngle);
+                       var startY = Math.sin(startAngle);
+                       var endX = Math.cos(endAngle);
+                       var endY = Math.sin(endAngle);
+                       var contains0 = (startAngle <= 0 && endAngle >= 0) || endAngle >= DOUBLE_PI$1;
+                       var contains90 = (startAngle <= HALF_PI$1 && endAngle >= HALF_PI$1) || endAngle >= DOUBLE_PI$1 + HALF_PI$1;
+                       var contains180 = startAngle === -PI$1 || endAngle >= PI$1;
+                       var contains270 = (startAngle <= -HALF_PI$1 && endAngle >= -HALF_PI$1) || endAngle >= PI$1 + HALF_PI$1;
+                       var minX = contains180 ? -1 : Math.min(startX, startX * cutout, endX, endX * cutout);
+                       var minY = contains270 ? -1 : Math.min(startY, startY * cutout, endY, endY * cutout);
+                       var maxX = contains0 ? 1 : Math.max(startX, startX * cutout, endX, endX * cutout);
+                       var maxY = contains90 ? 1 : Math.max(startY, startY * cutout, endY, endY * cutout);
+                       ratioX = (maxX - minX) / 2;
+                       ratioY = (maxY - minY) / 2;
+                       offsetX = -(maxX + minX) / 2;
+                       offsetY = -(maxY + minY) / 2;
+               }
+
+               for (i = 0, ilen = arcs.length; i < ilen; ++i) {
+                       arcs[i]._options = me._resolveDataElementOptions(arcs[i], i);
+               }
+
+               chart.borderWidth = me.getMaxBorderWidth();
+               maxWidth = (chartArea.right - chartArea.left - chart.borderWidth) / ratioX;
+               maxHeight = (chartArea.bottom - chartArea.top - chart.borderWidth) / ratioY;
+               chart.outerRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);
+               chart.innerRadius = Math.max(chart.outerRadius * cutout, 0);
+               chart.radiusLength = (chart.outerRadius - chart.innerRadius) / (me._getVisibleDatasetWeightTotal() || 1);
+               chart.offsetX = offsetX * chart.outerRadius;
+               chart.offsetY = offsetY * 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 / DOUBLE_PI$1);
+               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 DOUBLE_PI$1 * (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];
+                       if (controller) {
+                               controller._configure();
+                               options = controller._resolveDataElementOptions(arc, i);
+                       } else {
+                               options = 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$5(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
+               model.borderColor = valueOrDefault$5(options.hoverBorderColor, getHoverColor(options.borderColor));
+               model.borderWidth = valueOrDefault$5(options.hoverBorderWidth, options.borderWidth);
+       },
+
+       /**
+        * 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$5(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',
+                       offset: true,
+                       gridLines: {
+                               offsetGridLines: true
+                       }
+               }]
+       },
+
+       elements: {
+               rectangle: {
+                       borderSkipped: 'left'
+               }
+       },
+
+       tooltips: {
+               mode: 'index',
+               axis: 'y'
+       }
+});
+
+core_defaults._set('global', {
+       datasets: {
+               horizontalBar: {
+                       categoryPercentage: 0.8,
+                       barPercentage: 0.9
+               }
+       }
+});
+
+var controller_horizontalBar = controller_bar.extend({
+       /**
+        * @private
+        */
+       _getValueScaleId: function() {
+               return this.getMeta().xAxisID;
+       },
+
+       /**
+        * @private
+        */
+       _getIndexScaleId: function() {
+               return this.getMeta().yAxisID;
+       }
+});
+
+var valueOrDefault$6 = helpers$1.valueOrDefault;
+var resolve$2 = 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'
+               }]
+       }
+});
+
+var controller_line = core_datasetController.extend({
+
+       datasetElementType: elements.Line,
+
+       dataElementType: elements.Point,
+
+       /**
+        * @private
+        */
+       _datasetElementOptions: [
+               'backgroundColor',
+               'borderCapStyle',
+               'borderColor',
+               'borderDash',
+               'borderDashOffset',
+               'borderJoinStyle',
+               'borderWidth',
+               'cubicInterpolationMode',
+               'fill'
+       ],
+
+       /**
+        * @private
+        */
+       _dataElementOptions: {
+               backgroundColor: 'pointBackgroundColor',
+               borderColor: 'pointBorderColor',
+               borderWidth: 'pointBorderWidth',
+               hitRadius: 'pointHitRadius',
+               hoverBackgroundColor: 'pointHoverBackgroundColor',
+               hoverBorderColor: 'pointHoverBorderColor',
+               hoverBorderWidth: 'pointHoverBorderWidth',
+               hoverRadius: 'pointHoverRadius',
+               pointStyle: 'pointStyle',
+               radius: 'pointRadius',
+               rotation: 'pointRotation'
+       },
+
+       update: function(reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var line = meta.dataset;
+               var points = meta.data || [];
+               var options = me.chart.options;
+               var config = me._config;
+               var showLine = me._showLine = valueOrDefault$6(config.showLine, options.showLines);
+               var i, ilen;
+
+               me._xScale = me.getScaleForId(meta.xAxisID);
+               me._yScale = me.getScaleForId(meta.yAxisID);
+
+               // Update Line
+               if (showLine) {
+                       // Compatibility: If the properties are defined with only the old name, use those values
+                       if (config.tension !== undefined && config.lineTension === undefined) {
+                               config.lineTension = config.tension;
+                       }
+
+                       // Utility
+                       line._scale = me._yScale;
+                       line._datasetIndex = me.index;
+                       // Data
+                       line._children = points;
+                       // Model
+                       line._model = me._resolveDatasetElementOptions(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 xScale = me._xScale;
+               var yScale = me._yScale;
+               var lineModel = meta.dataset._model;
+               var x, y;
+
+               var options = me._resolveDataElementOptions(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$6(custom.tension, lineModel ? lineModel.tension : 0),
+                       steppedLine: lineModel ? lineModel.steppedLine : false,
+                       // Tooltip
+                       hitRadius: options.hitRadius
+               };
+       },
+
+       /**
+        * @private
+        */
+       _resolveDatasetElementOptions: function(element) {
+               var me = this;
+               var config = me._config;
+               var custom = element.custom || {};
+               var options = me.chart.options;
+               var lineOptions = options.elements.line;
+               var values = core_datasetController.prototype._resolveDatasetElementOptions.apply(me, arguments);
+
+               // 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$6(config.spanGaps, options.spanGaps);
+               values.tension = valueOrDefault$6(config.lineTension, lineOptions.tension);
+               values.steppedLine = resolve$2([custom.steppedLine, config.steppedLine, lineOptions.stepped]);
+
+               return values;
+       },
+
+       calculatePointY: function(value, index, datasetIndex) {
+               var me = this;
+               var chart = me.chart;
+               var yScale = me._yScale;
+               var sumPos = 0;
+               var sumNeg = 0;
+               var rightValue = +yScale.getRightValue(value);
+               var metasets = chart._getSortedVisibleDatasetMetas();
+               var ilen = metasets.length;
+               var i, ds, dsMeta, stackedRightValue;
+
+               if (yScale.options.stacked) {
+                       for (i = 0; i < ilen; ++i) {
+                               dsMeta = metasets[i];
+                               if (dsMeta.index === datasetIndex) {
+                                       break;
+                               }
+
+                               ds = chart.data.datasets[dsMeta.index];
+                               if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id) {
+                                       stackedRightValue = +yScale.getRightValue(ds.data[index]);
+                                       if (stackedRightValue < 0) {
+                                               sumNeg += stackedRightValue || 0;
+                                       } else {
+                                               sumPos += stackedRightValue || 0;
+                                       }
+                               }
+                       }
+
+                       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 i = 0;
+               var ilen = points.length;
+               var halfBorderWidth;
+
+               if (me._showLine) {
+                       halfBorderWidth = (meta.dataset._model.borderWidth || 0) / 2;
+
+                       helpers$1.canvas.clipArea(chart.ctx, {
+                               left: area.left - halfBorderWidth,
+                               right: area.right + halfBorderWidth,
+                               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$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);
+       },
+});
+
+var resolve$3 = 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 list = document.createElement('ul');
+               var data = chart.data;
+               var datasets = data.datasets;
+               var labels = data.labels;
+               var i, ilen, listItem, listItemSpan;
+
+               list.setAttribute('class', chart.id + '-legend');
+               if (datasets.length) {
+                       for (i = 0, ilen = datasets[0].data.length; i < ilen; ++i) {
+                               listItem = list.appendChild(document.createElement('li'));
+                               listItemSpan = listItem.appendChild(document.createElement('span'));
+                               listItemSpan.style.backgroundColor = datasets[0].backgroundColor[i];
+                               if (labels[i]) {
+                                       listItem.appendChild(document.createTextNode(labels[i]));
+                               }
+                       }
+               }
+
+               return list.outerHTML;
+       },
+       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 style = meta.controller.getStyle(i);
+
+                                               return {
+                                                       text: label,
+                                                       fillStyle: style.backgroundColor,
+                                                       strokeStyle: style.borderColor,
+                                                       lineWidth: style.borderWidth,
+                                                       hidden: isNaN(data.datasets[0].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,
+
+       /**
+        * @private
+        */
+       _dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderWidth',
+               'borderAlign',
+               'hoverBackgroundColor',
+               'hoverBorderColor',
+               'hoverBorderWidth',
+       ],
+
+       /**
+        * @private
+        */
+       _getIndexScaleId: function() {
+               return this.chart.scale.id;
+       },
+
+       /**
+        * @private
+        */
+       _getValueScaleId: function() {
+               return this.chart.scale.id;
+       },
+
+       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._resolveDataElementOptions(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
+        */
+       _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$3([
+                       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$7 = helpers$1.valueOrDefault;
+
+core_defaults._set('radar', {
+       spanGaps: false,
+       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,
+
+       /**
+        * @private
+        */
+       _datasetElementOptions: [
+               'backgroundColor',
+               'borderWidth',
+               'borderColor',
+               'borderCapStyle',
+               'borderDash',
+               'borderDashOffset',
+               'borderJoinStyle',
+               'fill'
+       ],
+
+       /**
+        * @private
+        */
+       _dataElementOptions: {
+               backgroundColor: 'pointBackgroundColor',
+               borderColor: 'pointBorderColor',
+               borderWidth: 'pointBorderWidth',
+               hitRadius: 'pointHitRadius',
+               hoverBackgroundColor: 'pointHoverBackgroundColor',
+               hoverBorderColor: 'pointHoverBorderColor',
+               hoverBorderWidth: 'pointHoverBorderWidth',
+               hoverRadius: 'pointHoverRadius',
+               pointStyle: 'pointStyle',
+               radius: 'pointRadius',
+               rotation: 'pointRotation'
+       },
+
+       /**
+        * @private
+        */
+       _getIndexScaleId: function() {
+               return this.chart.scale.id;
+       },
+
+       /**
+        * @private
+        */
+       _getValueScaleId: function() {
+               return this.chart.scale.id;
+       },
+
+       update: function(reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var line = meta.dataset;
+               var points = meta.data || [];
+               var scale = me.chart.scale;
+               var config = me._config;
+               var i, ilen;
+
+               // Compatibility: If the properties are defined with only the old name, use those values
+               if (config.tension !== undefined && config.lineTension === undefined) {
+                       config.lineTension = config.tension;
+               }
+
+               // Utility
+               line._scale = scale;
+               line._datasetIndex = me.index;
+               // Data
+               line._children = points;
+               line._loop = true;
+               // Model
+               line._model = me._resolveDatasetElementOptions(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._resolveDataElementOptions(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$7(custom.tension, lineModel ? lineModel.tension : 0),
+
+                       // Tooltip
+                       hitRadius: options.hitRadius
+               };
+       },
+
+       /**
+        * @private
+        */
+       _resolveDatasetElementOptions: function() {
+               var me = this;
+               var config = me._config;
+               var options = me.chart.options;
+               var values = core_datasetController.prototype._resolveDatasetElementOptions.apply(me, arguments);
+
+               values.spanGaps = valueOrDefault$7(config.spanGaps, options.spanGaps);
+               values.tension = valueOrDefault$7(config.lineTension, options.elements.line.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;
+
+               // Only consider points that are drawn in case the spanGaps option is used
+               if (meta.dataset._model.spanGaps) {
+                       points = points.filter(function(pt) {
+                               return !pt._model.skip;
+                       });
+               }
+
+               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$7(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
+               model.borderColor = valueOrDefault$7(options.hoverBorderColor, getHoverColor(options.borderColor));
+               model.borderWidth = valueOrDefault$7(options.hoverBorderWidth, options.borderWidth);
+               model.radius = valueOrDefault$7(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'
+               }]
+       },
+
+       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 + ')';
+                       }
+               }
+       }
+});
+
+core_defaults._set('global', {
+       datasets: {
+               scatter: {
+                       showLine: false
+               }
+       }
+});
+
+// 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 metasets = chart._getSortedVisibleDatasetMetas();
+       var metadata, i, j, ilen, jlen, element;
+
+       for (i = 0, ilen = metasets.length; i < ilen; ++i) {
+               metadata = metasets[i].data;
+               for (j = 0, jlen = metadata.length; j < jlen; ++j) {
+                       element = metadata[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._getSortedVisibleDatasetMetas().forEach(function(meta) {
+               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;
+               }
+       }
+};
+
+var extend = helpers$1.extend;
+
+function filterByPosition(array, position) {
+       return helpers$1.where(array, function(v) {
+               return v.pos === position;
+       });
+}
+
+function sortByWeight(array, reverse) {
+       return array.sort(function(a, b) {
+               var v0 = reverse ? b : a;
+               var v1 = reverse ? a : b;
+               return v0.weight === v1.weight ?
+                       v0.index - v1.index :
+                       v0.weight - v1.weight;
+       });
+}
+
+function wrapBoxes(boxes) {
+       var layoutBoxes = [];
+       var i, ilen, box;
+
+       for (i = 0, ilen = (boxes || []).length; i < ilen; ++i) {
+               box = boxes[i];
+               layoutBoxes.push({
+                       index: i,
+                       box: box,
+                       pos: box.position,
+                       horizontal: box.isHorizontal(),
+                       weight: box.weight
+               });
+       }
+       return layoutBoxes;
+}
+
+function setLayoutDims(layouts, params) {
+       var i, ilen, layout;
+       for (i = 0, ilen = layouts.length; i < ilen; ++i) {
+               layout = layouts[i];
+               // store width used instead of chartArea.w in fitBoxes
+               layout.width = layout.horizontal
+                       ? layout.box.fullWidth && params.availableWidth
+                       : params.vBoxMaxWidth;
+               // store height used instead of chartArea.h in fitBoxes
+               layout.height = layout.horizontal && params.hBoxMaxHeight;
+       }
+}
+
+function buildLayoutBoxes(boxes) {
+       var layoutBoxes = wrapBoxes(boxes);
+       var left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true);
+       var right = sortByWeight(filterByPosition(layoutBoxes, 'right'));
+       var top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true);
+       var bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom'));
+
+       return {
+               leftAndTop: left.concat(top),
+               rightAndBottom: right.concat(bottom),
+               chartArea: filterByPosition(layoutBoxes, 'chartArea'),
+               vertical: left.concat(right),
+               horizontal: top.concat(bottom)
+       };
+}
+
+function getCombinedMax(maxPadding, chartArea, a, b) {
+       return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]);
+}
+
+function updateDims(chartArea, params, layout) {
+       var box = layout.box;
+       var maxPadding = chartArea.maxPadding;
+       var newWidth, newHeight;
+
+       if (layout.size) {
+               // this layout was already counted for, lets first reduce old size
+               chartArea[layout.pos] -= layout.size;
+       }
+       layout.size = layout.horizontal ? box.height : box.width;
+       chartArea[layout.pos] += layout.size;
+
+       if (box.getPadding) {
+               var boxPadding = box.getPadding();
+               maxPadding.top = Math.max(maxPadding.top, boxPadding.top);
+               maxPadding.left = Math.max(maxPadding.left, boxPadding.left);
+               maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom);
+               maxPadding.right = Math.max(maxPadding.right, boxPadding.right);
+       }
+
+       newWidth = params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right');
+       newHeight = params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom');
+
+       if (newWidth !== chartArea.w || newHeight !== chartArea.h) {
+               chartArea.w = newWidth;
+               chartArea.h = newHeight;
+
+               // return true if chart area changed in layout's direction
+               return layout.horizontal ? newWidth !== chartArea.w : newHeight !== chartArea.h;
+       }
+}
+
+function handleMaxPadding(chartArea) {
+       var maxPadding = chartArea.maxPadding;
+
+       function updatePos(pos) {
+               var change = Math.max(maxPadding[pos] - chartArea[pos], 0);
+               chartArea[pos] += change;
+               return change;
+       }
+       chartArea.y += updatePos('top');
+       chartArea.x += updatePos('left');
+       updatePos('right');
+       updatePos('bottom');
+}
+
+function getMargins(horizontal, chartArea) {
+       var maxPadding = chartArea.maxPadding;
+
+       function marginForPositions(positions) {
+               var margin = {left: 0, top: 0, right: 0, bottom: 0};
+               positions.forEach(function(pos) {
+                       margin[pos] = Math.max(chartArea[pos], maxPadding[pos]);
+               });
+               return margin;
+       }
+
+       return horizontal
+               ? marginForPositions(['left', 'right'])
+               : marginForPositions(['top', 'bottom']);
+}
+
+function fitBoxes(boxes, chartArea, params) {
+       var refitBoxes = [];
+       var i, ilen, layout, box, refit, changed;
+
+       for (i = 0, ilen = boxes.length; i < ilen; ++i) {
+               layout = boxes[i];
+               box = layout.box;
+
+               box.update(
+                       layout.width || chartArea.w,
+                       layout.height || chartArea.h,
+                       getMargins(layout.horizontal, chartArea)
+               );
+               if (updateDims(chartArea, params, layout)) {
+                       changed = true;
+                       if (refitBoxes.length) {
+                               // Dimensions changed and there were non full width boxes before this
+                               // -> we have to refit those
+                               refit = true;
+                       }
+               }
+               if (!box.fullWidth) { // fullWidth boxes don't need to be re-fitted in any case
+                       refitBoxes.push(layout);
+               }
+       }
+
+       return refit ? fitBoxes(refitBoxes, chartArea, params) || changed : changed;
+}
+
+function placeBoxes(boxes, chartArea, params) {
+       var userPadding = params.padding;
+       var x = chartArea.x;
+       var y = chartArea.y;
+       var i, ilen, layout, box;
+
+       for (i = 0, ilen = boxes.length; i < ilen; ++i) {
+               layout = boxes[i];
+               box = layout.box;
+               if (layout.horizontal) {
+                       box.left = box.fullWidth ? userPadding.left : chartArea.left;
+                       box.right = box.fullWidth ? params.outerWidth - userPadding.right : chartArea.left + chartArea.w;
+                       box.top = y;
+                       box.bottom = y + box.height;
+                       box.width = box.right - box.left;
+                       y = box.bottom;
+               } else {
+                       box.left = x;
+                       box.right = x + box.width;
+                       box.top = chartArea.top;
+                       box.bottom = chartArea.top + chartArea.h;
+                       box.height = box.bottom - box.top;
+                       x = box.right;
+               }
+       }
+
+       chartArea.x = x;
+       chartArea.y = y;
+}
+
+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;
+               item._layers = item._layers || function() {
+                       return [{
+                               z: 0,
+                               draw: function() {
+                                       item.draw.apply(item, arguments);
+                               }
+                       }];
+               };
+
+               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 availableWidth = width - padding.width;
+               var availableHeight = height - padding.height;
+               var boxes = buildLayoutBoxes(chart.boxes);
+               var verticalBoxes = boxes.vertical;
+               var horizontalBoxes = boxes.horizontal;
+
+               // 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)                   |
+               // |----------------------------------------------------|
+               //
+
+               var params = Object.freeze({
+                       outerWidth: width,
+                       outerHeight: height,
+                       padding: padding,
+                       availableWidth: availableWidth,
+                       vBoxMaxWidth: availableWidth / 2 / verticalBoxes.length,
+                       hBoxMaxHeight: availableHeight / 2
+               });
+               var chartArea = extend({
+                       maxPadding: extend({}, padding),
+                       w: availableWidth,
+                       h: availableHeight,
+                       x: padding.left,
+                       y: padding.top
+               }, padding);
+
+               setLayoutDims(verticalBoxes.concat(horizontalBoxes), params);
+
+               // First fit vertical boxes
+               fitBoxes(verticalBoxes, chartArea, params);
+
+               // Then fit horizontal boxes
+               if (fitBoxes(horizontalBoxes, chartArea, params)) {
+                       // if the area changed, re-fit vertical boxes
+                       fitBoxes(verticalBoxes, chartArea, params);
+               }
+
+               handleMaxPadding(chartArea);
+
+               // Finally place the boxes to correct coordinates
+               placeBoxes(boxes.leftAndTop, chartArea, params);
+
+               // Move to opposite side of chart
+               chartArea.x += chartArea.w;
+               chartArea.y += chartArea.h;
+
+               placeBoxes(boxes.rightAndBottom, chartArea, params);
+
+               chart.chartArea = {
+                       left: chartArea.left,
+                       top: chartArea.top,
+                       right: chartArea.left + chartArea.w,
+                       bottom: chartArea.top + chartArea.h
+               };
+
+               // Finally update boxes in chartArea (radial scale for example)
+               helpers$1.each(boxes.chartArea, function(layout) {
+                       var box = layout.box;
+                       extend(box, chart.chartArea);
+                       box.update(chartArea.w, chartArea.h);
+               });
+       }
+};
+
+/**
+ * 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 globalThis !== 'undefined' ? globalThis : 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);
+       }
+}
+
+/**
+ * Injects CSS styles inline if the styles are not already present.
+ * @param {HTMLDocument|ShadowRoot} rootNode - the node to contain the <style>.
+ * @param {string} css - the CSS to be injected.
+ */
+function injectCSS(rootNode, css) {
+       // https://stackoverflow.com/q/3922139
+       var expando = rootNode[EXPANDO_KEY] || (rootNode[EXPANDO_KEY] = {});
+       if (!expando.containsStyles) {
+               expando.containsStyles = true;
+               css = '/* Chart.js */\n' + css;
+               var style = document.createElement('style');
+               style.setAttribute('type', 'text/css');
+               style.appendChild(document.createTextNode(css));
+               rootNode.appendChild(style);
+       }
+}
+
+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',
+
+       /**
+        * Initializes resources that depend on platform options.
+        * @param {HTMLCanvasElement} canvas - The Canvas element.
+        * @private
+        */
+       _ensureLoaded: function(canvas) {
+               if (!this.disableCSSInjection) {
+                       // If the canvas is in a shadow DOM, then the styles must also be inserted
+                       // into the same shadow DOM.
+                       // https://github.com/chartjs/Chart.js/issues/5763
+                       var root = canvas.getRootNode();
+                       var targetNode = root.host ? root : document.head;
+                       injectCSS(targetNode, 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');
+
+               // `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) {
+                       // Load platform resources on first chart creation, to make it possible to
+                       // import the library before setting platform options.
+                       this._ensureLoaded(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$8 = helpers$1.valueOrDefault;
+var getRtlHelper = helpers$1.rtl.getRtlAdapter;
+
+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,
+
+               // Drawing direction and text direction
+               rtl: tooltipOpts.rtl,
+               textDirection: tooltipOpts.textDirection,
+
+               // Body
+               bodyFontColor: tooltipOpts.bodyFontColor,
+               _bodyFontFamily: valueOrDefault$8(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
+               _bodyFontStyle: valueOrDefault$8(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
+               _bodyAlign: tooltipOpts.bodyAlign,
+               bodyFontSize: valueOrDefault$8(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
+               bodySpacing: tooltipOpts.bodySpacing,
+
+               // Title
+               titleFontColor: tooltipOpts.titleFontColor,
+               _titleFontFamily: valueOrDefault$8(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
+               _titleFontStyle: valueOrDefault$8(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
+               titleFontSize: valueOrDefault$8(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
+               _titleAlign: tooltipOpts.titleAlign,
+               titleSpacing: tooltipOpts.titleSpacing,
+               titleMarginBottom: tooltipOpts.titleMarginBottom,
+
+               // Footer
+               footerFontColor: tooltipOpts.footerFontColor,
+               _footerFontFamily: valueOrDefault$8(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
+               _footerFontStyle: valueOrDefault$8(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
+               footerFontSize: valueOrDefault$8(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$4 = 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;
+               var length = title.length;
+               var titleFontSize, titleSpacing, i;
+
+               if (length) {
+                       var rtlHelper = getRtlHelper(vm.rtl, vm.x, vm.width);
+
+                       pt.x = getAlignedX(vm, vm._titleAlign);
+
+                       ctx.textAlign = rtlHelper.textAlign(vm._titleAlign);
+                       ctx.textBaseline = 'middle';
+
+                       titleFontSize = vm.titleFontSize;
+                       titleSpacing = vm.titleSpacing;
+
+                       ctx.fillStyle = vm.titleFontColor;
+                       ctx.font = helpers$1.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
+
+                       for (i = 0; i < length; ++i) {
+                               ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFontSize / 2);
+                               pt.y += titleFontSize + titleSpacing; // Line Height and spacing
+
+                               if (i + 1 === 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 xLinePadding = 0;
+               var colorX = drawColorBoxes ? getAlignedX(vm, 'left') : 0;
+
+               var rtlHelper = getRtlHelper(vm.rtl, vm.x, vm.width);
+
+               var fillLineOfText = function(line) {
+                       ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyFontSize / 2);
+                       pt.y += bodyFontSize + bodySpacing;
+               };
+
+               var bodyItem, textColor, labelColors, lines, i, j, ilen, jlen;
+               var bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign);
+
+               ctx.textAlign = bodyAlign;
+               ctx.textBaseline = 'middle';
+               ctx.font = helpers$1.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
+
+               pt.x = getAlignedX(vm, bodyAlignForCalculation);
+
+               // Before body lines
+               ctx.fillStyle = vm.bodyFontColor;
+               helpers$1.each(vm.beforeBody, fillLineOfText);
+
+               xLinePadding = drawColorBoxes && bodyAlignForCalculation !== 'right'
+                       ? bodyAlign === 'center' ? (bodyFontSize / 2 + 1) : (bodyFontSize + 2)
+                       : 0;
+
+               // Draw body lines now
+               for (i = 0, ilen = body.length; i < ilen; ++i) {
+                       bodyItem = body[i];
+                       textColor = vm.labelTextColors[i];
+                       labelColors = vm.labelColors[i];
+
+                       ctx.fillStyle = textColor;
+                       helpers$1.each(bodyItem.before, fillLineOfText);
+
+                       lines = bodyItem.lines;
+                       for (j = 0, jlen = lines.length; j < jlen; ++j) {
+                               // Draw Legend-like boxes if needed
+                               if (drawColorBoxes) {
+                                       var rtlColorX = rtlHelper.x(colorX);
+
+                                       // Fill a white rect so that colours merge nicely if the opacity is < 1
+                                       ctx.fillStyle = vm.legendColorBackground;
+                                       ctx.fillRect(rtlHelper.leftForLtr(rtlColorX, bodyFontSize), pt.y, bodyFontSize, bodyFontSize);
+
+                                       // Border
+                                       ctx.lineWidth = 1;
+                                       ctx.strokeStyle = labelColors.borderColor;
+                                       ctx.strokeRect(rtlHelper.leftForLtr(rtlColorX, bodyFontSize), pt.y, bodyFontSize, bodyFontSize);
+
+                                       // Inner square
+                                       ctx.fillStyle = labelColors.backgroundColor;
+                                       ctx.fillRect(rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), bodyFontSize - 2), pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
+                                       ctx.fillStyle = textColor;
+                               }
+
+                               fillLineOfText(lines[j]);
+                       }
+
+                       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;
+               var length = footer.length;
+               var footerFontSize, i;
+
+               if (length) {
+                       var rtlHelper = getRtlHelper(vm.rtl, vm.x, vm.width);
+
+                       pt.x = getAlignedX(vm, vm._footerAlign);
+                       pt.y += vm.footerMarginTop;
+
+                       ctx.textAlign = rtlHelper.textAlign(vm._footerAlign);
+                       ctx.textBaseline = 'middle';
+
+                       footerFontSize = vm.footerFontSize;
+
+                       ctx.fillStyle = vm.footerFontColor;
+                       ctx.font = helpers$1.fontString(footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
+
+                       for (i = 0; i < length; ++i) {
+                               ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFontSize / 2);
+                               pt.y += 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;
+
+                       helpers$1.rtl.overrideTextDirection(ctx, vm.textDirection);
+
+                       // Titles
+                       this.drawTitle(pt, vm, ctx);
+
+                       // Body
+                       this.drawBody(pt, vm, ctx);
+
+                       // Footer
+                       this.drawFooter(pt, vm, ctx);
+
+                       helpers$1.rtl.restoreTextDirection(ctx, vm.textDirection);
+
+                       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);
+                       if (options.reverse) {
+                               me._active.reverse();
+                       }
+               }
+
+               // 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$4;
+core_tooltip.positioners = positioners_1;
+
+var valueOrDefault$9 = 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$9(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 nextAvailableScaleId(axesOpts, prefix, index) {
+       var id;
+       var hasId = function(obj) {
+               return obj.id === id;
+       };
+
+       do {
+               id = prefix + index++;
+       } while (helpers$1.findIndex(axesOpts, hasId) >= 0);
+
+       return id;
+}
+
+function positionIsHorizontal(position) {
+       return position === 'top' || position === 'bottom';
+}
+
+function compare2Level(l1, l2) {
+       return function(a, b) {
+               return a[l1] === b[l1]
+                       ? a[l2] - b[l2]
+                       : a[l1] - b[l1];
+       };
+}
+
+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;
+               me._layers = [];
+
+               /**
+                * 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);
+               }
+
+               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) {
+                       if (!xAxisOptions.id) {
+                               xAxisOptions.id = nextAvailableScaleId(scalesOptions.xAxes, 'x-axis-', index);
+                       }
+               });
+
+               helpers$1.each(scalesOptions.yAxes, function(yAxisOptions, index) {
+                       if (!yAxisOptions.id) {
+                               yAxisOptions.id = nextAvailableScaleId(scalesOptions.yAxes, '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$9(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 = [];
+               var datasets = me.data.datasets;
+               var i, ilen;
+
+               for (i = 0, ilen = datasets.length; i < ilen; i++) {
+                       var dataset = datasets[i];
+                       var meta = me.getDatasetMeta(i);
+                       var type = dataset.type || me.config.type;
+
+                       if (meta.type && meta.type !== type) {
+                               me.destroyDatasetMeta(i);
+                               meta = me.getDatasetMeta(i);
+                       }
+                       meta.type = type;
+                       meta.order = dataset.order || 0;
+                       meta.index = i;
+
+                       if (meta.controller) {
+                               meta.controller.updateIndex(i);
+                               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, i);
+                               newControllers.push(meta.controller);
+                       }
+               }
+
+               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;
+               var i, ilen;
+
+               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
+               for (i = 0, ilen = me.data.datasets.length; i < ilen; i++) {
+                       me.getDatasetMeta(i).controller.buildOrUpdateElements();
+               }
+
+               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');
+
+               me._layers.sort(compare2Level('z', '_idx'));
+
+               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);
+
+               me._layers = [];
+               helpers$1.each(me.boxes, function(box) {
+                       // _configure is called twice, once in core.scale.update and once here.
+                       // Here the boxes are fully updated and at their final positions.
+                       if (box._configure) {
+                               box._configure();
+                       }
+                       me._layers.push.apply(me._layers, box._layers());
+               }, me);
+
+               me._layers.forEach(function(item, index) {
+                       item._idx = index;
+               });
+
+               /**
+                * 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$9(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;
+               var i, layers;
+
+               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;
+               }
+
+               // Because of plugin hooks (before/afterDatasetsDraw), datasets can't
+               // currently be part of layers. Instead, we draw
+               // layers <= 0 before(default, backward compat), and the rest after
+               layers = me._layers;
+               for (i = 0; i < layers.length && layers[i].z <= 0; ++i) {
+                       layers[i].draw(me.chartArea);
+               }
+
+               me.drawDatasets(easingValue);
+
+               // Rest of layers
+               for (; i < layers.length; ++i) {
+                       layers[i].draw(me.chartArea);
+               }
+
+               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);
+       },
+
+       /**
+        * @private
+        */
+       _getSortedDatasetMetas: function(filterVisible) {
+               var me = this;
+               var datasets = me.data.datasets || [];
+               var result = [];
+               var i, ilen;
+
+               for (i = 0, ilen = datasets.length; i < ilen; ++i) {
+                       if (!filterVisible || me.isDatasetVisible(i)) {
+                               result.push(me.getDatasetMeta(i));
+                       }
+               }
+
+               result.sort(compare2Level('order', 'index'));
+
+               return result;
+       },
+
+       /**
+        * @private
+        */
+       _getSortedVisibleDatasetMetas: function() {
+               return this._getSortedDatasetMetas(true);
+       },
+
+       /**
+        * 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;
+               var metasets, i;
+
+               if (core_plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) {
+                       return;
+               }
+
+               metasets = me._getSortedVisibleDatasetMetas();
+               for (i = metasets.length - 1; i >= 0; --i) {
+                       me.drawDataset(metasets[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(meta, easingValue) {
+               var me = this;
+               var args = {
+                       meta: meta,
+                       index: meta.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,
+                               order: dataset.order || 0,
+                               index: datasetIndex
+                       };
+               }
+
+               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 prefix = enabled ? 'set' : 'remove';
+               var element, i, ilen;
+
+               for (i = 0, ilen = elements.length; i < ilen; ++i) {
+                       element = elements[i];
+                       if (element) {
+                               this.getDatasetMeta(element._datasetIndex).controller[prefix + 'HoverStyle'](element);
+                       }
+               }
+
+               if (mode === 'dataset') {
+                       this.getDatasetMeta(elements[0]._datasetIndex).controller['_' + prefix + 'DatasetHoverStyle']();
+               }
+       },
+
+       /**
+        * @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.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;
+               var ilen = arrayOfThings.length;
+               var i, j, jlen, thing, nestedThing;
+               for (i = 0; i < ilen; i++) {
+                       thing = arrayOfThings[i];
+
+                       // 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?
+                               for (j = 0, jlen = thing.length; j < jlen; j++) {
+                                       nestedThing = thing[j];
+                                       // 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 (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;
+       };
+
+       /**
+        * @deprecated
+        */
+       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));
+                                       var numExponential = Math.floor(logTick) - Math.floor(logDelta);
+                                       numExponential = Math.max(Math.min(numExponential, 20), 0);
+                                       tickString = tickValue.toExponential(numExponential);
+                               } 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 isArray = helpers$1.isArray;
+var isNullOrUndef = helpers$1.isNullOrUndef;
+var valueOrDefault$a = 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: {}
+       }
+});
+
+/** Returns a new array containing numItems from arr */
+function sample(arr, numItems) {
+       var result = [];
+       var increment = arr.length / numItems;
+       var i = 0;
+       var len = arr.length;
+
+       for (; i < len; i += increment) {
+               result.push(arr[Math.floor(i)]);
+       }
+       return result;
+}
+
+function getPixelForGridLine(scale, index, offsetGridLines) {
+       var length = scale.getTicks().length;
+       var validIndex = Math.min(index, length - 1);
+       var lineValue = scale.getPixelForTick(validIndex);
+       var start = scale._startPixel;
+       var end = scale._endPixel;
+       var epsilon = 1e-6; // 1e-6 is margin in pixels for accumulated error.
+       var offset;
+
+       if (offsetGridLines) {
+               if (length === 1) {
+                       offset = Math.max(lineValue - start, end - lineValue);
+               } else if (index === 0) {
+                       offset = (scale.getPixelForTick(1) - lineValue) / 2;
+               } else {
+                       offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2;
+               }
+               lineValue += validIndex < index ? offset : -offset;
+
+               // Return undefined if the pixel is out of the range
+               if (lineValue < start - epsilon || lineValue > end + epsilon) {
+                       return;
+               }
+       }
+       return lineValue;
+}
+
+function garbageCollect(caches, length) {
+       helpers$1.each(caches, function(cache) {
+               var gc = cache.gc;
+               var gcLen = gc.length / 2;
+               var i;
+               if (gcLen > length) {
+                       for (i = 0; i < gcLen; ++i) {
+                               delete cache.data[gc[i]];
+                       }
+                       gc.splice(0, gcLen);
+               }
+       });
+}
+
+/**
+ * Returns {width, height, offset} objects for the first, last, widest, highest tick
+ * labels where offset indicates the anchor point offset from the top in pixels.
+ */
+function computeLabelSizes(ctx, tickFonts, ticks, caches) {
+       var length = ticks.length;
+       var widths = [];
+       var heights = [];
+       var offsets = [];
+       var i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel, widest, highest;
+
+       for (i = 0; i < length; ++i) {
+               label = ticks[i].label;
+               tickFont = ticks[i].major ? tickFonts.major : tickFonts.minor;
+               ctx.font = fontString = tickFont.string;
+               cache = caches[fontString] = caches[fontString] || {data: {}, gc: []};
+               lineHeight = tickFont.lineHeight;
+               width = height = 0;
+               // Undefined labels and arrays should not be measured
+               if (!isNullOrUndef(label) && !isArray(label)) {
+                       width = helpers$1.measureText(ctx, cache.data, cache.gc, width, label);
+                       height = lineHeight;
+               } else if (isArray(label)) {
+                       // if it is an array let's measure each element
+                       for (j = 0, jlen = label.length; j < jlen; ++j) {
+                               nestedLabel = label[j];
+                               // Undefined labels and arrays should not be measured
+                               if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) {
+                                       width = helpers$1.measureText(ctx, cache.data, cache.gc, width, nestedLabel);
+                                       height += lineHeight;
+                               }
+                       }
+               }
+               widths.push(width);
+               heights.push(height);
+               offsets.push(lineHeight / 2);
+       }
+       garbageCollect(caches, length);
+
+       widest = widths.indexOf(Math.max.apply(null, widths));
+       highest = heights.indexOf(Math.max.apply(null, heights));
+
+       function valueAt(idx) {
+               return {
+                       width: widths[idx] || 0,
+                       height: heights[idx] || 0,
+                       offset: offsets[idx] || 0
+               };
+       }
+
+       return {
+               first: valueAt(0),
+               last: valueAt(length - 1),
+               widest: valueAt(widest),
+               highest: valueAt(highest)
+       };
+}
+
+function getTickMarkLength(options) {
+       return options.drawTicks ? options.tickMarkLength : 0;
+}
+
+function getScaleLabelHeight(options) {
+       var font, padding;
+
+       if (!options.display) {
+               return 0;
+       }
+
+       font = helpers$1.options._parseFont(options);
+       padding = helpers$1.options.toPadding(options.padding);
+
+       return font.lineHeight + padding.height;
+}
+
+function parseFontOptions(options, nestedOpts) {
+       return helpers$1.extend(helpers$1.options._parseFont({
+               fontFamily: valueOrDefault$a(nestedOpts.fontFamily, options.fontFamily),
+               fontSize: valueOrDefault$a(nestedOpts.fontSize, options.fontSize),
+               fontStyle: valueOrDefault$a(nestedOpts.fontStyle, options.fontStyle),
+               lineHeight: valueOrDefault$a(nestedOpts.lineHeight, options.lineHeight)
+       }), {
+               color: helpers$1.options.resolve([nestedOpts.fontColor, options.fontColor, core_defaults.global.defaultFontColor])
+       });
+}
+
+function parseTickFontOptions(options) {
+       var minor = parseFontOptions(options, options.minor);
+       var major = options.major.enabled ? parseFontOptions(options, options.major) : minor;
+
+       return {minor: minor, major: major};
+}
+
+function nonSkipped(ticksToFilter) {
+       var filtered = [];
+       var item, index, len;
+       for (index = 0, len = ticksToFilter.length; index < len; ++index) {
+               item = ticksToFilter[index];
+               if (typeof item._index !== 'undefined') {
+                       filtered.push(item);
+               }
+       }
+       return filtered;
+}
+
+function getEvenSpacing(arr) {
+       var len = arr.length;
+       var i, diff;
+
+       if (len < 2) {
+               return false;
+       }
+
+       for (diff = arr[0], i = 1; i < len; ++i) {
+               if (arr[i] - arr[i - 1] !== diff) {
+                       return false;
+               }
+       }
+       return diff;
+}
+
+function calculateSpacing(majorIndices, ticks, axisLength, ticksLimit) {
+       var evenMajorSpacing = getEvenSpacing(majorIndices);
+       var spacing = (ticks.length - 1) / ticksLimit;
+       var factors, factor, i, ilen;
+
+       // If the major ticks are evenly spaced apart, place the minor ticks
+       // so that they divide the major ticks into even chunks
+       if (!evenMajorSpacing) {
+               return Math.max(spacing, 1);
+       }
+
+       factors = helpers$1.math._factorize(evenMajorSpacing);
+       for (i = 0, ilen = factors.length - 1; i < ilen; i++) {
+               factor = factors[i];
+               if (factor > spacing) {
+                       return factor;
+               }
+       }
+       return Math.max(spacing, 1);
+}
+
+function getMajorIndices(ticks) {
+       var result = [];
+       var i, ilen;
+       for (i = 0, ilen = ticks.length; i < ilen; i++) {
+               if (ticks[i].major) {
+                       result.push(i);
+               }
+       }
+       return result;
+}
+
+function skipMajors(ticks, majorIndices, spacing) {
+       var count = 0;
+       var next = majorIndices[0];
+       var i, tick;
+
+       spacing = Math.ceil(spacing);
+       for (i = 0; i < ticks.length; i++) {
+               tick = ticks[i];
+               if (i === next) {
+                       tick._index = i;
+                       count++;
+                       next = majorIndices[count * spacing];
+               } else {
+                       delete tick.label;
+               }
+       }
+}
+
+function skip(ticks, spacing, majorStart, majorEnd) {
+       var start = valueOrDefault$a(majorStart, 0);
+       var end = Math.min(valueOrDefault$a(majorEnd, ticks.length), ticks.length);
+       var count = 0;
+       var length, i, tick, next;
+
+       spacing = Math.ceil(spacing);
+       if (majorEnd) {
+               length = majorEnd - majorStart;
+               spacing = length / Math.floor(length / spacing);
+       }
+
+       next = start;
+
+       while (next < 0) {
+               count++;
+               next = Math.round(start + count * spacing);
+       }
+
+       for (i = Math.max(start, 0); i < end; i++) {
+               tick = ticks[i];
+               if (i === next) {
+                       tick._index = i;
+                       count++;
+                       next = Math.round(start + count * spacing);
+               } else {
+                       delete tick.label;
+               }
+       }
+}
+
+var Scale = core_element.extend({
+
+       zeroLineIndex: 0,
+
+       /**
+        * 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;
+       },
+
+       /**
+       * @private
+       */
+       _getLabels: function() {
+               var data = this.chart.data;
+               return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels;
+       },
+
+       // 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
+
+       /**
+        * Provided for backward compatibility, not available anymore
+        * @function Chart.Scale.mergeTicksOptions
+        * @deprecated since version 2.8.0
+        * @todo remove at version 3
+        */
+       mergeTicksOptions: function() {
+               // noop
+       },
+
+       beforeUpdate: function() {
+               helpers$1.callback(this.options.beforeUpdate, [this]);
+       },
+
+       /**
+        * @param {number} maxWidth - the max width in pixels
+        * @param {number} maxHeight - the max height in pixels
+        * @param {object} margins - the space between the edge of the other scales and edge of the chart
+        *   This space comes from two sources:
+        *     - padding - space that's required to show the labels at the edges of the scale
+        *     - thickness of scales or legends in another orientation
+        */
+       update: function(maxWidth, maxHeight, margins) {
+               var me = this;
+               var tickOpts = me.options.ticks;
+               var sampleSize = tickOpts.sampleSize;
+               var i, ilen, labels, ticks, samplingEnabled;
+
+               // 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._ticks = null;
+               me.ticks = null;
+               me._labelSizes = null;
+               me._maxLabelLines = 0;
+               me.longestLabelWidth = 0;
+               me.longestTextCache = me.longestTextCache || {};
+               me._gridLineItems = null;
+               me._labelItems = null;
+
+               // 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;
+
+               // Ensure ticks contains ticks in new tick format
+               if ((!ticks || !ticks.length) && me.ticks) {
+                       ticks = [];
+                       for (i = 0, ilen = me.ticks.length; i < ilen; ++i) {
+                               ticks.push({
+                                       value: me.ticks[i],
+                                       major: false
+                               });
+                       }
+               }
+
+               me._ticks = ticks;
+
+               // Compute tick rotation and fit using a sampled subset of labels
+               // We generally don't need to compute the size of every single label for determining scale size
+               samplingEnabled = sampleSize < ticks.length;
+               labels = me._convertTicksToLabels(samplingEnabled ? sample(ticks, sampleSize) : ticks);
+
+               // _configure is called twice, once here, once from core.controller.updateLayout.
+               // Here we haven't been positioned yet, but dimensions are correct.
+               // Variables set in _configure are needed for calculateTickRotation, and
+               // it's ok that coordinates are not correct there, only dimensions matter.
+               me._configure();
+
+               // Tick Rotation
+               me.beforeCalculateTickRotation();
+               me.calculateTickRotation();
+               me.afterCalculateTickRotation();
+
+               me.beforeFit();
+               me.fit();
+               me.afterFit();
+
+               // Auto-skip
+               me._ticksToDraw = tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto') ? me._autoSkip(ticks) : ticks;
+
+               if (samplingEnabled) {
+                       // Generate labels using all non-skipped ticks
+                       labels = me._convertTicksToLabels(me._ticksToDraw);
+               }
+
+               me.ticks = labels;   // BACKWARD COMPATIBILITY
+
+               // IMPORTANT: after this point, we consider that `this.ticks` will NEVER change!
+
+               me.afterUpdate();
+
+               // TODO(v3): remove minSize as a public property and return value from all layout boxes. It is unused
+               // make maxWidth and maxHeight private
+               return me.minSize;
+       },
+
+       /**
+        * @private
+        */
+       _configure: function() {
+               var me = this;
+               var reversePixels = me.options.ticks.reverse;
+               var startPixel, endPixel;
+
+               if (me.isHorizontal()) {
+                       startPixel = me.left;
+                       endPixel = me.right;
+               } else {
+                       startPixel = me.top;
+                       endPixel = me.bottom;
+                       // by default vertical scales are from bottom to top, so pixels are reversed
+                       reversePixels = !reversePixels;
+               }
+               me._startPixel = startPixel;
+               me._endPixel = endPixel;
+               me._reversePixels = reversePixels;
+               me._length = endPixel - startPixel;
+       },
+
+       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 (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 options = me.options;
+               var tickOpts = options.ticks;
+               var numTicks = me.getTicks().length;
+               var minRotation = tickOpts.minRotation || 0;
+               var maxRotation = tickOpts.maxRotation;
+               var labelRotation = minRotation;
+               var labelSizes, maxLabelWidth, maxLabelHeight, maxWidth, tickWidth, maxHeight, maxLabelDiagonal;
+
+               if (!me._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !me.isHorizontal()) {
+                       me.labelRotation = minRotation;
+                       return;
+               }
+
+               labelSizes = me._getLabelSizes();
+               maxLabelWidth = labelSizes.widest.width;
+               maxLabelHeight = labelSizes.highest.height - labelSizes.highest.offset;
+
+               // Estimate the width of each grid based on the canvas width, the maximum
+               // label width and the number of tick intervals
+               maxWidth = Math.min(me.maxWidth, me.chart.width - maxLabelWidth);
+               tickWidth = options.offset ? me.maxWidth / numTicks : maxWidth / (numTicks - 1);
+
+               // Allow 3 pixels x2 padding either side for label readability
+               if (maxLabelWidth + 6 > tickWidth) {
+                       tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1));
+                       maxHeight = me.maxHeight - getTickMarkLength(options.gridLines)
+                               - tickOpts.padding - getScaleLabelHeight(options.scaleLabel);
+                       maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight);
+                       labelRotation = helpers$1.toDegrees(Math.min(
+                               Math.asin(Math.min((labelSizes.highest.height + 6) / tickWidth, 1)),
+                               Math.asin(Math.min(maxHeight / maxLabelDiagonal, 1)) - Math.asin(maxLabelHeight / maxLabelDiagonal)
+                       ));
+                       labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation));
+               }
+
+               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 chart = me.chart;
+               var opts = me.options;
+               var tickOpts = opts.ticks;
+               var scaleLabelOpts = opts.scaleLabel;
+               var gridLineOpts = opts.gridLines;
+               var display = me._isVisible();
+               var isBottom = opts.position === 'bottom';
+               var isHorizontal = me.isHorizontal();
+
+               // Width
+               if (isHorizontal) {
+                       minSize.width = me.maxWidth;
+               } else if (display) {
+                       minSize.width = getTickMarkLength(gridLineOpts) + getScaleLabelHeight(scaleLabelOpts);
+               }
+
+               // height
+               if (!isHorizontal) {
+                       minSize.height = me.maxHeight; // fill all the height
+               } else if (display) {
+                       minSize.height = getTickMarkLength(gridLineOpts) + getScaleLabelHeight(scaleLabelOpts);
+               }
+
+               // Don't bother fitting the ticks if we are not showing the labels
+               if (tickOpts.display && display) {
+                       var tickFonts = parseTickFontOptions(tickOpts);
+                       var labelSizes = me._getLabelSizes();
+                       var firstLabelSize = labelSizes.first;
+                       var lastLabelSize = labelSizes.last;
+                       var widestLabelSize = labelSizes.widest;
+                       var highestLabelSize = labelSizes.highest;
+                       var lineSpace = tickFonts.minor.lineHeight * 0.4;
+                       var tickPadding = tickOpts.padding;
+
+                       if (isHorizontal) {
+                               // A horizontal axis is more constrained by the height.
+                               var isRotated = me.labelRotation !== 0;
+                               var angleRadians = helpers$1.toRadians(me.labelRotation);
+                               var cosRotation = Math.cos(angleRadians);
+                               var sinRotation = Math.sin(angleRadians);
+
+                               var labelHeight = sinRotation * widestLabelSize.width
+                                       + cosRotation * (highestLabelSize.height - (isRotated ? highestLabelSize.offset : 0))
+                                       + (isRotated ? 0 : lineSpace); // padding
+
+                               minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding);
+
+                               var offsetLeft = me.getPixelForTick(0) - me.left;
+                               var offsetRight = me.right - me.getPixelForTick(me.getTicks().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 (isRotated) {
+                                       paddingLeft = isBottom ?
+                                               cosRotation * firstLabelSize.width + sinRotation * firstLabelSize.offset :
+                                               sinRotation * (firstLabelSize.height - firstLabelSize.offset);
+                                       paddingRight = isBottom ?
+                                               sinRotation * (lastLabelSize.height - lastLabelSize.offset) :
+                                               cosRotation * lastLabelSize.width + sinRotation * lastLabelSize.offset;
+                               } else {
+                                       paddingLeft = firstLabelSize.width / 2;
+                                       paddingRight = lastLabelSize.width / 2;
+                               }
+
+                               // Adjust padding taking into account changes in offsets
+                               // and add 3 px to move away from canvas edges
+                               me.paddingLeft = Math.max((paddingLeft - offsetLeft) * me.width / (me.width - offsetLeft), 0) + 3;
+                               me.paddingRight = Math.max((paddingRight - offsetRight) * me.width / (me.width - 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
+                               var labelWidth = tickOpts.mirror ? 0 :
+                                       // use lineSpace for consistency with horizontal axis
+                                       // tickPadding is not implemented for horizontal
+                                       widestLabelSize.width + tickPadding + lineSpace;
+
+                               minSize.width = Math.min(me.maxWidth, minSize.width + labelWidth);
+
+                               me.paddingTop = firstLabelSize.height / 2;
+                               me.paddingBottom = lastLabelSize.height / 2;
+                       }
+               }
+
+               me.handleMargins();
+
+               if (isHorizontal) {
+                       me.width = me._length = chart.width - me.margins.left - me.margins.right;
+                       me.height = minSize.height;
+               } else {
+                       me.width = minSize.width;
+                       me.height = me._length = chart.height - me.margins.top - me.margins.bottom;
+               }
+       },
+
+       /**
+        * Handle margins and padding interactions
+        * @private
+        */
+       handleMargins: function() {
+               var me = this;
+               if (me.margins) {
+                       me.margins.left = Math.max(me.paddingLeft, me.margins.left);
+                       me.margins.top = Math.max(me.paddingTop, me.margins.top);
+                       me.margins.right = Math.max(me.paddingRight, me.margins.right);
+                       me.margins.bottom = Math.max(me.paddingBottom, me.margins.bottom);
+               }
+       },
+
+       afterFit: function() {
+               helpers$1.callback(this.options.afterFit, [this]);
+       },
+
+       // Shared Methods
+       isHorizontal: function() {
+               var pos = this.options.position;
+               return pos === 'top' || pos === '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 (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;
+       },
+
+       _convertTicksToLabels: function(ticks) {
+               var me = this;
+               var labels, i, ilen;
+
+               me.ticks = ticks.map(function(tick) {
+                       return tick.value;
+               });
+
+               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();
+
+               // BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`)
+               for (i = 0, ilen = ticks.length; i < ilen; ++i) {
+                       ticks[i].label = labels[i];
+               }
+
+               return labels;
+       },
+
+       /**
+        * @private
+        */
+       _getLabelSizes: function() {
+               var me = this;
+               var labelSizes = me._labelSizes;
+
+               if (!labelSizes) {
+                       me._labelSizes = labelSizes = computeLabelSizes(me.ctx, parseTickFontOptions(me.options.ticks), me.getTicks(), me.longestTextCache);
+                       me.longestLabelWidth = labelSizes.widest.width;
+               }
+
+               return labelSizes;
+       },
+
+       /**
+        * @private
+        */
+       _parseValue: function(value) {
+               var start, end, min, max;
+
+               if (isArray(value)) {
+                       start = +this.getRightValue(value[0]);
+                       end = +this.getRightValue(value[1]);
+                       min = Math.min(start, end);
+                       max = Math.max(start, end);
+               } else {
+                       value = +this.getRightValue(value);
+                       start = undefined;
+                       end = value;
+                       min = value;
+                       max = value;
+               }
+
+               return {
+                       min: min,
+                       max: max,
+                       start: start,
+                       end: end
+               };
+       },
+
+       /**
+       * @private
+       */
+       _getScaleLabel: function(rawValue) {
+               var v = this._parseValue(rawValue);
+               if (v.start !== undefined) {
+                       return '[' + v.start + ', ' + v.end + ']';
+               }
+
+               return +this.getRightValue(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;
+               var numTicks = me._ticks.length;
+               var tickWidth = 1 / Math.max(numTicks - (offset ? 0 : 1), 1);
+
+               return index < 0 || index > numTicks - 1
+                       ? null
+                       : me.getPixelForDecimal(index * tickWidth + (offset ? tickWidth / 2 : 0));
+       },
+
+       /**
+        * 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._reversePixels) {
+                       decimal = 1 - decimal;
+               }
+
+               return me._startPixel + decimal * me._length;
+       },
+
+       getDecimalForPixel: function(pixel) {
+               var decimal = (pixel - this._startPixel) / this._length;
+               return this._reversePixels ? 1 - decimal : decimal;
+       },
+
+       /**
+        * 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 tickOpts = me.options.ticks;
+               var axisLength = me._length;
+               var ticksLimit = tickOpts.maxTicksLimit || axisLength / me._tickSize() + 1;
+               var majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];
+               var numMajorIndices = majorIndices.length;
+               var first = majorIndices[0];
+               var last = majorIndices[numMajorIndices - 1];
+               var i, ilen, spacing, avgMajorSpacing;
+
+               // If there are too many major ticks to display them all
+               if (numMajorIndices > ticksLimit) {
+                       skipMajors(ticks, majorIndices, numMajorIndices / ticksLimit);
+                       return nonSkipped(ticks);
+               }
+
+               spacing = calculateSpacing(majorIndices, ticks, axisLength, ticksLimit);
+
+               if (numMajorIndices > 0) {
+                       for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) {
+                               skip(ticks, spacing, majorIndices[i], majorIndices[i + 1]);
+                       }
+                       avgMajorSpacing = numMajorIndices > 1 ? (last - first) / (numMajorIndices - 1) : null;
+                       skip(ticks, spacing, helpers$1.isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);
+                       skip(ticks, spacing, last, helpers$1.isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);
+                       return nonSkipped(ticks);
+               }
+               skip(ticks, spacing);
+               return nonSkipped(ticks);
+       },
+
+       /**
+        * @private
+        */
+       _tickSize: function() {
+               var me = this;
+               var optionTicks = me.options.ticks;
+
+               // 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 labelSizes = me._getLabelSizes();
+               var padding = optionTicks.autoSkipPadding || 0;
+               var w = labelSizes ? labelSizes.widest.width + padding : 0;
+               var h = labelSizes ? labelSizes.highest.height + padding : 0;
+
+               // Calculate space needed for 1 tick in axis direction.
+               return me.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;
+       },
+
+       /**
+        * @private
+        */
+       _computeGridLineItems: function(chartArea) {
+               var me = this;
+               var chart = me.chart;
+               var options = me.options;
+               var gridLines = options.gridLines;
+               var position = options.position;
+               var offsetGridLines = gridLines.offsetGridLines;
+               var isHorizontal = me.isHorizontal();
+               var ticks = me._ticksToDraw;
+               var ticksLength = ticks.length + (offsetGridLines ? 1 : 0);
+
+               var tl = getTickMarkLength(gridLines);
+               var items = [];
+               var axisWidth = gridLines.drawBorder ? valueAtIndexOrDefault(gridLines.lineWidth, 0, 0) : 0;
+               var axisHalfWidth = axisWidth / 2;
+               var alignPixel = helpers$1._alignPixel;
+               var alignBorderValue = function(pixel) {
+                       return alignPixel(chart, pixel, axisWidth);
+               };
+               var borderValue, i, tick, lineValue, alignedLineValue;
+               var tx1, ty1, tx2, ty2, x1, y1, x2, y2, lineWidth, lineColor, borderDash, borderDashOffset;
+
+               if (position === 'top') {
+                       borderValue = alignBorderValue(me.bottom);
+                       ty1 = me.bottom - tl;
+                       ty2 = borderValue - axisHalfWidth;
+                       y1 = alignBorderValue(chartArea.top) + axisHalfWidth;
+                       y2 = chartArea.bottom;
+               } else if (position === 'bottom') {
+                       borderValue = alignBorderValue(me.top);
+                       y1 = chartArea.top;
+                       y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth;
+                       ty1 = borderValue + axisHalfWidth;
+                       ty2 = me.top + tl;
+               } else if (position === 'left') {
+                       borderValue = alignBorderValue(me.right);
+                       tx1 = me.right - tl;
+                       tx2 = borderValue - axisHalfWidth;
+                       x1 = alignBorderValue(chartArea.left) + axisHalfWidth;
+                       x2 = chartArea.right;
+               } else {
+                       borderValue = alignBorderValue(me.left);
+                       x1 = chartArea.left;
+                       x2 = alignBorderValue(chartArea.right) - axisHalfWidth;
+                       tx1 = borderValue + axisHalfWidth;
+                       tx2 = me.left + tl;
+               }
+
+               for (i = 0; i < ticksLength; ++i) {
+                       tick = ticks[i] || {};
+
+                       // autoskipper skipped this tick (#4635)
+                       if (isNullOrUndef(tick.label) && i < ticks.length) {
+                               continue;
+                       }
+
+                       if (i === me.zeroLineIndex && options.offset === 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, i, 1);
+                               lineColor = valueAtIndexOrDefault(gridLines.color, i, 'rgba(0,0,0,0.1)');
+                               borderDash = gridLines.borderDash || [];
+                               borderDashOffset = gridLines.borderDashOffset || 0.0;
+                       }
+
+                       lineValue = getPixelForGridLine(me, tick._index || i, offsetGridLines);
+
+                       // Skip if the pixel is out of the range
+                       if (lineValue === undefined) {
+                               continue;
+                       }
+
+                       alignedLineValue = alignPixel(chart, lineValue, lineWidth);
+
+                       if (isHorizontal) {
+                               tx1 = tx2 = x1 = x2 = alignedLineValue;
+                       } else {
+                               ty1 = ty2 = y1 = y2 = alignedLineValue;
+                       }
+
+                       items.push({
+                               tx1: tx1,
+                               ty1: ty1,
+                               tx2: tx2,
+                               ty2: ty2,
+                               x1: x1,
+                               y1: y1,
+                               x2: x2,
+                               y2: y2,
+                               width: lineWidth,
+                               color: lineColor,
+                               borderDash: borderDash,
+                               borderDashOffset: borderDashOffset,
+                       });
+               }
+
+               items.ticksLength = ticksLength;
+               items.borderValue = borderValue;
+
+               return items;
+       },
+
+       /**
+        * @private
+        */
+       _computeLabelItems: function() {
+               var me = this;
+               var options = me.options;
+               var optionTicks = options.ticks;
+               var position = options.position;
+               var isMirrored = optionTicks.mirror;
+               var isHorizontal = me.isHorizontal();
+               var ticks = me._ticksToDraw;
+               var fonts = parseTickFontOptions(optionTicks);
+               var tickPadding = optionTicks.padding;
+               var tl = getTickMarkLength(options.gridLines);
+               var rotation = -helpers$1.toRadians(me.labelRotation);
+               var items = [];
+               var i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset;
+
+               if (position === 'top') {
+                       y = me.bottom - tl - tickPadding;
+                       textAlign = !rotation ? 'center' : 'left';
+               } else if (position === 'bottom') {
+                       y = me.top + tl + tickPadding;
+                       textAlign = !rotation ? 'center' : 'right';
+               } else if (position === 'left') {
+                       x = me.right - (isMirrored ? 0 : tl) - tickPadding;
+                       textAlign = isMirrored ? 'left' : 'right';
+               } else {
+                       x = me.left + (isMirrored ? 0 : tl) + tickPadding;
+                       textAlign = isMirrored ? 'right' : 'left';
+               }
+
+               for (i = 0, ilen = ticks.length; i < ilen; ++i) {
+                       tick = ticks[i];
+                       label = tick.label;
+
+                       // autoskipper skipped this tick (#4635)
+                       if (isNullOrUndef(label)) {
+                               continue;
+                       }
+
+                       pixel = me.getPixelForTick(tick._index || i) + optionTicks.labelOffset;
+                       font = tick.major ? fonts.major : fonts.minor;
+                       lineHeight = font.lineHeight;
+                       lineCount = isArray(label) ? label.length : 1;
+
+                       if (isHorizontal) {
+                               x = pixel;
+                               textOffset = position === 'top'
+                                       ? ((!rotation ? 0.5 : 1) - lineCount) * lineHeight
+                                       : (!rotation ? 0.5 : 0) * lineHeight;
+                       } else {
+                               y = pixel;
+                               textOffset = (1 - lineCount) * lineHeight / 2;
+                       }
+
+                       items.push({
+                               x: x,
+                               y: y,
+                               rotation: rotation,
+                               label: label,
+                               font: font,
+                               textOffset: textOffset,
+                               textAlign: textAlign
+                       });
+               }
+
+               return items;
+       },
+
+       /**
+        * @private
+        */
+       _drawGrid: function(chartArea) {
+               var me = this;
+               var gridLines = me.options.gridLines;
+
+               if (!gridLines.display) {
+                       return;
+               }
+
+               var ctx = me.ctx;
+               var chart = me.chart;
+               var alignPixel = helpers$1._alignPixel;
+               var axisWidth = gridLines.drawBorder ? valueAtIndexOrDefault(gridLines.lineWidth, 0, 0) : 0;
+               var items = me._gridLineItems || (me._gridLineItems = me._computeGridLineItems(chartArea));
+               var width, color, i, ilen, item;
+
+               for (i = 0, ilen = items.length; i < ilen; ++i) {
+                       item = items[i];
+                       width = item.width;
+                       color = item.color;
+
+                       if (width && color) {
+                               ctx.save();
+                               ctx.lineWidth = width;
+                               ctx.strokeStyle = color;
+                               if (ctx.setLineDash) {
+                                       ctx.setLineDash(item.borderDash);
+                                       ctx.lineDashOffset = item.borderDashOffset;
+                               }
+
+                               ctx.beginPath();
+
+                               if (gridLines.drawTicks) {
+                                       ctx.moveTo(item.tx1, item.ty1);
+                                       ctx.lineTo(item.tx2, item.ty2);
+                               }
+
+                               if (gridLines.drawOnChartArea) {
+                                       ctx.moveTo(item.x1, item.y1);
+                                       ctx.lineTo(item.x2, item.y2);
+                               }
+
+                               ctx.stroke();
+                               ctx.restore();
+                       }
+               }
+
+               if (axisWidth) {
+                       // Draw the line at the edge of the axis
+                       var firstLineWidth = axisWidth;
+                       var lastLineWidth = valueAtIndexOrDefault(gridLines.lineWidth, items.ticksLength - 1, 1);
+                       var borderValue = items.borderValue;
+                       var x1, x2, y1, y2;
+
+                       if (me.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;
+                       }
+
+                       ctx.lineWidth = axisWidth;
+                       ctx.strokeStyle = valueAtIndexOrDefault(gridLines.color, 0);
+                       ctx.beginPath();
+                       ctx.moveTo(x1, y1);
+                       ctx.lineTo(x2, y2);
+                       ctx.stroke();
+               }
+       },
+
+       /**
+        * @private
+        */
+       _drawLabels: function() {
+               var me = this;
+               var optionTicks = me.options.ticks;
+
+               if (!optionTicks.display) {
+                       return;
+               }
+
+               var ctx = me.ctx;
+               var items = me._labelItems || (me._labelItems = me._computeLabelItems());
+               var i, j, ilen, jlen, item, tickFont, label, y;
+
+               for (i = 0, ilen = items.length; i < ilen; ++i) {
+                       item = items[i];
+                       tickFont = item.font;
+
+                       // Make sure we draw text in the correct color and font
+                       ctx.save();
+                       ctx.translate(item.x, item.y);
+                       ctx.rotate(item.rotation);
+                       ctx.font = tickFont.string;
+                       ctx.fillStyle = tickFont.color;
+                       ctx.textBaseline = 'middle';
+                       ctx.textAlign = item.textAlign;
+
+                       label = item.label;
+                       y = item.textOffset;
+                       if (isArray(label)) {
+                               for (j = 0, jlen = label.length; j < jlen; ++j) {
+                                       // We just make sure the multiline element is a string here..
+                                       ctx.fillText('' + label[j], 0, y);
+                                       y += tickFont.lineHeight;
+                               }
+                       } else {
+                               ctx.fillText(label, 0, y);
+                       }
+                       ctx.restore();
+               }
+       },
+
+       /**
+        * @private
+        */
+       _drawTitle: function() {
+               var me = this;
+               var ctx = me.ctx;
+               var options = me.options;
+               var scaleLabel = options.scaleLabel;
+
+               if (!scaleLabel.display) {
+                       return;
+               }
+
+               var scaleLabelFontColor = valueOrDefault$a(scaleLabel.fontColor, core_defaults.global.defaultFontColor);
+               var scaleLabelFont = helpers$1.options._parseFont(scaleLabel);
+               var scaleLabelPadding = helpers$1.options.toPadding(scaleLabel.padding);
+               var halfLineHeight = scaleLabelFont.lineHeight / 2;
+               var position = options.position;
+               var rotation = 0;
+               var scaleLabelX, scaleLabelY;
+
+               if (me.isHorizontal()) {
+                       scaleLabelX = me.left + me.width / 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.height / 2;
+                       rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
+               }
+
+               ctx.save();
+               ctx.translate(scaleLabelX, scaleLabelY);
+               ctx.rotate(rotation);
+               ctx.textAlign = 'center';
+               ctx.textBaseline = 'middle';
+               ctx.fillStyle = scaleLabelFontColor; // render in correct colour
+               ctx.font = scaleLabelFont.string;
+               ctx.fillText(scaleLabel.labelString, 0, 0);
+               ctx.restore();
+       },
+
+       draw: function(chartArea) {
+               var me = this;
+
+               if (!me._isVisible()) {
+                       return;
+               }
+
+               me._drawGrid(chartArea);
+               me._drawTitle();
+               me._drawLabels();
+       },
+
+       /**
+        * @private
+        */
+       _layers: function() {
+               var me = this;
+               var opts = me.options;
+               var tz = opts.ticks && opts.ticks.z || 0;
+               var gz = opts.gridLines && opts.gridLines.z || 0;
+
+               if (!me._isVisible() || tz === gz || me.draw !== me._draw) {
+                       // backward compatibility: draw has been overridden by custom scale
+                       return [{
+                               z: tz,
+                               draw: function() {
+                                       me.draw.apply(me, arguments);
+                               }
+                       }];
+               }
+
+               return [{
+                       z: gz,
+                       draw: function() {
+                               me._drawGrid.apply(me, arguments);
+                               me._drawTitle.apply(me, arguments);
+                       }
+               }, {
+                       z: tz,
+                       draw: function() {
+                               me._drawLabels.apply(me, arguments);
+                       }
+               }];
+       },
+
+       /**
+        * @private
+        */
+       _getMatchingVisibleMetas: function(type) {
+               var me = this;
+               var isHorizontal = me.isHorizontal();
+               return me.chart._getSortedVisibleDatasetMetas()
+                       .filter(function(meta) {
+                               return (!type || meta.type === type)
+                                       && (isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id);
+                       });
+       }
+});
+
+Scale.prototype._draw = Scale.prototype.draw;
+
+var core_scale = Scale;
+
+var isNullOrUndef$1 = helpers$1.isNullOrUndef;
+
+var defaultConfig = {
+       position: 'bottom'
+};
+
+var scale_category = core_scale.extend({
+       determineDataLimits: function() {
+               var me = this;
+               var labels = me._getLabels();
+               var ticksOpts = me.options.ticks;
+               var min = ticksOpts.min;
+               var max = ticksOpts.max;
+               var minIndex = 0;
+               var maxIndex = labels.length - 1;
+               var findIndex;
+
+               if (min !== undefined) {
+                       // user specified min value
+                       findIndex = labels.indexOf(min);
+                       if (findIndex >= 0) {
+                               minIndex = findIndex;
+                       }
+               }
+
+               if (max !== undefined) {
+                       // user specified max value
+                       findIndex = labels.indexOf(max);
+                       if (findIndex >= 0) {
+                               maxIndex = findIndex;
+                       }
+               }
+
+               me.minIndex = minIndex;
+               me.maxIndex = maxIndex;
+               me.min = labels[minIndex];
+               me.max = labels[maxIndex];
+       },
+
+       buildTicks: function() {
+               var me = this;
+               var labels = me._getLabels();
+               var minIndex = me.minIndex;
+               var maxIndex = me.maxIndex;
+
+               // If we are viewing some subset of labels, slice the original array
+               me.ticks = (minIndex === 0 && maxIndex === labels.length - 1) ? labels : labels.slice(minIndex, 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._getLabels()[index];
+       },
+
+       _configure: function() {
+               var me = this;
+               var offset = me.options.offset;
+               var ticks = me.ticks;
+
+               core_scale.prototype._configure.call(me);
+
+               if (!me.isHorizontal()) {
+                       // For backward compatibility, vertical category scale reverse is inverted.
+                       me._reversePixels = !me._reversePixels;
+               }
+
+               if (!ticks) {
+                       return;
+               }
+
+               me._startValue = me.minIndex - (offset ? 0.5 : 0);
+               me._valueRange = Math.max(ticks.length - (offset ? 0 : 1), 1);
+       },
+
+       // Used to get data value locations.  Value can either be an index or a numerical value
+       getPixelForValue: function(value, index, datasetIndex) {
+               var me = this;
+               var valueCategory, labels, idx;
+
+               if (!isNullOrUndef$1(index) && !isNullOrUndef$1(datasetIndex)) {
+                       value = me.chart.data.datasets[datasetIndex].data[index];
+               }
+
+               // 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.
+               if (!isNullOrUndef$1(value)) {
+                       valueCategory = me.isHorizontal() ? value.x : value.y;
+               }
+               if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
+                       labels = me._getLabels();
+                       value = helpers$1.valueOrDefault(valueCategory, value);
+                       idx = labels.indexOf(value);
+                       index = idx !== -1 ? idx : index;
+                       if (isNaN(index)) {
+                               index = value;
+                       }
+               }
+               return me.getPixelForDecimal((index - me._startValue) / me._valueRange);
+       },
+
+       getPixelForTick: function(index) {
+               var ticks = this.ticks;
+               return index < 0 || index > ticks.length - 1
+                       ? null
+                       : this.getPixelForValue(ticks[index], index + this.minIndex);
+       },
+
+       getValueForPixel: function(pixel) {
+               var me = this;
+               var value = Math.round(me._startValue + me.getDecimalForPixel(pixel) * me._valueRange);
+               return Math.min(Math.max(value, 0), me.ticks.length - 1);
+       },
+
+       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$2 = 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$2(min) && isNullOrUndef$2(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$2(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$2(min) && helpers$1.almostWhole(min / spacing, spacing / 1000)) {
+                       niceMin = min;
+               }
+               if (!isNullOrUndef$2(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$2(min) ? niceMin : min);
+       for (var j = 1; j < numSpaces; ++j) {
+               ticks.push(Math.round((niceMin + j * spacing) * factor) / factor);
+       }
+       ticks.push(isNullOrUndef$2(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);
+       },
+
+       _configure: function() {
+               var me = this;
+               var ticks = me.getTicks();
+               var start = me.min;
+               var end = me.max;
+               var offset;
+
+               core_scale.prototype._configure.call(me);
+
+               if (me.options.offset && ticks.length) {
+                       offset = (end - start) / Math.max(ticks.length - 1, 1) / 2;
+                       start -= offset;
+                       end += offset;
+               }
+               me._startValue = start;
+               me._endValue = end;
+               me._valueRange = end - start;
+       }
+});
+
+var defaultConfig$1 = {
+       position: 'left',
+       ticks: {
+               callback: core_ticks.formatters.linear
+       }
+};
+
+var DEFAULT_MIN = 0;
+var DEFAULT_MAX = 1;
+
+function getOrCreateStack(stacks, stacked, meta) {
+       var key = [
+               meta.type,
+               // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
+               stacked === undefined && meta.stack === undefined ? meta.index : '',
+               meta.stack
+       ].join('.');
+
+       if (stacks[key] === undefined) {
+               stacks[key] = {
+                       pos: [],
+                       neg: []
+               };
+       }
+
+       return stacks[key];
+}
+
+function stackData(scale, stacks, meta, data) {
+       var opts = scale.options;
+       var stacked = opts.stacked;
+       var stack = getOrCreateStack(stacks, stacked, meta);
+       var pos = stack.pos;
+       var neg = stack.neg;
+       var ilen = data.length;
+       var i, value;
+
+       for (i = 0; i < ilen; ++i) {
+               value = scale._parseValue(data[i]);
+               if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden) {
+                       continue;
+               }
+
+               pos[i] = pos[i] || 0;
+               neg[i] = neg[i] || 0;
+
+               if (opts.relativePoints) {
+                       pos[i] = 100;
+               } else if (value.min < 0 || value.max < 0) {
+                       neg[i] += value.min;
+               } else {
+                       pos[i] += value.max;
+               }
+       }
+}
+
+function updateMinMax(scale, meta, data) {
+       var ilen = data.length;
+       var i, value;
+
+       for (i = 0; i < ilen; ++i) {
+               value = scale._parseValue(data[i]);
+               if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden) {
+                       continue;
+               }
+
+               scale.min = Math.min(scale.min, value.min);
+               scale.max = Math.max(scale.max, value.max);
+       }
+}
+
+var scale_linear = scale_linearbase.extend({
+       determineDataLimits: function() {
+               var me = this;
+               var opts = me.options;
+               var chart = me.chart;
+               var datasets = chart.data.datasets;
+               var metasets = me._getMatchingVisibleMetas();
+               var hasStacks = opts.stacked;
+               var stacks = {};
+               var ilen = metasets.length;
+               var i, meta, data, values;
+
+               me.min = Number.POSITIVE_INFINITY;
+               me.max = Number.NEGATIVE_INFINITY;
+
+               if (hasStacks === undefined) {
+                       for (i = 0; !hasStacks && i < ilen; ++i) {
+                               meta = metasets[i];
+                               hasStacks = meta.stack !== undefined;
+                       }
+               }
+
+               for (i = 0; i < ilen; ++i) {
+                       meta = metasets[i];
+                       data = datasets[meta.index].data;
+                       if (hasStacks) {
+                               stackData(me, stacks, meta, data);
+                       } else {
+                               updateMinMax(me, meta, data);
+                       }
+               }
+
+               helpers$1.each(stacks, function(stackValues) {
+                       values = stackValues.pos.concat(stackValues.neg);
+                       me.min = Math.min(me.min, helpers$1.min(values));
+                       me.max = Math.max(me.max, helpers$1.max(values));
+               });
+
+               me.min = helpers$1.isFinite(me.min) && !isNaN(me.min) ? me.min : DEFAULT_MIN;
+               me.max = helpers$1.isFinite(me.max) && !isNaN(me.max) ? me.max : DEFAULT_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() {
+               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._getScaleLabel(this.chart.data.datasets[datasetIndex].data[index]);
+       },
+
+       // Utils
+       getPixelForValue: function(value) {
+               var me = this;
+               return me.getPixelForDecimal((+me.getRightValue(value) - me._startValue) / me._valueRange);
+       },
+
+       getValueForPixel: function(pixel) {
+               return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange;
+       },
+
+       getPixelForTick: function(index) {
+               var ticks = this.ticksAsNumbers;
+               if (index < 0 || index > ticks.length - 1) {
+                       return null;
+               }
+               return this.getPixelForValue(ticks[index]);
+       }
+});
+
+// INTERNAL: static default options, registered in src/index.js
+var _defaults$1 = defaultConfig$1;
+scale_linear._defaults = _defaults$1;
+
+var valueOrDefault$b = helpers$1.valueOrDefault;
+var log10 = helpers$1.math.log10;
+
+/**
+ * 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$b(generationOptions.min, Math.pow(10, Math.floor(log10(dataRange.min))));
+
+       var endExp = Math.floor(log10(dataRange.max));
+       var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
+       var exp, significand;
+
+       if (tickVal === 0) {
+               exp = Math.floor(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(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$b(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 datasets = chart.data.datasets;
+               var isHorizontal = me.isHorizontal();
+               function IDMatches(meta) {
+                       return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
+               }
+               var datasetIndex, meta, value, data, i, ilen;
+
+               // Calculate Range
+               me.min = Number.POSITIVE_INFINITY;
+               me.max = Number.NEGATIVE_INFINITY;
+               me.minNotZero = Number.POSITIVE_INFINITY;
+
+               var hasStacks = opts.stacked;
+               if (hasStacks === undefined) {
+                       for (datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {
+                               meta = chart.getDatasetMeta(datasetIndex);
+                               if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
+                                       meta.stack !== undefined) {
+                                       hasStacks = true;
+                                       break;
+                               }
+                       }
+               }
+
+               if (opts.stacked || hasStacks) {
+                       var valuesPerStack = {};
+
+                       for (datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {
+                               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] = [];
+                                       }
+
+                                       data = datasets[datasetIndex].data;
+                                       for (i = 0, ilen = data.length; i < ilen; i++) {
+                                               var values = valuesPerStack[key];
+                                               value = me._parseValue(data[i]);
+                                               // invalid, hidden and negative values are ignored
+                                               if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden || value.min < 0 || value.max < 0) {
+                                                       continue;
+                                               }
+                                               values[i] = values[i] || 0;
+                                               values[i] += value.max;
+                                       }
+                               }
+                       }
+
+                       helpers$1.each(valuesPerStack, function(valuesForType) {
+                               if (valuesForType.length > 0) {
+                                       var minVal = helpers$1.min(valuesForType);
+                                       var maxVal = helpers$1.max(valuesForType);
+                                       me.min = Math.min(me.min, minVal);
+                                       me.max = Math.max(me.max, maxVal);
+                               }
+                       });
+
+               } else {
+                       for (datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {
+                               meta = chart.getDatasetMeta(datasetIndex);
+                               if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+                                       data = datasets[datasetIndex].data;
+                                       for (i = 0, ilen = data.length; i < ilen; i++) {
+                                               value = me._parseValue(data[i]);
+                                               // invalid, hidden and negative values are ignored
+                                               if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden || value.min < 0 || value.max < 0) {
+                                                       continue;
+                                               }
+
+                                               me.min = Math.min(value.min, me.min);
+                                               me.max = Math.max(value.max, me.max);
+
+                                               if (value.min !== 0) {
+                                                       me.minNotZero = Math.min(value.min, me.minNotZero);
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               me.min = helpers$1.isFinite(me.min) ? me.min : null;
+               me.max = helpers$1.isFinite(me.max) ? me.max : null;
+               me.minNotZero = helpers$1.isFinite(me.minNotZero) ? me.minNotZero : null;
+
+               // 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(log10(me.min)) - 1);
+                               me.max = Math.pow(10, Math.floor(log10(me.max)) + 1);
+                       } else {
+                               me.min = DEFAULT_MIN;
+                               me.max = DEFAULT_MAX;
+                       }
+               }
+               if (me.min === null) {
+                       me.min = Math.pow(10, Math.floor(log10(me.max)) - 1);
+               }
+               if (me.max === null) {
+                       me.max = me.min !== 0
+                               ? Math.pow(10, Math.floor(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(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._getScaleLabel(this.chart.data.datasets[datasetIndex].data[index]);
+       },
+
+       getPixelForTick: function(index) {
+               var ticks = this.tickValues;
+               if (index < 0 || index > ticks.length - 1) {
+                       return null;
+               }
+               return this.getPixelForValue(ticks[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(log10(value));
+               var significand = Math.floor(value / Math.pow(10, exp));
+
+               return significand * Math.pow(10, exp);
+       },
+
+       _configure: function() {
+               var me = this;
+               var start = me.min;
+               var offset = 0;
+
+               core_scale.prototype._configure.call(me);
+
+               if (start === 0) {
+                       start = me._getFirstTickValue(me.minNotZero);
+                       offset = valueOrDefault$b(me.options.ticks.fontSize, core_defaults.global.defaultFontSize) / me._length;
+               }
+
+               me._startValue = log10(start);
+               me._valueOffset = offset;
+               me._valueRange = (log10(me.max) - log10(start)) / (1 - offset);
+       },
+
+       getPixelForValue: function(value) {
+               var me = this;
+               var decimal = 0;
+
+               value = +me.getRightValue(value);
+
+               if (value > me.min && value > 0) {
+                       decimal = (log10(value) - me._startValue) / me._valueRange + me._valueOffset;
+               }
+               return me.getPixelForDecimal(decimal);
+       },
+
+       getValueForPixel: function(pixel) {
+               var me = this;
+               var decimal = me.getDecimalForPixel(pixel);
+               return decimal === 0 && me.min === 0
+                       ? 0
+                       : Math.pow(10, me._startValue + (decimal - me._valueOffset) * me._valueRange);
+       }
+});
+
+// INTERNAL: static default options, registered in src/index.js
+var _defaults$2 = defaultConfig$2;
+scale_logarithmic._defaults = _defaults$2;
+
+var valueOrDefault$c = helpers$1.valueOrDefault;
+var valueAtIndexOrDefault$1 = helpers$1.valueAtIndexOrDefault;
+var resolve$4 = 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 getTickBackdropHeight(opts) {
+       var tickOpts = opts.ticks;
+
+       if (tickOpts.display && opts.display) {
+               return valueOrDefault$c(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 = scale.chart.data.labels.length;
+       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 pointLabelOpts = opts.pointLabels;
+       var tickBackdropHeight = getTickBackdropHeight(opts);
+       var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
+       var plFont = helpers$1.options._parseFont(pointLabelOpts);
+
+       ctx.save();
+
+       ctx.font = plFont.string;
+       ctx.textBaseline = 'middle';
+
+       for (var i = scale.chart.data.labels.length - 1; i >= 0; i--) {
+               // 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 = scale.chart.data.labels.length;
+       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(function() {
+                       var label = helpers$1.callback(me.options.pointLabels.callback, arguments, me);
+                       return label || label === 0 ? label : '';
+               });
+       },
+
+       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 chart = this.chart;
+               var angleMultiplier = 360 / chart.data.labels.length;
+               var options = chart.options || {};
+               var startAngle = options.startAngle || 0;
+
+               // Start from the top instead of right, so remove a quarter of the circle
+               var angle = (index * angleMultiplier + startAngle) % 360;
+
+               return (angle < 0 ? angle + 360 : angle) * Math.PI * 2 / 360;
+       },
+
+       getDistanceFromCenterForValue: function(value) {
+               var me = this;
+
+               if (helpers$1.isNullOrUndef(value)) {
+                       return NaN;
+               }
+
+               // 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(index) {
+               var me = this;
+               var min = me.min;
+               var max = me.max;
+
+               return me.getPointPositionForValue(index || 0,
+                       me.beginAtZero ? 0 :
+                       min < 0 && max < 0 ? max :
+                       min > 0 && max > 0 ? min :
+                       0);
+       },
+
+       /**
+        * @private
+        */
+       _drawGrid: function() {
+               var me = this;
+               var ctx = me.ctx;
+               var opts = me.options;
+               var gridLineOpts = opts.gridLines;
+               var angleLineOpts = opts.angleLines;
+               var lineWidth = valueOrDefault$c(angleLineOpts.lineWidth, gridLineOpts.lineWidth);
+               var lineColor = valueOrDefault$c(angleLineOpts.color, gridLineOpts.color);
+               var i, offset, position;
+
+               if (opts.pointLabels.display) {
+                       drawPointLabels(me);
+               }
+
+               if (gridLineOpts.display) {
+                       helpers$1.each(me.ticks, function(label, index) {
+                               if (index !== 0) {
+                                       offset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
+                                       drawRadiusLine(me, gridLineOpts, offset, index);
+                               }
+                       });
+               }
+
+               if (angleLineOpts.display && lineWidth && lineColor) {
+                       ctx.save();
+                       ctx.lineWidth = lineWidth;
+                       ctx.strokeStyle = lineColor;
+                       if (ctx.setLineDash) {
+                               ctx.setLineDash(resolve$4([angleLineOpts.borderDash, gridLineOpts.borderDash, []]));
+                               ctx.lineDashOffset = resolve$4([angleLineOpts.borderDashOffset, gridLineOpts.borderDashOffset, 0.0]);
+                       }
+
+                       for (i = me.chart.data.labels.length - 1; i >= 0; i--) {
+                               offset = me.getDistanceFromCenterForValue(opts.ticks.reverse ? me.min : me.max);
+                               position = me.getPointPosition(i, offset);
+                               ctx.beginPath();
+                               ctx.moveTo(me.xCenter, me.yCenter);
+                               ctx.lineTo(position.x, position.y);
+                               ctx.stroke();
+                       }
+
+                       ctx.restore();
+               }
+       },
+
+       /**
+        * @private
+        */
+       _drawLabels: function() {
+               var me = this;
+               var ctx = me.ctx;
+               var opts = me.options;
+               var tickOpts = opts.ticks;
+
+               if (!tickOpts.display) {
+                       return;
+               }
+
+               var startAngle = me.getIndexAngle(0);
+               var tickFont = helpers$1.options._parseFont(tickOpts);
+               var tickFontColor = valueOrDefault$c(tickOpts.fontColor, core_defaults.global.defaultFontColor);
+               var offset, width;
+
+               ctx.save();
+               ctx.font = tickFont.string;
+               ctx.translate(me.xCenter, me.yCenter);
+               ctx.rotate(startAngle);
+               ctx.textAlign = 'center';
+               ctx.textBaseline = 'middle';
+
+               helpers$1.each(me.ticks, function(label, index) {
+                       if (index === 0 && !tickOpts.reverse) {
+                               return;
+                       }
+
+                       offset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
+
+                       if (tickOpts.showLabelBackdrop) {
+                               width = ctx.measureText(label).width;
+                               ctx.fillStyle = tickOpts.backdropColor;
+
+                               ctx.fillRect(
+                                       -width / 2 - tickOpts.backdropPaddingX,
+                                       -offset - tickFont.size / 2 - tickOpts.backdropPaddingY,
+                                       width + tickOpts.backdropPaddingX * 2,
+                                       tickFont.size + tickOpts.backdropPaddingY * 2
+                               );
+                       }
+
+                       ctx.fillStyle = tickFontColor;
+                       ctx.fillText(label, 0, -offset);
+               });
+
+               ctx.restore();
+       },
+
+       /**
+        * @private
+        */
+       _drawTitle: helpers$1.noop
+});
+
+// INTERNAL: static default options, registered in src/index.js
+var _defaults$3 = defaultConfig$3;
+scale_radialLinear._defaults = _defaults$3;
+
+var deprecated$1 = helpers$1._deprecated;
+var resolve$5 = helpers$1.options.resolve;
+var valueOrDefault$d = 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: 1000
+       },
+       second: {
+               common: true,
+               size: 1000,
+               steps: 60
+       },
+       minute: {
+               common: true,
+               size: 60000,
+               steps: 60
+       },
+       hour: {
+               common: true,
+               size: 3600000,
+               steps: 24
+       },
+       day: {
+               common: true,
+               size: 86400000,
+               steps: 30
+       },
+       week: {
+               common: false,
+               size: 604800000,
+               steps: 4
+       },
+       month: {
+               common: true,
+               size: 2.628e9,
+               steps: 12
+       },
+       quarter: {
+               common: false,
+               size: 7.884e9,
+               steps: 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;
+}
+
+function getMin(options) {
+       return helpers$1.valueOrDefault(options.time.min, options.ticks.min);
+}
+
+function getMax(options) {
+       return helpers$1.valueOrDefault(options.time.max, options.ticks.max);
+}
+
+/**
+ * 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;
+}
+
+/**
+ * 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 : 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, numTicks, minUnit, min, max) {
+       var i, unit;
+
+       for (i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--) {
+               unit = UNITS[i];
+               if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) {
+                       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 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 stepSize = resolve$5([timeOpts.stepSize, timeOpts.unitStepSize, 1]);
+       var weekday = minor === 'week' ? timeOpts.isoWeekday : false;
+       var first = min;
+       var ticks = [];
+       var time;
+
+       // For 'week' unit, handle the first day of week option
+       if (weekday) {
+               first = +adapter.startOf(first, 'isoWeek', weekday);
+       }
+
+       // Align first ticks on unit
+       first = +adapter.startOf(first, weekday ? 'day' : minor);
+
+       // Prevent browser from freezing in case user options request millions of milliseconds
+       if (adapter.diff(max, min, minor) > 100000 * stepSize) {
+               throw min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor;
+       }
+
+       for (time = first; time < max; time = +adapter.add(time, stepSize, minor)) {
+               ticks.push(time);
+       }
+
+       if (time === max || options.bounds === 'ticks') {
+               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) {
+               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;
+               }
+               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, factor: 1 / (start + 1 + end)};
+}
+
+function setMajorTicks(scale, ticks, map, majorUnit) {
+       var adapter = scale._adapter;
+       var first = +adapter.startOf(ticks[0].value, majorUnit);
+       var last = ticks[ticks.length - 1].value;
+       var major, index;
+
+       for (major = first; major <= last; major = +adapter.add(major, 1, majorUnit)) {
+               index = map[major];
+               if (index >= 0) {
+                       ticks[index].major = true;
+               }
+       }
+       return ticks;
+}
+
+function ticksFromTimestamps(scale, values, majorUnit) {
+       var ticks = [];
+       var map = {};
+       var ilen = values.length;
+       var i, value;
+
+       for (i = 0; i < ilen; ++i) {
+               value = values[i];
+               map[value] = i;
+
+               ticks.push({
+                       value: value,
+                       major: false
+               });
+       }
+
+       // We set the major ticks separately from the above loop because calling startOf for every tick
+       // is expensive when there is a large number of ticks
+       return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit);
+}
+
+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
+               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
+               deprecated$1('time scale', time.format, 'time.format', 'time.parser');
+               deprecated$1('time scale', time.min, 'time.min', 'ticks.min');
+               deprecated$1('time scale', time.max, 'time.max', 'ticks.max');
+
+               // 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 options = me.options;
+               var unit = options.time.unit || 'day';
+               var min = MAX_INTEGER;
+               var max = MIN_INTEGER;
+               var timestamps = [];
+               var datasets = [];
+               var labels = [];
+               var i, j, ilen, jlen, data, timestamp, labelsAdded;
+               var dataLabels = me._getLabels();
+
+               for (i = 0, ilen = dataLabels.length; i < ilen; ++i) {
+                       labels.push(parse(me, dataLabels[i]));
+               }
+
+               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 {
+                                       datasets[i] = labels.slice(0);
+                                       if (!labelsAdded) {
+                                               timestamps = timestamps.concat(labels);
+                                               labelsAdded = true;
+                                       }
+                               }
+                       } else {
+                               datasets[i] = [];
+                       }
+               }
+
+               if (labels.length) {
+                       min = Math.min(min, labels[0]);
+                       max = Math.max(max, labels[labels.length - 1]);
+               }
+
+               if (timestamps.length) {
+                       timestamps = ilen > 1 ? arrayUnique(timestamps).sort(sorter) : timestamps.sort(sorter);
+                       min = Math.min(min, timestamps[0]);
+                       max = Math.max(max, timestamps[timestamps.length - 1]);
+               }
+
+               min = parse(me, getMin(options)) || min;
+               max = parse(me, getMax(options)) || 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._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 tickOpts = options.ticks;
+               var timeOpts = options.time;
+               var timestamps = me._timestamps;
+               var ticks = [];
+               var capacity = me.getLabelCapacity(min);
+               var source = tickOpts.source;
+               var distribution = options.distribution;
+               var i, ilen, timestamp;
+
+               if (source === 'data' || (source === 'auto' && distribution === 'series')) {
+                       timestamps = timestamps.data;
+               } else if (source === 'labels') {
+                       timestamps = timestamps.labels;
+               } else {
+                       timestamps = generate(me, min, max, capacity);
+               }
+
+               if (options.bounds === 'ticks' && timestamps.length) {
+                       min = timestamps[0];
+                       max = timestamps[timestamps.length - 1];
+               }
+
+               // Enforce limits with user min/max options
+               min = parse(me, getMin(options)) || min;
+               max = parse(me, getMax(options)) || 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
+               // determineUnitForFormatting relies on the number of ticks so we don't use it when
+               // autoSkip is enabled because we don't yet know what the final number of ticks will be
+               me._unit = timeOpts.unit || (tickOpts.autoSkip
+                       ? determineUnitForAutoTicks(timeOpts.minUnit, me.min, me.max, capacity)
+                       : determineUnitForFormatting(me, ticks.length, timeOpts.minUnit, me.min, me.max));
+               me._majorUnit = !tickOpts.major.enabled || me._unit === 'year' ? undefined
+                       : determineMajorUnit(me._unit);
+               me._table = buildLookupTable(me._timestamps.data, min, max, distribution);
+               me._offsets = computeOffsets(me._table, ticks, min, max, options);
+
+               if (tickOpts.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 tick = ticks[index];
+               var tickOpts = options.ticks;
+               var major = majorUnit && majorFormat && tick && tick.major;
+               var label = adapter.format(time, format ? format : major ? majorFormat : minorFormat);
+               var nestedTickOpts = major ? tickOpts.major : tickOpts.minor;
+               var formatter = resolve$5([
+                       nestedTickOpts.callback,
+                       nestedTickOpts.userCallback,
+                       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 offsets = me._offsets;
+               var pos = interpolate$1(me._table, 'time', time, 'pos');
+               return me.getPixelForDecimal((offsets.start + pos) * offsets.factor);
+       },
+
+       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 offsets = me._offsets;
+               var pos = me.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
+               var time = interpolate$1(me._table, 'pos', pos, 'time');
+
+               // DEPRECATION, we should return time directly
+               return me._adapter._create(time);
+       },
+
+       /**
+        * @private
+        */
+       _getLabelSize: function(label) {
+               var me = this;
+               var ticksOpts = me.options.ticks;
+               var tickLabelWidth = me.ctx.measureText(label).width;
+               var angle = helpers$1.toRadians(me.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation);
+               var cosRotation = Math.cos(angle);
+               var sinRotation = Math.sin(angle);
+               var tickFontSize = valueOrDefault$d(ticksOpts.fontSize, core_defaults.global.defaultFontSize);
+
+               return {
+                       w: (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation),
+                       h: (tickLabelWidth * sinRotation) + (tickFontSize * cosRotation)
+               };
+       },
+
+       /**
+        * Crude approximation of what the label width might be
+        * @private
+        */
+       getLabelWidth: function(label) {
+               return this._getLabelSize(label).w;
+       },
+
+       /**
+        * @private
+        */
+       getLabelCapacity: function(exampleTime) {
+               var me = this;
+               var timeOpts = me.options.time;
+               var displayFormats = timeOpts.displayFormats;
+
+               // pick the longest format (milliseconds) for guestimation
+               var format = displayFormats[timeOpts.unit] || displayFormats.millisecond;
+               var exampleLabel = me.tickFormatFunction(exampleTime, 0, ticksFromTimestamps(me, [exampleTime], me._majorUnit), format);
+               var size = me._getLabelSize(exampleLabel);
+               var capacity = Math.floor(me.isHorizontal() ? me.width / size.w : me.height / size.h);
+
+               if (me.options.offset) {
+                       capacity--;
+               }
+
+               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(max).diff(moment(min), 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;
+
+               if (helpers$1.isArray(boundary)) {
+                       return function(point, i) {
+                               return boundary[i];
+                       };
+               }
+
+               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 computeLinearBoundary(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.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 computeCircularBoundary(source) {
+       var scale = source.el._scale;
+       var options = scale.options;
+       var length = scale.chart.data.labels.length;
+       var fill = source.fill;
+       var target = [];
+       var start, end, center, i, point;
+
+       if (!length) {
+               return null;
+       }
+
+       start = options.ticks.reverse ? scale.max : scale.min;
+       end = options.ticks.reverse ? scale.min : scale.max;
+       center = scale.getPointPositionForValue(0, start);
+       for (i = 0; i < length; ++i) {
+               point = fill === 'start' || fill === 'end'
+                       ? scale.getPointPositionForValue(i, fill === 'start' ? start : end)
+                       : scale.getBasePosition(i);
+               if (options.gridLines.circular) {
+                       point.cx = center.x;
+                       point.cy = center.y;
+                       point.angle = scale.getIndexAngle(i) - Math.PI / 2;
+               }
+               target.push(point);
+       }
+       return target;
+}
+
+function computeBoundary(source) {
+       var scale = source.el._scale || {};
+
+       if (scale.getPointPositionForValue) {
+               return computeCircularBoundary(source);
+       }
+       return computeLinearBoundary(source);
+}
+
+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, cx, cy, r;
+
+       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]);
+       }
+
+       if (curve1[0].angle !== undefined) {
+               cx = curve1[0].cx;
+               cy = curve1[0].cy;
+               r = Math.sqrt(Math.pow(curve1[0].x - cx, 2) + Math.pow(curve1[0].y - cy, 2));
+               for (i = len1 - 1; i > 0; --i) {
+                       ctx.arc(cx, cy, r, curve1[i].angle, curve1[i - 1].angle, true);
+               }
+               return;
+       }
+
+       // 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, loopOffset;
+
+       ctx.beginPath();
+
+       for (i = 0, ilen = count; i < ilen; ++i) {
+               index = i % count;
+               p0 = points[index]._view;
+               p1 = mapper(p0, index, view);
+               d0 = isDrawable(p0);
+               d1 = isDrawable(p1);
+
+               if (loop && loopOffset === undefined && d0) {
+                       loopOffset = i + 1;
+                       ilen = count + loopOffset;
+               }
+
+               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);
+               }
+       },
+
+       beforeDatasetsDraw: function(chart) {
+               var metasets = chart._getSortedVisibleDatasetMetas();
+               var ctx = chart.ctx;
+               var meta, i, el, view, points, mapper, color;
+
+               for (i = metasets.length - 1; i >= 0; --i) {
+                       meta = metasets[i].$filler;
+
+                       if (!meta || !meta.visible) {
+                               continue;
+                       }
+
+                       el = meta.el;
+                       view = el._view;
+                       points = el._children || [];
+                       mapper = meta.mapper;
+                       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 getRtlHelper$1 = helpers$1.rtl.getRtlAdapter;
+var noop$1 = helpers$1.noop;
+var valueOrDefault$e = helpers$1.valueOrDefault;
+
+core_defaults._set('global', {
+       legend: {
+               display: true,
+               position: 'top',
+               align: 'center',
+               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 datasets = chart.data.datasets;
+                               var options = chart.options.legend || {};
+                               var usePointStyle = options.labels && options.labels.usePointStyle;
+
+                               return chart._getSortedDatasetMetas().map(function(meta, i) {
+                                       var style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
+
+                                       return {
+                                               text: datasets[meta.index].label,
+                                               fillStyle: style.backgroundColor,
+                                               hidden: !chart.isDatasetVisible(i),
+                                               lineCap: style.borderCapStyle,
+                                               lineDash: style.borderDash,
+                                               lineDashOffset: style.borderDashOffset,
+                                               lineJoin: style.borderJoinStyle,
+                                               lineWidth: style.borderWidth,
+                                               strokeStyle: style.borderColor,
+                                               pointStyle: style.pointStyle,
+                                               rotation: style.rotation,
+
+                                               // Below is extra data used for toggling the datasets
+                                               datasetIndex: i
+                                       };
+                               }, this);
+                       }
+               }
+       },
+
+       legendCallback: function(chart) {
+               var list = document.createElement('ul');
+               var datasets = chart.data.datasets;
+               var i, ilen, listItem, listItemSpan;
+
+               list.setAttribute('class', chart.id + '-legend');
+
+               for (i = 0, ilen = datasets.length; i < ilen; i++) {
+                       listItem = list.appendChild(document.createElement('li'));
+                       listItemSpan = listItem.appendChild(document.createElement('span'));
+                       listItemSpan.style.backgroundColor = datasets[i].backgroundColor;
+                       if (datasets[i].label) {
+                               listItem.appendChild(document.createTextNode(datasets[i].label));
+                       }
+               }
+
+               return list.outerHTML;
+       }
+});
+
+/**
+ * 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) {
+               var me = this;
+               helpers$1.extend(me, config);
+
+               // Contains hit boxes for each dataset (in dataset order)
+               me.legendHitBoxes = [];
+
+               /**
+                * @private
+                */
+               me._hoveredItem = null;
+
+               // Are we in doughnut mode which has a different data type
+               me.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) {
+                       me.width = minSize.width = me.height = minSize.height = 0;
+                       return;
+               }
+               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 = 'middle';
+
+                       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 + 2 * labelOpts.padding > minSize.width) {
+                                       totalHeight += fontSize + labelOpts.padding;
+                                       lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0;
+                               }
+
+                               // 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 columnHeights = me.columnHeights = [];
+                       var totalWidth = labelOpts.padding;
+                       var currentColWidth = 0;
+                       var currentColHeight = 0;
+
+                       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 + fontSize + 2 * vPadding > minSize.height) {
+                                       totalWidth += currentColWidth + labelOpts.padding;
+                                       columnWidths.push(currentColWidth); // previous column width
+                                       columnHeights.push(currentColHeight);
+                                       currentColWidth = 0;
+                                       currentColHeight = 0;
+                               }
+
+                               // Get max width
+                               currentColWidth = Math.max(currentColWidth, itemWidth);
+                               currentColHeight += fontSize + vPadding;
+
+                               // 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);
+                       columnHeights.push(currentColHeight);
+                       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 legendHeight = me.height;
+               var columnHeights = me.columnHeights;
+               var legendWidth = me.width;
+               var lineWidths = me.lineWidths;
+
+               if (!opts.display) {
+                       return;
+               }
+
+               var rtlHelper = getRtlHelper$1(opts.rtl, me.left, me.minSize.width);
+               var ctx = me.ctx;
+               var fontColor = valueOrDefault$e(labelOpts.fontColor, globalDefaults.defaultFontColor);
+               var labelFont = helpers$1.options._parseFont(labelOpts);
+               var fontSize = labelFont.size;
+               var cursor;
+
+               // Canvas setup
+               ctx.textAlign = rtlHelper.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$e(legendItem.lineWidth, lineDefault.borderWidth);
+                       ctx.fillStyle = valueOrDefault$e(legendItem.fillStyle, defaultColor);
+                       ctx.lineCap = valueOrDefault$e(legendItem.lineCap, lineDefault.borderCapStyle);
+                       ctx.lineDashOffset = valueOrDefault$e(legendItem.lineDashOffset, lineDefault.borderDashOffset);
+                       ctx.lineJoin = valueOrDefault$e(legendItem.lineJoin, lineDefault.borderJoinStyle);
+                       ctx.lineWidth = lineWidth;
+                       ctx.strokeStyle = valueOrDefault$e(legendItem.strokeStyle, defaultColor);
+
+                       if (ctx.setLineDash) {
+                               // IE 9 and 10 do not support line dash
+                               ctx.setLineDash(valueOrDefault$e(legendItem.lineDash, lineDefault.borderDash));
+                       }
+
+                       if (labelOpts && labelOpts.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 = rtlHelper.xPlus(x, boxWidth / 2);
+                               var centerY = y + fontSize / 2;
+
+                               // Draw pointStyle as legend symbol
+                               helpers$1.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY, legendItem.rotation);
+                       } else {
+                               // Draw box as legend symbol
+                               ctx.fillRect(rtlHelper.leftForLtr(x, boxWidth), y, boxWidth, fontSize);
+                               if (lineWidth !== 0) {
+                                       ctx.strokeRect(rtlHelper.leftForLtr(x, boxWidth), y, boxWidth, fontSize);
+                               }
+                       }
+
+                       ctx.restore();
+               };
+
+               var fillText = function(x, y, legendItem, textWidth) {
+                       var halfFontSize = fontSize / 2;
+                       var xLeft = rtlHelper.xPlus(x, boxWidth + halfFontSize);
+                       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(rtlHelper.xPlus(xLeft, textWidth), yMiddle);
+                               ctx.stroke();
+                       }
+               };
+
+               var alignmentOffset = function(dimension, blockSize) {
+                       switch (opts.align) {
+                       case 'start':
+                               return labelOpts.padding;
+                       case 'end':
+                               return dimension - blockSize;
+                       default: // center
+                               return (dimension - blockSize + labelOpts.padding) / 2;
+                       }
+               };
+
+               // Horizontal
+               var isHorizontal = me.isHorizontal();
+               if (isHorizontal) {
+                       cursor = {
+                               x: me.left + alignmentOffset(legendWidth, lineWidths[0]),
+                               y: me.top + labelOpts.padding,
+                               line: 0
+                       };
+               } else {
+                       cursor = {
+                               x: me.left + labelOpts.padding,
+                               y: me.top + alignmentOffset(legendHeight, columnHeights[0]),
+                               line: 0
+                       };
+               }
+
+               helpers$1.rtl.overrideTextDirection(me.ctx, opts.textDirection);
+
+               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;
+
+                       rtlHelper.setWidth(me.minSize.width);
+
+                       // 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 + alignmentOffset(legendWidth, lineWidths[cursor.line]);
+                               }
+                       } else if (i > 0 && y + itemHeight > me.top + me.minSize.height) {
+                               x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
+                               cursor.line++;
+                               y = cursor.y = me.top + alignmentOffset(legendHeight, columnHeights[cursor.line]);
+                       }
+
+                       var realX = rtlHelper.x(x);
+
+                       drawLegendBox(realX, y, legendItem);
+
+                       hitboxes[i].left = rtlHelper.leftForLtr(realX, hitboxes[i].width);
+                       hitboxes[i].top = y;
+
+                       // Fill the actual label
+                       fillText(realX, y, legendItem, textWidth);
+
+                       if (isHorizontal) {
+                               cursor.x += width + labelOpts.padding;
+                       } else {
+                               cursor.y += itemHeight;
+                       }
+               });
+
+               helpers$1.rtl.restoreTextDirection(me.ctx, opts.textDirection);
+       },
+
+       /**
+        * @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 minSize = me.minSize = {};
+               var isHorizontal = me.isHorizontal();
+               var lineCount, textSize;
+
+               if (!opts.display) {
+                       me.width = minSize.width = me.height = minSize.height = 0;
+                       return;
+               }
+
+               lineCount = helpers$1.isArray(opts.text) ? opts.text.length : 1;
+               textSize = lineCount * helpers$1.options._parseFont(opts).lineHeight + opts.padding * 2;
+
+               me.width = minSize.width = isHorizontal ? me.maxWidth : textSize;
+               me.height = minSize.height = isHorizontal ? textSize : me.maxHeight;
+       },
+       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) {
+                       return;
+               }
+
+               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._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..f1bbb90
--- /dev/null
@@ -0,0 +1,7 @@
+/*!
+ * Chart.js v2.9.1
+ * 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=t||self).Chart=e()}(this,function(){"use strict";var t={rgb2hsl:e,rgb2hsv:n,rgb2hwb:i,rgb2cmyk:a,rgb2keyword:o,rgb2xyz:s,rgb2lab:l,rgb2lch:function(t){return v(l(t))},hsl2rgb:u,hsl2hsv:function(t){var e=t[0],n=t[1]/100,i=t[2]/100;if(0===i)return[0,0,0];return[e,100*(2*(n*=(i*=2)<=1?i:2-i)/(i+n)),100*((i+n)/2)]},hsl2hwb:function(t){return i(u(t))},hsl2cmyk:function(t){return a(u(t))},hsl2keyword:function(t){return o(u(t))},hsv2rgb:d,hsv2hsl:function(t){var e,n,i=t[0],a=t[1]/100,r=t[2]/100;return e=a*r,[i,100*(e=(e/=(n=(2-a)*r)<=1?n:2-n)||0),100*(n/=2)]},hsv2hwb:function(t){return i(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 n(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 n(c(t))},cmyk2hwb:function(t){return i(c(t))},cmyk2keyword:function(t){return o(c(t))},keyword2rgb:_,keyword2hsl:function(t){return e(_(t))},keyword2hsv:function(t){return n(_(t))},keyword2hwb:function(t){return i(_(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,n,i=t[0]/255,a=t[1]/255,r=t[2]/255,o=Math.min(i,a,r),s=Math.max(i,a,r),l=s-o;return s==o?e=0:i==s?e=(a-r)/l:a==s?e=2+(r-i)/l:r==s&&(e=4+(i-a)/l),(e=Math.min(60*e,360))<0&&(e+=360),n=(o+s)/2,[e,100*(s==o?0:n<=.5?l/(s+o):l/(2-s-o)),100*n]}function n(t){var e,n,i=t[0],a=t[1],r=t[2],o=Math.min(i,a,r),s=Math.max(i,a,r),l=s-o;return n=0==s?0:l/s*1e3/10,s==o?e=0:i==s?e=(a-r)/l:a==s?e=2+(r-i)/l:r==s&&(e=4+(i-a)/l),(e=Math.min(60*e,360))<0&&(e+=360),[e,n,s/255*1e3/10]}function i(t){var n=t[0],i=t[1],a=t[2];return[e(t)[0],100*(1/255*Math.min(n,Math.min(i,a))),100*(a=1-1/255*Math.max(n,Math.max(i,a)))]}function a(t){var e,n=t[0]/255,i=t[1]/255,a=t[2]/255;return[100*((1-n-(e=Math.min(1-n,1-i,1-a)))/(1-e)||0),100*((1-i-e)/(1-e)||0),100*((1-a-e)/(1-e)||0),100*e]}function o(t){return k[JSON.stringify(t)]}function s(t){var e=t[0]/255,n=t[1]/255,i=t[2]/255;return[100*(.4124*(e=e>.04045?Math.pow((e+.055)/1.055,2.4):e/12.92)+.3576*(n=n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92)+.1805*(i=i>.04045?Math.pow((i+.055)/1.055,2.4):i/12.92)),100*(.2126*e+.7152*n+.0722*i),100*(.0193*e+.1192*n+.9505*i)]}function l(t){var e=s(t),n=e[0],i=e[1],a=e[2];return i/=100,a/=108.883,n=(n/=95.047)>.008856?Math.pow(n,1/3):7.787*n+16/116,[116*(i=i>.008856?Math.pow(i,1/3):7.787*i+16/116)-16,500*(n-i),200*(i-(a=a>.008856?Math.pow(a,1/3):7.787*a+16/116))]}function u(t){var e,n,i,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-(n=l<.5?l*(1+s):l+s-l*s),a=[0,0,0];for(var u=0;u<3;u++)(i=o+1/3*-(u-1))<0&&i++,i>1&&i--,r=6*i<1?e+6*(n-e)*i:2*i<1?n:3*i<2?e+(n-e)*(2/3-i)*6:e,a[u]=255*r;return a}function d(t){var e=t[0]/60,n=t[1]/100,i=t[2]/100,a=Math.floor(e)%6,r=e-Math.floor(e),o=255*i*(1-n),s=255*i*(1-n*r),l=255*i*(1-n*(1-r));i*=255;switch(a){case 0:return[i,l,o];case 1:return[s,i,o];case 2:return[o,i,l];case 3:return[o,s,i];case 4:return[l,o,i];case 5:return[i,o,s]}}function h(t){var e,n,i,a,o=t[0]/360,s=t[1]/100,l=t[2]/100,u=s+l;switch(u>1&&(s/=u,l/=u),i=6*o-(e=Math.floor(6*o)),0!=(1&e)&&(i=1-i),a=s+i*((n=1-l)-s),e){default:case 6:case 0:r=n,g=a,b=s;break;case 1:r=a,g=n,b=s;break;case 2:r=s,g=n,b=a;break;case 3:r=s,g=a,b=n;break;case 4:r=a,g=s,b=n;break;case 5:r=n,g=s,b=a}return[255*r,255*g,255*b]}function c(t){var e=t[0]/100,n=t[1]/100,i=t[2]/100,a=t[3]/100;return[255*(1-Math.min(1,e*(1-a)+a)),255*(1-Math.min(1,n*(1-a)+a)),255*(1-Math.min(1,i*(1-a)+a))]}function f(t){var e,n,i,a=t[0]/100,r=t[1]/100,o=t[2]/100;return n=-.9689*a+1.8758*r+.0415*o,i=.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,n=n>.0031308?1.055*Math.pow(n,1/2.4)-.055:n*=12.92,i=i>.0031308?1.055*Math.pow(i,1/2.4)-.055:i*=12.92,[255*(e=Math.min(Math.max(0,e),1)),255*(n=Math.min(Math.max(0,n),1)),255*(i=Math.min(Math.max(0,i),1))]}function m(t){var e=t[0],n=t[1],i=t[2];return n/=100,i/=108.883,e=(e/=95.047)>.008856?Math.pow(e,1/3):7.787*e+16/116,[116*(n=n>.008856?Math.pow(n,1/3):7.787*n+16/116)-16,500*(e-n),200*(n-(i=i>.008856?Math.pow(i,1/3):7.787*i+16/116))]}function p(t){var e,n,i,a,r=t[0],o=t[1],s=t[2];return r<=8?a=(n=100*r/903.3)/100*7.787+16/116:(n=100*Math.pow((r+16)/116,3),a=Math.pow(n/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),n,i=i/108.883<=.008859?i=108.883*(a-s/200-16/116)/7.787:108.883*Math.pow(a-s/200,3)]}function v(t){var e,n=t[0],i=t[1],a=t[2];return(e=360*Math.atan2(a,i)/2/Math.PI)<0&&(e+=360),[n,Math.sqrt(i*i+a*a),e]}function y(t){return f(p(t))}function x(t){var e,n=t[0],i=t[1];return e=t[2]/360*2*Math.PI,[n,i*Math.cos(e),i*Math.sin(e)]}function _(t){return w[t]}var w={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]},k={};for(var M in w)k[JSON.stringify(w[M])]=M;var S=function(){return new A};for(var D in t){S[D+"Raw"]=function(e){return function(n){return"number"==typeof n&&(n=Array.prototype.slice.call(arguments)),t[e](n)}}(D);var C=/(\w+)2(\w+)/.exec(D),T=C[1],P=C[2];(S[T]=S[T]||{})[P]=S[D]=function(e){return function(n){"number"==typeof n&&(n=Array.prototype.slice.call(arguments));var i=t[e](n);if("string"==typeof i||void 0===i)return i;for(var a=0;a<i.length;a++)i[a]=Math.round(i[a]);return i}}(D)}var A=function(){this.convs={}};A.prototype.routeSpace=function(t,e){var n=e[0];return void 0===n?this.getValues(t):("number"==typeof n&&(n=Array.prototype.slice.call(e)),this.setValues(t,n))},A.prototype.setValues=function(t,e){return this.space=t,this.convs={},this.convs[t]=e,this},A.prototype.getValues=function(t){var e=this.convs[t];if(!e){var n=this.space,i=this.convs[n];e=S[n][t](i),this.convs[t]=e}return e},["rgb","hsl","hsv","cmyk","keyword"].forEach(function(t){A.prototype[t]=function(e){return this.routeSpace(t,arguments)}});var O=S,F={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]},I={getRgba:L,getHsla:R,getRgb:function(t){var e=L(t);return e&&e.slice(0,3)},getHsl:function(t){var e=R(t);return e&&e.slice(0,3)},getHwb:N,getAlpha:function(t){var e=L(t);if(e)return e[3];if(e=R(t))return e[3];if(e=N(t))return e[3]},hexString:function(t,e){e=void 0!==e&&3===t.length?e:t[3];return"#"+E(t[0])+E(t[1])+E(t[2])+(e>=0&&e<1?E(Math.round(255*e)):"")},rgbString:function(t,e){if(e<1||t[3]&&t[3]<1)return W(t,e);return"rgb("+t[0]+", "+t[1]+", "+t[2]+")"},rgbaString:W,percentString:function(t,e){if(e<1||t[3]&&t[3]<1)return Y(t,e);var n=Math.round(t[0]/255*100),i=Math.round(t[1]/255*100),a=Math.round(t[2]/255*100);return"rgb("+n+"%, "+i+"%, "+a+"%)"},percentaString:Y,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 H[t.slice(0,3)]}};function L(t){if(t){var e=[0,0,0],n=1,i=t.match(/^#([a-fA-F0-9]{3,4})$/i),a="";if(i){a=(i=i[1])[3];for(var r=0;r<e.length;r++)e[r]=parseInt(i[r]+i[r],16);a&&(n=Math.round(parseInt(a+a,16)/255*100)/100)}else if(i=t.match(/^#([a-fA-F0-9]{6}([a-fA-F0-9]{2})?)$/i)){a=i[2],i=i[1];for(r=0;r<e.length;r++)e[r]=parseInt(i.slice(2*r,2*r+2),16);a&&(n=Math.round(parseInt(a,16)/255*100)/100)}else if(i=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(i[r+1]);n=parseFloat(i[4])}else if(i=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(i[r+1]));n=parseFloat(i[4])}else if(i=t.match(/(\w+)/)){if("transparent"==i[1])return[0,0,0,0];if(!(e=F[i[1]]))return}for(r=0;r<e.length;r++)e[r]=V(e[r],0,255);return n=n||0==n?V(n,0,1):1,e[3]=n,e}}function R(t){if(t){var e=t.match(/^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/);if(e){var n=parseFloat(e[4]);return[V(parseInt(e[1]),0,360),V(parseFloat(e[2]),0,100),V(parseFloat(e[3]),0,100),V(isNaN(n)?1:n,0,1)]}}}function N(t){if(t){var e=t.match(/^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/);if(e){var n=parseFloat(e[4]);return[V(parseInt(e[1]),0,360),V(parseFloat(e[2]),0,100),V(parseFloat(e[3]),0,100),V(isNaN(n)?1:n,0,1)]}}}function W(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"rgba("+t[0]+", "+t[1]+", "+t[2]+", "+e+")"}function Y(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,n){return Math.min(Math.max(e,t),n)}function E(t){var e=t.toString(16).toUpperCase();return e.length<2?"0"+e:e}var H={};for(var B in F)H[F[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=I.getRgba(t))?this.setValues("rgb",e):(e=I.getHsla(t))?this.setValues("hsl",e):(e=I.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 I.hexString(this.values.rgb)},rgbString:function(){return I.rgbString(this.values.rgb,this.values.alpha)},rgbaString:function(){return I.rgbaString(this.values.rgb,this.values.alpha)},percentString:function(){return I.percentString(this.values.rgb,this.values.alpha)},hslString:function(){return I.hslString(this.values.hsl,this.values.alpha)},hslaString:function(){return I.hslaString(this.values.hsl,this.values.alpha)},hwbString:function(){return I.hwbString(this.values.hwb,this.values.alpha)},keyword:function(){return I.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=[],n=0;n<t.length;n++){var i=t[n]/255;e[n]=i<=.03928?i/12.92:Math.pow((i+.055)/1.055,2.4)}return.2126*e[0]+.7152*e[1]+.0722*e[2]},contrast:function(t){var e=this.luminosity(),n=t.luminosity();return e>n?(e+.05)/(n+.05):(n+.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,n=(e[0]+t)%360;return e[0]=n<0?360+n:n,this.setValues("hsl",e),this},mix:function(t,e){var n=t,i=void 0===e?.5:e,a=2*i-1,r=this.alpha()-n.alpha(),o=((a*r==-1?a:(a+r)/(1+a*r))+1)/2,s=1-o;return this.rgb(o*this.red()+s*n.red(),o*this.green()+s*n.green(),o*this.blue()+s*n.blue()).alpha(this.alpha()*i+n.alpha()*(1-i))},toJSON:function(){return this.rgb()},clone:function(){var t,e,n=new j,i=this.values,a=n.values;for(var r in i)i.hasOwnProperty(r)&&(t=i[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 n}},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,n={},i=0;i<t.length;i++)n[t.charAt(i)]=e[t][i];return 1!==e.alpha&&(n.a=e.alpha),n},j.prototype.setValues=function(t,e){var n,i,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(n=0;n<t.length;n++)a[t][n]=e[t.charAt(n)];s=e.a}else if(void 0!==e[r[t][0]]){var l=r[t];for(n=0;n<t.length;n++)a[t][n]=e[l[n]];s=e.alpha}if(a.alpha=Math.max(0,Math.min(1,void 0===s?a.alpha:s)),"alpha"===t)return!1;for(n=0;n<t.length;n++)i=Math.max(0,Math.min(o[t][n],a[t][n])),a[t][n]=Math.round(i);for(var u in r)u!==t&&(a[u]=O[t][u](a[t]));return!0},j.prototype.setSpace=function(t,e){var n=e[0];return void 0===n?this.getValues(t):("number"==typeof n&&(n=Array.prototype.slice.call(e)),this.setValues(t,n),this)},j.prototype.setChannel=function(t,e,n){var i=this.values[t];return void 0===n?i[e]:n===i[e]?this:(i[e]=n,this.setValues(t,i),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,n){return q.valueOrDefault(q.isArray(t)?t[e]:t,n)},callback:function(t,e,n){if(t&&"function"==typeof t.call)return t.apply(n,e)},each:function(t,e,n,i){var a,r,o;if(q.isArray(t))if(r=t.length,i)for(a=r-1;a>=0;a--)e.call(n,t[a],a);else for(a=0;a<r;a++)e.call(n,t[a],a);else if(q.isObject(t))for(r=(o=Object.keys(t)).length,a=0;a<r;a++)e.call(n,t[o[a]],o[a])},arrayEquals:function(t,e){var n,i,a,r;if(!t||!e||t.length!==e.length)return!1;for(n=0,i=t.length;n<i;++n)if(a=t[n],r=e[n],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={},n=Object.keys(t),i=n.length,a=0;a<i;++a)e[n[a]]=q.clone(t[n[a]]);return e}return t},_merger:function(t,e,n,i){var a=e[t],r=n[t];q.isObject(a)&&q.isObject(r)?q.merge(a,r,i):e[t]=q.clone(r)},_mergerIf:function(t,e,n){var i=e[t],a=n[t];q.isObject(i)&&q.isObject(a)?q.mergeIf(i,a):e.hasOwnProperty(t)||(e[t]=q.clone(a))},merge:function(t,e,n){var i,a,r,o,s,l=q.isArray(e)?e:[e],u=l.length;if(!q.isObject(t))return t;for(i=(n=n||{}).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)i(r[s],t,e,n);return t},mergeIf:function(t,e){return q.merge(t,e,{merger:q._mergerIf})},extend:Object.assign||function(t){return q.merge(t,[].slice.call(arguments,1),{merger:function(t,e,n){e[t]=n[t]}})},inherits:function(t){var e=this,n=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return e.apply(this,arguments)},i=function(){this.constructor=n};return i.prototype=e.prototype,n.prototype=new i,n.extend=q.inherits,t&&q.extend(n.prototype,t),n.__super__=e.prototype,n},_deprecated:function(t,e,n,i){void 0!==e&&console.warn(t+': "'+n+'" is deprecated. Please use "'+i+'" instead')}},Z=q;q.callCallback=q.callback,q.indexOf=function(t,e,n){return Array.prototype.indexOf.call(t,e,n)},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,n=0,i=1;return 0===t?0:1===t?1:(n||(n=.3),i<1?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),-i*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/n))},easeOutElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:1===t?1:(n||(n=.3),i<1?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),i*Math.pow(2,-10*t)*Math.sin((t-e)*(2*Math.PI)/n)+1)},easeInOutElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:2==(t/=.5)?1:(n||(n=.45),i<1?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),t<1?i*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/n)*-.5:i*Math.pow(2,-10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/n)*.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,nt=2*K/3,it={clear:function(t){t.ctx.clearRect(0,0,t.width,t.height)},roundedRect:function(t,e,n,i,a,r){if(r){var o=Math.min(r,a/2,i/2),s=e+o,l=n+o,u=e+i-o,d=n+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,n),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,n)}else t.rect(e,n,i,a)},drawPoint:function(t,e,n,i,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))return t.save(),t.translate(i,a),t.rotate(h),t.drawImage(e,-e.width/2,-e.height/2,e.width,e.height),void t.restore();if(!(isNaN(n)||n<=0)){switch(t.beginPath(),e){default:t.arc(i,a,n,0,Q),t.closePath();break;case"triangle":t.moveTo(i+Math.sin(h)*n,a-Math.cos(h)*n),h+=nt,t.lineTo(i+Math.sin(h)*n,a-Math.cos(h)*n),h+=nt,t.lineTo(i+Math.sin(h)*n,a-Math.cos(h)*n),t.closePath();break;case"rectRounded":u=n-(d=.516*n),s=Math.cos(h+et)*u,l=Math.sin(h+et)*u,t.arc(i-s,a-l,d,h-K,h-tt),t.arc(i+l,a-s,d,h-tt,h),t.arc(i+s,a+l,d,h,h+tt),t.arc(i-l,a+s,d,h+tt,h+K),t.closePath();break;case"rect":if(!r){u=Math.SQRT1_2*n,t.rect(i-u,a-u,2*u,2*u);break}h+=et;case"rectRot":s=Math.cos(h)*n,l=Math.sin(h)*n,t.moveTo(i-s,a-l),t.lineTo(i+l,a-s),t.lineTo(i+s,a+l),t.lineTo(i-l,a+s),t.closePath();break;case"crossRot":h+=et;case"cross":s=Math.cos(h)*n,l=Math.sin(h)*n,t.moveTo(i-s,a-l),t.lineTo(i+s,a+l),t.moveTo(i+l,a-s),t.lineTo(i-l,a+s);break;case"star":s=Math.cos(h)*n,l=Math.sin(h)*n,t.moveTo(i-s,a-l),t.lineTo(i+s,a+l),t.moveTo(i+l,a-s),t.lineTo(i-l,a+s),h+=et,s=Math.cos(h)*n,l=Math.sin(h)*n,t.moveTo(i-s,a-l),t.lineTo(i+s,a+l),t.moveTo(i+l,a-s),t.lineTo(i-l,a+s);break;case"line":s=Math.cos(h)*n,l=Math.sin(h)*n,t.moveTo(i-s,a-l),t.lineTo(i+s,a+l);break;case"dash":t.moveTo(i,a),t.lineTo(i+Math.cos(h)*n,a+Math.sin(h)*n)}t.fill(),t.stroke()}},_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,n,i){var a=n.steppedLine;if(a){if("middle"===a){var r=(e.x+n.x)/2;t.lineTo(r,i?n.y:e.y),t.lineTo(r,i?e.y:n.y)}else"after"===a&&!i||"after"!==a&&i?t.lineTo(e.x,n.y):t.lineTo(n.x,e.y);t.lineTo(n.x,n.y)}else n.tension?t.bezierCurveTo(i?e.controlPointPreviousX:e.controlPointNextX,i?e.controlPointPreviousY:e.controlPointNextY,i?n.controlPointNextX:n.controlPointPreviousX,i?n.controlPointNextY:n.controlPointPreviousY,n.x,n.y):t.lineTo(n.x,n.y)}},at=it;Z.clear=it.clear,Z.drawRoundedRectangle=function(t){t.beginPath(),it.roundedRect.apply(it,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 n=(""+t).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);if(!n||"normal"===n[1])return 1.2*e;switch(t=+n[2],n[3]){case"px":return t;case"%":t/=100}return e*t},toPadding:function(t){var e,n,i,a;return Z.isObject(t)?(e=+t.top||0,n=+t.right||0,i=+t.bottom||0,a=+t.left||0):e=n=i=a=+t||0,{top:e,right:n,bottom:i,left:a,height:e+i,width:a+n}},_parseFont:function(t){var e=ot.global,n=st(t.fontSize,e.defaultFontSize),i={family:st(t.fontFamily,e.defaultFontFamily),lineHeight:Z.options.toLineHeight(st(t.lineHeight,e.defaultLineHeight),n),size:n,style:st(t.fontStyle,e.defaultFontStyle),weight:null,string:""};return i.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}(i),i},resolve:function(t,e,n,i){var a,r,o,s=!0;for(a=0,r=t.length;a<r;++a)if(void 0!==(o=t[a])&&(void 0!==e&&"function"==typeof o&&(o=o(e),s=!1),void 0!==n&&Z.isArray(o)&&(o=o[n],s=!1),void 0!==o))return i&&!s&&(i.cacheable=!1),o}},ut={_factorize:function(t){var e,n=[],i=Math.sqrt(t);for(e=1;e<i;e++)t%e==0&&(n.push(e),n.push(t/e));return i===(0|i)&&n.push(i),n.sort(function(t,e){return t-e}).pop(),n},log10:Math.log10||function(t){var e=Math.log(t)*Math.LOG10E,n=Math.round(e);return t===Math.pow(10,n)?n:e}},dt=ut;Z.log10=ut.log10;var ht=Z,ct=X,ft=at,gt=lt,mt=dt,pt={getRtlAdapter:function(t,e,n){return t?function(t,e){return{x:function(n){return t+t+e-n},setWidth:function(t){e=t},textAlign:function(t){return"center"===t?t:"right"===t?"left":"right"},xPlus:function(t,e){return t-e},leftForLtr:function(t,e){return t-e}}}(e,n):{x:function(t){return t},setWidth:function(t){},textAlign:function(t){return t},xPlus:function(t,e){return t+e},leftForLtr:function(t,e){return t}}},overrideTextDirection:function(t,e){var n,i;"ltr"!==e&&"rtl"!==e||(i=[(n=t.canvas.style).getPropertyValue("direction"),n.getPropertyPriority("direction")],n.setProperty("direction",e,"important"),t.prevTextDirection=i)},restoreTextDirection:function(t){var e=t.prevTextDirection;void 0!==e&&(delete t.prevTextDirection,t.canvas.style.setProperty("direction",e[0],e[1]))}};ht.easing=ct,ht.canvas=ft,ht.options=gt,ht.math=mt,ht.rtl=pt;var vt=function(t){ht.extend(this,t),this.initialize.apply(this,arguments)};ht.extend(vt.prototype,{_type:void 0,initialize:function(){this.hidden=!1},pivot:function(){var t=this;return t._view||(t._view=ht.extend({},t._model)),t._start={},t},transition:function(t){var e=this,n=e._model,i=e._start,a=e._view;return n&&1!==t?(a||(a=e._view={}),i||(i=e._start={}),function(t,e,n,i){var a,r,o,s,l,u,d,h,c,f=Object.keys(n);for(a=0,r=f.length;a<r;++a)if(u=n[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,i).rgbString();continue}}else if(ht.isFinite(l)&&ht.isFinite(u)){e[o]=l+(u-l)*i;continue}e[o]=u}}(i,a,n,t),e):(e._view=ht.extend({},n),e._start=null,e)},tooltipPosition:function(){return{x:this._model.x,y:this._model.y}},hasValue:function(){return ht.isNumber(this._model.x)&&ht.isNumber(this._model.y)}}),vt.extend=ht.inherits;var yt=vt,bt=yt.extend({chart:null,currentStep:0,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null}),xt=bt;Object.defineProperty(bt.prototype,"animationObject",{get:function(){return this}}),Object.defineProperty(bt.prototype,"chartInstance",{get:function(){return this.chart},set:function(t){this.chart=t}}),ot._set("global",{animation:{duration:1e3,easing:"easeOutQuart",onProgress:ht.noop,onComplete:ht.noop}});var _t={animations:[],request:null,addAnimation:function(t,e,n,i){var a,r,o=this.animations;for(e.chart=t,e.startTime=Date.now(),e.duration=n,i||(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=ht.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=ht.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,n,i,a=this.animations,r=0;r<a.length;)e=(t=a[r]).chart,n=t.numSteps,i=Math.floor((Date.now()-t.startTime)/t.duration*n)+1,t.currentStep=Math.min(i,n),ht.callback(t.render,[e,t],e),ht.callback(t.onAnimationProgress,[t],e),t.currentStep>=n?(ht.callback(t.onAnimationComplete,[t],e),e.animating=!1,a.splice(r,1)):++r}},wt=ht.options.resolve,kt=["push","pop","shift","splice","unshift"];function Mt(t,e){var n=t._chartjs;if(n){var i=n.listeners,a=i.indexOf(e);-1!==a&&i.splice(a,1),i.length>0||(kt.forEach(function(e){delete t[e]}),delete t._chartjs)}}var St=function(t,e){this.initialize(t,e)};ht.extend(St.prototype,{datasetElementType:null,dataElementType:null,_datasetElementOptions:["backgroundColor","borderCapStyle","borderColor","borderDash","borderDashOffset","borderJoinStyle","borderWidth"],_dataElementOptions:["backgroundColor","borderColor","borderWidth","pointStyle"],initialize:function(t,e){var n=this;n.chart=t,n.index=e,n.linkScales(),n.addElements(),n._type=n.getMeta().type},updateIndex:function(t){this.index=t},linkScales:function(){var t=this.getMeta(),e=this.chart,n=e.scales,i=this.getDataset(),a=e.options.scales;null!==t.xAxisID&&t.xAxisID in n&&!i.xAxisID||(t.xAxisID=i.xAxisID||a.xAxes[0].id),null!==t.yAxisID&&t.yAxisID in n&&!i.yAxisID||(t.yAxisID=i.yAxisID||a.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&&Mt(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,n=this.getMeta(),i=this.getDataset().data||[],a=n.data;for(t=0,e=i.length;t<e;++t)a[t]=a[t]||this.createMetaData(t);n.dataset=n.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,n=this,i=n.getDataset(),a=i.data||(i.data=[]);n._data!==a&&(n._data&&Mt(n._data,n),a&&Object.isExtensible(a)&&(e=n,(t=a)._chartjs?t._chartjs.listeners.push(e):(Object.defineProperty(t,"_chartjs",{configurable:!0,enumerable:!1,value:{listeners:[e]}}),kt.forEach(function(e){var n="onData"+e.charAt(0).toUpperCase()+e.slice(1),i=t[e];Object.defineProperty(t,e,{configurable:!0,enumerable:!1,value:function(){var e=Array.prototype.slice.call(arguments),a=i.apply(this,e);return ht.each(t._chartjs.listeners,function(t){"function"==typeof t[n]&&t[n].apply(t,e)}),a}})}))),n._data=a),n.resyncElements()},_configure:function(){this._config=ht.merge({},[this.chart.options.datasets[this._type],this.getDataset()],{merger:function(t,e,n){"_meta"!==t&&"data"!==t&&ht._merger(t,e,n)}})},_update:function(t){this._configure(),this._cachedDataOpts=null,this.update(t)},update:ht.noop,transition:function(t){for(var e=this.getMeta(),n=e.data||[],i=n.length,a=0;a<i;++a)n[a].transition(t);e.dataset&&e.dataset.transition(t)},draw:function(){var t=this.getMeta(),e=t.data||[],n=e.length,i=0;for(t.dataset&&t.dataset.draw();i<n;++i)e[i].draw()},getStyle:function(t){var e,n=this.getMeta(),i=n.dataset;return this._configure(),i&&void 0===t?e=this._resolveDatasetElementOptions(i||{}):(t=t||0,e=this._resolveDataElementOptions(n.data[t]||{},t)),!1!==e.fill&&null!==e.fill||(e.backgroundColor="rgba(0,0,0,0)"),e},_resolveDatasetElementOptions:function(t,e){var n,i,a,r,o=this,s=o.chart,l=o._config,u=t.custom||{},d=s.options.elements[o.datasetElementType.prototype._type]||{},h=o._datasetElementOptions,c={},f={chart:s,dataset:o.getDataset(),datasetIndex:o.index,hover:e};for(n=0,i=h.length;n<i;++n)a=h[n],r=e?"hover"+a.charAt(0).toUpperCase()+a.slice(1):a,c[a]=wt([u[r],l[r],d[r]],f);return c},_resolveDataElementOptions:function(t,e){var n=this,i=t&&t.custom,a=n._cachedDataOpts;if(a&&!i)return a;var r,o,s,l,u=n.chart,d=n._config,h=u.options.elements[n.dataElementType.prototype._type]||{},c=n._dataElementOptions,f={},g={chart:u,dataIndex:e,dataset:n.getDataset(),datasetIndex:n.index},m={cacheable:!i};if(i=i||{},ht.isArray(c))for(o=0,s=c.length;o<s;++o)f[l=c[o]]=wt([i[l],d[l],h[l]],g,e,m);else for(o=0,s=(r=Object.keys(c)).length;o<s;++o)f[l=r[o]]=wt([i[l],d[c[l]],d[l],h[l]],g,e,m);return m.cacheable&&(n._cachedDataOpts=Object.freeze(f)),f},removeHoverStyle:function(t){ht.merge(t._model,t.$previousStyle||{}),delete t.$previousStyle},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],n=t._index,i=t.custom||{},a=t._model,r=ht.getHoverColor;t.$previousStyle={backgroundColor:a.backgroundColor,borderColor:a.borderColor,borderWidth:a.borderWidth},a.backgroundColor=wt([i.hoverBackgroundColor,e.hoverBackgroundColor,r(a.backgroundColor)],void 0,n),a.borderColor=wt([i.hoverBorderColor,e.hoverBorderColor,r(a.borderColor)],void 0,n),a.borderWidth=wt([i.hoverBorderWidth,e.hoverBorderWidth,a.borderWidth],void 0,n)},_removeDatasetHoverStyle:function(){var t=this.getMeta().dataset;t&&this.removeHoverStyle(t)},_setDatasetHoverStyle:function(){var t,e,n,i,a,r,o=this.getMeta().dataset,s={};if(o){for(r=o._model,a=this._resolveDatasetElementOptions(o,!0),t=0,e=(i=Object.keys(a)).length;t<e;++t)s[n=i[t]]=r[n],r[n]=a[n];o.$previousStyle=s}},resyncElements:function(){var t=this.getMeta(),e=this.getDataset().data,n=t.data.length,i=e.length;i<n?t.data.splice(i,n-i):i>n&&this.insertElements(n,i-n)},insertElements:function(t,e){for(var n=0;n<e;++n)this.addElementAndReset(t+n)},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)}}),St.extend=ht.inherits;var Dt=St,Ct=2*Math.PI;function Tt(t,e){var n=e.startAngle,i=e.endAngle,a=e.pixelMargin,r=a/e.outerRadius,o=e.x,s=e.y;t.beginPath(),t.arc(o,s,e.outerRadius,n-r,i+r),e.innerRadius>a?(r=a/e.innerRadius,t.arc(o,s,e.innerRadius-a,i+r,n-r,!0)):t.arc(o,s,a,i+Math.PI/2,n-Math.PI/2),t.closePath(),t.clip()}function Pt(t,e,n){var i="inner"===e.borderAlign;i?(t.lineWidth=2*e.borderWidth,t.lineJoin="round"):(t.lineWidth=e.borderWidth,t.lineJoin="bevel"),n.fullCircles&&function(t,e,n,i){var a,r=n.endAngle;for(i&&(n.endAngle=n.startAngle+Ct,Tt(t,n),n.endAngle=r,n.endAngle===n.startAngle&&n.fullCircles&&(n.endAngle+=Ct,n.fullCircles--)),t.beginPath(),t.arc(n.x,n.y,n.innerRadius,n.startAngle+Ct,n.startAngle,!0),a=0;a<n.fullCircles;++a)t.stroke();for(t.beginPath(),t.arc(n.x,n.y,e.outerRadius,n.startAngle,n.startAngle+Ct),a=0;a<n.fullCircles;++a)t.stroke()}(t,e,n,i),i&&Tt(t,n),t.beginPath(),t.arc(n.x,n.y,e.outerRadius,n.startAngle,n.endAngle),t.arc(n.x,n.y,n.innerRadius,n.endAngle,n.startAngle,!0),t.closePath(),t.stroke()}ot._set("global",{elements:{arc:{backgroundColor:ot.global.defaultColor,borderColor:"#fff",borderWidth:2,borderAlign:"center"}}});var At=yt.extend({_type:"arc",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 n=this._view;if(n){for(var i=ht.getAngleFromPoint(n,{x:t,y:e}),a=i.angle,r=i.distance,o=n.startAngle,s=n.endAngle;s<o;)s+=Ct;for(;a>s;)a-=Ct;for(;a<o;)a+=Ct;var l=a>=o&&a<=s,u=r>=n.innerRadius&&r<=n.outerRadius;return l&&u}return!1},getCenterPoint:function(){var t=this._view,e=(t.startAngle+t.endAngle)/2,n=(t.innerRadius+t.outerRadius)/2;return{x:t.x+Math.cos(e)*n,y:t.y+Math.sin(e)*n}},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,n=(t.outerRadius-t.innerRadius)/2+t.innerRadius;return{x:t.x+Math.cos(e)*n,y:t.y+Math.sin(e)*n}},draw:function(){var t,e=this._chart.ctx,n=this._view,i="inner"===n.borderAlign?.33:0,a={x:n.x,y:n.y,innerRadius:n.innerRadius,outerRadius:Math.max(n.outerRadius-i,0),pixelMargin:i,startAngle:n.startAngle,endAngle:n.endAngle,fullCircles:Math.floor(n.circumference/Ct)};if(e.save(),e.fillStyle=n.backgroundColor,e.strokeStyle=n.borderColor,a.fullCircles){for(a.endAngle=a.startAngle+Ct,e.beginPath(),e.arc(a.x,a.y,a.outerRadius,a.startAngle,a.endAngle),e.arc(a.x,a.y,a.innerRadius,a.endAngle,a.startAngle,!0),e.closePath(),t=0;t<a.fullCircles;++t)e.fill();a.endAngle=a.startAngle+n.circumference%Ct}e.beginPath(),e.arc(a.x,a.y,a.outerRadius,a.startAngle,a.endAngle),e.arc(a.x,a.y,a.innerRadius,a.endAngle,a.startAngle,!0),e.closePath(),e.fill(),n.borderWidth&&Pt(e,n,a),e.restore()}}),Ot=ht.valueOrDefault,Ft=ot.global.defaultColor;ot._set("global",{elements:{line:{tension:.4,backgroundColor:Ft,borderWidth:3,borderColor:Ft,borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",capBezierPoints:!0,fill:!0}}});var It=yt.extend({_type:"line",draw:function(){var t,e,n,i=this,a=i._view,r=i._chart.ctx,o=a.spanGaps,s=i._children.slice(),l=ot.global,u=l.elements.line,d=-1,h=i._loop;if(s.length){if(i._loop){for(t=0;t<s.length;++t)if(e=ht.previousItem(s,t),!s[t]._view.skip&&e._view.skip){s=s.slice(t).concat(s.slice(0,t)),h=o;break}h&&s.push(s[0])}for(r.save(),r.lineCap=a.borderCapStyle||u.borderCapStyle,r.setLineDash&&r.setLineDash(a.borderDash||u.borderDash),r.lineDashOffset=Ot(a.borderDashOffset,u.borderDashOffset),r.lineJoin=a.borderJoinStyle||u.borderJoinStyle,r.lineWidth=Ot(a.borderWidth,u.borderWidth),r.strokeStyle=a.borderColor||l.defaultColor,r.beginPath(),(n=s[0]._view).skip||(r.moveTo(n.x,n.y),d=0),t=1;t<s.length;++t)n=s[t]._view,e=-1===d?ht.previousItem(s,t):s[d],n.skip||(d!==t-1&&!o||-1===d?r.moveTo(n.x,n.y):ht.canvas.lineTo(r,e._view,n),d=t);h&&r.closePath(),r.stroke(),r.restore()}}}),Lt=ht.valueOrDefault,Rt=ot.global.defaultColor;function Nt(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:Rt,borderColor:Rt,borderWidth:1,hitRadius:1,hoverRadius:4,hoverBorderWidth:1}}});var Wt=yt.extend({_type:"point",inRange:function(t,e){var n=this._view;return!!n&&Math.pow(t-n.x,2)+Math.pow(e-n.y,2)<Math.pow(n.hitRadius+n.radius,2)},inLabelRange:Nt,inXRange:Nt,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,n=this._chart.ctx,i=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||ht.canvas._isPointInArea(e,t))&&(n.strokeStyle=e.borderColor||u,n.lineWidth=Lt(e.borderWidth,l.elements.point.borderWidth),n.fillStyle=e.backgroundColor||u,ht.canvas.drawPoint(n,i,r,o,s,a))}}),Yt=ot.global.defaultColor;function zt(t){return t&&void 0!==t.width}function Vt(t){var e,n,i,a,r;return zt(t)?(r=t.width/2,e=t.x-r,n=t.x+r,i=Math.min(t.y,t.base),a=Math.max(t.y,t.base)):(r=t.height/2,e=Math.min(t.x,t.base),n=Math.max(t.x,t.base),i=t.y-r,a=t.y+r),{left:e,top:i,right:n,bottom:a}}function Et(t,e,n){return t===e?n:t===n?e:t}function Ht(t,e,n){var i,a,r,o,s=t.borderWidth,l=function(t){var e=t.borderSkipped,n={};return e?(t.horizontal?t.base>t.x&&(e=Et(e,"left","right")):t.base<t.y&&(e=Et(e,"bottom","top")),n[e]=!0,n):n}(t);return ht.isObject(s)?(i=+s.top||0,a=+s.right||0,r=+s.bottom||0,o=+s.left||0):i=a=r=o=+s||0,{t:l.top||i<0?0:i>n?n:i,r:l.right||a<0?0:a>e?e:a,b:l.bottom||r<0?0:r>n?n:r,l:l.left||o<0?0:o>e?e:o}}function Bt(t,e,n){var i=null===e,a=null===n,r=!(!t||i&&a)&&Vt(t);return r&&(i||e>=r.left&&e<=r.right)&&(a||n>=r.top&&n<=r.bottom)}ot._set("global",{elements:{rectangle:{backgroundColor:Yt,borderColor:Yt,borderSkipped:"bottom",borderWidth:0}}});var jt=yt.extend({_type:"rectangle",draw:function(){var t=this._chart.ctx,e=this._view,n=function(t){var e=Vt(t),n=e.right-e.left,i=e.bottom-e.top,a=Ht(t,n/2,i/2);return{outer:{x:e.left,y:e.top,w:n,h:i},inner:{x:e.left+a.l,y:e.top+a.t,w:n-a.l-a.r,h:i-a.t-a.b}}}(e),i=n.outer,a=n.inner;t.fillStyle=e.backgroundColor,t.fillRect(i.x,i.y,i.w,i.h),i.w===a.w&&i.h===a.h||(t.save(),t.beginPath(),t.rect(i.x,i.y,i.w,i.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 n=this._view;return zt(n)?Bt(n,t,null):Bt(n,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,n=this._view;return zt(n)?(t=n.x,e=(n.y+n.base)/2):(t=(n.x+n.base)/2,e=n.y),{x:t,y:e}},getArea:function(){var t=this._view;return zt(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}}}),Ut={},Gt=At,qt=It,Zt=Wt,$t=jt;Ut.Arc=Gt,Ut.Line=qt,Ut.Point=Zt,Ut.Rectangle=$t;var Xt=ht._deprecated,Kt=ht.valueOrDefault;function Jt(t,e,n){var i,a,r=n.barThickness,o=e.stackCount,s=e.pixels[t],l=ht.isNullOrUndef(r)?function(t,e){var n,i,a,r,o=t._length;for(a=1,r=e.length;a<r;++a)o=Math.min(o,Math.abs(e[a]-e[a-1]));for(a=0,r=t.getTicks().length;a<r;++a)i=t.getPixelForTick(a),o=a>0?Math.min(o,Math.abs(i-n)):o,n=i;return o}(e.scale,e.pixels):-1;return ht.isNullOrUndef(r)?(i=l*n.categoryPercentage,a=n.barPercentage):(i=r*o,a=1),{chunk:i/o,ratio:a,start:s-i/2}}ot._set("bar",{hover:{mode:"label"},scales:{xAxes:[{type:"category",offset:!0,gridLines:{offsetGridLines:!0}}],yAxes:[{type:"linear"}]}}),ot._set("global",{datasets:{bar:{categoryPercentage:.8,barPercentage:.9}}});var Qt=Dt.extend({dataElementType:Ut.Rectangle,_dataElementOptions:["backgroundColor","borderColor","borderSkipped","borderWidth","barPercentage","barThickness","categoryPercentage","maxBarThickness","minBarLength"],initialize:function(){var t,e,n=this;Dt.prototype.initialize.apply(n,arguments),(t=n.getMeta()).stack=n.getDataset().stack,t.bar=!0,e=n._getIndexScale().options,Xt("bar chart",e.barPercentage,"scales.[x/y]Axes.barPercentage","dataset.barPercentage"),Xt("bar chart",e.barThickness,"scales.[x/y]Axes.barThickness","dataset.barThickness"),Xt("bar chart",e.categoryPercentage,"scales.[x/y]Axes.categoryPercentage","dataset.categoryPercentage"),Xt("bar chart",n._getValueScale().options.minBarLength,"scales.[x/y]Axes.minBarLength","dataset.minBarLength"),Xt("bar chart",e.maxBarThickness,"scales.[x/y]Axes.maxBarThickness","dataset.maxBarThickness")},update:function(t){var e,n,i=this.getMeta().data;for(this._ruler=this.getRuler(),e=0,n=i.length;e<n;++e)this.updateElement(i[e],e,t)},updateElement:function(t,e,n){var i=this,a=i.getMeta(),r=i.getDataset(),o=i._resolveDataElementOptions(t,e);t._xScale=i.getScaleForId(a.xAxisID),t._yScale=i.getScaleForId(a.yAxisID),t._datasetIndex=i.index,t._index=e,t._model={backgroundColor:o.backgroundColor,borderColor:o.borderColor,borderSkipped:o.borderSkipped,borderWidth:o.borderWidth,datasetLabel:r.label,label:i.chart.data.labels[e]},ht.isArray(r.data[e])&&(t._model.borderSkipped=null),i._updateElementGeometry(t,e,n,o),t.pivot()},_updateElementGeometry:function(t,e,n,i){var a=this,r=t._model,o=a._getValueScale(),s=o.getBasePixel(),l=o.isHorizontal(),u=a._ruler||a.getRuler(),d=a.calculateBarValuePixels(a.index,e,i),h=a.calculateBarIndexPixels(a.index,e,u,i);r.horizontal=l,r.base=n?s:d.base,r.x=l?n?s:d.head:h.center,r.y=l?h.center:n?s:d.head,r.height=l?h.size:void 0,r.width=l?void 0:h.size},_getStacks:function(t){var e,n,i=this._getIndexScale(),a=i._getMatchingVisibleMetas(this._type),r=i.options.stacked,o=a.length,s=[];for(e=0;e<o&&(n=a[e],(!1===r||-1===s.indexOf(n.stack)||void 0===r&&void 0===n.stack)&&s.push(n.stack),n.index!==t);++e);return s},getStackCount:function(){return this._getStacks().length},getStackIndex:function(t,e){var n=this._getStacks(t),i=void 0!==e?n.indexOf(e):-1;return-1===i?n.length-1:i},getRuler:function(){var t,e,n=this._getIndexScale(),i=[];for(t=0,e=this.getMeta().data.length;t<e;++t)i.push(n.getPixelForValue(null,t,this.index));return{pixels:i,start:n._startPixel,end:n._endPixel,stackCount:this.getStackCount(),scale:n}},calculateBarValuePixels:function(t,e,n){var i,a,r,o,s,l,u,d=this.chart,h=this._getValueScale(),c=h.isHorizontal(),f=d.data.datasets,g=h._getMatchingVisibleMetas(this._type),m=h._parseValue(f[t].data[e]),p=n.minBarLength,v=h.options.stacked,y=this.getMeta().stack,b=void 0===m.start?0:m.max>=0&&m.min>=0?m.min:m.max,x=void 0===m.start?m.end:m.max>=0&&m.min>=0?m.max-m.min:m.min-m.max,_=g.length;if(v||void 0===v&&void 0!==y)for(i=0;i<_&&(a=g[i]).index!==t;++i)a.stack===y&&(r=void 0===(u=h._parseValue(f[a.index].data[e])).start?u.end:u.min>=0&&u.max>=0?u.max:u.min,(m.min<0&&r<0||m.max>=0&&r>0)&&(b+=r));return o=h.getPixelForValue(b),l=(s=h.getPixelForValue(b+x))-o,void 0!==p&&Math.abs(l)<p&&(l=p,s=x>=0&&!c||x<0&&c?o-p:o+p),{size:l,base:o,head:s,center:s+l/2}},calculateBarIndexPixels:function(t,e,n,i){var a="flex"===i.barThickness?function(t,e,n){var i,a=e.pixels,r=a[t],o=t>0?a[t-1]:null,s=t<a.length-1?a[t+1]:null,l=n.categoryPercentage;return null===o&&(o=r-(null===s?e.end-e.start:s-r)),null===s&&(s=r+r-o),i=r-(r-Math.min(o,s))/2*l,{chunk:Math.abs(s-o)/2*l/e.stackCount,ratio:n.barPercentage,start:i}}(e,n,i):Jt(e,n,i),r=this.getStackIndex(t,this.getMeta().stack),o=a.start+a.chunk*r+a.chunk/2,s=Math.min(Kt(i.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(),n=this.getMeta().data,i=this.getDataset(),a=n.length,r=0;for(ht.canvas.clipArea(t.ctx,t.chartArea);r<a;++r){var o=e._parseValue(i.data[r]);isNaN(o.min)||isNaN(o.max)||n[r].draw()}ht.canvas.unclipArea(t.ctx)},_resolveDataElementOptions:function(){var t=this,e=ht.extend({},Dt.prototype._resolveDataElementOptions.apply(t,arguments)),n=t._getIndexScale().options,i=t._getValueScale().options;return e.barPercentage=Kt(n.barPercentage,e.barPercentage),e.barThickness=Kt(n.barThickness,e.barThickness),e.categoryPercentage=Kt(n.categoryPercentage,e.categoryPercentage),e.maxBarThickness=Kt(n.maxBarThickness,e.maxBarThickness),e.minBarLength=Kt(i.minBarLength,e.minBarLength),e}}),te=ht.valueOrDefault,ee=ht.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 n=e.datasets[t.datasetIndex].label||"",i=e.datasets[t.datasetIndex].data[t.index];return n+": ("+t.xLabel+", "+t.yLabel+", "+i.r+")"}}}});var ne=Dt.extend({dataElementType:Ut.Point,_dataElementOptions:["backgroundColor","borderColor","borderWidth","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth","hoverRadius","hitRadius","pointStyle","rotation"],update:function(t){var e=this,n=e.getMeta().data;ht.each(n,function(n,i){e.updateElement(n,i,t)})},updateElement:function(t,e,n){var i=this,a=i.getMeta(),r=t.custom||{},o=i.getScaleForId(a.xAxisID),s=i.getScaleForId(a.yAxisID),l=i._resolveDataElementOptions(t,e),u=i.getDataset().data[e],d=i.index,h=n?o.getPixelForDecimal(.5):o.getPixelForValue("object"==typeof u?u:NaN,e,d),c=n?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:n?0:l.radius,skip:r.skip||isNaN(h)||isNaN(c),x:h,y:c},t.pivot()},setHoverStyle:function(t){var e=t._model,n=t._options,i=ht.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=te(n.hoverBackgroundColor,i(n.backgroundColor)),e.borderColor=te(n.hoverBorderColor,i(n.borderColor)),e.borderWidth=te(n.hoverBorderWidth,n.borderWidth),e.radius=n.radius+n.hoverRadius},_resolveDataElementOptions:function(t,e){var n=this,i=n.chart,a=n.getDataset(),r=t.custom||{},o=a.data[e]||{},s=Dt.prototype._resolveDataElementOptions.apply(n,arguments),l={chart:i,dataIndex:e,dataset:a,datasetIndex:n.index};return n._cachedDataOpts===s&&(s=ht.extend({},s)),s.radius=ee([r.radius,o.r,n._config.radius,i.options.elements.point.radius],l,e),s}}),ie=ht.valueOrDefault,ae=Math.PI,re=2*ae,oe=ae/2;ot._set("doughnut",{animation:{animateRotate:!0,animateScale:!1},hover:{mode:"single"},legendCallback:function(t){var e,n,i,a=document.createElement("ul"),r=t.data,o=r.datasets,s=r.labels;if(a.setAttribute("class",t.id+"-legend"),o.length)for(e=0,n=o[0].data.length;e<n;++e)(i=a.appendChild(document.createElement("li"))).appendChild(document.createElement("span")).style.backgroundColor=o[0].backgroundColor[e],s[e]&&i.appendChild(document.createTextNode(s[e]));return a.outerHTML},legend:{labels:{generateLabels:function(t){var e=t.data;return e.labels.length&&e.datasets.length?e.labels.map(function(n,i){var a=t.getDatasetMeta(0),r=a.controller.getStyle(i);return{text:n,fillStyle:r.backgroundColor,strokeStyle:r.borderColor,lineWidth:r.borderWidth,hidden:isNaN(e.datasets[0].data[i])||a.data[i].hidden,index:i}}):[]}},onClick:function(t,e){var n,i,a,r=e.index,o=this.chart;for(n=0,i=(o.data.datasets||[]).length;n<i;++n)(a=o.getDatasetMeta(n)).data[r]&&(a.data[r].hidden=!a.data[r].hidden);o.update()}},cutoutPercentage:50,rotation:-oe,circumference:re,tooltips:{callbacks:{title:function(){return""},label:function(t,e){var n=e.labels[t.index],i=": "+e.datasets[t.datasetIndex].data[t.index];return ht.isArray(n)?(n=n.slice())[0]+=i:n+=i,n}}}});var se=Dt.extend({dataElementType:Ut.Arc,linkScales:ht.noop,_dataElementOptions:["backgroundColor","borderColor","borderWidth","borderAlign","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth"],getRingIndex:function(t){for(var e=0,n=0;n<t;++n)this.chart.isDatasetVisible(n)&&++e;return e},update:function(t){var e,n,i,a,r=this,o=r.chart,s=o.chartArea,l=o.options,u=1,d=1,h=0,c=0,f=r.getMeta(),g=f.data,m=l.cutoutPercentage/100||0,p=l.circumference,v=r._getRingWeight(r.index);if(p<re){var y=l.rotation%re,b=(y+=y>=ae?-re:y<-ae?re:0)+p,x=Math.cos(y),_=Math.sin(y),w=Math.cos(b),k=Math.sin(b),M=y<=0&&b>=0||b>=re,S=y<=oe&&b>=oe||b>=re+oe,D=y<=-oe&&b>=-oe||b>=ae+oe,C=y===-ae||b>=ae?-1:Math.min(x,x*m,w,w*m),T=D?-1:Math.min(_,_*m,k,k*m),P=M?1:Math.max(x,x*m,w,w*m),A=S?1:Math.max(_,_*m,k,k*m);u=(P-C)/2,d=(A-T)/2,h=-(P+C)/2,c=-(A+T)/2}for(i=0,a=g.length;i<a;++i)g[i]._options=r._resolveDataElementOptions(g[i],i);for(o.borderWidth=r.getMaxBorderWidth(),e=(s.right-s.left-o.borderWidth)/u,n=(s.bottom-s.top-o.borderWidth)/d,o.outerRadius=Math.max(Math.min(e,n)/2,0),o.innerRadius=Math.max(o.outerRadius*m,0),o.radiusLength=(o.outerRadius-o.innerRadius)/(r._getVisibleDatasetWeightTotal()||1),o.offsetX=h*o.outerRadius,o.offsetY=c*o.outerRadius,f.total=r.calculateTotal(),r.outerRadius=o.outerRadius-o.radiusLength*r._getRingWeightOffset(r.index),r.innerRadius=Math.max(r.outerRadius-o.radiusLength*v,0),i=0,a=g.length;i<a;++i)r.updateElement(g[i],i,t)},updateElement:function(t,e,n){var i=this,a=i.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=i.getDataset(),f=n&&s.animateRotate?0:t.hidden?0:i.calculateCircumference(c.data[e])*(o.circumference/re),g=n&&s.animateScale?0:i.innerRadius,m=n&&s.animateScale?0:i.outerRadius,p=t._options||{};ht.extend(t,{_datasetIndex:i.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:ht.valueAtIndexOrDefault(c.label,e,a.data.labels[e])}});var v=t._model;n&&s.animateRotate||(v.startAngle=0===e?o.rotation:i.getMeta().data[e-1]._model.endAngle,v.endAngle=v.startAngle+v.circumference),t.pivot()},calculateTotal:function(){var t,e=this.getDataset(),n=this.getMeta(),i=0;return ht.each(n.data,function(n,a){t=e.data[a],isNaN(t)||n.hidden||(i+=Math.abs(t))}),i},calculateCircumference:function(t){var e=this.getMeta().total;return e>0&&!isNaN(t)?re*(Math.abs(t)/e):0},getMaxBorderWidth:function(t){var e,n,i,a,r,o,s,l,u=0,d=this.chart;if(!t)for(e=0,n=d.data.datasets.length;e<n;++e)if(d.isDatasetVisible(e)){t=(i=d.getDatasetMeta(e)).data,e!==this.index&&(r=i.controller);break}if(!t)return 0;for(e=0,n=t.length;e<n;++e)a=t[e],r?(r._configure(),o=r._resolveDataElementOptions(a,e)):o=a._options,"inner"!==o.borderAlign&&(s=o.borderWidth,u=(l=o.hoverBorderWidth)>(u=s>u?s:u)?l:u);return u},setHoverStyle:function(t){var e=t._model,n=t._options,i=ht.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth},e.backgroundColor=ie(n.hoverBackgroundColor,i(n.backgroundColor)),e.borderColor=ie(n.hoverBorderColor,i(n.borderColor)),e.borderWidth=ie(n.hoverBorderWidth,n.borderWidth)},_getRingWeightOffset:function(t){for(var e=0,n=0;n<t;++n)this.chart.isDatasetVisible(n)&&(e+=this._getRingWeight(n));return e},_getRingWeight:function(t){return Math.max(ie(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",offset:!0,gridLines:{offsetGridLines:!0}}]},elements:{rectangle:{borderSkipped:"left"}},tooltips:{mode:"index",axis:"y"}}),ot._set("global",{datasets:{horizontalBar:{categoryPercentage:.8,barPercentage:.9}}});var le=Qt.extend({_getValueScaleId:function(){return this.getMeta().xAxisID},_getIndexScaleId:function(){return this.getMeta().yAxisID}}),ue=ht.valueOrDefault,de=ht.options.resolve,he=ht.canvas._isPointInArea;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 ce=Dt.extend({datasetElementType:Ut.Line,dataElementType:Ut.Point,_datasetElementOptions:["backgroundColor","borderCapStyle","borderColor","borderDash","borderDashOffset","borderJoinStyle","borderWidth","cubicInterpolationMode","fill"],_dataElementOptions:{backgroundColor:"pointBackgroundColor",borderColor:"pointBorderColor",borderWidth:"pointBorderWidth",hitRadius:"pointHitRadius",hoverBackgroundColor:"pointHoverBackgroundColor",hoverBorderColor:"pointHoverBorderColor",hoverBorderWidth:"pointHoverBorderWidth",hoverRadius:"pointHoverRadius",pointStyle:"pointStyle",radius:"pointRadius",rotation:"pointRotation"},update:function(t){var e,n,i=this,a=i.getMeta(),r=a.dataset,o=a.data||[],s=i.chart.options,l=i._config,u=i._showLine=ue(l.showLine,s.showLines);for(i._xScale=i.getScaleForId(a.xAxisID),i._yScale=i.getScaleForId(a.yAxisID),u&&(void 0!==l.tension&&void 0===l.lineTension&&(l.lineTension=l.tension),r._scale=i._yScale,r._datasetIndex=i.index,r._children=o,r._model=i._resolveDatasetElementOptions(r),r.pivot()),e=0,n=o.length;e<n;++e)i.updateElement(o[e],e,t);for(u&&0!==r._model.tension&&i.updateBezierControlPoints(),e=0,n=o.length;e<n;++e)o[e].pivot()},updateElement:function(t,e,n){var i,a,r=this,o=r.getMeta(),s=t.custom||{},l=r.getDataset(),u=r.index,d=l.data[e],h=r._xScale,c=r._yScale,f=o.dataset._model,g=r._resolveDataElementOptions(t,e);i=h.getPixelForValue("object"==typeof d?d:NaN,e,u),a=n?c.getBasePixel():r.calculatePointY(d,e,u),t._xScale=h,t._yScale=c,t._options=g,t._datasetIndex=u,t._index=e,t._model={x:i,y:a,skip:s.skip||isNaN(i)||isNaN(a),radius:g.radius,pointStyle:g.pointStyle,rotation:g.rotation,backgroundColor:g.backgroundColor,borderColor:g.borderColor,borderWidth:g.borderWidth,tension:ue(s.tension,f?f.tension:0),steppedLine:!!f&&f.steppedLine,hitRadius:g.hitRadius}},_resolveDatasetElementOptions:function(t){var e=this,n=e._config,i=t.custom||{},a=e.chart.options,r=a.elements.line,o=Dt.prototype._resolveDatasetElementOptions.apply(e,arguments);return o.spanGaps=ue(n.spanGaps,a.spanGaps),o.tension=ue(n.lineTension,r.tension),o.steppedLine=de([i.steppedLine,n.steppedLine,r.stepped]),o},calculatePointY:function(t,e,n){var i,a,r,o,s=this.chart,l=this._yScale,u=0,d=0,h=+l.getRightValue(t),c=s._getSortedVisibleDatasetMetas(),f=c.length;if(l.options.stacked){for(i=0;i<f&&(r=c[i]).index!==n;++i)a=s.data.datasets[r.index],"line"===r.type&&r.yAxisID===l.id&&((o=+l.getRightValue(a.data[e]))<0?d+=o||0:u+=o||0);return h<0?l.getPixelForValue(d+h):l.getPixelForValue(u+h)}return l.getPixelForValue(t)},updateBezierControlPoints:function(){var t,e,n,i,a=this.chart,r=this.getMeta(),o=r.dataset._model,s=a.chartArea,l=r.data||[];function u(t,e,n){return Math.max(Math.min(t,n),e)}if(o.spanGaps&&(l=l.filter(function(t){return!t._model.skip})),"monotone"===o.cubicInterpolationMode)ht.splineCurveMonotone(l);else for(t=0,e=l.length;t<e;++t)n=l[t]._model,i=ht.splineCurve(ht.previousItem(l,t)._model,n,ht.nextItem(l,t)._model,o.tension),n.controlPointPreviousX=i.previous.x,n.controlPointPreviousY=i.previous.y,n.controlPointNextX=i.next.x,n.controlPointNextY=i.next.y;if(a.options.elements.line.capBezierPoints)for(t=0,e=l.length;t<e;++t)n=l[t]._model,he(n,s)&&(t>0&&he(l[t-1]._model,s)&&(n.controlPointPreviousX=u(n.controlPointPreviousX,s.left,s.right),n.controlPointPreviousY=u(n.controlPointPreviousY,s.top,s.bottom)),t<l.length-1&&he(l[t+1]._model,s)&&(n.controlPointNextX=u(n.controlPointNextX,s.left,s.right),n.controlPointNextY=u(n.controlPointNextY,s.top,s.bottom)))},draw:function(){var t,e=this.chart,n=this.getMeta(),i=n.data||[],a=e.chartArea,r=0,o=i.length;for(this._showLine&&(t=(n.dataset._model.borderWidth||0)/2,ht.canvas.clipArea(e.ctx,{left:a.left-t,right:a.right+t,top:a.top-t,bottom:a.bottom+t}),n.dataset.draw(),ht.canvas.unclipArea(e.ctx));r<o;++r)i[r].draw(a)},setHoverStyle:function(t){var e=t._model,n=t._options,i=ht.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=ue(n.hoverBackgroundColor,i(n.backgroundColor)),e.borderColor=ue(n.hoverBorderColor,i(n.borderColor)),e.borderWidth=ue(n.hoverBorderWidth,n.borderWidth),e.radius=ue(n.hoverRadius,n.radius)}}),fe=ht.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,n,i,a=document.createElement("ul"),r=t.data,o=r.datasets,s=r.labels;if(a.setAttribute("class",t.id+"-legend"),o.length)for(e=0,n=o[0].data.length;e<n;++e)(i=a.appendChild(document.createElement("li"))).appendChild(document.createElement("span")).style.backgroundColor=o[0].backgroundColor[e],s[e]&&i.appendChild(document.createTextNode(s[e]));return a.outerHTML},legend:{labels:{generateLabels:function(t){var e=t.data;return e.labels.length&&e.datasets.length?e.labels.map(function(n,i){var a=t.getDatasetMeta(0),r=a.controller.getStyle(i);return{text:n,fillStyle:r.backgroundColor,strokeStyle:r.borderColor,lineWidth:r.borderWidth,hidden:isNaN(e.datasets[0].data[i])||a.data[i].hidden,index:i}}):[]}},onClick:function(t,e){var n,i,a,r=e.index,o=this.chart;for(n=0,i=(o.data.datasets||[]).length;n<i;++n)(a=o.getDatasetMeta(n)).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 ge=Dt.extend({dataElementType:Ut.Arc,linkScales:ht.noop,_dataElementOptions:["backgroundColor","borderColor","borderWidth","borderAlign","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth"],_getIndexScaleId:function(){return this.chart.scale.id},_getValueScaleId:function(){return this.chart.scale.id},update:function(t){var e,n,i,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,n=r.data.length;e<n;e++)l[e]=s,i=a._computeAngle(e),u[e]=i,s+=i;for(e=0,n=d.length;e<n;++e)d[e]._options=a._resolveDataElementOptions(d[e],e),a.updateElement(d[e],e,t)},_updateRadius:function(){var t=this,e=t.chart,n=e.chartArea,i=e.options,a=Math.min(n.right-n.left,n.bottom-n.top);e.outerRadius=Math.max(a/2,0),e.innerRadius=Math.max(i.cutoutPercentage?e.outerRadius/100*i.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,n){var i=this,a=i.chart,r=i.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=i._starts[e],m=g+(t.hidden?0:i._angles[e]),p=s.animateScale?0:l.getDistanceFromCenterForValue(r.data[e]),v=t._options||{};ht.extend(t,{_datasetIndex:i.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:n?p:f,startAngle:n&&s.animateRotate?c:g,endAngle:n&&s.animateRotate?c:m,label:ht.valueAtIndexOrDefault(u,e,u[e])}}),t.pivot()},countVisibleElements:function(){var t=this.getDataset(),e=this.getMeta(),n=0;return ht.each(e.data,function(e,i){isNaN(t.data[i])||e.hidden||n++}),n},setHoverStyle:function(t){var e=t._model,n=t._options,i=ht.getHoverColor,a=ht.valueOrDefault;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth},e.backgroundColor=a(n.hoverBackgroundColor,i(n.backgroundColor)),e.borderColor=a(n.hoverBorderColor,i(n.borderColor)),e.borderWidth=a(n.hoverBorderWidth,n.borderWidth)},_computeAngle:function(t){var e=this,n=this.getMeta().count,i=e.getDataset(),a=e.getMeta();if(isNaN(i.data[t])||a.data[t].hidden)return 0;var r={chart:e.chart,dataIndex:t,dataset:i,datasetIndex:e.index};return fe([e.chart.options.elements.arc.angle,2*Math.PI/n],r,t)}});ot._set("pie",ht.clone(ot.doughnut)),ot._set("pie",{cutoutPercentage:0});var me=se,pe=ht.valueOrDefault;ot._set("radar",{spanGaps:!1,scale:{type:"radialLinear"},elements:{line:{tension:0}}});var ve=Dt.extend({datasetElementType:Ut.Line,dataElementType:Ut.Point,linkScales:ht.noop,_datasetElementOptions:["backgroundColor","borderWidth","borderColor","borderCapStyle","borderDash","borderDashOffset","borderJoinStyle","fill"],_dataElementOptions:{backgroundColor:"pointBackgroundColor",borderColor:"pointBorderColor",borderWidth:"pointBorderWidth",hitRadius:"pointHitRadius",hoverBackgroundColor:"pointHoverBackgroundColor",hoverBorderColor:"pointHoverBorderColor",hoverBorderWidth:"pointHoverBorderWidth",hoverRadius:"pointHoverRadius",pointStyle:"pointStyle",radius:"pointRadius",rotation:"pointRotation"},_getIndexScaleId:function(){return this.chart.scale.id},_getValueScaleId:function(){return this.chart.scale.id},update:function(t){var e,n,i=this,a=i.getMeta(),r=a.dataset,o=a.data||[],s=i.chart.scale,l=i._config;for(void 0!==l.tension&&void 0===l.lineTension&&(l.lineTension=l.tension),r._scale=s,r._datasetIndex=i.index,r._children=o,r._loop=!0,r._model=i._resolveDatasetElementOptions(r),r.pivot(),e=0,n=o.length;e<n;++e)i.updateElement(o[e],e,t);for(i.updateBezierControlPoints(),e=0,n=o.length;e<n;++e)o[e].pivot()},updateElement:function(t,e,n){var i=this,a=t.custom||{},r=i.getDataset(),o=i.chart.scale,s=o.getPointPositionForValue(e,r.data[e]),l=i._resolveDataElementOptions(t,e),u=i.getMeta().dataset._model,d=n?o.xCenter:s.x,h=n?o.yCenter:s.y;t._scale=o,t._options=l,t._datasetIndex=i.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:pe(a.tension,u?u.tension:0),hitRadius:l.hitRadius}},_resolveDatasetElementOptions:function(){var t=this,e=t._config,n=t.chart.options,i=Dt.prototype._resolveDatasetElementOptions.apply(t,arguments);return i.spanGaps=pe(e.spanGaps,n.spanGaps),i.tension=pe(e.lineTension,n.elements.line.tension),i},updateBezierControlPoints:function(){var t,e,n,i,a=this.getMeta(),r=this.chart.chartArea,o=a.data||[];function s(t,e,n){return Math.max(Math.min(t,n),e)}for(a.dataset._model.spanGaps&&(o=o.filter(function(t){return!t._model.skip})),t=0,e=o.length;t<e;++t)n=o[t]._model,i=ht.splineCurve(ht.previousItem(o,t,!0)._model,n,ht.nextItem(o,t,!0)._model,n.tension),n.controlPointPreviousX=s(i.previous.x,r.left,r.right),n.controlPointPreviousY=s(i.previous.y,r.top,r.bottom),n.controlPointNextX=s(i.next.x,r.left,r.right),n.controlPointNextY=s(i.next.y,r.top,r.bottom)},setHoverStyle:function(t){var e=t._model,n=t._options,i=ht.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=pe(n.hoverBackgroundColor,i(n.backgroundColor)),e.borderColor=pe(n.hoverBorderColor,i(n.borderColor)),e.borderWidth=pe(n.hoverBorderWidth,n.borderWidth),e.radius=pe(n.hoverRadius,n.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"}]},tooltips:{callbacks:{title:function(){return""},label:function(t){return"("+t.xLabel+", "+t.yLabel+")"}}}}),ot._set("global",{datasets:{scatter:{showLine:!1}}});var ye={bar:Qt,bubble:ne,doughnut:se,horizontalBar:le,line:ce,polarArea:ge,pie:me,radar:ve,scatter:ce};function be(t,e){return t.native?{x:t.x,y:t.y}:ht.getRelativePosition(t,e)}function xe(t,e){var n,i,a,r,o,s,l=t._getSortedVisibleDatasetMetas();for(i=0,r=l.length;i<r;++i)for(a=0,o=(n=l[i].data).length;a<o;++a)(s=n[a])._view.skip||e(s)}function _e(t,e){var n=[];return xe(t,function(t){t.inRange(e.x,e.y)&&n.push(t)}),n}function we(t,e,n,i){var a=Number.POSITIVE_INFINITY,r=[];return xe(t,function(t){if(!n||t.inRange(e.x,e.y)){var o=t.getCenterPoint(),s=i(e,o);s<a?(r=[t],a=s):s===a&&r.push(t)}}),r}function ke(t){var e=-1!==t.indexOf("x"),n=-1!==t.indexOf("y");return function(t,i){var a=e?Math.abs(t.x-i.x):0,r=n?Math.abs(t.y-i.y):0;return Math.sqrt(Math.pow(a,2)+Math.pow(r,2))}}function Me(t,e,n){var i=be(e,t);n.axis=n.axis||"x";var a=ke(n.axis),r=n.intersect?_e(t,i):we(t,i,!1,a),o=[];return r.length?(t._getSortedVisibleDatasetMetas().forEach(function(t){var e=t.data[r[0]._index];e&&!e._view.skip&&o.push(e)}),o):[]}var Se={modes:{single:function(t,e){var n=be(e,t),i=[];return xe(t,function(t){if(t.inRange(n.x,n.y))return i.push(t),i}),i.slice(0,1)},label:Me,index:Me,dataset:function(t,e,n){var i=be(e,t);n.axis=n.axis||"xy";var a=ke(n.axis),r=n.intersect?_e(t,i):we(t,i,!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 _e(t,be(e,t))},nearest:function(t,e,n){var i=be(e,t);n.axis=n.axis||"xy";var a=ke(n.axis);return we(t,i,n.intersect,a)},x:function(t,e,n){var i=be(e,t),a=[],r=!1;return xe(t,function(t){t.inXRange(i.x)&&a.push(t),t.inRange(i.x,i.y)&&(r=!0)}),n.intersect&&!r&&(a=[]),a},y:function(t,e,n){var i=be(e,t),a=[],r=!1;return xe(t,function(t){t.inYRange(i.y)&&a.push(t),t.inRange(i.x,i.y)&&(r=!0)}),n.intersect&&!r&&(a=[]),a}}},De=ht.extend;function Ce(t,e){return ht.where(t,function(t){return t.pos===e})}function Te(t,e){return t.sort(function(t,n){var i=e?n:t,a=e?t:n;return i.weight===a.weight?i.index-a.index:i.weight-a.weight})}function Pe(t,e,n,i){return Math.max(t[n],e[n])+Math.max(t[i],e[i])}function Ae(t,e,n){var i,a,r=n.box,o=t.maxPadding;if(n.size&&(t[n.pos]-=n.size),n.size=n.horizontal?r.height:r.width,t[n.pos]+=n.size,r.getPadding){var s=r.getPadding();o.top=Math.max(o.top,s.top),o.left=Math.max(o.left,s.left),o.bottom=Math.max(o.bottom,s.bottom),o.right=Math.max(o.right,s.right)}if(i=e.outerWidth-Pe(o,t,"left","right"),a=e.outerHeight-Pe(o,t,"top","bottom"),i!==t.w||a!==t.h)return t.w=i,t.h=a,n.horizontal?i!==t.w:a!==t.h}function Oe(t,e){var n=e.maxPadding;function i(t){var i={left:0,top:0,right:0,bottom:0};return t.forEach(function(t){i[t]=Math.max(e[t],n[t])}),i}return i(t?["left","right"]:["top","bottom"])}function Fe(t,e,n){var i,a,r,o,s,l,u=[];for(i=0,a=t.length;i<a;++i)(o=(r=t[i]).box).update(r.width||e.w,r.height||e.h,Oe(r.horizontal,e)),Ae(e,n,r)&&(l=!0,u.length&&(s=!0)),o.fullWidth||u.push(r);return s&&Fe(u,e,n)||l}function Ie(t,e,n){var i,a,r,o,s=n.padding,l=e.x,u=e.y;for(i=0,a=t.length;i<a;++i)o=(r=t[i]).box,r.horizontal?(o.left=o.fullWidth?s.left:e.left,o.right=o.fullWidth?n.outerWidth-s.right:e.left+e.w,o.top=u,o.bottom=u+o.height,o.width=o.right-o.left,u=o.bottom):(o.left=l,o.right=l+o.width,o.top=e.top,o.bottom=e.top+e.h,o.height=o.bottom-o.top,l=o.right);e.x=l,e.y=u}ot._set("global",{layout:{padding:{top:0,right:0,bottom:0,left:0}}});var Le={defaults:{},addBox:function(t,e){t.boxes||(t.boxes=[]),e.fullWidth=e.fullWidth||!1,e.position=e.position||"top",e.weight=e.weight||0,e._layers=e._layers||function(){return[{z:0,draw:function(){e.draw.apply(e,arguments)}}]},t.boxes.push(e)},removeBox:function(t,e){var n=t.boxes?t.boxes.indexOf(e):-1;-1!==n&&t.boxes.splice(n,1)},configure:function(t,e,n){for(var i,a=["fullWidth","position","weight"],r=a.length,o=0;o<r;++o)i=a[o],n.hasOwnProperty(i)&&(e[i]=n[i])},update:function(t,e,n){if(t){var i=t.options.layout||{},a=ht.options.toPadding(i.padding),r=e-a.width,o=n-a.height,s=function(t){var e=function(t){var e,n,i,a=[];for(e=0,n=(t||[]).length;e<n;++e)i=t[e],a.push({index:e,box:i,pos:i.position,horizontal:i.isHorizontal(),weight:i.weight});return a}(t),n=Te(Ce(e,"left"),!0),i=Te(Ce(e,"right")),a=Te(Ce(e,"top"),!0),r=Te(Ce(e,"bottom"));return{leftAndTop:n.concat(a),rightAndBottom:i.concat(r),chartArea:Ce(e,"chartArea"),vertical:n.concat(i),horizontal:a.concat(r)}}(t.boxes),l=s.vertical,u=s.horizontal,d=Object.freeze({outerWidth:e,outerHeight:n,padding:a,availableWidth:r,vBoxMaxWidth:r/2/l.length,hBoxMaxHeight:o/2}),h=De({maxPadding:De({},a),w:r,h:o,x:a.left,y:a.top},a);!function(t,e){var n,i,a;for(n=0,i=t.length;n<i;++n)(a=t[n]).width=a.horizontal?a.box.fullWidth&&e.availableWidth:e.vBoxMaxWidth,a.height=a.horizontal&&e.hBoxMaxHeight}(l.concat(u),d),Fe(l,h,d),Fe(u,h,d)&&Fe(l,h,d),function(t){var e=t.maxPadding;function n(n){var i=Math.max(e[n]-t[n],0);return t[n]+=i,i}t.y+=n("top"),t.x+=n("left"),n("right"),n("bottom")}(h),Ie(s.leftAndTop,h,d),h.x+=h.w,h.y+=h.h,Ie(s.rightAndBottom,h,d),t.chartArea={left:h.left,top:h.top,right:h.left+h.w,bottom:h.top+h.h},ht.each(s.chartArea,function(e){var n=e.box;De(n,t.chartArea),n.update(h.w,h.h)})}}};"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self&&self;function Re(){throw new Error("Dynamic requires are not currently supported by rollup-plugin-commonjs")}var Ne,We=(Ne=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}"}))&&Ne.default||Ne,Ye="$chartjs",ze="chartjs-size-monitor",Ve="chartjs-render-monitor",Ee="chartjs-render-animation",He=["animationstart","webkitAnimationStart"],Be={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"};function je(t,e){var n=ht.getStyle(t,e),i=n&&n.match(/^(\d+)(\.\d+)?px$/);return i?Number(i[1]):void 0}var Ue=!!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 Ge(t,e,n){t.addEventListener(e,n,Ue)}function qe(t,e,n){t.removeEventListener(e,n,Ue)}function Ze(t,e,n,i,a){return{type:t,chart:e,native:a||null,x:void 0!==n?n:null,y:void 0!==i?i:null}}function $e(t){var e=document.createElement("div");return e.className=t||"",e}function Xe(t,e,n){var i,a,r,o,s=t[Ye]||(t[Ye]={}),l=s.resizer=function(t){var e=$e(ze),n=$e(ze+"-expand"),i=$e(ze+"-shrink");n.appendChild($e()),i.appendChild($e()),e.appendChild(n),e.appendChild(i),e._reset=function(){n.scrollLeft=1e6,n.scrollTop=1e6,i.scrollLeft=1e6,i.scrollTop=1e6};var a=function(){e._reset(),t()};return Ge(n,"scroll",a.bind(n,"expand")),Ge(i,"scroll",a.bind(i,"shrink")),e}((i=function(){if(s.resizer){var i=n.options.maintainAspectRatio&&t.parentNode,a=i?i.clientWidth:0;e(Ze("resize",n)),i&&i.clientWidth<a&&n.canvas&&e(Ze("resize",n))}},r=!1,o=[],function(){o=Array.prototype.slice.call(arguments),a=a||this,r||(r=!0,ht.requestAnimFrame.call(window,function(){r=!1,i.apply(a,o)}))}));!function(t,e){var n=t[Ye]||(t[Ye]={}),i=n.renderProxy=function(t){t.animationName===Ee&&e()};ht.each(He,function(e){Ge(t,e,i)}),n.reflow=!!t.offsetParent,t.classList.add(Ve)}(t,function(){if(s.resizer){var e=t.parentNode;e&&e!==l.parentNode&&e.insertBefore(l,e.firstChild),l._reset()}})}function Ke(t){var e=t[Ye]||{},n=e.resizer;delete e.resizer,function(t){var e=t[Ye]||{},n=e.renderProxy;n&&(ht.each(He,function(e){qe(t,e,n)}),delete e.renderProxy),t.classList.remove(Ve)}(t),n&&n.parentNode&&n.parentNode.removeChild(n)}var Je={disableCSSInjection:!1,_enabled:"undefined"!=typeof window&&"undefined"!=typeof document,_ensureLoaded:function(t){if(!this.disableCSSInjection){var e=t.getRootNode();!function(t,e){var n=t[Ye]||(t[Ye]={});if(!n.containsStyles){n.containsStyles=!0,e="/* Chart.js */\n"+e;var i=document.createElement("style");i.setAttribute("type","text/css"),i.appendChild(document.createTextNode(e)),t.appendChild(i)}}(e.host?e:document.head,We)}},acquireContext:function(t,e){"string"==typeof t?t=document.getElementById(t):t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas);var n=t&&t.getContext&&t.getContext("2d");return n&&n.canvas===t?(this._ensureLoaded(t),function(t,e){var n=t.style,i=t.getAttribute("height"),a=t.getAttribute("width");if(t[Ye]={initial:{height:i,width:a,style:{display:n.display,height:n.height,width:n.width}}},n.display=n.display||"block",null===a||""===a){var r=je(t,"width");void 0!==r&&(t.width=r)}if(null===i||""===i)if(""===t.style.height)t.height=t.width/(e.options.aspectRatio||2);else{var o=je(t,"height");void 0!==r&&(t.height=o)}}(t,e),n):null},releaseContext:function(t){var e=t.canvas;if(e[Ye]){var n=e[Ye].initial;["height","width"].forEach(function(t){var i=n[t];ht.isNullOrUndef(i)?e.removeAttribute(t):e.setAttribute(t,i)}),ht.each(n.style||{},function(t,n){e.style[n]=t}),e.width=e.width,delete e[Ye]}},addEventListener:function(t,e,n){var i=t.canvas;if("resize"!==e){var a=n[Ye]||(n[Ye]={});Ge(i,e,(a.proxies||(a.proxies={}))[t.id+"_"+e]=function(e){n(function(t,e){var n=Be[t.type]||t.type,i=ht.getRelativePosition(t,e);return Ze(n,e,i.x,i.y,t)}(e,t))})}else Xe(i,n,t)},removeEventListener:function(t,e,n){var i=t.canvas;if("resize"!==e){var a=((n[Ye]||{}).proxies||{})[t.id+"_"+e];a&&qe(i,e,a)}else Ke(i)}};ht.addEvent=Ge,ht.removeEvent=qe;var Qe=Je._enabled?Je:{acquireContext:function(t){return t&&t.canvas&&(t=t.canvas),t&&t.getContext("2d")||null}},tn=ht.extend({initialize:function(){},acquireContext:function(){},releaseContext:function(){},addEventListener:function(){},removeEventListener:function(){}},Qe);ot._set("global",{plugins:{}});var en={_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 n=e.indexOf(t);-1!==n&&e.splice(n,1)}),this._cacheId++},clear:function(){this._plugins=[],this._cacheId++},count:function(){return this._plugins.length},getAll:function(){return this._plugins},notify:function(t,e,n){var i,a,r,o,s,l=this.descriptors(t),u=l.length;for(i=0;i<u;++i)if("function"==typeof(s=(r=(a=l[i]).plugin)[e])&&((o=[t].concat(n||[])).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 n=[],i=[],a=t&&t.config||{},r=a.options&&a.options.plugins||{};return this._plugins.concat(a.plugins||[]).forEach(function(t){if(-1===n.indexOf(t)){var e=t.id,a=r[e];!1!==a&&(!0===a&&(a=ht.clone(ot.global.plugins[e])),n.push(t),i.push({plugin:t,options:a||{}}))}}),e.descriptors=i,e.id=this._cacheId,i},_invalidate:function(t){delete t.$plugins}},nn={constructors:{},defaults:{},registerScaleType:function(t,e,n){this.constructors[t]=e,this.defaults[t]=ht.clone(n)},getScaleConstructor:function(t){return this.constructors.hasOwnProperty(t)?this.constructors[t]:void 0},getScaleDefaults:function(t){return this.defaults.hasOwnProperty(t)?ht.merge({},[ot.scale,this.defaults[t]]):{}},updateScaleDefaults:function(t,e){this.defaults.hasOwnProperty(t)&&(this.defaults[t]=ht.extend(this.defaults[t],e))},addScalesToLayout:function(t){ht.each(t.scales,function(e){e.fullWidth=e.options.fullWidth,e.position=e.options.position,e.weight=e.options.weight,Le.addBox(t,e)})}},an=ht.valueOrDefault,rn=ht.rtl.getRtlAdapter;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:ht.noop,title:function(t,e){var n="",i=e.labels,a=i?i.length:0;if(t.length>0){var r=t[0];r.label?n=r.label:r.xLabel?n=r.xLabel:a>0&&r.index<a&&(n=i[r.index])}return n},afterTitle:ht.noop,beforeBody:ht.noop,beforeLabel:ht.noop,label:function(t,e){var n=e.datasets[t.datasetIndex].label||"";return n&&(n+=": "),ht.isNullOrUndef(t.value)?n+=t.yLabel:n+=t.value,n},labelColor:function(t,e){var n=e.getDatasetMeta(t.datasetIndex).data[t.index]._view;return{borderColor:n.borderColor,backgroundColor:n.backgroundColor}},labelTextColor:function(){return this._options.bodyFontColor},afterLabel:ht.noop,afterBody:ht.noop,beforeFooter:ht.noop,footer:ht.noop,afterFooter:ht.noop}}});var on={average:function(t){if(!t.length)return!1;var e,n,i=0,a=0,r=0;for(e=0,n=t.length;e<n;++e){var o=t[e];if(o&&o.hasValue()){var s=o.tooltipPosition();i+=s.x,a+=s.y,++r}}return{x:i/r,y:a/r}},nearest:function(t,e){var n,i,a,r=e.x,o=e.y,s=Number.POSITIVE_INFINITY;for(n=0,i=t.length;n<i;++n){var l=t[n];if(l&&l.hasValue()){var u=l.getCenterPoint(),d=ht.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 sn(t,e){return e&&(ht.isArray(e)?Array.prototype.push.apply(t,e):t.push(e)),t}function ln(t){return("string"==typeof t||t instanceof String)&&t.indexOf("\n")>-1?t.split("\n"):t}function un(t){var e=ot.global;return{xPadding:t.xPadding,yPadding:t.yPadding,xAlign:t.xAlign,yAlign:t.yAlign,rtl:t.rtl,textDirection:t.textDirection,bodyFontColor:t.bodyFontColor,_bodyFontFamily:an(t.bodyFontFamily,e.defaultFontFamily),_bodyFontStyle:an(t.bodyFontStyle,e.defaultFontStyle),_bodyAlign:t.bodyAlign,bodyFontSize:an(t.bodyFontSize,e.defaultFontSize),bodySpacing:t.bodySpacing,titleFontColor:t.titleFontColor,_titleFontFamily:an(t.titleFontFamily,e.defaultFontFamily),_titleFontStyle:an(t.titleFontStyle,e.defaultFontStyle),titleFontSize:an(t.titleFontSize,e.defaultFontSize),_titleAlign:t.titleAlign,titleSpacing:t.titleSpacing,titleMarginBottom:t.titleMarginBottom,footerFontColor:t.footerFontColor,_footerFontFamily:an(t.footerFontFamily,e.defaultFontFamily),_footerFontStyle:an(t.footerFontStyle,e.defaultFontStyle),footerFontSize:an(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 dn(t,e){return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-t.xPadding:t.x+t.xPadding}function hn(t){return sn([],ln(t))}var cn=yt.extend({initialize:function(){this._model=un(this._options),this._lastActive=[]},getTitle:function(){var t=this,e=t._options,n=e.callbacks,i=n.beforeTitle.apply(t,arguments),a=n.title.apply(t,arguments),r=n.afterTitle.apply(t,arguments),o=[];return o=sn(o,ln(i)),o=sn(o,ln(a)),o=sn(o,ln(r))},getBeforeBody:function(){return hn(this._options.callbacks.beforeBody.apply(this,arguments))},getBody:function(t,e){var n=this,i=n._options.callbacks,a=[];return ht.each(t,function(t){var r={before:[],lines:[],after:[]};sn(r.before,ln(i.beforeLabel.call(n,t,e))),sn(r.lines,i.label.call(n,t,e)),sn(r.after,ln(i.afterLabel.call(n,t,e))),a.push(r)}),a},getAfterBody:function(){return hn(this._options.callbacks.afterBody.apply(this,arguments))},getFooter:function(){var t=this,e=t._options.callbacks,n=e.beforeFooter.apply(t,arguments),i=e.footer.apply(t,arguments),a=e.afterFooter.apply(t,arguments),r=[];return r=sn(r,ln(n)),r=sn(r,ln(i)),r=sn(r,ln(a))},update:function(t){var e,n,i,a,r,o,s,l,u,d,h=this,c=h._options,f=h._model,g=h._model=un(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 _=[],w=[];x=on[c.position].call(h,m,h._eventPosition);var k=[];for(e=0,n=m.length;e<n;++e)k.push((i=m[e],a=void 0,r=void 0,o=void 0,s=void 0,l=void 0,u=void 0,d=void 0,a=i._xScale,r=i._yScale||i._scale,o=i._index,s=i._datasetIndex,l=i._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:i._model.x,y:i._model.y}));c.filter&&(k=k.filter(function(t){return c.filter(t,p)})),c.itemSort&&(k=k.sort(function(t,e){return c.itemSort(t,e,p)})),ht.each(k,function(t){_.push(c.callbacks.labelColor.call(h,t,h._chart)),w.push(c.callbacks.labelTextColor.call(h,t,h._chart))}),g.title=h.getTitle(k,p),g.beforeBody=h.getBeforeBody(k,p),g.body=h.getBody(k,p),g.afterBody=h.getAfterBody(k,p),g.footer=h.getFooter(k,p),g.x=x.x,g.y=x.y,g.caretPadding=c.caretPadding,g.labelColors=_,g.labelTextColors=w,g.dataPoints=k,b=function(t,e){var n=t._chart.ctx,i=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;i+=s*u,i+=s?(s-1)*e.titleSpacing:0,i+=s?e.titleMarginBottom:0,i+=o*d,i+=o?(o-1)*e.bodySpacing:0,i+=l?e.footerMarginTop:0,i+=l*h,i+=l?(l-1)*e.footerSpacing:0;var c=0,f=function(t){a=Math.max(a,n.measureText(t).width+c)};return n.font=ht.fontString(u,e._titleFontStyle,e._titleFontFamily),ht.each(e.title,f),n.font=ht.fontString(d,e._bodyFontStyle,e._bodyFontFamily),ht.each(e.beforeBody.concat(e.afterBody),f),c=e.displayColors?d+2:0,ht.each(r,function(t){ht.each(t.before,f),ht.each(t.lines,f),ht.each(t.after,f)}),c=0,n.font=ht.fontString(h,e._footerFontStyle,e._footerFontFamily),ht.each(e.footer,f),{width:a+=2*e.xPadding,height:i}}(this,g),y=function(t,e,n,i){var a=t.x,r=t.y,o=t.caretSize,s=t.caretPadding,l=t.cornerRadius,u=n.xAlign,d=n.yAlign,h=o+s,c=l+s;return"right"===u?a-=e.width:"center"===u&&((a-=e.width/2)+e.width>i.width&&(a=i.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 n,i,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?(n=function(t){return t<=c},i=function(t){return t>c}):(n=function(t){return t<=e.width/2},i=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"},n(s.x)?(d="left",a(s.x)&&(d="center",h=o(s.y))):i(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 n=this._chart.ctx,i=this._view,a=this.getCaretPosition(t,e,i);n.lineTo(a.x1,a.y1),n.lineTo(a.x2,a.y2),n.lineTo(a.x3,a.y3)},getCaretPosition:function(t,e,n){var i,a,r,o,s,l,u=n.caretSize,d=n.cornerRadius,h=n.xAlign,c=n.yAlign,f=t.x,g=t.y,m=e.width,p=e.height;if("center"===c)s=g+p/2,"left"===h?(a=(i=f)-u,r=i,o=s+u,l=s-u):(a=(i=f+m)+u,r=i,o=s-u,l=s+u);else if("left"===h?(i=(a=f+d+u)-u,r=a+u):"right"===h?(i=(a=f+m-d-u)-u,r=a+u):(i=(a=n.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=i,i=v}return{x1:i,x2:a,x3:r,y1:o,y2:s,y3:l}},drawTitle:function(t,e,n){var i,a,r,o=e.title,s=o.length;if(s){var l=rn(e.rtl,e.x,e.width);for(t.x=dn(e,e._titleAlign),n.textAlign=l.textAlign(e._titleAlign),n.textBaseline="middle",i=e.titleFontSize,a=e.titleSpacing,n.fillStyle=e.titleFontColor,n.font=ht.fontString(i,e._titleFontStyle,e._titleFontFamily),r=0;r<s;++r)n.fillText(o[r],l.x(t.x),t.y+i/2),t.y+=i+a,r+1===s&&(t.y+=e.titleMarginBottom-a)}},drawBody:function(t,e,n){var i,a,r,o,s,l,u,d,h=e.bodyFontSize,c=e.bodySpacing,f=e._bodyAlign,g=e.body,m=e.displayColors,p=0,v=m?dn(e,"left"):0,y=rn(e.rtl,e.x,e.width),b=function(e){n.fillText(e,y.x(t.x+p),t.y+h/2),t.y+=h+c},x=y.textAlign(f);for(n.textAlign=f,n.textBaseline="middle",n.font=ht.fontString(h,e._bodyFontStyle,e._bodyFontFamily),t.x=dn(e,x),n.fillStyle=e.bodyFontColor,ht.each(e.beforeBody,b),p=m&&"right"!==x?"center"===f?h/2+1:h+2:0,s=0,u=g.length;s<u;++s){for(i=g[s],a=e.labelTextColors[s],r=e.labelColors[s],n.fillStyle=a,ht.each(i.before,b),l=0,d=(o=i.lines).length;l<d;++l){if(m){var _=y.x(v);n.fillStyle=e.legendColorBackground,n.fillRect(y.leftForLtr(_,h),t.y,h,h),n.lineWidth=1,n.strokeStyle=r.borderColor,n.strokeRect(y.leftForLtr(_,h),t.y,h,h),n.fillStyle=r.backgroundColor,n.fillRect(y.leftForLtr(y.xPlus(_,1),h-2),t.y+1,h-2,h-2),n.fillStyle=a}b(o[l])}ht.each(i.after,b)}p=0,ht.each(e.afterBody,b),t.y-=c},drawFooter:function(t,e,n){var i,a,r=e.footer,o=r.length;if(o){var s=rn(e.rtl,e.x,e.width);for(t.x=dn(e,e._footerAlign),t.y+=e.footerMarginTop,n.textAlign=s.textAlign(e._footerAlign),n.textBaseline="middle",i=e.footerFontSize,n.fillStyle=e.footerFontColor,n.font=ht.fontString(i,e._footerFontStyle,e._footerFontFamily),a=0;a<o;++a)n.fillText(r[a],s.x(t.x),t.y+i/2),t.y+=i+e.footerSpacing}},drawBackground:function(t,e,n,i){n.fillStyle=e.backgroundColor,n.strokeStyle=e.borderColor,n.lineWidth=e.borderWidth;var a=e.xAlign,r=e.yAlign,o=t.x,s=t.y,l=i.width,u=i.height,d=e.cornerRadius;n.beginPath(),n.moveTo(o+d,s),"top"===r&&this.drawCaret(t,i),n.lineTo(o+l-d,s),n.quadraticCurveTo(o+l,s,o+l,s+d),"center"===r&&"right"===a&&this.drawCaret(t,i),n.lineTo(o+l,s+u-d),n.quadraticCurveTo(o+l,s+u,o+l-d,s+u),"bottom"===r&&this.drawCaret(t,i),n.lineTo(o+d,s+u),n.quadraticCurveTo(o,s+u,o,s+u-d),"center"===r&&"left"===a&&this.drawCaret(t,i),n.lineTo(o,s+d),n.quadraticCurveTo(o,s,o+d,s),n.closePath(),n.fill(),e.borderWidth>0&&n.stroke()},draw:function(){var t=this._chart.ctx,e=this._view;if(0!==e.opacity){var n={width:e.width,height:e.height},i={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(i,e,t,n),i.y+=e.yPadding,ht.rtl.overrideTextDirection(t,e.textDirection),this.drawTitle(i,e,t),this.drawBody(i,e,t),this.drawFooter(i,e,t),ht.rtl.restoreTextDirection(t,e.textDirection),t.restore())}},handleEvent:function(t){var e,n=this,i=n._options;return n._lastActive=n._lastActive||[],"mouseout"===t.type?n._active=[]:(n._active=n._chart.getElementsAtEventForMode(t,i.mode,i),i.reverse&&n._active.reverse()),(e=!ht.arrayEquals(n._active,n._lastActive))&&(n._lastActive=n._active,(i.enabled||i.custom)&&(n._eventPosition={x:t.x,y:t.y},n.update(!0),n.pivot())),e}}),fn=on,gn=cn;gn.positioners=fn;var mn=ht.valueOrDefault;function pn(){return ht.merge({},[].slice.call(arguments),{merger:function(t,e,n,i){if("xAxes"===t||"yAxes"===t){var a,r,o,s=n[t].length;for(e[t]||(e[t]=[]),a=0;a<s;++a)o=n[t][a],r=mn(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?ht.merge(e[t][a],[nn.getScaleDefaults(r),o]):ht.merge(e[t][a],o)}else ht._merger(t,e,n,i)}})}function vn(){return ht.merge({},[].slice.call(arguments),{merger:function(t,e,n,i){var a=e[t]||{},r=n[t];"scales"===t?e[t]=pn(a,r):"scale"===t?e[t]=ht.merge(a,[nn.getScaleDefaults(r.type),r]):ht._merger(t,e,n,i)}})}function yn(t){var e=t.options;ht.each(t.scales,function(e){Le.removeBox(t,e)}),e=vn(ot.global,ot[t.config.type],e),t.options=t.config.options=e,t.ensureScalesHaveIDs(),t.buildOrUpdateScales(),t.tooltip._options=e.tooltips,t.tooltip.initialize()}function bn(t,e,n){var i,a=function(t){return t.id===i};do{i=e+n++}while(ht.findIndex(t,a)>=0);return i}function xn(t){return"top"===t||"bottom"===t}function _n(t,e){return function(n,i){return n[t]===i[t]?n[e]-i[e]:n[t]-i[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 wn=function(t,e){return this.construct(t,e),this};ht.extend(wn.prototype,{construct:function(t,e){var n=this;e=function(t){var e=(t=t||{}).data=t.data||{};return e.datasets=e.datasets||[],e.labels=e.labels||[],t.options=vn(ot.global,ot[t.type],t.options||{}),t}(e);var i=tn.acquireContext(t,e),a=i&&i.canvas,r=a&&a.height,o=a&&a.width;n.id=ht.uid(),n.ctx=i,n.canvas=a,n.config=e,n.width=o,n.height=r,n.aspectRatio=r?o/r:null,n.options=e.options,n._bufferedRender=!1,n._layers=[],n.chart=n,n.controller=n,wn.instances[n.id]=n,Object.defineProperty(n,"data",{get:function(){return n.config.data},set:function(t){n.config.data=t}}),i&&a?(n.initialize(),n.update()):console.error("Failed to create chart: can't acquire context from the given item")},initialize:function(){var t=this;return en.notify(t,"beforeInit"),ht.retinaScale(t,t.options.devicePixelRatio),t.bindEvents(),t.options.responsive&&t.resize(!0),t.initToolTip(),en.notify(t,"afterInit"),t},clear:function(){return ht.canvas.clear(this),this},stop:function(){return _t.cancelAnimation(this),this},resize:function(t){var e=this,n=e.options,i=e.canvas,a=n.maintainAspectRatio&&e.aspectRatio||null,r=Math.max(0,Math.floor(ht.getMaximumWidth(i))),o=Math.max(0,Math.floor(a?r/a:ht.getMaximumHeight(i)));if((e.width!==r||e.height!==o)&&(i.width=e.width=r,i.height=e.height=o,i.style.width=r+"px",i.style.height=o+"px",ht.retinaScale(e,n.devicePixelRatio),!t)){var s={width:r,height:o};en.notify(e,"resize",[s]),n.onResize&&n.onResize(e,s),e.stop(),e.update({duration:n.responsiveAnimationDuration})}},ensureScalesHaveIDs:function(){var t=this.options,e=t.scales||{},n=t.scale;ht.each(e.xAxes,function(t,n){t.id||(t.id=bn(e.xAxes,"x-axis-",n))}),ht.each(e.yAxes,function(t,n){t.id||(t.id=bn(e.yAxes,"y-axis-",n))}),n&&(n.id=n.id||"scale")},buildOrUpdateScales:function(){var t=this,e=t.options,n=t.scales||{},i=[],a=Object.keys(n).reduce(function(t,e){return t[e]=!1,t},{});e.scales&&(i=i.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&&i.push({options:e.scale,dtype:"radialLinear",isDefault:!0,dposition:"chartArea"}),ht.each(i,function(e){var i=e.options,r=i.id,o=mn(i.type,e.dtype);xn(i.position)!==xn(e.dposition)&&(i.position=e.dposition),a[r]=!0;var s=null;if(r in n&&n[r].type===o)(s=n[r]).options=i,s.ctx=t.ctx,s.chart=t;else{var l=nn.getScaleConstructor(o);if(!l)return;s=new l({id:r,type:o,options:i,ctx:t.ctx,chart:t}),n[s.id]=s}s.mergeTicksOptions(),e.isDefault&&(t.scale=s)}),ht.each(a,function(t,e){t||delete n[e]}),t.scales=n,nn.addScalesToLayout(this)},buildOrUpdateControllers:function(){var t,e,n=this,i=[],a=n.data.datasets;for(t=0,e=a.length;t<e;t++){var r=a[t],o=n.getDatasetMeta(t),s=r.type||n.config.type;if(o.type&&o.type!==s&&(n.destroyDatasetMeta(t),o=n.getDatasetMeta(t)),o.type=s,o.order=r.order||0,o.index=t,o.controller)o.controller.updateIndex(t),o.controller.linkScales();else{var l=ye[o.type];if(void 0===l)throw new Error('"'+o.type+'" is not a chart type.');o.controller=new l(n,t),i.push(o.controller)}}return i},resetElements:function(){var t=this;ht.each(t.data.datasets,function(e,n){t.getDatasetMeta(n).controller.reset()},t)},reset:function(){this.resetElements(),this.tooltip.initialize()},update:function(t){var e,n,i=this;if(t&&"object"==typeof t||(t={duration:t,lazy:arguments[1]}),yn(i),en._invalidate(i),!1!==en.notify(i,"beforeUpdate")){i.tooltip._data=i.data;var a=i.buildOrUpdateControllers();for(e=0,n=i.data.datasets.length;e<n;e++)i.getDatasetMeta(e).controller.buildOrUpdateElements();i.updateLayout(),i.options.animation&&i.options.animation.duration&&ht.each(a,function(t){t.reset()}),i.updateDatasets(),i.tooltip.initialize(),i.lastActive=[],en.notify(i,"afterUpdate"),i._layers.sort(_n("z","_idx")),i._bufferedRender?i._bufferedRequest={duration:t.duration,easing:t.easing,lazy:t.lazy}:i.render(t)}},updateLayout:function(){var t=this;!1!==en.notify(t,"beforeLayout")&&(Le.update(this,this.width,this.height),t._layers=[],ht.each(t.boxes,function(e){e._configure&&e._configure(),t._layers.push.apply(t._layers,e._layers())},t),t._layers.forEach(function(t,e){t._idx=e}),en.notify(t,"afterScaleUpdate"),en.notify(t,"afterLayout"))},updateDatasets:function(){if(!1!==en.notify(this,"beforeDatasetsUpdate")){for(var t=0,e=this.data.datasets.length;t<e;++t)this.updateDataset(t);en.notify(this,"afterDatasetsUpdate")}},updateDataset:function(t){var e=this.getDatasetMeta(t),n={meta:e,index:t};!1!==en.notify(this,"beforeDatasetUpdate",[n])&&(e.controller._update(),en.notify(this,"afterDatasetUpdate",[n]))},render:function(t){var e=this;t&&"object"==typeof t||(t={duration:t,lazy:arguments[1]});var n=e.options.animation,i=mn(t.duration,n&&n.duration),a=t.lazy;if(!1!==en.notify(e,"beforeRender")){var r=function(t){en.notify(e,"afterRender"),ht.callback(n&&n.onComplete,[t],e)};if(n&&i){var o=new xt({numSteps:i/16.66,easing:t.easing||n.easing,render:function(t,e){var n=ht.easing.effects[e.easing],i=e.currentStep,a=i/e.numSteps;t.draw(n(a),a,i)},onAnimationProgress:n.onProgress,onAnimationComplete:r});_t.addAnimation(e,o,i,a)}else e.draw(),r(new xt({numSteps:0,chart:e}));return e}},draw:function(t){var e,n,i=this;if(i.clear(),ht.isNullOrUndef(t)&&(t=1),i.transition(t),!(i.width<=0||i.height<=0)&&!1!==en.notify(i,"beforeDraw",[t])){for(n=i._layers,e=0;e<n.length&&n[e].z<=0;++e)n[e].draw(i.chartArea);for(i.drawDatasets(t);e<n.length;++e)n[e].draw(i.chartArea);i._drawTooltip(t),en.notify(i,"afterDraw",[t])}},transition:function(t){for(var e=0,n=(this.data.datasets||[]).length;e<n;++e)this.isDatasetVisible(e)&&this.getDatasetMeta(e).controller.transition(t);this.tooltip.transition(t)},_getSortedDatasetMetas:function(t){var e,n,i=[];for(e=0,n=(this.data.datasets||[]).length;e<n;++e)t&&!this.isDatasetVisible(e)||i.push(this.getDatasetMeta(e));return i.sort(_n("order","index")),i},_getSortedVisibleDatasetMetas:function(){return this._getSortedDatasetMetas(!0)},drawDatasets:function(t){var e,n;if(!1!==en.notify(this,"beforeDatasetsDraw",[t])){for(n=(e=this._getSortedVisibleDatasetMetas()).length-1;n>=0;--n)this.drawDataset(e[n],t);en.notify(this,"afterDatasetsDraw",[t])}},drawDataset:function(t,e){var n={meta:t,index:t.index,easingValue:e};!1!==en.notify(this,"beforeDatasetDraw",[n])&&(t.controller.draw(e),en.notify(this,"afterDatasetDraw",[n]))},_drawTooltip:function(t){var e=this.tooltip,n={tooltip:e,easingValue:t};!1!==en.notify(this,"beforeTooltipDraw",[n])&&(e.draw(),en.notify(this,"afterTooltipDraw",[n]))},getElementAtEvent:function(t){return Se.modes.single(this,t)},getElementsAtEvent:function(t){return Se.modes.label(this,t,{intersect:!0})},getElementsAtXAxis:function(t){return Se.modes["x-axis"](this,t,{intersect:!0})},getElementsAtEventForMode:function(t,e,n){var i=Se.modes[e];return"function"==typeof i?i(this,t,n):[]},getDatasetAtEvent:function(t){return Se.modes.dataset(this,t,{intersect:!0})},getDatasetMeta:function(t){var e=this.data.datasets[t];e._meta||(e._meta={});var n=e._meta[this.id];return n||(n=e._meta[this.id]={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:e.order||0,index:t}),n},getVisibleDatasetCount:function(){for(var t=0,e=0,n=this.data.datasets.length;e<n;++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,n=this.data.datasets[t],i=n._meta&&n._meta[e];i&&(i.controller.destroy(),delete n._meta[e])},destroy:function(){var t,e,n=this,i=n.canvas;for(n.stop(),t=0,e=n.data.datasets.length;t<e;++t)n.destroyDatasetMeta(t);i&&(n.unbindEvents(),ht.canvas.clear(n),tn.releaseContext(n.ctx),n.canvas=null,n.ctx=null),en.notify(n,"destroy"),delete wn.instances[n.id]},toBase64Image:function(){return this.canvas.toDataURL.apply(this.canvas,arguments)},initToolTip:function(){var t=this;t.tooltip=new gn({_chart:t,_chartInstance:t,_data:t.data,_options:t.options.tooltips},t)},bindEvents:function(){var t=this,e=t._listeners={},n=function(){t.eventHandler.apply(t,arguments)};ht.each(t.options.events,function(i){tn.addEventListener(t,i,n),e[i]=n}),t.options.responsive&&(n=function(){t.resize()},tn.addEventListener(t,"resize",n),e.resize=n)},unbindEvents:function(){var t=this,e=t._listeners;e&&(delete t._listeners,ht.each(e,function(e,n){tn.removeEventListener(t,n,e)}))},updateHoverStyle:function(t,e,n){var i,a,r,o=n?"set":"remove";for(a=0,r=t.length;a<r;++a)(i=t[a])&&this.getDatasetMeta(i._datasetIndex).controller[o+"HoverStyle"](i);"dataset"===e&&this.getDatasetMeta(t[0]._datasetIndex).controller["_"+o+"DatasetHoverStyle"]()},eventHandler:function(t){var e=this,n=e.tooltip;if(!1!==en.notify(e,"beforeEvent",[t])){e._bufferedRender=!0,e._bufferedRequest=null;var i=e.handleEvent(t);n&&(i=n._start?n.handleEvent(t):i|n.handleEvent(t)),en.notify(e,"afterEvent",[t]);var a=e._bufferedRequest;return a?e.render(a):i&&!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,n=this,i=n.options||{},a=i.hover;return n.lastActive=n.lastActive||[],"mouseout"===t.type?n.active=[]:n.active=n.getElementsAtEventForMode(t,a.mode,a),ht.callback(i.onHover||i.hover.onHover,[t.native,n.active],n),"mouseup"!==t.type&&"click"!==t.type||i.onClick&&i.onClick.call(n,t.native,n.active),n.lastActive.length&&n.updateHoverStyle(n.lastActive,a.mode,!1),n.active.length&&a.mode&&n.updateHoverStyle(n.active,a.mode,!0),e=!ht.arrayEquals(n.active,n.lastActive),n.lastActive=n.active,e}}),wn.instances={};var kn=wn;wn.Controller=wn,wn.types={},ht.configMerge=vn,ht.scaleMerge=pn;function Mn(){throw new Error("This method is not implemented: either no adapter can be found or an incomplete integration was provided.")}function Sn(t){this.options=t||{}}ht.extend(Sn.prototype,{formats:Mn,parse:Mn,format:Mn,add:Mn,diff:Mn,startOf:Mn,endOf:Mn,_create:function(t){return t}}),Sn.override=function(t){ht.extend(Sn.prototype,t)};var Dn={_date:Sn},Cn={formatters:{values:function(t){return ht.isArray(t)?t:""+t},linear:function(t,e,n){var i=n.length>3?n[2]-n[1]:n[1]-n[0];Math.abs(i)>1&&t!==Math.floor(t)&&(i=t-Math.floor(t));var a=ht.log10(Math.abs(i)),r="";if(0!==t)if(Math.max(Math.abs(n[0]),Math.abs(n[n.length-1]))<1e-4){var o=ht.log10(Math.abs(t)),s=Math.floor(o)-Math.floor(a);s=Math.max(Math.min(s,20),0),r=t.toExponential(s)}else{var l=-1*Math.floor(a);l=Math.max(Math.min(l,20),0),r=t.toFixed(l)}else r="0";return r},logarithmic:function(t,e,n){var i=t/Math.pow(10,Math.floor(ht.log10(t)));return 0===t?"0":1===i||2===i||5===i||0===e||e===n.length-1?t.toExponential():""}}},Tn=ht.isArray,Pn=ht.isNullOrUndef,An=ht.valueOrDefault,On=ht.valueAtIndexOrDefault;function Fn(t,e,n){var i,a=t.getTicks().length,r=Math.min(e,a-1),o=t.getPixelForTick(r),s=t._startPixel,l=t._endPixel;if(!(n&&(i=1===a?Math.max(o-s,l-o):0===e?(t.getPixelForTick(1)-o)/2:(o-t.getPixelForTick(r-1))/2,(o+=r<e?i:-i)<s-1e-6||o>l+1e-6)))return o}function In(t,e,n,i){var a,r,o,s,l,u,d,h,c,f,g,m,p,v=n.length,y=[],b=[],x=[];for(a=0;a<v;++a){if(s=n[a].label,l=n[a].major?e.major:e.minor,t.font=u=l.string,d=i[u]=i[u]||{data:{},gc:[]},h=l.lineHeight,c=f=0,Pn(s)||Tn(s)){if(Tn(s))for(r=0,o=s.length;r<o;++r)g=s[r],Pn(g)||Tn(g)||(c=ht.measureText(t,d.data,d.gc,c,g),f+=h)}else c=ht.measureText(t,d.data,d.gc,c,s),f=h;y.push(c),b.push(f),x.push(h/2)}function _(t){return{width:y[t]||0,height:b[t]||0,offset:x[t]||0}}return function(t,e){ht.each(t,function(t){var n,i=t.gc,a=i.length/2;if(a>e){for(n=0;n<a;++n)delete t.data[i[n]];i.splice(0,a)}})}(i,v),m=y.indexOf(Math.max.apply(null,y)),p=b.indexOf(Math.max.apply(null,b)),{first:_(0),last:_(v-1),widest:_(m),highest:_(p)}}function Ln(t){return t.drawTicks?t.tickMarkLength:0}function Rn(t){var e,n;return t.display?(e=ht.options._parseFont(t),n=ht.options.toPadding(t.padding),e.lineHeight+n.height):0}function Nn(t,e){return ht.extend(ht.options._parseFont({fontFamily:An(e.fontFamily,t.fontFamily),fontSize:An(e.fontSize,t.fontSize),fontStyle:An(e.fontStyle,t.fontStyle),lineHeight:An(e.lineHeight,t.lineHeight)}),{color:ht.options.resolve([e.fontColor,t.fontColor,ot.global.defaultFontColor])})}function Wn(t){var e=Nn(t,t.minor);return{minor:e,major:t.major.enabled?Nn(t,t.major):e}}function Yn(t){var e,n,i,a=[];for(n=0,i=t.length;n<i;++n)void 0!==(e=t[n])._index&&a.push(e);return a}function zn(t,e,n,i){var a,r,o,s,l=An(n,0),u=Math.min(An(i,t.length),t.length),d=0;for(e=Math.ceil(e),i&&(e=(a=i-n)/Math.floor(a/e)),s=l;s<0;)d++,s=Math.round(l+d*e);for(r=Math.max(l,0);r<u;r++)o=t[r],r===s?(o._index=r,d++,s=Math.round(l+d*e)):delete o.label}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:Cn.formatters.values,minor:{},major:{}}});var Vn=yt.extend({zeroLineIndex:0,getPadding:function(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}},getTicks:function(){return this._ticks},_getLabels:function(){var t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels},mergeTicksOptions:function(){},beforeUpdate:function(){ht.callback(this.options.beforeUpdate,[this])},update:function(t,e,n){var i,a,r,o,s,l=this,u=l.options.ticks,d=u.sampleSize;if(l.beforeUpdate(),l.maxWidth=t,l.maxHeight=e,l.margins=ht.extend({left:0,right:0,top:0,bottom:0},n),l._ticks=null,l.ticks=null,l._labelSizes=null,l._maxLabelLines=0,l.longestLabelWidth=0,l.longestTextCache=l.longestTextCache||{},l._gridLineItems=null,l._labelItems=null,l.beforeSetDimensions(),l.setDimensions(),l.afterSetDimensions(),l.beforeDataLimits(),l.determineDataLimits(),l.afterDataLimits(),l.beforeBuildTicks(),o=l.buildTicks()||[],(!(o=l.afterBuildTicks(o)||o)||!o.length)&&l.ticks)for(o=[],i=0,a=l.ticks.length;i<a;++i)o.push({value:l.ticks[i],major:!1});return l._ticks=o,s=d<o.length,r=l._convertTicksToLabels(s?function(t,e){for(var n=[],i=t.length/e,a=0,r=t.length;a<r;a+=i)n.push(t[Math.floor(a)]);return n}(o,d):o),l._configure(),l.beforeCalculateTickRotation(),l.calculateTickRotation(),l.afterCalculateTickRotation(),l.beforeFit(),l.fit(),l.afterFit(),l._ticksToDraw=u.display&&(u.autoSkip||"auto"===u.source)?l._autoSkip(o):o,s&&(r=l._convertTicksToLabels(l._ticksToDraw)),l.ticks=r,l.afterUpdate(),l.minSize},_configure:function(){var t,e,n=this,i=n.options.ticks.reverse;n.isHorizontal()?(t=n.left,e=n.right):(t=n.top,e=n.bottom,i=!i),n._startPixel=t,n._endPixel=e,n._reversePixels=i,n._length=e-t},afterUpdate:function(){ht.callback(this.options.afterUpdate,[this])},beforeSetDimensions:function(){ht.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(){ht.callback(this.options.afterSetDimensions,[this])},beforeDataLimits:function(){ht.callback(this.options.beforeDataLimits,[this])},determineDataLimits:ht.noop,afterDataLimits:function(){ht.callback(this.options.afterDataLimits,[this])},beforeBuildTicks:function(){ht.callback(this.options.beforeBuildTicks,[this])},buildTicks:ht.noop,afterBuildTicks:function(t){var e=this;return Tn(t)&&t.length?ht.callback(e.options.afterBuildTicks,[e,t]):(e.ticks=ht.callback(e.options.afterBuildTicks,[e,e.ticks])||e.ticks,t)},beforeTickToLabelConversion:function(){ht.callback(this.options.beforeTickToLabelConversion,[this])},convertTicksToLabels:function(){var t=this.options.ticks;this.ticks=this.ticks.map(t.userCallback||t.callback,this)},afterTickToLabelConversion:function(){ht.callback(this.options.afterTickToLabelConversion,[this])},beforeCalculateTickRotation:function(){ht.callback(this.options.beforeCalculateTickRotation,[this])},calculateTickRotation:function(){var t,e,n,i,a,r,o,s=this,l=s.options,u=l.ticks,d=s.getTicks().length,h=u.minRotation||0,c=u.maxRotation,f=h;!s._isVisible()||!u.display||h>=c||d<=1||!s.isHorizontal()?s.labelRotation=h:(e=(t=s._getLabelSizes()).widest.width,n=t.highest.height-t.highest.offset,i=Math.min(s.maxWidth,s.chart.width-e),e+6>(a=l.offset?s.maxWidth/d:i/(d-1))&&(a=i/(d-(l.offset?.5:1)),r=s.maxHeight-Ln(l.gridLines)-u.padding-Rn(l.scaleLabel),o=Math.sqrt(e*e+n*n),f=ht.toDegrees(Math.min(Math.asin(Math.min((t.highest.height+6)/a,1)),Math.asin(Math.min(r/o,1))-Math.asin(n/o))),f=Math.max(h,Math.min(c,f))),s.labelRotation=f)},afterCalculateTickRotation:function(){ht.callback(this.options.afterCalculateTickRotation,[this])},beforeFit:function(){ht.callback(this.options.beforeFit,[this])},fit:function(){var t=this,e=t.minSize={width:0,height:0},n=t.chart,i=t.options,a=i.ticks,r=i.scaleLabel,o=i.gridLines,s=t._isVisible(),l="bottom"===i.position,u=t.isHorizontal();if(u?e.width=t.maxWidth:s&&(e.width=Ln(o)+Rn(r)),u?s&&(e.height=Ln(o)+Rn(r)):e.height=t.maxHeight,a.display&&s){var d=Wn(a),h=t._getLabelSizes(),c=h.first,f=h.last,g=h.widest,m=h.highest,p=.4*d.minor.lineHeight,v=a.padding;if(u){var y=0!==t.labelRotation,b=ht.toRadians(t.labelRotation),x=Math.cos(b),_=Math.sin(b),w=_*g.width+x*(m.height-(y?m.offset:0))+(y?0:p);e.height=Math.min(t.maxHeight,e.height+w+v);var k,M,S=t.getPixelForTick(0)-t.left,D=t.right-t.getPixelForTick(t.getTicks().length-1);y?(k=l?x*c.width+_*c.offset:_*(c.height-c.offset),M=l?_*(f.height-f.offset):x*f.width+_*f.offset):(k=c.width/2,M=f.width/2),t.paddingLeft=Math.max((k-S)*t.width/(t.width-S),0)+3,t.paddingRight=Math.max((M-D)*t.width/(t.width-D),0)+3}else{var C=a.mirror?0:g.width+v+p;e.width=Math.min(t.maxWidth,e.width+C),t.paddingTop=c.height/2,t.paddingBottom=f.height/2}}t.handleMargins(),u?(t.width=t._length=n.width-t.margins.left-t.margins.right,t.height=e.height):(t.width=e.width,t.height=t._length=n.height-t.margins.top-t.margins.bottom)},handleMargins:function(){var t=this;t.margins&&(t.margins.left=Math.max(t.paddingLeft,t.margins.left),t.margins.top=Math.max(t.paddingTop,t.margins.top),t.margins.right=Math.max(t.paddingRight,t.margins.right),t.margins.bottom=Math.max(t.paddingBottom,t.margins.bottom))},afterFit:function(){ht.callback(this.options.afterFit,[this])},isHorizontal:function(){var t=this.options.position;return"top"===t||"bottom"===t},isFullWidth:function(){return this.options.fullWidth},getRightValue:function(t){if(Pn(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},_convertTicksToLabels:function(t){var e,n,i,a=this;for(a.ticks=t.map(function(t){return t.value}),a.beforeTickToLabelConversion(),e=a.convertTicksToLabels(t)||a.ticks,a.afterTickToLabelConversion(),n=0,i=t.length;n<i;++n)t[n].label=e[n];return e},_getLabelSizes:function(){var t=this,e=t._labelSizes;return e||(t._labelSizes=e=In(t.ctx,Wn(t.options.ticks),t.getTicks(),t.longestTextCache),t.longestLabelWidth=e.widest.width),e},_parseValue:function(t){var e,n,i,a;return Tn(t)?(e=+this.getRightValue(t[0]),n=+this.getRightValue(t[1]),i=Math.min(e,n),a=Math.max(e,n)):(e=void 0,n=t=+this.getRightValue(t),i=t,a=t),{min:i,max:a,start:e,end:n}},_getScaleLabel:function(t){var e=this._parseValue(t);return void 0!==e.start?"["+e.start+", "+e.end+"]":+this.getRightValue(t)},getLabelForIndex:ht.noop,getPixelForValue:ht.noop,getValueForPixel:ht.noop,getPixelForTick:function(t){var e=this.options.offset,n=this._ticks.length,i=1/Math.max(n-(e?0:1),1);return t<0||t>n-1?null:this.getPixelForDecimal(t*i+(e?i/2:0))},getPixelForDecimal:function(t){return this._reversePixels&&(t=1-t),this._startPixel+t*this._length},getDecimalForPixel:function(t){var e=(t-this._startPixel)/this._length;return this._reversePixels?1-e:e},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,n,i,a,r=this.options.ticks,o=this._length,s=r.maxTicksLimit||o/this._tickSize()+1,l=r.major.enabled?function(t){var e,n,i=[];for(e=0,n=t.length;e<n;e++)t[e].major&&i.push(e);return i}(t):[],u=l.length,d=l[0],h=l[u-1];if(u>s)return function(t,e,n){var i,a,r=0,o=e[0];for(n=Math.ceil(n),i=0;i<t.length;i++)a=t[i],i===o?(a._index=i,o=e[++r*n]):delete a.label}(t,l,u/s),Yn(t);if(i=function(t,e,n,i){var a,r,o,s,l=function(t){var e,n,i=t.length;if(i<2)return!1;for(n=t[0],e=1;e<i;++e)if(t[e]-t[e-1]!==n)return!1;return n}(t),u=(e.length-1)/i;if(!l)return Math.max(u,1);for(o=0,s=(a=ht.math._factorize(l)).length-1;o<s;o++)if((r=a[o])>u)return r;return Math.max(u,1)}(l,t,0,s),u>0){for(e=0,n=u-1;e<n;e++)zn(t,i,l[e],l[e+1]);return a=u>1?(h-d)/(u-1):null,zn(t,i,ht.isNullOrUndef(a)?0:d-a,d),zn(t,i,h,ht.isNullOrUndef(a)?t.length:h+a),Yn(t)}return zn(t,i),Yn(t)},_tickSize:function(){var t=this.options.ticks,e=ht.toRadians(this.labelRotation),n=Math.abs(Math.cos(e)),i=Math.abs(Math.sin(e)),a=this._getLabelSizes(),r=t.autoSkipPadding||0,o=a?a.widest.width+r:0,s=a?a.highest.height+r:0;return this.isHorizontal()?s*n>o*i?o/n:s/i:s*i<o*n?s/n:o/i},_isVisible:function(){var t,e,n,i=this.chart,a=this.options.display;if("auto"!==a)return!!a;for(t=0,e=i.data.datasets.length;t<e;++t)if(i.isDatasetVisible(t)&&((n=i.getDatasetMeta(t)).xAxisID===this.id||n.yAxisID===this.id))return!0;return!1},_computeGridLineItems:function(t){var e,n,i,a,r,o,s,l,u,d,h,c,f,g,m,p,v,y=this,b=y.chart,x=y.options,_=x.gridLines,w=x.position,k=_.offsetGridLines,M=y.isHorizontal(),S=y._ticksToDraw,D=S.length+(k?1:0),C=Ln(_),T=[],P=_.drawBorder?On(_.lineWidth,0,0):0,A=P/2,O=ht._alignPixel,F=function(t){return O(b,t,P)};for("top"===w?(e=F(y.bottom),s=y.bottom-C,u=e-A,h=F(t.top)+A,f=t.bottom):"bottom"===w?(e=F(y.top),h=t.top,f=F(t.bottom)-A,s=e+A,u=y.top+C):"left"===w?(e=F(y.right),o=y.right-C,l=e-A,d=F(t.left)+A,c=t.right):(e=F(y.left),d=t.left,c=F(t.right)-A,o=e+A,l=y.left+C),n=0;n<D;++n)i=S[n]||{},Pn(i.label)&&n<S.length||(n===y.zeroLineIndex&&x.offset===k?(g=_.zeroLineWidth,m=_.zeroLineColor,p=_.zeroLineBorderDash||[],v=_.zeroLineBorderDashOffset||0):(g=On(_.lineWidth,n,1),m=On(_.color,n,"rgba(0,0,0,0.1)"),p=_.borderDash||[],v=_.borderDashOffset||0),void 0!==(a=Fn(y,i._index||n,k))&&(r=O(b,a,g),M?o=l=d=c=r:s=u=h=f=r,T.push({tx1:o,ty1:s,tx2:l,ty2:u,x1:d,y1:h,x2:c,y2:f,width:g,color:m,borderDash:p,borderDashOffset:v})));return T.ticksLength=D,T.borderValue=e,T},_computeLabelItems:function(){var t,e,n,i,a,r,o,s,l,u,d,h,c=this,f=c.options,g=f.ticks,m=f.position,p=g.mirror,v=c.isHorizontal(),y=c._ticksToDraw,b=Wn(g),x=g.padding,_=Ln(f.gridLines),w=-ht.toRadians(c.labelRotation),k=[];for("top"===m?(r=c.bottom-_-x,o=w?"left":"center"):"bottom"===m?(r=c.top+_+x,o=w?"right":"center"):"left"===m?(a=c.right-(p?0:_)-x,o=p?"left":"right"):(a=c.left+(p?0:_)+x,o=p?"right":"left"),t=0,e=y.length;t<e;++t)i=(n=y[t]).label,Pn(i)||(s=c.getPixelForTick(n._index||t)+g.labelOffset,u=(l=n.major?b.major:b.minor).lineHeight,d=Tn(i)?i.length:1,v?(a=s,h="top"===m?((w?1:.5)-d)*u:(w?0:.5)*u):(r=s,h=(1-d)*u/2),k.push({x:a,y:r,rotation:w,label:i,font:l,textOffset:h,textAlign:o}));return k},_drawGrid:function(t){var e=this,n=e.options.gridLines;if(n.display){var i,a,r,o,s,l=e.ctx,u=e.chart,d=ht._alignPixel,h=n.drawBorder?On(n.lineWidth,0,0):0,c=e._gridLineItems||(e._gridLineItems=e._computeGridLineItems(t));for(r=0,o=c.length;r<o;++r)i=(s=c[r]).width,a=s.color,i&&a&&(l.save(),l.lineWidth=i,l.strokeStyle=a,l.setLineDash&&(l.setLineDash(s.borderDash),l.lineDashOffset=s.borderDashOffset),l.beginPath(),n.drawTicks&&(l.moveTo(s.tx1,s.ty1),l.lineTo(s.tx2,s.ty2)),n.drawOnChartArea&&(l.moveTo(s.x1,s.y1),l.lineTo(s.x2,s.y2)),l.stroke(),l.restore());if(h){var f,g,m,p,v=h,y=On(n.lineWidth,c.ticksLength-1,1),b=c.borderValue;e.isHorizontal()?(f=d(u,e.left,v)-v/2,g=d(u,e.right,y)+y/2,m=p=b):(m=d(u,e.top,v)-v/2,p=d(u,e.bottom,y)+y/2,f=g=b),l.lineWidth=h,l.strokeStyle=On(n.color,0),l.beginPath(),l.moveTo(f,m),l.lineTo(g,p),l.stroke()}}},_drawLabels:function(){var t=this;if(t.options.ticks.display){var e,n,i,a,r,o,s,l,u=t.ctx,d=t._labelItems||(t._labelItems=t._computeLabelItems());for(e=0,i=d.length;e<i;++e){if(o=(r=d[e]).font,u.save(),u.translate(r.x,r.y),u.rotate(r.rotation),u.font=o.string,u.fillStyle=o.color,u.textBaseline="middle",u.textAlign=r.textAlign,s=r.label,l=r.textOffset,Tn(s))for(n=0,a=s.length;n<a;++n)u.fillText(""+s[n],0,l),l+=o.lineHeight;else u.fillText(s,0,l);u.restore()}}},_drawTitle:function(){var t=this,e=t.ctx,n=t.options,i=n.scaleLabel;if(i.display){var a,r,o=An(i.fontColor,ot.global.defaultFontColor),s=ht.options._parseFont(i),l=ht.options.toPadding(i.padding),u=s.lineHeight/2,d=n.position,h=0;if(t.isHorizontal())a=t.left+t.width/2,r="bottom"===d?t.bottom-u-l.bottom:t.top+u+l.top;else{var c="left"===d;a=c?t.left+u+l.top:t.right-u-l.top,r=t.top+t.height/2,h=c?-.5*Math.PI:.5*Math.PI}e.save(),e.translate(a,r),e.rotate(h),e.textAlign="center",e.textBaseline="middle",e.fillStyle=o,e.font=s.string,e.fillText(i.labelString,0,0),e.restore()}},draw:function(t){this._isVisible()&&(this._drawGrid(t),this._drawTitle(),this._drawLabels())},_layers:function(){var t=this,e=t.options,n=e.ticks&&e.ticks.z||0,i=e.gridLines&&e.gridLines.z||0;return t._isVisible()&&n!==i&&t.draw===t._draw?[{z:i,draw:function(){t._drawGrid.apply(t,arguments),t._drawTitle.apply(t,arguments)}},{z:n,draw:function(){t._drawLabels.apply(t,arguments)}}]:[{z:n,draw:function(){t.draw.apply(t,arguments)}}]},_getMatchingVisibleMetas:function(t){var e=this,n=e.isHorizontal();return e.chart._getSortedVisibleDatasetMetas().filter(function(i){return(!t||i.type===t)&&(n?i.xAxisID===e.id:i.yAxisID===e.id)})}});Vn.prototype._draw=Vn.prototype.draw;var En=Vn,Hn=ht.isNullOrUndef,Bn=En.extend({determineDataLimits:function(){var t,e=this,n=e._getLabels(),i=e.options.ticks,a=i.min,r=i.max,o=0,s=n.length-1;void 0!==a&&(t=n.indexOf(a))>=0&&(o=t),void 0!==r&&(t=n.indexOf(r))>=0&&(s=t),e.minIndex=o,e.maxIndex=s,e.min=n[o],e.max=n[s]},buildTicks:function(){var t=this._getLabels(),e=this.minIndex,n=this.maxIndex;this.ticks=0===e&&n===t.length-1?t:t.slice(e,n+1)},getLabelForIndex:function(t,e){var n=this.chart;return n.getDatasetMeta(e).controller._getValueScaleId()===this.id?this.getRightValue(n.data.datasets[e].data[t]):this._getLabels()[t]},_configure:function(){var t=this,e=t.options.offset,n=t.ticks;En.prototype._configure.call(t),t.isHorizontal()||(t._reversePixels=!t._reversePixels),n&&(t._startValue=t.minIndex-(e?.5:0),t._valueRange=Math.max(n.length-(e?0:1),1))},getPixelForValue:function(t,e,n){var i,a,r,o=this;return Hn(e)||Hn(n)||(t=o.chart.data.datasets[n].data[e]),Hn(t)||(i=o.isHorizontal()?t.x:t.y),(void 0!==i||void 0!==t&&isNaN(e))&&(a=o._getLabels(),t=ht.valueOrDefault(i,t),e=-1!==(r=a.indexOf(t))?r:e,isNaN(e)&&(e=t)),o.getPixelForDecimal((e-o._startValue)/o._valueRange)},getPixelForTick:function(t){var e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t],t+this.minIndex)},getValueForPixel:function(t){var e=Math.round(this._startValue+this.getDecimalForPixel(t)*this._valueRange);return Math.min(Math.max(e,0),this.ticks.length-1)},getBasePixel:function(){return this.bottom}}),jn={position:"bottom"};Bn._defaults=jn;var Un=ht.noop,Gn=ht.isNullOrUndef;var qn=En.extend({getRightValue:function(t){return"string"==typeof t?+t:En.prototype.getRightValue.call(this,t)},handleTickRangeOptions:function(){var t=this,e=t.options.ticks;if(e.beginAtZero){var n=ht.sign(t.min),i=ht.sign(t.max);n<0&&i<0?t.max=0:n>0&&i>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,n=e.stepSize,i=e.maxTicksLimit;return n?t=Math.ceil(this.max/n)-Math.floor(this.min/n)+1:(t=this._computeTickLimit(),i=i||11),i&&(t=Math.min(i,t)),t},_computeTickLimit:function(){return Number.POSITIVE_INFINITY},handleDirectionalChanges:Un,buildTicks:function(){var t=this,e=t.options.ticks,n=t.getTickLimit(),i={maxTicks:n=Math.max(2,n),min:e.min,max:e.max,precision:e.precision,stepSize:ht.valueOrDefault(e.fixedStepSize,e.stepSize)},a=t.ticks=function(t,e){var n,i,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=ht.niceNum((g-f)/u/l)*l;if(m<1e-14&&Gn(d)&&Gn(h))return[f,g];(r=Math.ceil(g/m)-Math.floor(f/m))>u&&(m=ht.niceNum(r*m/u/l)*l),s||Gn(c)?n=Math.pow(10,ht._decimalPlaces(m)):(n=Math.pow(10,c),m=Math.ceil(m*n)/n),i=Math.floor(f/m)*m,a=Math.ceil(g/m)*m,s&&(!Gn(d)&&ht.almostWhole(d/m,m/1e3)&&(i=d),!Gn(h)&&ht.almostWhole(h/m,m/1e3)&&(a=h)),r=(a-i)/m,r=ht.almostEquals(r,Math.round(r),m/1e3)?Math.round(r):Math.ceil(r),i=Math.round(i*n)/n,a=Math.round(a*n)/n,o.push(Gn(d)?i:d);for(var p=1;p<r;++p)o.push(Math.round((i+p*m)*n)/n);return o.push(Gn(h)?a:h),o}(i,t);t.handleDirectionalChanges(),t.max=ht.max(a),t.min=ht.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),En.prototype.convertTicksToLabels.call(t)},_configure:function(){var t,e=this,n=e.getTicks(),i=e.min,a=e.max;En.prototype._configure.call(e),e.options.offset&&n.length&&(i-=t=(a-i)/Math.max(n.length-1,1)/2,a+=t),e._startValue=i,e._endValue=a,e._valueRange=a-i}}),Zn={position:"left",ticks:{callback:Cn.formatters.linear}};function $n(t,e,n,i){var a,r,o=t.options,s=function(t,e,n){var i=[n.type,void 0===e&&void 0===n.stack?n.index:"",n.stack].join(".");return void 0===t[i]&&(t[i]={pos:[],neg:[]}),t[i]}(e,o.stacked,n),l=s.pos,u=s.neg,d=i.length;for(a=0;a<d;++a)r=t._parseValue(i[a]),isNaN(r.min)||isNaN(r.max)||n.data[a].hidden||(l[a]=l[a]||0,u[a]=u[a]||0,o.relativePoints?l[a]=100:r.min<0||r.max<0?u[a]+=r.min:l[a]+=r.max)}function Xn(t,e,n){var i,a,r=n.length;for(i=0;i<r;++i)a=t._parseValue(n[i]),isNaN(a.min)||isNaN(a.max)||e.data[i].hidden||(t.min=Math.min(t.min,a.min),t.max=Math.max(t.max,a.max))}var Kn=qn.extend({determineDataLimits:function(){var t,e,n,i,a=this,r=a.options,o=a.chart.data.datasets,s=a._getMatchingVisibleMetas(),l=r.stacked,u={},d=s.length;if(a.min=Number.POSITIVE_INFINITY,a.max=Number.NEGATIVE_INFINITY,void 0===l)for(t=0;!l&&t<d;++t)l=void 0!==(e=s[t]).stack;for(t=0;t<d;++t)n=o[(e=s[t]).index].data,l?$n(a,u,e,n):Xn(a,e,n);ht.each(u,function(t){i=t.pos.concat(t.neg),a.min=Math.min(a.min,ht.min(i)),a.max=Math.max(a.max,ht.max(i))}),a.min=ht.isFinite(a.min)&&!isNaN(a.min)?a.min:0,a.max=ht.isFinite(a.max)&&!isNaN(a.max)?a.max:1,a.handleTickRangeOptions()},_computeTickLimit:function(){var t;return this.isHorizontal()?Math.ceil(this.width/40):(t=ht.options._parseFont(this.options.ticks),Math.ceil(this.height/t.lineHeight))},handleDirectionalChanges:function(){this.isHorizontal()||this.ticks.reverse()},getLabelForIndex:function(t,e){return this._getScaleLabel(this.chart.data.datasets[e].data[t])},getPixelForValue:function(t){return this.getPixelForDecimal((+this.getRightValue(t)-this._startValue)/this._valueRange)},getValueForPixel:function(t){return this._startValue+this.getDecimalForPixel(t)*this._valueRange},getPixelForTick:function(t){var e=this.ticksAsNumbers;return t<0||t>e.length-1?null:this.getPixelForValue(e[t])}}),Jn=Zn;Kn._defaults=Jn;var Qn=ht.valueOrDefault,ti=ht.math.log10;var ei={position:"left",ticks:{callback:Cn.formatters.logarithmic}};function ni(t,e){return ht.isFinite(t)&&t>=0?t:e}var ii=En.extend({determineDataLimits:function(){var t,e,n,i,a,r,o=this,s=o.options,l=o.chart,u=l.data.datasets,d=o.isHorizontal();function h(t){return d?t.xAxisID===o.id:t.yAxisID===o.id}o.min=Number.POSITIVE_INFINITY,o.max=Number.NEGATIVE_INFINITY,o.minNotZero=Number.POSITIVE_INFINITY;var c=s.stacked;if(void 0===c)for(t=0;t<u.length;t++)if(e=l.getDatasetMeta(t),l.isDatasetVisible(t)&&h(e)&&void 0!==e.stack){c=!0;break}if(s.stacked||c){var f={};for(t=0;t<u.length;t++){var g=[(e=l.getDatasetMeta(t)).type,void 0===s.stacked&&void 0===e.stack?t:"",e.stack].join(".");if(l.isDatasetVisible(t)&&h(e))for(void 0===f[g]&&(f[g]=[]),a=0,r=(i=u[t].data).length;a<r;a++){var m=f[g];n=o._parseValue(i[a]),isNaN(n.min)||isNaN(n.max)||e.data[a].hidden||n.min<0||n.max<0||(m[a]=m[a]||0,m[a]+=n.max)}}ht.each(f,function(t){if(t.length>0){var e=ht.min(t),n=ht.max(t);o.min=Math.min(o.min,e),o.max=Math.max(o.max,n)}})}else for(t=0;t<u.length;t++)if(e=l.getDatasetMeta(t),l.isDatasetVisible(t)&&h(e))for(a=0,r=(i=u[t].data).length;a<r;a++)n=o._parseValue(i[a]),isNaN(n.min)||isNaN(n.max)||e.data[a].hidden||n.min<0||n.max<0||(o.min=Math.min(n.min,o.min),o.max=Math.max(n.max,o.max),0!==n.min&&(o.minNotZero=Math.min(n.min,o.minNotZero)));o.min=ht.isFinite(o.min)?o.min:null,o.max=ht.isFinite(o.max)?o.max:null,o.minNotZero=ht.isFinite(o.minNotZero)?o.minNotZero:null,this.handleTickRangeOptions()},handleTickRangeOptions:function(){var t=this,e=t.options.ticks;t.min=ni(e.min,t.min),t.max=ni(e.max,t.max),t.min===t.max&&(0!==t.min&&null!==t.min?(t.min=Math.pow(10,Math.floor(ti(t.min))-1),t.max=Math.pow(10,Math.floor(ti(t.max))+1)):(t.min=1,t.max=10)),null===t.min&&(t.min=Math.pow(10,Math.floor(ti(t.max))-1)),null===t.max&&(t.max=0!==t.min?Math.pow(10,Math.floor(ti(t.min))+1):10),null===t.minNotZero&&(t.min>0?t.minNotZero=t.min:t.max<1?t.minNotZero=Math.pow(10,Math.floor(ti(t.max))):t.minNotZero=1)},buildTicks:function(){var t=this,e=t.options.ticks,n=!t.isHorizontal(),i={min:ni(e.min),max:ni(e.max)},a=t.ticks=function(t,e){var n,i,a=[],r=Qn(t.min,Math.pow(10,Math.floor(ti(e.min)))),o=Math.floor(ti(e.max)),s=Math.ceil(e.max/Math.pow(10,o));0===r?(n=Math.floor(ti(e.minNotZero)),i=Math.floor(e.minNotZero/Math.pow(10,n)),a.push(r),r=i*Math.pow(10,n)):(n=Math.floor(ti(r)),i=Math.floor(r/Math.pow(10,n)));var l=n<0?Math.pow(10,Math.abs(n)):1;do{a.push(r),10===++i&&(i=1,l=++n>=0?1:l),r=Math.round(i*Math.pow(10,n)*l)/l}while(n<o||n===o&&i<s);var u=Qn(t.max,r);return a.push(u),a}(i,t);t.max=ht.max(a),t.min=ht.min(a),e.reverse?(n=!n,t.start=t.max,t.end=t.min):(t.start=t.min,t.end=t.max),n&&a.reverse()},convertTicksToLabels:function(){this.tickValues=this.ticks.slice(),En.prototype.convertTicksToLabels.call(this)},getLabelForIndex:function(t,e){return this._getScaleLabel(this.chart.data.datasets[e].data[t])},getPixelForTick:function(t){var e=this.tickValues;return t<0||t>e.length-1?null:this.getPixelForValue(e[t])},_getFirstTickValue:function(t){var e=Math.floor(ti(t));return Math.floor(t/Math.pow(10,e))*Math.pow(10,e)},_configure:function(){var t=this,e=t.min,n=0;En.prototype._configure.call(t),0===e&&(e=t._getFirstTickValue(t.minNotZero),n=Qn(t.options.ticks.fontSize,ot.global.defaultFontSize)/t._length),t._startValue=ti(e),t._valueOffset=n,t._valueRange=(ti(t.max)-ti(e))/(1-n)},getPixelForValue:function(t){var e=this,n=0;return(t=+e.getRightValue(t))>e.min&&t>0&&(n=(ti(t)-e._startValue)/e._valueRange+e._valueOffset),e.getPixelForDecimal(n)},getValueForPixel:function(t){var e=this,n=e.getDecimalForPixel(t);return 0===n&&0===e.min?0:Math.pow(10,e._startValue+(n-e._valueOffset)*e._valueRange)}}),ai=ei;ii._defaults=ai;var ri=ht.valueOrDefault,oi=ht.valueAtIndexOrDefault,si=ht.options.resolve,li={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:Cn.formatters.linear},pointLabels:{display:!0,fontSize:10,callback:function(t){return t}}};function ui(t){var e=t.ticks;return e.display&&t.display?ri(e.fontSize,ot.global.defaultFontSize)+2*e.backdropPaddingY:0}function di(t,e,n,i,a){return t===i||t===a?{start:e-n/2,end:e+n/2}:t<i||t>a?{start:e-n,end:e}:{start:e,end:e+n}}function hi(t){return 0===t||180===t?"center":t<180?"left":"right"}function ci(t,e,n,i){var a,r,o=n.y+i/2;if(ht.isArray(e))for(a=0,r=e.length;a<r;++a)t.fillText(e[a],n.x,o),o+=i;else t.fillText(e,n.x,o)}function fi(t,e,n){90===t||270===t?n.y-=e.h/2:(t>270||t<90)&&(n.y-=e.h)}function gi(t){return ht.isNumber(t)?t:0}var mi=qn.extend({setDimensions:function(){var t=this;t.width=t.maxWidth,t.height=t.maxHeight,t.paddingTop=ui(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,n=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY;ht.each(e.data.datasets,function(a,r){if(e.isDatasetVisible(r)){var o=e.getDatasetMeta(r);ht.each(a.data,function(e,a){var r=+t.getRightValue(e);isNaN(r)||o.data[a].hidden||(n=Math.min(r,n),i=Math.max(r,i))})}}),t.min=n===Number.POSITIVE_INFINITY?0:n,t.max=i===Number.NEGATIVE_INFINITY?0:i,t.handleTickRangeOptions()},_computeTickLimit:function(){return Math.ceil(this.drawingArea/ui(this.options))},convertTicksToLabels:function(){var t=this;qn.prototype.convertTicksToLabels.call(t),t.pointLabels=t.chart.data.labels.map(function(){var e=ht.callback(t.options.pointLabels.callback,arguments,t);return e||0===e?e:""})},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,n,i,a=ht.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=t.chart.data.labels.length;for(e=0;e<d;e++){i=t.getPointPosition(e,t.drawingArea+5),s=t.ctx,l=a.lineHeight,u=t.pointLabels[e],n=ht.isArray(u)?{w:ht.longestText(s,s.font,u),h:u.length*l}:{w:s.measureText(u).width,h:l},t._pointLabelSizes[e]=n;var h=t.getIndexAngle(e),c=ht.toDegrees(h)%360,f=di(c,i.x,n.w,0,180),g=di(c,i.y,n.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,n){var i=this,a=e.l/Math.sin(n.l),r=Math.max(e.r-i.width,0)/Math.sin(n.r),o=-e.t/Math.cos(n.t),s=-Math.max(e.b-(i.height-i.paddingTop),0)/Math.cos(n.b);a=gi(a),r=gi(r),o=gi(o),s=gi(s),i.drawingArea=Math.min(Math.floor(t-(a+r)/2),Math.floor(t-(o+s)/2)),i.setCenterPoint(a,r,o,s)},setCenterPoint:function(t,e,n,i){var a=this,r=a.width-e-a.drawingArea,o=t+a.drawingArea,s=n+a.drawingArea,l=a.height-a.paddingTop-i-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){var e=this.chart,n=(t*(360/e.data.labels.length)+((e.options||{}).startAngle||0))%360;return(n<0?n+360:n)*Math.PI*2/360},getDistanceFromCenterForValue:function(t){var e=this;if(ht.isNullOrUndef(t))return NaN;var n=e.drawingArea/(e.max-e.min);return e.options.ticks.reverse?(e.max-t)*n:(t-e.min)*n},getPointPosition:function(t,e){var n=this.getIndexAngle(t)-Math.PI/2;return{x:Math.cos(n)*e+this.xCenter,y:Math.sin(n)*e+this.yCenter}},getPointPositionForValue:function(t,e){return this.getPointPosition(t,this.getDistanceFromCenterForValue(e))},getBasePosition:function(t){var e=this.min,n=this.max;return this.getPointPositionForValue(t||0,this.beginAtZero?0:e<0&&n<0?n:e>0&&n>0?e:0)},_drawGrid:function(){var t,e,n,i=this,a=i.ctx,r=i.options,o=r.gridLines,s=r.angleLines,l=ri(s.lineWidth,o.lineWidth),u=ri(s.color,o.color);if(r.pointLabels.display&&function(t){var e=t.ctx,n=t.options,i=n.pointLabels,a=ui(n),r=t.getDistanceFromCenterForValue(n.ticks.reverse?t.min:t.max),o=ht.options._parseFont(i);e.save(),e.font=o.string,e.textBaseline="middle";for(var s=t.chart.data.labels.length-1;s>=0;s--){var l=0===s?a/2:0,u=t.getPointPosition(s,r+l+5),d=oi(i.fontColor,s,ot.global.defaultFontColor);e.fillStyle=d;var h=t.getIndexAngle(s),c=ht.toDegrees(h);e.textAlign=hi(c),fi(c,t._pointLabelSizes[s],u),ci(e,t.pointLabels[s],u,o.lineHeight)}e.restore()}(i),o.display&&ht.each(i.ticks,function(t,n){0!==n&&(e=i.getDistanceFromCenterForValue(i.ticksAsNumbers[n]),function(t,e,n,i){var a,r=t.ctx,o=e.circular,s=t.chart.data.labels.length,l=oi(e.color,i-1),u=oi(e.lineWidth,i-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,n,0,2*Math.PI);else{a=t.getPointPosition(0,n),r.moveTo(a.x,a.y);for(var d=1;d<s;d++)a=t.getPointPosition(d,n),r.lineTo(a.x,a.y)}r.closePath(),r.stroke(),r.restore()}}(i,o,e,n))}),s.display&&l&&u){for(a.save(),a.lineWidth=l,a.strokeStyle=u,a.setLineDash&&(a.setLineDash(si([s.borderDash,o.borderDash,[]])),a.lineDashOffset=si([s.borderDashOffset,o.borderDashOffset,0])),t=i.chart.data.labels.length-1;t>=0;t--)e=i.getDistanceFromCenterForValue(r.ticks.reverse?i.min:i.max),n=i.getPointPosition(t,e),a.beginPath(),a.moveTo(i.xCenter,i.yCenter),a.lineTo(n.x,n.y),a.stroke();a.restore()}},_drawLabels:function(){var t=this,e=t.ctx,n=t.options.ticks;if(n.display){var i,a,r=t.getIndexAngle(0),o=ht.options._parseFont(n),s=ri(n.fontColor,ot.global.defaultFontColor);e.save(),e.font=o.string,e.translate(t.xCenter,t.yCenter),e.rotate(r),e.textAlign="center",e.textBaseline="middle",ht.each(t.ticks,function(r,l){(0!==l||n.reverse)&&(i=t.getDistanceFromCenterForValue(t.ticksAsNumbers[l]),n.showLabelBackdrop&&(a=e.measureText(r).width,e.fillStyle=n.backdropColor,e.fillRect(-a/2-n.backdropPaddingX,-i-o.size/2-n.backdropPaddingY,a+2*n.backdropPaddingX,o.size+2*n.backdropPaddingY)),e.fillStyle=s,e.fillText(r,0,-i))}),e.restore()}},_drawTitle:ht.noop}),pi=li;mi._defaults=pi;var vi=ht._deprecated,yi=ht.options.resolve,bi=ht.valueOrDefault,xi=Number.MIN_SAFE_INTEGER||-9007199254740991,_i=Number.MAX_SAFE_INTEGER||9007199254740991,wi={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},ki=Object.keys(wi);function Mi(t,e){return t-e}function Si(t){return ht.valueOrDefault(t.time.min,t.ticks.min)}function Di(t){return ht.valueOrDefault(t.time.max,t.ticks.max)}function Ci(t,e,n,i){var a=function(t,e,n){for(var i,a,r,o=0,s=t.length-1;o>=0&&o<=s;){if(a=t[(i=o+s>>1)-1]||null,r=t[i],!a)return{lo:null,hi:r};if(r[e]<n)o=i+1;else{if(!(a[e]>n))return{lo:a,hi:r};s=i-1}}return{lo:r,hi:null}}(t,e,n),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?(n-r[e])/s:0,u=(o[i]-r[i])*l;return r[i]+u}function Ti(t,e){var n=t._adapter,i=t.options.time,a=i.parser,r=a||i.format,o=e;return"function"==typeof a&&(o=a(o)),ht.isFinite(o)||(o="string"==typeof r?n.parse(o,r):n.parse(o)),null!==o?+o:(a||"function"!=typeof r||(o=r(e),ht.isFinite(o)||(o=n.parse(o))),o)}function Pi(t,e){if(ht.isNullOrUndef(e))return null;var n=t.options.time,i=Ti(t,t.getRightValue(e));return null===i?i:(n.round&&(i=+t._adapter.startOf(i,n.round)),i)}function Ai(t,e,n,i){var a,r,o,s=ki.length;for(a=ki.indexOf(t);a<s-1;++a)if(o=(r=wi[ki[a]]).steps?r.steps:_i,r.common&&Math.ceil((n-e)/(o*r.size))<=i)return ki[a];return ki[s-1]}function Oi(t,e,n){var i,a,r=[],o={},s=e.length;for(i=0;i<s;++i)o[a=e[i]]=i,r.push({value:a,major:!1});return 0!==s&&n?function(t,e,n,i){var a,r,o=t._adapter,s=+o.startOf(e[0].value,i),l=e[e.length-1].value;for(a=s;a<=l;a=+o.add(a,1,i))(r=n[a])>=0&&(e[r].major=!0);return e}(t,r,o,n):r}var Fi=En.extend({initialize:function(){this.mergeTicksOptions(),En.prototype.initialize.call(this)},update:function(){var t=this,e=t.options,n=e.time||(e.time={}),i=t._adapter=new Dn._date(e.adapters.date);return vi("time scale",n.format,"time.format","time.parser"),vi("time scale",n.min,"time.min","ticks.min"),vi("time scale",n.max,"time.max","ticks.max"),ht.mergeIf(n.displayFormats,i.formats()),En.prototype.update.apply(t,arguments)},getRightValue:function(t){return t&&void 0!==t.t&&(t=t.t),En.prototype.getRightValue.call(this,t)},determineDataLimits:function(){var t,e,n,i,a,r,o,s=this,l=s.chart,u=s._adapter,d=s.options,h=d.time.unit||"day",c=_i,f=xi,g=[],m=[],p=[],v=s._getLabels();for(t=0,n=v.length;t<n;++t)p.push(Pi(s,v[t]));for(t=0,n=(l.data.datasets||[]).length;t<n;++t)if(l.isDatasetVisible(t))if(a=l.data.datasets[t].data,ht.isObject(a[0]))for(m[t]=[],e=0,i=a.length;e<i;++e)r=Pi(s,a[e]),g.push(r),m[t][e]=r;else m[t]=p.slice(0),o||(g=g.concat(p),o=!0);else m[t]=[];p.length&&(c=Math.min(c,p[0]),f=Math.max(f,p[p.length-1])),g.length&&(g=n>1?function(t){var e,n,i,a={},r=[];for(e=0,n=t.length;e<n;++e)a[i=t[e]]||(a[i]=!0,r.push(i));return r}(g).sort(Mi):g.sort(Mi),c=Math.min(c,g[0]),f=Math.max(f,g[g.length-1])),c=Pi(s,Si(d))||c,f=Pi(s,Di(d))||f,c=c===_i?+u.startOf(Date.now(),h):c,f=f===xi?+u.endOf(Date.now(),h)+1:f,s.min=Math.min(c,f),s.max=Math.max(c+1,f),s._table=[],s._timestamps={data:g,datasets:m,labels:p}},buildTicks:function(){var t,e,n,i=this,a=i.min,r=i.max,o=i.options,s=o.ticks,l=o.time,u=i._timestamps,d=[],h=i.getLabelCapacity(a),c=s.source,f=o.distribution;for(u="data"===c||"auto"===c&&"series"===f?u.data:"labels"===c?u.labels:function(t,e,n,i){var a,r=t._adapter,o=t.options,s=o.time,l=s.unit||Ai(s.minUnit,e,n,i),u=yi([s.stepSize,s.unitStepSize,1]),d="week"===l&&s.isoWeekday,h=e,c=[];if(d&&(h=+r.startOf(h,"isoWeek",d)),h=+r.startOf(h,d?"day":l),r.diff(n,e,l)>1e5*u)throw e+" and "+n+" are too far apart with stepSize of "+u+" "+l;for(a=h;a<n;a=+r.add(a,u,l))c.push(a);return a!==n&&"ticks"!==o.bounds||c.push(a),c}(i,a,r,h),"ticks"===o.bounds&&u.length&&(a=u[0],r=u[u.length-1]),a=Pi(i,Si(o))||a,r=Pi(i,Di(o))||r,t=0,e=u.length;t<e;++t)(n=u[t])>=a&&n<=r&&d.push(n);return i.min=a,i.max=r,i._unit=l.unit||(s.autoSkip?Ai(l.minUnit,i.min,i.max,h):function(t,e,n,i,a){var r,o;for(r=ki.length-1;r>=ki.indexOf(n);r--)if(o=ki[r],wi[o].common&&t._adapter.diff(a,i,o)>=e-1)return o;return ki[n?ki.indexOf(n):0]}(i,d.length,l.minUnit,i.min,i.max)),i._majorUnit=s.major.enabled&&"year"!==i._unit?function(t){for(var e=ki.indexOf(t)+1,n=ki.length;e<n;++e)if(wi[ki[e]].common)return ki[e]}(i._unit):void 0,i._table=function(t,e,n,i){if("linear"===i||!t.length)return[{time:e,pos:0},{time:n,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<n&&d.push(s);for(d.push(n),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}(i._timestamps.data,a,r,f),i._offsets=function(t,e,n,i,a){var r,o,s=0,l=0;return a.offset&&e.length&&(r=Ci(t,"time",e[0],"pos"),s=1===e.length?1-r:(Ci(t,"time",e[1],"pos")-r)/2,o=Ci(t,"time",e[e.length-1],"pos"),l=1===e.length?o:(o-Ci(t,"time",e[e.length-2],"pos"))/2),{start:s,end:l,factor:1/(s+1+l)}}(i._table,d,0,0,o),s.reverse&&d.reverse(),Oi(i,d,i._majorUnit)},getLabelForIndex:function(t,e){var n=this,i=n._adapter,a=n.chart.data,r=n.options.time,o=a.labels&&t<a.labels.length?a.labels[t]:"",s=a.datasets[e].data[t];return ht.isObject(s)&&(o=n.getRightValue(s)),r.tooltipFormat?i.format(Ti(n,o),r.tooltipFormat):"string"==typeof o?o:i.format(Ti(n,o),r.displayFormats.datetime)},tickFormatFunction:function(t,e,n,i){var a=this._adapter,r=this.options,o=r.time.displayFormats,s=o[this._unit],l=this._majorUnit,u=o[l],d=n[e],h=r.ticks,c=l&&u&&d&&d.major,f=a.format(t,i||(c?u:s)),g=c?h.major:h.minor,m=yi([g.callback,g.userCallback,h.callback,h.userCallback]);return m?m(f,e,n):f},convertTicksToLabels:function(t){var e,n,i=[];for(e=0,n=t.length;e<n;++e)i.push(this.tickFormatFunction(t[e].value,e,t));return i},getPixelForOffset:function(t){var e=this._offsets,n=Ci(this._table,"time",t,"pos");return this.getPixelForDecimal((e.start+n)*e.factor)},getPixelForValue:function(t,e,n){var i=null;if(void 0!==e&&void 0!==n&&(i=this._timestamps.datasets[n][e]),null===i&&(i=Pi(this,t)),null!==i)return this.getPixelForOffset(i)},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._offsets,n=this.getDecimalForPixel(t)/e.factor-e.end,i=Ci(this._table,"pos",n,"time");return this._adapter._create(i)},_getLabelSize:function(t){var e=this.options.ticks,n=this.ctx.measureText(t).width,i=ht.toRadians(this.isHorizontal()?e.maxRotation:e.minRotation),a=Math.cos(i),r=Math.sin(i),o=bi(e.fontSize,ot.global.defaultFontSize);return{w:n*a+o*r,h:n*r+o*a}},getLabelWidth:function(t){return this._getLabelSize(t).w},getLabelCapacity:function(t){var e=this,n=e.options.time,i=n.displayFormats,a=i[n.unit]||i.millisecond,r=e.tickFormatFunction(t,0,Oi(e,[t],e._majorUnit),a),o=e._getLabelSize(r),s=Math.floor(e.isHorizontal()?e.width/o.w:e.height/o.h);return e.options.offset&&s--,s>0?s:1}}),Ii={position:"bottom",distribution:"linear",bounds:"data",adapters:{},time:{parser:!1,unit:!1,round:!1,displayFormat:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{autoSkip:!1,source:"auto",major:{enabled:!1}}};Fi._defaults=Ii;var Li={category:Bn,linear:Kn,logarithmic:ii,radialLinear:mi,time:Fi},Ri=function(t,e){return t(e={exports:{}},e.exports),e.exports}(function(t,e){t.exports=function(){var e,n;function i(){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 n,i=[];for(n=0;n<t.length;++n)i.push(e(t[n],n));return i}function d(t,e){return Object.prototype.hasOwnProperty.call(t,e)}function h(t,e){for(var n in e)d(e,n)&&(t[n]=e[n]);return d(e,"toString")&&(t.toString=e.toString),d(e,"valueOf")&&(t.valueOf=e.valueOf),t}function c(t,e,n,i){return Fe(t,e,n,i,!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),i=n.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&&i);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}n=Array.prototype.some?Array.prototype.some:function(t){for(var e=Object(this),n=e.length>>>0,i=0;i<n;i++)if(i in e&&t.call(this,e[i],i,e))return!0;return!1};var p=i.momentProperties=[];function v(t,e){var n,i,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(n=0;n<p.length;n++)o(a=e[i=p[n]])||(t[i]=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,i.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 w(t){var e=+t,n=0;return 0!==e&&isFinite(e)&&(n=_(e)),n}function k(t,e,n){var i,a=Math.min(t.length,e.length),r=Math.abs(t.length-e.length),o=0;for(i=0;i<a;i++)(n&&t[i]!==e[i]||!n&&w(t[i])!==w(e[i]))&&o++;return o+r}function M(t){!1===i.suppressDeprecationWarnings&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+t)}function S(t,e){var n=!0;return h(function(){if(null!=i.deprecationHandler&&i.deprecationHandler(null,t),n){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),n=!1}return e.apply(this,arguments)},e)}var D,C={};function T(t,e){null!=i.deprecationHandler&&i.deprecationHandler(t,e),C[t]||(M(e),C[t]=!0)}function P(t){return t instanceof Function||"[object Function]"===Object.prototype.toString.call(t)}function A(t,e){var n,i=h({},t);for(n in e)d(e,n)&&(r(t[n])&&r(e[n])?(i[n]={},h(i[n],t[n]),h(i[n],e[n])):null!=e[n]?i[n]=e[n]:delete i[n]);for(n in t)d(t,n)&&!d(e,n)&&r(t[n])&&(i[n]=h({},i[n]));return i}function O(t){null!=t&&this.set(t)}i.suppressDeprecationWarnings=!1,i.deprecationHandler=null,D=Object.keys?Object.keys:function(t){var e,n=[];for(e in t)d(t,e)&&n.push(e);return n};var F={};function I(t,e){var n=t.toLowerCase();F[n]=F[n+"s"]=F[e]=t}function L(t){return"string"==typeof t?F[t]||F[t.toLowerCase()]:void 0}function R(t){var e,n,i={};for(n in t)d(t,n)&&(e=L(n))&&(i[e]=t[n]);return i}var N={};function W(t,e){N[t]=e}function Y(t,e,n){var i=""+Math.abs(t),a=e-i.length;return(t>=0?n?"+":"":"-")+Math.pow(10,Math.max(0,a)).toString().substr(1)+i}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,E={},H={};function B(t,e,n,i){var a=i;"string"==typeof i&&(a=function(){return this[i]()}),t&&(H[t]=a),e&&(H[e[0]]=function(){return Y(a.apply(this,arguments),e[1],e[2])}),n&&(H[n]=function(){return this.localeData().ordinal(a.apply(this,arguments),t)})}function j(t,e){return t.isValid()?(e=U(e,t.localeData()),E[e]=E[e]||function(t){var e,n,i,a=t.match(z);for(e=0,n=a.length;e<n;e++)H[a[e]]?a[e]=H[a[e]]:a[e]=(i=a[e]).match(/\[[\s\S]/)?i.replace(/^\[|\]$/g,""):i.replace(/\\/g,"");return function(e){var i,r="";for(i=0;i<n;i++)r+=P(a[i])?a[i].call(e,t):a[i];return r}}(e),E[e](t)):t.localeData().invalidDate()}function U(t,e){var n=5;function i(t){return e.longDateFormat(t)||t}for(V.lastIndex=0;n>=0&&V.test(t);)t=t.replace(V,i),V.lastIndex=0,n-=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}/,nt=/[+-]?\d{1,6}/,it=/\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,n){lt[t]=P(e)?e:function(t,i){return t&&n?n: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,n,i,a){return e||n||i||a})))}function ht(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}var ct={};function ft(t,e){var n,i=e;for("string"==typeof t&&(t=[t]),s(e)&&(i=function(t,n){n[e]=w(t)}),n=0;n<t.length;n++)ct[t[n]]=i}function gt(t,e){ft(t,function(t,n,i,a){i._w=i._w||{},e(t,i._w,i,a)})}function mt(t,e,n){null!=e&&d(ct,t)&&ct[t](e,n._a,n,t)}var pt=0,vt=1,yt=2,bt=3,xt=4,_t=5,wt=6,kt=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"),I("year","y"),W("year",1),ut("Y",at),ut("YY",K,q),ut("YYYY",et,$),ut("YYYYY",nt,X),ut("YYYYYY",nt,X),ft(["YYYYY","YYYYYY"],pt),ft("YYYY",function(t,e){e[pt]=2===t.length?i.parseTwoDigitYear(t):w(t)}),ft("YY",function(t,e){e[pt]=i.parseTwoDigitYear(t)}),ft("Y",function(t,e){e[pt]=parseInt(t,10)}),i.parseTwoDigitYear=function(t){return w(t)+(w(t)>68?1900:2e3)};var Ct,Tt=Pt("FullYear",!0);function Pt(t,e){return function(n){return null!=n?(Ot(this,t,n),i.updateOffset(this,e),this):At(this,t)}}function At(t,e){return t.isValid()?t._d["get"+(t._isUTC?"UTC":"")+e]():NaN}function Ot(t,e,n){t.isValid()&&!isNaN(n)&&("FullYear"===e&&Dt(t.year())&&1===t.month()&&29===t.date()?t._d["set"+(t._isUTC?"UTC":"")+e](n,t.month(),Ft(n,t.month())):t._d["set"+(t._isUTC?"UTC":"")+e](n))}function Ft(t,e){if(isNaN(t)||isNaN(e))return NaN;var n=function(t,e){return(t%e+e)%e}(e,12);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)}),I("month","M"),W("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]=w(t)-1}),ft(["MMM","MMMM"],function(t,e,n,i){var a=n._locale.monthsParse(t,i,n._strict);null!=a?e[vt]=a:f(n).invalidMonth=t});var It=/D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/,Lt="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),Rt="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_");function Nt(t,e,n){var i,a,r,o=t.toLocaleLowerCase();if(!this._monthsParse)for(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[],i=0;i<12;++i)r=c([2e3,i]),this._shortMonthsParse[i]=this.monthsShort(r,"").toLocaleLowerCase(),this._longMonthsParse[i]=this.months(r,"").toLocaleLowerCase();return n?"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}function Wt(t,e){var n;if(!t.isValid())return t;if("string"==typeof e)if(/^\d+$/.test(e))e=w(e);else if(!s(e=t.localeData().monthsParse(e)))return t;return n=Math.min(t.date(),Ft(t.year(),e)),t._d["set"+(t._isUTC?"UTC":"")+"Month"](e,n),t}function Yt(t){return null!=t?(Wt(this,t),i.updateOffset(this,!0),this):At(this,"Month")}var zt=st,Vt=st;function Et(){function t(t,e){return e.length-t.length}var e,n,i=[],a=[],r=[];for(e=0;e<12;e++)n=c([2e3,e]),i.push(this.monthsShort(n,"")),a.push(this.months(n,"")),r.push(this.months(n,"")),r.push(this.monthsShort(n,""));for(i.sort(t),a.sort(t),r.sort(t),e=0;e<12;e++)i[e]=ht(i[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("^("+i.join("|")+")","i")}function Ht(t,e,n,i,a,r,o){var s;return t<100&&t>=0?(s=new Date(t+400,e,n,i,a,r,o),isFinite(s.getFullYear())&&s.setFullYear(t)):s=new Date(t,e,n,i,a,r,o),s}function Bt(t){var e;if(t<100&&t>=0){var n=Array.prototype.slice.call(arguments);n[0]=t+400,e=new Date(Date.UTC.apply(null,n)),isFinite(e.getUTCFullYear())&&e.setUTCFullYear(t)}else e=new Date(Date.UTC.apply(null,arguments));return e}function jt(t,e,n){var i=7+e-n;return-(7+Bt(t,0,i).getUTCDay()-e)%7+i-1}function Ut(t,e,n,i,a){var r,o,s=1+7*(e-1)+(7+n-i)%7+jt(t,i,a);return s<=0?o=St(r=t-1)+s:s>St(t)?(r=t+1,o=s-St(t)):(r=t,o=s),{year:r,dayOfYear:o}}function Gt(t,e,n){var i,a,r=jt(t.year(),e,n),o=Math.floor((t.dayOfYear()-r-1)/7)+1;return o<1?i=o+qt(a=t.year()-1,e,n):o>qt(t.year(),e,n)?(i=o-qt(t.year(),e,n),a=t.year()+1):(a=t.year(),i=o),{week:i,year:a}}function qt(t,e,n){var i=jt(t,e,n),a=jt(t+1,e,n);return(St(t)-i+a)/7}function Zt(t,e){return t.slice(e,7).concat(t.slice(0,e))}B("w",["ww",2],"wo","week"),B("W",["WW",2],"Wo","isoWeek"),I("week","w"),I("isoWeek","W"),W("week",5),W("isoWeek",5),ut("w",K),ut("ww",K,q),ut("W",K),ut("WW",K,q),gt(["w","ww","W","WW"],function(t,e,n,i){e[i.substr(0,1)]=w(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"),I("day","d"),I("weekday","e"),I("isoWeekday","E"),W("day",11),W("weekday",11),W("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,n,i){var a=n._locale.weekdaysParse(t,i,n._strict);null!=a?e.d=a:f(n).invalidWeekday=t}),gt(["d","e","E"],function(t,e,n,i){e[i]=w(t)});var $t="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Xt="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Kt="Su_Mo_Tu_We_Th_Fr_Sa".split("_");function Jt(t,e,n){var i,a,r,o=t.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],i=0;i<7;++i)r=c([2e3,1]).day(i),this._minWeekdaysParse[i]=this.weekdaysMin(r,"").toLocaleLowerCase(),this._shortWeekdaysParse[i]=this.weekdaysShort(r,"").toLocaleLowerCase(),this._weekdaysParse[i]=this.weekdays(r,"").toLocaleLowerCase();return n?"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}var Qt=st,te=st,ee=st;function ne(){function t(t,e){return e.length-t.length}var e,n,i,a,r,o=[],s=[],l=[],u=[];for(e=0;e<7;e++)n=c([2e3,1]).day(e),i=this.weekdaysMin(n,""),a=this.weekdaysShort(n,""),r=this.weekdays(n,""),o.push(i),s.push(a),l.push(r),u.push(i),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 ie(){return this.hours()%12||12}function ae(t,e){B(t,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),e)})}function re(t,e){return e._meridiemParse}B("H",["HH",2],0,"hour"),B("h",["hh",2],0,ie),B("k",["kk",2],0,function(){return this.hours()||24}),B("hmm",0,0,function(){return""+ie.apply(this)+Y(this.minutes(),2)}),B("hmmss",0,0,function(){return""+ie.apply(this)+Y(this.minutes(),2)+Y(this.seconds(),2)}),B("Hmm",0,0,function(){return""+this.hours()+Y(this.minutes(),2)}),B("Hmmss",0,0,function(){return""+this.hours()+Y(this.minutes(),2)+Y(this.seconds(),2)}),ae("a",!0),ae("A",!1),I("hour","h"),W("hour",13),ut("a",re),ut("A",re),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,n){var i=w(t);e[bt]=24===i?0:i}),ft(["a","A"],function(t,e,n){n._isPm=n._locale.isPM(t),n._meridiem=t}),ft(["h","hh"],function(t,e,n){e[bt]=w(t),f(n).bigHour=!0}),ft("hmm",function(t,e,n){var i=t.length-2;e[bt]=w(t.substr(0,i)),e[xt]=w(t.substr(i)),f(n).bigHour=!0}),ft("hmmss",function(t,e,n){var i=t.length-4,a=t.length-2;e[bt]=w(t.substr(0,i)),e[xt]=w(t.substr(i,2)),e[_t]=w(t.substr(a)),f(n).bigHour=!0}),ft("Hmm",function(t,e,n){var i=t.length-2;e[bt]=w(t.substr(0,i)),e[xt]=w(t.substr(i))}),ft("Hmmss",function(t,e,n){var i=t.length-4,a=t.length-2;e[bt]=w(t.substr(0,i)),e[xt]=w(t.substr(i,2)),e[_t]=w(t.substr(a))});var oe,se=Pt("Hours",!0),le={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:Lt,monthsShort:Rt,week:{dow:0,doy:6},weekdays:$t,weekdaysMin:Kt,weekdaysShort:Xt,meridiemParse:/[ap]\.?m?\.?/i},ue={},de={};function he(t){return t?t.toLowerCase().replace("_","-"):t}function ce(e){var n=null;if(!ue[e]&&t&&t.exports)try{n=oe._abbr,Re(),fe(n)}catch(t){}return ue[e]}function fe(t,e){var n;return t&&((n=o(e)?me(t):ge(t,e))?oe=n:"undefined"!=typeof console&&console.warn&&console.warn("Locale "+t+" not found. Did you forget to load it?")),oe._abbr}function ge(t,e){if(null!==e){var n,i=le;if(e.abbr=t,null!=ue[t])T("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."),i=ue[t]._config;else if(null!=e.parentLocale)if(null!=ue[e.parentLocale])i=ue[e.parentLocale]._config;else{if(null==(n=ce(e.parentLocale)))return de[e.parentLocale]||(de[e.parentLocale]=[]),de[e.parentLocale].push({name:t,config:e}),null;i=n._config}return ue[t]=new O(A(i,e)),de[t]&&de[t].forEach(function(t){ge(t.name,t.config)}),fe(t),ue[t]}return delete ue[t],null}function me(t){var e;if(t&&t._locale&&t._locale._abbr&&(t=t._locale._abbr),!t)return oe;if(!a(t)){if(e=ce(t))return e;t=[t]}return function(t){for(var e,n,i,a,r=0;r<t.length;){for(e=(a=he(t[r]).split("-")).length,n=(n=he(t[r+1]))?n.split("-"):null;e>0;){if(i=ce(a.slice(0,e).join("-")))return i;if(n&&n.length>=e&&k(a,n,!0)>=e-1)break;e--}r++}return oe}(t)}function pe(t){var e,n=t._a;return n&&-2===f(t).overflow&&(e=n[vt]<0||n[vt]>11?vt:n[yt]<1||n[yt]>Ft(n[pt],n[vt])?yt:n[bt]<0||n[bt]>24||24===n[bt]&&(0!==n[xt]||0!==n[_t]||0!==n[wt])?bt:n[xt]<0||n[xt]>59?xt:n[_t]<0||n[_t]>59?_t:n[wt]<0||n[wt]>999?wt:-1,f(t)._overflowDayOfYear&&(e<pt||e>yt)&&(e=yt),f(t)._overflowWeeks&&-1===e&&(e=kt),f(t)._overflowWeekday&&-1===e&&(e=Mt),f(t).overflow=e),t}function ve(t,e,n){return null!=t?t:null!=e?e:n}function ye(t){var e,n,a,r,o,s=[];if(!t._d){for(a=function(t){var e=new Date(i.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,n,i,a,r,o,s,l;if(null!=(e=t._w).GG||null!=e.W||null!=e.E)r=1,o=4,n=ve(e.GG,t._a[pt],Gt(Ie(),1,4).year),i=ve(e.W,1),((a=ve(e.E,1))<1||a>7)&&(l=!0);else{r=t._locale._week.dow,o=t._locale._week.doy;var u=Gt(Ie(),r,o);n=ve(e.gg,t._a[pt],u.year),i=ve(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}i<1||i>qt(n,r,o)?f(t)._overflowWeeks=!0:null!=l?f(t)._overflowWeekday=!0:(s=Ut(n,i,a,r,o),t._a[pt]=s.year,t._dayOfYear=s.dayOfYear)}(t),null!=t._dayOfYear&&(o=ve(t._a[pt],a[pt]),(t._dayOfYear>St(o)||0===t._dayOfYear)&&(f(t)._overflowDayOfYear=!0),n=Bt(o,0,t._dayOfYear),t._a[vt]=n.getUTCMonth(),t._a[yt]=n.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[wt]&&(t._nextDay=!0,t._a[bt]=0),t._d=(t._useUTC?Bt:Ht).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 be=/^\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)?)?$/,xe=/^\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)?)?$/,_e=/Z|[+-]\d\d(?::?\d\d)?/,we=[["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}/]],ke=[["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/]],Me=/^\/?Date\((\-?\d+)/i;function Se(t){var e,n,i,a,r,o,s=t._i,l=be.exec(s)||xe.exec(s);if(l){for(f(t).iso=!0,e=0,n=we.length;e<n;e++)if(we[e][1].exec(l[1])){a=we[e][0],i=!1!==we[e][2];break}if(null==a)return void(t._isValid=!1);if(l[3]){for(e=0,n=ke.length;e<n;e++)if(ke[e][1].exec(l[3])){r=(l[2]||" ")+ke[e][0];break}if(null==r)return void(t._isValid=!1)}if(!i&&null!=r)return void(t._isValid=!1);if(l[4]){if(!_e.exec(l[4]))return void(t._isValid=!1);o="Z"}t._f=a+(r||"")+(o||""),Ae(t)}else t._isValid=!1}var De=/^(?:(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 Ce(t){var e=parseInt(t,10);return e<=49?2e3+e:e<=999?1900+e:e}var Te={UT:0,GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function Pe(t){var e,n,i,a,r,o,s,l=De.exec(t._i.replace(/\([^)]*\)|[\n\t]/g," ").replace(/(\s\s+)/g," ").replace(/^\s\s*/,"").replace(/\s\s*$/,""));if(l){var u=(e=l[4],n=l[3],i=l[2],a=l[5],r=l[6],o=l[7],s=[Ce(e),Rt.indexOf(n),parseInt(i,10),parseInt(a,10),parseInt(r,10)],o&&s.push(parseInt(o,10)),s);if(!function(t,e,n){return!t||Xt.indexOf(t)===new Date(e[0],e[1],e[2]).getDay()||(f(n).weekdayMismatch=!0,n._isValid=!1,!1)}(l[1],u,t))return;t._a=u,t._tzm=function(t,e,n){if(t)return Te[t];if(e)return 0;var i=parseInt(n,10),a=i%100;return(i-a)/100*60+a}(l[8],l[9],l[10]),t._d=Bt.apply(null,t._a),t._d.setUTCMinutes(t._d.getUTCMinutes()-t._tzm),f(t).rfc2822=!0}else t._isValid=!1}function Ae(t){if(t._f!==i.ISO_8601)if(t._f!==i.RFC_2822){t._a=[],f(t).empty=!0;var e,n,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],(n=(s.match(dt(r,t))||[])[0])&&((o=s.substr(0,s.indexOf(n))).length>0&&f(t).unusedInput.push(o),s=s.slice(s.indexOf(n)+n.length),u+=n.length),H[r]?(n?f(t).empty=!1:f(t).unusedTokens.push(r),mt(r,n,t)):t._strict&&!n&&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]=function(t,e,n){var i;return null==n?e:null!=t.meridiemHour?t.meridiemHour(e,n):null!=t.isPM?((i=t.isPM(n))&&e<12&&(e+=12),i||12!==e||(e=0),e):e}(t._locale,t._a[bt],t._meridiem),ye(t),pe(t)}else Pe(t);else Se(t)}function Oe(t){var e=t._i,n=t._f;return t._locale=t._locale||me(t._l),null===e||void 0===n&&""===e?m({nullInput:!0}):("string"==typeof e&&(t._i=e=t._locale.preparse(e)),x(e)?new b(pe(e)):(l(e)?t._d=e:a(n)?function(t){var e,n,i,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],Ae(e),g(e)&&(r+=f(e).charsLeftOver,r+=10*f(e).unusedTokens.length,f(e).score=r,(null==i||r<i)&&(i=r,n=e));h(t,n||e)}(t):n?Ae(t):function(t){var e=t._i;o(e)?t._d=new Date(i.now()):l(e)?t._d=new Date(e.valueOf()):"string"==typeof e?function(t){var e=Me.exec(t._i);null===e?(Se(t),!1===t._isValid&&(delete t._isValid,Pe(t),!1===t._isValid&&(delete t._isValid,i.createFromInputFallback(t)))):t._d=new Date(+e[1])}(t):a(e)?(t._a=u(e.slice(0),function(t){return parseInt(t,10)}),ye(t)):r(e)?function(t){if(!t._d){var e=R(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)}),ye(t)}}(t):s(e)?t._d=new Date(e):i.createFromInputFallback(t)}(t),g(t)||(t._d=null),t))}function Fe(t,e,n,i,o){var s,l={};return!0!==n&&!1!==n||(i=n,n=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=n,l._i=t,l._f=e,l._strict=i,(s=new b(pe(Oe(l))))._nextDay&&(s.add(1,"d"),s._nextDay=void 0),s}function Ie(t,e,n,i){return Fe(t,e,n,i,!1)}i.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":""))}),i.ISO_8601=function(){},i.RFC_2822=function(){};var Le=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()}),Ne=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 We(t,e){var n,i;if(1===e.length&&a(e[0])&&(e=e[0]),!e.length)return Ie();for(n=e[0],i=1;i<e.length;++i)e[i].isValid()&&!e[i][t](n)||(n=e[i]);return n}var Ye=["year","quarter","month","week","day","hour","minute","second","millisecond"];function ze(t){var e=R(t),n=e.year||0,i=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(Ye,e)||null!=t[e]&&isNaN(t[e]))return!1;for(var n=!1,i=0;i<Ye.length;++i)if(t[Ye[i]]){if(n)return!1;parseFloat(t[Ye[i]])!==w(t[Ye[i]])&&(n=!0)}return!0}(e),this._milliseconds=+d+1e3*u+6e4*l+1e3*s*60*60,this._days=+o+7*r,this._months=+a+3*i+12*n,this._data={},this._locale=me(),this._bubble()}function Ve(t){return t instanceof ze}function Ee(t){return t<0?-1*Math.round(-1*t):Math.round(t)}function He(t,e){B(t,0,0,function(){var t=this.utcOffset(),n="+";return t<0&&(t=-t,n="-"),n+Y(~~(t/60),2)+e+Y(~~t%60,2)})}He("Z",":"),He("ZZ",""),ut("Z",ot),ut("ZZ",ot),ft(["Z","ZZ"],function(t,e,n){n._useUTC=!0,n._tzm=je(ot,t)});var Be=/([\+\-]|\d\d)/gi;function je(t,e){var n=(e||"").match(t);if(null===n)return null;var i=((n[n.length-1]||[])+"").match(Be)||["-",0,0],a=60*i[1]+w(i[2]);return 0===a?0:"+"===i[0]?a:-a}function Ue(t,e){var n,a;return e._isUTC?(n=e.clone(),a=(x(t)||l(t)?t.valueOf():Ie(t).valueOf())-n.valueOf(),n._d.setTime(n._d.valueOf()+a),i.updateOffset(n,!1),n):Ie(t).local()}function Ge(t){return 15*-Math.round(t._d.getTimezoneOffset()/15)}function qe(){return!!this.isValid()&&this._isUTC&&0===this._offset}i.updateOffset=function(){};var Ze=/^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,$e=/^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;function Xe(t,e){var n,i,a,r,o,l,u=t,h=null;return Ve(t)?u={ms:t._milliseconds,d:t._days,M:t._months}:s(t)?(u={},e?u[e]=t:u.milliseconds=t):(h=Ze.exec(t))?(n="-"===h[1]?-1:1,u={y:0,d:w(h[yt])*n,h:w(h[bt])*n,m:w(h[xt])*n,s:w(h[_t])*n,ms:w(Ee(1e3*h[wt]))*n}):(h=$e.exec(t))?(n="-"===h[1]?-1:1,u={y:Ke(h[2],n),M:Ke(h[3],n),w:Ke(h[4],n),d:Ke(h[5],n),h:Ke(h[6],n),m:Ke(h[7],n),s:Ke(h[8],n)}):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=Ue(o,r),r.isBefore(o)?l=Je(r,o):((l=Je(o,r)).milliseconds=-l.milliseconds,l.months=-l.months),l):{milliseconds:0,months:0},(u={}).ms=a.milliseconds,u.M=a.months),i=new ze(u),Ve(t)&&d(t,"_locale")&&(i._locale=t._locale),i}function Ke(t,e){var n=t&&parseFloat(t.replace(",","."));return(isNaN(n)?0:n)*e}function Je(t,e){var n={};return n.months=e.month()-t.month()+12*(e.year()-t.year()),t.clone().add(n.months,"M").isAfter(e)&&--n.months,n.milliseconds=+e-+t.clone().add(n.months,"M"),n}function Qe(t,e){return function(n,i){var a;return null===i||isNaN(+i)||(T(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=n,n=i,i=a),tn(this,Xe(n="string"==typeof n?+n:n,i),t),this}}function tn(t,e,n,a){var r=e._milliseconds,o=Ee(e._days),s=Ee(e._months);t.isValid()&&(a=null==a||a,s&&Wt(t,At(t,"Month")+s*n),o&&Ot(t,"Date",At(t,"Date")+o*n),r&&t._d.setTime(t._d.valueOf()+r*n),a&&i.updateOffset(t,o||s))}Xe.fn=ze.prototype,Xe.invalid=function(){return Xe(NaN)};var en=Qe(1,"add"),nn=Qe(-1,"subtract");function an(t,e){var n=12*(e.year()-t.year())+(e.month()-t.month()),i=t.clone().add(n,"months");return-(n+(e-i<0?(e-i)/(i-t.clone().add(n-1,"months")):(e-i)/(t.clone().add(n+1,"months")-i)))||0}function rn(t){var e;return void 0===t?this._locale._abbr:(null!=(e=me(t))&&(this._locale=e),this)}i.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",i.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var on=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 sn(){return this._locale}var ln=1e3,un=60*ln,dn=60*un,hn=3506328*dn;function cn(t,e){return(t%e+e)%e}function fn(t,e,n){return t<100&&t>=0?new Date(t+400,e,n)-hn:new Date(t,e,n).valueOf()}function gn(t,e,n){return t<100&&t>=0?Date.UTC(t+400,e,n)-hn:Date.UTC(t,e,n)}function mn(t,e){B(0,[t,t.length],0,e)}function pn(t,e,n,i,a){var r;return null==t?Gt(this,i,a).year:(e>(r=qt(t,i,a))&&(e=r),vn.call(this,t,e,n,i,a))}function vn(t,e,n,i,a){var r=Ut(t,e,n,i,a),o=Bt(r.year,0,r.dayOfYear);return this.year(o.getUTCFullYear()),this.month(o.getUTCMonth()),this.date(o.getUTCDate()),this}B(0,["gg",2],0,function(){return this.weekYear()%100}),B(0,["GG",2],0,function(){return this.isoWeekYear()%100}),mn("gggg","weekYear"),mn("ggggg","weekYear"),mn("GGGG","isoWeekYear"),mn("GGGGG","isoWeekYear"),I("weekYear","gg"),I("isoWeekYear","GG"),W("weekYear",1),W("isoWeekYear",1),ut("G",at),ut("g",at),ut("GG",K,q),ut("gg",K,q),ut("GGGG",et,$),ut("gggg",et,$),ut("GGGGG",nt,X),ut("ggggg",nt,X),gt(["gggg","ggggg","GGGG","GGGGG"],function(t,e,n,i){e[i.substr(0,2)]=w(t)}),gt(["gg","GG"],function(t,e,n,a){e[a]=i.parseTwoDigitYear(t)}),B("Q",0,"Qo","quarter"),I("quarter","Q"),W("quarter",7),ut("Q",G),ft("Q",function(t,e){e[vt]=3*(w(t)-1)}),B("D",["DD",2],"Do","date"),I("date","D"),W("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]=w(t.match(K)[0])});var yn=Pt("Date",!0);B("DDD",["DDDD",3],"DDDo","dayOfYear"),I("dayOfYear","DDD"),W("dayOfYear",4),ut("DDD",tt),ut("DDDD",Z),ft(["DDD","DDDD"],function(t,e,n){n._dayOfYear=w(t)}),B("m",["mm",2],0,"minute"),I("minute","m"),W("minute",14),ut("m",K),ut("mm",K,q),ft(["m","mm"],xt);var bn=Pt("Minutes",!1);B("s",["ss",2],0,"second"),I("second","s"),W("second",15),ut("s",K),ut("ss",K,q),ft(["s","ss"],_t);var xn,_n=Pt("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()}),I("millisecond","ms"),W("millisecond",16),ut("S",tt,G),ut("SS",tt,q),ut("SSS",tt,Z),xn="SSSS";xn.length<=9;xn+="S")ut(xn,it);function wn(t,e){e[wt]=w(1e3*("0."+t))}for(xn="S";xn.length<=9;xn+="S")ft(xn,wn);var kn=Pt("Milliseconds",!1);B("z",0,0,"zoneAbbr"),B("zz",0,0,"zoneName");var Mn=b.prototype;function Sn(t){return t}Mn.add=en,Mn.calendar=function(t,e){var n=t||Ie(),a=Ue(n,this).startOf("day"),r=i.calendarFormat(this,a)||"sameElse",o=e&&(P(e[r])?e[r].call(this,n):e[r]);return this.format(o||this.localeData().calendar(r,this,Ie(n)))},Mn.clone=function(){return new b(this)},Mn.diff=function(t,e,n){var i,a,r;if(!this.isValid())return NaN;if(!(i=Ue(t,this)).isValid())return NaN;switch(a=6e4*(i.utcOffset()-this.utcOffset()),e=L(e)){case"year":r=an(this,i)/12;break;case"month":r=an(this,i);break;case"quarter":r=an(this,i)/3;break;case"second":r=(this-i)/1e3;break;case"minute":r=(this-i)/6e4;break;case"hour":r=(this-i)/36e5;break;case"day":r=(this-i-a)/864e5;break;case"week":r=(this-i-a)/6048e5;break;default:r=this-i}return n?r:_(r)},Mn.endOf=function(t){var e;if(void 0===(t=L(t))||"millisecond"===t||!this.isValid())return this;var n=this._isUTC?gn:fn;switch(t){case"year":e=n(this.year()+1,0,1)-1;break;case"quarter":e=n(this.year(),this.month()-this.month()%3+3,1)-1;break;case"month":e=n(this.year(),this.month()+1,1)-1;break;case"week":e=n(this.year(),this.month(),this.date()-this.weekday()+7)-1;break;case"isoWeek":e=n(this.year(),this.month(),this.date()-(this.isoWeekday()-1)+7)-1;break;case"day":case"date":e=n(this.year(),this.month(),this.date()+1)-1;break;case"hour":e=this._d.valueOf(),e+=dn-cn(e+(this._isUTC?0:this.utcOffset()*un),dn)-1;break;case"minute":e=this._d.valueOf(),e+=un-cn(e,un)-1;break;case"second":e=this._d.valueOf(),e+=ln-cn(e,ln)-1}return this._d.setTime(e),i.updateOffset(this,!0),this},Mn.format=function(t){t||(t=this.isUtc()?i.defaultFormatUtc:i.defaultFormat);var e=j(this,t);return this.localeData().postformat(e)},Mn.from=function(t,e){return this.isValid()&&(x(t)&&t.isValid()||Ie(t).isValid())?Xe({to:this,from:t}).locale(this.locale()).humanize(!e):this.localeData().invalidDate()},Mn.fromNow=function(t){return this.from(Ie(),t)},Mn.to=function(t,e){return this.isValid()&&(x(t)&&t.isValid()||Ie(t).isValid())?Xe({from:this,to:t}).locale(this.locale()).humanize(!e):this.localeData().invalidDate()},Mn.toNow=function(t){return this.to(Ie(),t)},Mn.get=function(t){return P(this[t=L(t)])?this[t]():this},Mn.invalidAt=function(){return f(this).overflow},Mn.isAfter=function(t,e){var n=x(t)?t:Ie(t);return!(!this.isValid()||!n.isValid())&&("millisecond"===(e=L(e)||"millisecond")?this.valueOf()>n.valueOf():n.valueOf()<this.clone().startOf(e).valueOf())},Mn.isBefore=function(t,e){var n=x(t)?t:Ie(t);return!(!this.isValid()||!n.isValid())&&("millisecond"===(e=L(e)||"millisecond")?this.valueOf()<n.valueOf():this.clone().endOf(e).valueOf()<n.valueOf())},Mn.isBetween=function(t,e,n,i){var a=x(t)?t:Ie(t),r=x(e)?e:Ie(e);return!!(this.isValid()&&a.isValid()&&r.isValid())&&("("===(i=i||"()")[0]?this.isAfter(a,n):!this.isBefore(a,n))&&(")"===i[1]?this.isBefore(r,n):!this.isAfter(r,n))},Mn.isSame=function(t,e){var n,i=x(t)?t:Ie(t);return!(!this.isValid()||!i.isValid())&&("millisecond"===(e=L(e)||"millisecond")?this.valueOf()===i.valueOf():(n=i.valueOf(),this.clone().startOf(e).valueOf()<=n&&n<=this.clone().endOf(e).valueOf()))},Mn.isSameOrAfter=function(t,e){return this.isSame(t,e)||this.isAfter(t,e)},Mn.isSameOrBefore=function(t,e){return this.isSame(t,e)||this.isBefore(t,e)},Mn.isValid=function(){return g(this)},Mn.lang=on,Mn.locale=rn,Mn.localeData=sn,Mn.max=Ne,Mn.min=Le,Mn.parsingFlags=function(){return h({},f(this))},Mn.set=function(t,e){if("object"==typeof t)for(var n=function(t){var e=[];for(var n in t)e.push({unit:n,priority:N[n]});return e.sort(function(t,e){return t.priority-e.priority}),e}(t=R(t)),i=0;i<n.length;i++)this[n[i].unit](t[n[i].unit]);else if(P(this[t=L(t)]))return this[t](e);return this},Mn.startOf=function(t){var e;if(void 0===(t=L(t))||"millisecond"===t||!this.isValid())return this;var n=this._isUTC?gn:fn;switch(t){case"year":e=n(this.year(),0,1);break;case"quarter":e=n(this.year(),this.month()-this.month()%3,1);break;case"month":e=n(this.year(),this.month(),1);break;case"week":e=n(this.year(),this.month(),this.date()-this.weekday());break;case"isoWeek":e=n(this.year(),this.month(),this.date()-(this.isoWeekday()-1));break;case"day":case"date":e=n(this.year(),this.month(),this.date());break;case"hour":e=this._d.valueOf(),e-=cn(e+(this._isUTC?0:this.utcOffset()*un),dn);break;case"minute":e=this._d.valueOf(),e-=cn(e,un);break;case"second":e=this._d.valueOf(),e-=cn(e,ln)}return this._d.setTime(e),i.updateOffset(this,!0),this},Mn.subtract=nn,Mn.toArray=function(){var t=this;return[t.year(),t.month(),t.date(),t.hour(),t.minute(),t.second(),t.millisecond()]},Mn.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()}},Mn.toDate=function(){return new Date(this.valueOf())},Mn.toISOString=function(t){if(!this.isValid())return null;var e=!0!==t,n=e?this.clone().utc():this;return n.year()<0||n.year()>9999?j(n,e?"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ"):P(Date.prototype.toISOString)?e?this.toDate().toISOString():new Date(this.valueOf()+60*this.utcOffset()*1e3).toISOString().replace("Z",j(n,"Z")):j(n,e?"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYY-MM-DD[T]HH:mm:ss.SSSZ")},Mn.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 n="["+t+'("]',i=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",a=e+'[")]';return this.format(n+i+"-MM-DD[T]HH:mm:ss.SSS"+a)},Mn.toJSON=function(){return this.isValid()?this.toISOString():null},Mn.toString=function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},Mn.unix=function(){return Math.floor(this.valueOf()/1e3)},Mn.valueOf=function(){return this._d.valueOf()-6e4*(this._offset||0)},Mn.creationData=function(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},Mn.year=Tt,Mn.isLeapYear=function(){return Dt(this.year())},Mn.weekYear=function(t){return pn.call(this,t,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)},Mn.isoWeekYear=function(t){return pn.call(this,t,this.isoWeek(),this.isoWeekday(),1,4)},Mn.quarter=Mn.quarters=function(t){return null==t?Math.ceil((this.month()+1)/3):this.month(3*(t-1)+this.month()%3)},Mn.month=Yt,Mn.daysInMonth=function(){return Ft(this.year(),this.month())},Mn.week=Mn.weeks=function(t){var e=this.localeData().week(this);return null==t?e:this.add(7*(t-e),"d")},Mn.isoWeek=Mn.isoWeeks=function(t){var e=Gt(this,1,4).week;return null==t?e:this.add(7*(t-e),"d")},Mn.weeksInYear=function(){var t=this.localeData()._week;return qt(this.year(),t.dow,t.doy)},Mn.isoWeeksInYear=function(){return qt(this.year(),1,4)},Mn.date=yn,Mn.day=Mn.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},Mn.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")},Mn.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},Mn.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")},Mn.hour=Mn.hours=se,Mn.minute=Mn.minutes=bn,Mn.second=Mn.seconds=_n,Mn.millisecond=Mn.milliseconds=kn,Mn.utcOffset=function(t,e,n){var a,r=this._offset||0;if(!this.isValid())return null!=t?this:NaN;if(null!=t){if("string"==typeof t){if(null===(t=je(ot,t)))return this}else Math.abs(t)<16&&!n&&(t*=60);return!this._isUTC&&e&&(a=Ge(this)),this._offset=t,this._isUTC=!0,null!=a&&this.add(a,"m"),r!==t&&(!e||this._changeInProgress?tn(this,Xe(t-r,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,i.updateOffset(this,!0),this._changeInProgress=null)),this}return this._isUTC?r:Ge(this)},Mn.utc=function(t){return this.utcOffset(0,t)},Mn.local=function(t){return this._isUTC&&(this.utcOffset(0,t),this._isUTC=!1,t&&this.subtract(Ge(this),"m")),this},Mn.parseZone=function(){if(null!=this._tzm)this.utcOffset(this._tzm,!1,!0);else if("string"==typeof this._i){var t=je(rt,this._i);null!=t?this.utcOffset(t):this.utcOffset(0,!0)}return this},Mn.hasAlignedHourOffset=function(t){return!!this.isValid()&&(t=t?Ie(t).utcOffset():0,(this.utcOffset()-t)%60==0)},Mn.isDST=function(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},Mn.isLocal=function(){return!!this.isValid()&&!this._isUTC},Mn.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},Mn.isUtc=qe,Mn.isUTC=qe,Mn.zoneAbbr=function(){return this._isUTC?"UTC":""},Mn.zoneName=function(){return this._isUTC?"Coordinated Universal Time":""},Mn.dates=S("dates accessor is deprecated. Use date instead.",yn),Mn.months=S("months accessor is deprecated. Use month instead",Yt),Mn.years=S("years accessor is deprecated. Use year instead",Tt),Mn.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()}),Mn.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=Oe(t))._a){var e=t._isUTC?c(t._a):Ie(t._a);this._isDSTShifted=this.isValid()&&k(t._a,e.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted});var Dn=O.prototype;function Cn(t,e,n,i){var a=me(),r=c().set(i,e);return a[n](r,t)}function Tn(t,e,n){if(s(t)&&(e=t,t=void 0),t=t||"",null!=e)return Cn(t,e,n,"month");var i,a=[];for(i=0;i<12;i++)a[i]=Cn(t,i,n,"month");return a}function Pn(t,e,n,i){"boolean"==typeof t?(s(e)&&(n=e,e=void 0),e=e||""):(n=e=t,t=!1,s(e)&&(n=e,e=void 0),e=e||"");var a,r=me(),o=t?r._week.dow:0;if(null!=n)return Cn(e,(n+o)%7,i,"day");var l=[];for(a=0;a<7;a++)l[a]=Cn(e,(a+o)%7,i,"day");return l}Dn.calendar=function(t,e,n){var i=this._calendar[t]||this._calendar.sameElse;return P(i)?i.call(e,n):i},Dn.longDateFormat=function(t){var e=this._longDateFormat[t],n=this._longDateFormat[t.toUpperCase()];return e||!n?e:(this._longDateFormat[t]=n.replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t])},Dn.invalidDate=function(){return this._invalidDate},Dn.ordinal=function(t){return this._ordinal.replace("%d",t)},Dn.preparse=Sn,Dn.postformat=Sn,Dn.relativeTime=function(t,e,n,i){var a=this._relativeTime[n];return P(a)?a(t,e,n,i):a.replace(/%d/i,t)},Dn.pastFuture=function(t,e){var n=this._relativeTime[t>0?"future":"past"];return P(n)?n(e):n.replace(/%s/i,e)},Dn.set=function(t){var e,n;for(n in t)P(e=t[n])?this[n]=e:this["_"+n]=e;this._config=t,this._dayOfMonthOrdinalParseLenient=new RegExp((this._dayOfMonthOrdinalParse.source||this._ordinalParse.source)+"|"+/\d{1,2}/.source)},Dn.months=function(t,e){return t?a(this._months)?this._months[t.month()]:this._months[(this._months.isFormat||It).test(e)?"format":"standalone"][t.month()]:a(this._months)?this._months:this._months.standalone},Dn.monthsShort=function(t,e){return t?a(this._monthsShort)?this._monthsShort[t.month()]:this._monthsShort[It.test(e)?"format":"standalone"][t.month()]:a(this._monthsShort)?this._monthsShort:this._monthsShort.standalone},Dn.monthsParse=function(t,e,n){var i,a,r;if(this._monthsParseExact)return Nt.call(this,t,e,n);for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),i=0;i<12;i++){if(a=c([2e3,i]),n&&!this._longMonthsParse[i]&&(this._longMonthsParse[i]=new RegExp("^"+this.months(a,"").replace(".","")+"$","i"),this._shortMonthsParse[i]=new RegExp("^"+this.monthsShort(a,"").replace(".","")+"$","i")),n||this._monthsParse[i]||(r="^"+this.months(a,"")+"|^"+this.monthsShort(a,""),this._monthsParse[i]=new RegExp(r.replace(".",""),"i")),n&&"MMMM"===e&&this._longMonthsParse[i].test(t))return i;if(n&&"MMM"===e&&this._shortMonthsParse[i].test(t))return i;if(!n&&this._monthsParse[i].test(t))return i}},Dn.monthsRegex=function(t){return this._monthsParseExact?(d(this,"_monthsRegex")||Et.call(this),t?this._monthsStrictRegex:this._monthsRegex):(d(this,"_monthsRegex")||(this._monthsRegex=Vt),this._monthsStrictRegex&&t?this._monthsStrictRegex:this._monthsRegex)},Dn.monthsShortRegex=function(t){return this._monthsParseExact?(d(this,"_monthsRegex")||Et.call(this),t?this._monthsShortStrictRegex:this._monthsShortRegex):(d(this,"_monthsShortRegex")||(this._monthsShortRegex=zt),this._monthsShortStrictRegex&&t?this._monthsShortStrictRegex:this._monthsShortRegex)},Dn.week=function(t){return Gt(t,this._week.dow,this._week.doy).week},Dn.firstDayOfYear=function(){return this._week.doy},Dn.firstDayOfWeek=function(){return this._week.dow},Dn.weekdays=function(t,e){var n=a(this._weekdays)?this._weekdays:this._weekdays[t&&!0!==t&&this._weekdays.isFormat.test(e)?"format":"standalone"];return!0===t?Zt(n,this._week.dow):t?n[t.day()]:n},Dn.weekdaysMin=function(t){return!0===t?Zt(this._weekdaysMin,this._week.dow):t?this._weekdaysMin[t.day()]:this._weekdaysMin},Dn.weekdaysShort=function(t){return!0===t?Zt(this._weekdaysShort,this._week.dow):t?this._weekdaysShort[t.day()]:this._weekdaysShort},Dn.weekdaysParse=function(t,e,n){var i,a,r;if(this._weekdaysParseExact)return Jt.call(this,t,e,n);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),i=0;i<7;i++){if(a=c([2e3,1]).day(i),n&&!this._fullWeekdaysParse[i]&&(this._fullWeekdaysParse[i]=new RegExp("^"+this.weekdays(a,"").replace(".","\\.?")+"$","i"),this._shortWeekdaysParse[i]=new RegExp("^"+this.weekdaysShort(a,"").replace(".","\\.?")+"$","i"),this._minWeekdaysParse[i]=new RegExp("^"+this.weekdaysMin(a,"").replace(".","\\.?")+"$","i")),this._weekdaysParse[i]||(r="^"+this.weekdays(a,"")+"|^"+this.weekdaysShort(a,"")+"|^"+this.weekdaysMin(a,""),this._weekdaysParse[i]=new RegExp(r.replace(".",""),"i")),n&&"dddd"===e&&this._fullWeekdaysParse[i].test(t))return i;if(n&&"ddd"===e&&this._shortWeekdaysParse[i].test(t))return i;if(n&&"dd"===e&&this._minWeekdaysParse[i].test(t))return i;if(!n&&this._weekdaysParse[i].test(t))return i}},Dn.weekdaysRegex=function(t){return this._weekdaysParseExact?(d(this,"_weekdaysRegex")||ne.call(this),t?this._weekdaysStrictRegex:this._weekdaysRegex):(d(this,"_weekdaysRegex")||(this._weekdaysRegex=Qt),this._weekdaysStrictRegex&&t?this._weekdaysStrictRegex:this._weekdaysRegex)},Dn.weekdaysShortRegex=function(t){return this._weekdaysParseExact?(d(this,"_weekdaysRegex")||ne.call(this),t?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(d(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=te),this._weekdaysShortStrictRegex&&t?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)},Dn.weekdaysMinRegex=function(t){return this._weekdaysParseExact?(d(this,"_weekdaysRegex")||ne.call(this),t?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(d(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=ee),this._weekdaysMinStrictRegex&&t?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)},Dn.isPM=function(t){return"p"===(t+"").toLowerCase().charAt(0)},Dn.meridiem=function(t,e,n){return t>11?n?"pm":"PM":n?"am":"AM"},fe("en",{dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(t){var e=t%10;return t+(1===w(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th")}}),i.lang=S("moment.lang is deprecated. Use moment.locale instead.",fe),i.langData=S("moment.langData is deprecated. Use moment.localeData instead.",me);var An=Math.abs;function On(t,e,n,i){var a=Xe(e,n);return t._milliseconds+=i*a._milliseconds,t._days+=i*a._days,t._months+=i*a._months,t._bubble()}function Fn(t){return t<0?Math.floor(t):Math.ceil(t)}function In(t){return 4800*t/146097}function Ln(t){return 146097*t/4800}function Rn(t){return function(){return this.as(t)}}var Nn=Rn("ms"),Wn=Rn("s"),Yn=Rn("m"),zn=Rn("h"),Vn=Rn("d"),En=Rn("w"),Hn=Rn("M"),Bn=Rn("Q"),jn=Rn("y");function Un(t){return function(){return this.isValid()?this._data[t]:NaN}}var Gn=Un("milliseconds"),qn=Un("seconds"),Zn=Un("minutes"),$n=Un("hours"),Xn=Un("days"),Kn=Un("months"),Jn=Un("years"),Qn=Math.round,ti={ss:44,s:45,m:45,h:22,d:26,M:11};function ei(t,e,n,i,a){return a.relativeTime(e||1,!!n,t,i)}var ni=Math.abs;function ii(t){return(t>0)-(t<0)||+t}function ai(){if(!this.isValid())return this.localeData().invalidDate();var t,e,n=ni(this._milliseconds)/1e3,i=ni(this._days),a=ni(this._months);t=_(n/60),e=_(t/60),n%=60,t%=60;var r=_(a/12),o=a%=12,s=i,l=e,u=t,d=n?n.toFixed(3).replace(/\.?0+$/,""):"",h=this.asSeconds();if(!h)return"P0D";var c=h<0?"-":"",f=ii(this._months)!==ii(h)?"-":"",g=ii(this._days)!==ii(h)?"-":"",m=ii(this._milliseconds)!==ii(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 ri=ze.prototype;return ri.isValid=function(){return this._isValid},ri.abs=function(){var t=this._data;return this._milliseconds=An(this._milliseconds),this._days=An(this._days),this._months=An(this._months),t.milliseconds=An(t.milliseconds),t.seconds=An(t.seconds),t.minutes=An(t.minutes),t.hours=An(t.hours),t.months=An(t.months),t.years=An(t.years),this},ri.add=function(t,e){return On(this,t,e,1)},ri.subtract=function(t,e){return On(this,t,e,-1)},ri.as=function(t){if(!this.isValid())return NaN;var e,n,i=this._milliseconds;if("month"===(t=L(t))||"quarter"===t||"year"===t)switch(e=this._days+i/864e5,n=this._months+In(e),t){case"month":return n;case"quarter":return n/3;case"year":return n/12}else switch(e=this._days+Math.round(Ln(this._months)),t){case"week":return e/7+i/6048e5;case"day":return e+i/864e5;case"hour":return 24*e+i/36e5;case"minute":return 1440*e+i/6e4;case"second":return 86400*e+i/1e3;case"millisecond":return Math.floor(864e5*e)+i;default:throw new Error("Unknown unit "+t)}},ri.asMilliseconds=Nn,ri.asSeconds=Wn,ri.asMinutes=Yn,ri.asHours=zn,ri.asDays=Vn,ri.asWeeks=En,ri.asMonths=Hn,ri.asQuarters=Bn,ri.asYears=jn,ri.valueOf=function(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*w(this._months/12):NaN},ri._bubble=function(){var t,e,n,i,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*Fn(Ln(s)+o),o=0,s=0),l.milliseconds=r%1e3,t=_(r/1e3),l.seconds=t%60,e=_(t/60),l.minutes=e%60,n=_(e/60),l.hours=n%24,o+=_(n/24),a=_(In(o)),s+=a,o-=Fn(Ln(a)),i=_(s/12),s%=12,l.days=o,l.months=s,l.years=i,this},ri.clone=function(){return Xe(this)},ri.get=function(t){return t=L(t),this.isValid()?this[t+"s"]():NaN},ri.milliseconds=Gn,ri.seconds=qn,ri.minutes=Zn,ri.hours=$n,ri.days=Xn,ri.weeks=function(){return _(this.days()/7)},ri.months=Kn,ri.years=Jn,ri.humanize=function(t){if(!this.isValid())return this.localeData().invalidDate();var e=this.localeData(),n=function(t,e,n){var i=Xe(t).abs(),a=Qn(i.as("s")),r=Qn(i.as("m")),o=Qn(i.as("h")),s=Qn(i.as("d")),l=Qn(i.as("M")),u=Qn(i.as("y")),d=a<=ti.ss&&["s",a]||a<ti.s&&["ss",a]||r<=1&&["m"]||r<ti.m&&["mm",r]||o<=1&&["h"]||o<ti.h&&["hh",o]||s<=1&&["d"]||s<ti.d&&["dd",s]||l<=1&&["M"]||l<ti.M&&["MM",l]||u<=1&&["y"]||["yy",u];return d[2]=e,d[3]=+t>0,d[4]=n,ei.apply(null,d)}(this,!t,e);return t&&(n=e.pastFuture(+this,n)),e.postformat(n)},ri.toISOString=ai,ri.toString=ai,ri.toJSON=ai,ri.locale=rn,ri.localeData=sn,ri.toIsoString=S("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",ai),ri.lang=on,B("X",0,0,"unix"),B("x",0,0,"valueOf"),ut("x",at),ut("X",/[+-]?\d+(\.\d{1,3})?/),ft("X",function(t,e,n){n._d=new Date(1e3*parseFloat(t,10))}),ft("x",function(t,e,n){n._d=new Date(w(t))}),i.version="2.24.0",e=Ie,i.fn=Mn,i.min=function(){return We("isBefore",[].slice.call(arguments,0))},i.max=function(){return We("isAfter",[].slice.call(arguments,0))},i.now=function(){return Date.now?Date.now():+new Date},i.utc=c,i.unix=function(t){return Ie(1e3*t)},i.months=function(t,e){return Tn(t,e,"months")},i.isDate=l,i.locale=fe,i.invalid=m,i.duration=Xe,i.isMoment=x,i.weekdays=function(t,e,n){return Pn(t,e,n,"weekdays")},i.parseZone=function(){return Ie.apply(null,arguments).parseZone()},i.localeData=me,i.isDuration=Ve,i.monthsShort=function(t,e){return Tn(t,e,"monthsShort")},i.weekdaysMin=function(t,e,n){return Pn(t,e,n,"weekdaysMin")},i.defineLocale=ge,i.updateLocale=function(t,e){if(null!=e){var n,i,a=le;null!=(i=ce(t))&&(a=i._config),e=A(a,e),(n=new O(e)).parentLocale=ue[t],ue[t]=n,fe(t)}else null!=ue[t]&&(null!=ue[t].parentLocale?ue[t]=ue[t].parentLocale:null!=ue[t]&&delete ue[t]);return ue[t]},i.locales=function(){return D(ue)},i.weekdaysShort=function(t,e,n){return Pn(t,e,n,"weekdaysShort")},i.normalizeUnits=L,i.relativeTimeRounding=function(t){return void 0===t?Qn:"function"==typeof t&&(Qn=t,!0)},i.relativeTimeThreshold=function(t,e){return void 0!==ti[t]&&(void 0===e?ti[t]:(ti[t]=e,"s"===t&&(ti.ss=e-1),!0))},i.calendarFormat=function(t,e){var n=t.diff(e,"days",!0);return n<-6?"sameElse":n<-1?"lastWeek":n<0?"lastDay":n<1?"sameDay":n<2?"nextDay":n<7?"nextWeek":"sameElse"},i.prototype=Mn,i.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"},i}()}),Ni={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"};Dn._date.override("function"==typeof Ri?{_id:"moment",formats:function(){return Ni},parse:function(t,e){return"string"==typeof t&&"string"==typeof e?t=Ri(t,e):t instanceof Ri||(t=Ri(t)),t.isValid()?t.valueOf():null},format:function(t,e){return Ri(t).format(e)},add:function(t,e,n){return Ri(t).add(e,n).valueOf()},diff:function(t,e,n){return Ri(t).diff(Ri(e),n)},startOf:function(t,e,n){return t=Ri(t),"isoWeek"===e?t.isoWeekday(n).valueOf():t.startOf(e).valueOf()},endOf:function(t,e){return Ri(t).endOf(e).valueOf()},_create:function(t){return Ri(t)}}:{}),ot._set("global",{plugins:{filler:{propagate:!0}}});var Wi={dataset:function(t){var e=t.fill,n=t.chart,i=n.getDatasetMeta(e),a=i&&n.isDatasetVisible(e)&&i.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,n=e?e.x:null,i=e?e.y:null;return ht.isArray(e)?function(t,n){return e[n]}:function(t){return{x:null===n?t.x:n,y:null===i?t.y:i}}}};function Yi(t,e,n){var i,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(i=parseFloat(r,10),isFinite(i)&&Math.floor(i)===i)return"-"!==r[0]&&"+"!==r[0]||(i=e+i),!(i===e||i<0||i>=n)&&i;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 zi(t){return(t.el._scale||{}).getPointPositionForValue?function(t){var e,n,i,a,r,o=t.el._scale,s=o.options,l=o.chart.data.labels.length,u=t.fill,d=[];if(!l)return null;for(e=s.ticks.reverse?o.max:o.min,n=s.ticks.reverse?o.min:o.max,i=o.getPointPositionForValue(0,e),a=0;a<l;++a)r="start"===u||"end"===u?o.getPointPositionForValue(a,"start"===u?e:n):o.getBasePosition(a),s.gridLines.circular&&(r.cx=i.x,r.cy=i.y,r.angle=o.getIndexAngle(a)-Math.PI/2),d.push(r);return d}(t):function(t){var e,n=t.el._model||{},i=t.el._scale||{},a=t.fill,r=null;if(isFinite(a))return null;if("start"===a?r=void 0===n.scaleBottom?i.bottom:n.scaleBottom:"end"===a?r=void 0===n.scaleTop?i.top:n.scaleTop:void 0!==n.scaleZero?r=n.scaleZero:i.getBasePixel&&(r=i.getBasePixel()),null!=r){if(void 0!==r.x&&void 0!==r.y)return r;if(ht.isFinite(r))return{x:(e=i.isHorizontal())?r:null,y:e?null:r}}return null}(t)}function Vi(t,e,n){var i,a=t[e].fill,r=[e];if(!n)return a;for(;!1!==a&&-1===r.indexOf(a);){if(!isFinite(a))return a;if(!(i=t[a]))return!1;if(i.visible)return a;r.push(a),a=i.fill}return!1}function Ei(t){var e=t.fill,n="dataset";return!1===e?null:(isFinite(e)||(n="boundary"),Wi[n](t))}function Hi(t){return t&&!t.skip}function Bi(t,e,n,i,a){var r,o,s,l;if(i&&a){for(t.moveTo(e[0].x,e[0].y),r=1;r<i;++r)ht.canvas.lineTo(t,e[r-1],e[r]);if(void 0===n[0].angle)for(t.lineTo(n[a-1].x,n[a-1].y),r=a-1;r>0;--r)ht.canvas.lineTo(t,n[r],n[r-1],!0);else for(o=n[0].cx,s=n[0].cy,l=Math.sqrt(Math.pow(n[0].x-o,2)+Math.pow(n[0].y-s,2)),r=a-1;r>0;--r)t.arc(o,s,l,n[r].angle,n[r-1].angle,!0)}}function ji(t,e,n,i,a,r){var o,s,l,u,d,h,c,f,g=e.length,m=i.spanGaps,p=[],v=[],y=0,b=0;for(t.beginPath(),o=0,s=g;o<s;++o)d=n(u=e[l=o%g]._view,l,i),h=Hi(u),c=Hi(d),r&&void 0===f&&h&&(s=g+(f=o+1)),h&&c?(y=p.push(u),b=v.push(d)):y&&b&&(m?(h&&p.push(u),c&&v.push(d)):(Bi(t,p,v,y,b),y=b=0,p=[],v=[]));Bi(t,p,v,y,b),t.closePath(),t.fillStyle=a,t.fill()}var Ui={id:"filler",afterDatasetsUpdate:function(t,e){var n,i,a,r,o=(t.data.datasets||[]).length,s=e.propagate,l=[];for(i=0;i<o;++i)r=null,(a=(n=t.getDatasetMeta(i)).dataset)&&a._model&&a instanceof Ut.Line&&(r={visible:t.isDatasetVisible(i),fill:Yi(a,i,o),chart:t,el:a}),n.$filler=r,l.push(r);for(i=0;i<o;++i)(r=l[i])&&(r.fill=Vi(l,i,s),r.boundary=zi(r),r.mapper=Ei(r))},beforeDatasetsDraw:function(t){var e,n,i,a,r,o,s,l=t._getSortedVisibleDatasetMetas(),u=t.ctx;for(n=l.length-1;n>=0;--n)(e=l[n].$filler)&&e.visible&&(a=(i=e.el)._view,r=i._children||[],o=e.mapper,s=a.backgroundColor||ot.global.defaultColor,o&&s&&r.length&&(ht.canvas.clipArea(u,t.chartArea),ji(u,r,o,a,s,i._loop),ht.canvas.unclipArea(u)))}},Gi=ht.rtl.getRtlAdapter,qi=ht.noop,Zi=ht.valueOrDefault;function $i(t,e){return t.usePointStyle&&t.boxWidth>e?e:t.boxWidth}ot._set("global",{legend:{display:!0,position:"top",align:"center",fullWidth:!0,reverse:!1,weight:1e3,onClick:function(t,e){var n=e.datasetIndex,i=this.chart,a=i.getDatasetMeta(n);a.hidden=null===a.hidden?!i.data.datasets[n].hidden:null,i.update()},onHover:null,onLeave:null,labels:{boxWidth:40,padding:10,generateLabels:function(t){var e=t.data.datasets,n=t.options.legend||{},i=n.labels&&n.labels.usePointStyle;return t._getSortedDatasetMetas().map(function(n,a){var r=n.controller.getStyle(i?0:void 0);return{text:e[n.index].label,fillStyle:r.backgroundColor,hidden:!t.isDatasetVisible(a),lineCap:r.borderCapStyle,lineDash:r.borderDash,lineDashOffset:r.borderDashOffset,lineJoin:r.borderJoinStyle,lineWidth:r.borderWidth,strokeStyle:r.borderColor,pointStyle:r.pointStyle,rotation:r.rotation,datasetIndex:a}},this)}}},legendCallback:function(t){var e,n,i,a=document.createElement("ul"),r=t.data.datasets;for(a.setAttribute("class",t.id+"-legend"),e=0,n=r.length;e<n;e++)(i=a.appendChild(document.createElement("li"))).appendChild(document.createElement("span")).style.backgroundColor=r[e].backgroundColor,r[e].label&&i.appendChild(document.createTextNode(r[e].label));return a.outerHTML}});var Xi=yt.extend({initialize:function(t){ht.extend(this,t),this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1},beforeUpdate:qi,update:function(t,e,n){var i=this;return i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:qi,beforeSetDimensions:qi,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:qi,beforeBuildLabels:qi,buildLabels:function(){var t=this,e=t.options.labels||{},n=ht.callback(e.generateLabels,[t.chart],t)||[];e.filter&&(n=n.filter(function(n){return e.filter(n,t.chart.data)})),t.options.reverse&&n.reverse(),t.legendItems=n},afterBuildLabels:qi,beforeFit:qi,fit:function(){var t=this,e=t.options,n=e.labels,i=e.display,a=t.ctx,r=ht.options._parseFont(n),o=r.size,s=t.legendHitBoxes=[],l=t.minSize,u=t.isHorizontal();if(u?(l.width=t.maxWidth,l.height=i?10:0):(l.width=i?10:0,l.height=t.maxHeight),i){if(a.font=r.string,u){var d=t.lineWidths=[0],h=0;a.textAlign="left",a.textBaseline="middle",ht.each(t.legendItems,function(t,e){var i=$i(n,o)+o/2+a.measureText(t.text).width;(0===e||d[d.length-1]+i+2*n.padding>l.width)&&(h+=o+n.padding,d[d.length-(e>0?0:1)]=0),s[e]={left:0,top:0,width:i,height:o},d[d.length-1]+=i+n.padding}),l.height+=h}else{var c=n.padding,f=t.columnWidths=[],g=t.columnHeights=[],m=n.padding,p=0,v=0;ht.each(t.legendItems,function(t,e){var i=$i(n,o)+o/2+a.measureText(t.text).width;e>0&&v+o+2*c>l.height&&(m+=p+n.padding,f.push(p),g.push(v),p=0,v=0),p=Math.max(p,i),v+=o+c,s[e]={left:0,top:0,width:i,height:o}}),m+=p,f.push(p),g.push(v),l.width+=m}t.width=l.width,t.height=l.height}else t.width=l.width=t.height=l.height=0},afterFit:qi,isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},draw:function(){var t=this,e=t.options,n=e.labels,i=ot.global,a=i.defaultColor,r=i.elements.line,o=t.height,s=t.columnHeights,l=t.width,u=t.lineWidths;if(e.display){var d,h=Gi(e.rtl,t.left,t.minSize.width),c=t.ctx,f=Zi(n.fontColor,i.defaultFontColor),g=ht.options._parseFont(n),m=g.size;c.textAlign=h.textAlign("left"),c.textBaseline="middle",c.lineWidth=.5,c.strokeStyle=f,c.fillStyle=f,c.font=g.string;var p=$i(n,m),v=t.legendHitBoxes,y=function(t,i){switch(e.align){case"start":return n.padding;case"end":return t-i;default:return(t-i+n.padding)/2}},b=t.isHorizontal();d=b?{x:t.left+y(l,u[0]),y:t.top+n.padding,line:0}:{x:t.left+n.padding,y:t.top+y(o,s[0]),line:0},ht.rtl.overrideTextDirection(t.ctx,e.textDirection);var x=m+n.padding;ht.each(t.legendItems,function(e,i){var f=c.measureText(e.text).width,g=p+m/2+f,_=d.x,w=d.y;h.setWidth(t.minSize.width),b?i>0&&_+g+n.padding>t.left+t.minSize.width&&(w=d.y+=x,d.line++,_=d.x=t.left+y(l,u[d.line])):i>0&&w+x>t.top+t.minSize.height&&(_=d.x=_+t.columnWidths[d.line]+n.padding,d.line++,w=d.y=t.top+y(o,s[d.line]));var k=h.x(_);!function(t,e,i){if(!(isNaN(p)||p<=0)){c.save();var o=Zi(i.lineWidth,r.borderWidth);if(c.fillStyle=Zi(i.fillStyle,a),c.lineCap=Zi(i.lineCap,r.borderCapStyle),c.lineDashOffset=Zi(i.lineDashOffset,r.borderDashOffset),c.lineJoin=Zi(i.lineJoin,r.borderJoinStyle),c.lineWidth=o,c.strokeStyle=Zi(i.strokeStyle,a),c.setLineDash&&c.setLineDash(Zi(i.lineDash,r.borderDash)),n&&n.usePointStyle){var s=p*Math.SQRT2/2,l=h.xPlus(t,p/2),u=e+m/2;ht.canvas.drawPoint(c,i.pointStyle,s,l,u,i.rotation)}else c.fillRect(h.leftForLtr(t,p),e,p,m),0!==o&&c.strokeRect(h.leftForLtr(t,p),e,p,m);c.restore()}}(k,w,e),v[i].left=h.leftForLtr(k,v[i].width),v[i].top=w,function(t,e,n,i){var a=m/2,r=h.xPlus(t,p+a),o=e+a;c.fillText(n.text,r,o),n.hidden&&(c.beginPath(),c.lineWidth=2,c.moveTo(r,o),c.lineTo(h.xPlus(r,i),o),c.stroke())}(k,w,e,f),b?d.x+=g+n.padding:d.y+=x}),ht.rtl.restoreTextDirection(t.ctx,e.textDirection)}},_getLegendItemAt:function(t,e){var n,i,a,r=this;if(t>=r.left&&t<=r.right&&e>=r.top&&e<=r.bottom)for(a=r.legendHitBoxes,n=0;n<a.length;++n)if(t>=(i=a[n]).left&&t<=i.left+i.width&&e>=i.top&&e<=i.top+i.height)return r.legendItems[n];return null},handleEvent:function(t){var e,n=this,i=n.options,a="mouseup"===t.type?"click":t.type;if("mousemove"===a){if(!i.onHover&&!i.onLeave)return}else{if("click"!==a)return;if(!i.onClick)return}e=n._getLegendItemAt(t.x,t.y),"click"===a?e&&i.onClick&&i.onClick.call(n,t.native,e):(i.onLeave&&e!==n._hoveredItem&&(n._hoveredItem&&i.onLeave.call(n,t.native,n._hoveredItem),n._hoveredItem=e),i.onHover&&e&&i.onHover.call(n,t.native,e))}});function Ki(t,e){var n=new Xi({ctx:t.ctx,options:e,chart:t});Le.configure(t,n,e),Le.addBox(t,n),t.legend=n}var Ji={id:"legend",_element:Xi,beforeInit:function(t){var e=t.options.legend;e&&Ki(t,e)},beforeUpdate:function(t){var e=t.options.legend,n=t.legend;e?(ht.mergeIf(e,ot.global.legend),n?(Le.configure(t,n,e),n.options=e):Ki(t,e)):n&&(Le.removeBox(t,n),delete t.legend)},afterEvent:function(t,e){var n=t.legend;n&&n.handleEvent(e)}},Qi=ht.noop;ot._set("global",{title:{display:!1,fontStyle:"bold",fullWidth:!0,padding:10,position:"top",text:"",weight:2e3}});var ta=yt.extend({initialize:function(t){ht.extend(this,t),this.legendHitBoxes=[]},beforeUpdate:Qi,update:function(t,e,n){var i=this;return i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:Qi,beforeSetDimensions:Qi,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:Qi,beforeBuildLabels:Qi,buildLabels:Qi,afterBuildLabels:Qi,beforeFit:Qi,fit:function(){var t,e=this,n=e.options,i=e.minSize={},a=e.isHorizontal();n.display?(t=(ht.isArray(n.text)?n.text.length:1)*ht.options._parseFont(n).lineHeight+2*n.padding,e.width=i.width=a?e.maxWidth:t,e.height=i.height=a?t:e.maxHeight):e.width=i.width=e.height=i.height=0},afterFit:Qi,isHorizontal:function(){var t=this.options.position;return"top"===t||"bottom"===t},draw:function(){var t=this,e=t.ctx,n=t.options;if(n.display){var i,a,r,o=ht.options._parseFont(n),s=o.lineHeight,l=s/2+n.padding,u=0,d=t.top,h=t.left,c=t.bottom,f=t.right;e.fillStyle=ht.valueOrDefault(n.fontColor,ot.global.defaultFontColor),e.font=o.string,t.isHorizontal()?(a=h+(f-h)/2,r=d+l,i=f-h):(a="left"===n.position?h+l:f-l,r=d+(c-d)/2,i=c-d,u=Math.PI*("left"===n.position?-.5:.5)),e.save(),e.translate(a,r),e.rotate(u),e.textAlign="center",e.textBaseline="middle";var g=n.text;if(ht.isArray(g))for(var m=0,p=0;p<g.length;++p)e.fillText(g[p],0,m,i),m+=s;else e.fillText(g,0,0,i);e.restore()}}});function ea(t,e){var n=new ta({ctx:t.ctx,options:e,chart:t});Le.configure(t,n,e),Le.addBox(t,n),t.titleBlock=n}var na={},ia=Ui,aa=Ji,ra={id:"title",_element:ta,beforeInit:function(t){var e=t.options.title;e&&ea(t,e)},beforeUpdate:function(t){var e=t.options.title,n=t.titleBlock;e?(ht.mergeIf(e,ot.global.title),n?(Le.configure(t,n,e),n.options=e):ea(t,e)):n&&(Le.removeBox(t,n),delete t.titleBlock)}};for(var oa in na.filler=ia,na.legend=aa,na.title=ra,kn.helpers=ht,function(){function t(t,e,n){var i;return"string"==typeof t?(i=parseInt(t,10),-1!==t.indexOf("%")&&(i=i/100*e.parentNode[n])):i=t,i}function e(t){return null!=t&&"none"!==t}function n(n,i,a){var r=document.defaultView,o=ht._getParentNode(n),s=r.getComputedStyle(n)[i],l=r.getComputedStyle(o)[i],u=e(s),d=e(l),h=Number.POSITIVE_INFINITY;return u||d?Math.min(u?t(s,n,a):h,d?t(l,o,a):h):"none"}ht.where=function(t,e){if(ht.isArray(t)&&Array.prototype.filter)return t.filter(e);var n=[];return ht.each(t,function(t){e(t)&&n.push(t)}),n},ht.findIndex=Array.prototype.findIndex?function(t,e,n){return t.findIndex(e,n)}:function(t,e,n){n=void 0===n?t:n;for(var i=0,a=t.length;i<a;++i)if(e.call(n,t[i],i,t))return i;return-1},ht.findNextWhere=function(t,e,n){ht.isNullOrUndef(n)&&(n=-1);for(var i=n+1;i<t.length;i++){var a=t[i];if(e(a))return a}},ht.findPreviousWhere=function(t,e,n){ht.isNullOrUndef(n)&&(n=t.length);for(var i=n-1;i>=0;i--){var a=t[i];if(e(a))return a}},ht.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},ht.almostEquals=function(t,e,n){return Math.abs(t-e)<n},ht.almostWhole=function(t,e){var n=Math.round(t);return n-e<=t&&n+e>=t},ht.max=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.max(t,e)},Number.NEGATIVE_INFINITY)},ht.min=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.min(t,e)},Number.POSITIVE_INFINITY)},ht.sign=Math.sign?function(t){return Math.sign(t)}:function(t){return 0===(t=+t)||isNaN(t)?t:t>0?1:-1},ht.toRadians=function(t){return t*(Math.PI/180)},ht.toDegrees=function(t){return t*(180/Math.PI)},ht._decimalPlaces=function(t){if(ht.isFinite(t)){for(var e=1,n=0;Math.round(t*e)/e!==t;)e*=10,n++;return n}},ht.getAngleFromPoint=function(t,e){var n=e.x-t.x,i=e.y-t.y,a=Math.sqrt(n*n+i*i),r=Math.atan2(i,n);return r<-.5*Math.PI&&(r+=2*Math.PI),{angle:r,distance:a}},ht.distanceBetweenPoints=function(t,e){return Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))},ht.aliasPixel=function(t){return t%2==0?0:.5},ht._alignPixel=function(t,e,n){var i=t.currentDevicePixelRatio,a=n/2;return Math.round((e-a)*i)/i+a},ht.splineCurve=function(t,e,n,i){var a=t.skip?e:t,r=e,o=n.skip?e:n,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=i*(u=isNaN(u)?0:u),c=i*(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)}}},ht.EPSILON=Number.EPSILON||1e-14,ht.splineCurveMonotone=function(t){var e,n,i,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(!(i=d[e]).model.skip){if(n=e>0?d[e-1]:null,(a=e<h-1?d[e+1]:null)&&!a.model.skip){var c=a.model.x-i.model.x;i.deltaK=0!==c?(a.model.y-i.model.y)/c:0}!n||n.model.skip?i.mK=i.deltaK:!a||a.model.skip?i.mK=n.deltaK:this.sign(n.deltaK)!==this.sign(i.deltaK)?i.mK=0:i.mK=(n.deltaK+i.deltaK)/2}for(e=0;e<h-1;++e)i=d[e],a=d[e+1],i.model.skip||a.model.skip||(ht.almostEquals(i.deltaK,0,this.EPSILON)?i.mK=a.mK=0:(r=i.mK/i.deltaK,o=a.mK/i.deltaK,(l=Math.pow(r,2)+Math.pow(o,2))<=9||(s=3/Math.sqrt(l),i.mK=r*s*i.deltaK,a.mK=o*s*i.deltaK)));for(e=0;e<h;++e)(i=d[e]).model.skip||(n=e>0?d[e-1]:null,a=e<h-1?d[e+1]:null,n&&!n.model.skip&&(u=(i.model.x-n.model.x)/3,i.model.controlPointPreviousX=i.model.x-u,i.model.controlPointPreviousY=i.model.y-u*i.mK),a&&!a.model.skip&&(u=(a.model.x-i.model.x)/3,i.model.controlPointNextX=i.model.x+u,i.model.controlPointNextY=i.model.y+u*i.mK))},ht.nextItem=function(t,e,n){return n?e>=t.length-1?t[0]:t[e+1]:e>=t.length-1?t[t.length-1]:t[e+1]},ht.previousItem=function(t,e,n){return n?e<=0?t[t.length-1]:t[e-1]:e<=0?t[0]:t[e-1]},ht.niceNum=function(t,e){var n=Math.floor(ht.log10(t)),i=t/Math.pow(10,n);return(e?i<1.5?1:i<3?2:i<7?5:10:i<=1?1:i<=2?2:i<=5?5:10)*Math.pow(10,n)},ht.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)},ht.getRelativePosition=function(t,e){var n,i,a=t.originalEvent||t,r=t.target||t.srcElement,o=r.getBoundingClientRect(),s=a.touches;s&&s.length>0?(n=s[0].clientX,i=s[0].clientY):(n=a.clientX,i=a.clientY);var l=parseFloat(ht.getStyle(r,"padding-left")),u=parseFloat(ht.getStyle(r,"padding-top")),d=parseFloat(ht.getStyle(r,"padding-right")),h=parseFloat(ht.getStyle(r,"padding-bottom")),c=o.right-o.left-l-d,f=o.bottom-o.top-u-h;return{x:n=Math.round((n-o.left-l)/c*r.width/e.currentDevicePixelRatio),y:i=Math.round((i-o.top-u)/f*r.height/e.currentDevicePixelRatio)}},ht.getConstraintWidth=function(t){return n(t,"max-width","clientWidth")},ht.getConstraintHeight=function(t){return n(t,"max-height","clientHeight")},ht._calculatePadding=function(t,e,n){return(e=ht.getStyle(t,e)).indexOf("%")>-1?n*parseInt(e,10)/100:parseInt(e,10)},ht._getParentNode=function(t){var e=t.parentNode;return e&&"[object ShadowRoot]"===e.toString()&&(e=e.host),e},ht.getMaximumWidth=function(t){var e=ht._getParentNode(t);if(!e)return t.clientWidth;var n=e.clientWidth,i=n-ht._calculatePadding(e,"padding-left",n)-ht._calculatePadding(e,"padding-right",n),a=ht.getConstraintWidth(t);return isNaN(a)?i:Math.min(i,a)},ht.getMaximumHeight=function(t){var e=ht._getParentNode(t);if(!e)return t.clientHeight;var n=e.clientHeight,i=n-ht._calculatePadding(e,"padding-top",n)-ht._calculatePadding(e,"padding-bottom",n),a=ht.getConstraintHeight(t);return isNaN(a)?i:Math.min(i,a)},ht.getStyle=function(t,e){return t.currentStyle?t.currentStyle[e]:document.defaultView.getComputedStyle(t,null).getPropertyValue(e)},ht.retinaScale=function(t,e){var n=t.currentDevicePixelRatio=e||"undefined"!=typeof window&&window.devicePixelRatio||1;if(1!==n){var i=t.canvas,a=t.height,r=t.width;i.height=a*n,i.width=r*n,t.ctx.scale(n,n),i.style.height||i.style.width||(i.style.height=a+"px",i.style.width=r+"px")}},ht.fontString=function(t,e,n){return e+" "+t+"px "+n},ht.longestText=function(t,e,n,i){var a=(i=i||{}).data=i.data||{},r=i.garbageCollect=i.garbageCollect||[];i.font!==e&&(a=i.data={},r=i.garbageCollect=[],i.font=e),t.font=e;var o,s,l,u,d,h=0,c=n.length;for(o=0;o<c;o++)if(null!=(u=n[o])&&!0!==ht.isArray(u))h=ht.measureText(t,a,r,h,u);else if(ht.isArray(u))for(s=0,l=u.length;s<l;s++)null==(d=u[s])||ht.isArray(d)||(h=ht.measureText(t,a,r,h,d));var f=r.length/2;if(f>n.length){for(o=0;o<f;o++)delete a[r[o]];r.splice(0,f)}return h},ht.measureText=function(t,e,n,i,a){var r=e[a];return r||(r=e[a]=t.measureText(a).width,n.push(a)),r>i&&(i=r),i},ht.numberOfLabelLines=function(t){var e=1;return ht.each(t,function(t){ht.isArray(t)&&t.length>e&&(e=t.length)}),e},ht.color=G?function(t){return t instanceof CanvasGradient&&(t=ot.global.defaultColor),G(t)}:function(t){return console.error("Color.js not found!"),t},ht.getHoverColor=function(t){return t instanceof CanvasPattern||t instanceof CanvasGradient?t:ht.color(t).saturate(.5).darken(.1).rgbString()}}(),kn._adapters=Dn,kn.Animation=xt,kn.animationService=_t,kn.controllers=ye,kn.DatasetController=Dt,kn.defaults=ot,kn.Element=yt,kn.elements=Ut,kn.Interaction=Se,kn.layouts=Le,kn.platform=tn,kn.plugins=en,kn.Scale=En,kn.scaleService=nn,kn.Ticks=Cn,kn.Tooltip=gn,kn.helpers.each(Li,function(t,e){kn.scaleService.registerScaleType(e,t,t._defaults)}),na)na.hasOwnProperty(oa)&&kn.plugins.register(na[oa]);kn.platform.initialize();var sa=kn;return"undefined"!=typeof window&&(window.Chart=kn),kn.Chart=kn,kn.Legend=na.legend._element,kn.Title=na.title._element,kn.pluginService=kn.plugins,kn.PluginBase=kn.Element.extend({}),kn.canvasHelpers=kn.helpers.canvas,kn.layoutService=kn.layouts,kn.LinearScaleBase=qn,kn.helpers.each(["Bar","Bubble","Doughnut","Line","PolarArea","Radar","Scatter"],function(t){kn[t]=function(e,n){return new kn(e,kn.helpers.merge(n||{},{type:t.charAt(0).toLowerCase()+t.slice(1)}))}}),sa});
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..7f114e1
--- /dev/null
@@ -0,0 +1,15681 @@
+/*!
+ * Chart.js v2.9.1
+ * 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 = global || self, 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: Object.assign || function(target) {
+               return helpers.merge(target, [].slice.call(arguments, 1), {
+                       merger: function(key, dst, src) {
+                               dst[key] = src[key];
+                       }
+               });
+       },
+
+       /**
+        * 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;
+       },
+
+       _deprecated: function(scope, value, previous, current) {
+               if (value !== undefined) {
+                       console.warn(scope + ': "' + previous +
+                               '" is deprecated. Please use "' + current + '" instead');
+               }
+       }
+};
+
+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.save();
+                               ctx.translate(x, y);
+                               ctx.rotate(rad);
+                               ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height);
+                               ctx.restore();
+                               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);
+       }
+};
+
+// TODO(v3): remove 'global' from namespace.  all default are global and
+// there's inconsistency around which options are under 'global'
+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.
+        * @param {object} [info] - object to return information about resolution in
+        * @param {boolean} [info.cacheable] - Will be set to `false` if option is not cacheable.
+        * @since 2.7.0
+        */
+       resolve: function(inputs, context, index, info) {
+               var cacheable = true;
+               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);
+                               cacheable = false;
+                       }
+                       if (index !== undefined && helpers_core.isArray(value)) {
+                               value = value[index];
+                               cacheable = false;
+                       }
+                       if (value !== undefined) {
+                               if (info && !cacheable) {
+                                       info.cacheable = false;
+                               }
+                               return value;
+                       }
+               }
+       }
+};
+
+/**
+ * @alias Chart.helpers.math
+ * @namespace
+ */
+var exports$2 = {
+       /**
+        * Returns an array of factors sorted from 1 to sqrt(value)
+        * @private
+        */
+       _factorize: function(value) {
+               var result = [];
+               var sqrt = Math.sqrt(value);
+               var i;
+
+               for (i = 1; i < sqrt; i++) {
+                       if (value % i === 0) {
+                               result.push(i);
+                               result.push(value / i);
+                       }
+               }
+               if (sqrt === (sqrt | 0)) { // if value is a square number
+                       result.push(sqrt);
+               }
+
+               result.sort(function(a, b) {
+                       return a - b;
+               }).pop();
+               return result;
+       },
+
+       log10: Math.log10 || 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;
+       }
+};
+
+var helpers_math = exports$2;
+
+// DEPRECATIONS
+
+/**
+ * Provided for backward compatibility, use Chart.helpers.math.log10 instead.
+ * @namespace Chart.helpers.log10
+ * @deprecated since version 2.9.0
+ * @todo remove at version 3
+ * @private
+ */
+helpers_core.log10 = exports$2.log10;
+
+var getRtlAdapter = function(rectX, width) {
+       return {
+               x: function(x) {
+                       return rectX + rectX + width - x;
+               },
+               setWidth: function(w) {
+                       width = w;
+               },
+               textAlign: function(align) {
+                       if (align === 'center') {
+                               return align;
+                       }
+                       return align === 'right' ? 'left' : 'right';
+               },
+               xPlus: function(x, value) {
+                       return x - value;
+               },
+               leftForLtr: function(x, itemWidth) {
+                       return x - itemWidth;
+               },
+       };
+};
+
+var getLtrAdapter = function() {
+       return {
+               x: function(x) {
+                       return x;
+               },
+               setWidth: function(w) { // eslint-disable-line no-unused-vars
+               },
+               textAlign: function(align) {
+                       return align;
+               },
+               xPlus: function(x, value) {
+                       return x + value;
+               },
+               leftForLtr: function(x, _itemWidth) { // eslint-disable-line no-unused-vars
+                       return x;
+               },
+       };
+};
+
+var getAdapter = function(rtl, rectX, width) {
+       return rtl ? getRtlAdapter(rectX, width) : getLtrAdapter();
+};
+
+var overrideTextDirection = function(ctx, direction) {
+       var style, original;
+       if (direction === 'ltr' || direction === 'rtl') {
+               style = ctx.canvas.style;
+               original = [
+                       style.getPropertyValue('direction'),
+                       style.getPropertyPriority('direction'),
+               ];
+
+               style.setProperty('direction', direction, 'important');
+               ctx.prevTextDirection = original;
+       }
+};
+
+var restoreTextDirection = function(ctx) {
+       var original = ctx.prevTextDirection;
+       if (original !== undefined) {
+               delete ctx.prevTextDirection;
+               ctx.canvas.style.setProperty('direction', original[0], original[1]);
+       }
+};
+
+var helpers_rtl = {
+       getRtlAdapter: getAdapter,
+       overrideTextDirection: overrideTextDirection,
+       restoreTextDirection: restoreTextDirection,
+};
+
+var helpers$1 = helpers_core;
+var easing = helpers_easing;
+var canvas = helpers_canvas;
+var options = helpers_options;
+var math = helpers_math;
+var rtl = helpers_rtl;
+helpers$1.easing = easing;
+helpers$1.canvas = canvas;
+helpers$1.options = options;
+helpers$1.math = math;
+helpers$1.rtl = rtl;
+
+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, {
+       _type: undefined,
+
+       initialize: function() {
+               this.hidden = false;
+       },
+
+       pivot: function() {
+               var me = this;
+               if (!me._view) {
+                       me._view = helpers$1.extend({}, 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 = helpers$1.extend({}, 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$3 = 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$3;
+
+// 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$3.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$3.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,
+
+       /**
+        * Dataset element option keys to be resolved in _resolveDatasetElementOptions.
+        * A derived controller may override this to resolve controller-specific options.
+        * The keys defined here are for backward compatibility for legend styles.
+        * @private
+        */
+       _datasetElementOptions: [
+               'backgroundColor',
+               'borderCapStyle',
+               'borderColor',
+               'borderDash',
+               'borderDashOffset',
+               'borderJoinStyle',
+               'borderWidth'
+       ],
+
+       /**
+        * Data element option keys to be resolved in _resolveDataElementOptions.
+        * A derived controller may override this to resolve controller-specific options.
+        * The keys defined here are for backward compatibility for legend styles.
+        * @private
+        */
+       _dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderWidth',
+               'pointStyle'
+       ],
+
+       initialize: function(chart, datasetIndex) {
+               var me = this;
+               me.chart = chart;
+               me.index = datasetIndex;
+               me.linkScales();
+               me.addElements();
+               me._type = me.getMeta().type;
+       },
+
+       updateIndex: function(datasetIndex) {
+               this.index = datasetIndex;
+       },
+
+       linkScales: function() {
+               var me = this;
+               var meta = me.getMeta();
+               var chart = me.chart;
+               var scales = chart.scales;
+               var dataset = me.getDataset();
+               var scalesOpts = chart.options.scales;
+
+               if (meta.xAxisID === null || !(meta.xAxisID in scales) || dataset.xAxisID) {
+                       meta.xAxisID = dataset.xAxisID || scalesOpts.xAxes[0].id;
+               }
+               if (meta.yAxisID === null || !(meta.yAxisID in scales) || dataset.yAxisID) {
+                       meta.yAxisID = dataset.yAxisID || scalesOpts.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();
+       },
+
+       /**
+        * Returns the merged user-supplied and default dataset-level options
+        * @private
+        */
+       _configure: function() {
+               var me = this;
+               me._config = helpers$1.merge({}, [
+                       me.chart.options.datasets[me._type],
+                       me.getDataset(),
+               ], {
+                       merger: function(key, target, source) {
+                               if (key !== '_meta' && key !== 'data') {
+                                       helpers$1._merger(key, target, source);
+                               }
+                       }
+               });
+       },
+
+       _update: function(reset) {
+               var me = this;
+               me._configure();
+               me._cachedDataOpts = null;
+               me.update(reset);
+       },
+
+       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();
+               }
+       },
+
+       /**
+        * Returns a set of predefined style properties that should be used to represent the dataset
+        * or the data if the index is specified
+        * @param {number} index - data index
+        * @return {IStyleInterface} style object
+        */
+       getStyle: function(index) {
+               var me = this;
+               var meta = me.getMeta();
+               var dataset = meta.dataset;
+               var style;
+
+               me._configure();
+               if (dataset && index === undefined) {
+                       style = me._resolveDatasetElementOptions(dataset || {});
+               } else {
+                       index = index || 0;
+                       style = me._resolveDataElementOptions(meta.data[index] || {}, index);
+               }
+
+               if (style.fill === false || style.fill === null) {
+                       style.backgroundColor = 'rgba(0,0,0,0)';
+               }
+
+               return style;
+       },
+
+       /**
+        * @private
+        */
+       _resolveDatasetElementOptions: function(element, hover) {
+               var me = this;
+               var chart = me.chart;
+               var datasetOpts = me._config;
+               var custom = element.custom || {};
+               var options = chart.options.elements[me.datasetElementType.prototype._type] || {};
+               var elementOptions = me._datasetElementOptions;
+               var values = {};
+               var i, ilen, key, readKey;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataset: me.getDataset(),
+                       datasetIndex: me.index,
+                       hover: hover
+               };
+
+               for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {
+                       key = elementOptions[i];
+                       readKey = hover ? 'hover' + key.charAt(0).toUpperCase() + key.slice(1) : key;
+                       values[key] = resolve([
+                               custom[readKey],
+                               datasetOpts[readKey],
+                               options[readKey]
+                       ], context);
+               }
+
+               return values;
+       },
+
+       /**
+        * @private
+        */
+       _resolveDataElementOptions: function(element, index) {
+               var me = this;
+               var custom = element && element.custom;
+               var cached = me._cachedDataOpts;
+               if (cached && !custom) {
+                       return cached;
+               }
+               var chart = me.chart;
+               var datasetOpts = me._config;
+               var options = chart.options.elements[me.dataElementType.prototype._type] || {};
+               var elementOptions = me._dataElementOptions;
+               var values = {};
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: me.getDataset(),
+                       datasetIndex: me.index
+               };
+
+               // `resolve` sets cacheable to `false` if any option is indexed or scripted
+               var info = {cacheable: !custom};
+
+               var keys, i, ilen, key;
+
+               custom = custom || {};
+
+               if (helpers$1.isArray(elementOptions)) {
+                       for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {
+                               key = elementOptions[i];
+                               values[key] = resolve([
+                                       custom[key],
+                                       datasetOpts[key],
+                                       options[key]
+                               ], context, index, info);
+                       }
+               } else {
+                       keys = Object.keys(elementOptions);
+                       for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                               key = keys[i];
+                               values[key] = resolve([
+                                       custom[key],
+                                       datasetOpts[elementOptions[key]],
+                                       datasetOpts[key],
+                                       options[key]
+                               ], context, index, info);
+                       }
+               }
+
+               if (info.cacheable) {
+                       me._cachedDataOpts = Object.freeze(values);
+               }
+
+               return values;
+       },
+
+       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
+        */
+       _removeDatasetHoverStyle: function() {
+               var element = this.getMeta().dataset;
+
+               if (element) {
+                       this.removeHoverStyle(element);
+               }
+       },
+
+       /**
+        * @private
+        */
+       _setDatasetHoverStyle: function() {
+               var element = this.getMeta().dataset;
+               var prev = {};
+               var i, ilen, key, keys, hoverOptions, model;
+
+               if (!element) {
+                       return;
+               }
+
+               model = element._model;
+               hoverOptions = this._resolveDatasetElementOptions(element, true);
+
+               keys = Object.keys(hoverOptions);
+               for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                       key = keys[i];
+                       prev[key] = model[key];
+                       model[key] = hoverOptions[key];
+               }
+
+               element.$previousStyle = prev;
+       },
+
+       /**
+        * @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;
+
+var TAU = Math.PI * 2;
+
+core_defaults._set('global', {
+       elements: {
+               arc: {
+                       backgroundColor: core_defaults.global.defaultColor,
+                       borderColor: '#fff',
+                       borderWidth: 2,
+                       borderAlign: 'center'
+               }
+       }
+});
+
+function clipArc(ctx, arc) {
+       var startAngle = arc.startAngle;
+       var endAngle = arc.endAngle;
+       var pixelMargin = arc.pixelMargin;
+       var angleMargin = pixelMargin / arc.outerRadius;
+       var x = arc.x;
+       var y = arc.y;
+
+       // 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();
+       ctx.arc(x, y, arc.outerRadius, startAngle - angleMargin, endAngle + angleMargin);
+       if (arc.innerRadius > pixelMargin) {
+               angleMargin = pixelMargin / arc.innerRadius;
+               ctx.arc(x, y, arc.innerRadius - pixelMargin, endAngle + angleMargin, startAngle - angleMargin, true);
+       } else {
+               ctx.arc(x, y, pixelMargin, endAngle + Math.PI / 2, startAngle - Math.PI / 2);
+       }
+       ctx.closePath();
+       ctx.clip();
+}
+
+function drawFullCircleBorders(ctx, vm, arc, inner) {
+       var endAngle = arc.endAngle;
+       var i;
+
+       if (inner) {
+               arc.endAngle = arc.startAngle + TAU;
+               clipArc(ctx, arc);
+               arc.endAngle = endAngle;
+               if (arc.endAngle === arc.startAngle && arc.fullCircles) {
+                       arc.endAngle += TAU;
+                       arc.fullCircles--;
+               }
+       }
+
+       ctx.beginPath();
+       ctx.arc(arc.x, arc.y, arc.innerRadius, arc.startAngle + TAU, arc.startAngle, true);
+       for (i = 0; i < arc.fullCircles; ++i) {
+               ctx.stroke();
+       }
+
+       ctx.beginPath();
+       ctx.arc(arc.x, arc.y, vm.outerRadius, arc.startAngle, arc.startAngle + TAU);
+       for (i = 0; i < arc.fullCircles; ++i) {
+               ctx.stroke();
+       }
+}
+
+function drawBorder(ctx, vm, arc) {
+       var inner = vm.borderAlign === 'inner';
+
+       if (inner) {
+               ctx.lineWidth = vm.borderWidth * 2;
+               ctx.lineJoin = 'round';
+       } else {
+               ctx.lineWidth = vm.borderWidth;
+               ctx.lineJoin = 'bevel';
+       }
+
+       if (arc.fullCircles) {
+               drawFullCircleBorders(ctx, vm, arc, inner);
+       }
+
+       if (inner) {
+               clipArc(ctx, arc);
+       }
+
+       ctx.beginPath();
+       ctx.arc(arc.x, arc.y, vm.outerRadius, arc.startAngle, arc.endAngle);
+       ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true);
+       ctx.closePath();
+       ctx.stroke();
+}
+
+var element_arc = core_element.extend({
+       _type: 'arc',
+
+       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 += TAU;
+                       }
+                       while (angle > endAngle) {
+                               angle -= TAU;
+                       }
+                       while (angle < startAngle) {
+                               angle += TAU;
+                       }
+
+                       // 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 pixelMargin = (vm.borderAlign === 'inner') ? 0.33 : 0;
+               var arc = {
+                       x: vm.x,
+                       y: vm.y,
+                       innerRadius: vm.innerRadius,
+                       outerRadius: Math.max(vm.outerRadius - pixelMargin, 0),
+                       pixelMargin: pixelMargin,
+                       startAngle: vm.startAngle,
+                       endAngle: vm.endAngle,
+                       fullCircles: Math.floor(vm.circumference / TAU)
+               };
+               var i;
+
+               ctx.save();
+
+               ctx.fillStyle = vm.backgroundColor;
+               ctx.strokeStyle = vm.borderColor;
+
+               if (arc.fullCircles) {
+                       arc.endAngle = arc.startAngle + TAU;
+                       ctx.beginPath();
+                       ctx.arc(arc.x, arc.y, arc.outerRadius, arc.startAngle, arc.endAngle);
+                       ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true);
+                       ctx.closePath();
+                       for (i = 0; i < arc.fullCircles; ++i) {
+                               ctx.fill();
+                       }
+                       arc.endAngle = arc.startAngle + vm.circumference % TAU;
+               }
+
+               ctx.beginPath();
+               ctx.arc(arc.x, arc.y, arc.outerRadius, arc.startAngle, arc.endAngle);
+               ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true);
+               ctx.closePath();
+               ctx.fill();
+
+               if (vm.borderWidth) {
+                       drawBorder(ctx, vm, arc);
+               }
+
+               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({
+       _type: 'line',
+
+       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 closePath = me._loop;
+               var index, previous, currentVM;
+
+               if (!points.length) {
+                       return;
+               }
+
+               if (me._loop) {
+                       for (index = 0; index < points.length; ++index) {
+                               previous = helpers$1.previousItem(points, index);
+                               // If the line has an open path, shift the point array
+                               if (!points[index]._view.skip && previous._view.skip) {
+                                       points = points.slice(index).concat(points.slice(0, index));
+                                       closePath = spanGaps;
+                                       break;
+                               }
+                       }
+                       // If the line has a close path, add the first point again
+                       if (closePath) {
+                               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();
+
+               // First point moves to it's starting position no matter what
+               currentVM = points[0]._view;
+               if (!currentVM.skip) {
+                       ctx.moveTo(currentVM.x, currentVM.y);
+                       lastDrawnIndex = 0;
+               }
+
+               for (index = 1; index < points.length; ++index) {
+                       currentVM = points[index]._view;
+                       previous = lastDrawnIndex === -1 ? helpers$1.previousItem(points, index) : 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, currentVM);
+                               }
+                               lastDrawnIndex = index;
+                       }
+               }
+
+               if (closePath) {
+                       ctx.closePath();
+               }
+
+               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({
+       _type: 'point',
+
+       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({
+       _type: 'rectangle',
+
+       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 deprecated = helpers$1._deprecated;
+var valueOrDefault$3 = helpers$1.valueOrDefault;
+
+core_defaults._set('bar', {
+       hover: {
+               mode: 'label'
+       },
+
+       scales: {
+               xAxes: [{
+                       type: 'category',
+                       offset: true,
+                       gridLines: {
+                               offsetGridLines: true
+                       }
+               }],
+
+               yAxes: [{
+                       type: 'linear'
+               }]
+       }
+});
+
+core_defaults._set('global', {
+       datasets: {
+               bar: {
+                       categoryPercentage: 0.8,
+                       barPercentage: 0.9
+               }
+       }
+});
+
+/**
+ * Computes the "optimal" sample size to maintain bars equally sized while preventing overlap.
+ * @private
+ */
+function computeMinSampleSize(scale, pixels) {
+       var min = scale._length;
+       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 = scale.getTicks().length; i < ilen; ++i) {
+               curr = scale.getPixelForTick(i);
+               min = i > 0 ? Math.min(min, Math.abs(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 min = helpers$1.isNullOrUndef(thickness)
+               ? computeMinSampleSize(ruler.scale, ruler.pixels)
+               : -1;
+       var size, ratio;
+
+       if (helpers$1.isNullOrUndef(thickness)) {
+               size = 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,
+
+       /**
+        * @private
+        */
+       _dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderSkipped',
+               'borderWidth',
+               'barPercentage',
+               'barThickness',
+               'categoryPercentage',
+               'maxBarThickness',
+               'minBarLength'
+       ],
+
+       initialize: function() {
+               var me = this;
+               var meta, scaleOpts;
+
+               core_datasetController.prototype.initialize.apply(me, arguments);
+
+               meta = me.getMeta();
+               meta.stack = me.getDataset().stack;
+               meta.bar = true;
+
+               scaleOpts = me._getIndexScale().options;
+               deprecated('bar chart', scaleOpts.barPercentage, 'scales.[x/y]Axes.barPercentage', 'dataset.barPercentage');
+               deprecated('bar chart', scaleOpts.barThickness, 'scales.[x/y]Axes.barThickness', 'dataset.barThickness');
+               deprecated('bar chart', scaleOpts.categoryPercentage, 'scales.[x/y]Axes.categoryPercentage', 'dataset.categoryPercentage');
+               deprecated('bar chart', me._getValueScale().options.minBarLength, 'scales.[x/y]Axes.minBarLength', 'dataset.minBarLength');
+               deprecated('bar chart', scaleOpts.maxBarThickness, 'scales.[x/y]Axes.maxBarThickness', 'dataset.maxBarThickness');
+       },
+
+       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._resolveDataElementOptions(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]
+               };
+
+               if (helpers$1.isArray(dataset.data[index])) {
+                       rectangle._model.borderSkipped = null;
+               }
+
+               me._updateElementGeometry(rectangle, index, reset, options);
+
+               rectangle.pivot();
+       },
+
+       /**
+        * @private
+        */
+       _updateElementGeometry: function(rectangle, index, reset, options) {
+               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, options);
+               var ipixels = me.calculateBarIndexPixels(me.index, index, ruler, options);
+
+               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 scale = me._getIndexScale();
+               var metasets = scale._getMatchingVisibleMetas(me._type);
+               var stacked = scale.options.stacked;
+               var ilen = metasets.length;
+               var stacks = [];
+               var i, meta;
+
+               for (i = 0; i < ilen; ++i) {
+                       meta = metasets[i];
+                       // stacked   | meta.stack
+                       //           | found | not found | undefined
+                       // false     |   x   |     x     |     x
+                       // true      |       |     x     |
+                       // undefined |       |     x     |     x
+                       if (stacked === false || stacks.indexOf(meta.stack) === -1 ||
+                               (stacked === undefined && meta.stack === undefined)) {
+                               stacks.push(meta.stack);
+                       }
+                       if (meta.index === last) {
+                               break;
+                       }
+               }
+
+               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 pixels = [];
+               var i, ilen;
+
+               for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) {
+                       pixels.push(scale.getPixelForValue(null, i, me.index));
+               }
+
+               return {
+                       pixels: pixels,
+                       start: scale._startPixel,
+                       end: scale._endPixel,
+                       stackCount: me.getStackCount(),
+                       scale: scale
+               };
+       },
+
+       /**
+        * Note: pixel values are not clamped to the scale area.
+        * @private
+        */
+       calculateBarValuePixels: function(datasetIndex, index, options) {
+               var me = this;
+               var chart = me.chart;
+               var scale = me._getValueScale();
+               var isHorizontal = scale.isHorizontal();
+               var datasets = chart.data.datasets;
+               var metasets = scale._getMatchingVisibleMetas(me._type);
+               var value = scale._parseValue(datasets[datasetIndex].data[index]);
+               var minBarLength = options.minBarLength;
+               var stacked = scale.options.stacked;
+               var stack = me.getMeta().stack;
+               var start = value.start === undefined ? 0 : value.max >= 0 && value.min >= 0 ? value.min : value.max;
+               var length = value.start === undefined ? value.end : value.max >= 0 && value.min >= 0 ? value.max - value.min : value.min - value.max;
+               var ilen = metasets.length;
+               var i, imeta, ivalue, base, head, size, stackLength;
+
+               if (stacked || (stacked === undefined && stack !== undefined)) {
+                       for (i = 0; i < ilen; ++i) {
+                               imeta = metasets[i];
+
+                               if (imeta.index === datasetIndex) {
+                                       break;
+                               }
+
+                               if (imeta.stack === stack) {
+                                       stackLength = scale._parseValue(datasets[imeta.index].data[index]);
+                                       ivalue = stackLength.start === undefined ? stackLength.end : stackLength.min >= 0 && stackLength.max >= 0 ? stackLength.max : stackLength.min;
+
+                                       if ((value.min < 0 && ivalue < 0) || (value.max >= 0 && ivalue > 0)) {
+                                               start += ivalue;
+                                       }
+                               }
+                       }
+               }
+
+               base = scale.getPixelForValue(start);
+               head = scale.getPixelForValue(start + length);
+               size = head - base;
+
+               if (minBarLength !== undefined && Math.abs(size) < minBarLength) {
+                       size = minBarLength;
+                       if (length >= 0 && !isHorizontal || length < 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, options) {
+               var me = this;
+               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(
+                       valueOrDefault$3(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) {
+                       var val = scale._parseValue(dataset.data[i]);
+                       if (!isNaN(val.min) && !isNaN(val.max)) {
+                               rects[i].draw();
+                       }
+               }
+
+               helpers$1.canvas.unclipArea(chart.ctx);
+       },
+
+       /**
+        * @private
+        */
+       _resolveDataElementOptions: function() {
+               var me = this;
+               var values = helpers$1.extend({}, core_datasetController.prototype._resolveDataElementOptions.apply(me, arguments));
+               var indexOpts = me._getIndexScale().options;
+               var valueOpts = me._getValueScale().options;
+
+               values.barPercentage = valueOrDefault$3(indexOpts.barPercentage, values.barPercentage);
+               values.barThickness = valueOrDefault$3(indexOpts.barThickness, values.barThickness);
+               values.categoryPercentage = valueOrDefault$3(indexOpts.categoryPercentage, values.categoryPercentage);
+               values.maxBarThickness = valueOrDefault$3(indexOpts.maxBarThickness, values.maxBarThickness);
+               values.minBarLength = valueOrDefault$3(valueOpts.minBarLength, values.minBarLength);
+
+               return values;
+       }
+
+});
+
+var valueOrDefault$4 = helpers$1.valueOrDefault;
+var resolve$1 = 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,
+
+       /**
+        * @private
+        */
+       _dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderWidth',
+               'hoverBackgroundColor',
+               'hoverBorderColor',
+               'hoverBorderWidth',
+               'hoverRadius',
+               'hitRadius',
+               'pointStyle',
+               'rotation'
+       ],
+
+       /**
+        * @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._resolveDataElementOptions(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$4(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
+               model.borderColor = valueOrDefault$4(options.hoverBorderColor, getHoverColor(options.borderColor));
+               model.borderWidth = valueOrDefault$4(options.hoverBorderWidth, options.borderWidth);
+               model.radius = options.radius + options.hoverRadius;
+       },
+
+       /**
+        * @private
+        */
+       _resolveDataElementOptions: function(point, index) {
+               var me = this;
+               var chart = me.chart;
+               var dataset = me.getDataset();
+               var custom = point.custom || {};
+               var data = dataset.data[index] || {};
+               var values = core_datasetController.prototype._resolveDataElementOptions.apply(me, arguments);
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: dataset,
+                       datasetIndex: me.index
+               };
+
+               // In case values were cached (and thus frozen), we need to clone the values
+               if (me._cachedDataOpts === values) {
+                       values = helpers$1.extend({}, values);
+               }
+
+               // Custom radius resolution
+               values.radius = resolve$1([
+                       custom.radius,
+                       data.r,
+                       me._config.radius,
+                       chart.options.elements.point.radius
+               ], context, index);
+
+               return values;
+       }
+});
+
+var valueOrDefault$5 = helpers$1.valueOrDefault;
+
+var PI$1 = Math.PI;
+var DOUBLE_PI$1 = PI$1 * 2;
+var HALF_PI$1 = PI$1 / 2;
+
+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 list = document.createElement('ul');
+               var data = chart.data;
+               var datasets = data.datasets;
+               var labels = data.labels;
+               var i, ilen, listItem, listItemSpan;
+
+               list.setAttribute('class', chart.id + '-legend');
+               if (datasets.length) {
+                       for (i = 0, ilen = datasets[0].data.length; i < ilen; ++i) {
+                               listItem = list.appendChild(document.createElement('li'));
+                               listItemSpan = listItem.appendChild(document.createElement('span'));
+                               listItemSpan.style.backgroundColor = datasets[0].backgroundColor[i];
+                               if (labels[i]) {
+                                       listItem.appendChild(document.createTextNode(labels[i]));
+                               }
+                       }
+               }
+
+               return list.outerHTML;
+       },
+       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 style = meta.controller.getStyle(i);
+
+                                               return {
+                                                       text: label,
+                                                       fillStyle: style.backgroundColor,
+                                                       strokeStyle: style.borderColor,
+                                                       lineWidth: style.borderWidth,
+                                                       hidden: isNaN(data.datasets[0].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: -HALF_PI$1,
+
+       // The total circumference of the chart.
+       circumference: DOUBLE_PI$1,
+
+       // 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,
+
+       /**
+        * @private
+        */
+       _dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderWidth',
+               'borderAlign',
+               'hoverBackgroundColor',
+               'hoverBorderColor',
+               'hoverBorderWidth',
+       ],
+
+       // 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 ratioX = 1;
+               var ratioY = 1;
+               var offsetX = 0;
+               var offsetY = 0;
+               var meta = me.getMeta();
+               var arcs = meta.data;
+               var cutout = opts.cutoutPercentage / 100 || 0;
+               var circumference = opts.circumference;
+               var chartWeight = me._getRingWeight(me.index);
+               var maxWidth, maxHeight, i, ilen;
+
+               // If the chart's circumference isn't a full circle, calculate size as a ratio of the width/height of the arc
+               if (circumference < DOUBLE_PI$1) {
+                       var startAngle = opts.rotation % DOUBLE_PI$1;
+                       startAngle += startAngle >= PI$1 ? -DOUBLE_PI$1 : startAngle < -PI$1 ? DOUBLE_PI$1 : 0;
+                       var endAngle = startAngle + circumference;
+                       var startX = Math.cos(startAngle);
+                       var startY = Math.sin(startAngle);
+                       var endX = Math.cos(endAngle);
+                       var endY = Math.sin(endAngle);
+                       var contains0 = (startAngle <= 0 && endAngle >= 0) || endAngle >= DOUBLE_PI$1;
+                       var contains90 = (startAngle <= HALF_PI$1 && endAngle >= HALF_PI$1) || endAngle >= DOUBLE_PI$1 + HALF_PI$1;
+                       var contains180 = startAngle === -PI$1 || endAngle >= PI$1;
+                       var contains270 = (startAngle <= -HALF_PI$1 && endAngle >= -HALF_PI$1) || endAngle >= PI$1 + HALF_PI$1;
+                       var minX = contains180 ? -1 : Math.min(startX, startX * cutout, endX, endX * cutout);
+                       var minY = contains270 ? -1 : Math.min(startY, startY * cutout, endY, endY * cutout);
+                       var maxX = contains0 ? 1 : Math.max(startX, startX * cutout, endX, endX * cutout);
+                       var maxY = contains90 ? 1 : Math.max(startY, startY * cutout, endY, endY * cutout);
+                       ratioX = (maxX - minX) / 2;
+                       ratioY = (maxY - minY) / 2;
+                       offsetX = -(maxX + minX) / 2;
+                       offsetY = -(maxY + minY) / 2;
+               }
+
+               for (i = 0, ilen = arcs.length; i < ilen; ++i) {
+                       arcs[i]._options = me._resolveDataElementOptions(arcs[i], i);
+               }
+
+               chart.borderWidth = me.getMaxBorderWidth();
+               maxWidth = (chartArea.right - chartArea.left - chart.borderWidth) / ratioX;
+               maxHeight = (chartArea.bottom - chartArea.top - chart.borderWidth) / ratioY;
+               chart.outerRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);
+               chart.innerRadius = Math.max(chart.outerRadius * cutout, 0);
+               chart.radiusLength = (chart.outerRadius - chart.innerRadius) / (me._getVisibleDatasetWeightTotal() || 1);
+               chart.offsetX = offsetX * chart.outerRadius;
+               chart.offsetY = offsetY * 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 / DOUBLE_PI$1);
+               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 DOUBLE_PI$1 * (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];
+                       if (controller) {
+                               controller._configure();
+                               options = controller._resolveDataElementOptions(arc, i);
+                       } else {
+                               options = 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$5(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
+               model.borderColor = valueOrDefault$5(options.hoverBorderColor, getHoverColor(options.borderColor));
+               model.borderWidth = valueOrDefault$5(options.hoverBorderWidth, options.borderWidth);
+       },
+
+       /**
+        * 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$5(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',
+                       offset: true,
+                       gridLines: {
+                               offsetGridLines: true
+                       }
+               }]
+       },
+
+       elements: {
+               rectangle: {
+                       borderSkipped: 'left'
+               }
+       },
+
+       tooltips: {
+               mode: 'index',
+               axis: 'y'
+       }
+});
+
+core_defaults._set('global', {
+       datasets: {
+               horizontalBar: {
+                       categoryPercentage: 0.8,
+                       barPercentage: 0.9
+               }
+       }
+});
+
+var controller_horizontalBar = controller_bar.extend({
+       /**
+        * @private
+        */
+       _getValueScaleId: function() {
+               return this.getMeta().xAxisID;
+       },
+
+       /**
+        * @private
+        */
+       _getIndexScaleId: function() {
+               return this.getMeta().yAxisID;
+       }
+});
+
+var valueOrDefault$6 = helpers$1.valueOrDefault;
+var resolve$2 = 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'
+               }]
+       }
+});
+
+var controller_line = core_datasetController.extend({
+
+       datasetElementType: elements.Line,
+
+       dataElementType: elements.Point,
+
+       /**
+        * @private
+        */
+       _datasetElementOptions: [
+               'backgroundColor',
+               'borderCapStyle',
+               'borderColor',
+               'borderDash',
+               'borderDashOffset',
+               'borderJoinStyle',
+               'borderWidth',
+               'cubicInterpolationMode',
+               'fill'
+       ],
+
+       /**
+        * @private
+        */
+       _dataElementOptions: {
+               backgroundColor: 'pointBackgroundColor',
+               borderColor: 'pointBorderColor',
+               borderWidth: 'pointBorderWidth',
+               hitRadius: 'pointHitRadius',
+               hoverBackgroundColor: 'pointHoverBackgroundColor',
+               hoverBorderColor: 'pointHoverBorderColor',
+               hoverBorderWidth: 'pointHoverBorderWidth',
+               hoverRadius: 'pointHoverRadius',
+               pointStyle: 'pointStyle',
+               radius: 'pointRadius',
+               rotation: 'pointRotation'
+       },
+
+       update: function(reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var line = meta.dataset;
+               var points = meta.data || [];
+               var options = me.chart.options;
+               var config = me._config;
+               var showLine = me._showLine = valueOrDefault$6(config.showLine, options.showLines);
+               var i, ilen;
+
+               me._xScale = me.getScaleForId(meta.xAxisID);
+               me._yScale = me.getScaleForId(meta.yAxisID);
+
+               // Update Line
+               if (showLine) {
+                       // Compatibility: If the properties are defined with only the old name, use those values
+                       if (config.tension !== undefined && config.lineTension === undefined) {
+                               config.lineTension = config.tension;
+                       }
+
+                       // Utility
+                       line._scale = me._yScale;
+                       line._datasetIndex = me.index;
+                       // Data
+                       line._children = points;
+                       // Model
+                       line._model = me._resolveDatasetElementOptions(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 xScale = me._xScale;
+               var yScale = me._yScale;
+               var lineModel = meta.dataset._model;
+               var x, y;
+
+               var options = me._resolveDataElementOptions(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$6(custom.tension, lineModel ? lineModel.tension : 0),
+                       steppedLine: lineModel ? lineModel.steppedLine : false,
+                       // Tooltip
+                       hitRadius: options.hitRadius
+               };
+       },
+
+       /**
+        * @private
+        */
+       _resolveDatasetElementOptions: function(element) {
+               var me = this;
+               var config = me._config;
+               var custom = element.custom || {};
+               var options = me.chart.options;
+               var lineOptions = options.elements.line;
+               var values = core_datasetController.prototype._resolveDatasetElementOptions.apply(me, arguments);
+
+               // 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$6(config.spanGaps, options.spanGaps);
+               values.tension = valueOrDefault$6(config.lineTension, lineOptions.tension);
+               values.steppedLine = resolve$2([custom.steppedLine, config.steppedLine, lineOptions.stepped]);
+
+               return values;
+       },
+
+       calculatePointY: function(value, index, datasetIndex) {
+               var me = this;
+               var chart = me.chart;
+               var yScale = me._yScale;
+               var sumPos = 0;
+               var sumNeg = 0;
+               var rightValue = +yScale.getRightValue(value);
+               var metasets = chart._getSortedVisibleDatasetMetas();
+               var ilen = metasets.length;
+               var i, ds, dsMeta, stackedRightValue;
+
+               if (yScale.options.stacked) {
+                       for (i = 0; i < ilen; ++i) {
+                               dsMeta = metasets[i];
+                               if (dsMeta.index === datasetIndex) {
+                                       break;
+                               }
+
+                               ds = chart.data.datasets[dsMeta.index];
+                               if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id) {
+                                       stackedRightValue = +yScale.getRightValue(ds.data[index]);
+                                       if (stackedRightValue < 0) {
+                                               sumNeg += stackedRightValue || 0;
+                                       } else {
+                                               sumPos += stackedRightValue || 0;
+                                       }
+                               }
+                       }
+
+                       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 i = 0;
+               var ilen = points.length;
+               var halfBorderWidth;
+
+               if (me._showLine) {
+                       halfBorderWidth = (meta.dataset._model.borderWidth || 0) / 2;
+
+                       helpers$1.canvas.clipArea(chart.ctx, {
+                               left: area.left - halfBorderWidth,
+                               right: area.right + halfBorderWidth,
+                               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$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);
+       },
+});
+
+var resolve$3 = 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 list = document.createElement('ul');
+               var data = chart.data;
+               var datasets = data.datasets;
+               var labels = data.labels;
+               var i, ilen, listItem, listItemSpan;
+
+               list.setAttribute('class', chart.id + '-legend');
+               if (datasets.length) {
+                       for (i = 0, ilen = datasets[0].data.length; i < ilen; ++i) {
+                               listItem = list.appendChild(document.createElement('li'));
+                               listItemSpan = listItem.appendChild(document.createElement('span'));
+                               listItemSpan.style.backgroundColor = datasets[0].backgroundColor[i];
+                               if (labels[i]) {
+                                       listItem.appendChild(document.createTextNode(labels[i]));
+                               }
+                       }
+               }
+
+               return list.outerHTML;
+       },
+       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 style = meta.controller.getStyle(i);
+
+                                               return {
+                                                       text: label,
+                                                       fillStyle: style.backgroundColor,
+                                                       strokeStyle: style.borderColor,
+                                                       lineWidth: style.borderWidth,
+                                                       hidden: isNaN(data.datasets[0].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,
+
+       /**
+        * @private
+        */
+       _dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderWidth',
+               'borderAlign',
+               'hoverBackgroundColor',
+               'hoverBorderColor',
+               'hoverBorderWidth',
+       ],
+
+       /**
+        * @private
+        */
+       _getIndexScaleId: function() {
+               return this.chart.scale.id;
+       },
+
+       /**
+        * @private
+        */
+       _getValueScaleId: function() {
+               return this.chart.scale.id;
+       },
+
+       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._resolveDataElementOptions(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
+        */
+       _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$3([
+                       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$7 = helpers$1.valueOrDefault;
+
+core_defaults._set('radar', {
+       spanGaps: false,
+       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,
+
+       /**
+        * @private
+        */
+       _datasetElementOptions: [
+               'backgroundColor',
+               'borderWidth',
+               'borderColor',
+               'borderCapStyle',
+               'borderDash',
+               'borderDashOffset',
+               'borderJoinStyle',
+               'fill'
+       ],
+
+       /**
+        * @private
+        */
+       _dataElementOptions: {
+               backgroundColor: 'pointBackgroundColor',
+               borderColor: 'pointBorderColor',
+               borderWidth: 'pointBorderWidth',
+               hitRadius: 'pointHitRadius',
+               hoverBackgroundColor: 'pointHoverBackgroundColor',
+               hoverBorderColor: 'pointHoverBorderColor',
+               hoverBorderWidth: 'pointHoverBorderWidth',
+               hoverRadius: 'pointHoverRadius',
+               pointStyle: 'pointStyle',
+               radius: 'pointRadius',
+               rotation: 'pointRotation'
+       },
+
+       /**
+        * @private
+        */
+       _getIndexScaleId: function() {
+               return this.chart.scale.id;
+       },
+
+       /**
+        * @private
+        */
+       _getValueScaleId: function() {
+               return this.chart.scale.id;
+       },
+
+       update: function(reset) {
+               var me = this;
+               var meta = me.getMeta();
+               var line = meta.dataset;
+               var points = meta.data || [];
+               var scale = me.chart.scale;
+               var config = me._config;
+               var i, ilen;
+
+               // Compatibility: If the properties are defined with only the old name, use those values
+               if (config.tension !== undefined && config.lineTension === undefined) {
+                       config.lineTension = config.tension;
+               }
+
+               // Utility
+               line._scale = scale;
+               line._datasetIndex = me.index;
+               // Data
+               line._children = points;
+               line._loop = true;
+               // Model
+               line._model = me._resolveDatasetElementOptions(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._resolveDataElementOptions(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$7(custom.tension, lineModel ? lineModel.tension : 0),
+
+                       // Tooltip
+                       hitRadius: options.hitRadius
+               };
+       },
+
+       /**
+        * @private
+        */
+       _resolveDatasetElementOptions: function() {
+               var me = this;
+               var config = me._config;
+               var options = me.chart.options;
+               var values = core_datasetController.prototype._resolveDatasetElementOptions.apply(me, arguments);
+
+               values.spanGaps = valueOrDefault$7(config.spanGaps, options.spanGaps);
+               values.tension = valueOrDefault$7(config.lineTension, options.elements.line.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;
+
+               // Only consider points that are drawn in case the spanGaps option is used
+               if (meta.dataset._model.spanGaps) {
+                       points = points.filter(function(pt) {
+                               return !pt._model.skip;
+                       });
+               }
+
+               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$7(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
+               model.borderColor = valueOrDefault$7(options.hoverBorderColor, getHoverColor(options.borderColor));
+               model.borderWidth = valueOrDefault$7(options.hoverBorderWidth, options.borderWidth);
+               model.radius = valueOrDefault$7(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'
+               }]
+       },
+
+       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 + ')';
+                       }
+               }
+       }
+});
+
+core_defaults._set('global', {
+       datasets: {
+               scatter: {
+                       showLine: false
+               }
+       }
+});
+
+// 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 metasets = chart._getSortedVisibleDatasetMetas();
+       var metadata, i, j, ilen, jlen, element;
+
+       for (i = 0, ilen = metasets.length; i < ilen; ++i) {
+               metadata = metasets[i].data;
+               for (j = 0, jlen = metadata.length; j < jlen; ++j) {
+                       element = metadata[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._getSortedVisibleDatasetMetas().forEach(function(meta) {
+               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;
+               }
+       }
+};
+
+var extend = helpers$1.extend;
+
+function filterByPosition(array, position) {
+       return helpers$1.where(array, function(v) {
+               return v.pos === position;
+       });
+}
+
+function sortByWeight(array, reverse) {
+       return array.sort(function(a, b) {
+               var v0 = reverse ? b : a;
+               var v1 = reverse ? a : b;
+               return v0.weight === v1.weight ?
+                       v0.index - v1.index :
+                       v0.weight - v1.weight;
+       });
+}
+
+function wrapBoxes(boxes) {
+       var layoutBoxes = [];
+       var i, ilen, box;
+
+       for (i = 0, ilen = (boxes || []).length; i < ilen; ++i) {
+               box = boxes[i];
+               layoutBoxes.push({
+                       index: i,
+                       box: box,
+                       pos: box.position,
+                       horizontal: box.isHorizontal(),
+                       weight: box.weight
+               });
+       }
+       return layoutBoxes;
+}
+
+function setLayoutDims(layouts, params) {
+       var i, ilen, layout;
+       for (i = 0, ilen = layouts.length; i < ilen; ++i) {
+               layout = layouts[i];
+               // store width used instead of chartArea.w in fitBoxes
+               layout.width = layout.horizontal
+                       ? layout.box.fullWidth && params.availableWidth
+                       : params.vBoxMaxWidth;
+               // store height used instead of chartArea.h in fitBoxes
+               layout.height = layout.horizontal && params.hBoxMaxHeight;
+       }
+}
+
+function buildLayoutBoxes(boxes) {
+       var layoutBoxes = wrapBoxes(boxes);
+       var left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true);
+       var right = sortByWeight(filterByPosition(layoutBoxes, 'right'));
+       var top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true);
+       var bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom'));
+
+       return {
+               leftAndTop: left.concat(top),
+               rightAndBottom: right.concat(bottom),
+               chartArea: filterByPosition(layoutBoxes, 'chartArea'),
+               vertical: left.concat(right),
+               horizontal: top.concat(bottom)
+       };
+}
+
+function getCombinedMax(maxPadding, chartArea, a, b) {
+       return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]);
+}
+
+function updateDims(chartArea, params, layout) {
+       var box = layout.box;
+       var maxPadding = chartArea.maxPadding;
+       var newWidth, newHeight;
+
+       if (layout.size) {
+               // this layout was already counted for, lets first reduce old size
+               chartArea[layout.pos] -= layout.size;
+       }
+       layout.size = layout.horizontal ? box.height : box.width;
+       chartArea[layout.pos] += layout.size;
+
+       if (box.getPadding) {
+               var boxPadding = box.getPadding();
+               maxPadding.top = Math.max(maxPadding.top, boxPadding.top);
+               maxPadding.left = Math.max(maxPadding.left, boxPadding.left);
+               maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom);
+               maxPadding.right = Math.max(maxPadding.right, boxPadding.right);
+       }
+
+       newWidth = params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right');
+       newHeight = params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom');
+
+       if (newWidth !== chartArea.w || newHeight !== chartArea.h) {
+               chartArea.w = newWidth;
+               chartArea.h = newHeight;
+
+               // return true if chart area changed in layout's direction
+               return layout.horizontal ? newWidth !== chartArea.w : newHeight !== chartArea.h;
+       }
+}
+
+function handleMaxPadding(chartArea) {
+       var maxPadding = chartArea.maxPadding;
+
+       function updatePos(pos) {
+               var change = Math.max(maxPadding[pos] - chartArea[pos], 0);
+               chartArea[pos] += change;
+               return change;
+       }
+       chartArea.y += updatePos('top');
+       chartArea.x += updatePos('left');
+       updatePos('right');
+       updatePos('bottom');
+}
+
+function getMargins(horizontal, chartArea) {
+       var maxPadding = chartArea.maxPadding;
+
+       function marginForPositions(positions) {
+               var margin = {left: 0, top: 0, right: 0, bottom: 0};
+               positions.forEach(function(pos) {
+                       margin[pos] = Math.max(chartArea[pos], maxPadding[pos]);
+               });
+               return margin;
+       }
+
+       return horizontal
+               ? marginForPositions(['left', 'right'])
+               : marginForPositions(['top', 'bottom']);
+}
+
+function fitBoxes(boxes, chartArea, params) {
+       var refitBoxes = [];
+       var i, ilen, layout, box, refit, changed;
+
+       for (i = 0, ilen = boxes.length; i < ilen; ++i) {
+               layout = boxes[i];
+               box = layout.box;
+
+               box.update(
+                       layout.width || chartArea.w,
+                       layout.height || chartArea.h,
+                       getMargins(layout.horizontal, chartArea)
+               );
+               if (updateDims(chartArea, params, layout)) {
+                       changed = true;
+                       if (refitBoxes.length) {
+                               // Dimensions changed and there were non full width boxes before this
+                               // -> we have to refit those
+                               refit = true;
+                       }
+               }
+               if (!box.fullWidth) { // fullWidth boxes don't need to be re-fitted in any case
+                       refitBoxes.push(layout);
+               }
+       }
+
+       return refit ? fitBoxes(refitBoxes, chartArea, params) || changed : changed;
+}
+
+function placeBoxes(boxes, chartArea, params) {
+       var userPadding = params.padding;
+       var x = chartArea.x;
+       var y = chartArea.y;
+       var i, ilen, layout, box;
+
+       for (i = 0, ilen = boxes.length; i < ilen; ++i) {
+               layout = boxes[i];
+               box = layout.box;
+               if (layout.horizontal) {
+                       box.left = box.fullWidth ? userPadding.left : chartArea.left;
+                       box.right = box.fullWidth ? params.outerWidth - userPadding.right : chartArea.left + chartArea.w;
+                       box.top = y;
+                       box.bottom = y + box.height;
+                       box.width = box.right - box.left;
+                       y = box.bottom;
+               } else {
+                       box.left = x;
+                       box.right = x + box.width;
+                       box.top = chartArea.top;
+                       box.bottom = chartArea.top + chartArea.h;
+                       box.height = box.bottom - box.top;
+                       x = box.right;
+               }
+       }
+
+       chartArea.x = x;
+       chartArea.y = y;
+}
+
+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;
+               item._layers = item._layers || function() {
+                       return [{
+                               z: 0,
+                               draw: function() {
+                                       item.draw.apply(item, arguments);
+                               }
+                       }];
+               };
+
+               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 availableWidth = width - padding.width;
+               var availableHeight = height - padding.height;
+               var boxes = buildLayoutBoxes(chart.boxes);
+               var verticalBoxes = boxes.vertical;
+               var horizontalBoxes = boxes.horizontal;
+
+               // 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)                   |
+               // |----------------------------------------------------|
+               //
+
+               var params = Object.freeze({
+                       outerWidth: width,
+                       outerHeight: height,
+                       padding: padding,
+                       availableWidth: availableWidth,
+                       vBoxMaxWidth: availableWidth / 2 / verticalBoxes.length,
+                       hBoxMaxHeight: availableHeight / 2
+               });
+               var chartArea = extend({
+                       maxPadding: extend({}, padding),
+                       w: availableWidth,
+                       h: availableHeight,
+                       x: padding.left,
+                       y: padding.top
+               }, padding);
+
+               setLayoutDims(verticalBoxes.concat(horizontalBoxes), params);
+
+               // First fit vertical boxes
+               fitBoxes(verticalBoxes, chartArea, params);
+
+               // Then fit horizontal boxes
+               if (fitBoxes(horizontalBoxes, chartArea, params)) {
+                       // if the area changed, re-fit vertical boxes
+                       fitBoxes(verticalBoxes, chartArea, params);
+               }
+
+               handleMaxPadding(chartArea);
+
+               // Finally place the boxes to correct coordinates
+               placeBoxes(boxes.leftAndTop, chartArea, params);
+
+               // Move to opposite side of chart
+               chartArea.x += chartArea.w;
+               chartArea.y += chartArea.h;
+
+               placeBoxes(boxes.rightAndBottom, chartArea, params);
+
+               chart.chartArea = {
+                       left: chartArea.left,
+                       top: chartArea.top,
+                       right: chartArea.left + chartArea.w,
+                       bottom: chartArea.top + chartArea.h
+               };
+
+               // Finally update boxes in chartArea (radial scale for example)
+               helpers$1.each(boxes.chartArea, function(layout) {
+                       var box = layout.box;
+                       extend(box, chart.chartArea);
+                       box.update(chartArea.w, chartArea.h);
+               });
+       }
+};
+
+/**
+ * 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);
+       }
+}
+
+/**
+ * Injects CSS styles inline if the styles are not already present.
+ * @param {HTMLDocument|ShadowRoot} rootNode - the node to contain the <style>.
+ * @param {string} css - the CSS to be injected.
+ */
+function injectCSS(rootNode, css) {
+       // https://stackoverflow.com/q/3922139
+       var expando = rootNode[EXPANDO_KEY] || (rootNode[EXPANDO_KEY] = {});
+       if (!expando.containsStyles) {
+               expando.containsStyles = true;
+               css = '/* Chart.js */\n' + css;
+               var style = document.createElement('style');
+               style.setAttribute('type', 'text/css');
+               style.appendChild(document.createTextNode(css));
+               rootNode.appendChild(style);
+       }
+}
+
+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',
+
+       /**
+        * Initializes resources that depend on platform options.
+        * @param {HTMLCanvasElement} canvas - The Canvas element.
+        * @private
+        */
+       _ensureLoaded: function(canvas) {
+               if (!this.disableCSSInjection) {
+                       // If the canvas is in a shadow DOM, then the styles must also be inserted
+                       // into the same shadow DOM.
+                       // https://github.com/chartjs/Chart.js/issues/5763
+                       var root = canvas.getRootNode();
+                       var targetNode = root.host ? root : document.head;
+                       injectCSS(targetNode, 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');
+
+               // `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) {
+                       // Load platform resources on first chart creation, to make it possible to
+                       // import the library before setting platform options.
+                       this._ensureLoaded(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$8 = helpers$1.valueOrDefault;
+var getRtlHelper = helpers$1.rtl.getRtlAdapter;
+
+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,
+
+               // Drawing direction and text direction
+               rtl: tooltipOpts.rtl,
+               textDirection: tooltipOpts.textDirection,
+
+               // Body
+               bodyFontColor: tooltipOpts.bodyFontColor,
+               _bodyFontFamily: valueOrDefault$8(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
+               _bodyFontStyle: valueOrDefault$8(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
+               _bodyAlign: tooltipOpts.bodyAlign,
+               bodyFontSize: valueOrDefault$8(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
+               bodySpacing: tooltipOpts.bodySpacing,
+
+               // Title
+               titleFontColor: tooltipOpts.titleFontColor,
+               _titleFontFamily: valueOrDefault$8(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
+               _titleFontStyle: valueOrDefault$8(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
+               titleFontSize: valueOrDefault$8(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
+               _titleAlign: tooltipOpts.titleAlign,
+               titleSpacing: tooltipOpts.titleSpacing,
+               titleMarginBottom: tooltipOpts.titleMarginBottom,
+
+               // Footer
+               footerFontColor: tooltipOpts.footerFontColor,
+               _footerFontFamily: valueOrDefault$8(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
+               _footerFontStyle: valueOrDefault$8(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
+               footerFontSize: valueOrDefault$8(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$4 = 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;
+               var length = title.length;
+               var titleFontSize, titleSpacing, i;
+
+               if (length) {
+                       var rtlHelper = getRtlHelper(vm.rtl, vm.x, vm.width);
+
+                       pt.x = getAlignedX(vm, vm._titleAlign);
+
+                       ctx.textAlign = rtlHelper.textAlign(vm._titleAlign);
+                       ctx.textBaseline = 'middle';
+
+                       titleFontSize = vm.titleFontSize;
+                       titleSpacing = vm.titleSpacing;
+
+                       ctx.fillStyle = vm.titleFontColor;
+                       ctx.font = helpers$1.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
+
+                       for (i = 0; i < length; ++i) {
+                               ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFontSize / 2);
+                               pt.y += titleFontSize + titleSpacing; // Line Height and spacing
+
+                               if (i + 1 === 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 xLinePadding = 0;
+               var colorX = drawColorBoxes ? getAlignedX(vm, 'left') : 0;
+
+               var rtlHelper = getRtlHelper(vm.rtl, vm.x, vm.width);
+
+               var fillLineOfText = function(line) {
+                       ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyFontSize / 2);
+                       pt.y += bodyFontSize + bodySpacing;
+               };
+
+               var bodyItem, textColor, labelColors, lines, i, j, ilen, jlen;
+               var bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign);
+
+               ctx.textAlign = bodyAlign;
+               ctx.textBaseline = 'middle';
+               ctx.font = helpers$1.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
+
+               pt.x = getAlignedX(vm, bodyAlignForCalculation);
+
+               // Before body lines
+               ctx.fillStyle = vm.bodyFontColor;
+               helpers$1.each(vm.beforeBody, fillLineOfText);
+
+               xLinePadding = drawColorBoxes && bodyAlignForCalculation !== 'right'
+                       ? bodyAlign === 'center' ? (bodyFontSize / 2 + 1) : (bodyFontSize + 2)
+                       : 0;
+
+               // Draw body lines now
+               for (i = 0, ilen = body.length; i < ilen; ++i) {
+                       bodyItem = body[i];
+                       textColor = vm.labelTextColors[i];
+                       labelColors = vm.labelColors[i];
+
+                       ctx.fillStyle = textColor;
+                       helpers$1.each(bodyItem.before, fillLineOfText);
+
+                       lines = bodyItem.lines;
+                       for (j = 0, jlen = lines.length; j < jlen; ++j) {
+                               // Draw Legend-like boxes if needed
+                               if (drawColorBoxes) {
+                                       var rtlColorX = rtlHelper.x(colorX);
+
+                                       // Fill a white rect so that colours merge nicely if the opacity is < 1
+                                       ctx.fillStyle = vm.legendColorBackground;
+                                       ctx.fillRect(rtlHelper.leftForLtr(rtlColorX, bodyFontSize), pt.y, bodyFontSize, bodyFontSize);
+
+                                       // Border
+                                       ctx.lineWidth = 1;
+                                       ctx.strokeStyle = labelColors.borderColor;
+                                       ctx.strokeRect(rtlHelper.leftForLtr(rtlColorX, bodyFontSize), pt.y, bodyFontSize, bodyFontSize);
+
+                                       // Inner square
+                                       ctx.fillStyle = labelColors.backgroundColor;
+                                       ctx.fillRect(rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), bodyFontSize - 2), pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
+                                       ctx.fillStyle = textColor;
+                               }
+
+                               fillLineOfText(lines[j]);
+                       }
+
+                       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;
+               var length = footer.length;
+               var footerFontSize, i;
+
+               if (length) {
+                       var rtlHelper = getRtlHelper(vm.rtl, vm.x, vm.width);
+
+                       pt.x = getAlignedX(vm, vm._footerAlign);
+                       pt.y += vm.footerMarginTop;
+
+                       ctx.textAlign = rtlHelper.textAlign(vm._footerAlign);
+                       ctx.textBaseline = 'middle';
+
+                       footerFontSize = vm.footerFontSize;
+
+                       ctx.fillStyle = vm.footerFontColor;
+                       ctx.font = helpers$1.fontString(footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
+
+                       for (i = 0; i < length; ++i) {
+                               ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFontSize / 2);
+                               pt.y += 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;
+
+                       helpers$1.rtl.overrideTextDirection(ctx, vm.textDirection);
+
+                       // Titles
+                       this.drawTitle(pt, vm, ctx);
+
+                       // Body
+                       this.drawBody(pt, vm, ctx);
+
+                       // Footer
+                       this.drawFooter(pt, vm, ctx);
+
+                       helpers$1.rtl.restoreTextDirection(ctx, vm.textDirection);
+
+                       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);
+                       if (options.reverse) {
+                               me._active.reverse();
+                       }
+               }
+
+               // 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$4;
+core_tooltip.positioners = positioners_1;
+
+var valueOrDefault$9 = 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$9(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 nextAvailableScaleId(axesOpts, prefix, index) {
+       var id;
+       var hasId = function(obj) {
+               return obj.id === id;
+       };
+
+       do {
+               id = prefix + index++;
+       } while (helpers$1.findIndex(axesOpts, hasId) >= 0);
+
+       return id;
+}
+
+function positionIsHorizontal(position) {
+       return position === 'top' || position === 'bottom';
+}
+
+function compare2Level(l1, l2) {
+       return function(a, b) {
+               return a[l1] === b[l1]
+                       ? a[l2] - b[l2]
+                       : a[l1] - b[l1];
+       };
+}
+
+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;
+               me._layers = [];
+
+               /**
+                * 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);
+               }
+
+               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) {
+                       if (!xAxisOptions.id) {
+                               xAxisOptions.id = nextAvailableScaleId(scalesOptions.xAxes, 'x-axis-', index);
+                       }
+               });
+
+               helpers$1.each(scalesOptions.yAxes, function(yAxisOptions, index) {
+                       if (!yAxisOptions.id) {
+                               yAxisOptions.id = nextAvailableScaleId(scalesOptions.yAxes, '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$9(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 = [];
+               var datasets = me.data.datasets;
+               var i, ilen;
+
+               for (i = 0, ilen = datasets.length; i < ilen; i++) {
+                       var dataset = datasets[i];
+                       var meta = me.getDatasetMeta(i);
+                       var type = dataset.type || me.config.type;
+
+                       if (meta.type && meta.type !== type) {
+                               me.destroyDatasetMeta(i);
+                               meta = me.getDatasetMeta(i);
+                       }
+                       meta.type = type;
+                       meta.order = dataset.order || 0;
+                       meta.index = i;
+
+                       if (meta.controller) {
+                               meta.controller.updateIndex(i);
+                               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, i);
+                               newControllers.push(meta.controller);
+                       }
+               }
+
+               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;
+               var i, ilen;
+
+               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
+               for (i = 0, ilen = me.data.datasets.length; i < ilen; i++) {
+                       me.getDatasetMeta(i).controller.buildOrUpdateElements();
+               }
+
+               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');
+
+               me._layers.sort(compare2Level('z', '_idx'));
+
+               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);
+
+               me._layers = [];
+               helpers$1.each(me.boxes, function(box) {
+                       // _configure is called twice, once in core.scale.update and once here.
+                       // Here the boxes are fully updated and at their final positions.
+                       if (box._configure) {
+                               box._configure();
+                       }
+                       me._layers.push.apply(me._layers, box._layers());
+               }, me);
+
+               me._layers.forEach(function(item, index) {
+                       item._idx = index;
+               });
+
+               /**
+                * 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$9(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;
+               var i, layers;
+
+               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;
+               }
+
+               // Because of plugin hooks (before/afterDatasetsDraw), datasets can't
+               // currently be part of layers. Instead, we draw
+               // layers <= 0 before(default, backward compat), and the rest after
+               layers = me._layers;
+               for (i = 0; i < layers.length && layers[i].z <= 0; ++i) {
+                       layers[i].draw(me.chartArea);
+               }
+
+               me.drawDatasets(easingValue);
+
+               // Rest of layers
+               for (; i < layers.length; ++i) {
+                       layers[i].draw(me.chartArea);
+               }
+
+               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);
+       },
+
+       /**
+        * @private
+        */
+       _getSortedDatasetMetas: function(filterVisible) {
+               var me = this;
+               var datasets = me.data.datasets || [];
+               var result = [];
+               var i, ilen;
+
+               for (i = 0, ilen = datasets.length; i < ilen; ++i) {
+                       if (!filterVisible || me.isDatasetVisible(i)) {
+                               result.push(me.getDatasetMeta(i));
+                       }
+               }
+
+               result.sort(compare2Level('order', 'index'));
+
+               return result;
+       },
+
+       /**
+        * @private
+        */
+       _getSortedVisibleDatasetMetas: function() {
+               return this._getSortedDatasetMetas(true);
+       },
+
+       /**
+        * 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;
+               var metasets, i;
+
+               if (core_plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) {
+                       return;
+               }
+
+               metasets = me._getSortedVisibleDatasetMetas();
+               for (i = metasets.length - 1; i >= 0; --i) {
+                       me.drawDataset(metasets[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(meta, easingValue) {
+               var me = this;
+               var args = {
+                       meta: meta,
+                       index: meta.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,
+                               order: dataset.order || 0,
+                               index: datasetIndex
+                       };
+               }
+
+               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 prefix = enabled ? 'set' : 'remove';
+               var element, i, ilen;
+
+               for (i = 0, ilen = elements.length; i < ilen; ++i) {
+                       element = elements[i];
+                       if (element) {
+                               this.getDatasetMeta(element._datasetIndex).controller[prefix + 'HoverStyle'](element);
+                       }
+               }
+
+               if (mode === 'dataset') {
+                       this.getDatasetMeta(elements[0]._datasetIndex).controller['_' + prefix + 'DatasetHoverStyle']();
+               }
+       },
+
+       /**
+        * @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.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;
+               var ilen = arrayOfThings.length;
+               var i, j, jlen, thing, nestedThing;
+               for (i = 0; i < ilen; i++) {
+                       thing = arrayOfThings[i];
+
+                       // 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?
+                               for (j = 0, jlen = thing.length; j < jlen; j++) {
+                                       nestedThing = thing[j];
+                                       // 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 (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;
+       };
+
+       /**
+        * @deprecated
+        */
+       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));
+                                       var numExponential = Math.floor(logTick) - Math.floor(logDelta);
+                                       numExponential = Math.max(Math.min(numExponential, 20), 0);
+                                       tickString = tickValue.toExponential(numExponential);
+                               } 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 isArray = helpers$1.isArray;
+var isNullOrUndef = helpers$1.isNullOrUndef;
+var valueOrDefault$a = 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: {}
+       }
+});
+
+/** Returns a new array containing numItems from arr */
+function sample(arr, numItems) {
+       var result = [];
+       var increment = arr.length / numItems;
+       var i = 0;
+       var len = arr.length;
+
+       for (; i < len; i += increment) {
+               result.push(arr[Math.floor(i)]);
+       }
+       return result;
+}
+
+function getPixelForGridLine(scale, index, offsetGridLines) {
+       var length = scale.getTicks().length;
+       var validIndex = Math.min(index, length - 1);
+       var lineValue = scale.getPixelForTick(validIndex);
+       var start = scale._startPixel;
+       var end = scale._endPixel;
+       var epsilon = 1e-6; // 1e-6 is margin in pixels for accumulated error.
+       var offset;
+
+       if (offsetGridLines) {
+               if (length === 1) {
+                       offset = Math.max(lineValue - start, end - lineValue);
+               } else if (index === 0) {
+                       offset = (scale.getPixelForTick(1) - lineValue) / 2;
+               } else {
+                       offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2;
+               }
+               lineValue += validIndex < index ? offset : -offset;
+
+               // Return undefined if the pixel is out of the range
+               if (lineValue < start - epsilon || lineValue > end + epsilon) {
+                       return;
+               }
+       }
+       return lineValue;
+}
+
+function garbageCollect(caches, length) {
+       helpers$1.each(caches, function(cache) {
+               var gc = cache.gc;
+               var gcLen = gc.length / 2;
+               var i;
+               if (gcLen > length) {
+                       for (i = 0; i < gcLen; ++i) {
+                               delete cache.data[gc[i]];
+                       }
+                       gc.splice(0, gcLen);
+               }
+       });
+}
+
+/**
+ * Returns {width, height, offset} objects for the first, last, widest, highest tick
+ * labels where offset indicates the anchor point offset from the top in pixels.
+ */
+function computeLabelSizes(ctx, tickFonts, ticks, caches) {
+       var length = ticks.length;
+       var widths = [];
+       var heights = [];
+       var offsets = [];
+       var i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel, widest, highest;
+
+       for (i = 0; i < length; ++i) {
+               label = ticks[i].label;
+               tickFont = ticks[i].major ? tickFonts.major : tickFonts.minor;
+               ctx.font = fontString = tickFont.string;
+               cache = caches[fontString] = caches[fontString] || {data: {}, gc: []};
+               lineHeight = tickFont.lineHeight;
+               width = height = 0;
+               // Undefined labels and arrays should not be measured
+               if (!isNullOrUndef(label) && !isArray(label)) {
+                       width = helpers$1.measureText(ctx, cache.data, cache.gc, width, label);
+                       height = lineHeight;
+               } else if (isArray(label)) {
+                       // if it is an array let's measure each element
+                       for (j = 0, jlen = label.length; j < jlen; ++j) {
+                               nestedLabel = label[j];
+                               // Undefined labels and arrays should not be measured
+                               if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) {
+                                       width = helpers$1.measureText(ctx, cache.data, cache.gc, width, nestedLabel);
+                                       height += lineHeight;
+                               }
+                       }
+               }
+               widths.push(width);
+               heights.push(height);
+               offsets.push(lineHeight / 2);
+       }
+       garbageCollect(caches, length);
+
+       widest = widths.indexOf(Math.max.apply(null, widths));
+       highest = heights.indexOf(Math.max.apply(null, heights));
+
+       function valueAt(idx) {
+               return {
+                       width: widths[idx] || 0,
+                       height: heights[idx] || 0,
+                       offset: offsets[idx] || 0
+               };
+       }
+
+       return {
+               first: valueAt(0),
+               last: valueAt(length - 1),
+               widest: valueAt(widest),
+               highest: valueAt(highest)
+       };
+}
+
+function getTickMarkLength(options) {
+       return options.drawTicks ? options.tickMarkLength : 0;
+}
+
+function getScaleLabelHeight(options) {
+       var font, padding;
+
+       if (!options.display) {
+               return 0;
+       }
+
+       font = helpers$1.options._parseFont(options);
+       padding = helpers$1.options.toPadding(options.padding);
+
+       return font.lineHeight + padding.height;
+}
+
+function parseFontOptions(options, nestedOpts) {
+       return helpers$1.extend(helpers$1.options._parseFont({
+               fontFamily: valueOrDefault$a(nestedOpts.fontFamily, options.fontFamily),
+               fontSize: valueOrDefault$a(nestedOpts.fontSize, options.fontSize),
+               fontStyle: valueOrDefault$a(nestedOpts.fontStyle, options.fontStyle),
+               lineHeight: valueOrDefault$a(nestedOpts.lineHeight, options.lineHeight)
+       }), {
+               color: helpers$1.options.resolve([nestedOpts.fontColor, options.fontColor, core_defaults.global.defaultFontColor])
+       });
+}
+
+function parseTickFontOptions(options) {
+       var minor = parseFontOptions(options, options.minor);
+       var major = options.major.enabled ? parseFontOptions(options, options.major) : minor;
+
+       return {minor: minor, major: major};
+}
+
+function nonSkipped(ticksToFilter) {
+       var filtered = [];
+       var item, index, len;
+       for (index = 0, len = ticksToFilter.length; index < len; ++index) {
+               item = ticksToFilter[index];
+               if (typeof item._index !== 'undefined') {
+                       filtered.push(item);
+               }
+       }
+       return filtered;
+}
+
+function getEvenSpacing(arr) {
+       var len = arr.length;
+       var i, diff;
+
+       if (len < 2) {
+               return false;
+       }
+
+       for (diff = arr[0], i = 1; i < len; ++i) {
+               if (arr[i] - arr[i - 1] !== diff) {
+                       return false;
+               }
+       }
+       return diff;
+}
+
+function calculateSpacing(majorIndices, ticks, axisLength, ticksLimit) {
+       var evenMajorSpacing = getEvenSpacing(majorIndices);
+       var spacing = (ticks.length - 1) / ticksLimit;
+       var factors, factor, i, ilen;
+
+       // If the major ticks are evenly spaced apart, place the minor ticks
+       // so that they divide the major ticks into even chunks
+       if (!evenMajorSpacing) {
+               return Math.max(spacing, 1);
+       }
+
+       factors = helpers$1.math._factorize(evenMajorSpacing);
+       for (i = 0, ilen = factors.length - 1; i < ilen; i++) {
+               factor = factors[i];
+               if (factor > spacing) {
+                       return factor;
+               }
+       }
+       return Math.max(spacing, 1);
+}
+
+function getMajorIndices(ticks) {
+       var result = [];
+       var i, ilen;
+       for (i = 0, ilen = ticks.length; i < ilen; i++) {
+               if (ticks[i].major) {
+                       result.push(i);
+               }
+       }
+       return result;
+}
+
+function skipMajors(ticks, majorIndices, spacing) {
+       var count = 0;
+       var next = majorIndices[0];
+       var i, tick;
+
+       spacing = Math.ceil(spacing);
+       for (i = 0; i < ticks.length; i++) {
+               tick = ticks[i];
+               if (i === next) {
+                       tick._index = i;
+                       count++;
+                       next = majorIndices[count * spacing];
+               } else {
+                       delete tick.label;
+               }
+       }
+}
+
+function skip(ticks, spacing, majorStart, majorEnd) {
+       var start = valueOrDefault$a(majorStart, 0);
+       var end = Math.min(valueOrDefault$a(majorEnd, ticks.length), ticks.length);
+       var count = 0;
+       var length, i, tick, next;
+
+       spacing = Math.ceil(spacing);
+       if (majorEnd) {
+               length = majorEnd - majorStart;
+               spacing = length / Math.floor(length / spacing);
+       }
+
+       next = start;
+
+       while (next < 0) {
+               count++;
+               next = Math.round(start + count * spacing);
+       }
+
+       for (i = Math.max(start, 0); i < end; i++) {
+               tick = ticks[i];
+               if (i === next) {
+                       tick._index = i;
+                       count++;
+                       next = Math.round(start + count * spacing);
+               } else {
+                       delete tick.label;
+               }
+       }
+}
+
+var Scale = core_element.extend({
+
+       zeroLineIndex: 0,
+
+       /**
+        * 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;
+       },
+
+       /**
+       * @private
+       */
+       _getLabels: function() {
+               var data = this.chart.data;
+               return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels;
+       },
+
+       // 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
+
+       /**
+        * Provided for backward compatibility, not available anymore
+        * @function Chart.Scale.mergeTicksOptions
+        * @deprecated since version 2.8.0
+        * @todo remove at version 3
+        */
+       mergeTicksOptions: function() {
+               // noop
+       },
+
+       beforeUpdate: function() {
+               helpers$1.callback(this.options.beforeUpdate, [this]);
+       },
+
+       /**
+        * @param {number} maxWidth - the max width in pixels
+        * @param {number} maxHeight - the max height in pixels
+        * @param {object} margins - the space between the edge of the other scales and edge of the chart
+        *   This space comes from two sources:
+        *     - padding - space that's required to show the labels at the edges of the scale
+        *     - thickness of scales or legends in another orientation
+        */
+       update: function(maxWidth, maxHeight, margins) {
+               var me = this;
+               var tickOpts = me.options.ticks;
+               var sampleSize = tickOpts.sampleSize;
+               var i, ilen, labels, ticks, samplingEnabled;
+
+               // 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._ticks = null;
+               me.ticks = null;
+               me._labelSizes = null;
+               me._maxLabelLines = 0;
+               me.longestLabelWidth = 0;
+               me.longestTextCache = me.longestTextCache || {};
+               me._gridLineItems = null;
+               me._labelItems = null;
+
+               // 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;
+
+               // Ensure ticks contains ticks in new tick format
+               if ((!ticks || !ticks.length) && me.ticks) {
+                       ticks = [];
+                       for (i = 0, ilen = me.ticks.length; i < ilen; ++i) {
+                               ticks.push({
+                                       value: me.ticks[i],
+                                       major: false
+                               });
+                       }
+               }
+
+               me._ticks = ticks;
+
+               // Compute tick rotation and fit using a sampled subset of labels
+               // We generally don't need to compute the size of every single label for determining scale size
+               samplingEnabled = sampleSize < ticks.length;
+               labels = me._convertTicksToLabels(samplingEnabled ? sample(ticks, sampleSize) : ticks);
+
+               // _configure is called twice, once here, once from core.controller.updateLayout.
+               // Here we haven't been positioned yet, but dimensions are correct.
+               // Variables set in _configure are needed for calculateTickRotation, and
+               // it's ok that coordinates are not correct there, only dimensions matter.
+               me._configure();
+
+               // Tick Rotation
+               me.beforeCalculateTickRotation();
+               me.calculateTickRotation();
+               me.afterCalculateTickRotation();
+
+               me.beforeFit();
+               me.fit();
+               me.afterFit();
+
+               // Auto-skip
+               me._ticksToDraw = tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto') ? me._autoSkip(ticks) : ticks;
+
+               if (samplingEnabled) {
+                       // Generate labels using all non-skipped ticks
+                       labels = me._convertTicksToLabels(me._ticksToDraw);
+               }
+
+               me.ticks = labels;   // BACKWARD COMPATIBILITY
+
+               // IMPORTANT: after this point, we consider that `this.ticks` will NEVER change!
+
+               me.afterUpdate();
+
+               // TODO(v3): remove minSize as a public property and return value from all layout boxes. It is unused
+               // make maxWidth and maxHeight private
+               return me.minSize;
+       },
+
+       /**
+        * @private
+        */
+       _configure: function() {
+               var me = this;
+               var reversePixels = me.options.ticks.reverse;
+               var startPixel, endPixel;
+
+               if (me.isHorizontal()) {
+                       startPixel = me.left;
+                       endPixel = me.right;
+               } else {
+                       startPixel = me.top;
+                       endPixel = me.bottom;
+                       // by default vertical scales are from bottom to top, so pixels are reversed
+                       reversePixels = !reversePixels;
+               }
+               me._startPixel = startPixel;
+               me._endPixel = endPixel;
+               me._reversePixels = reversePixels;
+               me._length = endPixel - startPixel;
+       },
+
+       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 (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 options = me.options;
+               var tickOpts = options.ticks;
+               var numTicks = me.getTicks().length;
+               var minRotation = tickOpts.minRotation || 0;
+               var maxRotation = tickOpts.maxRotation;
+               var labelRotation = minRotation;
+               var labelSizes, maxLabelWidth, maxLabelHeight, maxWidth, tickWidth, maxHeight, maxLabelDiagonal;
+
+               if (!me._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !me.isHorizontal()) {
+                       me.labelRotation = minRotation;
+                       return;
+               }
+
+               labelSizes = me._getLabelSizes();
+               maxLabelWidth = labelSizes.widest.width;
+               maxLabelHeight = labelSizes.highest.height - labelSizes.highest.offset;
+
+               // Estimate the width of each grid based on the canvas width, the maximum
+               // label width and the number of tick intervals
+               maxWidth = Math.min(me.maxWidth, me.chart.width - maxLabelWidth);
+               tickWidth = options.offset ? me.maxWidth / numTicks : maxWidth / (numTicks - 1);
+
+               // Allow 3 pixels x2 padding either side for label readability
+               if (maxLabelWidth + 6 > tickWidth) {
+                       tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1));
+                       maxHeight = me.maxHeight - getTickMarkLength(options.gridLines)
+                               - tickOpts.padding - getScaleLabelHeight(options.scaleLabel);
+                       maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight);
+                       labelRotation = helpers$1.toDegrees(Math.min(
+                               Math.asin(Math.min((labelSizes.highest.height + 6) / tickWidth, 1)),
+                               Math.asin(Math.min(maxHeight / maxLabelDiagonal, 1)) - Math.asin(maxLabelHeight / maxLabelDiagonal)
+                       ));
+                       labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation));
+               }
+
+               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 chart = me.chart;
+               var opts = me.options;
+               var tickOpts = opts.ticks;
+               var scaleLabelOpts = opts.scaleLabel;
+               var gridLineOpts = opts.gridLines;
+               var display = me._isVisible();
+               var isBottom = opts.position === 'bottom';
+               var isHorizontal = me.isHorizontal();
+
+               // Width
+               if (isHorizontal) {
+                       minSize.width = me.maxWidth;
+               } else if (display) {
+                       minSize.width = getTickMarkLength(gridLineOpts) + getScaleLabelHeight(scaleLabelOpts);
+               }
+
+               // height
+               if (!isHorizontal) {
+                       minSize.height = me.maxHeight; // fill all the height
+               } else if (display) {
+                       minSize.height = getTickMarkLength(gridLineOpts) + getScaleLabelHeight(scaleLabelOpts);
+               }
+
+               // Don't bother fitting the ticks if we are not showing the labels
+               if (tickOpts.display && display) {
+                       var tickFonts = parseTickFontOptions(tickOpts);
+                       var labelSizes = me._getLabelSizes();
+                       var firstLabelSize = labelSizes.first;
+                       var lastLabelSize = labelSizes.last;
+                       var widestLabelSize = labelSizes.widest;
+                       var highestLabelSize = labelSizes.highest;
+                       var lineSpace = tickFonts.minor.lineHeight * 0.4;
+                       var tickPadding = tickOpts.padding;
+
+                       if (isHorizontal) {
+                               // A horizontal axis is more constrained by the height.
+                               var isRotated = me.labelRotation !== 0;
+                               var angleRadians = helpers$1.toRadians(me.labelRotation);
+                               var cosRotation = Math.cos(angleRadians);
+                               var sinRotation = Math.sin(angleRadians);
+
+                               var labelHeight = sinRotation * widestLabelSize.width
+                                       + cosRotation * (highestLabelSize.height - (isRotated ? highestLabelSize.offset : 0))
+                                       + (isRotated ? 0 : lineSpace); // padding
+
+                               minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding);
+
+                               var offsetLeft = me.getPixelForTick(0) - me.left;
+                               var offsetRight = me.right - me.getPixelForTick(me.getTicks().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 (isRotated) {
+                                       paddingLeft = isBottom ?
+                                               cosRotation * firstLabelSize.width + sinRotation * firstLabelSize.offset :
+                                               sinRotation * (firstLabelSize.height - firstLabelSize.offset);
+                                       paddingRight = isBottom ?
+                                               sinRotation * (lastLabelSize.height - lastLabelSize.offset) :
+                                               cosRotation * lastLabelSize.width + sinRotation * lastLabelSize.offset;
+                               } else {
+                                       paddingLeft = firstLabelSize.width / 2;
+                                       paddingRight = lastLabelSize.width / 2;
+                               }
+
+                               // Adjust padding taking into account changes in offsets
+                               // and add 3 px to move away from canvas edges
+                               me.paddingLeft = Math.max((paddingLeft - offsetLeft) * me.width / (me.width - offsetLeft), 0) + 3;
+                               me.paddingRight = Math.max((paddingRight - offsetRight) * me.width / (me.width - 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
+                               var labelWidth = tickOpts.mirror ? 0 :
+                                       // use lineSpace for consistency with horizontal axis
+                                       // tickPadding is not implemented for horizontal
+                                       widestLabelSize.width + tickPadding + lineSpace;
+
+                               minSize.width = Math.min(me.maxWidth, minSize.width + labelWidth);
+
+                               me.paddingTop = firstLabelSize.height / 2;
+                               me.paddingBottom = lastLabelSize.height / 2;
+                       }
+               }
+
+               me.handleMargins();
+
+               if (isHorizontal) {
+                       me.width = me._length = chart.width - me.margins.left - me.margins.right;
+                       me.height = minSize.height;
+               } else {
+                       me.width = minSize.width;
+                       me.height = me._length = chart.height - me.margins.top - me.margins.bottom;
+               }
+       },
+
+       /**
+        * Handle margins and padding interactions
+        * @private
+        */
+       handleMargins: function() {
+               var me = this;
+               if (me.margins) {
+                       me.margins.left = Math.max(me.paddingLeft, me.margins.left);
+                       me.margins.top = Math.max(me.paddingTop, me.margins.top);
+                       me.margins.right = Math.max(me.paddingRight, me.margins.right);
+                       me.margins.bottom = Math.max(me.paddingBottom, me.margins.bottom);
+               }
+       },
+
+       afterFit: function() {
+               helpers$1.callback(this.options.afterFit, [this]);
+       },
+
+       // Shared Methods
+       isHorizontal: function() {
+               var pos = this.options.position;
+               return pos === 'top' || pos === '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 (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;
+       },
+
+       _convertTicksToLabels: function(ticks) {
+               var me = this;
+               var labels, i, ilen;
+
+               me.ticks = ticks.map(function(tick) {
+                       return tick.value;
+               });
+
+               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();
+
+               // BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`)
+               for (i = 0, ilen = ticks.length; i < ilen; ++i) {
+                       ticks[i].label = labels[i];
+               }
+
+               return labels;
+       },
+
+       /**
+        * @private
+        */
+       _getLabelSizes: function() {
+               var me = this;
+               var labelSizes = me._labelSizes;
+
+               if (!labelSizes) {
+                       me._labelSizes = labelSizes = computeLabelSizes(me.ctx, parseTickFontOptions(me.options.ticks), me.getTicks(), me.longestTextCache);
+                       me.longestLabelWidth = labelSizes.widest.width;
+               }
+
+               return labelSizes;
+       },
+
+       /**
+        * @private
+        */
+       _parseValue: function(value) {
+               var start, end, min, max;
+
+               if (isArray(value)) {
+                       start = +this.getRightValue(value[0]);
+                       end = +this.getRightValue(value[1]);
+                       min = Math.min(start, end);
+                       max = Math.max(start, end);
+               } else {
+                       value = +this.getRightValue(value);
+                       start = undefined;
+                       end = value;
+                       min = value;
+                       max = value;
+               }
+
+               return {
+                       min: min,
+                       max: max,
+                       start: start,
+                       end: end
+               };
+       },
+
+       /**
+       * @private
+       */
+       _getScaleLabel: function(rawValue) {
+               var v = this._parseValue(rawValue);
+               if (v.start !== undefined) {
+                       return '[' + v.start + ', ' + v.end + ']';
+               }
+
+               return +this.getRightValue(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;
+               var numTicks = me._ticks.length;
+               var tickWidth = 1 / Math.max(numTicks - (offset ? 0 : 1), 1);
+
+               return index < 0 || index > numTicks - 1
+                       ? null
+                       : me.getPixelForDecimal(index * tickWidth + (offset ? tickWidth / 2 : 0));
+       },
+
+       /**
+        * 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._reversePixels) {
+                       decimal = 1 - decimal;
+               }
+
+               return me._startPixel + decimal * me._length;
+       },
+
+       getDecimalForPixel: function(pixel) {
+               var decimal = (pixel - this._startPixel) / this._length;
+               return this._reversePixels ? 1 - decimal : decimal;
+       },
+
+       /**
+        * 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 tickOpts = me.options.ticks;
+               var axisLength = me._length;
+               var ticksLimit = tickOpts.maxTicksLimit || axisLength / me._tickSize() + 1;
+               var majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];
+               var numMajorIndices = majorIndices.length;
+               var first = majorIndices[0];
+               var last = majorIndices[numMajorIndices - 1];
+               var i, ilen, spacing, avgMajorSpacing;
+
+               // If there are too many major ticks to display them all
+               if (numMajorIndices > ticksLimit) {
+                       skipMajors(ticks, majorIndices, numMajorIndices / ticksLimit);
+                       return nonSkipped(ticks);
+               }
+
+               spacing = calculateSpacing(majorIndices, ticks, axisLength, ticksLimit);
+
+               if (numMajorIndices > 0) {
+                       for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) {
+                               skip(ticks, spacing, majorIndices[i], majorIndices[i + 1]);
+                       }
+                       avgMajorSpacing = numMajorIndices > 1 ? (last - first) / (numMajorIndices - 1) : null;
+                       skip(ticks, spacing, helpers$1.isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);
+                       skip(ticks, spacing, last, helpers$1.isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);
+                       return nonSkipped(ticks);
+               }
+               skip(ticks, spacing);
+               return nonSkipped(ticks);
+       },
+
+       /**
+        * @private
+        */
+       _tickSize: function() {
+               var me = this;
+               var optionTicks = me.options.ticks;
+
+               // 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 labelSizes = me._getLabelSizes();
+               var padding = optionTicks.autoSkipPadding || 0;
+               var w = labelSizes ? labelSizes.widest.width + padding : 0;
+               var h = labelSizes ? labelSizes.highest.height + padding : 0;
+
+               // Calculate space needed for 1 tick in axis direction.
+               return me.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;
+       },
+
+       /**
+        * @private
+        */
+       _computeGridLineItems: function(chartArea) {
+               var me = this;
+               var chart = me.chart;
+               var options = me.options;
+               var gridLines = options.gridLines;
+               var position = options.position;
+               var offsetGridLines = gridLines.offsetGridLines;
+               var isHorizontal = me.isHorizontal();
+               var ticks = me._ticksToDraw;
+               var ticksLength = ticks.length + (offsetGridLines ? 1 : 0);
+
+               var tl = getTickMarkLength(gridLines);
+               var items = [];
+               var axisWidth = gridLines.drawBorder ? valueAtIndexOrDefault(gridLines.lineWidth, 0, 0) : 0;
+               var axisHalfWidth = axisWidth / 2;
+               var alignPixel = helpers$1._alignPixel;
+               var alignBorderValue = function(pixel) {
+                       return alignPixel(chart, pixel, axisWidth);
+               };
+               var borderValue, i, tick, lineValue, alignedLineValue;
+               var tx1, ty1, tx2, ty2, x1, y1, x2, y2, lineWidth, lineColor, borderDash, borderDashOffset;
+
+               if (position === 'top') {
+                       borderValue = alignBorderValue(me.bottom);
+                       ty1 = me.bottom - tl;
+                       ty2 = borderValue - axisHalfWidth;
+                       y1 = alignBorderValue(chartArea.top) + axisHalfWidth;
+                       y2 = chartArea.bottom;
+               } else if (position === 'bottom') {
+                       borderValue = alignBorderValue(me.top);
+                       y1 = chartArea.top;
+                       y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth;
+                       ty1 = borderValue + axisHalfWidth;
+                       ty2 = me.top + tl;
+               } else if (position === 'left') {
+                       borderValue = alignBorderValue(me.right);
+                       tx1 = me.right - tl;
+                       tx2 = borderValue - axisHalfWidth;
+                       x1 = alignBorderValue(chartArea.left) + axisHalfWidth;
+                       x2 = chartArea.right;
+               } else {
+                       borderValue = alignBorderValue(me.left);
+                       x1 = chartArea.left;
+                       x2 = alignBorderValue(chartArea.right) - axisHalfWidth;
+                       tx1 = borderValue + axisHalfWidth;
+                       tx2 = me.left + tl;
+               }
+
+               for (i = 0; i < ticksLength; ++i) {
+                       tick = ticks[i] || {};
+
+                       // autoskipper skipped this tick (#4635)
+                       if (isNullOrUndef(tick.label) && i < ticks.length) {
+                               continue;
+                       }
+
+                       if (i === me.zeroLineIndex && options.offset === 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, i, 1);
+                               lineColor = valueAtIndexOrDefault(gridLines.color, i, 'rgba(0,0,0,0.1)');
+                               borderDash = gridLines.borderDash || [];
+                               borderDashOffset = gridLines.borderDashOffset || 0.0;
+                       }
+
+                       lineValue = getPixelForGridLine(me, tick._index || i, offsetGridLines);
+
+                       // Skip if the pixel is out of the range
+                       if (lineValue === undefined) {
+                               continue;
+                       }
+
+                       alignedLineValue = alignPixel(chart, lineValue, lineWidth);
+
+                       if (isHorizontal) {
+                               tx1 = tx2 = x1 = x2 = alignedLineValue;
+                       } else {
+                               ty1 = ty2 = y1 = y2 = alignedLineValue;
+                       }
+
+                       items.push({
+                               tx1: tx1,
+                               ty1: ty1,
+                               tx2: tx2,
+                               ty2: ty2,
+                               x1: x1,
+                               y1: y1,
+                               x2: x2,
+                               y2: y2,
+                               width: lineWidth,
+                               color: lineColor,
+                               borderDash: borderDash,
+                               borderDashOffset: borderDashOffset,
+                       });
+               }
+
+               items.ticksLength = ticksLength;
+               items.borderValue = borderValue;
+
+               return items;
+       },
+
+       /**
+        * @private
+        */
+       _computeLabelItems: function() {
+               var me = this;
+               var options = me.options;
+               var optionTicks = options.ticks;
+               var position = options.position;
+               var isMirrored = optionTicks.mirror;
+               var isHorizontal = me.isHorizontal();
+               var ticks = me._ticksToDraw;
+               var fonts = parseTickFontOptions(optionTicks);
+               var tickPadding = optionTicks.padding;
+               var tl = getTickMarkLength(options.gridLines);
+               var rotation = -helpers$1.toRadians(me.labelRotation);
+               var items = [];
+               var i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset;
+
+               if (position === 'top') {
+                       y = me.bottom - tl - tickPadding;
+                       textAlign = !rotation ? 'center' : 'left';
+               } else if (position === 'bottom') {
+                       y = me.top + tl + tickPadding;
+                       textAlign = !rotation ? 'center' : 'right';
+               } else if (position === 'left') {
+                       x = me.right - (isMirrored ? 0 : tl) - tickPadding;
+                       textAlign = isMirrored ? 'left' : 'right';
+               } else {
+                       x = me.left + (isMirrored ? 0 : tl) + tickPadding;
+                       textAlign = isMirrored ? 'right' : 'left';
+               }
+
+               for (i = 0, ilen = ticks.length; i < ilen; ++i) {
+                       tick = ticks[i];
+                       label = tick.label;
+
+                       // autoskipper skipped this tick (#4635)
+                       if (isNullOrUndef(label)) {
+                               continue;
+                       }
+
+                       pixel = me.getPixelForTick(tick._index || i) + optionTicks.labelOffset;
+                       font = tick.major ? fonts.major : fonts.minor;
+                       lineHeight = font.lineHeight;
+                       lineCount = isArray(label) ? label.length : 1;
+
+                       if (isHorizontal) {
+                               x = pixel;
+                               textOffset = position === 'top'
+                                       ? ((!rotation ? 0.5 : 1) - lineCount) * lineHeight
+                                       : (!rotation ? 0.5 : 0) * lineHeight;
+                       } else {
+                               y = pixel;
+                               textOffset = (1 - lineCount) * lineHeight / 2;
+                       }
+
+                       items.push({
+                               x: x,
+                               y: y,
+                               rotation: rotation,
+                               label: label,
+                               font: font,
+                               textOffset: textOffset,
+                               textAlign: textAlign
+                       });
+               }
+
+               return items;
+       },
+
+       /**
+        * @private
+        */
+       _drawGrid: function(chartArea) {
+               var me = this;
+               var gridLines = me.options.gridLines;
+
+               if (!gridLines.display) {
+                       return;
+               }
+
+               var ctx = me.ctx;
+               var chart = me.chart;
+               var alignPixel = helpers$1._alignPixel;
+               var axisWidth = gridLines.drawBorder ? valueAtIndexOrDefault(gridLines.lineWidth, 0, 0) : 0;
+               var items = me._gridLineItems || (me._gridLineItems = me._computeGridLineItems(chartArea));
+               var width, color, i, ilen, item;
+
+               for (i = 0, ilen = items.length; i < ilen; ++i) {
+                       item = items[i];
+                       width = item.width;
+                       color = item.color;
+
+                       if (width && color) {
+                               ctx.save();
+                               ctx.lineWidth = width;
+                               ctx.strokeStyle = color;
+                               if (ctx.setLineDash) {
+                                       ctx.setLineDash(item.borderDash);
+                                       ctx.lineDashOffset = item.borderDashOffset;
+                               }
+
+                               ctx.beginPath();
+
+                               if (gridLines.drawTicks) {
+                                       ctx.moveTo(item.tx1, item.ty1);
+                                       ctx.lineTo(item.tx2, item.ty2);
+                               }
+
+                               if (gridLines.drawOnChartArea) {
+                                       ctx.moveTo(item.x1, item.y1);
+                                       ctx.lineTo(item.x2, item.y2);
+                               }
+
+                               ctx.stroke();
+                               ctx.restore();
+                       }
+               }
+
+               if (axisWidth) {
+                       // Draw the line at the edge of the axis
+                       var firstLineWidth = axisWidth;
+                       var lastLineWidth = valueAtIndexOrDefault(gridLines.lineWidth, items.ticksLength - 1, 1);
+                       var borderValue = items.borderValue;
+                       var x1, x2, y1, y2;
+
+                       if (me.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;
+                       }
+
+                       ctx.lineWidth = axisWidth;
+                       ctx.strokeStyle = valueAtIndexOrDefault(gridLines.color, 0);
+                       ctx.beginPath();
+                       ctx.moveTo(x1, y1);
+                       ctx.lineTo(x2, y2);
+                       ctx.stroke();
+               }
+       },
+
+       /**
+        * @private
+        */
+       _drawLabels: function() {
+               var me = this;
+               var optionTicks = me.options.ticks;
+
+               if (!optionTicks.display) {
+                       return;
+               }
+
+               var ctx = me.ctx;
+               var items = me._labelItems || (me._labelItems = me._computeLabelItems());
+               var i, j, ilen, jlen, item, tickFont, label, y;
+
+               for (i = 0, ilen = items.length; i < ilen; ++i) {
+                       item = items[i];
+                       tickFont = item.font;
+
+                       // Make sure we draw text in the correct color and font
+                       ctx.save();
+                       ctx.translate(item.x, item.y);
+                       ctx.rotate(item.rotation);
+                       ctx.font = tickFont.string;
+                       ctx.fillStyle = tickFont.color;
+                       ctx.textBaseline = 'middle';
+                       ctx.textAlign = item.textAlign;
+
+                       label = item.label;
+                       y = item.textOffset;
+                       if (isArray(label)) {
+                               for (j = 0, jlen = label.length; j < jlen; ++j) {
+                                       // We just make sure the multiline element is a string here..
+                                       ctx.fillText('' + label[j], 0, y);
+                                       y += tickFont.lineHeight;
+                               }
+                       } else {
+                               ctx.fillText(label, 0, y);
+                       }
+                       ctx.restore();
+               }
+       },
+
+       /**
+        * @private
+        */
+       _drawTitle: function() {
+               var me = this;
+               var ctx = me.ctx;
+               var options = me.options;
+               var scaleLabel = options.scaleLabel;
+
+               if (!scaleLabel.display) {
+                       return;
+               }
+
+               var scaleLabelFontColor = valueOrDefault$a(scaleLabel.fontColor, core_defaults.global.defaultFontColor);
+               var scaleLabelFont = helpers$1.options._parseFont(scaleLabel);
+               var scaleLabelPadding = helpers$1.options.toPadding(scaleLabel.padding);
+               var halfLineHeight = scaleLabelFont.lineHeight / 2;
+               var position = options.position;
+               var rotation = 0;
+               var scaleLabelX, scaleLabelY;
+
+               if (me.isHorizontal()) {
+                       scaleLabelX = me.left + me.width / 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.height / 2;
+                       rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
+               }
+
+               ctx.save();
+               ctx.translate(scaleLabelX, scaleLabelY);
+               ctx.rotate(rotation);
+               ctx.textAlign = 'center';
+               ctx.textBaseline = 'middle';
+               ctx.fillStyle = scaleLabelFontColor; // render in correct colour
+               ctx.font = scaleLabelFont.string;
+               ctx.fillText(scaleLabel.labelString, 0, 0);
+               ctx.restore();
+       },
+
+       draw: function(chartArea) {
+               var me = this;
+
+               if (!me._isVisible()) {
+                       return;
+               }
+
+               me._drawGrid(chartArea);
+               me._drawTitle();
+               me._drawLabels();
+       },
+
+       /**
+        * @private
+        */
+       _layers: function() {
+               var me = this;
+               var opts = me.options;
+               var tz = opts.ticks && opts.ticks.z || 0;
+               var gz = opts.gridLines && opts.gridLines.z || 0;
+
+               if (!me._isVisible() || tz === gz || me.draw !== me._draw) {
+                       // backward compatibility: draw has been overridden by custom scale
+                       return [{
+                               z: tz,
+                               draw: function() {
+                                       me.draw.apply(me, arguments);
+                               }
+                       }];
+               }
+
+               return [{
+                       z: gz,
+                       draw: function() {
+                               me._drawGrid.apply(me, arguments);
+                               me._drawTitle.apply(me, arguments);
+                       }
+               }, {
+                       z: tz,
+                       draw: function() {
+                               me._drawLabels.apply(me, arguments);
+                       }
+               }];
+       },
+
+       /**
+        * @private
+        */
+       _getMatchingVisibleMetas: function(type) {
+               var me = this;
+               var isHorizontal = me.isHorizontal();
+               return me.chart._getSortedVisibleDatasetMetas()
+                       .filter(function(meta) {
+                               return (!type || meta.type === type)
+                                       && (isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id);
+                       });
+       }
+});
+
+Scale.prototype._draw = Scale.prototype.draw;
+
+var core_scale = Scale;
+
+var isNullOrUndef$1 = helpers$1.isNullOrUndef;
+
+var defaultConfig = {
+       position: 'bottom'
+};
+
+var scale_category = core_scale.extend({
+       determineDataLimits: function() {
+               var me = this;
+               var labels = me._getLabels();
+               var ticksOpts = me.options.ticks;
+               var min = ticksOpts.min;
+               var max = ticksOpts.max;
+               var minIndex = 0;
+               var maxIndex = labels.length - 1;
+               var findIndex;
+
+               if (min !== undefined) {
+                       // user specified min value
+                       findIndex = labels.indexOf(min);
+                       if (findIndex >= 0) {
+                               minIndex = findIndex;
+                       }
+               }
+
+               if (max !== undefined) {
+                       // user specified max value
+                       findIndex = labels.indexOf(max);
+                       if (findIndex >= 0) {
+                               maxIndex = findIndex;
+                       }
+               }
+
+               me.minIndex = minIndex;
+               me.maxIndex = maxIndex;
+               me.min = labels[minIndex];
+               me.max = labels[maxIndex];
+       },
+
+       buildTicks: function() {
+               var me = this;
+               var labels = me._getLabels();
+               var minIndex = me.minIndex;
+               var maxIndex = me.maxIndex;
+
+               // If we are viewing some subset of labels, slice the original array
+               me.ticks = (minIndex === 0 && maxIndex === labels.length - 1) ? labels : labels.slice(minIndex, 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._getLabels()[index];
+       },
+
+       _configure: function() {
+               var me = this;
+               var offset = me.options.offset;
+               var ticks = me.ticks;
+
+               core_scale.prototype._configure.call(me);
+
+               if (!me.isHorizontal()) {
+                       // For backward compatibility, vertical category scale reverse is inverted.
+                       me._reversePixels = !me._reversePixels;
+               }
+
+               if (!ticks) {
+                       return;
+               }
+
+               me._startValue = me.minIndex - (offset ? 0.5 : 0);
+               me._valueRange = Math.max(ticks.length - (offset ? 0 : 1), 1);
+       },
+
+       // Used to get data value locations.  Value can either be an index or a numerical value
+       getPixelForValue: function(value, index, datasetIndex) {
+               var me = this;
+               var valueCategory, labels, idx;
+
+               if (!isNullOrUndef$1(index) && !isNullOrUndef$1(datasetIndex)) {
+                       value = me.chart.data.datasets[datasetIndex].data[index];
+               }
+
+               // 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.
+               if (!isNullOrUndef$1(value)) {
+                       valueCategory = me.isHorizontal() ? value.x : value.y;
+               }
+               if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
+                       labels = me._getLabels();
+                       value = helpers$1.valueOrDefault(valueCategory, value);
+                       idx = labels.indexOf(value);
+                       index = idx !== -1 ? idx : index;
+                       if (isNaN(index)) {
+                               index = value;
+                       }
+               }
+               return me.getPixelForDecimal((index - me._startValue) / me._valueRange);
+       },
+
+       getPixelForTick: function(index) {
+               var ticks = this.ticks;
+               return index < 0 || index > ticks.length - 1
+                       ? null
+                       : this.getPixelForValue(ticks[index], index + this.minIndex);
+       },
+
+       getValueForPixel: function(pixel) {
+               var me = this;
+               var value = Math.round(me._startValue + me.getDecimalForPixel(pixel) * me._valueRange);
+               return Math.min(Math.max(value, 0), me.ticks.length - 1);
+       },
+
+       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$2 = 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$2(min) && isNullOrUndef$2(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$2(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$2(min) && helpers$1.almostWhole(min / spacing, spacing / 1000)) {
+                       niceMin = min;
+               }
+               if (!isNullOrUndef$2(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$2(min) ? niceMin : min);
+       for (var j = 1; j < numSpaces; ++j) {
+               ticks.push(Math.round((niceMin + j * spacing) * factor) / factor);
+       }
+       ticks.push(isNullOrUndef$2(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);
+       },
+
+       _configure: function() {
+               var me = this;
+               var ticks = me.getTicks();
+               var start = me.min;
+               var end = me.max;
+               var offset;
+
+               core_scale.prototype._configure.call(me);
+
+               if (me.options.offset && ticks.length) {
+                       offset = (end - start) / Math.max(ticks.length - 1, 1) / 2;
+                       start -= offset;
+                       end += offset;
+               }
+               me._startValue = start;
+               me._endValue = end;
+               me._valueRange = end - start;
+       }
+});
+
+var defaultConfig$1 = {
+       position: 'left',
+       ticks: {
+               callback: core_ticks.formatters.linear
+       }
+};
+
+var DEFAULT_MIN = 0;
+var DEFAULT_MAX = 1;
+
+function getOrCreateStack(stacks, stacked, meta) {
+       var key = [
+               meta.type,
+               // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
+               stacked === undefined && meta.stack === undefined ? meta.index : '',
+               meta.stack
+       ].join('.');
+
+       if (stacks[key] === undefined) {
+               stacks[key] = {
+                       pos: [],
+                       neg: []
+               };
+       }
+
+       return stacks[key];
+}
+
+function stackData(scale, stacks, meta, data) {
+       var opts = scale.options;
+       var stacked = opts.stacked;
+       var stack = getOrCreateStack(stacks, stacked, meta);
+       var pos = stack.pos;
+       var neg = stack.neg;
+       var ilen = data.length;
+       var i, value;
+
+       for (i = 0; i < ilen; ++i) {
+               value = scale._parseValue(data[i]);
+               if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden) {
+                       continue;
+               }
+
+               pos[i] = pos[i] || 0;
+               neg[i] = neg[i] || 0;
+
+               if (opts.relativePoints) {
+                       pos[i] = 100;
+               } else if (value.min < 0 || value.max < 0) {
+                       neg[i] += value.min;
+               } else {
+                       pos[i] += value.max;
+               }
+       }
+}
+
+function updateMinMax(scale, meta, data) {
+       var ilen = data.length;
+       var i, value;
+
+       for (i = 0; i < ilen; ++i) {
+               value = scale._parseValue(data[i]);
+               if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden) {
+                       continue;
+               }
+
+               scale.min = Math.min(scale.min, value.min);
+               scale.max = Math.max(scale.max, value.max);
+       }
+}
+
+var scale_linear = scale_linearbase.extend({
+       determineDataLimits: function() {
+               var me = this;
+               var opts = me.options;
+               var chart = me.chart;
+               var datasets = chart.data.datasets;
+               var metasets = me._getMatchingVisibleMetas();
+               var hasStacks = opts.stacked;
+               var stacks = {};
+               var ilen = metasets.length;
+               var i, meta, data, values;
+
+               me.min = Number.POSITIVE_INFINITY;
+               me.max = Number.NEGATIVE_INFINITY;
+
+               if (hasStacks === undefined) {
+                       for (i = 0; !hasStacks && i < ilen; ++i) {
+                               meta = metasets[i];
+                               hasStacks = meta.stack !== undefined;
+                       }
+               }
+
+               for (i = 0; i < ilen; ++i) {
+                       meta = metasets[i];
+                       data = datasets[meta.index].data;
+                       if (hasStacks) {
+                               stackData(me, stacks, meta, data);
+                       } else {
+                               updateMinMax(me, meta, data);
+                       }
+               }
+
+               helpers$1.each(stacks, function(stackValues) {
+                       values = stackValues.pos.concat(stackValues.neg);
+                       me.min = Math.min(me.min, helpers$1.min(values));
+                       me.max = Math.max(me.max, helpers$1.max(values));
+               });
+
+               me.min = helpers$1.isFinite(me.min) && !isNaN(me.min) ? me.min : DEFAULT_MIN;
+               me.max = helpers$1.isFinite(me.max) && !isNaN(me.max) ? me.max : DEFAULT_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() {
+               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._getScaleLabel(this.chart.data.datasets[datasetIndex].data[index]);
+       },
+
+       // Utils
+       getPixelForValue: function(value) {
+               var me = this;
+               return me.getPixelForDecimal((+me.getRightValue(value) - me._startValue) / me._valueRange);
+       },
+
+       getValueForPixel: function(pixel) {
+               return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange;
+       },
+
+       getPixelForTick: function(index) {
+               var ticks = this.ticksAsNumbers;
+               if (index < 0 || index > ticks.length - 1) {
+                       return null;
+               }
+               return this.getPixelForValue(ticks[index]);
+       }
+});
+
+// INTERNAL: static default options, registered in src/index.js
+var _defaults$1 = defaultConfig$1;
+scale_linear._defaults = _defaults$1;
+
+var valueOrDefault$b = helpers$1.valueOrDefault;
+var log10 = helpers$1.math.log10;
+
+/**
+ * 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$b(generationOptions.min, Math.pow(10, Math.floor(log10(dataRange.min))));
+
+       var endExp = Math.floor(log10(dataRange.max));
+       var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
+       var exp, significand;
+
+       if (tickVal === 0) {
+               exp = Math.floor(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(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$b(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 datasets = chart.data.datasets;
+               var isHorizontal = me.isHorizontal();
+               function IDMatches(meta) {
+                       return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
+               }
+               var datasetIndex, meta, value, data, i, ilen;
+
+               // Calculate Range
+               me.min = Number.POSITIVE_INFINITY;
+               me.max = Number.NEGATIVE_INFINITY;
+               me.minNotZero = Number.POSITIVE_INFINITY;
+
+               var hasStacks = opts.stacked;
+               if (hasStacks === undefined) {
+                       for (datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {
+                               meta = chart.getDatasetMeta(datasetIndex);
+                               if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
+                                       meta.stack !== undefined) {
+                                       hasStacks = true;
+                                       break;
+                               }
+                       }
+               }
+
+               if (opts.stacked || hasStacks) {
+                       var valuesPerStack = {};
+
+                       for (datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {
+                               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] = [];
+                                       }
+
+                                       data = datasets[datasetIndex].data;
+                                       for (i = 0, ilen = data.length; i < ilen; i++) {
+                                               var values = valuesPerStack[key];
+                                               value = me._parseValue(data[i]);
+                                               // invalid, hidden and negative values are ignored
+                                               if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden || value.min < 0 || value.max < 0) {
+                                                       continue;
+                                               }
+                                               values[i] = values[i] || 0;
+                                               values[i] += value.max;
+                                       }
+                               }
+                       }
+
+                       helpers$1.each(valuesPerStack, function(valuesForType) {
+                               if (valuesForType.length > 0) {
+                                       var minVal = helpers$1.min(valuesForType);
+                                       var maxVal = helpers$1.max(valuesForType);
+                                       me.min = Math.min(me.min, minVal);
+                                       me.max = Math.max(me.max, maxVal);
+                               }
+                       });
+
+               } else {
+                       for (datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {
+                               meta = chart.getDatasetMeta(datasetIndex);
+                               if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+                                       data = datasets[datasetIndex].data;
+                                       for (i = 0, ilen = data.length; i < ilen; i++) {
+                                               value = me._parseValue(data[i]);
+                                               // invalid, hidden and negative values are ignored
+                                               if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden || value.min < 0 || value.max < 0) {
+                                                       continue;
+                                               }
+
+                                               me.min = Math.min(value.min, me.min);
+                                               me.max = Math.max(value.max, me.max);
+
+                                               if (value.min !== 0) {
+                                                       me.minNotZero = Math.min(value.min, me.minNotZero);
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               me.min = helpers$1.isFinite(me.min) ? me.min : null;
+               me.max = helpers$1.isFinite(me.max) ? me.max : null;
+               me.minNotZero = helpers$1.isFinite(me.minNotZero) ? me.minNotZero : null;
+
+               // 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(log10(me.min)) - 1);
+                               me.max = Math.pow(10, Math.floor(log10(me.max)) + 1);
+                       } else {
+                               me.min = DEFAULT_MIN;
+                               me.max = DEFAULT_MAX;
+                       }
+               }
+               if (me.min === null) {
+                       me.min = Math.pow(10, Math.floor(log10(me.max)) - 1);
+               }
+               if (me.max === null) {
+                       me.max = me.min !== 0
+                               ? Math.pow(10, Math.floor(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(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._getScaleLabel(this.chart.data.datasets[datasetIndex].data[index]);
+       },
+
+       getPixelForTick: function(index) {
+               var ticks = this.tickValues;
+               if (index < 0 || index > ticks.length - 1) {
+                       return null;
+               }
+               return this.getPixelForValue(ticks[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(log10(value));
+               var significand = Math.floor(value / Math.pow(10, exp));
+
+               return significand * Math.pow(10, exp);
+       },
+
+       _configure: function() {
+               var me = this;
+               var start = me.min;
+               var offset = 0;
+
+               core_scale.prototype._configure.call(me);
+
+               if (start === 0) {
+                       start = me._getFirstTickValue(me.minNotZero);
+                       offset = valueOrDefault$b(me.options.ticks.fontSize, core_defaults.global.defaultFontSize) / me._length;
+               }
+
+               me._startValue = log10(start);
+               me._valueOffset = offset;
+               me._valueRange = (log10(me.max) - log10(start)) / (1 - offset);
+       },
+
+       getPixelForValue: function(value) {
+               var me = this;
+               var decimal = 0;
+
+               value = +me.getRightValue(value);
+
+               if (value > me.min && value > 0) {
+                       decimal = (log10(value) - me._startValue) / me._valueRange + me._valueOffset;
+               }
+               return me.getPixelForDecimal(decimal);
+       },
+
+       getValueForPixel: function(pixel) {
+               var me = this;
+               var decimal = me.getDecimalForPixel(pixel);
+               return decimal === 0 && me.min === 0
+                       ? 0
+                       : Math.pow(10, me._startValue + (decimal - me._valueOffset) * me._valueRange);
+       }
+});
+
+// INTERNAL: static default options, registered in src/index.js
+var _defaults$2 = defaultConfig$2;
+scale_logarithmic._defaults = _defaults$2;
+
+var valueOrDefault$c = helpers$1.valueOrDefault;
+var valueAtIndexOrDefault$1 = helpers$1.valueAtIndexOrDefault;
+var resolve$4 = 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 getTickBackdropHeight(opts) {
+       var tickOpts = opts.ticks;
+
+       if (tickOpts.display && opts.display) {
+               return valueOrDefault$c(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 = scale.chart.data.labels.length;
+       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 pointLabelOpts = opts.pointLabels;
+       var tickBackdropHeight = getTickBackdropHeight(opts);
+       var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
+       var plFont = helpers$1.options._parseFont(pointLabelOpts);
+
+       ctx.save();
+
+       ctx.font = plFont.string;
+       ctx.textBaseline = 'middle';
+
+       for (var i = scale.chart.data.labels.length - 1; i >= 0; i--) {
+               // 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 = scale.chart.data.labels.length;
+       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(function() {
+                       var label = helpers$1.callback(me.options.pointLabels.callback, arguments, me);
+                       return label || label === 0 ? label : '';
+               });
+       },
+
+       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 chart = this.chart;
+               var angleMultiplier = 360 / chart.data.labels.length;
+               var options = chart.options || {};
+               var startAngle = options.startAngle || 0;
+
+               // Start from the top instead of right, so remove a quarter of the circle
+               var angle = (index * angleMultiplier + startAngle) % 360;
+
+               return (angle < 0 ? angle + 360 : angle) * Math.PI * 2 / 360;
+       },
+
+       getDistanceFromCenterForValue: function(value) {
+               var me = this;
+
+               if (helpers$1.isNullOrUndef(value)) {
+                       return NaN;
+               }
+
+               // 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(index) {
+               var me = this;
+               var min = me.min;
+               var max = me.max;
+
+               return me.getPointPositionForValue(index || 0,
+                       me.beginAtZero ? 0 :
+                       min < 0 && max < 0 ? max :
+                       min > 0 && max > 0 ? min :
+                       0);
+       },
+
+       /**
+        * @private
+        */
+       _drawGrid: function() {
+               var me = this;
+               var ctx = me.ctx;
+               var opts = me.options;
+               var gridLineOpts = opts.gridLines;
+               var angleLineOpts = opts.angleLines;
+               var lineWidth = valueOrDefault$c(angleLineOpts.lineWidth, gridLineOpts.lineWidth);
+               var lineColor = valueOrDefault$c(angleLineOpts.color, gridLineOpts.color);
+               var i, offset, position;
+
+               if (opts.pointLabels.display) {
+                       drawPointLabels(me);
+               }
+
+               if (gridLineOpts.display) {
+                       helpers$1.each(me.ticks, function(label, index) {
+                               if (index !== 0) {
+                                       offset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
+                                       drawRadiusLine(me, gridLineOpts, offset, index);
+                               }
+                       });
+               }
+
+               if (angleLineOpts.display && lineWidth && lineColor) {
+                       ctx.save();
+                       ctx.lineWidth = lineWidth;
+                       ctx.strokeStyle = lineColor;
+                       if (ctx.setLineDash) {
+                               ctx.setLineDash(resolve$4([angleLineOpts.borderDash, gridLineOpts.borderDash, []]));
+                               ctx.lineDashOffset = resolve$4([angleLineOpts.borderDashOffset, gridLineOpts.borderDashOffset, 0.0]);
+                       }
+
+                       for (i = me.chart.data.labels.length - 1; i >= 0; i--) {
+                               offset = me.getDistanceFromCenterForValue(opts.ticks.reverse ? me.min : me.max);
+                               position = me.getPointPosition(i, offset);
+                               ctx.beginPath();
+                               ctx.moveTo(me.xCenter, me.yCenter);
+                               ctx.lineTo(position.x, position.y);
+                               ctx.stroke();
+                       }
+
+                       ctx.restore();
+               }
+       },
+
+       /**
+        * @private
+        */
+       _drawLabels: function() {
+               var me = this;
+               var ctx = me.ctx;
+               var opts = me.options;
+               var tickOpts = opts.ticks;
+
+               if (!tickOpts.display) {
+                       return;
+               }
+
+               var startAngle = me.getIndexAngle(0);
+               var tickFont = helpers$1.options._parseFont(tickOpts);
+               var tickFontColor = valueOrDefault$c(tickOpts.fontColor, core_defaults.global.defaultFontColor);
+               var offset, width;
+
+               ctx.save();
+               ctx.font = tickFont.string;
+               ctx.translate(me.xCenter, me.yCenter);
+               ctx.rotate(startAngle);
+               ctx.textAlign = 'center';
+               ctx.textBaseline = 'middle';
+
+               helpers$1.each(me.ticks, function(label, index) {
+                       if (index === 0 && !tickOpts.reverse) {
+                               return;
+                       }
+
+                       offset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
+
+                       if (tickOpts.showLabelBackdrop) {
+                               width = ctx.measureText(label).width;
+                               ctx.fillStyle = tickOpts.backdropColor;
+
+                               ctx.fillRect(
+                                       -width / 2 - tickOpts.backdropPaddingX,
+                                       -offset - tickFont.size / 2 - tickOpts.backdropPaddingY,
+                                       width + tickOpts.backdropPaddingX * 2,
+                                       tickFont.size + tickOpts.backdropPaddingY * 2
+                               );
+                       }
+
+                       ctx.fillStyle = tickFontColor;
+                       ctx.fillText(label, 0, -offset);
+               });
+
+               ctx.restore();
+       },
+
+       /**
+        * @private
+        */
+       _drawTitle: helpers$1.noop
+});
+
+// INTERNAL: static default options, registered in src/index.js
+var _defaults$3 = defaultConfig$3;
+scale_radialLinear._defaults = _defaults$3;
+
+var deprecated$1 = helpers$1._deprecated;
+var resolve$5 = helpers$1.options.resolve;
+var valueOrDefault$d = 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: 1000
+       },
+       second: {
+               common: true,
+               size: 1000,
+               steps: 60
+       },
+       minute: {
+               common: true,
+               size: 60000,
+               steps: 60
+       },
+       hour: {
+               common: true,
+               size: 3600000,
+               steps: 24
+       },
+       day: {
+               common: true,
+               size: 86400000,
+               steps: 30
+       },
+       week: {
+               common: false,
+               size: 604800000,
+               steps: 4
+       },
+       month: {
+               common: true,
+               size: 2.628e9,
+               steps: 12
+       },
+       quarter: {
+               common: false,
+               size: 7.884e9,
+               steps: 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;
+}
+
+function getMin(options) {
+       return helpers$1.valueOrDefault(options.time.min, options.ticks.min);
+}
+
+function getMax(options) {
+       return helpers$1.valueOrDefault(options.time.max, options.ticks.max);
+}
+
+/**
+ * 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;
+}
+
+/**
+ * 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 : 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, numTicks, minUnit, min, max) {
+       var i, unit;
+
+       for (i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--) {
+               unit = UNITS[i];
+               if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) {
+                       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 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 stepSize = resolve$5([timeOpts.stepSize, timeOpts.unitStepSize, 1]);
+       var weekday = minor === 'week' ? timeOpts.isoWeekday : false;
+       var first = min;
+       var ticks = [];
+       var time;
+
+       // For 'week' unit, handle the first day of week option
+       if (weekday) {
+               first = +adapter.startOf(first, 'isoWeek', weekday);
+       }
+
+       // Align first ticks on unit
+       first = +adapter.startOf(first, weekday ? 'day' : minor);
+
+       // Prevent browser from freezing in case user options request millions of milliseconds
+       if (adapter.diff(max, min, minor) > 100000 * stepSize) {
+               throw min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor;
+       }
+
+       for (time = first; time < max; time = +adapter.add(time, stepSize, minor)) {
+               ticks.push(time);
+       }
+
+       if (time === max || options.bounds === 'ticks') {
+               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) {
+               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;
+               }
+               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, factor: 1 / (start + 1 + end)};
+}
+
+function setMajorTicks(scale, ticks, map, majorUnit) {
+       var adapter = scale._adapter;
+       var first = +adapter.startOf(ticks[0].value, majorUnit);
+       var last = ticks[ticks.length - 1].value;
+       var major, index;
+
+       for (major = first; major <= last; major = +adapter.add(major, 1, majorUnit)) {
+               index = map[major];
+               if (index >= 0) {
+                       ticks[index].major = true;
+               }
+       }
+       return ticks;
+}
+
+function ticksFromTimestamps(scale, values, majorUnit) {
+       var ticks = [];
+       var map = {};
+       var ilen = values.length;
+       var i, value;
+
+       for (i = 0; i < ilen; ++i) {
+               value = values[i];
+               map[value] = i;
+
+               ticks.push({
+                       value: value,
+                       major: false
+               });
+       }
+
+       // We set the major ticks separately from the above loop because calling startOf for every tick
+       // is expensive when there is a large number of ticks
+       return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit);
+}
+
+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
+               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
+               deprecated$1('time scale', time.format, 'time.format', 'time.parser');
+               deprecated$1('time scale', time.min, 'time.min', 'ticks.min');
+               deprecated$1('time scale', time.max, 'time.max', 'ticks.max');
+
+               // 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 options = me.options;
+               var unit = options.time.unit || 'day';
+               var min = MAX_INTEGER;
+               var max = MIN_INTEGER;
+               var timestamps = [];
+               var datasets = [];
+               var labels = [];
+               var i, j, ilen, jlen, data, timestamp, labelsAdded;
+               var dataLabels = me._getLabels();
+
+               for (i = 0, ilen = dataLabels.length; i < ilen; ++i) {
+                       labels.push(parse(me, dataLabels[i]));
+               }
+
+               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 {
+                                       datasets[i] = labels.slice(0);
+                                       if (!labelsAdded) {
+                                               timestamps = timestamps.concat(labels);
+                                               labelsAdded = true;
+                                       }
+                               }
+                       } else {
+                               datasets[i] = [];
+                       }
+               }
+
+               if (labels.length) {
+                       min = Math.min(min, labels[0]);
+                       max = Math.max(max, labels[labels.length - 1]);
+               }
+
+               if (timestamps.length) {
+                       timestamps = ilen > 1 ? arrayUnique(timestamps).sort(sorter) : timestamps.sort(sorter);
+                       min = Math.min(min, timestamps[0]);
+                       max = Math.max(max, timestamps[timestamps.length - 1]);
+               }
+
+               min = parse(me, getMin(options)) || min;
+               max = parse(me, getMax(options)) || 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._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 tickOpts = options.ticks;
+               var timeOpts = options.time;
+               var timestamps = me._timestamps;
+               var ticks = [];
+               var capacity = me.getLabelCapacity(min);
+               var source = tickOpts.source;
+               var distribution = options.distribution;
+               var i, ilen, timestamp;
+
+               if (source === 'data' || (source === 'auto' && distribution === 'series')) {
+                       timestamps = timestamps.data;
+               } else if (source === 'labels') {
+                       timestamps = timestamps.labels;
+               } else {
+                       timestamps = generate(me, min, max, capacity);
+               }
+
+               if (options.bounds === 'ticks' && timestamps.length) {
+                       min = timestamps[0];
+                       max = timestamps[timestamps.length - 1];
+               }
+
+               // Enforce limits with user min/max options
+               min = parse(me, getMin(options)) || min;
+               max = parse(me, getMax(options)) || 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
+               // determineUnitForFormatting relies on the number of ticks so we don't use it when
+               // autoSkip is enabled because we don't yet know what the final number of ticks will be
+               me._unit = timeOpts.unit || (tickOpts.autoSkip
+                       ? determineUnitForAutoTicks(timeOpts.minUnit, me.min, me.max, capacity)
+                       : determineUnitForFormatting(me, ticks.length, timeOpts.minUnit, me.min, me.max));
+               me._majorUnit = !tickOpts.major.enabled || me._unit === 'year' ? undefined
+                       : determineMajorUnit(me._unit);
+               me._table = buildLookupTable(me._timestamps.data, min, max, distribution);
+               me._offsets = computeOffsets(me._table, ticks, min, max, options);
+
+               if (tickOpts.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 tick = ticks[index];
+               var tickOpts = options.ticks;
+               var major = majorUnit && majorFormat && tick && tick.major;
+               var label = adapter.format(time, format ? format : major ? majorFormat : minorFormat);
+               var nestedTickOpts = major ? tickOpts.major : tickOpts.minor;
+               var formatter = resolve$5([
+                       nestedTickOpts.callback,
+                       nestedTickOpts.userCallback,
+                       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 offsets = me._offsets;
+               var pos = interpolate$1(me._table, 'time', time, 'pos');
+               return me.getPixelForDecimal((offsets.start + pos) * offsets.factor);
+       },
+
+       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 offsets = me._offsets;
+               var pos = me.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
+               var time = interpolate$1(me._table, 'pos', pos, 'time');
+
+               // DEPRECATION, we should return time directly
+               return me._adapter._create(time);
+       },
+
+       /**
+        * @private
+        */
+       _getLabelSize: function(label) {
+               var me = this;
+               var ticksOpts = me.options.ticks;
+               var tickLabelWidth = me.ctx.measureText(label).width;
+               var angle = helpers$1.toRadians(me.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation);
+               var cosRotation = Math.cos(angle);
+               var sinRotation = Math.sin(angle);
+               var tickFontSize = valueOrDefault$d(ticksOpts.fontSize, core_defaults.global.defaultFontSize);
+
+               return {
+                       w: (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation),
+                       h: (tickLabelWidth * sinRotation) + (tickFontSize * cosRotation)
+               };
+       },
+
+       /**
+        * Crude approximation of what the label width might be
+        * @private
+        */
+       getLabelWidth: function(label) {
+               return this._getLabelSize(label).w;
+       },
+
+       /**
+        * @private
+        */
+       getLabelCapacity: function(exampleTime) {
+               var me = this;
+               var timeOpts = me.options.time;
+               var displayFormats = timeOpts.displayFormats;
+
+               // pick the longest format (milliseconds) for guestimation
+               var format = displayFormats[timeOpts.unit] || displayFormats.millisecond;
+               var exampleLabel = me.tickFormatFunction(exampleTime, 0, ticksFromTimestamps(me, [exampleTime], me._majorUnit), format);
+               var size = me._getLabelSize(exampleLabel);
+               var capacity = Math.floor(me.isHorizontal() ? me.width / size.w : me.height / size.h);
+
+               if (me.options.offset) {
+                       capacity--;
+               }
+
+               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(max).diff(moment(min), 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;
+
+               if (helpers$1.isArray(boundary)) {
+                       return function(point, i) {
+                               return boundary[i];
+                       };
+               }
+
+               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 computeLinearBoundary(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.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 computeCircularBoundary(source) {
+       var scale = source.el._scale;
+       var options = scale.options;
+       var length = scale.chart.data.labels.length;
+       var fill = source.fill;
+       var target = [];
+       var start, end, center, i, point;
+
+       if (!length) {
+               return null;
+       }
+
+       start = options.ticks.reverse ? scale.max : scale.min;
+       end = options.ticks.reverse ? scale.min : scale.max;
+       center = scale.getPointPositionForValue(0, start);
+       for (i = 0; i < length; ++i) {
+               point = fill === 'start' || fill === 'end'
+                       ? scale.getPointPositionForValue(i, fill === 'start' ? start : end)
+                       : scale.getBasePosition(i);
+               if (options.gridLines.circular) {
+                       point.cx = center.x;
+                       point.cy = center.y;
+                       point.angle = scale.getIndexAngle(i) - Math.PI / 2;
+               }
+               target.push(point);
+       }
+       return target;
+}
+
+function computeBoundary(source) {
+       var scale = source.el._scale || {};
+
+       if (scale.getPointPositionForValue) {
+               return computeCircularBoundary(source);
+       }
+       return computeLinearBoundary(source);
+}
+
+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, cx, cy, r;
+
+       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]);
+       }
+
+       if (curve1[0].angle !== undefined) {
+               cx = curve1[0].cx;
+               cy = curve1[0].cy;
+               r = Math.sqrt(Math.pow(curve1[0].x - cx, 2) + Math.pow(curve1[0].y - cy, 2));
+               for (i = len1 - 1; i > 0; --i) {
+                       ctx.arc(cx, cy, r, curve1[i].angle, curve1[i - 1].angle, true);
+               }
+               return;
+       }
+
+       // 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, loopOffset;
+
+       ctx.beginPath();
+
+       for (i = 0, ilen = count; i < ilen; ++i) {
+               index = i % count;
+               p0 = points[index]._view;
+               p1 = mapper(p0, index, view);
+               d0 = isDrawable(p0);
+               d1 = isDrawable(p1);
+
+               if (loop && loopOffset === undefined && d0) {
+                       loopOffset = i + 1;
+                       ilen = count + loopOffset;
+               }
+
+               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);
+               }
+       },
+
+       beforeDatasetsDraw: function(chart) {
+               var metasets = chart._getSortedVisibleDatasetMetas();
+               var ctx = chart.ctx;
+               var meta, i, el, view, points, mapper, color;
+
+               for (i = metasets.length - 1; i >= 0; --i) {
+                       meta = metasets[i].$filler;
+
+                       if (!meta || !meta.visible) {
+                               continue;
+                       }
+
+                       el = meta.el;
+                       view = el._view;
+                       points = el._children || [];
+                       mapper = meta.mapper;
+                       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 getRtlHelper$1 = helpers$1.rtl.getRtlAdapter;
+var noop$1 = helpers$1.noop;
+var valueOrDefault$e = helpers$1.valueOrDefault;
+
+core_defaults._set('global', {
+       legend: {
+               display: true,
+               position: 'top',
+               align: 'center',
+               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 datasets = chart.data.datasets;
+                               var options = chart.options.legend || {};
+                               var usePointStyle = options.labels && options.labels.usePointStyle;
+
+                               return chart._getSortedDatasetMetas().map(function(meta, i) {
+                                       var style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
+
+                                       return {
+                                               text: datasets[meta.index].label,
+                                               fillStyle: style.backgroundColor,
+                                               hidden: !chart.isDatasetVisible(i),
+                                               lineCap: style.borderCapStyle,
+                                               lineDash: style.borderDash,
+                                               lineDashOffset: style.borderDashOffset,
+                                               lineJoin: style.borderJoinStyle,
+                                               lineWidth: style.borderWidth,
+                                               strokeStyle: style.borderColor,
+                                               pointStyle: style.pointStyle,
+                                               rotation: style.rotation,
+
+                                               // Below is extra data used for toggling the datasets
+                                               datasetIndex: i
+                                       };
+                               }, this);
+                       }
+               }
+       },
+
+       legendCallback: function(chart) {
+               var list = document.createElement('ul');
+               var datasets = chart.data.datasets;
+               var i, ilen, listItem, listItemSpan;
+
+               list.setAttribute('class', chart.id + '-legend');
+
+               for (i = 0, ilen = datasets.length; i < ilen; i++) {
+                       listItem = list.appendChild(document.createElement('li'));
+                       listItemSpan = listItem.appendChild(document.createElement('span'));
+                       listItemSpan.style.backgroundColor = datasets[i].backgroundColor;
+                       if (datasets[i].label) {
+                               listItem.appendChild(document.createTextNode(datasets[i].label));
+                       }
+               }
+
+               return list.outerHTML;
+       }
+});
+
+/**
+ * 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) {
+               var me = this;
+               helpers$1.extend(me, config);
+
+               // Contains hit boxes for each dataset (in dataset order)
+               me.legendHitBoxes = [];
+
+               /**
+                * @private
+                */
+               me._hoveredItem = null;
+
+               // Are we in doughnut mode which has a different data type
+               me.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) {
+                       me.width = minSize.width = me.height = minSize.height = 0;
+                       return;
+               }
+               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 = 'middle';
+
+                       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 + 2 * labelOpts.padding > minSize.width) {
+                                       totalHeight += fontSize + labelOpts.padding;
+                                       lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0;
+                               }
+
+                               // 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 columnHeights = me.columnHeights = [];
+                       var totalWidth = labelOpts.padding;
+                       var currentColWidth = 0;
+                       var currentColHeight = 0;
+
+                       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 + fontSize + 2 * vPadding > minSize.height) {
+                                       totalWidth += currentColWidth + labelOpts.padding;
+                                       columnWidths.push(currentColWidth); // previous column width
+                                       columnHeights.push(currentColHeight);
+                                       currentColWidth = 0;
+                                       currentColHeight = 0;
+                               }
+
+                               // Get max width
+                               currentColWidth = Math.max(currentColWidth, itemWidth);
+                               currentColHeight += fontSize + vPadding;
+
+                               // 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);
+                       columnHeights.push(currentColHeight);
+                       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 legendHeight = me.height;
+               var columnHeights = me.columnHeights;
+               var legendWidth = me.width;
+               var lineWidths = me.lineWidths;
+
+               if (!opts.display) {
+                       return;
+               }
+
+               var rtlHelper = getRtlHelper$1(opts.rtl, me.left, me.minSize.width);
+               var ctx = me.ctx;
+               var fontColor = valueOrDefault$e(labelOpts.fontColor, globalDefaults.defaultFontColor);
+               var labelFont = helpers$1.options._parseFont(labelOpts);
+               var fontSize = labelFont.size;
+               var cursor;
+
+               // Canvas setup
+               ctx.textAlign = rtlHelper.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$e(legendItem.lineWidth, lineDefault.borderWidth);
+                       ctx.fillStyle = valueOrDefault$e(legendItem.fillStyle, defaultColor);
+                       ctx.lineCap = valueOrDefault$e(legendItem.lineCap, lineDefault.borderCapStyle);
+                       ctx.lineDashOffset = valueOrDefault$e(legendItem.lineDashOffset, lineDefault.borderDashOffset);
+                       ctx.lineJoin = valueOrDefault$e(legendItem.lineJoin, lineDefault.borderJoinStyle);
+                       ctx.lineWidth = lineWidth;
+                       ctx.strokeStyle = valueOrDefault$e(legendItem.strokeStyle, defaultColor);
+
+                       if (ctx.setLineDash) {
+                               // IE 9 and 10 do not support line dash
+                               ctx.setLineDash(valueOrDefault$e(legendItem.lineDash, lineDefault.borderDash));
+                       }
+
+                       if (labelOpts && labelOpts.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 = rtlHelper.xPlus(x, boxWidth / 2);
+                               var centerY = y + fontSize / 2;
+
+                               // Draw pointStyle as legend symbol
+                               helpers$1.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY, legendItem.rotation);
+                       } else {
+                               // Draw box as legend symbol
+                               ctx.fillRect(rtlHelper.leftForLtr(x, boxWidth), y, boxWidth, fontSize);
+                               if (lineWidth !== 0) {
+                                       ctx.strokeRect(rtlHelper.leftForLtr(x, boxWidth), y, boxWidth, fontSize);
+                               }
+                       }
+
+                       ctx.restore();
+               };
+
+               var fillText = function(x, y, legendItem, textWidth) {
+                       var halfFontSize = fontSize / 2;
+                       var xLeft = rtlHelper.xPlus(x, boxWidth + halfFontSize);
+                       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(rtlHelper.xPlus(xLeft, textWidth), yMiddle);
+                               ctx.stroke();
+                       }
+               };
+
+               var alignmentOffset = function(dimension, blockSize) {
+                       switch (opts.align) {
+                       case 'start':
+                               return labelOpts.padding;
+                       case 'end':
+                               return dimension - blockSize;
+                       default: // center
+                               return (dimension - blockSize + labelOpts.padding) / 2;
+                       }
+               };
+
+               // Horizontal
+               var isHorizontal = me.isHorizontal();
+               if (isHorizontal) {
+                       cursor = {
+                               x: me.left + alignmentOffset(legendWidth, lineWidths[0]),
+                               y: me.top + labelOpts.padding,
+                               line: 0
+                       };
+               } else {
+                       cursor = {
+                               x: me.left + labelOpts.padding,
+                               y: me.top + alignmentOffset(legendHeight, columnHeights[0]),
+                               line: 0
+                       };
+               }
+
+               helpers$1.rtl.overrideTextDirection(me.ctx, opts.textDirection);
+
+               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;
+
+                       rtlHelper.setWidth(me.minSize.width);
+
+                       // 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 + alignmentOffset(legendWidth, lineWidths[cursor.line]);
+                               }
+                       } else if (i > 0 && y + itemHeight > me.top + me.minSize.height) {
+                               x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
+                               cursor.line++;
+                               y = cursor.y = me.top + alignmentOffset(legendHeight, columnHeights[cursor.line]);
+                       }
+
+                       var realX = rtlHelper.x(x);
+
+                       drawLegendBox(realX, y, legendItem);
+
+                       hitboxes[i].left = rtlHelper.leftForLtr(realX, hitboxes[i].width);
+                       hitboxes[i].top = y;
+
+                       // Fill the actual label
+                       fillText(realX, y, legendItem, textWidth);
+
+                       if (isHorizontal) {
+                               cursor.x += width + labelOpts.padding;
+                       } else {
+                               cursor.y += itemHeight;
+                       }
+               });
+
+               helpers$1.rtl.restoreTextDirection(me.ctx, opts.textDirection);
+       },
+
+       /**
+        * @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 minSize = me.minSize = {};
+               var isHorizontal = me.isHorizontal();
+               var lineCount, textSize;
+
+               if (!opts.display) {
+                       me.width = minSize.width = me.height = minSize.height = 0;
+                       return;
+               }
+
+               lineCount = helpers$1.isArray(opts.text) ? opts.text.length : 1;
+               textSize = lineCount * helpers$1.options._parseFont(opts).lineHeight + opts.padding * 2;
+
+               me.width = minSize.width = isHorizontal ? me.maxWidth : textSize;
+               me.height = minSize.height = isHorizontal ? textSize : me.maxHeight;
+       },
+       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) {
+                       return;
+               }
+
+               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._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..b8cf98c
--- /dev/null
@@ -0,0 +1,7 @@
+/*!
+ * Chart.js v2.9.1
+ * 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=t||self).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:u,rgb2lch:function(t){return x(u(t))},hsl2rgb:d,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(d(t))},hsl2cmyk:function(t){return o(d(t))},hsl2keyword:function(t){return s(d(t))},hsv2rgb:h,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 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:k,keyword2hsl:function(t){return i(k(t))},keyword2hsv:function(t){return n(k(t))},keyword2hwb:function(t){return a(k(t))},keyword2cmyk:function(t){return o(k(t))},keyword2lab:function(t){return u(k(t))},keyword2xyz:function(t){return l(k(t))},xyz2rgb:p,xyz2lab:m,xyz2lch:function(t){return x(m(t))},lab2xyz:v,lab2rgb:y,lab2lch:x,lch2lab:_,lch2xyz:function(t){return v(_(t))},lch2rgb:function(t){return y(_(t))}};function i(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 n(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 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 M[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 u(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 d(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 h(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 c(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 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,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 v(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 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 _(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 k(t){return w[t]}var w={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]},M={};for(var S in w)M[JSON.stringify(w[S])]=S;var C=function(){return new I};for(var P in e){C[P+"Raw"]=function(t){return function(i){return"number"==typeof i&&(i=Array.prototype.slice.call(arguments)),e[t](i)}}(P);var A=/(\w+)2(\w+)/.exec(P),D=A[1],T=A[2];(C[D]=C[D]||{})[T]=C[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 I=function(){this.convs={}};I.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))},I.prototype.setValues=function(t,e){return this.space=t,this.convs={},this.convs[t]=e,this},I.prototype.getValues=function(t){var e=this.convs[t];if(!e){var i=this.space,n=this.convs[i];e=C[i][t](n),this.convs[t]=e}return e},["rgb","hsl","hsv","cmyk","keyword"].forEach(function(t){I.prototype[t]=function(e){return this.routeSpace(t,arguments)}});var F=C,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]},O={getRgba:R,getHsla:z,getRgb:function(t){var e=R(t);return e&&e.slice(0,3)},getHsl:function(t){var e=z(t);return e&&e.slice(0,3)},getHwb:N,getAlpha:function(t){var e=R(t);if(e)return e[3];if(e=z(t))return e[3];if(e=N(t))return e[3]},hexString:function(t,e){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 B(t,e);return"rgb("+t[0]+", "+t[1]+", "+t[2]+")"},rgbaString:B,percentString:function(t,e){if(e<1||t[3]&&t[3]<1)return E(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:E,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 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=L[n[1]]))return}for(r=0;r<e.length;r++)e[r]=W(e[r],0,255);return i=i||0==i?W(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[W(parseInt(e[1]),0,360),W(parseFloat(e[2]),0,100),W(parseFloat(e[3]),0,100),W(isNaN(i)?1:i,0,1)]}}}function N(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[W(parseInt(e[1]),0,360),W(parseFloat(e[2]),0,100),W(parseFloat(e[3]),0,100),W(isNaN(i)?1:i,0,1)]}}}function B(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"rgba("+t[0]+", "+t[1]+", "+t[2]+", "+e+")"}function E(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 W(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 U=function(t){return t instanceof U?t:this instanceof U?(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=O.getRgba(t))?this.setValues("rgb",e):(e=O.getHsla(t))?this.setValues("hsl",e):(e=O.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 U(t);var e};U.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 O.hexString(this.values.rgb)},rgbString:function(){return O.rgbString(this.values.rgb,this.values.alpha)},rgbaString:function(){return O.rgbaString(this.values.rgb,this.values.alpha)},percentString:function(){return O.percentString(this.values.rgb,this.values.alpha)},hslString:function(){return O.hslString(this.values.hsl,this.values.alpha)},hslaString:function(){return O.hslaString(this.values.hsl,this.values.alpha)},hwbString:function(){return O.hwbString(this.values.hwb,this.values.alpha)},keyword:function(){return O.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 U,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}},U.prototype.spaces={rgb:["red","green","blue"],hsl:["hue","saturation","lightness"],hsv:["hue","saturation","value"],hwb:["hue","whiteness","blackness"],cmyk:["cyan","magenta","yellow","black"]},U.prototype.maxes={rgb:[255,255,255],hsl:[360,100,100],hsv:[360,100,100],hwb:[360,100,100],cmyk:[100,100,100,100]},U.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},U.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]=F[t][u](a[t]));return!0},U.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)},U.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=U);var Y,G=U,X={noop:function(){},uid:(Y=0,function(){return Y++}),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 X.valueOrDefault(X.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(X.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(X.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(!X.arrayEquals(a,r))return!1}else if(a!==r)return!1;return!0},clone:function(t){if(X.isArray(t))return t.map(X.clone);if(X.isObject(t)){for(var e={},i=Object.keys(t),n=i.length,a=0;a<n;++a)e[i[a]]=X.clone(t[i[a]]);return e}return t},_merger:function(t,e,i,n){var a=e[t],r=i[t];X.isObject(a)&&X.isObject(r)?X.merge(a,r,n):e[t]=X.clone(r)},_mergerIf:function(t,e,i){var n=e[t],a=i[t];X.isObject(n)&&X.isObject(a)?X.mergeIf(n,a):e.hasOwnProperty(t)||(e[t]=X.clone(a))},merge:function(t,e,i){var n,a,r,o,s,l=X.isArray(e)?e:[e],u=l.length;if(!X.isObject(t))return t;for(n=(i=i||{}).merger||X._merger,a=0;a<u;++a)if(e=l[a],X.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 X.merge(t,e,{merger:X._mergerIf})},extend:Object.assign||function(t){return X.merge(t,[].slice.call(arguments,1),{merger:function(t,e,i){e[t]=i[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=X.inherits,t&&X.extend(i.prototype,t),i.__super__=e.prototype,i},_deprecated:function(t,e,i,n){void 0!==e&&console.warn(t+': "'+i+'" is deprecated. Please use "'+n+'" instead')}},K=X;X.callCallback=X.callback,X.indexOf=function(t,e,i){return Array.prototype.indexOf.call(t,e,i)},X.getValueOrDefault=X.valueOrDefault,X.getValueAtIndexOrDefault=X.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};K.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,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,-J,-et),t.arc(u,l,o,-et,0),t.arc(u,d,o,0,et),t.arc(s,d,o,et,J)):s<u?(t.moveTo(s,i),t.arc(u,l,o,-et,et),t.arc(s,l,o,et,J+et)):l<d?(t.arc(s,l,o,-J,0),t.arc(s,d,o,0,J)):t.arc(s,l,o,-J,J),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)*Q;if(e&&"object"==typeof e&&("[object HTMLImageElement]"===(o=e.toString())||"[object HTMLCanvasElement]"===o))return t.save(),t.translate(n,a),t.rotate(h),t.drawImage(e,-e.width/2,-e.height/2,e.width,e.height),void t.restore();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":u=i-(d=.516*i),s=Math.cos(h+it)*u,l=Math.sin(h+it)*u,t.arc(n-s,a-l,d,h-J,h-et),t.arc(n+l,a-s,d,h-et,h),t.arc(n+s,a+l,d,h,h+et),t.arc(n-l,a+s,d,h+et,h+J),t.closePath();break;case"rect":if(!r){u=Math.SQRT1_2*i,t.rect(n-u,a-u,2*u,2*u);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()}},_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)}},rt=at;K.clear=at.clear,K.drawRoundedRectangle=function(t){t.beginPath(),at.roundedRect.apply(at,arguments)};var ot={_set:function(t,e){return K.merge(this[t]||(this[t]={}),e)}};ot._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=ot,lt=K.valueOrDefault;var ut={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 K.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:K.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||K.isNullOrUndef(t.size)||K.isNullOrUndef(t.family)?null:(t.style?t.style+" ":"")+(t.weight?t.weight+" ":"")+t.size+"px "+t.family}(n),n},resolve:function(t,e,i,n){var a,r,o,s=!0;for(a=0,r=t.length;a<r;++a)if(void 0!==(o=t[a])&&(void 0!==e&&"function"==typeof o&&(o=o(e),s=!1),void 0!==i&&K.isArray(o)&&(o=o[i],s=!1),void 0!==o))return n&&!s&&(n.cacheable=!1),o}},dt={_factorize:function(t){var e,i=[],n=Math.sqrt(t);for(e=1;e<n;e++)t%e==0&&(i.push(e),i.push(t/e));return n===(0|n)&&i.push(n),i.sort(function(t,e){return t-e}).pop(),i},log10:Math.log10||function(t){var e=Math.log(t)*Math.LOG10E,i=Math.round(e);return t===Math.pow(10,i)?i:e}},ht=dt;K.log10=dt.log10;var ct=K,ft=$,gt=rt,pt=ut,mt=ht,vt={getRtlAdapter:function(t,e,i){return t?function(t,e){return{x:function(i){return t+t+e-i},setWidth:function(t){e=t},textAlign:function(t){return"center"===t?t:"right"===t?"left":"right"},xPlus:function(t,e){return t-e},leftForLtr:function(t,e){return t-e}}}(e,i):{x:function(t){return t},setWidth:function(t){},textAlign:function(t){return t},xPlus:function(t,e){return t+e},leftForLtr:function(t,e){return t}}},overrideTextDirection:function(t,e){var i,n;"ltr"!==e&&"rtl"!==e||(n=[(i=t.canvas.style).getPropertyValue("direction"),i.getPropertyPriority("direction")],i.setProperty("direction",e,"important"),t.prevTextDirection=n)},restoreTextDirection:function(t){var e=t.prevTextDirection;void 0!==e&&(delete t.prevTextDirection,t.canvas.style.setProperty("direction",e[0],e[1]))}};ct.easing=ft,ct.canvas=gt,ct.options=pt,ct.math=mt,ct.rtl=vt;var bt=function(t){ct.extend(this,t),this.initialize.apply(this,arguments)};ct.extend(bt.prototype,{_type:void 0,initialize:function(){this.hidden=!1},pivot:function(){var t=this;return t._view||(t._view=ct.extend({},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(ct.isFinite(l)&&ct.isFinite(u)){e[o]=l+(u-l)*n;continue}e[o]=u}}(n,a,i,t),e):(e._view=ct.extend({},i),e._start=null,e)},tooltipPosition:function(){return{x:this._model.x,y:this._model.y}},hasValue:function(){return ct.isNumber(this._model.x)&&ct.isNumber(this._model.y)}}),bt.extend=ct.inherits;var xt=bt,yt=xt.extend({chart:null,currentStep:0,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null}),_t=yt;Object.defineProperty(yt.prototype,"animationObject",{get:function(){return this}}),Object.defineProperty(yt.prototype,"chartInstance",{get:function(){return this.chart},set:function(t){this.chart=t}}),st._set("global",{animation:{duration:1e3,easing:"easeOutQuart",onProgress:ct.noop,onComplete:ct.noop}});var kt={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=ct.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=ct.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),ct.callback(t.render,[e,t],e),ct.callback(t.onAnimationProgress,[t],e),t.currentStep>=i?(ct.callback(t.onAnimationComplete,[t],e),e.animating=!1,a.splice(r,1)):++r}},wt=ct.options.resolve,Mt=["push","pop","shift","splice","unshift"];function St(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||(Mt.forEach(function(e){delete t[e]}),delete t._chartjs)}}var Ct=function(t,e){this.initialize(t,e)};ct.extend(Ct.prototype,{datasetElementType:null,dataElementType:null,_datasetElementOptions:["backgroundColor","borderCapStyle","borderColor","borderDash","borderDashOffset","borderJoinStyle","borderWidth"],_dataElementOptions:["backgroundColor","borderColor","borderWidth","pointStyle"],initialize:function(t,e){var i=this;i.chart=t,i.index=e,i.linkScales(),i.addElements(),i._type=i.getMeta().type},updateIndex:function(t){this.index=t},linkScales:function(){var t=this.getMeta(),e=this.chart,i=e.scales,n=this.getDataset(),a=e.options.scales;null!==t.xAxisID&&t.xAxisID in i&&!n.xAxisID||(t.xAxisID=n.xAxisID||a.xAxes[0].id),null!==t.yAxisID&&t.yAxisID in i&&!n.yAxisID||(t.yAxisID=n.yAxisID||a.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&&St(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&&St(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]}}),Mt.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 ct.each(t._chartjs.listeners,function(t){"function"==typeof t[i]&&t[i].apply(t,e)}),a}})}))),i._data=a),i.resyncElements()},_configure:function(){this._config=ct.merge({},[this.chart.options.datasets[this._type],this.getDataset()],{merger:function(t,e,i){"_meta"!==t&&"data"!==t&&ct._merger(t,e,i)}})},_update:function(t){this._configure(),this._cachedDataOpts=null,this.update(t)},update:ct.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()},getStyle:function(t){var e,i=this.getMeta(),n=i.dataset;return this._configure(),n&&void 0===t?e=this._resolveDatasetElementOptions(n||{}):(t=t||0,e=this._resolveDataElementOptions(i.data[t]||{},t)),!1!==e.fill&&null!==e.fill||(e.backgroundColor="rgba(0,0,0,0)"),e},_resolveDatasetElementOptions:function(t,e){var i,n,a,r,o=this,s=o.chart,l=o._config,u=t.custom||{},d=s.options.elements[o.datasetElementType.prototype._type]||{},h=o._datasetElementOptions,c={},f={chart:s,dataset:o.getDataset(),datasetIndex:o.index,hover:e};for(i=0,n=h.length;i<n;++i)a=h[i],r=e?"hover"+a.charAt(0).toUpperCase()+a.slice(1):a,c[a]=wt([u[r],l[r],d[r]],f);return c},_resolveDataElementOptions:function(t,e){var i=this,n=t&&t.custom,a=i._cachedDataOpts;if(a&&!n)return a;var r,o,s,l,u=i.chart,d=i._config,h=u.options.elements[i.dataElementType.prototype._type]||{},c=i._dataElementOptions,f={},g={chart:u,dataIndex:e,dataset:i.getDataset(),datasetIndex:i.index},p={cacheable:!n};if(n=n||{},ct.isArray(c))for(o=0,s=c.length;o<s;++o)f[l=c[o]]=wt([n[l],d[l],h[l]],g,e,p);else for(o=0,s=(r=Object.keys(c)).length;o<s;++o)f[l=r[o]]=wt([n[l],d[c[l]],d[l],h[l]],g,e,p);return p.cacheable&&(i._cachedDataOpts=Object.freeze(f)),f},removeHoverStyle:function(t){ct.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=ct.getHoverColor;t.$previousStyle={backgroundColor:a.backgroundColor,borderColor:a.borderColor,borderWidth:a.borderWidth},a.backgroundColor=wt([n.hoverBackgroundColor,e.hoverBackgroundColor,r(a.backgroundColor)],void 0,i),a.borderColor=wt([n.hoverBorderColor,e.hoverBorderColor,r(a.borderColor)],void 0,i),a.borderWidth=wt([n.hoverBorderWidth,e.hoverBorderWidth,a.borderWidth],void 0,i)},_removeDatasetHoverStyle:function(){var t=this.getMeta().dataset;t&&this.removeHoverStyle(t)},_setDatasetHoverStyle:function(){var t,e,i,n,a,r,o=this.getMeta().dataset,s={};if(o){for(r=o._model,a=this._resolveDatasetElementOptions(o,!0),t=0,e=(n=Object.keys(a)).length;t<e;++t)s[i=n[t]]=r[i],r[i]=a[i];o.$previousStyle=s}},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)}}),Ct.extend=ct.inherits;var Pt=Ct,At=2*Math.PI;function Dt(t,e){var i=e.startAngle,n=e.endAngle,a=e.pixelMargin,r=a/e.outerRadius,o=e.x,s=e.y;t.beginPath(),t.arc(o,s,e.outerRadius,i-r,n+r),e.innerRadius>a?(r=a/e.innerRadius,t.arc(o,s,e.innerRadius-a,n+r,i-r,!0)):t.arc(o,s,a,n+Math.PI/2,i-Math.PI/2),t.closePath(),t.clip()}function Tt(t,e,i){var n="inner"===e.borderAlign;n?(t.lineWidth=2*e.borderWidth,t.lineJoin="round"):(t.lineWidth=e.borderWidth,t.lineJoin="bevel"),i.fullCircles&&function(t,e,i,n){var a,r=i.endAngle;for(n&&(i.endAngle=i.startAngle+At,Dt(t,i),i.endAngle=r,i.endAngle===i.startAngle&&i.fullCircles&&(i.endAngle+=At,i.fullCircles--)),t.beginPath(),t.arc(i.x,i.y,i.innerRadius,i.startAngle+At,i.startAngle,!0),a=0;a<i.fullCircles;++a)t.stroke();for(t.beginPath(),t.arc(i.x,i.y,e.outerRadius,i.startAngle,i.startAngle+At),a=0;a<i.fullCircles;++a)t.stroke()}(t,e,i,n),n&&Dt(t,i),t.beginPath(),t.arc(i.x,i.y,e.outerRadius,i.startAngle,i.endAngle),t.arc(i.x,i.y,i.innerRadius,i.endAngle,i.startAngle,!0),t.closePath(),t.stroke()}st._set("global",{elements:{arc:{backgroundColor:st.global.defaultColor,borderColor:"#fff",borderWidth:2,borderAlign:"center"}}});var It=xt.extend({_type:"arc",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=ct.getAngleFromPoint(i,{x:t,y:e}),a=n.angle,r=n.distance,o=i.startAngle,s=i.endAngle;s<o;)s+=At;for(;a>s;)a-=At;for(;a<o;)a+=At;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="inner"===i.borderAlign?.33:0,a={x:i.x,y:i.y,innerRadius:i.innerRadius,outerRadius:Math.max(i.outerRadius-n,0),pixelMargin:n,startAngle:i.startAngle,endAngle:i.endAngle,fullCircles:Math.floor(i.circumference/At)};if(e.save(),e.fillStyle=i.backgroundColor,e.strokeStyle=i.borderColor,a.fullCircles){for(a.endAngle=a.startAngle+At,e.beginPath(),e.arc(a.x,a.y,a.outerRadius,a.startAngle,a.endAngle),e.arc(a.x,a.y,a.innerRadius,a.endAngle,a.startAngle,!0),e.closePath(),t=0;t<a.fullCircles;++t)e.fill();a.endAngle=a.startAngle+i.circumference%At}e.beginPath(),e.arc(a.x,a.y,a.outerRadius,a.startAngle,a.endAngle),e.arc(a.x,a.y,a.innerRadius,a.endAngle,a.startAngle,!0),e.closePath(),e.fill(),i.borderWidth&&Tt(e,i,a),e.restore()}}),Ft=ct.valueOrDefault,Lt=st.global.defaultColor;st._set("global",{elements:{line:{tension:.4,backgroundColor:Lt,borderWidth:3,borderColor:Lt,borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",capBezierPoints:!0,fill:!0}}});var Ot=xt.extend({_type:"line",draw:function(){var t,e,i,n=this,a=n._view,r=n._chart.ctx,o=a.spanGaps,s=n._children.slice(),l=st.global,u=l.elements.line,d=-1,h=n._loop;if(s.length){if(n._loop){for(t=0;t<s.length;++t)if(e=ct.previousItem(s,t),!s[t]._view.skip&&e._view.skip){s=s.slice(t).concat(s.slice(0,t)),h=o;break}h&&s.push(s[0])}for(r.save(),r.lineCap=a.borderCapStyle||u.borderCapStyle,r.setLineDash&&r.setLineDash(a.borderDash||u.borderDash),r.lineDashOffset=Ft(a.borderDashOffset,u.borderDashOffset),r.lineJoin=a.borderJoinStyle||u.borderJoinStyle,r.lineWidth=Ft(a.borderWidth,u.borderWidth),r.strokeStyle=a.borderColor||l.defaultColor,r.beginPath(),(i=s[0]._view).skip||(r.moveTo(i.x,i.y),d=0),t=1;t<s.length;++t)i=s[t]._view,e=-1===d?ct.previousItem(s,t):s[d],i.skip||(d!==t-1&&!o||-1===d?r.moveTo(i.x,i.y):ct.canvas.lineTo(r,e._view,i),d=t);h&&r.closePath(),r.stroke(),r.restore()}}}),Rt=ct.valueOrDefault,zt=st.global.defaultColor;function Nt(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:zt,borderColor:zt,borderWidth:1,hitRadius:1,hoverRadius:4,hoverBorderWidth:1}}});var Bt=xt.extend({_type:"point",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:Nt,inXRange:Nt,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=st.global,u=l.defaultColor;e.skip||(void 0===t||ct.canvas._isPointInArea(e,t))&&(i.strokeStyle=e.borderColor||u,i.lineWidth=Rt(e.borderWidth,l.elements.point.borderWidth),i.fillStyle=e.backgroundColor||u,ct.canvas.drawPoint(i,n,r,o,s,a))}}),Et=st.global.defaultColor;function Vt(t){return t&&void 0!==t.width}function Wt(t){var e,i,n,a,r;return Vt(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 Ht(t,e,i){return t===e?i:t===i?e:t}function jt(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=Ht(e,"left","right")):t.base<t.y&&(e=Ht(e,"bottom","top")),i[e]=!0,i):i}(t);return ct.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 qt(t,e,i){var n=null===e,a=null===i,r=!(!t||n&&a)&&Wt(t);return r&&(n||e>=r.left&&e<=r.right)&&(a||i>=r.top&&i<=r.bottom)}st._set("global",{elements:{rectangle:{backgroundColor:Et,borderColor:Et,borderSkipped:"bottom",borderWidth:0}}});var Ut=xt.extend({_type:"rectangle",draw:function(){var t=this._chart.ctx,e=this._view,i=function(t){var e=Wt(t),i=e.right-e.left,n=e.bottom-e.top,a=jt(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 qt(this._view,t,e)},inLabelRange:function(t,e){var i=this._view;return Vt(i)?qt(i,t,null):qt(i,null,e)},inXRange:function(t){return qt(this._view,t,null)},inYRange:function(t){return qt(this._view,null,t)},getCenterPoint:function(){var t,e,i=this._view;return Vt(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 Vt(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}}}),Yt={},Gt=It,Xt=Ot,Kt=Bt,Zt=Ut;Yt.Arc=Gt,Yt.Line=Xt,Yt.Point=Kt,Yt.Rectangle=Zt;var $t=ct._deprecated,Jt=ct.valueOrDefault;function Qt(t,e,i){var n,a,r=i.barThickness,o=e.stackCount,s=e.pixels[t],l=ct.isNullOrUndef(r)?function(t,e){var i,n,a,r,o=t._length;for(a=1,r=e.length;a<r;++a)o=Math.min(o,Math.abs(e[a]-e[a-1]));for(a=0,r=t.getTicks().length;a<r;++a)n=t.getPixelForTick(a),o=a>0?Math.min(o,Math.abs(n-i)):o,i=n;return o}(e.scale,e.pixels):-1;return ct.isNullOrUndef(r)?(n=l*i.categoryPercentage,a=i.barPercentage):(n=r*o,a=1),{chunk:n/o,ratio:a,start:s-n/2}}st._set("bar",{hover:{mode:"label"},scales:{xAxes:[{type:"category",offset:!0,gridLines:{offsetGridLines:!0}}],yAxes:[{type:"linear"}]}}),st._set("global",{datasets:{bar:{categoryPercentage:.8,barPercentage:.9}}});var te=Pt.extend({dataElementType:Yt.Rectangle,_dataElementOptions:["backgroundColor","borderColor","borderSkipped","borderWidth","barPercentage","barThickness","categoryPercentage","maxBarThickness","minBarLength"],initialize:function(){var t,e,i=this;Pt.prototype.initialize.apply(i,arguments),(t=i.getMeta()).stack=i.getDataset().stack,t.bar=!0,e=i._getIndexScale().options,$t("bar chart",e.barPercentage,"scales.[x/y]Axes.barPercentage","dataset.barPercentage"),$t("bar chart",e.barThickness,"scales.[x/y]Axes.barThickness","dataset.barThickness"),$t("bar chart",e.categoryPercentage,"scales.[x/y]Axes.categoryPercentage","dataset.categoryPercentage"),$t("bar chart",i._getValueScale().options.minBarLength,"scales.[x/y]Axes.minBarLength","dataset.minBarLength"),$t("bar chart",e.maxBarThickness,"scales.[x/y]Axes.maxBarThickness","dataset.maxBarThickness")},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._resolveDataElementOptions(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]},ct.isArray(r.data[e])&&(t._model.borderSkipped=null),n._updateElementGeometry(t,e,i,o),t.pivot()},_updateElementGeometry:function(t,e,i,n){var a=this,r=t._model,o=a._getValueScale(),s=o.getBasePixel(),l=o.isHorizontal(),u=a._ruler||a.getRuler(),d=a.calculateBarValuePixels(a.index,e,n),h=a.calculateBarIndexPixels(a.index,e,u,n);r.horizontal=l,r.base=i?s:d.base,r.x=l?i?s:d.head:h.center,r.y=l?h.center:i?s:d.head,r.height=l?h.size:void 0,r.width=l?void 0:h.size},_getStacks:function(t){var e,i,n=this._getIndexScale(),a=n._getMatchingVisibleMetas(this._type),r=n.options.stacked,o=a.length,s=[];for(e=0;e<o&&(i=a[e],(!1===r||-1===s.indexOf(i.stack)||void 0===r&&void 0===i.stack)&&s.push(i.stack),i.index!==t);++e);return s},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=[];for(t=0,e=this.getMeta().data.length;t<e;++t)n.push(i.getPixelForValue(null,t,this.index));return{pixels:n,start:i._startPixel,end:i._endPixel,stackCount:this.getStackCount(),scale:i}},calculateBarValuePixels:function(t,e,i){var n,a,r,o,s,l,u,d=this.chart,h=this._getValueScale(),c=h.isHorizontal(),f=d.data.datasets,g=h._getMatchingVisibleMetas(this._type),p=h._parseValue(f[t].data[e]),m=i.minBarLength,v=h.options.stacked,b=this.getMeta().stack,x=void 0===p.start?0:p.max>=0&&p.min>=0?p.min:p.max,y=void 0===p.start?p.end:p.max>=0&&p.min>=0?p.max-p.min:p.min-p.max,_=g.length;if(v||void 0===v&&void 0!==b)for(n=0;n<_&&(a=g[n]).index!==t;++n)a.stack===b&&(r=void 0===(u=h._parseValue(f[a.index].data[e])).start?u.end:u.min>=0&&u.max>=0?u.max:u.min,(p.min<0&&r<0||p.max>=0&&r>0)&&(x+=r));return o=h.getPixelForValue(x),l=(s=h.getPixelForValue(x+y))-o,void 0!==m&&Math.abs(l)<m&&(l=m,s=y>=0&&!c||y<0&&c?o-m:o+m),{size:l,base:o,head:s,center:s+l/2}},calculateBarIndexPixels:function(t,e,i,n){var 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):Qt(e,i,n),r=this.getStackIndex(t,this.getMeta().stack),o=a.start+a.chunk*r+a.chunk/2,s=Math.min(Jt(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(ct.canvas.clipArea(t.ctx,t.chartArea);r<a;++r){var o=e._parseValue(n.data[r]);isNaN(o.min)||isNaN(o.max)||i[r].draw()}ct.canvas.unclipArea(t.ctx)},_resolveDataElementOptions:function(){var t=this,e=ct.extend({},Pt.prototype._resolveDataElementOptions.apply(t,arguments)),i=t._getIndexScale().options,n=t._getValueScale().options;return e.barPercentage=Jt(i.barPercentage,e.barPercentage),e.barThickness=Jt(i.barThickness,e.barThickness),e.categoryPercentage=Jt(i.categoryPercentage,e.categoryPercentage),e.maxBarThickness=Jt(i.maxBarThickness,e.maxBarThickness),e.minBarLength=Jt(n.minBarLength,e.minBarLength),e}}),ee=ct.valueOrDefault,ie=ct.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 ne=Pt.extend({dataElementType:Yt.Point,_dataElementOptions:["backgroundColor","borderColor","borderWidth","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth","hoverRadius","hitRadius","pointStyle","rotation"],update:function(t){var e=this,i=e.getMeta().data;ct.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._resolveDataElementOptions(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=ct.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=ee(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=ee(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=ee(i.hoverBorderWidth,i.borderWidth),e.radius=i.radius+i.hoverRadius},_resolveDataElementOptions:function(t,e){var i=this,n=i.chart,a=i.getDataset(),r=t.custom||{},o=a.data[e]||{},s=Pt.prototype._resolveDataElementOptions.apply(i,arguments),l={chart:n,dataIndex:e,dataset:a,datasetIndex:i.index};return i._cachedDataOpts===s&&(s=ct.extend({},s)),s.radius=ie([r.radius,o.r,i._config.radius,n.options.elements.point.radius],l,e),s}}),ae=ct.valueOrDefault,re=Math.PI,oe=2*re,se=re/2;st._set("doughnut",{animation:{animateRotate:!0,animateScale:!1},hover:{mode:"single"},legendCallback:function(t){var e,i,n,a=document.createElement("ul"),r=t.data,o=r.datasets,s=r.labels;if(a.setAttribute("class",t.id+"-legend"),o.length)for(e=0,i=o[0].data.length;e<i;++e)(n=a.appendChild(document.createElement("li"))).appendChild(document.createElement("span")).style.backgroundColor=o[0].backgroundColor[e],s[e]&&n.appendChild(document.createTextNode(s[e]));return a.outerHTML},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=a.controller.getStyle(n);return{text:i,fillStyle:r.backgroundColor,strokeStyle:r.borderColor,lineWidth:r.borderWidth,hidden:isNaN(e.datasets[0].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:-se,circumference:oe,tooltips:{callbacks:{title:function(){return""},label:function(t,e){var i=e.labels[t.index],n=": "+e.datasets[t.datasetIndex].data[t.index];return ct.isArray(i)?(i=i.slice())[0]+=n:i+=n,i}}}});var le=Pt.extend({dataElementType:Yt.Arc,linkScales:ct.noop,_dataElementOptions:["backgroundColor","borderColor","borderWidth","borderAlign","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth"],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,a,r=this,o=r.chart,s=o.chartArea,l=o.options,u=1,d=1,h=0,c=0,f=r.getMeta(),g=f.data,p=l.cutoutPercentage/100||0,m=l.circumference,v=r._getRingWeight(r.index);if(m<oe){var b=l.rotation%oe,x=(b+=b>=re?-oe:b<-re?oe:0)+m,y=Math.cos(b),_=Math.sin(b),k=Math.cos(x),w=Math.sin(x),M=b<=0&&x>=0||x>=oe,S=b<=se&&x>=se||x>=oe+se,C=b<=-se&&x>=-se||x>=re+se,P=b===-re||x>=re?-1:Math.min(y,y*p,k,k*p),A=C?-1:Math.min(_,_*p,w,w*p),D=M?1:Math.max(y,y*p,k,k*p),T=S?1:Math.max(_,_*p,w,w*p);u=(D-P)/2,d=(T-A)/2,h=-(D+P)/2,c=-(T+A)/2}for(n=0,a=g.length;n<a;++n)g[n]._options=r._resolveDataElementOptions(g[n],n);for(o.borderWidth=r.getMaxBorderWidth(),e=(s.right-s.left-o.borderWidth)/u,i=(s.bottom-s.top-o.borderWidth)/d,o.outerRadius=Math.max(Math.min(e,i)/2,0),o.innerRadius=Math.max(o.outerRadius*p,0),o.radiusLength=(o.outerRadius-o.innerRadius)/(r._getVisibleDatasetWeightTotal()||1),o.offsetX=h*o.outerRadius,o.offsetY=c*o.outerRadius,f.total=r.calculateTotal(),r.outerRadius=o.outerRadius-o.radiusLength*r._getRingWeightOffset(r.index),r.innerRadius=Math.max(r.outerRadius-o.radiusLength*v,0),n=0,a=g.length;n<a;++n)r.updateElement(g[n],n,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/oe),g=i&&s.animateScale?0:n.innerRadius,p=i&&s.animateScale?0:n.outerRadius,m=t._options||{};ct.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:u+a.offsetY,startAngle:d,endAngle:h,circumference:f,outerRadius:p,innerRadius:g,label:ct.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 ct.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)?oe*(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],r?(r._configure(),o=r._resolveDataElementOptions(a,e)):o=a._options,"inner"!==o.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=ct.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth},e.backgroundColor=ae(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=ae(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=ae(i.hoverBorderWidth,i.borderWidth)},_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(ae(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",offset:!0,gridLines:{offsetGridLines:!0}}]},elements:{rectangle:{borderSkipped:"left"}},tooltips:{mode:"index",axis:"y"}}),st._set("global",{datasets:{horizontalBar:{categoryPercentage:.8,barPercentage:.9}}});var ue=te.extend({_getValueScaleId:function(){return this.getMeta().xAxisID},_getIndexScaleId:function(){return this.getMeta().yAxisID}}),de=ct.valueOrDefault,he=ct.options.resolve,ce=ct.canvas._isPointInArea;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 fe=Pt.extend({datasetElementType:Yt.Line,dataElementType:Yt.Point,_datasetElementOptions:["backgroundColor","borderCapStyle","borderColor","borderDash","borderDashOffset","borderJoinStyle","borderWidth","cubicInterpolationMode","fill"],_dataElementOptions:{backgroundColor:"pointBackgroundColor",borderColor:"pointBorderColor",borderWidth:"pointBorderWidth",hitRadius:"pointHitRadius",hoverBackgroundColor:"pointHoverBackgroundColor",hoverBorderColor:"pointHoverBorderColor",hoverBorderWidth:"pointHoverBorderWidth",hoverRadius:"pointHoverRadius",pointStyle:"pointStyle",radius:"pointRadius",rotation:"pointRotation"},update:function(t){var e,i,n=this,a=n.getMeta(),r=a.dataset,o=a.data||[],s=n.chart.options,l=n._config,u=n._showLine=de(l.showLine,s.showLines);for(n._xScale=n.getScaleForId(a.xAxisID),n._yScale=n.getScaleForId(a.yAxisID),u&&(void 0!==l.tension&&void 0===l.lineTension&&(l.lineTension=l.tension),r._scale=n._yScale,r._datasetIndex=n.index,r._children=o,r._model=n._resolveDatasetElementOptions(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._xScale,c=r._yScale,f=o.dataset._model,g=r._resolveDataElementOptions(t,e);n=h.getPixelForValue("object"==typeof d?d:NaN,e,u),a=i?c.getBasePixel():r.calculatePointY(d,e,u),t._xScale=h,t._yScale=c,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:de(s.tension,f?f.tension:0),steppedLine:!!f&&f.steppedLine,hitRadius:g.hitRadius}},_resolveDatasetElementOptions:function(t){var e=this,i=e._config,n=t.custom||{},a=e.chart.options,r=a.elements.line,o=Pt.prototype._resolveDatasetElementOptions.apply(e,arguments);return o.spanGaps=de(i.spanGaps,a.spanGaps),o.tension=de(i.lineTension,r.tension),o.steppedLine=he([n.steppedLine,i.steppedLine,r.stepped]),o},calculatePointY:function(t,e,i){var n,a,r,o,s=this.chart,l=this._yScale,u=0,d=0,h=+l.getRightValue(t),c=s._getSortedVisibleDatasetMetas(),f=c.length;if(l.options.stacked){for(n=0;n<f&&(r=c[n]).index!==i;++n)a=s.data.datasets[r.index],"line"===r.type&&r.yAxisID===l.id&&((o=+l.getRightValue(a.data[e]))<0?d+=o||0:u+=o||0);return h<0?l.getPixelForValue(d+h):l.getPixelForValue(u+h)}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)ct.splineCurveMonotone(l);else for(t=0,e=l.length;t<e;++t)i=l[t]._model,n=ct.splineCurve(ct.previousItem(l,t)._model,i,ct.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,ce(i,s)&&(t>0&&ce(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&&ce(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=0,o=n.length;for(this._showLine&&(t=(i.dataset._model.borderWidth||0)/2,ct.canvas.clipArea(e.ctx,{left:a.left-t,right:a.right+t,top:a.top-t,bottom:a.bottom+t}),i.dataset.draw(),ct.canvas.unclipArea(e.ctx));r<o;++r)n[r].draw(a)},setHoverStyle:function(t){var e=t._model,i=t._options,n=ct.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=de(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=de(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=de(i.hoverBorderWidth,i.borderWidth),e.radius=de(i.hoverRadius,i.radius)}}),ge=ct.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,i,n,a=document.createElement("ul"),r=t.data,o=r.datasets,s=r.labels;if(a.setAttribute("class",t.id+"-legend"),o.length)for(e=0,i=o[0].data.length;e<i;++e)(n=a.appendChild(document.createElement("li"))).appendChild(document.createElement("span")).style.backgroundColor=o[0].backgroundColor[e],s[e]&&n.appendChild(document.createTextNode(s[e]));return a.outerHTML},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=a.controller.getStyle(n);return{text:i,fillStyle:r.backgroundColor,strokeStyle:r.borderColor,lineWidth:r.borderWidth,hidden:isNaN(e.datasets[0].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 pe=Pt.extend({dataElementType:Yt.Arc,linkScales:ct.noop,_dataElementOptions:["backgroundColor","borderColor","borderWidth","borderAlign","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth"],_getIndexScaleId:function(){return this.chart.scale.id},_getValueScaleId:function(){return this.chart.scale.id},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._resolveDataElementOptions(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],p=g+(t.hidden?0:n._angles[e]),m=s.animateScale?0:l.getDistanceFromCenterForValue(r.data[e]),v=t._options||{};ct.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?m:f,startAngle:i&&s.animateRotate?c:g,endAngle:i&&s.animateRotate?c:p,label:ct.valueAtIndexOrDefault(u,e,u[e])}}),t.pivot()},countVisibleElements:function(){var t=this.getDataset(),e=this.getMeta(),i=0;return ct.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=ct.getHoverColor,a=ct.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)},_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 ge([e.chart.options.elements.arc.angle,2*Math.PI/i],r,t)}});st._set("pie",ct.clone(st.doughnut)),st._set("pie",{cutoutPercentage:0});var me=le,ve=ct.valueOrDefault;st._set("radar",{spanGaps:!1,scale:{type:"radialLinear"},elements:{line:{tension:0}}});var be=Pt.extend({datasetElementType:Yt.Line,dataElementType:Yt.Point,linkScales:ct.noop,_datasetElementOptions:["backgroundColor","borderWidth","borderColor","borderCapStyle","borderDash","borderDashOffset","borderJoinStyle","fill"],_dataElementOptions:{backgroundColor:"pointBackgroundColor",borderColor:"pointBorderColor",borderWidth:"pointBorderWidth",hitRadius:"pointHitRadius",hoverBackgroundColor:"pointHoverBackgroundColor",hoverBorderColor:"pointHoverBorderColor",hoverBorderWidth:"pointHoverBorderWidth",hoverRadius:"pointHoverRadius",pointStyle:"pointStyle",radius:"pointRadius",rotation:"pointRotation"},_getIndexScaleId:function(){return this.chart.scale.id},_getValueScaleId:function(){return this.chart.scale.id},update:function(t){var e,i,n=this,a=n.getMeta(),r=a.dataset,o=a.data||[],s=n.chart.scale,l=n._config;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._resolveDatasetElementOptions(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._resolveDataElementOptions(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:ve(a.tension,u?u.tension:0),hitRadius:l.hitRadius}},_resolveDatasetElementOptions:function(){var t=this,e=t._config,i=t.chart.options,n=Pt.prototype._resolveDatasetElementOptions.apply(t,arguments);return n.spanGaps=ve(e.spanGaps,i.spanGaps),n.tension=ve(e.lineTension,i.elements.line.tension),n},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(a.dataset._model.spanGaps&&(o=o.filter(function(t){return!t._model.skip})),t=0,e=o.length;t<e;++t)i=o[t]._model,n=ct.splineCurve(ct.previousItem(o,t,!0)._model,i,ct.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=ct.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=ve(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=ve(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=ve(i.hoverBorderWidth,i.borderWidth),e.radius=ve(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"}]},tooltips:{callbacks:{title:function(){return""},label:function(t){return"("+t.xLabel+", "+t.yLabel+")"}}}}),st._set("global",{datasets:{scatter:{showLine:!1}}});var xe={bar:te,bubble:ne,doughnut:le,horizontalBar:ue,line:fe,polarArea:pe,pie:me,radar:be,scatter:fe};function ye(t,e){return t.native?{x:t.x,y:t.y}:ct.getRelativePosition(t,e)}function _e(t,e){var i,n,a,r,o,s,l=t._getSortedVisibleDatasetMetas();for(n=0,r=l.length;n<r;++n)for(a=0,o=(i=l[n].data).length;a<o;++a)(s=i[a])._view.skip||e(s)}function ke(t,e){var i=[];return _e(t,function(t){t.inRange(e.x,e.y)&&i.push(t)}),i}function we(t,e,i,n){var a=Number.POSITIVE_INFINITY,r=[];return _e(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 Me(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 Se(t,e,i){var n=ye(e,t);i.axis=i.axis||"x";var a=Me(i.axis),r=i.intersect?ke(t,n):we(t,n,!1,a),o=[];return r.length?(t._getSortedVisibleDatasetMetas().forEach(function(t){var e=t.data[r[0]._index];e&&!e._view.skip&&o.push(e)}),o):[]}var Ce={modes:{single:function(t,e){var i=ye(e,t),n=[];return _e(t,function(t){if(t.inRange(i.x,i.y))return n.push(t),n}),n.slice(0,1)},label:Se,index:Se,dataset:function(t,e,i){var n=ye(e,t);i.axis=i.axis||"xy";var a=Me(i.axis),r=i.intersect?ke(t,n):we(t,n,!1,a);return r.length>0&&(r=t.getDatasetMeta(r[0]._datasetIndex).data),r},"x-axis":function(t,e){return Se(t,e,{intersect:!1})},point:function(t,e){return ke(t,ye(e,t))},nearest:function(t,e,i){var n=ye(e,t);i.axis=i.axis||"xy";var a=Me(i.axis);return we(t,n,i.intersect,a)},x:function(t,e,i){var n=ye(e,t),a=[],r=!1;return _e(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=ye(e,t),a=[],r=!1;return _e(t,function(t){t.inYRange(n.y)&&a.push(t),t.inRange(n.x,n.y)&&(r=!0)}),i.intersect&&!r&&(a=[]),a}}},Pe=ct.extend;function Ae(t,e){return ct.where(t,function(t){return t.pos===e})}function De(t,e){return t.sort(function(t,i){var n=e?i:t,a=e?t:i;return n.weight===a.weight?n.index-a.index:n.weight-a.weight})}function Te(t,e,i,n){return Math.max(t[i],e[i])+Math.max(t[n],e[n])}function Ie(t,e,i){var n,a,r=i.box,o=t.maxPadding;if(i.size&&(t[i.pos]-=i.size),i.size=i.horizontal?r.height:r.width,t[i.pos]+=i.size,r.getPadding){var s=r.getPadding();o.top=Math.max(o.top,s.top),o.left=Math.max(o.left,s.left),o.bottom=Math.max(o.bottom,s.bottom),o.right=Math.max(o.right,s.right)}if(n=e.outerWidth-Te(o,t,"left","right"),a=e.outerHeight-Te(o,t,"top","bottom"),n!==t.w||a!==t.h)return t.w=n,t.h=a,i.horizontal?n!==t.w:a!==t.h}function Fe(t,e){var i=e.maxPadding;function n(t){var n={left:0,top:0,right:0,bottom:0};return t.forEach(function(t){n[t]=Math.max(e[t],i[t])}),n}return n(t?["left","right"]:["top","bottom"])}function Le(t,e,i){var n,a,r,o,s,l,u=[];for(n=0,a=t.length;n<a;++n)(o=(r=t[n]).box).update(r.width||e.w,r.height||e.h,Fe(r.horizontal,e)),Ie(e,i,r)&&(l=!0,u.length&&(s=!0)),o.fullWidth||u.push(r);return s&&Le(u,e,i)||l}function Oe(t,e,i){var n,a,r,o,s=i.padding,l=e.x,u=e.y;for(n=0,a=t.length;n<a;++n)o=(r=t[n]).box,r.horizontal?(o.left=o.fullWidth?s.left:e.left,o.right=o.fullWidth?i.outerWidth-s.right:e.left+e.w,o.top=u,o.bottom=u+o.height,o.width=o.right-o.left,u=o.bottom):(o.left=l,o.right=l+o.width,o.top=e.top,o.bottom=e.top+e.h,o.height=o.bottom-o.top,l=o.right);e.x=l,e.y=u}st._set("global",{layout:{padding:{top:0,right:0,bottom:0,left:0}}});var Re={defaults:{},addBox:function(t,e){t.boxes||(t.boxes=[]),e.fullWidth=e.fullWidth||!1,e.position=e.position||"top",e.weight=e.weight||0,e._layers=e._layers||function(){return[{z:0,draw:function(){e.draw.apply(e,arguments)}}]},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=ct.options.toPadding(n.padding),r=e-a.width,o=i-a.height,s=function(t){var e=function(t){var e,i,n,a=[];for(e=0,i=(t||[]).length;e<i;++e)n=t[e],a.push({index:e,box:n,pos:n.position,horizontal:n.isHorizontal(),weight:n.weight});return a}(t),i=De(Ae(e,"left"),!0),n=De(Ae(e,"right")),a=De(Ae(e,"top"),!0),r=De(Ae(e,"bottom"));return{leftAndTop:i.concat(a),rightAndBottom:n.concat(r),chartArea:Ae(e,"chartArea"),vertical:i.concat(n),horizontal:a.concat(r)}}(t.boxes),l=s.vertical,u=s.horizontal,d=Object.freeze({outerWidth:e,outerHeight:i,padding:a,availableWidth:r,vBoxMaxWidth:r/2/l.length,hBoxMaxHeight:o/2}),h=Pe({maxPadding:Pe({},a),w:r,h:o,x:a.left,y:a.top},a);!function(t,e){var i,n,a;for(i=0,n=t.length;i<n;++i)(a=t[i]).width=a.horizontal?a.box.fullWidth&&e.availableWidth:e.vBoxMaxWidth,a.height=a.horizontal&&e.hBoxMaxHeight}(l.concat(u),d),Le(l,h,d),Le(u,h,d)&&Le(l,h,d),function(t){var e=t.maxPadding;function i(i){var n=Math.max(e[i]-t[i],0);return t[i]+=n,n}t.y+=i("top"),t.x+=i("left"),i("right"),i("bottom")}(h),Oe(s.leftAndTop,h,d),h.x+=h.w,h.y+=h.h,Oe(s.rightAndBottom,h,d),t.chartArea={left:h.left,top:h.top,right:h.left+h.w,bottom:h.top+h.h},ct.each(s.chartArea,function(e){var i=e.box;Pe(i,t.chartArea),i.update(h.w,h.h)})}}};var ze,Ne=(ze=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}"}))&&ze.default||ze,Be="$chartjs",Ee="chartjs-size-monitor",Ve="chartjs-render-monitor",We="chartjs-render-animation",He=["animationstart","webkitAnimationStart"],je={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"};function qe(t,e){var i=ct.getStyle(t,e),n=i&&i.match(/^(\d+)(\.\d+)?px$/);return n?Number(n[1]):void 0}var Ue=!!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 Ye(t,e,i){t.addEventListener(e,i,Ue)}function Ge(t,e,i){t.removeEventListener(e,i,Ue)}function Xe(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 Ke(t){var e=document.createElement("div");return e.className=t||"",e}function Ze(t,e,i){var n,a,r,o,s=t[Be]||(t[Be]={}),l=s.resizer=function(t){var e=Ke(Ee),i=Ke(Ee+"-expand"),n=Ke(Ee+"-shrink");i.appendChild(Ke()),n.appendChild(Ke()),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 Ye(i,"scroll",a.bind(i,"expand")),Ye(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(Xe("resize",i)),n&&n.clientWidth<a&&i.canvas&&e(Xe("resize",i))}},r=!1,o=[],function(){o=Array.prototype.slice.call(arguments),a=a||this,r||(r=!0,ct.requestAnimFrame.call(window,function(){r=!1,n.apply(a,o)}))}));!function(t,e){var i=t[Be]||(t[Be]={}),n=i.renderProxy=function(t){t.animationName===We&&e()};ct.each(He,function(e){Ye(t,e,n)}),i.reflow=!!t.offsetParent,t.classList.add(Ve)}(t,function(){if(s.resizer){var e=t.parentNode;e&&e!==l.parentNode&&e.insertBefore(l,e.firstChild),l._reset()}})}function $e(t){var e=t[Be]||{},i=e.resizer;delete e.resizer,function(t){var e=t[Be]||{},i=e.renderProxy;i&&(ct.each(He,function(e){Ge(t,e,i)}),delete e.renderProxy),t.classList.remove(Ve)}(t),i&&i.parentNode&&i.parentNode.removeChild(i)}var Je={disableCSSInjection:!1,_enabled:"undefined"!=typeof window&&"undefined"!=typeof document,_ensureLoaded:function(t){if(!this.disableCSSInjection){var e=t.getRootNode();!function(t,e){var i=t[Be]||(t[Be]={});if(!i.containsStyles){i.containsStyles=!0,e="/* Chart.js */\n"+e;var n=document.createElement("style");n.setAttribute("type","text/css"),n.appendChild(document.createTextNode(e)),t.appendChild(n)}}(e.host?e:document.head,Ne)}},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 i&&i.canvas===t?(this._ensureLoaded(t),function(t,e){var i=t.style,n=t.getAttribute("height"),a=t.getAttribute("width");if(t[Be]={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=qe(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=qe(t,"height");void 0!==r&&(t.height=o)}}(t,e),i):null},releaseContext:function(t){var e=t.canvas;if(e[Be]){var i=e[Be].initial;["height","width"].forEach(function(t){var n=i[t];ct.isNullOrUndef(n)?e.removeAttribute(t):e.setAttribute(t,n)}),ct.each(i.style||{},function(t,i){e.style[i]=t}),e.width=e.width,delete e[Be]}},addEventListener:function(t,e,i){var n=t.canvas;if("resize"!==e){var a=i[Be]||(i[Be]={});Ye(n,e,(a.proxies||(a.proxies={}))[t.id+"_"+e]=function(e){i(function(t,e){var i=je[t.type]||t.type,n=ct.getRelativePosition(t,e);return Xe(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[Be]||{}).proxies||{})[t.id+"_"+e];a&&Ge(n,e,a)}else $e(n)}};ct.addEvent=Ye,ct.removeEvent=Ge;var Qe=Je._enabled?Je:{acquireContext:function(t){return t&&t.canvas&&(t=t.canvas),t&&t.getContext("2d")||null}},ti=ct.extend({initialize:function(){},acquireContext:function(){},releaseContext:function(){},addEventListener:function(){},removeEventListener:function(){}},Qe);st._set("global",{plugins:{}});var ei={_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=ct.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}},ii={constructors:{},defaults:{},registerScaleType:function(t,e,i){this.constructors[t]=e,this.defaults[t]=ct.clone(i)},getScaleConstructor:function(t){return this.constructors.hasOwnProperty(t)?this.constructors[t]:void 0},getScaleDefaults:function(t){return this.defaults.hasOwnProperty(t)?ct.merge({},[st.scale,this.defaults[t]]):{}},updateScaleDefaults:function(t,e){this.defaults.hasOwnProperty(t)&&(this.defaults[t]=ct.extend(this.defaults[t],e))},addScalesToLayout:function(t){ct.each(t.scales,function(e){e.fullWidth=e.options.fullWidth,e.position=e.options.position,e.weight=e.options.weight,Re.addBox(t,e)})}},ni=ct.valueOrDefault,ai=ct.rtl.getRtlAdapter;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:ct.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:ct.noop,beforeBody:ct.noop,beforeLabel:ct.noop,label:function(t,e){var i=e.datasets[t.datasetIndex].label||"";return i&&(i+=": "),ct.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:ct.noop,afterBody:ct.noop,beforeFooter:ct.noop,footer:ct.noop,afterFooter:ct.noop}}});var ri={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=ct.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 oi(t,e){return e&&(ct.isArray(e)?Array.prototype.push.apply(t,e):t.push(e)),t}function si(t){return("string"==typeof t||t instanceof String)&&t.indexOf("\n")>-1?t.split("\n"):t}function li(t){var e=st.global;return{xPadding:t.xPadding,yPadding:t.yPadding,xAlign:t.xAlign,yAlign:t.yAlign,rtl:t.rtl,textDirection:t.textDirection,bodyFontColor:t.bodyFontColor,_bodyFontFamily:ni(t.bodyFontFamily,e.defaultFontFamily),_bodyFontStyle:ni(t.bodyFontStyle,e.defaultFontStyle),_bodyAlign:t.bodyAlign,bodyFontSize:ni(t.bodyFontSize,e.defaultFontSize),bodySpacing:t.bodySpacing,titleFontColor:t.titleFontColor,_titleFontFamily:ni(t.titleFontFamily,e.defaultFontFamily),_titleFontStyle:ni(t.titleFontStyle,e.defaultFontStyle),titleFontSize:ni(t.titleFontSize,e.defaultFontSize),_titleAlign:t.titleAlign,titleSpacing:t.titleSpacing,titleMarginBottom:t.titleMarginBottom,footerFontColor:t.footerFontColor,_footerFontFamily:ni(t.footerFontFamily,e.defaultFontFamily),_footerFontStyle:ni(t.footerFontStyle,e.defaultFontStyle),footerFontSize:ni(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 ui(t,e){return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-t.xPadding:t.x+t.xPadding}function di(t){return oi([],si(t))}var hi=xt.extend({initialize:function(){this._model=li(this._options),this._lastActive=[]},getTitle:function(){var t=this,e=t._options,i=e.callbacks,n=i.beforeTitle.apply(t,arguments),a=i.title.apply(t,arguments),r=i.afterTitle.apply(t,arguments),o=[];return o=oi(o,si(n)),o=oi(o,si(a)),o=oi(o,si(r))},getBeforeBody:function(){return di(this._options.callbacks.beforeBody.apply(this,arguments))},getBody:function(t,e){var i=this,n=i._options.callbacks,a=[];return ct.each(t,function(t){var r={before:[],lines:[],after:[]};oi(r.before,si(n.beforeLabel.call(i,t,e))),oi(r.lines,n.label.call(i,t,e)),oi(r.after,si(n.afterLabel.call(i,t,e))),a.push(r)}),a},getAfterBody:function(){return di(this._options.callbacks.afterBody.apply(this,arguments))},getFooter:function(){var t=this,e=t._options.callbacks,i=e.beforeFooter.apply(t,arguments),n=e.footer.apply(t,arguments),a=e.afterFooter.apply(t,arguments),r=[];return r=oi(r,si(i)),r=oi(r,si(n)),r=oi(r,si(a))},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=li(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=[];y=ri[c.position].call(h,p,h._eventPosition);var w=[];for(e=0,i=p.length;e<i;++e)w.push((n=p[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,m)})),c.itemSort&&(w=w.sort(function(t,e){return c.itemSort(t,e,m)})),ct.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,m),g.beforeBody=h.getBeforeBody(w,m),g.body=h.getBody(w,m),g.afterBody=h.getAfterBody(w,m),g.footer=h.getFooter(w,m),g.x=y.x,g.y=y.y,g.caretPadding=c.caretPadding,g.labelColors=_,g.labelTextColors=k,g.dataPoints=w,x=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=ct.fontString(u,e._titleFontStyle,e._titleFontFamily),ct.each(e.title,f),i.font=ct.fontString(d,e._bodyFontStyle,e._bodyFontFamily),ct.each(e.beforeBody.concat(e.afterBody),f),c=e.displayColors?d+2:0,ct.each(r,function(t){ct.each(t.before,f),ct.each(t.lines,f),ct.each(t.after,f)}),c=0,i.font=ct.fontString(h,e._footerFontStyle,e._footerFontFamily),ct.each(e.footer,f),{width:a+=2*e.xPadding,height:n}}(this,g),b=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,x,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,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,r,o,s,l,u=i.caretSize,d=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)-u,r=n,o=s+u,l=s-u):(a=(n=f+p)+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+p-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+m)+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,a,r,o=e.title,s=o.length;if(s){var l=ai(e.rtl,e.x,e.width);for(t.x=ui(e,e._titleAlign),i.textAlign=l.textAlign(e._titleAlign),i.textBaseline="middle",n=e.titleFontSize,a=e.titleSpacing,i.fillStyle=e.titleFontColor,i.font=ct.fontString(n,e._titleFontStyle,e._titleFontFamily),r=0;r<s;++r)i.fillText(o[r],l.x(t.x),t.y+n/2),t.y+=n+a,r+1===s&&(t.y+=e.titleMarginBottom-a)}},drawBody:function(t,e,i){var n,a,r,o,s,l,u,d,h=e.bodyFontSize,c=e.bodySpacing,f=e._bodyAlign,g=e.body,p=e.displayColors,m=0,v=p?ui(e,"left"):0,b=ai(e.rtl,e.x,e.width),x=function(e){i.fillText(e,b.x(t.x+m),t.y+h/2),t.y+=h+c},y=b.textAlign(f);for(i.textAlign=f,i.textBaseline="middle",i.font=ct.fontString(h,e._bodyFontStyle,e._bodyFontFamily),t.x=ui(e,y),i.fillStyle=e.bodyFontColor,ct.each(e.beforeBody,x),m=p&&"right"!==y?"center"===f?h/2+1:h+2:0,s=0,u=g.length;s<u;++s){for(n=g[s],a=e.labelTextColors[s],r=e.labelColors[s],i.fillStyle=a,ct.each(n.before,x),l=0,d=(o=n.lines).length;l<d;++l){if(p){var _=b.x(v);i.fillStyle=e.legendColorBackground,i.fillRect(b.leftForLtr(_,h),t.y,h,h),i.lineWidth=1,i.strokeStyle=r.borderColor,i.strokeRect(b.leftForLtr(_,h),t.y,h,h),i.fillStyle=r.backgroundColor,i.fillRect(b.leftForLtr(b.xPlus(_,1),h-2),t.y+1,h-2,h-2),i.fillStyle=a}x(o[l])}ct.each(n.after,x)}m=0,ct.each(e.afterBody,x),t.y-=c},drawFooter:function(t,e,i){var n,a,r=e.footer,o=r.length;if(o){var s=ai(e.rtl,e.x,e.width);for(t.x=ui(e,e._footerAlign),t.y+=e.footerMarginTop,i.textAlign=s.textAlign(e._footerAlign),i.textBaseline="middle",n=e.footerFontSize,i.fillStyle=e.footerFontColor,i.font=ct.fontString(n,e._footerFontStyle,e._footerFontFamily),a=0;a<o;++a)i.fillText(r[a],s.x(t.x),t.y+n/2),t.y+=n+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,ct.rtl.overrideTextDirection(t,e.textDirection),this.drawTitle(n,e,t),this.drawBody(n,e,t),this.drawFooter(n,e,t),ct.rtl.restoreTextDirection(t,e.textDirection),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),n.reverse&&i._active.reverse()),(e=!ct.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}}),ci=ri,fi=hi;fi.positioners=ci;var gi=ct.valueOrDefault;function pi(){return ct.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=gi(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?ct.merge(e[t][a],[ii.getScaleDefaults(r),o]):ct.merge(e[t][a],o)}else ct._merger(t,e,i,n)}})}function mi(){return ct.merge({},[].slice.call(arguments),{merger:function(t,e,i,n){var a=e[t]||{},r=i[t];"scales"===t?e[t]=pi(a,r):"scale"===t?e[t]=ct.merge(a,[ii.getScaleDefaults(r.type),r]):ct._merger(t,e,i,n)}})}function vi(t){var e=t.options;ct.each(t.scales,function(e){Re.removeBox(t,e)}),e=mi(st.global,st[t.config.type],e),t.options=t.config.options=e,t.ensureScalesHaveIDs(),t.buildOrUpdateScales(),t.tooltip._options=e.tooltips,t.tooltip.initialize()}function bi(t,e,i){var n,a=function(t){return t.id===n};do{n=e+i++}while(ct.findIndex(t,a)>=0);return n}function xi(t){return"top"===t||"bottom"===t}function yi(t,e){return function(i,n){return i[t]===n[t]?i[e]-n[e]:i[t]-n[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 _i=function(t,e){return this.construct(t,e),this};ct.extend(_i.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=mi(st.global,st[t.type],t.options||{}),t}(e);var n=ti.acquireContext(t,e),a=n&&n.canvas,r=a&&a.height,o=a&&a.width;i.id=ct.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._layers=[],i.chart=i,i.controller=i,_i.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 ei.notify(t,"beforeInit"),ct.retinaScale(t,t.options.devicePixelRatio),t.bindEvents(),t.options.responsive&&t.resize(!0),t.initToolTip(),ei.notify(t,"afterInit"),t},clear:function(){return ct.canvas.clear(this),this},stop:function(){return kt.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(ct.getMaximumWidth(n))),o=Math.max(0,Math.floor(a?r/a:ct.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",ct.retinaScale(e,i.devicePixelRatio),!t)){var s={width:r,height:o};ei.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;ct.each(e.xAxes,function(t,i){t.id||(t.id=bi(e.xAxes,"x-axis-",i))}),ct.each(e.yAxes,function(t,i){t.id||(t.id=bi(e.yAxes,"y-axis-",i))}),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"}),ct.each(n,function(e){var n=e.options,r=n.id,o=gi(n.type,e.dtype);xi(n.position)!==xi(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=ii.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)}),ct.each(a,function(t,e){t||delete i[e]}),t.scales=i,ii.addScalesToLayout(this)},buildOrUpdateControllers:function(){var t,e,i=this,n=[],a=i.data.datasets;for(t=0,e=a.length;t<e;t++){var r=a[t],o=i.getDatasetMeta(t),s=r.type||i.config.type;if(o.type&&o.type!==s&&(i.destroyDatasetMeta(t),o=i.getDatasetMeta(t)),o.type=s,o.order=r.order||0,o.index=t,o.controller)o.controller.updateIndex(t),o.controller.linkScales();else{var l=xe[o.type];if(void 0===l)throw new Error('"'+o.type+'" is not a chart type.');o.controller=new l(i,t),n.push(o.controller)}}return n},resetElements:function(){var t=this;ct.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]}),vi(n),ei._invalidate(n),!1!==ei.notify(n,"beforeUpdate")){n.tooltip._data=n.data;var a=n.buildOrUpdateControllers();for(e=0,i=n.data.datasets.length;e<i;e++)n.getDatasetMeta(e).controller.buildOrUpdateElements();n.updateLayout(),n.options.animation&&n.options.animation.duration&&ct.each(a,function(t){t.reset()}),n.updateDatasets(),n.tooltip.initialize(),n.lastActive=[],ei.notify(n,"afterUpdate"),n._layers.sort(yi("z","_idx")),n._bufferedRender?n._bufferedRequest={duration:t.duration,easing:t.easing,lazy:t.lazy}:n.render(t)}},updateLayout:function(){var t=this;!1!==ei.notify(t,"beforeLayout")&&(Re.update(this,this.width,this.height),t._layers=[],ct.each(t.boxes,function(e){e._configure&&e._configure(),t._layers.push.apply(t._layers,e._layers())},t),t._layers.forEach(function(t,e){t._idx=e}),ei.notify(t,"afterScaleUpdate"),ei.notify(t,"afterLayout"))},updateDatasets:function(){if(!1!==ei.notify(this,"beforeDatasetsUpdate")){for(var t=0,e=this.data.datasets.length;t<e;++t)this.updateDataset(t);ei.notify(this,"afterDatasetsUpdate")}},updateDataset:function(t){var e=this.getDatasetMeta(t),i={meta:e,index:t};!1!==ei.notify(this,"beforeDatasetUpdate",[i])&&(e.controller._update(),ei.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=gi(t.duration,i&&i.duration),a=t.lazy;if(!1!==ei.notify(e,"beforeRender")){var r=function(t){ei.notify(e,"afterRender"),ct.callback(i&&i.onComplete,[t],e)};if(i&&n){var o=new _t({numSteps:n/16.66,easing:t.easing||i.easing,render:function(t,e){var i=ct.easing.effects[e.easing],n=e.currentStep,a=n/e.numSteps;t.draw(i(a),a,n)},onAnimationProgress:i.onProgress,onAnimationComplete:r});kt.addAnimation(e,o,n,a)}else e.draw(),r(new _t({numSteps:0,chart:e}));return e}},draw:function(t){var e,i,n=this;if(n.clear(),ct.isNullOrUndef(t)&&(t=1),n.transition(t),!(n.width<=0||n.height<=0)&&!1!==ei.notify(n,"beforeDraw",[t])){for(i=n._layers,e=0;e<i.length&&i[e].z<=0;++e)i[e].draw(n.chartArea);for(n.drawDatasets(t);e<i.length;++e)i[e].draw(n.chartArea);n._drawTooltip(t),ei.notify(n,"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)},_getSortedDatasetMetas:function(t){var e,i,n=[];for(e=0,i=(this.data.datasets||[]).length;e<i;++e)t&&!this.isDatasetVisible(e)||n.push(this.getDatasetMeta(e));return n.sort(yi("order","index")),n},_getSortedVisibleDatasetMetas:function(){return this._getSortedDatasetMetas(!0)},drawDatasets:function(t){var e,i;if(!1!==ei.notify(this,"beforeDatasetsDraw",[t])){for(i=(e=this._getSortedVisibleDatasetMetas()).length-1;i>=0;--i)this.drawDataset(e[i],t);ei.notify(this,"afterDatasetsDraw",[t])}},drawDataset:function(t,e){var i={meta:t,index:t.index,easingValue:e};!1!==ei.notify(this,"beforeDatasetDraw",[i])&&(t.controller.draw(e),ei.notify(this,"afterDatasetDraw",[i]))},_drawTooltip:function(t){var e=this.tooltip,i={tooltip:e,easingValue:t};!1!==ei.notify(this,"beforeTooltipDraw",[i])&&(e.draw(),ei.notify(this,"afterTooltipDraw",[i]))},getElementAtEvent:function(t){return Ce.modes.single(this,t)},getElementsAtEvent:function(t){return Ce.modes.label(this,t,{intersect:!0})},getElementsAtXAxis:function(t){return Ce.modes["x-axis"](this,t,{intersect:!0})},getElementsAtEventForMode:function(t,e,i){var n=Ce.modes[e];return"function"==typeof n?n(this,t,i):[]},getDatasetAtEvent:function(t){return Ce.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,order:e.order||0,index:t}),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(),ct.canvas.clear(i),ti.releaseContext(i.ctx),i.canvas=null,i.ctx=null),ei.notify(i,"destroy"),delete _i.instances[i.id]},toBase64Image:function(){return this.canvas.toDataURL.apply(this.canvas,arguments)},initToolTip:function(){var t=this;t.tooltip=new fi({_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)};ct.each(t.options.events,function(n){ti.addEventListener(t,n,i),e[n]=i}),t.options.responsive&&(i=function(){t.resize()},ti.addEventListener(t,"resize",i),e.resize=i)},unbindEvents:function(){var t=this,e=t._listeners;e&&(delete t._listeners,ct.each(e,function(e,i){ti.removeEventListener(t,i,e)}))},updateHoverStyle:function(t,e,i){var n,a,r,o=i?"set":"remove";for(a=0,r=t.length;a<r;++a)(n=t[a])&&this.getDatasetMeta(n._datasetIndex).controller[o+"HoverStyle"](n);"dataset"===e&&this.getDatasetMeta(t[0]._datasetIndex).controller["_"+o+"DatasetHoverStyle"]()},eventHandler:function(t){var e=this,i=e.tooltip;if(!1!==ei.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)),ei.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),ct.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=!ct.arrayEquals(i.active,i.lastActive),i.lastActive=i.active,e}}),_i.instances={};var ki=_i;_i.Controller=_i,_i.types={},ct.configMerge=mi,ct.scaleMerge=pi;function wi(){throw new Error("This method is not implemented: either no adapter can be found or an incomplete integration was provided.")}function Mi(t){this.options=t||{}}ct.extend(Mi.prototype,{formats:wi,parse:wi,format:wi,add:wi,diff:wi,startOf:wi,endOf:wi,_create:function(t){return t}}),Mi.override=function(t){ct.extend(Mi.prototype,t)};var Si={_date:Mi},Ci={formatters:{values:function(t){return ct.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=ct.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=ct.log10(Math.abs(t)),s=Math.floor(o)-Math.floor(a);s=Math.max(Math.min(s,20),0),r=t.toExponential(s)}else{var l=-1*Math.floor(a);l=Math.max(Math.min(l,20),0),r=t.toFixed(l)}else r="0";return r},logarithmic:function(t,e,i){var n=t/Math.pow(10,Math.floor(ct.log10(t)));return 0===t?"0":1===n||2===n||5===n||0===e||e===i.length-1?t.toExponential():""}}},Pi=ct.isArray,Ai=ct.isNullOrUndef,Di=ct.valueOrDefault,Ti=ct.valueAtIndexOrDefault;function Ii(t,e,i){var n,a=t.getTicks().length,r=Math.min(e,a-1),o=t.getPixelForTick(r),s=t._startPixel,l=t._endPixel;if(!(i&&(n=1===a?Math.max(o-s,l-o):0===e?(t.getPixelForTick(1)-o)/2:(o-t.getPixelForTick(r-1))/2,(o+=r<e?n:-n)<s-1e-6||o>l+1e-6)))return o}function Fi(t,e,i,n){var a,r,o,s,l,u,d,h,c,f,g,p,m,v=i.length,b=[],x=[],y=[];for(a=0;a<v;++a){if(s=i[a].label,l=i[a].major?e.major:e.minor,t.font=u=l.string,d=n[u]=n[u]||{data:{},gc:[]},h=l.lineHeight,c=f=0,Ai(s)||Pi(s)){if(Pi(s))for(r=0,o=s.length;r<o;++r)g=s[r],Ai(g)||Pi(g)||(c=ct.measureText(t,d.data,d.gc,c,g),f+=h)}else c=ct.measureText(t,d.data,d.gc,c,s),f=h;b.push(c),x.push(f),y.push(h/2)}function _(t){return{width:b[t]||0,height:x[t]||0,offset:y[t]||0}}return function(t,e){ct.each(t,function(t){var i,n=t.gc,a=n.length/2;if(a>e){for(i=0;i<a;++i)delete t.data[n[i]];n.splice(0,a)}})}(n,v),p=b.indexOf(Math.max.apply(null,b)),m=x.indexOf(Math.max.apply(null,x)),{first:_(0),last:_(v-1),widest:_(p),highest:_(m)}}function Li(t){return t.drawTicks?t.tickMarkLength:0}function Oi(t){var e,i;return t.display?(e=ct.options._parseFont(t),i=ct.options.toPadding(t.padding),e.lineHeight+i.height):0}function Ri(t,e){return ct.extend(ct.options._parseFont({fontFamily:Di(e.fontFamily,t.fontFamily),fontSize:Di(e.fontSize,t.fontSize),fontStyle:Di(e.fontStyle,t.fontStyle),lineHeight:Di(e.lineHeight,t.lineHeight)}),{color:ct.options.resolve([e.fontColor,t.fontColor,st.global.defaultFontColor])})}function zi(t){var e=Ri(t,t.minor);return{minor:e,major:t.major.enabled?Ri(t,t.major):e}}function Ni(t){var e,i,n,a=[];for(i=0,n=t.length;i<n;++i)void 0!==(e=t[i])._index&&a.push(e);return a}function Bi(t,e,i,n){var a,r,o,s,l=Di(i,0),u=Math.min(Di(n,t.length),t.length),d=0;for(e=Math.ceil(e),n&&(e=(a=n-i)/Math.floor(a/e)),s=l;s<0;)d++,s=Math.round(l+d*e);for(r=Math.max(l,0);r<u;r++)o=t[r],r===s?(o._index=r,d++,s=Math.round(l+d*e)):delete o.label}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:Ci.formatters.values,minor:{},major:{}}});var Ei=xt.extend({zeroLineIndex:0,getPadding:function(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}},getTicks:function(){return this._ticks},_getLabels:function(){var t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels},mergeTicksOptions:function(){},beforeUpdate:function(){ct.callback(this.options.beforeUpdate,[this])},update:function(t,e,i){var n,a,r,o,s,l=this,u=l.options.ticks,d=u.sampleSize;if(l.beforeUpdate(),l.maxWidth=t,l.maxHeight=e,l.margins=ct.extend({left:0,right:0,top:0,bottom:0},i),l._ticks=null,l.ticks=null,l._labelSizes=null,l._maxLabelLines=0,l.longestLabelWidth=0,l.longestTextCache=l.longestTextCache||{},l._gridLineItems=null,l._labelItems=null,l.beforeSetDimensions(),l.setDimensions(),l.afterSetDimensions(),l.beforeDataLimits(),l.determineDataLimits(),l.afterDataLimits(),l.beforeBuildTicks(),o=l.buildTicks()||[],(!(o=l.afterBuildTicks(o)||o)||!o.length)&&l.ticks)for(o=[],n=0,a=l.ticks.length;n<a;++n)o.push({value:l.ticks[n],major:!1});return l._ticks=o,s=d<o.length,r=l._convertTicksToLabels(s?function(t,e){for(var i=[],n=t.length/e,a=0,r=t.length;a<r;a+=n)i.push(t[Math.floor(a)]);return i}(o,d):o),l._configure(),l.beforeCalculateTickRotation(),l.calculateTickRotation(),l.afterCalculateTickRotation(),l.beforeFit(),l.fit(),l.afterFit(),l._ticksToDraw=u.display&&(u.autoSkip||"auto"===u.source)?l._autoSkip(o):o,s&&(r=l._convertTicksToLabels(l._ticksToDraw)),l.ticks=r,l.afterUpdate(),l.minSize},_configure:function(){var t,e,i=this,n=i.options.ticks.reverse;i.isHorizontal()?(t=i.left,e=i.right):(t=i.top,e=i.bottom,n=!n),i._startPixel=t,i._endPixel=e,i._reversePixels=n,i._length=e-t},afterUpdate:function(){ct.callback(this.options.afterUpdate,[this])},beforeSetDimensions:function(){ct.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(){ct.callback(this.options.afterSetDimensions,[this])},beforeDataLimits:function(){ct.callback(this.options.beforeDataLimits,[this])},determineDataLimits:ct.noop,afterDataLimits:function(){ct.callback(this.options.afterDataLimits,[this])},beforeBuildTicks:function(){ct.callback(this.options.beforeBuildTicks,[this])},buildTicks:ct.noop,afterBuildTicks:function(t){var e=this;return Pi(t)&&t.length?ct.callback(e.options.afterBuildTicks,[e,t]):(e.ticks=ct.callback(e.options.afterBuildTicks,[e,e.ticks])||e.ticks,t)},beforeTickToLabelConversion:function(){ct.callback(this.options.beforeTickToLabelConversion,[this])},convertTicksToLabels:function(){var t=this.options.ticks;this.ticks=this.ticks.map(t.userCallback||t.callback,this)},afterTickToLabelConversion:function(){ct.callback(this.options.afterTickToLabelConversion,[this])},beforeCalculateTickRotation:function(){ct.callback(this.options.beforeCalculateTickRotation,[this])},calculateTickRotation:function(){var t,e,i,n,a,r,o,s=this,l=s.options,u=l.ticks,d=s.getTicks().length,h=u.minRotation||0,c=u.maxRotation,f=h;!s._isVisible()||!u.display||h>=c||d<=1||!s.isHorizontal()?s.labelRotation=h:(e=(t=s._getLabelSizes()).widest.width,i=t.highest.height-t.highest.offset,n=Math.min(s.maxWidth,s.chart.width-e),e+6>(a=l.offset?s.maxWidth/d:n/(d-1))&&(a=n/(d-(l.offset?.5:1)),r=s.maxHeight-Li(l.gridLines)-u.padding-Oi(l.scaleLabel),o=Math.sqrt(e*e+i*i),f=ct.toDegrees(Math.min(Math.asin(Math.min((t.highest.height+6)/a,1)),Math.asin(Math.min(r/o,1))-Math.asin(i/o))),f=Math.max(h,Math.min(c,f))),s.labelRotation=f)},afterCalculateTickRotation:function(){ct.callback(this.options.afterCalculateTickRotation,[this])},beforeFit:function(){ct.callback(this.options.beforeFit,[this])},fit:function(){var t=this,e=t.minSize={width:0,height:0},i=t.chart,n=t.options,a=n.ticks,r=n.scaleLabel,o=n.gridLines,s=t._isVisible(),l="bottom"===n.position,u=t.isHorizontal();if(u?e.width=t.maxWidth:s&&(e.width=Li(o)+Oi(r)),u?s&&(e.height=Li(o)+Oi(r)):e.height=t.maxHeight,a.display&&s){var d=zi(a),h=t._getLabelSizes(),c=h.first,f=h.last,g=h.widest,p=h.highest,m=.4*d.minor.lineHeight,v=a.padding;if(u){var b=0!==t.labelRotation,x=ct.toRadians(t.labelRotation),y=Math.cos(x),_=Math.sin(x),k=_*g.width+y*(p.height-(b?p.offset:0))+(b?0:m);e.height=Math.min(t.maxHeight,e.height+k+v);var w,M,S=t.getPixelForTick(0)-t.left,C=t.right-t.getPixelForTick(t.getTicks().length-1);b?(w=l?y*c.width+_*c.offset:_*(c.height-c.offset),M=l?_*(f.height-f.offset):y*f.width+_*f.offset):(w=c.width/2,M=f.width/2),t.paddingLeft=Math.max((w-S)*t.width/(t.width-S),0)+3,t.paddingRight=Math.max((M-C)*t.width/(t.width-C),0)+3}else{var P=a.mirror?0:g.width+v+m;e.width=Math.min(t.maxWidth,e.width+P),t.paddingTop=c.height/2,t.paddingBottom=f.height/2}}t.handleMargins(),u?(t.width=t._length=i.width-t.margins.left-t.margins.right,t.height=e.height):(t.width=e.width,t.height=t._length=i.height-t.margins.top-t.margins.bottom)},handleMargins:function(){var t=this;t.margins&&(t.margins.left=Math.max(t.paddingLeft,t.margins.left),t.margins.top=Math.max(t.paddingTop,t.margins.top),t.margins.right=Math.max(t.paddingRight,t.margins.right),t.margins.bottom=Math.max(t.paddingBottom,t.margins.bottom))},afterFit:function(){ct.callback(this.options.afterFit,[this])},isHorizontal:function(){var t=this.options.position;return"top"===t||"bottom"===t},isFullWidth:function(){return this.options.fullWidth},getRightValue:function(t){if(Ai(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},_convertTicksToLabels:function(t){var e,i,n,a=this;for(a.ticks=t.map(function(t){return t.value}),a.beforeTickToLabelConversion(),e=a.convertTicksToLabels(t)||a.ticks,a.afterTickToLabelConversion(),i=0,n=t.length;i<n;++i)t[i].label=e[i];return e},_getLabelSizes:function(){var t=this,e=t._labelSizes;return e||(t._labelSizes=e=Fi(t.ctx,zi(t.options.ticks),t.getTicks(),t.longestTextCache),t.longestLabelWidth=e.widest.width),e},_parseValue:function(t){var e,i,n,a;return Pi(t)?(e=+this.getRightValue(t[0]),i=+this.getRightValue(t[1]),n=Math.min(e,i),a=Math.max(e,i)):(e=void 0,i=t=+this.getRightValue(t),n=t,a=t),{min:n,max:a,start:e,end:i}},_getScaleLabel:function(t){var e=this._parseValue(t);return void 0!==e.start?"["+e.start+", "+e.end+"]":+this.getRightValue(t)},getLabelForIndex:ct.noop,getPixelForValue:ct.noop,getValueForPixel:ct.noop,getPixelForTick:function(t){var e=this.options.offset,i=this._ticks.length,n=1/Math.max(i-(e?0:1),1);return t<0||t>i-1?null:this.getPixelForDecimal(t*n+(e?n/2:0))},getPixelForDecimal:function(t){return this._reversePixels&&(t=1-t),this._startPixel+t*this._length},getDecimalForPixel:function(t){var e=(t-this._startPixel)/this._length;return this._reversePixels?1-e:e},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,a,r=this.options.ticks,o=this._length,s=r.maxTicksLimit||o/this._tickSize()+1,l=r.major.enabled?function(t){var e,i,n=[];for(e=0,i=t.length;e<i;e++)t[e].major&&n.push(e);return n}(t):[],u=l.length,d=l[0],h=l[u-1];if(u>s)return function(t,e,i){var n,a,r=0,o=e[0];for(i=Math.ceil(i),n=0;n<t.length;n++)a=t[n],n===o?(a._index=n,o=e[++r*i]):delete a.label}(t,l,u/s),Ni(t);if(n=function(t,e,i,n){var a,r,o,s,l=function(t){var e,i,n=t.length;if(n<2)return!1;for(i=t[0],e=1;e<n;++e)if(t[e]-t[e-1]!==i)return!1;return i}(t),u=(e.length-1)/n;if(!l)return Math.max(u,1);for(o=0,s=(a=ct.math._factorize(l)).length-1;o<s;o++)if((r=a[o])>u)return r;return Math.max(u,1)}(l,t,0,s),u>0){for(e=0,i=u-1;e<i;e++)Bi(t,n,l[e],l[e+1]);return a=u>1?(h-d)/(u-1):null,Bi(t,n,ct.isNullOrUndef(a)?0:d-a,d),Bi(t,n,h,ct.isNullOrUndef(a)?t.length:h+a),Ni(t)}return Bi(t,n),Ni(t)},_tickSize:function(){var t=this.options.ticks,e=ct.toRadians(this.labelRotation),i=Math.abs(Math.cos(e)),n=Math.abs(Math.sin(e)),a=this._getLabelSizes(),r=t.autoSkipPadding||0,o=a?a.widest.width+r:0,s=a?a.highest.height+r:0;return this.isHorizontal()?s*i>o*n?o/i:s/n:s*n<o*i?s/i:o/n},_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},_computeGridLineItems:function(t){var e,i,n,a,r,o,s,l,u,d,h,c,f,g,p,m,v,b=this,x=b.chart,y=b.options,_=y.gridLines,k=y.position,w=_.offsetGridLines,M=b.isHorizontal(),S=b._ticksToDraw,C=S.length+(w?1:0),P=Li(_),A=[],D=_.drawBorder?Ti(_.lineWidth,0,0):0,T=D/2,I=ct._alignPixel,F=function(t){return I(x,t,D)};for("top"===k?(e=F(b.bottom),s=b.bottom-P,u=e-T,h=F(t.top)+T,f=t.bottom):"bottom"===k?(e=F(b.top),h=t.top,f=F(t.bottom)-T,s=e+T,u=b.top+P):"left"===k?(e=F(b.right),o=b.right-P,l=e-T,d=F(t.left)+T,c=t.right):(e=F(b.left),d=t.left,c=F(t.right)-T,o=e+T,l=b.left+P),i=0;i<C;++i)n=S[i]||{},Ai(n.label)&&i<S.length||(i===b.zeroLineIndex&&y.offset===w?(g=_.zeroLineWidth,p=_.zeroLineColor,m=_.zeroLineBorderDash||[],v=_.zeroLineBorderDashOffset||0):(g=Ti(_.lineWidth,i,1),p=Ti(_.color,i,"rgba(0,0,0,0.1)"),m=_.borderDash||[],v=_.borderDashOffset||0),void 0!==(a=Ii(b,n._index||i,w))&&(r=I(x,a,g),M?o=l=d=c=r:s=u=h=f=r,A.push({tx1:o,ty1:s,tx2:l,ty2:u,x1:d,y1:h,x2:c,y2:f,width:g,color:p,borderDash:m,borderDashOffset:v})));return A.ticksLength=C,A.borderValue=e,A},_computeLabelItems:function(){var t,e,i,n,a,r,o,s,l,u,d,h,c=this,f=c.options,g=f.ticks,p=f.position,m=g.mirror,v=c.isHorizontal(),b=c._ticksToDraw,x=zi(g),y=g.padding,_=Li(f.gridLines),k=-ct.toRadians(c.labelRotation),w=[];for("top"===p?(r=c.bottom-_-y,o=k?"left":"center"):"bottom"===p?(r=c.top+_+y,o=k?"right":"center"):"left"===p?(a=c.right-(m?0:_)-y,o=m?"left":"right"):(a=c.left+(m?0:_)+y,o=m?"right":"left"),t=0,e=b.length;t<e;++t)n=(i=b[t]).label,Ai(n)||(s=c.getPixelForTick(i._index||t)+g.labelOffset,u=(l=i.major?x.major:x.minor).lineHeight,d=Pi(n)?n.length:1,v?(a=s,h="top"===p?((k?1:.5)-d)*u:(k?0:.5)*u):(r=s,h=(1-d)*u/2),w.push({x:a,y:r,rotation:k,label:n,font:l,textOffset:h,textAlign:o}));return w},_drawGrid:function(t){var e=this,i=e.options.gridLines;if(i.display){var n,a,r,o,s,l=e.ctx,u=e.chart,d=ct._alignPixel,h=i.drawBorder?Ti(i.lineWidth,0,0):0,c=e._gridLineItems||(e._gridLineItems=e._computeGridLineItems(t));for(r=0,o=c.length;r<o;++r)n=(s=c[r]).width,a=s.color,n&&a&&(l.save(),l.lineWidth=n,l.strokeStyle=a,l.setLineDash&&(l.setLineDash(s.borderDash),l.lineDashOffset=s.borderDashOffset),l.beginPath(),i.drawTicks&&(l.moveTo(s.tx1,s.ty1),l.lineTo(s.tx2,s.ty2)),i.drawOnChartArea&&(l.moveTo(s.x1,s.y1),l.lineTo(s.x2,s.y2)),l.stroke(),l.restore());if(h){var f,g,p,m,v=h,b=Ti(i.lineWidth,c.ticksLength-1,1),x=c.borderValue;e.isHorizontal()?(f=d(u,e.left,v)-v/2,g=d(u,e.right,b)+b/2,p=m=x):(p=d(u,e.top,v)-v/2,m=d(u,e.bottom,b)+b/2,f=g=x),l.lineWidth=h,l.strokeStyle=Ti(i.color,0),l.beginPath(),l.moveTo(f,p),l.lineTo(g,m),l.stroke()}}},_drawLabels:function(){var t=this;if(t.options.ticks.display){var e,i,n,a,r,o,s,l,u=t.ctx,d=t._labelItems||(t._labelItems=t._computeLabelItems());for(e=0,n=d.length;e<n;++e){if(o=(r=d[e]).font,u.save(),u.translate(r.x,r.y),u.rotate(r.rotation),u.font=o.string,u.fillStyle=o.color,u.textBaseline="middle",u.textAlign=r.textAlign,s=r.label,l=r.textOffset,Pi(s))for(i=0,a=s.length;i<a;++i)u.fillText(""+s[i],0,l),l+=o.lineHeight;else u.fillText(s,0,l);u.restore()}}},_drawTitle:function(){var t=this,e=t.ctx,i=t.options,n=i.scaleLabel;if(n.display){var a,r,o=Di(n.fontColor,st.global.defaultFontColor),s=ct.options._parseFont(n),l=ct.options.toPadding(n.padding),u=s.lineHeight/2,d=i.position,h=0;if(t.isHorizontal())a=t.left+t.width/2,r="bottom"===d?t.bottom-u-l.bottom:t.top+u+l.top;else{var c="left"===d;a=c?t.left+u+l.top:t.right-u-l.top,r=t.top+t.height/2,h=c?-.5*Math.PI:.5*Math.PI}e.save(),e.translate(a,r),e.rotate(h),e.textAlign="center",e.textBaseline="middle",e.fillStyle=o,e.font=s.string,e.fillText(n.labelString,0,0),e.restore()}},draw:function(t){this._isVisible()&&(this._drawGrid(t),this._drawTitle(),this._drawLabels())},_layers:function(){var t=this,e=t.options,i=e.ticks&&e.ticks.z||0,n=e.gridLines&&e.gridLines.z||0;return t._isVisible()&&i!==n&&t.draw===t._draw?[{z:n,draw:function(){t._drawGrid.apply(t,arguments),t._drawTitle.apply(t,arguments)}},{z:i,draw:function(){t._drawLabels.apply(t,arguments)}}]:[{z:i,draw:function(){t.draw.apply(t,arguments)}}]},_getMatchingVisibleMetas:function(t){var e=this,i=e.isHorizontal();return e.chart._getSortedVisibleDatasetMetas().filter(function(n){return(!t||n.type===t)&&(i?n.xAxisID===e.id:n.yAxisID===e.id)})}});Ei.prototype._draw=Ei.prototype.draw;var Vi=Ei,Wi=ct.isNullOrUndef,Hi=Vi.extend({determineDataLimits:function(){var t,e=this,i=e._getLabels(),n=e.options.ticks,a=n.min,r=n.max,o=0,s=i.length-1;void 0!==a&&(t=i.indexOf(a))>=0&&(o=t),void 0!==r&&(t=i.indexOf(r))>=0&&(s=t),e.minIndex=o,e.maxIndex=s,e.min=i[o],e.max=i[s]},buildTicks:function(){var t=this._getLabels(),e=this.minIndex,i=this.maxIndex;this.ticks=0===e&&i===t.length-1?t:t.slice(e,i+1)},getLabelForIndex:function(t,e){var i=this.chart;return i.getDatasetMeta(e).controller._getValueScaleId()===this.id?this.getRightValue(i.data.datasets[e].data[t]):this._getLabels()[t]},_configure:function(){var t=this,e=t.options.offset,i=t.ticks;Vi.prototype._configure.call(t),t.isHorizontal()||(t._reversePixels=!t._reversePixels),i&&(t._startValue=t.minIndex-(e?.5:0),t._valueRange=Math.max(i.length-(e?0:1),1))},getPixelForValue:function(t,e,i){var n,a,r,o=this;return Wi(e)||Wi(i)||(t=o.chart.data.datasets[i].data[e]),Wi(t)||(n=o.isHorizontal()?t.x:t.y),(void 0!==n||void 0!==t&&isNaN(e))&&(a=o._getLabels(),t=ct.valueOrDefault(n,t),e=-1!==(r=a.indexOf(t))?r:e,isNaN(e)&&(e=t)),o.getPixelForDecimal((e-o._startValue)/o._valueRange)},getPixelForTick:function(t){var e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t],t+this.minIndex)},getValueForPixel:function(t){var e=Math.round(this._startValue+this.getDecimalForPixel(t)*this._valueRange);return Math.min(Math.max(e,0),this.ticks.length-1)},getBasePixel:function(){return this.bottom}}),ji={position:"bottom"};Hi._defaults=ji;var qi=ct.noop,Ui=ct.isNullOrUndef;var Yi=Vi.extend({getRightValue:function(t){return"string"==typeof t?+t:Vi.prototype.getRightValue.call(this,t)},handleTickRangeOptions:function(){var t=this,e=t.options.ticks;if(e.beginAtZero){var i=ct.sign(t.min),n=ct.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:qi,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:ct.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,p=ct.niceNum((g-f)/u/l)*l;if(p<1e-14&&Ui(d)&&Ui(h))return[f,g];(r=Math.ceil(g/p)-Math.floor(f/p))>u&&(p=ct.niceNum(r*p/u/l)*l),s||Ui(c)?i=Math.pow(10,ct._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&&(!Ui(d)&&ct.almostWhole(d/p,p/1e3)&&(n=d),!Ui(h)&&ct.almostWhole(h/p,p/1e3)&&(a=h)),r=(a-n)/p,r=ct.almostEquals(r,Math.round(r),p/1e3)?Math.round(r):Math.ceil(r),n=Math.round(n*i)/i,a=Math.round(a*i)/i,o.push(Ui(d)?n:d);for(var m=1;m<r;++m)o.push(Math.round((n+m*p)*i)/i);return o.push(Ui(h)?a:h),o}(n,t);t.handleDirectionalChanges(),t.max=ct.max(a),t.min=ct.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),Vi.prototype.convertTicksToLabels.call(t)},_configure:function(){var t,e=this,i=e.getTicks(),n=e.min,a=e.max;Vi.prototype._configure.call(e),e.options.offset&&i.length&&(n-=t=(a-n)/Math.max(i.length-1,1)/2,a+=t),e._startValue=n,e._endValue=a,e._valueRange=a-n}}),Gi={position:"left",ticks:{callback:Ci.formatters.linear}};function Xi(t,e,i,n){var a,r,o=t.options,s=function(t,e,i){var n=[i.type,void 0===e&&void 0===i.stack?i.index:"",i.stack].join(".");return void 0===t[n]&&(t[n]={pos:[],neg:[]}),t[n]}(e,o.stacked,i),l=s.pos,u=s.neg,d=n.length;for(a=0;a<d;++a)r=t._parseValue(n[a]),isNaN(r.min)||isNaN(r.max)||i.data[a].hidden||(l[a]=l[a]||0,u[a]=u[a]||0,o.relativePoints?l[a]=100:r.min<0||r.max<0?u[a]+=r.min:l[a]+=r.max)}function Ki(t,e,i){var n,a,r=i.length;for(n=0;n<r;++n)a=t._parseValue(i[n]),isNaN(a.min)||isNaN(a.max)||e.data[n].hidden||(t.min=Math.min(t.min,a.min),t.max=Math.max(t.max,a.max))}var Zi=Yi.extend({determineDataLimits:function(){var t,e,i,n,a=this,r=a.options,o=a.chart.data.datasets,s=a._getMatchingVisibleMetas(),l=r.stacked,u={},d=s.length;if(a.min=Number.POSITIVE_INFINITY,a.max=Number.NEGATIVE_INFINITY,void 0===l)for(t=0;!l&&t<d;++t)l=void 0!==(e=s[t]).stack;for(t=0;t<d;++t)i=o[(e=s[t]).index].data,l?Xi(a,u,e,i):Ki(a,e,i);ct.each(u,function(t){n=t.pos.concat(t.neg),a.min=Math.min(a.min,ct.min(n)),a.max=Math.max(a.max,ct.max(n))}),a.min=ct.isFinite(a.min)&&!isNaN(a.min)?a.min:0,a.max=ct.isFinite(a.max)&&!isNaN(a.max)?a.max:1,a.handleTickRangeOptions()},_computeTickLimit:function(){var t;return this.isHorizontal()?Math.ceil(this.width/40):(t=ct.options._parseFont(this.options.ticks),Math.ceil(this.height/t.lineHeight))},handleDirectionalChanges:function(){this.isHorizontal()||this.ticks.reverse()},getLabelForIndex:function(t,e){return this._getScaleLabel(this.chart.data.datasets[e].data[t])},getPixelForValue:function(t){return this.getPixelForDecimal((+this.getRightValue(t)-this._startValue)/this._valueRange)},getValueForPixel:function(t){return this._startValue+this.getDecimalForPixel(t)*this._valueRange},getPixelForTick:function(t){var e=this.ticksAsNumbers;return t<0||t>e.length-1?null:this.getPixelForValue(e[t])}}),$i=Gi;Zi._defaults=$i;var Ji=ct.valueOrDefault,Qi=ct.math.log10;var tn={position:"left",ticks:{callback:Ci.formatters.logarithmic}};function en(t,e){return ct.isFinite(t)&&t>=0?t:e}var nn=Vi.extend({determineDataLimits:function(){var t,e,i,n,a,r,o=this,s=o.options,l=o.chart,u=l.data.datasets,d=o.isHorizontal();function h(t){return d?t.xAxisID===o.id:t.yAxisID===o.id}o.min=Number.POSITIVE_INFINITY,o.max=Number.NEGATIVE_INFINITY,o.minNotZero=Number.POSITIVE_INFINITY;var c=s.stacked;if(void 0===c)for(t=0;t<u.length;t++)if(e=l.getDatasetMeta(t),l.isDatasetVisible(t)&&h(e)&&void 0!==e.stack){c=!0;break}if(s.stacked||c){var f={};for(t=0;t<u.length;t++){var g=[(e=l.getDatasetMeta(t)).type,void 0===s.stacked&&void 0===e.stack?t:"",e.stack].join(".");if(l.isDatasetVisible(t)&&h(e))for(void 0===f[g]&&(f[g]=[]),a=0,r=(n=u[t].data).length;a<r;a++){var p=f[g];i=o._parseValue(n[a]),isNaN(i.min)||isNaN(i.max)||e.data[a].hidden||i.min<0||i.max<0||(p[a]=p[a]||0,p[a]+=i.max)}}ct.each(f,function(t){if(t.length>0){var e=ct.min(t),i=ct.max(t);o.min=Math.min(o.min,e),o.max=Math.max(o.max,i)}})}else for(t=0;t<u.length;t++)if(e=l.getDatasetMeta(t),l.isDatasetVisible(t)&&h(e))for(a=0,r=(n=u[t].data).length;a<r;a++)i=o._parseValue(n[a]),isNaN(i.min)||isNaN(i.max)||e.data[a].hidden||i.min<0||i.max<0||(o.min=Math.min(i.min,o.min),o.max=Math.max(i.max,o.max),0!==i.min&&(o.minNotZero=Math.min(i.min,o.minNotZero)));o.min=ct.isFinite(o.min)?o.min:null,o.max=ct.isFinite(o.max)?o.max:null,o.minNotZero=ct.isFinite(o.minNotZero)?o.minNotZero:null,this.handleTickRangeOptions()},handleTickRangeOptions:function(){var t=this,e=t.options.ticks;t.min=en(e.min,t.min),t.max=en(e.max,t.max),t.min===t.max&&(0!==t.min&&null!==t.min?(t.min=Math.pow(10,Math.floor(Qi(t.min))-1),t.max=Math.pow(10,Math.floor(Qi(t.max))+1)):(t.min=1,t.max=10)),null===t.min&&(t.min=Math.pow(10,Math.floor(Qi(t.max))-1)),null===t.max&&(t.max=0!==t.min?Math.pow(10,Math.floor(Qi(t.min))+1):10),null===t.minNotZero&&(t.min>0?t.minNotZero=t.min:t.max<1?t.minNotZero=Math.pow(10,Math.floor(Qi(t.max))):t.minNotZero=1)},buildTicks:function(){var t=this,e=t.options.ticks,i=!t.isHorizontal(),n={min:en(e.min),max:en(e.max)},a=t.ticks=function(t,e){var i,n,a=[],r=Ji(t.min,Math.pow(10,Math.floor(Qi(e.min)))),o=Math.floor(Qi(e.max)),s=Math.ceil(e.max/Math.pow(10,o));0===r?(i=Math.floor(Qi(e.minNotZero)),n=Math.floor(e.minNotZero/Math.pow(10,i)),a.push(r),r=n*Math.pow(10,i)):(i=Math.floor(Qi(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=Ji(t.max,r);return a.push(u),a}(n,t);t.max=ct.max(a),t.min=ct.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(),Vi.prototype.convertTicksToLabels.call(this)},getLabelForIndex:function(t,e){return this._getScaleLabel(this.chart.data.datasets[e].data[t])},getPixelForTick:function(t){var e=this.tickValues;return t<0||t>e.length-1?null:this.getPixelForValue(e[t])},_getFirstTickValue:function(t){var e=Math.floor(Qi(t));return Math.floor(t/Math.pow(10,e))*Math.pow(10,e)},_configure:function(){var t=this,e=t.min,i=0;Vi.prototype._configure.call(t),0===e&&(e=t._getFirstTickValue(t.minNotZero),i=Ji(t.options.ticks.fontSize,st.global.defaultFontSize)/t._length),t._startValue=Qi(e),t._valueOffset=i,t._valueRange=(Qi(t.max)-Qi(e))/(1-i)},getPixelForValue:function(t){var e=this,i=0;return(t=+e.getRightValue(t))>e.min&&t>0&&(i=(Qi(t)-e._startValue)/e._valueRange+e._valueOffset),e.getPixelForDecimal(i)},getValueForPixel:function(t){var e=this,i=e.getDecimalForPixel(t);return 0===i&&0===e.min?0:Math.pow(10,e._startValue+(i-e._valueOffset)*e._valueRange)}}),an=tn;nn._defaults=an;var rn=ct.valueOrDefault,on=ct.valueAtIndexOrDefault,sn=ct.options.resolve,ln={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:Ci.formatters.linear},pointLabels:{display:!0,fontSize:10,callback:function(t){return t}}};function un(t){var e=t.ticks;return e.display&&t.display?rn(e.fontSize,st.global.defaultFontSize)+2*e.backdropPaddingY:0}function dn(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 hn(t){return 0===t||180===t?"center":t<180?"left":"right"}function cn(t,e,i,n){var a,r,o=i.y+n/2;if(ct.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 fn(t,e,i){90===t||270===t?i.y-=e.h/2:(t>270||t<90)&&(i.y-=e.h)}function gn(t){return ct.isNumber(t)?t:0}var pn=Yi.extend({setDimensions:function(){var t=this;t.width=t.maxWidth,t.height=t.maxHeight,t.paddingTop=un(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;ct.each(e.data.datasets,function(a,r){if(e.isDatasetVisible(r)){var o=e.getDatasetMeta(r);ct.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/un(this.options))},convertTicksToLabels:function(){var t=this;Yi.prototype.convertTicksToLabels.call(t),t.pointLabels=t.chart.data.labels.map(function(){var e=ct.callback(t.options.pointLabels.callback,arguments,t);return e||0===e?e:""})},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=ct.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=t.chart.data.labels.length;for(e=0;e<d;e++){n=t.getPointPosition(e,t.drawingArea+5),s=t.ctx,l=a.lineHeight,u=t.pointLabels[e],i=ct.isArray(u)?{w:ct.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=ct.toDegrees(h)%360,f=dn(c,n.x,i.w,0,180),g=dn(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=gn(a),r=gn(r),o=gn(o),s=gn(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){var e=this.chart,i=(t*(360/e.data.labels.length)+((e.options||{}).startAngle||0))%360;return(i<0?i+360:i)*Math.PI*2/360},getDistanceFromCenterForValue:function(t){var e=this;if(ct.isNullOrUndef(t))return NaN;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(t){var e=this.min,i=this.max;return this.getPointPositionForValue(t||0,this.beginAtZero?0:e<0&&i<0?i:e>0&&i>0?e:0)},_drawGrid:function(){var t,e,i,n=this,a=n.ctx,r=n.options,o=r.gridLines,s=r.angleLines,l=rn(s.lineWidth,o.lineWidth),u=rn(s.color,o.color);if(r.pointLabels.display&&function(t){var e=t.ctx,i=t.options,n=i.pointLabels,a=un(i),r=t.getDistanceFromCenterForValue(i.ticks.reverse?t.min:t.max),o=ct.options._parseFont(n);e.save(),e.font=o.string,e.textBaseline="middle";for(var s=t.chart.data.labels.length-1;s>=0;s--){var l=0===s?a/2:0,u=t.getPointPosition(s,r+l+5),d=on(n.fontColor,s,st.global.defaultFontColor);e.fillStyle=d;var h=t.getIndexAngle(s),c=ct.toDegrees(h);e.textAlign=hn(c),fn(c,t._pointLabelSizes[s],u),cn(e,t.pointLabels[s],u,o.lineHeight)}e.restore()}(n),o.display&&ct.each(n.ticks,function(t,i){0!==i&&(e=n.getDistanceFromCenterForValue(n.ticksAsNumbers[i]),function(t,e,i,n){var a,r=t.ctx,o=e.circular,s=t.chart.data.labels.length,l=on(e.color,n-1),u=on(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()}}(n,o,e,i))}),s.display&&l&&u){for(a.save(),a.lineWidth=l,a.strokeStyle=u,a.setLineDash&&(a.setLineDash(sn([s.borderDash,o.borderDash,[]])),a.lineDashOffset=sn([s.borderDashOffset,o.borderDashOffset,0])),t=n.chart.data.labels.length-1;t>=0;t--)e=n.getDistanceFromCenterForValue(r.ticks.reverse?n.min:n.max),i=n.getPointPosition(t,e),a.beginPath(),a.moveTo(n.xCenter,n.yCenter),a.lineTo(i.x,i.y),a.stroke();a.restore()}},_drawLabels:function(){var t=this,e=t.ctx,i=t.options.ticks;if(i.display){var n,a,r=t.getIndexAngle(0),o=ct.options._parseFont(i),s=rn(i.fontColor,st.global.defaultFontColor);e.save(),e.font=o.string,e.translate(t.xCenter,t.yCenter),e.rotate(r),e.textAlign="center",e.textBaseline="middle",ct.each(t.ticks,function(r,l){(0!==l||i.reverse)&&(n=t.getDistanceFromCenterForValue(t.ticksAsNumbers[l]),i.showLabelBackdrop&&(a=e.measureText(r).width,e.fillStyle=i.backdropColor,e.fillRect(-a/2-i.backdropPaddingX,-n-o.size/2-i.backdropPaddingY,a+2*i.backdropPaddingX,o.size+2*i.backdropPaddingY)),e.fillStyle=s,e.fillText(r,0,-n))}),e.restore()}},_drawTitle:ct.noop}),mn=ln;pn._defaults=mn;var vn=ct._deprecated,bn=ct.options.resolve,xn=ct.valueOrDefault,yn=Number.MIN_SAFE_INTEGER||-9007199254740991,_n=Number.MAX_SAFE_INTEGER||9007199254740991,kn={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},wn=Object.keys(kn);function Mn(t,e){return t-e}function Sn(t){return ct.valueOrDefault(t.time.min,t.ticks.min)}function Cn(t){return ct.valueOrDefault(t.time.max,t.ticks.max)}function Pn(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 An(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)),ct.isFinite(o)||(o="string"==typeof r?i.parse(o,r):i.parse(o)),null!==o?+o:(a||"function"!=typeof r||(o=r(e),ct.isFinite(o)||(o=i.parse(o))),o)}function Dn(t,e){if(ct.isNullOrUndef(e))return null;var i=t.options.time,n=An(t,t.getRightValue(e));return null===n?n:(i.round&&(n=+t._adapter.startOf(n,i.round)),n)}function Tn(t,e,i,n){var a,r,o,s=wn.length;for(a=wn.indexOf(t);a<s-1;++a)if(o=(r=kn[wn[a]]).steps?r.steps:_n,r.common&&Math.ceil((i-e)/(o*r.size))<=n)return wn[a];return wn[s-1]}function In(t,e,i){var n,a,r=[],o={},s=e.length;for(n=0;n<s;++n)o[a=e[n]]=n,r.push({value:a,major:!1});return 0!==s&&i?function(t,e,i,n){var a,r,o=t._adapter,s=+o.startOf(e[0].value,n),l=e[e.length-1].value;for(a=s;a<=l;a=+o.add(a,1,n))(r=i[a])>=0&&(e[r].major=!0);return e}(t,r,o,i):r}var Fn=Vi.extend({initialize:function(){this.mergeTicksOptions(),Vi.prototype.initialize.call(this)},update:function(){var t=this,e=t.options,i=e.time||(e.time={}),n=t._adapter=new Si._date(e.adapters.date);return vn("time scale",i.format,"time.format","time.parser"),vn("time scale",i.min,"time.min","ticks.min"),vn("time scale",i.max,"time.max","ticks.max"),ct.mergeIf(i.displayFormats,n.formats()),Vi.prototype.update.apply(t,arguments)},getRightValue:function(t){return t&&void 0!==t.t&&(t=t.t),Vi.prototype.getRightValue.call(this,t)},determineDataLimits:function(){var t,e,i,n,a,r,o,s=this,l=s.chart,u=s._adapter,d=s.options,h=d.time.unit||"day",c=_n,f=yn,g=[],p=[],m=[],v=s._getLabels();for(t=0,i=v.length;t<i;++t)m.push(Dn(s,v[t]));for(t=0,i=(l.data.datasets||[]).length;t<i;++t)if(l.isDatasetVisible(t))if(a=l.data.datasets[t].data,ct.isObject(a[0]))for(p[t]=[],e=0,n=a.length;e<n;++e)r=Dn(s,a[e]),g.push(r),p[t][e]=r;else p[t]=m.slice(0),o||(g=g.concat(m),o=!0);else p[t]=[];m.length&&(c=Math.min(c,m[0]),f=Math.max(f,m[m.length-1])),g.length&&(g=i>1?function(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}(g).sort(Mn):g.sort(Mn),c=Math.min(c,g[0]),f=Math.max(f,g[g.length-1])),c=Dn(s,Sn(d))||c,f=Dn(s,Cn(d))||f,c=c===_n?+u.startOf(Date.now(),h):c,f=f===yn?+u.endOf(Date.now(),h)+1:f,s.min=Math.min(c,f),s.max=Math.max(c+1,f),s._table=[],s._timestamps={data:g,datasets:p,labels:m}},buildTicks:function(){var t,e,i,n=this,a=n.min,r=n.max,o=n.options,s=o.ticks,l=o.time,u=n._timestamps,d=[],h=n.getLabelCapacity(a),c=s.source,f=o.distribution;for(u="data"===c||"auto"===c&&"series"===f?u.data:"labels"===c?u.labels:function(t,e,i,n){var a,r=t._adapter,o=t.options,s=o.time,l=s.unit||Tn(s.minUnit,e,i,n),u=bn([s.stepSize,s.unitStepSize,1]),d="week"===l&&s.isoWeekday,h=e,c=[];if(d&&(h=+r.startOf(h,"isoWeek",d)),h=+r.startOf(h,d?"day":l),r.diff(i,e,l)>1e5*u)throw e+" and "+i+" are too far apart with stepSize of "+u+" "+l;for(a=h;a<i;a=+r.add(a,u,l))c.push(a);return a!==i&&"ticks"!==o.bounds||c.push(a),c}(n,a,r,h),"ticks"===o.bounds&&u.length&&(a=u[0],r=u[u.length-1]),a=Dn(n,Sn(o))||a,r=Dn(n,Cn(o))||r,t=0,e=u.length;t<e;++t)(i=u[t])>=a&&i<=r&&d.push(i);return n.min=a,n.max=r,n._unit=l.unit||(s.autoSkip?Tn(l.minUnit,n.min,n.max,h):function(t,e,i,n,a){var r,o;for(r=wn.length-1;r>=wn.indexOf(i);r--)if(o=wn[r],kn[o].common&&t._adapter.diff(a,n,o)>=e-1)return o;return wn[i?wn.indexOf(i):0]}(n,d.length,l.minUnit,n.min,n.max)),n._majorUnit=s.major.enabled&&"year"!==n._unit?function(t){for(var e=wn.indexOf(t)+1,i=wn.length;e<i;++e)if(kn[wn[e]].common)return wn[e]}(n._unit):void 0,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,f),n._offsets=function(t,e,i,n,a){var r,o,s=0,l=0;return a.offset&&e.length&&(r=Pn(t,"time",e[0],"pos"),s=1===e.length?1-r:(Pn(t,"time",e[1],"pos")-r)/2,o=Pn(t,"time",e[e.length-1],"pos"),l=1===e.length?o:(o-Pn(t,"time",e[e.length-2],"pos"))/2),{start:s,end:l,factor:1/(s+1+l)}}(n._table,d,0,0,o),s.reverse&&d.reverse(),In(n,d,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 ct.isObject(s)&&(o=i.getRightValue(s)),r.tooltipFormat?n.format(An(i,o),r.tooltipFormat):"string"==typeof o?o:n.format(An(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=i[e],h=r.ticks,c=l&&u&&d&&d.major,f=a.format(t,n||(c?u:s)),g=c?h.major:h.minor,p=bn([g.callback,g.userCallback,h.callback,h.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._offsets,i=Pn(this._table,"time",t,"pos");return this.getPixelForDecimal((e.start+i)*e.factor)},getPixelForValue:function(t,e,i){var n=null;if(void 0!==e&&void 0!==i&&(n=this._timestamps.datasets[i][e]),null===n&&(n=Dn(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._offsets,i=this.getDecimalForPixel(t)/e.factor-e.end,n=Pn(this._table,"pos",i,"time");return this._adapter._create(n)},_getLabelSize:function(t){var e=this.options.ticks,i=this.ctx.measureText(t).width,n=ct.toRadians(this.isHorizontal()?e.maxRotation:e.minRotation),a=Math.cos(n),r=Math.sin(n),o=xn(e.fontSize,st.global.defaultFontSize);return{w:i*a+o*r,h:i*r+o*a}},getLabelWidth:function(t){return this._getLabelSize(t).w},getLabelCapacity:function(t){var e=this,i=e.options.time,n=i.displayFormats,a=n[i.unit]||n.millisecond,r=e.tickFormatFunction(t,0,In(e,[t],e._majorUnit),a),o=e._getLabelSize(r),s=Math.floor(e.isHorizontal()?e.width/o.w:e.height/o.h);return e.options.offset&&s--,s>0?s:1}}),Ln={position:"bottom",distribution:"linear",bounds:"data",adapters:{},time:{parser:!1,unit:!1,round:!1,displayFormat:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{autoSkip:!1,source:"auto",major:{enabled:!1}}};Fn._defaults=Ln;var On={category:Hi,linear:Zi,logarithmic:nn,radialLinear:pn,time:Fn},Rn={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 Rn},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(e).diff(t(i),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 zn={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 ct.isArray(e)?function(t,i){return e[i]}:function(t){return{x:null===i?t.x:i,y:null===n?t.y:n}}}};function Nn(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 Bn(t){return(t.el._scale||{}).getPointPositionForValue?function(t){var e,i,n,a,r,o=t.el._scale,s=o.options,l=o.chart.data.labels.length,u=t.fill,d=[];if(!l)return null;for(e=s.ticks.reverse?o.max:o.min,i=s.ticks.reverse?o.min:o.max,n=o.getPointPositionForValue(0,e),a=0;a<l;++a)r="start"===u||"end"===u?o.getPointPositionForValue(a,"start"===u?e:i):o.getBasePosition(a),s.gridLines.circular&&(r.cx=n.x,r.cy=n.y,r.angle=o.getIndexAngle(a)-Math.PI/2),d.push(r);return d}(t):function(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.getBasePixel&&(r=n.getBasePixel()),null!=r){if(void 0!==r.x&&void 0!==r.y)return r;if(ct.isFinite(r))return{x:(e=n.isHorizontal())?r:null,y:e?null:r}}return null}(t)}function En(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 Vn(t){var e=t.fill,i="dataset";return!1===e?null:(isFinite(e)||(i="boundary"),zn[i](t))}function Wn(t){return t&&!t.skip}function Hn(t,e,i,n,a){var r,o,s,l;if(n&&a){for(t.moveTo(e[0].x,e[0].y),r=1;r<n;++r)ct.canvas.lineTo(t,e[r-1],e[r]);if(void 0===i[0].angle)for(t.lineTo(i[a-1].x,i[a-1].y),r=a-1;r>0;--r)ct.canvas.lineTo(t,i[r],i[r-1],!0);else for(o=i[0].cx,s=i[0].cy,l=Math.sqrt(Math.pow(i[0].x-o,2)+Math.pow(i[0].y-s,2)),r=a-1;r>0;--r)t.arc(o,s,l,i[r].angle,i[r-1].angle,!0)}}function jn(t,e,i,n,a,r){var o,s,l,u,d,h,c,f,g=e.length,p=n.spanGaps,m=[],v=[],b=0,x=0;for(t.beginPath(),o=0,s=g;o<s;++o)d=i(u=e[l=o%g]._view,l,n),h=Wn(u),c=Wn(d),r&&void 0===f&&h&&(s=g+(f=o+1)),h&&c?(b=m.push(u),x=v.push(d)):b&&x&&(p?(h&&m.push(u),c&&v.push(d)):(Hn(t,m,v,b,x),b=x=0,m=[],v=[]));Hn(t,m,v,b,x),t.closePath(),t.fillStyle=a,t.fill()}var qn={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 Yt.Line&&(r={visible:t.isDatasetVisible(n),fill:Nn(a,n,o),chart:t,el:a}),i.$filler=r,l.push(r);for(n=0;n<o;++n)(r=l[n])&&(r.fill=En(l,n,s),r.boundary=Bn(r),r.mapper=Vn(r))},beforeDatasetsDraw:function(t){var e,i,n,a,r,o,s,l=t._getSortedVisibleDatasetMetas(),u=t.ctx;for(i=l.length-1;i>=0;--i)(e=l[i].$filler)&&e.visible&&(a=(n=e.el)._view,r=n._children||[],o=e.mapper,s=a.backgroundColor||st.global.defaultColor,o&&s&&r.length&&(ct.canvas.clipArea(u,t.chartArea),jn(u,r,o,a,s,n._loop),ct.canvas.unclipArea(u)))}},Un=ct.rtl.getRtlAdapter,Yn=ct.noop,Gn=ct.valueOrDefault;function Xn(t,e){return t.usePointStyle&&t.boxWidth>e?e:t.boxWidth}st._set("global",{legend:{display:!0,position:"top",align:"center",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.datasets,i=t.options.legend||{},n=i.labels&&i.labels.usePointStyle;return t._getSortedDatasetMetas().map(function(i,a){var r=i.controller.getStyle(n?0:void 0);return{text:e[i.index].label,fillStyle:r.backgroundColor,hidden:!t.isDatasetVisible(a),lineCap:r.borderCapStyle,lineDash:r.borderDash,lineDashOffset:r.borderDashOffset,lineJoin:r.borderJoinStyle,lineWidth:r.borderWidth,strokeStyle:r.borderColor,pointStyle:r.pointStyle,rotation:r.rotation,datasetIndex:a}},this)}}},legendCallback:function(t){var e,i,n,a=document.createElement("ul"),r=t.data.datasets;for(a.setAttribute("class",t.id+"-legend"),e=0,i=r.length;e<i;e++)(n=a.appendChild(document.createElement("li"))).appendChild(document.createElement("span")).style.backgroundColor=r[e].backgroundColor,r[e].label&&n.appendChild(document.createTextNode(r[e].label));return a.outerHTML}});var Kn=xt.extend({initialize:function(t){ct.extend(this,t),this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1},beforeUpdate:Yn,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:Yn,beforeSetDimensions:Yn,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:Yn,beforeBuildLabels:Yn,buildLabels:function(){var t=this,e=t.options.labels||{},i=ct.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:Yn,beforeFit:Yn,fit:function(){var t=this,e=t.options,i=e.labels,n=e.display,a=t.ctx,r=ct.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="middle",ct.each(t.legendItems,function(t,e){var n=Xn(i,o)+o/2+a.measureText(t.text).width;(0===e||d[d.length-1]+n+2*i.padding>l.width)&&(h+=o+i.padding,d[d.length-(e>0?0:1)]=0),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=t.columnHeights=[],p=i.padding,m=0,v=0;ct.each(t.legendItems,function(t,e){var n=Xn(i,o)+o/2+a.measureText(t.text).width;e>0&&v+o+2*c>l.height&&(p+=m+i.padding,f.push(m),g.push(v),m=0,v=0),m=Math.max(m,n),v+=o+c,s[e]={left:0,top:0,width:n,height:o}}),p+=m,f.push(m),g.push(v),l.width+=p}t.width=l.width,t.height=l.height}else t.width=l.width=t.height=l.height=0},afterFit:Yn,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,r=n.elements.line,o=t.height,s=t.columnHeights,l=t.width,u=t.lineWidths;if(e.display){var d,h=Un(e.rtl,t.left,t.minSize.width),c=t.ctx,f=Gn(i.fontColor,n.defaultFontColor),g=ct.options._parseFont(i),p=g.size;c.textAlign=h.textAlign("left"),c.textBaseline="middle",c.lineWidth=.5,c.strokeStyle=f,c.fillStyle=f,c.font=g.string;var m=Xn(i,p),v=t.legendHitBoxes,b=function(t,n){switch(e.align){case"start":return i.padding;case"end":return t-n;default:return(t-n+i.padding)/2}},x=t.isHorizontal();d=x?{x:t.left+b(l,u[0]),y:t.top+i.padding,line:0}:{x:t.left+i.padding,y:t.top+b(o,s[0]),line:0},ct.rtl.overrideTextDirection(t.ctx,e.textDirection);var y=p+i.padding;ct.each(t.legendItems,function(e,n){var f=c.measureText(e.text).width,g=m+p/2+f,_=d.x,k=d.y;h.setWidth(t.minSize.width),x?n>0&&_+g+i.padding>t.left+t.minSize.width&&(k=d.y+=y,d.line++,_=d.x=t.left+b(l,u[d.line])):n>0&&k+y>t.top+t.minSize.height&&(_=d.x=_+t.columnWidths[d.line]+i.padding,d.line++,k=d.y=t.top+b(o,s[d.line]));var w=h.x(_);!function(t,e,n){if(!(isNaN(m)||m<=0)){c.save();var o=Gn(n.lineWidth,r.borderWidth);if(c.fillStyle=Gn(n.fillStyle,a),c.lineCap=Gn(n.lineCap,r.borderCapStyle),c.lineDashOffset=Gn(n.lineDashOffset,r.borderDashOffset),c.lineJoin=Gn(n.lineJoin,r.borderJoinStyle),c.lineWidth=o,c.strokeStyle=Gn(n.strokeStyle,a),c.setLineDash&&c.setLineDash(Gn(n.lineDash,r.borderDash)),i&&i.usePointStyle){var s=m*Math.SQRT2/2,l=h.xPlus(t,m/2),u=e+p/2;ct.canvas.drawPoint(c,n.pointStyle,s,l,u,n.rotation)}else c.fillRect(h.leftForLtr(t,m),e,m,p),0!==o&&c.strokeRect(h.leftForLtr(t,m),e,m,p);c.restore()}}(w,k,e),v[n].left=h.leftForLtr(w,v[n].width),v[n].top=k,function(t,e,i,n){var a=p/2,r=h.xPlus(t,m+a),o=e+a;c.fillText(i.text,r,o),i.hidden&&(c.beginPath(),c.lineWidth=2,c.moveTo(r,o),c.lineTo(h.xPlus(r,n),o),c.stroke())}(w,k,e,f),x?d.x+=g+i.padding:d.y+=y}),ct.rtl.restoreTextDirection(t.ctx,e.textDirection)}},_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 Zn(t,e){var i=new Kn({ctx:t.ctx,options:e,chart:t});Re.configure(t,i,e),Re.addBox(t,i),t.legend=i}var $n={id:"legend",_element:Kn,beforeInit:function(t){var e=t.options.legend;e&&Zn(t,e)},beforeUpdate:function(t){var e=t.options.legend,i=t.legend;e?(ct.mergeIf(e,st.global.legend),i?(Re.configure(t,i,e),i.options=e):Zn(t,e)):i&&(Re.removeBox(t,i),delete t.legend)},afterEvent:function(t,e){var i=t.legend;i&&i.handleEvent(e)}},Jn=ct.noop;st._set("global",{title:{display:!1,fontStyle:"bold",fullWidth:!0,padding:10,position:"top",text:"",weight:2e3}});var Qn=xt.extend({initialize:function(t){ct.extend(this,t),this.legendHitBoxes=[]},beforeUpdate:Jn,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:Jn,beforeSetDimensions:Jn,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:Jn,beforeBuildLabels:Jn,buildLabels:Jn,afterBuildLabels:Jn,beforeFit:Jn,fit:function(){var t,e=this,i=e.options,n=e.minSize={},a=e.isHorizontal();i.display?(t=(ct.isArray(i.text)?i.text.length:1)*ct.options._parseFont(i).lineHeight+2*i.padding,e.width=n.width=a?e.maxWidth:t,e.height=n.height=a?t:e.maxHeight):e.width=n.width=e.height=n.height=0},afterFit:Jn,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=ct.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=ct.valueOrDefault(i.fontColor,st.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(ct.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 ta(t,e){var i=new Qn({ctx:t.ctx,options:e,chart:t});Re.configure(t,i,e),Re.addBox(t,i),t.titleBlock=i}var ea={},ia=qn,na=$n,aa={id:"title",_element:Qn,beforeInit:function(t){var e=t.options.title;e&&ta(t,e)},beforeUpdate:function(t){var e=t.options.title,i=t.titleBlock;e?(ct.mergeIf(e,st.global.title),i?(Re.configure(t,i,e),i.options=e):ta(t,e)):i&&(Re.removeBox(t,i),delete t.titleBlock)}};for(var ra in ea.filler=ia,ea.legend=na,ea.title=aa,ki.helpers=ct,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=ct._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"}ct.where=function(t,e){if(ct.isArray(t)&&Array.prototype.filter)return t.filter(e);var i=[];return ct.each(t,function(t){e(t)&&i.push(t)}),i},ct.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},ct.findNextWhere=function(t,e,i){ct.isNullOrUndef(i)&&(i=-1);for(var n=i+1;n<t.length;n++){var a=t[n];if(e(a))return a}},ct.findPreviousWhere=function(t,e,i){ct.isNullOrUndef(i)&&(i=t.length);for(var n=i-1;n>=0;n--){var a=t[n];if(e(a))return a}},ct.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},ct.almostEquals=function(t,e,i){return Math.abs(t-e)<i},ct.almostWhole=function(t,e){var i=Math.round(t);return i-e<=t&&i+e>=t},ct.max=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.max(t,e)},Number.NEGATIVE_INFINITY)},ct.min=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.min(t,e)},Number.POSITIVE_INFINITY)},ct.sign=Math.sign?function(t){return Math.sign(t)}:function(t){return 0===(t=+t)||isNaN(t)?t:t>0?1:-1},ct.toRadians=function(t){return t*(Math.PI/180)},ct.toDegrees=function(t){return t*(180/Math.PI)},ct._decimalPlaces=function(t){if(ct.isFinite(t)){for(var e=1,i=0;Math.round(t*e)/e!==t;)e*=10,i++;return i}},ct.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}},ct.distanceBetweenPoints=function(t,e){return Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))},ct.aliasPixel=function(t){return t%2==0?0:.5},ct._alignPixel=function(t,e,i){var n=t.currentDevicePixelRatio,a=i/2;return Math.round((e-a)*n)/n+a},ct.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)}}},ct.EPSILON=Number.EPSILON||1e-14,ct.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||(ct.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))},ct.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]},ct.previousItem=function(t,e,i){return i?e<=0?t[t.length-1]:t[e-1]:e<=0?t[0]:t[e-1]},ct.niceNum=function(t,e){var i=Math.floor(ct.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)},ct.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)},ct.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(ct.getStyle(r,"padding-left")),u=parseFloat(ct.getStyle(r,"padding-top")),d=parseFloat(ct.getStyle(r,"padding-right")),h=parseFloat(ct.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)}},ct.getConstraintWidth=function(t){return i(t,"max-width","clientWidth")},ct.getConstraintHeight=function(t){return i(t,"max-height","clientHeight")},ct._calculatePadding=function(t,e,i){return(e=ct.getStyle(t,e)).indexOf("%")>-1?i*parseInt(e,10)/100:parseInt(e,10)},ct._getParentNode=function(t){var e=t.parentNode;return e&&"[object ShadowRoot]"===e.toString()&&(e=e.host),e},ct.getMaximumWidth=function(t){var e=ct._getParentNode(t);if(!e)return t.clientWidth;var i=e.clientWidth,n=i-ct._calculatePadding(e,"padding-left",i)-ct._calculatePadding(e,"padding-right",i),a=ct.getConstraintWidth(t);return isNaN(a)?n:Math.min(n,a)},ct.getMaximumHeight=function(t){var e=ct._getParentNode(t);if(!e)return t.clientHeight;var i=e.clientHeight,n=i-ct._calculatePadding(e,"padding-top",i)-ct._calculatePadding(e,"padding-bottom",i),a=ct.getConstraintHeight(t);return isNaN(a)?n:Math.min(n,a)},ct.getStyle=function(t,e){return t.currentStyle?t.currentStyle[e]:document.defaultView.getComputedStyle(t,null).getPropertyValue(e)},ct.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")}},ct.fontString=function(t,e,i){return e+" "+t+"px "+i},ct.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,s,l,u,d,h=0,c=i.length;for(o=0;o<c;o++)if(null!=(u=i[o])&&!0!==ct.isArray(u))h=ct.measureText(t,a,r,h,u);else if(ct.isArray(u))for(s=0,l=u.length;s<l;s++)null==(d=u[s])||ct.isArray(d)||(h=ct.measureText(t,a,r,h,d));var f=r.length/2;if(f>i.length){for(o=0;o<f;o++)delete a[r[o]];r.splice(0,f)}return h},ct.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},ct.numberOfLabelLines=function(t){var e=1;return ct.each(t,function(t){ct.isArray(t)&&t.length>e&&(e=t.length)}),e},ct.color=G?function(t){return t instanceof CanvasGradient&&(t=st.global.defaultColor),G(t)}:function(t){return console.error("Color.js not found!"),t},ct.getHoverColor=function(t){return t instanceof CanvasPattern||t instanceof CanvasGradient?t:ct.color(t).saturate(.5).darken(.1).rgbString()}}(),ki._adapters=Si,ki.Animation=_t,ki.animationService=kt,ki.controllers=xe,ki.DatasetController=Pt,ki.defaults=st,ki.Element=xt,ki.elements=Yt,ki.Interaction=Ce,ki.layouts=Re,ki.platform=ti,ki.plugins=ei,ki.Scale=Vi,ki.scaleService=ii,ki.Ticks=Ci,ki.Tooltip=fi,ki.helpers.each(On,function(t,e){ki.scaleService.registerScaleType(e,t,t._defaults)}),ea)ea.hasOwnProperty(ra)&&ki.plugins.register(ea[ra]);ki.platform.initialize();var oa=ki;return"undefined"!=typeof window&&(window.Chart=ki),ki.Chart=ki,ki.Legend=ea.legend._element,ki.Title=ea.title._element,ki.pluginService=ki.plugins,ki.PluginBase=ki.Element.extend({}),ki.canvasHelpers=ki.helpers.canvas,ki.layoutService=ki.layouts,ki.LinearScaleBase=Yi,ki.helpers.each(["Bar","Bubble","Doughnut","Line","PolarArea","Radar","Scatter"],function(t){ki[t]=function(e,i){return new ki(e,ki.helpers.merge(i||{},{type:t.charAt(0).toLowerCase()+t.slice(1)}))}}),oa});